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