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