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