source: trunk/third/sendmail/src/conf.c @ 12629

Revision 12629, 103.7 KB checked in by danw, 26 years ago (diff)
fix hesiod calls
Line 
1/*
2 * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3 * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
4 * Copyright (c) 1988, 1993
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * By using this file, you agree to the terms and conditions set
8 * forth in the LICENSE file which can be found at the top level of
9 * the sendmail distribution.
10 *
11 */
12
13#ifndef lint
14static char sccsid[] = "@(#)conf.c      8.452 (Berkeley) 1/26/1999";
15#endif /* not lint */
16
17# include "sendmail.h"
18# include "pathnames.h"
19# include <sys/ioctl.h>
20# include <sys/param.h>
21# include <limits.h>
22
23# include <hesiod.h>
24
25/*
26**  CONF.C -- Sendmail Configuration Tables.
27**
28**      Defines the configuration of this installation.
29**
30**      Configuration Variables:
31**              HdrInfo -- a table describing well-known header fields.
32**                      Each entry has the field name and some flags,
33**                      which are described in sendmail.h.
34**
35**      Notes:
36**              I have tried to put almost all the reasonable
37**              configuration information into the configuration
38**              file read at runtime.  My intent is that anything
39**              here is a function of the version of UNIX you
40**              are running, or is really static -- for example
41**              the headers are a superset of widely used
42**              protocols.  If you find yourself playing with
43**              this file too much, you may be making a mistake!
44*/
45
46
47/*
48**  Header info table
49**      Final (null) entry contains the flags used for any other field.
50**
51**      Not all of these are actually handled specially by sendmail
52**      at this time.  They are included as placeholders, to let
53**      you know that "someday" I intend to have sendmail do
54**      something with them.
55*/
56
57struct hdrinfo  HdrInfo[] =
58{
59                /* originator fields, most to least significant  */
60        { "resent-sender",              H_FROM|H_RESENT                 },
61        { "resent-from",                H_FROM|H_RESENT                 },
62        { "resent-reply-to",            H_FROM|H_RESENT                 },
63        { "sender",                     H_FROM                          },
64        { "from",                       H_FROM                          },
65        { "reply-to",                   H_FROM                          },
66        { "errors-to",                  H_FROM|H_ERRORSTO               },
67        { "full-name",                  H_ACHECK                        },
68        { "return-receipt-to",          H_RECEIPTTO                     },
69
70                /* destination fields */
71        { "to",                         H_RCPT                          },
72        { "resent-to",                  H_RCPT|H_RESENT                 },
73        { "cc",                         H_RCPT                          },
74        { "resent-cc",                  H_RCPT|H_RESENT                 },
75        { "bcc",                        H_RCPT|H_BCC                    },
76        { "resent-bcc",                 H_RCPT|H_BCC|H_RESENT           },
77        { "apparently-to",              H_RCPT                          },
78
79                /* message identification and control */
80        { "message-id",                 0                               },
81        { "resent-message-id",          H_RESENT                        },
82        { "message",                    H_EOH                           },
83        { "text",                       H_EOH                           },
84
85                /* date fields */
86        { "date",                       0                               },
87        { "resent-date",                H_RESENT                        },
88
89                /* trace fields */
90        { "received",                   H_TRACE|H_FORCE                 },
91        { "x400-received",              H_TRACE|H_FORCE                 },
92        { "via",                        H_TRACE|H_FORCE                 },
93        { "mail-from",                  H_TRACE|H_FORCE                 },
94
95                /* miscellaneous fields */
96        { "comments",                   H_FORCE|H_ENCODABLE             },
97        { "return-path",                H_FORCE|H_ACHECK                },
98        { "content-transfer-encoding",  H_CTE                           },
99        { "content-type",               H_CTYPE                         },
100        { "content-length",             H_ACHECK                        },
101        { "subject",                    H_ENCODABLE                     },
102
103        { NULL,                         0                               }
104};
105
106
107
108/*
109**  Privacy values
110*/
111
112struct prival PrivacyValues[] =
113{
114        { "public",             PRIV_PUBLIC             },
115        { "needmailhelo",       PRIV_NEEDMAILHELO       },
116        { "needexpnhelo",       PRIV_NEEDEXPNHELO       },
117        { "needvrfyhelo",       PRIV_NEEDVRFYHELO       },
118        { "noexpn",             PRIV_NOEXPN             },
119        { "novrfy",             PRIV_NOVRFY             },
120        { "restrictmailq",      PRIV_RESTRICTMAILQ      },
121        { "restrictqrun",       PRIV_RESTRICTQRUN       },
122        { "noetrn",             PRIV_NOETRN             },
123        { "noverb",             PRIV_NOVERB             },
124        { "authwarnings",       PRIV_AUTHWARNINGS       },
125        { "noreceipts",         PRIV_NORECEIPTS         },
126        { "goaway",             PRIV_GOAWAY             },
127        { NULL,                 0                       }
128};
129
130/*
131**  DontBlameSendmail values
132*/
133struct dbsval DontBlameSendmailValues[] =
134{
135        { "safe",                       DBS_SAFE                        },
136        { "assumesafechown",            DBS_ASSUMESAFECHOWN             },
137        { "groupwritabledirpathsafe",   DBS_GROUPWRITABLEDIRPATHSAFE    },
138        { "groupwritableforwardfilesafe",
139                                        DBS_GROUPWRITABLEFORWARDFILESAFE },
140        { "groupwritableincludefilesafe",
141                                        DBS_GROUPWRITABLEINCLUDEFILESAFE },
142        { "groupwritablealiasfile",     DBS_GROUPWRITABLEALIASFILE      },
143        { "worldwritablealiasfile",     DBS_WORLDWRITABLEALIASFILE      },
144        { "forwardfileinunsafedirpath", DBS_FORWARDFILEINUNSAFEDIRPATH  },
145        { "includefileinunsafedirpath", DBS_INCLUDEFILEINUNSAFEDIRPATH  },
146        { "mapinunsafedirpath",         DBS_MAPINUNSAFEDIRPATH  },
147        { "linkedaliasfileinwritabledir",
148                                        DBS_LINKEDALIASFILEINWRITABLEDIR },
149        { "linkedclassfileinwritabledir",
150                                        DBS_LINKEDCLASSFILEINWRITABLEDIR },
151        { "linkedforwardfileinwritabledir",
152                                        DBS_LINKEDFORWARDFILEINWRITABLEDIR },
153        { "linkedincludefileinwritabledir",
154                                        DBS_LINKEDINCLUDEFILEINWRITABLEDIR },
155        { "linkedmapinwritabledir",     DBS_LINKEDMAPINWRITABLEDIR      },
156        { "linkedserviceswitchfileinwritabledir",
157                                        DBS_LINKEDSERVICESWITCHFILEINWRITABLEDIR },
158        { "filedeliverytohardlink",     DBS_FILEDELIVERYTOHARDLINK      },
159        { "filedeliverytosymlink",      DBS_FILEDELIVERYTOSYMLINK       },
160        { "writemaptohardlink",         DBS_WRITEMAPTOHARDLINK          },
161        { "writemaptosymlink",          DBS_WRITEMAPTOSYMLINK           },
162        { "writestatstohardlink",       DBS_WRITESTATSTOHARDLINK        },
163        { "writestatstosymlink",        DBS_WRITESTATSTOSYMLINK         },
164        { "forwardfileingroupwritabledirpath",
165                                        DBS_FORWARDFILEINGROUPWRITABLEDIRPATH },
166        { "includefileingroupwritabledirpath",
167                                        DBS_INCLUDEFILEINGROUPWRITABLEDIRPATH },
168        { "classfileinunsafedirpath",   DBS_CLASSFILEINUNSAFEDIRPATH    },
169        { "errorheaderinunsafedirpath", DBS_ERRORHEADERINUNSAFEDIRPATH  },
170        { "helpfileinunsafedirpath",    DBS_HELPFILEINUNSAFEDIRPATH     },
171        { "forwardfileinunsafedirpathsafe",
172                                        DBS_FORWARDFILEINUNSAFEDIRPATHSAFE },
173        { "includefileinunsafedirpathsafe",
174                                        DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE },
175        { "runprograminunsafedirpath",  DBS_RUNPROGRAMINUNSAFEDIRPATH   },
176        { "runwritableprogram",         DBS_RUNWRITABLEPROGRAM          },
177        { NULL,                         0                               }
178};
179
180
181/*
182**  Miscellaneous stuff.
183*/
184
185int     DtableSize =    50;             /* max open files; reset in 4.2bsd */
186/*
187**  SETDEFAULTS -- set default values
188**
189**      Because of the way freezing is done, these must be initialized
190**      using direct code.
191**
192**      Parameters:
193**              e -- the default envelope.
194**
195**      Returns:
196**              none.
197**
198**      Side Effects:
199**              Initializes a bunch of global variables to their
200**              default values.
201*/
202
203#define MINUTES         * 60
204#define HOURS           * 60 MINUTES
205#define DAYS            * 24 HOURS
206
207#ifndef _PATH_VARTMP
208# define _PATH_VARTMP   "/usr/tmp/"
209#endif
210
211#ifndef MAXRULERECURSION
212# define MAXRULERECURSION       50      /* max ruleset recursion depth */
213#endif
214
215void
216setdefaults(e)
217        register ENVELOPE *e;
218{
219        int i;
220        struct passwd *pw;
221        char buf[MAXNAME];
222        extern void setdefuser __P((void));
223        extern void setupmaps __P((void));
224        extern void setupmailers __P((void));
225        extern void setupheaders __P((void));
226
227        SpaceSub = ' ';                         /* option B */
228        QueueLA = 8;                            /* option x */
229        RefuseLA = 12;                          /* option X */
230        WkRecipFact = 30000L;                   /* option y */
231        WkClassFact = 1800L;                    /* option z */
232        WkTimeFact = 90000L;                    /* option Z */
233        QueueFactor = WkRecipFact * 20;         /* option q */
234        FileMode = (RealUid != geteuid()) ? 0644 : 0600;
235                                                /* option F */
236
237        if (((pw = getpwnam("mailnull")) != NULL && pw->pw_uid != 0) ||
238            ((pw = getpwnam("sendmail")) != NULL && pw->pw_uid != 0) ||
239            ((pw = getpwnam("daemon")) != NULL && pw->pw_uid != 0))
240        {
241                DefUid = pw->pw_uid;            /* option u */
242                DefGid = pw->pw_gid;            /* option g */
243                DefUser = newstr(pw->pw_name);
244        }
245        else
246        {
247                DefUid = 1;                     /* option u */
248                DefGid = 1;                     /* option g */
249                setdefuser();
250        }
251        TrustedUid = 0;
252        if (tTd(37, 4))
253                printf("setdefaults: DefUser=%s, DefUid=%d, DefGid=%d\n",
254                       DefUser != NULL ? DefUser : "<1:1>",
255                       (int) DefUid, (int) DefGid);
256        CheckpointInterval = 10;                /* option C */
257        MaxHopCount = 25;                       /* option h */
258        e->e_sendmode = SM_FORK;                /* option d */
259        e->e_errormode = EM_PRINT;              /* option e */
260        SevenBitInput = FALSE;                  /* option 7 */
261        MaxMciCache = 1;                        /* option k */
262        MciCacheTimeout = 5 MINUTES;            /* option K */
263        LogLevel = 9;                           /* option L */
264        inittimeouts(NULL);                     /* option r */
265        PrivacyFlags = PRIV_PUBLIC;             /* option p */
266        DontBlameSendmail = DBS_SAFE;           /* DontBlameSendmail option */
267#if MIME8TO7
268        MimeMode = MM_CVTMIME|MM_PASS8BIT;      /* option 8 */
269#else
270        MimeMode = MM_PASS8BIT;
271#endif
272        for (i = 0; i < MAXTOCLASS; i++)
273        {
274                TimeOuts.to_q_return[i] = 5 DAYS;       /* option T */
275                TimeOuts.to_q_warning[i] = 0;           /* option T */
276        }
277        ServiceSwitchFile = "/etc/service.switch";
278        ServiceCacheMaxAge = (time_t) 10;
279        HostsFile = _PATH_HOSTS;
280        PidFile = newstr(_PATH_SENDMAILPID);
281        MustQuoteChars = "@,;:\\()[].'";
282        MciInfoTimeout = 30 MINUTES;
283        MaxRuleRecursion = MAXRULERECURSION;
284        MaxAliasRecursion = 10;
285        MaxMacroRecursion = 10;
286        ColonOkInAddr = TRUE;
287        DontLockReadFiles = TRUE;
288        DoubleBounceAddr = "postmaster";
289        MaxHeadersLength = MAXHDRSLEN;
290        snprintf(buf, sizeof buf, "%s%sdead.letter",
291                _PATH_VARTMP,
292                _PATH_VARTMP[sizeof _PATH_VARTMP - 2] == '/' ? "" : "/");
293        DeadLetterDrop = newstr(buf);
294#ifdef HESIOD_INIT
295        HesiodContext = NULL;
296#endif
297        ControlSocketName = NULL;
298        setupmaps();
299        setupmailers();
300        setupheaders();
301}
302
303
304/*
305**  SETDEFUSER -- set/reset DefUser using DefUid (for initgroups())
306*/
307
308void
309setdefuser()
310{
311        struct passwd *defpwent;
312        static char defuserbuf[40];
313
314        DefUser = defuserbuf;
315        defpwent = sm_getpwuid(DefUid);
316        snprintf(defuserbuf, sizeof defuserbuf, "%s",
317                defpwent == NULL ? "nobody" : defpwent->pw_name);
318        if (tTd(37, 4))
319                printf("setdefuser: DefUid=%d, DefUser=%s\n",
320                       (int) DefUid, DefUser);
321}
322/*
323**  SETUPMAILERS -- initialize default mailers
324*/
325
326void
327setupmailers()
328{
329        char buf[100];
330
331        strcpy(buf, "prog, P=/bin/sh, F=lsoDq9, T=DNS/RFC822/X-Unix, A=sh -c \201u");
332        makemailer(buf);
333
334        strcpy(buf, "*file*, P=[FILE], F=lsDFMPEouq9, T=DNS/RFC822/X-Unix, A=FILE \201u");
335        makemailer(buf);
336
337        strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE \201u");
338        makemailer(buf);
339}
340/*
341**  SETUPMAPS -- set up map classes
342*/
343
344#define MAPDEF(name, ext, flags, parse, open, close, lookup, store) \
345        { \
346                extern bool parse __P((MAP *, char *)); \
347                extern bool open __P((MAP *, int)); \
348                extern void close __P((MAP *)); \
349                extern char *lookup __P((MAP *, char *, char **, int *)); \
350                extern void store __P((MAP *, char *, char *)); \
351                s = stab(name, ST_MAPCLASS, ST_ENTER); \
352                s->s_mapclass.map_cname = name; \
353                s->s_mapclass.map_ext = ext; \
354                s->s_mapclass.map_cflags = flags; \
355                s->s_mapclass.map_parse = parse; \
356                s->s_mapclass.map_open = open; \
357                s->s_mapclass.map_close = close; \
358                s->s_mapclass.map_lookup = lookup; \
359                s->s_mapclass.map_store = store; \
360        }
361
362void
363setupmaps()
364{
365        register STAB *s;
366
367#ifdef NEWDB
368        MAPDEF("hash", ".db", MCF_ALIASOK|MCF_REBUILDABLE,
369                map_parseargs, hash_map_open, db_map_close,
370                db_map_lookup, db_map_store);
371
372        MAPDEF("btree", ".db", MCF_ALIASOK|MCF_REBUILDABLE,
373                map_parseargs, bt_map_open, db_map_close,
374                db_map_lookup, db_map_store);
375#endif
376
377#ifdef NDBM
378        MAPDEF("dbm", ".dir", MCF_ALIASOK|MCF_REBUILDABLE,
379                map_parseargs, ndbm_map_open, ndbm_map_close,
380                ndbm_map_lookup, ndbm_map_store);
381#endif
382
383#ifdef NIS
384        MAPDEF("nis", NULL, MCF_ALIASOK,
385                map_parseargs, nis_map_open, null_map_close,
386                nis_map_lookup, null_map_store);
387#endif
388
389#ifdef NISPLUS
390        MAPDEF("nisplus", NULL, MCF_ALIASOK,
391                map_parseargs, nisplus_map_open, null_map_close,
392                nisplus_map_lookup, null_map_store);
393#endif
394#ifdef LDAPMAP
395        MAPDEF("ldapx", NULL, 0,
396                ldap_map_parseargs, ldap_map_open, ldap_map_close,
397                ldap_map_lookup, null_map_store);
398#endif
399
400#ifdef HESIOD
401        MAPDEF("hesiod", NULL, MCF_ALIASOK|MCF_ALIASONLY,
402                map_parseargs, hes_map_open, null_map_close,
403                hes_map_lookup, null_map_store);
404#endif
405
406#if NETINFO
407        MAPDEF("netinfo", NULL, MCF_ALIASOK,
408                map_parseargs, ni_map_open, null_map_close,
409                ni_map_lookup, null_map_store);
410#endif
411
412#if 0
413        MAPDEF("dns", NULL, 0,
414                dns_map_init, null_map_open, null_map_close,
415                dns_map_lookup, null_map_store);
416#endif
417
418#if NAMED_BIND
419        /* best MX DNS lookup */
420        MAPDEF("bestmx", NULL, MCF_OPTFILE,
421                map_parseargs, null_map_open, null_map_close,
422                bestmx_map_lookup, null_map_store);
423#endif
424
425        MAPDEF("host", NULL, 0,
426                host_map_init, null_map_open, null_map_close,
427                host_map_lookup, null_map_store);
428
429        MAPDEF("text", NULL, MCF_ALIASOK,
430                map_parseargs, text_map_open, null_map_close,
431                text_map_lookup, null_map_store);
432
433        MAPDEF("stab", NULL, MCF_ALIASOK|MCF_ALIASONLY,
434                map_parseargs, stab_map_open, null_map_close,
435                stab_map_lookup, stab_map_store);
436
437        MAPDEF("implicit", NULL, MCF_ALIASOK|MCF_ALIASONLY|MCF_REBUILDABLE,
438                map_parseargs, impl_map_open, impl_map_close,
439                impl_map_lookup, impl_map_store);
440
441        /* access to system passwd file */
442        MAPDEF("user", NULL, MCF_OPTFILE,
443                map_parseargs, user_map_open, null_map_close,
444                user_map_lookup, null_map_store);
445
446        /* dequote map */
447        MAPDEF("dequote", NULL, 0,
448                dequote_init, null_map_open, null_map_close,
449                dequote_map, null_map_store);
450
451#ifdef MAP_REGEX
452        MAPDEF("regex", NULL, 0,
453                regex_map_init, null_map_open, null_map_close,
454                regex_map_lookup, null_map_store);
455#endif
456
457#if USERDB
458        /* user database */
459        MAPDEF("userdb", ".db", 0,
460                map_parseargs, null_map_open, null_map_close,
461                udb_map_lookup, null_map_store);
462#endif
463
464        /* arbitrary programs */
465        MAPDEF("program", NULL, MCF_ALIASOK,
466                map_parseargs, null_map_open, null_map_close,
467                prog_map_lookup, null_map_store);
468
469        /* sequenced maps */
470        MAPDEF("sequence", NULL, MCF_ALIASOK,
471                seq_map_parse, null_map_open, null_map_close,
472                seq_map_lookup, seq_map_store);
473
474        /* switched interface to sequenced maps */
475        MAPDEF("switch", NULL, MCF_ALIASOK,
476                map_parseargs, switch_map_open, null_map_close,
477                seq_map_lookup, seq_map_store);
478
479        /* null map lookup -- really for internal use only */
480        MAPDEF("null", NULL, MCF_ALIASOK|MCF_OPTFILE,
481                map_parseargs, null_map_open, null_map_close,
482                null_map_lookup, null_map_store);
483
484#if _FFR_MAP_SYSLOG
485        /* syslog map -- logs information to syslog */
486        MAPDEF("syslog", NULL, 0,
487               syslog_map_parseargs, null_map_open, null_map_close,
488               syslog_map_lookup, null_map_store);
489#endif
490}
491
492#undef MAPDEF
493/*
494**  INITHOSTMAPS -- initial host-dependent maps
495**
496**      This should act as an interface to any local service switch
497**      provided by the host operating system.
498**
499**      Parameters:
500**              none
501**
502**      Returns:
503**              none
504**
505**      Side Effects:
506**              Should define maps "host" and "users" as necessary
507**              for this OS.  If they are not defined, they will get
508**              a default value later.  It should check to make sure
509**              they are not defined first, since it's possible that
510**              the config file has provided an override.
511*/
512
513void
514inithostmaps()
515{
516        register int i;
517        int nmaps;
518        char *maptype[MAXMAPSTACK];
519        short mapreturn[MAXMAPACTIONS];
520        char buf[MAXLINE];
521
522        /*
523        **  Set up default hosts maps.
524        */
525
526#if 0
527        nmaps = switch_map_find("hosts", maptype, mapreturn);
528        for (i = 0; i < nmaps; i++)
529        {
530                if (strcmp(maptype[i], "files") == 0 &&
531                    stab("hosts.files", ST_MAP, ST_FIND) == NULL)
532                {
533                        strcpy(buf, "hosts.files text -k 0 -v 1 /etc/hosts");
534                        (void) makemapentry(buf);
535                }
536#if NAMED_BIND
537                else if (strcmp(maptype[i], "dns") == 0 &&
538                    stab("hosts.dns", ST_MAP, ST_FIND) == NULL)
539                {
540                        strcpy(buf, "hosts.dns dns A");
541                        (void) makemapentry(buf);
542                }
543#endif
544#ifdef NISPLUS
545                else if (strcmp(maptype[i], "nisplus") == 0 &&
546                    stab("hosts.nisplus", ST_MAP, ST_FIND) == NULL)
547                {
548                        strcpy(buf, "hosts.nisplus nisplus -k name -v address -d hosts.org_dir");
549                        (void) makemapentry(buf);
550                }
551#endif
552#ifdef NIS
553                else if (strcmp(maptype[i], "nis") == 0 &&
554                    stab("hosts.nis", ST_MAP, ST_FIND) == NULL)
555                {
556                        strcpy(buf, "hosts.nis nis -d -k 0 -v 1 hosts.byname");
557                        (void) makemapentry(buf);
558                }
559#endif
560#if NETINFO
561                else if (strcmp(maptype[i], "netinfo") == 0) &&
562                    stab("hosts.netinfo", ST_MAP, ST_FIND) == NULL)
563                {
564                        strcpy(buf, "hosts.netinfo netinfo -v name /machines");
565                        (void) makemapentry(buf);
566                }
567#endif
568        }
569#endif
570
571        /*
572        **  Make sure we have a host map.
573        */
574
575        if (stab("host", ST_MAP, ST_FIND) == NULL)
576        {
577                /* user didn't initialize: set up host map */
578                strcpy(buf, "host host");
579#if NAMED_BIND
580                if (ConfigLevel >= 2)
581                        strcat(buf, " -a.");
582#endif
583                (void) makemapentry(buf);
584        }
585
586        /*
587        **  Set up default aliases maps
588        */
589
590        nmaps = switch_map_find("aliases", maptype, mapreturn);
591        for (i = 0; i < nmaps; i++)
592        {
593                if (strcmp(maptype[i], "files") == 0 &&
594                    stab("aliases.files", ST_MAP, ST_FIND) == NULL)
595                {
596                        strcpy(buf, "aliases.files null");
597                        (void) makemapentry(buf);
598                }
599#ifdef NISPLUS
600                else if (strcmp(maptype[i], "nisplus") == 0 &&
601                    stab("aliases.nisplus", ST_MAP, ST_FIND) == NULL)
602                {
603                        strcpy(buf, "aliases.nisplus nisplus -kalias -vexpansion -d mail_aliases.org_dir");
604                        (void) makemapentry(buf);
605                }
606#endif
607#ifdef NIS
608                else if (strcmp(maptype[i], "nis") == 0 &&
609                    stab("aliases.nis", ST_MAP, ST_FIND) == NULL)
610                {
611                        strcpy(buf, "aliases.nis nis -d mail.aliases");
612                        (void) makemapentry(buf);
613                }
614#endif
615#ifdef NETINFO
616                else if (strcmp(maptype[i], "netinfo") == 0 &&
617                    stab("aliases.netinfo", ST_MAP, ST_FIND) == NULL)
618                {
619                        strcpy(buf, "aliases.netinfo netinfo -z, /aliases");
620                        (void) makemapentry(buf);
621                }
622#endif
623#ifdef HESIOD
624                else if (strcmp(maptype[i], "hesiod") == 0 &&
625                    stab("aliases.hesiod", ST_MAP, ST_FIND) == NULL)
626                {
627                        strcpy(buf, "aliases.hesiod hesiod aliases");
628                        (void) makemapentry(buf);
629                }
630#endif
631        }
632        if (stab("aliases", ST_MAP, ST_FIND) == NULL)
633        {
634                strcpy(buf, "aliases switch aliases");
635                (void) makemapentry(buf);
636        }
637
638#if 0           /* "user" map class is a better choice */
639        /*
640        **  Set up default users maps.
641        */
642
643        nmaps = switch_map_find("passwd", maptype, mapreturn);
644        for (i = 0; i < nmaps; i++)
645        {
646                if (strcmp(maptype[i], "files") == 0 &&
647                    stab("users.files", ST_MAP, ST_FIND) == NULL)
648                {
649                        strcpy(buf, "users.files text -m -z: -k0 -v6 /etc/passwd");
650                        (void) makemapentry(buf);
651                }
652#ifdef NISPLUS
653                else if (strcmp(maptype[i], "nisplus") == 0 &&
654                    stab("users.nisplus", ST_MAP, ST_FIND) == NULL)
655                {
656                        strcpy(buf, "users.nisplus nisplus -m -kname -vhome -d passwd.org_dir");
657                        (void) makemapentry(buf);
658                }
659#endif
660#ifdef NIS
661                else if (strcmp(maptype[i], "nis") == 0 &&
662                    stab("users.nis", ST_MAP, ST_FIND) == NULL)
663                {
664                        strcpy(buf, "users.nis nis -m -d passwd.byname");
665                        (void) makemapentry(buf);
666                }
667#endif
668#ifdef HESIOD
669                else if (strcmp(maptype[i], "hesiod") == 0) &&
670                    stab("users.hesiod", ST_MAP, ST_FIND) == NULL)
671                {
672                        strcpy(buf, "users.hesiod hesiod");
673                        (void) makemapentry(buf);
674                }
675#endif
676        }
677        if (stab("users", ST_MAP, ST_FIND) == NULL)
678        {
679                strcpy(buf, "users switch -m passwd");
680                (void) makemapentry(buf);
681        }
682#endif
683}
684/*
685**  SWITCH_MAP_FIND -- find the list of types associated with a map
686**
687**      This is the system-dependent interface to the service switch.
688**
689**      Parameters:
690**              service -- the name of the service of interest.
691**              maptype -- an out-array of strings containing the types
692**                      of access to use for this service.  There can
693**                      be at most MAXMAPSTACK types for a single service.
694**              mapreturn -- an out-array of return information bitmaps
695**                      for the map.
696**
697**      Returns:
698**              The number of map types filled in, or -1 for failure.
699*/
700
701#if defined(SOLARIS) || (defined(sony_news) && defined(__svr4))
702# define _USE_SUN_NSSWITCH_
703#endif
704
705#ifdef _USE_SUN_NSSWITCH_
706# include <nsswitch.h>
707#endif
708
709#if defined(ultrix) || (defined(__osf__) && defined(__alpha))
710# define _USE_DEC_SVC_CONF_
711#endif
712
713#ifdef _USE_DEC_SVC_CONF_
714# include <sys/svcinfo.h>
715#endif
716
717int
718switch_map_find(service, maptype, mapreturn)
719        char *service;
720        char *maptype[MAXMAPSTACK];
721        short mapreturn[MAXMAPACTIONS];
722{
723        int svcno;
724
725#ifdef _USE_SUN_NSSWITCH_
726        struct __nsw_switchconfig *nsw_conf;
727        enum __nsw_parse_err pserr;
728        struct __nsw_lookup *lk;
729        static struct __nsw_lookup lkp0 =
730                { "files", {1, 0, 0, 0}, NULL, NULL };
731        static struct __nsw_switchconfig lkp_default =
732                { 0, "sendmail", 3, &lkp0 };
733
734        for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
735                mapreturn[svcno] = 0;
736
737        if ((nsw_conf = __nsw_getconfig(service, &pserr)) == NULL)
738                lk = lkp_default.lookups;
739        else
740                lk = nsw_conf->lookups;
741        svcno = 0;
742        while (lk != NULL)
743        {
744                maptype[svcno] = lk->service_name;
745                if (lk->actions[__NSW_NOTFOUND] == __NSW_RETURN)
746                        mapreturn[MA_NOTFOUND] |= 1 << svcno;
747                if (lk->actions[__NSW_TRYAGAIN] == __NSW_RETURN)
748                        mapreturn[MA_TRYAGAIN] |= 1 << svcno;
749                if (lk->actions[__NSW_UNAVAIL] == __NSW_RETURN)
750                        mapreturn[MA_TRYAGAIN] |= 1 << svcno;
751                svcno++;
752                lk = lk->next;
753        }
754        return svcno;
755#endif
756
757#ifdef _USE_DEC_SVC_CONF_
758        struct svcinfo *svcinfo;
759        int svc;
760
761        for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
762                mapreturn[svcno] = 0;
763
764        svcinfo = getsvc();
765        if (svcinfo == NULL)
766                goto punt;
767        if (strcmp(service, "hosts") == 0)
768                svc = SVC_HOSTS;
769        else if (strcmp(service, "aliases") == 0)
770                svc = SVC_ALIASES;
771        else if (strcmp(service, "passwd") == 0)
772                svc = SVC_PASSWD;
773        else
774                return -1;
775        for (svcno = 0; svcno < SVC_PATHSIZE; svcno++)
776        {
777                switch (svcinfo->svcpath[svc][svcno])
778                {
779                  case SVC_LOCAL:
780                        maptype[svcno] = "files";
781                        break;
782
783                  case SVC_YP:
784                        maptype[svcno] = "nis";
785                        break;
786
787                  case SVC_BIND:
788                        maptype[svcno] = "dns";
789                        break;
790
791#ifdef SVC_HESIOD
792                  case SVC_HESIOD:
793                        maptype[svcno] = "hesiod";
794                        break;
795#endif
796
797                  case SVC_LAST:
798                        return svcno;
799                }
800        }
801        return svcno;
802#endif
803
804#if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_)
805        /*
806        **  Fall-back mechanism.
807        */
808
809        STAB *st;
810        time_t now = curtime();
811
812        for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
813                mapreturn[svcno] = 0;
814
815        if ((now - ServiceCacheTime) > (time_t) ServiceCacheMaxAge)
816        {
817                /* (re)read service switch */
818                register FILE *fp;
819                int sff = SFF_REGONLY|SFF_OPENASROOT|SFF_NOLOCK;
820
821                if (!bitset(DBS_LINKEDSERVICESWITCHFILEINWRITABLEDIR, DontBlameSendmail))
822                        sff |= SFF_NOWLINK;
823
824                if (ConfigFileRead)
825                        ServiceCacheTime = now;
826                fp = safefopen(ServiceSwitchFile, O_RDONLY, 0, sff);
827                if (fp != NULL)
828                {
829                        char buf[MAXLINE];
830
831                        while (fgets(buf, sizeof buf, fp) != NULL)
832                        {
833                                register char *p;
834
835                                p = strpbrk(buf, "#\n");
836                                if (p != NULL)
837                                        *p = '\0';
838                                p = strpbrk(buf, " \t");
839                                if (p != NULL)
840                                        *p++ = '\0';
841                                if (buf[0] == '\0')
842                                        continue;
843                                if (p == NULL)
844                                {
845                                        sm_syslog(LOG_ERR, NOQID,
846                                                  "Bad line on %.100s: %.100s",
847                                                  ServiceSwitchFile,
848                                                  buf);
849                                        continue;
850                                }
851                                while (isspace(*p))
852                                        p++;
853                                if (*p == '\0')
854                                        continue;
855
856                                /*
857                                **  Find/allocate space for this service entry.
858                                **      Space for all of the service strings
859                                **      are allocated at once.  This means
860                                **      that we only have to free the first
861                                **      one to free all of them.
862                                */
863
864                                st = stab(buf, ST_SERVICE, ST_ENTER);
865                                if (st->s_service[0] != NULL)
866                                        free((void *) st->s_service[0]);
867                                p = newstr(p);
868                                for (svcno = 0; svcno < MAXMAPSTACK; )
869                                {
870                                        if (*p == '\0')
871                                                break;
872                                        st->s_service[svcno++] = p;
873                                        p = strpbrk(p, " \t");
874                                        if (p == NULL)
875                                                break;
876                                        *p++ = '\0';
877                                        while (isspace(*p))
878                                                p++;
879                                }
880                                if (svcno < MAXMAPSTACK)
881                                        st->s_service[svcno] = NULL;
882                        }
883                        fclose(fp);
884                }
885        }
886
887        /* look up entry in cache */
888        st = stab(service, ST_SERVICE, ST_FIND);
889        if (st != NULL && st->s_service[0] != NULL)
890        {
891                /* extract data */
892                svcno = 0;
893                while (svcno < MAXMAPSTACK)
894                {
895                        maptype[svcno] = st->s_service[svcno];
896                        if (maptype[svcno++] == NULL)
897                                break;
898                }
899                return --svcno;
900        }
901#endif
902
903#if !defined(_USE_SUN_NSSWITCH_)
904        /* if the service file doesn't work, use an absolute fallback */
905# ifdef _USE_DEC_SVC_CONF_
906  punt:
907# endif
908        for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
909                mapreturn[svcno] = 0;
910        svcno = 0;
911        if (strcmp(service, "aliases") == 0)
912        {
913                maptype[svcno++] = "files";
914# ifdef AUTO_NIS_ALIASES
915#  ifdef NISPLUS
916                maptype[svcno++] = "nisplus";
917#  endif
918#  ifdef NIS
919                maptype[svcno++] = "nis";
920#  endif
921# endif
922                return svcno;
923        }
924        if (strcmp(service, "hosts") == 0)
925        {
926#  if NAMED_BIND
927                maptype[svcno++] = "dns";
928#  else
929#   if defined(sun) && !defined(BSD)
930                /* SunOS */
931                maptype[svcno++] = "nis";
932#   endif
933#  endif
934                maptype[svcno++] = "files";
935                return svcno;
936        }
937        return -1;
938#endif
939}
940/*
941**  USERNAME -- return the user id of the logged in user.
942**
943**      Parameters:
944**              none.
945**
946**      Returns:
947**              The login name of the logged in user.
948**
949**      Side Effects:
950**              none.
951**
952**      Notes:
953**              The return value is statically allocated.
954*/
955
956char *
957username()
958{
959        static char *myname = NULL;
960        extern char *getlogin();
961        register struct passwd *pw;
962
963        /* cache the result */
964        if (myname == NULL)
965        {
966                myname = getlogin();
967                if (myname == NULL || myname[0] == '\0')
968                {
969                        pw = sm_getpwuid(RealUid);
970                        if (pw != NULL)
971                                myname = newstr(pw->pw_name);
972                }
973                else
974                {
975                        uid_t uid = RealUid;
976
977                        myname = newstr(myname);
978                        if ((pw = sm_getpwnam(myname)) == NULL ||
979                              (uid != 0 && uid != pw->pw_uid))
980                        {
981                                pw = sm_getpwuid(uid);
982                                if (pw != NULL)
983                                        myname = newstr(pw->pw_name);
984                        }
985                }
986                if (myname == NULL || myname[0] == '\0')
987                {
988                        syserr("554 Who are you?");
989                        myname = "postmaster";
990                }
991        }
992
993        return (myname);
994}
995/*
996**  TTYPATH -- Get the path of the user's tty
997**
998**      Returns the pathname of the user's tty.  Returns NULL if
999**      the user is not logged in or if s/he has write permission
1000**      denied.
1001**
1002**      Parameters:
1003**              none
1004**
1005**      Returns:
1006**              pathname of the user's tty.
1007**              NULL if not logged in or write permission denied.
1008**
1009**      Side Effects:
1010**              none.
1011**
1012**      WARNING:
1013**              Return value is in a local buffer.
1014**
1015**      Called By:
1016**              savemail
1017*/
1018
1019char *
1020ttypath()
1021{
1022        struct stat stbuf;
1023        register char *pathn;
1024        extern char *ttyname();
1025        extern char *getlogin();
1026
1027        /* compute the pathname of the controlling tty */
1028        if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL &&
1029            (pathn = ttyname(0)) == NULL)
1030        {
1031                errno = 0;
1032                return (NULL);
1033        }
1034
1035        /* see if we have write permission */
1036        if (stat(pathn, &stbuf) < 0 || !bitset(S_IWOTH, stbuf.st_mode))
1037        {
1038                errno = 0;
1039                return (NULL);
1040        }
1041
1042        /* see if the user is logged in */
1043        if (getlogin() == NULL)
1044                return (NULL);
1045
1046        /* looks good */
1047        return (pathn);
1048}
1049/*
1050**  CHECKCOMPAT -- check for From and To person compatible.
1051**
1052**      This routine can be supplied on a per-installation basis
1053**      to determine whether a person is allowed to send a message.
1054**      This allows restriction of certain types of internet
1055**      forwarding or registration of users.
1056**
1057**      If the hosts are found to be incompatible, an error
1058**      message should be given using "usrerr" and an EX_ code
1059**      should be returned.  You can also set to->q_status to
1060**      a DSN-style status code.
1061**
1062**      EF_NO_BODY_RETN can be set in e->e_flags to suppress the
1063**      body during the return-to-sender function; this should be done
1064**      on huge messages.  This bit may already be set by the ESMTP
1065**      protocol.
1066**
1067**      Parameters:
1068**              to -- the person being sent to.
1069**
1070**      Returns:
1071**              an exit status
1072**
1073**      Side Effects:
1074**              none (unless you include the usrerr stuff)
1075*/
1076
1077int
1078checkcompat(to, e)
1079        register ADDRESS *to;
1080        register ENVELOPE *e;
1081{
1082# ifdef lint
1083        if (to == NULL)
1084                to++;
1085# endif /* lint */
1086
1087        if (tTd(49, 1))
1088                printf("checkcompat(to=%s, from=%s)\n",
1089                        to->q_paddr, e->e_from.q_paddr);
1090
1091# ifdef EXAMPLE_CODE
1092        /* this code is intended as an example only */
1093        register STAB *s;
1094
1095        s = stab("arpa", ST_MAILER, ST_FIND);
1096        if (s != NULL && strcmp(e->e_from.q_mailer->m_name, "local") != 0 &&
1097            to->q_mailer == s->s_mailer)
1098        {
1099                usrerr("553 No ARPA mail through this machine: see your system administration");
1100                /* e->e_flags |= EF_NO_BODY_RETN; to supress body on return */
1101                to->q_status = "5.7.1";
1102                return (EX_UNAVAILABLE);
1103        }
1104# endif /* EXAMPLE_CODE */
1105        return (EX_OK);
1106}
1107/*
1108**  SETSIGNAL -- set a signal handler
1109**
1110**      This is essentially old BSD "signal(3)".
1111*/
1112
1113sigfunc_t
1114setsignal(sig, handler)
1115        int sig;
1116        sigfunc_t handler;
1117{
1118#if defined(SYS5SIGNALS) || defined(BSD4_3)
1119# ifdef BSD4_3
1120        return signal(sig, handler);
1121# else
1122        return sigset(sig, handler);
1123# endif
1124#else
1125        struct sigaction n, o;
1126
1127        bzero(&n, sizeof n);
1128# if USE_SA_SIGACTION
1129        n.sa_sigaction = (void(*)(int, siginfo_t *, void *)) handler;
1130        n.sa_flags = SA_RESTART|SA_SIGINFO;
1131# else
1132        n.sa_handler = handler;
1133#  ifdef SA_RESTART
1134        n.sa_flags = SA_RESTART;
1135#  endif
1136# endif
1137        if (sigaction(sig, &n, &o) < 0)
1138                return SIG_ERR;
1139        return o.sa_handler;
1140#endif
1141}
1142/*
1143**  BLOCKSIGNAL -- hold a signal to prevent delivery
1144**
1145**      Parameters:
1146**              sig -- the signal to block.
1147**
1148**      Returns:
1149**              1 signal was previously blocked
1150**              0 signal was not previously blocked
1151**              -1 on failure.
1152*/
1153
1154int
1155blocksignal(sig)
1156        int sig;
1157{
1158#ifdef BSD4_3
1159# ifndef sigmask
1160#  define sigmask(s)    (1 << ((s) - 1))
1161# endif
1162        return (sigblock(sigmask(sig)) & sigmask(sig)) != 0;
1163#else
1164# ifdef ALTOS_SYSTEM_V
1165        sigfunc_t handler;
1166
1167        handler = sigset(sig, SIG_HOLD);
1168        if (handler == SIG_ERR)
1169                return -1;
1170        else
1171                return handler == SIG_HOLD;
1172# else
1173        sigset_t sset, oset;
1174
1175        sigemptyset(&sset);
1176        sigaddset(&sset, sig);
1177        if (sigprocmask(SIG_BLOCK, &sset, &oset) < 0)
1178                return -1;
1179        else
1180                return sigismember(&oset, sig);
1181# endif
1182#endif
1183}
1184/*
1185**  RELEASESIGNAL -- release a held signal
1186**
1187**      Parameters:
1188**              sig -- the signal to release.
1189**
1190**      Returns:
1191**              1 signal was previously blocked
1192**              0 signal was not previously blocked
1193**              -1 on failure.
1194*/
1195
1196int
1197releasesignal(sig)
1198        int sig;
1199{
1200#ifdef BSD4_3
1201        return (sigsetmask(sigblock(0) & ~sigmask(sig)) & sigmask(sig)) != 0;
1202#else
1203# ifdef ALTOS_SYSTEM_V
1204        sigfunc_t handler;
1205
1206        handler = sigset(sig, SIG_HOLD);
1207        if (sigrelse(sig) < 0)
1208                return -1;
1209        else
1210                return handler == SIG_HOLD;
1211# else
1212        sigset_t sset, oset;
1213
1214        sigemptyset(&sset);
1215        sigaddset(&sset, sig);
1216        if (sigprocmask(SIG_UNBLOCK, &sset, &oset) < 0)
1217                return -1;
1218        else
1219                return sigismember(&oset, sig);
1220# endif
1221#endif
1222}
1223/*
1224**  HOLDSIGS -- arrange to hold all signals
1225**
1226**      Parameters:
1227**              none.
1228**
1229**      Returns:
1230**              none.
1231**
1232**      Side Effects:
1233**              Arranges that signals are held.
1234*/
1235
1236void
1237holdsigs()
1238{
1239}
1240/*
1241**  RLSESIGS -- arrange to release all signals
1242**
1243**      This undoes the effect of holdsigs.
1244**
1245**      Parameters:
1246**              none.
1247**
1248**      Returns:
1249**              none.
1250**
1251**      Side Effects:
1252**              Arranges that signals are released.
1253*/
1254
1255void
1256rlsesigs()
1257{
1258}
1259/*
1260**  INIT_MD -- do machine dependent initializations
1261**
1262**      Systems that have global modes that should be set should do
1263**      them here rather than in main.
1264*/
1265
1266#ifdef _AUX_SOURCE
1267# include <compat.h>
1268#endif
1269
1270#if SHARE_V1
1271# include <shares.h>
1272#endif
1273
1274void
1275init_md(argc, argv)
1276        int argc;
1277        char **argv;
1278{
1279#ifdef _AUX_SOURCE
1280        setcompat(getcompat() | COMPAT_BSDPROT);
1281#endif
1282
1283#ifdef SUN_EXTENSIONS
1284        init_md_sun();
1285#endif
1286
1287#if _CONVEX_SOURCE
1288        /* keep gethostby*() from stripping the local domain name */
1289        set_domain_trim_off();
1290#endif
1291#ifdef __QNX__
1292        /*
1293        **  Due to QNX's network distributed nature, you can target a tcpip
1294        **  stack on a different node in the qnx network; this patch lets
1295        **  this feature work.  The __sock_locate() must be done before the
1296        **  environment is clear.
1297        */
1298        __sock_locate();
1299#endif
1300#if SECUREWARE || defined(_SCO_unix_)
1301        set_auth_parameters(argc, argv);
1302
1303# ifdef _SCO_unix_
1304        /*
1305        **  This is required for highest security levels (the kernel
1306        **  won't let it call set*uid() or run setuid binaries without
1307        **  it).  It may be necessary on other SECUREWARE systems.
1308        */
1309
1310        if (getluid() == -1)
1311                setluid(0);
1312# endif
1313#endif
1314
1315#ifdef VENDOR_DEFAULT
1316        VendorCode = VENDOR_DEFAULT;
1317#else
1318        VendorCode = VENDOR_BERKELEY;
1319#endif
1320}
1321/*
1322**  INIT_VENDOR_MACROS -- vendor-dependent macro initializations
1323**
1324**      Called once, on startup.
1325**
1326**      Parameters:
1327**              e -- the global envelope.
1328**
1329**      Returns:
1330**              none.
1331**
1332**      Side Effects:
1333**              vendor-dependent.
1334*/
1335
1336void
1337init_vendor_macros(e)
1338        register ENVELOPE *e;
1339{
1340}
1341/*
1342**  GETLA -- get the current load average
1343**
1344**      This code stolen from la.c.
1345**
1346**      Parameters:
1347**              none.
1348**
1349**      Returns:
1350**              The current load average as an integer.
1351**
1352**      Side Effects:
1353**              none.
1354*/
1355
1356/* try to guess what style of load average we have */
1357#define LA_ZERO         1       /* always return load average as zero */
1358#define LA_INT          2       /* read kmem for avenrun; interpret as long */
1359#define LA_FLOAT        3       /* read kmem for avenrun; interpret as float */
1360#define LA_SUBR         4       /* call getloadavg */
1361#define LA_MACH         5       /* MACH load averages (as on NeXT boxes) */
1362#define LA_SHORT        6       /* read kmem for avenrun; interpret as short */
1363#define LA_PROCSTR      7       /* read string ("1.17") from /proc/loadavg */
1364#define LA_READKSYM     8       /* SVR4: use MIOC_READKSYM ioctl call */
1365#define LA_DGUX         9       /* special DGUX implementation */
1366#define LA_HPUX         10      /* special HPUX implementation */
1367#define LA_IRIX6        11      /* special IRIX 6.2 implementation */
1368#define LA_KSTAT        12      /* special Solaris kstat(3k) implementation */
1369#define LA_DEVSHORT     13      /* read short from a device */
1370#define LA_ALPHAOSF     14      /* Digital UNIX (OSF/1 on Alpha) table() call */
1371
1372/* do guesses based on general OS type */
1373#ifndef LA_TYPE
1374# define LA_TYPE        LA_ZERO
1375#endif
1376
1377#ifndef FSHIFT
1378# if defined(unixpc)
1379#  define FSHIFT        5
1380# endif
1381
1382# if defined(__alpha) || defined(IRIX)
1383#  define FSHIFT        10
1384# endif
1385
1386#endif
1387
1388#ifndef FSHIFT
1389# define FSHIFT         8
1390#endif
1391
1392#ifndef FSCALE
1393# define FSCALE         (1 << FSHIFT)
1394#endif
1395
1396#ifndef LA_AVENRUN
1397# ifdef SYSTEM5
1398#  define LA_AVENRUN    "avenrun"
1399# else
1400#  define LA_AVENRUN    "_avenrun"
1401# endif
1402#endif
1403
1404/* _PATH_KMEM should be defined in <paths.h> */
1405#ifndef _PATH_KMEM
1406# define _PATH_KMEM     "/dev/kmem"
1407#endif
1408
1409#if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT)
1410
1411#include <nlist.h>
1412
1413/* _PATH_UNIX should be defined in <paths.h> */
1414#ifndef _PATH_UNIX
1415# if defined(SYSTEM5)
1416#  define _PATH_UNIX    "/unix"
1417# else
1418#  define _PATH_UNIX    "/vmunix"
1419# endif
1420#endif
1421
1422#ifdef _AUX_SOURCE
1423struct nlist    Nl[2];
1424#else
1425struct nlist    Nl[] =
1426{
1427        { LA_AVENRUN },
1428        { 0 },
1429};
1430#endif
1431#define X_AVENRUN       0
1432
1433int
1434getla()
1435{
1436        static int kmem = -1;
1437#if LA_TYPE == LA_INT
1438        long avenrun[3];
1439#else
1440# if LA_TYPE == LA_SHORT
1441        short avenrun[3];
1442# else
1443        double avenrun[3];
1444# endif
1445#endif
1446        extern int errno;
1447        extern off_t lseek();
1448
1449        if (kmem < 0)
1450        {
1451#ifdef _AUX_SOURCE
1452                strcpy(Nl[X_AVENRUN].n_name, LA_AVENRUN);
1453                Nl[1].n_name[0] = '\0';
1454#endif
1455
1456#if defined(_AIX3) || defined(_AIX4)
1457                if (knlist(Nl, 1, sizeof Nl[0]) < 0)
1458#else
1459                if (nlist(_PATH_UNIX, Nl) < 0)
1460#endif
1461                {
1462                        if (tTd(3, 1))
1463                                printf("getla: nlist(%s): %s\n", _PATH_UNIX,
1464                                        errstring(errno));
1465                        return (-1);
1466                }
1467                if (Nl[X_AVENRUN].n_value == 0)
1468                {
1469                        if (tTd(3, 1))
1470                                printf("getla: nlist(%s, %s) ==> 0\n",
1471                                        _PATH_UNIX, LA_AVENRUN);
1472                        return (-1);
1473                }
1474#ifdef NAMELISTMASK
1475                Nl[X_AVENRUN].n_value &= NAMELISTMASK;
1476#endif
1477
1478                kmem = open(_PATH_KMEM, 0, 0);
1479                if (kmem < 0)
1480                {
1481                        if (tTd(3, 1))
1482                                printf("getla: open(/dev/kmem): %s\n",
1483                                        errstring(errno));
1484                        return (-1);
1485                }
1486                (void) fcntl(kmem, F_SETFD, 1);
1487        }
1488        if (tTd(3, 20))
1489                printf("getla: symbol address = %#lx\n",
1490                        (u_long) Nl[X_AVENRUN].n_value);
1491        if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, SEEK_SET) == -1 ||
1492            read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
1493        {
1494                /* thank you Ian */
1495                if (tTd(3, 1))
1496                        printf("getla: lseek or read: %s\n", errstring(errno));
1497                return (-1);
1498        }
1499# if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)
1500        if (tTd(3, 5))
1501        {
1502#  if LA_TYPE == LA_SHORT
1503                printf("getla: avenrun = %d", avenrun[0]);
1504                if (tTd(3, 15))
1505                        printf(", %d, %d", avenrun[1], avenrun[2]);
1506#  else
1507                printf("getla: avenrun = %ld", avenrun[0]);
1508                if (tTd(3, 15))
1509                        printf(", %ld, %ld", avenrun[1], avenrun[2]);
1510#  endif
1511                printf("\n");
1512        }
1513        if (tTd(3, 1))
1514                printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1515        return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1516# else /* LA_TYPE == LA_FLOAT */
1517        if (tTd(3, 5))
1518        {
1519                printf("getla: avenrun = %g", avenrun[0]);
1520                if (tTd(3, 15))
1521                        printf(", %g, %g", avenrun[1], avenrun[2]);
1522                printf("\n");
1523        }
1524        if (tTd(3, 1))
1525                printf("getla: %d\n", (int) (avenrun[0] +0.5));
1526        return ((int) (avenrun[0] + 0.5));
1527# endif
1528}
1529
1530#endif /* LA_TYPE == LA_INT or LA_SHORT or LA_FLOAT */
1531
1532#if LA_TYPE == LA_READKSYM
1533
1534# include <sys/ksym.h>
1535
1536getla()
1537{
1538        static int kmem = -1;
1539        long avenrun[3];
1540        extern int errno;
1541        struct mioc_rksym mirk;
1542
1543        if (kmem < 0)
1544        {
1545                kmem = open("/dev/kmem", 0, 0);
1546                if (kmem < 0)
1547                {
1548                        if (tTd(3, 1))
1549                                printf("getla: open(/dev/kmem): %s\n",
1550                                        errstring(errno));
1551                        return (-1);
1552                }
1553                (void) fcntl(kmem, F_SETFD, 1);
1554        }
1555        mirk.mirk_symname = LA_AVENRUN;
1556        mirk.mirk_buf = avenrun;
1557        mirk.mirk_buflen = sizeof(avenrun);
1558        if (ioctl(kmem, MIOC_READKSYM, &mirk) < 0)
1559        {
1560                if (tTd(3, 1))
1561                        printf("getla: ioctl(MIOC_READKSYM) failed: %s\n",
1562                                errstring(errno));
1563                return -1;
1564        }
1565        if (tTd(3, 5))
1566        {
1567                printf("getla: avenrun = %d", avenrun[0]);
1568                if (tTd(3, 15))
1569                        printf(", %d, %d", avenrun[1], avenrun[2]);
1570                printf("\n");
1571        }
1572        if (tTd(3, 1))
1573                printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1574        return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1575}
1576
1577#endif /* LA_TYPE == LA_READKSYM */
1578
1579#if LA_TYPE == LA_DGUX
1580
1581# include <sys/dg_sys_info.h>
1582
1583int
1584getla()
1585{
1586        struct dg_sys_info_load_info load_info;
1587
1588        dg_sys_info((long *)&load_info,
1589                DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0);
1590
1591        if (tTd(3, 1))
1592                printf("getla: %d\n", (int) (load_info.one_minute + 0.5));
1593
1594        return((int) (load_info.one_minute + 0.5));
1595}
1596
1597#endif /* LA_TYPE == LA_DGUX */
1598
1599#if LA_TYPE == LA_HPUX
1600
1601/* forward declarations to keep gcc from complaining */
1602struct pst_dynamic;
1603struct pst_status;
1604struct pst_static;
1605struct pst_vminfo;
1606struct pst_diskinfo;
1607struct pst_processor;
1608struct pst_lv;
1609struct pst_swapinfo;
1610
1611# include <sys/param.h>
1612# include <sys/pstat.h>
1613
1614int
1615getla()
1616{
1617        struct pst_dynamic pstd;
1618
1619        if (pstat_getdynamic(&pstd, sizeof(struct pst_dynamic),
1620                             (size_t) 1, 0) == -1)
1621                return 0;
1622
1623        if (tTd(3, 1))
1624                printf("getla: %d\n", (int) (pstd.psd_avg_1_min + 0.5));
1625
1626        return (int) (pstd.psd_avg_1_min + 0.5);
1627}
1628
1629#endif /* LA_TYPE == LA_HPUX */
1630
1631#if LA_TYPE == LA_SUBR
1632
1633int
1634getla()
1635{
1636        double avenrun[3];
1637
1638        if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0)
1639        {
1640                if (tTd(3, 1))
1641                        perror("getla: getloadavg failed:");
1642                return (-1);
1643        }
1644        if (tTd(3, 1))
1645                printf("getla: %d\n", (int) (avenrun[0] +0.5));
1646        return ((int) (avenrun[0] + 0.5));
1647}
1648
1649#endif /* LA_TYPE == LA_SUBR */
1650
1651#if LA_TYPE == LA_MACH
1652
1653/*
1654**  This has been tested on NEXTSTEP release 2.1/3.X.
1655*/
1656
1657#if defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0
1658# include <mach/mach.h>
1659#else
1660# include <mach.h>
1661#endif
1662
1663int
1664getla()
1665{
1666        processor_set_t default_set;
1667        kern_return_t error;
1668        unsigned int info_count;
1669        struct processor_set_basic_info info;
1670        host_t host;
1671
1672        error = processor_set_default(host_self(), &default_set);
1673        if (error != KERN_SUCCESS)
1674        {
1675                if (tTd(3, 1))
1676                        perror("getla: processor_set_default failed:");
1677                return -1;
1678        }
1679        info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
1680        if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO,
1681                               &host, (processor_set_info_t)&info,
1682                               &info_count) != KERN_SUCCESS)
1683        {
1684                if (tTd(3, 1))
1685                        perror("getla: processor_set_info failed:");
1686                return -1;
1687        }
1688        if (tTd(3, 1))
1689                printf("getla: %d\n", (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE);
1690        return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE;
1691}
1692
1693#endif /* LA_TYPE == LA_MACH */
1694
1695#if LA_TYPE == LA_PROCSTR
1696
1697/*
1698**  Read /proc/loadavg for the load average.  This is assumed to be
1699**  in a format like "0.15 0.12 0.06".
1700**
1701**      Initially intended for Linux.  This has been in the kernel
1702**      since at least 0.99.15.
1703*/
1704
1705# ifndef _PATH_LOADAVG
1706#  define _PATH_LOADAVG "/proc/loadavg"
1707# endif
1708
1709int
1710getla()
1711{
1712        double avenrun;
1713        register int result;
1714        FILE *fp;
1715
1716        fp = fopen(_PATH_LOADAVG, "r");
1717        if (fp == NULL)
1718        {
1719                if (tTd(3, 1))
1720                        printf("getla: fopen(%s): %s\n",
1721                                _PATH_LOADAVG, errstring(errno));
1722                return -1;
1723        }
1724        result = fscanf(fp, "%lf", &avenrun);
1725        fclose(fp);
1726        if (result != 1)
1727        {
1728                if (tTd(3, 1))
1729                        printf("getla: fscanf() = %d: %s\n",
1730                                result, errstring(errno));
1731                return -1;
1732        }
1733
1734        if (tTd(3, 1))
1735                printf("getla(): %.2f\n", avenrun);
1736
1737        return ((int) (avenrun + 0.5));
1738}
1739
1740#endif /* LA_TYPE == LA_PROCSTR */
1741
1742#if LA_TYPE == LA_IRIX6
1743#include <sys/sysmp.h>
1744
1745int getla(void)
1746{
1747        static int kmem = -1;
1748        int avenrun[3];
1749
1750        if (kmem < 0)
1751        {
1752                kmem = open(_PATH_KMEM, 0, 0);
1753                if (kmem < 0)
1754                {
1755                        if (tTd(3, 1))
1756                                printf("getla: open(%s): %s\n", _PATH_KMEM,
1757                                        errstring(errno));
1758                        return -1;
1759                }
1760                (void) fcntl(kmem, F_SETFD, 1);
1761        }
1762
1763        if (lseek(kmem, (sysmp(MP_KERNADDR, MPKA_AVENRUN) & 0x7fffffff), SEEK_SET) == -1 ||
1764            read(kmem, (char *)avenrun, sizeof(avenrun)) < sizeof(avenrun))
1765        {
1766                if (tTd(3, 1))
1767                        printf("getla: lseek or read: %s\n",
1768                               errstring(errno));
1769                return -1;
1770        }
1771        if (tTd(3, 5))
1772        {
1773                printf("getla: avenrun = %ld", (long int) avenrun[0]);
1774                if (tTd(3, 15))
1775                        printf(", %ld, %ld",
1776                               (long int) avenrun[1], (long int) avenrun[2]);
1777                printf("\n");
1778        }
1779
1780        if (tTd(3, 1))
1781                printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1782        return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1783
1784}
1785#endif
1786
1787#if LA_TYPE == LA_KSTAT
1788
1789#include <kstat.h>
1790
1791int
1792getla()
1793{
1794        static kstat_ctl_t *kc = NULL;
1795        static kstat_t *ksp = NULL;
1796        kstat_named_t *ksn;
1797        int la;
1798
1799        if (kc == NULL)         /* if not initialized before */
1800                kc = kstat_open();
1801        if (kc == NULL)
1802        {
1803                if (tTd(3, 1))
1804                        printf("getla: kstat_open(): %s\n",
1805                                errstring(errno));
1806                return -1;
1807        }
1808        if (ksp == NULL)
1809                ksp = kstat_lookup(kc, "unix", 0, "system_misc");
1810        if (ksp == NULL)
1811        {
1812                if (tTd(3, 1))
1813                        printf("getla: kstat_lookup(): %s\n",
1814                                errstring(errno));
1815                return -1;
1816        }
1817        if (kstat_read(kc, ksp, NULL) < 0)
1818        {
1819                if (tTd(3, 1))
1820                        printf("getla: kstat_read(): %s\n",
1821                                errstring(errno));
1822                return -1;
1823        }
1824        ksn = (kstat_named_t *) kstat_data_lookup(ksp, "avenrun_1min");
1825        la = ((double)ksn->value.ul + FSCALE/2) / FSCALE;
1826        /* kstat_close(kc); /o do not close for fast access */
1827        return la;
1828}
1829
1830#endif /* LA_TYPE == LA_KSTAT */
1831
1832#if LA_TYPE == LA_DEVSHORT
1833
1834/*
1835**  Read /dev/table/avenrun for the load average.  This should contain
1836**  three shorts for the 1, 5, and 15 minute loads.  We only read the
1837**  first, since that's all we care about.
1838**
1839**      Intended for SCO OpenServer 5.
1840*/
1841
1842# ifndef _PATH_AVENRUN
1843#  define _PATH_AVENRUN "/dev/table/avenrun"
1844# endif
1845
1846int
1847getla()
1848{
1849        static int afd = -1;
1850        short avenrun;
1851        int loadav;
1852        int r;
1853
1854        errno = EBADF;
1855
1856        if (afd == -1 || lseek(afd, 0L, SEEK_SET) == -1)
1857        {
1858                if (errno != EBADF)
1859                        return -1;
1860                afd = open(_PATH_AVENRUN, O_RDONLY|O_SYNC);
1861                if (afd < 0)
1862                {
1863                        sm_syslog(LOG_ERR, NOQID,
1864                                "can't open %s: %m",
1865                                _PATH_AVENRUN);
1866                        return -1;
1867                }
1868        }
1869
1870        r = read(afd, &avenrun, sizeof avenrun);
1871
1872        if (tTd(3, 5))
1873                printf("getla: avenrun = %d\n", avenrun);
1874        loadav = (int) (avenrun + FSCALE/2) >> FSHIFT;
1875        if (tTd(3, 1))
1876                printf("getla: %d\n", loadav);
1877        return loadav;
1878}
1879
1880#endif /* LA_TYPE == LA_DEVSHORT */
1881
1882#if LA_TYPE == LA_ALPHAOSF
1883struct rtentry;
1884struct mbuf;
1885# include <sys/table.h>
1886
1887int getla()
1888{
1889        int ave = 0;
1890        struct tbl_loadavg tab;
1891
1892        if (table(TBL_LOADAVG, 0, &tab, 1, sizeof(tab)) == -1)
1893        {
1894                if (tTd(3, 1))
1895                        printf("getla: table %s\n", errstring(errno));
1896                return (-1);
1897        }
1898
1899        if (tTd(3, 1))
1900                printf("getla: scale = %d\n", tab.tl_lscale);
1901
1902        if (tab.tl_lscale)
1903                ave = (tab.tl_avenrun.l[0] + (tab.tl_lscale/2)) / tab.tl_lscale;
1904        else
1905                ave = (int) (tab.tl_avenrun.d[0] + 0.5);
1906
1907        if (tTd(3, 1))
1908                printf("getla: %d\n", ave);
1909
1910        return ave;
1911}
1912
1913#endif
1914
1915#if LA_TYPE == LA_ZERO
1916
1917int
1918getla()
1919{
1920        if (tTd(3, 1))
1921                printf("getla: ZERO\n");
1922        return (0);
1923}
1924
1925#endif /* LA_TYPE == LA_ZERO */
1926
1927/*
1928 * Copyright 1989 Massachusetts Institute of Technology
1929 *
1930 * Permission to use, copy, modify, distribute, and sell this software and its
1931 * documentation for any purpose is hereby granted without fee, provided that
1932 * the above copyright notice appear in all copies and that both that
1933 * copyright notice and this permission notice appear in supporting
1934 * documentation, and that the name of M.I.T. not be used in advertising or
1935 * publicity pertaining to distribution of the software without specific,
1936 * written prior permission.  M.I.T. makes no representations about the
1937 * suitability of this software for any purpose.  It is provided "as is"
1938 * without express or implied warranty.
1939 *
1940 * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
1941 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
1942 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1943 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
1944 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
1945 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1946 *
1947 * Authors:  Many and varied...
1948 */
1949
1950/* Non Apollo stuff removed by Don Lewis 11/15/93 */
1951#ifndef lint
1952static char  rcsid[] = "@(#)$Id: conf.c,v 1.3 1999-03-04 01:03:48 danw Exp $";
1953#endif /* !lint */
1954
1955#ifdef apollo
1956# undef volatile
1957#    include <apollo/base.h>
1958
1959/* ARGSUSED */
1960int getloadavg( call_data )
1961     caddr_t    call_data;      /* pointer to (double) return value */
1962{
1963     double *avenrun = (double *) call_data;
1964     int i;
1965     status_$t      st;
1966     long loadav[3];
1967     proc1_$get_loadav(loadav, &st);
1968     *avenrun = loadav[0] / (double) (1 << 16);
1969     return(0);
1970}
1971#   endif /* apollo */
1972/*
1973**  SHOULDQUEUE -- should this message be queued or sent?
1974**
1975**      Compares the message cost to the load average to decide.
1976**
1977**      Parameters:
1978**              pri -- the priority of the message in question.
1979**              ctime -- the message creation time.
1980**
1981**      Returns:
1982**              TRUE -- if this message should be queued up for the
1983**                      time being.
1984**              FALSE -- if the load is low enough to send this message.
1985**
1986**      Side Effects:
1987**              none.
1988*/
1989
1990extern int      get_num_procs_online __P((void));
1991
1992bool
1993shouldqueue(pri, ctime)
1994        long pri;
1995        time_t ctime;
1996{
1997        bool rval;
1998        int queuela = QueueLA * get_num_procs_online();
1999
2000        if (tTd(3, 30))
2001                printf("shouldqueue: CurrentLA=%d, pri=%ld: ", CurrentLA, pri);
2002        if (CurrentLA < queuela)
2003        {
2004                if (tTd(3, 30))
2005                        printf("FALSE (CurrentLA < QueueLA)\n");
2006                return (FALSE);
2007        }
2008#if 0   /* this code is reported to cause oscillation around RefuseLA */
2009        if (CurrentLA >= RefuseLA && QueueLA < RefuseLA)
2010        {
2011                if (tTd(3, 30))
2012                        printf("TRUE (CurrentLA >= RefuseLA)\n");
2013                return (TRUE);
2014        }
2015#endif
2016        rval = pri > (QueueFactor / (CurrentLA - queuela + 1));
2017        if (tTd(3, 30))
2018                printf("%s (by calculation)\n", rval ? "TRUE" : "FALSE");
2019        return rval;
2020}
2021/*
2022**  REFUSECONNECTIONS -- decide if connections should be refused
2023**
2024**      Parameters:
2025**              port -- port number (for error messages only)
2026**
2027**      Returns:
2028**              TRUE if incoming SMTP connections should be refused
2029**                      (for now).
2030**              FALSE if we should accept new work.
2031**
2032**      Side Effects:
2033**              Sets process title when it is rejecting connections.
2034*/
2035
2036bool
2037refuseconnections(port)
2038        int port;
2039{
2040        int refusela = RefuseLA * get_num_procs_online();
2041        time_t now;
2042        static time_t lastconn = (time_t) 0;
2043        static int conncnt = 0;
2044        extern bool enoughdiskspace __P((long));
2045
2046#ifdef XLA
2047        if (!xla_smtp_ok())
2048                return TRUE;
2049#endif
2050
2051        now = curtime();
2052        if (now != lastconn)
2053        {
2054                lastconn = now;
2055                conncnt = 0;
2056        }
2057        else if (conncnt++ > ConnRateThrottle && ConnRateThrottle > 0)
2058        {
2059                /* sleep to flatten out connection load */
2060                sm_setproctitle(TRUE, "deferring connections on port %d: %d per second",
2061                        port, ConnRateThrottle);
2062                if (LogLevel >= 14)
2063                        sm_syslog(LOG_INFO, NOQID,
2064                                "deferring connections on port %d: %d per second",
2065                                port, ConnRateThrottle);
2066                sleep(1);
2067        }
2068
2069        CurrentLA = getla();
2070        if (CurrentLA >= refusela)
2071        {
2072                sm_setproctitle(TRUE, "rejecting connections on port %d: load average: %d",
2073                        port, CurrentLA);
2074                if (LogLevel >= 14)
2075                        sm_syslog(LOG_INFO, NOQID,
2076                                "rejecting connections on port %d: load average: %d",
2077                                port, CurrentLA);
2078                return TRUE;
2079        }
2080
2081        if (!enoughdiskspace(MinBlocksFree + 1))
2082        {
2083                sm_setproctitle(TRUE, "rejecting connections on port %d: min free: %d",
2084                        port, MinBlocksFree);
2085                if (LogLevel >= 14)
2086                        sm_syslog(LOG_INFO, NOQID,
2087                                "rejecting connections on port %d: min free: %d",
2088                                port, MinBlocksFree);
2089                return TRUE;
2090        }
2091
2092        if (MaxChildren > 0 && CurChildren >= MaxChildren)
2093        {
2094                proc_list_probe();
2095                if (CurChildren >= MaxChildren)
2096                {
2097                        sm_setproctitle(TRUE, "rejecting connections on port %d: %d children, max %d",
2098                                port, CurChildren, MaxChildren);
2099                        if (LogLevel >= 14)
2100                                sm_syslog(LOG_INFO, NOQID,
2101                                        "rejecting connections on port %d: %d children, max %d",
2102                                        port, CurChildren, MaxChildren);
2103                        return TRUE;
2104                }
2105        }
2106
2107        return FALSE;
2108}
2109/*
2110**  SETPROCTITLE -- set process title for ps
2111**
2112**      Parameters:
2113**              fmt -- a printf style format string.
2114**              a, b, c -- possible parameters to fmt.
2115**
2116**      Returns:
2117**              none.
2118**
2119**      Side Effects:
2120**              Clobbers argv of our main procedure so ps(1) will
2121**              display the title.
2122*/
2123
2124#define SPT_NONE        0       /* don't use it at all */
2125#define SPT_REUSEARGV   1       /* cover argv with title information */
2126#define SPT_BUILTIN     2       /* use libc builtin */
2127#define SPT_PSTAT       3       /* use pstat(PSTAT_SETCMD, ...) */
2128#define SPT_PSSTRINGS   4       /* use PS_STRINGS->... */
2129#define SPT_SYSMIPS     5       /* use sysmips() supported by NEWS-OS 6 */
2130#define SPT_SCO         6       /* write kernel u. area */
2131#define SPT_CHANGEARGV  7       /* write our own strings into argv[] */
2132
2133#ifndef SPT_TYPE
2134# define SPT_TYPE       SPT_REUSEARGV
2135#endif
2136
2137#if SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN
2138
2139# if SPT_TYPE == SPT_PSTAT
2140#  include <sys/pstat.h>
2141# endif
2142# if SPT_TYPE == SPT_PSSTRINGS
2143#  include <machine/vmparam.h>
2144#  include <sys/exec.h>
2145#  ifndef PS_STRINGS    /* hmmmm....  apparently not available after all */
2146#   undef SPT_TYPE
2147#   define SPT_TYPE     SPT_REUSEARGV
2148#  else
2149#   ifndef NKPDE                        /* FreeBSD 2.0 */
2150#    define NKPDE 63
2151typedef unsigned int    *pt_entry_t;
2152#   endif
2153#  endif
2154# endif
2155
2156# if SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV
2157#  define SETPROC_STATIC        static
2158# else
2159#  define SETPROC_STATIC
2160# endif
2161
2162# if SPT_TYPE == SPT_SYSMIPS
2163#  include <sys/sysmips.h>
2164#  include <sys/sysnews.h>
2165# endif
2166
2167# if SPT_TYPE == SPT_SCO
2168#  include <sys/immu.h>
2169#  include <sys/dir.h>
2170#  include <sys/user.h>
2171#  include <sys/fs/s5param.h>
2172#  if PSARGSZ > MAXLINE
2173#   define SPT_BUFSIZE  PSARGSZ
2174#  endif
2175# endif
2176
2177# ifndef SPT_PADCHAR
2178#  define SPT_PADCHAR   ' '
2179# endif
2180
2181#endif /* SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN */
2182
2183# ifndef SPT_BUFSIZE
2184#  define SPT_BUFSIZE   MAXLINE
2185# endif
2186
2187/*
2188**  Pointers for setproctitle.
2189**      This allows "ps" listings to give more useful information.
2190*/
2191
2192char            **Argv = NULL;          /* pointer to argument vector */
2193char            *LastArgv = NULL;       /* end of argv */
2194
2195void
2196initsetproctitle(argc, argv, envp)
2197        int argc;
2198        char **argv;
2199        char **envp;
2200{
2201        register int i, envpsize = 0;
2202        extern char **environ;
2203
2204        /*
2205        **  Move the environment so setproctitle can use the space at
2206        **  the top of memory.
2207        */
2208
2209        for (i = 0; envp[i] != NULL; i++)
2210                envpsize += strlen(envp[i]) + 1;
2211        environ = (char **) xalloc(sizeof (char *) * (i + 1));
2212        for (i = 0; envp[i] != NULL; i++)
2213                environ[i] = newstr(envp[i]);
2214        environ[i] = NULL;
2215
2216        /*
2217        **  Save start and extent of argv for setproctitle.
2218        */
2219
2220        Argv = argv;
2221
2222        /*
2223        **  Determine how much space we can use for setproctitle. 
2224        **  Use all contiguous argv and envp pointers starting at argv[0]
2225        */
2226        for (i = 0; i < argc; i++)
2227        {
2228                if (i==0 || LastArgv + 1 == argv[i])
2229                        LastArgv = argv[i] + strlen(argv[i]);
2230                else
2231                        continue;
2232        }
2233        for (i=0; envp[i] != NULL; i++)
2234        {
2235                if (LastArgv + 1 == envp[i])
2236                        LastArgv = envp[i] + strlen(envp[i]);
2237                else
2238                        continue;
2239        }
2240}
2241
2242#if SPT_TYPE != SPT_BUILTIN
2243
2244
2245/*VARARGS1*/
2246void
2247# ifdef __STDC__
2248setproctitle(const char *fmt, ...)
2249# else
2250setproctitle(fmt, va_alist)
2251        const char *fmt;
2252        va_dcl
2253# endif
2254{
2255# if SPT_TYPE != SPT_NONE
2256        register char *p;
2257        register int i;
2258        SETPROC_STATIC char buf[SPT_BUFSIZE];
2259        VA_LOCAL_DECL
2260#  if SPT_TYPE == SPT_PSTAT
2261        union pstun pst;
2262#  endif
2263#  if SPT_TYPE == SPT_SCO
2264        off_t seek_off;
2265        static int kmem = -1;
2266        static int kmempid = -1;
2267        struct user u;
2268#  endif
2269
2270        p = buf;
2271
2272        /* print sendmail: heading for grep */
2273        (void) strcpy(p, "sendmail: ");
2274        p += strlen(p);
2275
2276        /* print the argument string */
2277        VA_START(fmt);
2278        (void) vsnprintf(p, SPACELEFT(buf, p), fmt, ap);
2279        VA_END;
2280
2281        i = strlen(buf);
2282
2283#  if SPT_TYPE == SPT_PSTAT
2284        pst.pst_command = buf;
2285        pstat(PSTAT_SETCMD, pst, i, 0, 0);
2286#  endif
2287#  if SPT_TYPE == SPT_PSSTRINGS
2288        PS_STRINGS->ps_nargvstr = 1;
2289        PS_STRINGS->ps_argvstr = buf;
2290#  endif
2291#  if SPT_TYPE == SPT_SYSMIPS
2292        sysmips(SONY_SYSNEWS, NEWS_SETPSARGS, buf);
2293#  endif
2294#  if SPT_TYPE == SPT_SCO
2295        if (kmem < 0 || kmempid != getpid())
2296        {
2297                if (kmem >= 0)
2298                        close(kmem);
2299                kmem = open(_PATH_KMEM, O_RDWR, 0);
2300                if (kmem < 0)
2301                        return;
2302                (void) fcntl(kmem, F_SETFD, 1);
2303                kmempid = getpid();
2304        }
2305        buf[PSARGSZ - 1] = '\0';
2306        seek_off = UVUBLK + (off_t) u.u_psargs - (off_t) &u;
2307        if (lseek(kmem, (off_t) seek_off, SEEK_SET) == seek_off)
2308                (void) write(kmem, buf, PSARGSZ);
2309#  endif
2310#  if SPT_TYPE == SPT_REUSEARGV
2311        if (i > LastArgv - Argv[0] - 2)
2312        {
2313                i = LastArgv - Argv[0] - 2;
2314                buf[i] = '\0';
2315        }
2316        (void) strcpy(Argv[0], buf);
2317        p = &Argv[0][i];
2318        while (p < LastArgv)
2319                *p++ = SPT_PADCHAR;
2320        Argv[1] = NULL;
2321#  endif
2322#  if SPT_TYPE == SPT_CHANGEARGV
2323        Argv[0] = buf;
2324        Argv[1] = 0;
2325#  endif
2326# endif /* SPT_TYPE != SPT_NONE */
2327}
2328
2329#endif /* SPT_TYPE != SPT_BUILTIN */
2330/*
2331**  SM_SETPROCTITLE -- set process task and set process title for ps
2332**
2333**      Possibly set process status and call setproctitle() to
2334**      change the ps display.
2335**
2336**      Parameters:
2337**              status -- whether or not to store as process status
2338**              fmt -- a printf style format string.
2339**              a, b, c -- possible parameters to fmt.
2340**
2341**      Returns:
2342**              none.
2343*/
2344
2345/*VARARGS2*/
2346void
2347# ifdef __STDC__
2348sm_setproctitle(bool status, const char *fmt, ...)
2349# else
2350sm_setproctitle(status, fmt, va_alist)
2351        bool status;
2352        const char *fmt;
2353        va_dcl
2354#endif
2355{
2356        char buf[SPT_BUFSIZE];
2357
2358        VA_LOCAL_DECL
2359        /* print the argument string */
2360        VA_START(fmt);
2361        (void) vsnprintf(buf, SPT_BUFSIZE, fmt, ap);
2362        VA_END;
2363
2364        if (status)
2365                proc_list_set(getpid(), buf);
2366        setproctitle("%s", buf);
2367}
2368/*
2369**  WAITFOR -- wait for a particular process id.
2370**
2371**      Parameters:
2372**              pid -- process id to wait for.
2373**
2374**      Returns:
2375**              status of pid.
2376**              -1 if pid never shows up.
2377**
2378**      Side Effects:
2379**              none.
2380*/
2381
2382int
2383waitfor(pid)
2384        pid_t pid;
2385{
2386#ifdef WAITUNION
2387        union wait st;
2388#else
2389        auto int st;
2390#endif
2391        pid_t i;
2392#if defined(ISC_UNIX) || defined(_SCO_unix_)
2393        int savesig;
2394#endif
2395
2396        do
2397        {
2398                errno = 0;
2399#if defined(ISC_UNIX) || defined(_SCO_unix_)
2400                savesig = releasesignal(SIGCHLD);
2401#endif
2402                i = wait(&st);
2403#if defined(ISC_UNIX) || defined(_SCO_unix_)
2404                if (savesig > 0)
2405                        blocksignal(SIGCHLD);
2406#endif
2407                if (i > 0)
2408                        proc_list_drop(i);
2409        } while ((i >= 0 || errno == EINTR) && i != pid);
2410        if (i < 0)
2411                return -1;
2412#ifdef WAITUNION
2413        return st.w_status;
2414#else
2415        return st;
2416#endif
2417}
2418/*
2419**  REAPCHILD -- pick up the body of my child, lest it become a zombie
2420**
2421**      Parameters:
2422**              sig -- the signal that got us here (unused).
2423**
2424**      Returns:
2425**              none.
2426**
2427**      Side Effects:
2428**              Picks up extant zombies.
2429*/
2430
2431SIGFUNC_DECL
2432reapchild(sig)
2433        int sig;
2434{
2435        int olderrno = errno;
2436        pid_t pid;
2437# ifdef HASWAITPID
2438        auto int status;
2439        int count;
2440
2441        count = 0;
2442        while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
2443        {
2444                if (count++ > 1000)
2445                {
2446                        if (LogLevel > 0)
2447                                sm_syslog(LOG_ALERT, NOQID,
2448                                        "reapchild: waitpid loop: pid=%d, status=%x",
2449                                        pid, status);
2450                        break;
2451                }
2452                proc_list_drop(pid);
2453        }
2454# else
2455# ifdef WNOHANG
2456        union wait status;
2457
2458        while ((pid = wait3(&status, WNOHANG, (struct rusage *) NULL)) > 0)
2459                proc_list_drop(pid);
2460# else /* WNOHANG */
2461        auto int status;
2462
2463        /*
2464        **  Catch one zombie -- we will be re-invoked (we hope) if there
2465        **  are more.  Unreliable signals probably break this, but this
2466        **  is the "old system" situation -- waitpid or wait3 are to be
2467        **  strongly preferred.
2468        */
2469
2470        if ((pid = wait(&status)) > 0)
2471                proc_list_drop(pid);
2472# endif /* WNOHANG */
2473# endif
2474# ifdef SYS5SIGNALS
2475        (void) setsignal(SIGCHLD, reapchild);
2476# endif
2477        errno = olderrno;
2478        return SIGFUNC_RETURN;
2479}
2480/*
2481**  PUTENV -- emulation of putenv() in terms of setenv()
2482**
2483**      Not needed on Posix-compliant systems.
2484**      This doesn't have full Posix semantics, but it's good enough
2485**              for sendmail.
2486**
2487**      Parameter:
2488**              env -- the environment to put.
2489**
2490**      Returns:
2491**              none.
2492*/
2493
2494#ifdef NEEDPUTENV
2495
2496# if NEEDPUTENV == 2            /* no setenv(3) call available */
2497
2498int
2499putenv(str)
2500        char *str;
2501{
2502        char **current;
2503        int matchlen, envlen=0;
2504        char *tmp;
2505        char **newenv;
2506        static int first=1;
2507        extern char **environ;
2508
2509        /*
2510         * find out how much of str to match when searching
2511         * for a string to replace.
2512         */
2513        if ((tmp = strchr(str, '=')) == NULL || tmp == str)
2514                matchlen = strlen(str);
2515        else
2516                matchlen = (int) (tmp - str);
2517        ++matchlen;
2518
2519        /*
2520         * Search for an existing string in the environment and find the
2521         * length of environ.  If found, replace and exit.
2522         */
2523        for (current=environ; *current; current++) {
2524                ++envlen;
2525
2526                if (strncmp(str, *current, matchlen) == 0) {
2527                        /* found it, now insert the new version */
2528                        *current = (char *)str;
2529                        return(0);
2530                }
2531        }
2532
2533        /*
2534         * There wasn't already a slot so add space for a new slot.
2535         * If this is our first time through, use malloc(), else realloc().
2536         */
2537        if (first) {
2538                newenv = (char **) malloc(sizeof(char *) * (envlen + 2));
2539                if (newenv == NULL)
2540                        return(-1);
2541
2542                first=0;
2543                (void) memcpy(newenv, environ, sizeof(char *) * envlen);
2544        } else {
2545                newenv = (char **) realloc((char *)environ, sizeof(char *) * (envlen + 2));
2546                if (newenv == NULL)
2547                        return(-1);
2548        }
2549
2550        /* actually add in the new entry */
2551        environ = newenv;
2552        environ[envlen] = (char *)str;
2553        environ[envlen+1] = NULL;
2554
2555        return(0);
2556}
2557
2558#else                   /* implement putenv() in terms of setenv() */
2559
2560int
2561putenv(env)
2562        char *env;
2563{
2564        char *p;
2565        int l;
2566        char nbuf[100];
2567
2568        p = strchr(env, '=');
2569        if (p == NULL)
2570                return 0;
2571        l = p - env;
2572        if (l > sizeof nbuf - 1)
2573                l = sizeof nbuf - 1;
2574        bcopy(env, nbuf, l);
2575        nbuf[l] = '\0';
2576        return setenv(nbuf, ++p, 1);
2577}
2578
2579# endif
2580#endif
2581/*
2582**  UNSETENV -- remove a variable from the environment
2583**
2584**      Not needed on newer systems.
2585**
2586**      Parameters:
2587**              name -- the string name of the environment variable to be
2588**                      deleted from the current environment.
2589**
2590**      Returns:
2591**              none.
2592**
2593**      Globals:
2594**              environ -- a pointer to the current environment.
2595**
2596**      Side Effects:
2597**              Modifies environ.
2598*/
2599
2600#ifndef HASUNSETENV
2601
2602void
2603unsetenv(name)
2604        char *name;
2605{
2606        extern char **environ;
2607        register char **pp;
2608        int len = strlen(name);
2609
2610        for (pp = environ; *pp != NULL; pp++)
2611        {
2612                if (strncmp(name, *pp, len) == 0 &&
2613                    ((*pp)[len] == '=' || (*pp)[len] == '\0'))
2614                        break;
2615        }
2616
2617        for (; *pp != NULL; pp++)
2618                *pp = pp[1];
2619}
2620
2621#endif
2622/*
2623**  GETDTABLESIZE -- return number of file descriptors
2624**
2625**      Only on non-BSD systems
2626**
2627**      Parameters:
2628**              none
2629**
2630**      Returns:
2631**              size of file descriptor table
2632**
2633**      Side Effects:
2634**              none
2635*/
2636
2637#ifdef SOLARIS
2638# include <sys/resource.h>
2639#endif
2640
2641int
2642getdtsize()
2643{
2644#ifdef RLIMIT_NOFILE
2645        struct rlimit rl;
2646
2647        if (getrlimit(RLIMIT_NOFILE, &rl) >= 0)
2648                return rl.rlim_cur;
2649#endif
2650
2651# ifdef HASGETDTABLESIZE
2652        return getdtablesize();
2653# else
2654#  ifdef _SC_OPEN_MAX
2655        return sysconf(_SC_OPEN_MAX);
2656#  else
2657        return NOFILE;
2658#  endif
2659# endif
2660}
2661/*
2662**  UNAME -- get the UUCP name of this system.
2663*/
2664
2665#ifndef HASUNAME
2666
2667int
2668uname(name)
2669        struct utsname *name;
2670{
2671        FILE *file;
2672        char *n;
2673
2674        name->nodename[0] = '\0';
2675
2676        /* try /etc/whoami -- one line with the node name */
2677        if ((file = fopen("/etc/whoami", "r")) != NULL)
2678        {
2679                (void) fgets(name->nodename, NODE_LENGTH + 1, file);
2680                (void) fclose(file);
2681                n = strchr(name->nodename, '\n');
2682                if (n != NULL)
2683                        *n = '\0';
2684                if (name->nodename[0] != '\0')
2685                        return (0);
2686        }
2687
2688        /* try /usr/include/whoami.h -- has a #define somewhere */
2689        if ((file = fopen("/usr/include/whoami.h", "r")) != NULL)
2690        {
2691                char buf[MAXLINE];
2692
2693                while (fgets(buf, MAXLINE, file) != NULL)
2694                        if (sscanf(buf, "#define sysname \"%*[^\"]\"",
2695                                        NODE_LENGTH, name->nodename) > 0)
2696                                break;
2697                (void) fclose(file);
2698                if (name->nodename[0] != '\0')
2699                        return (0);
2700        }
2701
2702#ifdef TRUST_POPEN
2703        /*
2704        **  Popen is known to have security holes.
2705        */
2706
2707        /* try uuname -l to return local name */
2708        if ((file = popen("uuname -l", "r")) != NULL)
2709        {
2710                (void) fgets(name, NODE_LENGTH + 1, file);
2711                (void) pclose(file);
2712                n = strchr(name, '\n');
2713                if (n != NULL)
2714                        *n = '\0';
2715                if (name->nodename[0] != '\0')
2716                        return (0);
2717        }
2718#endif
2719
2720        return (-1);
2721}
2722#endif /* HASUNAME */
2723/*
2724**  INITGROUPS -- initialize groups
2725**
2726**      Stub implementation for System V style systems
2727*/
2728
2729#ifndef HASINITGROUPS
2730
2731initgroups(name, basegid)
2732        char *name;
2733        int basegid;
2734{
2735        return 0;
2736}
2737
2738#endif
2739/*
2740**  SETGROUPS -- set group list
2741**
2742**      Stub implementation for systems that don't have group lists
2743*/
2744
2745#ifndef NGROUPS_MAX
2746
2747int
2748setgroups(ngroups, grouplist)
2749        int ngroups;
2750        GIDSET_T grouplist[];
2751{
2752        return 0;
2753}
2754
2755#endif
2756/*
2757**  SETSID -- set session id (for non-POSIX systems)
2758*/
2759
2760#ifndef HASSETSID
2761
2762pid_t
2763setsid __P ((void))
2764{
2765#ifdef TIOCNOTTY
2766        int fd;
2767
2768        fd = open("/dev/tty", O_RDWR, 0);
2769        if (fd >= 0)
2770        {
2771                (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0);
2772                (void) close(fd);
2773        }
2774#endif /* TIOCNOTTY */
2775# ifdef SYS5SETPGRP
2776        return setpgrp();
2777# else
2778        return setpgid(0, getpid());
2779# endif
2780}
2781
2782#endif
2783/*
2784**  FSYNC -- dummy fsync
2785*/
2786
2787#ifdef NEEDFSYNC
2788
2789fsync(fd)
2790        int fd;
2791{
2792# ifdef O_SYNC
2793        return fcntl(fd, F_SETFL, O_SYNC);
2794# else
2795        /* nothing we can do */
2796        return 0;
2797# endif
2798}
2799
2800#endif
2801/*
2802**  DGUX_INET_ADDR -- inet_addr for DG/UX
2803**
2804**      Data General DG/UX version of inet_addr returns a struct in_addr
2805**      instead of a long.  This patches things.  Only needed on versions
2806**      prior to 5.4.3.
2807*/
2808
2809#ifdef DGUX_5_4_2
2810
2811#undef inet_addr
2812
2813long
2814dgux_inet_addr(host)
2815        char *host;
2816{
2817        struct in_addr haddr;
2818
2819        haddr = inet_addr(host);
2820        return haddr.s_addr;
2821}
2822
2823#endif
2824/*
2825**  GETOPT -- for old systems or systems with bogus implementations
2826*/
2827
2828#ifdef NEEDGETOPT
2829
2830/*
2831 * Copyright (c) 1985 Regents of the University of California.
2832 * All rights reserved.  The Berkeley software License Agreement
2833 * specifies the terms and conditions for redistribution.
2834 */
2835
2836
2837/*
2838**  this version hacked to add `atend' flag to allow state machine
2839**  to reset if invoked by the program to scan args for a 2nd time
2840*/
2841
2842#if defined(LIBC_SCCS) && !defined(lint)
2843static char sccsid[] = "@(#)getopt.c    4.3 (Berkeley) 3/9/86";
2844#endif /* LIBC_SCCS and not lint */
2845
2846#include <stdio.h>
2847
2848/*
2849 * get option letter from argument vector
2850 */
2851#ifdef _CONVEX_SOURCE
2852extern int      optind, opterr, optopt;
2853extern char     *optarg;
2854#else
2855int     opterr = 1;             /* if error message should be printed */
2856int     optind = 1;             /* index into parent argv vector */
2857int     optopt = 0;             /* character checked for validity */
2858char    *optarg = NULL;         /* argument associated with option */
2859#endif
2860
2861#define BADCH   (int)'?'
2862#define EMSG    ""
2863#define tell(s) if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \
2864                fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}
2865
2866int
2867getopt(nargc,nargv,ostr)
2868        int             nargc;
2869        char *const     *nargv;
2870        const char      *ostr;
2871{
2872        static char     *place = EMSG;  /* option letter processing */
2873        static char     atend = 0;
2874        register char   *oli = NULL;    /* option letter list index */
2875
2876        if (atend) {
2877                atend = 0;
2878                place = EMSG;
2879        }
2880        if(!*place) {                   /* update scanning pointer */
2881                if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) {
2882                        atend++;
2883                        return -1;
2884                }
2885                if (*place == '-') {    /* found "--" */
2886                        ++optind;
2887                        atend++;
2888                        return -1;
2889                }
2890        }                               /* option letter okay? */
2891        if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) {
2892                if (!*place) ++optind;
2893                tell(": illegal option -- ");
2894        }
2895        if (oli && *++oli != ':') {             /* don't need argument */
2896                optarg = NULL;
2897                if (!*place) ++optind;
2898        }
2899        else {                          /* need an argument */
2900                if (*place) optarg = place;     /* no white space */
2901                else if (nargc <= ++optind) {   /* no arg */
2902                        place = EMSG;
2903                        tell(": option requires an argument -- ");
2904                }
2905                else optarg = nargv[optind];    /* white space */
2906                place = EMSG;
2907                ++optind;
2908        }
2909        return(optopt);                 /* dump back option letter */
2910}
2911
2912#endif
2913/*
2914**  VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version
2915*/
2916
2917#ifdef NEEDVPRINTF
2918
2919#define MAXARG  16
2920
2921vfprintf(fp, fmt, ap)
2922        FILE *fp;
2923        char *fmt;
2924        char **ap;
2925{
2926        char *bp[MAXARG];
2927        int i = 0;
2928
2929        while (*ap && i < MAXARG)
2930                bp[i++] = *ap++;
2931        fprintf(fp, fmt, bp[0], bp[1], bp[2], bp[3],
2932                         bp[4], bp[5], bp[6], bp[7],
2933                         bp[8], bp[9], bp[10], bp[11],
2934                         bp[12], bp[13], bp[14], bp[15]);
2935}
2936
2937vsprintf(s, fmt, ap)
2938        char *s;
2939        char *fmt;
2940        char **ap;
2941{
2942        char *bp[MAXARG];
2943        int i = 0;
2944
2945        while (*ap && i < MAXARG)
2946                bp[i++] = *ap++;
2947        sprintf(s, fmt, bp[0], bp[1], bp[2], bp[3],
2948                        bp[4], bp[5], bp[6], bp[7],
2949                        bp[8], bp[9], bp[10], bp[11],
2950                        bp[12], bp[13], bp[14], bp[15]);
2951}
2952
2953#endif
2954/*
2955**  USERSHELLOK -- tell if a user's shell is ok for unrestricted use
2956**
2957**      Parameters:
2958**              user -- the name of the user we are checking.
2959**              shell -- the user's shell from /etc/passwd
2960**
2961**      Returns:
2962**              TRUE -- if it is ok to use this for unrestricted access.
2963**              FALSE -- if the shell is restricted.
2964*/
2965
2966#if !HASGETUSERSHELL
2967
2968# ifndef _PATH_SHELLS
2969#  define _PATH_SHELLS  "/etc/shells"
2970# endif
2971
2972# if defined(_AIX3) || defined(_AIX4)
2973#  include <userconf.h>
2974#  if _AIX4 >= 40200
2975#   include <userpw.h>
2976#  endif
2977#  include <usersec.h>
2978# endif
2979
2980char    *DefaultUserShells[] =
2981{
2982        "/bin/sh",              /* standard shell */
2983        "/usr/bin/sh",
2984        "/bin/csh",             /* C shell */
2985        "/usr/bin/csh",
2986#ifdef __hpux
2987# ifdef V4FS
2988        "/usr/bin/rsh",         /* restricted Bourne shell */
2989        "/usr/bin/ksh",         /* Korn shell */
2990        "/usr/bin/rksh",        /* restricted Korn shell */
2991        "/usr/bin/pam",
2992        "/usr/bin/keysh",       /* key shell (extended Korn shell) */
2993        "/usr/bin/posix/sh",
2994# else
2995        "/bin/rsh",             /* restricted Bourne shell */
2996        "/bin/ksh",             /* Korn shell */
2997        "/bin/rksh",            /* restricted Korn shell */
2998        "/bin/pam",
2999        "/usr/bin/keysh",       /* key shell (extended Korn shell) */
3000        "/bin/posix/sh",
3001# endif
3002#endif
3003#if defined(_AIX3) || defined(_AIX4)
3004        "/bin/ksh",             /* Korn shell */
3005        "/usr/bin/ksh",
3006        "/bin/tsh",             /* trusted shell */
3007        "/usr/bin/tsh",
3008        "/bin/bsh",             /* Bourne shell */
3009        "/usr/bin/bsh",
3010#endif
3011#if defined(__svr4__) || defined(__svr5__)
3012        "/bin/ksh",             /* Korn shell */
3013        "/usr/bin/ksh",
3014#endif
3015#ifdef sgi
3016        "/sbin/sh",             /* SGI's shells really live in /sbin */
3017        "/sbin/csh",
3018        "/bin/ksh",             /* Korn shell */
3019        "/sbin/ksh",
3020        "/usr/bin/ksh",
3021        "/bin/tcsh",            /* Extended csh */
3022        "/usr/bin/tcsh",
3023#endif
3024        NULL
3025};
3026
3027#endif
3028
3029#define WILDCARD_SHELL  "/SENDMAIL/ANY/SHELL/"
3030
3031bool
3032usershellok(user, shell)
3033        char *user;
3034        char *shell;
3035{
3036#if HASGETUSERSHELL
3037        register char *p;
3038        extern char *getusershell();
3039
3040        if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') ||
3041            ConfigLevel <= 1)
3042                return TRUE;
3043
3044        setusershell();
3045        while ((p = getusershell()) != NULL)
3046                if (strcmp(p, shell) == 0 || strcmp(p, WILDCARD_SHELL) == 0)
3047                        break;
3048        endusershell();
3049        return p != NULL;
3050#else
3051# if USEGETCONFATTR
3052        auto char *v;
3053# endif
3054        register FILE *shellf;
3055        char buf[MAXLINE];
3056
3057        if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') ||
3058            ConfigLevel <= 1)
3059                return TRUE;
3060
3061# if USEGETCONFATTR
3062        /*
3063        **  Naturally IBM has a "better" idea.....
3064        **
3065        **      What a crock.  This interface isn't documented, it is
3066        **      considered part of the security library (-ls), and it
3067        **      only works if you are running as root (since the list
3068        **      of valid shells is obviously a source of great concern).
3069        **      I recommend that you do NOT define USEGETCONFATTR,
3070        **      especially since you are going to have to set up an
3071        **      /etc/shells anyhow to handle the cases where getconfattr
3072        **      fails.
3073        */
3074
3075        if (getconfattr(SC_SYS_LOGIN, SC_SHELLS, &v, SEC_LIST) == 0 && v != NULL)
3076        {
3077                while (*v != '\0')
3078                {
3079                        if (strcmp(v, shell) == 0 || strcmp(v, WILDCARD_SHELL) == 0)
3080                                return TRUE;
3081                        v += strlen(v) + 1;
3082                }
3083                return FALSE;
3084        }
3085# endif
3086
3087        shellf = fopen(_PATH_SHELLS, "r");
3088        if (shellf == NULL)
3089        {
3090                /* no /etc/shells; see if it is one of the std shells */
3091                char **d;
3092               
3093                if (errno != ENOENT && LogLevel > 3)
3094                        sm_syslog(LOG_ERR, NOQID,
3095                                  "usershellok: cannot open %s: %s",
3096                                  _PATH_SHELLS, errstring(errno));
3097
3098                for (d = DefaultUserShells; *d != NULL; d++)
3099                {
3100                        if (strcmp(shell, *d) == 0)
3101                                return TRUE;
3102                }
3103                return FALSE;
3104        }
3105
3106        while (fgets(buf, sizeof buf, shellf) != NULL)
3107        {
3108                register char *p, *q;
3109
3110                p = buf;
3111                while (*p != '\0' && *p != '#' && *p != '/')
3112                        p++;
3113                if (*p == '#' || *p == '\0')
3114                        continue;
3115                q = p;
3116                while (*p != '\0' && *p != '#' && !(isascii(*p) && isspace(*p)))
3117                        p++;
3118                *p = '\0';
3119                if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0)
3120                {
3121                        fclose(shellf);
3122                        return TRUE;
3123                }
3124        }
3125        fclose(shellf);
3126        return FALSE;
3127#endif
3128}
3129/*
3130**  FREEDISKSPACE -- see how much free space is on the queue filesystem
3131**
3132**      Only implemented if you have statfs.
3133**
3134**      Parameters:
3135**              dir -- the directory in question.
3136**              bsize -- a variable into which the filesystem
3137**                      block size is stored.
3138**
3139**      Returns:
3140**              The number of bytes free on the queue filesystem.
3141**              -1 if the statfs call fails.
3142**
3143**      Side effects:
3144**              Puts the filesystem block size into bsize.
3145*/
3146
3147/* statfs types */
3148#define SFS_NONE        0       /* no statfs implementation */
3149#define SFS_USTAT       1       /* use ustat */
3150#define SFS_4ARGS       2       /* use four-argument statfs call */
3151#define SFS_VFS         3       /* use <sys/vfs.h> implementation */
3152#define SFS_MOUNT       4       /* use <sys/mount.h> implementation */
3153#define SFS_STATFS      5       /* use <sys/statfs.h> implementation */
3154#define SFS_STATVFS     6       /* use <sys/statvfs.h> implementation */
3155
3156#ifndef SFS_TYPE
3157# define SFS_TYPE       SFS_NONE
3158#endif
3159
3160#if SFS_TYPE == SFS_USTAT
3161# include <ustat.h>
3162#endif
3163#if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS
3164# include <sys/statfs.h>
3165#endif
3166#if SFS_TYPE == SFS_VFS
3167# include <sys/vfs.h>
3168#endif
3169#if SFS_TYPE == SFS_MOUNT
3170# include <sys/mount.h>
3171#endif
3172#if SFS_TYPE == SFS_STATVFS
3173# include <sys/statvfs.h>
3174#endif
3175
3176long
3177freediskspace(dir, bsize)
3178        char *dir;
3179        long *bsize;
3180{
3181#if SFS_TYPE != SFS_NONE
3182# if SFS_TYPE == SFS_USTAT
3183        struct ustat fs;
3184        struct stat statbuf;
3185#  define FSBLOCKSIZE   DEV_BSIZE
3186#  define SFS_BAVAIL    f_tfree
3187# else
3188#  if defined(ultrix)
3189        struct fs_data fs;
3190#   define SFS_BAVAIL   fd_bfreen
3191#   define FSBLOCKSIZE  1024L
3192#  else
3193#   if SFS_TYPE == SFS_STATVFS
3194        struct statvfs fs;
3195#    define FSBLOCKSIZE fs.f_frsize
3196#   else
3197        struct statfs fs;
3198#    define FSBLOCKSIZE fs.f_bsize
3199#   endif
3200#  endif
3201# endif
3202# ifndef SFS_BAVAIL
3203#  define SFS_BAVAIL f_bavail
3204# endif
3205
3206# if SFS_TYPE == SFS_USTAT
3207        if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0)
3208# else
3209#  if SFS_TYPE == SFS_4ARGS
3210        if (statfs(dir, &fs, sizeof fs, 0) == 0)
3211#  else
3212#   if SFS_TYPE == SFS_STATVFS
3213        if (statvfs(dir, &fs) == 0)
3214#   else
3215#    if defined(ultrix)
3216        if (statfs(dir, &fs) > 0)
3217#    else
3218        if (statfs(dir, &fs) == 0)
3219#    endif
3220#   endif
3221#  endif
3222# endif
3223        {
3224                if (bsize != NULL)
3225                        *bsize = FSBLOCKSIZE;
3226                if (fs.SFS_BAVAIL <= 0)
3227                        return 0;
3228                else if (fs.SFS_BAVAIL > LONG_MAX)
3229                        return LONG_MAX;
3230                else
3231                        return (long) fs.SFS_BAVAIL;
3232        }
3233#endif
3234        return (-1);
3235}
3236/*
3237**  ENOUGHDISKSPACE -- is there enough free space on the queue fs?
3238**
3239**      Only implemented if you have statfs.
3240**
3241**      Parameters:
3242**              msize -- the size to check against.  If zero, we don't yet
3243**              know how big the message will be, so just check for
3244**              a "reasonable" amount.
3245**
3246**      Returns:
3247**              TRUE if there is enough space.
3248**              FALSE otherwise.
3249*/
3250
3251bool
3252enoughdiskspace(msize)
3253        long msize;
3254{
3255        long bfree, bsize;
3256
3257        if (MinBlocksFree <= 0 && msize <= 0)
3258        {
3259                if (tTd(4, 80))
3260                        printf("enoughdiskspace: no threshold\n");
3261                return TRUE;
3262        }
3263
3264        if ((bfree = freediskspace(QueueDir, &bsize)) >= 0)
3265        {
3266                if (tTd(4, 80))
3267                        printf("enoughdiskspace: bavail=%ld, need=%ld\n",
3268                                bfree, msize);
3269
3270                /* convert msize to block count */
3271                msize = msize / bsize + 1;
3272                if (MinBlocksFree >= 0)
3273                        msize += MinBlocksFree;
3274
3275                if (bfree < msize)
3276                {
3277                        if (LogLevel > 0)
3278                                sm_syslog(LOG_ALERT, CurEnv->e_id,
3279                                        "low on space (have %ld, %s needs %ld in %s)",
3280                                        bfree,
3281                                        CurHostName == NULL ? "SMTP-DAEMON" : CurHostName,
3282                                        msize, QueueDir);
3283                        return FALSE;
3284                }
3285        }
3286        else if (tTd(4, 80))
3287                printf("enoughdiskspace failure: min=%ld, need=%ld: %s\n",
3288                        MinBlocksFree, msize, errstring(errno));
3289        return TRUE;
3290}
3291/*
3292**  TRANSIENTERROR -- tell if an error code indicates a transient failure
3293**
3294**      This looks at an errno value and tells if this is likely to
3295**      go away if retried later.
3296**
3297**      Parameters:
3298**              err -- the errno code to classify.
3299**
3300**      Returns:
3301**              TRUE if this is probably transient.
3302**              FALSE otherwise.
3303*/
3304
3305bool
3306transienterror(err)
3307        int err;
3308{
3309        switch (err)
3310        {
3311          case EIO:                     /* I/O error */
3312          case ENXIO:                   /* Device not configured */
3313          case EAGAIN:                  /* Resource temporarily unavailable */
3314          case ENOMEM:                  /* Cannot allocate memory */
3315          case ENODEV:                  /* Operation not supported by device */
3316          case ENFILE:                  /* Too many open files in system */
3317          case EMFILE:                  /* Too many open files */
3318          case ENOSPC:                  /* No space left on device */
3319#ifdef ETIMEDOUT
3320          case ETIMEDOUT:               /* Connection timed out */
3321#endif
3322#ifdef ESTALE
3323          case ESTALE:                  /* Stale NFS file handle */
3324#endif
3325#ifdef ENETDOWN
3326          case ENETDOWN:                /* Network is down */
3327#endif
3328#ifdef ENETUNREACH
3329          case ENETUNREACH:             /* Network is unreachable */
3330#endif
3331#ifdef ENETRESET
3332          case ENETRESET:               /* Network dropped connection on reset */
3333#endif
3334#ifdef ECONNABORTED
3335          case ECONNABORTED:            /* Software caused connection abort */
3336#endif
3337#ifdef ECONNRESET
3338          case ECONNRESET:              /* Connection reset by peer */
3339#endif
3340#ifdef ENOBUFS
3341          case ENOBUFS:                 /* No buffer space available */
3342#endif
3343#ifdef ESHUTDOWN
3344          case ESHUTDOWN:               /* Can't send after socket shutdown */
3345#endif
3346#ifdef ECONNREFUSED
3347          case ECONNREFUSED:            /* Connection refused */
3348#endif
3349#ifdef EHOSTDOWN
3350          case EHOSTDOWN:               /* Host is down */
3351#endif
3352#ifdef EHOSTUNREACH
3353          case EHOSTUNREACH:            /* No route to host */
3354#endif
3355#ifdef EDQUOT
3356          case EDQUOT:                  /* Disc quota exceeded */
3357#endif
3358#ifdef EPROCLIM
3359          case EPROCLIM:                /* Too many processes */
3360#endif
3361#ifdef EUSERS
3362          case EUSERS:                  /* Too many users */
3363#endif
3364#ifdef EDEADLK
3365          case EDEADLK:                 /* Resource deadlock avoided */
3366#endif
3367#ifdef EISCONN
3368          case EISCONN:                 /* Socket already connected */
3369#endif
3370#ifdef EINPROGRESS
3371          case EINPROGRESS:             /* Operation now in progress */
3372#endif
3373#ifdef EALREADY
3374          case EALREADY:                /* Operation already in progress */
3375#endif
3376#ifdef EADDRINUSE
3377          case EADDRINUSE:              /* Address already in use */
3378#endif
3379#ifdef EADDRNOTAVAIL
3380          case EADDRNOTAVAIL:           /* Can't assign requested address */
3381#endif
3382#ifdef ETXTBSY
3383          case ETXTBSY:                 /* (Apollo) file locked */
3384#endif
3385#if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR))
3386          case ENOSR:                   /* Out of streams resources */
3387#endif
3388          case E_SM_OPENTIMEOUT:        /* PSEUDO: open timed out */
3389                return TRUE;
3390        }
3391
3392        /* nope, must be permanent */
3393        return FALSE;
3394}
3395/*
3396**  LOCKFILE -- lock a file using flock or (shudder) fcntl locking
3397**
3398**      Parameters:
3399**              fd -- the file descriptor of the file.
3400**              filename -- the file name (for error messages).
3401**              ext -- the filename extension.
3402**              type -- type of the lock.  Bits can be:
3403**                      LOCK_EX -- exclusive lock.
3404**                      LOCK_NB -- non-blocking.
3405**
3406**      Returns:
3407**              TRUE if the lock was acquired.
3408**              FALSE otherwise.
3409*/
3410
3411bool
3412lockfile(fd, filename, ext, type)
3413        int fd;
3414        char *filename;
3415        char *ext;
3416        int type;
3417{
3418        int i;
3419        int save_errno;
3420# if !HASFLOCK
3421        int action;
3422        struct flock lfd;
3423
3424        if (ext == NULL)
3425                ext = "";
3426
3427        bzero(&lfd, sizeof lfd);
3428        if (bitset(LOCK_UN, type))
3429                lfd.l_type = F_UNLCK;
3430        else if (bitset(LOCK_EX, type))
3431                lfd.l_type = F_WRLCK;
3432        else
3433                lfd.l_type = F_RDLCK;
3434
3435        if (bitset(LOCK_NB, type))
3436                action = F_SETLK;
3437        else
3438                action = F_SETLKW;
3439
3440        if (tTd(55, 60))
3441                printf("lockfile(%s%s, action=%d, type=%d): ",
3442                        filename, ext, action, lfd.l_type);
3443
3444        while ((i = fcntl(fd, action, &lfd)) < 0 && errno == EINTR)
3445                continue;
3446        if (i >= 0)
3447        {
3448                if (tTd(55, 60))
3449                        printf("SUCCESS\n");
3450                return TRUE;
3451        }
3452        save_errno = errno;
3453
3454        if (tTd(55, 60))
3455                printf("(%s) ", errstring(save_errno));
3456
3457        /*
3458        **  On SunOS, if you are testing using -oQ/tmp/mqueue or
3459        **  -oA/tmp/aliases or anything like that, and /tmp is mounted
3460        **  as type "tmp" (that is, served from swap space), the
3461        **  previous fcntl will fail with "Invalid argument" errors.
3462        **  Since this is fairly common during testing, we will assume
3463        **  that this indicates that the lock is successfully grabbed.
3464        */
3465
3466        if (save_errno == EINVAL)
3467        {
3468                if (tTd(55, 60))
3469                        printf("SUCCESS\n");
3470                return TRUE;
3471        }
3472
3473        if (!bitset(LOCK_NB, type) || (save_errno != EACCES && save_errno != EAGAIN))
3474        {
3475                int omode = -1;
3476#  ifdef F_GETFL
3477                (void) fcntl(fd, F_GETFL, &omode);
3478                errno = save_errno;
3479#  endif
3480                syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
3481                        filename, ext, fd, type, omode, geteuid());
3482                dumpfd(fd, TRUE, TRUE);
3483        }
3484# else
3485        if (ext == NULL)
3486                ext = "";
3487
3488        if (tTd(55, 60))
3489                printf("lockfile(%s%s, type=%o): ", filename, ext, type);
3490
3491        while ((i = flock(fd, type)) < 0 && errno == EINTR)
3492                continue;
3493        if (i >= 0)
3494        {
3495                if (tTd(55, 60))
3496                        printf("SUCCESS\n");
3497                return TRUE;
3498        }
3499        save_errno = errno;
3500
3501        if (tTd(55, 60))
3502                printf("(%s) ", errstring(save_errno));
3503
3504        if (!bitset(LOCK_NB, type) || save_errno != EWOULDBLOCK)
3505        {
3506                int omode = -1;
3507#  ifdef F_GETFL
3508                (void) fcntl(fd, F_GETFL, &omode);
3509                errno = save_errno;
3510#  endif
3511                syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
3512                        filename, ext, fd, type, omode, geteuid());
3513                dumpfd(fd, TRUE, TRUE);
3514        }
3515# endif
3516        if (tTd(55, 60))
3517                printf("FAIL\n");
3518        errno = save_errno;
3519        return FALSE;
3520}
3521/*
3522**  CHOWNSAFE -- tell if chown is "safe" (executable only by root)
3523**
3524**      Unfortunately, given that we can't predict other systems on which
3525**      a remote mounted (NFS) filesystem will be mounted, the answer is
3526**      almost always that this is unsafe.
3527**
3528**      Note also that many operating systems have non-compliant
3529**      implementations of the _POSIX_CHOWN_RESTRICTED variable and the
3530**      fpathconf() routine.  According to IEEE 1003.1-1990, if
3531**      _POSIX_CHOWN_RESTRICTED is defined and not equal to -1, then
3532**      no non-root process can give away the file.  However, vendors
3533**      don't take NFS into account, so a comfortable value of
3534**      _POSIX_CHOWN_RESTRICTED tells us nothing.
3535**
3536**      Also, some systems (e.g., IRIX 6.2) return 1 from fpathconf()
3537**      even on files where chown is not restricted.  Many systems get
3538**      this wrong on NFS-based filesystems (that is, they say that chown
3539**      is restricted [safe] on NFS filesystems where it may not be, since
3540**      other systems can access the same filesystem and do file giveaway;
3541**      only the NFS server knows for sure!)  Hence, it is important to
3542**      get the value of SAFENFSPATHCONF correct -- it should be defined
3543**      _only_ after testing (see test/t_pathconf.c) a system on an unsafe
3544**      NFS-based filesystem to ensure that you can get meaningful results.
3545**      If in doubt, assume unsafe!
3546**
3547**      You may also need to tweak IS_SAFE_CHOWN -- it should be a
3548**      condition indicating whether the return from pathconf indicates
3549**      that chown is safe (typically either > 0 or >= 0 -- there isn't
3550**      even any agreement about whether a zero return means that a file
3551**      is or is not safe).  It defaults to "> 0".
3552**
3553**      If the parent directory is safe (writable only by owner back
3554**      to the root) then we can relax slightly and trust fpathconf
3555**      in more circumstances.  This is really a crock -- if this is an
3556**      NFS mounted filesystem then we really know nothing about the
3557**      underlying implementation.  However, most systems pessimize and
3558**      return an error (EINVAL or EOPNOTSUPP) on NFS filesystems, which
3559**      we interpret as unsafe, as we should.  Thus, this heuristic gets
3560**      us into a possible problem only on systems that have a broken
3561**      pathconf implementation and which are also poorly configured
3562**      (have :include: files in group- or world-writable directories).
3563**
3564**      Parameters:
3565**              fd -- the file descriptor to check.
3566**              safedir -- set if the parent directory is safe.
3567**
3568**      Returns:
3569**              TRUE -- if the chown(2) operation is "safe" -- that is,
3570**                      only root can chown the file to an arbitrary user.
3571**              FALSE -- if an arbitrary user can give away a file.
3572*/
3573
3574#ifndef IS_SAFE_CHOWN
3575# define IS_SAFE_CHOWN  > 0
3576#endif
3577
3578bool
3579chownsafe(fd, safedir)
3580        int fd;
3581        bool safedir;
3582{
3583#if (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \
3584    (defined(_PC_CHOWN_RESTRICTED) || defined(_GNU_TYPES_H))
3585        int rval;
3586
3587        /* give the system administrator a chance to override */
3588        if (bitset(DBS_ASSUMESAFECHOWN, DontBlameSendmail))
3589                return TRUE;
3590
3591        /*
3592        **  Some systems (e.g., SunOS) seem to have the call and the
3593        **  #define _PC_CHOWN_RESTRICTED, but don't actually implement
3594        **  the call.  This heuristic checks for that.
3595        */
3596
3597        errno = 0;
3598        rval = fpathconf(fd, _PC_CHOWN_RESTRICTED);
3599# if SAFENFSPATHCONF
3600        return errno == 0 && rval IS_SAFE_CHOWN;
3601# else
3602        return safedir && errno == 0 && rval IS_SAFE_CHOWN;
3603# endif
3604#else
3605        return bitset(DBS_ASSUMESAFECHOWN, DontBlameSendmail);
3606#endif
3607}
3608/*
3609**  RESETLIMITS -- reset system controlled resource limits
3610**
3611**      This is to avoid denial-of-service attacks
3612**
3613**      Parameters:
3614**              none
3615**
3616**      Returns:
3617**              none
3618*/
3619
3620#if HASSETRLIMIT
3621# ifdef RLIMIT_NEEDS_SYS_TIME_H
3622#  include <sys/time.h>
3623# endif
3624# include <sys/resource.h>
3625#endif
3626#ifndef FD_SETSIZE
3627# define FD_SETSIZE     256
3628#endif
3629
3630void
3631resetlimits()
3632{
3633#if HASSETRLIMIT
3634        struct rlimit lim;
3635
3636        lim.rlim_cur = lim.rlim_max = RLIM_INFINITY;
3637        (void) setrlimit(RLIMIT_CPU, &lim);
3638        (void) setrlimit(RLIMIT_FSIZE, &lim);
3639# ifdef RLIMIT_NOFILE
3640        lim.rlim_cur = lim.rlim_max = FD_SETSIZE;
3641        (void) setrlimit(RLIMIT_NOFILE, &lim);
3642# endif
3643#else
3644# if HASULIMIT
3645        (void) ulimit(2, 0x3fffff);
3646        (void) ulimit(4, FD_SETSIZE);
3647# endif
3648#endif
3649        errno = 0;
3650}
3651/*
3652**  GETCFNAME -- return the name of the .cf file.
3653**
3654**      Some systems (e.g., NeXT) determine this dynamically.
3655*/
3656
3657char *
3658getcfname()
3659{
3660
3661        if (ConfFile != NULL)
3662                return ConfFile;
3663#if NETINFO
3664        {
3665                extern char *ni_propval __P((char *, char *, char *, char *, int));
3666                char *cflocation;
3667
3668                cflocation = ni_propval("/locations", NULL, "sendmail",
3669                                        "sendmail.cf", '\0');
3670                if (cflocation != NULL)
3671                        return cflocation;
3672        }
3673#endif
3674
3675        return _PATH_SENDMAILCF;
3676}
3677/*
3678**  SETVENDOR -- process vendor code from V configuration line
3679**
3680**      Parameters:
3681**              vendor -- string representation of vendor.
3682**
3683**      Returns:
3684**              TRUE -- if ok.
3685**              FALSE -- if vendor code could not be processed.
3686**
3687**      Side Effects:
3688**              It is reasonable to set mode flags here to tweak
3689**              processing in other parts of the code if necessary.
3690**              For example, if you are a vendor that uses $%y to
3691**              indicate YP lookups, you could enable that here.
3692*/
3693
3694bool
3695setvendor(vendor)
3696        char *vendor;
3697{
3698        if (strcasecmp(vendor, "Berkeley") == 0)
3699        {
3700                VendorCode = VENDOR_BERKELEY;
3701                return TRUE;
3702        }
3703
3704        /* add vendor extensions here */
3705
3706#ifdef SUN_EXTENSIONS
3707        if (strcasecmp(vendor, "Sun") == 0)
3708        {
3709                VendorCode = VENDOR_SUN;
3710                return TRUE;
3711        }
3712#endif
3713
3714#if defined(VENDOR_NAME) && defined(VENDOR_CODE)
3715        if (strcasecmp(vendor, VENDOR_NAME) == 0)
3716        {
3717                VendorCode = VENDOR_CODE;
3718                return TRUE;
3719        }
3720#endif
3721
3722        return FALSE;
3723}
3724/*
3725**  GETVENDOR -- return vendor name based on vendor code
3726**
3727**      Parameters:
3728**              vendorcode -- numeric representation of vendor.
3729**
3730**      Returns:
3731**              string containing vendor name.
3732*/
3733
3734char *
3735getvendor(vendorcode)
3736        int vendorcode;
3737{
3738#if defined(VENDOR_NAME) && defined(VENDOR_CODE)
3739        /*
3740        **  Can't have the same switch case twice so need to
3741        **  handle VENDOR_CODE outside of switch.  It might
3742        **  match one of the existing VENDOR_* codes.
3743        */
3744
3745        if (vendorcode == VENDOR_CODE)
3746                return VENDOR_NAME;
3747#endif
3748
3749        switch (vendorcode)
3750        {
3751                case VENDOR_BERKELEY:
3752                        return "Berkeley";
3753               
3754                case VENDOR_SUN:
3755                        return "Sun";
3756
3757                case VENDOR_HP:
3758                        return "HP";
3759
3760                case VENDOR_IBM:
3761                        return "IBM";
3762
3763                case VENDOR_SENDMAIL:
3764                        return "Sendmail";
3765
3766                default:
3767                        return "Unknown";
3768        }
3769}
3770/*
3771**  VENDOR_PRE_DEFAULTS, VENDOR_POST_DEFAULTS -- set vendor-specific defaults
3772**
3773**      Vendor_pre_defaults is called before reading the configuration
3774**      file; vendor_post_defaults is called immediately after.
3775**
3776**      Parameters:
3777**              e -- the global environment to initialize.
3778**
3779**      Returns:
3780**              none.
3781*/
3782
3783#if SHARE_V1
3784int     DefShareUid;    /* default share uid to run as -- unused??? */
3785#endif
3786
3787void
3788vendor_pre_defaults(e)
3789        ENVELOPE *e;
3790{
3791#if SHARE_V1
3792        /* OTHERUID is defined in shares.h, do not be alarmed */
3793        DefShareUid = OTHERUID;
3794#endif
3795#if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES)
3796        sun_pre_defaults(e);
3797#endif
3798#ifdef apollo
3799        /* stupid domain/os can't even open /etc/sendmail.cf without this */
3800        setuserenv("ISP", NULL);
3801        setuserenv("SYSTYPE", NULL);
3802#endif
3803}
3804
3805
3806void
3807vendor_post_defaults(e)
3808        ENVELOPE *e;
3809{
3810#ifdef __QNX__
3811        char *p;
3812       
3813        /* Makes sure the SOCK environment variable remains */
3814        if (p = getextenv("SOCK"))
3815                setuserenv("SOCK", p);
3816#endif
3817#if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES)
3818        sun_post_defaults(e);
3819#endif
3820}
3821/*
3822**  VENDOR_DAEMON_SETUP -- special vendor setup needed for daemon mode
3823*/
3824
3825void
3826vendor_daemon_setup(e)
3827        ENVELOPE *e;
3828{
3829#if SECUREWARE
3830        if (getluid() != -1)
3831        {
3832                usrerr("Daemon cannot have LUID");
3833                finis(FALSE, EX_USAGE);
3834        }
3835#endif /* SECUREWARE */
3836}
3837/*
3838**  VENDOR_SET_UID -- do setup for setting a user id
3839**
3840**      This is called when we are still root.
3841**
3842**      Parameters:
3843**              uid -- the uid we are about to become.
3844**
3845**      Returns:
3846**              none.
3847*/
3848
3849void
3850vendor_set_uid(uid)
3851        UID_T uid;
3852{
3853        /*
3854        **  We need to setup the share groups (lnodes)
3855        **  and and auditing inforation (luid's)
3856        **  before we loose our ``root''ness.
3857        */
3858#if SHARE_V1
3859        if (setupshares(uid, syserr) != 0)
3860                syserr("Unable to set up shares");
3861#endif
3862#if SECUREWARE
3863        (void) setup_secure(uid);
3864#endif
3865}
3866/*
3867**  VALIDATE_CONNECTION -- check connection for rationality
3868**
3869**      If the connection is rejected, this routine should log an
3870**      appropriate message -- but should never issue any SMTP protocol.
3871**
3872**      Parameters:
3873**              sap -- a pointer to a SOCKADDR naming the peer.
3874**              hostname -- the name corresponding to sap.
3875**              e -- the current envelope.
3876**
3877**      Returns:
3878**              error message from rejection.
3879**              NULL if not rejected.
3880*/
3881
3882#if TCPWRAPPERS
3883# include <tcpd.h>
3884
3885/* tcpwrappers does no logging, but you still have to declare these -- ugh */
3886int     allow_severity  = LOG_INFO;
3887int     deny_severity   = LOG_NOTICE;
3888#endif
3889
3890#if DAEMON
3891char *
3892validate_connection(sap, hostname, e)
3893        SOCKADDR *sap;
3894        char *hostname;
3895        ENVELOPE *e;
3896{
3897#if TCPWRAPPERS
3898        char *host;
3899#endif
3900
3901        if (tTd(48, 3))
3902                printf("validate_connection(%s, %s)\n",
3903                        hostname, anynet_ntoa(sap));
3904
3905        if (rscheck("check_relay", hostname, anynet_ntoa(sap), e) != EX_OK)
3906        {
3907                static char reject[BUFSIZ*2];
3908                extern char MsgBuf[];
3909
3910                if (tTd(48, 4))
3911                        printf("  ... validate_connection: BAD (rscheck)\n");
3912
3913                if (strlen(MsgBuf) > 5)
3914                {
3915                        if (isascii(MsgBuf[0]) && isdigit(MsgBuf[0]) &&
3916                            isascii(MsgBuf[1]) && isdigit(MsgBuf[1]) &&
3917                            isascii(MsgBuf[2]) && isdigit(MsgBuf[2]))
3918                                strcpy(reject, &MsgBuf[4]);
3919                        else
3920                                strcpy(reject, MsgBuf);
3921                }
3922                else
3923                        strcpy(reject, "Access denied");
3924
3925                return reject;
3926        }
3927
3928#if TCPWRAPPERS
3929        if (hostname[0] == '[' && hostname[strlen(hostname) - 1] == ']')
3930                host = "unknown";
3931        else
3932                host = hostname;
3933        if (!hosts_ctl("sendmail", host, anynet_ntoa(sap), STRING_UNKNOWN))
3934        {
3935                if (tTd(48, 4))
3936                        printf("  ... validate_connection: BAD (tcpwrappers)\n");
3937                if (LogLevel >= 4)
3938                        sm_syslog(LOG_NOTICE, NOQID,
3939                                "tcpwrappers (%s, %s) rejection",
3940                                host, anynet_ntoa(sap));
3941                return "Access denied";
3942        }
3943#endif
3944        if (tTd(48, 4))
3945                printf("  ... validate_connection: OK\n");
3946        return NULL;
3947}
3948
3949#endif
3950/*
3951**  STRTOL -- convert string to long integer
3952**
3953**      For systems that don't have it in the C library.
3954**
3955**      This is taken verbatim from the 4.4-Lite C library.
3956*/
3957
3958#ifdef NEEDSTRTOL
3959
3960#if defined(LIBC_SCCS) && !defined(lint)
3961static char sccsid[] = "@(#)strtol.c    8.1 (Berkeley) 6/4/93";
3962#endif /* LIBC_SCCS and not lint */
3963
3964/*
3965 * Convert a string to a long integer.
3966 *
3967 * Ignores `locale' stuff.  Assumes that the upper and lower case
3968 * alphabets and digits are each contiguous.
3969 */
3970
3971long
3972strtol(nptr, endptr, base)
3973        const char *nptr;
3974        char **endptr;
3975        register int base;
3976{
3977        register const char *s = nptr;
3978        register unsigned long acc;
3979        register int c;
3980        register unsigned long cutoff;
3981        register int neg = 0, any, cutlim;
3982
3983        /*
3984         * Skip white space and pick up leading +/- sign if any.
3985         * If base is 0, allow 0x for hex and 0 for octal, else
3986         * assume decimal; if base is already 16, allow 0x.
3987         */
3988        do {
3989                c = *s++;
3990        } while (isspace(c));
3991        if (c == '-') {
3992                neg = 1;
3993                c = *s++;
3994        } else if (c == '+')
3995                c = *s++;
3996        if ((base == 0 || base == 16) &&
3997            c == '0' && (*s == 'x' || *s == 'X')) {
3998                c = s[1];
3999                s += 2;
4000                base = 16;
4001        }
4002        if (base == 0)
4003                base = c == '0' ? 8 : 10;
4004
4005        /*
4006         * Compute the cutoff value between legal numbers and illegal
4007         * numbers.  That is the largest legal value, divided by the
4008         * base.  An input number that is greater than this value, if
4009         * followed by a legal input character, is too big.  One that
4010         * is equal to this value may be valid or not; the limit
4011         * between valid and invalid numbers is then based on the last
4012         * digit.  For instance, if the range for longs is
4013         * [-2147483648..2147483647] and the input base is 10,
4014         * cutoff will be set to 214748364 and cutlim to either
4015         * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
4016         * a value > 214748364, or equal but the next digit is > 7 (or 8),
4017         * the number is too big, and we will return a range error.
4018         *
4019         * Set any if any `digits' consumed; make it negative to indicate
4020         * overflow.
4021         */
4022        cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
4023        cutlim = cutoff % (unsigned long)base;
4024        cutoff /= (unsigned long)base;
4025        for (acc = 0, any = 0;; c = *s++) {
4026                if (isdigit(c))
4027                        c -= '0';
4028                else if (isalpha(c))
4029                        c -= isupper(c) ? 'A' - 10 : 'a' - 10;
4030                else
4031                        break;
4032                if (c >= base)
4033                        break;
4034                if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
4035                        any = -1;
4036                else {
4037                        any = 1;
4038                        acc *= base;
4039                        acc += c;
4040                }
4041        }
4042        if (any < 0) {
4043                acc = neg ? LONG_MIN : LONG_MAX;
4044                errno = ERANGE;
4045        } else if (neg)
4046                acc = -acc;
4047        if (endptr != 0)
4048                *endptr = (char *)(any ? s - 1 : nptr);
4049        return (acc);
4050}
4051
4052#endif
4053/*
4054**  STRSTR -- find first substring in string
4055**
4056**      Parameters:
4057**              big -- the big (full) string.
4058**              little -- the little (sub) string.
4059**
4060**      Returns:
4061**              A pointer to the first instance of little in big.
4062**              big if little is the null string.
4063**              NULL if little is not contained in big.
4064*/
4065
4066#ifdef NEEDSTRSTR
4067
4068char *
4069strstr(big, little)
4070        char *big;
4071        char *little;
4072{
4073        register char *p = big;
4074        int l;
4075
4076        if (*little == '\0')
4077                return big;
4078        l = strlen(little);
4079
4080        while ((p = strchr(p, *little)) != NULL)
4081        {
4082                if (strncmp(p, little, l) == 0)
4083                        return p;
4084                p++;
4085        }
4086        return NULL;
4087}
4088
4089#endif
4090/*
4091**  SM_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX
4092**
4093**      Some operating systems have wierd problems with the gethostbyXXX
4094**      routines.  For example, Solaris versions at least through 2.3
4095**      don't properly deliver a canonical h_name field.  This tries to
4096**      work around these problems.
4097*/
4098
4099struct hostent *
4100sm_gethostbyname(name)
4101        char *name;
4102{
4103        struct hostent *h;
4104#if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4))
4105# if SOLARIS == 20300 || SOLARIS == 203
4106        static struct hostent hp;
4107        static char buf[1000];
4108        extern struct hostent *_switch_gethostbyname_r();
4109
4110        if (tTd(61, 10))
4111                printf("_switch_gethostbyname_r(%s)... ", name);
4112        h = _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno);
4113# else
4114        extern struct hostent *__switch_gethostbyname();
4115
4116        if (tTd(61, 10))
4117                printf("__switch_gethostbyname(%s)... ", name);
4118        h = __switch_gethostbyname(name);
4119# endif
4120#else
4121        int nmaps;
4122        char *maptype[MAXMAPSTACK];
4123        short mapreturn[MAXMAPACTIONS];
4124        char hbuf[MAXNAME];
4125
4126        if (tTd(61, 10))
4127                printf("gethostbyname(%s)... ", name);
4128        h = gethostbyname(name);
4129        if (h == NULL)
4130        {
4131                if (tTd(61, 10))
4132                        printf("failure\n");
4133
4134                nmaps = switch_map_find("hosts", maptype, mapreturn);
4135                while (--nmaps >= 0)
4136                        if (strcmp(maptype[nmaps], "nis") == 0 ||
4137                            strcmp(maptype[nmaps], "files") == 0)
4138                                break;
4139                if (nmaps >= 0)
4140                {
4141                        /* try short name */
4142                        if (strlen(name) > (SIZE_T) sizeof hbuf - 1)
4143                                return NULL;
4144                        strcpy(hbuf, name);
4145                        shorten_hostname(hbuf);
4146
4147                        /* if it hasn't been shortened, there's no point */
4148                        if (strcmp(hbuf, name) != 0)
4149                        {
4150                                if (tTd(61, 10))
4151                                        printf("gethostbyname(%s)... ", hbuf);
4152                                h = gethostbyname(hbuf);
4153                        }
4154                }
4155        }
4156#endif
4157        if (tTd(61, 10))
4158        {
4159                if (h == NULL)
4160                        printf("failure\n");
4161                else
4162                        printf("%s\n", h->h_name);
4163        }
4164        return h;
4165}
4166
4167struct hostent *
4168sm_gethostbyaddr(addr, len, type)
4169        char *addr;
4170        int len;
4171        int type;
4172{
4173#if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204)
4174# if SOLARIS == 20300 || SOLARIS == 203
4175        static struct hostent hp;
4176        static char buf[1000];
4177        extern struct hostent *_switch_gethostbyaddr_r();
4178
4179        return _switch_gethostbyaddr_r(addr, len, type, &hp, buf, sizeof(buf), &h_errno);
4180# else
4181        extern struct hostent *__switch_gethostbyaddr();
4182
4183        return __switch_gethostbyaddr(addr, len, type);
4184# endif
4185#else
4186        return gethostbyaddr(addr, len, type);
4187#endif
4188}
4189/*
4190**  SM_GETPW{NAM,UID} -- wrapper for getpwnam and getpwuid
4191*/
4192
4193struct passwd *
4194sm_getpwnam(user)
4195        char *user;
4196{
4197#ifdef _AIX4
4198        extern struct passwd *_getpwnam_shadow(const char *, const int);
4199
4200        return _getpwnam_shadow(user, 0);
4201#else
4202        struct passwd *pw;
4203        static struct passwd tmp;
4204        void *hes_context;
4205
4206        pw = getpwnam(user);
4207        if (!pw)
4208        {
4209                if (hesiod_init(&hes_context) != 0)
4210                        return pw;
4211                pw = hesiod_getpwnam(hes_context, user);
4212                if (pw)
4213                {
4214                        memcpy(&tmp, pw, sizeof(struct passwd));
4215                        hesiod_free_passwd(hes_context, pw);
4216                        pw = &tmp;
4217                }
4218                hesiod_end(hes_context);
4219        }
4220        return pw;
4221#endif
4222}
4223
4224struct passwd *
4225sm_getpwuid(uid)
4226        UID_T uid;
4227{
4228#if defined(_AIX4) && 0
4229        extern struct passwd *_getpwuid_shadow(const int, const int);
4230
4231        return _getpwuid_shadow(uid,0);
4232#else
4233        struct passwd *pw;
4234        static struct passwd tmp;
4235        void *hes_context;
4236
4237        pw = getpwuid(uid);
4238        if (!pw)
4239        {
4240                if (hesiod_init(&hes_context) != 0)
4241                        return pw;
4242                pw = hesiod_getpwuid(hes_context, uid);
4243                if (pw)
4244                {
4245                        memcpy(&tmp, pw, sizeof(struct passwd));
4246                        hesiod_free_passwd(hes_context, pw);
4247                        pw = &tmp;
4248                }
4249                hesiod_end(hes_context);
4250        }
4251        return pw;
4252#endif
4253}
4254/*
4255**  SECUREWARE_SETUP_SECURE -- Convex SecureWare setup
4256**
4257**      Set up the trusted computing environment for C2 level security
4258**      under SecureWare.
4259**
4260**      Parameters:
4261**              uid -- uid of the user to initialize in the TCB
4262**
4263**      Returns:
4264**              none
4265**
4266**      Side Effects:
4267**              Initialized the user in the trusted computing base
4268*/
4269
4270#if SECUREWARE
4271
4272# include <sys/security.h>
4273# include <prot.h>
4274
4275void
4276secureware_setup_secure(uid)
4277        UID_T uid;
4278{
4279        int rc;
4280
4281        if (getluid() != -1)
4282                return;
4283       
4284        if ((rc = set_secure_info(uid)) != SSI_GOOD_RETURN)
4285        {
4286                switch (rc)
4287                {
4288                  case SSI_NO_PRPW_ENTRY:
4289                        syserr("No protected passwd entry, uid = %d", uid);
4290                        break;
4291
4292                  case SSI_LOCKED:
4293                        syserr("Account has been disabled, uid = %d", uid);
4294                        break;
4295
4296                  case SSI_RETIRED:
4297                        syserr("Account has been retired, uid = %d", uid);
4298                        break;
4299
4300                  case SSI_BAD_SET_LUID:
4301                        syserr("Could not set LUID, uid = %d", uid);
4302                        break;
4303
4304                  case SSI_BAD_SET_PRIVS:
4305                        syserr("Could not set kernel privs, uid = %d", uid);
4306
4307                  default:
4308                        syserr("Unknown return code (%d) from set_secure_info(%d)",
4309                                rc, uid);
4310                        break;
4311                }
4312                finis(FALSE, EX_NOPERM);
4313        }
4314}
4315#endif /* SECUREWARE */
4316/*
4317**  ADD_LOCAL_HOST_NAMES -- Add a hostname to class 'w' based on IP address
4318**
4319**      Add hostnames to class 'w' based on the IP address read from
4320**      the network interface.
4321**
4322**      Parameters:
4323**              sa -- a pointer to a SOCKADDR containing the address
4324**
4325**      Returns:
4326**              0 if successful, -1 if host lookup fails.
4327*/
4328
4329int
4330add_hostnames(sa)
4331        SOCKADDR *sa;
4332{
4333        struct hostent *hp;
4334
4335        /* lookup name with IP address */
4336        switch (sa->sa.sa_family)
4337        {
4338                case AF_INET:
4339                        hp = sm_gethostbyaddr((char *) &sa->sin.sin_addr,
4340                                sizeof(sa->sin.sin_addr), sa->sa.sa_family);
4341                        break;
4342
4343                default:
4344#if _FFR_LOG_UNSUPPORTED_FAMILIES
4345                        /* XXX: Give warning about unsupported family */
4346                        if (LogLevel > 3)
4347                                sm_syslog(LOG_WARNING, NOQID,
4348                                          "Unsupported address family %d: %.100s",
4349                                          sa->sa.sa_family, anynet_ntoa(sa));
4350#endif
4351                        return -1;
4352        }
4353
4354        if (hp == NULL)
4355        {
4356                int save_errno = errno;
4357
4358                if (LogLevel > 3)
4359                        sm_syslog(LOG_WARNING, NOQID,
4360                                "gethostbyaddr(%.100s) failed: %d\n",
4361                                anynet_ntoa(sa),
4362#if NAMED_BIND
4363                                h_errno
4364#else
4365                                -1
4366#endif
4367                                );
4368                errno = save_errno;
4369                return -1;
4370        }
4371
4372        /* save its cname */
4373        if (!wordinclass((char *) hp->h_name, 'w'))
4374        {
4375                setclass('w', (char *) hp->h_name);
4376                if (tTd(0, 4))
4377                        printf("\ta.k.a.: %s\n", hp->h_name);
4378        }
4379
4380        /* save all it aliases name */
4381        while (*hp->h_aliases)
4382        {
4383                if (!wordinclass(*hp->h_aliases, 'w'))
4384                {
4385                        setclass('w', *hp->h_aliases);
4386                        if (tTd(0, 4))
4387                                printf("\ta.k.a.: %s\n", *hp->h_aliases);
4388                }
4389                hp->h_aliases++;
4390        }
4391        return 0;
4392}
4393/*
4394**  LOAD_IF_NAMES -- load interface-specific names into $=w
4395**
4396**      Parameters:
4397**              none.
4398**
4399**      Returns:
4400**              none.
4401**
4402**      Side Effects:
4403**              Loads $=w with the names of all the interfaces.
4404*/
4405
4406#if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
4407struct rtentry;
4408struct mbuf;
4409# include <arpa/inet.h>
4410# ifndef SUNOS403
4411#  include <sys/time.h>
4412# endif
4413# if _AIX4 >= 40300
4414#  undef __P
4415# endif
4416# include <net/if.h>
4417#endif
4418
4419void
4420load_if_names()
4421{
4422#if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
4423        int s;
4424        int i;
4425        struct ifconf ifc;
4426        int numifs;
4427
4428        s = socket(AF_INET, SOCK_DGRAM, 0);
4429        if (s == -1)
4430                return;
4431
4432        /* get the list of known IP address from the kernel */
4433# if defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN
4434        if (ioctl(s, SIOCGIFNUM, (char *) &numifs) < 0)
4435        {
4436                /* can't get number of interfaces -- fall back */
4437                if (tTd(0, 4))
4438                        printf("SIOCGIFNUM failed: %s\n", errstring(errno));
4439                numifs = -1;
4440        }
4441        else if (tTd(0, 42))
4442                printf("system has %d interfaces\n", numifs);
4443        if (numifs < 0)
4444# endif
4445                numifs = 512;
4446
4447        if (numifs <= 0)
4448        {
4449                close(s);
4450                return;
4451        }
4452        ifc.ifc_len = numifs * sizeof (struct ifreq);
4453        ifc.ifc_buf = xalloc(ifc.ifc_len);
4454        if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0)
4455        {
4456                if (tTd(0, 4))
4457                        printf("SIOGIFCONF failed: %s\n", errstring(errno));
4458                close(s);
4459                return;
4460        }
4461
4462        /* scan the list of IP address */
4463        if (tTd(0, 40))
4464                printf("scanning for interface specific names, ifc_len=%d\n",
4465                        ifc.ifc_len);
4466
4467        for (i = 0; i < ifc.ifc_len; )
4468        {
4469                struct ifreq *ifr = (struct ifreq *) &ifc.ifc_buf[i];
4470                SOCKADDR *sa = (SOCKADDR *) &ifr->ifr_addr;
4471                struct in_addr ia;
4472#ifdef SIOCGIFFLAGS
4473                struct ifreq ifrf;
4474#endif
4475                char ip_addr[256];
4476                extern char *inet_ntoa();
4477
4478#ifdef BSD4_4_SOCKADDR
4479                if (sa->sa.sa_len > sizeof ifr->ifr_addr)
4480                        i += sizeof ifr->ifr_name + sa->sa.sa_len;
4481                else
4482#endif
4483                        i += sizeof *ifr;
4484
4485                if (tTd(0, 20))
4486                        printf("%s\n", anynet_ntoa(sa));
4487
4488                if (ifr->ifr_addr.sa_family != AF_INET)
4489                        continue;
4490
4491#ifdef SIOCGIFFLAGS
4492                bzero(&ifrf, sizeof(struct ifreq));
4493                strncpy(ifrf.ifr_name, ifr->ifr_name, sizeof(ifrf.ifr_name));
4494                ioctl(s, SIOCGIFFLAGS, (char *) &ifrf);
4495                if (tTd(0, 41))
4496                        printf("\tflags: %x\n", ifrf.ifr_flags);
4497# define IFRFREF ifrf
4498#else
4499# define IFRFREF (*ifr)
4500#endif
4501                if (!bitset(IFF_UP, IFRFREF.ifr_flags))
4502                        continue;
4503
4504                /* extract IP address from the list*/
4505                ia = sa->sin.sin_addr;
4506                if (ia.s_addr == INADDR_ANY || ia.s_addr == INADDR_NONE)
4507                {
4508                        message("WARNING: interface %s is UP with %s address",
4509                                ifr->ifr_name, inet_ntoa(ia));
4510                        continue;
4511                }
4512
4513                /* save IP address in text from */
4514                (void) snprintf(ip_addr, sizeof ip_addr, "[%.*s]",
4515                        sizeof ip_addr - 3,
4516                        inet_ntoa(ia));
4517                if (!wordinclass(ip_addr, 'w'))
4518                {
4519                        setclass('w', ip_addr);
4520                        if (tTd(0, 4))
4521                                printf("\ta.k.a.: %s\n", ip_addr);
4522                }
4523
4524                /* skip "loopback" interface "lo" */
4525                if (bitset(IFF_LOOPBACK, IFRFREF.ifr_flags))
4526                        continue;
4527
4528                (void) add_hostnames(sa);
4529        }
4530        free(ifc.ifc_buf);
4531        close(s);
4532# undef IFRFREF
4533#endif
4534}
4535/*
4536**  GET_NUM_PROCS_ONLINE -- return the number of processors currently online
4537**
4538**      Parameters:
4539**              none.
4540**
4541**      Returns:
4542**              The number of processors online.
4543*/
4544
4545int
4546get_num_procs_online()
4547{
4548        int nproc = 0;
4549
4550#if _FFR_SCALE_LA_BY_NUM_PROCS
4551#ifdef _SC_NPROCESSORS_ONLN
4552        nproc = (int) sysconf(_SC_NPROCESSORS_ONLN);
4553#endif
4554#endif
4555        if (nproc <= 0)
4556                nproc = 1;
4557        return nproc;
4558}
4559/*
4560**  SM_SYSLOG -- syslog wrapper to keep messages under SYSLOG_BUFSIZE
4561**
4562**      Parameters:
4563**              level -- syslog level
4564**              id -- envelope ID or NULL (NOQUEUE)
4565**              fmt -- format string
4566**              arg... -- arguments as implied by fmt.
4567**
4568**      Returns:
4569**              none
4570*/
4571
4572/* VARARGS3 */
4573void
4574# ifdef __STDC__
4575sm_syslog(int level, const char *id, const char *fmt, ...)
4576# else
4577sm_syslog(level, id, fmt, va_alist)
4578        int level;
4579        const char *id;
4580        const char *fmt;
4581        va_dcl
4582#endif
4583{
4584        static char *buf = NULL;
4585        static size_t bufsize = MAXLINE;
4586        char *begin, *end;
4587        int seq = 1;
4588        int idlen;
4589        extern int SnprfOverflow;
4590        extern int SyslogErrno;
4591        extern char *DoprEnd;
4592        VA_LOCAL_DECL
4593        extern void sm_dopr __P((char *, const char *, va_list));
4594       
4595        SyslogErrno = errno;
4596        if (id == NULL)
4597        {
4598                id = "NOQUEUE";
4599                idlen = 9;
4600        }
4601        else if (strcmp(id, NOQID) == 0)
4602        {
4603                id = "";
4604                idlen = 0;
4605        }
4606        else
4607                idlen = strlen(id + 2);
4608bufalloc:
4609        if (buf == NULL)
4610                buf = (char *) xalloc(sizeof(char) * bufsize);
4611
4612        /* do a virtual vsnprintf into buf */
4613        VA_START(fmt);
4614        buf[0] = 0;
4615        DoprEnd = buf + bufsize - 1;
4616        SnprfOverflow = 0;
4617        sm_dopr(buf, fmt, ap);
4618        *DoprEnd = '\0';
4619        VA_END;
4620        /* end of virtual vsnprintf */
4621
4622        if (SnprfOverflow)
4623        {
4624                /* String too small, redo with correct size */
4625                bufsize += SnprfOverflow + 1;
4626                free(buf);
4627                buf = NULL;
4628                goto bufalloc;
4629        }
4630        if ((strlen(buf) + idlen + 1) < SYSLOG_BUFSIZE)
4631        {
4632#if LOG
4633                if (*id == '\0')
4634                        syslog(level, "%s", buf);
4635                else
4636                        syslog(level, "%s: %s", id, buf);
4637#else
4638                /*XXX should do something more sensible */
4639                if (*id == '\0')
4640                        fprintf(stderr, "%s\n", buf);
4641                else
4642                        fprintf(stderr, "%s: %s\n", id, buf);
4643#endif
4644                return;
4645        }
4646
4647        begin = buf;
4648        while (*begin != '\0' &&
4649               (strlen(begin) + idlen + 5) > SYSLOG_BUFSIZE)
4650        {
4651                char save;
4652       
4653                if (seq == 999)
4654                {
4655                        /* Too many messages */
4656                        break;
4657                }
4658                end = begin + SYSLOG_BUFSIZE - idlen - 12;
4659                while (end > begin)
4660                {
4661                        /* Break on comma or space */
4662                        if (*end == ',' || *end == ' ')
4663                        {
4664                                end++;    /* Include separator */
4665                                break;
4666                        }
4667                        end--;
4668                }
4669                /* No separator, break midstring... */
4670                if (end == begin)
4671                        end = begin + SYSLOG_BUFSIZE - idlen - 12;
4672                save = *end;
4673                *end = 0;
4674#if LOG
4675                syslog(level, "%s[%d]: %s ...", id, seq++, begin);
4676#else
4677                fprintf(stderr, "%s[%d]: %s ...\n", id, seq++, begin);
4678#endif
4679                *end = save;
4680                begin = end;
4681        }
4682        if (seq == 999)
4683#if LOG
4684                syslog(level, "%s[%d]: log terminated, too many parts", id, seq);
4685#else
4686                fprintf(stderr, "%s[%d]: log terminated, too many parts\n", id, seq);
4687#endif
4688        else if (*begin != '\0')
4689#if LOG
4690                syslog(level, "%s[%d]: %s", id, seq, begin);
4691#else
4692                fprintf(stderr, "%s[%d]: %s\n", id, seq, begin);
4693#endif
4694}
4695/*
4696**  HARD_SYSLOG -- call syslog repeatedly until it works
4697**
4698**      Needed on HP-UX, which apparently doesn't guarantee that
4699**      syslog succeeds during interrupt handlers.
4700*/
4701
4702#if defined(__hpux) && !defined(HPUX11)
4703
4704# define MAXSYSLOGTRIES 100
4705# undef syslog
4706# ifdef V4FS
4707#  define XCNST const
4708#  define CAST  (const char *)
4709# else
4710#  define XCNST
4711#  define CAST
4712# endif
4713
4714void
4715# ifdef __STDC__
4716hard_syslog(int pri, XCNST char *msg, ...)
4717# else
4718hard_syslog(pri, msg, va_alist)
4719        int pri;
4720        XCNST char *msg;
4721        va_dcl
4722# endif
4723{
4724        int i;
4725        char buf[SYSLOG_BUFSIZE];
4726        VA_LOCAL_DECL;
4727
4728        VA_START(msg);
4729        vsnprintf(buf, sizeof buf, msg, ap);
4730        VA_END;
4731
4732        for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, CAST "%s", buf) < 0; )
4733                continue;
4734}
4735
4736# undef CAST
4737#endif
4738/*
4739**  LOCAL_HOSTNAME_LENGTH
4740**
4741**      This is required to get sendmail to compile against BIND 4.9.x
4742**      on Ultrix.
4743*/
4744
4745#if defined(ultrix) && NAMED_BIND
4746
4747# include <resolv.h>
4748# if __RES >= 19931104 && __RES < 19950621
4749
4750int
4751local_hostname_length(hostname)
4752        char *hostname;
4753{
4754        int len_host, len_domain;
4755
4756        if (!*_res.defdname)
4757                res_init();
4758        len_host = strlen(hostname);
4759        len_domain = strlen(_res.defdname);
4760        if (len_host > len_domain &&
4761            (strcasecmp(hostname + len_host - len_domain,_res.defdname) == 0) &&
4762            hostname[len_host - len_domain - 1] == '.')
4763                return len_host - len_domain - 1;
4764        else
4765                return 0;
4766}
4767
4768# endif
4769#endif
4770/*
4771**  Compile-Time options
4772*/
4773
4774char    *CompileOptions[] =
4775{
4776#ifdef HESIOD
4777        "HESIOD",
4778#endif
4779#if HES_GETMAILHOST
4780        "HES_GETMAILHOST",
4781#endif
4782#ifdef LDAPMAP
4783        "LDAPMAP",
4784#endif
4785#ifdef MAP_REGEX
4786        "MAP_REGEX",
4787#endif
4788#if LOG
4789        "LOG",
4790#endif
4791#if MATCHGECOS
4792        "MATCHGECOS",
4793#endif
4794#if MIME7TO8
4795        "MIME7TO8",
4796#endif
4797#if MIME8TO7
4798        "MIME8TO7",
4799#endif
4800#if NAMED_BIND
4801        "NAMED_BIND",
4802#endif
4803#ifdef NDBM
4804        "NDBM",
4805#endif
4806#if NETINET
4807        "NETINET",
4808#endif
4809#if NETINFO
4810        "NETINFO",
4811#endif
4812#if NETISO
4813        "NETISO",
4814#endif
4815#if NETNS
4816        "NETNS",
4817#endif
4818#if NETUNIX
4819        "NETUNIX",
4820#endif
4821#if NETX25
4822        "NETX25",
4823#endif
4824#ifdef NEWDB
4825        "NEWDB",
4826#endif
4827#ifdef NIS
4828        "NIS",
4829#endif
4830#ifdef NISPLUS
4831        "NISPLUS",
4832#endif
4833#if QUEUE
4834        "QUEUE",
4835#endif
4836#if SCANF
4837        "SCANF",
4838#endif
4839#if SMTP
4840        "SMTP",
4841#endif
4842#if SMTPDEBUG
4843        "SMTPDEBUG",
4844#endif
4845#ifdef SUID_ROOT_FILES_OK
4846        "SUID_ROOT_FILES_OK",
4847#endif
4848#if TCPWRAPPERS
4849        "TCPWRAPPERS",
4850#endif
4851#if USERDB
4852        "USERDB",
4853#endif
4854#if XDEBUG
4855        "XDEBUG",
4856#endif
4857#ifdef XLA
4858        "XLA",
4859#endif
4860        NULL
4861};
4862
4863
4864/*
4865**  OS compile options.
4866*/
4867
4868char    *OsCompileOptions[] =
4869{
4870#if BOGUS_O_EXCL
4871        "BOGUS_O_EXCL",
4872#endif
4873#if HASFCHMOD
4874        "HASFCHMOD",
4875#endif
4876#if HASFLOCK
4877        "HASFLOCK",
4878#endif
4879#if HASGETDTABLESIZE
4880        "HASGETDTABLESIZE",
4881#endif
4882#if HASGETUSERSHELL
4883        "HASGETUSERSHELL",
4884#endif
4885#if HASINITGROUPS
4886        "HASINITGROUPS",
4887#endif
4888#if HASLSTAT
4889        "HASLSTAT",
4890#endif
4891#if HASSETREUID
4892        "HASSETREUID",
4893#endif
4894#if HASSETRLIMIT
4895        "HASSETRLIMIT",
4896#endif
4897#if HASSETSID
4898        "HASSETSID",
4899#endif
4900#if HASSETUSERCONTEXT
4901        "HASSETUSERCONTEXT",
4902#endif
4903#if HASSETVBUF
4904        "HASSETVBUF",
4905#endif
4906#if HASSNPRINTF
4907        "HASSNPRINTF",
4908#endif
4909#if HAS_ST_GEN
4910        "HAS_ST_GEN",
4911#endif
4912#if HASSTRERROR
4913        "HASSTRERROR",
4914#endif
4915#if HASULIMIT
4916        "HASULIMIT",
4917#endif
4918#if HASUNAME
4919        "HASUNAME",
4920#endif
4921#if HASUNSETENV
4922        "HASUNSETENV",
4923#endif
4924#if HASWAITPID
4925        "HASWAITPID",
4926#endif
4927#if IDENTPROTO
4928        "IDENTPROTO",
4929#endif
4930#if IP_SRCROUTE
4931        "IP_SRCROUTE",
4932#endif
4933#if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
4934        "LOCK_ON_OPEN",
4935#endif
4936#if NEEDFSYNC
4937        "NEEDFSYNC",
4938#endif
4939#if NOFTRUNCATE
4940        "NOFTRUNCATE",
4941#endif
4942#if RLIMIT_NEEDS_SYS_TIME_H
4943        "RLIMIT_NEEDS_SYS_TIME_H",
4944#endif
4945#if SAFENFSPATHCONF
4946        "SAFENFSPATHCONF",
4947#endif
4948#if SECUREWARE
4949        "SECUREWARE",
4950#endif
4951#if SHARE_V1
4952        "SHARE_V1",
4953#endif
4954#if SIOCGIFCONF_IS_BROKEN
4955        "SIOCGIFCONF_IS_BROKEN",
4956#endif
4957#if SIOCGIFNUM_IS_BROKEN
4958        "SIOCGIFNUM_IS_BROKEN",
4959#endif
4960#if SYS5SETPGRP
4961        "SYS5SETPGRP",
4962#endif
4963#if SYSTEM5
4964        "SYSTEM5",
4965#endif
4966#if USE_SA_SIGACTION
4967        "USE_SA_SIGACTION",
4968#endif
4969#if USE_SIGLONGJMP
4970        "USE_SIGLONGJMP",
4971#endif
4972#if USESETEUID
4973        "USESETEUID",
4974#endif
4975        NULL
4976};
Note: See TracBrowser for help on using the repository browser.