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