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