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