]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/sendmail/src/queue.c
Merge sendmail 8.16.1 to HEAD: See contrib/sendmail/RELEASE_NOTES for details
[FreeBSD/FreeBSD.git] / contrib / sendmail / src / queue.c
1 /*
2  * Copyright (c) 1998-2009, 2011, 2012, 2014 Proofpoint, Inc. and its suppliers.
3  *      All rights reserved.
4  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5  * Copyright (c) 1988, 1993
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * By using this file, you agree to the terms and conditions set
9  * forth in the LICENSE file which can be found at the top level of
10  * the sendmail distribution.
11  *
12  */
13
14 #include <sendmail.h>
15 #include <sm/sem.h>
16
17 SM_RCSID("@(#)$Id: queue.c,v 8.1000 2013-11-22 20:51:56 ca Exp $")
18
19 #include <dirent.h>
20
21 # define RELEASE_QUEUE  (void) 0
22 # define ST_INODE(st)   (st).st_ino
23
24 #  define sm_file_exists(errno) ((errno) == EEXIST)
25
26 # if HASFLOCK && defined(O_EXLOCK)
27 #   define SM_OPEN_EXLOCK 1
28 #   define TF_OPEN_FLAGS (O_CREAT|O_WRONLY|O_EXCL|O_EXLOCK)
29 # else
30 #  define TF_OPEN_FLAGS (O_CREAT|O_WRONLY|O_EXCL)
31 # endif
32
33 #ifndef SM_OPEN_EXLOCK
34 # define SM_OPEN_EXLOCK 0
35 #endif
36
37 /*
38 **  Historical notes:
39 **      QF_VERSION == 4 was sendmail 8.10/8.11 without _FFR_QUEUEDELAY
40 **      QF_VERSION == 5 was sendmail 8.10/8.11 with    _FFR_QUEUEDELAY
41 **      QF_VERSION == 6 was sendmail 8.12      without _FFR_QUEUEDELAY
42 **      QF_VERSION == 7 was sendmail 8.12      with    _FFR_QUEUEDELAY
43 **      QF_VERSION == 8 is  sendmail 8.13
44 */
45
46 #define QF_VERSION      8       /* version number of this queue format */
47
48 static char     queue_letter __P((ENVELOPE *, int));
49 static bool     quarantine_queue_item __P((int, int, ENVELOPE *, char *));
50
51 /* Naming convention: qgrp: index of queue group, qg: QUEUEGROUP */
52
53 /*
54 **  Work queue.
55 */
56
57 struct work
58 {
59         char            *w_name;        /* name of control file */
60         char            *w_host;        /* name of recipient host */
61         bool            w_lock;         /* is message locked? */
62         bool            w_tooyoung;     /* is it too young to run? */
63         long            w_pri;          /* priority of message, see below */
64         time_t          w_ctime;        /* creation time */
65         time_t          w_mtime;        /* modification time */
66         int             w_qgrp;         /* queue group located in */
67         int             w_qdir;         /* queue directory located in */
68         struct work     *w_next;        /* next in queue */
69 };
70
71 typedef struct work     WORK;
72
73 static WORK     *WorkQ;         /* queue of things to be done */
74 static int      NumWorkGroups;  /* number of work groups */
75 static time_t   Current_LA_time = 0;
76
77 /* Get new load average every 30 seconds. */
78 #define GET_NEW_LA_TIME 30
79
80 #define SM_GET_LA(now)  \
81         do                                                      \
82         {                                                       \
83                 now = curtime();                                \
84                 if (Current_LA_time < now - GET_NEW_LA_TIME)    \
85                 {                                               \
86                         sm_getla();                             \
87                         Current_LA_time = now;                  \
88                 }                                               \
89         } while (0)
90
91 /*
92 **  DoQueueRun indicates that a queue run is needed.
93 **      Notice: DoQueueRun is modified in a signal handler!
94 */
95
96 static bool     volatile DoQueueRun; /* non-interrupt time queue run needed */
97
98 /*
99 **  Work group definition structure.
100 **      Each work group contains one or more queue groups. This is done
101 **      to manage the number of queue group runners active at the same time
102 **      to be within the constraints of MaxQueueChildren (if it is set).
103 **      The number of queue groups that can be run on the next work run
104 **      is kept track of. The queue groups are run in a round robin.
105 */
106
107 struct workgrp
108 {
109         int             wg_numqgrp;     /* number of queue groups in work grp */
110         int             wg_runners;     /* total runners */
111         int             wg_curqgrp;     /* current queue group */
112         QUEUEGRP        **wg_qgs;       /* array of queue groups */
113         int             wg_maxact;      /* max # of active runners */
114         time_t          wg_lowqintvl;   /* lowest queue interval */
115         int             wg_restart;     /* needs restarting? */
116         int             wg_restartcnt;  /* count of times restarted */
117 };
118
119 typedef struct workgrp WORKGRP;
120
121 static WORKGRP  volatile WorkGrp[MAXWORKGROUPS + 1];    /* work groups */
122
123 #if SM_HEAP_CHECK
124 static SM_DEBUG_T DebugLeakQ = SM_DEBUG_INITIALIZER("leak_q",
125         "@(#)$Debug: leak_q - trace memory leaks during queue processing $");
126 #endif
127
128 static void     grow_wlist __P((int, int));
129 static int      multiqueue_cache __P((char *, int, QUEUEGRP *, int, unsigned int *));
130 static int      gatherq __P((int, int, bool, bool *, bool *, int *));
131 static int      sortq __P((int));
132 static void     printctladdr __P((ADDRESS *, SM_FILE_T *));
133 static bool     readqf __P((ENVELOPE *, bool));
134 static void     restart_work_group __P((int));
135 static void     runner_work __P((ENVELOPE *, int, bool, int, int));
136 static void     schedule_queue_runs __P((bool, int, bool));
137 static char     *strrev __P((char *));
138 static ADDRESS  *setctluser __P((char *, int, ENVELOPE *));
139 #if _FFR_RHS
140 static int      sm_strshufflecmp __P((char *, char *));
141 static void     init_shuffle_alphabet __P(());
142 #endif
143
144 /*
145 **  Note: workcmpf?() don't use a prototype because it will cause a conflict
146 **  with the qsort() call (which expects something like
147 **  int (*compar)(const void *, const void *), not (WORK *, WORK *))
148 */
149
150 static int      workcmpf0();
151 static int      workcmpf1();
152 static int      workcmpf2();
153 static int      workcmpf3();
154 static int      workcmpf4();
155 static int      randi = 3;      /* index for workcmpf5() */
156 static int      workcmpf5();
157 static int      workcmpf6();
158 #if _FFR_RHS
159 static int      workcmpf7();
160 #endif
161
162 #if RANDOMSHIFT
163 # define get_rand_mod(m)        ((get_random() >> RANDOMSHIFT) % (m))
164 #else
165 # define get_rand_mod(m)        (get_random() % (m))
166 #endif
167
168 /*
169 **  File system definition.
170 **      Used to keep track of how much free space is available
171 **      on a file system in which one or more queue directories reside.
172 */
173
174 typedef struct filesys_shared   FILESYS;
175
176 struct filesys_shared
177 {
178         dev_t   fs_dev;         /* unique device id */
179         long    fs_avail;       /* number of free blocks available */
180         long    fs_blksize;     /* block size, in bytes */
181 };
182
183 /* probably kept in shared memory */
184 static FILESYS  FileSys[MAXFILESYS];    /* queue file systems */
185 static const char *FSPath[MAXFILESYS];  /* pathnames for file systems */
186
187 #if SM_CONF_SHM
188 # include <ratectrl.h>
189
190 /*
191 **  Shared memory data
192 **
193 **  Current layout:
194 **      size -- size of shared memory segment
195 **      pid -- pid of owner, should be a unique id to avoid misinterpretations
196 **              by other processes.
197 **      tag -- should be a unique id to avoid misinterpretations by others.
198 **              idea: hash over configuration data that will be stored here.
199 **      NumFileSys -- number of file systems.
200 **      FileSys -- (array of) structure for used file systems.
201 **      RSATmpCnt -- counter for number of uses of ephemeral RSA key.
202 **      [OCC -- ...]
203 **      QShm -- (array of) structure for information about queue directories.
204 **              this must be last as the size is depending on the config.
205 */
206
207 /*
208 **  Queue data in shared memory
209 */
210
211 typedef struct queue_shared     QUEUE_SHM_T;
212
213 struct queue_shared
214 {
215         int     qs_entries;     /* number of entries */
216         /* XXX more to follow? */
217 };
218
219 static void     *Pshm;          /* pointer to shared memory */
220 static FILESYS  *PtrFileSys;    /* pointer to queue file system array */
221 int             ShmId = SM_SHM_NO_ID;   /* shared memory id */
222 static QUEUE_SHM_T      *QShm;          /* pointer to shared queue data */
223 static size_t shms;
224
225 # define SHM_OFF_PID(p) (((char *) (p)) + sizeof(int))
226 # define SHM_OFF_TAG(p) (((char *) (p)) + sizeof(pid_t) + sizeof(int))
227 # define SHM_OFF_HEAD   (sizeof(pid_t) + sizeof(int) * 2)
228
229 /* how to access FileSys */
230 # define FILE_SYS(i)    (PtrFileSys[i])
231
232 /* first entry is a tag, for now just the size */
233 # define OFF_FILE_SYS(p)        (((char *) (p)) + SHM_OFF_HEAD)
234
235 /* offset for PNumFileSys */
236 # define OFF_NUM_FILE_SYS(p)    (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys))
237
238 /* offset for PRSATmpCnt */
239 # define OFF_RSA_TMP_CNT(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int))
240 int     *PRSATmpCnt;
241
242 # if _FFR_OCC
243 #  define OFF_OCC_SHM(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2)
244 #  define OCC_SIZE (sizeof(CHash_T) * CPMHSIZE)
245 static CHash_T *occ = NULL;
246 # else
247 #  define OCC_SIZE 0
248 # endif
249
250 /* offset for queue_shm */
251 # define OFF_QUEUE_SHM(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2 + OCC_SIZE)
252
253 # define QSHM_ENTRIES(i)        QShm[i].qs_entries
254
255 /* basic size of shared memory segment */
256 # define SM_T_SIZE      (SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2 + OCC_SIZE)
257
258 static unsigned int     hash_q __P((char *, unsigned int));
259
260 /*
261 **  HASH_Q -- simple hash function
262 **
263 **      Parameters:
264 **              p -- string to hash.
265 **              h -- hash start value (from previous run).
266 **
267 **      Returns:
268 **              hash value.
269 */
270
271 static unsigned int
272 hash_q(p, h)
273         char *p;
274         unsigned int h;
275 {
276         int c, d;
277
278         while (*p != '\0')
279         {
280                 d = *p++;
281                 c = d;
282                 c ^= c<<6;
283                 h += (c<<11) ^ (c>>1);
284                 h ^= (d<<14) + (d<<7) + (d<<4) + d;
285         }
286         return h;
287 }
288
289 #else /* SM_CONF_SHM */
290 # define FILE_SYS(i)    FileSys[i]
291 #endif /* SM_CONF_SHM */
292
293 /* access to the various components of file system data */
294 #define FILE_SYS_NAME(i)        FSPath[i]
295 #define FILE_SYS_AVAIL(i)       FILE_SYS(i).fs_avail
296 #define FILE_SYS_BLKSIZE(i)     FILE_SYS(i).fs_blksize
297 #define FILE_SYS_DEV(i) FILE_SYS(i).fs_dev
298
299
300 /*
301 **  Current qf file field assignments:
302 **
303 **      A       AUTH= parameter
304 **      B       body type
305 **      C       controlling user
306 **      D       data file name (obsolete)
307 **      d       data file directory name (added in 8.12)
308 **      E       error recipient
309 **      F       flag bits
310 **      H       header
311 **      I       data file's inode number
312 **      K       time of last delivery attempt
313 **      L       Solaris Content-Length: header (obsolete)
314 **      M       message
315 **      N       number of delivery attempts
316 **      P       message priority
317 **      q       quarantine reason
318 **      Q       original recipient (ORCPT=)
319 **      r       final recipient (Final-Recipient: DSN field)
320 **      R       recipient
321 **      S       sender
322 **      T       init time
323 **      V       queue file version
324 **      X       free (was: character set if _FFR_SAVE_CHARSET)
325 **      Z       original envelope id from ESMTP
326 **      !       deliver by (added in 8.12)
327 **      $       define macro
328 **      .       terminate file
329 */
330
331 /*
332 **  QUEUEUP -- queue a message up for future transmission.
333 **
334 **      Parameters:
335 **              e -- the envelope to queue up.
336 **              announce -- if true, tell when you are queueing up.
337 **              msync -- if true, then fsync() if SuperSafe interactive mode.
338 **
339 **      Returns:
340 **              none.
341 **
342 **      Side Effects:
343 **              The current request is saved in a control file.
344 **              The queue file is left locked.
345 */
346
347 void
348 queueup(e, announce, msync)
349         register ENVELOPE *e;
350         bool announce;
351         bool msync;
352 {
353         register SM_FILE_T *tfp;
354         register HDR *h;
355         register ADDRESS *q;
356         int tfd = -1;
357         int i;
358         bool newid;
359         register char *p;
360         MAILER nullmailer;
361         MCI mcibuf;
362         char qf[MAXPATHLEN];
363         char tf[MAXPATHLEN];
364         char df[MAXPATHLEN];
365         char buf[MAXLINE];
366
367         /*
368         **  Create control file.
369         */
370
371 #define OPEN_TF do                                                      \
372                 {                                                       \
373                         MODE_T oldumask = 0;                            \
374                                                                         \
375                         if (bitset(S_IWGRP, QueueFileMode))             \
376                                 oldumask = umask(002);                  \
377                         tfd = open(tf, TF_OPEN_FLAGS, QueueFileMode);   \
378                         if (bitset(S_IWGRP, QueueFileMode))             \
379                                 (void) umask(oldumask);                 \
380                 } while (0)
381
382
383         newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags);
384         (void) sm_strlcpy(tf, queuename(e, NEWQFL_LETTER), sizeof(tf));
385         tfp = e->e_lockfp;
386         if (tfp == NULL && newid)
387         {
388                 /*
389                 **  open qf file directly: this will give an error if the file
390                 **  already exists and hence prevent problems if a queue-id
391                 **  is reused (e.g., because the clock is set back).
392                 */
393
394                 (void) sm_strlcpy(tf, queuename(e, ANYQFL_LETTER), sizeof(tf));
395                 OPEN_TF;
396                 if (tfd < 0 ||
397 #if !SM_OPEN_EXLOCK
398                     !lockfile(tfd, tf, NULL, LOCK_EX|LOCK_NB) ||
399 #endif
400                     (tfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
401                                          (void *) &tfd, SM_IO_WRONLY,
402                                          NULL)) == NULL)
403                 {
404                         int save_errno = errno;
405
406                         printopenfds(true);
407                         errno = save_errno;
408                         syserr("!queueup: cannot create queue file %s, euid=%ld, fd=%d, fp=%p",
409                                 tf, (long) geteuid(), tfd, (void *)tfp);
410                         /* NOTREACHED */
411                 }
412                 e->e_lockfp = tfp;
413                 upd_qs(e, 1, 0, "queueup");
414         }
415
416         /* if newid, write the queue file directly (instead of temp file) */
417         if (!newid)
418         {
419                 /* get a locked tf file */
420                 for (i = 0; i < 128; i++)
421                 {
422                         if (tfd < 0)
423                         {
424                                 OPEN_TF;
425                                 if (tfd < 0)
426                                 {
427                                         if (errno != EEXIST)
428                                                 break;
429                                         if (LogLevel > 0 && (i % 32) == 0)
430                                                 sm_syslog(LOG_ALERT, e->e_id,
431                                                           "queueup: cannot create %s, euid=%ld: %s",
432                                                           tf, (long) geteuid(),
433                                                           sm_errstring(errno));
434                                 }
435 #if SM_OPEN_EXLOCK
436                                 else
437                                         break;
438 #endif
439                         }
440                         if (tfd >= 0)
441                         {
442 #if SM_OPEN_EXLOCK
443                                 /* file is locked by open() */
444                                 break;
445 #else
446                                 if (lockfile(tfd, tf, NULL, LOCK_EX|LOCK_NB))
447                                         break;
448                                 else
449 #endif
450                                 if (LogLevel > 0 && (i % 32) == 0)
451                                         sm_syslog(LOG_ALERT, e->e_id,
452                                                   "queueup: cannot lock %s: %s",
453                                                   tf, sm_errstring(errno));
454                                 if ((i % 32) == 31)
455                                 {
456                                         (void) close(tfd);
457                                         tfd = -1;
458                                 }
459                         }
460
461                         if ((i % 32) == 31)
462                         {
463                                 /* save the old temp file away */
464                                 (void) rename(tf, queuename(e, TEMPQF_LETTER));
465                         }
466                         else
467                                 (void) sleep(i % 32);
468                 }
469                 if (tfd < 0 || (tfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
470                                                  (void *) &tfd, SM_IO_WRONLY_B,
471                                                  NULL)) == NULL)
472                 {
473                         int save_errno = errno;
474
475                         printopenfds(true);
476                         errno = save_errno;
477                         syserr("!queueup: cannot create queue temp file %s, uid=%ld",
478                                 tf, (long) geteuid());
479                 }
480         }
481
482         if (tTd(40, 1))
483                 sm_dprintf("\n>>>>> queueing %s/%s%s >>>>>\n",
484                            qid_printqueue(e->e_qgrp, e->e_qdir),
485                            queuename(e, ANYQFL_LETTER),
486                            newid ? " (new id)" : "");
487         if (tTd(40, 3))
488         {
489                 sm_dprintf("  e_flags=");
490                 printenvflags(e);
491         }
492         if (tTd(40, 32))
493         {
494                 sm_dprintf("  sendq=");
495                 printaddr(sm_debug_file(), e->e_sendqueue, true);
496         }
497         if (tTd(40, 9))
498         {
499                 sm_dprintf("  tfp=");
500                 dumpfd(sm_io_getinfo(tfp, SM_IO_WHAT_FD, NULL), true, false);
501                 sm_dprintf("  lockfp=");
502                 if (e->e_lockfp == NULL)
503                         sm_dprintf("NULL\n");
504                 else
505                         dumpfd(sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, NULL),
506                                true, false);
507         }
508
509         /*
510         **  If there is no data file yet, create one.
511         */
512
513         (void) sm_strlcpy(df, queuename(e, DATAFL_LETTER), sizeof(df));
514         if (bitset(EF_HAS_DF, e->e_flags))
515         {
516                 if (e->e_dfp != NULL &&
517                     SuperSafe != SAFE_REALLY &&
518                     SuperSafe != SAFE_REALLY_POSTMILTER &&
519                     sm_io_setinfo(e->e_dfp, SM_BF_COMMIT, NULL) < 0 &&
520                     errno != EINVAL)
521                 {
522                         syserr("!queueup: cannot commit data file %s, uid=%ld",
523                                queuename(e, DATAFL_LETTER), (long) geteuid());
524                 }
525                 if (e->e_dfp != NULL &&
526                     SuperSafe == SAFE_INTERACTIVE && msync)
527                 {
528                         if (tTd(40,32))
529                                 sm_syslog(LOG_INFO, e->e_id,
530                                           "queueup: fsync(e->e_dfp)");
531
532                         if (fsync(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD,
533                                                 NULL)) < 0)
534                         {
535                                 if (newid)
536                                         syserr("!552 Error writing data file %s",
537                                                df);
538                                 else
539                                         syserr("!452 Error writing data file %s",
540                                                df);
541                         }
542                 }
543         }
544         else
545         {
546                 int dfd;
547                 MODE_T oldumask = 0;
548                 register SM_FILE_T *dfp = NULL;
549                 struct stat stbuf;
550
551                 if (e->e_dfp != NULL &&
552                     sm_io_getinfo(e->e_dfp, SM_IO_WHAT_ISTYPE, BF_FILE_TYPE))
553                         syserr("committing over bf file");
554
555                 if (bitset(S_IWGRP, QueueFileMode))
556                         oldumask = umask(002);
557                 dfd = open(df, O_WRONLY|O_CREAT|O_TRUNC|QF_O_EXTRA,
558                            QueueFileMode);
559                 if (bitset(S_IWGRP, QueueFileMode))
560                         (void) umask(oldumask);
561                 if (dfd < 0 || (dfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
562                                                  (void *) &dfd, SM_IO_WRONLY_B,
563                                                  NULL)) == NULL)
564                         syserr("!queueup: cannot create data temp file %s, uid=%ld",
565                                 df, (long) geteuid());
566                 if (fstat(dfd, &stbuf) < 0)
567                         e->e_dfino = -1;
568                 else
569                 {
570                         e->e_dfdev = stbuf.st_dev;
571                         e->e_dfino = ST_INODE(stbuf);
572                 }
573                 e->e_flags |= EF_HAS_DF;
574                 memset(&mcibuf, '\0', sizeof(mcibuf));
575                 mcibuf.mci_out = dfp;
576                 mcibuf.mci_mailer = FileMailer;
577                 (*e->e_putbody)(&mcibuf, e, NULL);
578
579                 if (SuperSafe == SAFE_REALLY ||
580                     SuperSafe == SAFE_REALLY_POSTMILTER ||
581                     (SuperSafe == SAFE_INTERACTIVE && msync))
582                 {
583                         if (tTd(40,32))
584                                 sm_syslog(LOG_INFO, e->e_id,
585                                           "queueup: fsync(dfp)");
586
587                         if (fsync(sm_io_getinfo(dfp, SM_IO_WHAT_FD, NULL)) < 0)
588                         {
589                                 if (newid)
590                                         syserr("!552 Error writing data file %s",
591                                                df);
592                                 else
593                                         syserr("!452 Error writing data file %s",
594                                                df);
595                         }
596                 }
597
598                 if (sm_io_close(dfp, SM_TIME_DEFAULT) < 0)
599                         syserr("!queueup: cannot save data temp file %s, uid=%ld",
600                                 df, (long) geteuid());
601                 e->e_putbody = putbody;
602         }
603
604         /*
605         **  Output future work requests.
606         **      Priority and creation time should be first, since
607         **      they are required by gatherq.
608         */
609
610         /* output queue version number (must be first!) */
611         (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "V%d\n", QF_VERSION);
612
613         /* output creation time */
614         (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "T%ld\n", (long) e->e_ctime);
615
616         /* output last delivery time */
617         (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "K%ld\n", (long) e->e_dtime);
618
619         /* output number of delivery attempts */
620         (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "N%d\n", e->e_ntries);
621
622         /* output message priority */
623         (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "P%ld\n", e->e_msgpriority);
624
625         /*
626         **  If data file is in a different directory than the queue file,
627         **  output a "d" record naming the directory of the data file.
628         */
629
630         if (e->e_dfqgrp != e->e_qgrp)
631         {
632                 (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "d%s\n",
633                         Queue[e->e_dfqgrp]->qg_qpaths[e->e_dfqdir].qp_name);
634         }
635
636         /* output inode number of data file */
637         if (e->e_dfino != -1)
638         {
639                 (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "I%ld/%ld/%llu\n",
640                                      (long) major(e->e_dfdev),
641                                      (long) minor(e->e_dfdev),
642                                      (ULONGLONG_T) e->e_dfino);
643         }
644
645         /* output body type */
646         if (e->e_bodytype != NULL)
647                 (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "B%s\n",
648                                      denlstring(e->e_bodytype, true, false));
649
650         /* quarantine reason */
651         if (e->e_quarmsg != NULL)
652                 (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "q%s\n",
653                                      denlstring(e->e_quarmsg, true, false));
654
655         /* message from envelope, if it exists */
656         if (e->e_message != NULL)
657                 (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "M%s\n",
658                                      denlstring(e->e_message, true, false));
659
660         /* send various flag bits through */
661         p = buf;
662         if (bitset(EF_WARNING, e->e_flags))
663                 *p++ = 'w';
664         if (bitset(EF_RESPONSE, e->e_flags))
665                 *p++ = 'r';
666         if (bitset(EF_HAS8BIT, e->e_flags))
667                 *p++ = '8';
668         if (bitset(EF_DELETE_BCC, e->e_flags))
669                 *p++ = 'b';
670         if (bitset(EF_RET_PARAM, e->e_flags))
671                 *p++ = 'd';
672         if (bitset(EF_NO_BODY_RETN, e->e_flags))
673                 *p++ = 'n';
674         if (bitset(EF_SPLIT, e->e_flags))
675                 *p++ = 's';
676 #if _FFR_EAI
677         if (e->e_smtputf8)
678                 *p++ = 'e';
679 #endif
680         *p++ = '\0';
681         if (buf[0] != '\0')
682                 (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "F%s\n", buf);
683
684         /* save $={persistentMacros} macro values */
685         queueup_macros(macid("{persistentMacros}"), tfp, e);
686
687         /* output name of sender */
688         if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags))
689                 p = e->e_sender;
690         else
691                 p = e->e_from.q_paddr;
692         (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "S%s\n",
693                              denlstring(p, true, false));
694
695         /* output ESMTP-supplied "original" information */
696         if (e->e_envid != NULL)
697                 (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "Z%s\n",
698                                      denlstring(e->e_envid, true, false));
699
700         /* output AUTH= parameter */
701         if (e->e_auth_param != NULL)
702                 (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "A%s\n",
703                                      denlstring(e->e_auth_param, true, false));
704         if (e->e_dlvr_flag != 0)
705                 (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "!%c %ld\n",
706                                      (char) e->e_dlvr_flag, e->e_deliver_by);
707
708         /* output list of recipient addresses */
709         printctladdr(NULL, NULL);
710         for (q = e->e_sendqueue; q != NULL; q = q->q_next)
711         {
712                 q->q_flags &= ~QQUEUED;
713                 if (!QS_IS_UNDELIVERED(q->q_state))
714                         continue;
715
716                 /* message for this recipient, if it exists */
717                 if (q->q_message != NULL)
718                         (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "M%s\n",
719                                              denlstring(q->q_message, true,
720                                                         false));
721
722                 printctladdr(q, tfp);
723                 if (q->q_orcpt != NULL)
724                         (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "Q%s\n",
725                                              denlstring(q->q_orcpt, true,
726                                                         false));
727                 if (q->q_finalrcpt != NULL)
728                         (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "r%s\n",
729                                              denlstring(q->q_finalrcpt, true,
730                                                         false));
731                 (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'R');
732                 if (bitset(QPRIMARY, q->q_flags))
733                         (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'P');
734                 if (bitset(QHASNOTIFY, q->q_flags))
735                         (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'N');
736                 if (bitset(QPINGONSUCCESS, q->q_flags))
737                         (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'S');
738                 if (bitset(QPINGONFAILURE, q->q_flags))
739                         (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'F');
740                 if (bitset(QPINGONDELAY, q->q_flags))
741                         (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'D');
742                 if (bitset(QINTBCC, q->q_flags))
743                         (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'B');
744                 if (q->q_alias != NULL &&
745                     bitset(QALIAS, q->q_alias->q_flags))
746                         (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'A');
747
748                 /* _FFR_RCPTFLAGS */
749                 if (bitset(QDYNMAILER, q->q_flags))
750                         (void) sm_io_putc(tfp, SM_TIME_DEFAULT, QDYNMAILFLG);
751                 (void) sm_io_putc(tfp, SM_TIME_DEFAULT, ':');
752                 (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s\n",
753                                      denlstring(q->q_paddr, true, false));
754                 if (announce)
755                 {
756                         char *tag = "queued";
757
758                         if (e->e_quarmsg != NULL)
759                                 tag = "quarantined";
760
761                         e->e_to = q->q_paddr;
762                         message("%s", tag);
763                         if (LogLevel > 8)
764                                 logdelivery(q->q_mailer, NULL, q->q_status,
765                                             tag, NULL, (time_t) 0, e, q, EX_OK);
766                         e->e_to = NULL;
767                 }
768
769                 /*
770                 **  This is only "valid" when the msg is safely in the queue,
771                 **  i.e., EF_INQUEUE needs to be set.
772                 */
773
774                 q->q_flags |= QQUEUED;
775
776                 if (tTd(40, 1))
777                 {
778                         sm_dprintf("queueing ");
779                         printaddr(sm_debug_file(), q, false);
780                 }
781         }
782
783         /*
784         **  Output headers for this message.
785         **      Expand macros completely here.  Queue run will deal with
786         **      everything as absolute headers.
787         **              All headers that must be relative to the recipient
788         **              can be cracked later.
789         **      We set up a "null mailer" -- i.e., a mailer that will have
790         **      no effect on the addresses as they are output.
791         */
792
793         memset((char *) &nullmailer, '\0', sizeof(nullmailer));
794         nullmailer.m_re_rwset = nullmailer.m_rh_rwset =
795                         nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1;
796         nullmailer.m_eol = "\n";
797         memset(&mcibuf, '\0', sizeof(mcibuf));
798         mcibuf.mci_mailer = &nullmailer;
799         mcibuf.mci_out = tfp;
800
801         macdefine(&e->e_macro, A_PERM, 'g', "\201f");
802         for (h = e->e_header; h != NULL; h = h->h_link)
803         {
804                 if (h->h_value == NULL)
805                         continue;
806
807                 /* don't output resent headers on non-resent messages */
808                 if (bitset(H_RESENT, h->h_flags) &&
809                     !bitset(EF_RESENT, e->e_flags))
810                         continue;
811
812                 /* expand macros; if null, don't output header at all */
813                 if (bitset(H_DEFAULT, h->h_flags))
814                 {
815                         (void) expand(h->h_value, buf, sizeof(buf), e);
816                         if (buf[0] == '\0')
817                                 continue;
818                         if (buf[0] == ' ' && buf[1] == '\0')
819                                 continue;
820                 }
821
822                 /* output this header */
823                 (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "H?");
824
825                 /* output conditional macro if present */
826                 if (h->h_macro != '\0')
827                 {
828                         if (bitset(0200, h->h_macro))
829                                 (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT,
830                                                      "${%s}",
831                                                       macname(bitidx(h->h_macro)));
832                         else
833                                 (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT,
834                                                      "$%c", h->h_macro);
835                 }
836                 else if (!bitzerop(h->h_mflags) &&
837                          bitset(H_CHECK|H_ACHECK, h->h_flags))
838                 {
839                         int j;
840
841                         /* if conditional, output the set of conditions */
842                         for (j = '\0'; j <= '\177'; j++)
843                                 if (bitnset(j, h->h_mflags))
844                                         (void) sm_io_putc(tfp, SM_TIME_DEFAULT,
845                                                           j);
846                 }
847                 (void) sm_io_putc(tfp, SM_TIME_DEFAULT, '?');
848
849                 /* output the header: expand macros, convert addresses */
850                 if (bitset(H_DEFAULT, h->h_flags) &&
851                     !bitset(H_BINDLATE, h->h_flags))
852                 {
853                         (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s:%s\n",
854                                              h->h_field,
855                                              denlstring(buf, false, true));
856                 }
857                 else if (bitset(H_FROM|H_RCPT, h->h_flags) &&
858                          !bitset(H_BINDLATE, h->h_flags))
859                 {
860                         bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
861                         SM_FILE_T *savetrace = TrafficLogFile;
862
863                         TrafficLogFile = NULL;
864
865                         if (bitset(H_FROM, h->h_flags))
866                                 oldstyle = false;
867                         commaize(h, h->h_value, oldstyle, &mcibuf, e,
868                                  PXLF_HEADER);
869
870                         TrafficLogFile = savetrace;
871                 }
872                 else
873                 {
874                         (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s:%s\n",
875                                              h->h_field,
876                                              denlstring(h->h_value, false,
877                                                         true));
878                 }
879         }
880
881         /*
882         **  Clean up.
883         **
884         **      Write a terminator record -- this is to prevent
885         **      scurrilous crackers from appending any data.
886         */
887
888         (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, ".\n");
889
890         if (sm_io_flush(tfp, SM_TIME_DEFAULT) != 0 ||
891             ((SuperSafe == SAFE_REALLY ||
892               SuperSafe == SAFE_REALLY_POSTMILTER ||
893               (SuperSafe == SAFE_INTERACTIVE && msync)) &&
894              fsync(sm_io_getinfo(tfp, SM_IO_WHAT_FD, NULL)) < 0) ||
895             sm_io_error(tfp))
896         {
897                 if (newid)
898                         syserr("!552 Error writing control file %s", tf);
899                 else
900                         syserr("!452 Error writing control file %s", tf);
901         }
902
903         if (!newid)
904         {
905                 char new = queue_letter(e, ANYQFL_LETTER);
906
907                 /* rename (locked) tf to be (locked) [qh]f */
908                 (void) sm_strlcpy(qf, queuename(e, ANYQFL_LETTER),
909                                   sizeof(qf));
910                 if (rename(tf, qf) < 0)
911                         syserr("cannot rename(%s, %s), uid=%ld",
912                                 tf, qf, (long) geteuid());
913                 else
914                 {
915                         /*
916                         **  Check if type has changed and only
917                         **  remove the old item if the rename above
918                         **  succeeded.
919                         */
920
921                         if (e->e_qfletter != '\0' &&
922                             e->e_qfletter != new)
923                         {
924                                 if (tTd(40, 5))
925                                 {
926                                         sm_dprintf("type changed from %c to %c\n",
927                                                    e->e_qfletter, new);
928                                 }
929
930                                 if (unlink(queuename(e, e->e_qfletter)) < 0)
931                                 {
932                                         /* XXX: something more drastic? */
933                                         if (LogLevel > 0)
934                                                 sm_syslog(LOG_ERR, e->e_id,
935                                                           "queueup: unlink(%s) failed: %s",
936                                                           queuename(e, e->e_qfletter),
937                                                           sm_errstring(errno));
938                                 }
939                         }
940                 }
941                 e->e_qfletter = new;
942
943                 /*
944                 **  fsync() after renaming to make sure metadata is
945                 **  written to disk on filesystems in which renames are
946                 **  not guaranteed.
947                 */
948
949                 if (SuperSafe != SAFE_NO)
950                 {
951                         /* for softupdates */
952                         if (tfd >= 0 && fsync(tfd) < 0)
953                         {
954                                 syserr("!queueup: cannot fsync queue temp file %s",
955                                        tf);
956                         }
957                         SYNC_DIR(qf, true);
958                 }
959
960                 /* close and unlock old (locked) queue file */
961                 if (e->e_lockfp != NULL)
962                         (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT);
963                 e->e_lockfp = tfp;
964
965                 /* save log info */
966                 if (LogLevel > 79)
967                         sm_syslog(LOG_DEBUG, e->e_id, "queueup %s", qf);
968         }
969         else
970         {
971                 /* save log info */
972                 if (LogLevel > 79)
973                         sm_syslog(LOG_DEBUG, e->e_id, "queueup %s", tf);
974
975                 e->e_qfletter = queue_letter(e, ANYQFL_LETTER);
976         }
977
978         errno = 0;
979         e->e_flags |= EF_INQUEUE;
980
981         if (tTd(40, 1))
982                 sm_dprintf("<<<<< done queueing %s <<<<<\n\n", e->e_id);
983         return;
984 }
985
986 /*
987 **  PRINTCTLADDR -- print control address to file.
988 **
989 **      Parameters:
990 **              a -- address.
991 **              tfp -- file pointer.
992 **
993 **      Returns:
994 **              none.
995 **
996 **      Side Effects:
997 **              The control address (if changed) is printed to the file.
998 **              The last control address and uid are saved.
999 */
1000
1001 static void
1002 printctladdr(a, tfp)
1003         register ADDRESS *a;
1004         SM_FILE_T *tfp;
1005 {
1006         char *user;
1007         register ADDRESS *q;
1008         uid_t uid;
1009         gid_t gid;
1010         static ADDRESS *lastctladdr = NULL;
1011         static uid_t lastuid;
1012
1013         /* initialization */
1014         if (a == NULL || a->q_alias == NULL || tfp == NULL)
1015         {
1016                 if (lastctladdr != NULL && tfp != NULL)
1017                         (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "C\n");
1018                 lastctladdr = NULL;
1019                 lastuid = 0;
1020                 return;
1021         }
1022
1023         /* find the active uid */
1024         q = getctladdr(a);
1025         if (q == NULL)
1026         {
1027                 user = NULL;
1028                 uid = 0;
1029                 gid = 0;
1030         }
1031         else
1032         {
1033                 user = q->q_ruser != NULL ? q->q_ruser : q->q_user;
1034                 uid = q->q_uid;
1035                 gid = q->q_gid;
1036         }
1037         a = a->q_alias;
1038
1039         /* check to see if this is the same as last time */
1040         if (lastctladdr != NULL && uid == lastuid &&
1041             strcmp(lastctladdr->q_paddr, a->q_paddr) == 0)
1042                 return;
1043         lastuid = uid;
1044         lastctladdr = a;
1045
1046         if (uid == 0 || user == NULL || user[0] == '\0')
1047                 (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "C");
1048         else
1049                 (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "C%s:%ld:%ld",
1050                                      denlstring(user, true, false), (long) uid,
1051                                      (long) gid);
1052         (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, ":%s\n",
1053                              denlstring(a->q_paddr, true, false));
1054 }
1055
1056 /*
1057 **  RUNNERS_SIGTERM -- propagate a SIGTERM to queue runner process
1058 **
1059 **      This propagates the signal to the child processes that are queue
1060 **      runners. This is for a queue runner "cleanup". After all of the
1061 **      child queue runner processes are signaled (it should be SIGTERM
1062 **      being the sig) then the old signal handler (Oldsh) is called
1063 **      to handle any cleanup set for this process (provided it is not
1064 **      SIG_DFL or SIG_IGN). The signal may not be handled immediately
1065 **      if the BlockOldsh flag is set. If the current process doesn't
1066 **      have a parent then handle the signal immediately, regardless of
1067 **      BlockOldsh.
1068 **
1069 **      Parameters:
1070 **              sig -- the signal number being sent
1071 **
1072 **      Returns:
1073 **              none.
1074 **
1075 **      Side Effects:
1076 **              Sets the NoMoreRunners boolean to true to stop more runners
1077 **              from being started in runqueue().
1078 **
1079 **      NOTE:   THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
1080 **              ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
1081 **              DOING.
1082 */
1083
1084 static bool             volatile NoMoreRunners = false;
1085 static sigfunc_t        Oldsh_term = SIG_DFL;
1086 static sigfunc_t        Oldsh_hup = SIG_DFL;
1087 static sigfunc_t        volatile Oldsh = SIG_DFL;
1088 static bool             BlockOldsh = false;
1089 static int              volatile Oldsig = 0;
1090 static SIGFUNC_DECL     runners_sigterm __P((int));
1091 static SIGFUNC_DECL     runners_sighup __P((int));
1092
1093 static SIGFUNC_DECL
1094 runners_sigterm(sig)
1095         int sig;
1096 {
1097         int save_errno = errno;
1098
1099         FIX_SYSV_SIGNAL(sig, runners_sigterm);
1100         errno = save_errno;
1101         CHECK_CRITICAL(sig);
1102         NoMoreRunners = true;
1103         Oldsh = Oldsh_term;
1104         Oldsig = sig;
1105         proc_list_signal(PROC_QUEUE, sig);
1106
1107         if (!BlockOldsh || getppid() <= 1)
1108         {
1109                 /* Check that a valid 'old signal handler' is callable */
1110                 if (Oldsh_term != SIG_DFL && Oldsh_term != SIG_IGN &&
1111                     Oldsh_term != runners_sigterm)
1112                         (*Oldsh_term)(sig);
1113         }
1114         errno = save_errno;
1115         return SIGFUNC_RETURN;
1116 }
1117 /*
1118 **  RUNNERS_SIGHUP -- propagate a SIGHUP to queue runner process
1119 **
1120 **      This propagates the signal to the child processes that are queue
1121 **      runners. This is for a queue runner "cleanup". After all of the
1122 **      child queue runner processes are signaled (it should be SIGHUP
1123 **      being the sig) then the old signal handler (Oldsh) is called to
1124 **      handle any cleanup set for this process (provided it is not SIG_DFL
1125 **      or SIG_IGN). The signal may not be handled immediately if the
1126 **      BlockOldsh flag is set. If the current process doesn't have
1127 **      a parent then handle the signal immediately, regardless of
1128 **      BlockOldsh.
1129 **
1130 **      Parameters:
1131 **              sig -- the signal number being sent
1132 **
1133 **      Returns:
1134 **              none.
1135 **
1136 **      Side Effects:
1137 **              Sets the NoMoreRunners boolean to true to stop more runners
1138 **              from being started in runqueue().
1139 **
1140 **      NOTE:   THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
1141 **              ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
1142 **              DOING.
1143 */
1144
1145 static SIGFUNC_DECL
1146 runners_sighup(sig)
1147         int sig;
1148 {
1149         int save_errno = errno;
1150
1151         FIX_SYSV_SIGNAL(sig, runners_sighup);
1152         errno = save_errno;
1153         CHECK_CRITICAL(sig);
1154         NoMoreRunners = true;
1155         Oldsh = Oldsh_hup;
1156         Oldsig = sig;
1157         proc_list_signal(PROC_QUEUE, sig);
1158
1159         if (!BlockOldsh || getppid() <= 1)
1160         {
1161                 /* Check that a valid 'old signal handler' is callable */
1162                 if (Oldsh_hup != SIG_DFL && Oldsh_hup != SIG_IGN &&
1163                     Oldsh_hup != runners_sighup)
1164                         (*Oldsh_hup)(sig);
1165         }
1166         errno = save_errno;
1167         return SIGFUNC_RETURN;
1168 }
1169 /*
1170 **  MARK_WORK_GROUP_RESTART -- mark a work group as needing a restart
1171 **
1172 **  Sets a workgroup for restarting.
1173 **
1174 **      Parameters:
1175 **              wgrp -- the work group id to restart.
1176 **              reason -- why (signal?), -1 to turn off restart
1177 **
1178 **      Returns:
1179 **              none.
1180 **
1181 **      Side effects:
1182 **              May set global RestartWorkGroup to true.
1183 **
1184 **      NOTE:   THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
1185 **              ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
1186 **              DOING.
1187 */
1188
1189 void
1190 mark_work_group_restart(wgrp, reason)
1191         int wgrp;
1192         int reason;
1193 {
1194         if (wgrp < 0 || wgrp > NumWorkGroups)
1195                 return;
1196
1197         WorkGrp[wgrp].wg_restart = reason;
1198         if (reason >= 0)
1199                 RestartWorkGroup = true;
1200 }
1201 /*
1202 **  RESTART_MARKED_WORK_GROUPS -- restart work groups marked as needing restart
1203 **
1204 **  Restart any workgroup marked as needing a restart provided more
1205 **  runners are allowed.
1206 **
1207 **      Parameters:
1208 **              none.
1209 **
1210 **      Returns:
1211 **              none.
1212 **
1213 **      Side effects:
1214 **              Sets global RestartWorkGroup to false.
1215 */
1216
1217 void
1218 restart_marked_work_groups()
1219 {
1220         int i;
1221         int wasblocked;
1222
1223         if (NoMoreRunners)
1224                 return;
1225
1226         /* Block SIGCHLD so reapchild() doesn't mess with us */
1227         wasblocked = sm_blocksignal(SIGCHLD);
1228
1229         for (i = 0; i < NumWorkGroups; i++)
1230         {
1231                 if (WorkGrp[i].wg_restart >= 0)
1232                 {
1233                         if (LogLevel > 8)
1234                                 sm_syslog(LOG_ERR, NOQID,
1235                                           "restart queue runner=%d due to signal 0x%x",
1236                                           i, WorkGrp[i].wg_restart);
1237                         restart_work_group(i);
1238                 }
1239         }
1240         RestartWorkGroup = false;
1241
1242         if (wasblocked == 0)
1243                 (void) sm_releasesignal(SIGCHLD);
1244 }
1245 /*
1246 **  RESTART_WORK_GROUP -- restart a specific work group
1247 **
1248 **  Restart a specific workgroup provided more runners are allowed.
1249 **  If the requested work group has been restarted too many times log
1250 **  this and refuse to restart.
1251 **
1252 **      Parameters:
1253 **              wgrp -- the work group id to restart
1254 **
1255 **      Returns:
1256 **              none.
1257 **
1258 **      Side Effects:
1259 **              starts another process doing the work of wgrp
1260 */
1261
1262 #define MAX_PERSIST_RESTART     10      /* max allowed number of restarts */
1263
1264 static void
1265 restart_work_group(wgrp)
1266         int wgrp;
1267 {
1268         if (NoMoreRunners ||
1269             wgrp < 0 || wgrp > NumWorkGroups)
1270                 return;
1271
1272         WorkGrp[wgrp].wg_restart = -1;
1273         if (WorkGrp[wgrp].wg_restartcnt < MAX_PERSIST_RESTART)
1274         {
1275                 /* avoid overflow; increment here */
1276                 WorkGrp[wgrp].wg_restartcnt++;
1277                 (void) run_work_group(wgrp, RWG_FORK|RWG_PERSISTENT|RWG_RUNALL);
1278         }
1279         else
1280         {
1281                 sm_syslog(LOG_ERR, NOQID,
1282                           "ERROR: persistent queue runner=%d restarted too many times, queue runner lost",
1283                           wgrp);
1284         }
1285 }
1286 /*
1287 **  SCHEDULE_QUEUE_RUNS -- schedule the next queue run for a work group.
1288 **
1289 **      Parameters:
1290 **              runall -- schedule even if individual bit is not set.
1291 **              wgrp -- the work group id to schedule.
1292 **              didit -- the queue run was performed for this work group.
1293 **
1294 **      Returns:
1295 **              nothing
1296 */
1297
1298 #define INCR_MOD(v, m)  if (++v >= m)   \
1299                                 v = 0;  \
1300                         else
1301
1302 static void
1303 schedule_queue_runs(runall, wgrp, didit)
1304         bool runall;
1305         int wgrp;
1306         bool didit;
1307 {
1308         int qgrp, cgrp, endgrp;
1309 #if _FFR_QUEUE_SCHED_DBG
1310         time_t lastsched;
1311         bool sched;
1312 #endif
1313         time_t now;
1314         time_t minqintvl;
1315
1316         /*
1317         **  This is a bit ugly since we have to duplicate the
1318         **  code that "walks" through a work queue group.
1319         */
1320
1321         now = curtime();
1322         minqintvl = 0;
1323         cgrp = endgrp = WorkGrp[wgrp].wg_curqgrp;
1324         do
1325         {
1326                 time_t qintvl;
1327
1328 #if _FFR_QUEUE_SCHED_DBG
1329                 lastsched = 0;
1330                 sched = false;
1331 #endif
1332                 qgrp = WorkGrp[wgrp].wg_qgs[cgrp]->qg_index;
1333                 if (Queue[qgrp]->qg_queueintvl > 0)
1334                         qintvl = Queue[qgrp]->qg_queueintvl;
1335                 else if (QueueIntvl > 0)
1336                         qintvl = QueueIntvl;
1337                 else
1338                         qintvl = (time_t) 0;
1339 #if _FFR_QUEUE_SCHED_DBG
1340                 lastsched = Queue[qgrp]->qg_nextrun;
1341 #endif
1342                 if ((runall || Queue[qgrp]->qg_nextrun <= now) && qintvl > 0)
1343                 {
1344 #if _FFR_QUEUE_SCHED_DBG
1345                         sched = true;
1346 #endif
1347                         if (minqintvl == 0 || qintvl < minqintvl)
1348                                 minqintvl = qintvl;
1349
1350                         /*
1351                         **  Only set a new time if a queue run was performed
1352                         **  for this queue group.  If the queue was not run,
1353                         **  we could starve it by setting a new time on each
1354                         **  call.
1355                         */
1356
1357                         if (didit)
1358                                 Queue[qgrp]->qg_nextrun += qintvl;
1359                 }
1360 #if _FFR_QUEUE_SCHED_DBG
1361                 if (tTd(69, 10))
1362                         sm_syslog(LOG_INFO, NOQID,
1363                                 "sqr: wgrp=%d, cgrp=%d, qgrp=%d, intvl=%ld, QI=%ld, runall=%d, lastrun=%ld, nextrun=%ld, sched=%d",
1364                                 wgrp, cgrp, qgrp,
1365                                 (long) Queue[qgrp]->qg_queueintvl,
1366                                 (long) QueueIntvl, runall, (long) lastsched,
1367                                 (long) Queue[qgrp]->qg_nextrun, sched);
1368 #endif /* _FFR_QUEUE_SCHED_DBG */
1369                 INCR_MOD(cgrp, WorkGrp[wgrp].wg_numqgrp);
1370         } while (endgrp != cgrp);
1371         if (minqintvl > 0)
1372                 (void) sm_setevent(minqintvl, runqueueevent, 0);
1373 }
1374
1375 #if _FFR_QUEUE_RUN_PARANOIA
1376 /*
1377 **  CHECKQUEUERUNNER -- check whether a queue group hasn't been run.
1378 **
1379 **      Use this if events may get lost and hence queue runners may not
1380 **      be started and mail will pile up in a queue.
1381 **
1382 **      Parameters:
1383 **              none.
1384 **
1385 **      Returns:
1386 **              true if a queue run is necessary.
1387 **
1388 **      Side Effects:
1389 **              may schedule a queue run.
1390 */
1391
1392 bool
1393 checkqueuerunner()
1394 {
1395         int qgrp;
1396         time_t now, minqintvl;
1397
1398         now = curtime();
1399         minqintvl = 0;
1400         for (qgrp = 0; qgrp < NumQueue && Queue[qgrp] != NULL; qgrp++)
1401         {
1402                 time_t qintvl;
1403
1404                 if (Queue[qgrp]->qg_queueintvl > 0)
1405                         qintvl = Queue[qgrp]->qg_queueintvl;
1406                 else if (QueueIntvl > 0)
1407                         qintvl = QueueIntvl;
1408                 else
1409                         qintvl = (time_t) 0;
1410                 if (Queue[qgrp]->qg_nextrun <= now - qintvl)
1411                 {
1412                         if (minqintvl == 0 || qintvl < minqintvl)
1413                                 minqintvl = qintvl;
1414                         if (LogLevel > 1)
1415                                 sm_syslog(LOG_WARNING, NOQID,
1416                                         "checkqueuerunner: queue %d should have been run at %s, queue interval %ld",
1417                                         qgrp,
1418                                         arpadate(ctime(&Queue[qgrp]->qg_nextrun)),
1419                                         (long) qintvl);
1420                 }
1421         }
1422         if (minqintvl > 0)
1423         {
1424                 (void) sm_setevent(minqintvl, runqueueevent, 0);
1425                 return true;
1426         }
1427         return false;
1428 }
1429 #endif /* _FFR_QUEUE_RUN_PARANOIA */
1430
1431 /*
1432 **  RUNQUEUE -- run the jobs in the queue.
1433 **
1434 **      Gets the stuff out of the queue in some presumably logical
1435 **      order and processes them.
1436 **
1437 **      Parameters:
1438 **              forkflag -- true if the queue scanning should be done in
1439 **                      a child process.  We double-fork so it is not our
1440 **                      child and we don't have to clean up after it.
1441 **                      false can be ignored if we have multiple queues.
1442 **              verbose -- if true, print out status information.
1443 **              persistent -- persistent queue runner?
1444 **              runall -- run all groups or only a subset (DoQueueRun)?
1445 **
1446 **      Returns:
1447 **              true if the queue run successfully began.
1448 **
1449 **      Side Effects:
1450 **              runs things in the mail queue using run_work_group().
1451 **              maybe schedules next queue run.
1452 */
1453
1454 static ENVELOPE QueueEnvelope;          /* the queue run envelope */
1455 static time_t   LastQueueTime = 0;      /* last time a queue ID assigned */
1456 static pid_t    LastQueuePid = -1;      /* last PID which had a queue ID */
1457
1458 /* values for qp_supdirs */
1459 #define QP_NOSUB        0x0000  /* No subdirectories */
1460 #define QP_SUBDF        0x0001  /* "df" subdirectory */
1461 #define QP_SUBQF        0x0002  /* "qf" subdirectory */
1462 #define QP_SUBXF        0x0004  /* "xf" subdirectory */
1463
1464 bool
1465 runqueue(forkflag, verbose, persistent, runall)
1466         bool forkflag;
1467         bool verbose;
1468         bool persistent;
1469         bool runall;
1470 {
1471         int i;
1472         bool ret = true;
1473         static int curnum = 0;
1474         sigfunc_t cursh;
1475 #if SM_HEAP_CHECK
1476         SM_NONVOLATILE int oldgroup = 0;
1477
1478         if (sm_debug_active(&DebugLeakQ, 1))
1479         {
1480                 oldgroup = sm_heap_group();
1481                 sm_heap_newgroup();
1482                 sm_dprintf("runqueue() heap group #%d\n", sm_heap_group());
1483         }
1484 #endif /* SM_HEAP_CHECK */
1485
1486         /* queue run has been started, don't do any more this time */
1487         DoQueueRun = false;
1488
1489         /* more than one queue or more than one directory per queue */
1490         if (!forkflag && !verbose &&
1491             (WorkGrp[0].wg_qgs[0]->qg_numqueues > 1 || NumWorkGroups > 1 ||
1492              WorkGrp[0].wg_numqgrp > 1))
1493                 forkflag = true;
1494
1495         /*
1496         **  For controlling queue runners via signals sent to this process.
1497         **  Oldsh* will get called too by runners_sig* (if it is not SIG_IGN
1498         **  or SIG_DFL) to preserve cleanup behavior. Now that this process
1499         **  will have children (and perhaps grandchildren) this handler will
1500         **  be left in place. This is because this process, once it has
1501         **  finished spinning off queue runners, may go back to doing something
1502         **  else (like being a daemon). And we still want on a SIG{TERM,HUP} to
1503         **  clean up the child queue runners. Only install 'runners_sig*' once
1504         **  else we'll get stuck looping forever.
1505         */
1506
1507         cursh = sm_signal(SIGTERM, runners_sigterm);
1508         if (cursh != runners_sigterm)
1509                 Oldsh_term = cursh;
1510         cursh = sm_signal(SIGHUP, runners_sighup);
1511         if (cursh != runners_sighup)
1512                 Oldsh_hup = cursh;
1513
1514         for (i = 0; i < NumWorkGroups && !NoMoreRunners; i++)
1515         {
1516                 int rwgflags = RWG_NONE;
1517                 int wasblocked;
1518
1519                 /*
1520                 **  If MaxQueueChildren active then test whether the start
1521                 **  of the next queue group's additional queue runners (maximum)
1522                 **  will result in MaxQueueChildren being exceeded.
1523                 **
1524                 **  Note: do not use continue; even though another workgroup
1525                 **      may have fewer queue runners, this would be "unfair",
1526                 **      i.e., this work group might "starve" then.
1527                 */
1528
1529 #if _FFR_QUEUE_SCHED_DBG
1530                 if (tTd(69, 10))
1531                         sm_syslog(LOG_INFO, NOQID,
1532                                 "rq: curnum=%d, MaxQueueChildren=%d, CurRunners=%d, WorkGrp[curnum].wg_maxact=%d",
1533                                 curnum, MaxQueueChildren, CurRunners,
1534                                 WorkGrp[curnum].wg_maxact);
1535 #endif /* _FFR_QUEUE_SCHED_DBG */
1536                 if (MaxQueueChildren > 0 &&
1537                     CurRunners + WorkGrp[curnum].wg_maxact > MaxQueueChildren)
1538                         break;
1539
1540                 /*
1541                 **  Pick up where we left off (curnum), in case we
1542                 **  used up all the children last time without finishing.
1543                 **  This give a round-robin fairness to queue runs.
1544                 **
1545                 **  Increment CurRunners before calling run_work_group()
1546                 **  to avoid a "race condition" with proc_list_drop() which
1547                 **  decrements CurRunners if the queue runners terminate.
1548                 **  Notice: CurRunners is an upper limit, in some cases
1549                 **  (too few jobs in the queue) this value is larger than
1550                 **  the actual number of queue runners. The discrepancy can
1551                 **  increase if some queue runners "hang" for a long time.
1552                 */
1553
1554                 /* don't let proc_list_drop() change CurRunners */
1555                 wasblocked = sm_blocksignal(SIGCHLD);
1556                 CurRunners += WorkGrp[curnum].wg_maxact;
1557                 if (wasblocked == 0)
1558                         (void) sm_releasesignal(SIGCHLD);
1559                 if (forkflag)
1560                         rwgflags |= RWG_FORK;
1561                 if (verbose)
1562                         rwgflags |= RWG_VERBOSE;
1563                 if (persistent)
1564                         rwgflags |= RWG_PERSISTENT;
1565                 if (runall)
1566                         rwgflags |= RWG_RUNALL;
1567                 ret = run_work_group(curnum, rwgflags);
1568
1569                 /*
1570                 **  Failure means a message was printed for ETRN
1571                 **  and subsequent queues are likely to fail as well.
1572                 **  Decrement CurRunners in that case because
1573                 **  none have been started.
1574                 */
1575
1576                 if (!ret)
1577                 {
1578                         /* don't let proc_list_drop() change CurRunners */
1579                         wasblocked = sm_blocksignal(SIGCHLD);
1580                         CurRunners -= WorkGrp[curnum].wg_maxact;
1581                         CHK_CUR_RUNNERS("runqueue", curnum,
1582                                         WorkGrp[curnum].wg_maxact);
1583                         if (wasblocked == 0)
1584                                 (void) sm_releasesignal(SIGCHLD);
1585                         break;
1586                 }
1587
1588                 if (!persistent)
1589                         schedule_queue_runs(runall, curnum, true);
1590                 INCR_MOD(curnum, NumWorkGroups);
1591         }
1592
1593         /* schedule left over queue runs */
1594         if (i < NumWorkGroups && !NoMoreRunners && !persistent)
1595         {
1596                 int h;
1597
1598                 for (h = curnum; i < NumWorkGroups; i++)
1599                 {
1600                         schedule_queue_runs(runall, h, false);
1601                         INCR_MOD(h, NumWorkGroups);
1602                 }
1603         }
1604
1605
1606 #if SM_HEAP_CHECK
1607         if (sm_debug_active(&DebugLeakQ, 1))
1608                 sm_heap_setgroup(oldgroup);
1609 #endif
1610         return ret;
1611 }
1612
1613 #if _FFR_SKIP_DOMAINS
1614 /*
1615 **  SKIP_DOMAINS -- Skip 'skip' number of domains in the WorkQ.
1616 **
1617 **  Added by Stephen Frost <sfrost@snowman.net> to support
1618 **  having each runner process every N'th domain instead of
1619 **  every N'th message.
1620 **
1621 **      Parameters:
1622 **              skip -- number of domains in WorkQ to skip.
1623 **
1624 **      Returns:
1625 **              total number of messages skipped.
1626 **
1627 **      Side Effects:
1628 **              may change WorkQ
1629 */
1630
1631 static int
1632 skip_domains(skip)
1633         int skip;
1634 {
1635         int n, seqjump;
1636
1637         for (n = 0, seqjump = 0; n < skip && WorkQ != NULL; seqjump++)
1638         {
1639                 if (WorkQ->w_next != NULL)
1640                 {
1641                         if (WorkQ->w_host != NULL &&
1642                             WorkQ->w_next->w_host != NULL)
1643                         {
1644                                 if (sm_strcasecmp(WorkQ->w_host,
1645                                                 WorkQ->w_next->w_host) != 0)
1646                                         n++;
1647                         }
1648                         else
1649                         {
1650                                 if ((WorkQ->w_host != NULL &&
1651                                      WorkQ->w_next->w_host == NULL) ||
1652                                     (WorkQ->w_host == NULL &&
1653                                      WorkQ->w_next->w_host != NULL))
1654                                              n++;
1655                         }
1656                 }
1657                 WorkQ = WorkQ->w_next;
1658         }
1659         return seqjump;
1660 }
1661 #endif /* _FFR_SKIP_DOMAINS */
1662
1663 /*
1664 **  RUNNER_WORK -- have a queue runner do its work
1665 **
1666 **  Have a queue runner do its work a list of entries.
1667 **  When work isn't directly being done then this process can take a signal
1668 **  and terminate immediately (in a clean fashion of course).
1669 **  When work is directly being done, it's not to be interrupted
1670 **  immediately: the work should be allowed to finish at a clean point
1671 **  before termination (in a clean fashion of course).
1672 **
1673 **      Parameters:
1674 **              e -- envelope.
1675 **              sequenceno -- 'th process to run WorkQ.
1676 **              didfork -- did the calling process fork()?
1677 **              skip -- process only each skip'th item.
1678 **              njobs -- number of jobs in WorkQ.
1679 **
1680 **      Returns:
1681 **              none.
1682 **
1683 **      Side Effects:
1684 **              runs things in the mail queue.
1685 */
1686
1687 static void
1688 runner_work(e, sequenceno, didfork, skip, njobs)
1689         register ENVELOPE *e;
1690         int sequenceno;
1691         bool didfork;
1692         int skip;
1693         int njobs;
1694 {
1695         int n, seqjump;
1696         WORK *w;
1697         time_t now;
1698
1699         SM_GET_LA(now);
1700
1701         /*
1702         **  Here we temporarily block the second calling of the handlers.
1703         **  This allows us to handle the signal without terminating in the
1704         **  middle of direct work. If a signal does come, the test for
1705         **  NoMoreRunners will find it.
1706         */
1707
1708         BlockOldsh = true;
1709         seqjump = skip;
1710
1711         /* process them once at a time */
1712         while (WorkQ != NULL)
1713         {
1714 #if SM_HEAP_CHECK
1715                 SM_NONVOLATILE int oldgroup = 0;
1716
1717                 if (sm_debug_active(&DebugLeakQ, 1))
1718                 {
1719                         oldgroup = sm_heap_group();
1720                         sm_heap_newgroup();
1721                         sm_dprintf("run_queue_group() heap group #%d\n",
1722                                 sm_heap_group());
1723                 }
1724 #endif /* SM_HEAP_CHECK */
1725
1726                 /* do no more work */
1727                 if (NoMoreRunners)
1728                 {
1729                         /* Check that a valid signal handler is callable */
1730                         if (Oldsh != SIG_DFL && Oldsh != SIG_IGN &&
1731                             Oldsh != runners_sighup &&
1732                             Oldsh != runners_sigterm)
1733                                 (*Oldsh)(Oldsig);
1734                         break;
1735                 }
1736
1737                 w = WorkQ; /* assign current work item */
1738
1739                 /*
1740                 **  Set the head of the WorkQ to the next work item.
1741                 **  It is set 'skip' ahead (the number of parallel queue
1742                 **  runners working on WorkQ together) since each runner
1743                 **  works on every 'skip'th (N-th) item.
1744 #if _FFR_SKIP_DOMAINS
1745                 **  In the case of the BYHOST Queue Sort Order, the 'item'
1746                 **  is a domain, so we work on every 'skip'th (N-th) domain.
1747 #endif
1748                 */
1749
1750 #if _FFR_SKIP_DOMAINS
1751                 if (QueueSortOrder == QSO_BYHOST)
1752                 {
1753                         seqjump = 1;
1754                         if (WorkQ->w_next != NULL)
1755                         {
1756                                 if (WorkQ->w_host != NULL &&
1757                                     WorkQ->w_next->w_host != NULL)
1758                                 {
1759                                         if (sm_strcasecmp(WorkQ->w_host,
1760                                                         WorkQ->w_next->w_host)
1761                                                                 != 0)
1762                                                 seqjump = skip_domains(skip);
1763                                         else
1764                                                 WorkQ = WorkQ->w_next;
1765                                 }
1766                                 else
1767                                 {
1768                                         if ((WorkQ->w_host != NULL &&
1769                                              WorkQ->w_next->w_host == NULL) ||
1770                                             (WorkQ->w_host == NULL &&
1771                                              WorkQ->w_next->w_host != NULL))
1772                                                 seqjump = skip_domains(skip);
1773                                         else
1774                                                 WorkQ = WorkQ->w_next;
1775                                 }
1776                         }
1777                         else
1778                                 WorkQ = WorkQ->w_next;
1779                 }
1780                 else
1781 #endif /* _FFR_SKIP_DOMAINS */
1782                 {
1783                         for (n = 0; n < skip && WorkQ != NULL; n++)
1784                                 WorkQ = WorkQ->w_next;
1785                 }
1786
1787                 e->e_to = NULL;
1788
1789                 /*
1790                 **  Ignore jobs that are too expensive for the moment.
1791                 **
1792                 **      Get new load average every GET_NEW_LA_TIME seconds.
1793                 */
1794
1795                 SM_GET_LA(now);
1796                 if (shouldqueue(WkRecipFact, Current_LA_time))
1797                 {
1798                         char *msg = "Aborting queue run: load average too high";
1799
1800                         if (Verbose)
1801                                 message("%s", msg);
1802                         if (LogLevel > 8)
1803                                 sm_syslog(LOG_INFO, NOQID, "runqueue: %s", msg);
1804                         break;
1805                 }
1806                 if (shouldqueue(w->w_pri, w->w_ctime))
1807                 {
1808                         if (Verbose)
1809                                 message("%s", "");
1810                         if (QueueSortOrder == QSO_BYPRIORITY)
1811                         {
1812                                 if (Verbose)
1813                                         message("Skipping %s/%s (sequence %d of %d) and flushing rest of queue",
1814                                                 qid_printqueue(w->w_qgrp,
1815                                                                w->w_qdir),
1816                                                 w->w_name + 2, sequenceno,
1817                                                 njobs);
1818                                 if (LogLevel > 8)
1819                                         sm_syslog(LOG_INFO, NOQID,
1820                                                   "runqueue: Flushing queue from %s/%s (pri %ld, LA %d, %d of %d)",
1821                                                   qid_printqueue(w->w_qgrp,
1822                                                                  w->w_qdir),
1823                                                   w->w_name + 2, w->w_pri,
1824                                                   CurrentLA, sequenceno,
1825                                                   njobs);
1826                                 break;
1827                         }
1828                         else if (Verbose)
1829                                 message("Skipping %s/%s (sequence %d of %d)",
1830                                         qid_printqueue(w->w_qgrp, w->w_qdir),
1831                                         w->w_name + 2, sequenceno, njobs);
1832                 }
1833                 else
1834                 {
1835                         if (Verbose)
1836                         {
1837                                 message("%s", "");
1838                                 message("Running %s/%s (sequence %d of %d)",
1839                                         qid_printqueue(w->w_qgrp, w->w_qdir),
1840                                         w->w_name + 2, sequenceno, njobs);
1841                         }
1842                         if (didfork && MaxQueueChildren > 0)
1843                         {
1844                                 sm_blocksignal(SIGCHLD);
1845                                 (void) sm_signal(SIGCHLD, reapchild);
1846                         }
1847                         if (tTd(63, 100))
1848                                 sm_syslog(LOG_DEBUG, NOQID,
1849                                           "runqueue %s dowork(%s)",
1850                                           qid_printqueue(w->w_qgrp, w->w_qdir),
1851                                           w->w_name + 2);
1852
1853                         (void) dowork(w->w_qgrp, w->w_qdir, w->w_name + 2,
1854                                       ForkQueueRuns, false, e);
1855                         errno = 0;
1856                 }
1857                 sm_free(w->w_name); /* XXX */
1858                 if (w->w_host != NULL)
1859                         sm_free(w->w_host); /* XXX */
1860                 sm_free((char *) w); /* XXX */
1861                 sequenceno += seqjump; /* next sequence number */
1862 #if SM_HEAP_CHECK
1863                 if (sm_debug_active(&DebugLeakQ, 1))
1864                         sm_heap_setgroup(oldgroup);
1865 #endif
1866 #if _FFR_TESTS
1867                 if (tTd(76, 101))
1868                 {
1869                         int sl;
1870
1871                         sl = tTdlevel(76) - 100;
1872                         sm_dprintf("run_work_group: sleep=%d\n", sl);
1873                         sleep(sl);
1874                 }
1875 #endif
1876         }
1877
1878         BlockOldsh = false;
1879
1880         /* check the signals didn't happen during the revert */
1881         if (NoMoreRunners)
1882         {
1883                 /* Check that a valid signal handler is callable */
1884                 if (Oldsh != SIG_DFL && Oldsh != SIG_IGN &&
1885                     Oldsh != runners_sighup && Oldsh != runners_sigterm)
1886                         (*Oldsh)(Oldsig);
1887         }
1888
1889         Oldsh = SIG_DFL; /* after the NoMoreRunners check */
1890 }
1891 /*
1892 **  RUN_WORK_GROUP -- run the jobs in a queue group from a work group.
1893 **
1894 **      Gets the stuff out of the queue in some presumably logical
1895 **      order and processes them.
1896 **
1897 **      Parameters:
1898 **              wgrp -- work group to process.
1899 **              flags -- RWG_* flags
1900 **
1901 **      Returns:
1902 **              true if the queue run successfully began.
1903 **
1904 **      Side Effects:
1905 **              runs things in the mail queue.
1906 */
1907
1908 /* Minimum sleep time for persistent queue runners */
1909 #define MIN_SLEEP_TIME  5
1910
1911 bool
1912 run_work_group(wgrp, flags)
1913         int wgrp;
1914         int flags;
1915 {
1916         register ENVELOPE *e;
1917         int njobs, qdir;
1918         int sequenceno = 1;
1919         int qgrp, endgrp, h, i;
1920         time_t now;
1921         bool full, more;
1922         SM_RPOOL_T *rpool;
1923         extern ENVELOPE BlankEnvelope;
1924         extern SIGFUNC_DECL reapchild __P((int));
1925
1926         if (wgrp < 0)
1927                 return false;
1928
1929         /*
1930         **  If no work will ever be selected, don't even bother reading
1931         **  the queue.
1932         */
1933
1934         SM_GET_LA(now);
1935
1936         if (!bitset(RWG_PERSISTENT, flags) &&
1937             shouldqueue(WkRecipFact, Current_LA_time))
1938         {
1939                 char *msg = "Skipping queue run -- load average too high";
1940
1941                 if (bitset(RWG_VERBOSE, flags))
1942                         message("458 %s\n", msg);
1943                 if (LogLevel > 8)
1944                         sm_syslog(LOG_INFO, NOQID, "runqueue: %s", msg);
1945                 return false;
1946         }
1947
1948         /*
1949         **  See if we already have too many children.
1950         */
1951
1952         if (bitset(RWG_FORK, flags) &&
1953             WorkGrp[wgrp].wg_lowqintvl > 0 &&
1954             !bitset(RWG_PERSISTENT, flags) &&
1955             MaxChildren > 0 && CurChildren >= MaxChildren)
1956         {
1957                 char *msg = "Skipping queue run -- too many children";
1958
1959                 if (bitset(RWG_VERBOSE, flags))
1960                         message("458 %s (%d)\n", msg, CurChildren);
1961                 if (LogLevel > 8)
1962                         sm_syslog(LOG_INFO, NOQID, "runqueue: %s (%d)",
1963                                   msg, CurChildren);
1964                 return false;
1965         }
1966
1967         /*
1968         **  See if we want to go off and do other useful work.
1969         */
1970
1971         if (bitset(RWG_FORK, flags))
1972         {
1973                 pid_t pid;
1974
1975                 (void) sm_blocksignal(SIGCHLD);
1976                 (void) sm_signal(SIGCHLD, reapchild);
1977
1978                 pid = dofork();
1979                 if (pid == -1)
1980                 {
1981                         const char *msg = "Skipping queue run -- fork() failed";
1982                         const char *err = sm_errstring(errno);
1983
1984                         if (bitset(RWG_VERBOSE, flags))
1985                                 message("458 %s: %s\n", msg, err);
1986                         if (LogLevel > 8)
1987                                 sm_syslog(LOG_INFO, NOQID, "runqueue: %s: %s",
1988                                           msg, err);
1989                         (void) sm_releasesignal(SIGCHLD);
1990                         return false;
1991                 }
1992                 if (pid != 0)
1993                 {
1994                         /* parent -- pick up intermediate zombie */
1995                         (void) sm_blocksignal(SIGALRM);
1996
1997                         /* wgrp only used when queue runners are persistent */
1998                         proc_list_add(pid, "Queue runner", PROC_QUEUE,
1999                                       WorkGrp[wgrp].wg_maxact,
2000                                       bitset(RWG_PERSISTENT, flags) ? wgrp : -1,
2001                                       NULL);
2002                         (void) sm_releasesignal(SIGALRM);
2003                         (void) sm_releasesignal(SIGCHLD);
2004                         return true;
2005                 }
2006
2007                 /* child -- clean up signals */
2008
2009                 /* Reset global flags */
2010                 RestartRequest = NULL;
2011                 RestartWorkGroup = false;
2012                 ShutdownRequest = NULL;
2013                 PendingSignal = 0;
2014                 CurrentPid = getpid();
2015                 close_sendmail_pid();
2016
2017                 /*
2018                 **  Initialize exception stack and default exception
2019                 **  handler for child process.
2020                 */
2021
2022                 sm_exc_newthread(fatal_error);
2023                 clrcontrol();
2024                 proc_list_clear();
2025
2026                 /* Add parent process as first child item */
2027                 proc_list_add(CurrentPid, "Queue runner child process",
2028                               PROC_QUEUE_CHILD, 0, -1, NULL);
2029                 (void) sm_releasesignal(SIGCHLD);
2030                 (void) sm_signal(SIGCHLD, SIG_DFL);
2031                 (void) sm_signal(SIGHUP, SIG_DFL);
2032                 (void) sm_signal(SIGTERM, intsig);
2033         }
2034
2035         /*
2036         **  Release any resources used by the daemon code.
2037         */
2038
2039         clrdaemon();
2040
2041         /* force it to run expensive jobs */
2042         NoConnect = false;
2043
2044         /* drop privileges */
2045         if (geteuid() == (uid_t) 0)
2046                 (void) drop_privileges(false);
2047
2048         /*
2049         **  Create ourselves an envelope
2050         */
2051
2052         CurEnv = &QueueEnvelope;
2053         rpool = sm_rpool_new_x(NULL);
2054         e = newenvelope(&QueueEnvelope, CurEnv, rpool);
2055         e->e_flags = BlankEnvelope.e_flags;
2056         e->e_parent = NULL;
2057
2058         /* make sure we have disconnected from parent */
2059         if (bitset(RWG_FORK, flags))
2060         {
2061                 disconnect(1, e);
2062                 QuickAbort = false;
2063         }
2064
2065         /*
2066         **  If we are running part of the queue, always ignore stored
2067         **  host status.
2068         */
2069
2070         if (QueueLimitId != NULL || QueueLimitSender != NULL ||
2071             QueueLimitQuarantine != NULL ||
2072             QueueLimitRecipient != NULL)
2073         {
2074                 IgnoreHostStatus = true;
2075                 MinQueueAge = 0;
2076                 MaxQueueAge = 0;
2077         }
2078
2079         /*
2080         **  Here is where we choose the queue group from the work group.
2081         **  The caller of the "domorework" label must setup a new envelope.
2082         */
2083
2084         endgrp = WorkGrp[wgrp].wg_curqgrp; /* to not spin endlessly */
2085
2086   domorework:
2087
2088         /*
2089         **  Run a queue group if:
2090         **  RWG_RUNALL bit is set or the bit for this group is set.
2091         */
2092
2093         now = curtime();
2094         for (;;)
2095         {
2096                 /*
2097                 **  Find the next queue group within the work group that
2098                 **  has been marked as needing a run.
2099                 */
2100
2101                 qgrp = WorkGrp[wgrp].wg_qgs[WorkGrp[wgrp].wg_curqgrp]->qg_index;
2102                 WorkGrp[wgrp].wg_curqgrp++; /* advance */
2103                 WorkGrp[wgrp].wg_curqgrp %= WorkGrp[wgrp].wg_numqgrp; /* wrap */
2104                 if (bitset(RWG_RUNALL, flags) ||
2105                     (Queue[qgrp]->qg_nextrun <= now &&
2106                      Queue[qgrp]->qg_nextrun != (time_t) -1))
2107                         break;
2108                 if (endgrp == WorkGrp[wgrp].wg_curqgrp)
2109                 {
2110                         e->e_id = NULL;
2111                         if (bitset(RWG_FORK, flags))
2112                                 finis(true, true, ExitStat);
2113                         return true; /* we're done */
2114                 }
2115         }
2116
2117         qdir = Queue[qgrp]->qg_curnum; /* round-robin init of queue position */
2118 #if _FFR_QUEUE_SCHED_DBG
2119         if (tTd(69, 12))
2120                 sm_syslog(LOG_INFO, NOQID,
2121                         "rwg: wgrp=%d, qgrp=%d, qdir=%d, name=%s, curqgrp=%d, numgrps=%d",
2122                         wgrp, qgrp, qdir, qid_printqueue(qgrp, qdir),
2123                         WorkGrp[wgrp].wg_curqgrp, WorkGrp[wgrp].wg_numqgrp);
2124 #endif /* _FFR_QUEUE_SCHED_DBG */
2125
2126 #if HASNICE
2127         /* tweak niceness of queue runs */
2128         if (Queue[qgrp]->qg_nice > 0)
2129                 (void) nice(Queue[qgrp]->qg_nice);
2130 #endif
2131
2132         /* XXX running queue group... */
2133         sm_setproctitle(true, CurEnv, "running queue: %s",
2134                         qid_printqueue(qgrp, qdir));
2135
2136         if (LogLevel > 69 || tTd(63, 99))
2137                 sm_syslog(LOG_DEBUG, NOQID,
2138                           "runqueue %s, pid=%d, forkflag=%d",
2139                           qid_printqueue(qgrp, qdir), (int) CurrentPid,
2140                           bitset(RWG_FORK, flags));
2141
2142         /*
2143         **  Start making passes through the queue.
2144         **      First, read and sort the entire queue.
2145         **      Then, process the work in that order.
2146         **              But if you take too long, start over.
2147         */
2148
2149         for (i = 0; i < Queue[qgrp]->qg_numqueues; i++)
2150         {
2151                 (void) gatherq(qgrp, qdir, false, &full, &more, &h);
2152 #if SM_CONF_SHM
2153                 if (ShmId != SM_SHM_NO_ID)
2154                         QSHM_ENTRIES(Queue[qgrp]->qg_qpaths[qdir].qp_idx) = h;
2155 #endif
2156                 /* If there are no more items in this queue advance */
2157                 if (!more)
2158                 {
2159                         /* A round-robin advance */
2160                         qdir++;
2161                         qdir %= Queue[qgrp]->qg_numqueues;
2162                 }
2163
2164                 /* Has the WorkList reached the limit? */
2165                 if (full)
2166                         break; /* don't try to gather more */
2167         }
2168
2169         /* order the existing work requests */
2170         njobs = sortq(Queue[qgrp]->qg_maxlist);
2171         Queue[qgrp]->qg_curnum = qdir; /* update */
2172
2173
2174         if (!Verbose && bitnset(QD_FORK, Queue[qgrp]->qg_flags))
2175         {
2176                 int loop, maxrunners;
2177                 pid_t pid;
2178
2179                 /*
2180                 **  For this WorkQ we want to fork off N children (maxrunners)
2181                 **  at this point. Each child has a copy of WorkQ. Each child
2182                 **  will process every N-th item. The parent will wait for all
2183                 **  of the children to finish before moving on to the next
2184                 **  queue group within the work group. This saves us forking
2185                 **  a new runner-child for each work item.
2186                 **  It's valid for qg_maxqrun == 0 since this may be an
2187                 **  explicit "don't run this queue" setting.
2188                 */
2189
2190                 maxrunners = Queue[qgrp]->qg_maxqrun;
2191
2192                 /*
2193                 **  If no runners are configured for this group but
2194                 **  the queue is "forced" then lets use 1 runner.
2195                 */
2196
2197                 if (maxrunners == 0 && bitset(RWG_FORCE, flags))
2198                         maxrunners = 1;
2199
2200                 /* No need to have more runners then there are jobs */
2201                 if (maxrunners > njobs)
2202                         maxrunners = njobs;
2203                 for (loop = 0; loop < maxrunners; loop++)
2204                 {
2205                         /*
2206                         **  Since the delivery may happen in a child and the
2207                         **  parent does not wait, the parent may close the
2208                         **  maps thereby removing any shared memory used by
2209                         **  the map.  Therefore, close the maps now so the
2210                         **  child will dynamically open them if necessary.
2211                         */
2212
2213                         closemaps(false);
2214
2215                         pid = fork();
2216                         if (pid < 0)
2217                         {
2218                                 syserr("run_work_group: cannot fork");
2219                                 return false;
2220                         }
2221                         else if (pid > 0)
2222                         {
2223                                 /* parent -- clean out connection cache */
2224                                 mci_flush(false, NULL);
2225 #if _FFR_SKIP_DOMAINS
2226                                 if (QueueSortOrder == QSO_BYHOST)
2227                                 {
2228                                         sequenceno += skip_domains(1);
2229                                 }
2230                                 else
2231 #endif /* _FFR_SKIP_DOMAINS */
2232                                 {
2233                                         /* for the skip */
2234                                         WorkQ = WorkQ->w_next;
2235                                         sequenceno++;
2236                                 }
2237                                 proc_list_add(pid, "Queue child runner process",
2238                                               PROC_QUEUE_CHILD, 0, -1, NULL);
2239
2240                                 /* No additional work, no additional runners */
2241                                 if (WorkQ == NULL)
2242                                         break;
2243                         }
2244                         else
2245                         {
2246                                 /* child -- Reset global flags */
2247                                 RestartRequest = NULL;
2248                                 RestartWorkGroup = false;
2249                                 ShutdownRequest = NULL;
2250                                 PendingSignal = 0;
2251                                 CurrentPid = getpid();
2252                                 close_sendmail_pid();
2253
2254                                 /*
2255                                 **  Initialize exception stack and default
2256                                 **  exception handler for child process.
2257                                 **  When fork()'d the child now has a private
2258                                 **  copy of WorkQ at its current position.
2259                                 */
2260
2261                                 sm_exc_newthread(fatal_error);
2262
2263                                 /*
2264                                 **  SMTP processes (whether -bd or -bs) set
2265                                 **  SIGCHLD to reapchild to collect
2266                                 **  children status.  However, at delivery
2267                                 **  time, that status must be collected
2268                                 **  by sm_wait() to be dealt with properly
2269                                 **  (check success of delivery based
2270                                 **  on status code, etc).  Therefore, if we
2271                                 **  are an SMTP process, reset SIGCHLD
2272                                 **  back to the default so reapchild
2273                                 **  doesn't collect status before
2274                                 **  sm_wait().
2275                                 */
2276
2277                                 if (OpMode == MD_SMTP ||
2278                                     OpMode == MD_DAEMON ||
2279                                     MaxQueueChildren > 0)
2280                                 {
2281                                         proc_list_clear();
2282                                         sm_releasesignal(SIGCHLD);
2283                                         (void) sm_signal(SIGCHLD, SIG_DFL);
2284                                 }
2285
2286                                 /* child -- error messages to the transcript */
2287                                 QuickAbort = OnlyOneError = false;
2288                                 runner_work(e, sequenceno, true,
2289                                             maxrunners, njobs);
2290
2291                                 /* This child is done */
2292                                 finis(true, true, ExitStat);
2293                                 /* NOTREACHED */
2294                         }
2295                 }
2296
2297                 sm_releasesignal(SIGCHLD);
2298
2299                 /*
2300                 **  Wait until all of the runners have completed before
2301                 **  seeing if there is another queue group in the
2302                 **  work group to process.
2303                 **  XXX Future enhancement: don't wait() for all children
2304                 **  here, just go ahead and make sure that overall the number
2305                 **  of children is not exceeded.
2306                 */
2307
2308                 while (CurChildren > 0)
2309                 {
2310                         int status;
2311                         pid_t ret;
2312
2313                         while ((ret = sm_wait(&status)) <= 0)
2314                                 continue;
2315                         proc_list_drop(ret, status, NULL);
2316                 }
2317         }
2318         else if (Queue[qgrp]->qg_maxqrun > 0 || bitset(RWG_FORCE, flags))
2319         {
2320                 /*
2321                 **  When current process will not fork children to do the work,
2322                 **  it will do the work itself. The 'skip' will be 1 since
2323                 **  there are no child runners to divide the work across.
2324                 */
2325
2326                 runner_work(e, sequenceno, false, 1, njobs);
2327         }
2328
2329         /* free memory allocated by newenvelope() above */
2330         sm_rpool_free(rpool);
2331         QueueEnvelope.e_rpool = NULL;
2332
2333         /* Are there still more queues in the work group to process? */
2334         if (endgrp != WorkGrp[wgrp].wg_curqgrp)
2335         {
2336                 rpool = sm_rpool_new_x(NULL);
2337                 e = newenvelope(&QueueEnvelope, CurEnv, rpool);
2338                 e->e_flags = BlankEnvelope.e_flags;
2339                 goto domorework;
2340         }
2341
2342         /* No more queues in work group to process. Now check persistent. */
2343         if (bitset(RWG_PERSISTENT, flags))
2344         {
2345                 sequenceno = 1;
2346                 sm_setproctitle(true, NULL, "running queue: %s",
2347                                 qid_printqueue(qgrp, qdir));
2348
2349                 /*
2350                 **  close bogus maps, i.e., maps which caused a tempfail,
2351                 **      so we get fresh map connections on the next lookup.
2352                 **  closemaps() is also called when children are started.
2353                 */
2354
2355                 closemaps(true);
2356
2357                 /* Close any cached connections. */
2358                 mci_flush(true, NULL);
2359
2360                 /* Clean out expired related entries. */
2361                 rmexpstab();
2362
2363 #if NAMED_BIND
2364                 /* Update MX records for FallbackMX. */
2365                 if (FallbackMX != NULL)
2366                         (void) getfallbackmxrr(FallbackMX);
2367 #endif
2368
2369 #if USERDB
2370                 /* close UserDatabase */
2371                 _udbx_close();
2372 #endif
2373
2374 #if SM_HEAP_CHECK
2375                 if (sm_debug_active(&SmHeapCheck, 2)
2376                     && access("memdump", F_OK) == 0
2377                    )
2378                 {
2379                         SM_FILE_T *out;
2380
2381                         remove("memdump");
2382                         out = sm_io_open(SmFtStdio, SM_TIME_DEFAULT,
2383                                          "memdump.out", SM_IO_APPEND, NULL);
2384                         if (out != NULL)
2385                         {
2386                                 (void) sm_io_fprintf(out, SM_TIME_DEFAULT, "----------------------\n");
2387                                 sm_heap_report(out,
2388                                         sm_debug_level(&SmHeapCheck) - 1);
2389                                 (void) sm_io_close(out, SM_TIME_DEFAULT);
2390                         }
2391                 }
2392 #endif /* SM_HEAP_CHECK */
2393
2394                 /* let me rest for a second to catch my breath */
2395                 if (njobs == 0 && WorkGrp[wgrp].wg_lowqintvl < MIN_SLEEP_TIME)
2396                         sleep(MIN_SLEEP_TIME);
2397                 else if (WorkGrp[wgrp].wg_lowqintvl <= 0)
2398                         sleep(QueueIntvl > 0 ? QueueIntvl : MIN_SLEEP_TIME);
2399                 else
2400                         sleep(WorkGrp[wgrp].wg_lowqintvl);
2401
2402                 /*
2403                 **  Get the LA outside the WorkQ loop if necessary.
2404                 **  In a persistent queue runner the code is repeated over
2405                 **  and over but gatherq() may ignore entries due to
2406                 **  shouldqueue() (do we really have to do this twice?).
2407                 **  Hence the queue runners would just idle around when once
2408                 **  CurrentLA caused all entries in a queue to be ignored.
2409                 */
2410
2411                 if (njobs == 0)
2412                         SM_GET_LA(now);
2413                 rpool = sm_rpool_new_x(NULL);
2414                 e = newenvelope(&QueueEnvelope, CurEnv, rpool);
2415                 e->e_flags = BlankEnvelope.e_flags;
2416                 goto domorework;
2417         }
2418
2419         /* exit without the usual cleanup */
2420         e->e_id = NULL;
2421         if (bitset(RWG_FORK, flags))
2422                 finis(true, true, ExitStat);
2423         /* NOTREACHED */
2424         return true;
2425 }
2426
2427 /*
2428 **  DOQUEUERUN -- do a queue run?
2429 */
2430
2431 bool
2432 doqueuerun()
2433 {
2434         return DoQueueRun;
2435 }
2436
2437 /*
2438 **  RUNQUEUEEVENT -- Sets a flag to indicate that a queue run should be done.
2439 **
2440 **      Parameters:
2441 **              none.
2442 **
2443 **      Returns:
2444 **              none.
2445 **
2446 **      Side Effects:
2447 **              The invocation of this function via an alarm may interrupt
2448 **              a set of actions. Thus errno may be set in that context.
2449 **              We need to restore errno at the end of this function to ensure
2450 **              that any work done here that sets errno doesn't return a
2451 **              misleading/false errno value. Errno may be EINTR upon entry to
2452 **              this function because of non-restartable/continuable system
2453 **              API was active. Iff this is true we will override errno as
2454 **              a timeout (as a more accurate error message).
2455 **
2456 **      NOTE:   THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
2457 **              ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
2458 **              DOING.
2459 */
2460
2461 void
2462 runqueueevent(ignore)
2463         int ignore;
2464 {
2465         int save_errno = errno;
2466
2467         /*
2468         **  Set the general bit that we want a queue run,
2469         **  tested in doqueuerun()
2470         */
2471
2472         DoQueueRun = true;
2473 #if _FFR_QUEUE_SCHED_DBG
2474         if (tTd(69, 10))
2475                 sm_syslog(LOG_INFO, NOQID, "rqe: done");
2476 #endif
2477
2478         errno = save_errno;
2479         if (errno == EINTR)
2480                 errno = ETIMEDOUT;
2481 }
2482 /*
2483 **  GATHERQ -- gather messages from the message queue(s) the work queue.
2484 **
2485 **      Parameters:
2486 **              qgrp -- the index of the queue group.
2487 **              qdir -- the index of the queue directory.
2488 **              doall -- if set, include everything in the queue (even
2489 **                      the jobs that cannot be run because the load
2490 **                      average is too high, or MaxQueueRun is reached).
2491 **                      Otherwise, exclude those jobs.
2492 **              full -- (optional) to be set 'true' if WorkList is full
2493 **              more -- (optional) to be set 'true' if there are still more
2494 **                      messages in this queue not added to WorkList
2495 **              pnentries -- (optional) total nuber of entries in queue
2496 **
2497 **      Returns:
2498 **              The number of request in the queue (not necessarily
2499 **              the number of requests in WorkList however).
2500 **
2501 **      Side Effects:
2502 **              prepares available work into WorkList
2503 */
2504
2505 #define NEED_P          0001    /* 'P': priority */
2506 #define NEED_T          0002    /* 'T': time */
2507 #define NEED_R          0004    /* 'R': recipient */
2508 #define NEED_S          0010    /* 'S': sender */
2509 #define NEED_H          0020    /* host */
2510 #define HAS_QUARANTINE  0040    /* has an unexpected 'q' line */
2511 #define NEED_QUARANTINE 0100    /* 'q': reason */
2512
2513 static WORK     *WorkList = NULL;       /* list of unsort work */
2514 static int      WorkListSize = 0;       /* current max size of WorkList */
2515 static int      WorkListCount = 0;      /* # of work items in WorkList */
2516
2517 static int
2518 gatherq(qgrp, qdir, doall, full, more, pnentries)
2519         int qgrp;
2520         int qdir;
2521         bool doall;
2522         bool *full;
2523         bool *more;
2524         int *pnentries;
2525 {
2526         register struct dirent *d;
2527         register WORK *w;
2528         register char *p;
2529         DIR *f;
2530         int i, num_ent, wn, nentries;
2531         QUEUE_CHAR *check;
2532         char qd[MAXPATHLEN];
2533         char qf[MAXPATHLEN];
2534
2535         wn = WorkListCount - 1;
2536         num_ent = 0;
2537         nentries = 0;
2538         if (qdir == NOQDIR)
2539                 (void) sm_strlcpy(qd, ".", sizeof(qd));
2540         else
2541                 (void) sm_strlcpyn(qd, sizeof(qd), 2,
2542                         Queue[qgrp]->qg_qpaths[qdir].qp_name,
2543                         (bitset(QP_SUBQF,
2544                                 Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
2545                                         ? "/qf" : ""));
2546
2547         if (tTd(41, 1))
2548         {
2549                 sm_dprintf("gatherq: %s\n", qd);
2550
2551                 check = QueueLimitId;
2552                 while (check != NULL)
2553                 {
2554                         sm_dprintf("\tQueueLimitId = %s%s\n",
2555                                 check->queue_negate ? "!" : "",
2556                                 check->queue_match);
2557                         check = check->queue_next;
2558                 }
2559
2560                 check = QueueLimitSender;
2561                 while (check != NULL)
2562                 {
2563                         sm_dprintf("\tQueueLimitSender = %s%s\n",
2564                                 check->queue_negate ? "!" : "",
2565                                 check->queue_match);
2566                         check = check->queue_next;
2567                 }
2568
2569                 check = QueueLimitRecipient;
2570                 while (check != NULL)
2571                 {
2572                         sm_dprintf("\tQueueLimitRecipient = %s%s\n",
2573                                 check->queue_negate ? "!" : "",
2574                                 check->queue_match);
2575                         check = check->queue_next;
2576                 }
2577
2578                 if (QueueMode == QM_QUARANTINE)
2579                 {
2580                         check = QueueLimitQuarantine;
2581                         while (check != NULL)
2582                         {
2583                                 sm_dprintf("\tQueueLimitQuarantine = %s%s\n",
2584                                            check->queue_negate ? "!" : "",
2585                                            check->queue_match);
2586                                 check = check->queue_next;
2587                         }
2588                 }
2589         }
2590
2591         /* open the queue directory */
2592         f = opendir(qd);
2593         if (f == NULL)
2594         {
2595                 syserr("gatherq: cannot open \"%s\"",
2596                         qid_printqueue(qgrp, qdir));
2597                 if (full != NULL)
2598                         *full = WorkListCount >= MaxQueueRun && MaxQueueRun > 0;
2599                 if (more != NULL)
2600                         *more = false;
2601                 return 0;
2602         }
2603
2604         /*
2605         **  Read the work directory.
2606         */
2607
2608         while ((d = readdir(f)) != NULL)
2609         {
2610                 SM_FILE_T *cf;
2611                 int qfver = 0;
2612                 char lbuf[MAXNAME + 1];
2613                 struct stat sbuf;
2614
2615                 if (tTd(41, 50))
2616                         sm_dprintf("gatherq: checking %s..", d->d_name);
2617
2618                 /* is this an interesting entry? */
2619                 if (!(((QueueMode == QM_NORMAL &&
2620                         d->d_name[0] == NORMQF_LETTER) ||
2621                        (QueueMode == QM_QUARANTINE &&
2622                         d->d_name[0] == QUARQF_LETTER) ||
2623                        (QueueMode == QM_LOST &&
2624                         d->d_name[0] == LOSEQF_LETTER)) &&
2625                       d->d_name[1] == 'f'))
2626                 {
2627                         if (tTd(41, 50))
2628                                 sm_dprintf("  skipping\n");
2629                         continue;
2630                 }
2631                 if (tTd(41, 50))
2632                         sm_dprintf("\n");
2633
2634                 if (strlen(d->d_name) >= MAXQFNAME)
2635                 {
2636                         if (Verbose)
2637                                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2638                                                      "gatherq: %s too long, %d max characters\n",
2639                                                      d->d_name, MAXQFNAME);
2640                         if (LogLevel > 0)
2641                                 sm_syslog(LOG_ALERT, NOQID,
2642                                           "gatherq: %s too long, %d max characters",
2643                                           d->d_name, MAXQFNAME);
2644                         continue;
2645                 }
2646
2647                 ++nentries;
2648                 check = QueueLimitId;
2649                 while (check != NULL)
2650                 {
2651                         if (strcontainedin(false, check->queue_match,
2652                                            d->d_name) != check->queue_negate)
2653                                 break;
2654                         else
2655                                 check = check->queue_next;
2656                 }
2657                 if (QueueLimitId != NULL && check == NULL)
2658                         continue;
2659
2660                 /* grow work list if necessary */
2661                 if (++wn >= MaxQueueRun && MaxQueueRun > 0)
2662                 {
2663                         if (wn == MaxQueueRun && LogLevel > 0)
2664                                 sm_syslog(LOG_WARNING, NOQID,
2665                                           "WorkList for %s maxed out at %d",
2666                                           qid_printqueue(qgrp, qdir),
2667                                           MaxQueueRun);
2668                         if (doall)
2669                                 continue;       /* just count entries */
2670                         break;
2671                 }
2672                 if (wn >= WorkListSize)
2673                 {
2674                         grow_wlist(qgrp, qdir);
2675                         if (wn >= WorkListSize)
2676                                 continue;
2677                 }
2678                 SM_ASSERT(wn >= 0);
2679                 w = &WorkList[wn];
2680
2681                 (void) sm_strlcpyn(qf, sizeof(qf), 3, qd, "/", d->d_name);
2682                 if (stat(qf, &sbuf) < 0)
2683                 {
2684                         if (errno != ENOENT)
2685                                 sm_syslog(LOG_INFO, NOQID,
2686                                           "gatherq: can't stat %s/%s",
2687                                           qid_printqueue(qgrp, qdir),
2688                                           d->d_name);
2689                         wn--;
2690                         continue;
2691                 }
2692                 if (!bitset(S_IFREG, sbuf.st_mode))
2693                 {
2694                         /* Yikes!  Skip it or we will hang on open! */
2695                         if (!((d->d_name[0] == DATAFL_LETTER ||
2696                                d->d_name[0] == NORMQF_LETTER ||
2697                                d->d_name[0] == QUARQF_LETTER ||
2698                                d->d_name[0] == LOSEQF_LETTER ||
2699                                d->d_name[0] == XSCRPT_LETTER) &&
2700                               d->d_name[1] == 'f' && d->d_name[2] == '\0'))
2701                                 syserr("gatherq: %s/%s is not a regular file",
2702                                        qid_printqueue(qgrp, qdir), d->d_name);
2703                         wn--;
2704                         continue;
2705                 }
2706
2707                 /* avoid work if possible */
2708                 if ((QueueSortOrder == QSO_BYFILENAME ||
2709                      QueueSortOrder == QSO_BYMODTIME ||
2710                      QueueSortOrder == QSO_NONE ||
2711                      QueueSortOrder == QSO_RANDOM) &&
2712                     QueueLimitQuarantine == NULL &&
2713                     QueueLimitSender == NULL &&
2714                     QueueLimitRecipient == NULL)
2715                 {
2716                         w->w_qgrp = qgrp;
2717                         w->w_qdir = qdir;
2718                         w->w_name = newstr(d->d_name);
2719                         w->w_host = NULL;
2720                         w->w_lock = w->w_tooyoung = false;
2721                         w->w_pri = 0;
2722                         w->w_ctime = 0;
2723                         w->w_mtime = sbuf.st_mtime;
2724                         ++num_ent;
2725                         continue;
2726                 }
2727
2728                 /* open control file */
2729                 cf = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDONLY_B,
2730                                 NULL);
2731                 if (cf == NULL && OpMode != MD_PRINT)
2732                 {
2733                         /* this may be some random person sending hir msgs */
2734                         if (tTd(41, 2))
2735                                 sm_dprintf("gatherq: cannot open %s: %s\n",
2736                                         d->d_name, sm_errstring(errno));
2737                         errno = 0;
2738                         wn--;
2739                         continue;
2740                 }
2741                 w->w_qgrp = qgrp;
2742                 w->w_qdir = qdir;
2743                 w->w_name = newstr(d->d_name);
2744                 w->w_host = NULL;
2745                 if (cf != NULL)
2746                 {
2747                         w->w_lock = !lockfile(sm_io_getinfo(cf, SM_IO_WHAT_FD,
2748                                                             NULL),
2749                                               w->w_name, NULL,
2750                                               LOCK_SH|LOCK_NB);
2751                 }
2752                 w->w_tooyoung = false;
2753
2754                 /* make sure jobs in creation don't clog queue */
2755                 w->w_pri = 0x7fffffff;
2756                 w->w_ctime = 0;
2757                 w->w_mtime = sbuf.st_mtime;
2758
2759                 /* extract useful information */
2760                 i = NEED_P|NEED_T;
2761                 if (QueueSortOrder == QSO_BYHOST
2762 #if _FFR_RHS
2763                     || QueueSortOrder == QSO_BYSHUFFLE
2764 #endif
2765                    )
2766                 {
2767                         /* need w_host set for host sort order */
2768                         i |= NEED_H;
2769                 }
2770                 if (QueueLimitSender != NULL)
2771                         i |= NEED_S;
2772                 if (QueueLimitRecipient != NULL)
2773                         i |= NEED_R;
2774                 if (QueueLimitQuarantine != NULL)
2775                         i |= NEED_QUARANTINE;
2776                 while (cf != NULL && i != 0 &&
2777                        sm_io_fgets(cf, SM_TIME_DEFAULT, lbuf,
2778                                    sizeof(lbuf)) >= 0)
2779                 {
2780                         int c;
2781                         time_t age;
2782
2783                         p = strchr(lbuf, '\n');
2784                         if (p != NULL)
2785                                 *p = '\0';
2786                         else
2787                         {
2788                                 /* flush rest of overly long line */
2789                                 while ((c = sm_io_getc(cf, SM_TIME_DEFAULT))
2790                                        != SM_IO_EOF && c != '\n')
2791                                         continue;
2792                         }
2793
2794                         switch (lbuf[0])
2795                         {
2796                           case 'V':
2797                                 qfver = atoi(&lbuf[1]);
2798                                 break;
2799
2800                           case 'P':
2801                                 w->w_pri = atol(&lbuf[1]);
2802                                 i &= ~NEED_P;
2803                                 break;
2804
2805                           case 'T':
2806                                 w->w_ctime = atol(&lbuf[1]);
2807                                 i &= ~NEED_T;
2808                                 break;
2809
2810                           case 'q':
2811                                 if (QueueMode != QM_QUARANTINE &&
2812                                     QueueMode != QM_LOST)
2813                                 {
2814                                         if (tTd(41, 49))
2815                                                 sm_dprintf("%s not marked as quarantined but has a 'q' line\n",
2816                                                            w->w_name);
2817                                         i |= HAS_QUARANTINE;
2818                                 }
2819                                 else if (QueueMode == QM_QUARANTINE)
2820                                 {
2821                                         if (QueueLimitQuarantine == NULL)
2822                                         {
2823                                                 i &= ~NEED_QUARANTINE;
2824                                                 break;
2825                                         }
2826                                         p = &lbuf[1];
2827                                         check = QueueLimitQuarantine;
2828                                         while (check != NULL)
2829                                         {
2830                                                 if (strcontainedin(false,
2831                                                                    check->queue_match,
2832                                                                    p) !=
2833                                                     check->queue_negate)
2834                                                         break;
2835                                                 else
2836                                                         check = check->queue_next;
2837                                         }
2838                                         if (check != NULL)
2839                                                 i &= ~NEED_QUARANTINE;
2840                                 }
2841                                 break;
2842
2843                           case 'R':
2844                                 if (w->w_host == NULL &&
2845                                     (p = strrchr(&lbuf[1], '@')) != NULL)
2846                                 {
2847 #if _FFR_RHS
2848                                         if (QueueSortOrder == QSO_BYSHUFFLE)
2849                                                 w->w_host = newstr(&p[1]);
2850                                         else
2851 #endif
2852                                                 w->w_host = strrev(&p[1]);
2853                                         makelower(w->w_host);
2854                                         i &= ~NEED_H;
2855                                 }
2856                                 if (QueueLimitRecipient == NULL)
2857                                 {
2858                                         i &= ~NEED_R;
2859                                         break;
2860                                 }
2861                                 if (qfver > 0)
2862                                 {
2863                                         p = strchr(&lbuf[1], ':');
2864                                         if (p == NULL)
2865                                                 p = &lbuf[1];
2866                                         else
2867                                                 ++p; /* skip over ':' */
2868                                 }
2869                                 else
2870                                         p = &lbuf[1];
2871                                 check = QueueLimitRecipient;
2872                                 while (check != NULL)
2873                                 {
2874                                         if (strcontainedin(true,
2875                                                            check->queue_match,
2876                                                            p) !=
2877                                             check->queue_negate)
2878                                                 break;
2879                                         else
2880                                                 check = check->queue_next;
2881                                 }
2882                                 if (check != NULL)
2883                                         i &= ~NEED_R;
2884                                 break;
2885
2886                           case 'S':
2887                                 check = QueueLimitSender;
2888                                 while (check != NULL)
2889                                 {
2890                                         if (strcontainedin(true,
2891                                                            check->queue_match,
2892                                                            &lbuf[1]) !=
2893                                             check->queue_negate)
2894                                                 break;
2895                                         else
2896                                                 check = check->queue_next;
2897                                 }
2898                                 if (check != NULL)
2899                                         i &= ~NEED_S;
2900                                 break;
2901
2902                           case 'K':
2903                                 if (MaxQueueAge > 0)
2904                                 {
2905                                         time_t lasttry, delay;
2906
2907                                         lasttry = (time_t) atol(&lbuf[1]);
2908                                         delay = MIN(lasttry - w->w_ctime,
2909                                                     MaxQueueAge);
2910                                         age = curtime() - lasttry;
2911                                         if (age < delay)
2912                                                 w->w_tooyoung = true;
2913                                         break;
2914                                 }
2915
2916                                 age = curtime() - (time_t) atol(&lbuf[1]);
2917                                 if (age >= 0 && MinQueueAge > 0 &&
2918                                     age < MinQueueAge)
2919                                         w->w_tooyoung = true;
2920                                 break;
2921
2922                           case 'N':
2923                                 if (atol(&lbuf[1]) == 0)
2924                                         w->w_tooyoung = false;
2925                                 break;
2926                         }
2927                 }
2928                 if (cf != NULL)
2929                         (void) sm_io_close(cf, SM_TIME_DEFAULT);
2930
2931                 if ((!doall && (shouldqueue(w->w_pri, w->w_ctime) ||
2932                     w->w_tooyoung)) ||
2933                     bitset(HAS_QUARANTINE, i) ||
2934                     bitset(NEED_QUARANTINE, i) ||
2935                     bitset(NEED_R|NEED_S, i))
2936                 {
2937                         /* don't even bother sorting this job in */
2938                         if (tTd(41, 49))
2939                                 sm_dprintf("skipping %s (%x)\n", w->w_name, i);
2940                         sm_free(w->w_name); /* XXX */
2941                         if (w->w_host != NULL)
2942                                 sm_free(w->w_host); /* XXX */
2943                         wn--;
2944                 }
2945                 else
2946                         ++num_ent;
2947         }
2948         (void) closedir(f);
2949         wn++;
2950
2951         i = wn - WorkListCount;
2952         WorkListCount += SM_MIN(num_ent, WorkListSize);
2953
2954         if (more != NULL)
2955                 *more = WorkListCount < wn;
2956
2957         if (full != NULL)
2958                 *full = (wn >= MaxQueueRun && MaxQueueRun > 0) ||
2959                         (WorkList == NULL && wn > 0);
2960
2961         if (pnentries != NULL)
2962                 *pnentries = nentries;
2963         return i;
2964 }
2965 /*
2966 **  SORTQ -- sort the work list
2967 **
2968 **      First the old WorkQ is cleared away. Then the WorkList is sorted
2969 **      for all items so that important (higher sorting value) items are not
2970 **      truncated off. Then the most important items are moved from
2971 **      WorkList to WorkQ. The lower count of 'max' or MaxListCount items
2972 **      are moved.
2973 **
2974 **      Parameters:
2975 **              max -- maximum number of items to be placed in WorkQ
2976 **
2977 **      Returns:
2978 **              the number of items in WorkQ
2979 **
2980 **      Side Effects:
2981 **              WorkQ gets released and filled with new work. WorkList
2982 **              gets released. Work items get sorted in order.
2983 */
2984
2985 static int
2986 sortq(max)
2987         int max;
2988 {
2989         register int i;                 /* local counter */
2990         register WORK *w;               /* tmp item pointer */
2991         int wc = WorkListCount;         /* trim size for WorkQ */
2992
2993         if (WorkQ != NULL)
2994         {
2995                 WORK *nw;
2996
2997                 /* Clear out old WorkQ. */
2998                 for (w = WorkQ; w != NULL; w = nw)
2999                 {
3000                         nw = w->w_next;
3001                         sm_free(w->w_name); /* XXX */
3002                         if (w->w_host != NULL)
3003                                 sm_free(w->w_host); /* XXX */
3004                         sm_free((char *) w); /* XXX */
3005                 }
3006                 WorkQ = NULL;
3007         }
3008
3009         if (WorkList == NULL || wc <= 0)
3010                 return 0;
3011
3012         /*
3013         **  The sort now takes place using all of the items in WorkList.
3014         **  The list gets trimmed to the most important items after the sort.
3015         **  If the trim were to happen before the sort then one or more
3016         **  important items might get truncated off -- not what we want.
3017         */
3018
3019         if (QueueSortOrder == QSO_BYHOST)
3020         {
3021                 /*
3022                 **  Sort the work directory for the first time,
3023                 **  based on host name, lock status, and priority.
3024                 */
3025
3026                 qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf1);
3027
3028                 /*
3029                 **  If one message to host is locked, "lock" all messages
3030                 **  to that host.
3031                 */
3032
3033                 i = 0;
3034                 while (i < wc)
3035                 {
3036                         if (!WorkList[i].w_lock)
3037                         {
3038                                 i++;
3039                                 continue;
3040                         }
3041                         w = &WorkList[i];
3042                         while (++i < wc)
3043                         {
3044                                 if (WorkList[i].w_host == NULL &&
3045                                     w->w_host == NULL)
3046                                         WorkList[i].w_lock = true;
3047                                 else if (WorkList[i].w_host != NULL &&
3048                                          w->w_host != NULL &&
3049                                          sm_strcasecmp(WorkList[i].w_host,
3050                                                        w->w_host) == 0)
3051                                         WorkList[i].w_lock = true;
3052                                 else
3053                                         break;
3054                         }
3055                 }
3056
3057                 /*
3058                 **  Sort the work directory for the second time,
3059                 **  based on lock status, host name, and priority.
3060                 */
3061
3062                 qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf2);
3063         }
3064         else if (QueueSortOrder == QSO_BYTIME)
3065         {
3066                 /*
3067                 **  Simple sort based on submission time only.
3068                 */
3069
3070                 qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf3);
3071         }
3072         else if (QueueSortOrder == QSO_BYFILENAME)
3073         {
3074                 /*
3075                 **  Sort based on queue filename.
3076                 */
3077
3078                 qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf4);
3079         }
3080         else if (QueueSortOrder == QSO_RANDOM)
3081         {
3082                 /*
3083                 **  Sort randomly.  To avoid problems with an instable sort,
3084                 **  use a random index into the queue file name to start
3085                 **  comparison.
3086                 */
3087
3088                 randi = get_rand_mod(MAXQFNAME);
3089                 if (randi < 2)
3090                         randi = 3;
3091                 qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf5);
3092         }
3093         else if (QueueSortOrder == QSO_BYMODTIME)
3094         {
3095                 /*
3096                 **  Simple sort based on modification time of queue file.
3097                 **  This puts the oldest items first.
3098                 */
3099
3100                 qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf6);
3101         }
3102 #if _FFR_RHS
3103         else if (QueueSortOrder == QSO_BYSHUFFLE)
3104         {
3105                 /*
3106                 **  Simple sort based on shuffled host name.
3107                 */
3108
3109                 init_shuffle_alphabet();
3110                 qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf7);
3111         }
3112 #endif /* _FFR_RHS */
3113         else if (QueueSortOrder == QSO_BYPRIORITY)
3114         {
3115                 /*
3116                 **  Simple sort based on queue priority only.
3117                 */
3118
3119                 qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf0);
3120         }
3121         /* else don't sort at all */
3122
3123         /* Check if the per queue group item limit will be exceeded */
3124         if (wc > max && max > 0)
3125                 wc = max;
3126
3127         /*
3128         **  Convert the work list into canonical form.
3129         **      Should be turning it into a list of envelopes here perhaps.
3130         **  Only take the most important items up to the per queue group
3131         **  maximum.
3132         */
3133
3134         for (i = wc; --i >= 0; )
3135         {
3136                 w = (WORK *) xalloc(sizeof(*w));
3137                 w->w_qgrp = WorkList[i].w_qgrp;
3138                 w->w_qdir = WorkList[i].w_qdir;
3139                 w->w_name = WorkList[i].w_name;
3140                 w->w_host = WorkList[i].w_host;
3141                 w->w_lock = WorkList[i].w_lock;
3142                 w->w_tooyoung = WorkList[i].w_tooyoung;
3143                 w->w_pri = WorkList[i].w_pri;
3144                 w->w_ctime = WorkList[i].w_ctime;
3145                 w->w_mtime = WorkList[i].w_mtime;
3146                 w->w_next = WorkQ;
3147                 WorkQ = w;
3148         }
3149
3150         /* free the rest of the list */
3151         for (i = WorkListCount; --i >= wc; )
3152         {
3153                 sm_free(WorkList[i].w_name);
3154                 if (WorkList[i].w_host != NULL)
3155                         sm_free(WorkList[i].w_host);
3156         }
3157
3158         if (WorkList != NULL)
3159                 sm_free(WorkList); /* XXX */
3160         WorkList = NULL;
3161         WorkListSize = 0;
3162         WorkListCount = 0;
3163
3164         if (tTd(40, 1))
3165         {
3166                 for (w = WorkQ; w != NULL; w = w->w_next)
3167                 {
3168                         if (w->w_host != NULL)
3169                                 sm_dprintf("%22s: pri=%ld %s\n",
3170                                         w->w_name, w->w_pri, w->w_host);
3171                         else
3172                                 sm_dprintf("%32s: pri=%ld\n",
3173                                         w->w_name, w->w_pri);
3174                 }
3175         }
3176
3177         return wc; /* return number of WorkQ items */
3178 }
3179 /*
3180 **  GROW_WLIST -- make the work list larger
3181 **
3182 **      Parameters:
3183 **              qgrp -- the index for the queue group.
3184 **              qdir -- the index for the queue directory.
3185 **
3186 **      Returns:
3187 **              none.
3188 **
3189 **      Side Effects:
3190 **              Adds another QUEUESEGSIZE entries to WorkList if possible.
3191 **              It can fail if there isn't enough memory, so WorkListSize
3192 **              should be checked again upon return.
3193 */
3194
3195 static void
3196 grow_wlist(qgrp, qdir)
3197         int qgrp;
3198         int qdir;
3199 {
3200         if (tTd(41, 1))
3201                 sm_dprintf("grow_wlist: WorkListSize=%d\n", WorkListSize);
3202         if (WorkList == NULL)
3203         {
3204                 WorkList = (WORK *) xalloc((sizeof(*WorkList)) *
3205                                            (QUEUESEGSIZE + 1));
3206                 WorkListSize = QUEUESEGSIZE;
3207         }
3208         else
3209         {
3210                 int newsize = WorkListSize + QUEUESEGSIZE;
3211                 WORK *newlist = (WORK *) sm_realloc((char *) WorkList,
3212                                           (unsigned) sizeof(WORK) * (newsize + 1));
3213
3214                 if (newlist != NULL)
3215                 {
3216                         WorkListSize = newsize;
3217                         WorkList = newlist;
3218                         if (LogLevel > 1)
3219                         {
3220                                 sm_syslog(LOG_INFO, NOQID,
3221                                           "grew WorkList for %s to %d",
3222                                           qid_printqueue(qgrp, qdir),
3223                                           WorkListSize);
3224                         }
3225                 }
3226                 else if (LogLevel > 0)
3227                 {
3228                         sm_syslog(LOG_ALERT, NOQID,
3229                                   "FAILED to grow WorkList for %s to %d",
3230                                   qid_printqueue(qgrp, qdir), newsize);
3231                 }
3232         }
3233         if (tTd(41, 1))
3234                 sm_dprintf("grow_wlist: WorkListSize now %d\n", WorkListSize);
3235 }
3236 /*
3237 **  WORKCMPF0 -- simple priority-only compare function.
3238 **
3239 **      Parameters:
3240 **              a -- the first argument.
3241 **              b -- the second argument.
3242 **
3243 **      Returns:
3244 **              -1 if a < b
3245 **               0 if a == b
3246 **              +1 if a > b
3247 **
3248 */
3249
3250 static int
3251 workcmpf0(a, b)
3252         register WORK *a;
3253         register WORK *b;
3254 {
3255         long pa = a->w_pri;
3256         long pb = b->w_pri;
3257
3258         if (pa == pb)
3259                 return 0;
3260         else if (pa > pb)
3261                 return 1;
3262         else
3263                 return -1;
3264 }
3265 /*
3266 **  WORKCMPF1 -- first compare function for ordering work based on host name.
3267 **
3268 **      Sorts on host name, lock status, and priority in that order.
3269 **
3270 **      Parameters:
3271 **              a -- the first argument.
3272 **              b -- the second argument.
3273 **
3274 **      Returns:
3275 **              <0 if a < b
3276 **               0 if a == b
3277 **              >0 if a > b
3278 **
3279 */
3280
3281 static int
3282 workcmpf1(a, b)
3283         register WORK *a;
3284         register WORK *b;
3285 {
3286         int i;
3287
3288         /* host name */
3289         if (a->w_host != NULL && b->w_host == NULL)
3290                 return 1;
3291         else if (a->w_host == NULL && b->w_host != NULL)
3292                 return -1;
3293         if (a->w_host != NULL && b->w_host != NULL &&
3294             (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
3295                 return i;
3296
3297         /* lock status */
3298         if (a->w_lock != b->w_lock)
3299                 return b->w_lock - a->w_lock;
3300
3301         /* job priority */
3302         return workcmpf0(a, b);
3303 }
3304 /*
3305 **  WORKCMPF2 -- second compare function for ordering work based on host name.
3306 **
3307 **      Sorts on lock status, host name, and priority in that order.
3308 **
3309 **      Parameters:
3310 **              a -- the first argument.
3311 **              b -- the second argument.
3312 **
3313 **      Returns:
3314 **              <0 if a < b
3315 **               0 if a == b
3316 **              >0 if a > b
3317 **
3318 */
3319
3320 static int
3321 workcmpf2(a, b)
3322         register WORK *a;
3323         register WORK *b;
3324 {
3325         int i;
3326
3327         /* lock status */
3328         if (a->w_lock != b->w_lock)
3329                 return a->w_lock - b->w_lock;
3330
3331         /* host name */
3332         if (a->w_host != NULL && b->w_host == NULL)
3333                 return 1;
3334         else if (a->w_host == NULL && b->w_host != NULL)
3335                 return -1;
3336         if (a->w_host != NULL && b->w_host != NULL &&
3337             (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
3338                 return i;
3339
3340         /* job priority */
3341         return workcmpf0(a, b);
3342 }
3343 /*
3344 **  WORKCMPF3 -- simple submission-time-only compare function.
3345 **
3346 **      Parameters:
3347 **              a -- the first argument.
3348 **              b -- the second argument.
3349 **
3350 **      Returns:
3351 **              -1 if a < b
3352 **               0 if a == b
3353 **              +1 if a > b
3354 **
3355 */
3356
3357 static int
3358 workcmpf3(a, b)
3359         register WORK *a;
3360         register WORK *b;
3361 {
3362         if (a->w_ctime > b->w_ctime)
3363                 return 1;
3364         else if (a->w_ctime < b->w_ctime)
3365                 return -1;
3366         else
3367                 return 0;
3368 }
3369 /*
3370 **  WORKCMPF4 -- compare based on file name
3371 **
3372 **      Parameters:
3373 **              a -- the first argument.
3374 **              b -- the second argument.
3375 **
3376 **      Returns:
3377 **              -1 if a < b
3378 **               0 if a == b
3379 **              +1 if a > b
3380 **
3381 */
3382
3383 static int
3384 workcmpf4(a, b)
3385         register WORK *a;
3386         register WORK *b;
3387 {
3388         return strcmp(a->w_name, b->w_name);
3389 }
3390 /*
3391 **  WORKCMPF5 -- compare based on assigned random number
3392 **
3393 **      Parameters:
3394 **              a -- the first argument.
3395 **              b -- the second argument.
3396 **
3397 **      Returns:
3398 **              randomly 1/-1
3399 */
3400
3401 /* ARGSUSED0 */
3402 static int
3403 workcmpf5(a, b)
3404         register WORK *a;
3405         register WORK *b;
3406 {
3407         if (strlen(a->w_name) < randi || strlen(b->w_name) < randi)
3408                 return -1;
3409         return a->w_name[randi] - b->w_name[randi];
3410 }
3411 /*
3412 **  WORKCMPF6 -- simple modification-time-only compare function.
3413 **
3414 **      Parameters:
3415 **              a -- the first argument.
3416 **              b -- the second argument.
3417 **
3418 **      Returns:
3419 **              -1 if a < b
3420 **               0 if a == b
3421 **              +1 if a > b
3422 **
3423 */
3424
3425 static int
3426 workcmpf6(a, b)
3427         register WORK *a;
3428         register WORK *b;
3429 {
3430         if (a->w_mtime > b->w_mtime)
3431                 return 1;
3432         else if (a->w_mtime < b->w_mtime)
3433                 return -1;
3434         else
3435                 return 0;
3436 }
3437 #if _FFR_RHS
3438 /*
3439 **  WORKCMPF7 -- compare function for ordering work based on shuffled host name.
3440 **
3441 **      Sorts on lock status, host name, and priority in that order.
3442 **
3443 **      Parameters:
3444 **              a -- the first argument.
3445 **              b -- the second argument.
3446 **
3447 **      Returns:
3448 **              <0 if a < b
3449 **               0 if a == b
3450 **              >0 if a > b
3451 **
3452 */
3453
3454 static int
3455 workcmpf7(a, b)
3456         register WORK *a;
3457         register WORK *b;
3458 {
3459         int i;
3460
3461         /* lock status */
3462         if (a->w_lock != b->w_lock)
3463                 return a->w_lock - b->w_lock;
3464
3465         /* host name */
3466         if (a->w_host != NULL && b->w_host == NULL)
3467                 return 1;
3468         else if (a->w_host == NULL && b->w_host != NULL)
3469                 return -1;
3470         if (a->w_host != NULL && b->w_host != NULL &&
3471             (i = sm_strshufflecmp(a->w_host, b->w_host)) != 0)
3472                 return i;
3473
3474         /* job priority */
3475         return workcmpf0(a, b);
3476 }
3477 #endif /* _FFR_RHS */
3478 /*
3479 **  STRREV -- reverse string
3480 **
3481 **      Returns a pointer to a new string that is the reverse of
3482 **      the string pointed to by fwd.  The space for the new
3483 **      string is obtained using xalloc().
3484 **
3485 **      Parameters:
3486 **              fwd -- the string to reverse.
3487 **
3488 **      Returns:
3489 **              the reversed string.
3490 */
3491
3492 static char *
3493 strrev(fwd)
3494         char *fwd;
3495 {
3496         char *rev = NULL;
3497         int len, cnt;
3498
3499         len = strlen(fwd);
3500         rev = xalloc(len + 1);
3501         for (cnt = 0; cnt < len; ++cnt)
3502                 rev[cnt] = fwd[len - cnt - 1];
3503         rev[len] = '\0';
3504         return rev;
3505 }
3506
3507 #if _FFR_RHS
3508
3509 # define NASCII 128
3510 # define NCHAR  256
3511
3512 static unsigned char ShuffledAlphabet[NCHAR];
3513
3514 void
3515 init_shuffle_alphabet()
3516 {
3517         static bool init = false;
3518         int i;
3519
3520         if (init)
3521                 return;
3522
3523         /* fill the ShuffledAlphabet */
3524         for (i = 0; i < NASCII; i++)
3525                 ShuffledAlphabet[i] = i;
3526
3527         /* mix it */
3528         for (i = 1; i < NASCII; i++)
3529         {
3530                 register int j = get_random() % NASCII;
3531                 register int tmp;
3532
3533                 tmp = ShuffledAlphabet[j];
3534                 ShuffledAlphabet[j] = ShuffledAlphabet[i];
3535                 ShuffledAlphabet[i] = tmp;
3536         }
3537
3538         /* make it case insensitive */
3539         for (i = 'A'; i <= 'Z'; i++)
3540                 ShuffledAlphabet[i] = ShuffledAlphabet[i + 'a' - 'A'];
3541
3542         /* fill the upper part */
3543         for (i = 0; i < NASCII; i++)
3544                 ShuffledAlphabet[i + NASCII] = ShuffledAlphabet[i];
3545         init = true;
3546 }
3547
3548 static int
3549 sm_strshufflecmp(a, b)
3550         char *a;
3551         char *b;
3552 {
3553         const unsigned char *us1 = (const unsigned char *) a;
3554         const unsigned char *us2 = (const unsigned char *) b;
3555
3556         while (ShuffledAlphabet[*us1] == ShuffledAlphabet[*us2++])
3557         {
3558                 if (*us1++ == '\0')
3559                         return 0;
3560         }
3561         return (ShuffledAlphabet[*us1] - ShuffledAlphabet[*--us2]);
3562 }
3563 #endif /* _FFR_RHS */
3564
3565 /*
3566 **  DOWORK -- do a work request.
3567 **
3568 **      Parameters:
3569 **              qgrp -- the index of the queue group for the job.
3570 **              qdir -- the index of the queue directory for the job.
3571 **              id -- the ID of the job to run.
3572 **              forkflag -- if set, run this in background.
3573 **              requeueflag -- if set, reinstantiate the queue quickly.
3574 **                      This is used when expanding aliases in the queue.
3575 **                      If forkflag is also set, it doesn't wait for the
3576 **                      child.
3577 **              e - the envelope in which to run it.
3578 **
3579 **      Returns:
3580 **              process id of process that is running the queue job.
3581 **
3582 **      Side Effects:
3583 **              The work request is satisfied if possible.
3584 */
3585
3586 pid_t
3587 dowork(qgrp, qdir, id, forkflag, requeueflag, e)
3588         int qgrp;
3589         int qdir;
3590         char *id;
3591         bool forkflag;
3592         bool requeueflag;
3593         register ENVELOPE *e;
3594 {
3595         register pid_t pid;
3596         SM_RPOOL_T *rpool;
3597
3598         if (tTd(40, 1))
3599                 sm_dprintf("dowork(%s/%s)\n", qid_printqueue(qgrp, qdir), id);
3600
3601         /*
3602         **  Fork for work.
3603         */
3604
3605         if (forkflag)
3606         {
3607                 /*
3608                 **  Since the delivery may happen in a child and the
3609                 **  parent does not wait, the parent may close the
3610                 **  maps thereby removing any shared memory used by
3611                 **  the map.  Therefore, close the maps now so the
3612                 **  child will dynamically open them if necessary.
3613                 */
3614
3615                 closemaps(false);
3616
3617                 pid = fork();
3618                 if (pid < 0)
3619                 {
3620                         syserr("dowork: cannot fork");
3621                         return 0;
3622                 }
3623                 else if (pid > 0)
3624                 {
3625                         /* parent -- clean out connection cache */
3626                         mci_flush(false, NULL);
3627                 }
3628                 else
3629                 {
3630                         /*
3631                         **  Initialize exception stack and default exception
3632                         **  handler for child process.
3633                         */
3634
3635                         /* Reset global flags */
3636                         RestartRequest = NULL;
3637                         RestartWorkGroup = false;
3638                         ShutdownRequest = NULL;
3639                         PendingSignal = 0;
3640                         CurrentPid = getpid();
3641                         sm_exc_newthread(fatal_error);
3642
3643                         /*
3644                         **  See note above about SMTP processes and SIGCHLD.
3645                         */
3646
3647                         if (OpMode == MD_SMTP ||
3648                             OpMode == MD_DAEMON ||
3649                             MaxQueueChildren > 0)
3650                         {
3651                                 proc_list_clear();
3652                                 sm_releasesignal(SIGCHLD);
3653                                 (void) sm_signal(SIGCHLD, SIG_DFL);
3654                         }
3655
3656                         /* child -- error messages to the transcript */
3657                         QuickAbort = OnlyOneError = false;
3658                 }
3659         }
3660         else
3661         {
3662                 pid = 0;
3663         }
3664
3665         if (pid == 0)
3666         {
3667                 /*
3668                 **  CHILD
3669                 **      Lock the control file to avoid duplicate deliveries.
3670                 **              Then run the file as though we had just read it.
3671                 **      We save an idea of the temporary name so we
3672                 **              can recover on interrupt.
3673                 */
3674
3675                 if (forkflag)
3676                 {
3677                         /* Reset global flags */
3678                         RestartRequest = NULL;
3679                         RestartWorkGroup = false;
3680                         ShutdownRequest = NULL;
3681                         PendingSignal = 0;
3682                 }
3683
3684                 /* set basic modes, etc. */
3685                 sm_clear_events();
3686                 clearstats();
3687                 rpool = sm_rpool_new_x(NULL);
3688                 clearenvelope(e, false, rpool);
3689                 e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
3690                 set_delivery_mode(SM_DELIVER, e);
3691                 e->e_errormode = EM_MAIL;
3692                 e->e_id = id;
3693                 e->e_qgrp = qgrp;
3694                 e->e_qdir = qdir;
3695                 GrabTo = UseErrorsTo = false;
3696                 ExitStat = EX_OK;
3697                 if (forkflag)
3698                 {
3699                         disconnect(1, e);
3700                         set_op_mode(MD_QUEUERUN);
3701                 }
3702                 sm_setproctitle(true, e, "%s from queue", qid_printname(e));
3703                 if (LogLevel > 76)
3704                         sm_syslog(LOG_DEBUG, e->e_id, "dowork, pid=%d",
3705                                   (int) CurrentPid);
3706
3707                 /* don't use the headers from sendmail.cf... */
3708                 e->e_header = NULL;
3709
3710                 /* read the queue control file -- return if locked */
3711                 if (!readqf(e, false))
3712                 {
3713                         if (tTd(40, 4) && e->e_id != NULL)
3714                                 sm_dprintf("readqf(%s) failed\n",
3715                                         qid_printname(e));
3716                         e->e_id = NULL;
3717                         if (forkflag)
3718                                 finis(false, true, EX_OK);
3719                         else
3720                         {
3721                                 /* adding this frees 8 bytes */
3722                                 clearenvelope(e, false, rpool);
3723
3724                                 /* adding this frees 12 bytes */
3725                                 sm_rpool_free(rpool);
3726                                 e->e_rpool = NULL;
3727                                 return 0;
3728                         }
3729                 }
3730
3731                 e->e_flags |= EF_INQUEUE;
3732                 eatheader(e, requeueflag, true);
3733
3734                 if (requeueflag)
3735                         queueup(e, false, false);
3736
3737                 /* do the delivery */
3738                 sendall(e, SM_DELIVER);
3739
3740                 /* finish up and exit */
3741                 if (forkflag)
3742                         finis(true, true, ExitStat);
3743                 else
3744                 {
3745                         (void) dropenvelope(e, true, false);
3746                         sm_rpool_free(rpool);
3747                         e->e_rpool = NULL;
3748                         e->e_message = NULL;
3749                 }
3750         }
3751         e->e_id = NULL;
3752         return pid;
3753 }
3754
3755 /*
3756 **  DOWORKLIST -- process a list of envelopes as work requests
3757 **
3758 **      Similar to dowork(), except that after forking, it processes an
3759 **      envelope and its siblings, treating each envelope as a work request.
3760 **
3761 **      Parameters:
3762 **              el -- envelope to be processed including its siblings.
3763 **              forkflag -- if set, run this in background.
3764 **              requeueflag -- if set, reinstantiate the queue quickly.
3765 **                      This is used when expanding aliases in the queue.
3766 **                      If forkflag is also set, it doesn't wait for the
3767 **                      child.
3768 **
3769 **      Returns:
3770 **              process id of process that is running the queue job.
3771 **
3772 **      Side Effects:
3773 **              The work request is satisfied if possible.
3774 */
3775
3776 pid_t
3777 doworklist(el, forkflag, requeueflag)
3778         ENVELOPE *el;
3779         bool forkflag;
3780         bool requeueflag;
3781 {
3782         register pid_t pid;
3783         ENVELOPE *ei;
3784
3785         if (tTd(40, 1))
3786                 sm_dprintf("doworklist()\n");
3787
3788         /*
3789         **  Fork for work.
3790         */
3791
3792         if (forkflag)
3793         {
3794                 /*
3795                 **  Since the delivery may happen in a child and the
3796                 **  parent does not wait, the parent may close the
3797                 **  maps thereby removing any shared memory used by
3798                 **  the map.  Therefore, close the maps now so the
3799                 **  child will dynamically open them if necessary.
3800                 */
3801
3802                 closemaps(false);
3803
3804                 pid = fork();
3805                 if (pid < 0)
3806                 {
3807                         syserr("doworklist: cannot fork");
3808                         return 0;
3809                 }
3810                 else if (pid > 0)
3811                 {
3812                         /* parent -- clean out connection cache */
3813                         mci_flush(false, NULL);
3814                 }
3815                 else
3816                 {
3817                         /*
3818                         **  Initialize exception stack and default exception
3819                         **  handler for child process.
3820                         */
3821
3822                         /* Reset global flags */
3823                         RestartRequest = NULL;
3824                         RestartWorkGroup = false;
3825                         ShutdownRequest = NULL;
3826                         PendingSignal = 0;
3827                         CurrentPid = getpid();
3828                         sm_exc_newthread(fatal_error);
3829
3830                         /*
3831                         **  See note above about SMTP processes and SIGCHLD.
3832                         */
3833
3834                         if (OpMode == MD_SMTP ||
3835                             OpMode == MD_DAEMON ||
3836                             MaxQueueChildren > 0)
3837                         {
3838                                 proc_list_clear();
3839                                 sm_releasesignal(SIGCHLD);
3840                                 (void) sm_signal(SIGCHLD, SIG_DFL);
3841                         }
3842
3843                         /* child -- error messages to the transcript */
3844                         QuickAbort = OnlyOneError = false;
3845                 }
3846         }
3847         else
3848         {
3849                 pid = 0;
3850         }
3851
3852         if (pid != 0)
3853                 return pid;
3854
3855         /*
3856         **  IN CHILD
3857         **      Lock the control file to avoid duplicate deliveries.
3858         **              Then run the file as though we had just read it.
3859         **      We save an idea of the temporary name so we
3860         **              can recover on interrupt.
3861         */
3862
3863         if (forkflag)
3864         {
3865                 /* Reset global flags */
3866                 RestartRequest = NULL;
3867                 RestartWorkGroup = false;
3868                 ShutdownRequest = NULL;
3869                 PendingSignal = 0;
3870         }
3871
3872         /* set basic modes, etc. */
3873         sm_clear_events();
3874         clearstats();
3875         GrabTo = UseErrorsTo = false;
3876         ExitStat = EX_OK;
3877         if (forkflag)
3878         {
3879                 disconnect(1, el);
3880                 set_op_mode(MD_QUEUERUN);
3881         }
3882         if (LogLevel > 76)
3883                 sm_syslog(LOG_DEBUG, el->e_id, "doworklist, pid=%d",
3884                           (int) CurrentPid);
3885
3886         for (ei = el; ei != NULL; ei = ei->e_sibling)
3887         {
3888                 ENVELOPE e;
3889                 SM_RPOOL_T *rpool;
3890
3891                 if (WILL_BE_QUEUED(ei->e_sendmode))
3892                         continue;
3893                 else if (QueueMode != QM_QUARANTINE &&
3894                          ei->e_quarmsg != NULL)
3895                         continue;
3896
3897                 rpool = sm_rpool_new_x(NULL);
3898                 clearenvelope(&e, true, rpool);
3899                 e.e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
3900                 set_delivery_mode(SM_DELIVER, &e);
3901                 e.e_errormode = EM_MAIL;
3902                 e.e_id = ei->e_id;
3903                 e.e_qgrp = ei->e_qgrp;
3904                 e.e_qdir = ei->e_qdir;
3905                 openxscript(&e);
3906                 sm_setproctitle(true, &e, "%s from queue", qid_printname(&e));
3907
3908                 /* don't use the headers from sendmail.cf... */
3909                 e.e_header = NULL;
3910                 CurEnv = &e;
3911
3912                 /* read the queue control file -- return if locked */
3913                 if (readqf(&e, false))
3914                 {
3915                         e.e_flags |= EF_INQUEUE;
3916                         eatheader(&e, requeueflag, true);
3917
3918                         if (requeueflag)
3919                                 queueup(&e, false, false);
3920
3921                         /* do the delivery */
3922                         sendall(&e, SM_DELIVER);
3923                         (void) dropenvelope(&e, true, false);
3924                 }
3925                 else
3926                 {
3927                         if (tTd(40, 4) && e.e_id != NULL)
3928                                 sm_dprintf("readqf(%s) failed\n",
3929                                         qid_printname(&e));
3930                 }
3931                 sm_rpool_free(rpool);
3932                 ei->e_id = NULL;
3933         }
3934
3935         /* restore CurEnv */
3936         CurEnv = el;
3937
3938         /* finish up and exit */
3939         if (forkflag)
3940                 finis(true, true, ExitStat);
3941         return 0;
3942 }
3943 /*
3944 **  READQF -- read queue file and set up environment.
3945 **
3946 **      Parameters:
3947 **              e -- the envelope of the job to run.
3948 **              openonly -- only open the qf (returned as e_lockfp)
3949 **
3950 **      Returns:
3951 **              true if it successfully read the queue file.
3952 **              false otherwise.
3953 **
3954 **      Side Effects:
3955 **              The queue file is returned locked.
3956 */
3957
3958 static bool
3959 readqf(e, openonly)
3960         register ENVELOPE *e;
3961         bool openonly;
3962 {
3963         register SM_FILE_T *qfp;
3964         ADDRESS *ctladdr;
3965         struct stat st, stf;
3966         char *bp;
3967         int qfver = 0;
3968         long hdrsize = 0;
3969         register char *p;
3970         char *frcpt = NULL;
3971         char *orcpt = NULL;
3972         bool nomore = false;
3973         bool bogus = false;
3974         MODE_T qsafe;
3975         char *err;
3976         char qf[MAXPATHLEN];
3977         char buf[MAXLINE];
3978         int bufsize;
3979
3980         /*
3981         **  Read and process the file.
3982         */
3983
3984         SM_REQUIRE(e != NULL);
3985         bp = NULL;
3986         (void) sm_strlcpy(qf, queuename(e, ANYQFL_LETTER), sizeof(qf));
3987         qfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDWR_B, NULL);
3988         if (qfp == NULL)
3989         {
3990                 int save_errno = errno;
3991
3992                 if (tTd(40, 8))
3993                         sm_dprintf("readqf(%s): sm_io_open failure (%s)\n",
3994                                 qf, sm_errstring(errno));
3995                 errno = save_errno;
3996                 if (errno != ENOENT
3997                     )
3998                         syserr("readqf: no control file %s", qf);
3999                 RELEASE_QUEUE;
4000                 return false;
4001         }
4002
4003         if (!lockfile(sm_io_getinfo(qfp, SM_IO_WHAT_FD, NULL), qf, NULL,
4004                       LOCK_EX|LOCK_NB))
4005         {
4006                 /* being processed by another queuer */
4007                 if (Verbose)
4008                         (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4009                                              "%s: locked\n", e->e_id);
4010                 if (tTd(40, 8))
4011                         sm_dprintf("%s: locked\n", e->e_id);
4012                 if (LogLevel > 19)
4013                         sm_syslog(LOG_DEBUG, e->e_id, "locked");
4014                 (void) sm_io_close(qfp, SM_TIME_DEFAULT);
4015                 RELEASE_QUEUE;
4016                 return false;
4017         }
4018
4019         RELEASE_QUEUE;
4020
4021         /*
4022         **  Prevent locking race condition.
4023         **
4024         **  Process A: readqf(): qfp = fopen(qffile)
4025         **  Process B: queueup(): rename(tf, qf)
4026         **  Process B: unlocks(tf)
4027         **  Process A: lockfile(qf);
4028         **
4029         **  Process A (us) has the old qf file (before the rename deleted
4030         **  the directory entry) and will be delivering based on old data.
4031         **  This can lead to multiple deliveries of the same recipients.
4032         **
4033         **  Catch this by checking if the underlying qf file has changed
4034         **  *after* acquiring our lock and if so, act as though the file
4035         **  was still locked (i.e., just return like the lockfile() case
4036         **  above.
4037         */
4038
4039         if (stat(qf, &stf) < 0 ||
4040             fstat(sm_io_getinfo(qfp, SM_IO_WHAT_FD, NULL), &st) < 0)
4041         {
4042                 /* must have been being processed by someone else */
4043                 if (tTd(40, 8))
4044                         sm_dprintf("readqf(%s): [f]stat failure (%s)\n",
4045                                 qf, sm_errstring(errno));
4046                 (void) sm_io_close(qfp, SM_TIME_DEFAULT);
4047                 return false;
4048         }
4049
4050         if (st.st_nlink != stf.st_nlink ||
4051             st.st_dev != stf.st_dev ||
4052             ST_INODE(st) != ST_INODE(stf) ||
4053 #if HAS_ST_GEN && 0             /* AFS returns garbage in st_gen */
4054             st.st_gen != stf.st_gen ||
4055 #endif
4056             st.st_uid != stf.st_uid ||
4057             st.st_gid != stf.st_gid ||
4058             st.st_size != stf.st_size)
4059         {
4060                 /* changed after opened */
4061                 if (Verbose)
4062                         (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4063                                              "%s: changed\n", e->e_id);
4064                 if (tTd(40, 8))
4065                         sm_dprintf("%s: changed\n", e->e_id);
4066                 if (LogLevel > 19)
4067                         sm_syslog(LOG_DEBUG, e->e_id, "changed");
4068                 (void) sm_io_close(qfp, SM_TIME_DEFAULT);
4069                 return false;
4070         }
4071
4072         /*
4073         **  Check the queue file for plausibility to avoid attacks.
4074         */
4075
4076         qsafe = S_IWOTH|S_IWGRP;
4077         if (bitset(S_IWGRP, QueueFileMode))
4078                 qsafe &= ~S_IWGRP;
4079
4080         bogus = st.st_uid != geteuid() &&
4081                 st.st_uid != TrustedUid &&
4082                 geteuid() != RealUid;
4083
4084         /*
4085         **  If this qf file results from a set-group-ID binary, then
4086         **  we check whether the directory is group-writable,
4087         **  the queue file mode contains the group-writable bit, and
4088         **  the groups are the same.
4089         **  Notice: this requires that the set-group-ID binary is used to
4090         **  run the queue!
4091         */
4092
4093         if (bogus && st.st_gid == getegid() && UseMSP)
4094         {
4095                 char delim;
4096                 struct stat dst;
4097
4098                 bp = SM_LAST_DIR_DELIM(qf);
4099                 if (bp == NULL)
4100                         delim = '\0';
4101                 else
4102                 {
4103                         delim = *bp;
4104                         *bp = '\0';
4105                 }
4106                 if (stat(delim == '\0' ? "." : qf, &dst) < 0)
4107                         syserr("readqf: cannot stat directory %s",
4108                                 delim == '\0' ? "." : qf);
4109                 else
4110                 {
4111                         bogus = !(bitset(S_IWGRP, QueueFileMode) &&
4112                                   bitset(S_IWGRP, dst.st_mode) &&
4113                                   dst.st_gid == st.st_gid);
4114                 }
4115                 if (delim != '\0')
4116                         *bp = delim;
4117                 bp = NULL;
4118         }
4119         if (!bogus)
4120                 bogus = bitset(qsafe, st.st_mode);
4121         if (bogus)
4122         {
4123                 if (LogLevel > 0)
4124                 {
4125                         sm_syslog(LOG_ALERT, e->e_id,
4126                                   "bogus queue file, uid=%ld, gid=%ld, mode=%o",
4127                                   (long) st.st_uid, (long) st.st_gid,
4128                                   (unsigned int) st.st_mode);
4129                 }
4130                 if (tTd(40, 8))
4131                         sm_dprintf("readqf(%s): bogus file\n", qf);
4132                 e->e_flags |= EF_INQUEUE;
4133                 if (!openonly)
4134                         loseqfile(e, "bogus file uid/gid in mqueue");
4135                 (void) sm_io_close(qfp, SM_TIME_DEFAULT);
4136                 return false;
4137         }
4138
4139         if (st.st_size == 0)
4140         {
4141                 /* must be a bogus file -- if also old, just remove it */
4142                 if (!openonly && st.st_ctime + 10 * 60 < curtime())
4143                 {
4144                         (void) xunlink(queuename(e, DATAFL_LETTER));
4145                         (void) xunlink(queuename(e, ANYQFL_LETTER));
4146                 }
4147                 (void) sm_io_close(qfp, SM_TIME_DEFAULT);
4148                 return false;
4149         }
4150
4151         if (st.st_nlink == 0)
4152         {
4153                 /*
4154                 **  Race condition -- we got a file just as it was being
4155                 **  unlinked.  Just assume it is zero length.
4156                 */
4157
4158                 (void) sm_io_close(qfp, SM_TIME_DEFAULT);
4159                 return false;
4160         }
4161
4162 #if _FFR_TRUSTED_QF
4163         /*
4164         **  If we don't own the file mark it as unsafe.
4165         **  However, allow TrustedUser to own it as well
4166         **  in case TrustedUser manipulates the queue.
4167         */
4168
4169         if (st.st_uid != geteuid() && st.st_uid != TrustedUid)
4170                 e->e_flags |= EF_UNSAFE;
4171 #else /* _FFR_TRUSTED_QF */
4172         /* If we don't own the file mark it as unsafe */
4173         if (st.st_uid != geteuid())
4174                 e->e_flags |= EF_UNSAFE;
4175 #endif /* _FFR_TRUSTED_QF */
4176
4177         /* good file -- save this lock */
4178         e->e_lockfp = qfp;
4179
4180         /* Just wanted the open file */
4181         if (openonly)
4182                 return true;
4183
4184         /* do basic system initialization */
4185         initsys(e);
4186         macdefine(&e->e_macro, A_PERM, 'i', e->e_id);
4187
4188         LineNumber = 0;
4189         e->e_flags |= EF_GLOBALERRS;
4190         set_op_mode(MD_QUEUERUN);
4191         ctladdr = NULL;
4192         e->e_qfletter = queue_letter(e, ANYQFL_LETTER);
4193         e->e_dfqgrp = e->e_qgrp;
4194         e->e_dfqdir = e->e_qdir;
4195 #if _FFR_QUEUE_MACRO
4196         macdefine(&e->e_macro, A_TEMP, macid("{queue}"),
4197                   qid_printqueue(e->e_qgrp, e->e_qdir));
4198 #endif
4199         e->e_dfino = -1;
4200         e->e_msgsize = -1;
4201         while (bufsize = sizeof(buf),
4202                (bp = fgetfolded(buf, &bufsize, qfp)) != NULL)
4203         {
4204                 unsigned long qflags;
4205                 ADDRESS *q;
4206                 int r;
4207                 time_t now;
4208                 auto char *ep;
4209
4210                 if (tTd(40, 4))
4211                         sm_dprintf("+++++ %s\n", bp);
4212                 if (nomore)
4213                 {
4214                         /* hack attack */
4215   hackattack:
4216                         syserr("SECURITY ALERT: extra or bogus data in queue file: %s",
4217                                bp);
4218                         err = "bogus queue line";
4219                         goto fail;
4220                 }
4221                 switch (bp[0])
4222                 {
4223                   case 'A':             /* AUTH= parameter */
4224                         if (!xtextok(&bp[1]))
4225                                 goto hackattack;
4226                         e->e_auth_param = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
4227                         break;
4228
4229                   case 'B':             /* body type */
4230                         r = check_bodytype(&bp[1]);
4231                         if (!BODYTYPE_VALID(r))
4232                                 goto hackattack;
4233                         e->e_bodytype = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
4234                         break;
4235
4236                   case 'C':             /* specify controlling user */
4237                         ctladdr = setctluser(&bp[1], qfver, e);
4238                         break;
4239
4240                   case 'D':             /* data file name */
4241                         /* obsolete -- ignore */
4242                         break;
4243
4244                   case 'd':             /* data file directory name */
4245                         {
4246                                 int qgrp, qdir;
4247
4248 #if _FFR_MSP_PARANOIA
4249                                 /* forbid queue groups in MSP? */
4250                                 if (UseMSP)
4251                                         goto hackattack;
4252 #endif
4253                                 for (qgrp = 0;
4254                                      qgrp < NumQueue && Queue[qgrp] != NULL;
4255                                      ++qgrp)
4256                                 {
4257                                         for (qdir = 0;
4258                                              qdir < Queue[qgrp]->qg_numqueues;
4259                                              ++qdir)
4260                                         {
4261                                                 if (strcmp(&bp[1],
4262                                                            Queue[qgrp]->qg_qpaths[qdir].qp_name)
4263                                                     == 0)
4264                                                 {
4265                                                         e->e_dfqgrp = qgrp;
4266                                                         e->e_dfqdir = qdir;
4267                                                         goto done;
4268                                                 }
4269                                         }
4270                                 }
4271                                 err = "bogus queue file directory";
4272                                 goto fail;
4273                           done:
4274                                 break;
4275                         }
4276
4277                   case 'E':             /* specify error recipient */
4278                         /* no longer used */
4279                         break;
4280
4281                   case 'F':             /* flag bits */
4282                         if (strncmp(bp, "From ", 5) == 0)
4283                         {
4284                                 /* we are being spoofed! */
4285                                 syserr("SECURITY ALERT: bogus qf line %s", bp);
4286                                 err = "bogus queue line";
4287                                 goto fail;
4288                         }
4289                         for (p = &bp[1]; *p != '\0'; p++)
4290                         {
4291                                 switch (*p)
4292                                 {
4293                                   case '8':     /* has 8 bit data */
4294                                         e->e_flags |= EF_HAS8BIT;
4295                                         break;
4296
4297                                   case 'b':     /* delete Bcc: header */
4298                                         e->e_flags |= EF_DELETE_BCC;
4299                                         break;
4300
4301                                   case 'd':     /* envelope has DSN RET= */
4302                                         e->e_flags |= EF_RET_PARAM;
4303                                         break;
4304
4305                                   case 'n':     /* don't return body */
4306                                         e->e_flags |= EF_NO_BODY_RETN;
4307                                         break;
4308
4309                                   case 'r':     /* response */
4310                                         e->e_flags |= EF_RESPONSE;
4311                                         break;
4312
4313                                   case 's':     /* split */
4314                                         e->e_flags |= EF_SPLIT;
4315                                         break;
4316
4317                                   case 'w':     /* warning sent */
4318                                         e->e_flags |= EF_WARNING;
4319                                         break;
4320
4321 #if _FFR_EAI
4322                                   case 'e':     /* message requires EAI */
4323                                         e->e_smtputf8 = true;
4324                                         break;
4325 #endif /* _FFR_EAI */
4326                                 }
4327                         }
4328                         break;
4329
4330                   case 'q':             /* quarantine reason */
4331                         e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
4332                         macdefine(&e->e_macro, A_PERM,
4333                                   macid("{quarantine}"), e->e_quarmsg);
4334                         break;
4335
4336                   case 'H':             /* header */
4337
4338                         /*
4339                         **  count size before chompheader() destroys the line.
4340                         **  this isn't accurate due to macro expansion, but
4341                         **  better than before. "-3" to skip H?? at least.
4342                         */
4343
4344                         hdrsize += strlen(bp) - 3;
4345                         (void) chompheader(&bp[1], CHHDR_QUEUE, NULL, e);
4346                         break;
4347
4348                   case 'I':             /* data file's inode number */
4349                         /* regenerated below */
4350                         break;
4351
4352                   case 'K':             /* time of last delivery attempt */
4353                         e->e_dtime = atol(&buf[1]);
4354                         break;
4355
4356                   case 'L':             /* Solaris Content-Length: */
4357                   case 'M':             /* message */
4358                         /* ignore this; we want a new message next time */
4359                         break;
4360
4361                   case 'N':             /* number of delivery attempts */
4362                         e->e_ntries = atoi(&buf[1]);
4363
4364                         /* if this has been tried recently, let it be */
4365                         now = curtime();
4366                         if (e->e_ntries > 0 && e->e_dtime <= now &&
4367                             now < e->e_dtime + MinQueueAge)
4368                         {
4369                                 char *howlong;
4370
4371                                 howlong = pintvl(now - e->e_dtime, true);
4372                                 if (Verbose)
4373                                         (void) sm_io_fprintf(smioout,
4374                                                              SM_TIME_DEFAULT,
4375                                                              "%s: too young (%s)\n",
4376                                                              e->e_id, howlong);
4377                                 if (tTd(40, 8))
4378                                         sm_dprintf("%s: too young (%s)\n",
4379                                                 e->e_id, howlong);
4380                                 if (LogLevel > 19)
4381                                         sm_syslog(LOG_DEBUG, e->e_id,
4382                                                   "too young (%s)",
4383                                                   howlong);
4384                                 e->e_id = NULL;
4385                                 unlockqueue(e);
4386                                 if (bp != buf)
4387                                         sm_free(bp);
4388                                 return false;
4389                         }
4390                         macdefine(&e->e_macro, A_TEMP,
4391                                 macid("{ntries}"), &buf[1]);
4392
4393 #if NAMED_BIND
4394                         /* adjust BIND parameters immediately */
4395                         if (e->e_ntries == 0)
4396                         {
4397                                 _res.retry = TimeOuts.res_retry[RES_TO_FIRST];
4398                                 _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
4399                         }
4400                         else
4401                         {
4402                                 _res.retry = TimeOuts.res_retry[RES_TO_NORMAL];
4403                                 _res.retrans = TimeOuts.res_retrans[RES_TO_NORMAL];
4404                         }
4405 #endif /* NAMED_BIND */
4406                         break;
4407
4408                   case 'P':             /* message priority */
4409                         e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
4410                         break;
4411
4412                   case 'Q':             /* original recipient */
4413                         orcpt = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
4414                         break;
4415
4416                   case 'r':             /* final recipient */
4417                         frcpt = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
4418                         break;
4419
4420                   case 'R':             /* specify recipient */
4421                         p = bp;
4422                         qflags = 0;
4423                         if (qfver >= 1)
4424                         {
4425                                 /* get flag bits */
4426                                 while (*++p != '\0' && *p != ':')
4427                                 {
4428                                         switch (*p)
4429                                         {
4430                                           case 'N':
4431                                                 qflags |= QHASNOTIFY;
4432                                                 break;
4433
4434                                           case 'S':
4435                                                 qflags |= QPINGONSUCCESS;
4436                                                 break;
4437
4438                                           case 'F':
4439                                                 qflags |= QPINGONFAILURE;
4440                                                 break;
4441
4442                                           case 'D':
4443                                                 qflags |= QPINGONDELAY;
4444                                                 break;
4445
4446                                           case 'P':
4447                                                 qflags |= QPRIMARY;
4448                                                 break;
4449
4450                                           case 'A':
4451                                                 if (ctladdr != NULL)
4452                                                         ctladdr->q_flags |= QALIAS;
4453                                                 break;
4454
4455                                           case 'B':
4456                                                 qflags |= QINTBCC;
4457                                                 break;
4458
4459                                           case QDYNMAILFLG:
4460                                                 qflags |= QDYNMAILER;
4461                                                 break;
4462
4463                                           default: /* ignore or complain? */
4464                                                 break;
4465                                         }
4466                                 }
4467                         }
4468                         else
4469                                 qflags |= QPRIMARY;
4470                         macdefine(&e->e_macro, A_PERM, macid("{addr_type}"),
4471                                 ((qflags & QINTBCC) != 0) ? "e b" : "e r");
4472                         if (*p != '\0')
4473                                 q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0',
4474                                                 NULL, e, true);
4475                         else
4476                                 q = NULL;
4477                         if (q != NULL)
4478                         {
4479                                 /* make sure we keep the current qgrp */
4480                                 if (ISVALIDQGRP(e->e_qgrp))
4481                                         q->q_qgrp = e->e_qgrp;
4482                                 q->q_alias = ctladdr;
4483                                 if (qfver >= 1)
4484                                         q->q_flags &= ~Q_PINGFLAGS;
4485                                 q->q_flags |= qflags;
4486                                 q->q_finalrcpt = frcpt;
4487                                 q->q_orcpt = orcpt;
4488 #if _FFR_RCPTFLAGS
4489                                 if (bitset(QDYNMAILER, qflags))
4490                                         newmodmailer(q, QDYNMAILFLG);
4491 #endif
4492                                 (void) recipient(q, &e->e_sendqueue, 0, e);
4493                         }
4494                         frcpt = NULL;
4495                         orcpt = NULL;
4496                         macdefine(&e->e_macro, A_PERM, macid("{addr_type}"),
4497                                 NULL);
4498                         break;
4499
4500                   case 'S':             /* sender */
4501                         setsender(sm_rpool_strdup_x(e->e_rpool, &bp[1]),
4502                                   e, NULL, '\0', true);
4503                         break;
4504
4505                   case 'T':             /* init time */
4506                         e->e_ctime = atol(&bp[1]);
4507                         break;
4508
4509                   case 'V':             /* queue file version number */
4510                         qfver = atoi(&bp[1]);
4511                         if (qfver <= QF_VERSION)
4512                                 break;
4513                         syserr("Version number in queue file (%d) greater than max (%d)",
4514                                 qfver, QF_VERSION);
4515                         err = "unsupported queue file version";
4516                         goto fail;
4517                         /* NOTREACHED */
4518                         break;
4519
4520                   case 'Z':             /* original envelope id from ESMTP */
4521                         e->e_envid = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
4522                         macdefine(&e->e_macro, A_PERM,
4523                                 macid("{dsn_envid}"), e->e_envid);
4524                         break;
4525
4526                   case '!':             /* deliver by */
4527
4528                         /* format: flag (1 char) space long-integer */
4529                         e->e_dlvr_flag = buf[1];
4530                         e->e_deliver_by = strtol(&buf[3], NULL, 10);
4531
4532                   case '$':             /* define macro */
4533                         {
4534                                 r = macid_parse(&bp[1], &ep);
4535                                 if (r == 0)
4536                                         break;
4537                                 macdefine(&e->e_macro, A_PERM, r,
4538                                         sm_rpool_strdup_x(e->e_rpool, ep));
4539                         }
4540                         break;
4541
4542                   case '.':             /* terminate file */
4543                         nomore = true;
4544                         break;
4545
4546                   default:
4547                         syserr("readqf: %s: line %d: bad line \"%s\"",
4548                                 qf, LineNumber, shortenstring(bp, MAXSHORTSTR));
4549                         err = "unrecognized line";
4550                         goto fail;
4551                 }
4552
4553                 if (bp != buf)
4554                         SM_FREE(bp);
4555         }
4556
4557         /*
4558         **  If we haven't read any lines, this queue file is empty.
4559         **  Arrange to remove it without referencing any null pointers.
4560         */
4561
4562         if (LineNumber == 0)
4563         {
4564                 errno = 0;
4565                 e->e_flags |= EF_CLRQUEUE|EF_FATALERRS|EF_RESPONSE;
4566                 return true;
4567         }
4568
4569         /* Check to make sure we have a complete queue file read */
4570         if (!nomore)
4571         {
4572                 syserr("readqf: %s: incomplete queue file read", qf);
4573                 (void) sm_io_close(qfp, SM_TIME_DEFAULT);
4574                 return false;
4575         }
4576
4577 #if _FFR_QF_PARANOIA
4578         /* Check to make sure key fields were read */
4579         if (e->e_from.q_mailer == NULL)
4580         {
4581                 syserr("readqf: %s: sender not specified in queue file", qf);
4582                 (void) sm_io_close(qfp, SM_TIME_DEFAULT);
4583                 return false;
4584         }
4585         /* other checks? */
4586 #endif /* _FFR_QF_PARANOIA */
4587
4588 #if _FFR_EAI
4589         /*
4590         **  If this message originates from something other than
4591         **  srvrsmtp.c, then it might use UTF8 addresses but not be
4592         **  marked.  We'll just add the mark so we're sure that it
4593         **  either can be delivered or will be returned.
4594         */
4595
4596         if (!e->e_smtputf8)
4597         {
4598                 ADDRESS *q;
4599
4600                 for (q = e->e_sendqueue; q != NULL; q = q->q_next)
4601                         if (!addr_is_ascii(q->q_paddr) && !e->e_smtputf8)
4602                                 e->e_smtputf8 = true;
4603                 if (!addr_is_ascii(e->e_from.q_paddr) && !e->e_smtputf8)
4604                         e->e_smtputf8 = true;
4605         }
4606 #endif /* _FFR_EAI */
4607
4608         /* possibly set ${dsn_ret} macro */
4609         if (bitset(EF_RET_PARAM, e->e_flags))
4610         {
4611                 if (bitset(EF_NO_BODY_RETN, e->e_flags))
4612                         macdefine(&e->e_macro, A_PERM,
4613                                 macid("{dsn_ret}"), "hdrs");
4614                 else
4615                         macdefine(&e->e_macro, A_PERM,
4616                                 macid("{dsn_ret}"), "full");
4617         }
4618
4619         /*
4620         **  Arrange to read the data file.
4621         */
4622
4623         p = queuename(e, DATAFL_LETTER);
4624         e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, p, SM_IO_RDONLY_B,
4625                               NULL);
4626         if (e->e_dfp == NULL)
4627         {
4628                 syserr("readqf: cannot open %s", p);
4629         }
4630         else
4631         {
4632                 e->e_flags |= EF_HAS_DF;
4633                 if (fstat(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL), &st)
4634                     >= 0)
4635                 {
4636                         e->e_msgsize = st.st_size + hdrsize;
4637                         e->e_dfdev = st.st_dev;
4638                         e->e_dfino = ST_INODE(st);
4639                         (void) sm_snprintf(buf, sizeof(buf), "%ld",
4640                                            PRT_NONNEGL(e->e_msgsize));
4641                         macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"),
4642                                   buf);
4643                 }
4644         }
4645
4646         return true;
4647
4648   fail:
4649         /*
4650         **  There was some error reading the qf file (reason is in err var.)
4651         **  Cleanup:
4652         **      close file; clear e_lockfp since it is the same as qfp,
4653         **      hence it is invalid (as file) after qfp is closed;
4654         **      the qf file is on disk, so set the flag to avoid calling
4655         **      queueup() with bogus data.
4656         */
4657
4658         if (bp != buf)
4659                 SM_FREE(bp);
4660         if (qfp != NULL)
4661                 (void) sm_io_close(qfp, SM_TIME_DEFAULT);
4662         e->e_lockfp = NULL;
4663         e->e_flags |= EF_INQUEUE;
4664         loseqfile(e, err);
4665         return false;
4666 }
4667 /*
4668 **  PRTSTR -- print a string, "unprintable" characters are shown as \oct
4669 **
4670 **      Parameters:
4671 **              s -- string to print
4672 **              ml -- maximum length of output
4673 **
4674 **      Returns:
4675 **              number of entries
4676 **
4677 **      Side Effects:
4678 **              Prints a string on stdout.
4679 */
4680
4681 static void prtstr __P((char *, int));
4682
4683 #if _FFR_BOUNCE_QUEUE
4684 # define IS_BOUNCE_QUEUE(i) ((i) == BounceQueue)
4685 # define SKIP_BOUNCE_QUEUE(i)   \
4686                 if (IS_BOUNCE_QUEUE(i)) \
4687                         continue;
4688 #else
4689 # define IS_BOUNCE_QUEUE(i) false
4690 # define SKIP_BOUNCE_QUEUE(i)
4691 #endif
4692
4693 static void
4694 prtstr(s, ml)
4695         char *s;
4696         int ml;
4697 {
4698         int c;
4699
4700         if (s == NULL)
4701                 return;
4702         while (ml-- > 0 && ((c = *s++) != '\0'))
4703         {
4704                 if (c == '\\')
4705                 {
4706                         if (ml-- > 0)
4707                         {
4708                                 (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
4709                                 (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
4710                         }
4711                 }
4712                 else if (isascii(c) && isprint(c))
4713                         (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
4714                 else
4715                 {
4716                         if ((ml -= 3) > 0)
4717                                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4718                                                      "\\%03o", c & 0xFF);
4719                 }
4720         }
4721 }
4722 /*
4723 **  PRINTNQE -- print out number of entries in the mail queue
4724 **
4725 **      Parameters:
4726 **              out -- output file pointer.
4727 **              prefix -- string to output in front of each line.
4728 **
4729 **      Returns:
4730 **              none.
4731 */
4732
4733 void
4734 printnqe(out, prefix)
4735         SM_FILE_T *out;
4736         char *prefix;
4737 {
4738 #if SM_CONF_SHM
4739         int i, k = 0, nrequests = 0;
4740         bool unknown = false;
4741
4742         if (ShmId == SM_SHM_NO_ID)
4743         {
4744                 if (prefix == NULL)
4745                         (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4746                                         "Data unavailable: shared memory not updated\n");
4747                 else
4748                         (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4749                                         "%sNOTCONFIGURED:-1\r\n", prefix);
4750                 return;
4751         }
4752         for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
4753         {
4754                 int j;
4755
4756                 SKIP_BOUNCE_QUEUE(i)
4757                 k++;
4758                 for (j = 0; j < Queue[i]->qg_numqueues; j++)
4759                 {
4760                         int n;
4761
4762                         if (StopRequest)
4763                                 stop_sendmail();
4764
4765                         n = QSHM_ENTRIES(Queue[i]->qg_qpaths[j].qp_idx);
4766                         if (prefix != NULL)
4767                                 (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4768                                         "%s%s:%d\r\n",
4769                                         prefix, qid_printqueue(i, j), n);
4770                         else if (n < 0)
4771                         {
4772                                 (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4773                                         "%s: unknown number of entries\n",
4774                                         qid_printqueue(i, j));
4775                                 unknown = true;
4776                         }
4777                         else if (n == 0)
4778                         {
4779                                 (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4780                                         "%s is empty\n",
4781                                         qid_printqueue(i, j));
4782                         }
4783                         else if (n > 0)
4784                         {
4785                                 (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4786                                         "%s: entries=%d\n",
4787                                         qid_printqueue(i, j), n);
4788                                 nrequests += n;
4789                                 k++;
4790                         }
4791                 }
4792         }
4793         if (prefix == NULL && k > 1)
4794                 (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4795                                      "\t\tTotal requests: %d%s\n",
4796                                      nrequests, unknown ? " (about)" : "");
4797 #else /* SM_CONF_SHM */
4798         if (prefix == NULL)
4799                 (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4800                              "Data unavailable without shared memory support\n");
4801         else
4802                 (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4803                              "%sNOTAVAILABLE:-1\r\n", prefix);
4804 #endif /* SM_CONF_SHM */
4805 }
4806 /*
4807 **  PRINTQUEUE -- print out a representation of the mail queue
4808 **
4809 **      Parameters:
4810 **              none.
4811 **
4812 **      Returns:
4813 **              none.
4814 **
4815 **      Side Effects:
4816 **              Prints a listing of the mail queue on the standard output.
4817 */
4818
4819 void
4820 printqueue()
4821 {
4822         int i, k = 0, nrequests = 0;
4823
4824         for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
4825         {
4826                 int j;
4827
4828                 k++;
4829                 for (j = 0; j < Queue[i]->qg_numqueues; j++)
4830                 {
4831                         if (StopRequest)
4832                                 stop_sendmail();
4833                         nrequests += print_single_queue(i, j);
4834                         k++;
4835                 }
4836         }
4837         if (k > 1)
4838                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4839                                      "\t\tTotal requests: %d\n",
4840                                      nrequests);
4841 }
4842 /*
4843 **  PRINT_SINGLE_QUEUE -- print out a representation of a single mail queue
4844 **
4845 **      Parameters:
4846 **              qgrp -- the index of the queue group.
4847 **              qdir -- the queue directory.
4848 **
4849 **      Returns:
4850 **              number of requests in mail queue.
4851 **
4852 **      Side Effects:
4853 **              Prints a listing of the mail queue on the standard output.
4854 */
4855
4856 int
4857 print_single_queue(qgrp, qdir)
4858         int qgrp;
4859         int qdir;
4860 {
4861         register WORK *w;
4862         SM_FILE_T *f;
4863         int nrequests;
4864         char qd[MAXPATHLEN];
4865         char qddf[MAXPATHLEN];
4866         char buf[MAXLINE];
4867
4868         if (qdir == NOQDIR)
4869         {
4870                 (void) sm_strlcpy(qd, ".", sizeof(qd));
4871                 (void) sm_strlcpy(qddf, ".", sizeof(qddf));
4872         }
4873         else
4874         {
4875                 (void) sm_strlcpyn(qd, sizeof(qd), 2,
4876                         Queue[qgrp]->qg_qpaths[qdir].qp_name,
4877                         (bitset(QP_SUBQF,
4878                                 Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
4879                                         ? "/qf" : ""));
4880                 (void) sm_strlcpyn(qddf, sizeof(qddf), 2,
4881                         Queue[qgrp]->qg_qpaths[qdir].qp_name,
4882                         (bitset(QP_SUBDF,
4883                                 Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
4884                                         ? "/df" : ""));
4885         }
4886
4887         /*
4888         **  Check for permission to print the queue
4889         */
4890
4891         if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
4892         {
4893                 struct stat st;
4894 #ifdef NGROUPS_MAX
4895                 int n;
4896                 extern GIDSET_T InitialGidSet[NGROUPS_MAX];
4897 #endif
4898
4899                 if (stat(qd, &st) < 0)
4900                 {
4901                         syserr("Cannot stat %s",
4902                                 qid_printqueue(qgrp, qdir));
4903                         return 0;
4904                 }
4905 #ifdef NGROUPS_MAX
4906                 n = NGROUPS_MAX;
4907                 while (--n >= 0)
4908                 {
4909                         if (InitialGidSet[n] == st.st_gid)
4910                                 break;
4911                 }
4912                 if (n < 0 && RealGid != st.st_gid)
4913 #else /* NGROUPS_MAX */
4914                 if (RealGid != st.st_gid)
4915 #endif /* NGROUPS_MAX */
4916                 {
4917                         usrerr("510 You are not permitted to see the queue");
4918                         setstat(EX_NOPERM);
4919                         return 0;
4920                 }
4921         }
4922
4923         /*
4924         **  Read and order the queue.
4925         */
4926
4927         nrequests = gatherq(qgrp, qdir, true, NULL, NULL, NULL);
4928         (void) sortq(Queue[qgrp]->qg_maxlist);
4929
4930         /*
4931         **  Print the work list that we have read.
4932         */
4933
4934         /* first see if there is anything */
4935         if (nrequests <= 0)
4936         {
4937                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s is empty\n",
4938                                      qid_printqueue(qgrp, qdir));
4939                 return 0;
4940         }
4941
4942         sm_getla();     /* get load average */
4943
4944         (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\t\t%s (%d request%s",
4945                              qid_printqueue(qgrp, qdir),
4946                              nrequests, nrequests == 1 ? "" : "s");
4947         if (MaxQueueRun > 0 && nrequests > MaxQueueRun)
4948                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4949                                      ", only %d printed", MaxQueueRun);
4950         if (Verbose)
4951                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4952                         ")\n-----Q-ID----- --Size-- -Priority- ---Q-Time--- --------Sender/Recipient--------\n");
4953         else
4954                 (void) sm_io_fprintf(smioout,  SM_TIME_DEFAULT,
4955                         ")\n-----Q-ID----- --Size-- -----Q-Time----- ------------Sender/Recipient-----------\n");
4956         for (w = WorkQ; w != NULL; w = w->w_next)
4957         {
4958                 struct stat st;
4959                 auto time_t submittime = 0;
4960                 long dfsize;
4961                 int flags = 0;
4962                 int qfver;
4963                 char quarmsg[MAXLINE];
4964                 char statmsg[MAXLINE];
4965                 char bodytype[MAXNAME + 1];
4966                 char qf[MAXPATHLEN];
4967
4968                 if (StopRequest)
4969                         stop_sendmail();
4970
4971                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%13s",
4972                                      w->w_name + 2);
4973                 (void) sm_strlcpyn(qf, sizeof(qf), 3, qd, "/", w->w_name);
4974                 f = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDONLY_B,
4975                                NULL);
4976                 if (f == NULL)
4977                 {
4978                         if (errno == EPERM)
4979                                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4980                                                      " (permission denied)\n");
4981                         else if (errno == ENOENT)
4982                                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4983                                                      " (job completed)\n");
4984                         else
4985                                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4986                                                      " (%s)\n",
4987                                                      sm_errstring(errno));
4988                         errno = 0;
4989                         continue;
4990                 }
4991                 w->w_name[0] = DATAFL_LETTER;
4992                 (void) sm_strlcpyn(qf, sizeof(qf), 3, qddf, "/", w->w_name);
4993                 if (stat(qf, &st) >= 0)
4994                         dfsize = st.st_size;
4995                 else
4996                 {
4997                         ENVELOPE e;
4998
4999                         /*
5000                         **  Maybe the df file can't be statted because
5001                         **  it is in a different directory than the qf file.
5002                         **  In order to find out, we must read the qf file.
5003                         */
5004
5005                         newenvelope(&e, &BlankEnvelope, sm_rpool_new_x(NULL));
5006                         e.e_id = w->w_name + 2;
5007                         e.e_qgrp = qgrp;
5008                         e.e_qdir = qdir;
5009                         dfsize = -1;
5010                         if (readqf(&e, false))
5011                         {
5012                                 char *df = queuename(&e, DATAFL_LETTER);
5013                                 if (stat(df, &st) >= 0)
5014                                         dfsize = st.st_size;
5015                         }
5016                         if (e.e_lockfp != NULL)
5017                         {
5018                                 (void) sm_io_close(e.e_lockfp, SM_TIME_DEFAULT);
5019                                 e.e_lockfp = NULL;
5020                         }
5021                         clearenvelope(&e, false, e.e_rpool);
5022                         sm_rpool_free(e.e_rpool);
5023                 }
5024                 if (w->w_lock)
5025                         (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "*");
5026                 else if (QueueMode == QM_LOST)
5027                         (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "?");
5028                 else if (w->w_tooyoung)
5029                         (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "-");
5030                 else if (shouldqueue(w->w_pri, w->w_ctime))
5031                         (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "X");
5032                 else
5033                         (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " ");
5034
5035                 errno = 0;
5036
5037                 quarmsg[0] = '\0';
5038                 statmsg[0] = bodytype[0] = '\0';
5039                 qfver = 0;
5040                 while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0)
5041                 {
5042                         register int i;
5043                         register char *p;
5044
5045                         if (StopRequest)
5046                                 stop_sendmail();
5047
5048                         fixcrlf(buf, true);
5049                         switch (buf[0])
5050                         {
5051                           case 'V':     /* queue file version */
5052                                 qfver = atoi(&buf[1]);
5053                                 break;
5054
5055                           case 'M':     /* error message */
5056                                 if ((i = strlen(&buf[1])) >= sizeof(statmsg))
5057                                         i = sizeof(statmsg) - 1;
5058                                 memmove(statmsg, &buf[1], i);
5059                                 statmsg[i] = '\0';
5060                                 break;
5061
5062                           case 'q':     /* quarantine reason */
5063                                 if ((i = strlen(&buf[1])) >= sizeof(quarmsg))
5064                                         i = sizeof(quarmsg) - 1;
5065                                 memmove(quarmsg, &buf[1], i);
5066                                 quarmsg[i] = '\0';
5067                                 break;
5068
5069                           case 'B':     /* body type */
5070                                 if ((i = strlen(&buf[1])) >= sizeof(bodytype))
5071                                         i = sizeof(bodytype) - 1;
5072                                 memmove(bodytype, &buf[1], i);
5073                                 bodytype[i] = '\0';
5074                                 break;
5075
5076                           case 'S':     /* sender name */
5077                                 if (Verbose)
5078                                 {
5079                                         (void) sm_io_fprintf(smioout,
5080                                                 SM_TIME_DEFAULT,
5081                                                 "%8ld %10ld%c%.12s ",
5082                                                 dfsize,
5083                                                 w->w_pri,
5084                                                 bitset(EF_WARNING, flags)
5085                                                         ? '+' : ' ',
5086                                                 ctime(&submittime) + 4);
5087                                         prtstr(&buf[1], 78);
5088                                 }
5089                                 else
5090                                 {
5091                                         (void) sm_io_fprintf(smioout,
5092                                                 SM_TIME_DEFAULT,
5093                                                 "%8ld %.16s ",
5094                                                 dfsize,
5095                                                 ctime(&submittime));
5096                                         prtstr(&buf[1], 39);
5097                                 }
5098
5099                                 if (quarmsg[0] != '\0')
5100                                 {
5101                                         (void) sm_io_fprintf(smioout,
5102                                                              SM_TIME_DEFAULT,
5103                                                              "\n     QUARANTINE: %.*s",
5104                                                              Verbose ? 100 : 60,
5105                                                              quarmsg);
5106                                         quarmsg[0] = '\0';
5107                                 }
5108
5109                                 if (statmsg[0] != '\0' || bodytype[0] != '\0')
5110                                 {
5111                                         (void) sm_io_fprintf(smioout,
5112                                                 SM_TIME_DEFAULT,
5113                                                 "\n    %10.10s",
5114                                                 bodytype);
5115                                         if (statmsg[0] != '\0')
5116                                                 (void) sm_io_fprintf(smioout,
5117                                                         SM_TIME_DEFAULT,
5118                                                         "   (%.*s)",
5119                                                         Verbose ? 100 : 60,
5120                                                         statmsg);
5121                                         statmsg[0] = '\0';
5122                                 }
5123                                 break;
5124
5125                           case 'C':     /* controlling user */
5126                                 if (Verbose)
5127                                         (void) sm_io_fprintf(smioout,
5128                                                 SM_TIME_DEFAULT,
5129                                                 "\n\t\t\t\t\t\t(---%.64s---)",
5130                                                 &buf[1]);
5131                                 break;
5132
5133                           case 'R':     /* recipient name */
5134                                 p = &buf[1];
5135                                 if (qfver >= 1)
5136                                 {
5137                                         p = strchr(p, ':');
5138                                         if (p == NULL)
5139                                                 break;
5140                                         p++;
5141                                 }
5142                                 if (Verbose)
5143                                 {
5144                                         (void) sm_io_fprintf(smioout,
5145                                                         SM_TIME_DEFAULT,
5146                                                         "\n\t\t\t\t\t\t");
5147                                         prtstr(p, 71);
5148                                 }
5149                                 else
5150                                 {
5151                                         (void) sm_io_fprintf(smioout,
5152                                                         SM_TIME_DEFAULT,
5153                                                         "\n\t\t\t\t\t ");
5154                                         prtstr(p, 38);
5155                                 }
5156                                 if (Verbose && statmsg[0] != '\0')
5157                                 {
5158                                         (void) sm_io_fprintf(smioout,
5159                                                         SM_TIME_DEFAULT,
5160                                                         "\n\t\t (%.100s)",
5161                                                         statmsg);
5162                                         statmsg[0] = '\0';
5163                                 }
5164                                 break;
5165
5166                           case 'T':     /* creation time */
5167                                 submittime = atol(&buf[1]);
5168                                 break;
5169
5170                           case 'F':     /* flag bits */
5171                                 for (p = &buf[1]; *p != '\0'; p++)
5172                                 {
5173                                         switch (*p)
5174                                         {
5175                                           case 'w':
5176                                                 flags |= EF_WARNING;
5177                                                 break;
5178                                         }
5179                                 }
5180                         }
5181                 }
5182                 if (submittime == (time_t) 0)
5183                         (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
5184                                              " (no control file)");
5185                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n");
5186                 (void) sm_io_close(f, SM_TIME_DEFAULT);
5187         }
5188         return nrequests;
5189 }
5190
5191 /*
5192 **  QUEUE_LETTER -- get the proper queue letter for the current QueueMode.
5193 **
5194 **      Parameters:
5195 **              e -- envelope to build it in/from.
5196 **              type -- the file type, used as the first character
5197 **                      of the file name.
5198 **
5199 **      Returns:
5200 **              the letter to use
5201 */
5202
5203 static char
5204 queue_letter(e, type)
5205         ENVELOPE *e;
5206         int type;
5207 {
5208         /* Change type according to QueueMode */
5209         if (type == ANYQFL_LETTER)
5210         {
5211                 if (e->e_quarmsg != NULL)
5212                         type = QUARQF_LETTER;
5213                 else
5214                 {
5215                         switch (QueueMode)
5216                         {
5217                           case QM_NORMAL:
5218                                 type = NORMQF_LETTER;
5219                                 break;
5220
5221                           case QM_QUARANTINE:
5222                                 type = QUARQF_LETTER;
5223                                 break;
5224
5225                           case QM_LOST:
5226                                 type = LOSEQF_LETTER;
5227                                 break;
5228
5229                           default:
5230                                 /* should never happen */
5231                                 abort();
5232                                 /* NOTREACHED */
5233                         }
5234                 }
5235         }
5236         return type;
5237 }
5238
5239 /*
5240 **  QUEUENAME -- build a file name in the queue directory for this envelope.
5241 **
5242 **      Parameters:
5243 **              e -- envelope to build it in/from.
5244 **              type -- the file type, used as the first character
5245 **                      of the file name.
5246 **
5247 **      Returns:
5248 **              a pointer to the queue name (in a static buffer).
5249 **
5250 **      Side Effects:
5251 **              If no id code is already assigned, queuename() will
5252 **              assign an id code with assign_queueid().  If no queue
5253 **              directory is assigned, one will be set with setnewqueue().
5254 */
5255
5256 char *
5257 queuename(e, type)
5258         register ENVELOPE *e;
5259         int type;
5260 {
5261         int qd, qg;
5262         char *sub = "/";
5263         char pref[3];
5264         static char buf[MAXPATHLEN];
5265
5266         /* Assign an ID if needed */
5267         if (e->e_id == NULL)
5268         {
5269                 if (IntSig)
5270                         return NULL;
5271                 assign_queueid(e);
5272         }
5273         type = queue_letter(e, type);
5274
5275         /* begin of filename */
5276         pref[0] = (char) type;
5277         pref[1] = 'f';
5278         pref[2] = '\0';
5279
5280         /* Assign a queue group/directory if needed */
5281         if (type == XSCRPT_LETTER)
5282         {
5283                 /*
5284                 **  We don't want to call setnewqueue() if we are fetching
5285                 **  the pathname of the transcript file, because setnewqueue
5286                 **  chooses a queue, and sometimes we need to write to the
5287                 **  transcript file before we have gathered enough information
5288                 **  to choose a queue.
5289                 */
5290
5291                 if (e->e_xfqgrp == NOQGRP || e->e_xfqdir == NOQDIR)
5292                 {
5293                         if (e->e_qgrp != NOQGRP && e->e_qdir != NOQDIR)
5294                         {
5295                                 e->e_xfqgrp = e->e_qgrp;
5296                                 e->e_xfqdir = e->e_qdir;
5297                         }
5298                         else
5299                         {
5300                                 e->e_xfqgrp = 0;
5301                                 if (Queue[e->e_xfqgrp]->qg_numqueues <= 1)
5302                                         e->e_xfqdir = 0;
5303                                 else
5304                                 {
5305                                         e->e_xfqdir = get_rand_mod(
5306                                               Queue[e->e_xfqgrp]->qg_numqueues);
5307                                 }
5308                         }
5309                 }
5310                 qd = e->e_xfqdir;
5311                 qg = e->e_xfqgrp;
5312         }
5313         else
5314         {
5315                 if (e->e_qgrp == NOQGRP || e->e_qdir == NOQDIR)
5316                 {
5317                         if (IntSig)
5318                                 return NULL;
5319                         (void) setnewqueue(e);
5320                 }
5321                 if (type ==  DATAFL_LETTER)
5322                 {
5323                         qd = e->e_dfqdir;
5324                         qg = e->e_dfqgrp;
5325                 }
5326                 else
5327                 {
5328                         qd = e->e_qdir;
5329                         qg = e->e_qgrp;
5330                 }
5331         }
5332
5333         /* xf files always have a valid qd and qg picked above */
5334         if ((qd == NOQDIR || qg == NOQGRP) && type != XSCRPT_LETTER)
5335                 (void) sm_strlcpyn(buf, sizeof(buf), 2, pref, e->e_id);
5336         else
5337         {
5338                 switch (type)
5339                 {
5340                   case DATAFL_LETTER:
5341                         if (bitset(QP_SUBDF, Queue[qg]->qg_qpaths[qd].qp_subdirs))
5342                                 sub = "/df/";
5343                         break;
5344
5345                   case QUARQF_LETTER:
5346                   case TEMPQF_LETTER:
5347                   case NEWQFL_LETTER:
5348                   case LOSEQF_LETTER:
5349                   case NORMQF_LETTER:
5350                         if (bitset(QP_SUBQF, Queue[qg]->qg_qpaths[qd].qp_subdirs))
5351                                 sub = "/qf/";
5352                         break;
5353
5354                   case XSCRPT_LETTER:
5355                         if (bitset(QP_SUBXF, Queue[qg]->qg_qpaths[qd].qp_subdirs))
5356                                 sub = "/xf/";
5357                         break;
5358
5359                   default:
5360                         if (IntSig)
5361                                 return NULL;
5362                         sm_abort("queuename: bad queue file type %d", type);
5363                 }
5364
5365                 (void) sm_strlcpyn(buf, sizeof(buf), 4,
5366                                 Queue[qg]->qg_qpaths[qd].qp_name,
5367                                 sub, pref, e->e_id);
5368         }
5369
5370         if (tTd(7, 2))
5371                 sm_dprintf("queuename: %s\n", buf);
5372         return buf;
5373 }
5374
5375 /*
5376 **  INIT_QID_ALG -- Initialize the (static) parameters that are used to
5377 **      generate a queue ID.
5378 **
5379 **      This function is called by the daemon to reset
5380 **      LastQueueTime and LastQueuePid which are used by assign_queueid().
5381 **      Otherwise the algorithm may cause problems because
5382 **      LastQueueTime and LastQueuePid are set indirectly by main()
5383 **      before the daemon process is started, hence LastQueuePid is not
5384 **      the pid of the daemon and therefore a child of the daemon can
5385 **      actually have the same pid as LastQueuePid which means the section
5386 **      in  assign_queueid():
5387 **      * see if we need to get a new base time/pid *
5388 **      is NOT triggered which will cause the same queue id to be generated.
5389 **
5390 **      Parameters:
5391 **              none
5392 **
5393 **      Returns:
5394 **              none.
5395 */
5396
5397 void
5398 init_qid_alg()
5399 {
5400         LastQueueTime = 0;
5401         LastQueuePid = -1;
5402 }
5403
5404 /*
5405 **  ASSIGN_QUEUEID -- assign a queue ID for this envelope.
5406 **
5407 **      Assigns an id code if one does not already exist.
5408 **      This code assumes that nothing will remain in the queue for
5409 **      longer than 60 years.  It is critical that files with the given
5410 **      name do not already exist in the queue.
5411 **      [No longer initializes e_qdir to NOQDIR.]
5412 **
5413 **      Parameters:
5414 **              e -- envelope to set it in.
5415 **
5416 **      Returns:
5417 **              none.
5418 */
5419
5420 static const char QueueIdChars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
5421 # define QIC_LEN        60
5422 # define QIC_LEN_R      62
5423
5424 /*
5425 **  Note: the length is "officially" 60 because minutes and seconds are
5426 **      usually only 0-59.  However (Linux):
5427 **       tm_sec The number of seconds after the minute, normally in
5428 **              the range 0 to 59, but can be up to 61 to allow for
5429 **              leap seconds.
5430 **      Hence the real length of the string is 62 to take this into account.
5431 **      Alternatively % QIC_LEN can (should) be used for access everywhere.
5432 */
5433
5434 # define queuenextid() CurrentPid
5435 #define QIC_LEN_SQR     (QIC_LEN * QIC_LEN)
5436
5437 void
5438 assign_queueid(e)
5439         register ENVELOPE *e;
5440 {
5441         pid_t pid = queuenextid();
5442         static unsigned int cX = 0;
5443         static unsigned int random_offset;
5444         struct tm *tm;
5445         char idbuf[MAXQFNAME - 2];
5446         unsigned int seq;
5447
5448         if (e->e_id != NULL)
5449                 return;
5450
5451         /* see if we need to get a new base time/pid */
5452         if (cX >= QIC_LEN_SQR || LastQueueTime == 0 || LastQueuePid != pid)
5453         {
5454                 time_t then = LastQueueTime;
5455
5456                 /* if the first time through, pick a random offset */
5457                 if (LastQueueTime == 0)
5458                         random_offset = ((unsigned int)get_random())
5459                                         % QIC_LEN_SQR;
5460
5461                 while ((LastQueueTime = curtime()) == then &&
5462                        LastQueuePid == pid)
5463                 {
5464                         (void) sleep(1);
5465                 }
5466                 LastQueuePid = queuenextid();
5467                 cX = 0;
5468         }
5469
5470         /*
5471         **  Generate a new sequence number between 0 and QIC_LEN_SQR-1.
5472         **  This lets us generate up to QIC_LEN_SQR unique queue ids
5473         **  per second, per process.  With envelope splitting,
5474         **  a single message can consume many queue ids.
5475         */
5476
5477         seq = (cX + random_offset) % QIC_LEN_SQR;
5478         ++cX;
5479         if (tTd(7, 50))
5480                 sm_dprintf("assign_queueid: random_offset=%u (%u)\n",
5481                         random_offset, seq);
5482
5483         tm = gmtime(&LastQueueTime);
5484         idbuf[0] = QueueIdChars[tm->tm_year % QIC_LEN];
5485         idbuf[1] = QueueIdChars[tm->tm_mon];
5486         idbuf[2] = QueueIdChars[tm->tm_mday];
5487         idbuf[3] = QueueIdChars[tm->tm_hour];
5488         idbuf[4] = QueueIdChars[tm->tm_min % QIC_LEN_R];
5489         idbuf[5] = QueueIdChars[tm->tm_sec % QIC_LEN_R];
5490         idbuf[6] = QueueIdChars[seq / QIC_LEN];
5491         idbuf[7] = QueueIdChars[seq % QIC_LEN];
5492         (void) sm_snprintf(&idbuf[8], sizeof(idbuf) - 8, "%06d",
5493                            (int) LastQueuePid);
5494         e->e_id = sm_rpool_strdup_x(e->e_rpool, idbuf);
5495         macdefine(&e->e_macro, A_PERM, 'i', e->e_id);
5496 #if 0
5497         /* XXX: inherited from MainEnvelope */
5498         e->e_qgrp = NOQGRP;  /* too early to do anything else */
5499         e->e_qdir = NOQDIR;
5500         e->e_xfqgrp = NOQGRP;
5501 #endif /* 0 */
5502
5503         /* New ID means it's not on disk yet */
5504         e->e_qfletter = '\0';
5505
5506         if (tTd(7, 1))
5507                 sm_dprintf("assign_queueid: assigned id %s, e=%p\n",
5508                         e->e_id, (void *)e);
5509         if (LogLevel > 93)
5510                 sm_syslog(LOG_DEBUG, e->e_id, "assigned id");
5511 }
5512 /*
5513 **  SYNC_QUEUE_TIME -- Assure exclusive PID in any given second
5514 **
5515 **      Make sure one PID can't be used by two processes in any one second.
5516 **
5517 **              If the system rotates PIDs fast enough, may get the
5518 **              same pid in the same second for two distinct processes.
5519 **              This will interfere with the queue file naming system.
5520 **
5521 **      Parameters:
5522 **              none
5523 **
5524 **      Returns:
5525 **              none
5526 */
5527
5528 void
5529 sync_queue_time()
5530 {
5531 #if FAST_PID_RECYCLE
5532         if (OpMode != MD_TEST &&
5533             OpMode != MD_CHECKCONFIG &&
5534             OpMode != MD_VERIFY &&
5535             LastQueueTime > 0 &&
5536             LastQueuePid == CurrentPid &&
5537             curtime() == LastQueueTime)
5538                 (void) sleep(1);
5539 #endif /* FAST_PID_RECYCLE */
5540 }
5541 /*
5542 **  UNLOCKQUEUE -- unlock the queue entry for a specified envelope
5543 **
5544 **      Parameters:
5545 **              e -- the envelope to unlock.
5546 **
5547 **      Returns:
5548 **              none
5549 **
5550 **      Side Effects:
5551 **              unlocks the queue for `e'.
5552 */
5553
5554 void
5555 unlockqueue(e)
5556         ENVELOPE *e;
5557 {
5558         if (tTd(51, 4))
5559                 sm_dprintf("unlockqueue(%s)\n",
5560                         e->e_id == NULL ? "NOQUEUE" : e->e_id);
5561
5562
5563         /* if there is a lock file in the envelope, close it */
5564         if (e->e_lockfp != NULL)
5565                 (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT);
5566         e->e_lockfp = NULL;
5567
5568         /* don't create a queue id if we don't already have one */
5569         if (e->e_id == NULL)
5570                 return;
5571
5572         /* remove the transcript */
5573         if (LogLevel > 87)
5574                 sm_syslog(LOG_DEBUG, e->e_id, "unlock");
5575         if (!tTd(51, 104))
5576                 (void) xunlink(queuename(e, XSCRPT_LETTER));
5577 }
5578 /*
5579 **  SETCTLUSER -- create a controlling address
5580 **
5581 **      Create a fake "address" given only a local login name; this is
5582 **      used as a "controlling user" for future recipient addresses.
5583 **
5584 **      Parameters:
5585 **              user -- the user name of the controlling user.
5586 **              qfver -- the version stamp of this queue file.
5587 **              e -- envelope
5588 **
5589 **      Returns:
5590 **              An address descriptor for the controlling user,
5591 **              using storage allocated from e->e_rpool.
5592 **
5593 */
5594
5595 static ADDRESS *
5596 setctluser(user, qfver, e)
5597         char *user;
5598         int qfver;
5599         ENVELOPE *e;
5600 {
5601         register ADDRESS *a;
5602         struct passwd *pw;
5603         char *p;
5604
5605         /*
5606         **  See if this clears our concept of controlling user.
5607         */
5608
5609         if (user == NULL || *user == '\0')
5610                 return NULL;
5611
5612         /*
5613         **  Set up addr fields for controlling user.
5614         */
5615
5616         a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof(*a));
5617         memset((char *) a, '\0', sizeof(*a));
5618
5619         if (*user == ':')
5620         {
5621                 p = &user[1];
5622                 a->q_user = sm_rpool_strdup_x(e->e_rpool, p);
5623         }
5624         else
5625         {
5626                 p = strtok(user, ":");
5627                 a->q_user = sm_rpool_strdup_x(e->e_rpool, user);
5628                 if (qfver >= 2)
5629                 {
5630                         if ((p = strtok(NULL, ":")) != NULL)
5631                                 a->q_uid = atoi(p);
5632                         if ((p = strtok(NULL, ":")) != NULL)
5633                                 a->q_gid = atoi(p);
5634                         if ((p = strtok(NULL, ":")) != NULL)
5635                         {
5636                                 char *o;
5637
5638                                 a->q_flags |= QGOODUID;
5639
5640                                 /* if there is another ':': restore it */
5641                                 if ((o = strtok(NULL, ":")) != NULL && o > p)
5642                                         o[-1] = ':';
5643                         }
5644                 }
5645                 else if ((pw = sm_getpwnam(user)) != NULL)
5646                 {
5647                         if (*pw->pw_dir == '\0')
5648                                 a->q_home = NULL;
5649                         else if (strcmp(pw->pw_dir, "/") == 0)
5650                                 a->q_home = "";
5651                         else
5652                                 a->q_home = sm_rpool_strdup_x(e->e_rpool, pw->pw_dir);
5653                         a->q_uid = pw->pw_uid;
5654                         a->q_gid = pw->pw_gid;
5655                         a->q_flags |= QGOODUID;
5656                 }
5657         }
5658
5659         a->q_flags |= QPRIMARY;         /* flag as a "ctladdr" */
5660         a->q_mailer = LocalMailer;
5661         if (p == NULL)
5662                 a->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_user);
5663         else
5664                 a->q_paddr = sm_rpool_strdup_x(e->e_rpool, p);
5665         return a;
5666 }
5667 /*
5668 **  LOSEQFILE -- rename queue file with LOSEQF_LETTER & try to let someone know
5669 **
5670 **      Parameters:
5671 **              e -- the envelope (e->e_id will be used).
5672 **              why -- reported to whomever can hear.
5673 **
5674 **      Returns:
5675 **              none.
5676 */
5677
5678 void
5679 loseqfile(e, why)
5680         register ENVELOPE *e;
5681         char *why;
5682 {
5683         bool loseit = true;
5684         char *p;
5685         char buf[MAXPATHLEN];
5686
5687         if (e == NULL || e->e_id == NULL)
5688                 return;
5689         p = queuename(e, ANYQFL_LETTER);
5690         if (sm_strlcpy(buf, p, sizeof(buf)) >= sizeof(buf))
5691                 return;
5692         if (!bitset(EF_INQUEUE, e->e_flags))
5693                 queueup(e, false, true);
5694         else if (QueueMode == QM_LOST)
5695                 loseit = false;
5696
5697         /* if already lost, no need to re-lose */
5698         if (loseit)
5699         {
5700                 p = queuename(e, LOSEQF_LETTER);
5701                 if (rename(buf, p) < 0)
5702                         syserr("cannot rename(%s, %s), uid=%ld",
5703                                buf, p, (long) geteuid());
5704                 else if (LogLevel > 0)
5705                         sm_syslog(LOG_ALERT, e->e_id,
5706                                   "Losing %s: %s", buf, why);
5707         }
5708         if (e->e_dfp != NULL)
5709         {
5710                 (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
5711                 e->e_dfp = NULL;
5712         }
5713         e->e_flags &= ~EF_HAS_DF;
5714 }
5715 /*
5716 **  NAME2QID -- translate a queue group name to a queue group id
5717 **
5718 **      Parameters:
5719 **              queuename -- name of queue group.
5720 **
5721 **      Returns:
5722 **              queue group id if found.
5723 **              NOQGRP otherwise.
5724 */
5725
5726 int
5727 name2qid(queuename)
5728         char *queuename;
5729 {
5730         register STAB *s;
5731
5732         s = stab(queuename, ST_QUEUE, ST_FIND);
5733         if (s == NULL)
5734                 return NOQGRP;
5735         return s->s_quegrp->qg_index;
5736 }
5737 /*
5738 **  QID_PRINTNAME -- create externally printable version of queue id
5739 **
5740 **      Parameters:
5741 **              e -- the envelope.
5742 **
5743 **      Returns:
5744 **              a printable version
5745 */
5746
5747 char *
5748 qid_printname(e)
5749         ENVELOPE *e;
5750 {
5751         char *id;
5752         static char idbuf[MAXQFNAME + 34];
5753
5754         if (e == NULL)
5755                 return "";
5756
5757         if (e->e_id == NULL)
5758                 id = "";
5759         else
5760                 id = e->e_id;
5761
5762         if (e->e_qdir == NOQDIR)
5763                 return id;
5764
5765         (void) sm_snprintf(idbuf, sizeof(idbuf), "%.32s/%s",
5766                            Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_name,
5767                            id);
5768         return idbuf;
5769 }
5770 /*
5771 **  QID_PRINTQUEUE -- create full version of queue directory for data files
5772 **
5773 **      Parameters:
5774 **              qgrp -- index in queue group.
5775 **              qdir -- the short version of the queue directory
5776 **
5777 **      Returns:
5778 **              the full pathname to the queue (might point to a static var)
5779 */
5780
5781 char *
5782 qid_printqueue(qgrp, qdir)
5783         int qgrp;
5784         int qdir;
5785 {
5786         char *subdir;
5787         static char dir[MAXPATHLEN];
5788
5789         if (qdir == NOQDIR)
5790                 return Queue[qgrp]->qg_qdir;
5791
5792         if (strcmp(Queue[qgrp]->qg_qpaths[qdir].qp_name, ".") == 0)
5793                 subdir = NULL;
5794         else
5795                 subdir = Queue[qgrp]->qg_qpaths[qdir].qp_name;
5796
5797         (void) sm_strlcpyn(dir, sizeof(dir), 4,
5798                         Queue[qgrp]->qg_qdir,
5799                         subdir == NULL ? "" : "/",
5800                         subdir == NULL ? "" : subdir,
5801                         (bitset(QP_SUBDF,
5802                                 Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
5803                                         ? "/df" : ""));
5804         return dir;
5805 }
5806
5807 /*
5808 **  PICKQDIR -- Pick a queue directory from a queue group
5809 **
5810 **      Parameters:
5811 **              qg -- queue group
5812 **              fsize -- file size in bytes
5813 **              e -- envelope, or NULL
5814 **
5815 **      Result:
5816 **              NOQDIR if no queue directory in qg has enough free space to
5817 **              hold a file of size 'fsize', otherwise the index of
5818 **              a randomly selected queue directory which resides on a
5819 **              file system with enough disk space.
5820 **              XXX This could be extended to select a queuedir with
5821 **                      a few (the fewest?) number of entries. That data
5822 **                      is available if shared memory is used.
5823 **
5824 **      Side Effects:
5825 **              If the request fails and e != NULL then sm_syslog is called.
5826 */
5827
5828 int
5829 pickqdir(qg, fsize, e)
5830         QUEUEGRP *qg;
5831         long fsize;
5832         ENVELOPE *e;
5833 {
5834         int qdir;
5835         int i;
5836         long avail = 0;
5837
5838         /* Pick a random directory, as a starting point. */
5839         if (qg->qg_numqueues <= 1)
5840                 qdir = 0;
5841         else
5842                 qdir = get_rand_mod(qg->qg_numqueues);
5843
5844 #if _FFR_TESTS
5845         if (tTd(4, 101))
5846                 return NOQDIR;
5847 #endif
5848         if (MinBlocksFree <= 0 && fsize <= 0)
5849                 return qdir;
5850
5851         /*
5852         **  Now iterate over the queue directories,
5853         **  looking for a directory with enough space for this message.
5854         */
5855
5856         i = qdir;
5857         do
5858         {
5859                 QPATHS *qp = &qg->qg_qpaths[i];
5860                 long needed = 0;
5861                 long fsavail = 0;
5862
5863                 if (fsize > 0)
5864                         needed += fsize / FILE_SYS_BLKSIZE(qp->qp_fsysidx)
5865                                   + ((fsize % FILE_SYS_BLKSIZE(qp->qp_fsysidx)
5866                                       > 0) ? 1 : 0);
5867                 if (MinBlocksFree > 0)
5868                         needed += MinBlocksFree;
5869                 fsavail = FILE_SYS_AVAIL(qp->qp_fsysidx);
5870 #if SM_CONF_SHM
5871                 if (fsavail <= 0)
5872                 {
5873                         long blksize;
5874
5875                         /*
5876                         **  might be not correctly updated,
5877                         **  let's try to get the info directly.
5878                         */
5879
5880                         fsavail = freediskspace(FILE_SYS_NAME(qp->qp_fsysidx),
5881                                                 &blksize);
5882                         if (fsavail < 0)
5883                                 fsavail = 0;
5884                 }
5885 #endif /* SM_CONF_SHM */
5886                 if (needed <= fsavail)
5887                         return i;
5888                 if (avail < fsavail)
5889                         avail = fsavail;
5890
5891                 if (qg->qg_numqueues > 0)
5892                         i = (i + 1) % qg->qg_numqueues;
5893         } while (i != qdir);
5894
5895         if (e != NULL && LogLevel > 0)
5896                 sm_syslog(LOG_ALERT, e->e_id,
5897                         "low on space (%s needs %ld bytes + %ld blocks in %s), max avail: %ld",
5898                         CurHostName == NULL ? "SMTP-DAEMON" : CurHostName,
5899                         fsize, MinBlocksFree,
5900                         qg->qg_qdir, avail);
5901         return NOQDIR;
5902 }
5903 /*
5904 **  SETNEWQUEUE -- Sets a new queue group and directory
5905 **
5906 **      Assign a queue group and directory to an envelope and store the
5907 **      directory in e->e_qdir.
5908 **
5909 **      Parameters:
5910 **              e -- envelope to assign a queue for.
5911 **
5912 **      Returns:
5913 **              true if successful
5914 **              false otherwise
5915 **
5916 **      Side Effects:
5917 **              On success, e->e_qgrp and e->e_qdir are non-negative.
5918 **              On failure (not enough disk space),
5919 **              e->qgrp = NOQGRP, e->e_qdir = NOQDIR
5920 **              and usrerr() is invoked (which could raise an exception).
5921 */
5922
5923 bool
5924 setnewqueue(e)
5925         ENVELOPE *e;
5926 {
5927         if (tTd(41, 20))
5928                 sm_dprintf("setnewqueue: called\n");
5929
5930         /* not set somewhere else */
5931         if (e->e_qgrp == NOQGRP)
5932         {
5933                 ADDRESS *q;
5934
5935                 /*
5936                 **  Use the queue group of the "first" recipient, as set by
5937                 **  the "queuegroup" rule set.  If that is not defined, then
5938                 **  use the queue group of the mailer of the first recipient.
5939                 **  If that is not defined either, then use the default
5940                 **  queue group.
5941                 **  Notice: "first" depends on the sorting of sendqueue
5942                 **  in recipient().
5943                 **  To avoid problems with "bad" recipients look
5944                 **  for a valid address first.
5945                 */
5946
5947                 q = e->e_sendqueue;
5948                 while (q != NULL &&
5949                        (QS_IS_BADADDR(q->q_state) || QS_IS_DEAD(q->q_state)))
5950                 {
5951                         q = q->q_next;
5952                 }
5953                 if (q == NULL)
5954                         e->e_qgrp = 0;
5955                 else if (q->q_qgrp >= 0)
5956                         e->e_qgrp = q->q_qgrp;
5957                 else if (q->q_mailer != NULL &&
5958                          ISVALIDQGRP(q->q_mailer->m_qgrp))
5959                         e->e_qgrp = q->q_mailer->m_qgrp;
5960                 else
5961                         e->e_qgrp = 0;
5962                 e->e_dfqgrp = e->e_qgrp;
5963         }
5964
5965         if (ISVALIDQDIR(e->e_qdir) && ISVALIDQDIR(e->e_dfqdir))
5966         {
5967                 if (tTd(41, 20))
5968                         sm_dprintf("setnewqueue: e_qdir already assigned (%s)\n",
5969                                 qid_printqueue(e->e_qgrp, e->e_qdir));
5970                 return true;
5971         }
5972
5973         filesys_update();
5974         e->e_qdir = pickqdir(Queue[e->e_qgrp], e->e_msgsize, e);
5975         if (e->e_qdir == NOQDIR)
5976         {
5977                 e->e_qgrp = NOQGRP;
5978                 if (!bitset(EF_FATALERRS, e->e_flags))
5979                         usrerr("452 4.4.5 Insufficient disk space; try again later");
5980                 e->e_flags |= EF_FATALERRS;
5981                 return false;
5982         }
5983
5984         if (tTd(41, 3))
5985                 sm_dprintf("setnewqueue: Assigned queue directory %s\n",
5986                         qid_printqueue(e->e_qgrp, e->e_qdir));
5987
5988         if (e->e_xfqgrp == NOQGRP || e->e_xfqdir == NOQDIR)
5989         {
5990                 e->e_xfqgrp = e->e_qgrp;
5991                 e->e_xfqdir = e->e_qdir;
5992         }
5993         e->e_dfqdir = e->e_qdir;
5994         return true;
5995 }
5996 /*
5997 **  CHKQDIR -- check a queue directory
5998 **
5999 **      Parameters:
6000 **              name -- name of queue directory
6001 **              sff -- flags for safefile()
6002 **
6003 **      Returns:
6004 **              is it a queue directory?
6005 */
6006
6007 static bool chkqdir __P((char *, long));
6008
6009 static bool
6010 chkqdir(name, sff)
6011         char *name;
6012         long sff;
6013 {
6014         struct stat statb;
6015         int i;
6016
6017         /* skip over . and .. directories */
6018         if (name[0] == '.' &&
6019             (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
6020                 return false;
6021 #if HASLSTAT
6022         if (lstat(name, &statb) < 0)
6023 #else
6024         if (stat(name, &statb) < 0)
6025 #endif
6026         {
6027                 if (tTd(41, 2))
6028                         sm_dprintf("chkqdir: stat(\"%s\"): %s\n",
6029                                    name, sm_errstring(errno));
6030                 return false;
6031         }
6032 #if HASLSTAT
6033         if (S_ISLNK(statb.st_mode))
6034         {
6035                 /*
6036                 **  For a symlink we need to make sure the
6037                 **  target is a directory
6038                 */
6039
6040                 if (stat(name, &statb) < 0)
6041                 {
6042                         if (tTd(41, 2))
6043                                 sm_dprintf("chkqdir: stat(\"%s\"): %s\n",
6044                                            name, sm_errstring(errno));
6045                         return false;
6046                 }
6047         }
6048 #endif /* HASLSTAT */
6049
6050         if (!S_ISDIR(statb.st_mode))
6051         {
6052                 if (tTd(41, 2))
6053                         sm_dprintf("chkqdir: \"%s\": Not a directory\n",
6054                                 name);
6055                 return false;
6056         }
6057
6058         /* Print a warning if unsafe (but still use it) */
6059         /* XXX do this only if we want the warning? */
6060         i = safedirpath(name, RunAsUid, RunAsGid, NULL, sff, 0, 0);
6061         if (i != 0)
6062         {
6063                 if (tTd(41, 2))
6064                         sm_dprintf("chkqdir: \"%s\": Not safe: %s\n",
6065                                    name, sm_errstring(i));
6066 #if _FFR_CHK_QUEUE
6067                 if (LogLevel > 8)
6068                         sm_syslog(LOG_WARNING, NOQID,
6069                                   "queue directory \"%s\": Not safe: %s",
6070                                   name, sm_errstring(i));
6071 #endif /* _FFR_CHK_QUEUE */
6072         }
6073         return true;
6074 }
6075 /*
6076 **  MULTIQUEUE_CACHE -- cache a list of paths to queues.
6077 **
6078 **      Each potential queue is checked as the cache is built.
6079 **      Thereafter, each is blindly trusted.
6080 **      Note that we can be called again after a timeout to rebuild
6081 **      (although code for that is not ready yet).
6082 **
6083 **      Parameters:
6084 **              basedir -- base of all queue directories.
6085 **              blen -- strlen(basedir).
6086 **              qg -- queue group.
6087 **              qn -- number of queue directories already cached.
6088 **              phash -- pointer to hash value over queue dirs.
6089 #if SM_CONF_SHM
6090 **                      only used if shared memory is active.
6091 #endif * SM_CONF_SHM *
6092 **
6093 **      Returns:
6094 **              new number of queue directories.
6095 */
6096
6097 #define INITIAL_SLOTS   20
6098 #define ADD_SLOTS       10
6099
6100 static int
6101 multiqueue_cache(basedir, blen, qg, qn, phash)
6102         char *basedir;
6103         int blen;
6104         QUEUEGRP *qg;
6105         int qn;
6106         unsigned int *phash;
6107 {
6108         char *cp;
6109         int i, len;
6110         int slotsleft = 0;
6111         long sff = SFF_ANYFILE;
6112         char qpath[MAXPATHLEN];
6113         char subdir[MAXPATHLEN];
6114         char prefix[MAXPATHLEN];        /* dir relative to basedir */
6115
6116         if (tTd(41, 20))
6117                 sm_dprintf("multiqueue_cache: called\n");
6118
6119         /* Initialize to current directory */
6120         prefix[0] = '.';
6121         prefix[1] = '\0';
6122         if (qg->qg_numqueues != 0 && qg->qg_qpaths != NULL)
6123         {
6124                 for (i = 0; i < qg->qg_numqueues; i++)
6125                 {
6126                         if (qg->qg_qpaths[i].qp_name != NULL)
6127                                 (void) sm_free(qg->qg_qpaths[i].qp_name); /* XXX */
6128                 }
6129                 (void) sm_free((char *) qg->qg_qpaths); /* XXX */
6130                 qg->qg_qpaths = NULL;
6131                 qg->qg_numqueues = 0;
6132         }
6133
6134         /* If running as root, allow safedirpath() checks to use privs */
6135         if (RunAsUid == 0)
6136                 sff |= SFF_ROOTOK;
6137 #if _FFR_CHK_QUEUE
6138         sff |= SFF_SAFEDIRPATH|SFF_NOWWFILES;
6139         if (!UseMSP)
6140                 sff |= SFF_NOGWFILES;
6141 #endif
6142
6143         if (!SM_IS_DIR_START(qg->qg_qdir))
6144         {
6145                 /*
6146                 **  XXX we could add basedir, but then we have to realloc()
6147                 **  the string... Maybe another time.
6148                 */
6149
6150                 syserr("QueuePath %s not absolute", qg->qg_qdir);
6151                 ExitStat = EX_CONFIG;
6152                 return qn;
6153         }
6154
6155         /* qpath: directory of current workgroup */
6156         len = sm_strlcpy(qpath, qg->qg_qdir, sizeof(qpath));
6157         if (len >= sizeof(qpath))
6158         {
6159                 syserr("QueuePath %.256s too long (%d max)",
6160                        qg->qg_qdir, (int) sizeof(qpath));
6161                 ExitStat = EX_CONFIG;
6162                 return qn;
6163         }
6164
6165         /* begin of qpath must be same as basedir */
6166         if (strncmp(basedir, qpath, blen) != 0 &&
6167             (strncmp(basedir, qpath, blen - 1) != 0 || len != blen - 1))
6168         {
6169                 syserr("QueuePath %s not subpath of QueueDirectory %s",
6170                         qpath, basedir);
6171                 ExitStat = EX_CONFIG;
6172                 return qn;
6173         }
6174
6175         /* Do we have a nested subdirectory? */
6176         if (blen < len && SM_FIRST_DIR_DELIM(qg->qg_qdir + blen) != NULL)
6177         {
6178
6179                 /* Copy subdirectory into prefix for later use */
6180                 if (sm_strlcpy(prefix, qg->qg_qdir + blen, sizeof(prefix)) >=
6181                     sizeof(prefix))
6182                 {
6183                         syserr("QueuePath %.256s too long (%d max)",
6184                                 qg->qg_qdir, (int) sizeof(qpath));
6185                         ExitStat = EX_CONFIG;
6186                         return qn;
6187                 }
6188                 cp = SM_LAST_DIR_DELIM(prefix);
6189                 SM_ASSERT(cp != NULL);
6190                 *cp = '\0';     /* cut off trailing / */
6191         }
6192
6193         /* This is guaranteed by the basedir check above */
6194         SM_ASSERT(len >= blen - 1);
6195         cp = &qpath[len - 1];
6196         if (*cp == '*')
6197         {
6198                 register DIR *dp;
6199                 register struct dirent *d;
6200                 int off;
6201                 char *delim;
6202                 char relpath[MAXPATHLEN];
6203
6204                 *cp = '\0';     /* Overwrite wildcard */
6205                 if ((cp = SM_LAST_DIR_DELIM(qpath)) == NULL)
6206                 {
6207                         syserr("QueueDirectory: can not wildcard relative path");
6208                         if (tTd(41, 2))
6209                                 sm_dprintf("multiqueue_cache: \"%s*\": Can not wildcard relative path.\n",
6210                                         qpath);
6211                         ExitStat = EX_CONFIG;
6212                         return qn;
6213                 }
6214                 if (cp == qpath)
6215                 {
6216                         /*
6217                         **  Special case of top level wildcard, like /foo*
6218                         **      Change to //foo*
6219                         */
6220
6221                         (void) sm_strlcpy(qpath + 1, qpath, sizeof(qpath) - 1);
6222                         ++cp;
6223                 }
6224                 delim = cp;
6225                 *(cp++) = '\0';         /* Replace / with \0 */
6226                 len = strlen(cp);       /* Last component of queue directory */
6227
6228                 /*
6229                 **  Path relative to basedir, with trailing /
6230                 **  It will be modified below to specify the subdirectories
6231                 **  so they can be opened without chdir().
6232                 */
6233
6234                 off = sm_strlcpyn(relpath, sizeof(relpath), 2, prefix, "/");
6235                 SM_ASSERT(off < sizeof(relpath));
6236
6237                 if (tTd(41, 2))
6238                         sm_dprintf("multiqueue_cache: prefix=\"%s%s\"\n",
6239                                    relpath, cp);
6240
6241                 /* It is always basedir: we don't need to store it per group */
6242                 /* XXX: optimize this! -> one more global? */
6243                 qg->qg_qdir = newstr(basedir);
6244                 qg->qg_qdir[blen - 1] = '\0';   /* cut off trailing / */
6245
6246                 /*
6247                 **  XXX Should probably wrap this whole loop in a timeout
6248                 **  in case some wag decides to NFS mount the queues.
6249                 */
6250
6251                 /* Test path to get warning messages. */
6252                 if (qn == 0)
6253                 {
6254                         /*  XXX qg_runasuid and qg_runasgid for specials? */
6255                         i = safedirpath(basedir, RunAsUid, RunAsGid, NULL,
6256                                         sff, 0, 0);
6257                         if (i != 0 && tTd(41, 2))
6258                                 sm_dprintf("multiqueue_cache: \"%s\": Not safe: %s\n",
6259                                            basedir, sm_errstring(i));
6260                 }
6261
6262                 if ((dp = opendir(prefix)) == NULL)
6263                 {
6264                         syserr("can not opendir(%s/%s)", qg->qg_qdir, prefix);
6265                         if (tTd(41, 2))
6266                                 sm_dprintf("multiqueue_cache: opendir(\"%s/%s\"): %s\n",
6267                                            qg->qg_qdir, prefix,
6268                                            sm_errstring(errno));
6269                         ExitStat = EX_CONFIG;
6270                         return qn;
6271                 }
6272                 while ((d = readdir(dp)) != NULL)
6273                 {
6274                         /* Skip . and .. directories */
6275                         if (strcmp(d->d_name, ".") == 0 ||
6276                             strcmp(d->d_name, "..") == 0)
6277                                 continue;
6278
6279                         i = strlen(d->d_name);
6280                         if (i < len || strncmp(d->d_name, cp, len) != 0)
6281                         {
6282                                 if (tTd(41, 5))
6283                                         sm_dprintf("multiqueue_cache: \"%s\", skipped\n",
6284                                                 d->d_name);
6285                                 continue;
6286                         }
6287
6288                         /* Create relative pathname: prefix + local directory */
6289                         i = sizeof(relpath) - off;
6290                         if (sm_strlcpy(relpath + off, d->d_name, i) >= i)
6291                                 continue;       /* way too long */
6292
6293                         if (!chkqdir(relpath, sff))
6294                                 continue;
6295
6296                         if (qg->qg_qpaths == NULL)
6297                         {
6298                                 slotsleft = INITIAL_SLOTS;
6299                                 qg->qg_qpaths = (QPATHS *)xalloc((sizeof(*qg->qg_qpaths)) *
6300                                                                 slotsleft);
6301                                 qg->qg_numqueues = 0;
6302                         }
6303                         else if (slotsleft < 1)
6304                         {
6305                                 qg->qg_qpaths = (QPATHS *)sm_realloc((char *)qg->qg_qpaths,
6306                                                           (sizeof(*qg->qg_qpaths)) *
6307                                                           (qg->qg_numqueues +
6308                                                            ADD_SLOTS));
6309                                 if (qg->qg_qpaths == NULL)
6310                                 {
6311                                         (void) closedir(dp);
6312                                         return qn;
6313                                 }
6314                                 slotsleft += ADD_SLOTS;
6315                         }
6316
6317                         /* check subdirs */
6318                         qg->qg_qpaths[qg->qg_numqueues].qp_subdirs = QP_NOSUB;
6319
6320 #define CHKRSUBDIR(name, flag)  \
6321         (void) sm_strlcpyn(subdir, sizeof(subdir), 3, relpath, "/", name); \
6322         if (chkqdir(subdir, sff))       \
6323                 qg->qg_qpaths[qg->qg_numqueues].qp_subdirs |= flag;     \
6324         else
6325
6326
6327                         CHKRSUBDIR("qf", QP_SUBQF);
6328                         CHKRSUBDIR("df", QP_SUBDF);
6329                         CHKRSUBDIR("xf", QP_SUBXF);
6330
6331                         /* assert(strlen(d->d_name) < MAXPATHLEN - 14) */
6332                         /* maybe even - 17 (subdirs) */
6333
6334                         if (prefix[0] != '.')
6335                                 qg->qg_qpaths[qg->qg_numqueues].qp_name =
6336                                         newstr(relpath);
6337                         else
6338                                 qg->qg_qpaths[qg->qg_numqueues].qp_name =
6339                                         newstr(d->d_name);
6340
6341                         if (tTd(41, 2))
6342                                 sm_dprintf("multiqueue_cache: %d: \"%s\" cached (%x).\n",
6343                                         qg->qg_numqueues, relpath,
6344                                         qg->qg_qpaths[qg->qg_numqueues].qp_subdirs);
6345 #if SM_CONF_SHM
6346                         qg->qg_qpaths[qg->qg_numqueues].qp_idx = qn;
6347                         *phash = hash_q(relpath, *phash);
6348 #endif
6349                         qg->qg_numqueues++;
6350                         ++qn;
6351                         slotsleft--;
6352                 }
6353                 (void) closedir(dp);
6354
6355                 /* undo damage */
6356                 *delim = '/';
6357         }
6358         if (qg->qg_numqueues == 0)
6359         {
6360                 qg->qg_qpaths = (QPATHS *) xalloc(sizeof(*qg->qg_qpaths));
6361
6362                 /* test path to get warning messages */
6363                 i = safedirpath(qpath, RunAsUid, RunAsGid, NULL, sff, 0, 0);
6364                 if (i == ENOENT)
6365                 {
6366                         syserr("can not opendir(%s)", qpath);
6367                         if (tTd(41, 2))
6368                                 sm_dprintf("multiqueue_cache: opendir(\"%s\"): %s\n",
6369                                            qpath, sm_errstring(i));
6370                         ExitStat = EX_CONFIG;
6371                         return qn;
6372                 }
6373
6374                 qg->qg_qpaths[0].qp_subdirs = QP_NOSUB;
6375                 qg->qg_numqueues = 1;
6376
6377                 /* check subdirs */
6378 #define CHKSUBDIR(name, flag)   \
6379         (void) sm_strlcpyn(subdir, sizeof(subdir), 3, qg->qg_qdir, "/", name); \
6380         if (chkqdir(subdir, sff))       \
6381                 qg->qg_qpaths[0].qp_subdirs |= flag;    \
6382         else
6383
6384                 CHKSUBDIR("qf", QP_SUBQF);
6385                 CHKSUBDIR("df", QP_SUBDF);
6386                 CHKSUBDIR("xf", QP_SUBXF);
6387
6388                 if (qg->qg_qdir[blen - 1] != '\0' &&
6389                     qg->qg_qdir[blen] != '\0')
6390                 {
6391                         /*
6392                         **  Copy the last component into qpaths and
6393                         **  cut off qdir
6394                         */
6395
6396                         qg->qg_qpaths[0].qp_name = newstr(qg->qg_qdir + blen);
6397                         qg->qg_qdir[blen - 1] = '\0';
6398                 }
6399                 else
6400                         qg->qg_qpaths[0].qp_name = newstr(".");
6401
6402 #if SM_CONF_SHM
6403                 qg->qg_qpaths[0].qp_idx = qn;
6404                 *phash = hash_q(qg->qg_qpaths[0].qp_name, *phash);
6405 #endif
6406                 ++qn;
6407         }
6408         return qn;
6409 }
6410
6411 /*
6412 **  FILESYS_FIND -- find entry in FileSys table, or add new one
6413 **
6414 **      Given the pathname of a directory, determine the file system
6415 **      in which that directory resides, and return a pointer to the
6416 **      entry in the FileSys table that describes the file system.
6417 **      A new entry is added if necessary (and requested).
6418 **      If the directory does not exist, -1 is returned.
6419 **
6420 **      Parameters:
6421 **              name -- name of directory (must be persistent!)
6422 **              path -- pathname of directory (name plus maybe "/df")
6423 **              add -- add to structure if not found.
6424 **
6425 **      Returns:
6426 **              >=0: found: index in file system table
6427 **              <0: some error, i.e.,
6428 **              FSF_TOO_MANY: too many filesystems (-> syserr())
6429 **              FSF_STAT_FAIL: can't stat() filesystem (-> syserr())
6430 **              FSF_NOT_FOUND: not in list
6431 */
6432
6433 static short filesys_find __P((const char *, const char *, bool));
6434
6435 #define FSF_NOT_FOUND   (-1)
6436 #define FSF_STAT_FAIL   (-2)
6437 #define FSF_TOO_MANY    (-3)
6438
6439 static short
6440 filesys_find(name, path, add)
6441         const char *name;
6442         const char *path;
6443         bool add;
6444 {
6445         struct stat st;
6446         short i;
6447
6448         if (stat(path, &st) < 0)
6449         {
6450                 syserr("cannot stat queue directory %s", path);
6451                 return FSF_STAT_FAIL;
6452         }
6453         for (i = 0; i < NumFileSys; ++i)
6454         {
6455                 if (FILE_SYS_DEV(i) == st.st_dev)
6456                 {
6457                         /*
6458                         **  Make sure the file system (FS) name is set:
6459                         **  even though the source code indicates that
6460                         **  FILE_SYS_DEV() is only set below, it could be
6461                         **  set via shared memory, hence we need to perform
6462                         **  this check/assignment here.
6463                         */
6464
6465                         if (NULL == FILE_SYS_NAME(i))
6466                                 FILE_SYS_NAME(i) = name;
6467                         return i;
6468                 }
6469         }
6470         if (i >= MAXFILESYS)
6471         {
6472                 syserr("too many queue file systems (%d max)", MAXFILESYS);
6473                 return FSF_TOO_MANY;
6474         }
6475         if (!add)
6476                 return FSF_NOT_FOUND;
6477
6478         ++NumFileSys;
6479         FILE_SYS_NAME(i) = name;
6480         FILE_SYS_DEV(i) = st.st_dev;
6481         FILE_SYS_AVAIL(i) = 0;
6482         FILE_SYS_BLKSIZE(i) = 1024; /* avoid divide by zero */
6483         return i;
6484 }
6485
6486 /*
6487 **  FILESYS_SETUP -- set up mapping from queue directories to file systems
6488 **
6489 **      This data structure is used to efficiently check the amount of
6490 **      free space available in a set of queue directories.
6491 **
6492 **      Parameters:
6493 **              add -- initialize structure if necessary.
6494 **
6495 **      Returns:
6496 **              0: success
6497 **              <0: some error, i.e.,
6498 **              FSF_NOT_FOUND: not in list
6499 **              FSF_STAT_FAIL: can't stat() filesystem (-> syserr())
6500 **              FSF_TOO_MANY: too many filesystems (-> syserr())
6501 */
6502
6503 static int filesys_setup __P((bool));
6504
6505 static int
6506 filesys_setup(add)
6507         bool add;
6508 {
6509         int i, j;
6510         short fs;
6511         int ret;
6512
6513         ret = 0;
6514         for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
6515         {
6516                 for (j = 0; j < Queue[i]->qg_numqueues; ++j)
6517                 {
6518                         QPATHS *qp = &Queue[i]->qg_qpaths[j];
6519                         char qddf[MAXPATHLEN];
6520
6521                         (void) sm_strlcpyn(qddf, sizeof(qddf), 2, qp->qp_name,
6522                                         (bitset(QP_SUBDF, qp->qp_subdirs)
6523                                                 ? "/df" : ""));
6524                         fs = filesys_find(qp->qp_name, qddf, add);
6525                         if (fs >= 0)
6526                                 qp->qp_fsysidx = fs;
6527                         else
6528                                 qp->qp_fsysidx = 0;
6529                         if (fs < ret)
6530                                 ret = fs;
6531                 }
6532         }
6533         return ret;
6534 }
6535
6536 /*
6537 **  FILESYS_UPDATE -- update amount of free space on all file systems
6538 **
6539 **      The FileSys table is used to cache the amount of free space
6540 **      available on all queue directory file systems.
6541 **      This function updates the cached information if it has expired.
6542 **
6543 **      Parameters:
6544 **              none.
6545 **
6546 **      Returns:
6547 **              none.
6548 **
6549 **      Side Effects:
6550 **              Updates FileSys table.
6551 */
6552
6553 void
6554 filesys_update()
6555 {
6556         int i;
6557         long avail, blksize;
6558         time_t now;
6559         static time_t nextupdate = 0;
6560
6561 #if SM_CONF_SHM
6562         /*
6563         **  Only the daemon updates the shared memory, i.e.,
6564         **  if shared memory is available but the pid is not the
6565         **  one of the daemon, then don't do anything.
6566         */
6567
6568         if (ShmId != SM_SHM_NO_ID && DaemonPid != CurrentPid)
6569                 return;
6570 #endif /* SM_CONF_SHM */
6571         now = curtime();
6572         if (now < nextupdate)
6573                 return;
6574         nextupdate = now + FILESYS_UPDATE_INTERVAL;
6575         for (i = 0; i < NumFileSys; ++i)
6576         {
6577                 FILESYS *fs = &FILE_SYS(i);
6578
6579                 avail = freediskspace(FILE_SYS_NAME(i), &blksize);
6580                 if (avail < 0 || blksize <= 0)
6581                 {
6582                         if (LogLevel > 5)
6583                                 sm_syslog(LOG_ERR, NOQID,
6584                                         "filesys_update failed: %s, fs=%s, avail=%ld, blocksize=%ld",
6585                                         sm_errstring(errno),
6586                                         FILE_SYS_NAME(i), avail, blksize);
6587                         fs->fs_avail = 0;
6588                         fs->fs_blksize = 1024; /* avoid divide by zero */
6589                         nextupdate = now + 2; /* let's do this soon again */
6590                 }
6591                 else
6592                 {
6593                         fs->fs_avail = avail;
6594                         fs->fs_blksize = blksize;
6595                 }
6596         }
6597 }
6598
6599 #if _FFR_ANY_FREE_FS
6600 /*
6601 **  FILESYS_FREE -- check whether there is at least one fs with enough space.
6602 **
6603 **      Parameters:
6604 **              fsize -- file size in bytes
6605 **
6606 **      Returns:
6607 **              true iff there is one fs with more than fsize bytes free.
6608 */
6609
6610 bool
6611 filesys_free(fsize)
6612         long fsize;
6613 {
6614         int i;
6615
6616         if (fsize <= 0)
6617                 return true;
6618         for (i = 0; i < NumFileSys; ++i)
6619         {
6620                 long needed = 0;
6621
6622                 if (FILE_SYS_AVAIL(i) < 0 || FILE_SYS_BLKSIZE(i) <= 0)
6623                         continue;
6624                 needed += fsize / FILE_SYS_BLKSIZE(i)
6625                           + ((fsize % FILE_SYS_BLKSIZE(i)
6626                               > 0) ? 1 : 0)
6627                           + MinBlocksFree;
6628                 if (needed <= FILE_SYS_AVAIL(i))
6629                         return true;
6630         }
6631         return false;
6632 }
6633 #endif /* _FFR_ANY_FREE_FS */
6634
6635 /*
6636 **  DISK_STATUS -- show amount of free space in queue directories
6637 **
6638 **      Parameters:
6639 **              out -- output file pointer.
6640 **              prefix -- string to output in front of each line.
6641 **
6642 **      Returns:
6643 **              none.
6644 */
6645
6646 void
6647 disk_status(out, prefix)
6648         SM_FILE_T *out;
6649         char *prefix;
6650 {
6651         int i;
6652         long avail, blksize;
6653         long free;
6654
6655         for (i = 0; i < NumFileSys; ++i)
6656         {
6657                 avail = freediskspace(FILE_SYS_NAME(i), &blksize);
6658                 if (avail >= 0 && blksize > 0)
6659                 {
6660                         free = (long)((double) avail *
6661                                 ((double) blksize / 1024));
6662                 }
6663                 else
6664                         free = -1;
6665                 (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
6666                                 "%s%d/%s/%ld\r\n",
6667                                 prefix, i,
6668                                 FILE_SYS_NAME(i),
6669                                         free);
6670         }
6671 }
6672
6673 #if SM_CONF_SHM
6674
6675 /*
6676 **  INIT_SEM -- initialize semaphore system
6677 **
6678 **      Parameters:
6679 **              owner -- is this the owner of semaphores?
6680 **
6681 **      Returns:
6682 **              none.
6683 */
6684
6685 #if _FFR_USE_SEM_LOCKING && SM_CONF_SEM
6686 static int SemId = -1;          /* Semaphore Id */
6687 int SemKey = SM_SEM_KEY;
6688 #  define SEM_LOCK(r)   \
6689         do      \
6690         {       \
6691                 if (SemId >= 0) \
6692                         r = sm_sem_acq(SemId, 0, 1);    \
6693         } while (0)
6694 # define SEM_UNLOCK(r)  \
6695         do      \
6696         {       \
6697                 if (SemId >= 0 && r >= 0)       \
6698                         r = sm_sem_rel(SemId, 0, 1);    \
6699         } while (0)
6700 #else /* _FFR_USE_SEM_LOCKING && SM_CONF_SEM */
6701 # define SEM_LOCK(r)
6702 # define SEM_UNLOCK(r)
6703 #endif /* _FFR_USE_SEM_LOCKING && SM_CONF_SEM */
6704
6705 static void init_sem __P((bool));
6706
6707 static void
6708 init_sem(owner)
6709         bool owner;
6710 {
6711 #if _FFR_USE_SEM_LOCKING
6712 #if SM_CONF_SEM
6713         SemId = sm_sem_start(SemKey, 1, 0, owner);
6714         if (SemId < 0)
6715         {
6716                 sm_syslog(LOG_ERR, NOQID,
6717                         "func=init_sem, sem_key=%ld, sm_sem_start=%d, error=%s",
6718                         (long) SemKey, SemId, sm_errstring(-SemId));
6719                 return;
6720         }
6721         if (owner && RunAsUid != 0)
6722         {
6723                 int r;
6724
6725                 r = sm_semsetowner(SemId, RunAsUid, RunAsGid, 0660);
6726                 if (r != 0)
6727                         sm_syslog(LOG_ERR, NOQID,
6728                                 "key=%ld, sm_semsetowner=%d, RunAsUid=%ld, RunAsGid=%ld",
6729                                 (long) SemKey, r, (long) RunAsUid, (long) RunAsGid);
6730         }
6731 #endif /* SM_CONF_SEM */
6732 #endif /* _FFR_USE_SEM_LOCKING */
6733         return;
6734 }
6735
6736 /*
6737 **  STOP_SEM -- stop semaphore system
6738 **
6739 **      Parameters:
6740 **              owner -- is this the owner of semaphores?
6741 **
6742 **      Returns:
6743 **              none.
6744 */
6745
6746 static void stop_sem __P((bool));
6747
6748 static void
6749 stop_sem(owner)
6750         bool owner;
6751 {
6752 #if _FFR_USE_SEM_LOCKING
6753 #if SM_CONF_SEM
6754         if (owner && SemId >= 0)
6755                 sm_sem_stop(SemId);
6756 #endif
6757 #endif /* _FFR_USE_SEM_LOCKING */
6758         return;
6759 }
6760
6761 # if _FFR_OCC
6762 /*
6763 **  Todo: call occ_close()
6764 **  when closing a connection to decrease #open connections (and rate!)
6765 **  (currently done as hack in deliver())
6766 **  must also be done if connection couldn't be opened (see daemon.c: OCC_CLOSE)
6767 */
6768
6769 /*
6770 **  OCC_EXCEEDED -- is an outgoing connection limit exceeded?
6771 **
6772 **      Parameters:
6773 **              e -- envelope
6774 **              mci -- mail connection information
6775 **              host -- name of host
6776 **              addr -- address of host
6777 **
6778 **      Returns:
6779 **              true iff an outgoing connection limit is exceeded
6780 */
6781
6782 bool
6783 occ_exceeded(e, mci, host, addr)
6784         ENVELOPE *e;
6785         MCI *mci;
6786         const char *host;
6787         SOCKADDR *addr;
6788 {
6789         time_t now;
6790         bool exc;
6791         int r, ratelimit, conclimit;
6792         char *limit; /* allocated from e_rpool by rscheck(), no need to free() */
6793
6794 /* if necessary, some error checking for a number could be done here */
6795 #define STR2INT(r, limit, val)  \
6796         do \
6797         {       \
6798                 if ((r) == EX_OK && (limit) != NULL)    \
6799                         (val) = atoi((limit));  \
6800         } while (0);
6801
6802         if (occ == NULL || e == NULL)
6803                 return false;
6804         ratelimit = conclimit = 0;
6805         limit = NULL;
6806         r = rscheck("oc_rate", host, anynet_ntoa(addr), e, RSF_ADDR,
6807                 12, NULL, NOQID, NULL, &limit);
6808         STR2INT(r, limit, ratelimit);
6809         limit = NULL;
6810         r = rscheck("oc_conc", host, anynet_ntoa(addr), e, RSF_ADDR,
6811                 12, NULL, NOQID, NULL, &limit);
6812         STR2INT(r, limit, conclimit);
6813         now = curtime();
6814
6815         /* lock occ: lock entire shared memory segment */
6816         SEM_LOCK(r);
6817         exc = (bool) conn_limits(e, now, addr, SM_CLFL_EXC, occ, ratelimit,
6818                                 conclimit);
6819         SEM_UNLOCK(r);
6820         if (!exc && mci != NULL)
6821                 mci->mci_flags |= MCIF_OCC_INCR;
6822         return exc;
6823 }
6824
6825 /*
6826 **  OCC_CLOSE -- "close" an outgoing connection: up connection status
6827 **
6828 **      Parameters:
6829 **              e -- envelope
6830 **              mci -- mail connection information
6831 **              host -- name of host
6832 **              addr -- address of host
6833 **
6834 **      Returns:
6835 **              true after successful update
6836 */
6837
6838 bool
6839 occ_close(e, mci, host, addr)
6840         ENVELOPE *e;
6841         MCI *mci;
6842         const char *host;
6843         SOCKADDR *addr;
6844 {
6845         time_t now;
6846 #  if _FFR_USE_SEM_LOCKING && SM_CONF_SEM
6847         int r;
6848 #  endif
6849
6850         if (occ == NULL || e == NULL)
6851                 return false;
6852         if (mci == NULL || mci->mci_state == MCIS_CLOSED ||
6853             bitset(MCIF_CACHED, mci->mci_flags) ||
6854             !bitset(MCIF_OCC_INCR, mci->mci_flags))
6855                 return false;
6856         mci->mci_flags &= ~MCIF_OCC_INCR;
6857
6858         now = curtime();
6859
6860         /* lock occ: lock entire shared memory segment */
6861         SEM_LOCK(r);
6862         (void) conn_limits(e, now, addr, SM_CLFL_EXC, occ, -1, -1);
6863         SEM_UNLOCK(r);
6864         return true;
6865 }
6866 # endif /* _FFR_OCC */
6867
6868 /*
6869 **  UPD_QS -- update information about queue when adding/deleting an entry
6870 **
6871 **      Parameters:
6872 **              e -- envelope.
6873 **              count -- add/remove entry (+1/0/-1: add/no change/remove)
6874 **              space -- update the space available as well.
6875 **                      (>0/0/<0: add/no change/remove)
6876 **              where -- caller (for logging)
6877 **
6878 **      Returns:
6879 **              none.
6880 **
6881 **      Side Effects:
6882 **              Modifies available space in filesystem.
6883 **              Changes number of entries in queue directory.
6884 */
6885
6886 void
6887 upd_qs(e, count, space, where)
6888         ENVELOPE *e;
6889         int count;
6890         int space;
6891         char *where;
6892 {
6893         short fidx;
6894         int idx;
6895 # if _FFR_USE_SEM_LOCKING
6896         int r;
6897 # endif
6898         long s;
6899
6900         if (ShmId == SM_SHM_NO_ID || e == NULL)
6901                 return;
6902         if (e->e_qgrp == NOQGRP || e->e_qdir == NOQDIR)
6903                 return;
6904         idx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_idx;
6905         if (tTd(73,2))
6906                 sm_dprintf("func=upd_qs, count=%d, space=%d, where=%s, idx=%d, entries=%d\n",
6907                         count, space, where, idx, QSHM_ENTRIES(idx));
6908
6909         /* XXX in theory this needs to be protected with a mutex */
6910         if (QSHM_ENTRIES(idx) >= 0 && count != 0)
6911         {
6912                 SEM_LOCK(r);
6913                 QSHM_ENTRIES(idx) += count;
6914                 SEM_UNLOCK(r);
6915         }
6916
6917         fidx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_fsysidx;
6918         if (fidx < 0)
6919                 return;
6920
6921         /* update available space also?  (might be loseqfile) */
6922         if (space == 0)
6923                 return;
6924
6925         /* convert size to blocks; this causes rounding errors */
6926         s = e->e_msgsize / FILE_SYS_BLKSIZE(fidx);
6927         if (s == 0)
6928                 return;
6929
6930         /* XXX in theory this needs to be protected with a mutex */
6931         if (space > 0)
6932                 FILE_SYS_AVAIL(fidx) += s;
6933         else
6934                 FILE_SYS_AVAIL(fidx) -= s;
6935
6936 }
6937
6938 static bool write_key_file __P((char *, long));
6939 static long read_key_file __P((char *, long));
6940
6941 /*
6942 **  WRITE_KEY_FILE -- record some key into a file.
6943 **
6944 **      Parameters:
6945 **              keypath -- file name.
6946 **              key -- key to write.
6947 **
6948 **      Returns:
6949 **              true iff file could be written.
6950 **
6951 **      Side Effects:
6952 **              writes file.
6953 */
6954
6955 static bool
6956 write_key_file(keypath, key)
6957         char *keypath;
6958         long key;
6959 {
6960         bool ok;
6961         long sff;
6962         SM_FILE_T *keyf;
6963
6964         ok = false;
6965         if (keypath == NULL || *keypath == '\0')
6966                 return ok;
6967         sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT;
6968         if (TrustedUid != 0 && RealUid == TrustedUid)
6969                 sff |= SFF_OPENASROOT;
6970         keyf = safefopen(keypath, O_WRONLY|O_TRUNC, FileMode, sff);
6971         if (keyf == NULL)
6972         {
6973                 sm_syslog(LOG_ERR, NOQID, "unable to write %s: %s",
6974                           keypath, sm_errstring(errno));
6975         }
6976         else
6977         {
6978                 if (geteuid() == 0 && RunAsUid != 0)
6979                 {
6980 #  if HASFCHOWN
6981                         int fd;
6982
6983                         fd = keyf->f_file;
6984                         if (fd >= 0 && fchown(fd, RunAsUid, -1) < 0)
6985                         {
6986                                 int err = errno;
6987
6988                                 sm_syslog(LOG_ALERT, NOQID,
6989                                           "ownership change on %s to %ld failed: %s",
6990                                           keypath, (long) RunAsUid, sm_errstring(err));
6991                         }
6992 #  endif /* HASFCHOWN */
6993                 }
6994                 ok = sm_io_fprintf(keyf, SM_TIME_DEFAULT, "%ld\n", key) !=
6995                      SM_IO_EOF;
6996                 ok = (sm_io_close(keyf, SM_TIME_DEFAULT) != SM_IO_EOF) && ok;
6997         }
6998         return ok;
6999 }
7000
7001 /*
7002 **  READ_KEY_FILE -- read a key from a file.
7003 **
7004 **      Parameters:
7005 **              keypath -- file name.
7006 **              key -- default key.
7007 **
7008 **      Returns:
7009 **              key.
7010 */
7011
7012 static long
7013 read_key_file(keypath, key)
7014         char *keypath;
7015         long key;
7016 {
7017         int r;
7018         long sff, n;
7019         SM_FILE_T *keyf;
7020
7021         if (keypath == NULL || *keypath == '\0')
7022                 return key;
7023         sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY;
7024         if (RealUid == 0 || (TrustedUid != 0 && RealUid == TrustedUid))
7025                 sff |= SFF_OPENASROOT;
7026         keyf = safefopen(keypath, O_RDONLY, FileMode, sff);
7027         if (keyf == NULL)
7028         {
7029                 sm_syslog(LOG_ERR, NOQID, "unable to read %s: %s",
7030                           keypath, sm_errstring(errno));
7031         }
7032         else
7033         {
7034                 r = sm_io_fscanf(keyf, SM_TIME_DEFAULT, "%ld", &n);
7035                 if (r == 1)
7036                         key = n;
7037                 (void) sm_io_close(keyf, SM_TIME_DEFAULT);
7038         }
7039         return key;
7040 }
7041
7042 /*
7043 **  INIT_SHM -- initialize shared memory structure
7044 **
7045 **      Initialize or attach to shared memory segment.
7046 **      Currently it is not a fatal error if this doesn't work.
7047 **      However, it causes us to have a "fallback" storage location
7048 **      for everything that is supposed to be in the shared memory,
7049 **      which makes the code slightly ugly.
7050 **
7051 **      Parameters:
7052 **              qn -- number of queue directories.
7053 **              owner -- owner of shared memory.
7054 **              hash -- identifies data that is stored in shared memory.
7055 **
7056 **      Returns:
7057 **              none.
7058 */
7059
7060 static void init_shm __P((int, bool, unsigned int));
7061
7062 static void
7063 init_shm(qn, owner, hash)
7064         int qn;
7065         bool owner;
7066         unsigned int hash;
7067 {
7068         int i;
7069         int count;
7070         int save_errno;
7071         bool keyselect;
7072
7073         PtrFileSys = &FileSys[0];
7074         PNumFileSys = &Numfilesys;
7075 /* if this "key" is specified: select one yourself */
7076 #define SEL_SHM_KEY     ((key_t) -1)
7077 #define FIRST_SHM_KEY   25
7078
7079         /* This allows us to disable shared memory at runtime. */
7080         if (ShmKey == 0)
7081                 return;
7082
7083         count = 0;
7084         shms = SM_T_SIZE + qn * sizeof(QUEUE_SHM_T);
7085         keyselect = ShmKey == SEL_SHM_KEY;
7086         if (keyselect)
7087         {
7088                 if (owner)
7089                         ShmKey = FIRST_SHM_KEY;
7090                 else
7091                 {
7092                         errno = 0;
7093                         ShmKey = read_key_file(ShmKeyFile, ShmKey);
7094                         keyselect = false;
7095                         if (ShmKey == SEL_SHM_KEY)
7096                         {
7097                                 save_errno = (errno != 0) ? errno : EINVAL;
7098                                 goto error;
7099                         }
7100                 }
7101         }
7102         for (;;)
7103         {
7104                 /* allow read/write access for group? */
7105                 Pshm = sm_shmstart(ShmKey, shms,
7106                                 SHM_R|SHM_W|(SHM_R>>3)|(SHM_W>>3),
7107                                 &ShmId, owner);
7108                 save_errno = errno;
7109                 if (Pshm != NULL || !sm_file_exists(save_errno))
7110                         break;
7111                 if (++count >= 3)
7112                 {
7113                         if (keyselect)
7114                         {
7115                                 ++ShmKey;
7116
7117                                 /* back where we started? */
7118                                 if (ShmKey == SEL_SHM_KEY)
7119                                         break;
7120                                 continue;
7121                         }
7122                         break;
7123                 }
7124
7125                 /* only sleep if we are at the first key */
7126                 if (!keyselect || ShmKey == SEL_SHM_KEY)
7127                         sleep(count);
7128         }
7129         if (Pshm != NULL)
7130         {
7131                 int *p;
7132
7133                 if (keyselect)
7134                         (void) write_key_file(ShmKeyFile, (long) ShmKey);
7135                 if (owner && RunAsUid != 0)
7136                 {
7137                         i = sm_shmsetowner(ShmId, RunAsUid, RunAsGid, 0660);
7138                         if (i != 0)
7139                                 sm_syslog(LOG_ERR, NOQID,
7140                                         "key=%ld, sm_shmsetowner=%d, RunAsUid=%ld, RunAsGid=%ld",
7141                                         (long) ShmKey, i, (long) RunAsUid, (long) RunAsGid);
7142                 }
7143                 p = (int *) Pshm;
7144                 if (owner)
7145                 {
7146                         *p = (int) shms;
7147                         *((pid_t *) SHM_OFF_PID(Pshm)) = CurrentPid;
7148                         p = (int *) SHM_OFF_TAG(Pshm);
7149                         *p = hash;
7150                 }
7151                 else
7152                 {
7153                         if (*p != (int) shms)
7154                         {
7155                                 save_errno = EINVAL;
7156                                 cleanup_shm(false);
7157                                 goto error;
7158                         }
7159                         p = (int *) SHM_OFF_TAG(Pshm);
7160                         if (*p != (int) hash)
7161                         {
7162                                 save_errno = EINVAL;
7163                                 cleanup_shm(false);
7164                                 goto error;
7165                         }
7166
7167                         /*
7168                         **  XXX how to check the pid?
7169                         **  Read it from the pid-file? That does
7170                         **  not need to exist.
7171                         **  We could disable shm if we can't confirm
7172                         **  that it is the right one.
7173                         */
7174                 }
7175
7176                 PtrFileSys = (FILESYS *) OFF_FILE_SYS(Pshm);
7177                 PNumFileSys = (int *) OFF_NUM_FILE_SYS(Pshm);
7178                 QShm = (QUEUE_SHM_T *) OFF_QUEUE_SHM(Pshm);
7179                 PRSATmpCnt = (int *) OFF_RSA_TMP_CNT(Pshm);
7180                 *PRSATmpCnt = 0;
7181 # if _FFR_OCC
7182                 occ = (CHash_T *) OFF_OCC_SHM(Pshm);
7183 # endif
7184                 if (owner)
7185                 {
7186                         /* initialize values in shared memory */
7187                         NumFileSys = 0;
7188                         for (i = 0; i < qn; i++)
7189                                 QShm[i].qs_entries = -1;
7190 # if _FFR_OCC
7191                         memset(occ, 0, OCC_SIZE);
7192 # endif
7193                 }
7194                 init_sem(owner);
7195                 return;
7196         }
7197   error:
7198         if (LogLevel > (owner ? 8 : 11))
7199         {
7200                 sm_syslog(owner ? LOG_ERR : LOG_NOTICE, NOQID,
7201                           "can't %s shared memory, key=%ld: %s",
7202                           owner ? "initialize" : "attach to",
7203                           (long) ShmKey, sm_errstring(save_errno));
7204         }
7205 }
7206 #endif /* SM_CONF_SHM */
7207
7208
7209 /*
7210 **  SETUP_QUEUES -- set up all queue groups
7211 **
7212 **      Parameters:
7213 **              owner -- owner of shared memory?
7214 **
7215 **      Returns:
7216 **              none.
7217 **
7218 #if SM_CONF_SHM
7219 **      Side Effects:
7220 **              attaches shared memory.
7221 #endif * SM_CONF_SHM *
7222 */
7223
7224 void
7225 setup_queues(owner)
7226         bool owner;
7227 {
7228         int i, qn, len;
7229         unsigned int hashval;
7230         time_t now;
7231         char basedir[MAXPATHLEN];
7232         struct stat st;
7233
7234         /*
7235         **  Determine basedir for all queue directories.
7236         **  All queue directories must be (first level) subdirectories
7237         **  of the basedir.  The basedir is the QueueDir
7238         **  without wildcards, but with trailing /
7239         */
7240
7241         hashval = 0;
7242         errno = 0;
7243         len = sm_strlcpy(basedir, QueueDir, sizeof(basedir));
7244
7245         /* Provide space for trailing '/' */
7246         if (len >= sizeof(basedir) - 1)
7247         {
7248                 syserr("QueueDirectory: path too long: %d,  max %d",
7249                         len, (int) sizeof(basedir) - 1);
7250                 ExitStat = EX_CONFIG;
7251                 return;
7252         }
7253         SM_ASSERT(len > 0);
7254         if (basedir[len - 1] == '*')
7255         {
7256                 char *cp;
7257
7258                 cp = SM_LAST_DIR_DELIM(basedir);
7259                 if (cp == NULL)
7260                 {
7261                         syserr("QueueDirectory: can not wildcard relative path \"%s\"",
7262                                 QueueDir);
7263                         if (tTd(41, 2))
7264                                 sm_dprintf("setup_queues: \"%s\": Can not wildcard relative path.\n",
7265                                         QueueDir);
7266                         ExitStat = EX_CONFIG;
7267                         return;
7268                 }
7269
7270                 /* cut off wildcard pattern */
7271                 *++cp = '\0';
7272                 len = cp - basedir;
7273         }
7274         else if (!SM_IS_DIR_DELIM(basedir[len - 1]))
7275         {
7276                 /* append trailing slash since it is a directory */
7277                 basedir[len] = '/';
7278                 basedir[++len] = '\0';
7279         }
7280
7281         /* len counts up to the last directory delimiter */
7282         SM_ASSERT(basedir[len - 1] == '/');
7283
7284         if (chdir(basedir) < 0)
7285         {
7286                 int save_errno = errno;
7287
7288                 syserr("can not chdir(%s)", basedir);
7289                 if (save_errno == EACCES)
7290                         (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
7291                                 "Program mode requires special privileges, e.g., root or TrustedUser.\n");
7292                 if (tTd(41, 2))
7293                         sm_dprintf("setup_queues: \"%s\": %s\n",
7294                                    basedir, sm_errstring(errno));
7295                 ExitStat = EX_CONFIG;
7296                 return;
7297         }
7298 #if SM_CONF_SHM
7299         hashval = hash_q(basedir, hashval);
7300 #endif
7301
7302         /* initialize for queue runs */
7303         DoQueueRun = false;
7304         now = curtime();
7305         for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
7306                 Queue[i]->qg_nextrun = now;
7307
7308
7309         if (UseMSP && OpMode != MD_TEST)
7310         {
7311                 long sff = SFF_CREAT;
7312
7313                 if (stat(".", &st) < 0)
7314                 {
7315                         syserr("can not stat(%s)", basedir);
7316                         if (tTd(41, 2))
7317                                 sm_dprintf("setup_queues: \"%s\": %s\n",
7318                                            basedir, sm_errstring(errno));
7319                         ExitStat = EX_CONFIG;
7320                         return;
7321                 }
7322                 if (RunAsUid == 0)
7323                         sff |= SFF_ROOTOK;
7324
7325                 /*
7326                 **  Check queue directory permissions.
7327                 **      Can we write to a group writable queue directory?
7328                 */
7329
7330                 if (bitset(S_IWGRP, QueueFileMode) &&
7331                     bitset(S_IWGRP, st.st_mode) &&
7332                     safefile(" ", RunAsUid, RunAsGid, RunAsUserName, sff,
7333                              QueueFileMode, NULL) != 0)
7334                 {
7335                         syserr("can not write to queue directory %s (RunAsGid=%ld, required=%ld)",
7336                                 basedir, (long) RunAsGid, (long) st.st_gid);
7337                 }
7338                 if (bitset(S_IWOTH|S_IXOTH, st.st_mode))
7339                 {
7340 #if _FFR_MSP_PARANOIA
7341                         syserr("dangerous permissions=%o on queue directory %s",
7342                                 (unsigned int) st.st_mode, basedir);
7343 #else
7344                         if (LogLevel > 0)
7345                                 sm_syslog(LOG_ERR, NOQID,
7346                                           "dangerous permissions=%o on queue directory %s",
7347                                           (unsigned int) st.st_mode, basedir);
7348 #endif /* _FFR_MSP_PARANOIA */
7349                 }
7350 #if _FFR_MSP_PARANOIA
7351                 if (NumQueue > 1)
7352                         syserr("can not use multiple queues for MSP");
7353 #endif
7354         }
7355
7356         /* initial number of queue directories */
7357         qn = 0;
7358         for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
7359                 qn = multiqueue_cache(basedir, len, Queue[i], qn, &hashval);
7360
7361 #if SM_CONF_SHM
7362         init_shm(qn, owner, hashval);
7363         i = filesys_setup(owner || ShmId == SM_SHM_NO_ID);
7364         if (i == FSF_NOT_FOUND)
7365         {
7366                 /*
7367                 **  We didn't get the right filesystem data
7368                 **  This may happen if we don't have the right shared memory.
7369                 **  So let's do this without shared memory.
7370                 */
7371
7372                 SM_ASSERT(!owner);
7373                 cleanup_shm(false);     /* release shared memory */
7374                 i = filesys_setup(false);
7375                 if (i < 0)
7376                         syserr("filesys_setup failed twice, result=%d", i);
7377                 else if (LogLevel > 8)
7378                         sm_syslog(LOG_WARNING, NOQID,
7379                                   "shared memory does not contain expected data, ignored");
7380         }
7381 #else /* SM_CONF_SHM */
7382         i = filesys_setup(true);
7383 #endif /* SM_CONF_SHM */
7384         if (i < 0)
7385                 ExitStat = EX_CONFIG;
7386 }
7387
7388 #if SM_CONF_SHM
7389 /*
7390 **  CLEANUP_SHM -- do some cleanup work for shared memory etc
7391 **
7392 **      Parameters:
7393 **              owner -- owner of shared memory?
7394 **
7395 **      Returns:
7396 **              none.
7397 **
7398 **      Side Effects:
7399 **              detaches shared memory.
7400 */
7401
7402 void
7403 cleanup_shm(owner)
7404         bool owner;
7405 {
7406         if (ShmId != SM_SHM_NO_ID)
7407         {
7408                 if (sm_shmstop(Pshm, ShmId, owner) < 0 && LogLevel > 8)
7409                         sm_syslog(LOG_INFO, NOQID, "sm_shmstop failed=%s",
7410                                   sm_errstring(errno));
7411                 Pshm = NULL;
7412                 ShmId = SM_SHM_NO_ID;
7413         }
7414         stop_sem(owner);
7415 }
7416 #endif /* SM_CONF_SHM */
7417
7418 /*
7419 **  CLEANUP_QUEUES -- do some cleanup work for queues
7420 **
7421 **      Parameters:
7422 **              none.
7423 **
7424 **      Returns:
7425 **              none.
7426 **
7427 */
7428
7429 void
7430 cleanup_queues()
7431 {
7432         sync_queue_time();
7433 }
7434 /*
7435 **  SET_DEF_QUEUEVAL -- set default values for a queue group.
7436 **
7437 **      Parameters:
7438 **              qg -- queue group
7439 **              all -- set all values (true for default group)?
7440 **
7441 **      Returns:
7442 **              none.
7443 **
7444 **      Side Effects:
7445 **              sets default values for the queue group.
7446 */
7447
7448 void
7449 set_def_queueval(qg, all)
7450         QUEUEGRP *qg;
7451         bool all;
7452 {
7453         if (bitnset(QD_DEFINED, qg->qg_flags))
7454                 return;
7455         if (all)
7456                 qg->qg_qdir = QueueDir;
7457 #if _FFR_QUEUE_GROUP_SORTORDER
7458         qg->qg_sortorder = QueueSortOrder;
7459 #endif
7460         qg->qg_maxqrun = all ? MaxRunnersPerQueue : -1;
7461         qg->qg_nice = NiceQueueRun;
7462 }
7463 /*
7464 **  MAKEQUEUE -- define a new queue.
7465 **
7466 **      Parameters:
7467 **              line -- description of queue.  This is in labeled fields.
7468 **                      The fields are:
7469 **                         F -- the flags associated with the queue
7470 **                         I -- the interval between running the queue
7471 **                         J -- the maximum # of jobs in work list
7472 **                         [M -- the maximum # of jobs in a queue run]
7473 **                         N -- the niceness at which to run
7474 **                         P -- the path to the queue
7475 **                         S -- the queue sorting order
7476 **                         R -- number of parallel queue runners
7477 **                         r -- max recipients per envelope
7478 **                      The first word is the canonical name of the queue.
7479 **              qdef -- this is a 'Q' definition from .cf
7480 **
7481 **      Returns:
7482 **              none.
7483 **
7484 **      Side Effects:
7485 **              enters the queue into the queue table.
7486 */
7487
7488 void
7489 makequeue(line, qdef)
7490         char *line;
7491         bool qdef;
7492 {
7493         register char *p;
7494         register QUEUEGRP *qg;
7495         register STAB *s;
7496         int i;
7497         char fcode;
7498
7499         /* allocate a queue and set up defaults */
7500         qg = (QUEUEGRP *) xalloc(sizeof(*qg));
7501         memset((char *) qg, '\0', sizeof(*qg));
7502
7503         if (line[0] == '\0')
7504         {
7505                 syserr("name required for queue");
7506                 return;
7507         }
7508
7509         /* collect the queue name */
7510         for (p = line;
7511              *p != '\0' && *p != ',' && !(SM_ISSPACE(*p));
7512              p++)
7513                 continue;
7514         if (*p != '\0')
7515                 *p++ = '\0';
7516         qg->qg_name = newstr(line);
7517
7518         /* set default values, can be overridden below */
7519         set_def_queueval(qg, false);
7520
7521         /* now scan through and assign info from the fields */
7522         while (*p != '\0')
7523         {
7524                 auto char *delimptr;
7525
7526                 while (*p != '\0' && (*p == ',' || (SM_ISSPACE(*p))))
7527                         p++;
7528
7529                 /* p now points to field code */
7530                 fcode = *p;
7531                 while (*p != '\0' && *p != '=' && *p != ',')
7532                         p++;
7533                 if (*p++ != '=')
7534                 {
7535                         syserr("queue %s: `=' expected", qg->qg_name);
7536                         return;
7537                 }
7538                 while (SM_ISSPACE(*p))
7539                         p++;
7540
7541                 /* p now points to the field body */
7542                 p = munchstring(p, &delimptr, ',');
7543
7544                 /* install the field into the queue struct */
7545                 switch (fcode)
7546                 {
7547                   case 'P':             /* pathname */
7548                         if (*p == '\0')
7549                                 syserr("queue %s: empty path name",
7550                                         qg->qg_name);
7551                         else
7552                                 qg->qg_qdir = newstr(p);
7553                         break;
7554
7555                   case 'F':             /* flags */
7556                         for (; *p != '\0'; p++)
7557                                 if (!(SM_ISSPACE(*p)))
7558                                         setbitn(*p, qg->qg_flags);
7559                         break;
7560
7561                         /*
7562                         **  Do we need two intervals here:
7563                         **  One for persistent queue runners,
7564                         **  one for "normal" queue runs?
7565                         */
7566
7567                   case 'I':     /* interval between running the queue */
7568                         qg->qg_queueintvl = convtime(p, 'm');
7569                         break;
7570
7571                   case 'N':             /* run niceness */
7572                         qg->qg_nice = atoi(p);
7573                         break;
7574
7575                   case 'R':             /* maximum # of runners for the group */
7576                         i = atoi(p);
7577
7578                         /* can't have more runners than allowed total */
7579                         if (MaxQueueChildren > 0 && i > MaxQueueChildren)
7580                         {
7581                                 qg->qg_maxqrun = MaxQueueChildren;
7582                                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
7583                                                      "Q=%s: R=%d exceeds MaxQueueChildren=%d, set to MaxQueueChildren\n",
7584                                                      qg->qg_name, i,
7585                                                      MaxQueueChildren);
7586                         }
7587                         else
7588                                 qg->qg_maxqrun = i;
7589                         break;
7590
7591                   case 'J':             /* maximum # of jobs in work list */
7592                         qg->qg_maxlist = atoi(p);
7593                         break;
7594
7595                   case 'r':             /* max recipients per envelope */
7596                         qg->qg_maxrcpt = atoi(p);
7597                         break;
7598
7599 #if _FFR_QUEUE_GROUP_SORTORDER
7600                   case 'S':             /* queue sorting order */
7601                         switch (*p)
7602                         {
7603                           case 'h':     /* Host first */
7604                           case 'H':
7605                                 qg->qg_sortorder = QSO_BYHOST;
7606                                 break;
7607
7608                           case 'p':     /* Priority order */
7609                           case 'P':
7610                                 qg->qg_sortorder = QSO_BYPRIORITY;
7611                                 break;
7612
7613                           case 't':     /* Submission time */
7614                           case 'T':
7615                                 qg->qg_sortorder = QSO_BYTIME;
7616                                 break;
7617
7618                           case 'f':     /* File name */
7619                           case 'F':
7620                                 qg->qg_sortorder = QSO_BYFILENAME;
7621                                 break;
7622
7623                           case 'm':     /* Modification time */
7624                           case 'M':
7625                                 qg->qg_sortorder = QSO_BYMODTIME;
7626                                 break;
7627
7628                           case 'r':     /* Random */
7629                           case 'R':
7630                                 qg->qg_sortorder = QSO_RANDOM;
7631                                 break;
7632
7633 # if _FFR_RHS
7634                           case 's':     /* Shuffled host name */
7635                           case 'S':
7636                                 qg->qg_sortorder = QSO_BYSHUFFLE;
7637                                 break;
7638 # endif /* _FFR_RHS */
7639
7640                           case 'n':     /* none */
7641                           case 'N':
7642                                 qg->qg_sortorder = QSO_NONE;
7643                                 break;
7644
7645                           default:
7646                                 syserr("Invalid queue sort order \"%s\"", p);
7647                         }
7648                         break;
7649 #endif /* _FFR_QUEUE_GROUP_SORTORDER */
7650
7651                   default:
7652                         syserr("Q%s: unknown queue equate %c=",
7653                                qg->qg_name, fcode);
7654                         break;
7655                 }
7656
7657                 p = delimptr;
7658         }
7659
7660 #if !HASNICE
7661         if (qg->qg_nice != NiceQueueRun)
7662         {
7663                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
7664                                      "Q%s: Warning: N= set on system that doesn't support nice()\n",
7665                                      qg->qg_name);
7666         }
7667 #endif /* !HASNICE */
7668
7669         /* do some rationality checking */
7670         if (NumQueue >= MAXQUEUEGROUPS)
7671         {
7672                 syserr("too many queue groups defined (%d max)",
7673                         MAXQUEUEGROUPS);
7674                 return;
7675         }
7676
7677         if (qg->qg_qdir == NULL)
7678         {
7679                 if (QueueDir == NULL || *QueueDir == '\0')
7680                 {
7681                         syserr("QueueDir must be defined before queue groups");
7682                         return;
7683                 }
7684                 qg->qg_qdir = newstr(QueueDir);
7685         }
7686
7687         if (qg->qg_maxqrun > 1 && !bitnset(QD_FORK, qg->qg_flags))
7688         {
7689                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
7690                                      "Warning: Q=%s: R=%d: multiple queue runners specified\n\tbut flag '%c' is not set\n",
7691                                      qg->qg_name, qg->qg_maxqrun, QD_FORK);
7692         }
7693
7694         /* enter the queue into the symbol table */
7695         if (tTd(37, 8))
7696                 sm_syslog(LOG_INFO, NOQID,
7697                           "Adding %s to stab, path: %s", qg->qg_name,
7698                           qg->qg_qdir);
7699         s = stab(qg->qg_name, ST_QUEUE, ST_ENTER);
7700         if (s->s_quegrp != NULL)
7701         {
7702                 i = s->s_quegrp->qg_index;
7703
7704                 /* XXX what about the pointers inside this struct? */
7705                 sm_free(s->s_quegrp); /* XXX */
7706         }
7707         else
7708                 i = NumQueue++;
7709         Queue[i] = s->s_quegrp = qg;
7710         qg->qg_index = i;
7711
7712         /* set default value for max queue runners */
7713         if (qg->qg_maxqrun < 0)
7714         {
7715                 if (MaxRunnersPerQueue > 0)
7716                         qg->qg_maxqrun = MaxRunnersPerQueue;
7717                 else
7718                         qg->qg_maxqrun = 1;
7719         }
7720         if (qdef)
7721                 setbitn(QD_DEFINED, qg->qg_flags);
7722 }
7723 #if 0
7724 /*
7725 **  HASHFQN -- calculate a hash value for a fully qualified host name
7726 **
7727 **      Arguments:
7728 **              fqn -- an all lower-case host.domain string
7729 **              buckets -- the number of buckets (queue directories)
7730 **
7731 **      Returns:
7732 **              a bucket number (signed integer)
7733 **              -1 on error
7734 **
7735 **      Contributed by Exactis.com, Inc.
7736 */
7737
7738 int
7739 hashfqn(fqn, buckets)
7740         register char *fqn;
7741         int buckets;
7742 {
7743         register char *p;
7744         register int h = 0, hash, cnt;
7745
7746         if (fqn == NULL)
7747                 return -1;
7748
7749         /*
7750         **  A variation on the gdb hash
7751         **  This is the best as of Feb 19, 1996 --bcx
7752         */
7753
7754         p = fqn;
7755         h = 0x238F13AF * strlen(p);
7756         for (cnt = 0; *p != 0; ++p, cnt++)
7757         {
7758                 h = (h + (*p << (cnt * 5 % 24))) & 0x7FFFFFFF;
7759         }
7760         h = (1103515243 * h + 12345) & 0x7FFFFFFF;
7761         if (buckets < 2)
7762                 hash = 0;
7763         else
7764                 hash = (h % buckets);
7765
7766         return hash;
7767 }
7768 #endif /* 0 */
7769
7770 /*
7771 **  A structure for sorting Queue according to maxqrun without
7772 **      screwing up Queue itself.
7773 */
7774
7775 struct sortqgrp
7776 {
7777         int sg_idx;             /* original index */
7778         int sg_maxqrun;         /* max queue runners */
7779 };
7780 typedef struct sortqgrp SORTQGRP_T;
7781 static int cmpidx __P((const void *, const void *));
7782
7783 static int
7784 cmpidx(a, b)
7785         const void *a;
7786         const void *b;
7787 {
7788         /* The sort is highest to lowest, so the comparison is reversed */
7789         if (((SORTQGRP_T *)a)->sg_maxqrun < ((SORTQGRP_T *)b)->sg_maxqrun)
7790                 return 1;
7791         else if (((SORTQGRP_T *)a)->sg_maxqrun > ((SORTQGRP_T *)b)->sg_maxqrun)
7792                 return -1;
7793         else
7794                 return 0;
7795 }
7796
7797 /*
7798 **  MAKEWORKGROUPS -- balance queue groups into work groups per MaxQueueChildren
7799 **
7800 **  Take the now defined queue groups and assign them to work groups.
7801 **  This is done to balance out the number of concurrently active
7802 **  queue runners such that MaxQueueChildren is not exceeded. This may
7803 **  result in more than one queue group per work group. In such a case
7804 **  the number of running queue groups in that work group will have no
7805 **  more than the work group maximum number of runners (a "fair" portion
7806 **  of MaxQueueRunners). All queue groups within a work group will get a
7807 **  chance at running.
7808 **
7809 **      Parameters:
7810 **              none.
7811 **
7812 **      Returns:
7813 **              nothing.
7814 **
7815 **      Side Effects:
7816 **              Sets up WorkGrp structure.
7817 */
7818
7819 void
7820 makeworkgroups()
7821 {
7822         int i, j, total_runners, dir, h;
7823         SORTQGRP_T si[MAXQUEUEGROUPS + 1];
7824
7825         total_runners = 0;
7826         if (NumQueue == 1 && strcmp(Queue[0]->qg_name, "mqueue") == 0)
7827         {
7828                 /*
7829                 **  There is only the "mqueue" queue group (a default)
7830                 **  containing all of the queues. We want to provide to
7831                 **  this queue group the maximum allowable queue runners.
7832                 **  To match older behavior (8.10/8.11) we'll try for
7833                 **  1 runner per queue capping it at MaxQueueChildren.
7834                 **  So if there are N queues, then there will be N runners
7835                 **  for the "mqueue" queue group (where N is kept less than
7836                 **  MaxQueueChildren).
7837                 */
7838
7839                 NumWorkGroups = 1;
7840                 WorkGrp[0].wg_numqgrp = 1;
7841                 WorkGrp[0].wg_qgs = (QUEUEGRP **) xalloc(sizeof(QUEUEGRP *));
7842                 WorkGrp[0].wg_qgs[0] = Queue[0];
7843                 if (MaxQueueChildren > 0 &&
7844                     Queue[0]->qg_numqueues > MaxQueueChildren)
7845                         WorkGrp[0].wg_runners = MaxQueueChildren;
7846                 else
7847                         WorkGrp[0].wg_runners = Queue[0]->qg_numqueues;
7848
7849                 Queue[0]->qg_wgrp = 0;
7850
7851                 /* can't have more runners than allowed total */
7852                 if (MaxQueueChildren > 0 &&
7853                     Queue[0]->qg_maxqrun > MaxQueueChildren)
7854                         Queue[0]->qg_maxqrun = MaxQueueChildren;
7855                 WorkGrp[0].wg_maxact = Queue[0]->qg_maxqrun;
7856                 WorkGrp[0].wg_lowqintvl = Queue[0]->qg_queueintvl;
7857                 return;
7858         }
7859
7860         for (i = 0; i < NumQueue; i++)
7861         {
7862                 si[i].sg_maxqrun = Queue[i]->qg_maxqrun;
7863                 si[i].sg_idx = i;
7864
7865                 /* Hack to make sure BounceQueue ends up last */
7866                 if (IS_BOUNCE_QUEUE(i))
7867                         si[i].sg_maxqrun = INT_MIN;
7868         }
7869         qsort(si, NumQueue, sizeof(si[0]), cmpidx);
7870
7871         NumWorkGroups = 0;
7872         for (i = 0; i < NumQueue; i++)
7873         {
7874                 SKIP_BOUNCE_QUEUE(i)
7875                 total_runners += si[i].sg_maxqrun;
7876                 if (MaxQueueChildren <= 0 || total_runners <= MaxQueueChildren)
7877                         NumWorkGroups++;
7878                 else
7879                         break;
7880         }
7881
7882         if (NumWorkGroups < 1)
7883                 NumWorkGroups = 1; /* gotta have one at least */
7884         else if (NumWorkGroups > MAXWORKGROUPS)
7885                 NumWorkGroups = MAXWORKGROUPS; /* the limit */
7886
7887         /*
7888         **  We now know the number of work groups to pack the queue groups
7889         **  into. The queue groups in 'Queue' are sorted from highest
7890         **  to lowest for the number of runners per queue group.
7891         **  We put the queue groups with the largest number of runners
7892         **  into work groups first. Then the smaller ones are fitted in
7893         **  where it looks best.
7894         */
7895
7896         j = 0;
7897         dir = 1;
7898         for (i = 0; i < NumQueue; i++)
7899         {
7900                 h = si[i].sg_idx;
7901                 if (tTd(41, 49))
7902                         sm_dprintf("sortqg: i=%d, j=%d, h=%d, skip=%d\n",
7903                                 i, j, h, IS_BOUNCE_QUEUE(h));
7904                 SKIP_BOUNCE_QUEUE(h);
7905
7906                 /* a to-and-fro packing scheme, continue from last position */
7907                 if (j >= NumWorkGroups)
7908                 {
7909                         dir = -1;
7910                         j = NumWorkGroups - 1;
7911                 }
7912                 else if (j < 0)
7913                 {
7914                         j = 0;
7915                         dir = 1;
7916                 }
7917
7918                 if (WorkGrp[j].wg_qgs == NULL)
7919                         WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_malloc(sizeof(QUEUEGRP *) *
7920                                                         (WorkGrp[j].wg_numqgrp + 1));
7921                 else
7922                         WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_realloc(WorkGrp[j].wg_qgs,
7923                                                         sizeof(QUEUEGRP *) *
7924                                                         (WorkGrp[j].wg_numqgrp + 1));
7925                 if (WorkGrp[j].wg_qgs == NULL)
7926                 {
7927                         syserr("!cannot allocate memory for work queues, need %d bytes",
7928                                (int) (sizeof(QUEUEGRP *) *
7929                                       (WorkGrp[j].wg_numqgrp + 1)));
7930                 }
7931
7932                 WorkGrp[j].wg_qgs[WorkGrp[j].wg_numqgrp] = Queue[h];
7933                 WorkGrp[j].wg_numqgrp++;
7934                 WorkGrp[j].wg_runners += Queue[h]->qg_maxqrun;
7935                 Queue[h]->qg_wgrp = j;
7936
7937                 if (WorkGrp[j].wg_maxact == 0)
7938                 {
7939                         /* can't have more runners than allowed total */
7940                         if (MaxQueueChildren > 0 &&
7941                             Queue[h]->qg_maxqrun > MaxQueueChildren)
7942                                 Queue[h]->qg_maxqrun = MaxQueueChildren;
7943                         WorkGrp[j].wg_maxact = Queue[h]->qg_maxqrun;
7944                 }
7945
7946                 /*
7947                 **  XXX: must wg_lowqintvl be the GCD?
7948                 **  qg1: 2m, qg2: 3m, minimum: 2m, when do queue runs for
7949                 **  qg2 occur?
7950                 */
7951
7952                 /* keep track of the lowest interval for a persistent runner */
7953                 if (Queue[h]->qg_queueintvl > 0 &&
7954                     WorkGrp[j].wg_lowqintvl < Queue[h]->qg_queueintvl)
7955                         WorkGrp[j].wg_lowqintvl = Queue[h]->qg_queueintvl;
7956                 j += dir;
7957         }
7958         if (tTd(41, 9))
7959         {
7960                 for (i = 0; i < NumWorkGroups; i++)
7961                 {
7962                         sm_dprintf("Workgroup[%d]=", i);
7963                         for (j = 0; j < WorkGrp[i].wg_numqgrp; j++)
7964                         {
7965                                 sm_dprintf("%s, ",
7966                                         WorkGrp[i].wg_qgs[j]->qg_name);
7967                         }
7968                         if (tTd(41, 12))
7969                                 sm_dprintf("lowqintvl=%d",
7970                                         (int) WorkGrp[i].wg_lowqintvl);
7971                         sm_dprintf("\n");
7972                 }
7973         }
7974 }
7975
7976 /*
7977 **  DUP_DF -- duplicate envelope data file
7978 **
7979 **      Copy the data file from the 'old' envelope to the 'new' envelope
7980 **      in the most efficient way possible.
7981 **
7982 **      Create a hard link from the 'old' data file to the 'new' data file.
7983 **      If the old and new queue directories are on different file systems,
7984 **      then the new data file link is created in the old queue directory,
7985 **      and the new queue file will contain a 'd' record pointing to the
7986 **      directory containing the new data file.
7987 **
7988 **      Parameters:
7989 **              old -- old envelope.
7990 **              new -- new envelope.
7991 **
7992 **      Results:
7993 **              Returns true on success, false on failure.
7994 **
7995 **      Side Effects:
7996 **              On success, the new data file is created.
7997 **              On fatal failure, EF_FATALERRS is set in old->e_flags.
7998 */
7999
8000 static bool     dup_df __P((ENVELOPE *, ENVELOPE *));
8001
8002 static bool
8003 dup_df(old, new)
8004         ENVELOPE *old;
8005         ENVELOPE *new;
8006 {
8007         int ofs, nfs, r;
8008         char opath[MAXPATHLEN];
8009         char npath[MAXPATHLEN];
8010
8011         if (!bitset(EF_HAS_DF, old->e_flags))
8012         {
8013                 /*
8014                 **  this can happen if: SuperSafe != True
8015                 **  and a bounce mail is sent that is split.
8016                 */
8017
8018                 queueup(old, false, true);
8019         }
8020         SM_REQUIRE(ISVALIDQGRP(old->e_qgrp) && ISVALIDQDIR(old->e_qdir));
8021         SM_REQUIRE(ISVALIDQGRP(new->e_qgrp) && ISVALIDQDIR(new->e_qdir));
8022
8023         (void) sm_strlcpy(opath, queuename(old, DATAFL_LETTER), sizeof(opath));
8024         (void) sm_strlcpy(npath, queuename(new, DATAFL_LETTER), sizeof(npath));
8025
8026         if (old->e_dfp != NULL)
8027         {
8028                 r = sm_io_setinfo(old->e_dfp, SM_BF_COMMIT, NULL);
8029                 if (r < 0 && errno != EINVAL)
8030                 {
8031                         syserr("@can't commit %s", opath);
8032                         old->e_flags |= EF_FATALERRS;
8033                         return false;
8034                 }
8035         }
8036
8037         /*
8038         **  Attempt to create a hard link, if we think both old and new
8039         **  are on the same file system, otherwise copy the file.
8040         **
8041         **  Don't waste time attempting a hard link unless old and new
8042         **  are on the same file system.
8043         */
8044
8045         SM_REQUIRE(ISVALIDQGRP(old->e_dfqgrp) && ISVALIDQDIR(old->e_dfqdir));
8046         SM_REQUIRE(ISVALIDQGRP(new->e_dfqgrp) && ISVALIDQDIR(new->e_dfqdir));
8047
8048         ofs = Queue[old->e_dfqgrp]->qg_qpaths[old->e_dfqdir].qp_fsysidx;
8049         nfs = Queue[new->e_dfqgrp]->qg_qpaths[new->e_dfqdir].qp_fsysidx;
8050         if (FILE_SYS_DEV(ofs) == FILE_SYS_DEV(nfs))
8051         {
8052                 if (link(opath, npath) == 0)
8053                 {
8054                         new->e_flags |= EF_HAS_DF;
8055                         SYNC_DIR(npath, true);
8056                         return true;
8057                 }
8058                 goto error;
8059         }
8060
8061         /*
8062         **  Can't link across queue directories, so try to create a hard
8063         **  link in the same queue directory as the old df file.
8064         **  The qf file will refer to the new df file using a 'd' record.
8065         */
8066
8067         new->e_dfqgrp = old->e_dfqgrp;
8068         new->e_dfqdir = old->e_dfqdir;
8069         (void) sm_strlcpy(npath, queuename(new, DATAFL_LETTER), sizeof(npath));
8070         if (link(opath, npath) == 0)
8071         {
8072                 new->e_flags |= EF_HAS_DF;
8073                 SYNC_DIR(npath, true);
8074                 return true;
8075         }
8076
8077   error:
8078         if (LogLevel > 0)
8079                 sm_syslog(LOG_ERR, old->e_id,
8080                           "dup_df: can't link %s to %s, error=%s, envelope splitting failed",
8081                           opath, npath, sm_errstring(errno));
8082         return false;
8083 }
8084
8085 /*
8086 **  SPLIT_ENV -- Allocate a new envelope based on a given envelope.
8087 **
8088 **      Parameters:
8089 **              e -- envelope.
8090 **              sendqueue -- sendqueue for new envelope.
8091 **              qgrp -- index of queue group.
8092 **              qdir -- queue directory.
8093 **
8094 **      Results:
8095 **              new envelope.
8096 **
8097 */
8098
8099 static ENVELOPE *split_env __P((ENVELOPE *, ADDRESS *, int, int));
8100
8101 static ENVELOPE *
8102 split_env(e, sendqueue, qgrp, qdir)
8103         ENVELOPE *e;
8104         ADDRESS *sendqueue;
8105         int qgrp;
8106         int qdir;
8107 {
8108         ENVELOPE *ee;
8109
8110         ee = (ENVELOPE *) sm_rpool_malloc_x(e->e_rpool, sizeof(*ee));
8111         STRUCTCOPY(*e, *ee);
8112         ee->e_message = NULL;   /* XXX use original message? */
8113         ee->e_id = NULL;
8114         assign_queueid(ee);
8115         ee->e_sendqueue = sendqueue;
8116         ee->e_flags &= ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS
8117                          |EF_SENDRECEIPT|EF_RET_PARAM|EF_HAS_DF);
8118         ee->e_flags |= EF_NORECEIPT;    /* XXX really? */
8119         ee->e_from.q_state = QS_SENDER;
8120         ee->e_dfp = NULL;
8121         ee->e_lockfp = NULL;
8122         if (e->e_xfp != NULL)
8123                 ee->e_xfp = sm_io_dup(e->e_xfp);
8124
8125         /* failed to dup e->e_xfp, start a new transcript */
8126         if (ee->e_xfp == NULL)
8127                 openxscript(ee);
8128
8129         ee->e_qgrp = ee->e_dfqgrp = qgrp;
8130         ee->e_qdir = ee->e_dfqdir = qdir;
8131         ee->e_errormode = EM_MAIL;
8132         ee->e_statmsg = NULL;
8133         if (e->e_quarmsg != NULL)
8134                 ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool,
8135                                                   e->e_quarmsg);
8136
8137         /*
8138         **  XXX Not sure if this copying is necessary.
8139         **  sendall() does this copying, but I (dm) don't know if that is
8140         **  because of the storage management discipline we were using
8141         **  before rpools were introduced, or if it is because these lists
8142         **  can be modified later.
8143         */
8144
8145         ee->e_header = copyheader(e->e_header, ee->e_rpool);
8146         ee->e_errorqueue = copyqueue(e->e_errorqueue, ee->e_rpool);
8147
8148         return ee;
8149 }
8150
8151 /* return values from split functions, check also below! */
8152 #define SM_SPLIT_FAIL   (0)
8153 #define SM_SPLIT_NONE   (1)
8154 #define SM_SPLIT_NEW(n) (1 + (n))
8155
8156 /*
8157 **  SPLIT_ACROSS_QUEUE_GROUPS
8158 **
8159 **      This function splits an envelope across multiple queue groups
8160 **      based on the queue group of each recipient.
8161 **
8162 **      Parameters:
8163 **              e -- envelope.
8164 **
8165 **      Results:
8166 **              SM_SPLIT_FAIL on failure
8167 **              SM_SPLIT_NONE if no splitting occurred,
8168 **              or 1 + the number of additional envelopes created.
8169 **
8170 **      Side Effects:
8171 **              On success, e->e_sibling points to a list of zero or more
8172 **              additional envelopes, and the associated data files exist
8173 **              on disk.  But the queue files are not created.
8174 **
8175 **              On failure, e->e_sibling is not changed.
8176 **              The order of recipients in e->e_sendqueue is permuted.
8177 **              Abandoned data files for additional envelopes that failed
8178 **              to be created may exist on disk.
8179 */
8180
8181 static int      q_qgrp_compare __P((const void *, const void *));
8182 static int      e_filesys_compare __P((const void *, const void *));
8183
8184 static int
8185 q_qgrp_compare(p1, p2)
8186         const void *p1;
8187         const void *p2;
8188 {
8189         ADDRESS **pq1 = (ADDRESS **) p1;
8190         ADDRESS **pq2 = (ADDRESS **) p2;
8191
8192         return (*pq1)->q_qgrp - (*pq2)->q_qgrp;
8193 }
8194
8195 static int
8196 e_filesys_compare(p1, p2)
8197         const void *p1;
8198         const void *p2;
8199 {
8200         ENVELOPE **pe1 = (ENVELOPE **) p1;
8201         ENVELOPE **pe2 = (ENVELOPE **) p2;
8202         int fs1, fs2;
8203
8204         fs1 = Queue[(*pe1)->e_qgrp]->qg_qpaths[(*pe1)->e_qdir].qp_fsysidx;
8205         fs2 = Queue[(*pe2)->e_qgrp]->qg_qpaths[(*pe2)->e_qdir].qp_fsysidx;
8206         if (FILE_SYS_DEV(fs1) < FILE_SYS_DEV(fs2))
8207                 return -1;
8208         if (FILE_SYS_DEV(fs1) > FILE_SYS_DEV(fs2))
8209                 return 1;
8210         return 0;
8211 }
8212
8213 static int split_across_queue_groups __P((ENVELOPE *));
8214 static int
8215 split_across_queue_groups(e)
8216         ENVELOPE *e;
8217 {
8218         int naddrs, nsplits, i;
8219         bool changed;
8220         char **pvp;
8221         ADDRESS *q, **addrs;
8222         ENVELOPE *ee, *es;
8223         ENVELOPE *splits[MAXQUEUEGROUPS];
8224         char pvpbuf[PSBUFSIZE];
8225
8226         SM_REQUIRE(ISVALIDQGRP(e->e_qgrp));
8227
8228         /* Count addresses and assign queue groups. */
8229         naddrs = 0;
8230         changed = false;
8231         for (q = e->e_sendqueue; q != NULL; q = q->q_next)
8232         {
8233                 if (QS_IS_DEAD(q->q_state))
8234                         continue;
8235                 ++naddrs;
8236
8237                 /* bad addresses and those already sent stay put */
8238                 if (QS_IS_BADADDR(q->q_state) ||
8239                     QS_IS_SENT(q->q_state))
8240                         q->q_qgrp = e->e_qgrp;
8241                 else if (!ISVALIDQGRP(q->q_qgrp))
8242                 {
8243                         /* call ruleset which should return a queue group */
8244                         i = rscap(RS_QUEUEGROUP, q->q_user, NULL, e, &pvp,
8245                                   pvpbuf, sizeof(pvpbuf));
8246                         if (i == EX_OK &&
8247                             pvp != NULL && pvp[0] != NULL &&
8248                             (pvp[0][0] & 0377) == CANONNET &&
8249                             pvp[1] != NULL && pvp[1][0] != '\0')
8250                         {
8251                                 i = name2qid(pvp[1]);
8252                                 if (ISVALIDQGRP(i))
8253                                 {
8254                                         q->q_qgrp = i;
8255                                         changed = true;
8256                                         if (tTd(20, 4))
8257                                                 sm_syslog(LOG_INFO, NOQID,
8258                                                         "queue group name %s -> %d",
8259                                                         pvp[1], i);
8260                                         continue;
8261                                 }
8262                                 else if (LogLevel > 10)
8263                                         sm_syslog(LOG_INFO, NOQID,
8264                                                 "can't find queue group name %s, selection ignored",
8265                                                 pvp[1]);
8266                         }
8267                         if (q->q_mailer != NULL &&
8268                             ISVALIDQGRP(q->q_mailer->m_qgrp))
8269                         {
8270                                 changed = true;
8271                                 q->q_qgrp = q->q_mailer->m_qgrp;
8272                         }
8273                         else if (ISVALIDQGRP(e->e_qgrp))
8274                                 q->q_qgrp = e->e_qgrp;
8275                         else
8276                                 q->q_qgrp = 0;
8277                 }
8278         }
8279
8280         /* only one address? nothing to split. */
8281         if (naddrs <= 1 && !changed)
8282                 return SM_SPLIT_NONE;
8283
8284         /* sort the addresses by queue group */
8285         addrs = sm_rpool_malloc_x(e->e_rpool, naddrs * sizeof(ADDRESS *));
8286         for (i = 0, q = e->e_sendqueue; q != NULL; q = q->q_next)
8287         {
8288                 if (QS_IS_DEAD(q->q_state))
8289                         continue;
8290                 addrs[i++] = q;
8291         }
8292         qsort(addrs, naddrs, sizeof(ADDRESS *), q_qgrp_compare);
8293
8294         /* split into multiple envelopes, by queue group */
8295         nsplits = 0;
8296         es = NULL;
8297         e->e_sendqueue = NULL;
8298         for (i = 0; i < naddrs; ++i)
8299         {
8300                 if (i == naddrs - 1 || addrs[i]->q_qgrp != addrs[i + 1]->q_qgrp)
8301                         addrs[i]->q_next = NULL;
8302                 else
8303                         addrs[i]->q_next = addrs[i + 1];
8304
8305                 /* same queue group as original envelope? */
8306                 if (addrs[i]->q_qgrp == e->e_qgrp)
8307                 {
8308                         if (e->e_sendqueue == NULL)
8309                                 e->e_sendqueue = addrs[i];
8310                         continue;
8311                 }
8312
8313                 /* different queue group than original envelope */
8314                 if (es == NULL || addrs[i]->q_qgrp != es->e_qgrp)
8315                 {
8316                         ee = split_env(e, addrs[i], addrs[i]->q_qgrp, NOQDIR);
8317                         es = ee;
8318                         splits[nsplits++] = ee;
8319                 }
8320         }
8321
8322         /* no splits? return right now. */
8323         if (nsplits <= 0)
8324                 return SM_SPLIT_NONE;
8325
8326         /* assign a queue directory to each additional envelope */
8327         for (i = 0; i < nsplits; ++i)
8328         {
8329                 es = splits[i];
8330 #if 0
8331                 es->e_qdir = pickqdir(Queue[es->e_qgrp], es->e_msgsize, es);
8332 #endif
8333                 if (!setnewqueue(es))
8334                         goto failure;
8335         }
8336
8337         /* sort the additional envelopes by queue file system */
8338         qsort(splits, nsplits, sizeof(ENVELOPE *), e_filesys_compare);
8339
8340         /* create data files for each additional envelope */
8341         if (!dup_df(e, splits[0]))
8342         {
8343                 i = 0;
8344                 goto failure;
8345         }
8346         for (i = 1; i < nsplits; ++i)
8347         {
8348                 /* copy or link to the previous data file */
8349                 if (!dup_df(splits[i - 1], splits[i]))
8350                         goto failure;
8351         }
8352
8353         /* success: prepend the new envelopes to the e->e_sibling list */
8354         for (i = 0; i < nsplits; ++i)
8355         {
8356                 es = splits[i];
8357                 es->e_sibling = e->e_sibling;
8358                 e->e_sibling = es;
8359         }
8360         return SM_SPLIT_NEW(nsplits);
8361
8362         /* failure: clean up */
8363   failure:
8364         if (i > 0)
8365         {
8366                 int j;
8367
8368                 for (j = 0; j < i; j++)
8369                         (void) unlink(queuename(splits[j], DATAFL_LETTER));
8370         }
8371         e->e_sendqueue = addrs[0];
8372         for (i = 0; i < naddrs - 1; ++i)
8373                 addrs[i]->q_next = addrs[i + 1];
8374         addrs[naddrs - 1]->q_next = NULL;
8375         return SM_SPLIT_FAIL;
8376 }
8377
8378 /*
8379 **  SPLIT_WITHIN_QUEUE
8380 **
8381 **      Split an envelope with multiple recipients into several
8382 **      envelopes within the same queue directory, if the number of
8383 **      recipients exceeds the limit for the queue group.
8384 **
8385 **      Parameters:
8386 **              e -- envelope.
8387 **
8388 **      Results:
8389 **              SM_SPLIT_FAIL on failure
8390 **              SM_SPLIT_NONE if no splitting occurred,
8391 **              or 1 + the number of additional envelopes created.
8392 */
8393
8394 #define SPLIT_LOG_LEVEL 8
8395
8396 static int      split_within_queue __P((ENVELOPE *));
8397
8398 static int
8399 split_within_queue(e)
8400         ENVELOPE *e;
8401 {
8402         int maxrcpt, nrcpt, ndead, nsplit, i;
8403         int j, l;
8404         char *lsplits;
8405         ADDRESS *q, **addrs;
8406         ENVELOPE *ee, *firstsibling;
8407
8408         if (!ISVALIDQGRP(e->e_qgrp) || bitset(EF_SPLIT, e->e_flags))
8409                 return SM_SPLIT_NONE;
8410
8411         /* don't bother if there is no recipient limit */
8412         maxrcpt = Queue[e->e_qgrp]->qg_maxrcpt;
8413         if (maxrcpt <= 0)
8414                 return SM_SPLIT_NONE;
8415
8416         /* count recipients */
8417         nrcpt = 0;
8418         for (q = e->e_sendqueue; q != NULL; q = q->q_next)
8419         {
8420                 if (QS_IS_DEAD(q->q_state))
8421                         continue;
8422                 ++nrcpt;
8423         }
8424         if (nrcpt <= maxrcpt)
8425                 return SM_SPLIT_NONE;
8426
8427         /*
8428         **  Preserve the recipient list
8429         **  so that we can restore it in case of error.
8430         **  (But we discard dead addresses.)
8431         */
8432
8433         addrs = sm_rpool_malloc_x(e->e_rpool, nrcpt * sizeof(ADDRESS *));
8434         for (i = 0, q = e->e_sendqueue; q != NULL; q = q->q_next)
8435         {
8436                 if (QS_IS_DEAD(q->q_state))
8437                         continue;
8438                 addrs[i++] = q;
8439         }
8440
8441         /*
8442         **  Partition the recipient list so that bad and sent addresses
8443         **  come first. These will go with the original envelope, and
8444         **  do not count towards the maxrcpt limit.
8445         **  addrs[] does not contain QS_IS_DEAD() addresses.
8446         */
8447
8448         ndead = 0;
8449         for (i = 0; i < nrcpt; ++i)
8450         {
8451                 if (QS_IS_BADADDR(addrs[i]->q_state) ||
8452                     QS_IS_SENT(addrs[i]->q_state) ||
8453                     QS_IS_DEAD(addrs[i]->q_state)) /* for paranoia's sake */
8454                 {
8455                         if (i > ndead)
8456                         {
8457                                 ADDRESS *tmp = addrs[i];
8458
8459                                 addrs[i] = addrs[ndead];
8460                                 addrs[ndead] = tmp;
8461                         }
8462                         ++ndead;
8463                 }
8464         }
8465
8466         /* Check if no splitting required. */
8467         if (nrcpt - ndead <= maxrcpt)
8468                 return SM_SPLIT_NONE;
8469
8470         /* fix links */
8471         for (i = 0; i < nrcpt - 1; ++i)
8472                 addrs[i]->q_next = addrs[i + 1];
8473         addrs[nrcpt - 1]->q_next = NULL;
8474         e->e_sendqueue = addrs[0];
8475
8476         /* prepare buffer for logging */
8477         if (LogLevel > SPLIT_LOG_LEVEL)
8478         {
8479                 l = MAXLINE;
8480                 lsplits = sm_malloc(l);
8481                 if (lsplits != NULL)
8482                         *lsplits = '\0';
8483                 j = 0;
8484         }
8485         else
8486         {
8487                 /* get rid of stupid compiler warnings */
8488                 lsplits = NULL;
8489                 j = l = 0;
8490         }
8491
8492         /* split the envelope */
8493         firstsibling = e->e_sibling;
8494         i = maxrcpt + ndead;
8495         nsplit = 0;
8496         for (;;)
8497         {
8498                 addrs[i - 1]->q_next = NULL;
8499                 ee = split_env(e, addrs[i], e->e_qgrp, e->e_qdir);
8500                 if (!dup_df(e, ee))
8501                 {
8502
8503                         ee = firstsibling;
8504                         while (ee != NULL)
8505                         {
8506                                 (void) unlink(queuename(ee, DATAFL_LETTER));
8507                                 ee = ee->e_sibling;
8508                         }
8509
8510                         /* Error.  Restore e's sibling & recipient lists. */
8511                         e->e_sibling = firstsibling;
8512                         for (i = 0; i < nrcpt - 1; ++i)
8513                                 addrs[i]->q_next = addrs[i + 1];
8514                         if (lsplits != NULL)
8515                                 sm_free(lsplits);
8516                         return SM_SPLIT_FAIL;
8517                 }
8518
8519                 /* prepend the new envelope to e->e_sibling */
8520                 ee->e_sibling = e->e_sibling;
8521                 e->e_sibling = ee;
8522                 ++nsplit;
8523                 if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL)
8524                 {
8525                         if (j >= l - strlen(ee->e_id) - 3)
8526                         {
8527                                 char *p;
8528
8529                                 l += MAXLINE;
8530                                 p = sm_realloc(lsplits, l);
8531                                 if (p == NULL)
8532                                 {
8533                                         /* let's try to get this done */
8534                                         sm_free(lsplits);
8535                                         lsplits = NULL;
8536                                 }
8537                                 else
8538                                         lsplits = p;
8539                         }
8540                         if (lsplits != NULL)
8541                         {
8542                                 if (j == 0)
8543                                         j += sm_strlcat(lsplits + j,
8544                                                         ee->e_id,
8545                                                         l - j);
8546                                 else
8547                                         j += sm_strlcat2(lsplits + j,
8548                                                          "; ",
8549                                                          ee->e_id,
8550                                                          l - j);
8551                                 SM_ASSERT(j < l);
8552                         }
8553                 }
8554                 if (nrcpt - i <= maxrcpt)
8555                         break;
8556                 i += maxrcpt;
8557         }
8558         if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL)
8559         {
8560                 if (nsplit > 0)
8561                 {
8562                         sm_syslog(LOG_NOTICE, e->e_id,
8563                                   "split: maxrcpts=%d, rcpts=%d, count=%d, id%s=%s",
8564                                   maxrcpt, nrcpt - ndead, nsplit,
8565                                   nsplit > 1 ? "s" : "", lsplits);
8566                 }
8567                 sm_free(lsplits);
8568         }
8569         return SM_SPLIT_NEW(nsplit);
8570 }
8571 /*
8572 **  SPLIT_BY_RECIPIENT
8573 **
8574 **      Split an envelope with multiple recipients into multiple
8575 **      envelopes as required by the sendmail configuration.
8576 **
8577 **      Parameters:
8578 **              e -- envelope.
8579 **
8580 **      Results:
8581 **              Returns true on success, false on failure.
8582 **
8583 **      Side Effects:
8584 **              see split_across_queue_groups(), split_within_queue(e)
8585 */
8586
8587 bool
8588 split_by_recipient(e)
8589         ENVELOPE *e;
8590 {
8591         int split, n, i, j, l;
8592         char *lsplits;
8593         ENVELOPE *ee, *next, *firstsibling;
8594
8595         if (OpMode == SM_VERIFY || !ISVALIDQGRP(e->e_qgrp) ||
8596             bitset(EF_SPLIT, e->e_flags))
8597                 return true;
8598         n = split_across_queue_groups(e);
8599         if (n == SM_SPLIT_FAIL)
8600                 return false;
8601         firstsibling = ee = e->e_sibling;
8602         if (n > 1 && LogLevel > SPLIT_LOG_LEVEL)
8603         {
8604                 l = MAXLINE;
8605                 lsplits = sm_malloc(l);
8606                 if (lsplits != NULL)
8607                         *lsplits = '\0';
8608                 j = 0;
8609         }
8610         else
8611         {
8612                 /* get rid of stupid compiler warnings */
8613                 lsplits = NULL;
8614                 j = l = 0;
8615         }
8616         for (i = 1; i < n; ++i)
8617         {
8618                 next = ee->e_sibling;
8619                 if (split_within_queue(ee) == SM_SPLIT_FAIL)
8620                 {
8621                         e->e_sibling = firstsibling;
8622                         SM_FREE(lsplits);
8623                         return false;
8624                 }
8625                 ee->e_flags |= EF_SPLIT;
8626                 if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL)
8627                 {
8628                         if (j >= l - strlen(ee->e_id) - 3)
8629                         {
8630                                 char *p;
8631
8632                                 l += MAXLINE;
8633                                 p = sm_realloc(lsplits, l);
8634                                 if (p == NULL)
8635                                 {
8636                                         /* let's try to get this done */
8637                                         SM_FREE(lsplits);
8638                                 }
8639                                 else
8640                                         lsplits = p;
8641                         }
8642                         if (lsplits != NULL)
8643                         {
8644                                 if (j == 0)
8645                                         j += sm_strlcat(lsplits + j,
8646                                                         ee->e_id, l - j);
8647                                 else
8648                                         j += sm_strlcat2(lsplits + j, "; ",
8649                                                          ee->e_id, l - j);
8650                                 SM_ASSERT(j < l);
8651                         }
8652                 }
8653                 ee = next;
8654         }
8655         if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL && n > 1)
8656         {
8657                 sm_syslog(LOG_NOTICE, e->e_id, "split: count=%d, id%s=%s",
8658                           n - 1, n > 2 ? "s" : "", lsplits);
8659                 SM_FREE(lsplits);
8660         }
8661         split = split_within_queue(e) != SM_SPLIT_FAIL;
8662         if (split)
8663                 e->e_flags |= EF_SPLIT;
8664         return split;
8665 }
8666
8667 /*
8668 **  QUARANTINE_QUEUE_ITEM -- {un,}quarantine a single envelope
8669 **
8670 **      Add/remove quarantine reason and requeue appropriately.
8671 **
8672 **      Parameters:
8673 **              qgrp -- queue group for the item
8674 **              qdir -- queue directory in the given queue group
8675 **              e -- envelope information for the item
8676 **              reason -- quarantine reason, NULL means unquarantine.
8677 **
8678 **      Results:
8679 **              true if item changed, false otherwise
8680 **
8681 **      Side Effects:
8682 **              Changes quarantine tag in queue file and renames it.
8683 */
8684
8685 static bool
8686 quarantine_queue_item(qgrp, qdir, e, reason)
8687         int qgrp;
8688         int qdir;
8689         ENVELOPE *e;
8690         char *reason;
8691 {
8692         bool dirty = false;
8693         bool failing = false;
8694         bool foundq = false;
8695         bool finished = false;
8696         int fd;
8697         int flags;
8698         int oldtype;
8699         int newtype;
8700         int save_errno;
8701         MODE_T oldumask = 0;
8702         SM_FILE_T *oldqfp, *tempqfp;
8703         char *bp;
8704         int bufsize;
8705         char oldqf[MAXPATHLEN];
8706         char tempqf[MAXPATHLEN];
8707         char newqf[MAXPATHLEN];
8708         char buf[MAXLINE];
8709
8710         oldtype = queue_letter(e, ANYQFL_LETTER);
8711         (void) sm_strlcpy(oldqf, queuename(e, ANYQFL_LETTER), sizeof(oldqf));
8712         (void) sm_strlcpy(tempqf, queuename(e, NEWQFL_LETTER), sizeof(tempqf));
8713
8714         /*
8715         **  Instead of duplicating all the open
8716         **  and lock code here, tell readqf() to
8717         **  do that work and return the open
8718         **  file pointer in e_lockfp.  Note that
8719         **  we must release the locks properly when
8720         **  we are done.
8721         */
8722
8723         if (!readqf(e, true))
8724         {
8725                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8726                                      "Skipping %s\n", qid_printname(e));
8727                 return false;
8728         }
8729         oldqfp = e->e_lockfp;
8730
8731         /* open the new queue file */
8732         flags = O_CREAT|O_WRONLY|O_EXCL;
8733         if (bitset(S_IWGRP, QueueFileMode))
8734                 oldumask = umask(002);
8735         fd = open(tempqf, flags, QueueFileMode);
8736         if (bitset(S_IWGRP, QueueFileMode))
8737                 (void) umask(oldumask);
8738         RELEASE_QUEUE;
8739
8740         if (fd < 0)
8741         {
8742                 save_errno = errno;
8743                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8744                                      "Skipping %s: Could not open %s: %s\n",
8745                                      qid_printname(e), tempqf,
8746                                      sm_errstring(save_errno));
8747                 (void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
8748                 return false;
8749         }
8750         if (!lockfile(fd, tempqf, NULL, LOCK_EX|LOCK_NB))
8751         {
8752                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8753                                      "Skipping %s: Could not lock %s\n",
8754                                      qid_printname(e), tempqf);
8755                 (void) close(fd);
8756                 (void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
8757                 return false;
8758         }
8759
8760         tempqfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &fd,
8761                              SM_IO_WRONLY_B, NULL);
8762         if (tempqfp == NULL)
8763         {
8764                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8765                                      "Skipping %s: Could not lock %s\n",
8766                                      qid_printname(e), tempqf);
8767                 (void) close(fd);
8768                 (void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
8769                 return false;
8770         }
8771
8772         /* Copy the data over, changing the quarantine reason */
8773         while (bufsize = sizeof(buf),
8774                (bp = fgetfolded(buf, &bufsize, oldqfp)) != NULL)
8775         {
8776                 if (tTd(40, 4))
8777                         sm_dprintf("+++++ %s\n", bp);
8778                 switch (bp[0])
8779                 {
8780                   case 'q':             /* quarantine reason */
8781                         foundq = true;
8782                         if (reason == NULL)
8783                         {
8784                                 if (Verbose)
8785                                 {
8786                                         (void) sm_io_fprintf(smioout,
8787                                                              SM_TIME_DEFAULT,
8788                                                              "%s: Removed quarantine of \"%s\"\n",
8789                                                              e->e_id, &bp[1]);
8790                                 }
8791                                 sm_syslog(LOG_INFO, e->e_id, "unquarantine");
8792                                 dirty = true;
8793                         }
8794                         else if (strcmp(reason, &bp[1]) == 0)
8795                         {
8796                                 if (Verbose)
8797                                 {
8798                                         (void) sm_io_fprintf(smioout,
8799                                                              SM_TIME_DEFAULT,
8800                                                              "%s: Already quarantined with \"%s\"\n",
8801                                                              e->e_id, reason);
8802                                 }
8803                                 (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8804                                                      "q%s\n", reason);
8805                         }
8806                         else
8807                         {
8808                                 if (Verbose)
8809                                 {
8810                                         (void) sm_io_fprintf(smioout,
8811                                                              SM_TIME_DEFAULT,
8812                                                              "%s: Quarantine changed from \"%s\" to \"%s\"\n",
8813                                                              e->e_id, &bp[1],
8814                                                              reason);
8815                                 }
8816                                 (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8817                                                      "q%s\n", reason);
8818                                 sm_syslog(LOG_INFO, e->e_id, "quarantine=%s",
8819                                           reason);
8820                                 dirty = true;
8821                         }
8822                         break;
8823
8824                   case 'S':
8825                         /*
8826                         **  If we are quarantining an unquarantined item,
8827                         **  need to put in a new 'q' line before it's
8828                         **  too late.
8829                         */
8830
8831                         if (!foundq && reason != NULL)
8832                         {
8833                                 if (Verbose)
8834                                 {
8835                                         (void) sm_io_fprintf(smioout,
8836                                                              SM_TIME_DEFAULT,
8837                                                              "%s: Quarantined with \"%s\"\n",
8838                                                              e->e_id, reason);
8839                                 }
8840                                 (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8841                                                      "q%s\n", reason);
8842                                 sm_syslog(LOG_INFO, e->e_id, "quarantine=%s",
8843                                           reason);
8844                                 foundq = true;
8845                                 dirty = true;
8846                         }
8847
8848                         /* Copy the line to the new file */
8849                         (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8850                                              "%s\n", bp);
8851                         break;
8852
8853                   case '.':
8854                         finished = true;
8855                         /* FALLTHROUGH */
8856
8857                   default:
8858                         /* Copy the line to the new file */
8859                         (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8860                                              "%s\n", bp);
8861                         break;
8862                 }
8863                 if (bp != buf)
8864                         sm_free(bp);
8865         }
8866
8867         /* Make sure we read the whole old file */
8868         errno = sm_io_error(tempqfp);
8869         if (errno != 0 && errno != SM_IO_EOF)
8870         {
8871                 save_errno = errno;
8872                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8873                                      "Skipping %s: Error reading %s: %s\n",
8874                                      qid_printname(e), oldqf,
8875                                      sm_errstring(save_errno));
8876                 failing = true;
8877         }
8878
8879         if (!failing && !finished)
8880         {
8881                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8882                                      "Skipping %s: Incomplete file: %s\n",
8883                                      qid_printname(e), oldqf);
8884                 failing = true;
8885         }
8886
8887         /* Check if we actually changed anything or we can just bail now */
8888         if (!dirty)
8889         {
8890                 /* pretend we failed, even though we technically didn't */
8891                 failing = true;
8892         }
8893
8894         /* Make sure we wrote things out safely */
8895         if (!failing &&
8896             (sm_io_flush(tempqfp, SM_TIME_DEFAULT) != 0 ||
8897              ((SuperSafe == SAFE_REALLY ||
8898                SuperSafe == SAFE_REALLY_POSTMILTER ||
8899                SuperSafe == SAFE_INTERACTIVE) &&
8900               fsync(sm_io_getinfo(tempqfp, SM_IO_WHAT_FD, NULL)) < 0) ||
8901              ((errno = sm_io_error(tempqfp)) != 0)))
8902         {
8903                 save_errno = errno;
8904                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8905                                      "Skipping %s: Error writing %s: %s\n",
8906                                      qid_printname(e), tempqf,
8907                                      sm_errstring(save_errno));
8908                 failing = true;
8909         }
8910
8911
8912         /* Figure out the new filename */
8913         newtype = (reason == NULL ? NORMQF_LETTER : QUARQF_LETTER);
8914         if (oldtype == newtype)
8915         {
8916                 /* going to rename tempqf to oldqf */
8917                 (void) sm_strlcpy(newqf, oldqf, sizeof(newqf));
8918         }
8919         else
8920         {
8921                 /* going to rename tempqf to new name based on newtype */
8922                 (void) sm_strlcpy(newqf, queuename(e, newtype), sizeof(newqf));
8923         }
8924
8925         save_errno = 0;
8926
8927         /* rename tempqf to newqf */
8928         if (!failing &&
8929             rename(tempqf, newqf) < 0)
8930                 save_errno = (errno == 0) ? EINVAL : errno;
8931
8932         /* Check rename() success */
8933         if (!failing && save_errno != 0)
8934         {
8935                 sm_syslog(LOG_DEBUG, e->e_id,
8936                           "quarantine_queue_item: rename(%s, %s): %s",
8937                           tempqf, newqf, sm_errstring(save_errno));
8938
8939                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8940                                      "Error renaming %s to %s: %s\n",
8941                                      tempqf, newqf,
8942                                      sm_errstring(save_errno));
8943                 if (oldtype == newtype)
8944                 {
8945                         /*
8946                         **  Bail here since we don't know the state of
8947                         **  the filesystem and may need to keep tempqf
8948                         **  for the user to rescue us.
8949                         */
8950
8951                         RELEASE_QUEUE;
8952                         errno = save_errno;
8953                         syserr("!452 Error renaming control file %s", tempqf);
8954                         /* NOTREACHED */
8955                 }
8956                 else
8957                 {
8958                         /* remove new file (if rename() half completed) */
8959                         if (xunlink(newqf) < 0)
8960                         {
8961                                 save_errno = errno;
8962                                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8963                                                      "Error removing %s: %s\n",
8964                                                      newqf,
8965                                                      sm_errstring(save_errno));
8966                         }
8967
8968                         /* tempqf removed below */
8969                         failing = true;
8970                 }
8971
8972         }
8973
8974         /* If changing file types, need to remove old type */
8975         if (!failing && oldtype != newtype)
8976         {
8977                 if (xunlink(oldqf) < 0)
8978                 {
8979                         save_errno = errno;
8980                         (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8981                                              "Error removing %s: %s\n",
8982                                              oldqf, sm_errstring(save_errno));
8983                 }
8984         }
8985
8986         /* see if anything above failed */
8987         if (failing)
8988         {
8989                 /* Something failed: remove new file, old file still there */
8990                 (void) xunlink(tempqf);
8991         }
8992
8993         /*
8994         **  fsync() after file operations to make sure metadata is
8995         **  written to disk on filesystems in which renames are
8996         **  not guaranteed.  It's ok if they fail, mail won't be lost.
8997         */
8998
8999         if (SuperSafe != SAFE_NO)
9000         {
9001                 /* for soft-updates */
9002                 (void) fsync(sm_io_getinfo(tempqfp,
9003                                            SM_IO_WHAT_FD, NULL));
9004
9005                 if (!failing)
9006                 {
9007                         /* for soft-updates */
9008                         (void) fsync(sm_io_getinfo(oldqfp,
9009                                                    SM_IO_WHAT_FD, NULL));
9010                 }
9011
9012                 /* for other odd filesystems */
9013                 SYNC_DIR(tempqf, false);
9014         }
9015
9016         /* Close up shop */
9017         RELEASE_QUEUE;
9018         if (tempqfp != NULL)
9019                 (void) sm_io_close(tempqfp, SM_TIME_DEFAULT);
9020         if (oldqfp != NULL)
9021                 (void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
9022
9023         /* All went well */
9024         return !failing;
9025 }
9026
9027 /*
9028 **  QUARANTINE_QUEUE -- {un,}quarantine matching items in the queue
9029 **
9030 **      Read all matching queue items, add/remove quarantine
9031 **      reason, and requeue appropriately.
9032 **
9033 **      Parameters:
9034 **              reason -- quarantine reason, "." means unquarantine.
9035 **              qgrplimit -- limit to single queue group unless NOQGRP
9036 **
9037 **      Results:
9038 **              none.
9039 **
9040 **      Side Effects:
9041 **              Lots of changes to the queue.
9042 */
9043
9044 void
9045 quarantine_queue(reason, qgrplimit)
9046         char *reason;
9047         int qgrplimit;
9048 {
9049         int changed = 0;
9050         int qgrp;
9051
9052         /* Convert internal representation of unquarantine */
9053         if (reason != NULL && reason[0] == '.' && reason[1] == '\0')
9054                 reason = NULL;
9055
9056         if (reason != NULL)
9057         {
9058                 /* clean it */
9059                 reason = newstr(denlstring(reason, true, true));
9060         }
9061
9062         for (qgrp = 0; qgrp < NumQueue && Queue[qgrp] != NULL; qgrp++)
9063         {
9064                 int qdir;
9065
9066                 if (qgrplimit != NOQGRP && qgrplimit != qgrp)
9067                         continue;
9068
9069                 for (qdir = 0; qdir < Queue[qgrp]->qg_numqueues; qdir++)
9070                 {
9071                         int i;
9072                         int nrequests;
9073
9074                         if (StopRequest)
9075                                 stop_sendmail();
9076
9077                         nrequests = gatherq(qgrp, qdir, true, NULL, NULL, NULL);
9078
9079                         /* first see if there is anything */
9080                         if (nrequests <= 0)
9081                         {
9082                                 if (Verbose)
9083                                 {
9084                                         (void) sm_io_fprintf(smioout,
9085                                                              SM_TIME_DEFAULT, "%s: no matches\n",
9086                                                              qid_printqueue(qgrp, qdir));
9087                                 }
9088                                 continue;
9089                         }
9090
9091                         if (Verbose)
9092                         {
9093                                 (void) sm_io_fprintf(smioout,
9094                                                      SM_TIME_DEFAULT, "Processing %s:\n",
9095                                                      qid_printqueue(qgrp, qdir));
9096                         }
9097
9098                         for (i = 0; i < WorkListCount; i++)
9099                         {
9100                                 ENVELOPE e;
9101
9102                                 if (StopRequest)
9103                                         stop_sendmail();
9104
9105                                 /* setup envelope */
9106                                 clearenvelope(&e, true, sm_rpool_new_x(NULL));
9107                                 e.e_id = WorkList[i].w_name + 2;
9108                                 e.e_qgrp = qgrp;
9109                                 e.e_qdir = qdir;
9110
9111                                 if (tTd(70, 101))
9112                                 {
9113                                         sm_io_fprintf(smioout, SM_TIME_DEFAULT,
9114                                                       "Would do %s\n", e.e_id);
9115                                         changed++;
9116                                 }
9117                                 else if (quarantine_queue_item(qgrp, qdir,
9118                                                                &e, reason))
9119                                         changed++;
9120
9121                                 /* clean up */
9122                                 sm_rpool_free(e.e_rpool);
9123                                 e.e_rpool = NULL;
9124                         }
9125                         if (WorkList != NULL)
9126                                 sm_free(WorkList); /* XXX */
9127                         WorkList = NULL;
9128                         WorkListSize = 0;
9129                         WorkListCount = 0;
9130                 }
9131         }
9132         if (Verbose)
9133         {
9134                 if (changed == 0)
9135                         (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
9136                                              "No changes\n");
9137                 else
9138                         (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
9139                                              "%d change%s\n",
9140                                              changed,
9141                                              changed == 1 ? "" : "s");
9142         }
9143 }