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