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