sendmail: Update vendor branch to v8.14.15
[dragonfly.git] / contrib / sendmail-8.14 / sendmail / conf.c
1 /*
2  * Copyright (c) 1998-2010 Sendmail, 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
16 SM_RCSID("@(#)$Id: conf.c,v 8.1168 2011/01/25 18:31:30 ca Exp $")
17
18 #include <sm/sendmail.h>
19 #include <sendmail/pathnames.h>
20 #if NEWDB
21 # include "sm/bdb.h"
22 #endif /* NEWDB */
23
24 #include <daemon.h>
25 #include "map.h"
26
27 #ifdef DEC
28 # if NETINET6
29 /* for the IPv6 device lookup */
30 #  define _SOCKADDR_LEN
31 #  include <macros.h>
32 # endif /* NETINET6 */
33 #endif /* DEC */
34
35 # include <sys/ioctl.h>
36 # include <sys/param.h>
37
38 #include <limits.h>
39 #if NETINET || NETINET6
40 # include <arpa/inet.h>
41 #endif /* NETINET || NETINET6 */
42 #if HASULIMIT && defined(HPUX11)
43 # include <ulimit.h>
44 #endif /* HASULIMIT && defined(HPUX11) */
45
46 static void     setupmaps __P((void));
47 static void     setupmailers __P((void));
48 static void     setupqueues __P((void));
49 static int      get_num_procs_online __P((void));
50 static int      add_hostnames __P((SOCKADDR *));
51
52 #if NETINET6 && NEEDSGETIPNODE
53 static struct hostent *sm_getipnodebyname __P((const char *, int, int, int *));
54 static struct hostent *sm_getipnodebyaddr __P((const void *, size_t, int, int *));
55 #else /* NETINET6 && NEEDSGETIPNODE */
56 #define sm_getipnodebyname getipnodebyname 
57 #define sm_getipnodebyaddr getipnodebyaddr
58 #endif /* NETINET6 && NEEDSGETIPNODE */
59
60
61 /*
62 **  CONF.C -- Sendmail Configuration Tables.
63 **
64 **      Defines the configuration of this installation.
65 **
66 **      Configuration Variables:
67 **              HdrInfo -- a table describing well-known header fields.
68 **                      Each entry has the field name and some flags,
69 **                      which are described in sendmail.h.
70 **
71 **      Notes:
72 **              I have tried to put almost all the reasonable
73 **              configuration information into the configuration
74 **              file read at runtime.  My intent is that anything
75 **              here is a function of the version of UNIX you
76 **              are running, or is really static -- for example
77 **              the headers are a superset of widely used
78 **              protocols.  If you find yourself playing with
79 **              this file too much, you may be making a mistake!
80 */
81
82
83 /*
84 **  Header info table
85 **      Final (null) entry contains the flags used for any other field.
86 **
87 **      Not all of these are actually handled specially by sendmail
88 **      at this time.  They are included as placeholders, to let
89 **      you know that "someday" I intend to have sendmail do
90 **      something with them.
91 */
92
93 struct hdrinfo  HdrInfo[] =
94 {
95                 /* originator fields, most to least significant */
96         { "resent-sender",              H_FROM|H_RESENT,        NULL    },
97         { "resent-from",                H_FROM|H_RESENT,        NULL    },
98         { "resent-reply-to",            H_FROM|H_RESENT,        NULL    },
99         { "sender",                     H_FROM,                 NULL    },
100         { "from",                       H_FROM,                 NULL    },
101         { "reply-to",                   H_FROM,                 NULL    },
102         { "errors-to",                  H_FROM|H_ERRORSTO,      NULL    },
103         { "full-name",                  H_ACHECK,               NULL    },
104         { "return-receipt-to",          H_RECEIPTTO,            NULL    },
105         { "delivery-receipt-to",        H_RECEIPTTO,            NULL    },
106         { "disposition-notification-to",        H_FROM,         NULL    },
107
108                 /* destination fields */
109         { "to",                         H_RCPT,                 NULL    },
110         { "resent-to",                  H_RCPT|H_RESENT,        NULL    },
111         { "cc",                         H_RCPT,                 NULL    },
112         { "resent-cc",                  H_RCPT|H_RESENT,        NULL    },
113         { "bcc",                        H_RCPT|H_BCC,           NULL    },
114         { "resent-bcc",                 H_RCPT|H_BCC|H_RESENT,  NULL    },
115         { "apparently-to",              H_RCPT,                 NULL    },
116
117                 /* message identification and control */
118         { "message-id",                 0,                      NULL    },
119         { "resent-message-id",          H_RESENT,               NULL    },
120         { "message",                    H_EOH,                  NULL    },
121         { "text",                       H_EOH,                  NULL    },
122
123                 /* date fields */
124         { "date",                       0,                      NULL    },
125         { "resent-date",                H_RESENT,               NULL    },
126
127                 /* trace fields */
128         { "received",                   H_TRACE|H_FORCE,        NULL    },
129         { "x400-received",              H_TRACE|H_FORCE,        NULL    },
130         { "via",                        H_TRACE|H_FORCE,        NULL    },
131         { "mail-from",                  H_TRACE|H_FORCE,        NULL    },
132
133                 /* miscellaneous fields */
134         { "comments",                   H_FORCE|H_ENCODABLE,    NULL    },
135         { "return-path",                H_FORCE|H_ACHECK|H_BINDLATE,    NULL    },
136         { "content-transfer-encoding",  H_CTE,                  NULL    },
137         { "content-type",               H_CTYPE,                NULL    },
138         { "content-length",             H_ACHECK,               NULL    },
139         { "subject",                    H_ENCODABLE,            NULL    },
140         { "x-authentication-warning",   H_FORCE,                NULL    },
141
142         { NULL,                         0,                      NULL    }
143 };
144
145
146
147 /*
148 **  Privacy values
149 */
150
151 struct prival PrivacyValues[] =
152 {
153         { "public",             PRIV_PUBLIC             },
154         { "needmailhelo",       PRIV_NEEDMAILHELO       },
155         { "needexpnhelo",       PRIV_NEEDEXPNHELO       },
156         { "needvrfyhelo",       PRIV_NEEDVRFYHELO       },
157         { "noexpn",             PRIV_NOEXPN             },
158         { "novrfy",             PRIV_NOVRFY             },
159         { "restrictexpand",     PRIV_RESTRICTEXPAND     },
160         { "restrictmailq",      PRIV_RESTRICTMAILQ      },
161         { "restrictqrun",       PRIV_RESTRICTQRUN       },
162         { "noetrn",             PRIV_NOETRN             },
163         { "noverb",             PRIV_NOVERB             },
164         { "authwarnings",       PRIV_AUTHWARNINGS       },
165         { "noreceipts",         PRIV_NORECEIPTS         },
166         { "nobodyreturn",       PRIV_NOBODYRETN         },
167         { "goaway",             PRIV_GOAWAY             },
168         { "noactualrecipient",  PRIV_NOACTUALRECIPIENT  },
169         { NULL,                 0                       }
170 };
171
172 /*
173 **  DontBlameSendmail values
174 */
175
176 struct dbsval DontBlameSendmailValues[] =
177 {
178         { "safe",                       DBS_SAFE                        },
179         { "assumesafechown",            DBS_ASSUMESAFECHOWN             },
180         { "groupwritabledirpathsafe",   DBS_GROUPWRITABLEDIRPATHSAFE    },
181         { "groupwritableforwardfilesafe",
182                                         DBS_GROUPWRITABLEFORWARDFILESAFE },
183         { "groupwritableincludefilesafe",
184                                         DBS_GROUPWRITABLEINCLUDEFILESAFE },
185         { "groupwritablealiasfile",     DBS_GROUPWRITABLEALIASFILE      },
186         { "worldwritablealiasfile",     DBS_WORLDWRITABLEALIASFILE      },
187         { "forwardfileinunsafedirpath", DBS_FORWARDFILEINUNSAFEDIRPATH  },
188         { "includefileinunsafedirpath", DBS_INCLUDEFILEINUNSAFEDIRPATH  },
189         { "mapinunsafedirpath",         DBS_MAPINUNSAFEDIRPATH  },
190         { "linkedaliasfileinwritabledir",
191                                         DBS_LINKEDALIASFILEINWRITABLEDIR },
192         { "linkedclassfileinwritabledir",
193                                         DBS_LINKEDCLASSFILEINWRITABLEDIR },
194         { "linkedforwardfileinwritabledir",
195                                         DBS_LINKEDFORWARDFILEINWRITABLEDIR },
196         { "linkedincludefileinwritabledir",
197                                         DBS_LINKEDINCLUDEFILEINWRITABLEDIR },
198         { "linkedmapinwritabledir",     DBS_LINKEDMAPINWRITABLEDIR      },
199         { "linkedserviceswitchfileinwritabledir",
200                                         DBS_LINKEDSERVICESWITCHFILEINWRITABLEDIR },
201         { "filedeliverytohardlink",     DBS_FILEDELIVERYTOHARDLINK      },
202         { "filedeliverytosymlink",      DBS_FILEDELIVERYTOSYMLINK       },
203         { "writemaptohardlink",         DBS_WRITEMAPTOHARDLINK          },
204         { "writemaptosymlink",          DBS_WRITEMAPTOSYMLINK           },
205         { "writestatstohardlink",       DBS_WRITESTATSTOHARDLINK        },
206         { "writestatstosymlink",        DBS_WRITESTATSTOSYMLINK         },
207         { "forwardfileingroupwritabledirpath",
208                                         DBS_FORWARDFILEINGROUPWRITABLEDIRPATH },
209         { "includefileingroupwritabledirpath",
210                                         DBS_INCLUDEFILEINGROUPWRITABLEDIRPATH },
211         { "classfileinunsafedirpath",   DBS_CLASSFILEINUNSAFEDIRPATH    },
212         { "errorheaderinunsafedirpath", DBS_ERRORHEADERINUNSAFEDIRPATH  },
213         { "helpfileinunsafedirpath",    DBS_HELPFILEINUNSAFEDIRPATH     },
214         { "forwardfileinunsafedirpathsafe",
215                                         DBS_FORWARDFILEINUNSAFEDIRPATHSAFE },
216         { "includefileinunsafedirpathsafe",
217                                         DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE },
218         { "runprograminunsafedirpath",  DBS_RUNPROGRAMINUNSAFEDIRPATH   },
219         { "runwritableprogram",         DBS_RUNWRITABLEPROGRAM          },
220         { "nonrootsafeaddr",            DBS_NONROOTSAFEADDR             },
221         { "truststickybit",             DBS_TRUSTSTICKYBIT              },
222         { "dontwarnforwardfileinunsafedirpath",
223                                         DBS_DONTWARNFORWARDFILEINUNSAFEDIRPATH },
224         { "insufficiententropy",        DBS_INSUFFICIENTENTROPY },
225         { "groupreadablesasldbfile",    DBS_GROUPREADABLESASLDBFILE     },
226         { "groupwritablesasldbfile",    DBS_GROUPWRITABLESASLDBFILE     },
227         { "groupwritableforwardfile",   DBS_GROUPWRITABLEFORWARDFILE    },
228         { "groupwritableincludefile",   DBS_GROUPWRITABLEINCLUDEFILE    },
229         { "worldwritableforwardfile",   DBS_WORLDWRITABLEFORWARDFILE    },
230         { "worldwritableincludefile",   DBS_WORLDWRITABLEINCLUDEFILE    },
231         { "groupreadablekeyfile",       DBS_GROUPREADABLEKEYFILE        },
232 #if _FFR_GROUPREADABLEAUTHINFOFILE
233         { "groupreadableadefaultauthinfofile",
234                                         DBS_GROUPREADABLEAUTHINFOFILE   },
235 #endif /* _FFR_GROUPREADABLEAUTHINFOFILE */
236         { NULL,                         0                               }
237 };
238
239 /*
240 **  Miscellaneous stuff.
241 */
242
243 int     DtableSize =    50;             /* max open files; reset in 4.2bsd */
244 /*
245 **  SETDEFAULTS -- set default values
246 **
247 **      Some of these must be initialized using direct code since they
248 **      depend on run-time values. So let's do all of them this way.
249 **
250 **      Parameters:
251 **              e -- the default envelope.
252 **
253 **      Returns:
254 **              none.
255 **
256 **      Side Effects:
257 **              Initializes a bunch of global variables to their
258 **              default values.
259 */
260
261 #define MINUTES         * 60
262 #define HOURS           * 60 MINUTES
263 #define DAYS            * 24 HOURS
264
265 #ifndef MAXRULERECURSION
266 # define MAXRULERECURSION       50      /* max ruleset recursion depth */
267 #endif /* ! MAXRULERECURSION */
268
269 void
270 setdefaults(e)
271         register ENVELOPE *e;
272 {
273         int i;
274         int numprocs;
275         struct passwd *pw;
276
277         numprocs = get_num_procs_online();
278         SpaceSub = ' ';                         /* option B */
279         QueueLA = 8 * numprocs;                 /* option x */
280         RefuseLA = 12 * numprocs;               /* option X */
281         WkRecipFact = 30000L;                   /* option y */
282         WkClassFact = 1800L;                    /* option z */
283         WkTimeFact = 90000L;                    /* option Z */
284         QueueFactor = WkRecipFact * 20;         /* option q */
285         QueueMode = QM_NORMAL;          /* what queue items to act upon */
286         FileMode = (RealUid != geteuid()) ? 0644 : 0600;
287                                                 /* option F */
288         QueueFileMode = (RealUid != geteuid()) ? 0644 : 0600;
289                                                 /* option QueueFileMode */
290
291         if (((pw = sm_getpwnam("mailnull")) != NULL && pw->pw_uid != 0) ||
292             ((pw = sm_getpwnam("sendmail")) != NULL && pw->pw_uid != 0) ||
293             ((pw = sm_getpwnam("daemon")) != NULL && pw->pw_uid != 0))
294         {
295                 DefUid = pw->pw_uid;            /* option u */
296                 DefGid = pw->pw_gid;            /* option g */
297                 DefUser = newstr(pw->pw_name);
298         }
299         else
300         {
301                 DefUid = 1;                     /* option u */
302                 DefGid = 1;                     /* option g */
303                 setdefuser();
304         }
305         TrustedUid = 0;
306         if (tTd(37, 4))
307                 sm_dprintf("setdefaults: DefUser=%s, DefUid=%d, DefGid=%d\n",
308                         DefUser != NULL ? DefUser : "<1:1>",
309                         (int) DefUid, (int) DefGid);
310         CheckpointInterval = 10;                /* option C */
311         MaxHopCount = 25;                       /* option h */
312         set_delivery_mode(SM_FORK, e);          /* option d */
313         e->e_errormode = EM_PRINT;              /* option e */
314         e->e_qgrp = NOQGRP;
315         e->e_qdir = NOQDIR;
316         e->e_xfqgrp = NOQGRP;
317         e->e_xfqdir = NOQDIR;
318         e->e_ctime = curtime();
319         SevenBitInput = false;                  /* option 7 */
320         MaxMciCache = 1;                        /* option k */
321         MciCacheTimeout = 5 MINUTES;            /* option K */
322         LogLevel = 9;                           /* option L */
323 #if MILTER
324         MilterLogLevel = -1;
325 #endif /* MILTER */
326         inittimeouts(NULL, false);              /* option r */
327         PrivacyFlags = PRIV_PUBLIC;             /* option p */
328         MeToo = true;                           /* option m */
329         SendMIMEErrors = true;                  /* option f */
330         SuperSafe = SAFE_REALLY;                /* option s */
331         clrbitmap(DontBlameSendmail);           /* DontBlameSendmail option */
332 #if MIME8TO7
333         MimeMode = MM_CVTMIME|MM_PASS8BIT;      /* option 8 */
334 #else /* MIME8TO7 */
335         MimeMode = MM_PASS8BIT;
336 #endif /* MIME8TO7 */
337         for (i = 0; i < MAXTOCLASS; i++)
338         {
339                 TimeOuts.to_q_return[i] = 5 DAYS;       /* option T */
340                 TimeOuts.to_q_warning[i] = 0;           /* option T */
341         }
342         ServiceSwitchFile = "/etc/mail/service.switch";
343         ServiceCacheMaxAge = (time_t) 10;
344         HostsFile = _PATH_HOSTS;
345         PidFile = newstr(_PATH_SENDMAILPID);
346         MustQuoteChars = "@,;:\\()[].'";
347         MciInfoTimeout = 30 MINUTES;
348         MaxRuleRecursion = MAXRULERECURSION;
349         MaxAliasRecursion = 10;
350         MaxMacroRecursion = 10;
351         ColonOkInAddr = true;
352         DontLockReadFiles = true;
353         DontProbeInterfaces = DPI_PROBEALL;
354         DoubleBounceAddr = "postmaster";
355         MaxHeadersLength = MAXHDRSLEN;
356         MaxMimeHeaderLength = MAXLINE;
357         MaxMimeFieldLength = MaxMimeHeaderLength / 2;
358         MaxForwardEntries = 0;
359         FastSplit = 1;
360         MaxNOOPCommands = MAXNOOPCOMMANDS;
361 #if SASL
362         AuthMechanisms = newstr(AUTH_MECHANISMS);
363         AuthRealm = NULL;
364         MaxSLBits = INT_MAX;
365 #endif /* SASL */
366 #if STARTTLS
367         TLS_Srv_Opts = TLS_I_SRV;
368 #endif /* STARTTLS */
369 #ifdef HESIOD_INIT
370         HesiodContext = NULL;
371 #endif /* HESIOD_INIT */
372 #if NETINET6
373         /* Detect if IPv6 is available at run time */
374         i = socket(AF_INET6, SOCK_STREAM, 0);
375         if (i >= 0)
376         {
377                 InetMode = AF_INET6;
378                 (void) close(i);
379         }
380         else
381                 InetMode = AF_INET;
382 #else /* NETINET6 */
383         InetMode = AF_INET;
384 #endif /* NETINET6 */
385         ControlSocketName = NULL;
386         memset(&ConnectOnlyTo, '\0', sizeof(ConnectOnlyTo));
387         DataFileBufferSize = 4096;
388         XscriptFileBufferSize = 4096;
389         for (i = 0; i < MAXRWSETS; i++)
390                 RuleSetNames[i] = NULL;
391 #if MILTER
392         InputFilters[0] = NULL;
393 #endif /* MILTER */
394         RejectLogInterval = 3 HOURS;
395 #if REQUIRES_DIR_FSYNC
396         RequiresDirfsync = true;
397 #endif /* REQUIRES_DIR_FSYNC */
398 #if _FFR_RCPTTHROTDELAY
399         BadRcptThrottleDelay = 1;
400 #endif /* _FFR_RCPTTHROTDELAY */
401         ConnectionRateWindowSize = 60;
402         setupmaps();
403         setupqueues();
404         setupmailers();
405         setupheaders();
406 }
407
408
409 /*
410 **  SETDEFUSER -- set/reset DefUser using DefUid (for initgroups())
411 */
412
413 void
414 setdefuser()
415 {
416         struct passwd *defpwent;
417         static char defuserbuf[40];
418
419         DefUser = defuserbuf;
420         defpwent = sm_getpwuid(DefUid);
421         (void) sm_strlcpy(defuserbuf,
422                           (defpwent == NULL || defpwent->pw_name == NULL)
423                            ? "nobody" : defpwent->pw_name,
424                           sizeof(defuserbuf));
425         if (tTd(37, 4))
426                 sm_dprintf("setdefuser: DefUid=%d, DefUser=%s\n",
427                            (int) DefUid, DefUser);
428 }
429 /*
430 **  SETUPQUEUES -- initialize default queues
431 **
432 **      The mqueue QUEUE structure gets filled in after readcf() but
433 **      we need something to point to now for the mailer setup,
434 **      which use "mqueue" as default queue.
435 */
436
437 static void
438 setupqueues()
439 {
440         char buf[100];
441
442         MaxRunnersPerQueue = 1;
443         (void) sm_strlcpy(buf, "mqueue, P=/var/spool/mqueue", sizeof(buf));
444         makequeue(buf, false);
445 }
446 /*
447 **  SETUPMAILERS -- initialize default mailers
448 */
449
450 static void
451 setupmailers()
452 {
453         char buf[100];
454
455         (void) sm_strlcpy(buf, "prog, P=/bin/sh, F=lsouDq9, T=X-Unix/X-Unix/X-Unix, A=sh -c \201u",
456                         sizeof(buf));
457         makemailer(buf);
458
459         (void) sm_strlcpy(buf, "*file*, P=[FILE], F=lsDFMPEouq9, T=X-Unix/X-Unix/X-Unix, A=FILE \201u",
460                         sizeof(buf));
461         makemailer(buf);
462
463         (void) sm_strlcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE \201u",
464                         sizeof(buf));
465         makemailer(buf);
466         initerrmailers();
467 }
468 /*
469 **  SETUPMAPS -- set up map classes
470 */
471
472 #define MAPDEF(name, ext, flags, parse, open, close, lookup, store) \
473         { \
474                 extern bool parse __P((MAP *, char *)); \
475                 extern bool open __P((MAP *, int)); \
476                 extern void close __P((MAP *)); \
477                 extern char *lookup __P((MAP *, char *, char **, int *)); \
478                 extern void store __P((MAP *, char *, char *)); \
479                 s = stab(name, ST_MAPCLASS, ST_ENTER); \
480                 s->s_mapclass.map_cname = name; \
481                 s->s_mapclass.map_ext = ext; \
482                 s->s_mapclass.map_cflags = flags; \
483                 s->s_mapclass.map_parse = parse; \
484                 s->s_mapclass.map_open = open; \
485                 s->s_mapclass.map_close = close; \
486                 s->s_mapclass.map_lookup = lookup; \
487                 s->s_mapclass.map_store = store; \
488         }
489
490 static void
491 setupmaps()
492 {
493         register STAB *s;
494
495 #if NEWDB
496 # if DB_VERSION_MAJOR > 1
497         int major_v, minor_v, patch_v;
498
499         (void) db_version(&major_v, &minor_v, &patch_v);
500         if (major_v != DB_VERSION_MAJOR || minor_v != DB_VERSION_MINOR)
501         {
502                 errno = 0;
503                 syserr("Berkeley DB version mismatch: compiled against %d.%d.%d, run-time linked against %d.%d.%d",
504                   DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
505                   major_v, minor_v, patch_v);
506         }
507 # endif /* DB_VERSION_MAJOR > 1 */
508
509         MAPDEF("hash", ".db", MCF_ALIASOK|MCF_REBUILDABLE,
510                 map_parseargs, hash_map_open, db_map_close,
511                 db_map_lookup, db_map_store);
512
513         MAPDEF("btree", ".db", MCF_ALIASOK|MCF_REBUILDABLE,
514                 map_parseargs, bt_map_open, db_map_close,
515                 db_map_lookup, db_map_store);
516 #endif /* NEWDB */
517
518 #if NDBM
519         MAPDEF("dbm", ".dir", MCF_ALIASOK|MCF_REBUILDABLE,
520                 map_parseargs, ndbm_map_open, ndbm_map_close,
521                 ndbm_map_lookup, ndbm_map_store);
522 #endif /* NDBM */
523
524 #if NIS
525         MAPDEF("nis", NULL, MCF_ALIASOK,
526                 map_parseargs, nis_map_open, null_map_close,
527                 nis_map_lookup, null_map_store);
528 #endif /* NIS */
529
530 #if NISPLUS
531         MAPDEF("nisplus", NULL, MCF_ALIASOK,
532                 map_parseargs, nisplus_map_open, null_map_close,
533                 nisplus_map_lookup, null_map_store);
534 #endif /* NISPLUS */
535
536 #if LDAPMAP
537         MAPDEF("ldap", NULL, MCF_ALIASOK|MCF_NOTPERSIST,
538                 ldapmap_parseargs, ldapmap_open, ldapmap_close,
539                 ldapmap_lookup, null_map_store);
540 #endif /* LDAPMAP */
541
542 #if PH_MAP
543         MAPDEF("ph", NULL, MCF_NOTPERSIST,
544                 ph_map_parseargs, ph_map_open, ph_map_close,
545                 ph_map_lookup, null_map_store);
546 #endif /* PH_MAP */
547
548 #if MAP_NSD
549         /* IRIX 6.5 nsd support */
550         MAPDEF("nsd", NULL, MCF_ALIASOK,
551                map_parseargs, null_map_open, null_map_close,
552                nsd_map_lookup, null_map_store);
553 #endif /* MAP_NSD */
554
555 #if HESIOD
556         MAPDEF("hesiod", NULL, MCF_ALIASOK|MCF_ALIASONLY,
557                 map_parseargs, hes_map_open, hes_map_close,
558                 hes_map_lookup, null_map_store);
559 #endif /* HESIOD */
560
561 #if NETINFO
562         MAPDEF("netinfo", NULL, MCF_ALIASOK,
563                 map_parseargs, ni_map_open, null_map_close,
564                 ni_map_lookup, null_map_store);
565 #endif /* NETINFO */
566
567 #if 0
568         MAPDEF("dns", NULL, 0,
569                 dns_map_init, null_map_open, null_map_close,
570                 dns_map_lookup, null_map_store);
571 #endif /* 0 */
572
573 #if NAMED_BIND
574 # if DNSMAP
575 #  if _FFR_DNSMAP_ALIASABLE
576         MAPDEF("dns", NULL, MCF_ALIASOK,
577                dns_map_parseargs, dns_map_open, null_map_close,
578                dns_map_lookup, null_map_store);
579 #  else /* _FFR_DNSMAP_ALIASABLE */
580         MAPDEF("dns", NULL, 0,
581                dns_map_parseargs, dns_map_open, null_map_close,
582                dns_map_lookup, null_map_store);
583 #  endif /* _FFR_DNSMAP_ALIASABLE */
584 # endif /* DNSMAP */
585 #endif /* NAMED_BIND */
586
587 #if NAMED_BIND
588         /* best MX DNS lookup */
589         MAPDEF("bestmx", NULL, MCF_OPTFILE,
590                 map_parseargs, null_map_open, null_map_close,
591                 bestmx_map_lookup, null_map_store);
592 #endif /* NAMED_BIND */
593
594         MAPDEF("host", NULL, 0,
595                 host_map_init, null_map_open, null_map_close,
596                 host_map_lookup, null_map_store);
597
598         MAPDEF("text", NULL, MCF_ALIASOK,
599                 map_parseargs, text_map_open, null_map_close,
600                 text_map_lookup, null_map_store);
601
602         MAPDEF("stab", NULL, MCF_ALIASOK|MCF_ALIASONLY,
603                 map_parseargs, stab_map_open, null_map_close,
604                 stab_map_lookup, stab_map_store);
605
606         MAPDEF("implicit", NULL, MCF_ALIASOK|MCF_ALIASONLY|MCF_REBUILDABLE,
607                 map_parseargs, impl_map_open, impl_map_close,
608                 impl_map_lookup, impl_map_store);
609
610         /* access to system passwd file */
611         MAPDEF("user", NULL, MCF_OPTFILE,
612                 map_parseargs, user_map_open, null_map_close,
613                 user_map_lookup, null_map_store);
614
615         /* dequote map */
616         MAPDEF("dequote", NULL, 0,
617                 dequote_init, null_map_open, null_map_close,
618                 dequote_map, null_map_store);
619
620 #if MAP_REGEX
621         MAPDEF("regex", NULL, 0,
622                 regex_map_init, null_map_open, null_map_close,
623                 regex_map_lookup, null_map_store);
624 #endif /* MAP_REGEX */
625
626 #if USERDB
627         /* user database */
628         MAPDEF("userdb", ".db", 0,
629                 map_parseargs, null_map_open, null_map_close,
630                 udb_map_lookup, null_map_store);
631 #endif /* USERDB */
632
633         /* arbitrary programs */
634         MAPDEF("program", NULL, MCF_ALIASOK,
635                 map_parseargs, null_map_open, null_map_close,
636                 prog_map_lookup, null_map_store);
637
638         /* sequenced maps */
639         MAPDEF("sequence", NULL, MCF_ALIASOK,
640                 seq_map_parse, null_map_open, null_map_close,
641                 seq_map_lookup, seq_map_store);
642
643         /* switched interface to sequenced maps */
644         MAPDEF("switch", NULL, MCF_ALIASOK,
645                 map_parseargs, switch_map_open, null_map_close,
646                 seq_map_lookup, seq_map_store);
647
648         /* null map lookup -- really for internal use only */
649         MAPDEF("null", NULL, MCF_ALIASOK|MCF_OPTFILE,
650                 map_parseargs, null_map_open, null_map_close,
651                 null_map_lookup, null_map_store);
652
653         /* syslog map -- logs information to syslog */
654         MAPDEF("syslog", NULL, 0,
655                 syslog_map_parseargs, null_map_open, null_map_close,
656                 syslog_map_lookup, null_map_store);
657
658         /* macro storage map -- rulesets can set macros */
659         MAPDEF("macro", NULL, 0,
660                 dequote_init, null_map_open, null_map_close,
661                 macro_map_lookup, null_map_store);
662
663         /* arithmetic map -- add/subtract/compare */
664         MAPDEF("arith", NULL, 0,
665                 dequote_init, null_map_open, null_map_close,
666                 arith_map_lookup, null_map_store);
667
668 #if SOCKETMAP
669         /* arbitrary daemons */
670         MAPDEF("socket", NULL, MCF_ALIASOK,
671                 map_parseargs, socket_map_open, socket_map_close,
672                 socket_map_lookup, null_map_store);
673 #endif /* SOCKETMAP */
674
675 #if _FFR_DPRINTF_MAP
676         /* dprintf map -- logs information to syslog */
677         MAPDEF("dprintf", NULL, 0,
678                 dprintf_map_parseargs, null_map_open, null_map_close,
679                 dprintf_map_lookup, null_map_store);
680 #endif /* _FFR_DPRINTF_MAP */
681
682         if (tTd(38, 2))
683         {
684                 /* bogus map -- always return tempfail */
685                 MAPDEF("bogus", NULL, MCF_ALIASOK|MCF_OPTFILE,
686                        map_parseargs, null_map_open, null_map_close,
687                        bogus_map_lookup, null_map_store);
688         }
689 }
690
691 #undef MAPDEF
692 /*
693 **  INITHOSTMAPS -- initial host-dependent maps
694 **
695 **      This should act as an interface to any local service switch
696 **      provided by the host operating system.
697 **
698 **      Parameters:
699 **              none
700 **
701 **      Returns:
702 **              none
703 **
704 **      Side Effects:
705 **              Should define maps "host" and "users" as necessary
706 **              for this OS.  If they are not defined, they will get
707 **              a default value later.  It should check to make sure
708 **              they are not defined first, since it's possible that
709 **              the config file has provided an override.
710 */
711
712 void
713 inithostmaps()
714 {
715         register int i;
716         int nmaps;
717         char *maptype[MAXMAPSTACK];
718         short mapreturn[MAXMAPACTIONS];
719         char buf[MAXLINE];
720
721         /*
722         **  Make sure we have a host map.
723         */
724
725         if (stab("host", ST_MAP, ST_FIND) == NULL)
726         {
727                 /* user didn't initialize: set up host map */
728                 (void) sm_strlcpy(buf, "host host", sizeof(buf));
729 #if NAMED_BIND
730                 if (ConfigLevel >= 2)
731                         (void) sm_strlcat(buf, " -a. -D", sizeof(buf));
732 #endif /* NAMED_BIND */
733                 (void) makemapentry(buf);
734         }
735
736         /*
737         **  Set up default aliases maps
738         */
739
740         nmaps = switch_map_find("aliases", maptype, mapreturn);
741         for (i = 0; i < nmaps; i++)
742         {
743                 if (strcmp(maptype[i], "files") == 0 &&
744                     stab("aliases.files", ST_MAP, ST_FIND) == NULL)
745                 {
746                         (void) sm_strlcpy(buf, "aliases.files null",
747                                           sizeof(buf));
748                         (void) makemapentry(buf);
749                 }
750 #if NISPLUS
751                 else if (strcmp(maptype[i], "nisplus") == 0 &&
752                          stab("aliases.nisplus", ST_MAP, ST_FIND) == NULL)
753                 {
754                         (void) sm_strlcpy(buf, "aliases.nisplus nisplus -kalias -vexpansion mail_aliases.org_dir",
755                                 sizeof(buf));
756                         (void) makemapentry(buf);
757                 }
758 #endif /* NISPLUS */
759 #if NIS
760                 else if (strcmp(maptype[i], "nis") == 0 &&
761                          stab("aliases.nis", ST_MAP, ST_FIND) == NULL)
762                 {
763                         (void) sm_strlcpy(buf, "aliases.nis nis mail.aliases",
764                                 sizeof(buf));
765                         (void) makemapentry(buf);
766                 }
767 #endif /* NIS */
768 #if NETINFO
769                 else if (strcmp(maptype[i], "netinfo") == 0 &&
770                          stab("aliases.netinfo", ST_MAP, ST_FIND) == NULL)
771                 {
772                         (void) sm_strlcpy(buf, "aliases.netinfo netinfo -z, /aliases",
773                                 sizeof(buf));
774                         (void) makemapentry(buf);
775                 }
776 #endif /* NETINFO */
777 #if HESIOD
778                 else if (strcmp(maptype[i], "hesiod") == 0 &&
779                          stab("aliases.hesiod", ST_MAP, ST_FIND) == NULL)
780                 {
781                         (void) sm_strlcpy(buf, "aliases.hesiod hesiod aliases",
782                                 sizeof(buf));
783                         (void) makemapentry(buf);
784                 }
785 #endif /* HESIOD */
786 #if LDAPMAP && defined(SUN_EXTENSIONS) && \
787     defined(SUN_SIMPLIFIED_LDAP) && HASLDAPGETALIASBYNAME
788                 else if (strcmp(maptype[i], "ldap") == 0 &&
789                     stab("aliases.ldap", ST_MAP, ST_FIND) == NULL)
790                 {
791                         (void) sm_strlcpy(buf, "aliases.ldap ldap -b . -h localhost -k mail=%0 -v mailgroup",
792                                 sizeof buf);
793                         (void) makemapentry(buf);
794                 }
795 #endif /* LDAPMAP && defined(SUN_EXTENSIONS) && ... */
796         }
797         if (stab("aliases", ST_MAP, ST_FIND) == NULL)
798         {
799                 (void) sm_strlcpy(buf, "aliases switch aliases", sizeof(buf));
800                 (void) makemapentry(buf);
801         }
802 }
803
804 /*
805 **  SWITCH_MAP_FIND -- find the list of types associated with a map
806 **
807 **      This is the system-dependent interface to the service switch.
808 **
809 **      Parameters:
810 **              service -- the name of the service of interest.
811 **              maptype -- an out-array of strings containing the types
812 **                      of access to use for this service.  There can
813 **                      be at most MAXMAPSTACK types for a single service.
814 **              mapreturn -- an out-array of return information bitmaps
815 **                      for the map.
816 **
817 **      Returns:
818 **              The number of map types filled in, or -1 for failure.
819 **
820 **      Side effects:
821 **              Preserves errno so nothing in the routine clobbers it.
822 */
823
824 #if defined(SOLARIS) || (defined(sony_news) && defined(__svr4))
825 # define _USE_SUN_NSSWITCH_
826 #endif /* defined(SOLARIS) || (defined(sony_news) && defined(__svr4)) */
827
828 #if _FFR_HPUX_NSSWITCH
829 # ifdef __hpux
830 #  define _USE_SUN_NSSWITCH_
831 # endif /* __hpux */
832 #endif /* _FFR_HPUX_NSSWITCH */
833
834 #ifdef _USE_SUN_NSSWITCH_
835 # include <nsswitch.h>
836 #endif /* _USE_SUN_NSSWITCH_ */
837
838 #if defined(ultrix) || (defined(__osf__) && defined(__alpha))
839 # define _USE_DEC_SVC_CONF_
840 #endif /* defined(ultrix) || (defined(__osf__) && defined(__alpha)) */
841
842 #ifdef _USE_DEC_SVC_CONF_
843 # include <sys/svcinfo.h>
844 #endif /* _USE_DEC_SVC_CONF_ */
845
846 int
847 switch_map_find(service, maptype, mapreturn)
848         char *service;
849         char *maptype[MAXMAPSTACK];
850         short mapreturn[MAXMAPACTIONS];
851 {
852         int svcno = 0;
853         int save_errno = errno;
854
855 #ifdef _USE_SUN_NSSWITCH_
856         struct __nsw_switchconfig *nsw_conf;
857         enum __nsw_parse_err pserr;
858         struct __nsw_lookup *lk;
859         static struct __nsw_lookup lkp0 =
860                 { "files", {1, 0, 0, 0}, NULL, NULL };
861         static struct __nsw_switchconfig lkp_default =
862                 { 0, "sendmail", 3, &lkp0 };
863
864         for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
865                 mapreturn[svcno] = 0;
866
867         if ((nsw_conf = __nsw_getconfig(service, &pserr)) == NULL)
868                 lk = lkp_default.lookups;
869         else
870                 lk = nsw_conf->lookups;
871         svcno = 0;
872         while (lk != NULL && svcno < MAXMAPSTACK)
873         {
874                 maptype[svcno] = lk->service_name;
875                 if (lk->actions[__NSW_NOTFOUND] == __NSW_RETURN)
876                         mapreturn[MA_NOTFOUND] |= 1 << svcno;
877                 if (lk->actions[__NSW_TRYAGAIN] == __NSW_RETURN)
878                         mapreturn[MA_TRYAGAIN] |= 1 << svcno;
879                 if (lk->actions[__NSW_UNAVAIL] == __NSW_RETURN)
880                         mapreturn[MA_TRYAGAIN] |= 1 << svcno;
881                 svcno++;
882                 lk = lk->next;
883         }
884         errno = save_errno;
885         return svcno;
886 #endif /* _USE_SUN_NSSWITCH_ */
887
888 #ifdef _USE_DEC_SVC_CONF_
889         struct svcinfo *svcinfo;
890         int svc;
891
892         for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
893                 mapreturn[svcno] = 0;
894
895         svcinfo = getsvc();
896         if (svcinfo == NULL)
897                 goto punt;
898         if (strcmp(service, "hosts") == 0)
899                 svc = SVC_HOSTS;
900         else if (strcmp(service, "aliases") == 0)
901                 svc = SVC_ALIASES;
902         else if (strcmp(service, "passwd") == 0)
903                 svc = SVC_PASSWD;
904         else
905         {
906                 errno = save_errno;
907                 return -1;
908         }
909         for (svcno = 0; svcno < SVC_PATHSIZE && svcno < MAXMAPSTACK; svcno++)
910         {
911                 switch (svcinfo->svcpath[svc][svcno])
912                 {
913                   case SVC_LOCAL:
914                         maptype[svcno] = "files";
915                         break;
916
917                   case SVC_YP:
918                         maptype[svcno] = "nis";
919                         break;
920
921                   case SVC_BIND:
922                         maptype[svcno] = "dns";
923                         break;
924
925 # ifdef SVC_HESIOD
926                   case SVC_HESIOD:
927                         maptype[svcno] = "hesiod";
928                         break;
929 # endif /* SVC_HESIOD */
930
931                   case SVC_LAST:
932                         errno = save_errno;
933                         return svcno;
934                 }
935         }
936         errno = save_errno;
937         return svcno;
938 #endif /* _USE_DEC_SVC_CONF_ */
939
940 #if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_)
941         /*
942         **  Fall-back mechanism.
943         */
944
945         STAB *st;
946         static time_t servicecachetime; /* time service switch was cached */
947         time_t now = curtime();
948
949         for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
950                 mapreturn[svcno] = 0;
951
952         if ((now - servicecachetime) > (time_t) ServiceCacheMaxAge)
953         {
954                 /* (re)read service switch */
955                 register SM_FILE_T *fp;
956                 long sff = SFF_REGONLY|SFF_OPENASROOT|SFF_NOLOCK;
957
958                 if (!bitnset(DBS_LINKEDSERVICESWITCHFILEINWRITABLEDIR,
959                             DontBlameSendmail))
960                         sff |= SFF_NOWLINK;
961
962                 if (ConfigFileRead)
963                         servicecachetime = now;
964                 fp = safefopen(ServiceSwitchFile, O_RDONLY, 0, sff);
965                 if (fp != NULL)
966                 {
967                         char buf[MAXLINE];
968
969                         while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf,
970                                            sizeof(buf)) != NULL)
971                         {
972                                 register char *p;
973
974                                 p = strpbrk(buf, "#\n");
975                                 if (p != NULL)
976                                         *p = '\0';
977 #ifndef SM_NSSWITCH_DELIMS
978 # define SM_NSSWITCH_DELIMS     " \t"
979 #endif /* SM_NSSWITCH_DELIMS */
980                                 p = strpbrk(buf, SM_NSSWITCH_DELIMS);
981                                 if (p != NULL)
982                                         *p++ = '\0';
983                                 if (buf[0] == '\0')
984                                         continue;
985                                 if (p == NULL)
986                                 {
987                                         sm_syslog(LOG_ERR, NOQID,
988                                                   "Bad line on %.100s: %.100s",
989                                                   ServiceSwitchFile,
990                                                   buf);
991                                         continue;
992                                 }
993                                 while (isascii(*p) && isspace(*p))
994                                         p++;
995                                 if (*p == '\0')
996                                         continue;
997
998                                 /*
999                                 **  Find/allocate space for this service entry.
1000                                 **      Space for all of the service strings
1001                                 **      are allocated at once.  This means
1002                                 **      that we only have to free the first
1003                                 **      one to free all of them.
1004                                 */
1005
1006                                 st = stab(buf, ST_SERVICE, ST_ENTER);
1007                                 if (st->s_service[0] != NULL)
1008                                         sm_free((void *) st->s_service[0]); /* XXX */
1009                                 p = newstr(p);
1010                                 for (svcno = 0; svcno < MAXMAPSTACK; )
1011                                 {
1012                                         if (*p == '\0')
1013                                                 break;
1014                                         st->s_service[svcno++] = p;
1015                                         p = strpbrk(p, " \t");
1016                                         if (p == NULL)
1017                                                 break;
1018                                         *p++ = '\0';
1019                                         while (isascii(*p) && isspace(*p))
1020                                                 p++;
1021                                 }
1022                                 if (svcno < MAXMAPSTACK)
1023                                         st->s_service[svcno] = NULL;
1024                         }
1025                         (void) sm_io_close(fp, SM_TIME_DEFAULT);
1026                 }
1027         }
1028
1029         /* look up entry in cache */
1030         st = stab(service, ST_SERVICE, ST_FIND);
1031         if (st != NULL && st->s_service[0] != NULL)
1032         {
1033                 /* extract data */
1034                 svcno = 0;
1035                 while (svcno < MAXMAPSTACK)
1036                 {
1037                         maptype[svcno] = st->s_service[svcno];
1038                         if (maptype[svcno++] == NULL)
1039                                 break;
1040                 }
1041                 errno = save_errno;
1042                 return --svcno;
1043         }
1044 #endif /* !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) */
1045
1046 #if !defined(_USE_SUN_NSSWITCH_)
1047         /* if the service file doesn't work, use an absolute fallback */
1048 # ifdef _USE_DEC_SVC_CONF_
1049   punt:
1050 # endif /* _USE_DEC_SVC_CONF_ */
1051         for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
1052                 mapreturn[svcno] = 0;
1053         svcno = 0;
1054         if (strcmp(service, "aliases") == 0)
1055         {
1056                 maptype[svcno++] = "files";
1057 # if defined(AUTO_NETINFO_ALIASES) && defined (NETINFO)
1058                 maptype[svcno++] = "netinfo";
1059 # endif /* defined(AUTO_NETINFO_ALIASES) && defined (NETINFO) */
1060 # ifdef AUTO_NIS_ALIASES
1061 #  if NISPLUS
1062                 maptype[svcno++] = "nisplus";
1063 #  endif /* NISPLUS */
1064 #  if NIS
1065                 maptype[svcno++] = "nis";
1066 #  endif /* NIS */
1067 # endif /* AUTO_NIS_ALIASES */
1068                 errno = save_errno;
1069                 return svcno;
1070         }
1071         if (strcmp(service, "hosts") == 0)
1072         {
1073 # if NAMED_BIND
1074                 maptype[svcno++] = "dns";
1075 # else /* NAMED_BIND */
1076 #  if defined(sun) && !defined(BSD)
1077                 /* SunOS */
1078                 maptype[svcno++] = "nis";
1079 #  endif /* defined(sun) && !defined(BSD) */
1080 # endif /* NAMED_BIND */
1081 # if defined(AUTO_NETINFO_HOSTS) && defined (NETINFO)
1082                 maptype[svcno++] = "netinfo";
1083 # endif /* defined(AUTO_NETINFO_HOSTS) && defined (NETINFO) */
1084                 maptype[svcno++] = "files";
1085                 errno = save_errno;
1086                 return svcno;
1087         }
1088         errno = save_errno;
1089         return -1;
1090 #endif /* !defined(_USE_SUN_NSSWITCH_) */
1091 }
1092 /*
1093 **  USERNAME -- return the user id of the logged in user.
1094 **
1095 **      Parameters:
1096 **              none.
1097 **
1098 **      Returns:
1099 **              The login name of the logged in user.
1100 **
1101 **      Side Effects:
1102 **              none.
1103 **
1104 **      Notes:
1105 **              The return value is statically allocated.
1106 */
1107
1108 char *
1109 username()
1110 {
1111         static char *myname = NULL;
1112         extern char *getlogin();
1113         register struct passwd *pw;
1114
1115         /* cache the result */
1116         if (myname == NULL)
1117         {
1118                 myname = getlogin();
1119                 if (myname == NULL || myname[0] == '\0')
1120                 {
1121                         pw = sm_getpwuid(RealUid);
1122                         if (pw != NULL)
1123                                 myname = pw->pw_name;
1124                 }
1125                 else
1126                 {
1127                         uid_t uid = RealUid;
1128
1129                         if ((pw = sm_getpwnam(myname)) == NULL ||
1130                               (uid != 0 && uid != pw->pw_uid))
1131                         {
1132                                 pw = sm_getpwuid(uid);
1133                                 if (pw != NULL)
1134                                         myname = pw->pw_name;
1135                         }
1136                 }
1137                 if (myname == NULL || myname[0] == '\0')
1138                 {
1139                         syserr("554 5.3.0 Who are you?");
1140                         myname = "postmaster";
1141                 }
1142                 else if (strpbrk(myname, ",;:/|\"\\") != NULL)
1143                         myname = addquotes(myname, NULL);
1144                 else
1145                         myname = sm_pstrdup_x(myname);
1146         }
1147         return myname;
1148 }
1149 /*
1150 **  TTYPATH -- Get the path of the user's tty
1151 **
1152 **      Returns the pathname of the user's tty.  Returns NULL if
1153 **      the user is not logged in or if s/he has write permission
1154 **      denied.
1155 **
1156 **      Parameters:
1157 **              none
1158 **
1159 **      Returns:
1160 **              pathname of the user's tty.
1161 **              NULL if not logged in or write permission denied.
1162 **
1163 **      Side Effects:
1164 **              none.
1165 **
1166 **      WARNING:
1167 **              Return value is in a local buffer.
1168 **
1169 **      Called By:
1170 **              savemail
1171 */
1172
1173 char *
1174 ttypath()
1175 {
1176         struct stat stbuf;
1177         register char *pathn;
1178         extern char *ttyname();
1179         extern char *getlogin();
1180
1181         /* compute the pathname of the controlling tty */
1182         if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL &&
1183             (pathn = ttyname(0)) == NULL)
1184         {
1185                 errno = 0;
1186                 return NULL;
1187         }
1188
1189         /* see if we have write permission */
1190         if (stat(pathn, &stbuf) < 0 || !bitset(S_IWOTH, stbuf.st_mode))
1191         {
1192                 errno = 0;
1193                 return NULL;
1194         }
1195
1196         /* see if the user is logged in */
1197         if (getlogin() == NULL)
1198                 return NULL;
1199
1200         /* looks good */
1201         return pathn;
1202 }
1203 /*
1204 **  CHECKCOMPAT -- check for From and To person compatible.
1205 **
1206 **      This routine can be supplied on a per-installation basis
1207 **      to determine whether a person is allowed to send a message.
1208 **      This allows restriction of certain types of internet
1209 **      forwarding or registration of users.
1210 **
1211 **      If the hosts are found to be incompatible, an error
1212 **      message should be given using "usrerr" and an EX_ code
1213 **      should be returned.  You can also set to->q_status to
1214 **      a DSN-style status code.
1215 **
1216 **      EF_NO_BODY_RETN can be set in e->e_flags to suppress the
1217 **      body during the return-to-sender function; this should be done
1218 **      on huge messages.  This bit may already be set by the ESMTP
1219 **      protocol.
1220 **
1221 **      Parameters:
1222 **              to -- the person being sent to.
1223 **
1224 **      Returns:
1225 **              an exit status
1226 **
1227 **      Side Effects:
1228 **              none (unless you include the usrerr stuff)
1229 */
1230
1231 int
1232 checkcompat(to, e)
1233         register ADDRESS *to;
1234         register ENVELOPE *e;
1235 {
1236         if (tTd(49, 1))
1237                 sm_dprintf("checkcompat(to=%s, from=%s)\n",
1238                         to->q_paddr, e->e_from.q_paddr);
1239
1240 #ifdef EXAMPLE_CODE
1241         /* this code is intended as an example only */
1242         register STAB *s;
1243
1244         s = stab("arpa", ST_MAILER, ST_FIND);
1245         if (s != NULL && strcmp(e->e_from.q_mailer->m_name, "local") != 0 &&
1246             to->q_mailer == s->s_mailer)
1247         {
1248                 usrerr("553 No ARPA mail through this machine: see your system administration");
1249                 /* e->e_flags |= EF_NO_BODY_RETN; to suppress body on return */
1250                 to->q_status = "5.7.1";
1251                 return EX_UNAVAILABLE;
1252         }
1253 #endif /* EXAMPLE_CODE */
1254         return EX_OK;
1255 }
1256
1257 #ifdef SUN_EXTENSIONS
1258 static void
1259 init_md_sun()
1260 {
1261         struct stat sbuf;
1262
1263         /* Check for large file descriptor */
1264         if (fstat(fileno(stdin), &sbuf) < 0)
1265         {
1266                 if (errno == EOVERFLOW)
1267                 {
1268                         perror("stdin");
1269                         exit(EX_NOINPUT);
1270                 }
1271         }
1272 }
1273 #endif /* SUN_EXTENSIONS */
1274
1275 /*
1276 **  INIT_MD -- do machine dependent initializations
1277 **
1278 **      Systems that have global modes that should be set should do
1279 **      them here rather than in main.
1280 */
1281
1282 #ifdef _AUX_SOURCE
1283 # include <compat.h>
1284 #endif /* _AUX_SOURCE */
1285
1286 #if SHARE_V1
1287 # include <shares.h>
1288 #endif /* SHARE_V1 */
1289
1290 void
1291 init_md(argc, argv)
1292         int argc;
1293         char **argv;
1294 {
1295 #ifdef _AUX_SOURCE
1296         setcompat(getcompat() | COMPAT_BSDPROT);
1297 #endif /* _AUX_SOURCE */
1298
1299 #ifdef SUN_EXTENSIONS
1300         init_md_sun();
1301 #endif /* SUN_EXTENSIONS */
1302
1303 #if _CONVEX_SOURCE
1304         /* keep gethostby*() from stripping the local domain name */
1305         set_domain_trim_off();
1306 #endif /* _CONVEX_SOURCE */
1307 #if defined(__QNX__) && !defined(__QNXNTO__)
1308         /*
1309         **  Due to QNX's network distributed nature, you can target a tcpip
1310         **  stack on a different node in the qnx network; this patch lets
1311         **  this feature work.  The __sock_locate() must be done before the
1312         **  environment is clear.
1313         */
1314         __sock_locate();
1315 #endif /* __QNX__ */
1316 #if SECUREWARE || defined(_SCO_unix_)
1317         set_auth_parameters(argc, argv);
1318
1319 # ifdef _SCO_unix_
1320         /*
1321         **  This is required for highest security levels (the kernel
1322         **  won't let it call set*uid() or run setuid binaries without
1323         **  it).  It may be necessary on other SECUREWARE systems.
1324         */
1325
1326         if (getluid() == -1)
1327                 setluid(0);
1328 # endif /* _SCO_unix_ */
1329 #endif /* SECUREWARE || defined(_SCO_unix_) */
1330
1331
1332 #ifdef VENDOR_DEFAULT
1333         VendorCode = VENDOR_DEFAULT;
1334 #else /* VENDOR_DEFAULT */
1335         VendorCode = VENDOR_BERKELEY;
1336 #endif /* VENDOR_DEFAULT */
1337 }
1338 /*
1339 **  INIT_VENDOR_MACROS -- vendor-dependent macro initializations
1340 **
1341 **      Called once, on startup.
1342 **
1343 **      Parameters:
1344 **              e -- the global envelope.
1345 **
1346 **      Returns:
1347 **              none.
1348 **
1349 **      Side Effects:
1350 **              vendor-dependent.
1351 */
1352
1353 void
1354 init_vendor_macros(e)
1355         register ENVELOPE *e;
1356 {
1357 }
1358 /*
1359 **  GETLA -- get the current load average
1360 **
1361 **      This code stolen from la.c.
1362 **
1363 **      Parameters:
1364 **              none.
1365 **
1366 **      Returns:
1367 **              The current load average as an integer.
1368 **
1369 **      Side Effects:
1370 **              none.
1371 */
1372
1373 /* try to guess what style of load average we have */
1374 #define LA_ZERO         1       /* always return load average as zero */
1375 #define LA_INT          2       /* read kmem for avenrun; interpret as long */
1376 #define LA_FLOAT        3       /* read kmem for avenrun; interpret as float */
1377 #define LA_SUBR         4       /* call getloadavg */
1378 #define LA_MACH         5       /* MACH load averages (as on NeXT boxes) */
1379 #define LA_SHORT        6       /* read kmem for avenrun; interpret as short */
1380 #define LA_PROCSTR      7       /* read string ("1.17") from /proc/loadavg */
1381 #define LA_READKSYM     8       /* SVR4: use MIOC_READKSYM ioctl call */
1382 #define LA_DGUX         9       /* special DGUX implementation */
1383 #define LA_HPUX         10      /* special HPUX implementation */
1384 #define LA_IRIX6        11      /* special IRIX 6.2 implementation */
1385 #define LA_KSTAT        12      /* special Solaris kstat(3k) implementation */
1386 #define LA_DEVSHORT     13      /* read short from a device */
1387 #define LA_ALPHAOSF     14      /* Digital UNIX (OSF/1 on Alpha) table() call */
1388 #define LA_PSET         15      /* Solaris per-processor-set load average */
1389 #define LA_LONGLONG     17 /* read kmem for avenrun; interpret as long long */
1390
1391 /* do guesses based on general OS type */
1392 #ifndef LA_TYPE
1393 # define LA_TYPE        LA_ZERO
1394 #endif /* ! LA_TYPE */
1395
1396 #ifndef FSHIFT
1397 # if defined(unixpc)
1398 #  define FSHIFT        5
1399 # endif /* defined(unixpc) */
1400
1401 # if defined(__alpha) || defined(IRIX)
1402 #  define FSHIFT        10
1403 # endif /* defined(__alpha) || defined(IRIX) */
1404
1405 #endif /* ! FSHIFT */
1406
1407 #ifndef FSHIFT
1408 # define FSHIFT         8
1409 #endif /* ! FSHIFT */
1410
1411 #ifndef FSCALE
1412 # define FSCALE         (1 << FSHIFT)
1413 #endif /* ! FSCALE */
1414
1415 #ifndef LA_AVENRUN
1416 # ifdef SYSTEM5
1417 #  define LA_AVENRUN    "avenrun"
1418 # else /* SYSTEM5 */
1419 #  define LA_AVENRUN    "_avenrun"
1420 # endif /* SYSTEM5 */
1421 #endif /* ! LA_AVENRUN */
1422
1423 /* _PATH_KMEM should be defined in <paths.h> */
1424 #ifndef _PATH_KMEM
1425 # define _PATH_KMEM     "/dev/kmem"
1426 #endif /* ! _PATH_KMEM */
1427
1428 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT) || (LA_TYPE == LA_LONGLONG)
1429
1430 # include <nlist.h>
1431
1432 /* _PATH_UNIX should be defined in <paths.h> */
1433 # ifndef _PATH_UNIX
1434 #  if defined(SYSTEM5)
1435 #   define _PATH_UNIX   "/unix"
1436 #  else /* defined(SYSTEM5) */
1437 #   define _PATH_UNIX   "/vmunix"
1438 #  endif /* defined(SYSTEM5) */
1439 # endif /* ! _PATH_UNIX */
1440
1441 # ifdef _AUX_SOURCE
1442 struct nlist    Nl[2];
1443 # else /* _AUX_SOURCE */
1444 struct nlist    Nl[] =
1445 {
1446         { LA_AVENRUN },
1447         { 0 },
1448 };
1449 # endif /* _AUX_SOURCE */
1450 # define X_AVENRUN      0
1451
1452 int
1453 getla()
1454 {
1455         int j;
1456         static int kmem = -1;
1457 # if LA_TYPE == LA_INT
1458         long avenrun[3];
1459 # else /* LA_TYPE == LA_INT */
1460 #  if LA_TYPE == LA_SHORT
1461         short avenrun[3];
1462 #  else
1463 #   if LA_TYPE == LA_LONGLONG
1464         long long avenrun[3];
1465 #   else /* LA_TYPE == LA_LONGLONG */
1466         double avenrun[3];
1467 #   endif /* LA_TYPE == LA_LONGLONG */
1468 #  endif /* LA_TYPE == LA_SHORT */
1469 # endif /* LA_TYPE == LA_INT */
1470         extern off_t lseek();
1471
1472         if (kmem < 0)
1473         {
1474 # ifdef _AUX_SOURCE
1475                 (void) sm_strlcpy(Nl[X_AVENRUN].n_name, LA_AVENRUN,
1476                                sizeof(Nl[X_AVENRUN].n_name));
1477                 Nl[1].n_name[0] = '\0';
1478 # endif /* _AUX_SOURCE */
1479
1480 # if defined(_AIX3) || defined(_AIX4)
1481                 if (knlist(Nl, 1, sizeof(Nl[0])) < 0)
1482 # else /* defined(_AIX3) || defined(_AIX4) */
1483                 if (nlist(_PATH_UNIX, Nl) < 0)
1484 # endif /* defined(_AIX3) || defined(_AIX4) */
1485                 {
1486                         if (tTd(3, 1))
1487                                 sm_dprintf("getla: nlist(%s): %s\n", _PATH_UNIX,
1488                                            sm_errstring(errno));
1489                         return -1;
1490                 }
1491                 if (Nl[X_AVENRUN].n_value == 0)
1492                 {
1493                         if (tTd(3, 1))
1494                                 sm_dprintf("getla: nlist(%s, %s) ==> 0\n",
1495                                         _PATH_UNIX, LA_AVENRUN);
1496                         return -1;
1497                 }
1498 # ifdef NAMELISTMASK
1499                 Nl[X_AVENRUN].n_value &= NAMELISTMASK;
1500 # endif /* NAMELISTMASK */
1501
1502                 kmem = open(_PATH_KMEM, 0, 0);
1503                 if (kmem < 0)
1504                 {
1505                         if (tTd(3, 1))
1506                                 sm_dprintf("getla: open(/dev/kmem): %s\n",
1507                                            sm_errstring(errno));
1508                         return -1;
1509                 }
1510                 if ((j = fcntl(kmem, F_GETFD, 0)) < 0 ||
1511                     fcntl(kmem, F_SETFD, j | FD_CLOEXEC) < 0)
1512                 {
1513                         if (tTd(3, 1))
1514                                 sm_dprintf("getla: fcntl(/dev/kmem, FD_CLOEXEC): %s\n",
1515                                            sm_errstring(errno));
1516                         (void) close(kmem);
1517                         kmem = -1;
1518                         return -1;
1519                 }
1520         }
1521         if (tTd(3, 20))
1522                 sm_dprintf("getla: symbol address = %#lx\n",
1523                         (unsigned long) Nl[X_AVENRUN].n_value);
1524         if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, SEEK_SET) == -1 ||
1525             read(kmem, (char *) avenrun, sizeof(avenrun)) != sizeof(avenrun))
1526         {
1527                 /* thank you Ian */
1528                 if (tTd(3, 1))
1529                         sm_dprintf("getla: lseek or read: %s\n",
1530                                    sm_errstring(errno));
1531                 return -1;
1532         }
1533 # if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) || (LA_TYPE == LA_LONGLONG)
1534         if (tTd(3, 5))
1535         {
1536 #  if LA_TYPE == LA_SHORT
1537                 sm_dprintf("getla: avenrun = %d", avenrun[0]);
1538                 if (tTd(3, 15))
1539                         sm_dprintf(", %d, %d", avenrun[1], avenrun[2]);
1540 #  else /* LA_TYPE == LA_SHORT */
1541 #   if LA_TYPE == LA_LONGLONG
1542                 sm_dprintf("getla: avenrun = %lld", avenrun[0]);
1543                 if (tTd(3, 15))
1544                         sm_dprintf(", %lld, %lld", avenrun[1], avenrun[2]);
1545 #   else /* LA_TYPE == LA_LONGLONG */
1546                 sm_dprintf("getla: avenrun = %ld", avenrun[0]);
1547                 if (tTd(3, 15))
1548                         sm_dprintf(", %ld, %ld", avenrun[1], avenrun[2]);
1549 #   endif /* LA_TYPE == LA_LONGLONG */
1550 #  endif /* LA_TYPE == LA_SHORT */
1551                 sm_dprintf("\n");
1552         }
1553         if (tTd(3, 1))
1554                 sm_dprintf("getla: %d\n",
1555                         (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1556         return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1557 # else /* (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) || (LA_TYPE == LA_LONGLONG) */
1558         if (tTd(3, 5))
1559         {
1560                 sm_dprintf("getla: avenrun = %g", avenrun[0]);
1561                 if (tTd(3, 15))
1562                         sm_dprintf(", %g, %g", avenrun[1], avenrun[2]);
1563                 sm_dprintf("\n");
1564         }
1565         if (tTd(3, 1))
1566                 sm_dprintf("getla: %d\n", (int) (avenrun[0] +0.5));
1567         return ((int) (avenrun[0] + 0.5));
1568 # endif /* (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) || (LA_TYPE == LA_LONGLONG) */
1569 }
1570
1571 #endif /* (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT) || (LA_TYPE == LA_LONGLONG) */
1572
1573 #if LA_TYPE == LA_READKSYM
1574
1575 # include <sys/ksym.h>
1576
1577 int
1578 getla()
1579 {
1580         int j;
1581         static int kmem = -1;
1582         long avenrun[3];
1583         struct mioc_rksym mirk;
1584
1585         if (kmem < 0)
1586         {
1587                 kmem = open("/dev/kmem", 0, 0);
1588                 if (kmem < 0)
1589                 {
1590                         if (tTd(3, 1))
1591                                 sm_dprintf("getla: open(/dev/kmem): %s\n",
1592                                            sm_errstring(errno));
1593                         return -1;
1594                 }
1595                 if ((j = fcntl(kmem, F_GETFD, 0)) < 0 ||
1596                     fcntl(kmem, F_SETFD, j | FD_CLOEXEC) < 0)
1597                 {
1598                         if (tTd(3, 1))
1599                                 sm_dprintf("getla: fcntl(/dev/kmem, FD_CLOEXEC): %s\n",
1600                                            sm_errstring(errno));
1601                         (void) close(kmem);
1602                         kmem = -1;
1603                         return -1;
1604                 }
1605         }
1606         mirk.mirk_symname = LA_AVENRUN;
1607         mirk.mirk_buf = avenrun;
1608         mirk.mirk_buflen = sizeof(avenrun);
1609         if (ioctl(kmem, MIOC_READKSYM, &mirk) < 0)
1610         {
1611                 if (tTd(3, 1))
1612                         sm_dprintf("getla: ioctl(MIOC_READKSYM) failed: %s\n",
1613                                    sm_errstring(errno));
1614                 return -1;
1615         }
1616         if (tTd(3, 5))
1617         {
1618                 sm_dprintf("getla: avenrun = %d", avenrun[0]);
1619                 if (tTd(3, 15))
1620                         sm_dprintf(", %d, %d", avenrun[1], avenrun[2]);
1621                 sm_dprintf("\n");
1622         }
1623         if (tTd(3, 1))
1624                 sm_dprintf("getla: %d\n",
1625                         (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1626         return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1627 }
1628
1629 #endif /* LA_TYPE == LA_READKSYM */
1630
1631 #if LA_TYPE == LA_DGUX
1632
1633 # include <sys/dg_sys_info.h>
1634
1635 int
1636 getla()
1637 {
1638         struct dg_sys_info_load_info load_info;
1639
1640         dg_sys_info((long *)&load_info,
1641                 DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0);
1642
1643         if (tTd(3, 1))
1644                 sm_dprintf("getla: %d\n", (int) (load_info.one_minute + 0.5));
1645
1646         return ((int) (load_info.one_minute + 0.5));
1647 }
1648
1649 #endif /* LA_TYPE == LA_DGUX */
1650
1651 #if LA_TYPE == LA_HPUX
1652
1653 /* forward declarations to keep gcc from complaining */
1654 struct pst_dynamic;
1655 struct pst_status;
1656 struct pst_static;
1657 struct pst_vminfo;
1658 struct pst_diskinfo;
1659 struct pst_processor;
1660 struct pst_lv;
1661 struct pst_swapinfo;
1662
1663 # include <sys/param.h>
1664 # include <sys/pstat.h>
1665
1666 int
1667 getla()
1668 {
1669         struct pst_dynamic pstd;
1670
1671         if (pstat_getdynamic(&pstd, sizeof(struct pst_dynamic),
1672                              (size_t) 1, 0) == -1)
1673                 return 0;
1674
1675         if (tTd(3, 1))
1676                 sm_dprintf("getla: %d\n", (int) (pstd.psd_avg_1_min + 0.5));
1677
1678         return (int) (pstd.psd_avg_1_min + 0.5);
1679 }
1680
1681 #endif /* LA_TYPE == LA_HPUX */
1682
1683 #if LA_TYPE == LA_SUBR
1684
1685 int
1686 getla()
1687 {
1688         double avenrun[3];
1689
1690         if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0)
1691         {
1692                 if (tTd(3, 1))
1693                         sm_dprintf("getla: getloadavg failed: %s",
1694                                    sm_errstring(errno));
1695                 return -1;
1696         }
1697         if (tTd(3, 1))
1698                 sm_dprintf("getla: %d\n", (int) (avenrun[0] +0.5));
1699         return ((int) (avenrun[0] + 0.5));
1700 }
1701
1702 #endif /* LA_TYPE == LA_SUBR */
1703
1704 #if LA_TYPE == LA_MACH
1705
1706 /*
1707 **  This has been tested on NEXTSTEP release 2.1/3.X.
1708 */
1709
1710 # if defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0
1711 #  include <mach/mach.h>
1712 # else /* defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0 */
1713 #  include <mach.h>
1714 # endif /* defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0 */
1715
1716 int
1717 getla()
1718 {
1719         processor_set_t default_set;
1720         kern_return_t error;
1721         unsigned int info_count;
1722         struct processor_set_basic_info info;
1723         host_t host;
1724
1725         error = processor_set_default(host_self(), &default_set);
1726         if (error != KERN_SUCCESS)
1727         {
1728                 if (tTd(3, 1))
1729                         sm_dprintf("getla: processor_set_default failed: %s",
1730                                    sm_errstring(errno));
1731                 return -1;
1732         }
1733         info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
1734         if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO,
1735                                &host, (processor_set_info_t)&info,
1736                                &info_count) != KERN_SUCCESS)
1737         {
1738                 if (tTd(3, 1))
1739                         sm_dprintf("getla: processor_set_info failed: %s",
1740                                    sm_errstring(errno));
1741                 return -1;
1742         }
1743         if (tTd(3, 1))
1744                 sm_dprintf("getla: %d\n",
1745                         (int) ((info.load_average + (LOAD_SCALE / 2)) /
1746                                LOAD_SCALE));
1747         return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE;
1748 }
1749
1750 #endif /* LA_TYPE == LA_MACH */
1751
1752 #if LA_TYPE == LA_PROCSTR
1753 # if SM_CONF_BROKEN_STRTOD
1754         ERROR: This OS has most likely a broken strtod() implemenentation.
1755         ERROR: The function is required for getla().
1756         ERROR: Check the compilation options _LA_PROCSTR and
1757         ERROR: _SM_CONF_BROKEN_STRTOD (without the leading _).
1758 # endif /* SM_CONF_BROKEN_STRTOD */
1759
1760 /*
1761 **  Read /proc/loadavg for the load average.  This is assumed to be
1762 **  in a format like "0.15 0.12 0.06".
1763 **
1764 **      Initially intended for Linux.  This has been in the kernel
1765 **      since at least 0.99.15.
1766 */
1767
1768 # ifndef _PATH_LOADAVG
1769 #  define _PATH_LOADAVG "/proc/loadavg"
1770 # endif /* ! _PATH_LOADAVG */
1771
1772 int
1773 getla()
1774 {
1775         double avenrun;
1776         register int result;
1777         SM_FILE_T *fp;
1778
1779         fp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, _PATH_LOADAVG, SM_IO_RDONLY,
1780                         NULL);
1781         if (fp == NULL)
1782         {
1783                 if (tTd(3, 1))
1784                         sm_dprintf("getla: sm_io_open(%s): %s\n",
1785                                    _PATH_LOADAVG, sm_errstring(errno));
1786                 return -1;
1787         }
1788         result = sm_io_fscanf(fp, SM_TIME_DEFAULT, "%lf", &avenrun);
1789         (void) sm_io_close(fp, SM_TIME_DEFAULT);
1790         if (result != 1)
1791         {
1792                 if (tTd(3, 1))
1793                         sm_dprintf("getla: sm_io_fscanf() = %d: %s\n",
1794                                    result, sm_errstring(errno));
1795                 return -1;
1796         }
1797
1798         if (tTd(3, 1))
1799                 sm_dprintf("getla(): %.2f\n", avenrun);
1800
1801         return ((int) (avenrun + 0.5));
1802 }
1803
1804 #endif /* LA_TYPE == LA_PROCSTR */
1805
1806 #if LA_TYPE == LA_IRIX6
1807
1808 # include <sys/sysmp.h>
1809
1810 # ifdef _UNICOSMP
1811 #  define CAST_SYSMP(x) (x)
1812 # else /* _UNICOSMP */
1813 #  define CAST_SYSMP(x) ((x) & 0x7fffffff)
1814 # endif /* _UNICOSMP */
1815
1816 int
1817 getla(void)
1818 {
1819         int j;
1820         static int kmem = -1;
1821         int avenrun[3];
1822
1823         if (kmem < 0)
1824         {
1825                 kmem = open(_PATH_KMEM, 0, 0);
1826                 if (kmem < 0)
1827                 {
1828                         if (tTd(3, 1))
1829                                 sm_dprintf("getla: open(%s): %s\n", _PATH_KMEM,
1830                                            sm_errstring(errno));
1831                         return -1;
1832                 }
1833                 if ((j = fcntl(kmem, F_GETFD, 0)) < 0 ||
1834                     fcntl(kmem, F_SETFD, j | FD_CLOEXEC) < 0)
1835                 {
1836                         if (tTd(3, 1))
1837                                 sm_dprintf("getla: fcntl(/dev/kmem, FD_CLOEXEC): %s\n",
1838                                            sm_errstring(errno));
1839                         (void) close(kmem);
1840                         kmem = -1;
1841                         return -1;
1842                 }
1843         }
1844
1845         if (lseek(kmem, CAST_SYSMP(sysmp(MP_KERNADDR, MPKA_AVENRUN)), SEEK_SET)
1846                 == -1 ||
1847             read(kmem, (char *) avenrun, sizeof(avenrun)) != sizeof(avenrun))
1848         {
1849                 if (tTd(3, 1))
1850                         sm_dprintf("getla: lseek or read: %s\n",
1851                                    sm_errstring(errno));
1852                 return -1;
1853         }
1854         if (tTd(3, 5))
1855         {
1856                 sm_dprintf("getla: avenrun = %ld", (long int) avenrun[0]);
1857                 if (tTd(3, 15))
1858                         sm_dprintf(", %ld, %ld",
1859                                 (long int) avenrun[1], (long int) avenrun[2]);
1860                 sm_dprintf("\n");
1861         }
1862
1863         if (tTd(3, 1))
1864                 sm_dprintf("getla: %d\n",
1865                         (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1866         return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1867
1868 }
1869 #endif /* LA_TYPE == LA_IRIX6 */
1870
1871 #if LA_TYPE == LA_KSTAT
1872
1873 # include <kstat.h>
1874
1875 int
1876 getla()
1877 {
1878         static kstat_ctl_t *kc = NULL;
1879         static kstat_t *ksp = NULL;
1880         kstat_named_t *ksn;
1881         int la;
1882
1883         if (kc == NULL)         /* if not initialized before */
1884                 kc = kstat_open();
1885         if (kc == NULL)
1886         {
1887                 if (tTd(3, 1))
1888                         sm_dprintf("getla: kstat_open(): %s\n",
1889                                    sm_errstring(errno));
1890                 return -1;
1891         }
1892         if (ksp == NULL)
1893                 ksp = kstat_lookup(kc, "unix", 0, "system_misc");
1894         if (ksp == NULL)
1895         {
1896                 if (tTd(3, 1))
1897                         sm_dprintf("getla: kstat_lookup(): %s\n",
1898                                    sm_errstring(errno));
1899                 return -1;
1900         }
1901         if (kstat_read(kc, ksp, NULL) < 0)
1902         {
1903                 if (tTd(3, 1))
1904                         sm_dprintf("getla: kstat_read(): %s\n",
1905                                    sm_errstring(errno));
1906                 return -1;
1907         }
1908         ksn = (kstat_named_t *) kstat_data_lookup(ksp, "avenrun_1min");
1909         la = ((double) ksn->value.ul + FSCALE/2) / FSCALE;
1910         /* kstat_close(kc); /o do not close for fast access */
1911         return la;
1912 }
1913
1914 #endif /* LA_TYPE == LA_KSTAT */
1915
1916 #if LA_TYPE == LA_DEVSHORT
1917
1918 /*
1919 **  Read /dev/table/avenrun for the load average.  This should contain
1920 **  three shorts for the 1, 5, and 15 minute loads.  We only read the
1921 **  first, since that's all we care about.
1922 **
1923 **      Intended for SCO OpenServer 5.
1924 */
1925
1926 # ifndef _PATH_AVENRUN
1927 #  define _PATH_AVENRUN "/dev/table/avenrun"
1928 # endif /* ! _PATH_AVENRUN */
1929
1930 int
1931 getla()
1932 {
1933         static int afd = -1;
1934         short avenrun;
1935         int loadav;
1936         int r;
1937
1938         errno = EBADF;
1939
1940         if (afd == -1 || lseek(afd, 0L, SEEK_SET) == -1)
1941         {
1942                 if (errno != EBADF)
1943                         return -1;
1944                 afd = open(_PATH_AVENRUN, O_RDONLY|O_SYNC);
1945                 if (afd < 0)
1946                 {
1947                         sm_syslog(LOG_ERR, NOQID,
1948                                 "can't open %s: %s",
1949                                 _PATH_AVENRUN, sm_errstring(errno));
1950                         return -1;
1951                 }
1952         }
1953
1954         r = read(afd, &avenrun, sizeof(avenrun));
1955         if (r != sizeof(avenrun))
1956         {
1957                 sm_syslog(LOG_ERR, NOQID,
1958                         "can't read %s: %s", _PATH_AVENRUN,
1959                         r == -1 ? sm_errstring(errno) : "short read");
1960                 return -1;
1961         }
1962
1963         if (tTd(3, 5))
1964                 sm_dprintf("getla: avenrun = %d\n", avenrun);
1965         loadav = (int) (avenrun + FSCALE/2) >> FSHIFT;
1966         if (tTd(3, 1))
1967                 sm_dprintf("getla: %d\n", loadav);
1968         return loadav;
1969 }
1970
1971 #endif /* LA_TYPE == LA_DEVSHORT */
1972
1973 #if LA_TYPE == LA_ALPHAOSF
1974 struct rtentry;
1975 struct mbuf;
1976 # include <sys/table.h>
1977
1978 int
1979 getla()
1980 {
1981         int ave = 0;
1982         struct tbl_loadavg tab;
1983
1984         if (table(TBL_LOADAVG, 0, &tab, 1, sizeof(tab)) == -1)
1985         {
1986                 if (tTd(3, 1))
1987                         sm_dprintf("getla: table %s\n", sm_errstring(errno));
1988                 return -1;
1989         }
1990
1991         if (tTd(3, 1))
1992                 sm_dprintf("getla: scale = %d\n", tab.tl_lscale);
1993
1994         if (tab.tl_lscale)
1995                 ave = ((tab.tl_avenrun.l[2] + (tab.tl_lscale/2)) /
1996                        tab.tl_lscale);
1997         else
1998                 ave = (int) (tab.tl_avenrun.d[2] + 0.5);
1999
2000         if (tTd(3, 1))
2001                 sm_dprintf("getla: %d\n", ave);
2002
2003         return ave;
2004 }
2005
2006 #endif /* LA_TYPE == LA_ALPHAOSF */
2007
2008 #if LA_TYPE == LA_PSET
2009
2010 int
2011 getla()
2012 {
2013         double avenrun[3];
2014
2015         if (pset_getloadavg(PS_MYID, avenrun,
2016                             sizeof(avenrun) / sizeof(avenrun[0])) < 0)
2017         {
2018                 if (tTd(3, 1))
2019                         sm_dprintf("getla: pset_getloadavg failed: %s",
2020                                    sm_errstring(errno));
2021                 return -1;
2022         }
2023         if (tTd(3, 1))
2024                 sm_dprintf("getla: %d\n", (int) (avenrun[0] +0.5));
2025         return ((int) (avenrun[0] + 0.5));
2026 }
2027
2028 #endif /* LA_TYPE == LA_PSET */
2029
2030 #if LA_TYPE == LA_ZERO
2031
2032 int
2033 getla()
2034 {
2035         if (tTd(3, 1))
2036                 sm_dprintf("getla: ZERO\n");
2037         return 0;
2038 }
2039
2040 #endif /* LA_TYPE == LA_ZERO */
2041
2042 /*
2043  * Copyright 1989 Massachusetts Institute of Technology
2044  *
2045  * Permission to use, copy, modify, distribute, and sell this software and its
2046  * documentation for any purpose is hereby granted without fee, provided that
2047  * the above copyright notice appear in all copies and that both that
2048  * copyright notice and this permission notice appear in supporting
2049  * documentation, and that the name of M.I.T. not be used in advertising or
2050  * publicity pertaining to distribution of the software without specific,
2051  * written prior permission.  M.I.T. makes no representations about the
2052  * suitability of this software for any purpose.  It is provided "as is"
2053  * without express or implied warranty.
2054  *
2055  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
2056  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
2057  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2058  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
2059  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
2060  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2061  *
2062  * Authors:  Many and varied...
2063  */
2064
2065 /* Non Apollo stuff removed by Don Lewis 11/15/93 */
2066 #ifndef lint
2067 SM_UNUSED(static char  rcsid[]) = "@(#)$OrigId: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp $";
2068 #endif /* ! lint */
2069
2070 #ifdef apollo
2071 # undef volatile
2072 # include <apollo/base.h>
2073
2074 /* ARGSUSED */
2075 int getloadavg( call_data )
2076         caddr_t call_data;      /* pointer to (double) return value */
2077 {
2078         double *avenrun = (double *) call_data;
2079         int i;
2080         status_$t      st;
2081         long loadav[3];
2082
2083         proc1_$get_loadav(loadav, &st);
2084         *avenrun = loadav[0] / (double) (1 << 16);
2085         return 0;
2086 }
2087 #endif /* apollo */
2088 /*
2089 **  SM_GETLA -- get the current load average
2090 **
2091 **      Parameters:
2092 **              none
2093 **
2094 **      Returns:
2095 **              none
2096 **
2097 **      Side Effects:
2098 **              Set CurrentLA to the current load average.
2099 **              Set {load_avg} in GlobalMacros to the current load average.
2100 */
2101
2102 void
2103 sm_getla()
2104 {
2105         char labuf[8];
2106
2107         CurrentLA = getla();
2108         (void) sm_snprintf(labuf, sizeof(labuf), "%d", CurrentLA);
2109         macdefine(&GlobalMacros, A_TEMP, macid("{load_avg}"), labuf);
2110 }
2111 /*
2112 **  SHOULDQUEUE -- should this message be queued or sent?
2113 **
2114 **      Compares the message cost to the load average to decide.
2115 **
2116 **      Note: Do NOT change this API! It is documented in op.me
2117 **              and theoretically the user can change this function...
2118 **
2119 **      Parameters:
2120 **              pri -- the priority of the message in question.
2121 **              ct -- the message creation time (unused, but see above).
2122 **
2123 **      Returns:
2124 **              true -- if this message should be queued up for the
2125 **                      time being.
2126 **              false -- if the load is low enough to send this message.
2127 **
2128 **      Side Effects:
2129 **              none.
2130 */
2131
2132 /* ARGSUSED1 */
2133 bool
2134 shouldqueue(pri, ct)
2135         long pri;
2136         time_t ct;
2137 {
2138         bool rval;
2139 #if _FFR_MEMSTAT
2140         long memfree;
2141 #endif /* _FFR_MEMSTAT */
2142
2143         if (tTd(3, 30))
2144                 sm_dprintf("shouldqueue: CurrentLA=%d, pri=%ld: ",
2145                         CurrentLA, pri);
2146
2147 #if _FFR_MEMSTAT
2148         if (QueueLowMem > 0 &&
2149             sm_memstat_get(MemoryResource, &memfree) >= 0 &&
2150             memfree < QueueLowMem)
2151         {
2152                 if (tTd(3, 30))
2153                         sm_dprintf("true (memfree=%ld < QueueLowMem=%ld)\n",
2154                                 memfree, QueueLowMem);
2155                 return true;
2156         }
2157 #endif /* _FFR_MEMSTAT */
2158         if (CurrentLA < QueueLA)
2159         {
2160                 if (tTd(3, 30))
2161                         sm_dprintf("false (CurrentLA < QueueLA)\n");
2162                 return false;
2163         }
2164         rval = pri > (QueueFactor / (CurrentLA - QueueLA + 1));
2165         if (tTd(3, 30))
2166                 sm_dprintf("%s (by calculation)\n", rval ? "true" : "false");
2167         return rval;
2168 }
2169
2170 /*
2171 **  REFUSECONNECTIONS -- decide if connections should be refused
2172 **
2173 **      Parameters:
2174 **              e -- the current envelope.
2175 **              dn -- number of daemon.
2176 **              active -- was this daemon actually active?
2177 **
2178 **      Returns:
2179 **              true if incoming SMTP connections should be refused
2180 **                      (for now).
2181 **              false if we should accept new work.
2182 **
2183 **      Side Effects:
2184 **              Sets process title when it is rejecting connections.
2185 */
2186
2187 bool
2188 refuseconnections(e, dn, active)
2189         ENVELOPE *e;
2190         int dn;
2191         bool active;
2192 {
2193         static time_t lastconn[MAXDAEMONS];
2194         static int conncnt[MAXDAEMONS];
2195         static time_t firstrejtime[MAXDAEMONS];
2196         static time_t nextlogtime[MAXDAEMONS];
2197         int limit;
2198 #if _FFR_MEMSTAT
2199         long memfree;
2200 #endif /* _FFR_MEMSTAT */
2201
2202 #if XLA
2203         if (!xla_smtp_ok())
2204                 return true;
2205 #endif /* XLA */
2206
2207         SM_ASSERT(dn >= 0);
2208         SM_ASSERT(dn < MAXDAEMONS);
2209         if (ConnRateThrottle > 0)
2210         {
2211                 time_t now;
2212
2213                 now = curtime();
2214                 if (active)
2215                 {
2216                         if (now != lastconn[dn])
2217                         {
2218                                 lastconn[dn] = now;
2219                                 conncnt[dn] = 1;
2220                         }
2221                         else if (conncnt[dn]++ > ConnRateThrottle)
2222                         {
2223 #define D_MSG_CRT "deferring connections on daemon %s: %d per second"
2224                                 /* sleep to flatten out connection load */
2225                                 sm_setproctitle(true, e, D_MSG_CRT,
2226                                                 Daemons[dn].d_name,
2227                                                 ConnRateThrottle);
2228                                 if (LogLevel > 8)
2229                                         sm_syslog(LOG_INFO, NOQID, D_MSG_CRT,
2230                                                   Daemons[dn].d_name,
2231                                                   ConnRateThrottle);
2232                                 (void) sleep(1);
2233                         }
2234                 }
2235                 else if (now != lastconn[dn])
2236                         conncnt[dn] = 0;
2237         }
2238
2239
2240 #if _FFR_MEMSTAT
2241         if (RefuseLowMem > 0 &&
2242             sm_memstat_get(MemoryResource, &memfree) >= 0 &&
2243             memfree < RefuseLowMem)
2244         {
2245 # define R_MSG_LM "rejecting connections on daemon %s: free memory: %ld"
2246                 sm_setproctitle(true, e, R_MSG_LM, Daemons[dn].d_name, memfree);
2247                 if (LogLevel > 8)
2248                         sm_syslog(LOG_NOTICE, NOQID, R_MSG_LM,
2249                                 Daemons[dn].d_name, memfree);
2250                 return true;
2251         }
2252 #endif /* _FFR_MEMSTAT */
2253         sm_getla();
2254         limit = (Daemons[dn].d_refuseLA != DPO_NOTSET) ?
2255                 Daemons[dn].d_refuseLA : RefuseLA;
2256         if (limit > 0 && CurrentLA >= limit)
2257         {
2258                 time_t now;
2259
2260 # define R_MSG_LA "rejecting connections on daemon %s: load average: %d"
2261 # define R2_MSG_LA "have been rejecting connections on daemon %s for %s"
2262                 sm_setproctitle(true, e, R_MSG_LA, Daemons[dn].d_name,
2263                                 CurrentLA);
2264                 if (LogLevel > 8)
2265                         sm_syslog(LOG_NOTICE, NOQID, R_MSG_LA,
2266                                 Daemons[dn].d_name, CurrentLA);
2267                 now = curtime();
2268                 if (firstrejtime[dn] == 0)
2269                 {
2270                         firstrejtime[dn] = now;
2271                         nextlogtime[dn] = now + RejectLogInterval;
2272                 }
2273                 else if (nextlogtime[dn] < now)
2274                 {
2275                         sm_syslog(LOG_ERR, NOQID, R2_MSG_LA, Daemons[dn].d_name,
2276                                   pintvl(now - firstrejtime[dn], true));
2277                         nextlogtime[dn] = now + RejectLogInterval;
2278                 }
2279                 return true;
2280         }
2281         else
2282                 firstrejtime[dn] = 0;
2283
2284         limit = (Daemons[dn].d_delayLA != DPO_NOTSET) ?
2285                 Daemons[dn].d_delayLA : DelayLA;
2286         if (limit > 0 && CurrentLA >= limit)
2287         {
2288                 time_t now;
2289                 static time_t log_delay = (time_t) 0;
2290
2291 # define MIN_DELAY_LOG  90      /* wait before logging this again */
2292 # define D_MSG_LA "delaying connections on daemon %s: load average=%d >= %d"
2293                 /* sleep to flatten out connection load */
2294                 sm_setproctitle(true, e, D_MSG_LA, Daemons[dn].d_name,
2295                                 CurrentLA, limit);
2296                 if (LogLevel > 8 && (now = curtime()) > log_delay)
2297                 {
2298                         sm_syslog(LOG_INFO, NOQID, D_MSG_LA,
2299                                   Daemons[dn].d_name, CurrentLA, limit);
2300                         log_delay = now + MIN_DELAY_LOG;
2301                 }
2302                 (void) sleep(1);
2303         }
2304
2305         limit = (Daemons[dn].d_maxchildren != DPO_NOTSET) ?
2306                 Daemons[dn].d_maxchildren : MaxChildren;
2307         if (limit > 0 && CurChildren >= limit)
2308         {
2309                 proc_list_probe();
2310                 if (CurChildren >= limit)
2311                 {
2312 #define R_MSG_CHILD "rejecting connections on daemon %s: %d children, max %d"
2313                         sm_setproctitle(true, e, R_MSG_CHILD,
2314                                         Daemons[dn].d_name, CurChildren,
2315                                         limit);
2316                         if (LogLevel > 8)
2317                                 sm_syslog(LOG_INFO, NOQID, R_MSG_CHILD,
2318                                         Daemons[dn].d_name, CurChildren,
2319                                         limit);
2320                         return true;
2321                 }
2322         }
2323         return false;
2324 }
2325
2326 /*
2327 **  SETPROCTITLE -- set process title for ps
2328 **
2329 **      Parameters:
2330 **              fmt -- a printf style format string.
2331 **              a, b, c -- possible parameters to fmt.
2332 **
2333 **      Returns:
2334 **              none.
2335 **
2336 **      Side Effects:
2337 **              Clobbers argv of our main procedure so ps(1) will
2338 **              display the title.
2339 */
2340
2341 #define SPT_NONE        0       /* don't use it at all */
2342 #define SPT_REUSEARGV   1       /* cover argv with title information */
2343 #define SPT_BUILTIN     2       /* use libc builtin */
2344 #define SPT_PSTAT       3       /* use pstat(PSTAT_SETCMD, ...) */
2345 #define SPT_PSSTRINGS   4       /* use PS_STRINGS->... */
2346 #define SPT_SYSMIPS     5       /* use sysmips() supported by NEWS-OS 6 */
2347 #define SPT_SCO         6       /* write kernel u. area */
2348 #define SPT_CHANGEARGV  7       /* write our own strings into argv[] */
2349
2350 #ifndef SPT_TYPE
2351 # define SPT_TYPE       SPT_REUSEARGV
2352 #endif /* ! SPT_TYPE */
2353
2354
2355 #if SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN
2356
2357 # if SPT_TYPE == SPT_PSTAT
2358 #  include <sys/pstat.h>
2359 # endif /* SPT_TYPE == SPT_PSTAT */
2360 # if SPT_TYPE == SPT_PSSTRINGS
2361 #  include <machine/vmparam.h>
2362 #  include <sys/exec.h>
2363 #  ifndef PS_STRINGS    /* hmmmm....  apparently not available after all */
2364 #   undef SPT_TYPE
2365 #   define SPT_TYPE     SPT_REUSEARGV
2366 #  else /* ! PS_STRINGS */
2367 #   ifndef NKPDE                        /* FreeBSD 2.0 */
2368 #    define NKPDE 63
2369 typedef unsigned int    *pt_entry_t;
2370 #   endif /* ! NKPDE */
2371 #  endif /* ! PS_STRINGS */
2372 # endif /* SPT_TYPE == SPT_PSSTRINGS */
2373
2374 # if SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV
2375 #  define SETPROC_STATIC        static
2376 # else /* SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV */
2377 #  define SETPROC_STATIC
2378 # endif /* SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV */
2379
2380 # if SPT_TYPE == SPT_SYSMIPS
2381 #  include <sys/sysmips.h>
2382 #  include <sys/sysnews.h>
2383 # endif /* SPT_TYPE == SPT_SYSMIPS */
2384
2385 # if SPT_TYPE == SPT_SCO
2386 #  include <sys/immu.h>
2387 #  include <sys/dir.h>
2388 #  include <sys/user.h>
2389 #  include <sys/fs/s5param.h>
2390 #  if PSARGSZ > MAXLINE
2391 #   define SPT_BUFSIZE  PSARGSZ
2392 #  endif /* PSARGSZ > MAXLINE */
2393 # endif /* SPT_TYPE == SPT_SCO */
2394
2395 # ifndef SPT_PADCHAR
2396 #  define SPT_PADCHAR   ' '
2397 # endif /* ! SPT_PADCHAR */
2398
2399 #endif /* SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN */
2400
2401 #ifndef SPT_BUFSIZE
2402 # define SPT_BUFSIZE    MAXLINE
2403 #endif /* ! SPT_BUFSIZE */
2404
2405 #if _FFR_SPT_ALIGN
2406
2407 /*
2408 **  It looks like the Compaq Tru64 5.1A now aligns argv and envp to
2409 **  64 bit alignment, so unless each piece of argv and envp is a multiple
2410 **  of 8 bytes (including terminating NULL), initsetproctitle() won't use
2411 **  any of the space beyond argv[0].  Be sure to set SPT_ALIGN_SIZE if
2412 **  you use this FFR.
2413 */
2414
2415 # ifdef SPT_ALIGN_SIZE
2416 #  define SPT_ALIGN(x, align)   (((((x) + SPT_ALIGN_SIZE) >> (align)) << (align)) - 1)
2417 # else /* SPT_ALIGN_SIZE */
2418 #  define SPT_ALIGN(x, align)   (x)
2419 # endif /* SPT_ALIGN_SIZE */
2420 #else /* _FFR_SPT_ALIGN */
2421 # define SPT_ALIGN(x, align)    (x)
2422 #endif /* _FFR_SPT_ALIGN */
2423
2424 /*
2425 **  Pointers for setproctitle.
2426 **      This allows "ps" listings to give more useful information.
2427 */
2428
2429 static char     **Argv = NULL;          /* pointer to argument vector */
2430 static char     *LastArgv = NULL;       /* end of argv */
2431 #if SPT_TYPE != SPT_BUILTIN
2432 static void     setproctitle __P((const char *, ...));
2433 #endif /* SPT_TYPE != SPT_BUILTIN */
2434
2435 void
2436 initsetproctitle(argc, argv, envp)
2437         int argc;
2438         char **argv;
2439         char **envp;
2440 {
2441         register int i;
2442         int align;
2443         extern char **environ;
2444
2445         /*
2446         **  Move the environment so setproctitle can use the space at
2447         **  the top of memory.
2448         */
2449
2450         if (envp != NULL)
2451         {
2452                 for (i = 0; envp[i] != NULL; i++)
2453                         continue;
2454                 environ = (char **) xalloc(sizeof(char *) * (i + 1));
2455                 for (i = 0; envp[i] != NULL; i++)
2456                         environ[i] = newstr(envp[i]);
2457                 environ[i] = NULL;
2458         }
2459
2460         /*
2461         **  Save start and extent of argv for setproctitle.
2462         */
2463
2464         Argv = argv;
2465
2466         /*
2467         **  Determine how much space we can use for setproctitle.
2468         **  Use all contiguous argv and envp pointers starting at argv[0]
2469         */
2470
2471         align = -1;
2472 # if _FFR_SPT_ALIGN
2473 #  ifdef SPT_ALIGN_SIZE
2474         for (i = SPT_ALIGN_SIZE; i > 0; i >>= 1)
2475                 align++;
2476 #  endif /* SPT_ALIGN_SIZE */
2477 # endif /* _FFR_SPT_ALIGN */
2478
2479         for (i = 0; i < argc; i++)
2480         {
2481                 if (i == 0 || LastArgv + 1 == argv[i])
2482                         LastArgv = argv[i] + SPT_ALIGN(strlen(argv[i]), align);
2483         }
2484         for (i = 0; LastArgv != NULL && envp != NULL && envp[i] != NULL; i++)
2485         {
2486                 if (LastArgv + 1 == envp[i])
2487                         LastArgv = envp[i] + SPT_ALIGN(strlen(envp[i]), align);
2488         }
2489 }
2490
2491 #if SPT_TYPE != SPT_BUILTIN
2492
2493 /*VARARGS1*/
2494 static void
2495 # ifdef __STDC__
2496 setproctitle(const char *fmt, ...)
2497 # else /* __STDC__ */
2498 setproctitle(fmt, va_alist)
2499         const char *fmt;
2500         va_dcl
2501 # endif /* __STDC__ */
2502 {
2503 # if SPT_TYPE != SPT_NONE
2504         register int i;
2505         register char *p;
2506         SETPROC_STATIC char buf[SPT_BUFSIZE];
2507         SM_VA_LOCAL_DECL
2508 #  if SPT_TYPE == SPT_PSTAT
2509         union pstun pst;
2510 #  endif /* SPT_TYPE == SPT_PSTAT */
2511 #  if SPT_TYPE == SPT_SCO
2512         int j;
2513         off_t seek_off;
2514         static int kmem = -1;
2515         static pid_t kmempid = -1;
2516         struct user u;
2517 #  endif /* SPT_TYPE == SPT_SCO */
2518
2519         p = buf;
2520
2521         /* print sendmail: heading for grep */
2522         (void) sm_strlcpy(p, "sendmail: ", SPACELEFT(buf, p));
2523         p += strlen(p);
2524
2525         /* print the argument string */
2526         SM_VA_START(ap, fmt);
2527         (void) sm_vsnprintf(p, SPACELEFT(buf, p), fmt, ap);
2528         SM_VA_END(ap);
2529
2530         i = (int) strlen(buf);
2531         if (i < 0)
2532                 return;
2533
2534 #  if SPT_TYPE == SPT_PSTAT
2535         pst.pst_command = buf;
2536         pstat(PSTAT_SETCMD, pst, i, 0, 0);
2537 #  endif /* SPT_TYPE == SPT_PSTAT */
2538 #  if SPT_TYPE == SPT_PSSTRINGS
2539         PS_STRINGS->ps_nargvstr = 1;
2540         PS_STRINGS->ps_argvstr = buf;
2541 #  endif /* SPT_TYPE == SPT_PSSTRINGS */
2542 #  if SPT_TYPE == SPT_SYSMIPS
2543         sysmips(SONY_SYSNEWS, NEWS_SETPSARGS, buf);
2544 #  endif /* SPT_TYPE == SPT_SYSMIPS */
2545 #  if SPT_TYPE == SPT_SCO
2546         if (kmem < 0 || kmempid != CurrentPid)
2547         {
2548                 if (kmem >= 0)
2549                         (void) close(kmem);
2550                 kmem = open(_PATH_KMEM, O_RDWR, 0);
2551                 if (kmem < 0)
2552                         return;
2553                 if ((j = fcntl(kmem, F_GETFD, 0)) < 0 ||
2554                     fcntl(kmem, F_SETFD, j | FD_CLOEXEC) < 0)
2555                 {
2556                         (void) close(kmem);
2557                         kmem = -1;
2558                         return;
2559                 }
2560                 kmempid = CurrentPid;
2561         }
2562         buf[PSARGSZ - 1] = '\0';
2563         seek_off = UVUBLK + (off_t) u.u_psargs - (off_t) &u;
2564         if (lseek(kmem, (off_t) seek_off, SEEK_SET) == seek_off)
2565                 (void) write(kmem, buf, PSARGSZ);
2566 #  endif /* SPT_TYPE == SPT_SCO */
2567 #  if SPT_TYPE == SPT_REUSEARGV
2568         if (LastArgv == NULL)
2569                 return;
2570
2571         if (i > LastArgv - Argv[0] - 2)
2572         {
2573                 i = LastArgv - Argv[0] - 2;
2574                 buf[i] = '\0';
2575         }
2576         (void) sm_strlcpy(Argv[0], buf, i + 1);
2577         p = &Argv[0][i];
2578         while (p < LastArgv)
2579                 *p++ = SPT_PADCHAR;
2580         Argv[1] = NULL;
2581 #  endif /* SPT_TYPE == SPT_REUSEARGV */
2582 #  if SPT_TYPE == SPT_CHANGEARGV
2583         Argv[0] = buf;
2584         Argv[1] = 0;
2585 #  endif /* SPT_TYPE == SPT_CHANGEARGV */
2586 # endif /* SPT_TYPE != SPT_NONE */
2587 }
2588
2589 #endif /* SPT_TYPE != SPT_BUILTIN */
2590 /*
2591 **  SM_SETPROCTITLE -- set process task and set process title for ps
2592 **
2593 **      Possibly set process status and call setproctitle() to
2594 **      change the ps display.
2595 **
2596 **      Parameters:
2597 **              status -- whether or not to store as process status
2598 **              e -- the current envelope.
2599 **              fmt -- a printf style format string.
2600 **              a, b, c -- possible parameters to fmt.
2601 **
2602 **      Returns:
2603 **              none.
2604 */
2605
2606 /*VARARGS3*/
2607 void
2608 #ifdef __STDC__
2609 sm_setproctitle(bool status, ENVELOPE *e, const char *fmt, ...)
2610 #else /* __STDC__ */
2611 sm_setproctitle(status, e, fmt, va_alist)
2612         bool status;
2613         ENVELOPE *e;
2614         const char *fmt;
2615         va_dcl
2616 #endif /* __STDC__ */
2617 {
2618         char buf[SPT_BUFSIZE];
2619         SM_VA_LOCAL_DECL
2620
2621         /* print the argument string */
2622         SM_VA_START(ap, fmt);
2623         (void) sm_vsnprintf(buf, sizeof(buf), fmt, ap);
2624         SM_VA_END(ap);
2625
2626         if (status)
2627                 proc_list_set(CurrentPid, buf);
2628
2629         if (ProcTitlePrefix != NULL)
2630         {
2631                 char prefix[SPT_BUFSIZE];
2632
2633                 expand(ProcTitlePrefix, prefix, sizeof(prefix), e);
2634                 setproctitle("%s: %s", prefix, buf);
2635         }
2636         else
2637                 setproctitle("%s", buf);
2638 }
2639 /*
2640 **  WAITFOR -- wait for a particular process id.
2641 **
2642 **      Parameters:
2643 **              pid -- process id to wait for.
2644 **
2645 **      Returns:
2646 **              status of pid.
2647 **              -1 if pid never shows up.
2648 **
2649 **      Side Effects:
2650 **              none.
2651 */
2652
2653 int
2654 waitfor(pid)
2655         pid_t pid;
2656 {
2657         int st;
2658         pid_t i;
2659
2660         do
2661         {
2662                 errno = 0;
2663                 i = sm_wait(&st);
2664                 if (i > 0)
2665                         proc_list_drop(i, st, NULL);
2666         } while ((i >= 0 || errno == EINTR) && i != pid);
2667         if (i < 0)
2668                 return -1;
2669         return st;
2670 }
2671 /*
2672 **  SM_WAIT -- wait
2673 **
2674 **      Parameters:
2675 **              status -- pointer to status (return value)
2676 **
2677 **      Returns:
2678 **              pid
2679 */
2680
2681 pid_t
2682 sm_wait(status)
2683         int *status;
2684 {
2685 # ifdef WAITUNION
2686         union wait st;
2687 # else /* WAITUNION */
2688         auto int st;
2689 # endif /* WAITUNION */
2690         pid_t i;
2691 # if defined(ISC_UNIX) || defined(_SCO_unix_)
2692         int savesig;
2693 # endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */
2694
2695 # if defined(ISC_UNIX) || defined(_SCO_unix_)
2696         savesig = sm_releasesignal(SIGCHLD);
2697 # endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */
2698         i = wait(&st);
2699 # if defined(ISC_UNIX) || defined(_SCO_unix_)
2700         if (savesig > 0)
2701                 sm_blocksignal(SIGCHLD);
2702 # endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */
2703 # ifdef WAITUNION
2704         *status = st.w_status;
2705 # else /* WAITUNION */
2706         *status = st;
2707 # endif /* WAITUNION */
2708         return i;
2709 }
2710 /*
2711 **  REAPCHILD -- pick up the body of my child, lest it become a zombie
2712 **
2713 **      Parameters:
2714 **              sig -- the signal that got us here (unused).
2715 **
2716 **      Returns:
2717 **              none.
2718 **
2719 **      Side Effects:
2720 **              Picks up extant zombies.
2721 **              Control socket exits may restart/shutdown daemon.
2722 **
2723 **      NOTE:   THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
2724 **              ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
2725 **              DOING.
2726 */
2727
2728 /* ARGSUSED0 */
2729 SIGFUNC_DECL
2730 reapchild(sig)
2731         int sig;
2732 {
2733         int save_errno = errno;
2734         int st;
2735         pid_t pid;
2736 # if HASWAITPID
2737         auto int status;
2738         int count;
2739
2740         count = 0;
2741         while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
2742         {
2743                 st = status;
2744                 if (count++ > 1000)
2745                         break;
2746 # else /* HASWAITPID */
2747 #  ifdef WNOHANG
2748         union wait status;
2749
2750         while ((pid = wait3(&status, WNOHANG, (struct rusage *) NULL)) > 0)
2751         {
2752                 st = status.w_status;
2753 #  else /* WNOHANG */
2754         auto int status;
2755
2756         /*
2757         **  Catch one zombie -- we will be re-invoked (we hope) if there
2758         **  are more.  Unreliable signals probably break this, but this
2759         **  is the "old system" situation -- waitpid or wait3 are to be
2760         **  strongly preferred.
2761         */
2762
2763         if ((pid = wait(&status)) > 0)
2764         {
2765                 st = status;
2766 #  endif /* WNOHANG */
2767 # endif /* HASWAITPID */
2768                 /* Drop PID and check if it was a control socket child */
2769                 proc_list_drop(pid, st, NULL);
2770         }
2771         FIX_SYSV_SIGNAL(sig, reapchild);
2772         errno = save_errno;
2773         return SIGFUNC_RETURN;
2774 }
2775 /*
2776 **  GETDTABLESIZE -- return number of file descriptors
2777 **
2778 **      Only on non-BSD systems
2779 **
2780 **      Parameters:
2781 **              none
2782 **
2783 **      Returns:
2784 **              size of file descriptor table
2785 **
2786 **      Side Effects:
2787 **              none
2788 */
2789
2790 #ifdef SOLARIS
2791 # include <sys/resource.h>
2792 #endif /* SOLARIS */
2793
2794 int
2795 getdtsize()
2796 {
2797 # ifdef RLIMIT_NOFILE
2798         struct rlimit rl;
2799
2800         if (getrlimit(RLIMIT_NOFILE, &rl) >= 0)
2801                 return rl.rlim_cur;
2802 # endif /* RLIMIT_NOFILE */
2803
2804 # if HASGETDTABLESIZE
2805         return getdtablesize();
2806 # else /* HASGETDTABLESIZE */
2807 #  ifdef _SC_OPEN_MAX
2808         return sysconf(_SC_OPEN_MAX);
2809 #  else /* _SC_OPEN_MAX */
2810         return NOFILE;
2811 #  endif /* _SC_OPEN_MAX */
2812 # endif /* HASGETDTABLESIZE */
2813 }
2814 /*
2815 **  UNAME -- get the UUCP name of this system.
2816 */
2817
2818 #if !HASUNAME
2819
2820 int
2821 uname(name)
2822         struct utsname *name;
2823 {
2824         SM_FILE_T *file;
2825         char *n;
2826
2827         name->nodename[0] = '\0';
2828
2829         /* try /etc/whoami -- one line with the node name */
2830         if ((file = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, "/etc/whoami",
2831                                SM_IO_RDONLY, NULL)) != NULL)
2832         {
2833                 (void) sm_io_fgets(file, SM_TIME_DEFAULT, name->nodename,
2834                                    NODE_LENGTH + 1);
2835                 (void) sm_io_close(file, SM_TIME_DEFAULT);
2836                 n = strchr(name->nodename, '\n');
2837                 if (n != NULL)
2838                         *n = '\0';
2839                 if (name->nodename[0] != '\0')
2840                         return 0;
2841         }
2842
2843         /* try /usr/include/whoami.h -- has a #define somewhere */
2844         if ((file = sm_io_open(SmFtStdio, SM_TIME_DEFAULT,
2845                                "/usr/include/whoami.h", SM_IO_RDONLY, NULL))
2846             != NULL)
2847         {
2848                 char buf[MAXLINE];
2849
2850                 while (sm_io_fgets(file, SM_TIME_DEFAULT,
2851                                    buf, sizeof(buf)) != NULL)
2852                 {
2853                         if (sm_io_sscanf(buf, "#define sysname \"%*[^\"]\"",
2854                                         NODE_LENGTH, name->nodename) > 0)
2855                                 break;
2856                 }
2857                 (void) sm_io_close(file, SM_TIME_DEFAULT);
2858                 if (name->nodename[0] != '\0')
2859                         return 0;
2860         }
2861
2862         return -1;
2863 }
2864 #endif /* !HASUNAME */
2865 /*
2866 **  INITGROUPS -- initialize groups
2867 **
2868 **      Stub implementation for System V style systems
2869 */
2870
2871 #if !HASINITGROUPS
2872
2873 initgroups(name, basegid)
2874         char *name;
2875         int basegid;
2876 {
2877         return 0;
2878 }
2879
2880 #endif /* !HASINITGROUPS */
2881 /*
2882 **  SETGROUPS -- set group list
2883 **
2884 **      Stub implementation for systems that don't have group lists
2885 */
2886
2887 #ifndef NGROUPS_MAX
2888
2889 int
2890 setgroups(ngroups, grouplist)
2891         int ngroups;
2892         GIDSET_T grouplist[];
2893 {
2894         return 0;
2895 }
2896
2897 #endif /* ! NGROUPS_MAX */
2898 /*
2899 **  SETSID -- set session id (for non-POSIX systems)
2900 */
2901
2902 #if !HASSETSID
2903
2904 pid_t
2905 setsid __P ((void))
2906 {
2907 #  ifdef TIOCNOTTY
2908         int fd;
2909
2910         fd = open("/dev/tty", O_RDWR, 0);
2911         if (fd >= 0)
2912         {
2913                 (void) ioctl(fd, TIOCNOTTY, (char *) 0);
2914                 (void) close(fd);
2915         }
2916 #  endif /* TIOCNOTTY */
2917 #  ifdef SYS5SETPGRP
2918         return setpgrp();
2919 #  else /* SYS5SETPGRP */
2920         return setpgid(0, CurrentPid);
2921 #  endif /* SYS5SETPGRP */
2922 }
2923
2924 #endif /* !HASSETSID */
2925 /*
2926 **  FSYNC -- dummy fsync
2927 */
2928
2929 #if NEEDFSYNC
2930
2931 fsync(fd)
2932         int fd;
2933 {
2934 # ifdef O_SYNC
2935         return fcntl(fd, F_SETFL, O_SYNC);
2936 # else /* O_SYNC */
2937         /* nothing we can do */
2938         return 0;
2939 # endif /* O_SYNC */
2940 }
2941
2942 #endif /* NEEDFSYNC */
2943 /*
2944 **  DGUX_INET_ADDR -- inet_addr for DG/UX
2945 **
2946 **      Data General DG/UX version of inet_addr returns a struct in_addr
2947 **      instead of a long.  This patches things.  Only needed on versions
2948 **      prior to 5.4.3.
2949 */
2950
2951 #ifdef DGUX_5_4_2
2952
2953 # undef inet_addr
2954
2955 long
2956 dgux_inet_addr(host)
2957         char *host;
2958 {
2959         struct in_addr haddr;
2960
2961         haddr = inet_addr(host);
2962         return haddr.s_addr;
2963 }
2964
2965 #endif /* DGUX_5_4_2 */
2966 /*
2967 **  GETOPT -- for old systems or systems with bogus implementations
2968 */
2969
2970 #if !SM_CONF_GETOPT
2971
2972 /*
2973  * Copyright (c) 1985 Regents of the University of California.
2974  * All rights reserved.  The Berkeley software License Agreement
2975  * specifies the terms and conditions for redistribution.
2976  */
2977
2978
2979 /*
2980 **  this version hacked to add `atend' flag to allow state machine
2981 **  to reset if invoked by the program to scan args for a 2nd time
2982 */
2983
2984 # if defined(LIBC_SCCS) && !defined(lint)
2985 static char sccsid[] = "@(#)getopt.c    4.3 (Berkeley) 3/9/86";
2986 # endif /* defined(LIBC_SCCS) && !defined(lint) */
2987
2988 /*
2989 **  get option letter from argument vector
2990 */
2991 # ifdef _CONVEX_SOURCE
2992 extern int      optind, opterr, optopt;
2993 extern char     *optarg;
2994 # else /* _CONVEX_SOURCE */
2995 int     opterr = 1;             /* if error message should be printed */
2996 int     optind = 1;             /* index into parent argv vector */
2997 int     optopt = 0;             /* character checked for validity */
2998 char    *optarg = NULL;         /* argument associated with option */
2999 # endif /* _CONVEX_SOURCE */
3000
3001 # define BADCH  (int)'?'
3002 # define EMSG   ""
3003 # define tell(s)        if (opterr) \
3004                         {sm_io_fputs(smioerr, SM_TIME_DEFAULT, *nargv); \
3005                         (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT, s); \
3006                         (void) sm_io_putc(smioerr, SM_TIME_DEFAULT, optopt); \
3007                         (void) sm_io_putc(smioerr, SM_TIME_DEFAULT, '\n'); \
3008                         return BADCH;}
3009
3010 int
3011 getopt(nargc,nargv,ostr)
3012         int             nargc;
3013         char *const     *nargv;
3014         const char      *ostr;
3015 {
3016         static char     *place = EMSG;  /* option letter processing */
3017         static char     atend = 0;
3018         register char   *oli = NULL;    /* option letter list index */
3019
3020         if (atend) {
3021                 atend = 0;
3022                 place = EMSG;
3023         }
3024         if(!*place) {                   /* update scanning pointer */
3025                 if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) {
3026                         atend++;
3027                         return -1;
3028                 }
3029                 if (*place == '-') {    /* found "--" */
3030                         ++optind;
3031                         atend++;
3032                         return -1;
3033                 }
3034         }                               /* option letter okay? */
3035         if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) {
3036                 if (!*place) ++optind;
3037                 tell(": illegal option -- ");
3038         }
3039         if (oli && *++oli != ':') {             /* don't need argument */
3040                 optarg = NULL;
3041                 if (!*place) ++optind;
3042         }
3043         else {                          /* need an argument */
3044                 if (*place) optarg = place;     /* no white space */
3045                 else if (nargc <= ++optind) {   /* no arg */
3046                         place = EMSG;
3047                         tell(": option requires an argument -- ");
3048                 }
3049                 else optarg = nargv[optind];    /* white space */
3050                 place = EMSG;
3051                 ++optind;
3052         }
3053         return optopt;                  /* dump back option letter */
3054 }
3055
3056 #endif /* !SM_CONF_GETOPT */
3057 /*
3058 **  USERSHELLOK -- tell if a user's shell is ok for unrestricted use
3059 **
3060 **      Parameters:
3061 **              user -- the name of the user we are checking.
3062 **              shell -- the user's shell from /etc/passwd
3063 **
3064 **      Returns:
3065 **              true -- if it is ok to use this for unrestricted access.
3066 **              false -- if the shell is restricted.
3067 */
3068
3069 #if !HASGETUSERSHELL
3070
3071 # ifndef _PATH_SHELLS
3072 #  define _PATH_SHELLS  "/etc/shells"
3073 # endif /* ! _PATH_SHELLS */
3074
3075 # if defined(_AIX3) || defined(_AIX4)
3076 #  include <userconf.h>
3077 #  if _AIX4 >= 40200
3078 #   include <userpw.h>
3079 #  endif /* _AIX4 >= 40200 */
3080 #  include <usersec.h>
3081 # endif /* defined(_AIX3) || defined(_AIX4) */
3082
3083 static char     *DefaultUserShells[] =
3084 {
3085         "/bin/sh",              /* standard shell */
3086 # ifdef MPE
3087         "/SYS/PUB/CI",
3088 # else /* MPE */
3089         "/usr/bin/sh",
3090         "/bin/csh",             /* C shell */
3091         "/usr/bin/csh",
3092 # endif /* MPE */
3093 # ifdef __hpux
3094 #  ifdef V4FS
3095         "/usr/bin/rsh",         /* restricted Bourne shell */
3096         "/usr/bin/ksh",         /* Korn shell */
3097         "/usr/bin/rksh",        /* restricted Korn shell */
3098         "/usr/bin/pam",
3099         "/usr/bin/keysh",       /* key shell (extended Korn shell) */
3100         "/usr/bin/posix/sh",
3101 #  else /* V4FS */
3102         "/bin/rsh",             /* restricted Bourne shell */
3103         "/bin/ksh",             /* Korn shell */
3104         "/bin/rksh",            /* restricted Korn shell */
3105         "/bin/pam",
3106         "/usr/bin/keysh",       /* key shell (extended Korn shell) */
3107         "/bin/posix/sh",
3108         "/sbin/sh",
3109 #  endif /* V4FS */
3110 # endif /* __hpux */
3111 # if defined(_AIX3) || defined(_AIX4)
3112         "/bin/ksh",             /* Korn shell */
3113         "/usr/bin/ksh",
3114         "/bin/tsh",             /* trusted shell */
3115         "/usr/bin/tsh",
3116         "/bin/bsh",             /* Bourne shell */
3117         "/usr/bin/bsh",
3118 # endif /* defined(_AIX3) || defined(_AIX4) */
3119 # if defined(__svr4__) || defined(__svr5__)
3120         "/bin/ksh",             /* Korn shell */
3121         "/usr/bin/ksh",
3122 # endif /* defined(__svr4__) || defined(__svr5__) */
3123 # ifdef sgi
3124         "/sbin/sh",             /* SGI's shells really live in /sbin */
3125         "/usr/bin/sh",
3126         "/sbin/bsh",            /* classic Bourne shell */
3127         "/bin/bsh",
3128         "/usr/bin/bsh",
3129         "/sbin/csh",            /* standard csh */
3130         "/bin/csh",
3131         "/usr/bin/csh",
3132         "/sbin/jsh",            /* classic Bourne shell w/ job control*/
3133         "/bin/jsh",
3134         "/usr/bin/jsh",
3135         "/bin/ksh",             /* Korn shell */
3136         "/sbin/ksh",
3137         "/usr/bin/ksh",
3138         "/sbin/tcsh",           /* Extended csh */
3139         "/bin/tcsh",
3140         "/usr/bin/tcsh",
3141 # endif /* sgi */
3142         NULL
3143 };
3144
3145 #endif /* !HASGETUSERSHELL */
3146
3147 #define WILDCARD_SHELL  "/SENDMAIL/ANY/SHELL/"
3148
3149 bool
3150 usershellok(user, shell)
3151         char *user;
3152         char *shell;
3153 {
3154 # if HASGETUSERSHELL
3155         register char *p;
3156         extern char *getusershell();
3157
3158         if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') ||
3159             ConfigLevel <= 1)
3160                 return true;
3161
3162         setusershell();
3163         while ((p = getusershell()) != NULL)
3164                 if (strcmp(p, shell) == 0 || strcmp(p, WILDCARD_SHELL) == 0)
3165                         break;
3166         endusershell();
3167         return p != NULL;
3168 # else /* HASGETUSERSHELL */
3169 #  if USEGETCONFATTR
3170         auto char *v;
3171 #  endif /* USEGETCONFATTR */
3172         register SM_FILE_T *shellf;
3173         char buf[MAXLINE];
3174
3175         if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') ||
3176             ConfigLevel <= 1)
3177                 return true;
3178
3179 #  if USEGETCONFATTR
3180         /*
3181         **  Naturally IBM has a "better" idea.....
3182         **
3183         **      What a crock.  This interface isn't documented, it is
3184         **      considered part of the security library (-ls), and it
3185         **      only works if you are running as root (since the list
3186         **      of valid shells is obviously a source of great concern).
3187         **      I recommend that you do NOT define USEGETCONFATTR,
3188         **      especially since you are going to have to set up an
3189         **      /etc/shells anyhow to handle the cases where getconfattr
3190         **      fails.
3191         */
3192
3193         if (getconfattr(SC_SYS_LOGIN, SC_SHELLS, &v, SEC_LIST) == 0 && v != NULL)
3194         {
3195                 while (*v != '\0')
3196                 {
3197                         if (strcmp(v, shell) == 0 || strcmp(v, WILDCARD_SHELL) == 0)
3198                                 return true;
3199                         v += strlen(v) + 1;
3200                 }
3201                 return false;
3202         }
3203 #  endif /* USEGETCONFATTR */
3204
3205         shellf = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, _PATH_SHELLS,
3206                             SM_IO_RDONLY, NULL);
3207         if (shellf == NULL)
3208         {
3209                 /* no /etc/shells; see if it is one of the std shells */
3210                 char **d;
3211
3212                 if (errno != ENOENT && LogLevel > 3)
3213                         sm_syslog(LOG_ERR, NOQID,
3214                                   "usershellok: cannot open %s: %s",
3215                                   _PATH_SHELLS, sm_errstring(errno));
3216
3217                 for (d = DefaultUserShells; *d != NULL; d++)
3218                 {
3219                         if (strcmp(shell, *d) == 0)
3220                                 return true;
3221                 }
3222                 return false;
3223         }
3224
3225         while (sm_io_fgets(shellf, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
3226         {
3227                 register char *p, *q;
3228
3229                 p = buf;
3230                 while (*p != '\0' && *p != '#' && *p != '/')
3231                         p++;
3232                 if (*p == '#' || *p == '\0')
3233                         continue;
3234                 q = p;
3235                 while (*p != '\0' && *p != '#' && !(isascii(*p) && isspace(*p)))
3236                         p++;
3237                 *p = '\0';
3238                 if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0)
3239                 {
3240                         (void) sm_io_close(shellf, SM_TIME_DEFAULT);
3241                         return true;
3242                 }
3243         }
3244         (void) sm_io_close(shellf, SM_TIME_DEFAULT);
3245         return false;
3246 # endif /* HASGETUSERSHELL */
3247 }
3248 /*
3249 **  FREEDISKSPACE -- see how much free space is on the queue filesystem
3250 **
3251 **      Only implemented if you have statfs.
3252 **
3253 **      Parameters:
3254 **              dir -- the directory in question.
3255 **              bsize -- a variable into which the filesystem
3256 **                      block size is stored.
3257 **
3258 **      Returns:
3259 **              The number of blocks free on the queue filesystem.
3260 **              -1 if the statfs call fails.
3261 **
3262 **      Side effects:
3263 **              Puts the filesystem block size into bsize.
3264 */
3265
3266 /* statfs types */
3267 # define SFS_NONE       0       /* no statfs implementation */
3268 # define SFS_USTAT      1       /* use ustat */
3269 # define SFS_4ARGS      2       /* use four-argument statfs call */
3270 # define SFS_VFS        3       /* use <sys/vfs.h> implementation */
3271 # define SFS_MOUNT      4       /* use <sys/mount.h> implementation */
3272 # define SFS_STATFS     5       /* use <sys/statfs.h> implementation */
3273 # define SFS_STATVFS    6       /* use <sys/statvfs.h> implementation */
3274
3275 # ifndef SFS_TYPE
3276 #  define SFS_TYPE      SFS_NONE
3277 # endif /* ! SFS_TYPE */
3278
3279 # if SFS_TYPE == SFS_USTAT
3280 #  include <ustat.h>
3281 # endif /* SFS_TYPE == SFS_USTAT */
3282 # if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS
3283 #  include <sys/statfs.h>
3284 # endif /* SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS */
3285 # if SFS_TYPE == SFS_VFS
3286 #  include <sys/vfs.h>
3287 # endif /* SFS_TYPE == SFS_VFS */
3288 # if SFS_TYPE == SFS_MOUNT
3289 #  include <sys/mount.h>
3290 # endif /* SFS_TYPE == SFS_MOUNT */
3291 # if SFS_TYPE == SFS_STATVFS
3292 #  include <sys/statvfs.h>
3293 # endif /* SFS_TYPE == SFS_STATVFS */
3294
3295 long
3296 freediskspace(dir, bsize)
3297         const char *dir;
3298         long *bsize;
3299 {
3300 # if SFS_TYPE == SFS_NONE
3301         if (bsize != NULL)
3302                 *bsize = 4096L;
3303
3304         /* assume free space is plentiful */
3305         return (long) LONG_MAX;
3306 # else /* SFS_TYPE == SFS_NONE */
3307 #  if SFS_TYPE == SFS_USTAT
3308         struct ustat fs;
3309         struct stat statbuf;
3310 #   define FSBLOCKSIZE  DEV_BSIZE
3311 #   define SFS_BAVAIL   f_tfree
3312 #  else /* SFS_TYPE == SFS_USTAT */
3313 #   if defined(ultrix)
3314         struct fs_data fs;
3315 #    define SFS_BAVAIL  fd_bfreen
3316 #    define FSBLOCKSIZE 1024L
3317 #   else /* defined(ultrix) */
3318 #    if SFS_TYPE == SFS_STATVFS
3319         struct statvfs fs;
3320 #     define FSBLOCKSIZE        fs.f_frsize
3321 #    else /* SFS_TYPE == SFS_STATVFS */
3322         struct statfs fs;
3323 #     define FSBLOCKSIZE        fs.f_bsize
3324 #    endif /* SFS_TYPE == SFS_STATVFS */
3325 #   endif /* defined(ultrix) */
3326 #  endif /* SFS_TYPE == SFS_USTAT */
3327 #  ifndef SFS_BAVAIL
3328 #   define SFS_BAVAIL f_bavail
3329 #  endif /* ! SFS_BAVAIL */
3330
3331 #  if SFS_TYPE == SFS_USTAT
3332         if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0)
3333 #  else /* SFS_TYPE == SFS_USTAT */
3334 #   if SFS_TYPE == SFS_4ARGS
3335         if (statfs(dir, &fs, sizeof(fs), 0) == 0)
3336 #   else /* SFS_TYPE == SFS_4ARGS */
3337 #    if SFS_TYPE == SFS_STATVFS
3338         if (statvfs(dir, &fs) == 0)
3339 #    else /* SFS_TYPE == SFS_STATVFS */
3340 #     if defined(ultrix)
3341         if (statfs(dir, &fs) > 0)
3342 #     else /* defined(ultrix) */
3343         if (statfs(dir, &fs) == 0)
3344 #     endif /* defined(ultrix) */
3345 #    endif /* SFS_TYPE == SFS_STATVFS */
3346 #   endif /* SFS_TYPE == SFS_4ARGS */
3347 #  endif /* SFS_TYPE == SFS_USTAT */
3348         {
3349                 if (bsize != NULL)
3350                         *bsize = FSBLOCKSIZE;
3351                 if (fs.SFS_BAVAIL <= 0)
3352                         return 0;
3353                 else if (fs.SFS_BAVAIL > LONG_MAX)
3354                         return (long) LONG_MAX;
3355                 else
3356                         return (long) fs.SFS_BAVAIL;
3357         }
3358         return -1;
3359 # endif /* SFS_TYPE == SFS_NONE */
3360 }
3361 /*
3362 **  ENOUGHDISKSPACE -- is there enough free space on the queue file systems?
3363 **
3364 **      Parameters:
3365 **              msize -- the size to check against.  If zero, we don't yet
3366 **              know how big the message will be, so just check for
3367 **              a "reasonable" amount.
3368 **              e -- envelope, or NULL -- controls logging
3369 **
3370 **      Returns:
3371 **              true if in every queue group there is at least one
3372 **              queue directory whose file system contains enough free space.
3373 **              false otherwise.
3374 **
3375 **      Side Effects:
3376 **              If there is not enough disk space and e != NULL
3377 **              then sm_syslog is called.
3378 */
3379
3380 bool
3381 enoughdiskspace(msize, e)
3382         long msize;
3383         ENVELOPE *e;
3384 {
3385         int i;
3386
3387 #if _FFR_TESTS
3388         if (tTd(4, 101))
3389                 return false;
3390 #endif /* _FFR_TESTS */
3391         if (MinBlocksFree <= 0 && msize <= 0)
3392         {
3393                 if (tTd(4, 80))
3394                         sm_dprintf("enoughdiskspace: no threshold\n");
3395                 return true;
3396         }
3397
3398         filesys_update();
3399         for (i = 0; i < NumQueue; ++i)
3400         {
3401                 if (pickqdir(Queue[i], msize, e) < 0)
3402                         return false;
3403         }
3404         return true;
3405 }
3406 /*
3407 **  TRANSIENTERROR -- tell if an error code indicates a transient failure
3408 **
3409 **      This looks at an errno value and tells if this is likely to
3410 **      go away if retried later.
3411 **
3412 **      Parameters:
3413 **              err -- the errno code to classify.
3414 **
3415 **      Returns:
3416 **              true if this is probably transient.
3417 **              false otherwise.
3418 */
3419
3420 bool
3421 transienterror(err)
3422         int err;
3423 {
3424         switch (err)
3425         {
3426           case EIO:                     /* I/O error */
3427           case ENXIO:                   /* Device not configured */
3428           case EAGAIN:                  /* Resource temporarily unavailable */
3429           case ENOMEM:                  /* Cannot allocate memory */
3430           case ENODEV:                  /* Operation not supported by device */
3431           case ENFILE:                  /* Too many open files in system */
3432           case EMFILE:                  /* Too many open files */
3433           case ENOSPC:                  /* No space left on device */
3434           case ETIMEDOUT:               /* Connection timed out */
3435 #ifdef ESTALE
3436           case ESTALE:                  /* Stale NFS file handle */
3437 #endif /* ESTALE */
3438 #ifdef ENETDOWN
3439           case ENETDOWN:                /* Network is down */
3440 #endif /* ENETDOWN */
3441 #ifdef ENETUNREACH
3442           case ENETUNREACH:             /* Network is unreachable */
3443 #endif /* ENETUNREACH */
3444 #ifdef ENETRESET
3445           case ENETRESET:               /* Network dropped connection on reset */
3446 #endif /* ENETRESET */
3447 #ifdef ECONNABORTED
3448           case ECONNABORTED:            /* Software caused connection abort */
3449 #endif /* ECONNABORTED */
3450 #ifdef ECONNRESET
3451           case ECONNRESET:              /* Connection reset by peer */
3452 #endif /* ECONNRESET */
3453 #ifdef ENOBUFS
3454           case ENOBUFS:                 /* No buffer space available */
3455 #endif /* ENOBUFS */
3456 #ifdef ESHUTDOWN
3457           case ESHUTDOWN:               /* Can't send after socket shutdown */
3458 #endif /* ESHUTDOWN */
3459 #ifdef ECONNREFUSED
3460           case ECONNREFUSED:            /* Connection refused */
3461 #endif /* ECONNREFUSED */
3462 #ifdef EHOSTDOWN
3463           case EHOSTDOWN:               /* Host is down */
3464 #endif /* EHOSTDOWN */
3465 #ifdef EHOSTUNREACH
3466           case EHOSTUNREACH:            /* No route to host */
3467 #endif /* EHOSTUNREACH */
3468 #ifdef EDQUOT
3469           case EDQUOT:                  /* Disc quota exceeded */
3470 #endif /* EDQUOT */
3471 #ifdef EPROCLIM
3472           case EPROCLIM:                /* Too many processes */
3473 #endif /* EPROCLIM */
3474 #ifdef EUSERS
3475           case EUSERS:                  /* Too many users */
3476 #endif /* EUSERS */
3477 #ifdef EDEADLK
3478           case EDEADLK:                 /* Resource deadlock avoided */
3479 #endif /* EDEADLK */
3480 #ifdef EISCONN
3481           case EISCONN:                 /* Socket already connected */
3482 #endif /* EISCONN */
3483 #ifdef EINPROGRESS
3484           case EINPROGRESS:             /* Operation now in progress */
3485 #endif /* EINPROGRESS */
3486 #ifdef EALREADY
3487           case EALREADY:                /* Operation already in progress */
3488 #endif /* EALREADY */
3489 #ifdef EADDRINUSE
3490           case EADDRINUSE:              /* Address already in use */
3491 #endif /* EADDRINUSE */
3492 #ifdef EADDRNOTAVAIL
3493           case EADDRNOTAVAIL:           /* Can't assign requested address */
3494 #endif /* EADDRNOTAVAIL */
3495 #ifdef ETXTBSY
3496           case ETXTBSY:                 /* (Apollo) file locked */
3497 #endif /* ETXTBSY */
3498 #if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR))
3499           case ENOSR:                   /* Out of streams resources */
3500 #endif /* defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) */
3501 #ifdef ENOLCK
3502           case ENOLCK:                  /* No locks available */
3503 #endif /* ENOLCK */
3504           case E_SM_OPENTIMEOUT:        /* PSEUDO: open timed out */
3505                 return true;
3506         }
3507
3508         /* nope, must be permanent */
3509         return false;
3510 }
3511 /*
3512 **  LOCKFILE -- lock a file using flock or (shudder) fcntl locking
3513 **
3514 **      Parameters:
3515 **              fd -- the file descriptor of the file.
3516 **              filename -- the file name (for error messages).
3517 **              ext -- the filename extension.
3518 **              type -- type of the lock.  Bits can be:
3519 **                      LOCK_EX -- exclusive lock.
3520 **                      LOCK_NB -- non-blocking.
3521 **                      LOCK_UN -- unlock.
3522 **
3523 **      Returns:
3524 **              true if the lock was acquired.
3525 **              false otherwise.
3526 */
3527
3528 bool
3529 lockfile(fd, filename, ext, type)
3530         int fd;
3531         char *filename;
3532         char *ext;
3533         int type;
3534 {
3535         int i;
3536         int save_errno;
3537 # if !HASFLOCK
3538         int action;
3539         struct flock lfd;
3540
3541         if (ext == NULL)
3542                 ext = "";
3543
3544         memset(&lfd, '\0', sizeof(lfd));
3545         if (bitset(LOCK_UN, type))
3546                 lfd.l_type = F_UNLCK;
3547         else if (bitset(LOCK_EX, type))
3548                 lfd.l_type = F_WRLCK;
3549         else
3550                 lfd.l_type = F_RDLCK;
3551
3552         if (bitset(LOCK_NB, type))
3553                 action = F_SETLK;
3554         else
3555                 action = F_SETLKW;
3556
3557         if (tTd(55, 60))
3558                 sm_dprintf("lockfile(%s%s, action=%d, type=%d): ",
3559                         filename, ext, action, lfd.l_type);
3560
3561         while ((i = fcntl(fd, action, &lfd)) < 0 && errno == EINTR)
3562                 continue;
3563         if (i >= 0)
3564         {
3565                 if (tTd(55, 60))
3566                         sm_dprintf("SUCCESS\n");
3567                 return true;
3568         }
3569         save_errno = errno;
3570
3571         if (tTd(55, 60))
3572                 sm_dprintf("(%s) ", sm_errstring(save_errno));
3573
3574         /*
3575         **  On SunOS, if you are testing using -oQ/tmp/mqueue or
3576         **  -oA/tmp/aliases or anything like that, and /tmp is mounted
3577         **  as type "tmp" (that is, served from swap space), the
3578         **  previous fcntl will fail with "Invalid argument" errors.
3579         **  Since this is fairly common during testing, we will assume
3580         **  that this indicates that the lock is successfully grabbed.
3581         */
3582
3583         if (save_errno == EINVAL)
3584         {
3585                 if (tTd(55, 60))
3586                         sm_dprintf("SUCCESS\n");
3587                 return true;
3588         }
3589
3590         if (!bitset(LOCK_NB, type) ||
3591             (save_errno != EACCES && save_errno != EAGAIN))
3592         {
3593                 int omode = fcntl(fd, F_GETFL, 0);
3594                 uid_t euid = geteuid();
3595
3596                 errno = save_errno;
3597                 syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
3598                        filename, ext, fd, type, omode, euid);
3599                 dumpfd(fd, true, true);
3600         }
3601 # else /* !HASFLOCK */
3602         if (ext == NULL)
3603                 ext = "";
3604
3605         if (tTd(55, 60))
3606                 sm_dprintf("lockfile(%s%s, type=%o): ", filename, ext, type);
3607
3608         while ((i = flock(fd, type)) < 0 && errno == EINTR)
3609                 continue;
3610         if (i >= 0)
3611         {
3612                 if (tTd(55, 60))
3613                         sm_dprintf("SUCCESS\n");
3614                 return true;
3615         }
3616         save_errno = errno;
3617
3618         if (tTd(55, 60))
3619                 sm_dprintf("(%s) ", sm_errstring(save_errno));
3620
3621         if (!bitset(LOCK_NB, type) || save_errno != EWOULDBLOCK)
3622         {
3623                 int omode = fcntl(fd, F_GETFL, 0);
3624                 uid_t euid = geteuid();
3625
3626                 errno = save_errno;
3627                 syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
3628                         filename, ext, fd, type, omode, euid);
3629                 dumpfd(fd, true, true);
3630         }
3631 # endif /* !HASFLOCK */
3632         if (tTd(55, 60))
3633                 sm_dprintf("FAIL\n");
3634         errno = save_errno;
3635         return false;
3636 }
3637 /*
3638 **  CHOWNSAFE -- tell if chown is "safe" (executable only by root)
3639 **
3640 **      Unfortunately, given that we can't predict other systems on which
3641 **      a remote mounted (NFS) filesystem will be mounted, the answer is
3642 **      almost always that this is unsafe.
3643 **
3644 **      Note also that many operating systems have non-compliant
3645 **      implementations of the _POSIX_CHOWN_RESTRICTED variable and the
3646 **      fpathconf() routine.  According to IEEE 1003.1-1990, if
3647 **      _POSIX_CHOWN_RESTRICTED is defined and not equal to -1, then
3648 **      no non-root process can give away the file.  However, vendors
3649 **      don't take NFS into account, so a comfortable value of
3650 **      _POSIX_CHOWN_RESTRICTED tells us nothing.
3651 **
3652 **      Also, some systems (e.g., IRIX 6.2) return 1 from fpathconf()
3653 **      even on files where chown is not restricted.  Many systems get
3654 **      this wrong on NFS-based filesystems (that is, they say that chown
3655 **      is restricted [safe] on NFS filesystems where it may not be, since
3656 **      other systems can access the same filesystem and do file giveaway;
3657 **      only the NFS server knows for sure!)  Hence, it is important to
3658 **      get the value of SAFENFSPATHCONF correct -- it should be defined
3659 **      _only_ after testing (see test/t_pathconf.c) a system on an unsafe
3660 **      NFS-based filesystem to ensure that you can get meaningful results.
3661 **      If in doubt, assume unsafe!
3662 **
3663 **      You may also need to tweak IS_SAFE_CHOWN -- it should be a
3664 **      condition indicating whether the return from pathconf indicates
3665 **      that chown is safe (typically either > 0 or >= 0 -- there isn't
3666 **      even any agreement about whether a zero return means that a file
3667 **      is or is not safe).  It defaults to "> 0".
3668 **
3669 **      If the parent directory is safe (writable only by owner back
3670 **      to the root) then we can relax slightly and trust fpathconf
3671 **      in more circumstances.  This is really a crock -- if this is an
3672 **      NFS mounted filesystem then we really know nothing about the
3673 **      underlying implementation.  However, most systems pessimize and
3674 **      return an error (EINVAL or EOPNOTSUPP) on NFS filesystems, which
3675 **      we interpret as unsafe, as we should.  Thus, this heuristic gets
3676 **      us into a possible problem only on systems that have a broken
3677 **      pathconf implementation and which are also poorly configured
3678 **      (have :include: files in group- or world-writable directories).
3679 **
3680 **      Parameters:
3681 **              fd -- the file descriptor to check.
3682 **              safedir -- set if the parent directory is safe.
3683 **
3684 **      Returns:
3685 **              true -- if the chown(2) operation is "safe" -- that is,
3686 **                      only root can chown the file to an arbitrary user.
3687 **              false -- if an arbitrary user can give away a file.
3688 */
3689
3690 #ifndef IS_SAFE_CHOWN
3691 # define IS_SAFE_CHOWN  > 0
3692 #endif /* ! IS_SAFE_CHOWN */
3693
3694 bool
3695 chownsafe(fd, safedir)
3696         int fd;
3697         bool safedir;
3698 {
3699 # if (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \
3700     (defined(_PC_CHOWN_RESTRICTED) || defined(_GNU_TYPES_H))
3701         int rval;
3702
3703         /* give the system administrator a chance to override */
3704         if (bitnset(DBS_ASSUMESAFECHOWN, DontBlameSendmail))
3705                 return true;
3706
3707         /*
3708         **  Some systems (e.g., SunOS) seem to have the call and the
3709         **  #define _PC_CHOWN_RESTRICTED, but don't actually implement
3710         **  the call.  This heuristic checks for that.
3711         */
3712
3713         errno = 0;
3714         rval = fpathconf(fd, _PC_CHOWN_RESTRICTED);
3715 #  if SAFENFSPATHCONF
3716         return errno == 0 && rval IS_SAFE_CHOWN;
3717 #  else /* SAFENFSPATHCONF */
3718         return safedir && errno == 0 && rval IS_SAFE_CHOWN;
3719 #  endif /* SAFENFSPATHCONF */
3720 # else /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && ... */
3721         return bitnset(DBS_ASSUMESAFECHOWN, DontBlameSendmail);
3722 # endif /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && ... */
3723 }
3724 /*
3725 **  RESETLIMITS -- reset system controlled resource limits
3726 **
3727 **      This is to avoid denial-of-service attacks
3728 **
3729 **      Parameters:
3730 **              none
3731 **
3732 **      Returns:
3733 **              none
3734 */
3735
3736 #if HASSETRLIMIT
3737 # ifdef RLIMIT_NEEDS_SYS_TIME_H
3738 #  include <sm/time.h>
3739 # endif /* RLIMIT_NEEDS_SYS_TIME_H */
3740 # include <sys/resource.h>
3741 #endif /* HASSETRLIMIT */
3742
3743 void
3744 resetlimits()
3745 {
3746 #if HASSETRLIMIT
3747         struct rlimit lim;
3748
3749         lim.rlim_cur = lim.rlim_max = RLIM_INFINITY;
3750         (void) setrlimit(RLIMIT_CPU, &lim);
3751         (void) setrlimit(RLIMIT_FSIZE, &lim);
3752 # ifdef RLIMIT_NOFILE
3753         lim.rlim_cur = lim.rlim_max = FD_SETSIZE;
3754         (void) setrlimit(RLIMIT_NOFILE, &lim);
3755 # endif /* RLIMIT_NOFILE */
3756 #else /* HASSETRLIMIT */
3757 # if HASULIMIT
3758         (void) ulimit(2, 0x3fffff);
3759         (void) ulimit(4, FD_SETSIZE);
3760 # endif /* HASULIMIT */
3761 #endif /* HASSETRLIMIT */
3762         errno = 0;
3763 }
3764 /*
3765 **  SETVENDOR -- process vendor code from V configuration line
3766 **
3767 **      Parameters:
3768 **              vendor -- string representation of vendor.
3769 **
3770 **      Returns:
3771 **              true -- if ok.
3772 **              false -- if vendor code could not be processed.
3773 **
3774 **      Side Effects:
3775 **              It is reasonable to set mode flags here to tweak
3776 **              processing in other parts of the code if necessary.
3777 **              For example, if you are a vendor that uses $%y to
3778 **              indicate YP lookups, you could enable that here.
3779 */
3780
3781 bool
3782 setvendor(vendor)
3783         char *vendor;
3784 {
3785         if (sm_strcasecmp(vendor, "Berkeley") == 0)
3786         {
3787                 VendorCode = VENDOR_BERKELEY;
3788                 return true;
3789         }
3790
3791         /* add vendor extensions here */
3792
3793 #ifdef SUN_EXTENSIONS
3794         if (sm_strcasecmp(vendor, "Sun") == 0)
3795         {
3796                 VendorCode = VENDOR_SUN;
3797                 return true;
3798         }
3799 #endif /* SUN_EXTENSIONS */
3800 #ifdef DEC
3801         if (sm_strcasecmp(vendor, "Digital") == 0)
3802         {
3803                 VendorCode = VENDOR_DEC;
3804                 return true;
3805         }
3806 #endif /* DEC */
3807
3808 #if defined(VENDOR_NAME) && defined(VENDOR_CODE)
3809         if (sm_strcasecmp(vendor, VENDOR_NAME) == 0)
3810         {
3811                 VendorCode = VENDOR_CODE;
3812                 return true;
3813         }
3814 #endif /* defined(VENDOR_NAME) && defined(VENDOR_CODE) */
3815
3816         return false;
3817 }
3818 /*
3819 **  GETVENDOR -- return vendor name based on vendor code
3820 **
3821 **      Parameters:
3822 **              vendorcode -- numeric representation of vendor.
3823 **
3824 **      Returns:
3825 **              string containing vendor name.
3826 */
3827
3828 char *
3829 getvendor(vendorcode)
3830         int vendorcode;
3831 {
3832 #if defined(VENDOR_NAME) && defined(VENDOR_CODE)
3833         /*
3834         **  Can't have the same switch case twice so need to
3835         **  handle VENDOR_CODE outside of switch.  It might
3836         **  match one of the existing VENDOR_* codes.
3837         */
3838
3839         if (vendorcode == VENDOR_CODE)
3840                 return VENDOR_NAME;
3841 #endif /* defined(VENDOR_NAME) && defined(VENDOR_CODE) */
3842
3843         switch (vendorcode)
3844         {
3845           case VENDOR_BERKELEY:
3846                 return "Berkeley";
3847
3848           case VENDOR_SUN:
3849                 return "Sun";
3850
3851           case VENDOR_HP:
3852                 return "HP";
3853
3854           case VENDOR_IBM:
3855                 return "IBM";
3856
3857           case VENDOR_SENDMAIL:
3858                 return "Sendmail";
3859
3860           default:
3861                 return "Unknown";
3862         }
3863 }
3864 /*
3865 **  VENDOR_PRE_DEFAULTS, VENDOR_POST_DEFAULTS -- set vendor-specific defaults
3866 **
3867 **      Vendor_pre_defaults is called before reading the configuration
3868 **      file; vendor_post_defaults is called immediately after.
3869 **
3870 **      Parameters:
3871 **              e -- the global environment to initialize.
3872 **
3873 **      Returns:
3874 **              none.
3875 */
3876
3877 #if SHARE_V1
3878 int     DefShareUid;    /* default share uid to run as -- unused??? */
3879 #endif /* SHARE_V1 */
3880
3881 void
3882 vendor_pre_defaults(e)
3883         ENVELOPE *e;
3884 {
3885 #if SHARE_V1
3886         /* OTHERUID is defined in shares.h, do not be alarmed */
3887         DefShareUid = OTHERUID;
3888 #endif /* SHARE_V1 */
3889 #if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES)
3890         sun_pre_defaults(e);
3891 #endif /* defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) */
3892 #ifdef apollo
3893         /*
3894         **  stupid domain/os can't even open
3895         **  /etc/mail/sendmail.cf without this
3896         */
3897
3898         sm_setuserenv("ISP", NULL);
3899         sm_setuserenv("SYSTYPE", NULL);
3900 #endif /* apollo */
3901 }
3902
3903
3904 void
3905 vendor_post_defaults(e)
3906         ENVELOPE *e;
3907 {
3908 #ifdef __QNX__
3909         /* Makes sure the SOCK environment variable remains */
3910         sm_setuserenv("SOCK", NULL);
3911 #endif /* __QNX__ */
3912 #if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES)
3913         sun_post_defaults(e);
3914 #endif /* defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) */
3915 }
3916 /*
3917 **  VENDOR_DAEMON_SETUP -- special vendor setup needed for daemon mode
3918 */
3919
3920 void
3921 vendor_daemon_setup(e)
3922         ENVELOPE *e;
3923 {
3924 #if HASSETLOGIN
3925         (void) setlogin(RunAsUserName);
3926 #endif /* HASSETLOGIN */
3927 #if SECUREWARE
3928         if (getluid() != -1)
3929         {
3930                 usrerr("Daemon cannot have LUID");
3931                 finis(false, true, EX_USAGE);
3932         }
3933 #endif /* SECUREWARE */
3934 }
3935 /*
3936 **  VENDOR_SET_UID -- do setup for setting a user id
3937 **
3938 **      This is called when we are still root.
3939 **
3940 **      Parameters:
3941 **              uid -- the uid we are about to become.
3942 **
3943 **      Returns:
3944 **              none.
3945 */
3946
3947 void
3948 vendor_set_uid(uid)
3949         UID_T uid;
3950 {
3951         /*
3952         **  We need to setup the share groups (lnodes)
3953         **  and add auditing information (luid's)
3954         **  before we loose our ``root''ness.
3955         */
3956 #if SHARE_V1
3957         if (setupshares(uid, syserr) != 0)
3958                 syserr("Unable to set up shares");
3959 #endif /* SHARE_V1 */
3960 #if SECUREWARE
3961         (void) setup_secure(uid);
3962 #endif /* SECUREWARE */
3963 }
3964 /*
3965 **  VALIDATE_CONNECTION -- check connection for rationality
3966 **
3967 **      If the connection is rejected, this routine should log an
3968 **      appropriate message -- but should never issue any SMTP protocol.
3969 **
3970 **      Parameters:
3971 **              sap -- a pointer to a SOCKADDR naming the peer.
3972 **              hostname -- the name corresponding to sap.
3973 **              e -- the current envelope.
3974 **
3975 **      Returns:
3976 **              error message from rejection.
3977 **              NULL if not rejected.
3978 */
3979
3980 #if TCPWRAPPERS
3981 # include <tcpd.h>
3982
3983 /* tcpwrappers does no logging, but you still have to declare these -- ugh */
3984 int     allow_severity  = LOG_INFO;
3985 int     deny_severity   = LOG_NOTICE;
3986 #endif /* TCPWRAPPERS */
3987
3988 char *
3989 validate_connection(sap, hostname, e)
3990         SOCKADDR *sap;
3991         char *hostname;
3992         ENVELOPE *e;
3993 {
3994 #if TCPWRAPPERS
3995         char *host;
3996         char *addr;
3997         extern int hosts_ctl();
3998 #endif /* TCPWRAPPERS */
3999
4000         if (tTd(48, 3))
4001                 sm_dprintf("validate_connection(%s, %s)\n",
4002                         hostname, anynet_ntoa(sap));
4003
4004         connection_rate_check(sap, e);
4005         if (rscheck("check_relay", hostname, anynet_ntoa(sap),
4006                     e, RSF_RMCOMM|RSF_COUNT, 3, NULL, NOQID, NULL) != EX_OK)
4007         {
4008                 static char reject[BUFSIZ*2];
4009                 extern char MsgBuf[];
4010
4011                 if (tTd(48, 4))
4012                         sm_dprintf("  ... validate_connection: BAD (rscheck)\n");
4013
4014                 if (strlen(MsgBuf) >= 3)
4015                         (void) sm_strlcpy(reject, MsgBuf, sizeof(reject));
4016                 else
4017                         (void) sm_strlcpy(reject, "Access denied", sizeof(reject));
4018
4019                 return reject;
4020         }
4021
4022 #if TCPWRAPPERS
4023         if (hostname[0] == '[' && hostname[strlen(hostname) - 1] == ']')
4024                 host = "unknown";
4025         else
4026                 host = hostname;
4027         addr = anynet_ntoa(sap);
4028
4029 # if NETINET6
4030         /* TCP/Wrappers don't want the IPv6: protocol label */
4031         if (addr != NULL && sm_strncasecmp(addr, "IPv6:", 5) == 0)
4032                 addr += 5;
4033 # endif /* NETINET6 */
4034
4035         if (!hosts_ctl("sendmail", host, addr, STRING_UNKNOWN))
4036         {
4037                 if (tTd(48, 4))
4038                         sm_dprintf("  ... validate_connection: BAD (tcpwrappers)\n");
4039                 if (LogLevel > 3)
4040                         sm_syslog(LOG_NOTICE, e->e_id,
4041                                   "tcpwrappers (%s, %s) rejection",
4042                                   host, addr);
4043                 return "Access denied";
4044         }
4045 #endif /* TCPWRAPPERS */
4046         if (tTd(48, 4))
4047                 sm_dprintf("  ... validate_connection: OK\n");
4048         return NULL;
4049 }
4050
4051 /*
4052 **  STRTOL -- convert string to long integer
4053 **
4054 **      For systems that don't have it in the C library.
4055 **
4056 **      This is taken verbatim from the 4.4-Lite C library.
4057 */
4058
4059 #if NEEDSTRTOL
4060
4061 # if defined(LIBC_SCCS) && !defined(lint)
4062 static char sccsid[] = "@(#)strtol.c    8.1 (Berkeley) 6/4/93";
4063 # endif /* defined(LIBC_SCCS) && !defined(lint) */
4064
4065 /*
4066 **  Convert a string to a long integer.
4067 **
4068 **  Ignores `locale' stuff.  Assumes that the upper and lower case
4069 **  alphabets and digits are each contiguous.
4070 */
4071
4072 long
4073 strtol(nptr, endptr, base)
4074         const char *nptr;
4075         char **endptr;
4076         register int base;
4077 {
4078         register const char *s = nptr;
4079         register unsigned long acc;
4080         register int c;
4081         register unsigned long cutoff;
4082         register int neg = 0, any, cutlim;
4083
4084         /*
4085         **  Skip white space and pick up leading +/- sign if any.
4086         **  If base is 0, allow 0x for hex and 0 for octal, else
4087         **  assume decimal; if base is already 16, allow 0x.
4088         */
4089         do {
4090                 c = *s++;
4091         } while (isascii(c) && isspace(c));
4092         if (c == '-') {
4093                 neg = 1;
4094                 c = *s++;
4095         } else if (c == '+')
4096                 c = *s++;
4097         if ((base == 0 || base == 16) &&
4098             c == '0' && (*s == 'x' || *s == 'X')) {
4099                 c = s[1];
4100                 s += 2;
4101                 base = 16;
4102         }
4103         if (base == 0)
4104                 base = c == '0' ? 8 : 10;
4105
4106         /*
4107         **  Compute the cutoff value between legal numbers and illegal
4108         **  numbers.  That is the largest legal value, divided by the
4109         **  base.  An input number that is greater than this value, if
4110         **  followed by a legal input character, is too big.  One that
4111         **  is equal to this value may be valid or not; the limit
4112         **  between valid and invalid numbers is then based on the last
4113         **  digit.  For instance, if the range for longs is
4114         **  [-2147483648..2147483647] and the input base is 10,
4115         **  cutoff will be set to 214748364 and cutlim to either
4116         **  7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
4117         **  a value > 214748364, or equal but the next digit is > 7 (or 8),
4118         **  the number is too big, and we will return a range error.
4119         **
4120         **  Set any if any `digits' consumed; make it negative to indicate
4121         **  overflow.
4122         */
4123         cutoff = neg ? -(unsigned long) LONG_MIN : LONG_MAX;
4124         cutlim = cutoff % (unsigned long) base;
4125         cutoff /= (unsigned long) base;
4126         for (acc = 0, any = 0;; c = *s++) {
4127                 if (isascii(c) && isdigit(c))
4128                         c -= '0';
4129                 else if (isascii(c) && isalpha(c))
4130                         c -= isupper(c) ? 'A' - 10 : 'a' - 10;
4131                 else
4132                         break;
4133                 if (c >= base)
4134                         break;
4135                 if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
4136                         any = -1;
4137                 else {
4138                         any = 1;
4139                         acc *= base;
4140                         acc += c;
4141                 }
4142         }
4143         if (any < 0) {
4144                 acc = neg ? LONG_MIN : LONG_MAX;
4145                 errno = ERANGE;
4146         } else if (neg)
4147                 acc = -acc;
4148         if (endptr != 0)
4149                 *endptr = (char *)(any ? s - 1 : nptr);
4150         return acc;
4151 }
4152
4153 #endif /* NEEDSTRTOL */
4154 /*
4155 **  STRSTR -- find first substring in string
4156 **
4157 **      Parameters:
4158 **              big -- the big (full) string.
4159 **              little -- the little (sub) string.
4160 **
4161 **      Returns:
4162 **              A pointer to the first instance of little in big.
4163 **              big if little is the null string.
4164 **              NULL if little is not contained in big.
4165 */
4166
4167 #if NEEDSTRSTR
4168
4169 char *
4170 strstr(big, little)
4171         char *big;
4172         char *little;
4173 {
4174         register char *p = big;
4175         int l;
4176
4177         if (*little == '\0')
4178                 return big;
4179         l = strlen(little);
4180
4181         while ((p = strchr(p, *little)) != NULL)
4182         {
4183                 if (strncmp(p, little, l) == 0)
4184                         return p;
4185                 p++;
4186         }
4187         return NULL;
4188 }
4189
4190 #endif /* NEEDSTRSTR */
4191 /*
4192 **  SM_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX
4193 **
4194 **      Some operating systems have weird problems with the gethostbyXXX
4195 **      routines.  For example, Solaris versions at least through 2.3
4196 **      don't properly deliver a canonical h_name field.  This tries to
4197 **      work around these problems.
4198 **
4199 **      Support IPv6 as well as IPv4.
4200 */
4201
4202 #if NETINET6 && NEEDSGETIPNODE
4203
4204 # ifndef AI_DEFAULT
4205 #  define AI_DEFAULT    0       /* dummy */
4206 # endif /* ! AI_DEFAULT */
4207 # ifndef AI_ADDRCONFIG
4208 #  define AI_ADDRCONFIG 0       /* dummy */
4209 # endif /* ! AI_ADDRCONFIG */
4210 # ifndef AI_V4MAPPED
4211 #  define AI_V4MAPPED   0       /* dummy */
4212 # endif /* ! AI_V4MAPPED */
4213 # ifndef AI_ALL
4214 #  define AI_ALL        0       /* dummy */
4215 # endif /* ! AI_ALL */
4216
4217 static struct hostent *
4218 sm_getipnodebyname(name, family, flags, err)
4219         const char *name;
4220         int family;
4221         int flags;
4222         int *err;
4223 {
4224         bool resv6 = true;
4225         struct hostent *h;
4226
4227         if (family == AF_INET6)
4228         {
4229                 /* From RFC2133, section 6.1 */
4230                 resv6 = bitset(RES_USE_INET6, _res.options);
4231                 _res.options |= RES_USE_INET6;
4232         }
4233         SM_SET_H_ERRNO(0);
4234         h = gethostbyname(name);
4235         if (!resv6)
4236                 _res.options &= ~RES_USE_INET6;
4237         *err = h_errno;
4238         return h;
4239 }
4240
4241 static struct hostent *
4242 sm_getipnodebyaddr(addr, len, family, err)
4243         const void *addr;
4244         size_t len;
4245         int family;
4246         int *err;
4247 {
4248         struct hostent *h;
4249
4250         SM_SET_H_ERRNO(0);
4251         h = gethostbyaddr(addr, len, family);
4252         *err = h_errno;
4253         return h;
4254 }
4255
4256 void
4257 freehostent(h)
4258         struct hostent *h;
4259 {
4260         /*
4261         **  Stub routine -- if they don't have getipnodeby*(),
4262         **  they probably don't have the free routine either.
4263         */
4264
4265         return;
4266 }
4267 #endif /* NETINET6 && NEEDSGETIPNODE */
4268
4269 struct hostent *
4270 sm_gethostbyname(name, family)
4271         char *name;
4272         int family;
4273 {
4274         int save_errno;
4275         struct hostent *h = NULL;
4276 #if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4))
4277 # if SOLARIS == 20300 || SOLARIS == 203
4278         static struct hostent hp;
4279         static char buf[1000];
4280         extern struct hostent *_switch_gethostbyname_r();
4281
4282         if (tTd(61, 10))
4283                 sm_dprintf("_switch_gethostbyname_r(%s)... ", name);
4284         h = _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno);
4285         save_errno = errno;
4286 # else /* SOLARIS == 20300 || SOLARIS == 203 */
4287         extern struct hostent *__switch_gethostbyname();
4288
4289         if (tTd(61, 10))
4290                 sm_dprintf("__switch_gethostbyname(%s)... ", name);
4291         h = __switch_gethostbyname(name);
4292         save_errno = errno;
4293 # endif /* SOLARIS == 20300 || SOLARIS == 203 */
4294 #else /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */
4295         int nmaps;
4296 # if NETINET6
4297         int flags = AI_DEFAULT|AI_ALL;
4298         int err;
4299 # endif /* NETINET6 */
4300         char *maptype[MAXMAPSTACK];
4301         short mapreturn[MAXMAPACTIONS];
4302         char hbuf[MAXNAME];
4303
4304         if (tTd(61, 10))
4305                 sm_dprintf("sm_gethostbyname(%s, %d)... ", name, family);
4306
4307 # if NETINET6
4308 #  if ADDRCONFIG_IS_BROKEN
4309         flags &= ~AI_ADDRCONFIG;
4310 #  endif /* ADDRCONFIG_IS_BROKEN */
4311         h = sm_getipnodebyname(name, family, flags, &err);
4312         SM_SET_H_ERRNO(err);
4313 # else /* NETINET6 */
4314         h = gethostbyname(name);
4315 # endif /* NETINET6 */
4316
4317         save_errno = errno;
4318         if (h == NULL)
4319         {
4320                 if (tTd(61, 10))
4321                         sm_dprintf("failure\n");
4322
4323                 nmaps = switch_map_find("hosts", maptype, mapreturn);
4324                 while (--nmaps >= 0)
4325                 {
4326                         if (strcmp(maptype[nmaps], "nis") == 0 ||
4327                             strcmp(maptype[nmaps], "files") == 0)
4328                                 break;
4329                 }
4330
4331                 if (nmaps >= 0)
4332                 {
4333                         /* try short name */
4334                         if (strlen(name) > sizeof(hbuf) - 1)
4335                         {
4336                                 errno = save_errno;
4337                                 return NULL;
4338                         }
4339                         (void) sm_strlcpy(hbuf, name, sizeof(hbuf));
4340                         (void) shorten_hostname(hbuf);
4341
4342                         /* if it hasn't been shortened, there's no point */
4343                         if (strcmp(hbuf, name) != 0)
4344                         {
4345                                 if (tTd(61, 10))
4346                                         sm_dprintf("sm_gethostbyname(%s, %d)... ",
4347                                                hbuf, family);
4348
4349 # if NETINET6
4350                                 h = sm_getipnodebyname(hbuf, family, flags, &err);
4351                                 SM_SET_H_ERRNO(err);
4352                                 save_errno = errno;
4353 # else /* NETINET6 */
4354                                 h = gethostbyname(hbuf);
4355                                 save_errno = errno;
4356 # endif /* NETINET6 */
4357                         }
4358                 }
4359         }
4360 #endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */
4361         if (tTd(61, 10))
4362         {
4363                 if (h == NULL)
4364                         sm_dprintf("failure\n");
4365                 else
4366                 {
4367                         sm_dprintf("%s\n", h->h_name);
4368                         if (tTd(61, 11))
4369                         {
4370 #if NETINET6
4371                                 struct in6_addr ia6;
4372                                 char buf6[INET6_ADDRSTRLEN];
4373 #else /* NETINET6 */
4374                                 struct in_addr ia;
4375 #endif /* NETINET6 */
4376                                 size_t i;
4377
4378                                 if (h->h_aliases != NULL)
4379                                         for (i = 0; h->h_aliases[i] != NULL;
4380                                              i++)
4381                                                 sm_dprintf("\talias: %s\n",
4382                                                         h->h_aliases[i]);
4383                                 for (i = 0; h->h_addr_list[i] != NULL; i++)
4384                                 {
4385                                         char *addr;
4386
4387 #if NETINET6
4388                                         memmove(&ia6, h->h_addr_list[i],
4389                                                 IN6ADDRSZ);
4390                                         addr = anynet_ntop(&ia6,
4391                                                            buf6, sizeof(buf6));
4392 #else /* NETINET6 */
4393                                         memmove(&ia, h->h_addr_list[i],
4394                                                 INADDRSZ);
4395                                         addr = (char *) inet_ntoa(ia);
4396 #endif /* NETINET6 */
4397                                         if (addr != NULL)
4398                                                 sm_dprintf("\taddr: %s\n", addr);
4399                                 }
4400                         }
4401                 }
4402         }
4403         errno = save_errno;
4404         return h;
4405 }
4406
4407 struct hostent *
4408 sm_gethostbyaddr(addr, len, type)
4409         char *addr;
4410         int len;
4411         int type;
4412 {
4413         struct hostent *hp;
4414
4415 #if NETINET6
4416         if (type == AF_INET6 &&
4417             IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *) addr))
4418         {
4419                 /* Avoid reverse lookup for IPv6 unspecified address */
4420                 SM_SET_H_ERRNO(HOST_NOT_FOUND);
4421                 return NULL;
4422         }
4423 #endif /* NETINET6 */
4424
4425 #if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204)
4426 # if SOLARIS == 20300 || SOLARIS == 203
4427         {
4428                 static struct hostent he;
4429                 static char buf[1000];
4430                 extern struct hostent *_switch_gethostbyaddr_r();
4431
4432                 hp = _switch_gethostbyaddr_r(addr, len, type, &he,
4433                                              buf, sizeof(buf), &h_errno);
4434         }
4435 # else /* SOLARIS == 20300 || SOLARIS == 203 */
4436         {
4437                 extern struct hostent *__switch_gethostbyaddr();
4438
4439                 hp = __switch_gethostbyaddr(addr, len, type);
4440         }
4441 # endif /* SOLARIS == 20300 || SOLARIS == 203 */
4442 #else /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) */
4443 # if NETINET6
4444         {
4445                 int err;
4446
4447                 hp = sm_getipnodebyaddr(addr, len, type, &err);
4448                 SM_SET_H_ERRNO(err);
4449         }
4450 # else /* NETINET6 */
4451         hp = gethostbyaddr(addr, len, type);
4452 # endif /* NETINET6 */
4453 #endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) */
4454         return hp;
4455 }
4456 /*
4457 **  SM_GETPW{NAM,UID} -- wrapper for getpwnam and getpwuid
4458 */
4459
4460 struct passwd *
4461 sm_getpwnam(user)
4462         char *user;
4463 {
4464 #ifdef _AIX4
4465         extern struct passwd *_getpwnam_shadow(const char *, const int);
4466
4467         return _getpwnam_shadow(user, 0);
4468 #else /* _AIX4 */
4469         return getpwnam(user);
4470 #endif /* _AIX4 */
4471 }
4472
4473 struct passwd *
4474 sm_getpwuid(uid)
4475         UID_T uid;
4476 {
4477 #if defined(_AIX4) && 0
4478         extern struct passwd *_getpwuid_shadow(const int, const int);
4479
4480         return _getpwuid_shadow(uid,0);
4481 #else /* defined(_AIX4) && 0 */
4482         return getpwuid(uid);
4483 #endif /* defined(_AIX4) && 0 */
4484 }
4485 /*
4486 **  SECUREWARE_SETUP_SECURE -- Convex SecureWare setup
4487 **
4488 **      Set up the trusted computing environment for C2 level security
4489 **      under SecureWare.
4490 **
4491 **      Parameters:
4492 **              uid -- uid of the user to initialize in the TCB
4493 **
4494 **      Returns:
4495 **              none
4496 **
4497 **      Side Effects:
4498 **              Initialized the user in the trusted computing base
4499 */
4500
4501 #if SECUREWARE
4502
4503 # include <sys/security.h>
4504 # include <prot.h>
4505
4506 void
4507 secureware_setup_secure(uid)
4508         UID_T uid;
4509 {
4510         int rc;
4511
4512         if (getluid() != -1)
4513                 return;
4514
4515         if ((rc = set_secure_info(uid)) != SSI_GOOD_RETURN)
4516         {
4517                 switch (rc)
4518                 {
4519                   case SSI_NO_PRPW_ENTRY:
4520                         syserr("No protected passwd entry, uid = %d",
4521                                (int) uid);
4522                         break;
4523
4524                   case SSI_LOCKED:
4525                         syserr("Account has been disabled, uid = %d",
4526                                (int) uid);
4527                         break;
4528
4529                   case SSI_RETIRED:
4530                         syserr("Account has been retired, uid = %d",
4531                                (int) uid);
4532                         break;
4533
4534                   case SSI_BAD_SET_LUID:
4535                         syserr("Could not set LUID, uid = %d", (int) uid);
4536                         break;
4537
4538                   case SSI_BAD_SET_PRIVS:
4539                         syserr("Could not set kernel privs, uid = %d",
4540                                (int) uid);
4541
4542                   default:
4543                         syserr("Unknown return code (%d) from set_secure_info(%d)",
4544                                 rc, (int) uid);
4545                         break;
4546                 }
4547                 finis(false, true, EX_NOPERM);
4548         }
4549 }
4550 #endif /* SECUREWARE */
4551 /*
4552 **  ADD_HOSTNAMES -- Add a hostname to class 'w' based on IP address
4553 **
4554 **      Add hostnames to class 'w' based on the IP address read from
4555 **      the network interface.
4556 **
4557 **      Parameters:
4558 **              sa -- a pointer to a SOCKADDR containing the address
4559 **
4560 **      Returns:
4561 **              0 if successful, -1 if host lookup fails.
4562 */
4563
4564 static int
4565 add_hostnames(sa)
4566         SOCKADDR *sa;
4567 {
4568         struct hostent *hp;
4569         char **ha;
4570         char hnb[MAXHOSTNAMELEN];
4571
4572         /* lookup name with IP address */
4573         switch (sa->sa.sa_family)
4574         {
4575 #if NETINET
4576           case AF_INET:
4577                 hp = sm_gethostbyaddr((char *) &sa->sin.sin_addr,
4578                                       sizeof(sa->sin.sin_addr),
4579                                       sa->sa.sa_family);
4580                 break;
4581 #endif /* NETINET */
4582
4583 #if NETINET6
4584           case AF_INET6:
4585                 hp = sm_gethostbyaddr((char *) &sa->sin6.sin6_addr,
4586                                       sizeof(sa->sin6.sin6_addr),
4587                                       sa->sa.sa_family);
4588                 break;
4589 #endif /* NETINET6 */
4590
4591           default:
4592                 /* Give warning about unsupported family */
4593                 if (LogLevel > 3)
4594                         sm_syslog(LOG_WARNING, NOQID,
4595                                   "Unsupported address family %d: %.100s",
4596                                   sa->sa.sa_family, anynet_ntoa(sa));
4597                 return -1;
4598         }
4599
4600         if (hp == NULL)
4601         {
4602                 int save_errno = errno;
4603
4604                 if (LogLevel > 3 &&
4605 #if NETINET6
4606                     !(sa->sa.sa_family == AF_INET6 &&
4607                       IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr)) &&
4608 #endif /* NETINET6 */
4609                     true)
4610                         sm_syslog(LOG_WARNING, NOQID,
4611                                   "gethostbyaddr(%.100s) failed: %d",
4612                                   anynet_ntoa(sa),
4613 #if NAMED_BIND
4614                                   h_errno
4615 #else /* NAMED_BIND */
4616                                   -1
4617 #endif /* NAMED_BIND */
4618                                  );
4619                 errno = save_errno;
4620                 return -1;
4621         }
4622
4623         /* save its cname */
4624         if (!wordinclass((char *) hp->h_name, 'w'))
4625         {
4626                 setclass('w', (char *) hp->h_name);
4627                 if (tTd(0, 4))
4628                         sm_dprintf("\ta.k.a.: %s\n", hp->h_name);
4629
4630                 if (sm_snprintf(hnb, sizeof(hnb), "[%s]", hp->h_name) <
4631                                                                 sizeof(hnb)
4632                     && !wordinclass((char *) hnb, 'w'))
4633                         setclass('w', hnb);
4634         }
4635         else
4636         {
4637                 if (tTd(0, 43))
4638                         sm_dprintf("\ta.k.a.: %s (already in $=w)\n", hp->h_name);
4639         }
4640
4641         /* save all it aliases name */
4642         for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++)
4643         {
4644                 if (!wordinclass(*ha, 'w'))
4645                 {
4646                         setclass('w', *ha);
4647                         if (tTd(0, 4))
4648                                 sm_dprintf("\ta.k.a.: %s\n", *ha);
4649                         if (sm_snprintf(hnb, sizeof(hnb),
4650                                      "[%s]", *ha) < sizeof(hnb) &&
4651                             !wordinclass((char *) hnb, 'w'))
4652                                 setclass('w', hnb);
4653                 }
4654                 else
4655                 {
4656                         if (tTd(0, 43))
4657                                 sm_dprintf("\ta.k.a.: %s (already in $=w)\n",
4658                                         *ha);
4659                 }
4660         }
4661 #if NETINET6
4662         freehostent(hp);
4663 #endif /* NETINET6 */
4664         return 0;
4665 }
4666 /*
4667 **  LOAD_IF_NAMES -- load interface-specific names into $=w
4668 **
4669 **      Parameters:
4670 **              none.
4671 **
4672 **      Returns:
4673 **              none.
4674 **
4675 **      Side Effects:
4676 **              Loads $=w with the names of all the interfaces.
4677 */
4678
4679 #if !NETINET
4680 # define SIOCGIFCONF_IS_BROKEN  1 /* XXX */
4681 #endif /* !NETINET */
4682
4683 #if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
4684 struct rtentry;
4685 struct mbuf;
4686 # ifndef SUNOS403
4687 #  include <sm/time.h>
4688 # endif /* ! SUNOS403 */
4689 # if (_AIX4 >= 40300) && !defined(_NET_IF_H)
4690 #  undef __P
4691 # endif /* (_AIX4 >= 40300) && !defined(_NET_IF_H) */
4692 # include <net/if.h>
4693 #endif /* defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN */
4694
4695 void
4696 load_if_names()
4697 {
4698 # if NETINET6 && defined(SIOCGLIFCONF)
4699 #  ifdef __hpux
4700
4701     /*
4702     **  Unfortunately, HP has changed all of the structures,
4703     **  making life difficult for implementors.
4704     */
4705
4706 #   define lifconf      if_laddrconf
4707 #   define lifc_len     iflc_len
4708 #   define lifc_buf     iflc_buf
4709 #   define lifreq       if_laddrreq
4710 #   define lifr_addr    iflr_addr
4711 #   define lifr_name    iflr_name
4712 #   define lifr_flags   iflr_flags
4713 #   define ss_family    sa_family
4714 #   undef SIOCGLIFNUM
4715 #  endif /* __hpux */
4716
4717         int s;
4718         int i;
4719         size_t len;
4720         int numifs;
4721         char *buf;
4722         struct lifconf lifc;
4723 #  ifdef SIOCGLIFNUM
4724         struct lifnum lifn;
4725 #  endif /* SIOCGLIFNUM */
4726
4727         s = socket(InetMode, SOCK_DGRAM, 0);
4728         if (s == -1)
4729                 return;
4730
4731         /* get the list of known IP address from the kernel */
4732 #  ifdef __hpux
4733         i = ioctl(s, SIOCGIFNUM, (char *) &numifs);
4734 #  endif /* __hpux */
4735 #  ifdef SIOCGLIFNUM
4736         lifn.lifn_family = AF_UNSPEC;
4737         lifn.lifn_flags = 0;
4738         i = ioctl(s, SIOCGLIFNUM, (char *)&lifn);
4739         numifs = lifn.lifn_count;
4740 #  endif /* SIOCGLIFNUM */
4741
4742 #  if defined(__hpux) || defined(SIOCGLIFNUM)
4743         if (i < 0)
4744         {
4745                 /* can't get number of interfaces -- fall back */
4746                 if (tTd(0, 4))
4747                         sm_dprintf("SIOCGLIFNUM failed: %s\n",
4748                                    sm_errstring(errno));
4749                 numifs = -1;
4750         }
4751         else if (tTd(0, 42))
4752                 sm_dprintf("system has %d interfaces\n", numifs);
4753         if (numifs < 0)
4754 #  endif /* defined(__hpux) || defined(SIOCGLIFNUM) */
4755                 numifs = MAXINTERFACES;
4756
4757         if (numifs <= 0)
4758         {
4759                 (void) close(s);
4760                 return;
4761         }
4762
4763         len = lifc.lifc_len = numifs * sizeof(struct lifreq);
4764         buf = lifc.lifc_buf = xalloc(lifc.lifc_len);
4765 #  ifndef __hpux
4766         lifc.lifc_family = AF_UNSPEC;
4767         lifc.lifc_flags = 0;
4768 #  endif /* ! __hpux */
4769         if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0)
4770         {
4771                 if (tTd(0, 4))
4772                         sm_dprintf("SIOCGLIFCONF failed: %s\n",
4773                                    sm_errstring(errno));
4774                 (void) close(s);
4775                 sm_free(buf);
4776                 return;
4777         }
4778
4779         /* scan the list of IP address */
4780         if (tTd(0, 40))
4781                 sm_dprintf("scanning for interface specific names, lifc_len=%ld\n",
4782                            (long) len);
4783
4784         for (i = 0; i < len && i >= 0; )
4785         {
4786                 int flags;
4787                 struct lifreq *ifr = (struct lifreq *)&buf[i];
4788                 SOCKADDR *sa = (SOCKADDR *) &ifr->lifr_addr;
4789                 int af = ifr->lifr_addr.ss_family;
4790                 char *addr;
4791                 char *name;
4792                 struct in6_addr ia6;
4793                 struct in_addr ia;
4794 #  ifdef SIOCGLIFFLAGS
4795                 struct lifreq ifrf;
4796 #  endif /* SIOCGLIFFLAGS */
4797                 char ip_addr[256];
4798                 char buf6[INET6_ADDRSTRLEN];
4799
4800                 /*
4801                 **  We must close and recreate the socket each time
4802                 **  since we don't know what type of socket it is now
4803                 **  (each status function may change it).
4804                 */
4805
4806                 (void) close(s);
4807
4808                 s = socket(af, SOCK_DGRAM, 0);
4809                 if (s == -1)
4810                 {
4811                         sm_free(buf); /* XXX */
4812                         return;
4813                 }
4814
4815                 /*
4816                 **  If we don't have a complete ifr structure,
4817                 **  don't try to use it.
4818                 */
4819
4820                 if ((len - i) < sizeof(*ifr))
4821                         break;
4822
4823 #  ifdef BSD4_4_SOCKADDR
4824                 if (sa->sa.sa_len > sizeof(ifr->lifr_addr))
4825                         i += sizeof(ifr->lifr_name) + sa->sa.sa_len;
4826                 else
4827 #  endif /* BSD4_4_SOCKADDR */
4828 #  ifdef DEC
4829                         /* fix for IPv6  size differences */
4830                         i += sizeof(ifr->ifr_name) +
4831                              max(sizeof(ifr->ifr_addr), ifr->ifr_addr.sa_len);
4832 #   else /* DEC */
4833                         i += sizeof(*ifr);
4834 #   endif /* DEC */
4835
4836                 if (tTd(0, 20))
4837                         sm_dprintf("%s\n", anynet_ntoa(sa));
4838
4839                 if (af != AF_INET && af != AF_INET6)
4840                         continue;
4841
4842 #  ifdef SIOCGLIFFLAGS
4843                 memset(&ifrf, '\0', sizeof(struct lifreq));
4844                 (void) sm_strlcpy(ifrf.lifr_name, ifr->lifr_name,
4845                                   sizeof(ifrf.lifr_name));
4846                 if (ioctl(s, SIOCGLIFFLAGS, (char *) &ifrf) < 0)
4847                 {
4848                         if (tTd(0, 4))
4849                                 sm_dprintf("SIOCGLIFFLAGS failed: %s\n",
4850                                            sm_errstring(errno));
4851                         continue;
4852                 }
4853
4854                 name = ifr->lifr_name;
4855                 flags = ifrf.lifr_flags;
4856
4857                 if (tTd(0, 41))
4858                         sm_dprintf("\tflags: %lx\n", (unsigned long) flags);
4859
4860                 if (!bitset(IFF_UP, flags))
4861                         continue;
4862 #  endif /* SIOCGLIFFLAGS */
4863
4864                 ip_addr[0] = '\0';
4865
4866                 /* extract IP address from the list*/
4867                 switch (af)
4868                 {
4869                   case AF_INET6:
4870                         SETV6LOOPBACKADDRFOUND(*sa);
4871 #  ifdef __KAME__
4872                         /* convert into proper scoped address */
4873                         if ((IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr) ||
4874                              IN6_IS_ADDR_SITELOCAL(&sa->sin6.sin6_addr)) &&
4875                             sa->sin6.sin6_scope_id == 0)
4876                         {
4877                                 struct in6_addr *ia6p;
4878
4879                                 ia6p = &sa->sin6.sin6_addr;
4880                                 sa->sin6.sin6_scope_id = ntohs(ia6p->s6_addr[3] |
4881                                                                ((unsigned int)ia6p->s6_addr[2] << 8));
4882                                 ia6p->s6_addr[2] = ia6p->s6_addr[3] = 0;
4883                         }
4884 #  endif /* __KAME__ */
4885                         ia6 = sa->sin6.sin6_addr;
4886                         if (IN6_IS_ADDR_UNSPECIFIED(&ia6))
4887                         {
4888                                 addr = anynet_ntop(&ia6, buf6, sizeof(buf6));
4889                                 message("WARNING: interface %s is UP with %s address",
4890                                         name, addr == NULL ? "(NULL)" : addr);
4891                                 continue;
4892                         }
4893
4894                         /* save IP address in text from */
4895                         addr = anynet_ntop(&ia6, buf6, sizeof(buf6));
4896                         if (addr != NULL)
4897                                 (void) sm_snprintf(ip_addr, sizeof(ip_addr),
4898                                                    "[%.*s]",
4899                                                    (int) sizeof(ip_addr) - 3,
4900                                                    addr);
4901                         break;
4902
4903                   case AF_INET:
4904                         ia = sa->sin.sin_addr;
4905                         if (ia.s_addr == INADDR_ANY ||
4906                             ia.s_addr == INADDR_NONE)
4907                         {
4908                                 message("WARNING: interface %s is UP with %s address",
4909                                         name, inet_ntoa(ia));
4910                                 continue;
4911                         }
4912
4913                         /* save IP address in text from */
4914                         (void) sm_snprintf(ip_addr, sizeof(ip_addr), "[%.*s]",
4915                                         (int) sizeof(ip_addr) - 3, inet_ntoa(ia));
4916                         break;
4917                 }
4918
4919                 if (*ip_addr == '\0')
4920                         continue;
4921
4922                 if (!wordinclass(ip_addr, 'w'))
4923                 {
4924                         setclass('w', ip_addr);
4925                         if (tTd(0, 4))
4926                                 sm_dprintf("\ta.k.a.: %s\n", ip_addr);
4927                 }
4928
4929 #  ifdef SIOCGLIFFLAGS
4930                 /* skip "loopback" interface "lo" */
4931                 if (DontProbeInterfaces == DPI_SKIPLOOPBACK &&
4932                     bitset(IFF_LOOPBACK, flags))
4933                         continue;
4934 #  endif /* SIOCGLIFFLAGS */
4935                 (void) add_hostnames(sa);
4936         }
4937         sm_free(buf); /* XXX */
4938         (void) close(s);
4939 # else /* NETINET6 && defined(SIOCGLIFCONF) */
4940 #  if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
4941         int s;
4942         int i;
4943         struct ifconf ifc;
4944         int numifs;
4945
4946         s = socket(AF_INET, SOCK_DGRAM, 0);
4947         if (s == -1)
4948                 return;
4949
4950         /* get the list of known IP address from the kernel */
4951 #   if defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN
4952         if (ioctl(s, SIOCGIFNUM, (char *) &numifs) < 0)
4953         {
4954                 /* can't get number of interfaces -- fall back */
4955                 if (tTd(0, 4))
4956                         sm_dprintf("SIOCGIFNUM failed: %s\n",
4957                                    sm_errstring(errno));
4958                 numifs = -1;
4959         }
4960         else if (tTd(0, 42))
4961                 sm_dprintf("system has %d interfaces\n", numifs);
4962         if (numifs < 0)
4963 #   endif /* defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN */
4964                 numifs = MAXINTERFACES;
4965
4966         if (numifs <= 0)
4967         {
4968                 (void) close(s);
4969                 return;
4970         }
4971         ifc.ifc_len = numifs * sizeof(struct ifreq);
4972         ifc.ifc_buf = xalloc(ifc.ifc_len);
4973         if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0)
4974         {
4975                 if (tTd(0, 4))
4976                         sm_dprintf("SIOCGIFCONF failed: %s\n",
4977                                    sm_errstring(errno));
4978                 (void) close(s);
4979                 return;
4980         }
4981
4982         /* scan the list of IP address */
4983         if (tTd(0, 40))
4984                 sm_dprintf("scanning for interface specific names, ifc_len=%d\n",
4985                         ifc.ifc_len);
4986
4987         for (i = 0; i < ifc.ifc_len && i >= 0; )
4988         {
4989                 int af;
4990                 struct ifreq *ifr = (struct ifreq *) &ifc.ifc_buf[i];
4991                 SOCKADDR *sa = (SOCKADDR *) &ifr->ifr_addr;
4992 #   if NETINET6
4993                 char *addr;
4994                 struct in6_addr ia6;
4995 #   endif /* NETINET6 */
4996                 struct in_addr ia;
4997 #   ifdef SIOCGIFFLAGS
4998                 struct ifreq ifrf;
4999 #   endif /* SIOCGIFFLAGS */
5000                 char ip_addr[256];
5001 #   if NETINET6
5002                 char buf6[INET6_ADDRSTRLEN];
5003 #   endif /* NETINET6 */
5004
5005                 /*
5006                 **  If we don't have a complete ifr structure,
5007                 **  don't try to use it.
5008                 */
5009
5010                 if ((ifc.ifc_len - i) < sizeof(*ifr))
5011                         break;
5012
5013 #   ifdef BSD4_4_SOCKADDR
5014                 if (sa->sa.sa_len > sizeof(ifr->ifr_addr))
5015                         i += sizeof(ifr->ifr_name) + sa->sa.sa_len;
5016                 else
5017 #   endif /* BSD4_4_SOCKADDR */
5018                         i += sizeof(*ifr);
5019
5020                 if (tTd(0, 20))
5021                         sm_dprintf("%s\n", anynet_ntoa(sa));
5022
5023                 af = ifr->ifr_addr.sa_family;
5024                 if (af != AF_INET
5025 #   if NETINET6
5026                     && af != AF_INET6
5027 #   endif /* NETINET6 */
5028                     )
5029                         continue;
5030
5031 #   ifdef SIOCGIFFLAGS
5032                 memset(&ifrf, '\0', sizeof(struct ifreq));
5033                 (void) sm_strlcpy(ifrf.ifr_name, ifr->ifr_name,
5034                                sizeof(ifrf.ifr_name));
5035                 (void) ioctl(s, SIOCGIFFLAGS, (char *) &ifrf);
5036                 if (tTd(0, 41))
5037                         sm_dprintf("\tflags: %lx\n",
5038                                 (unsigned long) ifrf.ifr_flags);
5039 #    define IFRFREF ifrf
5040 #   else /* SIOCGIFFLAGS */
5041 #    define IFRFREF (*ifr)
5042 #   endif /* SIOCGIFFLAGS */
5043
5044                 if (!bitset(IFF_UP, IFRFREF.ifr_flags))
5045                         continue;
5046
5047                 ip_addr[0] = '\0';
5048
5049                 /* extract IP address from the list*/
5050                 switch (af)
5051                 {
5052                   case AF_INET:
5053                         ia = sa->sin.sin_addr;
5054                         if (ia.s_addr == INADDR_ANY ||
5055                             ia.s_addr == INADDR_NONE)
5056                         {
5057                                 message("WARNING: interface %s is UP with %s address",
5058                                         ifr->ifr_name, inet_ntoa(ia));
5059                                 continue;
5060                         }
5061
5062                         /* save IP address in text from */
5063                         (void) sm_snprintf(ip_addr, sizeof(ip_addr), "[%.*s]",
5064                                         (int) sizeof(ip_addr) - 3,
5065                                         inet_ntoa(ia));
5066                         break;
5067
5068 #   if NETINET6
5069                   case AF_INET6:
5070                         SETV6LOOPBACKADDRFOUND(*sa);
5071 #    ifdef __KAME__
5072                         /* convert into proper scoped address */
5073                         if ((IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr) ||
5074                              IN6_IS_ADDR_SITELOCAL(&sa->sin6.sin6_addr)) &&
5075                             sa->sin6.sin6_scope_id == 0)
5076                         {
5077                                 struct in6_addr *ia6p;
5078
5079                                 ia6p = &sa->sin6.sin6_addr;
5080                                 sa->sin6.sin6_scope_id = ntohs(ia6p->s6_addr[3] |
5081                                                                ((unsigned int)ia6p->s6_addr[2] << 8));
5082                                 ia6p->s6_addr[2] = ia6p->s6_addr[3] = 0;
5083                         }
5084 #    endif /* __KAME__ */
5085                         ia6 = sa->sin6.sin6_addr;
5086                         if (IN6_IS_ADDR_UNSPECIFIED(&ia6))
5087                         {
5088                                 addr = anynet_ntop(&ia6, buf6, sizeof(buf6));
5089                                 message("WARNING: interface %s is UP with %s address",
5090                                         ifr->ifr_name,
5091                                         addr == NULL ? "(NULL)" : addr);
5092                                 continue;
5093                         }
5094
5095                         /* save IP address in text from */
5096                         addr = anynet_ntop(&ia6, buf6, sizeof(buf6));
5097                         if (addr != NULL)
5098                                 (void) sm_snprintf(ip_addr, sizeof(ip_addr),
5099                                                    "[%.*s]",
5100                                                    (int) sizeof(ip_addr) - 3,
5101                                                    addr);
5102                         break;
5103
5104 #   endif /* NETINET6 */
5105                 }
5106
5107                 if (ip_addr[0] == '\0')
5108                         continue;
5109
5110                 if (!wordinclass(ip_addr, 'w'))
5111                 {
5112                         setclass('w', ip_addr);
5113                         if (tTd(0, 4))
5114                                 sm_dprintf("\ta.k.a.: %s\n", ip_addr);
5115                 }
5116
5117                 /* skip "loopback" interface "lo" */
5118                 if (DontProbeInterfaces == DPI_SKIPLOOPBACK &&
5119                     bitset(IFF_LOOPBACK, IFRFREF.ifr_flags))
5120                         continue;
5121
5122                 (void) add_hostnames(sa);
5123         }
5124         sm_free(ifc.ifc_buf); /* XXX */
5125         (void) close(s);
5126 #   undef IFRFREF
5127 #  endif /* defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN */
5128 # endif /* NETINET6 && defined(SIOCGLIFCONF) */
5129 }
5130 /*
5131 **  ISLOOPBACK -- is socket address in the loopback net?
5132 **
5133 **      Parameters:
5134 **              sa -- socket address.
5135 **
5136 **      Returns:
5137 **              true -- is socket address in the loopback net?
5138 **              false -- otherwise
5139 **
5140 */
5141
5142 bool
5143 isloopback(sa)
5144         SOCKADDR sa;
5145 {
5146 #if NETINET6
5147         if (IN6_IS_ADDR_LOOPBACK(&sa.sin6.sin6_addr))
5148                 return true;
5149 #else /* NETINET6 */
5150         /* XXX how to correctly extract IN_LOOPBACKNET part? */
5151         if (((ntohl(sa.sin.sin_addr.s_addr) & IN_CLASSA_NET)
5152              >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
5153                 return true;
5154 #endif /* NETINET6 */
5155         return false;
5156 }
5157 /*
5158 **  GET_NUM_PROCS_ONLINE -- return the number of processors currently online
5159 **
5160 **      Parameters:
5161 **              none.
5162 **
5163 **      Returns:
5164 **              The number of processors online.
5165 */
5166
5167 static int
5168 get_num_procs_online()
5169 {
5170         int nproc = 0;
5171
5172 #ifdef USESYSCTL
5173 # if defined(CTL_HW) && defined(HW_NCPU)
5174         size_t sz;
5175         int mib[2];
5176
5177         mib[0] = CTL_HW;
5178         mib[1] = HW_NCPU;
5179         sz = (size_t) sizeof(nproc);
5180         (void) sysctl(mib, 2, &nproc, &sz, NULL, 0);
5181 # endif /* defined(CTL_HW) && defined(HW_NCPU) */
5182 #else /* USESYSCTL */
5183 # ifdef _SC_NPROCESSORS_ONLN
5184         nproc = (int) sysconf(_SC_NPROCESSORS_ONLN);
5185 # else /* _SC_NPROCESSORS_ONLN */
5186 #  ifdef __hpux
5187 #   include <sys/pstat.h>
5188         struct pst_dynamic psd;
5189
5190         if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) != -1)
5191                 nproc = psd.psd_proc_cnt;
5192 #  endif /* __hpux */
5193 # endif /* _SC_NPROCESSORS_ONLN */
5194 #endif /* USESYSCTL */
5195
5196         if (nproc <= 0)
5197                 nproc = 1;
5198         return nproc;
5199 }
5200 /*
5201 **  SM_CLOSEFROM -- close file descriptors
5202 **
5203 **      Parameters:
5204 **              lowest -- first fd to close
5205 **              highest -- last fd + 1 to close
5206 **
5207 **      Returns:
5208 **              none
5209 */
5210
5211 void
5212 sm_closefrom(lowest, highest)
5213         int lowest, highest;
5214 {
5215 #if HASCLOSEFROM
5216         closefrom(lowest);
5217 #else /* HASCLOSEFROM */
5218         int i;
5219
5220         for (i = lowest; i < highest; i++)
5221                 (void) close(i);
5222 #endif /* HASCLOSEFROM */
5223 }
5224 #if HASFDWALK
5225 /*
5226 **  CLOSEFD_WALK -- walk fd's arranging to close them
5227 **      Callback for fdwalk()
5228 **
5229 **      Parameters:
5230 **              lowest -- first fd to arrange to be closed
5231 **              fd -- fd to arrange to be closed
5232 **
5233 **      Returns:
5234 **              zero
5235 */
5236
5237 static int
5238 closefd_walk(lowest, fd)
5239         void *lowest;
5240         int fd;
5241 {
5242         if (fd >= *(int *)lowest)
5243                 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
5244         return 0;
5245 }
5246 #endif /* HASFDWALK */
5247 /*
5248 **  SM_CLOSE_ON_EXEC -- arrange for file descriptors to be closed
5249 **
5250 **      Parameters:
5251 **              lowest -- first fd to arrange to be closed
5252 **              highest -- last fd + 1 to arrange to be closed
5253 **
5254 **      Returns:
5255 **              none
5256 */
5257
5258 void
5259 sm_close_on_exec(highest, lowest)
5260         int highest, lowest;
5261 {
5262 #if HASFDWALK
5263         (void) fdwalk(closefd_walk, &lowest);
5264 #else /* HASFDWALK */
5265         int i, j;
5266
5267         for (i = lowest; i < highest; i++)
5268         {
5269                 if ((j = fcntl(i, F_GETFD, 0)) != -1)
5270                         (void) fcntl(i, F_SETFD, j | FD_CLOEXEC);
5271         }
5272 #endif /* HASFDWALK */
5273 }
5274 /*
5275 **  SEED_RANDOM -- seed the random number generator
5276 **
5277 **      Parameters:
5278 **              none
5279 **
5280 **      Returns:
5281 **              none
5282 */
5283
5284 void
5285 seed_random()
5286 {
5287 #if HASSRANDOMDEV
5288         srandomdev();
5289 #else /* HASSRANDOMDEV */
5290         long seed;
5291         struct timeval t;
5292
5293         seed = (long) CurrentPid;
5294         if (gettimeofday(&t, NULL) >= 0)
5295                 seed += t.tv_sec + t.tv_usec;
5296
5297 # if HASRANDOM
5298         (void) srandom(seed);
5299 # else /* HASRANDOM */
5300         (void) srand((unsigned int) seed);
5301 # endif /* HASRANDOM */
5302 #endif /* HASSRANDOMDEV */
5303 }
5304 /*
5305 **  SM_SYSLOG -- syslog wrapper to keep messages under SYSLOG_BUFSIZE
5306 **
5307 **      Parameters:
5308 **              level -- syslog level
5309 **              id -- envelope ID or NULL (NOQUEUE)
5310 **              fmt -- format string
5311 **              arg... -- arguments as implied by fmt.
5312 **
5313 **      Returns:
5314 **              none
5315 */
5316
5317 /* VARARGS3 */
5318 void
5319 #ifdef __STDC__
5320 sm_syslog(int level, const char *id, const char *fmt, ...)
5321 #else /* __STDC__ */
5322 sm_syslog(level, id, fmt, va_alist)
5323         int level;
5324         const char *id;
5325         const char *fmt;
5326         va_dcl
5327 #endif /* __STDC__ */
5328 {
5329         char *buf;
5330         size_t bufsize;
5331         char *begin, *end;
5332         int save_errno;
5333         int seq = 1;
5334         int idlen;
5335         char buf0[MAXLINE];
5336         char *newstring;
5337         extern int SyslogPrefixLen;
5338         SM_VA_LOCAL_DECL
5339
5340         save_errno = errno;
5341         if (id == NULL)
5342                 id = "NOQUEUE";
5343         idlen = strlen(id) + SyslogPrefixLen;
5344
5345         buf = buf0;
5346         bufsize = sizeof(buf0);
5347
5348         for (;;)
5349         {
5350                 int n;
5351
5352                 /* print log message into buf */
5353                 SM_VA_START(ap, fmt);
5354                 n = sm_vsnprintf(buf, bufsize, fmt, ap);
5355                 SM_VA_END(ap);
5356                 SM_ASSERT(n > 0);
5357                 if (n < bufsize)
5358                         break;
5359
5360                 /* String too small, redo with correct size */
5361                 bufsize = n + 1;
5362                 if (buf != buf0)
5363                 {
5364                         sm_free(buf);
5365                         buf = NULL;
5366                 }
5367                 buf = sm_malloc_x(bufsize);
5368         }
5369
5370         /* clean up buf after it has been expanded with args */
5371         newstring = str2prt(buf);
5372         if ((strlen(newstring) + idlen + 1) < SYSLOG_BUFSIZE)
5373         {
5374 #if LOG
5375                 if (*id == '\0')
5376                 {
5377                         if (tTd(89, 8))
5378                                 sm_dprintf("%s\n", newstring);
5379                         else
5380                                 syslog(level, "%s", newstring);
5381                 }
5382                 else
5383                 {
5384                         if (tTd(89, 8))
5385                                 sm_dprintf("%s: %s\n", id, newstring);
5386                         else
5387                                 syslog(level, "%s: %s", id, newstring);
5388                 }
5389 #else /* LOG */
5390                 /*XXX should do something more sensible */
5391                 if (*id == '\0')
5392                         (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s\n",
5393                                              newstring);
5394                 else
5395                         (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
5396                                              "%s: %s\n", id, newstring);
5397 #endif /* LOG */
5398                 if (buf != buf0)
5399                         sm_free(buf);
5400                 errno = save_errno;
5401                 return;
5402         }
5403
5404 /*
5405 **  additional length for splitting: " ..." + 3, where 3 is magic to
5406 **  have some data for the next entry.
5407 */
5408
5409 #define SL_SPLIT 7
5410
5411         begin = newstring;
5412         idlen += 5;     /* strlen("[999]"), see below */
5413         while (*begin != '\0' &&
5414                (strlen(begin) + idlen) > SYSLOG_BUFSIZE)
5415         {
5416                 char save;
5417
5418                 if (seq >= 999)
5419                 {
5420                         /* Too many messages */
5421                         break;
5422                 }
5423                 end = begin + SYSLOG_BUFSIZE - idlen - SL_SPLIT;
5424                 while (end > begin)
5425                 {
5426                         /* Break on comma or space */
5427                         if (*end == ',' || *end == ' ')
5428                         {
5429                                 end++;    /* Include separator */
5430                                 break;
5431                         }
5432                         end--;
5433                 }
5434                 /* No separator, break midstring... */
5435                 if (end == begin)
5436                         end = begin + SYSLOG_BUFSIZE - idlen - SL_SPLIT;
5437                 save = *end;
5438                 *end = 0;
5439 #if LOG
5440                 if (tTd(89, 8))
5441                         sm_dprintf("%s[%d]: %s ...\n", id, seq++, begin);
5442                 else
5443                         syslog(level, "%s[%d]: %s ...", id, seq++, begin);
5444 #else /* LOG */
5445                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
5446                                      "%s[%d]: %s ...\n", id, seq++, begin);
5447 #endif /* LOG */
5448                 *end = save;
5449                 begin = end;
5450         }
5451         if (seq >= 999)
5452         {
5453 #if LOG
5454                 if (tTd(89, 8))
5455                         sm_dprintf("%s[%d]: log terminated, too many parts\n",
5456                                 id, seq);
5457                 else
5458                         syslog(level, "%s[%d]: log terminated, too many parts",
5459                                 id, seq);
5460 #else /* LOG */
5461                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
5462                               "%s[%d]: log terminated, too many parts\n", id, seq);
5463 #endif /* LOG */
5464         }
5465         else if (*begin != '\0')
5466         {
5467 #if LOG
5468                 if (tTd(89, 8))
5469                         sm_dprintf("%s[%d]: %s\n", id, seq, begin);
5470                 else
5471                         syslog(level, "%s[%d]: %s", id, seq, begin);
5472 #else /* LOG */
5473                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
5474                                      "%s[%d]: %s\n", id, seq, begin);
5475 #endif /* LOG */
5476         }
5477         if (buf != buf0)
5478                 sm_free(buf);
5479         errno = save_errno;
5480 }
5481 /*
5482 **  HARD_SYSLOG -- call syslog repeatedly until it works
5483 **
5484 **      Needed on HP-UX, which apparently doesn't guarantee that
5485 **      syslog succeeds during interrupt handlers.
5486 */
5487
5488 #if defined(__hpux) && !defined(HPUX11)
5489
5490 # define MAXSYSLOGTRIES 100
5491 # undef syslog
5492 # ifdef V4FS
5493 #  define XCNST const
5494 #  define CAST  (const char *)
5495 # else /* V4FS */
5496 #  define XCNST
5497 #  define CAST
5498 # endif /* V4FS */
5499
5500 void
5501 # ifdef __STDC__
5502 hard_syslog(int pri, XCNST char *msg, ...)
5503 # else /* __STDC__ */
5504 hard_syslog(pri, msg, va_alist)
5505         int pri;
5506         XCNST char *msg;
5507         va_dcl
5508 # endif /* __STDC__ */
5509 {
5510         int i;
5511         char buf[SYSLOG_BUFSIZE];
5512         SM_VA_LOCAL_DECL
5513
5514         SM_VA_START(ap, msg);
5515         (void) sm_vsnprintf(buf, sizeof(buf), msg, ap);
5516         SM_VA_END(ap);
5517
5518         for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, CAST "%s", buf) < 0; )
5519                 continue;
5520 }
5521
5522 # undef CAST
5523 #endif /* defined(__hpux) && !defined(HPUX11) */
5524 #if NEEDLOCAL_HOSTNAME_LENGTH
5525 /*
5526 **  LOCAL_HOSTNAME_LENGTH
5527 **
5528 **      This is required to get sendmail to compile against BIND 4.9.x
5529 **      on Ultrix.
5530 **
5531 **      Unfortunately, a Compaq Y2K patch kit provides it without
5532 **      bumping __RES in /usr/include/resolv.h so we can't automatically
5533 **      figure out whether it is needed.
5534 */
5535
5536 int
5537 local_hostname_length(hostname)
5538         char *hostname;
5539 {
5540         size_t len_host, len_domain;
5541
5542         if (!*_res.defdname)
5543                 res_init();
5544         len_host = strlen(hostname);
5545         len_domain = strlen(_res.defdname);
5546         if (len_host > len_domain &&
5547             (sm_strcasecmp(hostname + len_host - len_domain,
5548                         _res.defdname) == 0) &&
5549             hostname[len_host - len_domain - 1] == '.')
5550                 return len_host - len_domain - 1;
5551         else
5552                 return 0;
5553 }
5554 #endif /* NEEDLOCAL_HOSTNAME_LENGTH */
5555
5556 #if NEEDLINK
5557 /*
5558 **  LINK -- clone a file
5559 **
5560 **      Some OS's lacks link() and hard links.  Since sendmail is using
5561 **      link() as an efficient way to clone files, this implementation
5562 **      will simply do a file copy.
5563 **
5564 **      NOTE: This link() replacement is not a generic replacement as it
5565 **      does not handle all of the semantics of the real link(2).
5566 **
5567 **      Parameters:
5568 **              source -- pathname of existing file.
5569 **              target -- pathname of link (clone) to be created.
5570 **
5571 **      Returns:
5572 **              0 -- success.
5573 **              -1 -- failure, see errno for details.
5574 */
5575
5576 int
5577 link(source, target)
5578         const char *source;
5579         const char *target;
5580 {
5581         int save_errno;
5582         int sff;
5583         int src = -1, dst = -1;
5584         ssize_t readlen;
5585         ssize_t writelen;
5586         char buf[BUFSIZ];
5587         struct stat st;
5588
5589         sff = SFF_REGONLY|SFF_OPENASROOT;
5590         if (DontLockReadFiles)
5591                 sff |= SFF_NOLOCK;
5592
5593         /* Open the original file */
5594         src = safeopen((char *)source, O_RDONLY, 0, sff);
5595         if (src < 0)
5596                 goto fail;
5597
5598         /* Obtain the size and the mode */
5599         if (fstat(src, &st) < 0)
5600                 goto fail;
5601
5602         /* Create the duplicate copy */
5603         sff &= ~SFF_NOLOCK;
5604         sff |= SFF_CREAT;
5605         dst = safeopen((char *)target, O_CREAT|O_EXCL|O_WRONLY,
5606                        st.st_mode, sff);
5607         if (dst < 0)
5608                 goto fail;
5609
5610         /* Copy all of the bytes one buffer at a time */
5611         while ((readlen = read(src, &buf, sizeof(buf))) > 0)
5612         {
5613                 ssize_t left = readlen;
5614                 char *p = buf;
5615
5616                 while (left > 0 &&
5617                        (writelen = write(dst, p, (size_t) left)) >= 0)
5618                 {
5619                         left -= writelen;
5620                         p += writelen;
5621                 }
5622                 if (writelen < 0)
5623                         break;
5624         }
5625
5626         /* Any trouble reading? */
5627         if (readlen < 0 || writelen < 0)
5628                 goto fail;
5629
5630         /* Close the input file */
5631         if (close(src) < 0)
5632         {
5633                 src = -1;
5634                 goto fail;
5635         }
5636         src = -1;
5637
5638         /* Close the output file */
5639         if (close(dst) < 0)
5640         {
5641                 /* don't set dst = -1 here so we unlink the file */
5642                 goto fail;
5643         }
5644
5645         /* Success */
5646         return 0;
5647
5648  fail:
5649         save_errno = errno;
5650         if (src >= 0)
5651                 (void) close(src);
5652         if (dst >= 0)
5653         {
5654                 (void) unlink(target);
5655                 (void) close(dst);
5656         }
5657         errno = save_errno;
5658         return -1;
5659 }
5660 #endif /* NEEDLINK */
5661
5662 /*
5663 **  Compile-Time options
5664 */
5665
5666 char    *CompileOptions[] =
5667 {
5668 #if ALLOW_255
5669         "ALLOW_255",
5670 #endif /* ALLOW_255 */
5671 #if NAMED_BIND
5672 # if DNSMAP
5673         "DNSMAP",
5674 # endif /* DNSMAP */
5675 #endif /* NAMED_BIND */
5676 #if EGD
5677         "EGD",
5678 #endif /* EGD */
5679 #if HESIOD
5680         "HESIOD",
5681 #endif /* HESIOD */
5682 #if HES_GETMAILHOST
5683         "HES_GETMAILHOST",
5684 #endif /* HES_GETMAILHOST */
5685 #if LDAPMAP
5686         "LDAPMAP",
5687 #endif /* LDAPMAP */
5688 #if LDAP_REFERRALS
5689         "LDAP_REFERRALS",
5690 #endif /* LDAP_REFERRALS */
5691 #if LOG
5692         "LOG",
5693 #endif /* LOG */
5694 #if MAP_NSD
5695         "MAP_NSD",
5696 #endif /* MAP_NSD */
5697 #if MAP_REGEX
5698         "MAP_REGEX",
5699 #endif /* MAP_REGEX */
5700 #if MATCHGECOS
5701         "MATCHGECOS",
5702 #endif /* MATCHGECOS */
5703 #if MILTER
5704         "MILTER",
5705 #endif /* MILTER */
5706 #if MIME7TO8
5707         "MIME7TO8",
5708 #endif /* MIME7TO8 */
5709 #if MIME7TO8_OLD
5710         "MIME7TO8_OLD",
5711 #endif /* MIME7TO8_OLD */
5712 #if MIME8TO7
5713         "MIME8TO7",
5714 #endif /* MIME8TO7 */
5715 #if NAMED_BIND
5716         "NAMED_BIND",
5717 #endif /* NAMED_BIND */
5718 #if NDBM
5719         "NDBM",
5720 #endif /* NDBM */
5721 #if NETINET
5722         "NETINET",
5723 #endif /* NETINET */
5724 #if NETINET6
5725         "NETINET6",
5726 #endif /* NETINET6 */
5727 #if NETINFO
5728         "NETINFO",
5729 #endif /* NETINFO */
5730 #if NETISO
5731         "NETISO",
5732 #endif /* NETISO */
5733 #if NETNS
5734         "NETNS",
5735 #endif /* NETNS */
5736 #if NETUNIX
5737         "NETUNIX",
5738 #endif /* NETUNIX */
5739 #if NETX25
5740         "NETX25",
5741 #endif /* NETX25 */
5742 #if NEWDB
5743         "NEWDB",
5744 #endif /* NEWDB */
5745 #if NIS
5746         "NIS",
5747 #endif /* NIS */
5748 #if NISPLUS
5749         "NISPLUS",
5750 #endif /* NISPLUS */
5751 #if NO_DH
5752         "NO_DH",
5753 #endif /* NO_DH */
5754 #if PH_MAP
5755         "PH_MAP",
5756 #endif /* PH_MAP */
5757 #ifdef PICKY_HELO_CHECK
5758         "PICKY_HELO_CHECK",
5759 #endif /* PICKY_HELO_CHECK */
5760 #if PIPELINING
5761         "PIPELINING",
5762 #endif /* PIPELINING */
5763 #if SASL
5764 # if SASL >= 20000
5765         "SASLv2",
5766 # else /* SASL >= 20000 */
5767         "SASL",
5768 # endif /* SASL >= 20000 */
5769 #endif /* SASL */
5770 #if SCANF
5771         "SCANF",
5772 #endif /* SCANF */
5773 #if SM_LDAP_ERROR_ON_MISSING_ARGS
5774         "SM_LDAP_ERROR_ON_MISSING_ARGS",
5775 #endif /* SM_LDAP_ERROR_ON_MISSING_ARGS */
5776 #if SMTPDEBUG
5777         "SMTPDEBUG",
5778 #endif /* SMTPDEBUG */
5779 #if SOCKETMAP
5780         "SOCKETMAP",
5781 #endif /* SOCKETMAP */
5782 #if STARTTLS
5783         "STARTTLS",
5784 #endif /* STARTTLS */
5785 #if SUID_ROOT_FILES_OK
5786         "SUID_ROOT_FILES_OK",
5787 #endif /* SUID_ROOT_FILES_OK */
5788 #if TCPWRAPPERS
5789         "TCPWRAPPERS",
5790 #endif /* TCPWRAPPERS */
5791 #if TLS_NO_RSA
5792         "TLS_NO_RSA",
5793 #endif /* TLS_NO_RSA */
5794 #if TLS_VRFY_PER_CTX
5795         "TLS_VRFY_PER_CTX",
5796 #endif /* TLS_VRFY_PER_CTX */
5797 #if USERDB
5798         "USERDB",
5799 #endif /* USERDB */
5800 #if USE_LDAP_INIT
5801         "USE_LDAP_INIT",
5802 #endif /* USE_LDAP_INIT */
5803 #if USE_TTYPATH
5804         "USE_TTYPATH",
5805 #endif /* USE_TTYPATH */
5806 #if XDEBUG
5807         "XDEBUG",
5808 #endif /* XDEBUG */
5809 #if XLA
5810         "XLA",
5811 #endif /* XLA */
5812         NULL
5813 };
5814
5815
5816 /*
5817 **  OS compile options.
5818 */
5819
5820 char    *OsCompileOptions[] =
5821 {
5822 #if ADDRCONFIG_IS_BROKEN
5823         "ADDRCONFIG_IS_BROKEN",
5824 #endif /* ADDRCONFIG_IS_BROKEN */
5825 #ifdef AUTO_NETINFO_HOSTS
5826         "AUTO_NETINFO_HOSTS",
5827 #endif /* AUTO_NETINFO_HOSTS */
5828 #ifdef AUTO_NIS_ALIASES
5829         "AUTO_NIS_ALIASES",
5830 #endif /* AUTO_NIS_ALIASES */
5831 #if BROKEN_RES_SEARCH
5832         "BROKEN_RES_SEARCH",
5833 #endif /* BROKEN_RES_SEARCH */
5834 #ifdef BSD4_4_SOCKADDR
5835         "BSD4_4_SOCKADDR",
5836 #endif /* BSD4_4_SOCKADDR */
5837 #if BOGUS_O_EXCL
5838         "BOGUS_O_EXCL",
5839 #endif /* BOGUS_O_EXCL */
5840 #if DEC_OSF_BROKEN_GETPWENT
5841         "DEC_OSF_BROKEN_GETPWENT",
5842 #endif /* DEC_OSF_BROKEN_GETPWENT */
5843 #if FAST_PID_RECYCLE
5844         "FAST_PID_RECYCLE",
5845 #endif /* FAST_PID_RECYCLE */
5846 #if HASCLOSEFROM
5847         "HASCLOSEFROM",
5848 #endif /* HASCLOSEFROM */
5849 #if HASFCHOWN
5850         "HASFCHOWN",
5851 #endif /* HASFCHOWN */
5852 #if HASFCHMOD
5853         "HASFCHMOD",
5854 #endif /* HASFCHMOD */
5855 #if HASFDWALK
5856         "HASFDWALK",
5857 #endif /* HASFDWALK */
5858 #if HASFLOCK
5859         "HASFLOCK",
5860 #endif /* HASFLOCK */
5861 #if HASGETDTABLESIZE
5862         "HASGETDTABLESIZE",
5863 #endif /* HASGETDTABLESIZE */
5864 #if HASGETUSERSHELL
5865         "HASGETUSERSHELL",
5866 #endif /* HASGETUSERSHELL */
5867 #if HASINITGROUPS
5868         "HASINITGROUPS",
5869 #endif /* HASINITGROUPS */
5870 #if HASLDAPGETALIASBYNAME
5871         "HASLDAPGETALIASBYNAME",
5872 #endif /* HASLDAPGETALIASBYNAME */
5873 #if HASLSTAT
5874         "HASLSTAT",
5875 #endif /* HASLSTAT */
5876 #if HASNICE
5877         "HASNICE",
5878 #endif /* HASNICE */
5879 #if HASRANDOM
5880         "HASRANDOM",
5881 #endif /* HASRANDOM */
5882 #if HASRRESVPORT
5883         "HASRRESVPORT",
5884 #endif /* HASRRESVPORT */
5885 #if HASSETEGID
5886         "HASSETEGID",
5887 #endif /* HASSETEGID */
5888 #if HASSETLOGIN
5889         "HASSETLOGIN",
5890 #endif /* HASSETLOGIN */
5891 #if HASSETREGID
5892         "HASSETREGID",
5893 #endif /* HASSETREGID */
5894 #if HASSETRESGID
5895         "HASSETRESGID",
5896 #endif /* HASSETRESGID */
5897 #if HASSETREUID
5898         "HASSETREUID",
5899 #endif /* HASSETREUID */
5900 #if HASSETRLIMIT
5901         "HASSETRLIMIT",
5902 #endif /* HASSETRLIMIT */
5903 #if HASSETSID
5904         "HASSETSID",
5905 #endif /* HASSETSID */
5906 #if HASSETUSERCONTEXT
5907         "HASSETUSERCONTEXT",
5908 #endif /* HASSETUSERCONTEXT */
5909 #if HASSETVBUF
5910         "HASSETVBUF",
5911 #endif /* HASSETVBUF */
5912 #if HAS_ST_GEN
5913         "HAS_ST_GEN",
5914 #endif /* HAS_ST_GEN */
5915 #if HASSRANDOMDEV
5916         "HASSRANDOMDEV",
5917 #endif /* HASSRANDOMDEV */
5918 #if HASURANDOMDEV
5919         "HASURANDOMDEV",
5920 #endif /* HASURANDOMDEV */
5921 #if HASSTRERROR
5922         "HASSTRERROR",
5923 #endif /* HASSTRERROR */
5924 #if HASULIMIT
5925         "HASULIMIT",
5926 #endif /* HASULIMIT */
5927 #if HASUNAME
5928         "HASUNAME",
5929 #endif /* HASUNAME */
5930 #if HASUNSETENV
5931         "HASUNSETENV",
5932 #endif /* HASUNSETENV */
5933 #if HASWAITPID
5934         "HASWAITPID",
5935 #endif /* HASWAITPID */
5936 #if HAVE_NANOSLEEP
5937         "HAVE_NANOSLEEP",
5938 #endif /* HAVE_NANOSLEEP */
5939 #if IDENTPROTO
5940         "IDENTPROTO",
5941 #endif /* IDENTPROTO */
5942 #if IP_SRCROUTE
5943         "IP_SRCROUTE",
5944 #endif /* IP_SRCROUTE */
5945 #if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
5946         "LOCK_ON_OPEN",
5947 #endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
5948 #if MILTER_NO_NAGLE
5949         "MILTER_NO_NAGLE ",
5950 #endif /* MILTER_NO_NAGLE */
5951 #if NEEDFSYNC
5952         "NEEDFSYNC",
5953 #endif /* NEEDFSYNC */
5954 #if NEEDLINK
5955         "NEEDLINK",
5956 #endif /* NEEDLINK */
5957 #if NEEDLOCAL_HOSTNAME_LENGTH
5958         "NEEDLOCAL_HOSTNAME_LENGTH",
5959 #endif /* NEEDLOCAL_HOSTNAME_LENGTH */
5960 #if NEEDSGETIPNODE
5961         "NEEDSGETIPNODE",
5962 #endif /* NEEDSGETIPNODE */
5963 #if NEEDSTRSTR
5964         "NEEDSTRSTR",
5965 #endif /* NEEDSTRSTR */
5966 #if NEEDSTRTOL
5967         "NEEDSTRTOL",
5968 #endif /* NEEDSTRTOL */
5969 #ifdef NO_GETSERVBYNAME
5970         "NO_GETSERVBYNAME",
5971 #endif /* NO_GETSERVBYNAME */
5972 #if NOFTRUNCATE
5973         "NOFTRUNCATE",
5974 #endif /* NOFTRUNCATE */
5975 #if REQUIRES_DIR_FSYNC
5976         "REQUIRES_DIR_FSYNC",
5977 #endif /* REQUIRES_DIR_FSYNC */
5978 #if RLIMIT_NEEDS_SYS_TIME_H
5979         "RLIMIT_NEEDS_SYS_TIME_H",
5980 #endif /* RLIMIT_NEEDS_SYS_TIME_H */
5981 #if SAFENFSPATHCONF
5982         "SAFENFSPATHCONF",
5983 #endif /* SAFENFSPATHCONF */
5984 #if SECUREWARE
5985         "SECUREWARE",
5986 #endif /* SECUREWARE */
5987 #if SHARE_V1
5988         "SHARE_V1",
5989 #endif /* SHARE_V1 */
5990 #if SIOCGIFCONF_IS_BROKEN
5991         "SIOCGIFCONF_IS_BROKEN",
5992 #endif /* SIOCGIFCONF_IS_BROKEN */
5993 #if SIOCGIFNUM_IS_BROKEN
5994         "SIOCGIFNUM_IS_BROKEN",
5995 #endif /* SIOCGIFNUM_IS_BROKEN */
5996 #if SNPRINTF_IS_BROKEN
5997         "SNPRINTF_IS_BROKEN",
5998 #endif /* SNPRINTF_IS_BROKEN */
5999 #if SO_REUSEADDR_IS_BROKEN
6000         "SO_REUSEADDR_IS_BROKEN",
6001 #endif /* SO_REUSEADDR_IS_BROKEN */
6002 #if SYS5SETPGRP
6003         "SYS5SETPGRP",
6004 #endif /* SYS5SETPGRP */
6005 #if SYSTEM5
6006         "SYSTEM5",
6007 #endif /* SYSTEM5 */
6008 #if USE_DOUBLE_FORK
6009         "USE_DOUBLE_FORK",
6010 #endif /* USE_DOUBLE_FORK */
6011 #if USE_ENVIRON
6012         "USE_ENVIRON",
6013 #endif /* USE_ENVIRON */
6014 #if USE_SA_SIGACTION
6015         "USE_SA_SIGACTION",
6016 #endif /* USE_SA_SIGACTION */
6017 #if USE_SIGLONGJMP
6018         "USE_SIGLONGJMP",
6019 #endif /* USE_SIGLONGJMP */
6020 #if USEGETCONFATTR
6021         "USEGETCONFATTR",
6022 #endif /* USEGETCONFATTR */
6023 #if USESETEUID
6024         "USESETEUID",
6025 #endif /* USESETEUID */
6026 #ifdef USESYSCTL
6027         "USESYSCTL",
6028 #endif /* USESYSCTL */
6029 #if USE_OPENSSL_ENGINE
6030         "USE_OPENSSL_ENGINE",
6031 #endif /* USE_OPENSSL_ENGINE */
6032 #if USING_NETSCAPE_LDAP
6033         "USING_NETSCAPE_LDAP",
6034 #endif /* USING_NETSCAPE_LDAP */
6035 #ifdef WAITUNION
6036         "WAITUNION",
6037 #endif /* WAITUNION */
6038         NULL
6039 };
6040
6041 /*
6042 **  FFR compile options.
6043 */
6044
6045 char    *FFRCompileOptions[] =
6046 {
6047 #if _FFR_ADDR_TYPE_MODES
6048         /* more info in {addr_type}, requires m4 changes! */
6049         "_FFR_ADDR_TYPE_MODES",
6050 #endif /* _FFR_ADDR_TYPE_MODES */
6051 #if _FFR_ALLOW_SASLINFO
6052         /* DefaultAuthInfo can be specified by user. */
6053         /* DefaultAuthInfo doesn't really work in 8.13 anymore. */
6054         "_FFR_ALLOW_SASLINFO",
6055 #endif /* _FFR_ALLOW_SASLINFO */
6056 #if _FFR_BADRCPT_SHUTDOWN
6057         /* shut down connection (421) if there are too many bad RCPTs */
6058         "_FFR_BADRCPT_SHUTDOWN",
6059 #endif /* _FFR_BADRCPT_SHUTDOWN */
6060 #if _FFR_BESTMX_BETTER_TRUNCATION
6061         /* Better truncation of list of MX records for dns map. */
6062         "_FFR_BESTMX_BETTER_TRUNCATION",
6063 #endif /* _FFR_BESTMX_BETTER_TRUNCATION */
6064 #if _FFR_CATCH_BROKEN_MTAS
6065         /* Deal with MTAs that send a reply during the DATA phase. */
6066         "_FFR_CATCH_BROKEN_MTAS",
6067 #endif /* _FFR_CATCH_BROKEN_MTAS */
6068 #if _FFR_CHECKCONFIG
6069         /* New OpMode to check the configuration file */
6070         "_FFR_CHECKCONFIG",
6071 #endif /* _FFR_CHECKCONFIG */
6072 #if _FFR_CHK_QUEUE
6073         /* Stricter checks about queue directory permissions. */
6074         "_FFR_CHK_QUEUE",
6075 #endif /* _FFR_CHK_QUEUE */
6076 #if _FFR_CLIENT_SIZE
6077         /* Don't try to send mail if its size exceeds SIZE= of server. */
6078         "_FFR_CLIENT_SIZE",
6079 #endif /* _FFR_CLIENT_SIZE */
6080 #if _FFR_CRLPATH
6081         /* CRLPath; needs documentation; Al Smith */
6082         "_FFR_CRLPATH",
6083 #endif /* _FFR_CRLPATH */
6084 #if _FFR_DAEMON_NETUNIX
6085         /* Allow local (not just TCP) socket connection to server. */
6086         "_FFR_DAEMON_NETUNIX",
6087 #endif /* _FFR_DAEMON_NETUNIX */
6088 #if _FFR_DEPRECATE_MAILER_FLAG_I
6089         /* What it says :-) */
6090         "_FFR_DEPRECATE_MAILER_FLAG_I",
6091 #endif /* _FFR_DEPRECATE_MAILER_FLAG_I */
6092 #if _FFR_DM_ONE
6093         /* deliver first TA in background, then queue */
6094         "_FFR_DM_ONE",
6095 #endif /* _FFR_DM_ONE */
6096 #if _FFR_DIGUNIX_SAFECHOWN
6097         /* Properly set SAFECHOWN (include/sm/conf.h) for Digital UNIX */
6098 /* Problem noted by Anne Bennett of Concordia University */
6099         "_FFR_DIGUNIX_SAFECHOWN",
6100 #endif /* _FFR_DIGUNIX_SAFECHOWN */
6101 #if _FFR_DNSMAP_ALIASABLE
6102         /* Allow dns map type to be used for aliases. */
6103 /* Don Lewis of TDK */
6104         "_FFR_DNSMAP_ALIASABLE",
6105 #endif /* _FFR_DNSMAP_ALIASABLE */
6106 #if _FFR_DONTLOCKFILESFORREAD_OPTION
6107         /* Enable DontLockFilesForRead option. */
6108         "_FFR_DONTLOCKFILESFORREAD_OPTION",
6109 #endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */
6110 #if _FFR_DOTTED_USERNAMES
6111         /* Allow usernames with '.' */
6112         "_FFR_DOTTED_USERNAMES",
6113 #endif /* _FFR_DOTTED_USERNAMES */
6114 #if _FFR_DPO_CS
6115         /*
6116         **  Make DaemonPortOptions case sensitive.
6117         **  For some unknown reasons the code converted every option
6118         **  to uppercase (first letter only, as that's the only one that
6119         **  is actually checked). This prevented all new lower case options
6120         **  from working...
6121         **  The documentation doesn't say anything about case (in)sensitivity,
6122         **  which means it should be case sensitive by default,
6123         **  but it's not a good idea to change this within a patch release,
6124         **  so let's delay this to 8.15.
6125         */
6126
6127         "_FFR_DPO_CS",
6128 #endif /* _FFR_DPO_CS */
6129 #if _FFR_DPRINTF_MAP
6130         /* dprintf map for logging */
6131         "_FFR_DPRINTF_MAP",
6132 #endif /* _FFR_DPRINTF_MAP */
6133 #if _FFR_DROP_TRUSTUSER_WARNING
6134         /*
6135         **  Don't issue this warning:
6136         **  "readcf: option TrustedUser may cause problems on systems
6137         **  which do not support fchown() if UseMSP is not set.
6138         */
6139
6140         "_FFR_DROP_TRUSTUSER_WARNING",
6141 #endif /* _FFR_DROP_TRUSTUSER_WARNING */
6142 #if _FFR_EIGHT_BIT_ADDR_OK
6143         /* EightBitAddrOK: allow 8-bit e-mail addresses */
6144         "_FFR_EIGHT_BIT_ADDR_OK",
6145 #endif /* _FFR_EIGHT_BIT_ADDR_OK */
6146 #if _FFR_EXPDELAY
6147         /* exponential queue delay */
6148         "_FFR_EXPDELAY",
6149 #endif /* _FFR_EXPDELAY */
6150 #if _FFR_EXTRA_MAP_CHECK
6151         /* perform extra checks on $( $) in R lines */
6152         "_FFR_EXTRA_MAP_CHECK",
6153 #endif /* _FFR_EXTRA_MAP_CHECK */
6154 #if _FFR_GETHBN_ExFILE
6155         /*
6156         **  According to Motonori Nakamura some gethostbyname()
6157         **  implementations (TurboLinux?) may (temporarily) fail
6158         **  due to a lack of file discriptors. Enabling this FFR
6159         **  will check errno for EMFILE and ENFILE and in case of a match
6160         **  cause a temporary error instead of a permanent error.
6161         **  The right solution is of course to file a bug against those
6162         **  systems such that they actually set h_errno = TRY_AGAIN.
6163         */
6164
6165         "_FFR_GETHBN_ExFILE",
6166 #endif /* _FFR_GETHBN_ExFILE */
6167 #if _FFR_FIX_DASHT
6168         /*
6169         **  If using -t, force not sending to argv recipients, even
6170         **  if they are mentioned in the headers.
6171         */
6172
6173         "_FFR_FIX_DASHT",
6174 #endif /* _FFR_FIX_DASHT */
6175 #if _FFR_FORWARD_SYSERR
6176         /* Cause a "syserr" if forward file isn't "safe". */
6177         "_FFR_FORWARD_SYSERR",
6178 #endif /* _FFR_FORWARD_SYSERR */
6179 #if _FFR_GEN_ORCPT
6180         /* Generate a ORCPT DSN arg if not already provided */
6181         "_FFR_GEN_ORCPT",
6182 #endif /* _FFR_GEN_ORCPT */
6183 #if _FFR_GROUPREADABLEAUTHINFOFILE
6184         /* Allow group readable DefaultAuthInfo file. */
6185         "_FFR_GROUPREADABLEAUTHINFOFILE",
6186 #endif /* _FFR_GROUPREADABLEAUTHINFOFILE */
6187 #if _FFR_HANDLE_ISO8859_GECOS
6188         /*
6189         **  Allow ISO 8859 characters in GECOS field: replace them
6190         **  ith ASCII "equivalent".
6191         */
6192
6193 /* Peter Eriksson of Linkopings universitet */
6194         "_FFR_HANDLE_ISO8859_GECOS",
6195 #endif /* _FFR_HANDLE_ISO8859_GECOS */
6196 #if _FFR_HPUX_NSSWITCH
6197         /* Use nsswitch on HP-UX */
6198         "_FFR_HPUX_NSSWITCH",
6199 #endif /* _FFR_HPUX_NSSWITCH */
6200 #if _FFR_IGNORE_BOGUS_ADDR
6201         /* Ignore addresses for which prescan() failed */
6202         "_FFR_IGNORE_BOGUS_ADDR",
6203 #endif /* _FFR_IGNORE_BOGUS_ADDR */
6204 #if _FFR_IGNORE_EXT_ON_HELO
6205         /* Ignore extensions offered in response to HELO */
6206         "_FFR_IGNORE_EXT_ON_HELO",
6207 #endif /* _FFR_IGNORE_EXT_ON_HELO */
6208 #if _FFR_LINUX_MHNL
6209         /* Set MAXHOSTNAMELEN to 256 (Linux) */
6210         "_FFR_LINUX_MHNL",
6211 #endif /* _FFR_LINUX_MHNL */
6212 #if _FFR_LOCAL_DAEMON
6213         /* Local daemon mode (-bl) which only accepts loopback connections */
6214         "_FFR_LOCAL_DAEMON",
6215 #endif /* _FFR_LOCAL_DAEMON */
6216 #if _FFR_MAIL_MACRO
6217         "_FFR_MAIL_MACRO",
6218 #endif /* _FFR_MAIL_MACRO */
6219 #if _FFR_MAXDATASIZE
6220         /*
6221         **  It is possible that a header is larger than MILTER_CHUNK_SIZE,
6222         **  hence this shouldn't be used as limit for milter communication.
6223         **  see also libmilter/comm.c
6224         **  Gurusamy Sarathy of ActiveState
6225         */
6226
6227         "_FFR_MAXDATASIZE",
6228 #endif /* _FFR_MAXDATASIZE */
6229 #if _FFR_MAX_FORWARD_ENTRIES
6230         /* Try to limit number of .forward entries */
6231         /* (doesn't work) */
6232 /* Randall S. Winchester of the University of Maryland */
6233         "_FFR_MAX_FORWARD_ENTRIES",
6234 #endif /* _FFR_MAX_FORWARD_ENTRIES */
6235 #if _FFR_MAX_SLEEP_TIME
6236         /* Limit sleep(2) time in libsm/clock.c */
6237         "_FFR_MAX_SLEEP_TIME",
6238 #endif /* _FFR_MAX_SLEEP_TIME */
6239 #if _FFR_MDS_NEGOTIATE
6240         /* MaxDataSize negotation with libmilter */
6241         "_FFR_MDS_NEGOTIATE",
6242 #endif /* _FFR_MDS_NEGOTIATE */
6243 #if _FFR_MEMSTAT
6244         /* Check free memory */
6245         "_FFR_MEMSTAT",
6246 #endif /* _FFR_MEMSTAT */
6247 #if _FFR_MILTER_CHECK
6248         "_FFR_MILTER_CHECK",
6249 #endif /* _FFR_MILTER_CHECK */
6250 #if _FFR_MILTER_CONVERT_ALL_LF_TO_CRLF
6251         /*
6252         **  milter_body() uses the same conversion algorithm as putbody()
6253         **  to translate the "local" df format (\n) to SMTP format (\r\n).
6254         **  However, putbody() and mime8to7() use different conversion
6255         **  algorithms.
6256         **  If the input date does not follow the SMTP standard
6257         **  (e.g., if it has "naked \r"s), then the output from putbody()
6258         **  and mime8to7() will most likely be different.
6259         **  By turning on this FFR milter_body() will try to "imitate"
6260         **  mime8to7().
6261         **  Note: there is no (simple) way to deal with both conversions
6262         **  in a consistent manner. Moreover, as the "GiGo" principle applies,
6263         **  it's not really worth to fix it.
6264         */
6265
6266         "_FFR_MILTER_CONVERT_ALL_LF_TO_CRLF",
6267 #endif /* _FFR_MILTER_CONVERT_ALL_LF_TO_CRLF */
6268 #if _FFR_MILTER_CHECK_REJECTIONS_TOO
6269         /*
6270         **  Also send RCPTs that are rejected by check_rcpt to a milter
6271         **  (if requested during option negotiation).
6272         */
6273
6274         "_FFR_MILTER_CHECK_REJECTIONS_TOO",
6275 #endif /* _FFR_MILTER_CHECK_REJECTIONS_TOO */
6276 #if _FFR_MILTER_ENHSC
6277         /* extract enhanced status code from milter replies for dsn= logging */
6278         "_FFR_MILTER_ENHSC",
6279 #endif /* _FFR_MILTER_ENHSC */
6280 #if _FFR_MIME7TO8_OLD
6281         /* Old mime7to8 code, the new is broken for at least one example. */
6282         "_FFR_MIME7TO8_OLD",
6283 #endif /* _FFR_MAX_SLEEP_TIME */
6284 #if _FFR_MORE_MACROS
6285         /* allow more long macro names ("unprintable" characters). */
6286         "_FFR_MORE_MACROS",
6287 #endif /* _FFR_MORE_MACROS */
6288 #if _FFR_MSG_ACCEPT
6289         /* allow to override "Message accepted for delivery" */
6290         "_FFR_MSG_ACCEPT",
6291 #endif /* _FFR_MSG_ACCEPT */
6292 #if _FFR_NODELAYDSN_ON_HOLD
6293         /* Do not issue a DELAY DSN for mailers that use the hold flag. */
6294 /* Steven Pitzl */
6295         "_FFR_NODELAYDSN_ON_HOLD",
6296 #endif /* _FFR_NODELAYDSN_ON_HOLD */
6297 #if _FFR_NO_PIPE
6298         /* Disable PIPELINING, delay client if used. */
6299         "_FFR_NO_PIPE",
6300 #endif /* _FFR_NO_PIPE */
6301 #if _FFR_LDAP_NETWORK_TIMEOUT
6302         /* set LDAP_OPT_NETWORK_TIMEOUT if available (-c) */
6303         "_FFR_LDAP_NETWORK_TIMEOUT",
6304 #endif /* _FFR_LDAP_NETWORK_TIMEOUT */
6305 #if _FFR_LOG_NTRIES
6306         /* log ntries=, from Nik Clayton of FreeBSD */
6307         "_FFR_LOG_NTRIES",
6308 #endif /* _FFR_LOG_NTRIES */
6309 #if _FFR_QF_PARANOIA
6310         "_FFR_QF_PARANOIA",
6311 #endif /* _FFR_QF_PARANOIA */
6312 #if _FFR_QUEUEDELAY
6313         /* Exponential queue delay; disabled in 8.13 since it isn't used. */
6314         "_FFR_QUEUEDELAY",
6315 #endif /* _FFR_QUEUEDELAY */
6316 #if _FFR_QUEUE_GROUP_SORTORDER
6317         /* Allow QueueSortOrder per queue group. */
6318 /* XXX: Still need to actually use qgrp->qg_sortorder */
6319         "_FFR_QUEUE_GROUP_SORTORDER",
6320 #endif /* _FFR_QUEUE_GROUP_SORTORDER */
6321 #if _FFR_QUEUE_MACRO
6322         /* Define {queue} macro. */
6323         "_FFR_QUEUE_MACRO",
6324 #endif /* _FFR_QUEUE_MACRO */
6325 #if _FFR_QUEUE_RUN_PARANOIA
6326         /* Additional checks when doing queue runs; interval of checks */
6327         "_FFR_QUEUE_RUN_PARANOIA",
6328 #endif /* _FFR_QUEUE_RUN_PARANOIA */
6329 #if _FFR_QUEUE_SCHED_DBG
6330         /* Debug output for the queue scheduler. */
6331         "_FFR_QUEUE_SCHED_DBG",
6332 #endif /* _FFR_QUEUE_SCHED_DBG */
6333 #if _FFR_RCPTTHROTDELAY
6334         /* configurable delay for BadRcptThrottle */
6335         "_FFR_RCPTTHROTDELAY",
6336 #endif /* _FFR_RCPTTHROTDELAY */
6337 #if _FFR_REDIRECTEMPTY
6338         /*
6339         **  envelope <> can't be sent to mailing lists, only owner-
6340         **  send spam of this type to owner- of the list
6341         **  ----  to stop spam from going to mailing lists.
6342         */
6343
6344         "_FFR_REDIRECTEMPTY",
6345 #endif /* _FFR_REDIRECTEMPTY */
6346 #if _FFR_RESET_MACRO_GLOBALS
6347         /* Allow macro 'j' to be set dynamically via rulesets. */
6348         "_FFR_RESET_MACRO_GLOBALS",
6349 #endif /* _FFR_RESET_MACRO_GLOBALS */
6350 #if _FFR_RHS
6351         /* Random shuffle for queue sorting. */
6352         "_FFR_RHS",
6353 #endif /* _FFR_RHS */
6354 #if _FFR_RUNPQG
6355         /*
6356         **  allow -qGqueue_group -qp to work, i.e.,
6357         **  restrict a persistent queue runner to a queue group.
6358         */
6359
6360         "_FFR_RUNPQG",
6361 #endif /* _FFR_RUNPQG */
6362 #if _FFR_SESSID
6363         /* session id (for logging) */
6364         "_FFR_SESSID",
6365 #endif /* _FFR_SESSID */
6366 #if _FFR_SHM_STATUS
6367         /* Donated code (unused). */
6368         "_FFR_SHM_STATUS",
6369 #endif /* _FFR_SHM_STATUS */
6370 #if _FFR_LDAP_SINGLEDN
6371         /*
6372         **  The LDAP database map code in Sendmail 8.12.10, when
6373         **  given the -1 switch, would match only a single DN,
6374         **  but was able to return multiple attributes for that
6375         **  DN.  In Sendmail 8.13 this "bug" was corrected to
6376         **  only return if exactly one attribute matched.
6377         **
6378         **  Unfortunately, our configuration uses the former
6379         **  behaviour.  Attached is a relatively simple patch
6380         **  to 8.13.4 which adds a -2 switch (for lack of a
6381         **  better option) which returns the single dn/multiple
6382         **  attributes.
6383         **
6384         ** Jeffrey T. Eaton, Carnegie-Mellon University
6385         */
6386
6387         "_FFR_LDAP_SINGLEDN",
6388 #endif /* _FFR_LDAP_SINGLEDN */
6389 #if _FFR_SKIP_DOMAINS
6390         /* process every N'th domain instead of every N'th message */
6391         "_FFR_SKIP_DOMAINS",
6392 #endif /* _FFR_SKIP_DOMAINS */
6393 #if _FFR_SLEEP_USE_SELECT
6394         /* Use select(2) in libsm/clock.c to emulate sleep(2) */
6395         "_FFR_SLEEP_USE_SELECT ",
6396 #endif /* _FFR_SLEEP_USE_SELECT */
6397 #if _FFR_SPT_ALIGN
6398         /*
6399         **  It looks like the Compaq Tru64 5.1A now aligns argv and envp to 64
6400         **  bit alignment, so unless each piece of argv and envp is a multiple
6401         **  of 8 bytes (including terminating NULL), initsetproctitle() won't
6402         **  use any of the space beyond argv[0]. Be sure to set SPT_ALIGN_SIZE
6403         **  if you use this FFR.
6404         */
6405
6406 /* Chris Adams of HiWAAY Informations Services */
6407         "_FFR_SPT_ALIGN",
6408 #endif /* _FFR_SPT_ALIGN */
6409 #if _FFR_SS_PER_DAEMON
6410         /* SuperSafe per DaemonPortOptions: 'T' (better letter?) */
6411         "_FFR_SS_PER_DAEMON",
6412 #endif /* _FFR_SS_PER_DAEMON */
6413 #if _FFR_TESTS
6414         /* enable some test code */
6415         "_FFR_TESTS",
6416 #endif /* _FFR_TESTS */
6417 #if _FFR_TIMERS
6418         /* Donated code (unused). */
6419         "_FFR_TIMERS",
6420 #endif /* _FFR_TIMERS */
6421 #if _FFR_TLS_1
6422         /* More STARTTLS options, e.g., secondary certs. */
6423         "_FFR_TLS_1",
6424 #endif /* _FFR_TLS_1 */
6425 #if _FFR_TRUSTED_QF
6426         /*
6427         **  If we don't own the file mark it as unsafe.
6428         **  However, allow TrustedUser to own it as well
6429         **  in case TrustedUser manipulates the queue.
6430         */
6431
6432         "_FFR_TRUSTED_QF",
6433 #endif /* _FFR_TRUSTED_QF */
6434 #if _FFR_USE_SEM_LOCKING
6435         "_FFR_USE_SEM_LOCKING",
6436 #endif /* _FFR_USE_SEM_LOCKING */
6437 #if _FFR_USE_SETLOGIN
6438         /* Use setlogin() */
6439 /* Peter Philipp */
6440         "_FFR_USE_SETLOGIN",
6441 #endif /* _FFR_USE_SETLOGIN */
6442         NULL
6443 };
6444