clean up confUSERDB_SPEC
[unix-history] / usr / src / usr.sbin / sendmail / src / queue.c
CommitLineData
b2a81223 1/*
dc45ba8c 2 * Copyright (c) 1983 Eric P. Allman
bee79b64
KB
3 * Copyright (c) 1988 Regents of the University of California.
4 * All rights reserved.
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
fbab5052 13static char sccsid[] = "@(#)queue.c 6.31 (Berkeley) %G% (with queueing)";
bee79b64 14#else
fbab5052 15static char sccsid[] = "@(#)queue.c 6.31 (Berkeley) %G% (without queueing)";
bee79b64
KB
16#endif
17#endif /* not lint */
18
81b7d258 19# include <sys/stat.h>
a2cb9a08 20# include <sys/dir.h>
aba51985 21# include <signal.h>
81b7d258 22# include <errno.h>
3fbc69d6 23# include <pwd.h>
aa102c71 24# ifndef MAXNAMLEN
6feb509e
EA
25# include <dirent.h>
26# endif
4287d84d 27
76b607b2
EA
28# ifdef QUEUE
29
81b7d258 30/*
7338e3d4
EA
31** Work queue.
32*/
33
34struct work
35{
36 char *w_name; /* name of control file */
37 long w_pri; /* priority of message, see below */
f746582a 38 time_t w_ctime; /* creation time of message */
7338e3d4
EA
39 struct work *w_next; /* next in queue */
40};
41
42typedef struct work WORK;
43
44WORK *WorkQ; /* queue of things to be done */
45\f/*
81b7d258
EA
46** QUEUEUP -- queue a message up for future transmission.
47**
81b7d258 48** Parameters:
dd1fe05b 49** e -- the envelope to queue up.
d0bd03ce
EA
50** queueall -- if TRUE, queue all addresses, rather than
51** just those with the QQUEUEUP flag set.
7338e3d4 52** announce -- if TRUE, tell when you are queueing up.
81b7d258
EA
53**
54** Returns:
3620ad97 55** none.
81b7d258
EA
56**
57** Side Effects:
7338e3d4 58** The current request are saved in a control file.
3620ad97 59** The queue file is left locked.
81b7d258
EA
60*/
61
7338e3d4 62queueup(e, queueall, announce)
dd1fe05b 63 register ENVELOPE *e;
d0bd03ce 64 bool queueall;
7338e3d4 65 bool announce;
81b7d258 66{
2cce0c26 67 char *qf;
2cce0c26 68 register FILE *tfp;
81b7d258 69 register HDR *h;
d4f42161 70 register ADDRESS *q;
3620ad97
EA
71 int fd;
72 int i;
73 bool newid;
22293c34 74 register char *p;
4db45bf1 75 MAILER nullmailer;
d2213d6c 76 ADDRESS *lastctladdr;
3620ad97 77 char buf[MAXLINE], tf[MAXLINE];
22293c34 78 extern char *macvalue();
d2213d6c 79 extern ADDRESS *getctladdr();
81b7d258 80
9ccf54c4 81 /*
11e3f8b5 82 ** Create control file.
9ccf54c4 83 */
81b7d258 84
3620ad97
EA
85 newid = (e->e_id == NULL);
86 strcpy(tf, queuename(e, 't'));
87 tfp = e->e_lockfp;
88 if (tfp == NULL)
89 newid = FALSE;
90 if (newid)
4287d84d 91 {
3620ad97
EA
92 tfp = e->e_lockfp;
93 }
94 else
95 {
96 /* get a locked tf file */
97 for (i = 100; --i >= 0; )
4287d84d 98 {
f8a31c8e 99 extern bool lockfile();
76b607b2 100
3620ad97
EA
101 fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode);
102 if (fd < 0)
4287d84d 103 {
3620ad97
EA
104 if (errno == EEXIST)
105 continue;
e0539260 106 syserr("!queueup: cannot create temp file %s", tf);
6680179d 107 }
f8a31c8e
EA
108
109 if (lockfile(fd, tf, LOCK_EX|LOCK_NB))
3620ad97 110 break;
f8a31c8e 111
3620ad97 112 close(fd);
6680179d 113 }
6680179d 114
3620ad97
EA
115 tfp = fdopen(fd, "w");
116 }
81b7d258 117
9678c96d 118 if (tTd(40, 1))
560a80d9 119 printf("queueing %s\n", e->e_id);
81b7d258 120
dd1fe05b
EA
121 /*
122 ** If there is no data file yet, create one.
123 */
124
125 if (e->e_df == NULL)
126 {
127 register FILE *dfp;
80482eb5 128 extern putbody();
dd1fe05b 129
2cce0c26 130 e->e_df = newstr(queuename(e, 'd'));
3f9ac8ea
RA
131 fd = open(e->e_df, O_WRONLY|O_CREAT, FileMode);
132 if (fd < 0)
e0539260 133 syserr("!queueup: cannot create %s", e->e_df);
3f9ac8ea 134 dfp = fdopen(fd, "w");
4db45bf1 135 (*e->e_putbody)(dfp, ProgMailer, e);
bc854e30 136 (void) xfclose(dfp, "queueup dfp", e->e_id);
80482eb5 137 e->e_putbody = putbody;
dd1fe05b
EA
138 }
139
81b7d258
EA
140 /*
141 ** Output future work requests.
4e969be0
EA
142 ** Priority and creation time should be first, since
143 ** they are required by orderq.
81b7d258
EA
144 */
145
7338e3d4
EA
146 /* output message priority */
147 fprintf(tfp, "P%ld\n", e->e_msgpriority);
148
64912e7e
EA
149 /* output creation time */
150 fprintf(tfp, "T%ld\n", e->e_ctime);
151
81b7d258 152 /* output name of data file */
2cce0c26 153 fprintf(tfp, "D%s\n", e->e_df);
81b7d258 154
baa0c390
EA
155 /* message from envelope, if it exists */
156 if (e->e_message != NULL)
157 fprintf(tfp, "M%s\n", e->e_message);
158
22293c34
EA
159 /* $r and $s macro values */
160 if ((p = macvalue('r', e)) != NULL)
161 fprintf(tfp, "$r%s\n", p);
162 if ((p = macvalue('s', e)) != NULL)
163 fprintf(tfp, "$s%s\n", p);
164
81b7d258 165 /* output name of sender */
2cce0c26 166 fprintf(tfp, "S%s\n", e->e_from.q_paddr);
81b7d258 167
ca4d0c0b 168 /* output list of error recipients */
d2213d6c 169 lastctladdr = NULL;
ca4d0c0b
EA
170 for (q = e->e_errorqueue; q != NULL; q = q->q_next)
171 {
bc854e30 172 if (!bitset(QDONTSEND|QBADADDR, q->q_flags))
ca4d0c0b
EA
173 {
174 ADDRESS *ctladdr;
175
176 ctladdr = getctladdr(q);
ca4d0c0b
EA
177 if (ctladdr != lastctladdr)
178 {
179 printctladdr(ctladdr, tfp);
180 lastctladdr = ctladdr;
181 }
182 fprintf(tfp, "E%s\n", q->q_paddr);
183 }
184 }
185
186 /* output list of recipient addresses */
dd1fe05b 187 for (q = e->e_sendqueue; q != NULL; q = q->q_next)
81b7d258 188 {
374579b6 189 if (bitset(QQUEUEUP, q->q_flags) ||
bc854e30 190 (queueall && !bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags)))
4d237f16 191 {
d2213d6c 192 ADDRESS *ctladdr;
3fbc69d6 193
f8a74171 194 ctladdr = getctladdr(q);
f8a74171 195 if (ctladdr != lastctladdr)
d2213d6c
EA
196 {
197 printctladdr(ctladdr, tfp);
198 lastctladdr = ctladdr;
199 }
2cce0c26 200 fprintf(tfp, "R%s\n", q->q_paddr);
7338e3d4
EA
201 if (announce)
202 {
203 e->e_to = q->q_paddr;
b6edea3d 204 message("queued");
68f7099c 205 if (LogLevel > 8)
c0ae0b24 206 logdelivery(NULL, NULL, "queued", e);
7338e3d4
EA
207 e->e_to = NULL;
208 }
b9accadd
EA
209 if (tTd(40, 1))
210 {
211 printf("queueing ");
212 printaddr(q, FALSE);
213 }
4d237f16 214 }
81b7d258
EA
215 }
216
7338e3d4
EA
217 /*
218 ** Output headers for this message.
219 ** Expand macros completely here. Queue run will deal with
220 ** everything as absolute headers.
221 ** All headers that must be relative to the recipient
222 ** can be cracked later.
4db45bf1
EA
223 ** We set up a "null mailer" -- i.e., a mailer that will have
224 ** no effect on the addresses as they are output.
7338e3d4
EA
225 */
226
1dbda134 227 bzero((char *) &nullmailer, sizeof nullmailer);
68f7099c
EA
228 nullmailer.m_re_rwset = nullmailer.m_rh_rwset =
229 nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1;
281ef7f0 230 nullmailer.m_eol = "\n";
4db45bf1 231
2bee003d 232 define('g', "\201f", e);
dd1fe05b 233 for (h = e->e_header; h != NULL; h = h->h_link)
81b7d258 234 {
1dbda134
EA
235 extern bool bitzerop();
236
83e9910e 237 /* don't output null headers */
81b7d258
EA
238 if (h->h_value == NULL || h->h_value[0] == '\0')
239 continue;
83e9910e
EA
240
241 /* don't output resent headers on non-resent messages */
242 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
243 continue;
244
245 /* output this header */
2cce0c26 246 fprintf(tfp, "H");
83e9910e
EA
247
248 /* if conditional, output the set of conditions */
1dbda134
EA
249 if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))
250 {
251 int j;
252
0e306e7f 253 (void) putc('?', tfp);
1dbda134
EA
254 for (j = '\0'; j <= '\177'; j++)
255 if (bitnset(j, h->h_mflags))
0e306e7f
EA
256 (void) putc(j, tfp);
257 (void) putc('?', tfp);
1dbda134 258 }
83e9910e
EA
259
260 /* output the header: expand macros, convert addresses */
9416f3a0
EA
261 if (bitset(H_DEFAULT, h->h_flags))
262 {
263 (void) expand(h->h_value, buf, &buf[sizeof buf], e);
3ba0846a 264 fprintf(tfp, "%s: %s\n", h->h_field, buf);
9416f3a0 265 }
4d237f16 266 else if (bitset(H_FROM|H_RCPT, h->h_flags))
611b763d 267 {
a4076aed
EA
268 commaize(h, h->h_value, tfp,
269 bitset(EF_OLDSTYLE, e->e_flags),
270 &nullmailer, e);
611b763d 271 }
4d237f16
EA
272 else
273 fprintf(tfp, "%s: %s\n", h->h_field, h->h_value);
81b7d258
EA
274 }
275
276 /*
277 ** Clean up.
278 */
279
3620ad97
EA
280 if (!newid)
281 {
282 qf = queuename(e, 'q');
283 if (rename(tf, qf) < 0)
284 syserr("cannot rename(%s, %s), df=%s", tf, qf, e->e_df);
285 if (e->e_lockfp != NULL)
bc854e30 286 (void) xfclose(e->e_lockfp, "queueup lockfp", e->e_id);
3620ad97
EA
287 e->e_lockfp = tfp;
288 }
289 else
290 qf = tf;
6680179d 291 errno = 0;
1a13ccd8 292
9678c96d
EA
293# ifdef LOG
294 /* save log info */
68f7099c 295 if (LogLevel > 79)
a8f5bbff 296 syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df);
f3d8f6d6 297# endif /* LOG */
3f9ac8ea 298 fflush(tfp);
3620ad97 299 return;
81b7d258 300}
d2213d6c
EA
301
302printctladdr(a, tfp)
303 ADDRESS *a;
304 FILE *tfp;
305{
306 char *u;
307 struct passwd *pw;
308 extern struct passwd *getpwuid();
309
310 if (a == NULL)
311 {
312 fprintf(tfp, "C\n");
313 return;
314 }
315 if (a->q_uid == 0 || (pw = getpwuid(a->q_uid)) == NULL)
316 u = DefUser;
317 else
318 u = pw->pw_name;
319 fprintf(tfp, "C%s\n", u);
320}
321
81b7d258
EA
322\f/*
323** RUNQUEUE -- run the jobs in the queue.
324**
325** Gets the stuff out of the queue in some presumably logical
326** order and processes them.
327**
328** Parameters:
2e3062fe
EA
329** forkflag -- TRUE if the queue scanning should be done in
330** a child process. We double-fork so it is not our
331** child and we don't have to clean up after it.
81b7d258
EA
332**
333** Returns:
334** none.
335**
336** Side Effects:
337** runs things in the mail queue.
338*/
339
ca4d0c0b
EA
340ENVELOPE QueueEnvelope; /* the queue run envelope */
341
342runqueue(forkflag)
2cf55cb7 343 bool forkflag;
81b7d258 344{
4bc44f60 345 extern bool shouldqueue();
ca4d0c0b
EA
346 register ENVELOPE *e;
347 extern ENVELOPE BlankEnvelope;
348 extern ENVELOPE *newenvelope();
4bc44f60
EA
349
350 /*
351 ** If no work will ever be selected, don't even bother reading
352 ** the queue.
353 */
354
3620ad97 355 CurrentLA = getla(); /* get load average */
3f9ac8ea 356
986065ef 357 if (shouldqueue(0L, curtime()))
4bc44f60
EA
358 {
359 if (Verbose)
360 printf("Skipping queue run -- load average too high\n");
fe80f8e1
EA
361 if (forkflag && QueueIntvl != 0)
362 (void) setevent(QueueIntvl, runqueue, TRUE);
ca4d0c0b 363 return;
4bc44f60
EA
364 }
365
b6dffdf5
EA
366 /*
367 ** See if we want to go off and do other useful work.
368 */
2cf55cb7
EA
369
370 if (forkflag)
371 {
6d06102a
EA
372 int pid;
373
374 pid = dofork();
375 if (pid != 0)
2cf55cb7 376 {
0df908a9 377 extern void reapchild();
c8ad461a 378
6d06102a 379 /* parent -- pick up intermediate zombie */
c8ad461a 380#ifndef SIGCHLD
7338e3d4 381 (void) waitfor(pid);
f3d8f6d6 382#else /* SIGCHLD */
c8ad461a 383 (void) signal(SIGCHLD, reapchild);
f3d8f6d6 384#endif /* SIGCHLD */
c4442979 385 if (QueueIntvl != 0)
611b763d 386 (void) setevent(QueueIntvl, runqueue, TRUE);
2cf55cb7
EA
387 return;
388 }
6d06102a 389 /* child -- double fork */
c8ad461a 390#ifndef SIGCHLD
6d06102a
EA
391 if (fork() != 0)
392 exit(EX_OK);
f3d8f6d6 393#else /* SIGCHLD */
c8ad461a 394 (void) signal(SIGCHLD, SIG_DFL);
f3d8f6d6 395#endif /* SIGCHLD */
b6dffdf5 396 }
2e3062fe 397
3f9ac8ea 398 setproctitle("running queue: %s", QueueDir);
2e3062fe 399
36a4e219 400# ifdef LOG
68f7099c 401 if (LogLevel > 69)
ca4d0c0b
EA
402 syslog(LOG_DEBUG, "runqueue %s, pid=%d, forkflag=%d",
403 QueueDir, getpid(), forkflag);
f3d8f6d6 404# endif /* LOG */
81b7d258 405
eb8af3ce
EA
406 /*
407 ** Release any resources used by the daemon code.
408 */
409
410# ifdef DAEMON
411 clrdaemon();
f3d8f6d6 412# endif /* DAEMON */
eb8af3ce 413
ca4d0c0b
EA
414 /*
415 ** Create ourselves an envelope
416 */
417
418 CurEnv = &QueueEnvelope;
fda58daa 419 e = newenvelope(&QueueEnvelope, CurEnv);
ca4d0c0b
EA
420 e->e_flags = BlankEnvelope.e_flags;
421
a78155b0
EA
422 /*
423 ** Make sure the alias database is open.
424 */
425
a4076aed 426 initaliases(AliasFile, FALSE, e);
a78155b0 427
b6dffdf5
EA
428 /*
429 ** Start making passes through the queue.
430 ** First, read and sort the entire queue.
431 ** Then, process the work in that order.
432 ** But if you take too long, start over.
b6dffdf5 433 */
81b7d258 434
6d06102a 435 /* order the existing work requests */
8ff78b51 436 (void) orderq(FALSE);
291fa573 437
6d06102a
EA
438 /* process them once at a time */
439 while (WorkQ != NULL)
2cf55cb7 440 {
6d06102a 441 WORK *w = WorkQ;
2cf55cb7 442
6d06102a 443 WorkQ = WorkQ->w_next;
a4076aed 444 dowork(w, e);
6d06102a
EA
445 free(w->w_name);
446 free((char *) w);
2cf55cb7 447 }
37ea3cbf
EA
448
449 /* exit without the usual cleanup */
4e20c4d2
EA
450 e->e_id = NULL;
451 finis();
aba51985
EA
452}
453\f/*
81b7d258
EA
454** ORDERQ -- order the work queue.
455**
456** Parameters:
2e3062fe
EA
457** doall -- if set, include everything in the queue (even
458** the jobs that cannot be run because the load
459** average is too high). Otherwise, exclude those
460** jobs.
81b7d258
EA
461**
462** Returns:
e65b95c4
EA
463** The number of request in the queue (not necessarily
464** the number of requests in WorkQ however).
81b7d258
EA
465**
466** Side Effects:
467** Sets WorkQ to the queue of available work, in order.
468*/
469
4e969be0
EA
470# define NEED_P 001
471# define NEED_T 002
d6c28d1a
EA
472# define NEED_R 004
473# define NEED_S 010
81b7d258 474
38d3b461
EA
475# ifndef DIR
476# define DIR FILE
477# define direct dir
478# define opendir(d) fopen(d, "r")
07a8f29b 479# define readdir(f) ((fread(&dbuf, sizeof dbuf, 1, f) > 0) ? &dbuf : 0)
38d3b461
EA
480static struct dir dbuf;
481# define closedir(f) fclose(f)
482# endif DIR
483
2e3062fe
EA
484orderq(doall)
485 bool doall;
81b7d258 486{
ccd1d833 487 register struct direct *d;
81b7d258 488 register WORK *w;
ccd1d833 489 DIR *f;
81b7d258 490 register int i;
4e969be0 491 WORK wlist[QUEUESIZE+1];
0490b7d7 492 int wn = -1;
81b7d258 493 extern workcmpf();
81b7d258 494
d6c28d1a
EA
495 if (tTd(41, 1))
496 {
497 printf("orderq:\n");
498 if (QueueLimitId != NULL)
499 printf("\tQueueLimitId = %s\n", QueueLimitId);
500 if (QueueLimitSender != NULL)
501 printf("\tQueueLimitSender = %s\n", QueueLimitSender);
502 if (QueueLimitRecipient != NULL)
503 printf("\tQueueLimitRecipient = %s\n", QueueLimitRecipient);
504 }
505
81b7d258
EA
506 /* clear out old WorkQ */
507 for (w = WorkQ; w != NULL; )
508 {
509 register WORK *nw = w->w_next;
510
511 WorkQ = nw;
512 free(w->w_name);
513 free((char *) w);
514 w = nw;
515 }
516
517 /* open the queue directory */
6bbaf971 518 f = opendir(".");
81b7d258
EA
519 if (f == NULL)
520 {
6bbaf971 521 syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
0490b7d7 522 return (0);
81b7d258
EA
523 }
524
525 /*
526 ** Read the work directory.
527 */
528
0490b7d7 529 while ((d = readdir(f)) != NULL)
81b7d258 530 {
81b7d258 531 FILE *cf;
7338e3d4 532 char lbuf[MAXNAME];
6e99f903 533 extern bool shouldqueue();
d6c28d1a 534 extern bool strcontainedin();
81b7d258
EA
535
536 /* is this an interesting entry? */
07a8f29b
EA
537 if (d->d_ino == 0)
538 continue;
539# ifdef DEBUG
540 if (tTd(40, 10))
541 printf("orderq: %12s\n", d->d_name);
542# endif DEBUG
2cce0c26 543 if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
81b7d258
EA
544 continue;
545
d6c28d1a
EA
546 if (QueueLimitId != NULL &&
547 !strcontainedin(QueueLimitId, d->d_name))
548 continue;
549
fbab5052 550 if (strlen(d->d_name) != 10)
68f7099c
EA
551 {
552 if (Verbose)
553 printf("orderq: bogus qf name %s\n", d->d_name);
554#ifdef LOG
555 if (LogLevel > 3)
556 syslog(LOG_NOTICE, "orderq: bogus qf name %s",
557 d->d_name);
558#endif
559 if (strlen(d->d_name) >= MAXNAME)
560 d->d_name[MAXNAME - 1] = '\0';
561 strcpy(lbuf, d->d_name);
562 lbuf[0] = 'Q';
563 (void) rename(d->d_name, lbuf);
564 continue;
565 }
566
0490b7d7 567 /* yes -- open control file (if not too many files) */
4e969be0 568 if (++wn >= QUEUESIZE)
0490b7d7 569 continue;
d6c28d1a 570
6bbaf971 571 cf = fopen(d->d_name, "r");
81b7d258
EA
572 if (cf == NULL)
573 {
91f69adf
EA
574 /* this may be some random person sending hir msgs */
575 /* syserr("orderq: cannot open %s", cbuf); */
bd0712bd
EA
576 if (tTd(41, 2))
577 printf("orderq: cannot open %s (%d)\n",
578 d->d_name, errno);
91f69adf 579 errno = 0;
bd0712bd 580 wn--;
81b7d258
EA
581 continue;
582 }
4e969be0
EA
583 w = &wlist[wn];
584 w->w_name = newstr(d->d_name);
81b7d258 585
4ff794a3 586 /* make sure jobs in creation don't clog queue */
4e969be0
EA
587 w->w_pri = 0x7fffffff;
588 w->w_ctime = 0;
4ff794a3 589
81b7d258 590 /* extract useful information */
4e969be0 591 i = NEED_P | NEED_T;
d6c28d1a
EA
592 if (QueueLimitSender != NULL)
593 i |= NEED_S;
594 if (QueueLimitRecipient != NULL)
595 i |= NEED_R;
4e969be0 596 while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
81b7d258 597 {
8ff78b51 598 extern long atol();
d6c28d1a 599 extern bool strcontainedin();
8ff78b51 600
2e3062fe 601 switch (lbuf[0])
81b7d258 602 {
2e3062fe 603 case 'P':
4e969be0
EA
604 w->w_pri = atol(&lbuf[1]);
605 i &= ~NEED_P;
2e3062fe 606 break;
f746582a
EA
607
608 case 'T':
4e969be0
EA
609 w->w_ctime = atol(&lbuf[1]);
610 i &= ~NEED_T;
f746582a 611 break;
d6c28d1a
EA
612
613 case 'R':
614 if (QueueLimitRecipient != NULL &&
615 strcontainedin(QueueLimitRecipient, &lbuf[1]))
616 i &= ~NEED_R;
617 break;
618
619 case 'S':
620 if (QueueLimitSender != NULL &&
621 strcontainedin(QueueLimitSender, &lbuf[1]))
622 i &= ~NEED_S;
623 break;
81b7d258
EA
624 }
625 }
81b7d258 626 (void) fclose(cf);
4bc44f60 627
d6c28d1a
EA
628 if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
629 bitset(NEED_R|NEED_S, i))
4bc44f60
EA
630 {
631 /* don't even bother sorting this job in */
632 wn--;
633 }
81b7d258 634 }
ccd1d833 635 (void) closedir(f);
bd0712bd 636 wn++;
81b7d258
EA
637
638 /*
639 ** Sort the work directory.
640 */
641
4e969be0 642 qsort((char *) wlist, min(wn, QUEUESIZE), sizeof *wlist, workcmpf);
81b7d258
EA
643
644 /*
645 ** Convert the work list into canonical form.
7338e3d4 646 ** Should be turning it into a list of envelopes here perhaps.
81b7d258
EA
647 */
648
a0225d08 649 WorkQ = NULL;
4e969be0 650 for (i = min(wn, QUEUESIZE); --i >= 0; )
81b7d258
EA
651 {
652 w = (WORK *) xalloc(sizeof *w);
653 w->w_name = wlist[i].w_name;
81b7d258 654 w->w_pri = wlist[i].w_pri;
f746582a 655 w->w_ctime = wlist[i].w_ctime;
a0225d08
EA
656 w->w_next = WorkQ;
657 WorkQ = w;
81b7d258
EA
658 }
659
9678c96d 660 if (tTd(40, 1))
81b7d258
EA
661 {
662 for (w = WorkQ; w != NULL; w = w->w_next)
9ccf54c4 663 printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
81b7d258 664 }
0490b7d7 665
bd0712bd 666 return (wn);
81b7d258
EA
667}
668\f/*
9678c96d 669** WORKCMPF -- compare function for ordering work.
81b7d258
EA
670**
671** Parameters:
672** a -- the first argument.
673** b -- the second argument.
674**
675** Returns:
a0225d08
EA
676** -1 if a < b
677** 0 if a == b
678** +1 if a > b
81b7d258
EA
679**
680** Side Effects:
681** none.
682*/
683
81b7d258 684workcmpf(a, b)
9ccf54c4
EA
685 register WORK *a;
686 register WORK *b;
81b7d258 687{
abccefc9
EA
688 long pa = a->w_pri;
689 long pb = b->w_pri;
2e3062fe
EA
690
691 if (pa == pb)
81b7d258 692 return (0);
2e3062fe 693 else if (pa > pb)
e65b95c4 694 return (1);
a0225d08
EA
695 else
696 return (-1);
81b7d258
EA
697}
698\f/*
699** DOWORK -- do a work request.
700**
701** Parameters:
702** w -- the work request to be satisfied.
703**
704** Returns:
705** none.
706**
707** Side Effects:
708** The work request is satisfied if possible.
709*/
710
a4076aed 711dowork(w, e)
81b7d258 712 register WORK *w;
a4076aed 713 register ENVELOPE *e;
81b7d258
EA
714{
715 register int i;
2e3062fe 716 extern bool shouldqueue();
3620ad97 717 extern bool readqf();
81b7d258 718
9678c96d 719 if (tTd(40, 1))
9ccf54c4 720 printf("dowork: %s pri %ld\n", w->w_name, w->w_pri);
81b7d258
EA
721
722 /*
2e3062fe 723 ** Ignore jobs that are too expensive for the moment.
81b7d258
EA
724 */
725
abccefc9 726 if (shouldqueue(w->w_pri, w->w_ctime))
81b7d258 727 {
2e3062fe 728 if (Verbose)
559f8745 729 printf("\nSkipping %s\n", w->w_name + 2);
81b7d258
EA
730 return;
731 }
732
2e3062fe
EA
733 /*
734 ** Fork for work.
735 */
736
737 if (ForkQueueRuns)
738 {
739 i = fork();
740 if (i < 0)
741 {
742 syserr("dowork: cannot fork");
743 return;
744 }
745 }
746 else
747 {
748 i = 0;
749 }
750
81b7d258
EA
751 if (i == 0)
752 {
753 /*
754 ** CHILD
6bbaf971
EA
755 ** Lock the control file to avoid duplicate deliveries.
756 ** Then run the file as though we had just read it.
68f0b54c
EA
757 ** We save an idea of the temporary name so we
758 ** can recover on interrupt.
81b7d258
EA
759 */
760
9416f3a0 761 /* set basic modes, etc. */
37eaaadb 762 (void) alarm(0);
a4076aed 763 clearenvelope(e, FALSE);
81b7d258 764 QueueRun = TRUE;
7338e3d4 765 ErrorMode = EM_MAIL;
a4076aed 766 e->e_id = &w->w_name[2];
36a4e219 767# ifdef LOG
68f7099c 768 if (LogLevel > 76)
a4076aed 769 syslog(LOG_DEBUG, "%s: dowork, pid=%d", e->e_id,
291fa573 770 getpid());
f3d8f6d6 771# endif /* LOG */
9416f3a0
EA
772
773 /* don't use the headers from sendmail.cf... */
a4076aed 774 e->e_header = NULL;
9416f3a0 775
3620ad97 776 /* read the queue control file -- return if locked */
a4076aed 777 if (!readqf(e))
dd1fe05b 778 {
2e3062fe
EA
779 if (ForkQueueRuns)
780 exit(EX_OK);
781 else
782 return;
dd1fe05b 783 }
dd1fe05b 784
a4076aed 785 e->e_flags |= EF_INQUEUE;
6e99f903 786 eatheader(e, TRUE);
dd1fe05b
EA
787
788 /* do the delivery */
a4076aed
EA
789 if (!bitset(EF_FATALERRS, e->e_flags))
790 sendall(e, SM_DELIVER);
dd1fe05b 791
dd1fe05b 792 /* finish up and exit */
2e3062fe
EA
793 if (ForkQueueRuns)
794 finis();
795 else
a4076aed 796 dropenvelope(e);
81b7d258 797 }
2e3062fe
EA
798 else
799 {
800 /*
801 ** Parent -- pick up results.
802 */
81b7d258 803
2e3062fe
EA
804 errno = 0;
805 (void) waitfor(i);
806 }
81b7d258
EA
807}
808\f/*
809** READQF -- read queue file and set up environment.
810**
811** Parameters:
7338e3d4 812** e -- the envelope of the job to run.
81b7d258
EA
813**
814** Returns:
3620ad97
EA
815** TRUE if it successfully read the queue file.
816** FALSE otherwise.
81b7d258
EA
817**
818** Side Effects:
3620ad97 819** The queue file is returned locked.
81b7d258
EA
820*/
821
3620ad97
EA
822bool
823readqf(e)
7338e3d4 824 register ENVELOPE *e;
81b7d258 825{
11e3f8b5
EA
826 char *qf;
827 register FILE *qfp;
d2213d6c 828 ADDRESS *ctladdr;
dcbc04c7 829 struct stat st;
07b49560
EA
830 char *bp;
831 char buf[MAXLINE];
611b763d 832 extern char *fgetfolded();
8ff78b51 833 extern long atol();
d2213d6c 834 extern ADDRESS *setctluser();
f8a31c8e 835 extern bool lockfile();
abae7b2d 836 extern ADDRESS *sendto();
81b7d258 837
81b7d258
EA
838 /*
839 ** Read and process the file.
840 */
841
11e3f8b5 842 qf = queuename(e, 'q');
76b607b2 843 qfp = fopen(qf, "r+");
11e3f8b5
EA
844 if (qfp == NULL)
845 {
3f9ac8ea
RA
846 if (errno != ENOENT)
847 syserr("readqf: no control file %s", qf);
3620ad97 848 return FALSE;
3f9ac8ea
RA
849 }
850
dcbc04c7
EA
851 /*
852 ** Check the queue file for plausibility to avoid attacks.
853 */
854
855 if (fstat(fileno(qfp), &st) < 0)
856 {
857 /* must have been being processed by someone else */
858 fclose(qfp);
859 return FALSE;
860 }
861
07b49560 862 if (st.st_uid != geteuid() || (st.st_mode & 07777) != FileMode)
dcbc04c7
EA
863 {
864# ifdef LOG
865 if (LogLevel > 0)
866 {
867 syslog(LOG_ALERT, "%s: bogus queue file, uid=%d, mode=%o",
868 e->e_id, st.st_uid, st.st_mode);
869 }
f3d8f6d6 870# endif /* LOG */
dcbc04c7
EA
871 fclose(qfp);
872 return FALSE;
873 }
874
f8a31c8e 875 if (!lockfile(fileno(qfp), qf, LOCK_EX|LOCK_NB))
3f9ac8ea 876 {
f8a31c8e
EA
877 /* being processed by another queuer */
878 if (Verbose)
879 printf("%s: locked\n", e->e_id);
3620ad97 880# ifdef LOG
f8a31c8e
EA
881 if (LogLevel > 19)
882 syslog(LOG_DEBUG, "%s: locked", e->e_id);
f3d8f6d6 883# endif /* LOG */
3f9ac8ea 884 (void) fclose(qfp);
3620ad97 885 return FALSE;
11e3f8b5 886 }
3f9ac8ea 887
3620ad97
EA
888 /* save this lock */
889 e->e_lockfp = qfp;
890
3f9ac8ea 891 /* do basic system initialization */
a4076aed 892 initsys(e);
3f9ac8ea 893
11e3f8b5 894 FileName = qf;
560a80d9 895 LineNumber = 0;
3620ad97 896 if (Verbose)
7338e3d4 897 printf("\nRunning %s\n", e->e_id);
d2213d6c 898 ctladdr = NULL;
07b49560 899 while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
81b7d258 900 {
65b5adb6
EA
901 struct stat st;
902
795590e2 903 if (tTd(40, 4))
07b49560
EA
904 printf("+++++ %s\n", bp);
905 switch (bp[0])
81b7d258 906 {
3fbc69d6 907 case 'C': /* specify controlling user */
07b49560 908 ctladdr = setctluser(&bp[1]);
3fbc69d6
KB
909 break;
910
81b7d258 911 case 'R': /* specify recipient */
abae7b2d 912 (void) sendto(&buf[1], 1, (ADDRESS *) NULL, 0);
81b7d258
EA
913 break;
914
4e969be0 915 case 'E': /* specify error recipient */
1c7897ef 916 (void) sendtolist(&bp[1], ctladdr, &e->e_errorqueue, e);
4e969be0
EA
917 break;
918
81b7d258 919 case 'H': /* header */
07b49560 920 (void) chompheader(&bp[1], FALSE, e);
81b7d258
EA
921 break;
922
baa0c390 923 case 'M': /* message */
07b49560 924 e->e_message = newstr(&bp[1]);
baa0c390
EA
925 break;
926
81b7d258 927 case 'S': /* sender */
4a2da288 928 setsender(newstr(&bp[1]), e, NULL, TRUE);
81b7d258
EA
929 break;
930
931 case 'D': /* data file name */
07b49560 932 e->e_df = newstr(&bp[1]);
912acb74
EA
933 e->e_dfp = fopen(e->e_df, "r");
934 if (e->e_dfp == NULL)
68f7099c 935 {
7338e3d4 936 syserr("readqf: cannot open %s", e->e_df);
68f7099c
EA
937 e->e_msgsize = -1;
938 }
939 else if (fstat(fileno(e->e_dfp), &st) >= 0)
65b5adb6 940 e->e_msgsize = st.st_size;
81b7d258
EA
941 break;
942
96476cab 943 case 'T': /* init time */
07b49560 944 e->e_ctime = atol(&bp[1]);
81b7d258
EA
945 break;
946
aba51985 947 case 'P': /* message priority */
07b49560 948 e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
dd1fe05b
EA
949 break;
950
22293c34 951 case '$': /* define macro */
07b49560 952 define(bp[1], newstr(&bp[2]), e);
22293c34
EA
953 break;
954
2e3062fe
EA
955 case '\0': /* blank line; ignore */
956 break;
957
81b7d258 958 default:
2e3062fe 959 syserr("readqf(%s:%d): bad line \"%s\"", e->e_id,
07b49560 960 LineNumber, bp);
81b7d258
EA
961 break;
962 }
07b49560
EA
963
964 if (bp != buf)
965 free(bp);
81b7d258 966 }
7338e3d4
EA
967
968 FileName = NULL;
2e3062fe
EA
969
970 /*
971 ** If we haven't read any lines, this queue file is empty.
972 ** Arrange to remove it without referencing any null pointers.
973 */
974
975 if (LineNumber == 0)
976 {
977 errno = 0;
978 e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
979 }
3620ad97 980 return TRUE;
81b7d258
EA
981}
982\f/*
64912e7e
EA
983** PRINTQUEUE -- print out a representation of the mail queue
984**
985** Parameters:
986** none.
987**
988** Returns:
989** none.
990**
991** Side Effects:
992** Prints a listing of the mail queue on the standard output.
993*/
994
995printqueue()
996{
997 register WORK *w;
998 FILE *f;
0490b7d7 999 int nrequests;
64912e7e
EA
1000 char buf[MAXLINE];
1001
374579b6
EA
1002 /*
1003 ** Check for permission to print the queue
1004 */
1005
3afbc0f1 1006 if (bitset(PRIV_RESTRMAILQ, PrivacyFlags) && getuid() != 0)
374579b6
EA
1007 {
1008 struct stat st;
3afbc0f1
EA
1009# ifdef NGROUPS
1010 int n;
1011 int gidset[NGROUPS];
1012# endif
374579b6 1013
7c8b3fd4 1014 if (stat(QueueDir, &st) < 0)
374579b6
EA
1015 {
1016 syserr("Cannot stat %s", QueueDir);
1017 return;
1018 }
3afbc0f1
EA
1019# ifdef NGROUPS
1020 n = getgroups(NGROUPS, gidset);
1021 while (--n >= 0)
1022 {
1023 if (gidset[n] == st.st_gid)
1024 break;
1025 }
1026 if (n < 0)
1027# else
374579b6 1028 if (getgid() != st.st_gid)
3afbc0f1 1029# endif
374579b6
EA
1030 {
1031 usrerr("510 You are not permitted to see the queue");
1032 setstat(EX_NOPERM);
1033 return;
1034 }
1035 }
1036
64912e7e
EA
1037 /*
1038 ** Read and order the queue.
1039 */
1040
2e3062fe 1041 nrequests = orderq(TRUE);
64912e7e
EA
1042
1043 /*
1044 ** Print the work list that we have read.
1045 */
1046
1047 /* first see if there is anything */
0490b7d7 1048 if (nrequests <= 0)
64912e7e 1049 {
0490b7d7 1050 printf("Mail queue is empty\n");
64912e7e
EA
1051 return;
1052 }
1053
3620ad97 1054 CurrentLA = getla(); /* get load average */
3f9ac8ea 1055
d7b5594c 1056 printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
4e969be0
EA
1057 if (nrequests > QUEUESIZE)
1058 printf(", only %d printed", QUEUESIZE);
f4b05990 1059 if (Verbose)
fbab5052 1060 printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
f4b05990 1061 else
fbab5052 1062 printf(")\n--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
64912e7e
EA
1063 for (w = WorkQ; w != NULL; w = w->w_next)
1064 {
1065 struct stat st;
0490b7d7
EA
1066 auto time_t submittime = 0;
1067 long dfsize = -1;
baa0c390 1068 char message[MAXLINE];
2e3062fe 1069 extern bool shouldqueue();
f8a31c8e 1070 extern bool lockfile();
64912e7e 1071
560a80d9
EA
1072 f = fopen(w->w_name, "r");
1073 if (f == NULL)
1074 {
1075 errno = 0;
1076 continue;
1077 }
64912e7e 1078 printf("%7s", w->w_name + 2);
f8a31c8e 1079 if (!lockfile(fileno(f), w->w_name, LOCK_SH|LOCK_NB))
0490b7d7 1080 printf("*");
abccefc9 1081 else if (shouldqueue(w->w_pri, w->w_ctime))
2e3062fe 1082 printf("X");
0490b7d7
EA
1083 else
1084 printf(" ");
1085 errno = 0;
560a80d9 1086
baa0c390 1087 message[0] = '\0';
64912e7e
EA
1088 while (fgets(buf, sizeof buf, f) != NULL)
1089 {
22293c34
EA
1090 register int i;
1091
64912e7e
EA
1092 fixcrlf(buf, TRUE);
1093 switch (buf[0])
1094 {
baa0c390 1095 case 'M': /* error message */
22293c34
EA
1096 if ((i = strlen(&buf[1])) >= sizeof message)
1097 i = sizeof message;
1098 bcopy(&buf[1], message, i);
1099 message[i] = '\0';
baa0c390
EA
1100 break;
1101
64912e7e 1102 case 'S': /* sender name */
f4b05990 1103 if (Verbose)
4ff794a3
EA
1104 printf("%8ld %10ld %.12s %.38s", dfsize,
1105 w->w_pri, ctime(&submittime) + 4,
f4b05990
EA
1106 &buf[1]);
1107 else
1108 printf("%8ld %.16s %.45s", dfsize,
1109 ctime(&submittime), &buf[1]);
1742e60b 1110 if (message[0] != '\0')
4ff794a3 1111 printf("\n\t\t (%.60s)", message);
64912e7e 1112 break;
3620ad97 1113
3fbc69d6 1114 case 'C': /* controlling user */
d2213d6c 1115 if (Verbose)
fbab5052
EA
1116 printf("\n\t\t\t\t (---%.34s---)",
1117 &buf[1]);
3fbc69d6 1118 break;
64912e7e
EA
1119
1120 case 'R': /* recipient name */
f4b05990 1121 if (Verbose)
fbab5052 1122 printf("\n\t\t\t\t\t %.38s", &buf[1]);
f4b05990 1123 else
fbab5052 1124 printf("\n\t\t\t\t %.45s", &buf[1]);
64912e7e
EA
1125 break;
1126
1127 case 'T': /* creation time */
2e3062fe 1128 submittime = atol(&buf[1]);
0490b7d7
EA
1129 break;
1130
1131 case 'D': /* data file name */
1132 if (stat(&buf[1], &st) >= 0)
1133 dfsize = st.st_size;
64912e7e
EA
1134 break;
1135 }
1136 }
0490b7d7
EA
1137 if (submittime == (time_t) 0)
1138 printf(" (no control file)");
64912e7e 1139 printf("\n");
0e306e7f 1140 (void) fclose(f);
64912e7e
EA
1141 }
1142}
884a20cb 1143
f3d8f6d6 1144# endif /* QUEUE */
560a80d9
EA
1145\f/*
1146** QUEUENAME -- build a file name in the queue directory for this envelope.
1147**
1148** Assigns an id code if one does not already exist.
1149** This code is very careful to avoid trashing existing files
1150** under any circumstances.
560a80d9
EA
1151**
1152** Parameters:
1153** e -- envelope to build it in/from.
1154** type -- the file type, used as the first character
1155** of the file name.
1156**
1157** Returns:
1158** a pointer to the new file name (in a static buffer).
1159**
1160** Side Effects:
3620ad97
EA
1161** If no id code is already assigned, queuename will
1162** assign an id code, create a qf file, and leave a
1163** locked, open-for-write file pointer in the envelope.
560a80d9
EA
1164*/
1165
1166char *
1167queuename(e, type)
1168 register ENVELOPE *e;
1169 char type;
1170{
560a80d9 1171 static int pid = -1;
fbab5052 1172 char c0;
bc854e30
EA
1173 static char c1 = 'A';
1174 static char c2 = 'A';
fbab5052
EA
1175 time_t now;
1176 struct tm *tm;
f8a31c8e
EA
1177 static char buf[MAXNAME];
1178 extern bool lockfile();
560a80d9
EA
1179
1180 if (e->e_id == NULL)
1181 {
1182 char qf[20];
560a80d9
EA
1183
1184 /* find a unique id */
1185 if (pid != getpid())
1186 {
1187 /* new process -- start back at "AA" */
1188 pid = getpid();
fbab5052
EA
1189 now = curtime();
1190 tm = localtime(&now);
1191 c0 = 'A' + tm->tm_hour;
560a80d9
EA
1192 c1 = 'A';
1193 c2 = 'A' - 1;
1194 }
fbab5052 1195 (void) sprintf(qf, "qf%cAA%05d", c0, pid);
560a80d9
EA
1196
1197 while (c1 < '~' || c2 < 'Z')
1198 {
1199 int i;
1200
1201 if (c2 >= 'Z')
1202 {
1203 c1++;
1204 c2 = 'A' - 1;
1205 }
fbab5052
EA
1206 qf[3] = c1;
1207 qf[4] = ++c2;
560a80d9 1208 if (tTd(7, 20))
3f9ac8ea 1209 printf("queuename: trying \"%s\"\n", qf);
560a80d9 1210
3f9ac8ea 1211 i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode);
3620ad97
EA
1212 if (i < 0)
1213 {
1214 if (errno == EEXIST)
1215 continue;
1216 syserr("queuename: Cannot create \"%s\" in \"%s\"",
1217 qf, QueueDir);
1218 exit(EX_UNAVAILABLE);
1219 }
f8a31c8e 1220 if (lockfile(i, qf, LOCK_EX|LOCK_NB))
3620ad97
EA
1221 {
1222 e->e_lockfp = fdopen(i, "w");
bb09c502 1223 break;
3f9ac8ea 1224 }
3620ad97
EA
1225
1226 /* a reader got the file; abandon it and try again */
1227 (void) close(i);
560a80d9
EA
1228 }
1229 if (c1 >= '~' && c2 >= 'Z')
1230 {
1231 syserr("queuename: Cannot create \"%s\" in \"%s\"",
1232 qf, QueueDir);
1233 exit(EX_OSERR);
1234 }
1235 e->e_id = newstr(&qf[2]);
1236 define('i', e->e_id, e);
560a80d9
EA
1237 if (tTd(7, 1))
1238 printf("queuename: assigned id %s, env=%x\n", e->e_id, e);
1239# ifdef LOG
68f7099c 1240 if (LogLevel > 93)
560a80d9 1241 syslog(LOG_DEBUG, "%s: assigned id", e->e_id);
f3d8f6d6 1242# endif /* LOG */
560a80d9
EA
1243 }
1244
1245 if (type == '\0')
1246 return (NULL);
1247 (void) sprintf(buf, "%cf%s", type, e->e_id);
560a80d9
EA
1248 if (tTd(7, 2))
1249 printf("queuename: %s\n", buf);
560a80d9
EA
1250 return (buf);
1251}
1252\f/*
1253** UNLOCKQUEUE -- unlock the queue entry for a specified envelope
1254**
1255** Parameters:
1256** e -- the envelope to unlock.
1257**
1258** Returns:
1259** none
1260**
1261** Side Effects:
1262** unlocks the queue for `e'.
1263*/
1264
1265unlockqueue(e)
1266 ENVELOPE *e;
1267{
bc854e30
EA
1268 if (tTd(51, 4))
1269 printf("unlockqueue(%s)\n", e->e_id);
1270
3620ad97
EA
1271 /* if there is a lock file in the envelope, close it */
1272 if (e->e_lockfp != NULL)
bc854e30 1273 xfclose(e->e_lockfp, "unlockqueue", e->e_id);
3620ad97
EA
1274 e->e_lockfp = NULL;
1275
560a80d9 1276 /* remove the transcript */
560a80d9 1277# ifdef LOG
68f7099c 1278 if (LogLevel > 87)
560a80d9 1279 syslog(LOG_DEBUG, "%s: unlock", e->e_id);
f3d8f6d6 1280# endif /* LOG */
bc854e30 1281 if (!tTd(51, 104))
560a80d9
EA
1282 xunlink(queuename(e, 'x'));
1283
560a80d9 1284}
3fbc69d6 1285\f/*
d2213d6c 1286** SETCTLUSER -- create a controlling address
3fbc69d6 1287**
d2213d6c
EA
1288** Create a fake "address" given only a local login name; this is
1289** used as a "controlling user" for future recipient addresses.
3fbc69d6
KB
1290**
1291** Parameters:
d2213d6c 1292** user -- the user name of the controlling user.
3fbc69d6
KB
1293**
1294** Returns:
d2213d6c 1295** An address descriptor for the controlling user.
3fbc69d6
KB
1296**
1297** Side Effects:
1298** none.
1299*/
1300
d2213d6c
EA
1301ADDRESS *
1302setctluser(user)
1303 char *user;
3fbc69d6 1304{
d2213d6c 1305 register ADDRESS *a;
3fbc69d6 1306 struct passwd *pw;
3fbc69d6
KB
1307
1308 /*
d2213d6c 1309 ** See if this clears our concept of controlling user.
3fbc69d6
KB
1310 */
1311
d2213d6c 1312 if (user == NULL || *user == '\0')
4a2da288 1313 user = DefUser;
3fbc69d6
KB
1314
1315 /*
d2213d6c 1316 ** Set up addr fields for controlling user.
3fbc69d6
KB
1317 */
1318
d2213d6c
EA
1319 a = (ADDRESS *) xalloc(sizeof *a);
1320 bzero((char *) a, sizeof *a);
1321 if ((pw = getpwnam(user)) != NULL)
3fbc69d6 1322 {
3fbc69d6
KB
1323 a->q_home = newstr(pw->pw_dir);
1324 a->q_uid = pw->pw_uid;
1325 a->q_gid = pw->pw_gid;
6e99f903 1326 a->q_user = newstr(user);
3fbc69d6
KB
1327 }
1328 else
1329 {
1330 a->q_uid = DefUid;
1331 a->q_gid = DefGid;
6e99f903 1332 a->q_user = newstr(DefUser);
3fbc69d6
KB
1333 }
1334
35943e55 1335 a->q_flags |= QGOODUID|QPRIMARY; /* flag as a "ctladdr" */
d0a69620 1336 a->q_mailer = LocalMailer;
d2213d6c 1337 return a;
3fbc69d6 1338}