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