]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/sendmail/src/conf.c
Fix sendmail improper close-on-exec flag handling. [SA-14:11]
[FreeBSD/releng/10.0.git] / contrib / sendmail / src / conf.c
1 /*
2  * Copyright (c) 1998-2013 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.1182 2013/04/05 17:39:09 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)) >= 0)
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)) >= 0)
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)) >= 0)
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 #  ifndef SM_IPNODEBYNAME_FLAGS
4298     /* For IPv4-mapped addresses, use: AI_DEFAULT|AI_ALL */
4299 #   define SM_IPNODEBYNAME_FLAGS        AI_ADDRCONFIG
4300 #  endif /* SM_IPNODEBYNAME_FLAGS */
4301
4302         int flags = SM_IPNODEBYNAME_FLAGS;
4303         int err;
4304 # endif /* NETINET6 */
4305         char *maptype[MAXMAPSTACK];
4306         short mapreturn[MAXMAPACTIONS];
4307         char hbuf[MAXNAME];
4308
4309         if (tTd(61, 10))
4310                 sm_dprintf("sm_gethostbyname(%s, %d)... ", name, family);
4311
4312 # if NETINET6
4313 #  if ADDRCONFIG_IS_BROKEN
4314         flags &= ~AI_ADDRCONFIG;
4315 #  endif /* ADDRCONFIG_IS_BROKEN */
4316         h = sm_getipnodebyname(name, family, flags, &err);
4317         SM_SET_H_ERRNO(err);
4318 # else /* NETINET6 */
4319         h = gethostbyname(name);
4320 # endif /* NETINET6 */
4321
4322         save_errno = errno;
4323         if (h == NULL)
4324         {
4325                 if (tTd(61, 10))
4326                         sm_dprintf("failure\n");
4327
4328                 nmaps = switch_map_find("hosts", maptype, mapreturn);
4329                 while (--nmaps >= 0)
4330                 {
4331                         if (strcmp(maptype[nmaps], "nis") == 0 ||
4332                             strcmp(maptype[nmaps], "files") == 0)
4333                                 break;
4334                 }
4335
4336                 if (nmaps >= 0)
4337                 {
4338                         /* try short name */
4339                         if (strlen(name) > sizeof(hbuf) - 1)
4340                         {
4341                                 errno = save_errno;
4342                                 return NULL;
4343                         }
4344                         (void) sm_strlcpy(hbuf, name, sizeof(hbuf));
4345                         (void) shorten_hostname(hbuf);
4346
4347                         /* if it hasn't been shortened, there's no point */
4348                         if (strcmp(hbuf, name) != 0)
4349                         {
4350                                 if (tTd(61, 10))
4351                                         sm_dprintf("sm_gethostbyname(%s, %d)... ",
4352                                                hbuf, family);
4353
4354 # if NETINET6
4355                                 h = sm_getipnodebyname(hbuf, family, flags, &err);
4356                                 SM_SET_H_ERRNO(err);
4357                                 save_errno = errno;
4358 # else /* NETINET6 */
4359                                 h = gethostbyname(hbuf);
4360                                 save_errno = errno;
4361 # endif /* NETINET6 */
4362                         }
4363                 }
4364         }
4365 #endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */
4366         if (tTd(61, 10))
4367         {
4368                 if (h == NULL)
4369                         sm_dprintf("failure\n");
4370                 else
4371                 {
4372                         sm_dprintf("%s\n", h->h_name);
4373                         if (tTd(61, 11))
4374                         {
4375 #if NETINET6
4376                                 struct in6_addr ia6;
4377                                 char buf6[INET6_ADDRSTRLEN];
4378 #else /* NETINET6 */
4379                                 struct in_addr ia;
4380 #endif /* NETINET6 */
4381                                 size_t i;
4382
4383                                 if (h->h_aliases != NULL)
4384                                         for (i = 0; h->h_aliases[i] != NULL;
4385                                              i++)
4386                                                 sm_dprintf("\talias: %s\n",
4387                                                         h->h_aliases[i]);
4388                                 for (i = 0; h->h_addr_list[i] != NULL; i++)
4389                                 {
4390                                         char *addr;
4391
4392 #if NETINET6
4393                                         memmove(&ia6, h->h_addr_list[i],
4394                                                 IN6ADDRSZ);
4395                                         addr = anynet_ntop(&ia6,
4396                                                            buf6, sizeof(buf6));
4397 #else /* NETINET6 */
4398                                         memmove(&ia, h->h_addr_list[i],
4399                                                 INADDRSZ);
4400                                         addr = (char *) inet_ntoa(ia);
4401 #endif /* NETINET6 */
4402                                         if (addr != NULL)
4403                                                 sm_dprintf("\taddr: %s\n", addr);
4404                                 }
4405                         }
4406                 }
4407         }
4408         errno = save_errno;
4409         return h;
4410 }
4411
4412 struct hostent *
4413 sm_gethostbyaddr(addr, len, type)
4414         char *addr;
4415         int len;
4416         int type;
4417 {
4418         struct hostent *hp;
4419
4420 #if NETINET6
4421         if (type == AF_INET6 &&
4422             IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *) addr))
4423         {
4424                 /* Avoid reverse lookup for IPv6 unspecified address */
4425                 SM_SET_H_ERRNO(HOST_NOT_FOUND);
4426                 return NULL;
4427         }
4428 #endif /* NETINET6 */
4429
4430 #if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204)
4431 # if SOLARIS == 20300 || SOLARIS == 203
4432         {
4433                 static struct hostent he;
4434                 static char buf[1000];
4435                 extern struct hostent *_switch_gethostbyaddr_r();
4436
4437                 hp = _switch_gethostbyaddr_r(addr, len, type, &he,
4438                                              buf, sizeof(buf), &h_errno);
4439         }
4440 # else /* SOLARIS == 20300 || SOLARIS == 203 */
4441         {
4442                 extern struct hostent *__switch_gethostbyaddr();
4443
4444                 hp = __switch_gethostbyaddr(addr, len, type);
4445         }
4446 # endif /* SOLARIS == 20300 || SOLARIS == 203 */
4447 #else /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) */
4448 # if NETINET6
4449         {
4450                 int err;
4451
4452                 hp = sm_getipnodebyaddr(addr, len, type, &err);
4453                 SM_SET_H_ERRNO(err);
4454         }
4455 # else /* NETINET6 */
4456         hp = gethostbyaddr(addr, len, type);
4457 # endif /* NETINET6 */
4458 #endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) */
4459         return hp;
4460 }
4461 /*
4462 **  SM_GETPW{NAM,UID} -- wrapper for getpwnam and getpwuid
4463 */
4464
4465 struct passwd *
4466 sm_getpwnam(user)
4467         char *user;
4468 {
4469 #ifdef _AIX4
4470         extern struct passwd *_getpwnam_shadow(const char *, const int);
4471
4472         return _getpwnam_shadow(user, 0);
4473 #else /* _AIX4 */
4474         return getpwnam(user);
4475 #endif /* _AIX4 */
4476 }
4477
4478 struct passwd *
4479 sm_getpwuid(uid)
4480         UID_T uid;
4481 {
4482 #if defined(_AIX4) && 0
4483         extern struct passwd *_getpwuid_shadow(const int, const int);
4484
4485         return _getpwuid_shadow(uid,0);
4486 #else /* defined(_AIX4) && 0 */
4487         return getpwuid(uid);
4488 #endif /* defined(_AIX4) && 0 */
4489 }
4490 /*
4491 **  SECUREWARE_SETUP_SECURE -- Convex SecureWare setup
4492 **
4493 **      Set up the trusted computing environment for C2 level security
4494 **      under SecureWare.
4495 **
4496 **      Parameters:
4497 **              uid -- uid of the user to initialize in the TCB
4498 **
4499 **      Returns:
4500 **              none
4501 **
4502 **      Side Effects:
4503 **              Initialized the user in the trusted computing base
4504 */
4505
4506 #if SECUREWARE
4507
4508 # include <sys/security.h>
4509 # include <prot.h>
4510
4511 void
4512 secureware_setup_secure(uid)
4513         UID_T uid;
4514 {
4515         int rc;
4516
4517         if (getluid() != -1)
4518                 return;
4519
4520         if ((rc = set_secure_info(uid)) != SSI_GOOD_RETURN)
4521         {
4522                 switch (rc)
4523                 {
4524                   case SSI_NO_PRPW_ENTRY:
4525                         syserr("No protected passwd entry, uid = %d",
4526                                (int) uid);
4527                         break;
4528
4529                   case SSI_LOCKED:
4530                         syserr("Account has been disabled, uid = %d",
4531                                (int) uid);
4532                         break;
4533
4534                   case SSI_RETIRED:
4535                         syserr("Account has been retired, uid = %d",
4536                                (int) uid);
4537                         break;
4538
4539                   case SSI_BAD_SET_LUID:
4540                         syserr("Could not set LUID, uid = %d", (int) uid);
4541                         break;
4542
4543                   case SSI_BAD_SET_PRIVS:
4544                         syserr("Could not set kernel privs, uid = %d",
4545                                (int) uid);
4546
4547                   default:
4548                         syserr("Unknown return code (%d) from set_secure_info(%d)",
4549                                 rc, (int) uid);
4550                         break;
4551                 }
4552                 finis(false, true, EX_NOPERM);
4553         }
4554 }
4555 #endif /* SECUREWARE */
4556 /*
4557 **  ADD_HOSTNAMES -- Add a hostname to class 'w' based on IP address
4558 **
4559 **      Add hostnames to class 'w' based on the IP address read from
4560 **      the network interface.
4561 **
4562 **      Parameters:
4563 **              sa -- a pointer to a SOCKADDR containing the address
4564 **
4565 **      Returns:
4566 **              0 if successful, -1 if host lookup fails.
4567 */
4568
4569 static int
4570 add_hostnames(sa)
4571         SOCKADDR *sa;
4572 {
4573         struct hostent *hp;
4574         char **ha;
4575         char hnb[MAXHOSTNAMELEN];
4576
4577         /* lookup name with IP address */
4578         switch (sa->sa.sa_family)
4579         {
4580 #if NETINET
4581           case AF_INET:
4582                 hp = sm_gethostbyaddr((char *) &sa->sin.sin_addr,
4583                                       sizeof(sa->sin.sin_addr),
4584                                       sa->sa.sa_family);
4585                 break;
4586 #endif /* NETINET */
4587
4588 #if NETINET6
4589           case AF_INET6:
4590                 hp = sm_gethostbyaddr((char *) &sa->sin6.sin6_addr,
4591                                       sizeof(sa->sin6.sin6_addr),
4592                                       sa->sa.sa_family);
4593                 break;
4594 #endif /* NETINET6 */
4595
4596           default:
4597                 /* Give warning about unsupported family */
4598                 if (LogLevel > 3)
4599                         sm_syslog(LOG_WARNING, NOQID,
4600                                   "Unsupported address family %d: %.100s",
4601                                   sa->sa.sa_family, anynet_ntoa(sa));
4602                 return -1;
4603         }
4604
4605         if (hp == NULL)
4606         {
4607                 int save_errno = errno;
4608
4609                 if (LogLevel > 3 &&
4610 #if NETINET && defined(IN_LINKLOCAL)
4611                     !(sa->sa.sa_family == AF_INET &&
4612                       IN_LINKLOCAL(ntohl(sa->sin.sin_addr.s_addr))) &&
4613 #endif /* NETINET && defined(IN_LINKLOCAL) */
4614 #if NETINET6
4615                     !(sa->sa.sa_family == AF_INET6 &&
4616                       IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr)) &&
4617 #endif /* NETINET6 */
4618                     true)
4619                         sm_syslog(LOG_WARNING, NOQID,
4620                                   "gethostbyaddr(%.100s) failed: %d",
4621                                   anynet_ntoa(sa),
4622 #if NAMED_BIND
4623                                   h_errno
4624 #else /* NAMED_BIND */
4625                                   -1
4626 #endif /* NAMED_BIND */
4627                                  );
4628                 errno = save_errno;
4629                 return -1;
4630         }
4631
4632         /* save its cname */
4633         if (!wordinclass((char *) hp->h_name, 'w'))
4634         {
4635                 setclass('w', (char *) hp->h_name);
4636                 if (tTd(0, 4))
4637                         sm_dprintf("\ta.k.a.: %s\n", hp->h_name);
4638
4639                 if (sm_snprintf(hnb, sizeof(hnb), "[%s]", hp->h_name) <
4640                                                                 sizeof(hnb)
4641                     && !wordinclass((char *) hnb, 'w'))
4642                         setclass('w', hnb);
4643         }
4644         else
4645         {
4646                 if (tTd(0, 43))
4647                         sm_dprintf("\ta.k.a.: %s (already in $=w)\n", hp->h_name);
4648         }
4649
4650         /* save all it aliases name */
4651         for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++)
4652         {
4653                 if (!wordinclass(*ha, 'w'))
4654                 {
4655                         setclass('w', *ha);
4656                         if (tTd(0, 4))
4657                                 sm_dprintf("\ta.k.a.: %s\n", *ha);
4658                         if (sm_snprintf(hnb, sizeof(hnb),
4659                                      "[%s]", *ha) < sizeof(hnb) &&
4660                             !wordinclass((char *) hnb, 'w'))
4661                                 setclass('w', hnb);
4662                 }
4663                 else
4664                 {
4665                         if (tTd(0, 43))
4666                                 sm_dprintf("\ta.k.a.: %s (already in $=w)\n",
4667                                         *ha);
4668                 }
4669         }
4670 #if NETINET6
4671         freehostent(hp);
4672 #endif /* NETINET6 */
4673         return 0;
4674 }
4675 /*
4676 **  LOAD_IF_NAMES -- load interface-specific names into $=w
4677 **
4678 **      Parameters:
4679 **              none.
4680 **
4681 **      Returns:
4682 **              none.
4683 **
4684 **      Side Effects:
4685 **              Loads $=w with the names of all the interfaces.
4686 */
4687
4688 #if !NETINET
4689 # define SIOCGIFCONF_IS_BROKEN  1 /* XXX */
4690 #endif /* !NETINET */
4691
4692 #if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
4693 struct rtentry;
4694 struct mbuf;
4695 # ifndef SUNOS403
4696 #  include <sm/time.h>
4697 # endif /* ! SUNOS403 */
4698 # if (_AIX4 >= 40300) && !defined(_NET_IF_H)
4699 #  undef __P
4700 # endif /* (_AIX4 >= 40300) && !defined(_NET_IF_H) */
4701 # include <net/if.h>
4702 #endif /* defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN */
4703
4704 void
4705 load_if_names()
4706 {
4707 # if NETINET6 && defined(SIOCGLIFCONF)
4708 #  ifdef __hpux
4709
4710     /*
4711     **  Unfortunately, HP has changed all of the structures,
4712     **  making life difficult for implementors.
4713     */
4714
4715 #   define lifconf      if_laddrconf
4716 #   define lifc_len     iflc_len
4717 #   define lifc_buf     iflc_buf
4718 #   define lifreq       if_laddrreq
4719 #   define lifr_addr    iflr_addr
4720 #   define lifr_name    iflr_name
4721 #   define lifr_flags   iflr_flags
4722 #   define ss_family    sa_family
4723 #   undef SIOCGLIFNUM
4724 #  endif /* __hpux */
4725
4726         int s;
4727         int i;
4728         size_t len;
4729         int numifs;
4730         char *buf;
4731         struct lifconf lifc;
4732 #  ifdef SIOCGLIFNUM
4733         struct lifnum lifn;
4734 #  endif /* SIOCGLIFNUM */
4735
4736         s = socket(InetMode, SOCK_DGRAM, 0);
4737         if (s == -1)
4738                 return;
4739
4740         /* get the list of known IP address from the kernel */
4741 #  ifdef __hpux
4742         i = ioctl(s, SIOCGIFNUM, (char *) &numifs);
4743 #  endif /* __hpux */
4744 #  ifdef SIOCGLIFNUM
4745         lifn.lifn_family = AF_UNSPEC;
4746         lifn.lifn_flags = 0;
4747         i = ioctl(s, SIOCGLIFNUM, (char *)&lifn);
4748         numifs = lifn.lifn_count;
4749 #  endif /* SIOCGLIFNUM */
4750
4751 #  if defined(__hpux) || defined(SIOCGLIFNUM)
4752         if (i < 0)
4753         {
4754                 /* can't get number of interfaces -- fall back */
4755                 if (tTd(0, 4))
4756                         sm_dprintf("SIOCGLIFNUM failed: %s\n",
4757                                    sm_errstring(errno));
4758                 numifs = -1;
4759         }
4760         else if (tTd(0, 42))
4761                 sm_dprintf("system has %d interfaces\n", numifs);
4762         if (numifs < 0)
4763 #  endif /* defined(__hpux) || defined(SIOCGLIFNUM) */
4764                 numifs = MAXINTERFACES;
4765
4766         if (numifs <= 0)
4767         {
4768                 (void) close(s);
4769                 return;
4770         }
4771
4772         len = lifc.lifc_len = numifs * sizeof(struct lifreq);
4773         buf = lifc.lifc_buf = xalloc(lifc.lifc_len);
4774 #  ifndef __hpux
4775         lifc.lifc_family = AF_UNSPEC;
4776         lifc.lifc_flags = 0;
4777 #  endif /* ! __hpux */
4778         if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0)
4779         {
4780                 if (tTd(0, 4))
4781                         sm_dprintf("SIOCGLIFCONF failed: %s\n",
4782                                    sm_errstring(errno));
4783                 (void) close(s);
4784                 sm_free(buf);
4785                 return;
4786         }
4787
4788         /* scan the list of IP address */
4789         if (tTd(0, 40))
4790                 sm_dprintf("scanning for interface specific names, lifc_len=%ld\n",
4791                            (long) len);
4792
4793         for (i = 0; i < len && i >= 0; )
4794         {
4795                 int flags;
4796                 struct lifreq *ifr = (struct lifreq *)&buf[i];
4797                 SOCKADDR *sa = (SOCKADDR *) &ifr->lifr_addr;
4798                 int af = ifr->lifr_addr.ss_family;
4799                 char *addr;
4800                 char *name;
4801                 struct in6_addr ia6;
4802                 struct in_addr ia;
4803 #  ifdef SIOCGLIFFLAGS
4804                 struct lifreq ifrf;
4805 #  endif /* SIOCGLIFFLAGS */
4806                 char ip_addr[256];
4807                 char buf6[INET6_ADDRSTRLEN];
4808
4809                 /*
4810                 **  We must close and recreate the socket each time
4811                 **  since we don't know what type of socket it is now
4812                 **  (each status function may change it).
4813                 */
4814
4815                 (void) close(s);
4816
4817                 s = socket(af, SOCK_DGRAM, 0);
4818                 if (s == -1)
4819                 {
4820                         sm_free(buf); /* XXX */
4821                         return;
4822                 }
4823
4824                 /*
4825                 **  If we don't have a complete ifr structure,
4826                 **  don't try to use it.
4827                 */
4828
4829                 if ((len - i) < sizeof(*ifr))
4830                         break;
4831
4832 #  ifdef BSD4_4_SOCKADDR
4833                 if (sa->sa.sa_len > sizeof(ifr->lifr_addr))
4834                         i += sizeof(ifr->lifr_name) + sa->sa.sa_len;
4835                 else
4836 #  endif /* BSD4_4_SOCKADDR */
4837 #  ifdef DEC
4838                         /* fix for IPv6  size differences */
4839                         i += sizeof(ifr->ifr_name) +
4840                              max(sizeof(ifr->ifr_addr), ifr->ifr_addr.sa_len);
4841 #   else /* DEC */
4842                         i += sizeof(*ifr);
4843 #   endif /* DEC */
4844
4845                 if (tTd(0, 20))
4846                         sm_dprintf("%s\n", anynet_ntoa(sa));
4847
4848                 if (af != AF_INET && af != AF_INET6)
4849                         continue;
4850
4851 #  ifdef SIOCGLIFFLAGS
4852                 memset(&ifrf, '\0', sizeof(struct lifreq));
4853                 (void) sm_strlcpy(ifrf.lifr_name, ifr->lifr_name,
4854                                   sizeof(ifrf.lifr_name));
4855                 if (ioctl(s, SIOCGLIFFLAGS, (char *) &ifrf) < 0)
4856                 {
4857                         if (tTd(0, 4))
4858                                 sm_dprintf("SIOCGLIFFLAGS failed: %s\n",
4859                                            sm_errstring(errno));
4860                         continue;
4861                 }
4862
4863                 name = ifr->lifr_name;
4864                 flags = ifrf.lifr_flags;
4865
4866                 if (tTd(0, 41))
4867                         sm_dprintf("\tflags: %lx\n", (unsigned long) flags);
4868
4869                 if (!bitset(IFF_UP, flags))
4870                         continue;
4871 #  endif /* SIOCGLIFFLAGS */
4872
4873                 ip_addr[0] = '\0';
4874
4875                 /* extract IP address from the list*/
4876                 switch (af)
4877                 {
4878                   case AF_INET6:
4879                         SETV6LOOPBACKADDRFOUND(*sa);
4880 #  ifdef __KAME__
4881                         /* convert into proper scoped address */
4882                         if ((IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr) ||
4883                              IN6_IS_ADDR_SITELOCAL(&sa->sin6.sin6_addr)) &&
4884                             sa->sin6.sin6_scope_id == 0)
4885                         {
4886                                 struct in6_addr *ia6p;
4887
4888                                 ia6p = &sa->sin6.sin6_addr;
4889                                 sa->sin6.sin6_scope_id = ntohs(ia6p->s6_addr[3] |
4890                                                                ((unsigned int)ia6p->s6_addr[2] << 8));
4891                                 ia6p->s6_addr[2] = ia6p->s6_addr[3] = 0;
4892                         }
4893 #  endif /* __KAME__ */
4894                         ia6 = sa->sin6.sin6_addr;
4895                         if (IN6_IS_ADDR_UNSPECIFIED(&ia6))
4896                         {
4897                                 addr = anynet_ntop(&ia6, buf6, sizeof(buf6));
4898                                 message("WARNING: interface %s is UP with %s address",
4899                                         name, addr == NULL ? "(NULL)" : addr);
4900                                 continue;
4901                         }
4902
4903                         /* save IP address in text from */
4904                         addr = anynet_ntop(&ia6, buf6, sizeof(buf6));
4905                         if (addr != NULL)
4906                                 (void) sm_snprintf(ip_addr, sizeof(ip_addr),
4907                                                    "[%.*s]",
4908                                                    (int) sizeof(ip_addr) - 3,
4909                                                    addr);
4910                         break;
4911
4912                   case AF_INET:
4913                         ia = sa->sin.sin_addr;
4914                         if (ia.s_addr == INADDR_ANY ||
4915                             ia.s_addr == INADDR_NONE)
4916                         {
4917                                 message("WARNING: interface %s is UP with %s address",
4918                                         name, inet_ntoa(ia));
4919                                 continue;
4920                         }
4921
4922                         /* save IP address in text from */
4923                         (void) sm_snprintf(ip_addr, sizeof(ip_addr), "[%.*s]",
4924                                         (int) sizeof(ip_addr) - 3, inet_ntoa(ia));
4925                         break;
4926                 }
4927
4928                 if (*ip_addr == '\0')
4929                         continue;
4930
4931                 if (!wordinclass(ip_addr, 'w'))
4932                 {
4933                         setclass('w', ip_addr);
4934                         if (tTd(0, 4))
4935                                 sm_dprintf("\ta.k.a.: %s\n", ip_addr);
4936                 }
4937
4938 #  ifdef SIOCGLIFFLAGS
4939                 /* skip "loopback" interface "lo" */
4940                 if (DontProbeInterfaces == DPI_SKIPLOOPBACK &&
4941                     bitset(IFF_LOOPBACK, flags))
4942                         continue;
4943 #  endif /* SIOCGLIFFLAGS */
4944                 (void) add_hostnames(sa);
4945         }
4946         sm_free(buf); /* XXX */
4947         (void) close(s);
4948 # else /* NETINET6 && defined(SIOCGLIFCONF) */
4949 #  if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
4950         int s;
4951         int i;
4952         struct ifconf ifc;
4953         int numifs;
4954
4955         s = socket(AF_INET, SOCK_DGRAM, 0);
4956         if (s == -1)
4957                 return;
4958
4959         /* get the list of known IP address from the kernel */
4960 #   if defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN
4961         if (ioctl(s, SIOCGIFNUM, (char *) &numifs) < 0)
4962         {
4963                 /* can't get number of interfaces -- fall back */
4964                 if (tTd(0, 4))
4965                         sm_dprintf("SIOCGIFNUM failed: %s\n",
4966                                    sm_errstring(errno));
4967                 numifs = -1;
4968         }
4969         else if (tTd(0, 42))
4970                 sm_dprintf("system has %d interfaces\n", numifs);
4971         if (numifs < 0)
4972 #   endif /* defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN */
4973                 numifs = MAXINTERFACES;
4974
4975         if (numifs <= 0)
4976         {
4977                 (void) close(s);
4978                 return;
4979         }
4980         ifc.ifc_len = numifs * sizeof(struct ifreq);
4981         ifc.ifc_buf = xalloc(ifc.ifc_len);
4982         if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0)
4983         {
4984                 if (tTd(0, 4))
4985                         sm_dprintf("SIOCGIFCONF failed: %s\n",
4986                                    sm_errstring(errno));
4987                 (void) close(s);
4988                 return;
4989         }
4990
4991         /* scan the list of IP address */
4992         if (tTd(0, 40))
4993                 sm_dprintf("scanning for interface specific names, ifc_len=%d\n",
4994                         ifc.ifc_len);
4995
4996         for (i = 0; i < ifc.ifc_len && i >= 0; )
4997         {
4998                 int af;
4999                 struct ifreq *ifr = (struct ifreq *) &ifc.ifc_buf[i];
5000                 SOCKADDR *sa = (SOCKADDR *) &ifr->ifr_addr;
5001 #   if NETINET6
5002                 char *addr;
5003                 struct in6_addr ia6;
5004 #   endif /* NETINET6 */
5005                 struct in_addr ia;
5006 #   ifdef SIOCGIFFLAGS
5007                 struct ifreq ifrf;
5008 #   endif /* SIOCGIFFLAGS */
5009                 char ip_addr[256];
5010 #   if NETINET6
5011                 char buf6[INET6_ADDRSTRLEN];
5012 #   endif /* NETINET6 */
5013
5014                 /*
5015                 **  If we don't have a complete ifr structure,
5016                 **  don't try to use it.
5017                 */
5018
5019                 if ((ifc.ifc_len - i) < sizeof(*ifr))
5020                         break;
5021
5022 #   ifdef BSD4_4_SOCKADDR
5023                 if (sa->sa.sa_len > sizeof(ifr->ifr_addr))
5024                         i += sizeof(ifr->ifr_name) + sa->sa.sa_len;
5025                 else
5026 #   endif /* BSD4_4_SOCKADDR */
5027                         i += sizeof(*ifr);
5028
5029                 if (tTd(0, 20))
5030                         sm_dprintf("%s\n", anynet_ntoa(sa));
5031
5032                 af = ifr->ifr_addr.sa_family;
5033                 if (af != AF_INET
5034 #   if NETINET6
5035                     && af != AF_INET6
5036 #   endif /* NETINET6 */
5037                     )
5038                         continue;
5039
5040 #   ifdef SIOCGIFFLAGS
5041                 memset(&ifrf, '\0', sizeof(struct ifreq));
5042                 (void) sm_strlcpy(ifrf.ifr_name, ifr->ifr_name,
5043                                sizeof(ifrf.ifr_name));
5044                 (void) ioctl(s, SIOCGIFFLAGS, (char *) &ifrf);
5045                 if (tTd(0, 41))
5046                         sm_dprintf("\tflags: %lx\n",
5047                                 (unsigned long) ifrf.ifr_flags);
5048 #    define IFRFREF ifrf
5049 #   else /* SIOCGIFFLAGS */
5050 #    define IFRFREF (*ifr)
5051 #   endif /* SIOCGIFFLAGS */
5052
5053                 if (!bitset(IFF_UP, IFRFREF.ifr_flags))
5054                         continue;
5055
5056                 ip_addr[0] = '\0';
5057
5058                 /* extract IP address from the list*/
5059                 switch (af)
5060                 {
5061                   case AF_INET:
5062                         ia = sa->sin.sin_addr;
5063                         if (ia.s_addr == INADDR_ANY ||
5064                             ia.s_addr == INADDR_NONE)
5065                         {
5066                                 message("WARNING: interface %s is UP with %s address",
5067                                         ifr->ifr_name, inet_ntoa(ia));
5068                                 continue;
5069                         }
5070
5071                         /* save IP address in text from */
5072                         (void) sm_snprintf(ip_addr, sizeof(ip_addr), "[%.*s]",
5073                                         (int) sizeof(ip_addr) - 3,
5074                                         inet_ntoa(ia));
5075                         break;
5076
5077 #   if NETINET6
5078                   case AF_INET6:
5079                         SETV6LOOPBACKADDRFOUND(*sa);
5080 #    ifdef __KAME__
5081                         /* convert into proper scoped address */
5082                         if ((IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr) ||
5083                              IN6_IS_ADDR_SITELOCAL(&sa->sin6.sin6_addr)) &&
5084                             sa->sin6.sin6_scope_id == 0)
5085                         {
5086                                 struct in6_addr *ia6p;
5087
5088                                 ia6p = &sa->sin6.sin6_addr;
5089                                 sa->sin6.sin6_scope_id = ntohs(ia6p->s6_addr[3] |
5090                                                                ((unsigned int)ia6p->s6_addr[2] << 8));
5091                                 ia6p->s6_addr[2] = ia6p->s6_addr[3] = 0;
5092                         }
5093 #    endif /* __KAME__ */
5094                         ia6 = sa->sin6.sin6_addr;
5095                         if (IN6_IS_ADDR_UNSPECIFIED(&ia6))
5096                         {
5097                                 addr = anynet_ntop(&ia6, buf6, sizeof(buf6));
5098                                 message("WARNING: interface %s is UP with %s address",
5099                                         ifr->ifr_name,
5100                                         addr == NULL ? "(NULL)" : addr);
5101                                 continue;
5102                         }
5103
5104                         /* save IP address in text from */
5105                         addr = anynet_ntop(&ia6, buf6, sizeof(buf6));
5106                         if (addr != NULL)
5107                                 (void) sm_snprintf(ip_addr, sizeof(ip_addr),
5108                                                    "[%.*s]",
5109                                                    (int) sizeof(ip_addr) - 3,
5110                                                    addr);
5111                         break;
5112
5113 #   endif /* NETINET6 */
5114                 }
5115
5116                 if (ip_addr[0] == '\0')
5117                         continue;
5118
5119                 if (!wordinclass(ip_addr, 'w'))
5120                 {
5121                         setclass('w', ip_addr);
5122                         if (tTd(0, 4))
5123                                 sm_dprintf("\ta.k.a.: %s\n", ip_addr);
5124                 }
5125
5126                 /* skip "loopback" interface "lo" */
5127                 if (DontProbeInterfaces == DPI_SKIPLOOPBACK &&
5128                     bitset(IFF_LOOPBACK, IFRFREF.ifr_flags))
5129                         continue;
5130
5131                 (void) add_hostnames(sa);
5132         }
5133         sm_free(ifc.ifc_buf); /* XXX */
5134         (void) close(s);
5135 #   undef IFRFREF
5136 #  endif /* defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN */
5137 # endif /* NETINET6 && defined(SIOCGLIFCONF) */
5138 }
5139 /*
5140 **  ISLOOPBACK -- is socket address in the loopback net?
5141 **
5142 **      Parameters:
5143 **              sa -- socket address.
5144 **
5145 **      Returns:
5146 **              true -- is socket address in the loopback net?
5147 **              false -- otherwise
5148 **
5149 */
5150
5151 bool
5152 isloopback(sa)
5153         SOCKADDR sa;
5154 {
5155 #if NETINET6
5156         if (IN6_IS_ADDR_LOOPBACK(&sa.sin6.sin6_addr))
5157                 return true;
5158 #else /* NETINET6 */
5159         /* XXX how to correctly extract IN_LOOPBACKNET part? */
5160         if (((ntohl(sa.sin.sin_addr.s_addr) & IN_CLASSA_NET)
5161              >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
5162                 return true;
5163 #endif /* NETINET6 */
5164         return false;
5165 }
5166 /*
5167 **  GET_NUM_PROCS_ONLINE -- return the number of processors currently online
5168 **
5169 **      Parameters:
5170 **              none.
5171 **
5172 **      Returns:
5173 **              The number of processors online.
5174 */
5175
5176 static int
5177 get_num_procs_online()
5178 {
5179         int nproc = 0;
5180
5181 #ifdef USESYSCTL
5182 # if defined(CTL_HW) && defined(HW_NCPU)
5183         size_t sz;
5184         int mib[2];
5185
5186         mib[0] = CTL_HW;
5187         mib[1] = HW_NCPU;
5188         sz = (size_t) sizeof(nproc);
5189         (void) sysctl(mib, 2, &nproc, &sz, NULL, 0);
5190 # endif /* defined(CTL_HW) && defined(HW_NCPU) */
5191 #else /* USESYSCTL */
5192 # ifdef _SC_NPROCESSORS_ONLN
5193         nproc = (int) sysconf(_SC_NPROCESSORS_ONLN);
5194 # else /* _SC_NPROCESSORS_ONLN */
5195 #  ifdef __hpux
5196 #   include <sys/pstat.h>
5197         struct pst_dynamic psd;
5198
5199         if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) != -1)
5200                 nproc = psd.psd_proc_cnt;
5201 #  endif /* __hpux */
5202 # endif /* _SC_NPROCESSORS_ONLN */
5203 #endif /* USESYSCTL */
5204
5205         if (nproc <= 0)
5206                 nproc = 1;
5207         return nproc;
5208 }
5209 /*
5210 **  SM_CLOSEFROM -- close file descriptors
5211 **
5212 **      Parameters:
5213 **              lowest -- first fd to close
5214 **              highest -- last fd + 1 to close
5215 **
5216 **      Returns:
5217 **              none
5218 */
5219
5220 void
5221 sm_closefrom(lowest, highest)
5222         int lowest, highest;
5223 {
5224 #if HASCLOSEFROM
5225         closefrom(lowest);
5226 #else /* HASCLOSEFROM */
5227         int i;
5228
5229         for (i = lowest; i < highest; i++)
5230                 (void) close(i);
5231 #endif /* HASCLOSEFROM */
5232 }
5233 #if HASFDWALK
5234 /*
5235 **  CLOSEFD_WALK -- walk fd's arranging to close them
5236 **      Callback for fdwalk()
5237 **
5238 **      Parameters:
5239 **              lowest -- first fd to arrange to be closed
5240 **              fd -- fd to arrange to be closed
5241 **
5242 **      Returns:
5243 **              zero
5244 */
5245
5246 static int
5247 closefd_walk(lowest, fd)
5248         void *lowest;
5249         int fd;
5250 {
5251         if (fd >= *(int *)lowest)
5252                 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
5253         return 0;
5254 }
5255 #endif /* HASFDWALK */
5256 /*
5257 **  SM_CLOSE_ON_EXEC -- arrange for file descriptors to be closed
5258 **
5259 **      Parameters:
5260 **              lowest -- first fd to arrange to be closed
5261 **              highest -- last fd + 1 to arrange to be closed
5262 **
5263 **      Returns:
5264 **              none
5265 */
5266
5267 void
5268 sm_close_on_exec(lowest, highest)
5269         int lowest, highest;
5270 {
5271 #if HASFDWALK
5272         (void) fdwalk(closefd_walk, &lowest);
5273 #else /* HASFDWALK */
5274         int i, j;
5275
5276         for (i = lowest; i < highest; i++)
5277         {
5278                 if ((j = fcntl(i, F_GETFD, 0)) != -1)
5279                         (void) fcntl(i, F_SETFD, j | FD_CLOEXEC);
5280         }
5281 #endif /* HASFDWALK */
5282 }
5283 /*
5284 **  SEED_RANDOM -- seed the random number generator
5285 **
5286 **      Parameters:
5287 **              none
5288 **
5289 **      Returns:
5290 **              none
5291 */
5292
5293 void
5294 seed_random()
5295 {
5296 #if HASSRANDOMDEV
5297         srandomdev();
5298 #else /* HASSRANDOMDEV */
5299         long seed;
5300         struct timeval t;
5301
5302         seed = (long) CurrentPid;
5303         if (gettimeofday(&t, NULL) >= 0)
5304                 seed += t.tv_sec + t.tv_usec;
5305
5306 # if HASRANDOM
5307         (void) srandom(seed);
5308 # else /* HASRANDOM */
5309         (void) srand((unsigned int) seed);
5310 # endif /* HASRANDOM */
5311 #endif /* HASSRANDOMDEV */
5312 }
5313 /*
5314 **  SM_SYSLOG -- syslog wrapper to keep messages under SYSLOG_BUFSIZE
5315 **
5316 **      Parameters:
5317 **              level -- syslog level
5318 **              id -- envelope ID or NULL (NOQUEUE)
5319 **              fmt -- format string
5320 **              arg... -- arguments as implied by fmt.
5321 **
5322 **      Returns:
5323 **              none
5324 */
5325
5326 /* VARARGS3 */
5327 void
5328 #ifdef __STDC__
5329 sm_syslog(int level, const char *id, const char *fmt, ...)
5330 #else /* __STDC__ */
5331 sm_syslog(level, id, fmt, va_alist)
5332         int level;
5333         const char *id;
5334         const char *fmt;
5335         va_dcl
5336 #endif /* __STDC__ */
5337 {
5338         char *buf;
5339         size_t bufsize;
5340         char *begin, *end;
5341         int save_errno;
5342         int seq = 1;
5343         int idlen;
5344         char buf0[MAXLINE];
5345         char *newstring;
5346         extern int SyslogPrefixLen;
5347         SM_VA_LOCAL_DECL
5348
5349         save_errno = errno;
5350         if (id == NULL)
5351                 id = "NOQUEUE";
5352         idlen = strlen(id) + SyslogPrefixLen;
5353
5354         buf = buf0;
5355         bufsize = sizeof(buf0);
5356
5357         for (;;)
5358         {
5359                 int n;
5360
5361                 /* print log message into buf */
5362                 SM_VA_START(ap, fmt);
5363                 n = sm_vsnprintf(buf, bufsize, fmt, ap);
5364                 SM_VA_END(ap);
5365                 SM_ASSERT(n > 0);
5366                 if (n < bufsize)
5367                         break;
5368
5369                 /* String too small, redo with correct size */
5370                 bufsize = n + 1;
5371                 if (buf != buf0)
5372                 {
5373                         sm_free(buf);
5374                         buf = NULL;
5375                 }
5376                 buf = sm_malloc_x(bufsize);
5377         }
5378
5379         /* clean up buf after it has been expanded with args */
5380         newstring = str2prt(buf);
5381         if ((strlen(newstring) + idlen + 1) < SYSLOG_BUFSIZE)
5382         {
5383 #if LOG
5384                 if (*id == '\0')
5385                 {
5386                         if (tTd(89, 10))
5387                         {
5388                                 struct timeval tv;
5389
5390                                 gettimeofday(&tv, NULL);
5391                                 sm_dprintf("%ld.%06ld %s\n", (long) tv.tv_sec,
5392                                         (long) tv.tv_usec, newstring);
5393                         }
5394                         else if (tTd(89, 8))
5395                                 sm_dprintf("%s\n", newstring);
5396                         else
5397                                 syslog(level, "%s", newstring);
5398                 }
5399                 else
5400                 {
5401                         if (tTd(89, 10))
5402                         {
5403                                 struct timeval tv;
5404
5405                                 gettimeofday(&tv, NULL);
5406                                 sm_dprintf("%ld.%06ld %s: %s\n", (long) tv.tv_sec,
5407                                         (long) tv.tv_usec, id, newstring);
5408                         }
5409                         else if (tTd(89, 8))
5410                                 sm_dprintf("%s: %s\n", id, newstring);
5411                         else
5412                                 syslog(level, "%s: %s", id, newstring);
5413                 }
5414 #else /* LOG */
5415                 /*XXX should do something more sensible */
5416                 if (*id == '\0')
5417                         (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s\n",
5418                                              newstring);
5419                 else
5420                         (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
5421                                              "%s: %s\n", id, newstring);
5422 #endif /* LOG */
5423                 if (buf != buf0)
5424                         sm_free(buf);
5425                 errno = save_errno;
5426                 return;
5427         }
5428
5429 /*
5430 **  additional length for splitting: " ..." + 3, where 3 is magic to
5431 **  have some data for the next entry.
5432 */
5433
5434 #define SL_SPLIT 7
5435
5436         begin = newstring;
5437         idlen += 5;     /* strlen("[999]"), see below */
5438         while (*begin != '\0' &&
5439                (strlen(begin) + idlen) > SYSLOG_BUFSIZE)
5440         {
5441                 char save;
5442
5443                 if (seq >= 999)
5444                 {
5445                         /* Too many messages */
5446                         break;
5447                 }
5448                 end = begin + SYSLOG_BUFSIZE - idlen - SL_SPLIT;
5449                 while (end > begin)
5450                 {
5451                         /* Break on comma or space */
5452                         if (*end == ',' || *end == ' ')
5453                         {
5454                                 end++;    /* Include separator */
5455                                 break;
5456                         }
5457                         end--;
5458                 }
5459                 /* No separator, break midstring... */
5460                 if (end == begin)
5461                         end = begin + SYSLOG_BUFSIZE - idlen - SL_SPLIT;
5462                 save = *end;
5463                 *end = 0;
5464 #if LOG
5465                 if (tTd(89, 8))
5466                         sm_dprintf("%s[%d]: %s ...\n", id, seq++, begin);
5467                 else
5468                         syslog(level, "%s[%d]: %s ...", id, seq++, begin);
5469 #else /* LOG */
5470                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
5471                                      "%s[%d]: %s ...\n", id, seq++, begin);
5472 #endif /* LOG */
5473                 *end = save;
5474                 begin = end;
5475         }
5476         if (seq >= 999)
5477         {
5478 #if LOG
5479                 if (tTd(89, 8))
5480                         sm_dprintf("%s[%d]: log terminated, too many parts\n",
5481                                 id, seq);
5482                 else
5483                         syslog(level, "%s[%d]: log terminated, too many parts",
5484                                 id, seq);
5485 #else /* LOG */
5486                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
5487                               "%s[%d]: log terminated, too many parts\n", id, seq);
5488 #endif /* LOG */
5489         }
5490         else if (*begin != '\0')
5491         {
5492 #if LOG
5493                 if (tTd(89, 8))
5494                         sm_dprintf("%s[%d]: %s\n", id, seq, begin);
5495                 else
5496                         syslog(level, "%s[%d]: %s", id, seq, begin);
5497 #else /* LOG */
5498                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
5499                                      "%s[%d]: %s\n", id, seq, begin);
5500 #endif /* LOG */
5501         }
5502         if (buf != buf0)
5503                 sm_free(buf);
5504         errno = save_errno;
5505 }
5506 /*
5507 **  HARD_SYSLOG -- call syslog repeatedly until it works
5508 **
5509 **      Needed on HP-UX, which apparently doesn't guarantee that
5510 **      syslog succeeds during interrupt handlers.
5511 */
5512
5513 #if defined(__hpux) && !defined(HPUX11)
5514
5515 # define MAXSYSLOGTRIES 100
5516 # undef syslog
5517 # ifdef V4FS
5518 #  define XCNST const
5519 #  define CAST  (const char *)
5520 # else /* V4FS */
5521 #  define XCNST
5522 #  define CAST
5523 # endif /* V4FS */
5524
5525 void
5526 # ifdef __STDC__
5527 hard_syslog(int pri, XCNST char *msg, ...)
5528 # else /* __STDC__ */
5529 hard_syslog(pri, msg, va_alist)
5530         int pri;
5531         XCNST char *msg;
5532         va_dcl
5533 # endif /* __STDC__ */
5534 {
5535         int i;
5536         char buf[SYSLOG_BUFSIZE];
5537         SM_VA_LOCAL_DECL
5538
5539         SM_VA_START(ap, msg);
5540         (void) sm_vsnprintf(buf, sizeof(buf), msg, ap);
5541         SM_VA_END(ap);
5542
5543         for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, CAST "%s", buf) < 0; )
5544                 continue;
5545 }
5546
5547 # undef CAST
5548 #endif /* defined(__hpux) && !defined(HPUX11) */
5549 #if NEEDLOCAL_HOSTNAME_LENGTH
5550 /*
5551 **  LOCAL_HOSTNAME_LENGTH
5552 **
5553 **      This is required to get sendmail to compile against BIND 4.9.x
5554 **      on Ultrix.
5555 **
5556 **      Unfortunately, a Compaq Y2K patch kit provides it without
5557 **      bumping __RES in /usr/include/resolv.h so we can't automatically
5558 **      figure out whether it is needed.
5559 */
5560
5561 int
5562 local_hostname_length(hostname)
5563         char *hostname;
5564 {
5565         size_t len_host, len_domain;
5566
5567         if (!*_res.defdname)
5568                 res_init();
5569         len_host = strlen(hostname);
5570         len_domain = strlen(_res.defdname);
5571         if (len_host > len_domain &&
5572             (sm_strcasecmp(hostname + len_host - len_domain,
5573                         _res.defdname) == 0) &&
5574             hostname[len_host - len_domain - 1] == '.')
5575                 return len_host - len_domain - 1;
5576         else
5577                 return 0;
5578 }
5579 #endif /* NEEDLOCAL_HOSTNAME_LENGTH */
5580
5581 #if NEEDLINK
5582 /*
5583 **  LINK -- clone a file
5584 **
5585 **      Some OS's lacks link() and hard links.  Since sendmail is using
5586 **      link() as an efficient way to clone files, this implementation
5587 **      will simply do a file copy.
5588 **
5589 **      NOTE: This link() replacement is not a generic replacement as it
5590 **      does not handle all of the semantics of the real link(2).
5591 **
5592 **      Parameters:
5593 **              source -- pathname of existing file.
5594 **              target -- pathname of link (clone) to be created.
5595 **
5596 **      Returns:
5597 **              0 -- success.
5598 **              -1 -- failure, see errno for details.
5599 */
5600
5601 int
5602 link(source, target)
5603         const char *source;
5604         const char *target;
5605 {
5606         int save_errno;
5607         int sff;
5608         int src = -1, dst = -1;
5609         ssize_t readlen;
5610         ssize_t writelen;
5611         char buf[BUFSIZ];
5612         struct stat st;
5613
5614         sff = SFF_REGONLY|SFF_OPENASROOT;
5615         if (DontLockReadFiles)
5616                 sff |= SFF_NOLOCK;
5617
5618         /* Open the original file */
5619         src = safeopen((char *)source, O_RDONLY, 0, sff);
5620         if (src < 0)
5621                 goto fail;
5622
5623         /* Obtain the size and the mode */
5624         if (fstat(src, &st) < 0)
5625                 goto fail;
5626
5627         /* Create the duplicate copy */
5628         sff &= ~SFF_NOLOCK;
5629         sff |= SFF_CREAT;
5630         dst = safeopen((char *)target, O_CREAT|O_EXCL|O_WRONLY,
5631                        st.st_mode, sff);
5632         if (dst < 0)
5633                 goto fail;
5634
5635         /* Copy all of the bytes one buffer at a time */
5636         while ((readlen = read(src, &buf, sizeof(buf))) > 0)
5637         {
5638                 ssize_t left = readlen;
5639                 char *p = buf;
5640
5641                 while (left > 0 &&
5642                        (writelen = write(dst, p, (size_t) left)) >= 0)
5643                 {
5644                         left -= writelen;
5645                         p += writelen;
5646                 }
5647                 if (writelen < 0)
5648                         break;
5649         }
5650
5651         /* Any trouble reading? */
5652         if (readlen < 0 || writelen < 0)
5653                 goto fail;
5654
5655         /* Close the input file */
5656         if (close(src) < 0)
5657         {
5658                 src = -1;
5659                 goto fail;
5660         }
5661         src = -1;
5662
5663         /* Close the output file */
5664         if (close(dst) < 0)
5665         {
5666                 /* don't set dst = -1 here so we unlink the file */
5667                 goto fail;
5668         }
5669
5670         /* Success */
5671         return 0;
5672
5673  fail:
5674         save_errno = errno;
5675         if (src >= 0)
5676                 (void) close(src);
5677         if (dst >= 0)
5678         {
5679                 (void) unlink(target);
5680                 (void) close(dst);
5681         }
5682         errno = save_errno;
5683         return -1;
5684 }
5685 #endif /* NEEDLINK */
5686
5687 /*
5688 **  Compile-Time options
5689 */
5690
5691 char    *CompileOptions[] =
5692 {
5693 #if ALLOW_255
5694         "ALLOW_255",
5695 #endif /* ALLOW_255 */
5696 #if NAMED_BIND
5697 # if DNSMAP
5698         "DNSMAP",
5699 # endif /* DNSMAP */
5700 #endif /* NAMED_BIND */
5701 #if EGD
5702         "EGD",
5703 #endif /* EGD */
5704 #if HESIOD
5705         "HESIOD",
5706 #endif /* HESIOD */
5707 #if HES_GETMAILHOST
5708         "HES_GETMAILHOST",
5709 #endif /* HES_GETMAILHOST */
5710 #if LDAPMAP
5711         "LDAPMAP",
5712 #endif /* LDAPMAP */
5713 #if LDAP_REFERRALS
5714         "LDAP_REFERRALS",
5715 #endif /* LDAP_REFERRALS */
5716 #if LOG
5717         "LOG",
5718 #endif /* LOG */
5719 #if MAP_NSD
5720         "MAP_NSD",
5721 #endif /* MAP_NSD */
5722 #if MAP_REGEX
5723         "MAP_REGEX",
5724 #endif /* MAP_REGEX */
5725 #if MATCHGECOS
5726         "MATCHGECOS",
5727 #endif /* MATCHGECOS */
5728 #if MILTER
5729         "MILTER",
5730 #endif /* MILTER */
5731 #if MIME7TO8
5732         "MIME7TO8",
5733 #endif /* MIME7TO8 */
5734 #if MIME7TO8_OLD
5735         "MIME7TO8_OLD",
5736 #endif /* MIME7TO8_OLD */
5737 #if MIME8TO7
5738         "MIME8TO7",
5739 #endif /* MIME8TO7 */
5740 #if NAMED_BIND
5741         "NAMED_BIND",
5742 #endif /* NAMED_BIND */
5743 #if NDBM
5744         "NDBM",
5745 #endif /* NDBM */
5746 #if NETINET
5747         "NETINET",
5748 #endif /* NETINET */
5749 #if NETINET6
5750         "NETINET6",
5751 #endif /* NETINET6 */
5752 #if NETINFO
5753         "NETINFO",
5754 #endif /* NETINFO */
5755 #if NETISO
5756         "NETISO",
5757 #endif /* NETISO */
5758 #if NETNS
5759         "NETNS",
5760 #endif /* NETNS */
5761 #if NETUNIX
5762         "NETUNIX",
5763 #endif /* NETUNIX */
5764 #if NETX25
5765         "NETX25",
5766 #endif /* NETX25 */
5767 #if NEWDB
5768         "NEWDB",
5769 #endif /* NEWDB */
5770 #if NIS
5771         "NIS",
5772 #endif /* NIS */
5773 #if NISPLUS
5774         "NISPLUS",
5775 #endif /* NISPLUS */
5776 #if NO_DH
5777         "NO_DH",
5778 #endif /* NO_DH */
5779 #if PH_MAP
5780         "PH_MAP",
5781 #endif /* PH_MAP */
5782 #ifdef PICKY_HELO_CHECK
5783         "PICKY_HELO_CHECK",
5784 #endif /* PICKY_HELO_CHECK */
5785 #if PIPELINING
5786         "PIPELINING",
5787 #endif /* PIPELINING */
5788 #if SASL
5789 # if SASL >= 20000
5790         "SASLv2",
5791 # else /* SASL >= 20000 */
5792         "SASL",
5793 # endif /* SASL >= 20000 */
5794 #endif /* SASL */
5795 #if SCANF
5796         "SCANF",
5797 #endif /* SCANF */
5798 #if SM_LDAP_ERROR_ON_MISSING_ARGS
5799         "SM_LDAP_ERROR_ON_MISSING_ARGS",
5800 #endif /* SM_LDAP_ERROR_ON_MISSING_ARGS */
5801 #if SMTPDEBUG
5802         "SMTPDEBUG",
5803 #endif /* SMTPDEBUG */
5804 #if SOCKETMAP
5805         "SOCKETMAP",
5806 #endif /* SOCKETMAP */
5807 #if STARTTLS
5808         "STARTTLS",
5809 #endif /* STARTTLS */
5810 #if SUID_ROOT_FILES_OK
5811         "SUID_ROOT_FILES_OK",
5812 #endif /* SUID_ROOT_FILES_OK */
5813 #if TCPWRAPPERS
5814         "TCPWRAPPERS",
5815 #endif /* TCPWRAPPERS */
5816 #if TLS_NO_RSA
5817         "TLS_NO_RSA",
5818 #endif /* TLS_NO_RSA */
5819 #if TLS_VRFY_PER_CTX
5820         "TLS_VRFY_PER_CTX",
5821 #endif /* TLS_VRFY_PER_CTX */
5822 #if USERDB
5823         "USERDB",
5824 #endif /* USERDB */
5825 #if USE_LDAP_INIT
5826         "USE_LDAP_INIT",
5827 #endif /* USE_LDAP_INIT */
5828 #if USE_TTYPATH
5829         "USE_TTYPATH",
5830 #endif /* USE_TTYPATH */
5831 #if XDEBUG
5832         "XDEBUG",
5833 #endif /* XDEBUG */
5834 #if XLA
5835         "XLA",
5836 #endif /* XLA */
5837         NULL
5838 };
5839
5840
5841 /*
5842 **  OS compile options.
5843 */
5844
5845 char    *OsCompileOptions[] =
5846 {
5847 #if ADDRCONFIG_IS_BROKEN
5848         "ADDRCONFIG_IS_BROKEN",
5849 #endif /* ADDRCONFIG_IS_BROKEN */
5850 #ifdef AUTO_NETINFO_HOSTS
5851         "AUTO_NETINFO_HOSTS",
5852 #endif /* AUTO_NETINFO_HOSTS */
5853 #ifdef AUTO_NIS_ALIASES
5854         "AUTO_NIS_ALIASES",
5855 #endif /* AUTO_NIS_ALIASES */
5856 #if BROKEN_RES_SEARCH
5857         "BROKEN_RES_SEARCH",
5858 #endif /* BROKEN_RES_SEARCH */
5859 #ifdef BSD4_4_SOCKADDR
5860         "BSD4_4_SOCKADDR",
5861 #endif /* BSD4_4_SOCKADDR */
5862 #if BOGUS_O_EXCL
5863         "BOGUS_O_EXCL",
5864 #endif /* BOGUS_O_EXCL */
5865 #if DEC_OSF_BROKEN_GETPWENT
5866         "DEC_OSF_BROKEN_GETPWENT",
5867 #endif /* DEC_OSF_BROKEN_GETPWENT */
5868 #if FAST_PID_RECYCLE
5869         "FAST_PID_RECYCLE",
5870 #endif /* FAST_PID_RECYCLE */
5871 #if HASCLOSEFROM
5872         "HASCLOSEFROM",
5873 #endif /* HASCLOSEFROM */
5874 #if HASFCHOWN
5875         "HASFCHOWN",
5876 #endif /* HASFCHOWN */
5877 #if HASFCHMOD
5878         "HASFCHMOD",
5879 #endif /* HASFCHMOD */
5880 #if HASFDWALK
5881         "HASFDWALK",
5882 #endif /* HASFDWALK */
5883 #if HASFLOCK
5884         "HASFLOCK",
5885 #endif /* HASFLOCK */
5886 #if HASGETDTABLESIZE
5887         "HASGETDTABLESIZE",
5888 #endif /* HASGETDTABLESIZE */
5889 #if HASGETUSERSHELL
5890         "HASGETUSERSHELL",
5891 #endif /* HASGETUSERSHELL */
5892 #if HASINITGROUPS
5893         "HASINITGROUPS",
5894 #endif /* HASINITGROUPS */
5895 #if HASLDAPGETALIASBYNAME
5896         "HASLDAPGETALIASBYNAME",
5897 #endif /* HASLDAPGETALIASBYNAME */
5898 #if HASLSTAT
5899         "HASLSTAT",
5900 #endif /* HASLSTAT */
5901 #if HASNICE
5902         "HASNICE",
5903 #endif /* HASNICE */
5904 #if HASRANDOM
5905         "HASRANDOM",
5906 #endif /* HASRANDOM */
5907 #if HASRRESVPORT
5908         "HASRRESVPORT",
5909 #endif /* HASRRESVPORT */
5910 #if HASSETEGID
5911         "HASSETEGID",
5912 #endif /* HASSETEGID */
5913 #if HASSETLOGIN
5914         "HASSETLOGIN",
5915 #endif /* HASSETLOGIN */
5916 #if HASSETREGID
5917         "HASSETREGID",
5918 #endif /* HASSETREGID */
5919 #if HASSETRESGID
5920         "HASSETRESGID",
5921 #endif /* HASSETRESGID */
5922 #if HASSETREUID
5923         "HASSETREUID",
5924 #endif /* HASSETREUID */
5925 #if HASSETRLIMIT
5926         "HASSETRLIMIT",
5927 #endif /* HASSETRLIMIT */
5928 #if HASSETSID
5929         "HASSETSID",
5930 #endif /* HASSETSID */
5931 #if HASSETUSERCONTEXT
5932         "HASSETUSERCONTEXT",
5933 #endif /* HASSETUSERCONTEXT */
5934 #if HASSETVBUF
5935         "HASSETVBUF",
5936 #endif /* HASSETVBUF */
5937 #if HAS_ST_GEN
5938         "HAS_ST_GEN",
5939 #endif /* HAS_ST_GEN */
5940 #if HASSRANDOMDEV
5941         "HASSRANDOMDEV",
5942 #endif /* HASSRANDOMDEV */
5943 #if HASURANDOMDEV
5944         "HASURANDOMDEV",
5945 #endif /* HASURANDOMDEV */
5946 #if HASSTRERROR
5947         "HASSTRERROR",
5948 #endif /* HASSTRERROR */
5949 #if HASULIMIT
5950         "HASULIMIT",
5951 #endif /* HASULIMIT */
5952 #if HASUNAME
5953         "HASUNAME",
5954 #endif /* HASUNAME */
5955 #if HASUNSETENV
5956         "HASUNSETENV",
5957 #endif /* HASUNSETENV */
5958 #if HASWAITPID
5959         "HASWAITPID",
5960 #endif /* HASWAITPID */
5961 #if HAVE_NANOSLEEP
5962         "HAVE_NANOSLEEP",
5963 #endif /* HAVE_NANOSLEEP */
5964 #if IDENTPROTO
5965         "IDENTPROTO",
5966 #endif /* IDENTPROTO */
5967 #if IP_SRCROUTE
5968         "IP_SRCROUTE",
5969 #endif /* IP_SRCROUTE */
5970 #if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
5971         "LOCK_ON_OPEN",
5972 #endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
5973 #if MILTER_NO_NAGLE
5974         "MILTER_NO_NAGLE ",
5975 #endif /* MILTER_NO_NAGLE */
5976 #if NEEDFSYNC
5977         "NEEDFSYNC",
5978 #endif /* NEEDFSYNC */
5979 #if NEEDLINK
5980         "NEEDLINK",
5981 #endif /* NEEDLINK */
5982 #if NEEDLOCAL_HOSTNAME_LENGTH
5983         "NEEDLOCAL_HOSTNAME_LENGTH",
5984 #endif /* NEEDLOCAL_HOSTNAME_LENGTH */
5985 #if NEEDSGETIPNODE
5986         "NEEDSGETIPNODE",
5987 #endif /* NEEDSGETIPNODE */
5988 #if NEEDSTRSTR
5989         "NEEDSTRSTR",
5990 #endif /* NEEDSTRSTR */
5991 #if NEEDSTRTOL
5992         "NEEDSTRTOL",
5993 #endif /* NEEDSTRTOL */
5994 #ifdef NO_GETSERVBYNAME
5995         "NO_GETSERVBYNAME",
5996 #endif /* NO_GETSERVBYNAME */
5997 #if NOFTRUNCATE
5998         "NOFTRUNCATE",
5999 #endif /* NOFTRUNCATE */
6000 #if REQUIRES_DIR_FSYNC
6001         "REQUIRES_DIR_FSYNC",
6002 #endif /* REQUIRES_DIR_FSYNC */
6003 #if RLIMIT_NEEDS_SYS_TIME_H
6004         "RLIMIT_NEEDS_SYS_TIME_H",
6005 #endif /* RLIMIT_NEEDS_SYS_TIME_H */
6006 #if SAFENFSPATHCONF
6007         "SAFENFSPATHCONF",
6008 #endif /* SAFENFSPATHCONF */
6009 #if SECUREWARE
6010         "SECUREWARE",
6011 #endif /* SECUREWARE */
6012 #if SFS_TYPE == SFS_4ARGS
6013         "SFS_4ARGS",
6014 #elif SFS_TYPE == SFS_MOUNT
6015         "SFS_MOUNT",
6016 #elif SFS_TYPE == SFS_NONE
6017         "SFS_NONE",
6018 #elif SFS_TYPE == SFS_NT
6019         "SFS_NT",
6020 #elif SFS_TYPE == SFS_STATFS
6021         "SFS_STATFS",
6022 #elif SFS_TYPE == SFS_STATVFS
6023         "SFS_STATVFS",
6024 #elif SFS_TYPE == SFS_USTAT
6025         "SFS_USTAT",
6026 #elif SFS_TYPE == SFS_VFS
6027         "SFS_VFS",
6028 #endif
6029 #if SHARE_V1
6030         "SHARE_V1",
6031 #endif /* SHARE_V1 */
6032 #if SIOCGIFCONF_IS_BROKEN
6033         "SIOCGIFCONF_IS_BROKEN",
6034 #endif /* SIOCGIFCONF_IS_BROKEN */
6035 #if SIOCGIFNUM_IS_BROKEN
6036         "SIOCGIFNUM_IS_BROKEN",
6037 #endif /* SIOCGIFNUM_IS_BROKEN */
6038 #if SNPRINTF_IS_BROKEN
6039         "SNPRINTF_IS_BROKEN",
6040 #endif /* SNPRINTF_IS_BROKEN */
6041 #if SO_REUSEADDR_IS_BROKEN
6042         "SO_REUSEADDR_IS_BROKEN",
6043 #endif /* SO_REUSEADDR_IS_BROKEN */
6044 #if SYS5SETPGRP
6045         "SYS5SETPGRP",
6046 #endif /* SYS5SETPGRP */
6047 #if SYSTEM5
6048         "SYSTEM5",
6049 #endif /* SYSTEM5 */
6050 #if USE_DOUBLE_FORK
6051         "USE_DOUBLE_FORK",
6052 #endif /* USE_DOUBLE_FORK */
6053 #if USE_ENVIRON
6054         "USE_ENVIRON",
6055 #endif /* USE_ENVIRON */
6056 #if USE_SA_SIGACTION
6057         "USE_SA_SIGACTION",
6058 #endif /* USE_SA_SIGACTION */
6059 #if USE_SIGLONGJMP
6060         "USE_SIGLONGJMP",
6061 #endif /* USE_SIGLONGJMP */
6062 #if USEGETCONFATTR
6063         "USEGETCONFATTR",
6064 #endif /* USEGETCONFATTR */
6065 #if USESETEUID
6066         "USESETEUID",
6067 #endif /* USESETEUID */
6068 #ifdef USESYSCTL
6069         "USESYSCTL",
6070 #endif /* USESYSCTL */
6071 #if USE_OPENSSL_ENGINE
6072         "USE_OPENSSL_ENGINE",
6073 #endif /* USE_OPENSSL_ENGINE */
6074 #if USING_NETSCAPE_LDAP
6075         "USING_NETSCAPE_LDAP",
6076 #endif /* USING_NETSCAPE_LDAP */
6077 #ifdef WAITUNION
6078         "WAITUNION",
6079 #endif /* WAITUNION */
6080         NULL
6081 };
6082
6083 /*
6084 **  FFR compile options.
6085 */
6086
6087 char    *FFRCompileOptions[] =
6088 {
6089 #if _FFR_ADDR_TYPE_MODES
6090         /* more info in {addr_type}, requires m4 changes! */
6091         "_FFR_ADDR_TYPE_MODES",
6092 #endif /* _FFR_ADDR_TYPE_MODES */
6093 #if _FFR_ALLOW_SASLINFO
6094         /* DefaultAuthInfo can be specified by user. */
6095         /* DefaultAuthInfo doesn't really work in 8.13 anymore. */
6096         "_FFR_ALLOW_SASLINFO",
6097 #endif /* _FFR_ALLOW_SASLINFO */
6098 #if _FFR_BADRCPT_SHUTDOWN
6099         /* shut down connection (421) if there are too many bad RCPTs */
6100         "_FFR_BADRCPT_SHUTDOWN",
6101 #endif /* _FFR_BADRCPT_SHUTDOWN */
6102 #if _FFR_BESTMX_BETTER_TRUNCATION
6103         /* Better truncation of list of MX records for dns map. */
6104         "_FFR_BESTMX_BETTER_TRUNCATION",
6105 #endif /* _FFR_BESTMX_BETTER_TRUNCATION */
6106 #if _FFR_CATCH_BROKEN_MTAS
6107         /* Deal with MTAs that send a reply during the DATA phase. */
6108         "_FFR_CATCH_BROKEN_MTAS",
6109 #endif /* _FFR_CATCH_BROKEN_MTAS */
6110 #if _FFR_CHECKCONFIG
6111         /* New OpMode to check the configuration file */
6112         "_FFR_CHECKCONFIG",
6113 #endif /* _FFR_CHECKCONFIG */
6114 #if _FFR_CHK_QUEUE
6115         /* Stricter checks about queue directory permissions. */
6116         "_FFR_CHK_QUEUE",
6117 #endif /* _FFR_CHK_QUEUE */
6118 #if _FFR_CLIENT_SIZE
6119         /* Don't try to send mail if its size exceeds SIZE= of server. */
6120         "_FFR_CLIENT_SIZE",
6121 #endif /* _FFR_CLIENT_SIZE */
6122 #if _FFR_CRLPATH
6123         /* CRLPath; needs documentation; Al Smith */
6124         "_FFR_CRLPATH",
6125 #endif /* _FFR_CRLPATH */
6126 #if _FFR_DAEMON_NETUNIX
6127         /* Allow local (not just TCP) socket connection to server. */
6128         "_FFR_DAEMON_NETUNIX",
6129 #endif /* _FFR_DAEMON_NETUNIX */
6130 #if _FFR_DEPRECATE_MAILER_FLAG_I
6131         /* What it says :-) */
6132         "_FFR_DEPRECATE_MAILER_FLAG_I",
6133 #endif /* _FFR_DEPRECATE_MAILER_FLAG_I */
6134 #if _FFR_DM_ONE
6135         /* deliver first TA in background, then queue */
6136         "_FFR_DM_ONE",
6137 #endif /* _FFR_DM_ONE */
6138 #if _FFR_DIGUNIX_SAFECHOWN
6139         /* Properly set SAFECHOWN (include/sm/conf.h) for Digital UNIX */
6140 /* Problem noted by Anne Bennett of Concordia University */
6141         "_FFR_DIGUNIX_SAFECHOWN",
6142 #endif /* _FFR_DIGUNIX_SAFECHOWN */
6143 #if _FFR_DNSMAP_ALIASABLE
6144         /* Allow dns map type to be used for aliases. */
6145 /* Don Lewis of TDK */
6146         "_FFR_DNSMAP_ALIASABLE",
6147 #endif /* _FFR_DNSMAP_ALIASABLE */
6148 #if _FFR_DONTLOCKFILESFORREAD_OPTION
6149         /* Enable DontLockFilesForRead option. */
6150         "_FFR_DONTLOCKFILESFORREAD_OPTION",
6151 #endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */
6152 #if _FFR_DOTTED_USERNAMES
6153         /* Allow usernames with '.' */
6154         "_FFR_DOTTED_USERNAMES",
6155 #endif /* _FFR_DOTTED_USERNAMES */
6156 #if _FFR_DPO_CS
6157         /*
6158         **  Make DaemonPortOptions case sensitive.
6159         **  For some unknown reasons the code converted every option
6160         **  to uppercase (first letter only, as that's the only one that
6161         **  is actually checked). This prevented all new lower case options
6162         **  from working...
6163         **  The documentation doesn't say anything about case (in)sensitivity,
6164         **  which means it should be case sensitive by default,
6165         **  but it's not a good idea to change this within a patch release,
6166         **  so let's delay this to 8.15.
6167         */
6168
6169         "_FFR_DPO_CS",
6170 #endif /* _FFR_DPO_CS */
6171 #if _FFR_DPRINTF_MAP
6172         /* dprintf map for logging */
6173         "_FFR_DPRINTF_MAP",
6174 #endif /* _FFR_DPRINTF_MAP */
6175 #if _FFR_DROP_TRUSTUSER_WARNING
6176         /*
6177         **  Don't issue this warning:
6178         **  "readcf: option TrustedUser may cause problems on systems
6179         **  which do not support fchown() if UseMSP is not set.
6180         */
6181
6182         "_FFR_DROP_TRUSTUSER_WARNING",
6183 #endif /* _FFR_DROP_TRUSTUSER_WARNING */
6184 #if _FFR_EIGHT_BIT_ADDR_OK
6185         /* EightBitAddrOK: allow 8-bit e-mail addresses */
6186         "_FFR_EIGHT_BIT_ADDR_OK",
6187 #endif /* _FFR_EIGHT_BIT_ADDR_OK */
6188 #if _FFR_EXPDELAY
6189         /* exponential queue delay */
6190         "_FFR_EXPDELAY",
6191 #endif /* _FFR_EXPDELAY */
6192 #if _FFR_EXTRA_MAP_CHECK
6193         /* perform extra checks on $( $) in R lines */
6194         "_FFR_EXTRA_MAP_CHECK",
6195 #endif /* _FFR_EXTRA_MAP_CHECK */
6196 #if _FFR_GETHBN_ExFILE
6197         /*
6198         **  According to Motonori Nakamura some gethostbyname()
6199         **  implementations (TurboLinux?) may (temporarily) fail
6200         **  due to a lack of file discriptors. Enabling this FFR
6201         **  will check errno for EMFILE and ENFILE and in case of a match
6202         **  cause a temporary error instead of a permanent error.
6203         **  The right solution is of course to file a bug against those
6204         **  systems such that they actually set h_errno = TRY_AGAIN.
6205         */
6206
6207         "_FFR_GETHBN_ExFILE",
6208 #endif /* _FFR_GETHBN_ExFILE */
6209 #if _FFR_FIPSMODE
6210         /* FIPSMode (if supported by OpenSSL library) */
6211         "_FFR_FIPSMODE",
6212 #endif /* _FFR_FIPSMODE */
6213 #if _FFR_FIX_DASHT
6214         /*
6215         **  If using -t, force not sending to argv recipients, even
6216         **  if they are mentioned in the headers.
6217         */
6218
6219         "_FFR_FIX_DASHT",
6220 #endif /* _FFR_FIX_DASHT */
6221 #if _FFR_FORWARD_SYSERR
6222         /* Cause a "syserr" if forward file isn't "safe". */
6223         "_FFR_FORWARD_SYSERR",
6224 #endif /* _FFR_FORWARD_SYSERR */
6225 #if _FFR_GEN_ORCPT
6226         /* Generate a ORCPT DSN arg if not already provided */
6227         "_FFR_GEN_ORCPT",
6228 #endif /* _FFR_GEN_ORCPT */
6229 #if _FFR_GROUPREADABLEAUTHINFOFILE
6230         /* Allow group readable DefaultAuthInfo file. */
6231         "_FFR_GROUPREADABLEAUTHINFOFILE",
6232 #endif /* _FFR_GROUPREADABLEAUTHINFOFILE */
6233 #if _FFR_HANDLE_ISO8859_GECOS
6234         /*
6235         **  Allow ISO 8859 characters in GECOS field: replace them
6236         **  ith ASCII "equivalent".
6237         */
6238
6239 /* Peter Eriksson of Linkopings universitet */
6240         "_FFR_HANDLE_ISO8859_GECOS",
6241 #endif /* _FFR_HANDLE_ISO8859_GECOS */
6242 #if _FFR_HPUX_NSSWITCH
6243         /* Use nsswitch on HP-UX */
6244         "_FFR_HPUX_NSSWITCH",
6245 #endif /* _FFR_HPUX_NSSWITCH */
6246 #if _FFR_IGNORE_BOGUS_ADDR
6247         /* Ignore addresses for which prescan() failed */
6248         "_FFR_IGNORE_BOGUS_ADDR",
6249 #endif /* _FFR_IGNORE_BOGUS_ADDR */
6250 #if _FFR_IGNORE_EXT_ON_HELO
6251         /* Ignore extensions offered in response to HELO */
6252         "_FFR_IGNORE_EXT_ON_HELO",
6253 #endif /* _FFR_IGNORE_EXT_ON_HELO */
6254 #if _FFR_LINUX_MHNL
6255         /* Set MAXHOSTNAMELEN to 256 (Linux) */
6256         "_FFR_LINUX_MHNL",
6257 #endif /* _FFR_LINUX_MHNL */
6258 #if _FFR_LOCAL_DAEMON
6259         /* Local daemon mode (-bl) which only accepts loopback connections */
6260         "_FFR_LOCAL_DAEMON",
6261 #endif /* _FFR_LOCAL_DAEMON */
6262 #if _FFR_MAIL_MACRO
6263         "_FFR_MAIL_MACRO",
6264 #endif /* _FFR_MAIL_MACRO */
6265 #if _FFR_MAXDATASIZE
6266         /*
6267         **  It is possible that a header is larger than MILTER_CHUNK_SIZE,
6268         **  hence this shouldn't be used as limit for milter communication.
6269         **  see also libmilter/comm.c
6270         **  Gurusamy Sarathy of ActiveState
6271         */
6272
6273         "_FFR_MAXDATASIZE",
6274 #endif /* _FFR_MAXDATASIZE */
6275 #if _FFR_MAX_FORWARD_ENTRIES
6276         /* Try to limit number of .forward entries */
6277         /* (doesn't work) */
6278 /* Randall S. Winchester of the University of Maryland */
6279         "_FFR_MAX_FORWARD_ENTRIES",
6280 #endif /* _FFR_MAX_FORWARD_ENTRIES */
6281 #if _FFR_MAX_SLEEP_TIME
6282         /* Limit sleep(2) time in libsm/clock.c */
6283         "_FFR_MAX_SLEEP_TIME",
6284 #endif /* _FFR_MAX_SLEEP_TIME */
6285 #if _FFR_MDS_NEGOTIATE
6286         /* MaxDataSize negotation with libmilter */
6287         "_FFR_MDS_NEGOTIATE",
6288 #endif /* _FFR_MDS_NEGOTIATE */
6289 #if _FFR_MEMSTAT
6290         /* Check free memory */
6291         "_FFR_MEMSTAT",
6292 #endif /* _FFR_MEMSTAT */
6293 #if _FFR_MILTER_CHECK
6294         "_FFR_MILTER_CHECK",
6295 #endif /* _FFR_MILTER_CHECK */
6296 #if _FFR_MILTER_CONVERT_ALL_LF_TO_CRLF
6297         /*
6298         **  milter_body() uses the same conversion algorithm as putbody()
6299         **  to translate the "local" df format (\n) to SMTP format (\r\n).
6300         **  However, putbody() and mime8to7() use different conversion
6301         **  algorithms.
6302         **  If the input date does not follow the SMTP standard
6303         **  (e.g., if it has "naked \r"s), then the output from putbody()
6304         **  and mime8to7() will most likely be different.
6305         **  By turning on this FFR milter_body() will try to "imitate"
6306         **  mime8to7().
6307         **  Note: there is no (simple) way to deal with both conversions
6308         **  in a consistent manner. Moreover, as the "GiGo" principle applies,
6309         **  it's not really worth to fix it.
6310         */
6311
6312         "_FFR_MILTER_CONVERT_ALL_LF_TO_CRLF",
6313 #endif /* _FFR_MILTER_CONVERT_ALL_LF_TO_CRLF */
6314 #if _FFR_MILTER_CHECK_REJECTIONS_TOO
6315         /*
6316         **  Also send RCPTs that are rejected by check_rcpt to a milter
6317         **  (if requested during option negotiation).
6318         */
6319
6320         "_FFR_MILTER_CHECK_REJECTIONS_TOO",
6321 #endif /* _FFR_MILTER_CHECK_REJECTIONS_TOO */
6322 #if _FFR_MILTER_ENHSC
6323         /* extract enhanced status code from milter replies for dsn= logging */
6324         "_FFR_MILTER_ENHSC",
6325 #endif /* _FFR_MILTER_ENHSC */
6326 #if _FFR_MIME7TO8_OLD
6327         /* Old mime7to8 code, the new is broken for at least one example. */
6328         "_FFR_MIME7TO8_OLD",
6329 #endif /* _FFR_MAX_SLEEP_TIME */
6330 #if _FFR_MORE_MACROS
6331         /* allow more long macro names ("unprintable" characters). */
6332         "_FFR_MORE_MACROS",
6333 #endif /* _FFR_MORE_MACROS */
6334 #if _FFR_MSG_ACCEPT
6335         /* allow to override "Message accepted for delivery" */
6336         "_FFR_MSG_ACCEPT",
6337 #endif /* _FFR_MSG_ACCEPT */
6338 #if _FFR_NODELAYDSN_ON_HOLD
6339         /* Do not issue a DELAY DSN for mailers that use the hold flag. */
6340 /* Steven Pitzl */
6341         "_FFR_NODELAYDSN_ON_HOLD",
6342 #endif /* _FFR_NODELAYDSN_ON_HOLD */
6343 #if _FFR_NO_PIPE
6344         /* Disable PIPELINING, delay client if used. */
6345         "_FFR_NO_PIPE",
6346 #endif /* _FFR_NO_PIPE */
6347 #if _FFR_LDAP_NETWORK_TIMEOUT
6348         /* set LDAP_OPT_NETWORK_TIMEOUT if available (-c) */
6349         "_FFR_LDAP_NETWORK_TIMEOUT",
6350 #endif /* _FFR_LDAP_NETWORK_TIMEOUT */
6351 #if _FFR_LOG_NTRIES
6352         /* log ntries=, from Nik Clayton of FreeBSD */
6353         "_FFR_LOG_NTRIES",
6354 #endif /* _FFR_LOG_NTRIES */
6355 #if _FFR_QF_PARANOIA
6356         "_FFR_QF_PARANOIA",
6357 #endif /* _FFR_QF_PARANOIA */
6358 #if _FFR_QUEUEDELAY
6359         /* Exponential queue delay; disabled in 8.13 since it isn't used. */
6360         "_FFR_QUEUEDELAY",
6361 #endif /* _FFR_QUEUEDELAY */
6362 #if _FFR_QUEUE_GROUP_SORTORDER
6363         /* Allow QueueSortOrder per queue group. */
6364 /* XXX: Still need to actually use qgrp->qg_sortorder */
6365         "_FFR_QUEUE_GROUP_SORTORDER",
6366 #endif /* _FFR_QUEUE_GROUP_SORTORDER */
6367 #if _FFR_QUEUE_MACRO
6368         /* Define {queue} macro. */
6369         "_FFR_QUEUE_MACRO",
6370 #endif /* _FFR_QUEUE_MACRO */
6371 #if _FFR_QUEUE_RUN_PARANOIA
6372         /* Additional checks when doing queue runs; interval of checks */
6373         "_FFR_QUEUE_RUN_PARANOIA",
6374 #endif /* _FFR_QUEUE_RUN_PARANOIA */
6375 #if _FFR_QUEUE_SCHED_DBG
6376         /* Debug output for the queue scheduler. */
6377         "_FFR_QUEUE_SCHED_DBG",
6378 #endif /* _FFR_QUEUE_SCHED_DBG */
6379 #if _FFR_RCPTTHROTDELAY
6380         /* configurable delay for BadRcptThrottle */
6381         "_FFR_RCPTTHROTDELAY",
6382 #endif /* _FFR_RCPTTHROTDELAY */
6383 #if _FFR_REDIRECTEMPTY
6384         /*
6385         **  envelope <> can't be sent to mailing lists, only owner-
6386         **  send spam of this type to owner- of the list
6387         **  ----  to stop spam from going to mailing lists.
6388         */
6389
6390         "_FFR_REDIRECTEMPTY",
6391 #endif /* _FFR_REDIRECTEMPTY */
6392 #if _FFR_REJECT_NUL_BYTE
6393         /* reject NUL bytes in body */
6394         "_FFR_REJECT_NUL_BYTE",
6395 #endif /* _FFR_REJECT_NUL_BYTE */
6396 #if _FFR_RESET_MACRO_GLOBALS
6397         /* Allow macro 'j' to be set dynamically via rulesets. */
6398         "_FFR_RESET_MACRO_GLOBALS",
6399 #endif /* _FFR_RESET_MACRO_GLOBALS */
6400 #if _FFR_RHS
6401         /* Random shuffle for queue sorting. */
6402         "_FFR_RHS",
6403 #endif /* _FFR_RHS */
6404 #if _FFR_RUNPQG
6405         /*
6406         **  allow -qGqueue_group -qp to work, i.e.,
6407         **  restrict a persistent queue runner to a queue group.
6408         */
6409
6410         "_FFR_RUNPQG",
6411 #endif /* _FFR_RUNPQG */
6412 #if _FFR_SESSID
6413         /* session id (for logging) */
6414         "_FFR_SESSID",
6415 #endif /* _FFR_SESSID */
6416 #if _FFR_SHM_STATUS
6417         /* Donated code (unused). */
6418         "_FFR_SHM_STATUS",
6419 #endif /* _FFR_SHM_STATUS */
6420 #if _FFR_LDAP_SINGLEDN
6421         /*
6422         **  The LDAP database map code in Sendmail 8.12.10, when
6423         **  given the -1 switch, would match only a single DN,
6424         **  but was able to return multiple attributes for that
6425         **  DN.  In Sendmail 8.13 this "bug" was corrected to
6426         **  only return if exactly one attribute matched.
6427         **
6428         **  Unfortunately, our configuration uses the former
6429         **  behaviour.  Attached is a relatively simple patch
6430         **  to 8.13.4 which adds a -2 switch (for lack of a
6431         **  better option) which returns the single dn/multiple
6432         **  attributes.
6433         **
6434         ** Jeffrey T. Eaton, Carnegie-Mellon University
6435         */
6436
6437         "_FFR_LDAP_SINGLEDN",
6438 #endif /* _FFR_LDAP_SINGLEDN */
6439 #if _FFR_SKIP_DOMAINS
6440         /* process every N'th domain instead of every N'th message */
6441         "_FFR_SKIP_DOMAINS",
6442 #endif /* _FFR_SKIP_DOMAINS */
6443 #if _FFR_SLEEP_USE_SELECT
6444         /* Use select(2) in libsm/clock.c to emulate sleep(2) */
6445         "_FFR_SLEEP_USE_SELECT ",
6446 #endif /* _FFR_SLEEP_USE_SELECT */
6447 #if _FFR_SPT_ALIGN
6448         /*
6449         **  It looks like the Compaq Tru64 5.1A now aligns argv and envp to 64
6450         **  bit alignment, so unless each piece of argv and envp is a multiple
6451         **  of 8 bytes (including terminating NULL), initsetproctitle() won't
6452         **  use any of the space beyond argv[0]. Be sure to set SPT_ALIGN_SIZE
6453         **  if you use this FFR.
6454         */
6455
6456 /* Chris Adams of HiWAAY Informations Services */
6457         "_FFR_SPT_ALIGN",
6458 #endif /* _FFR_SPT_ALIGN */
6459 #if _FFR_SS_PER_DAEMON
6460         /* SuperSafe per DaemonPortOptions: 'T' (better letter?) */
6461         "_FFR_SS_PER_DAEMON",
6462 #endif /* _FFR_SS_PER_DAEMON */
6463 #if _FFR_TESTS
6464         /* enable some test code */
6465         "_FFR_TESTS",
6466 #endif /* _FFR_TESTS */
6467 #if _FFR_TIMERS
6468         /* Donated code (unused). */
6469         "_FFR_TIMERS",
6470 #endif /* _FFR_TIMERS */
6471 #if _FFR_TLS_1
6472         /* More STARTTLS options, e.g., secondary certs. */
6473         "_FFR_TLS_1",
6474 #endif /* _FFR_TLS_1 */
6475 #if _FFR_TRUSTED_QF
6476         /*
6477         **  If we don't own the file mark it as unsafe.
6478         **  However, allow TrustedUser to own it as well
6479         **  in case TrustedUser manipulates the queue.
6480         */
6481
6482         "_FFR_TRUSTED_QF",
6483 #endif /* _FFR_TRUSTED_QF */
6484 #if _FFR_USE_SEM_LOCKING
6485         "_FFR_USE_SEM_LOCKING",
6486 #endif /* _FFR_USE_SEM_LOCKING */
6487 #if _FFR_USE_SETLOGIN
6488         /* Use setlogin() */
6489 /* Peter Philipp */
6490         "_FFR_USE_SETLOGIN",
6491 #endif /* _FFR_USE_SETLOGIN */
6492         NULL
6493 };
6494