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