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