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