1 /*
2 * Copyright (c) 1983, 1995 Eric P. Allman
3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * %sccs.include.redist.c%
7 */
8
9 # include "sendmail.h"
10
11 #ifndef lint
12 #ifdef QUEUE
13 static char sccsid[] = "@(#)queue.c 8.88 (Berkeley) 06/16/95 (with queueing)";
14 #else
15 static char sccsid[] = "@(#)queue.c 8.88 (Berkeley) 06/16/95 (without queueing)";
16 #endif
17 #endif /* not lint */
18
19 # include <errno.h>
20 # include <dirent.h>
21
22 # ifdef QUEUE
23
24 /*
25 ** Work queue.
26 */
27
28 struct work
29 {
30 char *w_name; /* name of control file */
31 char *w_host; /* name of recipient host */
32 bool w_lock; /* is message locked? */
33 long w_pri; /* priority of message, see below */
34 time_t w_ctime; /* creation time of message */
35 struct work *w_next; /* next in queue */
36 };
37
38 typedef struct work WORK;
39
40 WORK *WorkQ; /* queue of things to be done */
41
42 #define QF_VERSION 1 /* version number of this queue format */
43 /*
44 ** QUEUEUP -- queue a message up for future transmission.
45 **
46 ** Parameters:
47 ** e -- the envelope to queue up.
48 ** queueall -- if TRUE, queue all addresses, rather than
49 ** just those with the QQUEUEUP flag set.
50 ** announce -- if TRUE, tell when you are queueing up.
51 **
52 ** Returns:
53 ** none.
54 **
55 ** Side Effects:
56 ** The current request are saved in a control file.
57 ** The queue file is left locked.
58 */
59
60 void
queueup(e,queueall,announce)61 queueup(e, queueall, announce)
62 register ENVELOPE *e;
63 bool queueall;
64 bool announce;
65 {
66 char *qf;
67 register FILE *tfp;
68 register HDR *h;
69 register ADDRESS *q;
70 int fd;
71 int i;
72 bool newid;
73 register char *p;
74 MAILER nullmailer;
75 MCI mcibuf;
76 char buf[MAXLINE], tf[MAXLINE];
77 extern void printctladdr __P((ADDRESS *, FILE *));
78
79 /*
80 ** Create control file.
81 */
82
83 newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags);
84
85 /* if newid, queuename will create a locked qf file in e->lockfp */
86 strcpy(tf, queuename(e, 't'));
87 tfp = e->e_lockfp;
88 if (tfp == NULL)
89 newid = FALSE;
90
91 /* if newid, just write the qf file directly (instead of tf file) */
92 if (!newid)
93 {
94 /* get a locked tf file */
95 for (i = 0; i < 128; i++)
96 {
97 fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode);
98 if (fd < 0)
99 {
100 if (errno != EEXIST)
101 break;
102 #ifdef LOG
103 if (LogLevel > 0 && (i % 32) == 0)
104 syslog(LOG_ALERT, "queueup: cannot create %s, uid=%d: %s",
105 tf, geteuid(), errstring(errno));
106 #endif
107 }
108 else
109 {
110 if (lockfile(fd, tf, NULL, LOCK_EX|LOCK_NB))
111 break;
112 #ifdef LOG
113 else if (LogLevel > 0 && (i % 32) == 0)
114 syslog(LOG_ALERT, "queueup: cannot lock %s: %s",
115 tf, errstring(errno));
116 #endif
117 close(fd);
118 }
119
120 if ((i % 32) == 31)
121 {
122 /* save the old temp file away */
123 (void) rename(tf, queuename(e, 'T'));
124 }
125 else
126 sleep(i % 32);
127 }
128 if (fd < 0 || (tfp = fdopen(fd, "w")) == NULL)
129 {
130 printopenfds(TRUE);
131 syserr("!queueup: cannot create queue temp file %s, uid=%d",
132 tf, geteuid());
133 }
134 }
135
136 if (tTd(40, 1))
137 printf("\n>>>>> queueing %s%s queueall=%d >>>>>\n", e->e_id,
138 newid ? " (new id)" : "", queueall);
139 if (tTd(40, 3))
140 {
141 extern void printenvflags();
142
143 printf(" e_flags=");
144 printenvflags(e);
145 }
146 if (tTd(40, 32))
147 {
148 printf(" sendq=");
149 printaddr(e->e_sendqueue, TRUE);
150 }
151 if (tTd(40, 9))
152 {
153 printf(" tfp=");
154 dumpfd(fileno(tfp), TRUE, FALSE);
155 printf(" lockfp=");
156 if (e->e_lockfp == NULL)
157 printf("NULL\n");
158 else
159 dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
160 }
161
162 /*
163 ** If there is no data file yet, create one.
164 */
165
166 if (!bitset(EF_HAS_DF, e->e_flags))
167 {
168 register FILE *dfp;
169 char dfname[20];
170 struct stat stbuf;
171
172 strcpy(dfname, queuename(e, 'd'));
173 fd = open(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode);
174 if (fd < 0 || (dfp = fdopen(fd, "w")) == NULL)
175 syserr("!queueup: cannot create data temp file %s, uid=%d",
176 dfname, geteuid());
177 if (fstat(fd, &stbuf) < 0)
178 e->e_dfino = -1;
179 else
180 {
181 e->e_dfdev = stbuf.st_dev;
182 e->e_dfino = stbuf.st_ino;
183 }
184 e->e_flags |= EF_HAS_DF;
185 bzero(&mcibuf, sizeof mcibuf);
186 mcibuf.mci_out = dfp;
187 mcibuf.mci_mailer = FileMailer;
188 (*e->e_putbody)(&mcibuf, e, NULL);
189 (void) xfclose(dfp, "queueup dfp", e->e_id);
190 e->e_putbody = putbody;
191 }
192
193 /*
194 ** Output future work requests.
195 ** Priority and creation time should be first, since
196 ** they are required by orderq.
197 */
198
199 /* output queue version number (must be first!) */
200 fprintf(tfp, "V%d\n", QF_VERSION);
201
202 /* output message priority */
203 fprintf(tfp, "P%ld\n", e->e_msgpriority);
204
205 /* output creation time */
206 fprintf(tfp, "T%ld\n", e->e_ctime);
207
208 /* output last delivery time */
209 fprintf(tfp, "K%ld\n", e->e_dtime);
210
211 /* output number of delivery attempts */
212 fprintf(tfp, "N%d\n", e->e_ntries);
213
214 /* output inode number of data file */
215 /* XXX should probably include device major/minor too */
216 if (e->e_dfino != -1)
217 fprintf(tfp, "I%d/%d/%ld\n",
218 major(e->e_dfdev), minor(e->e_dfdev), e->e_dfino);
219
220 /* output body type */
221 if (e->e_bodytype != NULL)
222 fprintf(tfp, "B%s\n", e->e_bodytype);
223
224 /* message from envelope, if it exists */
225 if (e->e_message != NULL)
226 fprintf(tfp, "M%s\n", denlstring(e->e_message, TRUE, FALSE));
227
228 /* send various flag bits through */
229 p = buf;
230 if (bitset(EF_WARNING, e->e_flags))
231 *p++ = 'w';
232 if (bitset(EF_RESPONSE, e->e_flags))
233 *p++ = 'r';
234 if (bitset(EF_HAS8BIT, e->e_flags))
235 *p++ = '8';
236 *p++ = '\0';
237 if (buf[0] != '\0')
238 fprintf(tfp, "F%s\n", buf);
239
240 /* $r and $s and $_ macro values */
241 if ((p = macvalue('r', e)) != NULL)
242 fprintf(tfp, "$r%s\n", denlstring(p, TRUE, FALSE));
243 if ((p = macvalue('s', e)) != NULL)
244 fprintf(tfp, "$s%s\n", denlstring(p, TRUE, FALSE));
245 if ((p = macvalue('_', e)) != NULL)
246 fprintf(tfp, "$_%s\n", denlstring(p, TRUE, FALSE));
247
248 /* output name of sender */
249 if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags))
250 p = e->e_sender;
251 else
252 p = e->e_from.q_paddr;
253 fprintf(tfp, "S%s\n", denlstring(p, TRUE, FALSE));
254
255 /* output ESMTP-supplied "original" information */
256 if (e->e_envid != NULL)
257 fprintf(tfp, "Z%s\n", denlstring(e->e_envid, TRUE, FALSE));
258
259 /* output list of recipient addresses */
260 printctladdr(NULL, NULL);
261 for (q = e->e_sendqueue; q != NULL; q = q->q_next)
262 {
263 if (bitset(QQUEUEUP, q->q_flags) ||
264 (queueall && !bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags)))
265 {
266 printctladdr(q, tfp);
267 if (q->q_orcpt != NULL)
268 fprintf(tfp, "Q%s\n",
269 denlstring(q->q_orcpt, TRUE, FALSE));
270 putc('R', tfp);
271 if (bitset(QPRIMARY, q->q_flags))
272 putc('P', tfp);
273 if (bitset(QPINGONSUCCESS, q->q_flags))
274 putc('S', tfp);
275 if (bitset(QPINGONFAILURE, q->q_flags))
276 putc('F', tfp);
277 if (bitset(QPINGONDELAY, q->q_flags))
278 putc('D', tfp);
279 putc(':', tfp);
280 fprintf(tfp, "%s\n", denlstring(q->q_paddr, TRUE, FALSE));
281 if (announce)
282 {
283 e->e_to = q->q_paddr;
284 message("queued");
285 if (LogLevel > 8)
286 logdelivery(NULL, NULL, "queued",
287 NULL, (time_t) 0, e);
288 e->e_to = NULL;
289 }
290 if (tTd(40, 1))
291 {
292 printf("queueing ");
293 printaddr(q, FALSE);
294 }
295 }
296 }
297
298 /*
299 ** Output headers for this message.
300 ** Expand macros completely here. Queue run will deal with
301 ** everything as absolute headers.
302 ** All headers that must be relative to the recipient
303 ** can be cracked later.
304 ** We set up a "null mailer" -- i.e., a mailer that will have
305 ** no effect on the addresses as they are output.
306 */
307
308 bzero((char *) &nullmailer, sizeof nullmailer);
309 nullmailer.m_re_rwset = nullmailer.m_rh_rwset =
310 nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1;
311 nullmailer.m_eol = "\n";
312 bzero(&mcibuf, sizeof mcibuf);
313 mcibuf.mci_mailer = &nullmailer;
314 mcibuf.mci_out = tfp;
315
316 define('g', "\201f", e);
317 for (h = e->e_header; h != NULL; h = h->h_link)
318 {
319 extern bool bitzerop();
320
321 /* don't output null headers */
322 if (h->h_value == NULL || h->h_value[0] == '\0')
323 continue;
324
325 /* don't output resent headers on non-resent messages */
326 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
327 continue;
328
329 /* expand macros; if null, don't output header at all */
330 if (bitset(H_DEFAULT, h->h_flags))
331 {
332 (void) expand(h->h_value, buf, sizeof buf, e);
333 if (buf[0] == '\0')
334 continue;
335 }
336
337 /* output this header */
338 fprintf(tfp, "H");
339
340 /* if conditional, output the set of conditions */
341 if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))
342 {
343 int j;
344
345 (void) putc('?', tfp);
346 for (j = '\0'; j <= '\177'; j++)
347 if (bitnset(j, h->h_mflags))
348 (void) putc(j, tfp);
349 (void) putc('?', tfp);
350 }
351
352 /* output the header: expand macros, convert addresses */
353 if (bitset(H_DEFAULT, h->h_flags))
354 {
355 fprintf(tfp, "%s: %s\n", h->h_field, buf);
356 }
357 else if (bitset(H_FROM|H_RCPT, h->h_flags))
358 {
359 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
360 FILE *savetrace = TrafficLogFile;
361
362 TrafficLogFile = NULL;
363
364 if (bitset(H_FROM, h->h_flags))
365 oldstyle = FALSE;
366
367 commaize(h, h->h_value, oldstyle, &mcibuf, e);
368
369 TrafficLogFile = savetrace;
370 }
371 else
372 fprintf(tfp, "%s: %s\n", h->h_field, h->h_value);
373 }
374
375 /*
376 ** Clean up.
377 **
378 ** Write a terminator record -- this is to prevent
379 ** scurrilous crackers from appending any data.
380 */
381
382 fprintf(tfp, ".\n");
383
384 if (fflush(tfp) < 0 || fsync(fileno(tfp)) < 0 || ferror(tfp))
385 {
386 if (newid)
387 syserr("!552 Error writing control file %s", tf);
388 else
389 syserr("!452 Error writing control file %s", tf);
390 }
391
392 if (!newid)
393 {
394 /* rename (locked) tf to be (locked) qf */
395 qf = queuename(e, 'q');
396 if (rename(tf, qf) < 0)
397 syserr("cannot rename(%s, %s), uid=%d",
398 tf, qf, geteuid());
399
400 /* close and unlock old (locked) qf */
401 if (e->e_lockfp != NULL)
402 (void) xfclose(e->e_lockfp, "queueup lockfp", e->e_id);
403 e->e_lockfp = tfp;
404 }
405 else
406 qf = tf;
407 errno = 0;
408 e->e_flags |= EF_INQUEUE;
409
410 # ifdef LOG
411 /* save log info */
412 if (LogLevel > 79)
413 syslog(LOG_DEBUG, "%s: queueup, qf=%s", e->e_id, qf);
414 # endif /* LOG */
415
416 if (tTd(40, 1))
417 printf("<<<<< done queueing %s <<<<<\n\n", e->e_id);
418 return;
419 }
420
421 void
printctladdr(a,tfp)422 printctladdr(a, tfp)
423 register ADDRESS *a;
424 FILE *tfp;
425 {
426 char *uname;
427 register struct passwd *pw;
428 register ADDRESS *q;
429 uid_t uid;
430 static ADDRESS *lastctladdr;
431 static uid_t lastuid;
432
433 /* initialization */
434 if (a == NULL || a->q_alias == NULL || tfp == NULL)
435 {
436 if (lastctladdr != NULL && tfp != NULL)
437 fprintf(tfp, "C\n");
438 lastctladdr = NULL;
439 lastuid = 0;
440 return;
441 }
442
443 /* find the active uid */
444 q = getctladdr(a);
445 if (q == NULL)
446 uid = 0;
447 else
448 uid = q->q_uid;
449 a = a->q_alias;
450
451 /* check to see if this is the same as last time */
452 if (lastctladdr != NULL && uid == lastuid &&
453 strcmp(lastctladdr->q_paddr, a->q_paddr) == 0)
454 return;
455 lastuid = uid;
456 lastctladdr = a;
457
458 if (uid == 0 || (pw = sm_getpwuid(uid)) == NULL)
459 uname = "";
460 else
461 uname = pw->pw_name;
462
463 fprintf(tfp, "C%s:%s\n", uname, denlstring(a->q_paddr, TRUE, FALSE));
464 }
465 /*
466 ** RUNQUEUE -- run the jobs in the queue.
467 **
468 ** Gets the stuff out of the queue in some presumably logical
469 ** order and processes them.
470 **
471 ** Parameters:
472 ** forkflag -- TRUE if the queue scanning should be done in
473 ** a child process. We double-fork so it is not our
474 ** child and we don't have to clean up after it.
475 **
476 ** Returns:
477 ** none.
478 **
479 ** Side Effects:
480 ** runs things in the mail queue.
481 */
482
483 ENVELOPE QueueEnvelope; /* the queue run envelope */
484
485 void
runqueue(forkflag)486 runqueue(forkflag)
487 bool forkflag;
488 {
489 register ENVELOPE *e;
490 int njobs;
491 int sequenceno = 0;
492 extern ENVELOPE BlankEnvelope;
493
494 /*
495 ** If no work will ever be selected, don't even bother reading
496 ** the queue.
497 */
498
499 CurrentLA = getla(); /* get load average */
500
501 if (shouldqueue(0L, curtime()))
502 {
503 char *msg = "Skipping queue run -- load average too high";
504
505 if (Verbose)
506 printf("%s\n", msg);
507 #ifdef LOG
508 if (LogLevel > 8)
509 syslog(LOG_INFO, "runqueue: %s", msg);
510 #endif
511 if (forkflag && QueueIntvl != 0)
512 (void) setevent(QueueIntvl, runqueue, TRUE);
513 return;
514 }
515
516 /*
517 ** See if we want to go off and do other useful work.
518 */
519
520 if (forkflag)
521 {
522 int pid;
523 #ifdef SIGCHLD
524 extern void reapchild();
525
526 (void) setsignal(SIGCHLD, reapchild);
527 #endif
528
529 pid = dofork();
530 if (pid != 0)
531 {
532 /* parent -- pick up intermediate zombie */
533 #ifndef SIGCHLD
534 (void) waitfor(pid);
535 #else
536 CurChildren++;
537 #endif /* SIGCHLD */
538 if (QueueIntvl != 0)
539 (void) setevent(QueueIntvl, runqueue, TRUE);
540 return;
541 }
542 /* child -- double fork */
543 #ifndef SIGCHLD
544 if (fork() != 0)
545 exit(EX_OK);
546 #else /* SIGCHLD */
547 (void) setsignal(SIGCHLD, SIG_DFL);
548 #endif /* SIGCHLD */
549 }
550
551 setproctitle("running queue: %s", QueueDir);
552
553 # ifdef LOG
554 if (LogLevel > 69)
555 syslog(LOG_DEBUG, "runqueue %s, pid=%d, forkflag=%d",
556 QueueDir, getpid(), forkflag);
557 # endif /* LOG */
558
559 /*
560 ** Release any resources used by the daemon code.
561 */
562
563 # ifdef DAEMON
564 clrdaemon();
565 # endif /* DAEMON */
566
567 /* force it to run expensive jobs */
568 NoConnect = FALSE;
569
570 /*
571 ** Create ourselves an envelope
572 */
573
574 CurEnv = &QueueEnvelope;
575 e = newenvelope(&QueueEnvelope, CurEnv);
576 e->e_flags = BlankEnvelope.e_flags;
577
578 /*
579 ** Make sure the alias database is open.
580 */
581
582 initmaps(FALSE, e);
583
584 /*
585 ** Start making passes through the queue.
586 ** First, read and sort the entire queue.
587 ** Then, process the work in that order.
588 ** But if you take too long, start over.
589 */
590
591 /* order the existing work requests */
592 njobs = orderq(FALSE);
593
594 /* process them once at a time */
595 while (WorkQ != NULL)
596 {
597 WORK *w = WorkQ;
598
599 WorkQ = WorkQ->w_next;
600
601 /*
602 ** Ignore jobs that are too expensive for the moment.
603 */
604
605 sequenceno++;
606 if (shouldqueue(w->w_pri, w->w_ctime))
607 {
608 if (Verbose)
609 printf("\nSkipping %s (sequence %d of %d)\n",
610 w->w_name + 2, sequenceno, njobs);
611 }
612 else
613 {
614 pid_t pid;
615 extern pid_t dowork();
616
617 if (Verbose)
618 printf("\nRunning %s (sequence %d of %d)\n",
619 w->w_name + 2, sequenceno, njobs);
620 pid = dowork(w->w_name + 2, ForkQueueRuns, FALSE, e);
621 errno = 0;
622 if (pid != 0)
623 (void) waitfor(pid);
624 }
625 free(w->w_name);
626 if (w->w_host)
627 free(w->w_host);
628 free((char *) w);
629 }
630
631 /* exit without the usual cleanup */
632 e->e_id = NULL;
633 finis();
634 }
635 /*
636 ** ORDERQ -- order the work queue.
637 **
638 ** Parameters:
639 ** doall -- if set, include everything in the queue (even
640 ** the jobs that cannot be run because the load
641 ** average is too high). Otherwise, exclude those
642 ** jobs.
643 **
644 ** Returns:
645 ** The number of request in the queue (not necessarily
646 ** the number of requests in WorkQ however).
647 **
648 ** Side Effects:
649 ** Sets WorkQ to the queue of available work, in order.
650 */
651
652 # define NEED_P 001
653 # define NEED_T 002
654 # define NEED_R 004
655 # define NEED_S 010
656
657 static WORK *WorkList = NULL;
658 static int WorkListSize = 0;
659
660 int
orderq(doall)661 orderq(doall)
662 bool doall;
663 {
664 register struct dirent *d;
665 register WORK *w;
666 DIR *f;
667 register int i;
668 int wn = -1;
669 int wc;
670
671 if (tTd(41, 1))
672 {
673 printf("orderq:\n");
674 if (QueueLimitId != NULL)
675 printf("\tQueueLimitId = %s\n", QueueLimitId);
676 if (QueueLimitSender != NULL)
677 printf("\tQueueLimitSender = %s\n", QueueLimitSender);
678 if (QueueLimitRecipient != NULL)
679 printf("\tQueueLimitRecipient = %s\n", QueueLimitRecipient);
680 }
681
682 /* clear out old WorkQ */
683 for (w = WorkQ; w != NULL; )
684 {
685 register WORK *nw = w->w_next;
686
687 WorkQ = nw;
688 free(w->w_name);
689 if (w->w_host)
690 free(w->w_host);
691 free((char *) w);
692 w = nw;
693 }
694
695 /* open the queue directory */
696 f = opendir(".");
697 if (f == NULL)
698 {
699 syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
700 return (0);
701 }
702
703 /*
704 ** Read the work directory.
705 */
706
707 while ((d = readdir(f)) != NULL)
708 {
709 FILE *cf;
710 register char *p;
711 char lbuf[MAXNAME + 1];
712 extern bool strcontainedin();
713
714 /* is this an interesting entry? */
715 if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
716 continue;
717
718 if (QueueLimitId != NULL &&
719 !strcontainedin(QueueLimitId, d->d_name))
720 continue;
721
722 #ifdef PICKY_QF_NAME_CHECK
723 /*
724 ** Check queue name for plausibility. This handles
725 ** both old and new type ids.
726 */
727
728 p = d->d_name + 2;
729 if (isupper(p[0]) && isupper(p[2]))
730 p += 3;
731 else if (isupper(p[1]))
732 p += 2;
733 else
734 p = d->d_name;
735 for (i = 0; isdigit(*p); p++)
736 i++;
737 if (i < 5 || *p != '\0')
738 {
739 if (Verbose)
740 printf("orderq: bogus qf name %s\n", d->d_name);
741 # ifdef LOG
742 if (LogLevel > 0)
743 syslog(LOG_ALERT, "orderq: bogus qf name %s",
744 d->d_name);
745 # endif
746 if (strlen(d->d_name) > (SIZE_T) MAXNAME)
747 d->d_name[MAXNAME] = '\0';
748 strcpy(lbuf, d->d_name);
749 lbuf[0] = 'Q';
750 (void) rename(d->d_name, lbuf);
751 continue;
752 }
753 #endif
754
755 /* open control file (if not too many files) */
756 if (++wn > MaxQueueRun && MaxQueueRun > 0)
757 {
758 # ifdef LOG
759 if (wn == MaxQueueRun + 1 && LogLevel > 0)
760 syslog(LOG_ALERT, "WorkList for %s maxed out at %d",
761 QueueDir, MaxQueueRun);
762 # endif
763 continue;
764 }
765 if (wn >= WorkListSize)
766 {
767 extern void grow_wlist __P((void));
768
769 grow_wlist();
770 if (wn >= WorkListSize)
771 continue;
772 }
773
774 cf = fopen(d->d_name, "r");
775 if (cf == NULL)
776 {
777 /* this may be some random person sending hir msgs */
778 /* syserr("orderq: cannot open %s", cbuf); */
779 if (tTd(41, 2))
780 printf("orderq: cannot open %s (%d)\n",
781 d->d_name, errno);
782 errno = 0;
783 wn--;
784 continue;
785 }
786 w = &WorkList[wn];
787 w->w_name = newstr(d->d_name);
788 w->w_host = NULL;
789 w->w_lock = !lockfile(fileno(cf), w->w_name, NULL, LOCK_SH|LOCK_NB);
790
791 /* make sure jobs in creation don't clog queue */
792 w->w_pri = 0x7fffffff;
793 w->w_ctime = 0;
794
795 /* extract useful information */
796 i = NEED_P | NEED_T;
797 if (QueueLimitSender != NULL)
798 i |= NEED_S;
799 if (QueueSortOrder == QS_BYHOST || QueueLimitRecipient != NULL)
800 i |= NEED_R;
801 while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
802 {
803 extern bool strcontainedin();
804
805 switch (lbuf[0])
806 {
807 case 'P':
808 w->w_pri = atol(&lbuf[1]);
809 i &= ~NEED_P;
810 break;
811
812 case 'T':
813 w->w_ctime = atol(&lbuf[1]);
814 i &= ~NEED_T;
815 break;
816
817 case 'R':
818 if (w->w_host == NULL &&
819 (p = strrchr(&lbuf[1], '@')) != NULL)
820 w->w_host = newstr(&p[1]);
821 if (QueueLimitRecipient == NULL ||
822 strcontainedin(QueueLimitRecipient, &lbuf[1]))
823 i &= ~NEED_R;
824 break;
825
826 case 'S':
827 if (QueueLimitSender != NULL &&
828 strcontainedin(QueueLimitSender, &lbuf[1]))
829 i &= ~NEED_S;
830 break;
831 }
832 }
833 (void) fclose(cf);
834
835 if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
836 bitset(NEED_R|NEED_S, i))
837 {
838 /* don't even bother sorting this job in */
839 free(w->w_name);
840 if (w->w_host)
841 free(w->w_host);
842 wn--;
843 }
844 }
845 (void) closedir(f);
846 wn++;
847
848 wc = min(wn, WorkListSize);
849
850 if (QueueSortOrder == QS_BYHOST)
851 {
852 extern workcmpf1();
853 extern workcmpf2();
854
855 /*
856 ** Sort the work directory for the first time,
857 ** based on host name, lock status, and priority.
858 */
859
860 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf1);
861
862 /*
863 ** If one message to host is locked, "lock" all messages
864 ** to that host.
865 */
866
867 i = 0;
868 while (i < wc)
869 {
870 if (!WorkList[i].w_lock)
871 {
872 i++;
873 continue;
874 }
875 w = &WorkList[i];
876 while (++i < wc)
877 {
878 if (WorkList[i].w_host == NULL &&
879 w->w_host == NULL)
880 WorkList[i].w_lock = TRUE;
881 else if (WorkList[i].w_host != NULL &&
882 w->w_host != NULL &&
883 strcmp(WorkList[i].w_host, w->w_host) == 0)
884 WorkList[i].w_lock = TRUE;
885 else
886 break;
887 }
888 }
889
890 /*
891 ** Sort the work directory for the second time,
892 ** based on lock status, host name, and priority.
893 */
894
895 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2);
896 }
897 else
898 {
899 extern workcmpf0();
900
901 /*
902 ** Simple sort based on queue priority only.
903 */
904
905 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0);
906 }
907
908 /*
909 ** Convert the work list into canonical form.
910 ** Should be turning it into a list of envelopes here perhaps.
911 */
912
913 WorkQ = NULL;
914 for (i = wc; --i >= 0; )
915 {
916 w = (WORK *) xalloc(sizeof *w);
917 w->w_name = WorkList[i].w_name;
918 w->w_host = WorkList[i].w_host;
919 w->w_lock = WorkList[i].w_lock;
920 w->w_pri = WorkList[i].w_pri;
921 w->w_ctime = WorkList[i].w_ctime;
922 w->w_next = WorkQ;
923 WorkQ = w;
924 }
925 free(WorkList);
926 WorkList = NULL;
927
928 if (tTd(40, 1))
929 {
930 for (w = WorkQ; w != NULL; w = w->w_next)
931 printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
932 }
933
934 return (wn);
935 }
936 /*
937 ** GROW_WLIST -- make the work list larger
938 **
939 ** Parameters:
940 ** none.
941 **
942 ** Returns:
943 ** none.
944 **
945 ** Side Effects:
946 ** Adds another QUEUESEGSIZE entries to WorkList if possible.
947 ** It can fail if there isn't enough memory, so WorkListSize
948 ** should be checked again upon return.
949 */
950
951 void
grow_wlist()952 grow_wlist()
953 {
954 if (tTd(41, 1))
955 printf("grow_wlist: WorkListSize=%d\n", WorkListSize);
956 if (WorkList == NULL)
957 {
958 WorkList = (WORK *) xalloc(sizeof(WORK) * (QUEUESEGSIZE + 1));
959 WorkListSize = QUEUESEGSIZE;
960 }
961 else
962 {
963 int newsize = WorkListSize + QUEUESEGSIZE;
964 WORK *newlist = (WORK *) realloc((char *)WorkList,
965 (unsigned)sizeof(WORK) * (newsize + 1));
966
967 if (newlist != NULL)
968 {
969 WorkListSize = newsize;
970 WorkList = newlist;
971 # ifdef LOG
972 if (LogLevel > 1)
973 {
974 syslog(LOG_NOTICE, "grew WorkList for %s to %d",
975 QueueDir, WorkListSize);
976 }
977 }
978 else if (LogLevel > 0)
979 {
980 syslog(LOG_ALERT, "FAILED to grow WorkList for %s to %d",
981 QueueDir, newsize);
982 # endif
983 }
984 }
985 if (tTd(41, 1))
986 printf("grow_wlist: WorkListSize now %d\n", WorkListSize);
987 }
988 /*
989 ** WORKCMPF0 -- simple priority-only compare function.
990 **
991 ** Parameters:
992 ** a -- the first argument.
993 ** b -- the second argument.
994 **
995 ** Returns:
996 ** -1 if a < b
997 ** 0 if a == b
998 ** +1 if a > b
999 **
1000 ** Side Effects:
1001 ** none.
1002 */
1003
1004 int
workcmpf0(a,b)1005 workcmpf0(a, b)
1006 register WORK *a;
1007 register WORK *b;
1008 {
1009 long pa = a->w_pri;
1010 long pb = b->w_pri;
1011
1012 if (pa == pb)
1013 return 0;
1014 else if (pa > pb)
1015 return 1;
1016 else
1017 return -1;
1018 }
1019 /*
1020 ** WORKCMPF1 -- first compare function for ordering work based on host name.
1021 **
1022 ** Sorts on host name, lock status, and priority in that order.
1023 **
1024 ** Parameters:
1025 ** a -- the first argument.
1026 ** b -- the second argument.
1027 **
1028 ** Returns:
1029 ** <0 if a < b
1030 ** 0 if a == b
1031 ** >0 if a > b
1032 **
1033 ** Side Effects:
1034 ** none.
1035 */
1036
1037 int
workcmpf1(a,b)1038 workcmpf1(a, b)
1039 register WORK *a;
1040 register WORK *b;
1041 {
1042 int i;
1043
1044 /* host name */
1045 if (a->w_host != NULL && b->w_host == NULL)
1046 return 1;
1047 else if (a->w_host == NULL && b->w_host != NULL)
1048 return -1;
1049 if (a->w_host != NULL && b->w_host != NULL &&
1050 (i = strcmp(a->w_host, b->w_host)))
1051 return i;
1052
1053 /* lock status */
1054 if (a->w_lock != b->w_lock)
1055 return b->w_lock - a->w_lock;
1056
1057 /* job priority */
1058 return a->w_pri - b->w_pri;
1059 }
1060 /*
1061 ** WORKCMPF2 -- second compare function for ordering work based on host name.
1062 **
1063 ** Sorts on lock status, host name, and priority in that order.
1064 **
1065 ** Parameters:
1066 ** a -- the first argument.
1067 ** b -- the second argument.
1068 **
1069 ** Returns:
1070 ** <0 if a < b
1071 ** 0 if a == b
1072 ** >0 if a > b
1073 **
1074 ** Side Effects:
1075 ** none.
1076 */
1077
1078 int
workcmpf2(a,b)1079 workcmpf2(a, b)
1080 register WORK *a;
1081 register WORK *b;
1082 {
1083 int i;
1084
1085 /* lock status */
1086 if (a->w_lock != b->w_lock)
1087 return a->w_lock - b->w_lock;
1088
1089 /* host name */
1090 if (a->w_host != NULL && b->w_host == NULL)
1091 return 1;
1092 else if (a->w_host == NULL && b->w_host != NULL)
1093 return -1;
1094 if (a->w_host != NULL && b->w_host != NULL &&
1095 (i = strcmp(a->w_host, b->w_host)))
1096 return i;
1097
1098 /* job priority */
1099 return a->w_pri - b->w_pri;
1100 }
1101 /*
1102 ** DOWORK -- do a work request.
1103 **
1104 ** Parameters:
1105 ** id -- the ID of the job to run.
1106 ** forkflag -- if set, run this in background.
1107 ** requeueflag -- if set, reinstantiate the queue quickly.
1108 ** This is used when expanding aliases in the queue.
1109 ** If forkflag is also set, it doesn't wait for the
1110 ** child.
1111 ** e - the envelope in which to run it.
1112 **
1113 ** Returns:
1114 ** process id of process that is running the queue job.
1115 **
1116 ** Side Effects:
1117 ** The work request is satisfied if possible.
1118 */
1119
1120 pid_t
dowork(id,forkflag,requeueflag,e)1121 dowork(id, forkflag, requeueflag, e)
1122 char *id;
1123 bool forkflag;
1124 bool requeueflag;
1125 register ENVELOPE *e;
1126 {
1127 register pid_t pid;
1128 extern bool readqf();
1129
1130 if (tTd(40, 1))
1131 printf("dowork(%s)\n", id);
1132
1133 /*
1134 ** Fork for work.
1135 */
1136
1137 if (forkflag)
1138 {
1139 pid = fork();
1140 if (pid < 0)
1141 {
1142 syserr("dowork: cannot fork");
1143 return 0;
1144 }
1145 else if (pid > 0)
1146 {
1147 /* parent -- clean out connection cache */
1148 mci_flush(FALSE, NULL);
1149 }
1150 }
1151 else
1152 {
1153 pid = 0;
1154 }
1155
1156 if (pid == 0)
1157 {
1158 /*
1159 ** CHILD
1160 ** Lock the control file to avoid duplicate deliveries.
1161 ** Then run the file as though we had just read it.
1162 ** We save an idea of the temporary name so we
1163 ** can recover on interrupt.
1164 */
1165
1166 /* set basic modes, etc. */
1167 (void) alarm(0);
1168 clearenvelope(e, FALSE);
1169 e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
1170 e->e_errormode = EM_MAIL;
1171 e->e_id = id;
1172 GrabTo = UseErrorsTo = FALSE;
1173 ExitStat = EX_OK;
1174 if (forkflag)
1175 {
1176 disconnect(1, e);
1177 OpMode = MD_DELIVER;
1178 }
1179 # ifdef LOG
1180 if (LogLevel > 76)
1181 syslog(LOG_DEBUG, "%s: dowork, pid=%d", e->e_id,
1182 getpid());
1183 # endif /* LOG */
1184
1185 /* don't use the headers from sendmail.cf... */
1186 e->e_header = NULL;
1187
1188 /* read the queue control file -- return if locked */
1189 if (!readqf(e))
1190 {
1191 if (tTd(40, 4))
1192 printf("readqf(%s) failed\n", e->e_id);
1193 if (forkflag)
1194 exit(EX_OK);
1195 else
1196 return 0;
1197 }
1198
1199 e->e_flags |= EF_INQUEUE;
1200
1201 /* if this has been tried recently, let it be */
1202 if (e->e_ntries > 0 && (curtime() - e->e_dtime) < MinQueueAge)
1203 {
1204 char *howlong = pintvl(curtime() - e->e_dtime, TRUE);
1205
1206 e->e_flags |= EF_KEEPQUEUE;
1207 if (Verbose || tTd(40, 8))
1208 printf("%s: too young (%s)\n",
1209 e->e_id, howlong);
1210 #ifdef LOG
1211 if (LogLevel > 19)
1212 syslog(LOG_DEBUG, "%s: too young (%s)",
1213 e->e_id, howlong);
1214 #endif
1215 }
1216 else
1217 {
1218 eatheader(e, requeueflag);
1219
1220 if (requeueflag)
1221 queueup(e, TRUE, FALSE);
1222
1223 /* do the delivery */
1224 sendall(e, SM_DELIVER);
1225 }
1226
1227 /* finish up and exit */
1228 if (forkflag)
1229 finis();
1230 else
1231 dropenvelope(e);
1232 }
1233 e->e_id = NULL;
1234 return pid;
1235 }
1236 /*
1237 ** READQF -- read queue file and set up environment.
1238 **
1239 ** Parameters:
1240 ** e -- the envelope of the job to run.
1241 **
1242 ** Returns:
1243 ** TRUE if it successfully read the queue file.
1244 ** FALSE otherwise.
1245 **
1246 ** Side Effects:
1247 ** The queue file is returned locked.
1248 */
1249
1250 bool
readqf(e)1251 readqf(e)
1252 register ENVELOPE *e;
1253 {
1254 register FILE *qfp;
1255 ADDRESS *ctladdr;
1256 struct stat st;
1257 char *bp;
1258 int qfver = 0;
1259 register char *p;
1260 char *orcpt = NULL;
1261 bool nomore = FALSE;
1262 char qf[20];
1263 char buf[MAXLINE];
1264 extern ADDRESS *setctluser();
1265 extern void loseqfile();
1266
1267 /*
1268 ** Read and process the file.
1269 */
1270
1271 strcpy(qf, queuename(e, 'q'));
1272 qfp = fopen(qf, "r+");
1273 if (qfp == NULL)
1274 {
1275 if (tTd(40, 8))
1276 printf("readqf(%s): fopen failure (%s)\n",
1277 qf, errstring(errno));
1278 if (errno != ENOENT)
1279 syserr("readqf: no control file %s", qf);
1280 return FALSE;
1281 }
1282
1283 if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB))
1284 {
1285 /* being processed by another queuer */
1286 if (Verbose || tTd(40, 8))
1287 printf("%s: locked\n", e->e_id);
1288 # ifdef LOG
1289 if (LogLevel > 19)
1290 syslog(LOG_DEBUG, "%s: locked", e->e_id);
1291 # endif /* LOG */
1292 (void) fclose(qfp);
1293 return FALSE;
1294 }
1295
1296 /*
1297 ** Check the queue file for plausibility to avoid attacks.
1298 */
1299
1300 if (fstat(fileno(qfp), &st) < 0)
1301 {
1302 /* must have been being processed by someone else */
1303 if (tTd(40, 8))
1304 printf("readqf(%s): fstat failure (%s)\n",
1305 qf, errstring(errno));
1306 fclose(qfp);
1307 return FALSE;
1308 }
1309
1310 if (st.st_uid != geteuid() || bitset(S_IWOTH|S_IWGRP, st.st_mode))
1311 {
1312 # ifdef LOG
1313 if (LogLevel > 0)
1314 {
1315 syslog(LOG_ALERT, "%s: bogus queue file, uid=%d, mode=%o",
1316 e->e_id, st.st_uid, st.st_mode);
1317 }
1318 # endif /* LOG */
1319 if (tTd(40, 8))
1320 printf("readqf(%s): bogus file\n", qf);
1321 loseqfile(e, "bogus file uid in mqueue");
1322 fclose(qfp);
1323 return FALSE;
1324 }
1325
1326 if (st.st_size == 0)
1327 {
1328 /* must be a bogus file -- just remove it */
1329 (void) unlink(qf);
1330 fclose(qfp);
1331 return FALSE;
1332 }
1333
1334 if (st.st_nlink == 0)
1335 {
1336 /*
1337 ** Race condition -- we got a file just as it was being
1338 ** unlinked. Just assume it is zero length.
1339 */
1340
1341 fclose(qfp);
1342 return FALSE;
1343 }
1344
1345 /* good file -- save this lock */
1346 e->e_lockfp = qfp;
1347
1348 /* do basic system initialization */
1349 initsys(e);
1350 define('i', e->e_id, e);
1351
1352 LineNumber = 0;
1353 e->e_flags |= EF_GLOBALERRS;
1354 OpMode = MD_DELIVER;
1355 ctladdr = NULL;
1356 e->e_dfino = -1;
1357 e->e_msgsize = -1;
1358 while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
1359 {
1360 register char *p;
1361 u_long qflags;
1362 ADDRESS *q;
1363
1364 if (tTd(40, 4))
1365 printf("+++++ %s\n", bp);
1366 if (nomore)
1367 {
1368 /* hack attack */
1369 syserr("SECURITY ALERT: extra data in qf: %s", bp);
1370 fclose(qfp);
1371 loseqfile(e, "bogus queue line");
1372 return FALSE;
1373 }
1374 switch (bp[0])
1375 {
1376 case 'V': /* queue file version number */
1377 qfver = atoi(&bp[1]);
1378 if (qfver > QF_VERSION)
1379 {
1380 syserr("Version number in qf (%d) greater than max (%d)",
1381 qfver, QF_VERSION);
1382 }
1383 break;
1384
1385 case 'C': /* specify controlling user */
1386 ctladdr = setctluser(&bp[1]);
1387 break;
1388
1389 case 'Q': /* original recipient */
1390 orcpt = newstr(&bp[1]);
1391 break;
1392
1393 case 'R': /* specify recipient */
1394 p = bp;
1395 qflags = 0;
1396 if (qfver >= 1)
1397 {
1398 /* get flag bits */
1399 while (*++p != '\0' && *p != ':')
1400 {
1401 switch (*p)
1402 {
1403 case 'S':
1404 qflags |= QPINGONSUCCESS;
1405 break;
1406
1407 case 'F':
1408 qflags |= QPINGONFAILURE;
1409 break;
1410
1411 case 'D':
1412 qflags |= QPINGONDELAY;
1413 break;
1414
1415 case 'P':
1416 qflags |= QPRIMARY;
1417 break;
1418 }
1419 }
1420 }
1421 else
1422 qflags |= QPRIMARY;
1423 q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', NULL, e);
1424 if (q != NULL)
1425 {
1426 q->q_alias = ctladdr;
1427 q->q_flags |= qflags;
1428 q->q_orcpt = orcpt;
1429 (void) recipient(q, &e->e_sendqueue, 0, e);
1430 }
1431 orcpt = NULL;
1432 break;
1433
1434 case 'E': /* specify error recipient */
1435 /* no longer used */
1436 break;
1437
1438 case 'H': /* header */
1439 (void) chompheader(&bp[1], FALSE, NULL, e);
1440 break;
1441
1442 case 'M': /* message */
1443 /* ignore this; we want a new message next time */
1444 break;
1445
1446 case 'S': /* sender */
1447 setsender(newstr(&bp[1]), e, NULL, TRUE);
1448 break;
1449
1450 case 'B': /* body type */
1451 e->e_bodytype = newstr(&bp[1]);
1452 break;
1453
1454 case 'D': /* data file name */
1455 /* obsolete -- ignore */
1456 break;
1457
1458 case 'T': /* init time */
1459 e->e_ctime = atol(&bp[1]);
1460 break;
1461
1462 case 'I': /* data file's inode number */
1463 if (e->e_dfino == -1)
1464 e->e_dfino = atol(&buf[1]);
1465 break;
1466
1467 case 'K': /* time of last deliver attempt */
1468 e->e_dtime = atol(&buf[1]);
1469 break;
1470
1471 case 'N': /* number of delivery attempts */
1472 e->e_ntries = atoi(&buf[1]);
1473 break;
1474
1475 case 'P': /* message priority */
1476 e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
1477 break;
1478
1479 case 'F': /* flag bits */
1480 if (strncmp(bp, "From ", 5) == 0)
1481 {
1482 /* we are being spoofed! */
1483 syserr("SECURITY ALERT: bogus qf line %s", bp);
1484 fclose(qfp);
1485 loseqfile(e, "bogus queue line");
1486 return FALSE;
1487 }
1488 for (p = &bp[1]; *p != '\0'; p++)
1489 {
1490 switch (*p)
1491 {
1492 case 'w': /* warning sent */
1493 e->e_flags |= EF_WARNING;
1494 break;
1495
1496 case 'r': /* response */
1497 e->e_flags |= EF_RESPONSE;
1498 break;
1499
1500 case '8': /* has 8 bit data */
1501 e->e_flags |= EF_HAS8BIT;
1502 break;
1503 }
1504 }
1505 break;
1506
1507 case 'Z': /* original envelope id from ESMTP */
1508 e->e_envid = newstr(&bp[1]);
1509 break;
1510
1511 case '$': /* define macro */
1512 define(bp[1], newstr(&bp[2]), e);
1513 break;
1514
1515 case '.': /* terminate file */
1516 nomore = TRUE;
1517 break;
1518
1519 default:
1520 syserr("readqf: %s: line %d: bad line \"%s\"",
1521 qf, LineNumber, bp);
1522 fclose(qfp);
1523 loseqfile(e, "unrecognized line");
1524 return FALSE;
1525 }
1526
1527 if (bp != buf)
1528 free(bp);
1529 }
1530
1531 /*
1532 ** If we haven't read any lines, this queue file is empty.
1533 ** Arrange to remove it without referencing any null pointers.
1534 */
1535
1536 if (LineNumber == 0)
1537 {
1538 errno = 0;
1539 e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
1540 }
1541 else
1542 {
1543 /*
1544 ** Arrange to read the data file.
1545 */
1546
1547 p = queuename(e, 'd');
1548 e->e_dfp = fopen(p, "r");
1549 if (e->e_dfp == NULL)
1550 {
1551 syserr("readqf: cannot open %s", p);
1552 }
1553 else
1554 {
1555 e->e_flags |= EF_HAS_DF;
1556 if (fstat(fileno(e->e_dfp), &st) >= 0)
1557 {
1558 e->e_msgsize = st.st_size;
1559 e->e_dfdev = st.st_dev;
1560 e->e_dfino = st.st_ino;
1561 }
1562 }
1563 }
1564
1565 return TRUE;
1566 }
1567 /*
1568 ** PRINTQUEUE -- print out a representation of the mail queue
1569 **
1570 ** Parameters:
1571 ** none.
1572 **
1573 ** Returns:
1574 ** none.
1575 **
1576 ** Side Effects:
1577 ** Prints a listing of the mail queue on the standard output.
1578 */
1579
1580 void
printqueue()1581 printqueue()
1582 {
1583 register WORK *w;
1584 FILE *f;
1585 int nrequests;
1586 char buf[MAXLINE];
1587
1588 /*
1589 ** Check for permission to print the queue
1590 */
1591
1592 if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
1593 {
1594 struct stat st;
1595 # ifdef NGROUPS
1596 int n;
1597 GIDSET_T gidset[NGROUPS];
1598 # endif
1599
1600 if (stat(QueueDir, &st) < 0)
1601 {
1602 syserr("Cannot stat %s", QueueDir);
1603 return;
1604 }
1605 # ifdef NGROUPS
1606 n = getgroups(NGROUPS, gidset);
1607 while (--n >= 0)
1608 {
1609 if (gidset[n] == st.st_gid)
1610 break;
1611 }
1612 if (n < 0 && RealGid != st.st_gid)
1613 # else
1614 if (RealGid != st.st_gid)
1615 # endif
1616 {
1617 usrerr("510 You are not permitted to see the queue");
1618 setstat(EX_NOPERM);
1619 return;
1620 }
1621 }
1622
1623 /*
1624 ** Read and order the queue.
1625 */
1626
1627 nrequests = orderq(TRUE);
1628
1629 /*
1630 ** Print the work list that we have read.
1631 */
1632
1633 /* first see if there is anything */
1634 if (nrequests <= 0)
1635 {
1636 printf("Mail queue is empty\n");
1637 return;
1638 }
1639
1640 CurrentLA = getla(); /* get load average */
1641
1642 printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
1643 if (nrequests > WorkListSize)
1644 printf(", only %d printed", WorkListSize);
1645 if (Verbose)
1646 printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
1647 else
1648 printf(")\n--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
1649 for (w = WorkQ; w != NULL; w = w->w_next)
1650 {
1651 struct stat st;
1652 auto time_t submittime = 0;
1653 long dfsize;
1654 int flags = 0;
1655 int qfver;
1656 char statmsg[MAXLINE];
1657 char bodytype[MAXNAME + 1];
1658
1659 printf("%8s", w->w_name + 2);
1660 f = fopen(w->w_name, "r");
1661 if (f == NULL)
1662 {
1663 printf(" (job completed)\n");
1664 errno = 0;
1665 continue;
1666 }
1667 w->w_name[0] = 'd';
1668 if (stat(w->w_name, &st) >= 0)
1669 dfsize = st.st_size;
1670 else
1671 dfsize = -1;
1672 if (w->w_lock)
1673 printf("*");
1674 else if (shouldqueue(w->w_pri, w->w_ctime))
1675 printf("X");
1676 else
1677 printf(" ");
1678 errno = 0;
1679
1680 statmsg[0] = bodytype[0] = '\0';
1681 qfver = 0;
1682 while (fgets(buf, sizeof buf, f) != NULL)
1683 {
1684 register int i;
1685 register char *p;
1686
1687 fixcrlf(buf, TRUE);
1688 switch (buf[0])
1689 {
1690 case 'V': /* queue file version */
1691 qfver = atoi(&buf[1]);
1692 break;
1693
1694 case 'M': /* error message */
1695 if ((i = strlen(&buf[1])) >= sizeof statmsg)
1696 i = sizeof statmsg - 1;
1697 bcopy(&buf[1], statmsg, i);
1698 statmsg[i] = '\0';
1699 break;
1700
1701 case 'B': /* body type */
1702 if ((i = strlen(&buf[1])) >= sizeof bodytype)
1703 i = sizeof bodytype - 1;
1704 bcopy(&buf[1], bodytype, i);
1705 bodytype[i] = '\0';
1706 break;
1707
1708 case 'S': /* sender name */
1709 if (Verbose)
1710 printf("%8ld %10ld%c%.12s %.38s",
1711 dfsize,
1712 w->w_pri,
1713 bitset(EF_WARNING, flags) ? '+' : ' ',
1714 ctime(&submittime) + 4,
1715 &buf[1]);
1716 else
1717 printf("%8ld %.16s %.45s", dfsize,
1718 ctime(&submittime), &buf[1]);
1719 if (statmsg[0] != '\0' || bodytype[0] != '\0')
1720 {
1721 printf("\n %10.10s", bodytype);
1722 if (statmsg[0] != '\0')
1723 printf(" (%.60s)", statmsg);
1724 }
1725 break;
1726
1727 case 'C': /* controlling user */
1728 if (Verbose)
1729 printf("\n\t\t\t\t (---%.34s---)",
1730 &buf[1]);
1731 break;
1732
1733 case 'R': /* recipient name */
1734 p = &buf[1];
1735 if (qfver >= 1)
1736 {
1737 p = strchr(p, ':');
1738 if (p == NULL)
1739 break;
1740 p++;
1741 }
1742 if (Verbose)
1743 printf("\n\t\t\t\t\t %.38s", p);
1744 else
1745 printf("\n\t\t\t\t %.45s", p);
1746 break;
1747
1748 case 'T': /* creation time */
1749 submittime = atol(&buf[1]);
1750 break;
1751
1752 case 'F': /* flag bits */
1753 for (p = &buf[1]; *p != '\0'; p++)
1754 {
1755 switch (*p)
1756 {
1757 case 'w':
1758 flags |= EF_WARNING;
1759 break;
1760 }
1761 }
1762 }
1763 }
1764 if (submittime == (time_t) 0)
1765 printf(" (no control file)");
1766 printf("\n");
1767 (void) fclose(f);
1768 }
1769 }
1770
1771 # endif /* QUEUE */
1772 /*
1773 ** QUEUENAME -- build a file name in the queue directory for this envelope.
1774 **
1775 ** Assigns an id code if one does not already exist.
1776 ** This code is very careful to avoid trashing existing files
1777 ** under any circumstances.
1778 **
1779 ** Parameters:
1780 ** e -- envelope to build it in/from.
1781 ** type -- the file type, used as the first character
1782 ** of the file name.
1783 **
1784 ** Returns:
1785 ** a pointer to the new file name (in a static buffer).
1786 **
1787 ** Side Effects:
1788 ** If no id code is already assigned, queuename will
1789 ** assign an id code, create a qf file, and leave a
1790 ** locked, open-for-write file pointer in the envelope.
1791 */
1792
1793 char *
queuename(e,type)1794 queuename(e, type)
1795 register ENVELOPE *e;
1796 int type;
1797 {
1798 static int pid = -1;
1799 static char c0;
1800 static char c1;
1801 static char c2;
1802 time_t now;
1803 struct tm *tm;
1804 static char buf[MAXNAME + 1];
1805
1806 if (e->e_id == NULL)
1807 {
1808 char qf[20];
1809
1810 /* find a unique id */
1811 if (pid != getpid())
1812 {
1813 /* new process -- start back at "AA" */
1814 pid = getpid();
1815 now = curtime();
1816 tm = localtime(&now);
1817 c0 = 'A' + tm->tm_hour;
1818 c1 = 'A';
1819 c2 = 'A' - 1;
1820 }
1821 (void) sprintf(qf, "qf%cAA%05d", c0, pid);
1822
1823 while (c1 < '~' || c2 < 'Z')
1824 {
1825 int i;
1826
1827 if (c2 >= 'Z')
1828 {
1829 c1++;
1830 c2 = 'A' - 1;
1831 }
1832 qf[3] = c1;
1833 qf[4] = ++c2;
1834 if (tTd(7, 20))
1835 printf("queuename: trying \"%s\"\n", qf);
1836
1837 i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode);
1838 if (i < 0)
1839 {
1840 if (errno == EEXIST)
1841 continue;
1842 syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
1843 qf, QueueDir, geteuid());
1844 exit(EX_UNAVAILABLE);
1845 }
1846 if (lockfile(i, qf, NULL, LOCK_EX|LOCK_NB))
1847 {
1848 e->e_lockfp = fdopen(i, "w");
1849 break;
1850 }
1851
1852 /* a reader got the file; abandon it and try again */
1853 (void) close(i);
1854 }
1855 if (c1 >= '~' && c2 >= 'Z')
1856 {
1857 syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
1858 qf, QueueDir, geteuid());
1859 exit(EX_OSERR);
1860 }
1861 e->e_id = newstr(&qf[2]);
1862 define('i', e->e_id, e);
1863 if (tTd(7, 1))
1864 printf("queuename: assigned id %s, env=%x\n", e->e_id, e);
1865 if (tTd(7, 9))
1866 {
1867 printf(" lockfd=");
1868 dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
1869 }
1870 # ifdef LOG
1871 if (LogLevel > 93)
1872 syslog(LOG_DEBUG, "%s: assigned id", e->e_id);
1873 # endif /* LOG */
1874 }
1875
1876 if (type == '\0')
1877 return (NULL);
1878 (void) sprintf(buf, "%cf%s", type, e->e_id);
1879 if (tTd(7, 2))
1880 printf("queuename: %s\n", buf);
1881 return (buf);
1882 }
1883 /*
1884 ** UNLOCKQUEUE -- unlock the queue entry for a specified envelope
1885 **
1886 ** Parameters:
1887 ** e -- the envelope to unlock.
1888 **
1889 ** Returns:
1890 ** none
1891 **
1892 ** Side Effects:
1893 ** unlocks the queue for `e'.
1894 */
1895
1896 void
unlockqueue(e)1897 unlockqueue(e)
1898 ENVELOPE *e;
1899 {
1900 if (tTd(51, 4))
1901 printf("unlockqueue(%s)\n", e->e_id);
1902
1903 /* if there is a lock file in the envelope, close it */
1904 if (e->e_lockfp != NULL)
1905 xfclose(e->e_lockfp, "unlockqueue", e->e_id);
1906 e->e_lockfp = NULL;
1907
1908 /* don't create a queue id if we don't already have one */
1909 if (e->e_id == NULL)
1910 return;
1911
1912 /* remove the transcript */
1913 # ifdef LOG
1914 if (LogLevel > 87)
1915 syslog(LOG_DEBUG, "%s: unlock", e->e_id);
1916 # endif /* LOG */
1917 if (!tTd(51, 104))
1918 xunlink(queuename(e, 'x'));
1919
1920 }
1921 /*
1922 ** SETCTLUSER -- create a controlling address
1923 **
1924 ** Create a fake "address" given only a local login name; this is
1925 ** used as a "controlling user" for future recipient addresses.
1926 **
1927 ** Parameters:
1928 ** user -- the user name of the controlling user.
1929 **
1930 ** Returns:
1931 ** An address descriptor for the controlling user.
1932 **
1933 ** Side Effects:
1934 ** none.
1935 */
1936
1937 ADDRESS *
setctluser(user)1938 setctluser(user)
1939 char *user;
1940 {
1941 register ADDRESS *a;
1942 struct passwd *pw;
1943 char *p;
1944
1945 /*
1946 ** See if this clears our concept of controlling user.
1947 */
1948
1949 if (user == NULL || *user == '\0')
1950 return NULL;
1951
1952 /*
1953 ** Set up addr fields for controlling user.
1954 */
1955
1956 a = (ADDRESS *) xalloc(sizeof *a);
1957 bzero((char *) a, sizeof *a);
1958
1959 p = strchr(user, ':');
1960 if (p != NULL)
1961 *p++ = '\0';
1962 if (*user != '\0' && (pw = sm_getpwnam(user)) != NULL)
1963 {
1964 if (strcmp(pw->pw_dir, "/") == 0)
1965 a->q_home = "";
1966 else
1967 a->q_home = newstr(pw->pw_dir);
1968 a->q_uid = pw->pw_uid;
1969 a->q_gid = pw->pw_gid;
1970 a->q_flags |= QGOODUID;
1971 }
1972
1973 if (*user != '\0')
1974 a->q_user = newstr(user);
1975 else if (p != NULL)
1976 a->q_user = newstr(p);
1977 else
1978 a->q_user = newstr(DefUser);
1979
1980 a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */
1981 a->q_mailer = LocalMailer;
1982 if (p == NULL)
1983 a->q_paddr = a->q_user;
1984 else
1985 a->q_paddr = newstr(p);
1986 return a;
1987 }
1988 /*
1989 ** LOSEQFILE -- save the qf as Qf and try to let someone know
1990 **
1991 ** Parameters:
1992 ** e -- the envelope (e->e_id will be used).
1993 ** why -- reported to whomever can hear.
1994 **
1995 ** Returns:
1996 ** none.
1997 */
1998
1999 void
loseqfile(e,why)2000 loseqfile(e, why)
2001 register ENVELOPE *e;
2002 char *why;
2003 {
2004 char *p;
2005 char buf[40];
2006
2007 if (e == NULL || e->e_id == NULL)
2008 return;
2009 if (strlen(e->e_id) > sizeof buf - 4)
2010 return;
2011 strcpy(buf, queuename(e, 'q'));
2012 p = queuename(e, 'Q');
2013 if (rename(buf, p) < 0)
2014 syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid());
2015 #ifdef LOG
2016 else if (LogLevel > 0)
2017 syslog(LOG_ALERT, "Losing %s: %s", buf, why);
2018 #endif
2019 }
2020