more cleanup for DSN drafts
[unix-history] / usr / src / usr.sbin / sendmail / src / queue.c
CommitLineData
b2a81223 1/*
dc45ba8c 2 * Copyright (c) 1983 Eric P. Allman
eb0bafab
KB
3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
bee79b64 5 *
417f7a11 6 * %sccs.include.redist.c%
bee79b64 7 */
b2a81223 8
81b7d258 9# include "sendmail.h"
bee79b64
KB
10
11#ifndef lint
12#ifdef QUEUE
66d16835 13static char sccsid[] = "@(#)queue.c 8.74 (Berkeley) %G% (with queueing)";
bee79b64 14#else
66d16835 15static char sccsid[] = "@(#)queue.c 8.74 (Berkeley) %G% (without queueing)";
bee79b64
KB
16#endif
17#endif /* not lint */
18
81b7d258 19# include <errno.h>
3fbc69d6 20# include <pwd.h>
6feb509e 21# include <dirent.h>
4287d84d 22
76b607b2
EA
23# ifdef QUEUE
24
81b7d258 25/*
7338e3d4
EA
26** Work queue.
27*/
28
29struct work
30{
31 char *w_name; /* name of control file */
a9ca3259
EA
32 char *w_host; /* name of recipient host */
33 bool w_lock; /* is message locked? */
7338e3d4 34 long w_pri; /* priority of message, see below */
f746582a 35 time_t w_ctime; /* creation time of message */
7338e3d4
EA
36 struct work *w_next; /* next in queue */
37};
38
39typedef struct work WORK;
40
41WORK *WorkQ; /* queue of things to be done */
68d9129a
EA
42
43#define QF_VERSION 1 /* version number of this queue format */
7338e3d4 44\f/*
81b7d258
EA
45** QUEUEUP -- queue a message up for future transmission.
46**
81b7d258 47** Parameters:
dd1fe05b 48** e -- the envelope to queue up.
d0bd03ce
EA
49** queueall -- if TRUE, queue all addresses, rather than
50** just those with the QQUEUEUP flag set.
7338e3d4 51** announce -- if TRUE, tell when you are queueing up.
81b7d258
EA
52**
53** Returns:
3620ad97 54** none.
81b7d258
EA
55**
56** Side Effects:
7338e3d4 57** The current request are saved in a control file.
3620ad97 58** The queue file is left locked.
81b7d258
EA
59*/
60
7338e3d4 61queueup(e, queueall, announce)
dd1fe05b 62 register ENVELOPE *e;
d0bd03ce 63 bool queueall;
7338e3d4 64 bool announce;
81b7d258 65{
2cce0c26 66 char *qf;
2cce0c26 67 register FILE *tfp;
81b7d258 68 register HDR *h;
d4f42161 69 register ADDRESS *q;
3620ad97
EA
70 int fd;
71 int i;
72 bool newid;
22293c34 73 register char *p;
4db45bf1 74 MAILER nullmailer;
23fafb99 75 MCI mcibuf;
3620ad97 76 char buf[MAXLINE], tf[MAXLINE];
81b7d258 77
9ccf54c4 78 /*
11e3f8b5 79 ** Create control file.
9ccf54c4 80 */
81b7d258 81
eead656c 82 newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags);
e3778690
EA
83
84 /* if newid, queuename will create a locked qf file in e->lockfp */
3620ad97
EA
85 strcpy(tf, queuename(e, 't'));
86 tfp = e->e_lockfp;
87 if (tfp == NULL)
88 newid = FALSE;
e3778690
EA
89
90 /* if newid, just write the qf file directly (instead of tf file) */
eead656c 91 if (!newid)
3620ad97
EA
92 {
93 /* get a locked tf file */
b1c8be09 94 for (i = 0; i < 128; i++)
4287d84d 95 {
3620ad97
EA
96 fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode);
97 if (fd < 0)
4287d84d 98 {
b1c8be09
EA
99 if (errno != EEXIST)
100 break;
101#ifdef LOG
102 if (LogLevel > 0 && (i % 32) == 0)
e8f51a65
EA
103 syslog(LOG_ALERT, "queueup: cannot create %s, uid=%d: %s",
104 tf, geteuid(), errstring(errno));
b1c8be09 105#endif
6680179d 106 }
e8f51a65
EA
107 else
108 {
109 if (lockfile(fd, tf, NULL, LOCK_EX|LOCK_NB))
110 break;
b1c8be09 111#ifdef LOG
e8f51a65
EA
112 else if (LogLevel > 0 && (i % 32) == 0)
113 syslog(LOG_ALERT, "queueup: cannot lock %s: %s",
114 tf, errstring(errno));
b1c8be09 115#endif
e8f51a65
EA
116 close(fd);
117 }
b1c8be09
EA
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);
6680179d 126 }
e9d81da2 127 if (fd < 0 || (tfp = fdopen(fd, "w")) == NULL)
cea561e2
EA
128 {
129 printopenfds(TRUE);
e8f51a65
EA
130 syserr("!queueup: cannot create queue temp file %s, uid=%d",
131 tf, geteuid());
cea561e2 132 }
3620ad97 133 }
81b7d258 134
9678c96d 135 if (tTd(40, 1))
68d9129a
EA
136 printf("\n>>>>> queueing %s%s queueall=%d >>>>>\n", e->e_id,
137 newid ? " (new id)" : "", queueall);
66d16835
EA
138 if (tTd(40, 3))
139 {
140 extern void printenvflags();
141
142 printf(" e_flags=");
143 printenvflags(e);
144 }
68d9129a
EA
145 if (tTd(40, 32))
146 {
147 printf(" sendq=");
148 printaddr(e->e_sendqueue, TRUE);
149 }
eead656c
EA
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 }
81b7d258 160
dd1fe05b
EA
161 /*
162 ** If there is no data file yet, create one.
163 */
164
18a81ac0 165 if (!bitset(EF_HAS_DF, e->e_flags))
dd1fe05b
EA
166 {
167 register FILE *dfp;
18a81ac0 168 char dfname[20];
f009d24b 169 struct stat stbuf;
80482eb5 170 extern putbody();
dd1fe05b 171
18a81ac0
EA
172 strcpy(dfname, queuename(e, 'd'));
173 fd = open(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode);
e9d81da2 174 if (fd < 0 || (dfp = fdopen(fd, "w")) == NULL)
e8f51a65 175 syserr("!queueup: cannot create data temp file %s, uid=%d",
18a81ac0 176 dfname, geteuid());
f009d24b
EA
177 if (fstat(fd, &stbuf) < 0)
178 e->e_dfino = -1;
179 else
bb4fde22
EA
180 {
181 e->e_dfdev = stbuf.st_dev;
f009d24b 182 e->e_dfino = stbuf.st_ino;
bb4fde22 183 }
18a81ac0 184 e->e_flags |= EF_HAS_DF;
23fafb99
EA
185 bzero(&mcibuf, sizeof mcibuf);
186 mcibuf.mci_out = dfp;
187 mcibuf.mci_mailer = FileMailer;
51d448e5 188 (*e->e_putbody)(&mcibuf, e, NULL);
bc854e30 189 (void) xfclose(dfp, "queueup dfp", e->e_id);
80482eb5 190 e->e_putbody = putbody;
dd1fe05b
EA
191 }
192
81b7d258
EA
193 /*
194 ** Output future work requests.
4e969be0
EA
195 ** Priority and creation time should be first, since
196 ** they are required by orderq.
81b7d258
EA
197 */
198
68d9129a
EA
199 /* output queue version number (must be first!) */
200 fprintf(tfp, "V%d\n", QF_VERSION);
201
7338e3d4
EA
202 /* output message priority */
203 fprintf(tfp, "P%ld\n", e->e_msgpriority);
204
64912e7e
EA
205 /* output creation time */
206 fprintf(tfp, "T%ld\n", e->e_ctime);
207
f009d24b
EA
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
bb4fde22
EA
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
18a81ac0 220 /* output body type */
96bfbc2c
EA
221 if (e->e_bodytype != NULL)
222 fprintf(tfp, "B%s\n", e->e_bodytype);
81b7d258 223
baa0c390
EA
224 /* message from envelope, if it exists */
225 if (e->e_message != NULL)
dcf45886 226 fprintf(tfp, "M%s\n", denlstring(e->e_message, TRUE, FALSE));
baa0c390 227
c2bdb1dd
EA
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';
e3c84ea8
EA
234 if (bitset(EF_HAS8BIT, e->e_flags))
235 *p++ = '8';
c2bdb1dd
EA
236 *p++ = '\0';
237 if (buf[0] != '\0')
238 fprintf(tfp, "F%s\n", buf);
239
a9bac7a9 240 /* $r and $s and $_ macro values */
22293c34 241 if ((p = macvalue('r', e)) != NULL)
dcf45886 242 fprintf(tfp, "$r%s\n", denlstring(p, TRUE, FALSE));
22293c34 243 if ((p = macvalue('s', e)) != NULL)
dcf45886 244 fprintf(tfp, "$s%s\n", denlstring(p, TRUE, FALSE));
a9bac7a9 245 if ((p = macvalue('_', e)) != NULL)
dcf45886 246 fprintf(tfp, "$_%s\n", denlstring(p, TRUE, FALSE));
22293c34 247
81b7d258 248 /* output name of sender */
b2af5ecf 249 fprintf(tfp, "S%s\n", denlstring(p, TRUE, FALSE));
81b7d258 250
6da3ba01
EA
251 /* output ESMTP-supplied "original" information */
252 if (e->e_envid != NULL)
6da3ba01 253
ca4d0c0b 254 /* output list of recipient addresses */
b7b719e4 255 printctladdr(NULL, NULL);
dd1fe05b 256 for (q = e->e_sendqueue; q != NULL; q = q->q_next)
81b7d258 257 {
374579b6 258 if (bitset(QQUEUEUP, q->q_flags) ||
bc854e30 259 (queueall && !bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags)))
4d237f16 260 {
9cdb0b30 261 printctladdr(q, tfp);
3b6c2253 262 if (q->q_orcpt != NULL)
b2af5ecf 263 fprintf(tfp, "%s\n", denlstring(q->q_paddr, TRUE, FALSE));
7338e3d4
EA
264 if (announce)
265 {
266 e->e_to = q->q_paddr;
b6edea3d 267 message("queued");
68f7099c 268 if (LogLevel > 8)
3500a891
EA
269 logdelivery(NULL, NULL, "queued",
270 NULL, (time_t) 0, e);
7338e3d4
EA
271 e->e_to = NULL;
272 }
b9accadd
EA
273 if (tTd(40, 1))
274 {
275 printf("queueing ");
276 printaddr(q, FALSE);
277 }
4d237f16 278 }
81b7d258
EA
279 }
280
7338e3d4
EA
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.
4db45bf1
EA
287 ** We set up a "null mailer" -- i.e., a mailer that will have
288 ** no effect on the addresses as they are output.
7338e3d4
EA
289 */
290
1dbda134 291 bzero((char *) &nullmailer, sizeof nullmailer);
68f7099c 292 nullmailer.m_re_rwset = nullmailer.m_rh_rwset =
21efe526 293 nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1;
281ef7f0 294 nullmailer.m_eol = "\n";
23fafb99
EA
295 bzero(&mcibuf, sizeof mcibuf);
296 mcibuf.mci_mailer = &nullmailer;
297 mcibuf.mci_out = tfp;
4db45bf1 298
2bee003d 299 define('g', "\201f", e);
dd1fe05b 300 for (h = e->e_header; h != NULL; h = h->h_link)
81b7d258 301 {
1dbda134
EA
302 extern bool bitzerop();
303
83e9910e 304 /* don't output null headers */
81b7d258
EA
305 if (h->h_value == NULL || h->h_value[0] == '\0')
306 continue;
83e9910e
EA
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
d27723b2
EA
312 /* expand macros; if null, don't output header at all */
313 if (bitset(H_DEFAULT, h->h_flags))
314 {
832e8a27 315 (void) expand(h->h_value, buf, sizeof buf, e);
d27723b2
EA
316 if (buf[0] == '\0')
317 continue;
318 }
319
83e9910e 320 /* output this header */
2cce0c26 321 fprintf(tfp, "H");
83e9910e
EA
322
323 /* if conditional, output the set of conditions */
1dbda134
EA
324 if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))
325 {
326 int j;
327
0e306e7f 328 (void) putc('?', tfp);
1dbda134
EA
329 for (j = '\0'; j <= '\177'; j++)
330 if (bitnset(j, h->h_mflags))
0e306e7f
EA
331 (void) putc(j, tfp);
332 (void) putc('?', tfp);
1dbda134 333 }
83e9910e
EA
334
335 /* output the header: expand macros, convert addresses */
9416f3a0
EA
336 if (bitset(H_DEFAULT, h->h_flags))
337 {
d27723b2 338 fprintf(tfp, "%s: %s\n", h->h_field, buf);
9416f3a0 339 }
4d237f16 340 else if (bitset(H_FROM|H_RCPT, h->h_flags))
611b763d 341 {
c2bdb1dd 342 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
8e5c6745
EA
343 FILE *savetrace = TrafficLogFile;
344
345 TrafficLogFile = NULL;
c2bdb1dd
EA
346
347 if (bitset(H_FROM, h->h_flags))
348 oldstyle = FALSE;
349
23fafb99 350 commaize(h, h->h_value, oldstyle, &mcibuf, e);
8e5c6745
EA
351
352 TrafficLogFile = savetrace;
611b763d 353 }
4d237f16
EA
354 else
355 fprintf(tfp, "%s: %s\n", h->h_field, h->h_value);
81b7d258
EA
356 }
357
358 /*
359 ** Clean up.
360 */
361
eb1ada3c 362 if (fflush(tfp) < 0 || fsync(fileno(tfp)) < 0 || ferror(tfp))
e6d43796
EA
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
3620ad97
EA
370 if (!newid)
371 {
e3778690 372 /* rename (locked) tf to be (locked) qf */
3620ad97
EA
373 qf = queuename(e, 'q');
374 if (rename(tf, qf) < 0)
18a81ac0
EA
375 syserr("cannot rename(%s, %s), uid=%d",
376 tf, qf, geteuid());
e3778690
EA
377
378 /* close and unlock old (locked) qf */
3620ad97 379 if (e->e_lockfp != NULL)
bc854e30 380 (void) xfclose(e->e_lockfp, "queueup lockfp", e->e_id);
3620ad97
EA
381 e->e_lockfp = tfp;
382 }
383 else
384 qf = tf;
6680179d 385 errno = 0;
eead656c 386 e->e_flags |= EF_INQUEUE;
1a13ccd8 387
9678c96d
EA
388# ifdef LOG
389 /* save log info */
68f7099c 390 if (LogLevel > 79)
18a81ac0 391 syslog(LOG_DEBUG, "%s: queueup, qf=%s", e->e_id, qf);
f3d8f6d6 392# endif /* LOG */
51458e80
EA
393
394 if (tTd(40, 1))
395 printf("<<<<< done queueing %s <<<<<\n\n", e->e_id);
3620ad97 396 return;
81b7d258 397}
d2213d6c
EA
398
399printctladdr(a, tfp)
9cdb0b30 400 register ADDRESS *a;
d2213d6c
EA
401 FILE *tfp;
402{
9cdb0b30
EA
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;
d2213d6c 409
9cdb0b30 410 /* initialization */
c6c403f7 411 if (a == NULL || a->q_alias == NULL || tfp == NULL)
d2213d6c 412 {
31739b4e 413 if (lastctladdr != NULL && tfp != NULL)
9cdb0b30
EA
414 fprintf(tfp, "C\n");
415 lastctladdr = NULL;
416 lastuid = 0;
d2213d6c
EA
417 return;
418 }
9cdb0b30
EA
419
420 /* find the active uid */
421 q = getctladdr(a);
422 if (q == NULL)
423 uid = 0;
424 else
425 uid = q->q_uid;
c6c403f7 426 a = a->q_alias;
9cdb0b30
EA
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)
f7894324 436 uname = "";
d2213d6c 437 else
9cdb0b30
EA
438 uname = pw->pw_name;
439
dcf45886 440 fprintf(tfp, "C%s:%s\n", uname, denlstring(a->q_paddr, TRUE, FALSE));
d2213d6c 441}
81b7d258
EA
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:
2e3062fe
EA
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.
81b7d258
EA
452**
453** Returns:
454** none.
455**
456** Side Effects:
457** runs things in the mail queue.
458*/
459
ca4d0c0b
EA
460ENVELOPE QueueEnvelope; /* the queue run envelope */
461
ea07b2d2 462void
ca4d0c0b 463runqueue(forkflag)
2cf55cb7 464 bool forkflag;
81b7d258 465{
ca4d0c0b 466 register ENVELOPE *e;
d3a63a56
EA
467 int njobs;
468 int sequenceno = 0;
ca4d0c0b 469 extern ENVELOPE BlankEnvelope;
4bc44f60
EA
470
471 /*
472 ** If no work will ever be selected, don't even bother reading
473 ** the queue.
474 */
475
3620ad97 476 CurrentLA = getla(); /* get load average */
3f9ac8ea 477
986065ef 478 if (shouldqueue(0L, curtime()))
4bc44f60
EA
479 {
480 if (Verbose)
481 printf("Skipping queue run -- load average too high\n");
fe80f8e1
EA
482 if (forkflag && QueueIntvl != 0)
483 (void) setevent(QueueIntvl, runqueue, TRUE);
ca4d0c0b 484 return;
4bc44f60
EA
485 }
486
b6dffdf5
EA
487 /*
488 ** See if we want to go off and do other useful work.
489 */
2cf55cb7
EA
490
491 if (forkflag)
492 {
6d06102a 493 int pid;
a72af781
EA
494#ifdef SIGCHLD
495 extern void reapchild();
496
497 (void) setsignal(SIGCHLD, reapchild);
498#endif
6d06102a
EA
499
500 pid = dofork();
501 if (pid != 0)
2cf55cb7 502 {
6d06102a 503 /* parent -- pick up intermediate zombie */
c8ad461a 504#ifndef SIGCHLD
7338e3d4 505 (void) waitfor(pid);
f3d8f6d6 506#endif /* SIGCHLD */
c4442979 507 if (QueueIntvl != 0)
611b763d 508 (void) setevent(QueueIntvl, runqueue, TRUE);
2cf55cb7
EA
509 return;
510 }
6d06102a 511 /* child -- double fork */
c8ad461a 512#ifndef SIGCHLD
6d06102a
EA
513 if (fork() != 0)
514 exit(EX_OK);
f3d8f6d6 515#else /* SIGCHLD */
39270cfd 516 (void) setsignal(SIGCHLD, SIG_DFL);
f3d8f6d6 517#endif /* SIGCHLD */
b6dffdf5 518 }
2e3062fe 519
3f9ac8ea 520 setproctitle("running queue: %s", QueueDir);
2e3062fe 521
36a4e219 522# ifdef LOG
68f7099c 523 if (LogLevel > 69)
ca4d0c0b
EA
524 syslog(LOG_DEBUG, "runqueue %s, pid=%d, forkflag=%d",
525 QueueDir, getpid(), forkflag);
f3d8f6d6 526# endif /* LOG */
81b7d258 527
eb8af3ce
EA
528 /*
529 ** Release any resources used by the daemon code.
530 */
531
532# ifdef DAEMON
533 clrdaemon();
f3d8f6d6 534# endif /* DAEMON */
eb8af3ce 535
6b951123
EA
536 /* force it to run expensive jobs */
537 NoConnect = FALSE;
538
ca4d0c0b
EA
539 /*
540 ** Create ourselves an envelope
541 */
542
543 CurEnv = &QueueEnvelope;
fda58daa 544 e = newenvelope(&QueueEnvelope, CurEnv);
ca4d0c0b
EA
545 e->e_flags = BlankEnvelope.e_flags;
546
a78155b0
EA
547 /*
548 ** Make sure the alias database is open.
549 */
550
36b09297 551 initmaps(FALSE, e);
a78155b0 552
b6dffdf5
EA
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.
b6dffdf5 558 */
81b7d258 559
6d06102a 560 /* order the existing work requests */
d3a63a56 561 njobs = orderq(FALSE);
291fa573 562
6d06102a
EA
563 /* process them once at a time */
564 while (WorkQ != NULL)
2cf55cb7 565 {
6d06102a 566 WORK *w = WorkQ;
2cf55cb7 567
6d06102a 568 WorkQ = WorkQ->w_next;
a7dc53bd
EA
569
570 /*
571 ** Ignore jobs that are too expensive for the moment.
572 */
573
d3a63a56 574 sequenceno++;
a7dc53bd
EA
575 if (shouldqueue(w->w_pri, w->w_ctime))
576 {
577 if (Verbose)
d3a63a56
EA
578 printf("\nSkipping %s (sequence %d of %d)\n",
579 w->w_name + 2, sequenceno, njobs);
a7dc53bd 580 }
1c791deb
EA
581 else
582 {
d0268270
EA
583 pid_t pid;
584 extern pid_t dowork();
585
d3a63a56
EA
586 if (Verbose)
587 printf("\nRunning %s (sequence %d of %d)\n",
588 w->w_name + 2, sequenceno, njobs);
d0268270
EA
589 pid = dowork(w->w_name + 2, ForkQueueRuns, FALSE, e);
590 errno = 0;
a9927082
EA
591 if (pid != 0)
592 (void) waitfor(pid);
1c791deb 593 }
6d06102a 594 free(w->w_name);
a9ca3259
EA
595 if (w->w_host)
596 free(w->w_host);
6d06102a 597 free((char *) w);
2cf55cb7 598 }
37ea3cbf
EA
599
600 /* exit without the usual cleanup */
4e20c4d2
EA
601 e->e_id = NULL;
602 finis();
aba51985
EA
603}
604\f/*
81b7d258
EA
605** ORDERQ -- order the work queue.
606**
607** Parameters:
2e3062fe
EA
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.
81b7d258
EA
612**
613** Returns:
e65b95c4
EA
614** The number of request in the queue (not necessarily
615** the number of requests in WorkQ however).
81b7d258
EA
616**
617** Side Effects:
618** Sets WorkQ to the queue of available work, in order.
619*/
620
4e969be0
EA
621# define NEED_P 001
622# define NEED_T 002
d6c28d1a
EA
623# define NEED_R 004
624# define NEED_S 010
81b7d258 625
38d3b461
EA
626# ifndef DIR
627# define DIR FILE
628# define direct dir
629# define opendir(d) fopen(d, "r")
07a8f29b 630# define readdir(f) ((fread(&dbuf, sizeof dbuf, 1, f) > 0) ? &dbuf : 0)
38d3b461
EA
631static struct dir dbuf;
632# define closedir(f) fclose(f)
633# endif DIR
634
2e3062fe
EA
635orderq(doall)
636 bool doall;
81b7d258 637{
9114f86c 638 register struct dirent *d;
81b7d258 639 register WORK *w;
ccd1d833 640 DIR *f;
81b7d258 641 register int i;
4e969be0 642 WORK wlist[QUEUESIZE+1];
0490b7d7 643 int wn = -1;
a9ca3259 644 int wc;
81b7d258 645
d6c28d1a
EA
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
81b7d258
EA
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);
a9ca3259
EA
664 if (w->w_host)
665 free(w->w_host);
81b7d258
EA
666 free((char *) w);
667 w = nw;
668 }
669
670 /* open the queue directory */
6bbaf971 671 f = opendir(".");
81b7d258
EA
672 if (f == NULL)
673 {
6bbaf971 674 syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
0490b7d7 675 return (0);
81b7d258
EA
676 }
677
678 /*
679 ** Read the work directory.
680 */
681
0490b7d7 682 while ((d = readdir(f)) != NULL)
81b7d258 683 {
81b7d258 684 FILE *cf;
bb530db4 685 register char *p;
8446c922 686 char lbuf[MAXNAME + 1];
d6c28d1a 687 extern bool strcontainedin();
81b7d258
EA
688
689 /* is this an interesting entry? */
07a8f29b
EA
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
2cce0c26 696 if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
81b7d258
EA
697 continue;
698
d6c28d1a
EA
699 if (QueueLimitId != NULL &&
700 !strcontainedin(QueueLimitId, d->d_name))
701 continue;
702
6502fd93 703#ifdef PICKY_QF_NAME_CHECK
45ce4b34
EA
704 /*
705 ** Check queue name for plausibility. This handles
706 ** both old and new type ids.
707 */
708
bb530db4
EA
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')
68f7099c
EA
719 {
720 if (Verbose)
721 printf("orderq: bogus qf name %s\n", d->d_name);
6502fd93
EA
722# ifdef LOG
723 if (LogLevel > 0)
724 syslog(LOG_ALERT, "orderq: bogus qf name %s",
68f7099c 725 d->d_name);
6502fd93 726# endif
8446c922
EA
727 if (strlen(d->d_name) > MAXNAME)
728 d->d_name[MAXNAME] = '\0';
68f7099c
EA
729 strcpy(lbuf, d->d_name);
730 lbuf[0] = 'Q';
731 (void) rename(d->d_name, lbuf);
732 continue;
733 }
6502fd93 734#endif
68f7099c 735
6502fd93 736 /* open control file (if not too many files) */
4e969be0 737 if (++wn >= QUEUESIZE)
0490b7d7 738 continue;
d6c28d1a 739
6bbaf971 740 cf = fopen(d->d_name, "r");
81b7d258
EA
741 if (cf == NULL)
742 {
91f69adf
EA
743 /* this may be some random person sending hir msgs */
744 /* syserr("orderq: cannot open %s", cbuf); */
bd0712bd
EA
745 if (tTd(41, 2))
746 printf("orderq: cannot open %s (%d)\n",
747 d->d_name, errno);
91f69adf 748 errno = 0;
bd0712bd 749 wn--;
81b7d258
EA
750 continue;
751 }
4e969be0
EA
752 w = &wlist[wn];
753 w->w_name = newstr(d->d_name);
a9ca3259
EA
754 w->w_host = NULL;
755 w->w_lock = !lockfile(fileno(cf), w->w_name, NULL, LOCK_SH|LOCK_NB);
81b7d258 756
4ff794a3 757 /* make sure jobs in creation don't clog queue */
4e969be0
EA
758 w->w_pri = 0x7fffffff;
759 w->w_ctime = 0;
4ff794a3 760
81b7d258 761 /* extract useful information */
4e969be0 762 i = NEED_P | NEED_T;
d6c28d1a
EA
763 if (QueueLimitSender != NULL)
764 i |= NEED_S;
92830179 765 if (QueueSortOrder == QS_BYHOST || QueueLimitRecipient != NULL)
d6c28d1a 766 i |= NEED_R;
4e969be0 767 while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
81b7d258 768 {
8ff78b51 769 extern long atol();
d6c28d1a 770 extern bool strcontainedin();
8ff78b51 771
2e3062fe 772 switch (lbuf[0])
81b7d258 773 {
2e3062fe 774 case 'P':
4e969be0
EA
775 w->w_pri = atol(&lbuf[1]);
776 i &= ~NEED_P;
2e3062fe 777 break;
f746582a
EA
778
779 case 'T':
4e969be0
EA
780 w->w_ctime = atol(&lbuf[1]);
781 i &= ~NEED_T;
f746582a 782 break;
d6c28d1a
EA
783
784 case 'R':
a9ca3259
EA
785 if (w->w_host == NULL &&
786 (p = strrchr(&lbuf[1], '@')) != NULL)
787 w->w_host = newstr(&p[1]);
788 if (QueueLimitRecipient == NULL ||
d6c28d1a
EA
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;
81b7d258
EA
798 }
799 }
81b7d258 800 (void) fclose(cf);
4bc44f60 801
d6c28d1a
EA
802 if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
803 bitset(NEED_R|NEED_S, i))
4bc44f60
EA
804 {
805 /* don't even bother sorting this job in */
a9ca3259
EA
806 free(w->w_name);
807 if (w->w_host)
808 free(w->w_host);
4bc44f60
EA
809 wn--;
810 }
81b7d258 811 }
ccd1d833 812 (void) closedir(f);
bd0712bd 813 wn++;
81b7d258 814
a9ca3259
EA
815 wc = min(wn, QUEUESIZE);
816
92830179 817 if (QueueSortOrder == QS_BYHOST)
a9ca3259
EA
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 }
92830179
EA
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 }
81b7d258
EA
874
875 /*
876 ** Convert the work list into canonical form.
7338e3d4 877 ** Should be turning it into a list of envelopes here perhaps.
81b7d258
EA
878 */
879
a0225d08 880 WorkQ = NULL;
a9ca3259 881 for (i = wc; --i >= 0; )
81b7d258
EA
882 {
883 w = (WORK *) xalloc(sizeof *w);
884 w->w_name = wlist[i].w_name;
a9ca3259
EA
885 w->w_host = wlist[i].w_host;
886 w->w_lock = wlist[i].w_lock;
81b7d258 887 w->w_pri = wlist[i].w_pri;
f746582a 888 w->w_ctime = wlist[i].w_ctime;
a0225d08
EA
889 w->w_next = WorkQ;
890 WorkQ = w;
81b7d258
EA
891 }
892
9678c96d 893 if (tTd(40, 1))
81b7d258
EA
894 {
895 for (w = WorkQ; w != NULL; w = w->w_next)
9ccf54c4 896 printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
81b7d258 897 }
0490b7d7 898
bd0712bd 899 return (wn);
81b7d258
EA
900}
901\f/*
a9ca3259 902** WORKCMPF0 -- simple priority-only compare function.
81b7d258
EA
903**
904** Parameters:
905** a -- the first argument.
906** b -- the second argument.
907**
908** Returns:
a0225d08
EA
909** -1 if a < b
910** 0 if a == b
911** +1 if a > b
81b7d258
EA
912**
913** Side Effects:
914** none.
915*/
916
a9ca3259 917workcmpf0(a, b)
9ccf54c4
EA
918 register WORK *a;
919 register WORK *b;
81b7d258 920{
abccefc9
EA
921 long pa = a->w_pri;
922 long pb = b->w_pri;
2e3062fe
EA
923
924 if (pa == pb)
a9ca3259 925 return 0;
2e3062fe 926 else if (pa > pb)
a9ca3259 927 return 1;
a0225d08 928 else
a9ca3259
EA
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;
81b7d258
EA
1010}
1011\f/*
1012** DOWORK -- do a work request.
1013**
1014** Parameters:
a7dc53bd
EA
1015** id -- the ID of the job to run.
1016** forkflag -- if set, run this in background.
f5303697
EA
1017** requeueflag -- if set, reinstantiate the queue quickly.
1018** This is used when expanding aliases in the queue.
8d00c219
EA
1019** If forkflag is also set, it doesn't wait for the
1020** child.
a7dc53bd 1021** e - the envelope in which to run it.
81b7d258
EA
1022**
1023** Returns:
d0268270 1024** process id of process that is running the queue job.
81b7d258
EA
1025**
1026** Side Effects:
1027** The work request is satisfied if possible.
1028*/
1029
d0268270 1030pid_t
f5303697 1031dowork(id, forkflag, requeueflag, e)
a7dc53bd
EA
1032 char *id;
1033 bool forkflag;
f5303697 1034 bool requeueflag;
a4076aed 1035 register ENVELOPE *e;
81b7d258 1036{
d0268270 1037 register pid_t pid;
3620ad97 1038 extern bool readqf();
81b7d258 1039
9678c96d 1040 if (tTd(40, 1))
a7dc53bd 1041 printf("dowork(%s)\n", id);
81b7d258 1042
2e3062fe
EA
1043 /*
1044 ** Fork for work.
1045 */
1046
a7dc53bd 1047 if (forkflag)
2e3062fe 1048 {
d0268270
EA
1049 pid = fork();
1050 if (pid < 0)
2e3062fe
EA
1051 {
1052 syserr("dowork: cannot fork");
d0268270 1053 return 0;
2e3062fe 1054 }
5cf47fbf
EA
1055 else if (pid > 0)
1056 {
1057 /* parent -- clean out connection cache */
1058 mci_flush(FALSE, NULL);
1059 }
2e3062fe
EA
1060 }
1061 else
1062 {
d0268270 1063 pid = 0;
2e3062fe
EA
1064 }
1065
d0268270 1066 if (pid == 0)
81b7d258
EA
1067 {
1068 /*
1069 ** CHILD
6bbaf971
EA
1070 ** Lock the control file to avoid duplicate deliveries.
1071 ** Then run the file as though we had just read it.
68f0b54c
EA
1072 ** We save an idea of the temporary name so we
1073 ** can recover on interrupt.
81b7d258
EA
1074 */
1075
9416f3a0 1076 /* set basic modes, etc. */
37eaaadb 1077 (void) alarm(0);
a4076aed 1078 clearenvelope(e, FALSE);
164f3011 1079 e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
8c8e8e94 1080 e->e_errormode = EM_MAIL;
a7dc53bd 1081 e->e_id = id;
48cb554d 1082 GrabTo = UseErrorsTo = FALSE;
a9927082 1083 ExitStat = EX_OK;
47e2f242 1084 if (forkflag)
164f3011 1085 {
d0268270 1086 disconnect(1, e);
164f3011
EA
1087 OpMode = MD_DELIVER;
1088 }
36a4e219 1089# ifdef LOG
68f7099c 1090 if (LogLevel > 76)
a4076aed 1091 syslog(LOG_DEBUG, "%s: dowork, pid=%d", e->e_id,
291fa573 1092 getpid());
f3d8f6d6 1093# endif /* LOG */
9416f3a0
EA
1094
1095 /* don't use the headers from sendmail.cf... */
a4076aed 1096 e->e_header = NULL;
9416f3a0 1097
3620ad97 1098 /* read the queue control file -- return if locked */
63a34fcd 1099 if (!readqf(e))
dd1fe05b 1100 {
a7dc53bd
EA
1101 if (tTd(40, 4))
1102 printf("readqf(%s) failed\n", e->e_id);
1103 if (forkflag)
2e3062fe
EA
1104 exit(EX_OK);
1105 else
a9927082 1106 return 0;
dd1fe05b 1107 }
dd1fe05b 1108
a4076aed 1109 e->e_flags |= EF_INQUEUE;
dd1fe05b 1110
3df50535 1111 /* if this has been tried recently, let it be */
1b9b1753 1112 if (e->e_ntries > 0 && (curtime() - e->e_dtime) < MinQueueAge)
3df50535
EA
1113 {
1114 char *howlong = pintvl(curtime() - e->e_dtime, TRUE);
f5303697 1115
3df50535
EA
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 }
dd1fe05b 1136
dd1fe05b 1137 /* finish up and exit */
a7dc53bd 1138 if (forkflag)
2e3062fe
EA
1139 finis();
1140 else
a4076aed 1141 dropenvelope(e);
81b7d258 1142 }
d0268270
EA
1143 e->e_id = NULL;
1144 return pid;
81b7d258
EA
1145}
1146\f/*
1147** READQF -- read queue file and set up environment.
1148**
1149** Parameters:
7338e3d4 1150** e -- the envelope of the job to run.
81b7d258
EA
1151**
1152** Returns:
3620ad97
EA
1153** TRUE if it successfully read the queue file.
1154** FALSE otherwise.
81b7d258
EA
1155**
1156** Side Effects:
3620ad97 1157** The queue file is returned locked.
81b7d258
EA
1158*/
1159
3620ad97 1160bool
63a34fcd 1161readqf(e)
7338e3d4 1162 register ENVELOPE *e;
81b7d258 1163{
11e3f8b5 1164 register FILE *qfp;
d2213d6c 1165 ADDRESS *ctladdr;
dcbc04c7 1166 struct stat st;
07b49560 1167 char *bp;
68d9129a
EA
1168 int qfver = 0;
1169 register char *p;
3b6c2253 1170 char *orcpt = NULL;
e678ee95 1171 char qf[20];
07b49560 1172 char buf[MAXLINE];
8ff78b51 1173 extern long atol();
d2213d6c 1174 extern ADDRESS *setctluser();
99fd9645 1175 extern void loseqfile();
abae7b2d 1176 extern ADDRESS *sendto();
81b7d258 1177
81b7d258
EA
1178 /*
1179 ** Read and process the file.
1180 */
1181
e678ee95 1182 strcpy(qf, queuename(e, 'q'));
76b607b2 1183 qfp = fopen(qf, "r+");
11e3f8b5
EA
1184 if (qfp == NULL)
1185 {
a7dc53bd
EA
1186 if (tTd(40, 8))
1187 printf("readqf(%s): fopen failure (%s)\n",
1188 qf, errstring(errno));
3f9ac8ea
RA
1189 if (errno != ENOENT)
1190 syserr("readqf: no control file %s", qf);
3620ad97 1191 return FALSE;
3f9ac8ea
RA
1192 }
1193
71936fbe 1194 if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB))
e3778690
EA
1195 {
1196 /* being processed by another queuer */
3df50535 1197 if (Verbose || tTd(40, 8))
e3778690
EA
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
dcbc04c7
EA
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 */
a7dc53bd
EA
1214 if (tTd(40, 8))
1215 printf("readqf(%s): fstat failure (%s)\n",
1216 qf, errstring(errno));
dcbc04c7
EA
1217 fclose(qfp);
1218 return FALSE;
1219 }
1220
6502fd93 1221 if (st.st_uid != geteuid() || bitset(S_IWOTH|S_IWGRP, st.st_mode))
dcbc04c7
EA
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 }
f3d8f6d6 1229# endif /* LOG */
a7dc53bd
EA
1230 if (tTd(40, 8))
1231 printf("readqf(%s): bogus file\n", qf);
99fd9645 1232 loseqfile(e, "bogus file uid in mqueue");
e3778690 1233 fclose(qfp);
dcbc04c7
EA
1234 return FALSE;
1235 }
1236
e3778690 1237 if (st.st_size == 0)
3f9ac8ea 1238 {
e3778690
EA
1239 /* must be a bogus file -- just remove it */
1240 (void) unlink(qf);
1241 fclose(qfp);
3620ad97 1242 return FALSE;
11e3f8b5 1243 }
3f9ac8ea 1244
e3778690 1245 if (st.st_nlink == 0)
c87034b7 1246 {
e3778690
EA
1247 /*
1248 ** Race condition -- we got a file just as it was being
1249 ** unlinked. Just assume it is zero length.
1250 */
1251
c87034b7
EA
1252 fclose(qfp);
1253 return FALSE;
1254 }
1255
e3778690 1256 /* good file -- save this lock */
3620ad97
EA
1257 e->e_lockfp = qfp;
1258
3f9ac8ea 1259 /* do basic system initialization */
a4076aed 1260 initsys(e);
b276598d 1261 define('i', e->e_id, e);
3f9ac8ea 1262
560a80d9 1263 LineNumber = 0;
c6c403f7
EA
1264 e->e_flags |= EF_GLOBALERRS;
1265 OpMode = MD_DELIVER;
d2213d6c 1266 ctladdr = NULL;
bb4fde22 1267 e->e_dfino = -1;
18a81ac0 1268 e->e_msgsize = -1;
07b49560 1269 while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
81b7d258 1270 {
c2bdb1dd 1271 register char *p;
68d9129a
EA
1272 u_long qflags;
1273 ADDRESS *q;
65b5adb6 1274
795590e2 1275 if (tTd(40, 4))
07b49560
EA
1276 printf("+++++ %s\n", bp);
1277 switch (bp[0])
81b7d258 1278 {
68d9129a
EA
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
3fbc69d6 1288 case 'C': /* specify controlling user */
07b49560 1289 ctladdr = setctluser(&bp[1]);
3fbc69d6
KB
1290 break;
1291
3b6c2253
EA
1292 case 'Q': /* original recipient */
1293 orcpt = newstr(&bp[1]);
1294 break;
1295
81b7d258 1296 case 'R': /* specify recipient */
abae7b2d 1297 (void) sendto(&buf[1], 1, (ADDRESS *) NULL, 0);
81b7d258
EA
1298 break;
1299
4e969be0 1300 case 'E': /* specify error recipient */
b7b719e4 1301 /* no longer used */
4e969be0
EA
1302 break;
1303
81b7d258 1304 case 'H': /* header */
07b49560 1305 (void) chompheader(&bp[1], FALSE, e);
81b7d258
EA
1306 break;
1307
baa0c390 1308 case 'M': /* message */
82530719 1309 /* ignore this; we want a new message next time */
baa0c390
EA
1310 break;
1311
81b7d258 1312 case 'S': /* sender */
4a2da288 1313 setsender(newstr(&bp[1]), e, NULL, TRUE);
81b7d258
EA
1314 break;
1315
96bfbc2c
EA
1316 case 'B': /* body type */
1317 e->e_bodytype = newstr(&bp[1]);
1318 break;
1319
81b7d258 1320 case 'D': /* data file name */
18a81ac0 1321 /* obsolete -- ignore */
81b7d258
EA
1322 break;
1323
96476cab 1324 case 'T': /* init time */
07b49560 1325 e->e_ctime = atol(&bp[1]);
81b7d258
EA
1326 break;
1327
f009d24b 1328 case 'I': /* data file's inode number */
bb4fde22
EA
1329 if (e->e_dfino == -1)
1330 e->e_dfino = atol(&buf[1]);
f009d24b
EA
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
aba51985 1341 case 'P': /* message priority */
07b49560 1342 e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
dd1fe05b
EA
1343 break;
1344
c2bdb1dd
EA
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;
e3c84ea8
EA
1357
1358 case '8': /* has 8 bit data */
1359 e->e_flags |= EF_HAS8BIT;
1360 break;
c2bdb1dd
EA
1361 }
1362 }
1363 break;
1364
6da3ba01 1365 case 'Z': /* original envelope id from ESMTP */
36c7ff6a 1366 e->e_envid = newstr(&bp[1]);
6da3ba01
EA
1367 break;
1368
22293c34 1369 case '$': /* define macro */
07b49560 1370 define(bp[1], newstr(&bp[2]), e);
22293c34
EA
1371 break;
1372
2e3062fe
EA
1373 case '\0': /* blank line; ignore */
1374 break;
1375
81b7d258 1376 default:
5e90e563 1377 syserr("readqf: %s: line %d: bad line \"%s\"",
63a34fcd 1378 qf, LineNumber, bp);
8e5c6745 1379 fclose(qfp);
99fd9645 1380 loseqfile(e, "unrecognized line");
8e5c6745 1381 return FALSE;
81b7d258 1382 }
07b49560
EA
1383
1384 if (bp != buf)
1385 free(bp);
81b7d258 1386 }
7338e3d4 1387
2e3062fe
EA
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 }
18a81ac0
EA
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 }
66d16835 1410 else
18a81ac0 1411 {
66d16835
EA
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 }
18a81ac0
EA
1419 }
1420 }
1421
3620ad97 1422 return TRUE;
81b7d258
EA
1423}
1424\f/*
64912e7e
EA
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;
0490b7d7 1441 int nrequests;
64912e7e
EA
1442 char buf[MAXLINE];
1443
374579b6
EA
1444 /*
1445 ** Check for permission to print the queue
1446 */
1447
fd178efd 1448 if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
374579b6
EA
1449 {
1450 struct stat st;
3afbc0f1
EA
1451# ifdef NGROUPS
1452 int n;
e6cb9fc4 1453 GIDSET_T gidset[NGROUPS];
3afbc0f1 1454# endif
374579b6 1455
7c8b3fd4 1456 if (stat(QueueDir, &st) < 0)
374579b6
EA
1457 {
1458 syserr("Cannot stat %s", QueueDir);
1459 return;
1460 }
3afbc0f1
EA
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
fd57f063 1470 if (RealGid != st.st_gid)
3afbc0f1 1471# endif
374579b6
EA
1472 {
1473 usrerr("510 You are not permitted to see the queue");
1474 setstat(EX_NOPERM);
1475 return;
1476 }
1477 }
1478
64912e7e
EA
1479 /*
1480 ** Read and order the queue.
1481 */
1482
2e3062fe 1483 nrequests = orderq(TRUE);
64912e7e
EA
1484
1485 /*
1486 ** Print the work list that we have read.
1487 */
1488
1489 /* first see if there is anything */
0490b7d7 1490 if (nrequests <= 0)
64912e7e 1491 {
0490b7d7 1492 printf("Mail queue is empty\n");
64912e7e
EA
1493 return;
1494 }
1495
3620ad97 1496 CurrentLA = getla(); /* get load average */
3f9ac8ea 1497
d7b5594c 1498 printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
4e969be0
EA
1499 if (nrequests > QUEUESIZE)
1500 printf(", only %d printed", QUEUESIZE);
f4b05990 1501 if (Verbose)
fbab5052 1502 printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
f4b05990 1503 else
fbab5052 1504 printf(")\n--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
64912e7e
EA
1505 for (w = WorkQ; w != NULL; w = w->w_next)
1506 {
1507 struct stat st;
0490b7d7 1508 auto time_t submittime = 0;
73af81f9 1509 long dfsize;
c2bdb1dd 1510 int flags = 0;
68d9129a 1511 int qfver;
baa0c390 1512 char message[MAXLINE];
8446c922 1513 char bodytype[MAXNAME + 1];
64912e7e 1514
4ba6a6f4 1515 printf("%8s", w->w_name + 2);
560a80d9
EA
1516 f = fopen(w->w_name, "r");
1517 if (f == NULL)
1518 {
4ba6a6f4 1519 printf(" (job completed)\n");
560a80d9
EA
1520 errno = 0;
1521 continue;
1522 }
73af81f9
EA
1523 w->w_name[0] = 'd';
1524 if (stat(w->w_name, &st) >= 0)
1525 dfsize = st.st_size;
1526 else
1527 dfsize = -1;
a9ca3259 1528 if (w->w_lock)
0490b7d7 1529 printf("*");
abccefc9 1530 else if (shouldqueue(w->w_pri, w->w_ctime))
2e3062fe 1531 printf("X");
0490b7d7
EA
1532 else
1533 printf(" ");
1534 errno = 0;
560a80d9 1535
96bfbc2c 1536 message[0] = bodytype[0] = '\0';
68d9129a 1537 qfver = 0;
64912e7e
EA
1538 while (fgets(buf, sizeof buf, f) != NULL)
1539 {
22293c34 1540 register int i;
c2bdb1dd 1541 register char *p;
22293c34 1542
64912e7e
EA
1543 fixcrlf(buf, TRUE);
1544 switch (buf[0])
1545 {
68d9129a
EA
1546 case 'V': /* queue file version */
1547 qfver = atoi(&buf[1]);
1548 break;
1549
baa0c390 1550 case 'M': /* error message */
22293c34 1551 if ((i = strlen(&buf[1])) >= sizeof message)
c2bdb1dd 1552 i = sizeof message - 1;
22293c34
EA
1553 bcopy(&buf[1], message, i);
1554 message[i] = '\0';
baa0c390
EA
1555 break;
1556
96bfbc2c
EA
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
64912e7e 1564 case 'S': /* sender name */
f4b05990 1565 if (Verbose)
c2bdb1dd
EA
1566 printf("%8ld %10ld%c%.12s %.38s",
1567 dfsize,
1568 w->w_pri,
1569 bitset(EF_WARNING, flags) ? '+' : ' ',
1570 ctime(&submittime) + 4,
f4b05990
EA
1571 &buf[1]);
1572 else
1573 printf("%8ld %.16s %.45s", dfsize,
1574 ctime(&submittime), &buf[1]);
96bfbc2c
EA
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 }
64912e7e 1581 break;
3620ad97 1582
3fbc69d6 1583 case 'C': /* controlling user */
d2213d6c 1584 if (Verbose)
fbab5052
EA
1585 printf("\n\t\t\t\t (---%.34s---)",
1586 &buf[1]);
3fbc69d6 1587 break;
64912e7e
EA
1588
1589 case 'R': /* recipient name */
68d9129a
EA
1590 p = &buf[1];
1591 if (qfver >= 1)
1592 {
1593 p = strchr(p, ':');
1594 if (p == NULL)
1595 break;
1596 p++;
1597 }
f4b05990 1598 if (Verbose)
68d9129a 1599 printf("\n\t\t\t\t\t %.38s", p);
f4b05990 1600 else
68d9129a 1601 printf("\n\t\t\t\t %.45s", p);
64912e7e
EA
1602 break;
1603
1604 case 'T': /* creation time */
2e3062fe 1605 submittime = atol(&buf[1]);
0490b7d7
EA
1606 break;
1607
c2bdb1dd
EA
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 }
64912e7e
EA
1618 }
1619 }
0490b7d7
EA
1620 if (submittime == (time_t) 0)
1621 printf(" (no control file)");
64912e7e 1622 printf("\n");
0e306e7f 1623 (void) fclose(f);
64912e7e
EA
1624 }
1625}
884a20cb 1626
f3d8f6d6 1627# endif /* QUEUE */
560a80d9
EA
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.
560a80d9
EA
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:
3620ad97
EA
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.
560a80d9
EA
1647*/
1648
1649char *
1650queuename(e, type)
1651 register ENVELOPE *e;
ef3bc6b1 1652 int type;
560a80d9 1653{
560a80d9 1654 static int pid = -1;
e3bb0d32
EA
1655 static char c0;
1656 static char c1;
1657 static char c2;
fbab5052
EA
1658 time_t now;
1659 struct tm *tm;
8446c922 1660 static char buf[MAXNAME + 1];
560a80d9
EA
1661
1662 if (e->e_id == NULL)
1663 {
1664 char qf[20];
560a80d9
EA
1665
1666 /* find a unique id */
1667 if (pid != getpid())
1668 {
1669 /* new process -- start back at "AA" */
1670 pid = getpid();
fbab5052
EA
1671 now = curtime();
1672 tm = localtime(&now);
1673 c0 = 'A' + tm->tm_hour;
560a80d9
EA
1674 c1 = 'A';
1675 c2 = 'A' - 1;
1676 }
fbab5052 1677 (void) sprintf(qf, "qf%cAA%05d", c0, pid);
560a80d9
EA
1678
1679 while (c1 < '~' || c2 < 'Z')
1680 {
1681 int i;
1682
1683 if (c2 >= 'Z')
1684 {
1685 c1++;
1686 c2 = 'A' - 1;
1687 }
fbab5052
EA
1688 qf[3] = c1;
1689 qf[4] = ++c2;
560a80d9 1690 if (tTd(7, 20))
3f9ac8ea 1691 printf("queuename: trying \"%s\"\n", qf);
560a80d9 1692
3f9ac8ea 1693 i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode);
3620ad97
EA
1694 if (i < 0)
1695 {
1696 if (errno == EEXIST)
1697 continue;
82530719
EA
1698 syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
1699 qf, QueueDir, geteuid());
3620ad97
EA
1700 exit(EX_UNAVAILABLE);
1701 }
71936fbe 1702 if (lockfile(i, qf, NULL, LOCK_EX|LOCK_NB))
3620ad97
EA
1703 {
1704 e->e_lockfp = fdopen(i, "w");
bb09c502 1705 break;
3f9ac8ea 1706 }
3620ad97
EA
1707
1708 /* a reader got the file; abandon it and try again */
1709 (void) close(i);
560a80d9
EA
1710 }
1711 if (c1 >= '~' && c2 >= 'Z')
1712 {
82530719
EA
1713 syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
1714 qf, QueueDir, geteuid());
560a80d9
EA
1715 exit(EX_OSERR);
1716 }
1717 e->e_id = newstr(&qf[2]);
1718 define('i', e->e_id, e);
560a80d9
EA
1719 if (tTd(7, 1))
1720 printf("queuename: assigned id %s, env=%x\n", e->e_id, e);
eead656c
EA
1721 if (tTd(7, 9))
1722 {
1723 printf(" lockfd=");
1724 dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
1725 }
560a80d9 1726# ifdef LOG
68f7099c 1727 if (LogLevel > 93)
560a80d9 1728 syslog(LOG_DEBUG, "%s: assigned id", e->e_id);
f3d8f6d6 1729# endif /* LOG */
560a80d9
EA
1730 }
1731
1732 if (type == '\0')
1733 return (NULL);
1734 (void) sprintf(buf, "%cf%s", type, e->e_id);
560a80d9
EA
1735 if (tTd(7, 2))
1736 printf("queuename: %s\n", buf);
560a80d9
EA
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{
bc854e30
EA
1755 if (tTd(51, 4))
1756 printf("unlockqueue(%s)\n", e->e_id);
1757
3620ad97
EA
1758 /* if there is a lock file in the envelope, close it */
1759 if (e->e_lockfp != NULL)
bc854e30 1760 xfclose(e->e_lockfp, "unlockqueue", e->e_id);
3620ad97
EA
1761 e->e_lockfp = NULL;
1762
32061c38
EA
1763 /* don't create a queue id if we don't already have one */
1764 if (e->e_id == NULL)
1765 return;
1766
560a80d9 1767 /* remove the transcript */
560a80d9 1768# ifdef LOG
68f7099c 1769 if (LogLevel > 87)
560a80d9 1770 syslog(LOG_DEBUG, "%s: unlock", e->e_id);
f3d8f6d6 1771# endif /* LOG */
bc854e30 1772 if (!tTd(51, 104))
560a80d9
EA
1773 xunlink(queuename(e, 'x'));
1774
560a80d9 1775}
3fbc69d6 1776\f/*
d2213d6c 1777** SETCTLUSER -- create a controlling address
3fbc69d6 1778**
d2213d6c
EA
1779** Create a fake "address" given only a local login name; this is
1780** used as a "controlling user" for future recipient addresses.
3fbc69d6
KB
1781**
1782** Parameters:
d2213d6c 1783** user -- the user name of the controlling user.
3fbc69d6
KB
1784**
1785** Returns:
d2213d6c 1786** An address descriptor for the controlling user.
3fbc69d6
KB
1787**
1788** Side Effects:
1789** none.
1790*/
1791
d2213d6c
EA
1792ADDRESS *
1793setctluser(user)
1794 char *user;
3fbc69d6 1795{
d2213d6c 1796 register ADDRESS *a;
3fbc69d6 1797 struct passwd *pw;
9cdb0b30 1798 char *p;
3fbc69d6
KB
1799
1800 /*
d2213d6c 1801 ** See if this clears our concept of controlling user.
3fbc69d6
KB
1802 */
1803
c6c403f7
EA
1804 if (user == NULL || *user == '\0')
1805 return NULL;
3fbc69d6
KB
1806
1807 /*
d2213d6c 1808 ** Set up addr fields for controlling user.
3fbc69d6
KB
1809 */
1810
d2213d6c
EA
1811 a = (ADDRESS *) xalloc(sizeof *a);
1812 bzero((char *) a, sizeof *a);
9cdb0b30
EA
1813
1814 p = strchr(user, ':');
1815 if (p != NULL)
1816 *p++ = '\0';
f7894324 1817 if (*user != '\0' && (pw = getpwnam(user)) != NULL)
3fbc69d6 1818 {
c841d671
EA
1819 if (strcmp(pw->pw_dir, "/") == 0)
1820 a->q_home = "";
1821 else
1822 a->q_home = newstr(pw->pw_dir);
3fbc69d6
KB
1823 a->q_uid = pw->pw_uid;
1824 a->q_gid = pw->pw_gid;
f7894324 1825 a->q_flags |= QGOODUID;
3fbc69d6 1826 }
66d16835
EA
1827
1828 if (*user != '\0')
1829 a->q_user = newstr(user);
1830 else if (p != NULL)
1831 a->q_user = newstr(p);
3fbc69d6 1832 else
6e99f903 1833 a->q_user = newstr(DefUser);
3fbc69d6 1834
f7894324 1835 a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */
d0a69620 1836 a->q_mailer = LocalMailer;
9cdb0b30
EA
1837 if (p == NULL)
1838 a->q_paddr = a->q_user;
1839 else
1840 a->q_paddr = newstr(p);
d2213d6c 1841 return a;
3fbc69d6 1842}
99fd9645
EA
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{
6502fd93 1859 char *p;
99fd9645
EA
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'));
6502fd93
EA
1867 p = queuename(e, 'Q');
1868 if (rename(buf, p) < 0)
1869 syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid());
99fd9645 1870#ifdef LOG
6502fd93
EA
1871 else if (LogLevel > 0)
1872 syslog(LOG_ALERT, "Losing %s: %s", buf, why);
99fd9645
EA
1873#endif
1874}