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.
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.
14 static char sccsid[] = "@(#)conf.c 8.452 (Berkeley) 1/26/1999";
17 # include "sendmail.h"
18 # include "pathnames.h"
19 # include <sys/ioctl.h>
20 # include <sys/param.h>
24 ** CONF.C -- Sendmail Configuration Tables.
26 ** Defines the configuration of this installation.
28 ** Configuration Variables:
29 ** HdrInfo -- a table describing well-known header fields.
30 ** Each entry has the field name and some flags,
31 ** which are described in sendmail.h.
34 ** I have tried to put almost all the reasonable
35 ** configuration information into the configuration
36 ** file read at runtime. My intent is that anything
37 ** here is a function of the version of UNIX you
38 ** are running, or is really static -- for example
39 ** the headers are a superset of widely used
40 ** protocols. If you find yourself playing with
41 ** this file too much, you may be making a mistake!
47 ** Final (null) entry contains the flags used for any other field.
49 ** Not all of these are actually handled specially by sendmail
50 ** at this time. They are included as placeholders, to let
51 ** you know that "someday" I intend to have sendmail do
52 ** something with them.
55 struct hdrinfo HdrInfo[] =
57 /* originator fields, most to least significant */
58 { "resent-sender", H_FROM|H_RESENT },
59 { "resent-from", H_FROM|H_RESENT },
60 { "resent-reply-to", H_FROM|H_RESENT },
63 { "reply-to", H_FROM },
64 { "errors-to", H_FROM|H_ERRORSTO },
65 { "full-name", H_ACHECK },
66 { "return-receipt-to", H_RECEIPTTO },
68 /* destination fields */
70 { "resent-to", H_RCPT|H_RESENT },
72 { "resent-cc", H_RCPT|H_RESENT },
73 { "bcc", H_RCPT|H_BCC },
74 { "resent-bcc", H_RCPT|H_BCC|H_RESENT },
75 { "apparently-to", H_RCPT },
77 /* message identification and control */
79 { "resent-message-id", H_RESENT },
85 { "resent-date", H_RESENT },
88 { "received", H_TRACE|H_FORCE },
89 { "x400-received", H_TRACE|H_FORCE },
90 { "via", H_TRACE|H_FORCE },
91 { "mail-from", H_TRACE|H_FORCE },
93 /* miscellaneous fields */
94 { "comments", H_FORCE|H_ENCODABLE },
95 { "return-path", H_FORCE|H_ACHECK },
96 { "content-transfer-encoding", H_CTE },
97 { "content-type", H_CTYPE },
98 { "content-length", H_ACHECK },
99 { "subject", H_ENCODABLE },
110 struct prival PrivacyValues[] =
112 { "public", PRIV_PUBLIC },
113 { "needmailhelo", PRIV_NEEDMAILHELO },
114 { "needexpnhelo", PRIV_NEEDEXPNHELO },
115 { "needvrfyhelo", PRIV_NEEDVRFYHELO },
116 { "noexpn", PRIV_NOEXPN },
117 { "novrfy", PRIV_NOVRFY },
118 { "restrictmailq", PRIV_RESTRICTMAILQ },
119 { "restrictqrun", PRIV_RESTRICTQRUN },
120 { "noetrn", PRIV_NOETRN },
121 { "noverb", PRIV_NOVERB },
122 { "authwarnings", PRIV_AUTHWARNINGS },
123 { "noreceipts", PRIV_NORECEIPTS },
124 { "goaway", PRIV_GOAWAY },
129 ** DontBlameSendmail values
131 struct dbsval DontBlameSendmailValues[] =
133 { "safe", DBS_SAFE },
134 { "assumesafechown", DBS_ASSUMESAFECHOWN },
135 { "groupwritabledirpathsafe", DBS_GROUPWRITABLEDIRPATHSAFE },
136 { "groupwritableforwardfilesafe",
137 DBS_GROUPWRITABLEFORWARDFILESAFE },
138 { "groupwritableincludefilesafe",
139 DBS_GROUPWRITABLEINCLUDEFILESAFE },
140 { "groupwritablealiasfile", DBS_GROUPWRITABLEALIASFILE },
141 { "worldwritablealiasfile", DBS_WORLDWRITABLEALIASFILE },
142 { "forwardfileinunsafedirpath", DBS_FORWARDFILEINUNSAFEDIRPATH },
143 { "includefileinunsafedirpath", DBS_INCLUDEFILEINUNSAFEDIRPATH },
144 { "mapinunsafedirpath", DBS_MAPINUNSAFEDIRPATH },
145 { "linkedaliasfileinwritabledir",
146 DBS_LINKEDALIASFILEINWRITABLEDIR },
147 { "linkedclassfileinwritabledir",
148 DBS_LINKEDCLASSFILEINWRITABLEDIR },
149 { "linkedforwardfileinwritabledir",
150 DBS_LINKEDFORWARDFILEINWRITABLEDIR },
151 { "linkedincludefileinwritabledir",
152 DBS_LINKEDINCLUDEFILEINWRITABLEDIR },
153 { "linkedmapinwritabledir", DBS_LINKEDMAPINWRITABLEDIR },
154 { "linkedserviceswitchfileinwritabledir",
155 DBS_LINKEDSERVICESWITCHFILEINWRITABLEDIR },
156 { "filedeliverytohardlink", DBS_FILEDELIVERYTOHARDLINK },
157 { "filedeliverytosymlink", DBS_FILEDELIVERYTOSYMLINK },
158 { "writemaptohardlink", DBS_WRITEMAPTOHARDLINK },
159 { "writemaptosymlink", DBS_WRITEMAPTOSYMLINK },
160 { "writestatstohardlink", DBS_WRITESTATSTOHARDLINK },
161 { "writestatstosymlink", DBS_WRITESTATSTOSYMLINK },
162 { "forwardfileingroupwritabledirpath",
163 DBS_FORWARDFILEINGROUPWRITABLEDIRPATH },
164 { "includefileingroupwritabledirpath",
165 DBS_INCLUDEFILEINGROUPWRITABLEDIRPATH },
166 { "classfileinunsafedirpath", DBS_CLASSFILEINUNSAFEDIRPATH },
167 { "errorheaderinunsafedirpath", DBS_ERRORHEADERINUNSAFEDIRPATH },
168 { "helpfileinunsafedirpath", DBS_HELPFILEINUNSAFEDIRPATH },
169 { "forwardfileinunsafedirpathsafe",
170 DBS_FORWARDFILEINUNSAFEDIRPATHSAFE },
171 { "includefileinunsafedirpathsafe",
172 DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE },
173 { "runprograminunsafedirpath", DBS_RUNPROGRAMINUNSAFEDIRPATH },
174 { "runwritableprogram", DBS_RUNWRITABLEPROGRAM },
180 ** Miscellaneous stuff.
183 int DtableSize = 50; /* max open files; reset in 4.2bsd */
185 ** SETDEFAULTS -- set default values
187 ** Because of the way freezing is done, these must be initialized
188 ** using direct code.
191 ** e -- the default envelope.
197 ** Initializes a bunch of global variables to their
202 #define HOURS * 60 MINUTES
203 #define DAYS * 24 HOURS
206 # define _PATH_VARTMP "/usr/tmp/"
209 #ifndef MAXRULERECURSION
210 # define MAXRULERECURSION 50 /* max ruleset recursion depth */
215 register ENVELOPE *e;
220 extern void setdefuser __P((void));
221 extern void setupmaps __P((void));
222 extern void setupmailers __P((void));
223 extern void setupheaders __P((void));
225 SpaceSub = ' '; /* option B */
226 QueueLA = 8; /* option x */
227 RefuseLA = 12; /* option X */
228 WkRecipFact = 30000L; /* option y */
229 WkClassFact = 1800L; /* option z */
230 WkTimeFact = 90000L; /* option Z */
231 QueueFactor = WkRecipFact * 20; /* option q */
232 FileMode = (RealUid != geteuid()) ? 0644 : 0600;
235 if (((pw = getpwnam("mailnull")) != NULL && pw->pw_uid != 0) ||
236 ((pw = getpwnam("sendmail")) != NULL && pw->pw_uid != 0) ||
237 ((pw = getpwnam("daemon")) != NULL && pw->pw_uid != 0))
239 DefUid = pw->pw_uid; /* option u */
240 DefGid = pw->pw_gid; /* option g */
241 DefUser = newstr(pw->pw_name);
245 DefUid = 1; /* option u */
246 DefGid = 1; /* option g */
251 printf("setdefaults: DefUser=%s, DefUid=%d, DefGid=%d\n",
252 DefUser != NULL ? DefUser : "<1:1>",
253 (int) DefUid, (int) DefGid);
254 CheckpointInterval = 10; /* option C */
255 MaxHopCount = 25; /* option h */
256 e->e_sendmode = SM_FORK; /* option d */
257 e->e_errormode = EM_PRINT; /* option e */
258 SevenBitInput = FALSE; /* option 7 */
259 MaxMciCache = 1; /* option k */
260 MciCacheTimeout = 5 MINUTES; /* option K */
261 LogLevel = 9; /* option L */
262 inittimeouts(NULL); /* option r */
263 PrivacyFlags = PRIV_PUBLIC; /* option p */
264 DontBlameSendmail = DBS_SAFE; /* DontBlameSendmail option */
266 MimeMode = MM_CVTMIME|MM_PASS8BIT; /* option 8 */
268 MimeMode = MM_PASS8BIT;
270 for (i = 0; i < MAXTOCLASS; i++)
272 TimeOuts.to_q_return[i] = 5 DAYS; /* option T */
273 TimeOuts.to_q_warning[i] = 0; /* option T */
275 ServiceSwitchFile = "/etc/service.switch";
276 ServiceCacheMaxAge = (time_t) 10;
277 HostsFile = _PATH_HOSTS;
278 PidFile = newstr(_PATH_SENDMAILPID);
279 MustQuoteChars = "@,;:\\()[].'";
280 MciInfoTimeout = 30 MINUTES;
281 MaxRuleRecursion = MAXRULERECURSION;
282 MaxAliasRecursion = 10;
283 MaxMacroRecursion = 10;
284 ColonOkInAddr = TRUE;
285 DontLockReadFiles = TRUE;
286 DoubleBounceAddr = "postmaster";
287 MaxHeadersLength = MAXHDRSLEN;
288 snprintf(buf, sizeof buf, "%s%sdead.letter",
290 _PATH_VARTMP[sizeof _PATH_VARTMP - 2] == '/' ? "" : "/");
291 DeadLetterDrop = newstr(buf);
293 HesiodContext = NULL;
295 ControlSocketName = NULL;
303 ** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups())
309 struct passwd *defpwent;
310 static char defuserbuf[40];
312 DefUser = defuserbuf;
313 defpwent = sm_getpwuid(DefUid);
314 snprintf(defuserbuf, sizeof defuserbuf, "%s",
315 defpwent == NULL ? "nobody" : defpwent->pw_name);
317 printf("setdefuser: DefUid=%d, DefUser=%s\n",
318 (int) DefUid, DefUser);
321 ** SETUPMAILERS -- initialize default mailers
329 strcpy(buf, "prog, P=/bin/sh, F=lsoDq9, T=DNS/RFC822/X-Unix, A=sh -c \201u");
332 strcpy(buf, "*file*, P=[FILE], F=lsDFMPEouq9, T=DNS/RFC822/X-Unix, A=FILE \201u");
335 strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE \201u");
339 ** SETUPMAPS -- set up map classes
342 #define MAPDEF(name, ext, flags, parse, open, close, lookup, store) \
344 extern bool parse __P((MAP *, char *)); \
345 extern bool open __P((MAP *, int)); \
346 extern void close __P((MAP *)); \
347 extern char *lookup __P((MAP *, char *, char **, int *)); \
348 extern void store __P((MAP *, char *, char *)); \
349 s = stab(name, ST_MAPCLASS, ST_ENTER); \
350 s->s_mapclass.map_cname = name; \
351 s->s_mapclass.map_ext = ext; \
352 s->s_mapclass.map_cflags = flags; \
353 s->s_mapclass.map_parse = parse; \
354 s->s_mapclass.map_open = open; \
355 s->s_mapclass.map_close = close; \
356 s->s_mapclass.map_lookup = lookup; \
357 s->s_mapclass.map_store = store; \
366 MAPDEF("hash", ".db", MCF_ALIASOK|MCF_REBUILDABLE,
367 map_parseargs, hash_map_open, db_map_close,
368 db_map_lookup, db_map_store);
370 MAPDEF("btree", ".db", MCF_ALIASOK|MCF_REBUILDABLE,
371 map_parseargs, bt_map_open, db_map_close,
372 db_map_lookup, db_map_store);
376 MAPDEF("dbm", ".dir", MCF_ALIASOK|MCF_REBUILDABLE,
377 map_parseargs, ndbm_map_open, ndbm_map_close,
378 ndbm_map_lookup, ndbm_map_store);
382 MAPDEF("nis", NULL, MCF_ALIASOK,
383 map_parseargs, nis_map_open, null_map_close,
384 nis_map_lookup, null_map_store);
388 MAPDEF("nisplus", NULL, MCF_ALIASOK,
389 map_parseargs, nisplus_map_open, null_map_close,
390 nisplus_map_lookup, null_map_store);
393 MAPDEF("ldapx", NULL, 0,
394 ldap_map_parseargs, ldap_map_open, ldap_map_close,
395 ldap_map_lookup, null_map_store);
399 MAPDEF("hesiod", NULL, MCF_ALIASOK|MCF_ALIASONLY,
400 map_parseargs, hes_map_open, null_map_close,
401 hes_map_lookup, null_map_store);
405 MAPDEF("netinfo", NULL, MCF_ALIASOK,
406 map_parseargs, ni_map_open, null_map_close,
407 ni_map_lookup, null_map_store);
411 MAPDEF("dns", NULL, 0,
412 dns_map_init, null_map_open, null_map_close,
413 dns_map_lookup, null_map_store);
417 /* best MX DNS lookup */
418 MAPDEF("bestmx", NULL, MCF_OPTFILE,
419 map_parseargs, null_map_open, null_map_close,
420 bestmx_map_lookup, null_map_store);
423 MAPDEF("host", NULL, 0,
424 host_map_init, null_map_open, null_map_close,
425 host_map_lookup, null_map_store);
427 MAPDEF("text", NULL, MCF_ALIASOK,
428 map_parseargs, text_map_open, null_map_close,
429 text_map_lookup, null_map_store);
431 MAPDEF("stab", NULL, MCF_ALIASOK|MCF_ALIASONLY,
432 map_parseargs, stab_map_open, null_map_close,
433 stab_map_lookup, stab_map_store);
435 MAPDEF("implicit", NULL, MCF_ALIASOK|MCF_ALIASONLY|MCF_REBUILDABLE,
436 map_parseargs, impl_map_open, impl_map_close,
437 impl_map_lookup, impl_map_store);
439 /* access to system passwd file */
440 MAPDEF("user", NULL, MCF_OPTFILE,
441 map_parseargs, user_map_open, null_map_close,
442 user_map_lookup, null_map_store);
445 MAPDEF("dequote", NULL, 0,
446 dequote_init, null_map_open, null_map_close,
447 dequote_map, null_map_store);
450 MAPDEF("regex", NULL, 0,
451 regex_map_init, null_map_open, null_map_close,
452 regex_map_lookup, null_map_store);
457 MAPDEF("userdb", ".db", 0,
458 map_parseargs, null_map_open, null_map_close,
459 udb_map_lookup, null_map_store);
462 /* arbitrary programs */
463 MAPDEF("program", NULL, MCF_ALIASOK,
464 map_parseargs, null_map_open, null_map_close,
465 prog_map_lookup, null_map_store);
468 MAPDEF("sequence", NULL, MCF_ALIASOK,
469 seq_map_parse, null_map_open, null_map_close,
470 seq_map_lookup, seq_map_store);
472 /* switched interface to sequenced maps */
473 MAPDEF("switch", NULL, MCF_ALIASOK,
474 map_parseargs, switch_map_open, null_map_close,
475 seq_map_lookup, seq_map_store);
477 /* null map lookup -- really for internal use only */
478 MAPDEF("null", NULL, MCF_ALIASOK|MCF_OPTFILE,
479 map_parseargs, null_map_open, null_map_close,
480 null_map_lookup, null_map_store);
483 /* syslog map -- logs information to syslog */
484 MAPDEF("syslog", NULL, 0,
485 syslog_map_parseargs, null_map_open, null_map_close,
486 syslog_map_lookup, null_map_store);
492 ** INITHOSTMAPS -- initial host-dependent maps
494 ** This should act as an interface to any local service switch
495 ** provided by the host operating system.
504 ** Should define maps "host" and "users" as necessary
505 ** for this OS. If they are not defined, they will get
506 ** a default value later. It should check to make sure
507 ** they are not defined first, since it's possible that
508 ** the config file has provided an override.
516 char *maptype[MAXMAPSTACK];
517 short mapreturn[MAXMAPACTIONS];
521 ** Set up default hosts maps.
525 nmaps = switch_map_find("hosts", maptype, mapreturn);
526 for (i = 0; i < nmaps; i++)
528 if (strcmp(maptype[i], "files") == 0 &&
529 stab("hosts.files", ST_MAP, ST_FIND) == NULL)
531 strcpy(buf, "hosts.files text -k 0 -v 1 /etc/hosts");
532 (void) makemapentry(buf);
535 else if (strcmp(maptype[i], "dns") == 0 &&
536 stab("hosts.dns", ST_MAP, ST_FIND) == NULL)
538 strcpy(buf, "hosts.dns dns A");
539 (void) makemapentry(buf);
543 else if (strcmp(maptype[i], "nisplus") == 0 &&
544 stab("hosts.nisplus", ST_MAP, ST_FIND) == NULL)
546 strcpy(buf, "hosts.nisplus nisplus -k name -v address -d hosts.org_dir");
547 (void) makemapentry(buf);
551 else if (strcmp(maptype[i], "nis") == 0 &&
552 stab("hosts.nis", ST_MAP, ST_FIND) == NULL)
554 strcpy(buf, "hosts.nis nis -d -k 0 -v 1 hosts.byname");
555 (void) makemapentry(buf);
559 else if (strcmp(maptype[i], "netinfo") == 0) &&
560 stab("hosts.netinfo", ST_MAP, ST_FIND) == NULL)
562 strcpy(buf, "hosts.netinfo netinfo -v name /machines");
563 (void) makemapentry(buf);
570 ** Make sure we have a host map.
573 if (stab("host", ST_MAP, ST_FIND) == NULL)
575 /* user didn't initialize: set up host map */
576 strcpy(buf, "host host");
578 if (ConfigLevel >= 2)
581 (void) makemapentry(buf);
585 ** Set up default aliases maps
588 nmaps = switch_map_find("aliases", maptype, mapreturn);
589 for (i = 0; i < nmaps; i++)
591 if (strcmp(maptype[i], "files") == 0 &&
592 stab("aliases.files", ST_MAP, ST_FIND) == NULL)
594 strcpy(buf, "aliases.files null");
595 (void) makemapentry(buf);
598 else if (strcmp(maptype[i], "nisplus") == 0 &&
599 stab("aliases.nisplus", ST_MAP, ST_FIND) == NULL)
601 strcpy(buf, "aliases.nisplus nisplus -kalias -vexpansion -d mail_aliases.org_dir");
602 (void) makemapentry(buf);
606 else if (strcmp(maptype[i], "nis") == 0 &&
607 stab("aliases.nis", ST_MAP, ST_FIND) == NULL)
609 strcpy(buf, "aliases.nis nis -d mail.aliases");
610 (void) makemapentry(buf);
614 else if (strcmp(maptype[i], "netinfo") == 0 &&
615 stab("aliases.netinfo", ST_MAP, ST_FIND) == NULL)
617 strcpy(buf, "aliases.netinfo netinfo -z, /aliases");
618 (void) makemapentry(buf);
622 else if (strcmp(maptype[i], "hesiod") == 0 &&
623 stab("aliases.hesiod", ST_MAP, ST_FIND) == NULL)
625 strcpy(buf, "aliases.hesiod hesiod aliases");
626 (void) makemapentry(buf);
630 if (stab("aliases", ST_MAP, ST_FIND) == NULL)
632 strcpy(buf, "aliases switch aliases");
633 (void) makemapentry(buf);
636 #if 0 /* "user" map class is a better choice */
638 ** Set up default users maps.
641 nmaps = switch_map_find("passwd", maptype, mapreturn);
642 for (i = 0; i < nmaps; i++)
644 if (strcmp(maptype[i], "files") == 0 &&
645 stab("users.files", ST_MAP, ST_FIND) == NULL)
647 strcpy(buf, "users.files text -m -z: -k0 -v6 /etc/passwd");
648 (void) makemapentry(buf);
651 else if (strcmp(maptype[i], "nisplus") == 0 &&
652 stab("users.nisplus", ST_MAP, ST_FIND) == NULL)
654 strcpy(buf, "users.nisplus nisplus -m -kname -vhome -d passwd.org_dir");
655 (void) makemapentry(buf);
659 else if (strcmp(maptype[i], "nis") == 0 &&
660 stab("users.nis", ST_MAP, ST_FIND) == NULL)
662 strcpy(buf, "users.nis nis -m -d passwd.byname");
663 (void) makemapentry(buf);
667 else if (strcmp(maptype[i], "hesiod") == 0) &&
668 stab("users.hesiod", ST_MAP, ST_FIND) == NULL)
670 strcpy(buf, "users.hesiod hesiod");
671 (void) makemapentry(buf);
675 if (stab("users", ST_MAP, ST_FIND) == NULL)
677 strcpy(buf, "users switch -m passwd");
678 (void) makemapentry(buf);
683 ** SWITCH_MAP_FIND -- find the list of types associated with a map
685 ** This is the system-dependent interface to the service switch.
688 ** service -- the name of the service of interest.
689 ** maptype -- an out-array of strings containing the types
690 ** of access to use for this service. There can
691 ** be at most MAXMAPSTACK types for a single service.
692 ** mapreturn -- an out-array of return information bitmaps
696 ** The number of map types filled in, or -1 for failure.
699 #if defined(SOLARIS) || (defined(sony_news) && defined(__svr4))
700 # define _USE_SUN_NSSWITCH_
703 #ifdef _USE_SUN_NSSWITCH_
704 # include <nsswitch.h>
707 #if defined(ultrix) || (defined(__osf__) && defined(__alpha))
708 # define _USE_DEC_SVC_CONF_
711 #ifdef _USE_DEC_SVC_CONF_
712 # include <sys/svcinfo.h>
716 switch_map_find(service, maptype, mapreturn)
718 char *maptype[MAXMAPSTACK];
719 short mapreturn[MAXMAPACTIONS];
723 #ifdef _USE_SUN_NSSWITCH_
724 struct __nsw_switchconfig *nsw_conf;
725 enum __nsw_parse_err pserr;
726 struct __nsw_lookup *lk;
727 static struct __nsw_lookup lkp0 =
728 { "files", {1, 0, 0, 0}, NULL, NULL };
729 static struct __nsw_switchconfig lkp_default =
730 { 0, "sendmail", 3, &lkp0 };
732 for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
733 mapreturn[svcno] = 0;
735 if ((nsw_conf = __nsw_getconfig(service, &pserr)) == NULL)
736 lk = lkp_default.lookups;
738 lk = nsw_conf->lookups;
742 maptype[svcno] = lk->service_name;
743 if (lk->actions[__NSW_NOTFOUND] == __NSW_RETURN)
744 mapreturn[MA_NOTFOUND] |= 1 << svcno;
745 if (lk->actions[__NSW_TRYAGAIN] == __NSW_RETURN)
746 mapreturn[MA_TRYAGAIN] |= 1 << svcno;
747 if (lk->actions[__NSW_UNAVAIL] == __NSW_RETURN)
748 mapreturn[MA_TRYAGAIN] |= 1 << svcno;
755 #ifdef _USE_DEC_SVC_CONF_
756 struct svcinfo *svcinfo;
759 for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
760 mapreturn[svcno] = 0;
765 if (strcmp(service, "hosts") == 0)
767 else if (strcmp(service, "aliases") == 0)
769 else if (strcmp(service, "passwd") == 0)
773 for (svcno = 0; svcno < SVC_PATHSIZE; svcno++)
775 switch (svcinfo->svcpath[svc][svcno])
778 maptype[svcno] = "files";
782 maptype[svcno] = "nis";
786 maptype[svcno] = "dns";
791 maptype[svcno] = "hesiod";
802 #if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_)
804 ** Fall-back mechanism.
808 time_t now = curtime();
810 for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
811 mapreturn[svcno] = 0;
813 if ((now - ServiceCacheTime) > (time_t) ServiceCacheMaxAge)
815 /* (re)read service switch */
817 int sff = SFF_REGONLY|SFF_OPENASROOT|SFF_NOLOCK;
819 if (!bitset(DBS_LINKEDSERVICESWITCHFILEINWRITABLEDIR, DontBlameSendmail))
823 ServiceCacheTime = now;
824 fp = safefopen(ServiceSwitchFile, O_RDONLY, 0, sff);
829 while (fgets(buf, sizeof buf, fp) != NULL)
833 p = strpbrk(buf, "#\n");
836 p = strpbrk(buf, " \t");
843 sm_syslog(LOG_ERR, NOQID,
844 "Bad line on %.100s: %.100s",
855 ** Find/allocate space for this service entry.
856 ** Space for all of the service strings
857 ** are allocated at once. This means
858 ** that we only have to free the first
859 ** one to free all of them.
862 st = stab(buf, ST_SERVICE, ST_ENTER);
863 if (st->s_service[0] != NULL)
864 free((void *) st->s_service[0]);
866 for (svcno = 0; svcno < MAXMAPSTACK; )
870 st->s_service[svcno++] = p;
871 p = strpbrk(p, " \t");
878 if (svcno < MAXMAPSTACK)
879 st->s_service[svcno] = NULL;
885 /* look up entry in cache */
886 st = stab(service, ST_SERVICE, ST_FIND);
887 if (st != NULL && st->s_service[0] != NULL)
891 while (svcno < MAXMAPSTACK)
893 maptype[svcno] = st->s_service[svcno];
894 if (maptype[svcno++] == NULL)
901 #if !defined(_USE_SUN_NSSWITCH_)
902 /* if the service file doesn't work, use an absolute fallback */
903 # ifdef _USE_DEC_SVC_CONF_
906 for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
907 mapreturn[svcno] = 0;
909 if (strcmp(service, "aliases") == 0)
911 maptype[svcno++] = "files";
912 # ifdef AUTO_NIS_ALIASES
914 maptype[svcno++] = "nisplus";
917 maptype[svcno++] = "nis";
922 if (strcmp(service, "hosts") == 0)
925 maptype[svcno++] = "dns";
927 # if defined(sun) && !defined(BSD)
929 maptype[svcno++] = "nis";
932 maptype[svcno++] = "files";
939 ** USERNAME -- return the user id of the logged in user.
945 ** The login name of the logged in user.
951 ** The return value is statically allocated.
957 static char *myname = NULL;
958 extern char *getlogin();
959 register struct passwd *pw;
961 /* cache the result */
965 if (myname == NULL || myname[0] == '\0')
967 pw = sm_getpwuid(RealUid);
969 myname = newstr(pw->pw_name);
975 myname = newstr(myname);
976 if ((pw = sm_getpwnam(myname)) == NULL ||
977 (uid != 0 && uid != pw->pw_uid))
979 pw = sm_getpwuid(uid);
981 myname = newstr(pw->pw_name);
984 if (myname == NULL || myname[0] == '\0')
986 syserr("554 Who are you?");
987 myname = "postmaster";
994 ** TTYPATH -- Get the path of the user's tty
996 ** Returns the pathname of the user's tty. Returns NULL if
997 ** the user is not logged in or if s/he has write permission
1004 ** pathname of the user's tty.
1005 ** NULL if not logged in or write permission denied.
1011 ** Return value is in a local buffer.
1021 register char *pathn;
1022 extern char *ttyname();
1023 extern char *getlogin();
1025 /* compute the pathname of the controlling tty */
1026 if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL &&
1027 (pathn = ttyname(0)) == NULL)
1033 /* see if we have write permission */
1034 if (stat(pathn, &stbuf) < 0 || !bitset(S_IWOTH, stbuf.st_mode))
1040 /* see if the user is logged in */
1041 if (getlogin() == NULL)
1048 ** CHECKCOMPAT -- check for From and To person compatible.
1050 ** This routine can be supplied on a per-installation basis
1051 ** to determine whether a person is allowed to send a message.
1052 ** This allows restriction of certain types of internet
1053 ** forwarding or registration of users.
1055 ** If the hosts are found to be incompatible, an error
1056 ** message should be given using "usrerr" and an EX_ code
1057 ** should be returned. You can also set to->q_status to
1058 ** a DSN-style status code.
1060 ** EF_NO_BODY_RETN can be set in e->e_flags to suppress the
1061 ** body during the return-to-sender function; this should be done
1062 ** on huge messages. This bit may already be set by the ESMTP
1066 ** to -- the person being sent to.
1072 ** none (unless you include the usrerr stuff)
1077 register ADDRESS *to;
1078 register ENVELOPE *e;
1086 printf("checkcompat(to=%s, from=%s)\n",
1087 to->q_paddr, e->e_from.q_paddr);
1089 # ifdef EXAMPLE_CODE
1090 /* this code is intended as an example only */
1093 s = stab("arpa", ST_MAILER, ST_FIND);
1094 if (s != NULL && strcmp(e->e_from.q_mailer->m_name, "local") != 0 &&
1095 to->q_mailer == s->s_mailer)
1097 usrerr("553 No ARPA mail through this machine: see your system administration");
1098 /* e->e_flags |= EF_NO_BODY_RETN; to supress body on return */
1099 to->q_status = "5.7.1";
1100 return (EX_UNAVAILABLE);
1102 # endif /* EXAMPLE_CODE */
1106 ** SETSIGNAL -- set a signal handler
1108 ** This is essentially old BSD "signal(3)".
1112 setsignal(sig, handler)
1116 #if defined(SYS5SIGNALS) || defined(BSD4_3)
1118 return signal(sig, handler);
1120 return sigset(sig, handler);
1123 struct sigaction n, o;
1125 bzero(&n, sizeof n);
1126 # if USE_SA_SIGACTION
1127 n.sa_sigaction = (void(*)(int, siginfo_t *, void *)) handler;
1128 n.sa_flags = SA_RESTART|SA_SIGINFO;
1130 n.sa_handler = handler;
1132 n.sa_flags = SA_RESTART;
1135 if (sigaction(sig, &n, &o) < 0)
1137 return o.sa_handler;
1141 ** BLOCKSIGNAL -- hold a signal to prevent delivery
1144 ** sig -- the signal to block.
1147 ** 1 signal was previously blocked
1148 ** 0 signal was not previously blocked
1158 # define sigmask(s) (1 << ((s) - 1))
1160 return (sigblock(sigmask(sig)) & sigmask(sig)) != 0;
1162 # ifdef ALTOS_SYSTEM_V
1165 handler = sigset(sig, SIG_HOLD);
1166 if (handler == SIG_ERR)
1169 return handler == SIG_HOLD;
1171 sigset_t sset, oset;
1174 sigaddset(&sset, sig);
1175 if (sigprocmask(SIG_BLOCK, &sset, &oset) < 0)
1178 return sigismember(&oset, sig);
1183 ** RELEASESIGNAL -- release a held signal
1186 ** sig -- the signal to release.
1189 ** 1 signal was previously blocked
1190 ** 0 signal was not previously blocked
1199 return (sigsetmask(sigblock(0) & ~sigmask(sig)) & sigmask(sig)) != 0;
1201 # ifdef ALTOS_SYSTEM_V
1204 handler = sigset(sig, SIG_HOLD);
1205 if (sigrelse(sig) < 0)
1208 return handler == SIG_HOLD;
1210 sigset_t sset, oset;
1213 sigaddset(&sset, sig);
1214 if (sigprocmask(SIG_UNBLOCK, &sset, &oset) < 0)
1217 return sigismember(&oset, sig);
1222 ** HOLDSIGS -- arrange to hold all signals
1231 ** Arranges that signals are held.
1239 ** RLSESIGS -- arrange to release all signals
1241 ** This undoes the effect of holdsigs.
1250 ** Arranges that signals are released.
1258 ** INIT_MD -- do machine dependent initializations
1260 ** Systems that have global modes that should be set should do
1261 ** them here rather than in main.
1265 # include <compat.h>
1269 # include <shares.h>
1278 setcompat(getcompat() | COMPAT_BSDPROT);
1281 #ifdef SUN_EXTENSIONS
1286 /* keep gethostby*() from stripping the local domain name */
1287 set_domain_trim_off();
1291 ** Due to QNX's network distributed nature, you can target a tcpip
1292 ** stack on a different node in the qnx network; this patch lets
1293 ** this feature work. The __sock_locate() must be done before the
1294 ** environment is clear.
1298 #if SECUREWARE || defined(_SCO_unix_)
1299 set_auth_parameters(argc, argv);
1303 ** This is required for highest security levels (the kernel
1304 ** won't let it call set*uid() or run setuid binaries without
1305 ** it). It may be necessary on other SECUREWARE systems.
1308 if (getluid() == -1)
1313 #ifdef VENDOR_DEFAULT
1314 VendorCode = VENDOR_DEFAULT;
1316 VendorCode = VENDOR_BERKELEY;
1320 ** INIT_VENDOR_MACROS -- vendor-dependent macro initializations
1322 ** Called once, on startup.
1325 ** e -- the global envelope.
1331 ** vendor-dependent.
1335 init_vendor_macros(e)
1336 register ENVELOPE *e;
1340 ** GETLA -- get the current load average
1342 ** This code stolen from la.c.
1348 ** The current load average as an integer.
1354 /* try to guess what style of load average we have */
1355 #define LA_ZERO 1 /* always return load average as zero */
1356 #define LA_INT 2 /* read kmem for avenrun; interpret as long */
1357 #define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */
1358 #define LA_SUBR 4 /* call getloadavg */
1359 #define LA_MACH 5 /* MACH load averages (as on NeXT boxes) */
1360 #define LA_SHORT 6 /* read kmem for avenrun; interpret as short */
1361 #define LA_PROCSTR 7 /* read string ("1.17") from /proc/loadavg */
1362 #define LA_READKSYM 8 /* SVR4: use MIOC_READKSYM ioctl call */
1363 #define LA_DGUX 9 /* special DGUX implementation */
1364 #define LA_HPUX 10 /* special HPUX implementation */
1365 #define LA_IRIX6 11 /* special IRIX 6.2 implementation */
1366 #define LA_KSTAT 12 /* special Solaris kstat(3k) implementation */
1367 #define LA_DEVSHORT 13 /* read short from a device */
1368 #define LA_ALPHAOSF 14 /* Digital UNIX (OSF/1 on Alpha) table() call */
1370 /* do guesses based on general OS type */
1372 # define LA_TYPE LA_ZERO
1376 # if defined(unixpc)
1380 # if defined(__alpha) || defined(IRIX)
1391 # define FSCALE (1 << FSHIFT)
1396 # define LA_AVENRUN "avenrun"
1398 # define LA_AVENRUN "_avenrun"
1402 /* _PATH_KMEM should be defined in <paths.h> */
1404 # define _PATH_KMEM "/dev/kmem"
1407 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT)
1411 /* _PATH_UNIX should be defined in <paths.h> */
1413 # if defined(SYSTEM5)
1414 # define _PATH_UNIX "/unix"
1416 # define _PATH_UNIX "/vmunix"
1434 static int kmem = -1;
1435 #if LA_TYPE == LA_INT
1438 # if LA_TYPE == LA_SHORT
1445 extern off_t lseek();
1450 strcpy(Nl[X_AVENRUN].n_name, LA_AVENRUN);
1451 Nl[1].n_name[0] = '\0';
1454 #if defined(_AIX3) || defined(_AIX4)
1455 if (knlist(Nl, 1, sizeof Nl[0]) < 0)
1457 if (nlist(_PATH_UNIX, Nl) < 0)
1461 printf("getla: nlist(%s): %s\n", _PATH_UNIX,
1465 if (Nl[X_AVENRUN].n_value == 0)
1468 printf("getla: nlist(%s, %s) ==> 0\n",
1469 _PATH_UNIX, LA_AVENRUN);
1473 Nl[X_AVENRUN].n_value &= NAMELISTMASK;
1476 kmem = open(_PATH_KMEM, 0, 0);
1480 printf("getla: open(/dev/kmem): %s\n",
1484 (void) fcntl(kmem, F_SETFD, 1);
1487 printf("getla: symbol address = %#lx\n",
1488 (u_long) Nl[X_AVENRUN].n_value);
1489 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, SEEK_SET) == -1 ||
1490 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
1494 printf("getla: lseek or read: %s\n", errstring(errno));
1497 # if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)
1500 # if LA_TYPE == LA_SHORT
1501 printf("getla: avenrun = %d", avenrun[0]);
1503 printf(", %d, %d", avenrun[1], avenrun[2]);
1505 printf("getla: avenrun = %ld", avenrun[0]);
1507 printf(", %ld, %ld", avenrun[1], avenrun[2]);
1512 printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1513 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1514 # else /* LA_TYPE == LA_FLOAT */
1517 printf("getla: avenrun = %g", avenrun[0]);
1519 printf(", %g, %g", avenrun[1], avenrun[2]);
1523 printf("getla: %d\n", (int) (avenrun[0] +0.5));
1524 return ((int) (avenrun[0] + 0.5));
1528 #endif /* LA_TYPE == LA_INT or LA_SHORT or LA_FLOAT */
1530 #if LA_TYPE == LA_READKSYM
1532 # include <sys/ksym.h>
1536 static int kmem = -1;
1539 struct mioc_rksym mirk;
1543 kmem = open("/dev/kmem", 0, 0);
1547 printf("getla: open(/dev/kmem): %s\n",
1551 (void) fcntl(kmem, F_SETFD, 1);
1553 mirk.mirk_symname = LA_AVENRUN;
1554 mirk.mirk_buf = avenrun;
1555 mirk.mirk_buflen = sizeof(avenrun);
1556 if (ioctl(kmem, MIOC_READKSYM, &mirk) < 0)
1559 printf("getla: ioctl(MIOC_READKSYM) failed: %s\n",
1565 printf("getla: avenrun = %d", avenrun[0]);
1567 printf(", %d, %d", avenrun[1], avenrun[2]);
1571 printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1572 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1575 #endif /* LA_TYPE == LA_READKSYM */
1577 #if LA_TYPE == LA_DGUX
1579 # include <sys/dg_sys_info.h>
1584 struct dg_sys_info_load_info load_info;
1586 dg_sys_info((long *)&load_info,
1587 DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0);
1590 printf("getla: %d\n", (int) (load_info.one_minute + 0.5));
1592 return((int) (load_info.one_minute + 0.5));
1595 #endif /* LA_TYPE == LA_DGUX */
1597 #if LA_TYPE == LA_HPUX
1599 /* forward declarations to keep gcc from complaining */
1604 struct pst_diskinfo;
1605 struct pst_processor;
1607 struct pst_swapinfo;
1609 # include <sys/param.h>
1610 # include <sys/pstat.h>
1615 struct pst_dynamic pstd;
1617 if (pstat_getdynamic(&pstd, sizeof(struct pst_dynamic),
1618 (size_t) 1, 0) == -1)
1622 printf("getla: %d\n", (int) (pstd.psd_avg_1_min + 0.5));
1624 return (int) (pstd.psd_avg_1_min + 0.5);
1627 #endif /* LA_TYPE == LA_HPUX */
1629 #if LA_TYPE == LA_SUBR
1636 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0)
1639 perror("getla: getloadavg failed:");
1643 printf("getla: %d\n", (int) (avenrun[0] +0.5));
1644 return ((int) (avenrun[0] + 0.5));
1647 #endif /* LA_TYPE == LA_SUBR */
1649 #if LA_TYPE == LA_MACH
1652 ** This has been tested on NEXTSTEP release 2.1/3.X.
1655 #if defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0
1656 # include <mach/mach.h>
1664 processor_set_t default_set;
1665 kern_return_t error;
1666 unsigned int info_count;
1667 struct processor_set_basic_info info;
1670 error = processor_set_default(host_self(), &default_set);
1671 if (error != KERN_SUCCESS)
1674 perror("getla: processor_set_default failed:");
1677 info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
1678 if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO,
1679 &host, (processor_set_info_t)&info,
1680 &info_count) != KERN_SUCCESS)
1683 perror("getla: processor_set_info failed:");
1687 printf("getla: %d\n", (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE);
1688 return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE;
1691 #endif /* LA_TYPE == LA_MACH */
1693 #if LA_TYPE == LA_PROCSTR
1696 ** Read /proc/loadavg for the load average. This is assumed to be
1697 ** in a format like "0.15 0.12 0.06".
1699 ** Initially intended for Linux. This has been in the kernel
1700 ** since at least 0.99.15.
1703 # ifndef _PATH_LOADAVG
1704 # define _PATH_LOADAVG "/proc/loadavg"
1711 register int result;
1714 fp = fopen(_PATH_LOADAVG, "r");
1718 printf("getla: fopen(%s): %s\n",
1719 _PATH_LOADAVG, errstring(errno));
1722 result = fscanf(fp, "%lf", &avenrun);
1727 printf("getla: fscanf() = %d: %s\n",
1728 result, errstring(errno));
1733 printf("getla(): %.2f\n", avenrun);
1735 return ((int) (avenrun + 0.5));
1738 #endif /* LA_TYPE == LA_PROCSTR */
1740 #if LA_TYPE == LA_IRIX6
1741 #include <sys/sysmp.h>
1745 static int kmem = -1;
1750 kmem = open(_PATH_KMEM, 0, 0);
1754 printf("getla: open(%s): %s\n", _PATH_KMEM,
1758 (void) fcntl(kmem, F_SETFD, 1);
1761 if (lseek(kmem, (sysmp(MP_KERNADDR, MPKA_AVENRUN) & 0x7fffffff), SEEK_SET) == -1 ||
1762 read(kmem, (char *)avenrun, sizeof(avenrun)) < sizeof(avenrun))
1765 printf("getla: lseek or read: %s\n",
1771 printf("getla: avenrun = %ld", (long int) avenrun[0]);
1773 printf(", %ld, %ld",
1774 (long int) avenrun[1], (long int) avenrun[2]);
1779 printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1780 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1785 #if LA_TYPE == LA_KSTAT
1792 static kstat_ctl_t *kc = NULL;
1793 static kstat_t *ksp = NULL;
1797 if (kc == NULL) /* if not initialized before */
1802 printf("getla: kstat_open(): %s\n",
1807 ksp = kstat_lookup(kc, "unix", 0, "system_misc");
1811 printf("getla: kstat_lookup(): %s\n",
1815 if (kstat_read(kc, ksp, NULL) < 0)
1818 printf("getla: kstat_read(): %s\n",
1822 ksn = (kstat_named_t *) kstat_data_lookup(ksp, "avenrun_1min");
1823 la = ((double)ksn->value.ul + FSCALE/2) / FSCALE;
1824 /* kstat_close(kc); /o do not close for fast access */
1828 #endif /* LA_TYPE == LA_KSTAT */
1830 #if LA_TYPE == LA_DEVSHORT
1833 ** Read /dev/table/avenrun for the load average. This should contain
1834 ** three shorts for the 1, 5, and 15 minute loads. We only read the
1835 ** first, since that's all we care about.
1837 ** Intended for SCO OpenServer 5.
1840 # ifndef _PATH_AVENRUN
1841 # define _PATH_AVENRUN "/dev/table/avenrun"
1847 static int afd = -1;
1854 if (afd == -1 || lseek(afd, 0L, SEEK_SET) == -1)
1858 afd = open(_PATH_AVENRUN, O_RDONLY|O_SYNC);
1861 sm_syslog(LOG_ERR, NOQID,
1862 "can't open %s: %m",
1868 r = read(afd, &avenrun, sizeof avenrun);
1871 printf("getla: avenrun = %d\n", avenrun);
1872 loadav = (int) (avenrun + FSCALE/2) >> FSHIFT;
1874 printf("getla: %d\n", loadav);
1878 #endif /* LA_TYPE == LA_DEVSHORT */
1880 #if LA_TYPE == LA_ALPHAOSF
1883 # include <sys/table.h>
1888 struct tbl_loadavg tab;
1890 if (table(TBL_LOADAVG, 0, &tab, 1, sizeof(tab)) == -1)
1893 printf("getla: table %s\n", errstring(errno));
1898 printf("getla: scale = %d\n", tab.tl_lscale);
1901 ave = (tab.tl_avenrun.l[0] + (tab.tl_lscale/2)) / tab.tl_lscale;
1903 ave = (int) (tab.tl_avenrun.d[0] + 0.5);
1906 printf("getla: %d\n", ave);
1913 #if LA_TYPE == LA_ZERO
1919 printf("getla: ZERO\n");
1923 #endif /* LA_TYPE == LA_ZERO */
1926 * Copyright 1989 Massachusetts Institute of Technology
1928 * Permission to use, copy, modify, distribute, and sell this software and its
1929 * documentation for any purpose is hereby granted without fee, provided that
1930 * the above copyright notice appear in all copies and that both that
1931 * copyright notice and this permission notice appear in supporting
1932 * documentation, and that the name of M.I.T. not be used in advertising or
1933 * publicity pertaining to distribution of the software without specific,
1934 * written prior permission. M.I.T. makes no representations about the
1935 * suitability of this software for any purpose. It is provided "as is"
1936 * without express or implied warranty.
1938 * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
1939 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
1940 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1941 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
1942 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
1943 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1945 * Authors: Many and varied...
1948 /* Non Apollo stuff removed by Don Lewis 11/15/93 */
1950 static char rcsid[] = "@(#)$Id: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp $";
1955 # include <apollo/base.h>
1958 int getloadavg( call_data )
1959 caddr_t call_data; /* pointer to (double) return value */
1961 double *avenrun = (double *) call_data;
1965 proc1_$get_loadav(loadav, &st);
1966 *avenrun = loadav[0] / (double) (1 << 16);
1969 # endif /* apollo */
1971 ** SHOULDQUEUE -- should this message be queued or sent?
1973 ** Compares the message cost to the load average to decide.
1976 ** pri -- the priority of the message in question.
1977 ** ctime -- the message creation time.
1980 ** TRUE -- if this message should be queued up for the
1982 ** FALSE -- if the load is low enough to send this message.
1988 extern int get_num_procs_online __P((void));
1991 shouldqueue(pri, ctime)
1996 int queuela = QueueLA * get_num_procs_online();
1999 printf("shouldqueue: CurrentLA=%d, pri=%ld: ", CurrentLA, pri);
2000 if (CurrentLA < queuela)
2003 printf("FALSE (CurrentLA < QueueLA)\n");
2006 #if 0 /* this code is reported to cause oscillation around RefuseLA */
2007 if (CurrentLA >= RefuseLA && QueueLA < RefuseLA)
2010 printf("TRUE (CurrentLA >= RefuseLA)\n");
2014 rval = pri > (QueueFactor / (CurrentLA - queuela + 1));
2016 printf("%s (by calculation)\n", rval ? "TRUE" : "FALSE");
2020 ** REFUSECONNECTIONS -- decide if connections should be refused
2023 ** port -- port number (for error messages only)
2026 ** TRUE if incoming SMTP connections should be refused
2028 ** FALSE if we should accept new work.
2031 ** Sets process title when it is rejecting connections.
2035 refuseconnections(port)
2038 int refusela = RefuseLA * get_num_procs_online();
2040 static time_t lastconn = (time_t) 0;
2041 static int conncnt = 0;
2042 extern bool enoughdiskspace __P((long));
2050 if (now != lastconn)
2055 else if (conncnt++ > ConnRateThrottle && ConnRateThrottle > 0)
2057 /* sleep to flatten out connection load */
2058 sm_setproctitle(TRUE, "deferring connections on port %d: %d per second",
2059 port, ConnRateThrottle);
2061 sm_syslog(LOG_INFO, NOQID,
2062 "deferring connections on port %d: %d per second",
2063 port, ConnRateThrottle);
2067 CurrentLA = getla();
2068 if (CurrentLA >= refusela)
2070 sm_setproctitle(TRUE, "rejecting connections on port %d: load average: %d",
2073 sm_syslog(LOG_INFO, NOQID,
2074 "rejecting connections on port %d: load average: %d",
2079 if (!enoughdiskspace(MinBlocksFree + 1))
2081 sm_setproctitle(TRUE, "rejecting connections on port %d: min free: %d",
2082 port, MinBlocksFree);
2084 sm_syslog(LOG_INFO, NOQID,
2085 "rejecting connections on port %d: min free: %d",
2086 port, MinBlocksFree);
2090 if (MaxChildren > 0 && CurChildren >= MaxChildren)
2093 if (CurChildren >= MaxChildren)
2095 sm_setproctitle(TRUE, "rejecting connections on port %d: %d children, max %d",
2096 port, CurChildren, MaxChildren);
2098 sm_syslog(LOG_INFO, NOQID,
2099 "rejecting connections on port %d: %d children, max %d",
2100 port, CurChildren, MaxChildren);
2108 ** SETPROCTITLE -- set process title for ps
2111 ** fmt -- a printf style format string.
2112 ** a, b, c -- possible parameters to fmt.
2118 ** Clobbers argv of our main procedure so ps(1) will
2119 ** display the title.
2122 #define SPT_NONE 0 /* don't use it at all */
2123 #define SPT_REUSEARGV 1 /* cover argv with title information */
2124 #define SPT_BUILTIN 2 /* use libc builtin */
2125 #define SPT_PSTAT 3 /* use pstat(PSTAT_SETCMD, ...) */
2126 #define SPT_PSSTRINGS 4 /* use PS_STRINGS->... */
2127 #define SPT_SYSMIPS 5 /* use sysmips() supported by NEWS-OS 6 */
2128 #define SPT_SCO 6 /* write kernel u. area */
2129 #define SPT_CHANGEARGV 7 /* write our own strings into argv[] */
2132 # define SPT_TYPE SPT_REUSEARGV
2135 #if SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN
2137 # if SPT_TYPE == SPT_PSTAT
2138 # include <sys/pstat.h>
2140 # if SPT_TYPE == SPT_PSSTRINGS
2141 # include <machine/vmparam.h>
2142 # include <sys/exec.h>
2143 # ifndef PS_STRINGS /* hmmmm.... apparently not available after all */
2145 # define SPT_TYPE SPT_REUSEARGV
2147 # ifndef NKPDE /* FreeBSD 2.0 */
2149 typedef unsigned int *pt_entry_t;
2154 # if SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV
2155 # define SETPROC_STATIC static
2157 # define SETPROC_STATIC
2160 # if SPT_TYPE == SPT_SYSMIPS
2161 # include <sys/sysmips.h>
2162 # include <sys/sysnews.h>
2165 # if SPT_TYPE == SPT_SCO
2166 # include <sys/immu.h>
2167 # include <sys/dir.h>
2168 # include <sys/user.h>
2169 # include <sys/fs/s5param.h>
2170 # if PSARGSZ > MAXLINE
2171 # define SPT_BUFSIZE PSARGSZ
2175 # ifndef SPT_PADCHAR
2176 # define SPT_PADCHAR ' '
2179 #endif /* SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN */
2181 # ifndef SPT_BUFSIZE
2182 # define SPT_BUFSIZE MAXLINE
2186 ** Pointers for setproctitle.
2187 ** This allows "ps" listings to give more useful information.
2190 char **Argv = NULL; /* pointer to argument vector */
2191 char *LastArgv = NULL; /* end of argv */
2194 initsetproctitle(argc, argv, envp)
2199 register int i, envpsize = 0;
2200 extern char **environ;
2203 ** Move the environment so setproctitle can use the space at
2204 ** the top of memory.
2207 for (i = 0; envp[i] != NULL; i++)
2208 envpsize += strlen(envp[i]) + 1;
2209 environ = (char **) xalloc(sizeof (char *) * (i + 1));
2210 for (i = 0; envp[i] != NULL; i++)
2211 environ[i] = newstr(envp[i]);
2215 ** Save start and extent of argv for setproctitle.
2221 ** Determine how much space we can use for setproctitle.
2222 ** Use all contiguous argv and envp pointers starting at argv[0]
2224 for (i = 0; i < argc; i++)
2226 if (i==0 || LastArgv + 1 == argv[i])
2227 LastArgv = argv[i] + strlen(argv[i]);
2231 for (i=0; envp[i] != NULL; i++)
2233 if (LastArgv + 1 == envp[i])
2234 LastArgv = envp[i] + strlen(envp[i]);
2240 #if SPT_TYPE != SPT_BUILTIN
2246 setproctitle(const char *fmt, ...)
2248 setproctitle(fmt, va_alist)
2253 # if SPT_TYPE != SPT_NONE
2256 SETPROC_STATIC char buf[SPT_BUFSIZE];
2258 # if SPT_TYPE == SPT_PSTAT
2261 # if SPT_TYPE == SPT_SCO
2263 static int kmem = -1;
2264 static int kmempid = -1;
2270 /* print sendmail: heading for grep */
2271 (void) strcpy(p, "sendmail: ");
2274 /* print the argument string */
2276 (void) vsnprintf(p, SPACELEFT(buf, p), fmt, ap);
2281 # if SPT_TYPE == SPT_PSTAT
2282 pst.pst_command = buf;
2283 pstat(PSTAT_SETCMD, pst, i, 0, 0);
2285 # if SPT_TYPE == SPT_PSSTRINGS
2286 PS_STRINGS->ps_nargvstr = 1;
2287 PS_STRINGS->ps_argvstr = buf;
2289 # if SPT_TYPE == SPT_SYSMIPS
2290 sysmips(SONY_SYSNEWS, NEWS_SETPSARGS, buf);
2292 # if SPT_TYPE == SPT_SCO
2293 if (kmem < 0 || kmempid != getpid())
2297 kmem = open(_PATH_KMEM, O_RDWR, 0);
2300 (void) fcntl(kmem, F_SETFD, 1);
2303 buf[PSARGSZ - 1] = '\0';
2304 seek_off = UVUBLK + (off_t) u.u_psargs - (off_t) &u;
2305 if (lseek(kmem, (off_t) seek_off, SEEK_SET) == seek_off)
2306 (void) write(kmem, buf, PSARGSZ);
2308 # if SPT_TYPE == SPT_REUSEARGV
2309 if (i > LastArgv - Argv[0] - 2)
2311 i = LastArgv - Argv[0] - 2;
2314 (void) strcpy(Argv[0], buf);
2316 while (p < LastArgv)
2320 # if SPT_TYPE == SPT_CHANGEARGV
2324 # endif /* SPT_TYPE != SPT_NONE */
2327 #endif /* SPT_TYPE != SPT_BUILTIN */
2329 ** SM_SETPROCTITLE -- set process task and set process title for ps
2331 ** Possibly set process status and call setproctitle() to
2332 ** change the ps display.
2335 ** status -- whether or not to store as process status
2336 ** fmt -- a printf style format string.
2337 ** a, b, c -- possible parameters to fmt.
2346 sm_setproctitle(bool status, const char *fmt, ...)
2348 sm_setproctitle(status, fmt, va_alist)
2354 char buf[SPT_BUFSIZE];
2357 /* print the argument string */
2359 (void) vsnprintf(buf, SPT_BUFSIZE, fmt, ap);
2363 proc_list_set(getpid(), buf);
2364 setproctitle("%s", buf);
2367 ** WAITFOR -- wait for a particular process id.
2370 ** pid -- process id to wait for.
2374 ** -1 if pid never shows up.
2390 #if defined(ISC_UNIX) || defined(_SCO_unix_)
2397 #if defined(ISC_UNIX) || defined(_SCO_unix_)
2398 savesig = releasesignal(SIGCHLD);
2401 #if defined(ISC_UNIX) || defined(_SCO_unix_)
2403 blocksignal(SIGCHLD);
2407 } while ((i >= 0 || errno == EINTR) && i != pid);
2417 ** REAPCHILD -- pick up the body of my child, lest it become a zombie
2420 ** sig -- the signal that got us here (unused).
2426 ** Picks up extant zombies.
2433 int olderrno = errno;
2440 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
2445 sm_syslog(LOG_ALERT, NOQID,
2446 "reapchild: waitpid loop: pid=%d, status=%x",
2450 proc_list_drop(pid);
2456 while ((pid = wait3(&status, WNOHANG, (struct rusage *) NULL)) > 0)
2457 proc_list_drop(pid);
2458 # else /* WNOHANG */
2462 ** Catch one zombie -- we will be re-invoked (we hope) if there
2463 ** are more. Unreliable signals probably break this, but this
2464 ** is the "old system" situation -- waitpid or wait3 are to be
2465 ** strongly preferred.
2468 if ((pid = wait(&status)) > 0)
2469 proc_list_drop(pid);
2470 # endif /* WNOHANG */
2473 (void) setsignal(SIGCHLD, reapchild);
2476 return SIGFUNC_RETURN;
2479 ** PUTENV -- emulation of putenv() in terms of setenv()
2481 ** Not needed on Posix-compliant systems.
2482 ** This doesn't have full Posix semantics, but it's good enough
2486 ** env -- the environment to put.
2494 # if NEEDPUTENV == 2 /* no setenv(3) call available */
2501 int matchlen, envlen=0;
2505 extern char **environ;
2508 * find out how much of str to match when searching
2509 * for a string to replace.
2511 if ((tmp = strchr(str, '=')) == NULL || tmp == str)
2512 matchlen = strlen(str);
2514 matchlen = (int) (tmp - str);
2518 * Search for an existing string in the environment and find the
2519 * length of environ. If found, replace and exit.
2521 for (current=environ; *current; current++) {
2524 if (strncmp(str, *current, matchlen) == 0) {
2525 /* found it, now insert the new version */
2526 *current = (char *)str;
2532 * There wasn't already a slot so add space for a new slot.
2533 * If this is our first time through, use malloc(), else realloc().
2536 newenv = (char **) malloc(sizeof(char *) * (envlen + 2));
2541 (void) memcpy(newenv, environ, sizeof(char *) * envlen);
2543 newenv = (char **) realloc((char *)environ, sizeof(char *) * (envlen + 2));
2548 /* actually add in the new entry */
2550 environ[envlen] = (char *)str;
2551 environ[envlen+1] = NULL;
2556 #else /* implement putenv() in terms of setenv() */
2566 p = strchr(env, '=');
2570 if (l > sizeof nbuf - 1)
2571 l = sizeof nbuf - 1;
2572 bcopy(env, nbuf, l);
2574 return setenv(nbuf, ++p, 1);
2580 ** UNSETENV -- remove a variable from the environment
2582 ** Not needed on newer systems.
2585 ** name -- the string name of the environment variable to be
2586 ** deleted from the current environment.
2592 ** environ -- a pointer to the current environment.
2595 ** Modifies environ.
2604 extern char **environ;
2606 int len = strlen(name);
2608 for (pp = environ; *pp != NULL; pp++)
2610 if (strncmp(name, *pp, len) == 0 &&
2611 ((*pp)[len] == '=' || (*pp)[len] == '\0'))
2615 for (; *pp != NULL; pp++)
2621 ** GETDTABLESIZE -- return number of file descriptors
2623 ** Only on non-BSD systems
2629 ** size of file descriptor table
2636 # include <sys/resource.h>
2642 #ifdef RLIMIT_NOFILE
2645 if (getrlimit(RLIMIT_NOFILE, &rl) >= 0)
2649 # ifdef HASGETDTABLESIZE
2650 return getdtablesize();
2652 # ifdef _SC_OPEN_MAX
2653 return sysconf(_SC_OPEN_MAX);
2660 ** UNAME -- get the UUCP name of this system.
2667 struct utsname *name;
2672 name->nodename[0] = '\0';
2674 /* try /etc/whoami -- one line with the node name */
2675 if ((file = fopen("/etc/whoami", "r")) != NULL)
2677 (void) fgets(name->nodename, NODE_LENGTH + 1, file);
2678 (void) fclose(file);
2679 n = strchr(name->nodename, '\n');
2682 if (name->nodename[0] != '\0')
2686 /* try /usr/include/whoami.h -- has a #define somewhere */
2687 if ((file = fopen("/usr/include/whoami.h", "r")) != NULL)
2691 while (fgets(buf, MAXLINE, file) != NULL)
2692 if (sscanf(buf, "#define sysname \"%*[^\"]\"",
2693 NODE_LENGTH, name->nodename) > 0)
2695 (void) fclose(file);
2696 if (name->nodename[0] != '\0')
2702 ** Popen is known to have security holes.
2705 /* try uuname -l to return local name */
2706 if ((file = popen("uuname -l", "r")) != NULL)
2708 (void) fgets(name, NODE_LENGTH + 1, file);
2709 (void) pclose(file);
2710 n = strchr(name, '\n');
2713 if (name->nodename[0] != '\0')
2720 #endif /* HASUNAME */
2722 ** INITGROUPS -- initialize groups
2724 ** Stub implementation for System V style systems
2727 #ifndef HASINITGROUPS
2729 initgroups(name, basegid)
2738 ** SETGROUPS -- set group list
2740 ** Stub implementation for systems that don't have group lists
2746 setgroups(ngroups, grouplist)
2748 GIDSET_T grouplist[];
2755 ** SETSID -- set session id (for non-POSIX systems)
2766 fd = open("/dev/tty", O_RDWR, 0);
2769 (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0);
2772 #endif /* TIOCNOTTY */
2776 return setpgid(0, getpid());
2782 ** FSYNC -- dummy fsync
2791 return fcntl(fd, F_SETFL, O_SYNC);
2793 /* nothing we can do */
2800 ** DGUX_INET_ADDR -- inet_addr for DG/UX
2802 ** Data General DG/UX version of inet_addr returns a struct in_addr
2803 ** instead of a long. This patches things. Only needed on versions
2812 dgux_inet_addr(host)
2815 struct in_addr haddr;
2817 haddr = inet_addr(host);
2818 return haddr.s_addr;
2823 ** GETOPT -- for old systems or systems with bogus implementations
2829 * Copyright (c) 1985 Regents of the University of California.
2830 * All rights reserved. The Berkeley software License Agreement
2831 * specifies the terms and conditions for redistribution.
2836 ** this version hacked to add `atend' flag to allow state machine
2837 ** to reset if invoked by the program to scan args for a 2nd time
2840 #if defined(LIBC_SCCS) && !defined(lint)
2841 static char sccsid[] = "@(#)getopt.c 4.3 (Berkeley) 3/9/86";
2842 #endif /* LIBC_SCCS and not lint */
2847 * get option letter from argument vector
2849 #ifdef _CONVEX_SOURCE
2850 extern int optind, opterr, optopt;
2851 extern char *optarg;
2853 int opterr = 1; /* if error message should be printed */
2854 int optind = 1; /* index into parent argv vector */
2855 int optopt = 0; /* character checked for validity */
2856 char *optarg = NULL; /* argument associated with option */
2859 #define BADCH (int)'?'
2861 #define tell(s) if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \
2862 fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}
2865 getopt(nargc,nargv,ostr)
2870 static char *place = EMSG; /* option letter processing */
2871 static char atend = 0;
2872 register char *oli = NULL; /* option letter list index */
2878 if(!*place) { /* update scanning pointer */
2879 if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) {
2883 if (*place == '-') { /* found "--" */
2888 } /* option letter okay? */
2889 if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) {
2890 if (!*place) ++optind;
2891 tell(": illegal option -- ");
2893 if (oli && *++oli != ':') { /* don't need argument */
2895 if (!*place) ++optind;
2897 else { /* need an argument */
2898 if (*place) optarg = place; /* no white space */
2899 else if (nargc <= ++optind) { /* no arg */
2901 tell(": option requires an argument -- ");
2903 else optarg = nargv[optind]; /* white space */
2907 return(optopt); /* dump back option letter */
2912 ** VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version
2919 vfprintf(fp, fmt, ap)
2927 while (*ap && i < MAXARG)
2929 fprintf(fp, fmt, bp[0], bp[1], bp[2], bp[3],
2930 bp[4], bp[5], bp[6], bp[7],
2931 bp[8], bp[9], bp[10], bp[11],
2932 bp[12], bp[13], bp[14], bp[15]);
2935 vsprintf(s, fmt, ap)
2943 while (*ap && i < MAXARG)
2945 sprintf(s, fmt, bp[0], bp[1], bp[2], bp[3],
2946 bp[4], bp[5], bp[6], bp[7],
2947 bp[8], bp[9], bp[10], bp[11],
2948 bp[12], bp[13], bp[14], bp[15]);
2953 ** USERSHELLOK -- tell if a user's shell is ok for unrestricted use
2956 ** user -- the name of the user we are checking.
2957 ** shell -- the user's shell from /etc/passwd
2960 ** TRUE -- if it is ok to use this for unrestricted access.
2961 ** FALSE -- if the shell is restricted.
2964 #if !HASGETUSERSHELL
2966 # ifndef _PATH_SHELLS
2967 # define _PATH_SHELLS "/etc/shells"
2970 # if defined(_AIX3) || defined(_AIX4)
2971 # include <userconf.h>
2973 # include <userpw.h>
2975 # include <usersec.h>
2978 char *DefaultUserShells[] =
2980 "/bin/sh", /* standard shell */
2982 "/bin/csh", /* C shell */
2986 "/usr/bin/rsh", /* restricted Bourne shell */
2987 "/usr/bin/ksh", /* Korn shell */
2988 "/usr/bin/rksh", /* restricted Korn shell */
2990 "/usr/bin/keysh", /* key shell (extended Korn shell) */
2991 "/usr/bin/posix/sh",
2993 "/bin/rsh", /* restricted Bourne shell */
2994 "/bin/ksh", /* Korn shell */
2995 "/bin/rksh", /* restricted Korn shell */
2997 "/usr/bin/keysh", /* key shell (extended Korn shell) */
3001 #if defined(_AIX3) || defined(_AIX4)
3002 "/bin/ksh", /* Korn shell */
3004 "/bin/tsh", /* trusted shell */
3006 "/bin/bsh", /* Bourne shell */
3009 #if defined(__svr4__) || defined(__svr5__)
3010 "/bin/ksh", /* Korn shell */
3014 "/sbin/sh", /* SGI's shells really live in /sbin */
3016 "/bin/ksh", /* Korn shell */
3019 "/bin/tcsh", /* Extended csh */
3027 #define WILDCARD_SHELL "/SENDMAIL/ANY/SHELL/"
3030 usershellok(user, shell)
3036 extern char *getusershell();
3038 if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') ||
3043 while ((p = getusershell()) != NULL)
3044 if (strcmp(p, shell) == 0 || strcmp(p, WILDCARD_SHELL) == 0)
3052 register FILE *shellf;
3055 if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') ||
3061 ** Naturally IBM has a "better" idea.....
3063 ** What a crock. This interface isn't documented, it is
3064 ** considered part of the security library (-ls), and it
3065 ** only works if you are running as root (since the list
3066 ** of valid shells is obviously a source of great concern).
3067 ** I recommend that you do NOT define USEGETCONFATTR,
3068 ** especially since you are going to have to set up an
3069 ** /etc/shells anyhow to handle the cases where getconfattr
3073 if (getconfattr(SC_SYS_LOGIN, SC_SHELLS, &v, SEC_LIST) == 0 && v != NULL)
3077 if (strcmp(v, shell) == 0 || strcmp(v, WILDCARD_SHELL) == 0)
3085 shellf = fopen(_PATH_SHELLS, "r");
3088 /* no /etc/shells; see if it is one of the std shells */
3091 if (errno != ENOENT && LogLevel > 3)
3092 sm_syslog(LOG_ERR, NOQID,
3093 "usershellok: cannot open %s: %s",
3094 _PATH_SHELLS, errstring(errno));
3096 for (d = DefaultUserShells; *d != NULL; d++)
3098 if (strcmp(shell, *d) == 0)
3104 while (fgets(buf, sizeof buf, shellf) != NULL)
3106 register char *p, *q;
3109 while (*p != '\0' && *p != '#' && *p != '/')
3111 if (*p == '#' || *p == '\0')
3114 while (*p != '\0' && *p != '#' && !(isascii(*p) && isspace(*p)))
3117 if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0)
3128 ** FREEDISKSPACE -- see how much free space is on the queue filesystem
3130 ** Only implemented if you have statfs.
3133 ** dir -- the directory in question.
3134 ** bsize -- a variable into which the filesystem
3135 ** block size is stored.
3138 ** The number of bytes free on the queue filesystem.
3139 ** -1 if the statfs call fails.
3142 ** Puts the filesystem block size into bsize.
3146 #define SFS_NONE 0 /* no statfs implementation */
3147 #define SFS_USTAT 1 /* use ustat */
3148 #define SFS_4ARGS 2 /* use four-argument statfs call */
3149 #define SFS_VFS 3 /* use <sys/vfs.h> implementation */
3150 #define SFS_MOUNT 4 /* use <sys/mount.h> implementation */
3151 #define SFS_STATFS 5 /* use <sys/statfs.h> implementation */
3152 #define SFS_STATVFS 6 /* use <sys/statvfs.h> implementation */
3155 # define SFS_TYPE SFS_NONE
3158 #if SFS_TYPE == SFS_USTAT
3161 #if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS
3162 # include <sys/statfs.h>
3164 #if SFS_TYPE == SFS_VFS
3165 # include <sys/vfs.h>
3167 #if SFS_TYPE == SFS_MOUNT
3168 # include <sys/mount.h>
3170 #if SFS_TYPE == SFS_STATVFS
3171 # include <sys/statvfs.h>
3175 freediskspace(dir, bsize)
3179 #if SFS_TYPE != SFS_NONE
3180 # if SFS_TYPE == SFS_USTAT
3182 struct stat statbuf;
3183 # define FSBLOCKSIZE DEV_BSIZE
3184 # define SFS_BAVAIL f_tfree
3186 # if defined(ultrix)
3188 # define SFS_BAVAIL fd_bfreen
3189 # define FSBLOCKSIZE 1024L
3191 # if SFS_TYPE == SFS_STATVFS
3193 # define FSBLOCKSIZE fs.f_frsize
3196 # define FSBLOCKSIZE fs.f_bsize
3201 # define SFS_BAVAIL f_bavail
3204 # if SFS_TYPE == SFS_USTAT
3205 if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0)
3207 # if SFS_TYPE == SFS_4ARGS
3208 if (statfs(dir, &fs, sizeof fs, 0) == 0)
3210 # if SFS_TYPE == SFS_STATVFS
3211 if (statvfs(dir, &fs) == 0)
3213 # if defined(ultrix)
3214 if (statfs(dir, &fs) > 0)
3216 if (statfs(dir, &fs) == 0)
3223 *bsize = FSBLOCKSIZE;
3224 if (fs.SFS_BAVAIL <= 0)
3226 else if (fs.SFS_BAVAIL > LONG_MAX)
3229 return (long) fs.SFS_BAVAIL;
3235 ** ENOUGHDISKSPACE -- is there enough free space on the queue fs?
3237 ** Only implemented if you have statfs.
3240 ** msize -- the size to check against. If zero, we don't yet
3241 ** know how big the message will be, so just check for
3242 ** a "reasonable" amount.
3245 ** TRUE if there is enough space.
3250 enoughdiskspace(msize)
3255 if (MinBlocksFree <= 0 && msize <= 0)
3258 printf("enoughdiskspace: no threshold\n");
3262 if ((bfree = freediskspace(QueueDir, &bsize)) >= 0)
3265 printf("enoughdiskspace: bavail=%ld, need=%ld\n",
3268 /* convert msize to block count */
3269 msize = msize / bsize + 1;
3270 if (MinBlocksFree >= 0)
3271 msize += MinBlocksFree;
3276 sm_syslog(LOG_ALERT, CurEnv->e_id,
3277 "low on space (have %ld, %s needs %ld in %s)",
3279 CurHostName == NULL ? "SMTP-DAEMON" : CurHostName,
3284 else if (tTd(4, 80))
3285 printf("enoughdiskspace failure: min=%ld, need=%ld: %s\n",
3286 MinBlocksFree, msize, errstring(errno));
3290 ** TRANSIENTERROR -- tell if an error code indicates a transient failure
3292 ** This looks at an errno value and tells if this is likely to
3293 ** go away if retried later.
3296 ** err -- the errno code to classify.
3299 ** TRUE if this is probably transient.
3309 case EIO: /* I/O error */
3310 case ENXIO: /* Device not configured */
3311 case EAGAIN: /* Resource temporarily unavailable */
3312 case ENOMEM: /* Cannot allocate memory */
3313 case ENODEV: /* Operation not supported by device */
3314 case ENFILE: /* Too many open files in system */
3315 case EMFILE: /* Too many open files */
3316 case ENOSPC: /* No space left on device */
3318 case ETIMEDOUT: /* Connection timed out */
3321 case ESTALE: /* Stale NFS file handle */
3324 case ENETDOWN: /* Network is down */
3327 case ENETUNREACH: /* Network is unreachable */
3330 case ENETRESET: /* Network dropped connection on reset */
3333 case ECONNABORTED: /* Software caused connection abort */
3336 case ECONNRESET: /* Connection reset by peer */
3339 case ENOBUFS: /* No buffer space available */
3342 case ESHUTDOWN: /* Can't send after socket shutdown */
3345 case ECONNREFUSED: /* Connection refused */
3348 case EHOSTDOWN: /* Host is down */
3351 case EHOSTUNREACH: /* No route to host */
3354 case EDQUOT: /* Disc quota exceeded */
3357 case EPROCLIM: /* Too many processes */
3360 case EUSERS: /* Too many users */
3363 case EDEADLK: /* Resource deadlock avoided */
3366 case EISCONN: /* Socket already connected */
3369 case EINPROGRESS: /* Operation now in progress */
3372 case EALREADY: /* Operation already in progress */
3375 case EADDRINUSE: /* Address already in use */
3377 #ifdef EADDRNOTAVAIL
3378 case EADDRNOTAVAIL: /* Can't assign requested address */
3381 case ETXTBSY: /* (Apollo) file locked */
3383 #if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR))
3384 case ENOSR: /* Out of streams resources */
3386 case E_SM_OPENTIMEOUT: /* PSEUDO: open timed out */
3390 /* nope, must be permanent */
3394 ** LOCKFILE -- lock a file using flock or (shudder) fcntl locking
3397 ** fd -- the file descriptor of the file.
3398 ** filename -- the file name (for error messages).
3399 ** ext -- the filename extension.
3400 ** type -- type of the lock. Bits can be:
3401 ** LOCK_EX -- exclusive lock.
3402 ** LOCK_NB -- non-blocking.
3405 ** TRUE if the lock was acquired.
3410 lockfile(fd, filename, ext, type)
3425 bzero(&lfd, sizeof lfd);
3426 if (bitset(LOCK_UN, type))
3427 lfd.l_type = F_UNLCK;
3428 else if (bitset(LOCK_EX, type))
3429 lfd.l_type = F_WRLCK;
3431 lfd.l_type = F_RDLCK;
3433 if (bitset(LOCK_NB, type))
3439 printf("lockfile(%s%s, action=%d, type=%d): ",
3440 filename, ext, action, lfd.l_type);
3442 while ((i = fcntl(fd, action, &lfd)) < 0 && errno == EINTR)
3447 printf("SUCCESS\n");
3453 printf("(%s) ", errstring(save_errno));
3456 ** On SunOS, if you are testing using -oQ/tmp/mqueue or
3457 ** -oA/tmp/aliases or anything like that, and /tmp is mounted
3458 ** as type "tmp" (that is, served from swap space), the
3459 ** previous fcntl will fail with "Invalid argument" errors.
3460 ** Since this is fairly common during testing, we will assume
3461 ** that this indicates that the lock is successfully grabbed.
3464 if (save_errno == EINVAL)
3467 printf("SUCCESS\n");
3471 if (!bitset(LOCK_NB, type) || (save_errno != EACCES && save_errno != EAGAIN))
3475 (void) fcntl(fd, F_GETFL, &omode);
3478 syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
3479 filename, ext, fd, type, omode, geteuid());
3480 dumpfd(fd, TRUE, TRUE);
3487 printf("lockfile(%s%s, type=%o): ", filename, ext, type);
3489 while ((i = flock(fd, type)) < 0 && errno == EINTR)
3494 printf("SUCCESS\n");
3500 printf("(%s) ", errstring(save_errno));
3502 if (!bitset(LOCK_NB, type) || save_errno != EWOULDBLOCK)
3506 (void) fcntl(fd, F_GETFL, &omode);
3509 syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
3510 filename, ext, fd, type, omode, geteuid());
3511 dumpfd(fd, TRUE, TRUE);
3520 ** CHOWNSAFE -- tell if chown is "safe" (executable only by root)
3522 ** Unfortunately, given that we can't predict other systems on which
3523 ** a remote mounted (NFS) filesystem will be mounted, the answer is
3524 ** almost always that this is unsafe.
3526 ** Note also that many operating systems have non-compliant
3527 ** implementations of the _POSIX_CHOWN_RESTRICTED variable and the
3528 ** fpathconf() routine. According to IEEE 1003.1-1990, if
3529 ** _POSIX_CHOWN_RESTRICTED is defined and not equal to -1, then
3530 ** no non-root process can give away the file. However, vendors
3531 ** don't take NFS into account, so a comfortable value of
3532 ** _POSIX_CHOWN_RESTRICTED tells us nothing.
3534 ** Also, some systems (e.g., IRIX 6.2) return 1 from fpathconf()
3535 ** even on files where chown is not restricted. Many systems get
3536 ** this wrong on NFS-based filesystems (that is, they say that chown
3537 ** is restricted [safe] on NFS filesystems where it may not be, since
3538 ** other systems can access the same filesystem and do file giveaway;
3539 ** only the NFS server knows for sure!) Hence, it is important to
3540 ** get the value of SAFENFSPATHCONF correct -- it should be defined
3541 ** _only_ after testing (see test/t_pathconf.c) a system on an unsafe
3542 ** NFS-based filesystem to ensure that you can get meaningful results.
3543 ** If in doubt, assume unsafe!
3545 ** You may also need to tweak IS_SAFE_CHOWN -- it should be a
3546 ** condition indicating whether the return from pathconf indicates
3547 ** that chown is safe (typically either > 0 or >= 0 -- there isn't
3548 ** even any agreement about whether a zero return means that a file
3549 ** is or is not safe). It defaults to "> 0".
3551 ** If the parent directory is safe (writable only by owner back
3552 ** to the root) then we can relax slightly and trust fpathconf
3553 ** in more circumstances. This is really a crock -- if this is an
3554 ** NFS mounted filesystem then we really know nothing about the
3555 ** underlying implementation. However, most systems pessimize and
3556 ** return an error (EINVAL or EOPNOTSUPP) on NFS filesystems, which
3557 ** we interpret as unsafe, as we should. Thus, this heuristic gets
3558 ** us into a possible problem only on systems that have a broken
3559 ** pathconf implementation and which are also poorly configured
3560 ** (have :include: files in group- or world-writable directories).
3563 ** fd -- the file descriptor to check.
3564 ** safedir -- set if the parent directory is safe.
3567 ** TRUE -- if the chown(2) operation is "safe" -- that is,
3568 ** only root can chown the file to an arbitrary user.
3569 ** FALSE -- if an arbitrary user can give away a file.
3572 #ifndef IS_SAFE_CHOWN
3573 # define IS_SAFE_CHOWN > 0
3577 chownsafe(fd, safedir)
3581 #if (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \
3582 (defined(_PC_CHOWN_RESTRICTED) || defined(_GNU_TYPES_H))
3585 /* give the system administrator a chance to override */
3586 if (bitset(DBS_ASSUMESAFECHOWN, DontBlameSendmail))
3590 ** Some systems (e.g., SunOS) seem to have the call and the
3591 ** #define _PC_CHOWN_RESTRICTED, but don't actually implement
3592 ** the call. This heuristic checks for that.
3596 rval = fpathconf(fd, _PC_CHOWN_RESTRICTED);
3597 # if SAFENFSPATHCONF
3598 return errno == 0 && rval IS_SAFE_CHOWN;
3600 return safedir && errno == 0 && rval IS_SAFE_CHOWN;
3603 return bitset(DBS_ASSUMESAFECHOWN, DontBlameSendmail);
3607 ** RESETLIMITS -- reset system controlled resource limits
3609 ** This is to avoid denial-of-service attacks
3619 # ifdef RLIMIT_NEEDS_SYS_TIME_H
3620 # include <sys/time.h>
3622 # include <sys/resource.h>
3625 # define FD_SETSIZE 256
3634 lim.rlim_cur = lim.rlim_max = RLIM_INFINITY;
3635 (void) setrlimit(RLIMIT_CPU, &lim);
3636 (void) setrlimit(RLIMIT_FSIZE, &lim);
3637 # ifdef RLIMIT_NOFILE
3638 lim.rlim_cur = lim.rlim_max = FD_SETSIZE;
3639 (void) setrlimit(RLIMIT_NOFILE, &lim);
3643 (void) ulimit(2, 0x3fffff);
3644 (void) ulimit(4, FD_SETSIZE);
3650 ** GETCFNAME -- return the name of the .cf file.
3652 ** Some systems (e.g., NeXT) determine this dynamically.
3659 if (ConfFile != NULL)
3663 extern char *ni_propval __P((char *, char *, char *, char *, int));
3666 cflocation = ni_propval("/locations", NULL, "sendmail",
3667 "sendmail.cf", '\0');
3668 if (cflocation != NULL)
3673 return _PATH_SENDMAILCF;
3676 ** SETVENDOR -- process vendor code from V configuration line
3679 ** vendor -- string representation of vendor.
3683 ** FALSE -- if vendor code could not be processed.
3686 ** It is reasonable to set mode flags here to tweak
3687 ** processing in other parts of the code if necessary.
3688 ** For example, if you are a vendor that uses $%y to
3689 ** indicate YP lookups, you could enable that here.
3696 if (strcasecmp(vendor, "Berkeley") == 0)
3698 VendorCode = VENDOR_BERKELEY;
3702 /* add vendor extensions here */
3704 #ifdef SUN_EXTENSIONS
3705 if (strcasecmp(vendor, "Sun") == 0)
3707 VendorCode = VENDOR_SUN;
3712 #if defined(VENDOR_NAME) && defined(VENDOR_CODE)
3713 if (strcasecmp(vendor, VENDOR_NAME) == 0)
3715 VendorCode = VENDOR_CODE;
3723 ** GETVENDOR -- return vendor name based on vendor code
3726 ** vendorcode -- numeric representation of vendor.
3729 ** string containing vendor name.
3733 getvendor(vendorcode)
3736 #if defined(VENDOR_NAME) && defined(VENDOR_CODE)
3738 ** Can't have the same switch case twice so need to
3739 ** handle VENDOR_CODE outside of switch. It might
3740 ** match one of the existing VENDOR_* codes.
3743 if (vendorcode == VENDOR_CODE)
3749 case VENDOR_BERKELEY:
3761 case VENDOR_SENDMAIL:
3769 ** VENDOR_PRE_DEFAULTS, VENDOR_POST_DEFAULTS -- set vendor-specific defaults
3771 ** Vendor_pre_defaults is called before reading the configuration
3772 ** file; vendor_post_defaults is called immediately after.
3775 ** e -- the global environment to initialize.
3782 int DefShareUid; /* default share uid to run as -- unused??? */
3786 vendor_pre_defaults(e)
3790 /* OTHERUID is defined in shares.h, do not be alarmed */
3791 DefShareUid = OTHERUID;
3793 #if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES)
3794 sun_pre_defaults(e);
3797 /* stupid domain/os can't even open /etc/sendmail.cf without this */
3798 setuserenv("ISP", NULL);
3799 setuserenv("SYSTYPE", NULL);
3805 vendor_post_defaults(e)
3811 /* Makes sure the SOCK environment variable remains */
3812 if (p = getextenv("SOCK"))
3813 setuserenv("SOCK", p);
3815 #if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES)
3816 sun_post_defaults(e);
3820 ** VENDOR_DAEMON_SETUP -- special vendor setup needed for daemon mode
3824 vendor_daemon_setup(e)
3828 if (getluid() != -1)
3830 usrerr("Daemon cannot have LUID");
3831 finis(FALSE, EX_USAGE);
3833 #endif /* SECUREWARE */
3836 ** VENDOR_SET_UID -- do setup for setting a user id
3838 ** This is called when we are still root.
3841 ** uid -- the uid we are about to become.
3852 ** We need to setup the share groups (lnodes)
3853 ** and and auditing inforation (luid's)
3854 ** before we loose our ``root''ness.
3857 if (setupshares(uid, syserr) != 0)
3858 syserr("Unable to set up shares");
3861 (void) setup_secure(uid);
3865 ** VALIDATE_CONNECTION -- check connection for rationality
3867 ** If the connection is rejected, this routine should log an
3868 ** appropriate message -- but should never issue any SMTP protocol.
3871 ** sap -- a pointer to a SOCKADDR naming the peer.
3872 ** hostname -- the name corresponding to sap.
3873 ** e -- the current envelope.
3876 ** error message from rejection.
3877 ** NULL if not rejected.
3883 /* tcpwrappers does no logging, but you still have to declare these -- ugh */
3884 int allow_severity = LOG_INFO;
3885 int deny_severity = LOG_NOTICE;
3890 validate_connection(sap, hostname, e)
3900 printf("validate_connection(%s, %s)\n",
3901 hostname, anynet_ntoa(sap));
3903 if (rscheck("check_relay", hostname, anynet_ntoa(sap), e) != EX_OK)
3905 static char reject[BUFSIZ*2];
3906 extern char MsgBuf[];
3909 printf(" ... validate_connection: BAD (rscheck)\n");
3911 if (strlen(MsgBuf) > 5)
3913 if (isascii(MsgBuf[0]) && isdigit(MsgBuf[0]) &&
3914 isascii(MsgBuf[1]) && isdigit(MsgBuf[1]) &&
3915 isascii(MsgBuf[2]) && isdigit(MsgBuf[2]))
3916 strcpy(reject, &MsgBuf[4]);
3918 strcpy(reject, MsgBuf);
3921 strcpy(reject, "Access denied");
3927 if (hostname[0] == '[' && hostname[strlen(hostname) - 1] == ']')
3931 if (!hosts_ctl("sendmail", host, anynet_ntoa(sap), STRING_UNKNOWN))
3934 printf(" ... validate_connection: BAD (tcpwrappers)\n");
3936 sm_syslog(LOG_NOTICE, NOQID,
3937 "tcpwrappers (%s, %s) rejection",
3938 host, anynet_ntoa(sap));
3939 return "Access denied";
3943 printf(" ... validate_connection: OK\n");
3949 ** STRTOL -- convert string to long integer
3951 ** For systems that don't have it in the C library.
3953 ** This is taken verbatim from the 4.4-Lite C library.
3958 #if defined(LIBC_SCCS) && !defined(lint)
3959 static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93";
3960 #endif /* LIBC_SCCS and not lint */
3963 * Convert a string to a long integer.
3965 * Ignores `locale' stuff. Assumes that the upper and lower case
3966 * alphabets and digits are each contiguous.
3970 strtol(nptr, endptr, base)
3975 register const char *s = nptr;
3976 register unsigned long acc;
3978 register unsigned long cutoff;
3979 register int neg = 0, any, cutlim;
3982 * Skip white space and pick up leading +/- sign if any.
3983 * If base is 0, allow 0x for hex and 0 for octal, else
3984 * assume decimal; if base is already 16, allow 0x.
3988 } while (isspace(c));
3992 } else if (c == '+')
3994 if ((base == 0 || base == 16) &&
3995 c == '0' && (*s == 'x' || *s == 'X')) {
4001 base = c == '0' ? 8 : 10;
4004 * Compute the cutoff value between legal numbers and illegal
4005 * numbers. That is the largest legal value, divided by the
4006 * base. An input number that is greater than this value, if
4007 * followed by a legal input character, is too big. One that
4008 * is equal to this value may be valid or not; the limit
4009 * between valid and invalid numbers is then based on the last
4010 * digit. For instance, if the range for longs is
4011 * [-2147483648..2147483647] and the input base is 10,
4012 * cutoff will be set to 214748364 and cutlim to either
4013 * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
4014 * a value > 214748364, or equal but the next digit is > 7 (or 8),
4015 * the number is too big, and we will return a range error.
4017 * Set any if any `digits' consumed; make it negative to indicate
4020 cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
4021 cutlim = cutoff % (unsigned long)base;
4022 cutoff /= (unsigned long)base;
4023 for (acc = 0, any = 0;; c = *s++) {
4026 else if (isalpha(c))
4027 c -= isupper(c) ? 'A' - 10 : 'a' - 10;
4032 if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
4041 acc = neg ? LONG_MIN : LONG_MAX;
4046 *endptr = (char *)(any ? s - 1 : nptr);
4052 ** STRSTR -- find first substring in string
4055 ** big -- the big (full) string.
4056 ** little -- the little (sub) string.
4059 ** A pointer to the first instance of little in big.
4060 ** big if little is the null string.
4061 ** NULL if little is not contained in big.
4071 register char *p = big;
4074 if (*little == '\0')
4078 while ((p = strchr(p, *little)) != NULL)
4080 if (strncmp(p, little, l) == 0)
4089 ** SM_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX
4091 ** Some operating systems have wierd problems with the gethostbyXXX
4092 ** routines. For example, Solaris versions at least through 2.3
4093 ** don't properly deliver a canonical h_name field. This tries to
4094 ** work around these problems.
4098 sm_gethostbyname(name)
4102 #if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4))
4103 # if SOLARIS == 20300 || SOLARIS == 203
4104 static struct hostent hp;
4105 static char buf[1000];
4106 extern struct hostent *_switch_gethostbyname_r();
4109 printf("_switch_gethostbyname_r(%s)... ", name);
4110 h = _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno);
4112 extern struct hostent *__switch_gethostbyname();
4115 printf("__switch_gethostbyname(%s)... ", name);
4116 h = __switch_gethostbyname(name);
4120 char *maptype[MAXMAPSTACK];
4121 short mapreturn[MAXMAPACTIONS];
4125 printf("gethostbyname(%s)... ", name);
4126 h = gethostbyname(name);
4130 printf("failure\n");
4132 nmaps = switch_map_find("hosts", maptype, mapreturn);
4133 while (--nmaps >= 0)
4134 if (strcmp(maptype[nmaps], "nis") == 0 ||
4135 strcmp(maptype[nmaps], "files") == 0)
4139 /* try short name */
4140 if (strlen(name) > (SIZE_T) sizeof hbuf - 1)
4143 shorten_hostname(hbuf);
4145 /* if it hasn't been shortened, there's no point */
4146 if (strcmp(hbuf, name) != 0)
4149 printf("gethostbyname(%s)... ", hbuf);
4150 h = gethostbyname(hbuf);
4158 printf("failure\n");
4160 printf("%s\n", h->h_name);
4166 sm_gethostbyaddr(addr, len, type)
4171 #if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204)
4172 # if SOLARIS == 20300 || SOLARIS == 203
4173 static struct hostent hp;
4174 static char buf[1000];
4175 extern struct hostent *_switch_gethostbyaddr_r();
4177 return _switch_gethostbyaddr_r(addr, len, type, &hp, buf, sizeof(buf), &h_errno);
4179 extern struct hostent *__switch_gethostbyaddr();
4181 return __switch_gethostbyaddr(addr, len, type);
4184 return gethostbyaddr(addr, len, type);
4188 ** SM_GETPW{NAM,UID} -- wrapper for getpwnam and getpwuid
4196 extern struct passwd *_getpwnam_shadow(const char *, const int);
4198 return _getpwnam_shadow(user, 0);
4200 return getpwnam(user);
4208 #if defined(_AIX4) && 0
4209 extern struct passwd *_getpwuid_shadow(const int, const int);
4211 return _getpwuid_shadow(uid,0);
4213 return getpwuid(uid);
4217 ** SECUREWARE_SETUP_SECURE -- Convex SecureWare setup
4219 ** Set up the trusted computing environment for C2 level security
4220 ** under SecureWare.
4223 ** uid -- uid of the user to initialize in the TCB
4229 ** Initialized the user in the trusted computing base
4234 # include <sys/security.h>
4238 secureware_setup_secure(uid)
4243 if (getluid() != -1)
4246 if ((rc = set_secure_info(uid)) != SSI_GOOD_RETURN)
4250 case SSI_NO_PRPW_ENTRY:
4251 syserr("No protected passwd entry, uid = %d", uid);
4255 syserr("Account has been disabled, uid = %d", uid);
4259 syserr("Account has been retired, uid = %d", uid);
4262 case SSI_BAD_SET_LUID:
4263 syserr("Could not set LUID, uid = %d", uid);
4266 case SSI_BAD_SET_PRIVS:
4267 syserr("Could not set kernel privs, uid = %d", uid);
4270 syserr("Unknown return code (%d) from set_secure_info(%d)",
4274 finis(FALSE, EX_NOPERM);
4277 #endif /* SECUREWARE */
4279 ** ADD_LOCAL_HOST_NAMES -- Add a hostname to class 'w' based on IP address
4281 ** Add hostnames to class 'w' based on the IP address read from
4282 ** the network interface.
4285 ** sa -- a pointer to a SOCKADDR containing the address
4288 ** 0 if successful, -1 if host lookup fails.
4297 /* lookup name with IP address */
4298 switch (sa->sa.sa_family)
4301 hp = sm_gethostbyaddr((char *) &sa->sin.sin_addr,
4302 sizeof(sa->sin.sin_addr), sa->sa.sa_family);
4306 #if _FFR_LOG_UNSUPPORTED_FAMILIES
4307 /* XXX: Give warning about unsupported family */
4309 sm_syslog(LOG_WARNING, NOQID,
4310 "Unsupported address family %d: %.100s",
4311 sa->sa.sa_family, anynet_ntoa(sa));
4318 int save_errno = errno;
4321 sm_syslog(LOG_WARNING, NOQID,
4322 "gethostbyaddr(%.100s) failed: %d\n",
4334 /* save its cname */
4335 if (!wordinclass((char *) hp->h_name, 'w'))
4337 setclass('w', (char *) hp->h_name);
4339 printf("\ta.k.a.: %s\n", hp->h_name);
4342 /* save all it aliases name */
4343 while (*hp->h_aliases)
4345 if (!wordinclass(*hp->h_aliases, 'w'))
4347 setclass('w', *hp->h_aliases);
4349 printf("\ta.k.a.: %s\n", *hp->h_aliases);
4356 ** LOAD_IF_NAMES -- load interface-specific names into $=w
4365 ** Loads $=w with the names of all the interfaces.
4368 #if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
4371 # include <arpa/inet.h>
4373 # include <sys/time.h>
4378 # include <net/if.h>
4384 #if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
4390 s = socket(AF_INET, SOCK_DGRAM, 0);
4394 /* get the list of known IP address from the kernel */
4395 # if defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN
4396 if (ioctl(s, SIOCGIFNUM, (char *) &numifs) < 0)
4398 /* can't get number of interfaces -- fall back */
4400 printf("SIOCGIFNUM failed: %s\n", errstring(errno));
4403 else if (tTd(0, 42))
4404 printf("system has %d interfaces\n", numifs);
4414 ifc.ifc_len = numifs * sizeof (struct ifreq);
4415 ifc.ifc_buf = xalloc(ifc.ifc_len);
4416 if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0)
4419 printf("SIOGIFCONF failed: %s\n", errstring(errno));
4424 /* scan the list of IP address */
4426 printf("scanning for interface specific names, ifc_len=%d\n",
4429 for (i = 0; i < ifc.ifc_len; )
4431 struct ifreq *ifr = (struct ifreq *) &ifc.ifc_buf[i];
4432 SOCKADDR *sa = (SOCKADDR *) &ifr->ifr_addr;
4438 extern char *inet_ntoa();
4440 #ifdef BSD4_4_SOCKADDR
4441 if (sa->sa.sa_len > sizeof ifr->ifr_addr)
4442 i += sizeof ifr->ifr_name + sa->sa.sa_len;
4448 printf("%s\n", anynet_ntoa(sa));
4450 if (ifr->ifr_addr.sa_family != AF_INET)
4454 bzero(&ifrf, sizeof(struct ifreq));
4455 strncpy(ifrf.ifr_name, ifr->ifr_name, sizeof(ifrf.ifr_name));
4456 ioctl(s, SIOCGIFFLAGS, (char *) &ifrf);
4458 printf("\tflags: %x\n", ifrf.ifr_flags);
4459 # define IFRFREF ifrf
4461 # define IFRFREF (*ifr)
4463 if (!bitset(IFF_UP, IFRFREF.ifr_flags))
4466 /* extract IP address from the list*/
4467 ia = sa->sin.sin_addr;
4468 if (ia.s_addr == INADDR_ANY || ia.s_addr == INADDR_NONE)
4470 message("WARNING: interface %s is UP with %s address",
4471 ifr->ifr_name, inet_ntoa(ia));
4475 /* save IP address in text from */
4476 (void) snprintf(ip_addr, sizeof ip_addr, "[%.*s]",
4477 (int)sizeof ip_addr - 3,
4479 if (!wordinclass(ip_addr, 'w'))
4481 setclass('w', ip_addr);
4483 printf("\ta.k.a.: %s\n", ip_addr);
4486 /* skip "loopback" interface "lo" */
4487 if (bitset(IFF_LOOPBACK, IFRFREF.ifr_flags))
4490 (void) add_hostnames(sa);
4498 ** GET_NUM_PROCS_ONLINE -- return the number of processors currently online
4504 ** The number of processors online.
4508 get_num_procs_online()
4512 #if _FFR_SCALE_LA_BY_NUM_PROCS
4513 #ifdef _SC_NPROCESSORS_ONLN
4514 nproc = (int) sysconf(_SC_NPROCESSORS_ONLN);
4522 ** SM_SYSLOG -- syslog wrapper to keep messages under SYSLOG_BUFSIZE
4525 ** level -- syslog level
4526 ** id -- envelope ID or NULL (NOQUEUE)
4527 ** fmt -- format string
4528 ** arg... -- arguments as implied by fmt.
4537 sm_syslog(int level, const char *id, const char *fmt, ...)
4539 sm_syslog(level, id, fmt, va_alist)
4546 static char *buf = NULL;
4547 static size_t bufsize = MAXLINE;
4551 extern int SnprfOverflow;
4552 extern int SyslogErrno;
4553 extern char *DoprEnd;
4555 extern void sm_dopr __P((char *, const char *, va_list));
4557 SyslogErrno = errno;
4563 else if (strcmp(id, NOQID) == 0)
4569 idlen = strlen(id + 2);
4572 buf = (char *) xalloc(sizeof(char) * bufsize);
4574 /* do a virtual vsnprintf into buf */
4577 DoprEnd = buf + bufsize - 1;
4579 sm_dopr(buf, fmt, ap);
4582 /* end of virtual vsnprintf */
4586 /* String too small, redo with correct size */
4587 bufsize += SnprfOverflow + 1;
4592 if ((strlen(buf) + idlen + 1) < SYSLOG_BUFSIZE)
4596 syslog(level, "%s", buf);
4598 syslog(level, "%s: %s", id, buf);
4600 /*XXX should do something more sensible */
4602 fprintf(stderr, "%s\n", buf);
4604 fprintf(stderr, "%s: %s\n", id, buf);
4610 while (*begin != '\0' &&
4611 (strlen(begin) + idlen + 5) > SYSLOG_BUFSIZE)
4617 /* Too many messages */
4620 end = begin + SYSLOG_BUFSIZE - idlen - 12;
4623 /* Break on comma or space */
4624 if (*end == ',' || *end == ' ')
4626 end++; /* Include separator */
4631 /* No separator, break midstring... */
4633 end = begin + SYSLOG_BUFSIZE - idlen - 12;
4637 syslog(level, "%s[%d]: %s ...", id, seq++, begin);
4639 fprintf(stderr, "%s[%d]: %s ...\n", id, seq++, begin);
4646 syslog(level, "%s[%d]: log terminated, too many parts", id, seq);
4648 fprintf(stderr, "%s[%d]: log terminated, too many parts\n", id, seq);
4650 else if (*begin != '\0')
4652 syslog(level, "%s[%d]: %s", id, seq, begin);
4654 fprintf(stderr, "%s[%d]: %s\n", id, seq, begin);
4658 ** HARD_SYSLOG -- call syslog repeatedly until it works
4660 ** Needed on HP-UX, which apparently doesn't guarantee that
4661 ** syslog succeeds during interrupt handlers.
4664 #if defined(__hpux) && !defined(HPUX11)
4666 # define MAXSYSLOGTRIES 100
4669 # define XCNST const
4670 # define CAST (const char *)
4678 hard_syslog(int pri, XCNST char *msg, ...)
4680 hard_syslog(pri, msg, va_alist)
4687 char buf[SYSLOG_BUFSIZE];
4691 vsnprintf(buf, sizeof buf, msg, ap);
4694 for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, CAST "%s", buf) < 0; )
4701 ** LOCAL_HOSTNAME_LENGTH
4703 ** This is required to get sendmail to compile against BIND 4.9.x
4707 #if defined(ultrix) && NAMED_BIND
4709 # include <resolv.h>
4710 # if __RES >= 19931104 && __RES < 19950621
4713 local_hostname_length(hostname)
4716 int len_host, len_domain;
4718 if (!*_res.defdname)
4720 len_host = strlen(hostname);
4721 len_domain = strlen(_res.defdname);
4722 if (len_host > len_domain &&
4723 (strcasecmp(hostname + len_host - len_domain,_res.defdname) == 0) &&
4724 hostname[len_host - len_domain - 1] == '.')
4725 return len_host - len_domain - 1;
4733 ** Compile-Time options
4736 char *CompileOptions[] =
4807 #ifdef SUID_ROOT_FILES_OK
4808 "SUID_ROOT_FILES_OK",
4827 ** OS compile options.
4830 char *OsCompileOptions[] =
4841 #if HASGETDTABLESIZE
4862 #if HASSETUSERCONTEXT
4863 "HASSETUSERCONTEXT",
4895 #if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
4904 #if RLIMIT_NEEDS_SYS_TIME_H
4905 "RLIMIT_NEEDS_SYS_TIME_H",
4916 #if SIOCGIFCONF_IS_BROKEN
4917 "SIOCGIFCONF_IS_BROKEN",
4919 #if SIOCGIFNUM_IS_BROKEN
4920 "SIOCGIFNUM_IS_BROKEN",
4928 #if USE_SA_SIGACTION