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