diff options
Diffstat (limited to 'usr.sbin/sendmail/src/queue.c')
-rw-r--r-- | usr.sbin/sendmail/src/queue.c | 278 |
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'); |