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