source: trunk/third/sendmail/src/queue.c @ 12554

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