]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/sendmail/src/conf.c
This commit was generated by cvs2svn to compensate for changes in r99461,
[FreeBSD/FreeBSD.git] / contrib / sendmail / src / conf.c
1 /*
2  * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
3  *      All rights reserved.
4  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5  * Copyright (c) 1988, 1993
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * By using this file, you agree to the terms and conditions set
9  * forth in the LICENSE file which can be found at the top level of
10  * the sendmail distribution.
11  *
12  */
13
14 #include <sendmail.h>
15
16 SM_RCSID("@(#)$Id: conf.c,v 8.972 2002/06/18 16:11:44 ca 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 #if _FFR_SPT_ALIGN
2333
2334 /*
2335 **  It looks like the Compaq Tru64 5.1A now aligns argv and envp to
2336 **  64 bit alignment, so unless each piece of argv and envp is a multiple
2337 **  of 8 bytes (including terminating NULL), initsetproctitle() won't use
2338 **  any of the space beyond argv[0].  Be sure to set SPT_ALIGN_SIZE if
2339 **  you use this FFR.
2340 */
2341
2342 # ifdef SPT_ALIGN_SIZE
2343 #  define SPT_ALIGN(x, align)   (((((x) + SPT_ALIGN_SIZE) >> (align)) << (align)) - 1)
2344 # else /* SPT_ALIGN_SIZE */
2345 #  define SPT_ALIGN(x, align)   (x)
2346 # endif /* SPT_ALIGN_SIZE */
2347 #else /* _FFR_SPT_ALIGN */
2348 # define SPT_ALIGN(x, align)    (x)
2349 #endif /* _FFR_SPT_ALIGN */
2350
2351 /*
2352 **  Pointers for setproctitle.
2353 **      This allows "ps" listings to give more useful information.
2354 */
2355
2356 static char     **Argv = NULL;          /* pointer to argument vector */
2357 static char     *LastArgv = NULL;       /* end of argv */
2358 #if SPT_TYPE != SPT_BUILTIN
2359 static void     setproctitle __P((const char *, ...));
2360 #endif /* SPT_TYPE != SPT_BUILTIN */
2361
2362 void
2363 initsetproctitle(argc, argv, envp)
2364         int argc;
2365         char **argv;
2366         char **envp;
2367 {
2368         register int i;
2369         int align;
2370         extern char **environ;
2371
2372         /*
2373         **  Move the environment so setproctitle can use the space at
2374         **  the top of memory.
2375         */
2376
2377         for (i = 0; envp[i] != NULL; i++)
2378                 continue;
2379         environ = (char **) xalloc(sizeof (char *) * (i + 1));
2380         for (i = 0; envp[i] != NULL; i++)
2381                 environ[i] = newstr(envp[i]);
2382         environ[i] = NULL;
2383
2384         /*
2385         **  Save start and extent of argv for setproctitle.
2386         */
2387
2388         Argv = argv;
2389
2390         /*
2391         **  Determine how much space we can use for setproctitle.
2392         **  Use all contiguous argv and envp pointers starting at argv[0]
2393         */
2394
2395         align = -1;
2396 #if _FFR_SPT_ALIGN
2397 # ifdef SPT_ALIGN_SIZE
2398         for (i = SPT_ALIGN_SIZE; i > 0; i >>= 1)
2399                 align++;
2400 # endif /* SPT_ALIGN_SIZE */
2401 #endif /* _FFR_SPT_ALIGN */
2402
2403         for (i = 0; i < argc; i++)
2404         {
2405                 if (i == 0 || LastArgv + 1 == argv[i])
2406                         LastArgv = argv[i] + SPT_ALIGN(strlen(argv[i]), align);
2407         }
2408         for (i = 0; LastArgv != NULL && envp[i] != NULL; i++)
2409         {
2410                 if (LastArgv + 1 == envp[i])
2411                         LastArgv = envp[i] + SPT_ALIGN(strlen(envp[i]), align);
2412         }
2413 }
2414
2415 #if SPT_TYPE != SPT_BUILTIN
2416
2417 /*VARARGS1*/
2418 static void
2419 # ifdef __STDC__
2420 setproctitle(const char *fmt, ...)
2421 # else /* __STDC__ */
2422 setproctitle(fmt, va_alist)
2423         const char *fmt;
2424         va_dcl
2425 # endif /* __STDC__ */
2426 {
2427 # if SPT_TYPE != SPT_NONE
2428         register int i;
2429         register char *p;
2430         SETPROC_STATIC char buf[SPT_BUFSIZE];
2431         SM_VA_LOCAL_DECL
2432 #  if SPT_TYPE == SPT_PSTAT
2433         union pstun pst;
2434 #  endif /* SPT_TYPE == SPT_PSTAT */
2435 #  if SPT_TYPE == SPT_SCO
2436         int j;
2437         off_t seek_off;
2438         static int kmem = -1;
2439         static pid_t kmempid = -1;
2440         struct user u;
2441 #  endif /* SPT_TYPE == SPT_SCO */
2442
2443         p = buf;
2444
2445         /* print sendmail: heading for grep */
2446         (void) sm_strlcpy(p, "sendmail: ", SPACELEFT(buf, p));
2447         p += strlen(p);
2448
2449         /* print the argument string */
2450         SM_VA_START(ap, fmt);
2451         (void) sm_vsnprintf(p, SPACELEFT(buf, p), fmt, ap);
2452         SM_VA_END(ap);
2453
2454         i = (int) strlen(buf);
2455         if (i < 0)
2456                 return;
2457
2458 #  if SPT_TYPE == SPT_PSTAT
2459         pst.pst_command = buf;
2460         pstat(PSTAT_SETCMD, pst, i, 0, 0);
2461 #  endif /* SPT_TYPE == SPT_PSTAT */
2462 #  if SPT_TYPE == SPT_PSSTRINGS
2463         PS_STRINGS->ps_nargvstr = 1;
2464         PS_STRINGS->ps_argvstr = buf;
2465 #  endif /* SPT_TYPE == SPT_PSSTRINGS */
2466 #  if SPT_TYPE == SPT_SYSMIPS
2467         sysmips(SONY_SYSNEWS, NEWS_SETPSARGS, buf);
2468 #  endif /* SPT_TYPE == SPT_SYSMIPS */
2469 #  if SPT_TYPE == SPT_SCO
2470         if (kmem < 0 || kmempid != CurrentPid)
2471         {
2472                 if (kmem >= 0)
2473                         (void) close(kmem);
2474                 kmem = open(_PATH_KMEM, O_RDWR, 0);
2475                 if (kmem < 0)
2476                         return;
2477                 if ((j = fcntl(kmem, F_GETFD, 0)) < 0 ||
2478                     fcntl(kmem, F_SETFD, j | FD_CLOEXEC) < 0)
2479                 {
2480                         (void) close(kmem);
2481                         kmem = -1;
2482                         return;
2483                 }
2484                 kmempid = CurrentPid;
2485         }
2486         buf[PSARGSZ - 1] = '\0';
2487         seek_off = UVUBLK + (off_t) u.u_psargs - (off_t) &u;
2488         if (lseek(kmem, (off_t) seek_off, SEEK_SET) == seek_off)
2489                 (void) write(kmem, buf, PSARGSZ);
2490 #  endif /* SPT_TYPE == SPT_SCO */
2491 #  if SPT_TYPE == SPT_REUSEARGV
2492         if (LastArgv == NULL)
2493                 return;
2494
2495         if (i > LastArgv - Argv[0] - 2)
2496         {
2497                 i = LastArgv - Argv[0] - 2;
2498                 buf[i] = '\0';
2499         }
2500         (void) sm_strlcpy(Argv[0], buf, i + 1);
2501         p = &Argv[0][i];
2502         while (p < LastArgv)
2503                 *p++ = SPT_PADCHAR;
2504         Argv[1] = NULL;
2505 #  endif /* SPT_TYPE == SPT_REUSEARGV */
2506 #  if SPT_TYPE == SPT_CHANGEARGV
2507         Argv[0] = buf;
2508         Argv[1] = 0;
2509 #  endif /* SPT_TYPE == SPT_CHANGEARGV */
2510 # endif /* SPT_TYPE != SPT_NONE */
2511 }
2512
2513 #endif /* SPT_TYPE != SPT_BUILTIN */
2514 /*
2515 **  SM_SETPROCTITLE -- set process task and set process title for ps
2516 **
2517 **      Possibly set process status and call setproctitle() to
2518 **      change the ps display.
2519 **
2520 **      Parameters:
2521 **              status -- whether or not to store as process status
2522 **              e -- the current envelope.
2523 **              fmt -- a printf style format string.
2524 **              a, b, c -- possible parameters to fmt.
2525 **
2526 **      Returns:
2527 **              none.
2528 */
2529
2530 /*VARARGS2*/
2531 void
2532 #ifdef __STDC__
2533 sm_setproctitle(bool status, ENVELOPE *e, const char *fmt, ...)
2534 #else /* __STDC__ */
2535 sm_setproctitle(status, e, fmt, va_alist)
2536         bool status;
2537         ENVELOPE *e;
2538         const char *fmt;
2539         va_dcl
2540 #endif /* __STDC__ */
2541 {
2542         char buf[SPT_BUFSIZE];
2543         SM_VA_LOCAL_DECL
2544
2545         /* print the argument string */
2546         SM_VA_START(ap, fmt);
2547         (void) sm_vsnprintf(buf, sizeof buf, fmt, ap);
2548         SM_VA_END(ap);
2549
2550         if (status)
2551                 proc_list_set(CurrentPid, buf);
2552
2553         if (ProcTitlePrefix != NULL)
2554         {
2555                 char prefix[SPT_BUFSIZE];
2556
2557                 expand(ProcTitlePrefix, prefix, sizeof prefix, e);
2558                 setproctitle("%s: %s", prefix, buf);
2559         }
2560         else
2561                 setproctitle("%s", buf);
2562 }
2563 /*
2564 **  WAITFOR -- wait for a particular process id.
2565 **
2566 **      Parameters:
2567 **              pid -- process id to wait for.
2568 **
2569 **      Returns:
2570 **              status of pid.
2571 **              -1 if pid never shows up.
2572 **
2573 **      Side Effects:
2574 **              none.
2575 */
2576
2577 int
2578 waitfor(pid)
2579         pid_t pid;
2580 {
2581         int st;
2582         pid_t i;
2583
2584         do
2585         {
2586                 errno = 0;
2587                 i = sm_wait(&st);
2588                 if (i > 0)
2589                         proc_list_drop(i, st, NULL);
2590         } while ((i >= 0 || errno == EINTR) && i != pid);
2591         if (i < 0)
2592                 return -1;
2593         return st;
2594 }
2595 /*
2596 **  SM_WAIT -- wait
2597 **
2598 **      Parameters:
2599 **              status -- pointer to status (return value)
2600 **
2601 **      Returns:
2602 **              pid
2603 */
2604
2605 pid_t
2606 sm_wait(status)
2607         int *status;
2608 {
2609 # ifdef WAITUNION
2610         union wait st;
2611 # else /* WAITUNION */
2612         auto int st;
2613 # endif /* WAITUNION */
2614         pid_t i;
2615 # if defined(ISC_UNIX) || defined(_SCO_unix_)
2616         int savesig;
2617 # endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */
2618
2619 # if defined(ISC_UNIX) || defined(_SCO_unix_)
2620         savesig = sm_releasesignal(SIGCHLD);
2621 # endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */
2622         i = wait(&st);
2623 # if defined(ISC_UNIX) || defined(_SCO_unix_)
2624         if (savesig > 0)
2625                 sm_blocksignal(SIGCHLD);
2626 # endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */
2627 # ifdef WAITUNION
2628         *status = st.w_status;
2629 # else /* WAITUNION */
2630         *status = st;
2631 # endif /* WAITUNION */
2632         return i;
2633 }
2634 /*
2635 **  REAPCHILD -- pick up the body of my child, lest it become a zombie
2636 **
2637 **      Parameters:
2638 **              sig -- the signal that got us here (unused).
2639 **
2640 **      Returns:
2641 **              none.
2642 **
2643 **      Side Effects:
2644 **              Picks up extant zombies.
2645 **              Control socket exits may restart/shutdown daemon.
2646 **
2647 **      NOTE:   THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
2648 **              ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
2649 **              DOING.
2650 */
2651
2652 /* ARGSUSED0 */
2653 SIGFUNC_DECL
2654 reapchild(sig)
2655         int sig;
2656 {
2657         int m = 0;
2658         int save_errno = errno;
2659         int st;
2660         pid_t pid;
2661 # if HASWAITPID
2662         auto int status;
2663         int count;
2664
2665         count = 0;
2666         while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
2667         {
2668                 st = status;
2669                 if (count++ > 1000)
2670                         break;
2671 # else /* HASWAITPID */
2672 #  ifdef WNOHANG
2673         union wait status;
2674
2675         while ((pid = wait3(&status, WNOHANG, (struct rusage *) NULL)) > 0)
2676         {
2677                 st = status.w_status;
2678 #  else /* WNOHANG */
2679         auto int status;
2680
2681         /*
2682         **  Catch one zombie -- we will be re-invoked (we hope) if there
2683         **  are more.  Unreliable signals probably break this, but this
2684         **  is the "old system" situation -- waitpid or wait3 are to be
2685         **  strongly preferred.
2686         */
2687
2688         if ((pid = wait(&status)) > 0)
2689         {
2690                 st = status;
2691 #  endif /* WNOHANG */
2692 # endif /* HASWAITPID */
2693                 /* Drop PID and check if it was a control socket child */
2694                 proc_list_drop(pid, st, NULL);
2695                 CurRunners -= m; /* Update */
2696         }
2697         FIX_SYSV_SIGNAL(sig, reapchild);
2698         errno = save_errno;
2699         return SIGFUNC_RETURN;
2700 }
2701 /*
2702 **  GETDTABLESIZE -- return number of file descriptors
2703 **
2704 **      Only on non-BSD systems
2705 **
2706 **      Parameters:
2707 **              none
2708 **
2709 **      Returns:
2710 **              size of file descriptor table
2711 **
2712 **      Side Effects:
2713 **              none
2714 */
2715
2716 #ifdef SOLARIS
2717 # include <sys/resource.h>
2718 #endif /* SOLARIS */
2719
2720 int
2721 getdtsize()
2722 {
2723 # ifdef RLIMIT_NOFILE
2724         struct rlimit rl;
2725
2726         if (getrlimit(RLIMIT_NOFILE, &rl) >= 0)
2727                 return rl.rlim_cur;
2728 # endif /* RLIMIT_NOFILE */
2729
2730 # if HASGETDTABLESIZE
2731         return getdtablesize();
2732 # else /* HASGETDTABLESIZE */
2733 #  ifdef _SC_OPEN_MAX
2734         return sysconf(_SC_OPEN_MAX);
2735 #  else /* _SC_OPEN_MAX */
2736         return NOFILE;
2737 #  endif /* _SC_OPEN_MAX */
2738 # endif /* HASGETDTABLESIZE */
2739 }
2740 /*
2741 **  UNAME -- get the UUCP name of this system.
2742 */
2743
2744 #if !HASUNAME
2745
2746 int
2747 uname(name)
2748         struct utsname *name;
2749 {
2750         SM_FILE_T *file;
2751         char *n;
2752
2753         name->nodename[0] = '\0';
2754
2755         /* try /etc/whoami -- one line with the node name */
2756         if ((file = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, "/etc/whoami",
2757                                SM_IO_RDONLY, NULL)) != NULL)
2758         {
2759                 (void) sm_io_fgets(file, SM_TIME_DEFAULT, name->nodename,
2760                                    NODE_LENGTH + 1);
2761                 (void) sm_io_close(file, SM_TIME_DEFAULT);
2762                 n = strchr(name->nodename, '\n');
2763                 if (n != NULL)
2764                         *n = '\0';
2765                 if (name->nodename[0] != '\0')
2766                         return 0;
2767         }
2768
2769         /* try /usr/include/whoami.h -- has a #define somewhere */
2770         if ((file = sm_io_open(SmFtStdio, SM_TIME_DEFAULT,
2771                                "/usr/include/whoami.h", SM_IO_RDONLY, NULL))
2772             != NULL)
2773         {
2774                 char buf[MAXLINE];
2775
2776                 while (sm_io_fgets(file, SM_TIME_DEFAULT,
2777                                    buf, sizeof buf) != NULL)
2778                 {
2779                         if (sm_io_sscanf(buf, "#define sysname \"%*[^\"]\"",
2780                                         NODE_LENGTH, name->nodename) > 0)
2781                                 break;
2782                 }
2783                 (void) sm_io_close(file, SM_TIME_DEFAULT);
2784                 if (name->nodename[0] != '\0')
2785                         return 0;
2786         }
2787
2788 #  if 0
2789         /*
2790         **  Popen is known to have security holes.
2791         */
2792
2793         /* try uuname -l to return local name */
2794         if ((file = popen("uuname -l", "r")) != NULL)
2795         {
2796                 (void) sm_io_fgets(file, SM_TIME_DEFAULT, name,
2797                                    NODE_LENGTH + 1);
2798                 (void) pclose(file);
2799                 n = strchr(name, '\n');
2800                 if (n != NULL)
2801                         *n = '\0';
2802                 if (name->nodename[0] != '\0')
2803                         return 0;
2804         }
2805 #  endif /* 0 */
2806
2807         return -1;
2808 }
2809 #endif /* !HASUNAME */
2810 /*
2811 **  INITGROUPS -- initialize groups
2812 **
2813 **      Stub implementation for System V style systems
2814 */
2815
2816 #if !HASINITGROUPS
2817
2818 initgroups(name, basegid)
2819         char *name;
2820         int basegid;
2821 {
2822         return 0;
2823 }
2824
2825 #endif /* !HASINITGROUPS */
2826 /*
2827 **  SETGROUPS -- set group list
2828 **
2829 **      Stub implementation for systems that don't have group lists
2830 */
2831
2832 #ifndef NGROUPS_MAX
2833
2834 int
2835 setgroups(ngroups, grouplist)
2836         int ngroups;
2837         GIDSET_T grouplist[];
2838 {
2839         return 0;
2840 }
2841
2842 #endif /* ! NGROUPS_MAX */
2843 /*
2844 **  SETSID -- set session id (for non-POSIX systems)
2845 */
2846
2847 #if !HASSETSID
2848
2849 pid_t
2850 setsid __P ((void))
2851 {
2852 #  ifdef TIOCNOTTY
2853         int fd;
2854
2855         fd = open("/dev/tty", O_RDWR, 0);
2856         if (fd >= 0)
2857         {
2858                 (void) ioctl(fd, TIOCNOTTY, (char *) 0);
2859                 (void) close(fd);
2860         }
2861 #  endif /* TIOCNOTTY */
2862 #  ifdef SYS5SETPGRP
2863         return setpgrp();
2864 #  else /* SYS5SETPGRP */
2865         return setpgid(0, CurrentPid);
2866 #  endif /* SYS5SETPGRP */
2867 }
2868
2869 #endif /* !HASSETSID */
2870 /*
2871 **  FSYNC -- dummy fsync
2872 */
2873
2874 #if NEEDFSYNC
2875
2876 fsync(fd)
2877         int fd;
2878 {
2879 # ifdef O_SYNC
2880         return fcntl(fd, F_SETFL, O_SYNC);
2881 # else /* O_SYNC */
2882         /* nothing we can do */
2883         return 0;
2884 # endif /* O_SYNC */
2885 }
2886
2887 #endif /* NEEDFSYNC */
2888 /*
2889 **  DGUX_INET_ADDR -- inet_addr for DG/UX
2890 **
2891 **      Data General DG/UX version of inet_addr returns a struct in_addr
2892 **      instead of a long.  This patches things.  Only needed on versions
2893 **      prior to 5.4.3.
2894 */
2895
2896 #ifdef DGUX_5_4_2
2897
2898 # undef inet_addr
2899
2900 long
2901 dgux_inet_addr(host)
2902         char *host;
2903 {
2904         struct in_addr haddr;
2905
2906         haddr = inet_addr(host);
2907         return haddr.s_addr;
2908 }
2909
2910 #endif /* DGUX_5_4_2 */
2911 /*
2912 **  GETOPT -- for old systems or systems with bogus implementations
2913 */
2914
2915 #if !SM_CONF_GETOPT
2916
2917 /*
2918  * Copyright (c) 1985 Regents of the University of California.
2919  * All rights reserved.  The Berkeley software License Agreement
2920  * specifies the terms and conditions for redistribution.
2921  */
2922
2923
2924 /*
2925 **  this version hacked to add `atend' flag to allow state machine
2926 **  to reset if invoked by the program to scan args for a 2nd time
2927 */
2928
2929 # if defined(LIBC_SCCS) && !defined(lint)
2930 static char sccsid[] = "@(#)getopt.c    4.3 (Berkeley) 3/9/86";
2931 # endif /* defined(LIBC_SCCS) && !defined(lint) */
2932
2933 /*
2934 **  get option letter from argument vector
2935 */
2936 # ifdef _CONVEX_SOURCE
2937 extern int      optind, opterr, optopt;
2938 extern char     *optarg;
2939 # else /* _CONVEX_SOURCE */
2940 int     opterr = 1;             /* if error message should be printed */
2941 int     optind = 1;             /* index into parent argv vector */
2942 int     optopt = 0;             /* character checked for validity */
2943 char    *optarg = NULL;         /* argument associated with option */
2944 # endif /* _CONVEX_SOURCE */
2945
2946 # define BADCH  (int)'?'
2947 # define EMSG   ""
2948 # define tell(s)        if (opterr) \
2949                         {sm_io_fputs(smioerr, SM_TIME_DEFAULT, *nargv); \
2950                         (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT, s); \
2951                         (void) sm_io_putc(smioerr, SM_TIME_DEFAULT, optopt); \
2952                         (void) sm_io_putc(smioerr, SM_TIME_DEFAULT, '\n'); \
2953                         return BADCH;}
2954
2955 int
2956 getopt(nargc,nargv,ostr)
2957         int             nargc;
2958         char *const     *nargv;
2959         const char      *ostr;
2960 {
2961         static char     *place = EMSG;  /* option letter processing */
2962         static char     atend = 0;
2963         register char   *oli = NULL;    /* option letter list index */
2964
2965         if (atend) {
2966                 atend = 0;
2967                 place = EMSG;
2968         }
2969         if(!*place) {                   /* update scanning pointer */
2970                 if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) {
2971                         atend++;
2972                         return -1;
2973                 }
2974                 if (*place == '-') {    /* found "--" */
2975                         ++optind;
2976                         atend++;
2977                         return -1;
2978                 }
2979         }                               /* option letter okay? */
2980         if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) {
2981                 if (!*place) ++optind;
2982                 tell(": illegal option -- ");
2983         }
2984         if (oli && *++oli != ':') {             /* don't need argument */
2985                 optarg = NULL;
2986                 if (!*place) ++optind;
2987         }
2988         else {                          /* need an argument */
2989                 if (*place) optarg = place;     /* no white space */
2990                 else if (nargc <= ++optind) {   /* no arg */
2991                         place = EMSG;
2992                         tell(": option requires an argument -- ");
2993                 }
2994                 else optarg = nargv[optind];    /* white space */
2995                 place = EMSG;
2996                 ++optind;
2997         }
2998         return optopt;                  /* dump back option letter */
2999 }
3000
3001 #endif /* !SM_CONF_GETOPT */
3002 /*
3003 **  USERSHELLOK -- tell if a user's shell is ok for unrestricted use
3004 **
3005 **      Parameters:
3006 **              user -- the name of the user we are checking.
3007 **              shell -- the user's shell from /etc/passwd
3008 **
3009 **      Returns:
3010 **              true -- if it is ok to use this for unrestricted access.
3011 **              false -- if the shell is restricted.
3012 */
3013
3014 #if !HASGETUSERSHELL
3015
3016 # ifndef _PATH_SHELLS
3017 #  define _PATH_SHELLS  "/etc/shells"
3018 # endif /* ! _PATH_SHELLS */
3019
3020 # if defined(_AIX3) || defined(_AIX4)
3021 #  include <userconf.h>
3022 #  if _AIX4 >= 40200
3023 #   include <userpw.h>
3024 #  endif /* _AIX4 >= 40200 */
3025 #  include <usersec.h>
3026 # endif /* defined(_AIX3) || defined(_AIX4) */
3027
3028 static char     *DefaultUserShells[] =
3029 {
3030         "/bin/sh",              /* standard shell */
3031 # ifdef MPE
3032         "/SYS/PUB/CI",
3033 # else /* MPE */
3034         "/usr/bin/sh",
3035         "/bin/csh",             /* C shell */
3036         "/usr/bin/csh",
3037 # endif /* MPE */
3038 # ifdef __hpux
3039 #  ifdef V4FS
3040         "/usr/bin/rsh",         /* restricted Bourne shell */
3041         "/usr/bin/ksh",         /* Korn shell */
3042         "/usr/bin/rksh",        /* restricted Korn shell */
3043         "/usr/bin/pam",
3044         "/usr/bin/keysh",       /* key shell (extended Korn shell) */
3045         "/usr/bin/posix/sh",
3046 #  else /* V4FS */
3047         "/bin/rsh",             /* restricted Bourne shell */
3048         "/bin/ksh",             /* Korn shell */
3049         "/bin/rksh",            /* restricted Korn shell */
3050         "/bin/pam",
3051         "/usr/bin/keysh",       /* key shell (extended Korn shell) */
3052         "/bin/posix/sh",
3053         "/sbin/sh"
3054 #  endif /* V4FS */
3055 # endif /* __hpux */
3056 # if defined(_AIX3) || defined(_AIX4)
3057         "/bin/ksh",             /* Korn shell */
3058         "/usr/bin/ksh",
3059         "/bin/tsh",             /* trusted shell */
3060         "/usr/bin/tsh",
3061         "/bin/bsh",             /* Bourne shell */
3062         "/usr/bin/bsh",
3063 # endif /* defined(_AIX3) || defined(_AIX4) */
3064 # if defined(__svr4__) || defined(__svr5__)
3065         "/bin/ksh",             /* Korn shell */
3066         "/usr/bin/ksh",
3067 # endif /* defined(__svr4__) || defined(__svr5__) */
3068 # ifdef sgi
3069         "/sbin/sh",             /* SGI's shells really live in /sbin */
3070         "/sbin/csh",
3071         "/bin/ksh",             /* Korn shell */
3072         "/sbin/ksh",
3073         "/usr/bin/ksh",
3074         "/bin/tcsh",            /* Extended csh */
3075         "/usr/bin/tcsh",
3076 # endif /* sgi */
3077         NULL
3078 };
3079
3080 #endif /* !HASGETUSERSHELL */
3081
3082 #define WILDCARD_SHELL  "/SENDMAIL/ANY/SHELL/"
3083
3084 bool
3085 usershellok(user, shell)
3086         char *user;
3087         char *shell;
3088 {
3089 # if HASGETUSERSHELL
3090         register char *p;
3091         extern char *getusershell();
3092
3093         if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') ||
3094             ConfigLevel <= 1)
3095                 return true;
3096
3097         setusershell();
3098         while ((p = getusershell()) != NULL)
3099                 if (strcmp(p, shell) == 0 || strcmp(p, WILDCARD_SHELL) == 0)
3100                         break;
3101         endusershell();
3102         return p != NULL;
3103 # else /* HASGETUSERSHELL */
3104 #  if USEGETCONFATTR
3105         auto char *v;
3106 #  endif /* USEGETCONFATTR */
3107         register SM_FILE_T *shellf;
3108         char buf[MAXLINE];
3109
3110         if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') ||
3111             ConfigLevel <= 1)
3112                 return true;
3113
3114 #  if USEGETCONFATTR
3115         /*
3116         **  Naturally IBM has a "better" idea.....
3117         **
3118         **      What a crock.  This interface isn't documented, it is
3119         **      considered part of the security library (-ls), and it
3120         **      only works if you are running as root (since the list
3121         **      of valid shells is obviously a source of great concern).
3122         **      I recommend that you do NOT define USEGETCONFATTR,
3123         **      especially since you are going to have to set up an
3124         **      /etc/shells anyhow to handle the cases where getconfattr
3125         **      fails.
3126         */
3127
3128         if (getconfattr(SC_SYS_LOGIN, SC_SHELLS, &v, SEC_LIST) == 0 && v != NULL)
3129         {
3130                 while (*v != '\0')
3131                 {
3132                         if (strcmp(v, shell) == 0 || strcmp(v, WILDCARD_SHELL) == 0)
3133                                 return true;
3134                         v += strlen(v) + 1;
3135                 }
3136                 return false;
3137         }
3138 #  endif /* USEGETCONFATTR */
3139
3140         shellf = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, _PATH_SHELLS,
3141                             SM_IO_RDONLY, NULL);
3142         if (shellf == NULL)
3143         {
3144                 /* no /etc/shells; see if it is one of the std shells */
3145                 char **d;
3146
3147                 if (errno != ENOENT && LogLevel > 3)
3148                         sm_syslog(LOG_ERR, NOQID,
3149                                   "usershellok: cannot open %s: %s",
3150                                   _PATH_SHELLS, sm_errstring(errno));
3151
3152                 for (d = DefaultUserShells; *d != NULL; d++)
3153                 {
3154                         if (strcmp(shell, *d) == 0)
3155                                 return true;
3156                 }
3157                 return false;
3158         }
3159
3160         while (sm_io_fgets(shellf, SM_TIME_DEFAULT, buf, sizeof buf) != NULL)
3161         {
3162                 register char *p, *q;
3163
3164                 p = buf;
3165                 while (*p != '\0' && *p != '#' && *p != '/')
3166                         p++;
3167                 if (*p == '#' || *p == '\0')
3168                         continue;
3169                 q = p;
3170                 while (*p != '\0' && *p != '#' && !(isascii(*p) && isspace(*p)))
3171                         p++;
3172                 *p = '\0';
3173                 if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0)
3174                 {
3175                         (void) sm_io_close(shellf, SM_TIME_DEFAULT);
3176                         return true;
3177                 }
3178         }
3179         (void) sm_io_close(shellf, SM_TIME_DEFAULT);
3180         return false;
3181 # endif /* HASGETUSERSHELL */
3182 }
3183 /*
3184 **  FREEDISKSPACE -- see how much free space is on the queue filesystem
3185 **
3186 **      Only implemented if you have statfs.
3187 **
3188 **      Parameters:
3189 **              dir -- the directory in question.
3190 **              bsize -- a variable into which the filesystem
3191 **                      block size is stored.
3192 **
3193 **      Returns:
3194 **              The number of blocks free on the queue filesystem.
3195 **              -1 if the statfs call fails.
3196 **
3197 **      Side effects:
3198 **              Puts the filesystem block size into bsize.
3199 */
3200
3201 /* statfs types */
3202 # define SFS_NONE       0       /* no statfs implementation */
3203 # define SFS_USTAT      1       /* use ustat */
3204 # define SFS_4ARGS      2       /* use four-argument statfs call */
3205 # define SFS_VFS        3       /* use <sys/vfs.h> implementation */
3206 # define SFS_MOUNT      4       /* use <sys/mount.h> implementation */
3207 # define SFS_STATFS     5       /* use <sys/statfs.h> implementation */
3208 # define SFS_STATVFS    6       /* use <sys/statvfs.h> implementation */
3209
3210 # ifndef SFS_TYPE
3211 #  define SFS_TYPE      SFS_NONE
3212 # endif /* ! SFS_TYPE */
3213
3214 # if SFS_TYPE == SFS_USTAT
3215 #  include <ustat.h>
3216 # endif /* SFS_TYPE == SFS_USTAT */
3217 # if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS
3218 #  include <sys/statfs.h>
3219 # endif /* SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS */
3220 # if SFS_TYPE == SFS_VFS
3221 #  include <sys/vfs.h>
3222 # endif /* SFS_TYPE == SFS_VFS */
3223 # if SFS_TYPE == SFS_MOUNT
3224 #  include <sys/mount.h>
3225 # endif /* SFS_TYPE == SFS_MOUNT */
3226 # if SFS_TYPE == SFS_STATVFS
3227 #  include <sys/statvfs.h>
3228 # endif /* SFS_TYPE == SFS_STATVFS */
3229
3230 long
3231 freediskspace(dir, bsize)
3232         char *dir;
3233         long *bsize;
3234 {
3235 # if SFS_TYPE == SFS_NONE
3236         if (bsize != NULL)
3237                 *bsize = 4096L;
3238
3239         /* assume free space is plentiful */
3240         return (long) LONG_MAX;
3241 # else /* SFS_TYPE == SFS_NONE */
3242 #  if SFS_TYPE == SFS_USTAT
3243         struct ustat fs;
3244         struct stat statbuf;
3245 #   define FSBLOCKSIZE  DEV_BSIZE
3246 #   define SFS_BAVAIL   f_tfree
3247 #  else /* SFS_TYPE == SFS_USTAT */
3248 #   if defined(ultrix)
3249         struct fs_data fs;
3250 #    define SFS_BAVAIL  fd_bfreen
3251 #    define FSBLOCKSIZE 1024L
3252 #   else /* defined(ultrix) */
3253 #    if SFS_TYPE == SFS_STATVFS
3254         struct statvfs fs;
3255 #     define FSBLOCKSIZE        fs.f_frsize
3256 #    else /* SFS_TYPE == SFS_STATVFS */
3257         struct statfs fs;
3258 #     define FSBLOCKSIZE        fs.f_bsize
3259 #    endif /* SFS_TYPE == SFS_STATVFS */
3260 #   endif /* defined(ultrix) */
3261 #  endif /* SFS_TYPE == SFS_USTAT */
3262 #  ifndef SFS_BAVAIL
3263 #   define SFS_BAVAIL f_bavail
3264 #  endif /* ! SFS_BAVAIL */
3265
3266 #  if SFS_TYPE == SFS_USTAT
3267         if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0)
3268 #  else /* SFS_TYPE == SFS_USTAT */
3269 #   if SFS_TYPE == SFS_4ARGS
3270         if (statfs(dir, &fs, sizeof fs, 0) == 0)
3271 #   else /* SFS_TYPE == SFS_4ARGS */
3272 #    if SFS_TYPE == SFS_STATVFS
3273         if (statvfs(dir, &fs) == 0)
3274 #    else /* SFS_TYPE == SFS_STATVFS */
3275 #     if defined(ultrix)
3276         if (statfs(dir, &fs) > 0)
3277 #     else /* defined(ultrix) */
3278         if (statfs(dir, &fs) == 0)
3279 #     endif /* defined(ultrix) */
3280 #    endif /* SFS_TYPE == SFS_STATVFS */
3281 #   endif /* SFS_TYPE == SFS_4ARGS */
3282 #  endif /* SFS_TYPE == SFS_USTAT */
3283         {
3284                 if (bsize != NULL)
3285                         *bsize = FSBLOCKSIZE;
3286                 if (fs.SFS_BAVAIL <= 0)
3287                         return 0;
3288                 else if (fs.SFS_BAVAIL > LONG_MAX)
3289                         return (long) LONG_MAX;
3290                 else
3291                         return (long) fs.SFS_BAVAIL;
3292         }
3293         return -1;
3294 # endif /* SFS_TYPE == SFS_NONE */
3295 }
3296 /*
3297 **  ENOUGHDISKSPACE -- is there enough free space on the queue file systems?
3298 **
3299 **      Parameters:
3300 **              msize -- the size to check against.  If zero, we don't yet
3301 **              know how big the message will be, so just check for
3302 **              a "reasonable" amount.
3303 **              e -- envelope, or NULL -- controls logging
3304 **
3305 **      Returns:
3306 **              true if in every queue group there is at least one
3307 **              queue directory whose file system contains enough free space.
3308 **              false otherwise.
3309 **
3310 **      Side Effects:
3311 **              If there is not enough disk space and e != NULL
3312 **              then sm_syslog is called.
3313 */
3314
3315 bool
3316 enoughdiskspace(msize, e)
3317         long msize;
3318         ENVELOPE *e;
3319 {
3320         int i;
3321
3322         if (MinBlocksFree <= 0 && msize <= 0)
3323         {
3324                 if (tTd(4, 80))
3325                         sm_dprintf("enoughdiskspace: no threshold\n");
3326                 return true;
3327         }
3328
3329         filesys_update();
3330         for (i = 0; i < NumQueue; ++i)
3331         {
3332                 if (pickqdir(Queue[i], msize, e) < 0)
3333                         return false;
3334         }
3335         return true;
3336 }
3337 /*
3338 **  TRANSIENTERROR -- tell if an error code indicates a transient failure
3339 **
3340 **      This looks at an errno value and tells if this is likely to
3341 **      go away if retried later.
3342 **
3343 **      Parameters:
3344 **              err -- the errno code to classify.
3345 **
3346 **      Returns:
3347 **              true if this is probably transient.
3348 **              false otherwise.
3349 */
3350
3351 bool
3352 transienterror(err)
3353         int err;
3354 {
3355         switch (err)
3356         {
3357           case EIO:                     /* I/O error */
3358           case ENXIO:                   /* Device not configured */
3359           case EAGAIN:                  /* Resource temporarily unavailable */
3360           case ENOMEM:                  /* Cannot allocate memory */
3361           case ENODEV:                  /* Operation not supported by device */
3362           case ENFILE:                  /* Too many open files in system */
3363           case EMFILE:                  /* Too many open files */
3364           case ENOSPC:                  /* No space left on device */
3365           case ETIMEDOUT:               /* Connection timed out */
3366 #ifdef ESTALE
3367           case ESTALE:                  /* Stale NFS file handle */
3368 #endif /* ESTALE */
3369 #ifdef ENETDOWN
3370           case ENETDOWN:                /* Network is down */
3371 #endif /* ENETDOWN */
3372 #ifdef ENETUNREACH
3373           case ENETUNREACH:             /* Network is unreachable */
3374 #endif /* ENETUNREACH */
3375 #ifdef ENETRESET
3376           case ENETRESET:               /* Network dropped connection on reset */
3377 #endif /* ENETRESET */
3378 #ifdef ECONNABORTED
3379           case ECONNABORTED:            /* Software caused connection abort */
3380 #endif /* ECONNABORTED */
3381 #ifdef ECONNRESET
3382           case ECONNRESET:              /* Connection reset by peer */
3383 #endif /* ECONNRESET */
3384 #ifdef ENOBUFS
3385           case ENOBUFS:                 /* No buffer space available */
3386 #endif /* ENOBUFS */
3387 #ifdef ESHUTDOWN
3388           case ESHUTDOWN:               /* Can't send after socket shutdown */
3389 #endif /* ESHUTDOWN */
3390 #ifdef ECONNREFUSED
3391           case ECONNREFUSED:            /* Connection refused */
3392 #endif /* ECONNREFUSED */
3393 #ifdef EHOSTDOWN
3394           case EHOSTDOWN:               /* Host is down */
3395 #endif /* EHOSTDOWN */
3396 #ifdef EHOSTUNREACH
3397           case EHOSTUNREACH:            /* No route to host */
3398 #endif /* EHOSTUNREACH */
3399 #ifdef EDQUOT
3400           case EDQUOT:                  /* Disc quota exceeded */
3401 #endif /* EDQUOT */
3402 #ifdef EPROCLIM
3403           case EPROCLIM:                /* Too many processes */
3404 #endif /* EPROCLIM */
3405 #ifdef EUSERS
3406           case EUSERS:                  /* Too many users */
3407 #endif /* EUSERS */
3408 #ifdef EDEADLK
3409           case EDEADLK:                 /* Resource deadlock avoided */
3410 #endif /* EDEADLK */
3411 #ifdef EISCONN
3412           case EISCONN:                 /* Socket already connected */
3413 #endif /* EISCONN */
3414 #ifdef EINPROGRESS
3415           case EINPROGRESS:             /* Operation now in progress */
3416 #endif /* EINPROGRESS */
3417 #ifdef EALREADY
3418           case EALREADY:                /* Operation already in progress */
3419 #endif /* EALREADY */
3420 #ifdef EADDRINUSE
3421           case EADDRINUSE:              /* Address already in use */
3422 #endif /* EADDRINUSE */
3423 #ifdef EADDRNOTAVAIL
3424           case EADDRNOTAVAIL:           /* Can't assign requested address */
3425 #endif /* EADDRNOTAVAIL */
3426 #ifdef ETXTBSY
3427           case ETXTBSY:                 /* (Apollo) file locked */
3428 #endif /* ETXTBSY */
3429 #if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR))
3430           case ENOSR:                   /* Out of streams resources */
3431 #endif /* defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) */
3432 #ifdef ENOLCK
3433           case ENOLCK:                  /* No locks available */
3434 #endif /* ENOLCK */
3435           case E_SM_OPENTIMEOUT:        /* PSEUDO: open timed out */
3436                 return true;
3437         }
3438
3439         /* nope, must be permanent */
3440         return false;
3441 }
3442 /*
3443 **  LOCKFILE -- lock a file using flock or (shudder) fcntl locking
3444 **
3445 **      Parameters:
3446 **              fd -- the file descriptor of the file.
3447 **              filename -- the file name (for error messages).
3448 **              ext -- the filename extension.
3449 **              type -- type of the lock.  Bits can be:
3450 **                      LOCK_EX -- exclusive lock.
3451 **                      LOCK_NB -- non-blocking.
3452 **                      LOCK_UN -- unlock.
3453 **
3454 **      Returns:
3455 **              true if the lock was acquired.
3456 **              false otherwise.
3457 */
3458
3459 bool
3460 lockfile(fd, filename, ext, type)
3461         int fd;
3462         char *filename;
3463         char *ext;
3464         int type;
3465 {
3466         int i;
3467         int save_errno;
3468 # if !HASFLOCK
3469         int action;
3470         struct flock lfd;
3471
3472         if (ext == NULL)
3473                 ext = "";
3474
3475         memset(&lfd, '\0', sizeof lfd);
3476         if (bitset(LOCK_UN, type))
3477                 lfd.l_type = F_UNLCK;
3478         else if (bitset(LOCK_EX, type))
3479                 lfd.l_type = F_WRLCK;
3480         else
3481                 lfd.l_type = F_RDLCK;
3482
3483         if (bitset(LOCK_NB, type))
3484                 action = F_SETLK;
3485         else
3486                 action = F_SETLKW;
3487
3488         if (tTd(55, 60))
3489                 sm_dprintf("lockfile(%s%s, action=%d, type=%d): ",
3490                         filename, ext, action, lfd.l_type);
3491
3492         while ((i = fcntl(fd, action, &lfd)) < 0 && errno == EINTR)
3493                 continue;
3494         if (i >= 0)
3495         {
3496                 if (tTd(55, 60))
3497                         sm_dprintf("SUCCESS\n");
3498                 return true;
3499         }
3500         save_errno = errno;
3501
3502         if (tTd(55, 60))
3503                 sm_dprintf("(%s) ", sm_errstring(save_errno));
3504
3505         /*
3506         **  On SunOS, if you are testing using -oQ/tmp/mqueue or
3507         **  -oA/tmp/aliases or anything like that, and /tmp is mounted
3508         **  as type "tmp" (that is, served from swap space), the
3509         **  previous fcntl will fail with "Invalid argument" errors.
3510         **  Since this is fairly common during testing, we will assume
3511         **  that this indicates that the lock is successfully grabbed.
3512         */
3513
3514         if (save_errno == EINVAL)
3515         {
3516                 if (tTd(55, 60))
3517                         sm_dprintf("SUCCESS\n");
3518                 return true;
3519         }
3520
3521         if (!bitset(LOCK_NB, type) ||
3522             (save_errno != EACCES && save_errno != EAGAIN))
3523         {
3524                 int omode = fcntl(fd, F_GETFL, 0);
3525                 uid_t euid = geteuid();
3526
3527                 errno = save_errno;
3528                 syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
3529                        filename, ext, fd, type, omode, euid);
3530                 dumpfd(fd, true, true);
3531         }
3532 # else /* !HASFLOCK */
3533         if (ext == NULL)
3534                 ext = "";
3535
3536         if (tTd(55, 60))
3537                 sm_dprintf("lockfile(%s%s, type=%o): ", filename, ext, type);
3538
3539         while ((i = flock(fd, type)) < 0 && errno == EINTR)
3540                 continue;
3541         if (i >= 0)
3542         {
3543                 if (tTd(55, 60))
3544                         sm_dprintf("SUCCESS\n");
3545                 return true;
3546         }
3547         save_errno = errno;
3548
3549         if (tTd(55, 60))
3550                 sm_dprintf("(%s) ", sm_errstring(save_errno));
3551
3552         if (!bitset(LOCK_NB, type) || save_errno != EWOULDBLOCK)
3553         {
3554                 int omode = fcntl(fd, F_GETFL, 0);
3555                 uid_t euid = geteuid();
3556
3557                 errno = save_errno;
3558                 syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
3559                         filename, ext, fd, type, omode, euid);
3560                 dumpfd(fd, true, true);
3561         }
3562 # endif /* !HASFLOCK */
3563         if (tTd(55, 60))
3564                 sm_dprintf("FAIL\n");
3565         errno = save_errno;
3566         return false;
3567 }
3568 /*
3569 **  CHOWNSAFE -- tell if chown is "safe" (executable only by root)
3570 **
3571 **      Unfortunately, given that we can't predict other systems on which
3572 **      a remote mounted (NFS) filesystem will be mounted, the answer is
3573 **      almost always that this is unsafe.
3574 **
3575 **      Note also that many operating systems have non-compliant
3576 **      implementations of the _POSIX_CHOWN_RESTRICTED variable and the
3577 **      fpathconf() routine.  According to IEEE 1003.1-1990, if
3578 **      _POSIX_CHOWN_RESTRICTED is defined and not equal to -1, then
3579 **      no non-root process can give away the file.  However, vendors
3580 **      don't take NFS into account, so a comfortable value of
3581 **      _POSIX_CHOWN_RESTRICTED tells us nothing.
3582 **
3583 **      Also, some systems (e.g., IRIX 6.2) return 1 from fpathconf()
3584 **      even on files where chown is not restricted.  Many systems get
3585 **      this wrong on NFS-based filesystems (that is, they say that chown
3586 **      is restricted [safe] on NFS filesystems where it may not be, since
3587 **      other systems can access the same filesystem and do file giveaway;
3588 **      only the NFS server knows for sure!)  Hence, it is important to
3589 **      get the value of SAFENFSPATHCONF correct -- it should be defined
3590 **      _only_ after testing (see test/t_pathconf.c) a system on an unsafe
3591 **      NFS-based filesystem to ensure that you can get meaningful results.
3592 **      If in doubt, assume unsafe!
3593 **
3594 **      You may also need to tweak IS_SAFE_CHOWN -- it should be a
3595 **      condition indicating whether the return from pathconf indicates
3596 **      that chown is safe (typically either > 0 or >= 0 -- there isn't
3597 **      even any agreement about whether a zero return means that a file
3598 **      is or is not safe).  It defaults to "> 0".
3599 **
3600 **      If the parent directory is safe (writable only by owner back
3601 **      to the root) then we can relax slightly and trust fpathconf
3602 **      in more circumstances.  This is really a crock -- if this is an
3603 **      NFS mounted filesystem then we really know nothing about the
3604 **      underlying implementation.  However, most systems pessimize and
3605 **      return an error (EINVAL or EOPNOTSUPP) on NFS filesystems, which
3606 **      we interpret as unsafe, as we should.  Thus, this heuristic gets
3607 **      us into a possible problem only on systems that have a broken
3608 **      pathconf implementation and which are also poorly configured
3609 **      (have :include: files in group- or world-writable directories).
3610 **
3611 **      Parameters:
3612 **              fd -- the file descriptor to check.
3613 **              safedir -- set if the parent directory is safe.
3614 **
3615 **      Returns:
3616 **              true -- if the chown(2) operation is "safe" -- that is,
3617 **                      only root can chown the file to an arbitrary user.
3618 **              false -- if an arbitrary user can give away a file.
3619 */
3620
3621 #ifndef IS_SAFE_CHOWN
3622 # define IS_SAFE_CHOWN  > 0
3623 #endif /* ! IS_SAFE_CHOWN */
3624
3625 bool
3626 chownsafe(fd, safedir)
3627         int fd;
3628         bool safedir;
3629 {
3630 # if (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \
3631     (defined(_PC_CHOWN_RESTRICTED) || defined(_GNU_TYPES_H))
3632         int rval;
3633
3634         /* give the system administrator a chance to override */
3635         if (bitnset(DBS_ASSUMESAFECHOWN, DontBlameSendmail))
3636                 return true;
3637
3638         /*
3639         **  Some systems (e.g., SunOS) seem to have the call and the
3640         **  #define _PC_CHOWN_RESTRICTED, but don't actually implement
3641         **  the call.  This heuristic checks for that.
3642         */
3643
3644         errno = 0;
3645         rval = fpathconf(fd, _PC_CHOWN_RESTRICTED);
3646 #  if SAFENFSPATHCONF
3647         return errno == 0 && rval IS_SAFE_CHOWN;
3648 #  else /* SAFENFSPATHCONF */
3649         return safedir && errno == 0 && rval IS_SAFE_CHOWN;
3650 #  endif /* SAFENFSPATHCONF */
3651 # else /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && ... */
3652         return bitnset(DBS_ASSUMESAFECHOWN, DontBlameSendmail);
3653 # endif /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && ... */
3654 }
3655 /*
3656 **  RESETLIMITS -- reset system controlled resource limits
3657 **
3658 **      This is to avoid denial-of-service attacks
3659 **
3660 **      Parameters:
3661 **              none
3662 **
3663 **      Returns:
3664 **              none
3665 */
3666
3667 #if HASSETRLIMIT
3668 # ifdef RLIMIT_NEEDS_SYS_TIME_H
3669 #  include <sys/time.h>
3670 # endif /* RLIMIT_NEEDS_SYS_TIME_H */
3671 # include <sys/resource.h>
3672 #endif /* HASSETRLIMIT */
3673 #ifndef FD_SETSIZE
3674 # define FD_SETSIZE     256
3675 #endif /* ! FD_SETSIZE */
3676
3677 void
3678 resetlimits()
3679 {
3680 #if HASSETRLIMIT
3681         struct rlimit lim;
3682
3683         lim.rlim_cur = lim.rlim_max = RLIM_INFINITY;
3684         (void) setrlimit(RLIMIT_CPU, &lim);
3685         (void) setrlimit(RLIMIT_FSIZE, &lim);
3686 # ifdef RLIMIT_NOFILE
3687         lim.rlim_cur = lim.rlim_max = FD_SETSIZE;
3688         (void) setrlimit(RLIMIT_NOFILE, &lim);
3689 # endif /* RLIMIT_NOFILE */
3690 #else /* HASSETRLIMIT */
3691 # if HASULIMIT
3692         (void) ulimit(2, 0x3fffff);
3693         (void) ulimit(4, FD_SETSIZE);
3694 # endif /* HASULIMIT */
3695 #endif /* HASSETRLIMIT */
3696         errno = 0;
3697 }
3698 /*
3699 **  SETVENDOR -- process vendor code from V configuration line
3700 **
3701 **      Parameters:
3702 **              vendor -- string representation of vendor.
3703 **
3704 **      Returns:
3705 **              true -- if ok.
3706 **              false -- if vendor code could not be processed.
3707 **
3708 **      Side Effects:
3709 **              It is reasonable to set mode flags here to tweak
3710 **              processing in other parts of the code if necessary.
3711 **              For example, if you are a vendor that uses $%y to
3712 **              indicate YP lookups, you could enable that here.
3713 */
3714
3715 bool
3716 setvendor(vendor)
3717         char *vendor;
3718 {
3719         if (sm_strcasecmp(vendor, "Berkeley") == 0)
3720         {
3721                 VendorCode = VENDOR_BERKELEY;
3722                 return true;
3723         }
3724
3725         /* add vendor extensions here */
3726
3727 #ifdef SUN_EXTENSIONS
3728         if (sm_strcasecmp(vendor, "Sun") == 0)
3729         {
3730                 VendorCode = VENDOR_SUN;
3731                 return true;
3732         }
3733 #endif /* SUN_EXTENSIONS */
3734
3735 #if defined(VENDOR_NAME) && defined(VENDOR_CODE)
3736         if (sm_strcasecmp(vendor, VENDOR_NAME) == 0)
3737         {
3738                 VendorCode = VENDOR_CODE;
3739                 return true;
3740         }
3741 #endif /* defined(VENDOR_NAME) && defined(VENDOR_CODE) */
3742
3743         return false;
3744 }
3745 /*
3746 **  GETVENDOR -- return vendor name based on vendor code
3747 **
3748 **      Parameters:
3749 **              vendorcode -- numeric representation of vendor.
3750 **
3751 **      Returns:
3752 **              string containing vendor name.
3753 */
3754
3755 char *
3756 getvendor(vendorcode)
3757         int vendorcode;
3758 {
3759 #if defined(VENDOR_NAME) && defined(VENDOR_CODE)
3760         /*
3761         **  Can't have the same switch case twice so need to
3762         **  handle VENDOR_CODE outside of switch.  It might
3763         **  match one of the existing VENDOR_* codes.
3764         */
3765
3766         if (vendorcode == VENDOR_CODE)
3767                 return VENDOR_NAME;
3768 #endif /* defined(VENDOR_NAME) && defined(VENDOR_CODE) */
3769
3770         switch (vendorcode)
3771         {
3772           case VENDOR_BERKELEY:
3773                 return "Berkeley";
3774
3775           case VENDOR_SUN:
3776                 return "Sun";
3777
3778           case VENDOR_HP:
3779                 return "HP";
3780
3781           case VENDOR_IBM:
3782                 return "IBM";
3783
3784           case VENDOR_SENDMAIL:
3785                 return "Sendmail";
3786
3787           default:
3788                 return "Unknown";
3789         }
3790 }
3791 /*
3792 **  VENDOR_PRE_DEFAULTS, VENDOR_POST_DEFAULTS -- set vendor-specific defaults
3793 **
3794 **      Vendor_pre_defaults is called before reading the configuration
3795 **      file; vendor_post_defaults is called immediately after.
3796 **
3797 **      Parameters:
3798 **              e -- the global environment to initialize.
3799 **
3800 **      Returns:
3801 **              none.
3802 */
3803
3804 #if SHARE_V1
3805 int     DefShareUid;    /* default share uid to run as -- unused??? */
3806 #endif /* SHARE_V1 */
3807
3808 void
3809 vendor_pre_defaults(e)
3810         ENVELOPE *e;
3811 {
3812 #if SHARE_V1
3813         /* OTHERUID is defined in shares.h, do not be alarmed */
3814         DefShareUid = OTHERUID;
3815 #endif /* SHARE_V1 */
3816 #if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES)
3817         sun_pre_defaults(e);
3818 #endif /* defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) */
3819 #ifdef apollo
3820         /*
3821         **  stupid domain/os can't even open
3822         **  /etc/mail/sendmail.cf without this
3823         */
3824
3825         setuserenv("ISP", NULL);
3826         setuserenv("SYSTYPE", NULL);
3827 #endif /* apollo */
3828 }
3829
3830
3831 void
3832 vendor_post_defaults(e)
3833         ENVELOPE *e;
3834 {
3835 #ifdef __QNX__
3836         char *p;
3837
3838         /* Makes sure the SOCK environment variable remains */
3839         if (p = getextenv("SOCK"))
3840                 setuserenv("SOCK", p);
3841 #endif /* __QNX__ */
3842 #if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES)
3843         sun_post_defaults(e);
3844 #endif /* defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) */
3845 }
3846 /*
3847 **  VENDOR_DAEMON_SETUP -- special vendor setup needed for daemon mode
3848 */
3849
3850 void
3851 vendor_daemon_setup(e)
3852         ENVELOPE *e;
3853 {
3854 #if HASSETLOGIN
3855         (void) setlogin(RunAsUserName);
3856 #endif /* HASSETLOGIN */
3857 #if SECUREWARE
3858         if (getluid() != -1)
3859         {
3860                 usrerr("Daemon cannot have LUID");
3861                 finis(false, true, EX_USAGE);
3862         }
3863 #endif /* SECUREWARE */
3864 }
3865 /*
3866 **  VENDOR_SET_UID -- do setup for setting a user id
3867 **
3868 **      This is called when we are still root.
3869 **
3870 **      Parameters:
3871 **              uid -- the uid we are about to become.
3872 **
3873 **      Returns:
3874 **              none.
3875 */
3876
3877 void
3878 vendor_set_uid(uid)
3879         UID_T uid;
3880 {
3881         /*
3882         **  We need to setup the share groups (lnodes)
3883         **  and add auditing information (luid's)
3884         **  before we loose our ``root''ness.
3885         */
3886 #if SHARE_V1
3887         if (setupshares(uid, syserr) != 0)
3888                 syserr("Unable to set up shares");
3889 #endif /* SHARE_V1 */
3890 #if SECUREWARE
3891         (void) setup_secure(uid);
3892 #endif /* SECUREWARE */
3893 }
3894 /*
3895 **  VALIDATE_CONNECTION -- check connection for rationality
3896 **
3897 **      If the connection is rejected, this routine should log an
3898 **      appropriate message -- but should never issue any SMTP protocol.
3899 **
3900 **      Parameters:
3901 **              sap -- a pointer to a SOCKADDR naming the peer.
3902 **              hostname -- the name corresponding to sap.
3903 **              e -- the current envelope.
3904 **
3905 **      Returns:
3906 **              error message from rejection.
3907 **              NULL if not rejected.
3908 */
3909
3910 #if TCPWRAPPERS
3911 # include <tcpd.h>
3912
3913 /* tcpwrappers does no logging, but you still have to declare these -- ugh */
3914 int     allow_severity  = LOG_INFO;
3915 int     deny_severity   = LOG_NOTICE;
3916 #endif /* TCPWRAPPERS */
3917
3918 char *
3919 validate_connection(sap, hostname, e)
3920         SOCKADDR *sap;
3921         char *hostname;
3922         ENVELOPE *e;
3923 {
3924 #if TCPWRAPPERS
3925         char *host;
3926         char *addr;
3927         extern int hosts_ctl();
3928 #endif /* TCPWRAPPERS */
3929
3930         if (tTd(48, 3))
3931                 sm_dprintf("validate_connection(%s, %s)\n",
3932                         hostname, anynet_ntoa(sap));
3933
3934         if (rscheck("check_relay", hostname, anynet_ntoa(sap),
3935                     e, true, true, 3, NULL, NOQID) != EX_OK)
3936         {
3937                 static char reject[BUFSIZ*2];
3938                 extern char MsgBuf[];
3939
3940                 if (tTd(48, 4))
3941                         sm_dprintf("  ... validate_connection: BAD (rscheck)\n");
3942
3943                 if (strlen(MsgBuf) >= 3)
3944                         (void) sm_strlcpy(reject, MsgBuf, sizeof reject);
3945                 else
3946                         (void) sm_strlcpy(reject, "Access denied", sizeof reject);
3947
3948                 return reject;
3949         }
3950
3951 #if TCPWRAPPERS
3952         if (hostname[0] == '[' && hostname[strlen(hostname) - 1] == ']')
3953                 host = "unknown";
3954         else
3955                 host = hostname;
3956         addr = anynet_ntoa(sap);
3957
3958 # if NETINET6
3959         /* TCP/Wrappers don't want the IPv6: protocol label */
3960         if (addr != NULL && sm_strncasecmp(addr, "IPv6:", 5) == 0)
3961                 addr += 5;
3962 # endif /* NETINET6 */
3963
3964         if (!hosts_ctl("sendmail", host, addr, STRING_UNKNOWN))
3965         {
3966                 if (tTd(48, 4))
3967                         sm_dprintf("  ... validate_connection: BAD (tcpwrappers)\n");
3968                 if (LogLevel > 3)
3969                         sm_syslog(LOG_NOTICE, e->e_id,
3970                                   "tcpwrappers (%s, %s) rejection",
3971                                   host, addr);
3972                 return "Access denied";
3973         }
3974 #endif /* TCPWRAPPERS */
3975         if (tTd(48, 4))
3976                 sm_dprintf("  ... validate_connection: OK\n");
3977         return NULL;
3978 }
3979
3980 /*
3981 **  STRTOL -- convert string to long integer
3982 **
3983 **      For systems that don't have it in the C library.
3984 **
3985 **      This is taken verbatim from the 4.4-Lite C library.
3986 */
3987
3988 #if NEEDSTRTOL
3989
3990 # if defined(LIBC_SCCS) && !defined(lint)
3991 static char sccsid[] = "@(#)strtol.c    8.1 (Berkeley) 6/4/93";
3992 # endif /* defined(LIBC_SCCS) && !defined(lint) */
3993
3994 /*
3995 **  Convert a string to a long integer.
3996 **
3997 **  Ignores `locale' stuff.  Assumes that the upper and lower case
3998 **  alphabets and digits are each contiguous.
3999 */
4000
4001 long
4002 strtol(nptr, endptr, base)
4003         const char *nptr;
4004         char **endptr;
4005         register int base;
4006 {
4007         register const char *s = nptr;
4008         register unsigned long acc;
4009         register int c;
4010         register unsigned long cutoff;
4011         register int neg = 0, any, cutlim;
4012
4013         /*
4014         **  Skip white space and pick up leading +/- sign if any.
4015         **  If base is 0, allow 0x for hex and 0 for octal, else
4016         **  assume decimal; if base is already 16, allow 0x.
4017         */
4018         do {
4019                 c = *s++;
4020         } while (isspace(c));
4021         if (c == '-') {
4022                 neg = 1;
4023                 c = *s++;
4024         } else if (c == '+')
4025                 c = *s++;
4026         if ((base == 0 || base == 16) &&
4027             c == '0' && (*s == 'x' || *s == 'X')) {
4028                 c = s[1];
4029                 s += 2;
4030                 base = 16;
4031         }
4032         if (base == 0)
4033                 base = c == '0' ? 8 : 10;
4034
4035         /*
4036         **  Compute the cutoff value between legal numbers and illegal
4037         **  numbers.  That is the largest legal value, divided by the
4038         **  base.  An input number that is greater than this value, if
4039         **  followed by a legal input character, is too big.  One that
4040         **  is equal to this value may be valid or not; the limit
4041         **  between valid and invalid numbers is then based on the last
4042         **  digit.  For instance, if the range for longs is
4043         **  [-2147483648..2147483647] and the input base is 10,
4044         **  cutoff will be set to 214748364 and cutlim to either
4045         **  7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
4046         **  a value > 214748364, or equal but the next digit is > 7 (or 8),
4047         **  the number is too big, and we will return a range error.
4048         **
4049         **  Set any if any `digits' consumed; make it negative to indicate
4050         **  overflow.
4051         */
4052         cutoff = neg ? -(unsigned long) LONG_MIN : LONG_MAX;
4053         cutlim = cutoff % (unsigned long) base;
4054         cutoff /= (unsigned long) base;
4055         for (acc = 0, any = 0;; c = *s++) {
4056                 if (isdigit(c))
4057                         c -= '0';
4058                 else if (isalpha(c))
4059                         c -= isupper(c) ? 'A' - 10 : 'a' - 10;
4060                 else
4061                         break;
4062                 if (c >= base)
4063                         break;
4064                 if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
4065                         any = -1;
4066                 else {
4067                         any = 1;
4068                         acc *= base;
4069                         acc += c;
4070                 }
4071         }
4072         if (any < 0) {
4073                 acc = neg ? LONG_MIN : LONG_MAX;
4074                 errno = ERANGE;
4075         } else if (neg)
4076                 acc = -acc;
4077         if (endptr != 0)
4078                 *endptr = (char *)(any ? s - 1 : nptr);
4079         return acc;
4080 }
4081
4082 #endif /* NEEDSTRTOL */
4083 /*
4084 **  STRSTR -- find first substring in string
4085 **
4086 **      Parameters:
4087 **              big -- the big (full) string.
4088 **              little -- the little (sub) string.
4089 **
4090 **      Returns:
4091 **              A pointer to the first instance of little in big.
4092 **              big if little is the null string.
4093 **              NULL if little is not contained in big.
4094 */
4095
4096 #if NEEDSTRSTR
4097
4098 char *
4099 strstr(big, little)
4100         char *big;
4101         char *little;
4102 {
4103         register char *p = big;
4104         int l;
4105
4106         if (*little == '\0')
4107                 return big;
4108         l = strlen(little);
4109
4110         while ((p = strchr(p, *little)) != NULL)
4111         {
4112                 if (strncmp(p, little, l) == 0)
4113                         return p;
4114                 p++;
4115         }
4116         return NULL;
4117 }
4118
4119 #endif /* NEEDSTRSTR */
4120 /*
4121 **  SM_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX
4122 **
4123 **      Some operating systems have wierd problems with the gethostbyXXX
4124 **      routines.  For example, Solaris versions at least through 2.3
4125 **      don't properly deliver a canonical h_name field.  This tries to
4126 **      work around these problems.
4127 **
4128 **      Support IPv6 as well as IPv4.
4129 */
4130
4131 #if NETINET6 && NEEDSGETIPNODE
4132
4133 # ifndef AI_DEFAULT
4134 #  define AI_DEFAULT    0       /* dummy */
4135 # endif /* ! AI_DEFAULT */
4136 # ifndef AI_ADDRCONFIG
4137 #  define AI_ADDRCONFIG 0       /* dummy */
4138 # endif /* ! AI_ADDRCONFIG */
4139 # ifndef AI_V4MAPPED
4140 #  define AI_V4MAPPED   0       /* dummy */
4141 # endif /* ! AI_V4MAPPED */
4142 # ifndef AI_ALL
4143 #  define AI_ALL        0       /* dummy */
4144 # endif /* ! AI_ALL */
4145
4146 static struct hostent *
4147 getipnodebyname(name, family, flags, err)
4148         char *name;
4149         int family;
4150         int flags;
4151         int *err;
4152 {
4153         bool resv6 = true;
4154         struct hostent *h;
4155
4156         if (family == AF_INET6)
4157         {
4158                 /* From RFC2133, section 6.1 */
4159                 resv6 = bitset(RES_USE_INET6, _res.options);
4160                 _res.options |= RES_USE_INET6;
4161         }
4162         SM_SET_H_ERRNO(0);
4163         h = gethostbyname(name);
4164         if (!resv6)
4165                 _res.options &= ~RES_USE_INET6;
4166         *err = h_errno;
4167         return h;
4168 }
4169
4170 static struct hostent *
4171 getipnodebyaddr(addr, len, family, err)
4172         char *addr;
4173         int len;
4174         int family;
4175         int *err;
4176 {
4177         struct hostent *h;
4178
4179         SM_SET_H_ERRNO(0);
4180         h = gethostbyaddr(addr, len, family);
4181         *err = h_errno;
4182         return h;
4183 }
4184
4185 void
4186 freehostent(h)
4187         struct hostent *h;
4188 {
4189         /*
4190         **  Stub routine -- if they don't have getipnodeby*(),
4191         **  they probably don't have the free routine either.
4192         */
4193
4194         return;
4195 }
4196 #endif /* NETINET6 && NEEDSGETIPNODE */
4197
4198 struct hostent *
4199 sm_gethostbyname(name, family)
4200         char *name;
4201         int family;
4202 {
4203         int save_errno;
4204         struct hostent *h = NULL;
4205 #if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4))
4206 # if SOLARIS == 20300 || SOLARIS == 203
4207         static struct hostent hp;
4208         static char buf[1000];
4209         extern struct hostent *_switch_gethostbyname_r();
4210
4211         if (tTd(61, 10))
4212                 sm_dprintf("_switch_gethostbyname_r(%s)... ", name);
4213         h = _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno);
4214         save_errno = errno;
4215 # else /* SOLARIS == 20300 || SOLARIS == 203 */
4216         extern struct hostent *__switch_gethostbyname();
4217
4218         if (tTd(61, 10))
4219                 sm_dprintf("__switch_gethostbyname(%s)... ", name);
4220         h = __switch_gethostbyname(name);
4221         save_errno = errno;
4222 # endif /* SOLARIS == 20300 || SOLARIS == 203 */
4223 #else /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */
4224         int nmaps;
4225 # if NETINET6
4226         int flags = AI_DEFAULT|AI_ALL;
4227         int err;
4228 # endif /* NETINET6 */
4229         char *maptype[MAXMAPSTACK];
4230         short mapreturn[MAXMAPACTIONS];
4231         char hbuf[MAXNAME];
4232
4233         if (tTd(61, 10))
4234                 sm_dprintf("sm_gethostbyname(%s, %d)... ", name, family);
4235
4236 # if NETINET6
4237 #  if ADDRCONFIG_IS_BROKEN
4238         flags &= ~AI_ADDRCONFIG;
4239 #  endif /* ADDRCONFIG_IS_BROKEN */
4240         h = getipnodebyname(name, family, flags, &err);
4241         SM_SET_H_ERRNO(err);
4242 # else /* NETINET6 */
4243         h = gethostbyname(name);
4244 # endif /* NETINET6 */
4245
4246         save_errno = errno;
4247         if (h == NULL)
4248         {
4249                 if (tTd(61, 10))
4250                         sm_dprintf("failure\n");
4251
4252                 nmaps = switch_map_find("hosts", maptype, mapreturn);
4253                 while (--nmaps >= 0)
4254                 {
4255                         if (strcmp(maptype[nmaps], "nis") == 0 ||
4256                             strcmp(maptype[nmaps], "files") == 0)
4257                                 break;
4258                 }
4259
4260                 if (nmaps >= 0)
4261                 {
4262                         /* try short name */
4263                         if (strlen(name) > sizeof hbuf - 1)
4264                         {
4265                                 errno = save_errno;
4266                                 return NULL;
4267                         }
4268                         (void) sm_strlcpy(hbuf, name, sizeof hbuf);
4269                         (void) shorten_hostname(hbuf);
4270
4271                         /* if it hasn't been shortened, there's no point */
4272                         if (strcmp(hbuf, name) != 0)
4273                         {
4274                                 if (tTd(61, 10))
4275                                         sm_dprintf("sm_gethostbyname(%s, %d)... ",
4276                                                hbuf, family);
4277
4278 # if NETINET6
4279                                 h = getipnodebyname(hbuf, family, flags, &err);
4280                                 SM_SET_H_ERRNO(err);
4281                                 save_errno = errno;
4282 # else /* NETINET6 */
4283                                 h = gethostbyname(hbuf);
4284                                 save_errno = errno;
4285 # endif /* NETINET6 */
4286                         }
4287                 }
4288         }
4289 #endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */
4290         if (tTd(61, 10))
4291         {
4292                 if (h == NULL)
4293                         sm_dprintf("failure\n");
4294                 else
4295                 {
4296                         sm_dprintf("%s\n", h->h_name);
4297                         if (tTd(61, 11))
4298                         {
4299 #if NETINET6
4300                                 struct in6_addr ia6;
4301                                 char buf6[INET6_ADDRSTRLEN];
4302 #else /* NETINET6 */
4303                                 struct in_addr ia;
4304 #endif /* NETINET6 */
4305                                 size_t i;
4306
4307                                 if (h->h_aliases != NULL)
4308                                         for (i = 0; h->h_aliases[i] != NULL;
4309                                              i++)
4310                                                 sm_dprintf("\talias: %s\n",
4311                                                         h->h_aliases[i]);
4312                                 for (i = 0; h->h_addr_list[i] != NULL; i++)
4313                                 {
4314                                         char *addr;
4315
4316 #if NETINET6
4317                                         memmove(&ia6, h->h_addr_list[i],
4318                                                 IN6ADDRSZ);
4319                                         addr = anynet_ntop(&ia6,
4320                                                            buf6, sizeof buf6);
4321 #else /* NETINET6 */
4322                                         memmove(&ia, h->h_addr_list[i],
4323                                                 INADDRSZ);
4324                                         addr = (char *) inet_ntoa(ia);
4325 #endif /* NETINET6 */
4326                                         if (addr != NULL)
4327                                                 sm_dprintf("\taddr: %s\n", addr);
4328                                 }
4329                         }
4330                 }
4331         }
4332         errno = save_errno;
4333         return h;
4334 }
4335
4336 struct hostent *
4337 sm_gethostbyaddr(addr, len, type)
4338         char *addr;
4339         int len;
4340         int type;
4341 {
4342         struct hostent *hp;
4343
4344 #if NETINET6
4345         if (type == AF_INET6 &&
4346             IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *) addr))
4347         {
4348                 /* Avoid reverse lookup for IPv6 unspecified address */
4349                 SM_SET_H_ERRNO(HOST_NOT_FOUND);
4350                 return NULL;
4351         }
4352 #endif /* NETINET6 */
4353
4354 #if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204)
4355 # if SOLARIS == 20300 || SOLARIS == 203
4356         {
4357                 static struct hostent he;
4358                 static char buf[1000];
4359                 extern struct hostent *_switch_gethostbyaddr_r();
4360
4361                 hp = _switch_gethostbyaddr_r(addr, len, type, &he,
4362                                              buf, sizeof(buf), &h_errno);
4363         }
4364 # else /* SOLARIS == 20300 || SOLARIS == 203 */
4365         {
4366                 extern struct hostent *__switch_gethostbyaddr();
4367
4368                 hp = __switch_gethostbyaddr(addr, len, type);
4369         }
4370 # endif /* SOLARIS == 20300 || SOLARIS == 203 */
4371 #else /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) */
4372 # if NETINET6
4373         {
4374                 int err;
4375
4376                 hp = getipnodebyaddr(addr, len, type, &err);
4377                 SM_SET_H_ERRNO(err);
4378         }
4379 # else /* NETINET6 */
4380         hp = gethostbyaddr(addr, len, type);
4381 # endif /* NETINET6 */
4382 #endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) */
4383         return hp;
4384 }
4385 /*
4386 **  SM_GETPW{NAM,UID} -- wrapper for getpwnam and getpwuid
4387 */
4388
4389 struct passwd *
4390 sm_getpwnam(user)
4391         char *user;
4392 {
4393 #ifdef _AIX4
4394         extern struct passwd *_getpwnam_shadow(const char *, const int);
4395
4396         return _getpwnam_shadow(user, 0);
4397 #else /* _AIX4 */
4398         return getpwnam(user);
4399 #endif /* _AIX4 */
4400 }
4401
4402 struct passwd *
4403 sm_getpwuid(uid)
4404         UID_T uid;
4405 {
4406 #if defined(_AIX4) && 0
4407         extern struct passwd *_getpwuid_shadow(const int, const int);
4408
4409         return _getpwuid_shadow(uid,0);
4410 #else /* defined(_AIX4) && 0 */
4411         return getpwuid(uid);
4412 #endif /* defined(_AIX4) && 0 */
4413 }
4414 /*
4415 **  SECUREWARE_SETUP_SECURE -- Convex SecureWare setup
4416 **
4417 **      Set up the trusted computing environment for C2 level security
4418 **      under SecureWare.
4419 **
4420 **      Parameters:
4421 **              uid -- uid of the user to initialize in the TCB
4422 **
4423 **      Returns:
4424 **              none
4425 **
4426 **      Side Effects:
4427 **              Initialized the user in the trusted computing base
4428 */
4429
4430 #if SECUREWARE
4431
4432 # include <sys/security.h>
4433 # include <prot.h>
4434
4435 void
4436 secureware_setup_secure(uid)
4437         UID_T uid;
4438 {
4439         int rc;
4440
4441         if (getluid() != -1)
4442                 return;
4443
4444         if ((rc = set_secure_info(uid)) != SSI_GOOD_RETURN)
4445         {
4446                 switch (rc)
4447                 {
4448                   case SSI_NO_PRPW_ENTRY:
4449                         syserr("No protected passwd entry, uid = %d",
4450                                (int) uid);
4451                         break;
4452
4453                   case SSI_LOCKED:
4454                         syserr("Account has been disabled, uid = %d",
4455                                (int) uid);
4456                         break;
4457
4458                   case SSI_RETIRED:
4459                         syserr("Account has been retired, uid = %d",
4460                                (int) uid);
4461                         break;
4462
4463                   case SSI_BAD_SET_LUID:
4464                         syserr("Could not set LUID, uid = %d", (int) uid);
4465                         break;
4466
4467                   case SSI_BAD_SET_PRIVS:
4468                         syserr("Could not set kernel privs, uid = %d",
4469                                (int) uid);
4470
4471                   default:
4472                         syserr("Unknown return code (%d) from set_secure_info(%d)",
4473                                 rc, (int) uid);
4474                         break;
4475                 }
4476                 finis(false, true, EX_NOPERM);
4477         }
4478 }
4479 #endif /* SECUREWARE */
4480 /*
4481 **  ADD_HOSTNAMES -- Add a hostname to class 'w' based on IP address
4482 **
4483 **      Add hostnames to class 'w' based on the IP address read from
4484 **      the network interface.
4485 **
4486 **      Parameters:
4487 **              sa -- a pointer to a SOCKADDR containing the address
4488 **
4489 **      Returns:
4490 **              0 if successful, -1 if host lookup fails.
4491 */
4492
4493 static int
4494 add_hostnames(sa)
4495         SOCKADDR *sa;
4496 {
4497         struct hostent *hp;
4498         char **ha;
4499         char hnb[MAXHOSTNAMELEN];
4500
4501         /* lookup name with IP address */
4502         switch (sa->sa.sa_family)
4503         {
4504 #if NETINET
4505           case AF_INET:
4506                 hp = sm_gethostbyaddr((char *) &sa->sin.sin_addr,
4507                                       sizeof(sa->sin.sin_addr),
4508                                       sa->sa.sa_family);
4509                 break;
4510 #endif /* NETINET */
4511
4512 #if NETINET6
4513           case AF_INET6:
4514                 hp = sm_gethostbyaddr((char *) &sa->sin6.sin6_addr,
4515                                       sizeof(sa->sin6.sin6_addr),
4516                                       sa->sa.sa_family);
4517                 break;
4518 #endif /* NETINET6 */
4519
4520           default:
4521                 /* Give warning about unsupported family */
4522                 if (LogLevel > 3)
4523                         sm_syslog(LOG_WARNING, NOQID,
4524                                   "Unsupported address family %d: %.100s",
4525                                   sa->sa.sa_family, anynet_ntoa(sa));
4526                 return -1;
4527         }
4528
4529         if (hp == NULL)
4530         {
4531                 int save_errno = errno;
4532
4533                 if (LogLevel > 3 &&
4534 #if NETINET6
4535                     !(sa->sa.sa_family == AF_INET6 &&
4536                       IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr)) &&
4537 #endif /* NETINET6 */
4538                     true)
4539                         sm_syslog(LOG_WARNING, NOQID,
4540                                   "gethostbyaddr(%.100s) failed: %d",
4541                                   anynet_ntoa(sa),
4542 #if NAMED_BIND
4543                                   h_errno
4544 #else /* NAMED_BIND */
4545                                   -1
4546 #endif /* NAMED_BIND */
4547                                  );
4548                 errno = save_errno;
4549                 return -1;
4550         }
4551
4552         /* save its cname */
4553         if (!wordinclass((char *) hp->h_name, 'w'))
4554         {
4555                 setclass('w', (char *) hp->h_name);
4556                 if (tTd(0, 4))
4557                         sm_dprintf("\ta.k.a.: %s\n", hp->h_name);
4558
4559                 if (sm_snprintf(hnb, sizeof hnb, "[%s]", hp->h_name) < sizeof hnb
4560                     && !wordinclass((char *) hnb, 'w'))
4561                         setclass('w', hnb);
4562         }
4563         else
4564         {
4565                 if (tTd(0, 43))
4566                         sm_dprintf("\ta.k.a.: %s (already in $=w)\n", hp->h_name);
4567         }
4568
4569         /* save all it aliases name */
4570         for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++)
4571         {
4572                 if (!wordinclass(*ha, 'w'))
4573                 {
4574                         setclass('w', *ha);
4575                         if (tTd(0, 4))
4576                                 sm_dprintf("\ta.k.a.: %s\n", *ha);
4577                         if (sm_snprintf(hnb, sizeof hnb,
4578                                      "[%s]", *ha) < sizeof hnb &&
4579                             !wordinclass((char *) hnb, 'w'))
4580                                 setclass('w', hnb);
4581                 }
4582                 else
4583                 {
4584                         if (tTd(0, 43))
4585                                 sm_dprintf("\ta.k.a.: %s (already in $=w)\n",
4586                                         *ha);
4587                 }
4588         }
4589 #if NETINET6
4590         freehostent(hp);
4591 #endif /* NETINET6 */
4592         return 0;
4593 }
4594 /*
4595 **  LOAD_IF_NAMES -- load interface-specific names into $=w
4596 **
4597 **      Parameters:
4598 **              none.
4599 **
4600 **      Returns:
4601 **              none.
4602 **
4603 **      Side Effects:
4604 **              Loads $=w with the names of all the interfaces.
4605 */
4606
4607 #if !NETINET
4608 # define SIOCGIFCONF_IS_BROKEN  1 /* XXX */
4609 #endif /* !NETINET */
4610
4611 #if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
4612 struct rtentry;
4613 struct mbuf;
4614 # ifndef SUNOS403
4615 #  include <sys/time.h>
4616 # endif /* ! SUNOS403 */
4617 # if (_AIX4 >= 40300) && !defined(_NET_IF_H)
4618 #  undef __P
4619 # endif /* (_AIX4 >= 40300) && !defined(_NET_IF_H) */
4620 # include <net/if.h>
4621 #endif /* defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN */
4622
4623 void
4624 load_if_names()
4625 {
4626 # if NETINET6 && defined(SIOCGLIFCONF)
4627 #  ifdef __hpux
4628
4629     /*
4630     **  Unfortunately, HP has changed all of the structures,
4631     **  making life difficult for implementors.
4632     */
4633
4634 #   define lifconf      if_laddrconf
4635 #   define lifc_len     iflc_len
4636 #   define lifc_buf     iflc_buf
4637 #   define lifreq       if_laddrreq
4638 #   define lifr_addr    iflr_addr
4639 #   define lifr_name    iflr_name
4640 #   define lifr_flags   iflr_flags
4641 #   define ss_family    sa_family
4642 #   undef SIOCGLIFNUM
4643 #  endif /* __hpux */
4644
4645         int s;
4646         int i;
4647         size_t len;
4648         int numifs;
4649         char *buf;
4650         struct lifconf lifc;
4651 #  ifdef SIOCGLIFNUM
4652         struct lifnum lifn;
4653 #  endif /* SIOCGLIFNUM */
4654
4655         s = socket(InetMode, SOCK_DGRAM, 0);
4656         if (s == -1)
4657                 return;
4658
4659         /* get the list of known IP address from the kernel */
4660 #  ifdef __hpux
4661         i = ioctl(s, SIOCGIFNUM, (char *) &numifs);
4662 #  endif /* __hpux */
4663 #  ifdef SIOCGLIFNUM
4664         lifn.lifn_family = AF_UNSPEC;
4665         lifn.lifn_flags = 0;
4666         i = ioctl(s, SIOCGLIFNUM, (char *)&lifn);
4667         numifs = lifn.lifn_count;
4668 #  endif /* SIOCGLIFNUM */
4669
4670 #  if defined(__hpux) || defined(SIOCGLIFNUM)
4671         if (i < 0)
4672         {
4673                 /* can't get number of interfaces -- fall back */
4674                 if (tTd(0, 4))
4675                         sm_dprintf("SIOCGLIFNUM failed: %s\n",
4676                                    sm_errstring(errno));
4677                 numifs = -1;
4678         }
4679         else if (tTd(0, 42))
4680                 sm_dprintf("system has %d interfaces\n", numifs);
4681         if (numifs < 0)
4682 #  endif /* defined(__hpux) || defined(SIOCGLIFNUM) */
4683                 numifs = MAXINTERFACES;
4684
4685         if (numifs <= 0)
4686         {
4687                 (void) close(s);
4688                 return;
4689         }
4690
4691         len = lifc.lifc_len = numifs * sizeof (struct lifreq);
4692         buf = lifc.lifc_buf = xalloc(lifc.lifc_len);
4693 #  ifndef __hpux
4694         lifc.lifc_family = AF_UNSPEC;
4695         lifc.lifc_flags = 0;
4696 #  endif /* __hpux */
4697         if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0)
4698         {
4699                 if (tTd(0, 4))
4700                         sm_dprintf("SIOCGLIFCONF failed: %s\n",
4701                                    sm_errstring(errno));
4702                 (void) close(s);
4703                 sm_free(buf);
4704                 return;
4705         }
4706
4707         /* scan the list of IP address */
4708         if (tTd(0, 40))
4709                 sm_dprintf("scanning for interface specific names, lifc_len=%ld\n",
4710                            (long) len);
4711
4712         for (i = 0; i < len && i >= 0; )
4713         {
4714                 int flags;
4715                 struct lifreq *ifr = (struct lifreq *)&buf[i];
4716                 SOCKADDR *sa = (SOCKADDR *) &ifr->lifr_addr;
4717                 int af = ifr->lifr_addr.ss_family;
4718                 char *addr;
4719                 char *name;
4720                 struct in6_addr ia6;
4721                 struct in_addr ia;
4722 #  ifdef SIOCGLIFFLAGS
4723                 struct lifreq ifrf;
4724 #  endif /* SIOCGLIFFLAGS */
4725                 char ip_addr[256];
4726                 char buf6[INET6_ADDRSTRLEN];
4727
4728                 /*
4729                 **  We must close and recreate the socket each time
4730                 **  since we don't know what type of socket it is now
4731                 **  (each status function may change it).
4732                 */
4733
4734                 (void) close(s);
4735
4736                 s = socket(af, SOCK_DGRAM, 0);
4737                 if (s == -1)
4738                 {
4739                         sm_free(buf); /* XXX */
4740                         return;
4741                 }
4742
4743                 /*
4744                 **  If we don't have a complete ifr structure,
4745                 **  don't try to use it.
4746                 */
4747
4748                 if ((len - i) < sizeof *ifr)
4749                         break;
4750
4751 #  ifdef BSD4_4_SOCKADDR
4752                 if (sa->sa.sa_len > sizeof ifr->lifr_addr)
4753                         i += sizeof ifr->lifr_name + sa->sa.sa_len;
4754                 else
4755 #  endif /* BSD4_4_SOCKADDR */
4756                         i += sizeof *ifr;
4757
4758                 if (tTd(0, 20))
4759                         sm_dprintf("%s\n", anynet_ntoa(sa));
4760
4761                 if (af != AF_INET && af != AF_INET6)
4762                         continue;
4763
4764 #  ifdef SIOCGLIFFLAGS
4765                 memset(&ifrf, '\0', sizeof(struct lifreq));
4766                 (void) sm_strlcpy(ifrf.lifr_name, ifr->lifr_name,
4767                                   sizeof(ifrf.lifr_name));
4768                 if (ioctl(s, SIOCGLIFFLAGS, (char *) &ifrf) < 0)
4769                 {
4770                         if (tTd(0, 4))
4771                                 sm_dprintf("SIOCGLIFFLAGS failed: %s\n",
4772                                            sm_errstring(errno));
4773                         continue;
4774                 }
4775
4776                 name = ifr->lifr_name;
4777                 flags = ifrf.lifr_flags;
4778
4779                 if (tTd(0, 41))
4780                         sm_dprintf("\tflags: %lx\n", (unsigned long) flags);
4781
4782                 if (!bitset(IFF_UP, flags))
4783                         continue;
4784 #  endif /* SIOCGLIFFLAGS */
4785
4786                 ip_addr[0] = '\0';
4787
4788                 /* extract IP address from the list*/
4789                 switch (af)
4790                 {
4791                   case AF_INET6:
4792 #  ifdef __KAME__
4793                         /* convert into proper scoped address */
4794                         if ((IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr) ||
4795                              IN6_IS_ADDR_SITELOCAL(&sa->sin6.sin6_addr)) &&
4796                             sa->sin6.sin6_scope_id == 0)
4797                         {
4798                                 struct in6_addr *ia6p;
4799
4800                                 ia6p = &sa->sin6.sin6_addr;
4801                                 sa->sin6.sin6_scope_id = ntohs(ia6p->s6_addr[3] |
4802                                                                ((unsigned int)ia6p->s6_addr[2] << 8));
4803                                 ia6p->s6_addr[2] = ia6p->s6_addr[3] = 0;
4804                         }
4805 #  endif /* __KAME__ */
4806                         ia6 = sa->sin6.sin6_addr;
4807                         if (IN6_IS_ADDR_UNSPECIFIED(&ia6))
4808                         {
4809                                 addr = anynet_ntop(&ia6, buf6, sizeof buf6);
4810                                 message("WARNING: interface %s is UP with %s address",
4811                                         name, addr == NULL ? "(NULL)" : addr);
4812                                 continue;
4813                         }
4814
4815                         /* save IP address in text from */
4816                         addr = anynet_ntop(&ia6, buf6, sizeof buf6);
4817                         if (addr != NULL)
4818                                 (void) sm_snprintf(ip_addr, sizeof ip_addr,
4819                                                    "[%.*s]",
4820                                                    (int) sizeof ip_addr - 3,
4821                                                    addr);
4822                         break;
4823
4824                   case AF_INET:
4825                         ia = sa->sin.sin_addr;
4826                         if (ia.s_addr == INADDR_ANY ||
4827                             ia.s_addr == INADDR_NONE)
4828                         {
4829                                 message("WARNING: interface %s is UP with %s address",
4830                                         name, inet_ntoa(ia));
4831                                 continue;
4832                         }
4833
4834                         /* save IP address in text from */
4835                         (void) sm_snprintf(ip_addr, sizeof ip_addr, "[%.*s]",
4836                                         (int) sizeof ip_addr - 3, inet_ntoa(ia));
4837                         break;
4838                 }
4839
4840                 if (*ip_addr == '\0')
4841                         continue;
4842
4843                 if (!wordinclass(ip_addr, 'w'))
4844                 {
4845                         setclass('w', ip_addr);
4846                         if (tTd(0, 4))
4847                                 sm_dprintf("\ta.k.a.: %s\n", ip_addr);
4848                 }
4849
4850 #  ifdef SIOCGLIFFLAGS
4851                 /* skip "loopback" interface "lo" */
4852                 if (DontProbeInterfaces == DPI_SKIPLOOPBACK &&
4853                     bitset(IFF_LOOPBACK, flags))
4854                         continue;
4855 #  endif /* SIOCGLIFFLAGS */
4856                 (void) add_hostnames(sa);
4857         }
4858         sm_free(buf); /* XXX */
4859         (void) close(s);
4860 # else /* NETINET6 && defined(SIOCGLIFCONF) */
4861 #  if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
4862         int s;
4863         int i;
4864         struct ifconf ifc;
4865         int numifs;
4866
4867         s = socket(AF_INET, SOCK_DGRAM, 0);
4868         if (s == -1)
4869                 return;
4870
4871         /* get the list of known IP address from the kernel */
4872 #   if defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN
4873         if (ioctl(s, SIOCGIFNUM, (char *) &numifs) < 0)
4874         {
4875                 /* can't get number of interfaces -- fall back */
4876                 if (tTd(0, 4))
4877                         sm_dprintf("SIOCGIFNUM failed: %s\n",
4878                                    sm_errstring(errno));
4879                 numifs = -1;
4880         }
4881         else if (tTd(0, 42))
4882                 sm_dprintf("system has %d interfaces\n", numifs);
4883         if (numifs < 0)
4884 #   endif /* defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN */
4885                 numifs = MAXINTERFACES;
4886
4887         if (numifs <= 0)
4888         {
4889                 (void) close(s);
4890                 return;
4891         }
4892         ifc.ifc_len = numifs * sizeof (struct ifreq);
4893         ifc.ifc_buf = xalloc(ifc.ifc_len);
4894         if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0)
4895         {
4896                 if (tTd(0, 4))
4897                         sm_dprintf("SIOCGIFCONF failed: %s\n",
4898                                    sm_errstring(errno));
4899                 (void) close(s);
4900                 return;
4901         }
4902
4903         /* scan the list of IP address */
4904         if (tTd(0, 40))
4905                 sm_dprintf("scanning for interface specific names, ifc_len=%d\n",
4906                         ifc.ifc_len);
4907
4908         for (i = 0; i < ifc.ifc_len && i >= 0; )
4909         {
4910                 int af;
4911                 struct ifreq *ifr = (struct ifreq *) &ifc.ifc_buf[i];
4912                 SOCKADDR *sa = (SOCKADDR *) &ifr->ifr_addr;
4913 #   if NETINET6
4914                 char *addr;
4915                 struct in6_addr ia6;
4916 #   endif /* NETINET6 */
4917                 struct in_addr ia;
4918 #   ifdef SIOCGIFFLAGS
4919                 struct ifreq ifrf;
4920 #   endif /* SIOCGIFFLAGS */
4921                 char ip_addr[256];
4922 #   if NETINET6
4923                 char buf6[INET6_ADDRSTRLEN];
4924 #   endif /* NETINET6 */
4925
4926                 /*
4927                 **  If we don't have a complete ifr structure,
4928                 **  don't try to use it.
4929                 */
4930
4931                 if ((ifc.ifc_len - i) < sizeof *ifr)
4932                         break;
4933
4934 #   ifdef BSD4_4_SOCKADDR
4935                 if (sa->sa.sa_len > sizeof ifr->ifr_addr)
4936                         i += sizeof ifr->ifr_name + sa->sa.sa_len;
4937                 else
4938 #   endif /* BSD4_4_SOCKADDR */
4939                         i += sizeof *ifr;
4940
4941                 if (tTd(0, 20))
4942                         sm_dprintf("%s\n", anynet_ntoa(sa));
4943
4944                 af = ifr->ifr_addr.sa_family;
4945                 if (af != AF_INET
4946 #   if NETINET6
4947                     && af != AF_INET6
4948 #   endif /* NETINET6 */
4949                     )
4950                         continue;
4951
4952 #   ifdef SIOCGIFFLAGS
4953                 memset(&ifrf, '\0', sizeof(struct ifreq));
4954                 (void) sm_strlcpy(ifrf.ifr_name, ifr->ifr_name,
4955                                sizeof(ifrf.ifr_name));
4956                 (void) ioctl(s, SIOCGIFFLAGS, (char *) &ifrf);
4957                 if (tTd(0, 41))
4958                         sm_dprintf("\tflags: %lx\n",
4959                                 (unsigned long) ifrf.ifr_flags);
4960 #    define IFRFREF ifrf
4961 #   else /* SIOCGIFFLAGS */
4962 #    define IFRFREF (*ifr)
4963 #   endif /* SIOCGIFFLAGS */
4964
4965                 if (!bitset(IFF_UP, IFRFREF.ifr_flags))
4966                         continue;
4967
4968                 ip_addr[0] = '\0';
4969
4970                 /* extract IP address from the list*/
4971                 switch (af)
4972                 {
4973                   case AF_INET:
4974                         ia = sa->sin.sin_addr;
4975                         if (ia.s_addr == INADDR_ANY ||
4976                             ia.s_addr == INADDR_NONE)
4977                         {
4978                                 message("WARNING: interface %s is UP with %s address",
4979                                         ifr->ifr_name, inet_ntoa(ia));
4980                                 continue;
4981                         }
4982
4983                         /* save IP address in text from */
4984                         (void) sm_snprintf(ip_addr, sizeof ip_addr, "[%.*s]",
4985                                         (int) sizeof ip_addr - 3,
4986                                         inet_ntoa(ia));
4987                         break;
4988
4989 #   if NETINET6
4990                   case AF_INET6:
4991 #    ifdef __KAME__
4992                         /* convert into proper scoped address */
4993                         if ((IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr) ||
4994                              IN6_IS_ADDR_SITELOCAL(&sa->sin6.sin6_addr)) &&
4995                             sa->sin6.sin6_scope_id == 0)
4996                         {
4997                                 struct in6_addr *ia6p;
4998
4999                                 ia6p = &sa->sin6.sin6_addr;
5000                                 sa->sin6.sin6_scope_id = ntohs(ia6p->s6_addr[3] |
5001                                                                ((unsigned int)ia6p->s6_addr[2] << 8));
5002                                 ia6p->s6_addr[2] = ia6p->s6_addr[3] = 0;
5003                         }
5004 #    endif /* __KAME__ */
5005                         ia6 = sa->sin6.sin6_addr;
5006                         if (IN6_IS_ADDR_UNSPECIFIED(&ia6))
5007                         {
5008                                 addr = anynet_ntop(&ia6, buf6, sizeof buf6);
5009                                 message("WARNING: interface %s is UP with %s address",
5010                                         ifr->ifr_name,
5011                                         addr == NULL ? "(NULL)" : addr);
5012                                 continue;
5013                         }
5014
5015                         /* save IP address in text from */
5016                         addr = anynet_ntop(&ia6, buf6, sizeof buf6);
5017                         if (addr != NULL)
5018                                 (void) sm_snprintf(ip_addr, sizeof ip_addr,
5019                                                    "[%.*s]",
5020                                                    (int) sizeof ip_addr - 3,
5021                                                    addr);
5022                         break;
5023
5024 #   endif /* NETINET6 */
5025                 }
5026
5027                 if (ip_addr[0] == '\0')
5028                         continue;
5029
5030                 if (!wordinclass(ip_addr, 'w'))
5031                 {
5032                         setclass('w', ip_addr);
5033                         if (tTd(0, 4))
5034                                 sm_dprintf("\ta.k.a.: %s\n", ip_addr);
5035                 }
5036
5037                 /* skip "loopback" interface "lo" */
5038                 if (DontProbeInterfaces == DPI_SKIPLOOPBACK &&
5039                     bitset(IFF_LOOPBACK, IFRFREF.ifr_flags))
5040                         continue;
5041
5042                 (void) add_hostnames(sa);
5043         }
5044         sm_free(ifc.ifc_buf); /* XXX */
5045         (void) close(s);
5046 #   undef IFRFREF
5047 #  endif /* defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN */
5048 # endif /* NETINET6 && defined(SIOCGLIFCONF) */
5049 }
5050 /*
5051 **  ISLOOPBACK -- is socket address in the loopback net?
5052 **
5053 **      Parameters:
5054 **              sa -- socket address.
5055 **
5056 **      Returns:
5057 **              true -- is socket address in the loopback net?
5058 **              false -- otherwise
5059 **
5060 */
5061
5062 bool
5063 isloopback(sa)
5064         SOCKADDR sa;
5065 {
5066 #if NETINET6
5067         if (IN6_IS_ADDR_LOOPBACK(&sa.sin6.sin6_addr))
5068                 return true;
5069 #else /* NETINET6 */
5070         /* XXX how to correctly extract IN_LOOPBACKNET part? */
5071         if (((ntohl(sa.sin.sin_addr.s_addr) & IN_CLASSA_NET)
5072              >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
5073                 return true;
5074 #endif /* NETINET6 */
5075         return false;
5076 }
5077 /*
5078 **  GET_NUM_PROCS_ONLINE -- return the number of processors currently online
5079 **
5080 **      Parameters:
5081 **              none.
5082 **
5083 **      Returns:
5084 **              The number of processors online.
5085 */
5086
5087 static int
5088 get_num_procs_online()
5089 {
5090         int nproc = 0;
5091
5092 #ifdef USESYSCTL
5093 # if defined(CTL_HW) && defined(HW_NCPU)
5094         size_t sz;
5095         int mib[2];
5096
5097         mib[0] = CTL_HW;
5098         mib[1] = HW_NCPU;
5099         sz = (size_t) sizeof nproc;
5100         (void) sysctl(mib, 2, &nproc, &sz, NULL, 0);
5101 # endif /* defined(CTL_HW) && defined(HW_NCPU) */
5102 #else /* USESYSCTL */
5103 # ifdef _SC_NPROCESSORS_ONLN
5104         nproc = (int) sysconf(_SC_NPROCESSORS_ONLN);
5105 # else /* _SC_NPROCESSORS_ONLN */
5106 #  ifdef __hpux
5107 #   include <sys/pstat.h>
5108         struct pst_dynamic psd;
5109
5110         if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) != -1)
5111                 nproc = psd.psd_proc_cnt;
5112 #  endif /* __hpux */
5113 # endif /* _SC_NPROCESSORS_ONLN */
5114 #endif /* USESYSCTL */
5115
5116         if (nproc <= 0)
5117                 nproc = 1;
5118         return nproc;
5119 }
5120 /*
5121 **  SEED_RANDOM -- seed the random number generator
5122 **
5123 **      Parameters:
5124 **              none
5125 **
5126 **      Returns:
5127 **              none
5128 */
5129
5130 void
5131 seed_random()
5132 {
5133 #if HASSRANDOMDEV
5134         srandomdev();
5135 #else /* HASSRANDOMDEV */
5136         long seed;
5137         struct timeval t;
5138
5139         seed = (long) CurrentPid;
5140         if (gettimeofday(&t, NULL) >= 0)
5141                 seed += t.tv_sec + t.tv_usec;
5142
5143 # if HASRANDOM
5144         (void) srandom(seed);
5145 # else /* HASRANDOM */
5146         (void) srand((unsigned int) seed);
5147 # endif /* HASRANDOM */
5148 #endif /* HASSRANDOMDEV */
5149 }
5150 /*
5151 **  SM_SYSLOG -- syslog wrapper to keep messages under SYSLOG_BUFSIZE
5152 **
5153 **      Parameters:
5154 **              level -- syslog level
5155 **              id -- envelope ID or NULL (NOQUEUE)
5156 **              fmt -- format string
5157 **              arg... -- arguments as implied by fmt.
5158 **
5159 **      Returns:
5160 **              none
5161 */
5162
5163 /* VARARGS3 */
5164 void
5165 #ifdef __STDC__
5166 sm_syslog(int level, const char *id, const char *fmt, ...)
5167 #else /* __STDC__ */
5168 sm_syslog(level, id, fmt, va_alist)
5169         int level;
5170         const char *id;
5171         const char *fmt;
5172         va_dcl
5173 #endif /* __STDC__ */
5174 {
5175         static char *buf = NULL;
5176         static size_t bufsize;
5177         char *begin, *end;
5178         int save_errno;
5179         int seq = 1;
5180         int idlen;
5181         char buf0[MAXLINE];
5182         char *newstring;
5183         extern int SyslogPrefixLen;
5184         SM_VA_LOCAL_DECL
5185
5186         save_errno = errno;
5187         if (id == NULL)
5188         {
5189                 id = "NOQUEUE";
5190                 idlen = strlen(id) + SyslogPrefixLen;
5191         }
5192         else if (strcmp(id, NOQID) == 0)
5193         {
5194                 id = "";
5195                 idlen = SyslogPrefixLen;
5196         }
5197         else
5198                 idlen = strlen(id) + SyslogPrefixLen;
5199
5200         if (buf == NULL)
5201         {
5202                 buf = buf0;
5203                 bufsize = sizeof buf0;
5204         }
5205
5206         for (;;)
5207         {
5208                 int n;
5209
5210                 /* print log message into buf */
5211                 SM_VA_START(ap, fmt);
5212                 n = sm_vsnprintf(buf, bufsize, fmt, ap);
5213                 SM_VA_END(ap);
5214                 SM_ASSERT(n > 0);
5215                 if (n < bufsize)
5216                         break;
5217
5218                 /* String too small, redo with correct size */
5219                 bufsize = n + 1;
5220                 if (buf != buf0)
5221                 {
5222                         sm_free(buf);
5223                         buf = NULL;
5224                 }
5225                 buf = sm_malloc_x(bufsize);
5226         }
5227
5228         /* clean up buf after it has been expanded with args */
5229         newstring = str2prt(buf);
5230         if ((strlen(newstring) + idlen + 1) < SYSLOG_BUFSIZE)
5231         {
5232 #if LOG
5233                 if (*id == '\0')
5234                         syslog(level, "%s", newstring);
5235                 else
5236                         syslog(level, "%s: %s", id, newstring);
5237 #else /* LOG */
5238                 /*XXX should do something more sensible */
5239                 if (*id == '\0')
5240                         (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s\n",
5241                                              newstring);
5242                 else
5243                         (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
5244                                              "%s: %s\n", id, newstring);
5245 #endif /* LOG */
5246                 if (buf == buf0)
5247                         buf = NULL;
5248                 errno = save_errno;
5249                 return;
5250         }
5251
5252 /*
5253 **  additional length for splitting: " ..." + 3, where 3 is magic to
5254 **  have some data for the next entry.
5255 */
5256
5257 #define SL_SPLIT 7
5258
5259         begin = newstring;
5260         idlen += 5;     /* strlen("[999]"), see below */
5261         while (*begin != '\0' &&
5262                (strlen(begin) + idlen) > SYSLOG_BUFSIZE)
5263         {
5264                 char save;
5265
5266                 if (seq >= 999)
5267                 {
5268                         /* Too many messages */
5269                         break;
5270                 }
5271                 end = begin + SYSLOG_BUFSIZE - idlen - SL_SPLIT;
5272                 while (end > begin)
5273                 {
5274                         /* Break on comma or space */
5275                         if (*end == ',' || *end == ' ')
5276                         {
5277                                 end++;    /* Include separator */
5278                                 break;
5279                         }
5280                         end--;
5281                 }
5282                 /* No separator, break midstring... */
5283                 if (end == begin)
5284                         end = begin + SYSLOG_BUFSIZE - idlen - SL_SPLIT;
5285                 save = *end;
5286                 *end = 0;
5287 #if LOG
5288                 syslog(level, "%s[%d]: %s ...", id, seq++, begin);
5289 #else /* LOG */
5290                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
5291                                      "%s[%d]: %s ...\n", id, seq++, begin);
5292 #endif /* LOG */
5293                 *end = save;
5294                 begin = end;
5295         }
5296         if (seq >= 999)
5297 #if LOG
5298                 syslog(level, "%s[%d]: log terminated, too many parts",
5299                         id, seq);
5300 #else /* LOG */
5301                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
5302                               "%s[%d]: log terminated, too many parts\n", id, seq);
5303 #endif /* LOG */
5304         else if (*begin != '\0')
5305 #if LOG
5306                 syslog(level, "%s[%d]: %s", id, seq, begin);
5307 #else /* LOG */
5308                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
5309                                      "%s[%d]: %s\n", id, seq, begin);
5310 #endif /* LOG */
5311         if (buf == buf0)
5312                 buf = NULL;
5313         errno = save_errno;
5314 }
5315 /*
5316 **  HARD_SYSLOG -- call syslog repeatedly until it works
5317 **
5318 **      Needed on HP-UX, which apparently doesn't guarantee that
5319 **      syslog succeeds during interrupt handlers.
5320 */
5321
5322 #if defined(__hpux) && !defined(HPUX11)
5323
5324 # define MAXSYSLOGTRIES 100
5325 # undef syslog
5326 # ifdef V4FS
5327 #  define XCNST const
5328 #  define CAST  (const char *)
5329 # else /* V4FS */
5330 #  define XCNST
5331 #  define CAST
5332 # endif /* V4FS */
5333
5334 void
5335 # ifdef __STDC__
5336 hard_syslog(int pri, XCNST char *msg, ...)
5337 # else /* __STDC__ */
5338 hard_syslog(pri, msg, va_alist)
5339         int pri;
5340         XCNST char *msg;
5341         va_dcl
5342 # endif /* __STDC__ */
5343 {
5344         int i;
5345         char buf[SYSLOG_BUFSIZE];
5346         SM_VA_LOCAL_DECL
5347
5348         SM_VA_START(ap, msg);
5349         (void) sm_vsnprintf(buf, sizeof buf, msg, ap);
5350         SM_VA_END(ap);
5351
5352         for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, CAST "%s", buf) < 0; )
5353                 continue;
5354 }
5355
5356 # undef CAST
5357 #endif /* defined(__hpux) && !defined(HPUX11) */
5358 #if NEEDLOCAL_HOSTNAME_LENGTH
5359 /*
5360 **  LOCAL_HOSTNAME_LENGTH
5361 **
5362 **      This is required to get sendmail to compile against BIND 4.9.x
5363 **      on Ultrix.
5364 **
5365 **      Unfortunately, a Compaq Y2K patch kit provides it without
5366 **      bumping __RES in /usr/include/resolv.h so we can't automatically
5367 **      figure out whether it is needed.
5368 */
5369
5370 int
5371 local_hostname_length(hostname)
5372         char *hostname;
5373 {
5374         size_t len_host, len_domain;
5375
5376         if (!*_res.defdname)
5377                 res_init();
5378         len_host = strlen(hostname);
5379         len_domain = strlen(_res.defdname);
5380         if (len_host > len_domain &&
5381             (sm_strcasecmp(hostname + len_host - len_domain,
5382                         _res.defdname) == 0) &&
5383             hostname[len_host - len_domain - 1] == '.')
5384                 return len_host - len_domain - 1;
5385         else
5386                 return 0;
5387 }
5388 #endif /* NEEDLOCAL_HOSTNAME_LENGTH */
5389
5390 #if NEEDLINK
5391 /*
5392 **  LINK -- clone a file
5393 **
5394 **      Some OS's lacks link() and hard links.  Since sendmail is using
5395 **      link() as an efficient way to clone files, this implementation
5396 **      will simply do a file copy.
5397 **
5398 **      NOTE: This link() replacement is not a generic replacement as it
5399 **      does not handle all of the semantics of the real link(2).
5400 **
5401 **      Parameters:
5402 **              source -- pathname of existing file.
5403 **              target -- pathname of link (clone) to be created.
5404 **
5405 **      Returns:
5406 **              0 -- success.
5407 **              -1 -- failure, see errno for details.
5408 */
5409
5410 int
5411 link(source, target)
5412         const char *source;
5413         const char *target;
5414 {
5415         int save_errno;
5416         int sff;
5417         int src = -1, dst = -1;
5418         ssize_t readlen;
5419         ssize_t writelen;
5420         char buf[BUFSIZ];
5421         struct stat st;
5422
5423         sff = SFF_REGONLY|SFF_OPENASROOT;
5424         if (DontLockReadFiles)
5425                 sff |= SFF_NOLOCK;
5426
5427         /* Open the original file */
5428         src = safeopen((char *)source, O_RDONLY, 0, sff);
5429         if (src < 0)
5430                 goto fail;
5431
5432         /* Obtain the size and the mode */
5433         if (fstat(src, &st) < 0)
5434                 goto fail;
5435
5436         /* Create the duplicate copy */
5437         sff &= ~SFF_NOLOCK;
5438         sff |= SFF_CREAT;
5439         dst = safeopen((char *)target, O_CREAT|O_EXCL|O_WRONLY,
5440                        st.st_mode, sff);
5441         if (dst < 0)
5442                 goto fail;
5443
5444         /* Copy all of the bytes one buffer at a time */
5445         while ((readlen = read(src, &buf, sizeof(buf))) > 0)
5446         {
5447                 ssize_t left = readlen;
5448                 char *p = buf;
5449
5450                 while (left > 0 &&
5451                        (writelen = write(dst, p, (size_t) left)) >= 0)
5452                 {
5453                         left -= writelen;
5454                         p += writelen;
5455                 }
5456                 if (writelen < 0)
5457                         break;
5458         }
5459
5460         /* Any trouble reading? */
5461         if (readlen < 0 || writelen < 0)
5462                 goto fail;
5463
5464         /* Close the input file */
5465         if (close(src) < 0)
5466         {
5467                 src = -1;
5468                 goto fail;
5469         }
5470         src = -1;
5471
5472         /* Close the output file */
5473         if (close(dst) < 0)
5474         {
5475                 /* don't set dst = -1 here so we unlink the file */
5476                 goto fail;
5477         }
5478
5479         /* Success */
5480         return 0;
5481
5482  fail:
5483         save_errno = errno;
5484         if (src >= 0)
5485                 (void) close(src);
5486         if (dst >= 0)
5487         {
5488                 (void) unlink(target);
5489                 (void) close(dst);
5490         }
5491         errno = save_errno;
5492         return -1;
5493 }
5494 #endif /* NEEDLINK */
5495
5496 /*
5497 **  Compile-Time options
5498 */
5499
5500 char    *CompileOptions[] =
5501 {
5502 #if NAMED_BIND
5503 # if DNSMAP
5504         "DNSMAP",
5505 # endif /* DNSMAP */
5506 #endif /* NAMED_BIND */
5507 #if EGD
5508         "EGD",
5509 #endif /* EGD */
5510 #if HESIOD
5511         "HESIOD",
5512 #endif /* HESIOD */
5513 #if HES_GETMAILHOST
5514         "HES_GETMAILHOST",
5515 #endif /* HES_GETMAILHOST */
5516 #if LDAPMAP
5517         "LDAPMAP",
5518 #endif /* LDAPMAP */
5519 #if LOG
5520         "LOG",
5521 #endif /* LOG */
5522 #if MAP_NSD
5523         "MAP_NSD",
5524 #endif /* MAP_NSD */
5525 #if MAP_REGEX
5526         "MAP_REGEX",
5527 #endif /* MAP_REGEX */
5528 #if MATCHGECOS
5529         "MATCHGECOS",
5530 #endif /* MATCHGECOS */
5531 #if MILTER
5532         "MILTER",
5533 #endif /* MILTER */
5534 #if MIME7TO8
5535         "MIME7TO8",
5536 #endif /* MIME7TO8 */
5537 #if MIME8TO7
5538         "MIME8TO7",
5539 #endif /* MIME8TO7 */
5540 #if NAMED_BIND
5541         "NAMED_BIND",
5542 #endif /* NAMED_BIND */
5543 #if NDBM
5544         "NDBM",
5545 #endif /* NDBM */
5546 #if NETINET
5547         "NETINET",
5548 #endif /* NETINET */
5549 #if NETINET6
5550         "NETINET6",
5551 #endif /* NETINET6 */
5552 #if NETINFO
5553         "NETINFO",
5554 #endif /* NETINFO */
5555 #if NETISO
5556         "NETISO",
5557 #endif /* NETISO */
5558 #if NETNS
5559         "NETNS",
5560 #endif /* NETNS */
5561 #if NETUNIX
5562         "NETUNIX",
5563 #endif /* NETUNIX */
5564 #if NETX25
5565         "NETX25",
5566 #endif /* NETX25 */
5567 #if NEWDB
5568         "NEWDB",
5569 #endif /* NEWDB */
5570 #if NIS
5571         "NIS",
5572 #endif /* NIS */
5573 #if NISPLUS
5574         "NISPLUS",
5575 #endif /* NISPLUS */
5576 #if NO_DH
5577         "NO_DH",
5578 #endif /* NO_DH */
5579 #if PH_MAP
5580         "PH_MAP",
5581 #endif /* PH_MAP */
5582 #ifdef PICKY_HELO_CHECK
5583         "PICKY_HELO_CHECK",
5584 #endif /* PICKY_HELO_CHECK */
5585 #if PIPELINING
5586         "PIPELINING",
5587 #endif /* PIPELINING */
5588 #if SASL
5589 # if SASL >= 20000
5590         "SASLv2",
5591 # else /* SASL >= 20000 */
5592         "SASL",
5593 # endif /* SASL >= 20000 */
5594 #endif /* SASL */
5595 #if SCANF
5596         "SCANF",
5597 #endif /* SCANF */
5598 #if SMTPDEBUG
5599         "SMTPDEBUG",
5600 #endif /* SMTPDEBUG */
5601 #if STARTTLS
5602         "STARTTLS",
5603 #endif /* STARTTLS */
5604 #if SUID_ROOT_FILES_OK
5605         "SUID_ROOT_FILES_OK",
5606 #endif /* SUID_ROOT_FILES_OK */
5607 #if TCPWRAPPERS
5608         "TCPWRAPPERS",
5609 #endif /* TCPWRAPPERS */
5610 #if TLS_NO_RSA
5611         "TLS_NO_RSA",
5612 #endif /* TLS_NO_RSA */
5613 #if TLS_VRFY_PER_CTX
5614         "TLS_VRFY_PER_CTX",
5615 #endif /* TLS_VRFY_PER_CTX */
5616 #if USERDB
5617         "USERDB",
5618 #endif /* USERDB */
5619 #if USE_LDAP_INIT
5620         "USE_LDAP_INIT",
5621 #endif /* USE_LDAP_INIT */
5622 #if XDEBUG
5623         "XDEBUG",
5624 #endif /* XDEBUG */
5625 #if XLA
5626         "XLA",
5627 #endif /* XLA */
5628         NULL
5629 };
5630
5631
5632 /*
5633 **  OS compile options.
5634 */
5635
5636 char    *OsCompileOptions[] =
5637 {
5638 #if ADDRCONFIG_IS_BROKEN
5639         "ADDRCONFIG_IS_BROKEN",
5640 #endif /* ADDRCONFIG_IS_BROKEN */
5641 #ifdef AUTO_NETINFO_HOSTS
5642         "AUTO_NETINFO_HOSTS",
5643 #endif /* AUTO_NETINFO_HOSTS */
5644 #ifdef AUTO_NIS_ALIASES
5645         "AUTO_NIS_ALIASES",
5646 #endif /* AUTO_NIS_ALIASES */
5647 #if BROKEN_RES_SEARCH
5648         "BROKEN_RES_SEARCH",
5649 #endif /* BROKEN_RES_SEARCH */
5650 #ifdef BSD4_4_SOCKADDR
5651         "BSD4_4_SOCKADDR",
5652 #endif /* BSD4_4_SOCKADDR */
5653 #if BOGUS_O_EXCL
5654         "BOGUS_O_EXCL",
5655 #endif /* BOGUS_O_EXCL */
5656 #if DEC_OSF_BROKEN_GETPWENT
5657         "DEC_OSF_BROKEN_GETPWENT",
5658 #endif /* DEC_OSF_BROKEN_GETPWENT */
5659 #if FAST_PID_RECYCLE
5660         "FAST_PID_RECYCLE",
5661 #endif /* FAST_PID_RECYCLE */
5662 #if HASFCHOWN
5663         "HASFCHOWN",
5664 #endif /* HASFCHOWN */
5665 #if HASFCHMOD
5666         "HASFCHMOD",
5667 #endif /* HASFCHMOD */
5668 #if HASFLOCK
5669         "HASFLOCK",
5670 #endif /* HASFLOCK */
5671 #if HASGETDTABLESIZE
5672         "HASGETDTABLESIZE",
5673 #endif /* HASGETDTABLESIZE */
5674 #if HASGETUSERSHELL
5675         "HASGETUSERSHELL",
5676 #endif /* HASGETUSERSHELL */
5677 #if HASINITGROUPS
5678         "HASINITGROUPS",
5679 #endif /* HASINITGROUPS */
5680 #if HASLSTAT
5681         "HASLSTAT",
5682 #endif /* HASLSTAT */
5683 #if HASNICE
5684         "HASNICE",
5685 #endif /* HASNICE */
5686 #if HASRANDOM
5687         "HASRANDOM",
5688 #endif /* HASRANDOM */
5689 #if HASRRESVPORT
5690         "HASRRESVPORT",
5691 #endif /* HASRRESVPORT */
5692 #if HASSETEGID
5693         "HASSETEGID",
5694 #endif /* HASSETEGID */
5695 #if HASSETLOGIN
5696         "HASSETLOGIN",
5697 #endif /* HASSETLOGIN */
5698 #if HASSETREGID
5699         "HASSETREGID",
5700 #endif /* HASSETREGID */
5701 #if HASSETRESGID
5702         "HASSETRESGID",
5703 #endif /* HASSETRESGID */
5704 #if HASSETREUID
5705         "HASSETREUID",
5706 #endif /* HASSETREUID */
5707 #if HASSETRLIMIT
5708         "HASSETRLIMIT",
5709 #endif /* HASSETRLIMIT */
5710 #if HASSETSID
5711         "HASSETSID",
5712 #endif /* HASSETSID */
5713 #if HASSETUSERCONTEXT
5714         "HASSETUSERCONTEXT",
5715 #endif /* HASSETUSERCONTEXT */
5716 #if HASSETVBUF
5717         "HASSETVBUF",
5718 #endif /* HASSETVBUF */
5719 #if HAS_ST_GEN
5720         "HAS_ST_GEN",
5721 #endif /* HAS_ST_GEN */
5722 #if HASSRANDOMDEV
5723         "HASSRANDOMDEV",
5724 #endif /* HASSRANDOMDEV */
5725 #if HASURANDOMDEV
5726         "HASURANDOMDEV",
5727 #endif /* HASURANDOMDEV */
5728 #if HASSTRERROR
5729         "HASSTRERROR",
5730 #endif /* HASSTRERROR */
5731 #if HASULIMIT
5732         "HASULIMIT",
5733 #endif /* HASULIMIT */
5734 #if HASUNAME
5735         "HASUNAME",
5736 #endif /* HASUNAME */
5737 #if HASUNSETENV
5738         "HASUNSETENV",
5739 #endif /* HASUNSETENV */
5740 #if HASWAITPID
5741         "HASWAITPID",
5742 #endif /* HASWAITPID */
5743 #if IDENTPROTO
5744         "IDENTPROTO",
5745 #endif /* IDENTPROTO */
5746 #if IP_SRCROUTE
5747         "IP_SRCROUTE",
5748 #endif /* IP_SRCROUTE */
5749 #if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
5750         "LOCK_ON_OPEN",
5751 #endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
5752 #if NEEDFSYNC
5753         "NEEDFSYNC",
5754 #endif /* NEEDFSYNC */
5755 #if NEEDLINK
5756         "NEEDLINK",
5757 #endif /* NEEDLINK */
5758 #if NEEDLOCAL_HOSTNAME_LENGTH
5759         "NEEDLOCAL_HOSTNAME_LENGTH",
5760 #endif /* NEEDLOCAL_HOSTNAME_LENGTH */
5761 #if NEEDSGETIPNODE
5762         "NEEDSGETIPNODE",
5763 #endif /* NEEDSGETIPNODE */
5764 #if NEEDSTRSTR
5765         "NEEDSTRSTR",
5766 #endif /* NEEDSTRSTR */
5767 #if NEEDSTRTOL
5768         "NEEDSTRTOL",
5769 #endif /* NEEDSTRTOL */
5770 #ifdef NO_GETSERVBYNAME
5771         "NO_GETSERVBYNAME",
5772 #endif /* NO_GETSERVBYNAME */
5773 #if NOFTRUNCATE
5774         "NOFTRUNCATE",
5775 #endif /* NOFTRUNCATE */
5776 #if REQUIRES_DIR_FSYNC
5777         "REQUIRES_DIR_FSYNC",
5778 #endif /* REQUIRES_DIR_FSYNC */
5779 #if RLIMIT_NEEDS_SYS_TIME_H
5780         "RLIMIT_NEEDS_SYS_TIME_H",
5781 #endif /* RLIMIT_NEEDS_SYS_TIME_H */
5782 #if SAFENFSPATHCONF
5783         "SAFENFSPATHCONF",
5784 #endif /* SAFENFSPATHCONF */
5785 #if SECUREWARE
5786         "SECUREWARE",
5787 #endif /* SECUREWARE */
5788 #if SHARE_V1
5789         "SHARE_V1",
5790 #endif /* SHARE_V1 */
5791 #if SIOCGIFCONF_IS_BROKEN
5792         "SIOCGIFCONF_IS_BROKEN",
5793 #endif /* SIOCGIFCONF_IS_BROKEN */
5794 #if SIOCGIFNUM_IS_BROKEN
5795         "SIOCGIFNUM_IS_BROKEN",
5796 #endif /* SIOCGIFNUM_IS_BROKEN */
5797 #if SNPRINTF_IS_BROKEN
5798         "SNPRINTF_IS_BROKEN",
5799 #endif /* SNPRINTF_IS_BROKEN */
5800 #if SO_REUSEADDR_IS_BROKEN
5801         "SO_REUSEADDR_IS_BROKEN",
5802 #endif /* SO_REUSEADDR_IS_BROKEN */
5803 #if SYS5SETPGRP
5804         "SYS5SETPGRP",
5805 #endif /* SYS5SETPGRP */
5806 #if SYSTEM5
5807         "SYSTEM5",
5808 #endif /* SYSTEM5 */
5809 #if USE_DOUBLE_FORK
5810         "USE_DOUBLE_FORK",
5811 #endif /* USE_DOUBLE_FORK */
5812 #if USE_ENVIRON
5813         "USE_ENVIRON",
5814 #endif /* USE_ENVIRON */
5815 #if USE_SA_SIGACTION
5816         "USE_SA_SIGACTION",
5817 #endif /* USE_SA_SIGACTION */
5818 #if USE_SIGLONGJMP
5819         "USE_SIGLONGJMP",
5820 #endif /* USE_SIGLONGJMP */
5821 #if USEGETCONFATTR
5822         "USEGETCONFATTR",
5823 #endif /* USEGETCONFATTR */
5824 #if USESETEUID
5825         "USESETEUID",
5826 #endif /* USESETEUID */
5827 #ifdef USESYSCTL
5828         "USESYSCTL",
5829 #endif /* USESYSCTL */
5830 #if USING_NETSCAPE_LDAP
5831         "USING_NETSCAPE_LDAP",
5832 #endif /* USING_NETSCAPE_LDAP */
5833 #ifdef WAITUNION
5834         "WAITUNION",
5835 #endif /* WAITUNION */
5836         NULL
5837 };
5838
5839 /*
5840 **  FFR compile options.
5841 */
5842
5843 char    *FFRCompileOptions[] =
5844 {
5845 #if _FFR_ADAPTIVE_EOL
5846         "_FFR_ADAPTIVE_EOL",
5847 #endif /* _FFR_ADAPTIVE_EOL */
5848 #if _FFR_ALLOW_SASLINFO
5849         "_FFR_ALLOW_SASLINFO",
5850 #endif /* _FFR_ALLOW_SASLINFO */
5851 #if _FFR_ALLOW_S0_ERROR_4XX
5852         "_FFR_ALLOW_S0_ERROR_4XX",
5853 #endif /* _FFR_ALLOW_S0_ERROR_4XX */
5854 #if _FFR_BESTMX_BETTER_TRUNCATION
5855         "_FFR_BESTMX_BETTER_TRUNCATION",
5856 #endif /* _FFR_BESTMX_BETTER_TRUNCATION */
5857 #if _FFR_CACHE_LPC
5858 /* Christophe Wolfhugel of France Telecom Oleane */
5859         "_FFR_CACHE_LPC",
5860 #endif /* _FFR_CACHE_LPC */
5861 #if _FFR_CATCH_BROKEN_MTAS
5862         "_FFR_CATCH_BROKEN_MTAS",
5863 #endif /* _FFR_CATCH_BROKEN_MTAS */
5864 #if _FFR_CATCH_LONG_STRINGS
5865         "_FFR_CATCH_LONG_STRINGS",
5866 #endif /* _FFR_CATCH_LONG_STRINGS */
5867 #if _FFR_CHECK_EOM
5868         "_FFR_CHECK_EOM",
5869 #endif /* _FFR_CHECK_EOM */
5870 #if _FFR_CHK_QUEUE
5871         "_FFR_CHK_QUEUE",
5872 #endif /* _FFR_CHK_QUEUE */
5873 #if _FFR_CONTROL_MSTAT
5874         "_FFR_CONTROL_MSTAT",
5875 #endif /* _FFR_CONTROL_MSTAT */
5876 #if _FFR_DAEMON_NETUNIX
5877         "_FFR_DAEMON_NETUNIX",
5878 #endif /* _FFR_DAEMON_NETUNIX */
5879 #if _FFR_DEPRECATE_MAILER_FLAG_I
5880         "_FFR_DEPRECATE_MAILER_FLAG_I",
5881 #endif /* _FFR_DEPRECATE_MAILER_FLAG_I */
5882 #if _FFR_DIGUNIX_SAFECHOWN
5883 /* Problem noted by Anne Bennett of Concordia University */
5884         "_FFR_DIGUNIX_SAFECHOWN",
5885 #endif /* _FFR_DIGUNIX_SAFECHOWN */
5886 #if _FFR_DNSMAP_ALIASABLE
5887 /* Don Lewis of TDK */
5888         "_FFR_DNSMAP_ALIASABLE",
5889 #endif /* _FFR_DNSMAP_ALIASABLE */
5890 #if _FFR_DNSMAP_BASE
5891         "_FFR_DNSMAP_BASE",
5892 #endif /* _FFR_DNSMAP_BASE */
5893 #if _FFR_DNSMAP_MULTI
5894         "_FFR_DNSMAP_MULTI",
5895 # if _FFR_DNSMAP_MULTILIMIT
5896         "_FFR_DNSMAP_MULTILIMIT",
5897 # endif /* _FFR_DNSMAP_MULTILIMIT */
5898 #endif /* _FFR_DNSMAP_MULTI */
5899 #if _FFR_DONTLOCKFILESFORREAD_OPTION
5900         "_FFR_DONTLOCKFILESFORREAD_OPTION",
5901 #endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */
5902 # if _FFR_DONT_STOP_LOOKING
5903 /* Noted by Neil Rickert of Northern Illinois University */
5904         "_FFR_DONT_STOP_LOOKING",
5905 # endif /* _FFR_DONT_STOP_LOOKING */
5906 #if _FFR_DOTTED_USERNAMES
5907         "_FFR_DOTTED_USERNAMES",
5908 #endif /* _FFR_DOTTED_USERNAMES */
5909 #if _FFR_DROP_TRUSTUSER_WARNING
5910         "_FFR_DROP_TRUSTUSER_WARNING",
5911 #endif /* _FFR_DROP_TRUSTUSER_WARNING */
5912 #if _FFR_FIX_DASHT
5913         "_FFR_FIX_DASHT",
5914 #endif /* _FFR_FIX_DASHT */
5915 #if _FFR_FORWARD_SYSERR
5916         "_FFR_FORWARD_SYSERR",
5917 #endif /* _FFR_FORWARD_SYSERR */
5918 #if _FFR_GEN_ORCPT
5919         "_FFR_GEN_ORCPT",
5920 #endif /* _FFR_GEN_ORCPT */
5921 #if _FFR_GROUPREADABLEAUTHINFOFILE
5922         "_FFR_GROUPREADABLEAUTHINFOFILE",
5923 #endif /* _FFR_GROUPREADABLEAUTHINFOFILE */
5924 #if _FFR_HANDLE_ISO8859_GECOS
5925 /* Peter Eriksson of Linkopings universitet */
5926         "_FFR_HANDLE_ISO8859_GECOS",
5927 #endif /* _FFR_HANDLE_ISO8859_GECOS */
5928 #if _FFR_HDR_TYPE
5929         "_FFR_HDR_TYPE",
5930 #endif /* _FFR_HDR_TYPE */
5931 #if _FFR_HPUX_NSSWITCH
5932         "_FFR_HPUX_NSSWITCH",
5933 #endif /* _FFR_HPUX_NSSWITCH */
5934 #if _FFR_IGNORE_EXT_ON_HELO
5935         "_FFR_IGNORE_EXT_ON_HELO",
5936 #endif /* _FFR_IGNORE_EXT_ON_HELO */
5937 #if _FFR_LDAP_RECURSION
5938 /* Andrew Baucom */
5939         "_FFR_LDAP_RECURSION",
5940 #endif /* _FFR_LDAP_RECURSION */
5941 #if _FFR_LDAP_SETVERSION
5942         "_FFR_LDAP_SETVERSION",
5943 #endif /* _FFR_LDAP_SETVERSION */
5944 #if _FFR_LDAP_URI
5945         "_FFR_LDAP_URI",
5946 #endif /* _FFR_LDAP_URI */
5947 #if _FFR_MAX_FORWARD_ENTRIES
5948 /* Randall S. Winchester of the University of Maryland */
5949         "_FFR_MAX_FORWARD_ENTRIES",
5950 #endif /* _FFR_MAX_FORWARD_ENTRIES */
5951 #if MILTER
5952 # if  _FFR_MILTER_PERDAEMON
5953         "_FFR_MILTER_PERDAEMON",
5954 # endif /* _FFR_MILTER_PERDAEMON */
5955 #endif /* MILTER */
5956 #if _FFR_NODELAYDSN_ON_HOLD
5957 /* Steven Pitzl */
5958         "_FFR_NODELAYDSN_ON_HOLD",
5959 #endif /* _FFR_NODELAYDSN_ON_HOLD */
5960 #if _FFR_NO_PIPE
5961         "_FFR_NO_PIPE",
5962 #endif /* _FFR_NO_PIPE */
5963 #if _FFR_QUARANTINE
5964         "_FFR_QUARANTINE",
5965 #endif /* _FFR_QUARANTINE */
5966 #if _FFR_QUEUEDELAY
5967         "_FFR_QUEUEDELAY",
5968 #endif /* _FFR_QUEUEDELAY */
5969 #if _FFR_QUEUE_GROUP_SORTORDER
5970 /* XXX: Still need to actually use qgrp->qg_sortorder */
5971         "_FFR_QUEUE_GROUP_SORTORDER",
5972 #endif /* _FFR_QUEUE_GROUP_SORTORDER */
5973 #if _FFR_QUEUE_MACRO
5974         "_FFR_QUEUE_MACRO",
5975 #endif /* _FFR_QUEUE_MACRO */
5976 #if _FFR_QUEUE_RUN_PARANOIA
5977         "_FFR_QUEUE_RUN_PARANOIA",
5978 #endif /* _FFR_QUEUE_RUN_PARANOIA */
5979 #if _FFR_QUEUE_SCHED_DBG
5980         "_FFR_QUEUE_SCHED_DBG",
5981 #endif /* _FFR_QUEUE_SCHED_DBG */
5982 #if _FFR_REDIRECTEMPTY
5983         "_FFR_REDIRECTEMPTY",
5984 #endif /* _FFR_REDIRECTEMPTY */
5985 #if _FFR_RESET_MACRO_GLOBALS
5986         "_FFR_RESET_MACRO_GLOBALS",
5987 #endif /* _FFR_RESET_MACRO_GLOBALS */
5988 #if _FFR_RESPOND_ALL
5989         /* in vacation */
5990         "_FFR_RESPOND_ALL",
5991 #endif /* _FFR_RESPOND_ALL */
5992 #if _FFR_RHS
5993         "_FFR_RHS",
5994 #endif /* _FFR_RHS */
5995 #if _FFR_SASL_OPT_M
5996         "_FFR_SASL_OPT_M",
5997 #endif /* _FFR_SASL_OPT_M */
5998 #if _FFR_SELECT_SHM
5999         "_FFR_SELECT_SHM",
6000 #endif /* _FFR_SELECT_SHM */
6001 #if _FFR_SHM_STATUS
6002         "_FFR_SHM_STATUS",
6003 #endif /* _FFR_SHM_STATUS */
6004 #if _FFR_SMFI_OPENSOCKET
6005         "_FFR_SMFI_OPENSOCKET",
6006 #endif /* _FFR_SMFI_OPENSOCKET */
6007 #if _FFR_SMTP_SSL
6008         "_FFR_SMTP_SSL",
6009 #endif /* _FFR_SMTP_SSL */
6010 #if _FFR_SOFT_BOUNCE
6011         "_FFR_SOFT_BOUNCE",
6012 #endif /* _FFR_SOFT_BOUNCE */
6013 #if _FFR_SPT_ALIGN
6014 /* Chris Adams of HiWAAY Informations Services */
6015         "_FFR_SPT_ALIGN",
6016 #endif /* _FFR_SPT_ALIGN */
6017 #if _FFR_TIMERS
6018         "_FFR_TIMERS",
6019 #endif /* _FFR_TIMERS */
6020 #if _FFR_TLS_1
6021         "_FFR_TLS_1",
6022 #endif /* _FFR_TLS_1 */
6023 #if _FFR_TRUSTED_QF
6024         "_FFR_TRUSTED_QF",
6025 #endif /* _FFR_TRUSTED_QF */
6026 #if _FFR_USE_SETLOGIN
6027 /* Peter Philipp */
6028         "_FFR_USE_SETLOGIN",
6029 #endif /* _FFR_USE_SETLOGIN */
6030         NULL
6031 };
6032