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

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