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