summaryrefslogtreecommitdiff
path: root/usr.sbin/sendmail/src/queue.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/sendmail/src/queue.c')
-rw-r--r--usr.sbin/sendmail/src/queue.c278
1 files changed, 202 insertions, 76 deletions
diff --git a/usr.sbin/sendmail/src/queue.c b/usr.sbin/sendmail/src/queue.c
index eb5176eade915..299a0167ef9ce 100644
--- a/usr.sbin/sendmail/src/queue.c
+++ b/usr.sbin/sendmail/src/queue.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1983, 1995 Eric P. Allman
+ * Copyright (c) 1983, 1995, 1996 Eric P. Allman
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -36,9 +36,9 @@
#ifndef lint
#ifdef QUEUE
-static char sccsid[] = "@(#)queue.c 8.98.1.3 (Berkeley) 9/16/96 (with queueing)";
+static char sccsid[] = "@(#)queue.c 8.131 (Berkeley) 11/8/96 (with queueing)";
#else
-static char sccsid[] = "@(#)queue.c 8.98.1.3 (Berkeley) 9/16/96 (without queueing)";
+static char sccsid[] = "@(#)queue.c 8.131 (Berkeley) 11/8/96 (without queueing)";
#endif
#endif /* not lint */
@@ -71,6 +71,8 @@ WORK *WorkQ; /* queue of things to be done */
#if !defined(NGROUPS_MAX) && defined(NGROUPS)
# define NGROUPS_MAX NGROUPS /* POSIX naming convention */
#endif
+
+extern int orderq __P((bool));
/*
** QUEUEUP -- queue a message up for future transmission.
**
@@ -261,6 +263,12 @@ queueup(e, announce)
*p++ = 'r';
if (bitset(EF_HAS8BIT, e->e_flags))
*p++ = '8';
+ if (bitset(EF_DELETE_BCC, e->e_flags))
+ *p++ = 'b';
+ if (bitset(EF_RET_PARAM, e->e_flags))
+ *p++ = 'd';
+ if (bitset(EF_NO_BODY_RETN, e->e_flags))
+ *p++ = 'n';
*p++ = '\0';
if (buf[0] != '\0')
fprintf(tfp, "F%s\n", buf);
@@ -288,38 +296,45 @@ queueup(e, announce)
printctladdr(NULL, NULL);
for (q = e->e_sendqueue; q != NULL; q = q->q_next)
{
- if (bitset(QQUEUEUP, q->q_flags) ||
- !bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags))
+ if (bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags))
{
- printctladdr(q, tfp);
- if (q->q_orcpt != NULL)
- fprintf(tfp, "Q%s\n",
- denlstring(q->q_orcpt, TRUE, FALSE));
- putc('R', tfp);
- if (bitset(QPRIMARY, q->q_flags))
- putc('P', tfp);
- if (bitset(QPINGONSUCCESS, q->q_flags))
- putc('S', tfp);
- if (bitset(QPINGONFAILURE, q->q_flags))
- putc('F', tfp);
- if (bitset(QPINGONDELAY, q->q_flags))
- putc('D', tfp);
- putc(':', tfp);
- fprintf(tfp, "%s\n", denlstring(q->q_paddr, TRUE, FALSE));
- if (announce)
- {
- e->e_to = q->q_paddr;
- message("queued");
- if (LogLevel > 8)
- logdelivery(q->q_mailer, NULL, "queued",
- NULL, (time_t) 0, e);
- e->e_to = NULL;
- }
- if (tTd(40, 1))
- {
- printf("queueing ");
- printaddr(q, FALSE);
- }
+#if XDEBUG
+ if (bitset(QQUEUEUP, q->q_flags))
+ syslog(LOG_DEBUG, "%s: q_flags = %x",
+ e->e_id, q->q_flags);
+#endif
+ continue;
+ }
+ printctladdr(q, tfp);
+ if (q->q_orcpt != NULL)
+ fprintf(tfp, "Q%s\n",
+ denlstring(q->q_orcpt, TRUE, FALSE));
+ putc('R', tfp);
+ if (bitset(QPRIMARY, q->q_flags))
+ putc('P', tfp);
+ if (bitset(QHASNOTIFY, q->q_flags))
+ putc('N', tfp);
+ if (bitset(QPINGONSUCCESS, q->q_flags))
+ putc('S', tfp);
+ if (bitset(QPINGONFAILURE, q->q_flags))
+ putc('F', tfp);
+ if (bitset(QPINGONDELAY, q->q_flags))
+ putc('D', tfp);
+ putc(':', tfp);
+ fprintf(tfp, "%s\n", denlstring(q->q_paddr, TRUE, FALSE));
+ if (announce)
+ {
+ e->e_to = q->q_paddr;
+ message("queued");
+ if (LogLevel > 8)
+ logdelivery(q->q_mailer, NULL, "queued",
+ NULL, (time_t) 0, e);
+ e->e_to = NULL;
+ }
+ if (tTd(40, 1))
+ {
+ printf("queueing ");
+ printaddr(q, FALSE);
}
}
@@ -534,6 +549,7 @@ runqueue(forkflag)
int njobs;
int sequenceno = 0;
extern ENVELOPE BlankEnvelope;
+ extern void clrdaemon __P((void));
/*
** If no work will ever be selected, don't even bother reading
@@ -563,7 +579,7 @@ runqueue(forkflag)
if (forkflag)
{
- int pid;
+ pid_t pid;
extern void intsig();
#ifdef SIGCHLD
extern void reapchild();
@@ -578,7 +594,7 @@ runqueue(forkflag)
#ifndef SIGCHLD
(void) waitfor(pid);
#else
- CurChildren++;
+ proc_list_add(pid);
#endif /* SIGCHLD */
if (QueueIntvl != 0)
(void) setevent(QueueIntvl, runqueue, TRUE);
@@ -592,6 +608,7 @@ runqueue(forkflag)
(void) setsignal(SIGCHLD, SIG_DFL);
#endif /* SIGCHLD */
(void) setsignal(SIGHUP, intsig);
+ Verbose = FALSE;
}
setproctitle("running queue: %s", QueueDir);
@@ -613,6 +630,15 @@ runqueue(forkflag)
/* force it to run expensive jobs */
NoConnect = FALSE;
+ /* drop privileges */
+ if (geteuid() == (uid_t) 0)
+ {
+ if (RunAsGid != (gid_t) 0)
+ (void) setgid(RunAsGid);
+ if (RunAsUid != (uid_t) 0)
+ (void) setuid(RunAsUid);
+ }
+
/*
** Create ourselves an envelope
*/
@@ -628,6 +654,15 @@ runqueue(forkflag)
initmaps(FALSE, e);
/*
+ ** If we are running part of the queue, always ignore stored
+ ** host status.
+ */
+
+ if (QueueLimitId != NULL || QueueLimitSender != NULL ||
+ QueueLimitRecipient != NULL)
+ HostStatDir = NULL;
+
+ /*
** Start making passes through the queue.
** First, read and sort the entire queue.
** Then, process the work in that order.
@@ -643,6 +678,7 @@ runqueue(forkflag)
WORK *w = WorkQ;
WorkQ = WorkQ->w_next;
+ e->e_to = NULL;
/*
** Ignore jobs that are too expensive for the moment.
@@ -652,8 +688,11 @@ runqueue(forkflag)
if (shouldqueue(w->w_pri, w->w_ctime))
{
if (Verbose)
- printf("\nSkipping %s (sequence %d of %d)\n",
+ {
+ message("");
+ message("Skipping %s (sequence %d of %d)",
w->w_name + 2, sequenceno, njobs);
+ }
}
else
{
@@ -661,8 +700,11 @@ runqueue(forkflag)
extern pid_t dowork();
if (Verbose)
- printf("\nRunning %s (sequence %d of %d)\n",
+ {
+ message("");
+ message("Running %s (sequence %d of %d)",
w->w_name + 2, sequenceno, njobs);
+ }
pid = dowork(w->w_name + 2, ForkQueueRuns, FALSE, e);
errno = 0;
if (pid != 0)
@@ -850,10 +892,15 @@ orderq(doall)
i |= NEED_R;
while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
{
+ int qfver = 0;
extern bool strcontainedin();
switch (lbuf[0])
{
+ case 'V':
+ qfver = atoi(&lbuf[1]);
+ break;
+
case 'P':
w->w_pri = atol(&lbuf[1]);
i &= ~NEED_P;
@@ -868,8 +915,20 @@ orderq(doall)
if (w->w_host == NULL &&
(p = strrchr(&lbuf[1], '@')) != NULL)
w->w_host = newstr(&p[1]);
- if (QueueLimitRecipient == NULL ||
- strcontainedin(QueueLimitRecipient, &lbuf[1]))
+ if (QueueLimitRecipient == NULL)
+ {
+ i &= ~NEED_R;
+ break;
+ }
+ if (qfver > 0)
+ {
+ p = strchr(&lbuf[1], ':');
+ if (p == NULL)
+ p = &lbuf[1];
+ }
+ else
+ p = &lbuf[1];
+ if (strcontainedin(QueueLimitRecipient, p))
i &= ~NEED_R;
break;
@@ -958,6 +1017,16 @@ orderq(doall)
qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2);
}
+ else if (QueueSortOrder == QS_BYTIME)
+ {
+ extern workcmpf3();
+
+ /*
+ ** Simple sort based on submission time only.
+ */
+
+ qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf3);
+ }
else
{
extern workcmpf0();
@@ -1165,6 +1234,34 @@ workcmpf2(a, b)
return a->w_pri - b->w_pri;
}
/*
+** WORKCMPF3 -- simple submission-time-only compare function.
+**
+** Parameters:
+** a -- the first argument.
+** b -- the second argument.
+**
+** Returns:
+** -1 if a < b
+** 0 if a == b
+** +1 if a > b
+**
+** Side Effects:
+** none.
+*/
+
+int
+workcmpf3(a, b)
+ register WORK *a;
+ register WORK *b;
+{
+ if (a->w_ctime > b->w_ctime)
+ return 1;
+ else if (a->w_ctime < b->w_ctime)
+ return 1;
+ else
+ return 0;
+}
+ /*
** DOWORK -- do a work request.
**
** Parameters:
@@ -1276,7 +1373,7 @@ dowork(id, forkflag, requeueflag, e)
if (forkflag)
finis();
else
- dropenvelope(e);
+ dropenvelope(e, TRUE);
}
e->e_id = NULL;
return pid;
@@ -1304,13 +1401,13 @@ readqf(e)
struct stat st;
char *bp;
int qfver = 0;
+ long hdrsize = 0;
register char *p;
char *orcpt = NULL;
bool nomore = FALSE;
char qf[20];
char buf[MAXLINE];
extern ADDRESS *setctluser __P((char *, int));
- extern void loseqfile();
/*
** Read and process the file.
@@ -1355,7 +1452,8 @@ readqf(e)
return FALSE;
}
- if (st.st_uid != geteuid() || bitset(S_IWOTH|S_IWGRP, st.st_mode))
+ if ((st.st_uid != geteuid() && geteuid() != RealUid) ||
+ bitset(S_IWOTH|S_IWGRP, st.st_mode))
{
# ifdef LOG
if (LogLevel > 0)
@@ -1374,6 +1472,9 @@ readqf(e)
if (st.st_size == 0)
{
/* must be a bogus file -- just remove it */
+ qf[0] = 'd';
+ (void) unlink(qf);
+ qf[0] = 'q';
(void) unlink(qf);
fclose(qfp);
return FALSE;
@@ -1408,6 +1509,8 @@ readqf(e)
register char *p;
u_long qflags;
ADDRESS *q;
+ int mid;
+ auto char *ep;
if (tTd(40, 4))
printf("+++++ %s\n", bp);
@@ -1448,6 +1551,10 @@ readqf(e)
{
switch (*p)
{
+ case 'N':
+ qflags |= QHASNOTIFY;
+ break;
+
case 'S':
qflags |= QPINGONSUCCESS;
break;
@@ -1472,6 +1579,8 @@ readqf(e)
if (q != NULL)
{
q->q_alias = ctladdr;
+ if (qfver >= 1)
+ q->q_flags &= ~Q_PINGFLAGS;
q->q_flags |= qflags;
q->q_orcpt = orcpt;
(void) recipient(q, &e->e_sendqueue, 0, e);
@@ -1485,6 +1594,7 @@ readqf(e)
case 'H': /* header */
(void) chompheader(&bp[1], FALSE, NULL, e);
+ hdrsize += strlen(&bp[1]);
break;
case 'M': /* message */
@@ -1508,8 +1618,7 @@ readqf(e)
break;
case 'I': /* data file's inode number */
- if (e->e_dfino == -1)
- e->e_dfino = atol(&buf[1]);
+ /* regenerated below */
break;
case 'K': /* time of last deliver attempt */
@@ -1518,6 +1627,26 @@ readqf(e)
case 'N': /* number of delivery attempts */
e->e_ntries = atoi(&buf[1]);
+
+ /* if this has been tried recently, let it be */
+ if (e->e_ntries > 0 &&
+ (curtime() - e->e_dtime) < MinQueueAge)
+ {
+ char *howlong = pintvl(curtime() - e->e_dtime, TRUE);
+ extern void unlockqueue();
+
+ if (Verbose || tTd(40, 8))
+ printf("%s: too young (%s)\n",
+ e->e_id, howlong);
+#ifdef LOG
+ if (LogLevel > 19)
+ syslog(LOG_DEBUG, "%s: too young (%s)",
+ e->e_id, howlong);
+#endif
+ e->e_id = NULL;
+ unlockqueue(e);
+ return FALSE;
+ }
break;
case 'P': /* message priority */
@@ -1548,6 +1677,18 @@ readqf(e)
case '8': /* has 8 bit data */
e->e_flags |= EF_HAS8BIT;
break;
+
+ case 'b': /* delete Bcc: header */
+ e->e_flags |= EF_DELETE_BCC;
+ break;
+
+ case 'd': /* envelope has DSN RET= */
+ e->e_flags |= EF_RET_PARAM;
+ break;
+
+ case 'n': /* don't return body */
+ e->e_flags |= EF_NO_BODY_RETN;
+ break;
}
}
break;
@@ -1557,7 +1698,8 @@ readqf(e)
break;
case '$': /* define macro */
- define(bp[1], newstr(&bp[2]), e);
+ mid = macid(&bp[1], &ep);
+ define(mid, newstr(ep), e);
break;
case '.': /* terminate file */
@@ -1566,7 +1708,7 @@ readqf(e)
default:
syserr("readqf: %s: line %d: bad line \"%s\"",
- qf, LineNumber, bp);
+ qf, LineNumber, shortenstring(bp, 203));
fclose(qfp);
loseqfile(e, "unrecognized line");
return FALSE;
@@ -1588,25 +1730,6 @@ readqf(e)
return TRUE;
}
- /* if this has been tried recently, let it be */
- if (e->e_ntries > 0 && (curtime() - e->e_dtime) < MinQueueAge)
- {
- char *howlong = pintvl(curtime() - e->e_dtime, TRUE);
- extern void unlockqueue();
-
- if (Verbose || tTd(40, 8))
- printf("%s: too young (%s)\n",
- e->e_id, howlong);
-#ifdef LOG
- if (LogLevel > 19)
- syslog(LOG_DEBUG, "%s: too young (%s)",
- e->e_id, howlong);
-#endif
- e->e_id = NULL;
- unlockqueue(e);
- return FALSE;
- }
-
/*
** Arrange to read the data file.
*/
@@ -1622,7 +1745,7 @@ readqf(e)
e->e_flags |= EF_HAS_DF;
if (fstat(fileno(e->e_dfp), &st) >= 0)
{
- e->e_msgsize = st.st_size;
+ e->e_msgsize = st.st_size + hdrsize;
e->e_dfdev = st.st_dev;
e->e_dfino = st.st_ino;
}
@@ -1706,8 +1829,8 @@ printqueue()
CurrentLA = getla(); /* get load average */
printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
- if (nrequests > WorkListSize)
- printf(", only %d printed", WorkListSize);
+ if (MaxQueueRun > 0 && nrequests > MaxQueueRun)
+ printf(", only %d printed", MaxQueueRun);
if (Verbose)
printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
else
@@ -1775,7 +1898,7 @@ printqueue()
case 'S': /* sender name */
if (Verbose)
- printf("%8ld %10ld%c%.12s %.38s",
+ printf("%8ld %10ld%c%.12s %.78s",
dfsize,
w->w_pri,
bitset(EF_WARNING, flags) ? '+' : ' ',
@@ -1788,13 +1911,15 @@ printqueue()
{
printf("\n %10.10s", bodytype);
if (statmsg[0] != '\0')
- printf(" (%.60s)", statmsg);
+ printf(" (%.*s)",
+ Verbose ? 100 : 60,
+ statmsg);
}
break;
case 'C': /* controlling user */
if (Verbose)
- printf("\n\t\t\t\t (---%.34s---)",
+ printf("\n\t\t\t\t (---%.74s---)",
&buf[1]);
break;
@@ -1808,7 +1933,7 @@ printqueue()
p++;
}
if (Verbose)
- printf("\n\t\t\t\t\t %.38s", p);
+ printf("\n\t\t\t\t\t %.78s", p);
else
printf("\n\t\t\t\t %.45s", p);
break;
@@ -1863,7 +1988,7 @@ queuename(e, type)
register ENVELOPE *e;
int type;
{
- static int pid = -1;
+ static pid_t pid = -1;
static char c0;
static char c1;
static char c2;
@@ -1966,7 +2091,8 @@ unlockqueue(e)
ENVELOPE *e;
{
if (tTd(51, 4))
- printf("unlockqueue(%s)\n", e->e_id);
+ printf("unlockqueue(%s)\n",
+ e->e_id == NULL ? "NOQUEUE" : e->e_id);
/* if there is a lock file in the envelope, close it */
if (e->e_lockfp != NULL)
@@ -2090,7 +2216,7 @@ loseqfile(e, why)
if (e == NULL || e->e_id == NULL)
return;
- if (strlen(e->e_id) > sizeof buf - 4)
+ if (strlen(e->e_id) > (SIZE_T) sizeof buf - 4)
return;
strcpy(buf, queuename(e, 'q'));
p = queuename(e, 'Q');