source: trunk/third/sendmail/sendmail/conf.c @ 22421

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