xref: /freebsd/contrib/sendmail/src/conf.c (revision 5521ff5a4d1929056e7ffc982fac3341ca54df7c)
1 /*
2  * Copyright (c) 1998-2001 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.86 2001/05/17 18:18:40 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=lsouDq9, 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 = 0;
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 && svcno < MAXMAPSTACK)
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 < MAXMAPSTACK; 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 					sm_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 **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
1233 **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
1234 **		DOING.
1235 */
1236 
1237 sigfunc_t
1238 setsignal(sig, handler)
1239 	int sig;
1240 	sigfunc_t handler;
1241 {
1242 # if defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3))
1243 	struct sigaction n, o;
1244 # endif /* defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3)) */
1245 
1246 	/*
1247 	**  First, try for modern signal calls
1248 	**  and restartable syscalls
1249 	*/
1250 
1251 # ifdef SA_RESTART
1252 	memset(&n, '\0', sizeof n);
1253 #  if USE_SA_SIGACTION
1254 	n.sa_sigaction = (void(*)(int, siginfo_t *, void *)) handler;
1255 	n.sa_flags = SA_RESTART|SA_SIGINFO;
1256 #  else /* USE_SA_SIGACTION */
1257 	n.sa_handler = handler;
1258 	n.sa_flags = SA_RESTART;
1259 #  endif /* USE_SA_SIGACTION */
1260 	if (sigaction(sig, &n, &o) < 0)
1261 		return SIG_ERR;
1262 	return o.sa_handler;
1263 # else /* SA_RESTART */
1264 
1265 	/*
1266 	**  Else check for SYS5SIGNALS or
1267 	**  BSD4_3 signals
1268 	*/
1269 
1270 #  if defined(SYS5SIGNALS) || defined(BSD4_3)
1271 #   ifdef BSD4_3
1272 	return signal(sig, handler);
1273 #   else /* BSD4_3 */
1274 	return sigset(sig, handler);
1275 #   endif /* BSD4_3 */
1276 #  else /* defined(SYS5SIGNALS) || defined(BSD4_3) */
1277 
1278 	/*
1279 	**  Finally, if nothing else is available,
1280 	**  go for a default
1281 	*/
1282 
1283 	memset(&n, '\0', sizeof n);
1284 	n.sa_handler = handler;
1285 	if (sigaction(sig, &n, &o) < 0)
1286 		return SIG_ERR;
1287 	return o.sa_handler;
1288 #  endif /* defined(SYS5SIGNALS) || defined(BSD4_3) */
1289 # endif /* SA_RESTART */
1290 }
1291 /*
1292 **  ALLSIGNALS -- act on all signals
1293 **
1294 **	Parameters:
1295 **		block -- whether to block or release all signals.
1296 **
1297 **	Returns:
1298 **		none.
1299 */
1300 
1301 void
1302 allsignals(block)
1303 	bool block;
1304 {
1305 # ifdef BSD4_3
1306 #  ifndef sigmask
1307 #   define sigmask(s)	(1 << ((s) - 1))
1308 #  endif /* ! sigmask */
1309 	if (block)
1310 	{
1311 		int mask = 0;
1312 
1313 		mask |= sigmask(SIGALRM);
1314 		mask |= sigmask(SIGCHLD);
1315 		mask |= sigmask(SIGHUP);
1316 		mask |= sigmask(SIGINT);
1317 		mask |= sigmask(SIGTERM);
1318 		mask |= sigmask(SIGUSR1);
1319 
1320 		(void) sigblock(mask);
1321 	}
1322 	else
1323 		sigsetmask(0);
1324 # else /* BSD4_3 */
1325 #  ifdef ALTOS_SYSTEM_V
1326 	if (block)
1327 	{
1328 		(void) sigset(SIGALRM, SIG_HOLD);
1329 		(void) sigset(SIGCHLD, SIG_HOLD);
1330 		(void) sigset(SIGHUP, SIG_HOLD);
1331 		(void) sigset(SIGINT, SIG_HOLD);
1332 		(void) sigset(SIGTERM, SIG_HOLD);
1333 		(void) sigset(SIGUSR1, SIG_HOLD);
1334 	}
1335 	else
1336 	{
1337 		(void) sigset(SIGALRM, SIG_DFL);
1338 		(void) sigset(SIGCHLD, SIG_DFL);
1339 		(void) sigset(SIGHUP, SIG_DFL);
1340 		(void) sigset(SIGINT, SIG_DFL);
1341 		(void) sigset(SIGTERM, SIG_DFL);
1342 		(void) sigset(SIGUSR1, SIG_DFL);
1343 	}
1344 #  else /* ALTOS_SYSTEM_V */
1345 	sigset_t sset;
1346 
1347 	(void) sigemptyset(&sset);
1348 	(void) sigaddset(&sset, SIGALRM);
1349 	(void) sigaddset(&sset, SIGCHLD);
1350 	(void) sigaddset(&sset, SIGHUP);
1351 	(void) sigaddset(&sset, SIGINT);
1352 	(void) sigaddset(&sset, SIGTERM);
1353 	(void) sigaddset(&sset, SIGUSR1);
1354 	(void) sigprocmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sset, NULL);
1355 #  endif /* ALTOS_SYSTEM_V */
1356 # endif /* BSD4_3 */
1357 }
1358 /*
1359 **  BLOCKSIGNAL -- hold a signal to prevent delivery
1360 **
1361 **	Parameters:
1362 **		sig -- the signal to block.
1363 **
1364 **	Returns:
1365 **		1 signal was previously blocked
1366 **		0 signal was not previously blocked
1367 **		-1 on failure.
1368 */
1369 
1370 int
1371 blocksignal(sig)
1372 	int sig;
1373 {
1374 # ifdef BSD4_3
1375 #  ifndef sigmask
1376 #   define sigmask(s)	(1 << ((s) - 1))
1377 #  endif /* ! sigmask */
1378 	return (sigblock(sigmask(sig)) & sigmask(sig)) != 0;
1379 # else /* BSD4_3 */
1380 #  ifdef ALTOS_SYSTEM_V
1381 	sigfunc_t handler;
1382 
1383 	handler = sigset(sig, SIG_HOLD);
1384 	if (handler == SIG_ERR)
1385 		return -1;
1386 	else
1387 		return handler == SIG_HOLD;
1388 #  else /* ALTOS_SYSTEM_V */
1389 	sigset_t sset, oset;
1390 
1391 	(void) sigemptyset(&sset);
1392 	(void) sigaddset(&sset, sig);
1393 	if (sigprocmask(SIG_BLOCK, &sset, &oset) < 0)
1394 		return -1;
1395 	else
1396 		return sigismember(&oset, sig);
1397 #  endif /* ALTOS_SYSTEM_V */
1398 # endif /* BSD4_3 */
1399 }
1400 /*
1401 **  RELEASESIGNAL -- release a held signal
1402 **
1403 **	Parameters:
1404 **		sig -- the signal to release.
1405 **
1406 **	Returns:
1407 **		1 signal was previously blocked
1408 **		0 signal was not previously blocked
1409 **		-1 on failure.
1410 */
1411 
1412 int
1413 releasesignal(sig)
1414 	int sig;
1415 {
1416 # ifdef BSD4_3
1417 	return (sigsetmask(sigblock(0) & ~sigmask(sig)) & sigmask(sig)) != 0;
1418 # else /* BSD4_3 */
1419 #  ifdef ALTOS_SYSTEM_V
1420 	sigfunc_t handler;
1421 
1422 	handler = sigset(sig, SIG_HOLD);
1423 	if (sigrelse(sig) < 0)
1424 		return -1;
1425 	else
1426 		return handler == SIG_HOLD;
1427 #  else /* ALTOS_SYSTEM_V */
1428 	sigset_t sset, oset;
1429 
1430 	(void) sigemptyset(&sset);
1431 	(void) sigaddset(&sset, sig);
1432 	if (sigprocmask(SIG_UNBLOCK, &sset, &oset) < 0)
1433 		return -1;
1434 	else
1435 		return sigismember(&oset, sig);
1436 #  endif /* ALTOS_SYSTEM_V */
1437 # endif /* BSD4_3 */
1438 }
1439 /*
1440 **  HOLDSIGS -- arrange to hold all signals
1441 **
1442 **	Parameters:
1443 **		none.
1444 **
1445 **	Returns:
1446 **		none.
1447 **
1448 **	Side Effects:
1449 **		Arranges that signals are held.
1450 */
1451 
1452 void
1453 holdsigs()
1454 {
1455 }
1456 /*
1457 **  RLSESIGS -- arrange to release all signals
1458 **
1459 **	This undoes the effect of holdsigs.
1460 **
1461 **	Parameters:
1462 **		none.
1463 **
1464 **	Returns:
1465 **		none.
1466 **
1467 **	Side Effects:
1468 **		Arranges that signals are released.
1469 */
1470 
1471 void
1472 rlsesigs()
1473 {
1474 }
1475 /*
1476 **  INIT_MD -- do machine dependent initializations
1477 **
1478 **	Systems that have global modes that should be set should do
1479 **	them here rather than in main.
1480 */
1481 
1482 #ifdef _AUX_SOURCE
1483 # include <compat.h>
1484 #endif /* _AUX_SOURCE */
1485 
1486 #if SHARE_V1
1487 # include <shares.h>
1488 #endif /* SHARE_V1 */
1489 
1490 void
1491 init_md(argc, argv)
1492 	int argc;
1493 	char **argv;
1494 {
1495 #ifdef _AUX_SOURCE
1496 	setcompat(getcompat() | COMPAT_BSDPROT);
1497 #endif /* _AUX_SOURCE */
1498 
1499 #ifdef SUN_EXTENSIONS
1500 	init_md_sun();
1501 #endif /* SUN_EXTENSIONS */
1502 
1503 #if _CONVEX_SOURCE
1504 	/* keep gethostby*() from stripping the local domain name */
1505 	set_domain_trim_off();
1506 #endif /* _CONVEX_SOURCE */
1507 #ifdef __QNX__
1508 	/*
1509 	**  Due to QNX's network distributed nature, you can target a tcpip
1510 	**  stack on a different node in the qnx network; this patch lets
1511 	**  this feature work.  The __sock_locate() must be done before the
1512 	**  environment is clear.
1513 	*/
1514 	__sock_locate();
1515 #endif /* __QNX__ */
1516 #if SECUREWARE || defined(_SCO_unix_)
1517 	set_auth_parameters(argc, argv);
1518 
1519 # ifdef _SCO_unix_
1520 	/*
1521 	**  This is required for highest security levels (the kernel
1522 	**  won't let it call set*uid() or run setuid binaries without
1523 	**  it).  It may be necessary on other SECUREWARE systems.
1524 	*/
1525 
1526 	if (getluid() == -1)
1527 		setluid(0);
1528 # endif /* _SCO_unix_ */
1529 #endif /* SECUREWARE || defined(_SCO_unix_) */
1530 
1531 
1532 #ifdef VENDOR_DEFAULT
1533 	VendorCode = VENDOR_DEFAULT;
1534 #else /* VENDOR_DEFAULT */
1535 	VendorCode = VENDOR_BERKELEY;
1536 #endif /* VENDOR_DEFAULT */
1537 }
1538 /*
1539 **  INIT_VENDOR_MACROS -- vendor-dependent macro initializations
1540 **
1541 **	Called once, on startup.
1542 **
1543 **	Parameters:
1544 **		e -- the global envelope.
1545 **
1546 **	Returns:
1547 **		none.
1548 **
1549 **	Side Effects:
1550 **		vendor-dependent.
1551 */
1552 
1553 void
1554 init_vendor_macros(e)
1555 	register ENVELOPE *e;
1556 {
1557 }
1558 /*
1559 **  GETLA -- get the current load average
1560 **
1561 **	This code stolen from la.c.
1562 **
1563 **	Parameters:
1564 **		none.
1565 **
1566 **	Returns:
1567 **		The current load average as an integer.
1568 **
1569 **	Side Effects:
1570 **		none.
1571 */
1572 
1573 /* try to guess what style of load average we have */
1574 #define LA_ZERO		1	/* always return load average as zero */
1575 #define LA_INT		2	/* read kmem for avenrun; interpret as long */
1576 #define LA_FLOAT	3	/* read kmem for avenrun; interpret as float */
1577 #define LA_SUBR		4	/* call getloadavg */
1578 #define LA_MACH		5	/* MACH load averages (as on NeXT boxes) */
1579 #define LA_SHORT	6	/* read kmem for avenrun; interpret as short */
1580 #define LA_PROCSTR	7	/* read string ("1.17") from /proc/loadavg */
1581 #define LA_READKSYM	8	/* SVR4: use MIOC_READKSYM ioctl call */
1582 #define LA_DGUX		9	/* special DGUX implementation */
1583 #define LA_HPUX		10	/* special HPUX implementation */
1584 #define LA_IRIX6	11	/* special IRIX 6.2 implementation */
1585 #define LA_KSTAT	12	/* special Solaris kstat(3k) implementation */
1586 #define LA_DEVSHORT	13	/* read short from a device */
1587 #define LA_ALPHAOSF	14	/* Digital UNIX (OSF/1 on Alpha) table() call */
1588 #define LA_PSET		15	/* Solaris per-processor-set load average */
1589 
1590 /* do guesses based on general OS type */
1591 #ifndef LA_TYPE
1592 # define LA_TYPE	LA_ZERO
1593 #endif /* ! LA_TYPE */
1594 
1595 #ifndef FSHIFT
1596 # if defined(unixpc)
1597 #  define FSHIFT	5
1598 # endif /* defined(unixpc) */
1599 
1600 # if defined(__alpha) || defined(IRIX)
1601 #  define FSHIFT	10
1602 # endif /* defined(__alpha) || defined(IRIX) */
1603 
1604 #endif /* ! FSHIFT */
1605 
1606 #ifndef FSHIFT
1607 # define FSHIFT		8
1608 #endif /* ! FSHIFT */
1609 
1610 #ifndef FSCALE
1611 # define FSCALE		(1 << FSHIFT)
1612 #endif /* ! FSCALE */
1613 
1614 #ifndef LA_AVENRUN
1615 # ifdef SYSTEM5
1616 #  define LA_AVENRUN	"avenrun"
1617 # else /* SYSTEM5 */
1618 #  define LA_AVENRUN	"_avenrun"
1619 # endif /* SYSTEM5 */
1620 #endif /* ! LA_AVENRUN */
1621 
1622 /* _PATH_KMEM should be defined in <paths.h> */
1623 #ifndef _PATH_KMEM
1624 # define _PATH_KMEM	"/dev/kmem"
1625 #endif /* ! _PATH_KMEM */
1626 
1627 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT)
1628 
1629 # include <nlist.h>
1630 
1631 /* _PATH_UNIX should be defined in <paths.h> */
1632 # ifndef _PATH_UNIX
1633 #  if defined(SYSTEM5)
1634 #   define _PATH_UNIX	"/unix"
1635 #  else /* defined(SYSTEM5) */
1636 #   define _PATH_UNIX	"/vmunix"
1637 #  endif /* defined(SYSTEM5) */
1638 # endif /* ! _PATH_UNIX */
1639 
1640 # ifdef _AUX_SOURCE
1641 struct nlist	Nl[2];
1642 # else /* _AUX_SOURCE */
1643 struct nlist	Nl[] =
1644 {
1645 	{ LA_AVENRUN },
1646 	{ 0 },
1647 };
1648 # endif /* _AUX_SOURCE */
1649 # define X_AVENRUN	0
1650 
1651 static int
1652 getla()
1653 {
1654 	static int kmem = -1;
1655 # if LA_TYPE == LA_INT
1656 	long avenrun[3];
1657 # else /* LA_TYPE == LA_INT */
1658 #  if LA_TYPE == LA_SHORT
1659 	short avenrun[3];
1660 #  else /* LA_TYPE == LA_SHORT */
1661 	double avenrun[3];
1662 #  endif /* LA_TYPE == LA_SHORT */
1663 # endif /* LA_TYPE == LA_INT */
1664 	extern int errno;
1665 	extern off_t lseek();
1666 
1667 	if (kmem < 0)
1668 	{
1669 # ifdef _AUX_SOURCE
1670 		(void) strlcpy(Nl[X_AVENRUN].n_name, LA_AVENRUN,
1671 			       sizeof Nl[X_AVENRUN].n_name);
1672 		Nl[1].n_name[0] = '\0';
1673 # endif /* _AUX_SOURCE */
1674 
1675 # if defined(_AIX3) || defined(_AIX4)
1676 		if (knlist(Nl, 1, sizeof Nl[0]) < 0)
1677 # else /* defined(_AIX3) || defined(_AIX4) */
1678 		if (nlist(_PATH_UNIX, Nl) < 0)
1679 # endif /* defined(_AIX3) || defined(_AIX4) */
1680 		{
1681 			if (tTd(3, 1))
1682 				dprintf("getla: nlist(%s): %s\n", _PATH_UNIX,
1683 					errstring(errno));
1684 			return -1;
1685 		}
1686 		if (Nl[X_AVENRUN].n_value == 0)
1687 		{
1688 			if (tTd(3, 1))
1689 				dprintf("getla: nlist(%s, %s) ==> 0\n",
1690 					_PATH_UNIX, LA_AVENRUN);
1691 			return -1;
1692 		}
1693 # ifdef NAMELISTMASK
1694 		Nl[X_AVENRUN].n_value &= NAMELISTMASK;
1695 # endif /* NAMELISTMASK */
1696 
1697 		kmem = open(_PATH_KMEM, 0, 0);
1698 		if (kmem < 0)
1699 		{
1700 			if (tTd(3, 1))
1701 				dprintf("getla: open(/dev/kmem): %s\n",
1702 					errstring(errno));
1703 			return -1;
1704 		}
1705 		(void) fcntl(kmem, F_SETFD, FD_CLOEXEC);
1706 	}
1707 	if (tTd(3, 20))
1708 		dprintf("getla: symbol address = %#lx\n",
1709 			(u_long) Nl[X_AVENRUN].n_value);
1710 	if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, SEEK_SET) == -1 ||
1711 	    read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
1712 	{
1713 		/* thank you Ian */
1714 		if (tTd(3, 1))
1715 			dprintf("getla: lseek or read: %s\n",
1716 				errstring(errno));
1717 		return -1;
1718 	}
1719 # if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)
1720 	if (tTd(3, 5))
1721 	{
1722 #  if LA_TYPE == LA_SHORT
1723 		dprintf("getla: avenrun = %d", avenrun[0]);
1724 		if (tTd(3, 15))
1725 			dprintf(", %d, %d", avenrun[1], avenrun[2]);
1726 #  else /* LA_TYPE == LA_SHORT */
1727 		dprintf("getla: avenrun = %ld", avenrun[0]);
1728 		if (tTd(3, 15))
1729 			dprintf(", %ld, %ld", avenrun[1], avenrun[2]);
1730 #  endif /* LA_TYPE == LA_SHORT */
1731 		dprintf("\n");
1732 	}
1733 	if (tTd(3, 1))
1734 		dprintf("getla: %d\n",
1735 			(int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1736 	return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1737 # else /* (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) */
1738 	if (tTd(3, 5))
1739 	{
1740 		dprintf("getla: avenrun = %g", avenrun[0]);
1741 		if (tTd(3, 15))
1742 			dprintf(", %g, %g", avenrun[1], avenrun[2]);
1743 		dprintf("\n");
1744 	}
1745 	if (tTd(3, 1))
1746 		dprintf("getla: %d\n", (int) (avenrun[0] +0.5));
1747 	return ((int) (avenrun[0] + 0.5));
1748 # endif /* (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) */
1749 }
1750 
1751 #endif /* (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT) */
1752 
1753 #if LA_TYPE == LA_READKSYM
1754 
1755 # include <sys/ksym.h>
1756 
1757 static int
1758 getla()
1759 {
1760 	static int kmem = -1;
1761 	long avenrun[3];
1762 	extern int errno;
1763 	struct mioc_rksym mirk;
1764 
1765 	if (kmem < 0)
1766 	{
1767 		kmem = open("/dev/kmem", 0, 0);
1768 		if (kmem < 0)
1769 		{
1770 			if (tTd(3, 1))
1771 				dprintf("getla: open(/dev/kmem): %s\n",
1772 					errstring(errno));
1773 			return -1;
1774 		}
1775 		(void) fcntl(kmem, F_SETFD, FD_CLOEXEC);
1776 	}
1777 	mirk.mirk_symname = LA_AVENRUN;
1778 	mirk.mirk_buf = avenrun;
1779 	mirk.mirk_buflen = sizeof(avenrun);
1780 	if (ioctl(kmem, MIOC_READKSYM, &mirk) < 0)
1781 	{
1782 		if (tTd(3, 1))
1783 			dprintf("getla: ioctl(MIOC_READKSYM) failed: %s\n",
1784 				errstring(errno));
1785 		return -1;
1786 	}
1787 	if (tTd(3, 5))
1788 	{
1789 		dprintf("getla: avenrun = %d", avenrun[0]);
1790 		if (tTd(3, 15))
1791 			dprintf(", %d, %d", avenrun[1], avenrun[2]);
1792 		dprintf("\n");
1793 	}
1794 	if (tTd(3, 1))
1795 		dprintf("getla: %d\n",
1796 			(int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1797 	return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1798 }
1799 
1800 #endif /* LA_TYPE == LA_READKSYM */
1801 
1802 #if LA_TYPE == LA_DGUX
1803 
1804 # include <sys/dg_sys_info.h>
1805 
1806 static int
1807 getla()
1808 {
1809 	struct dg_sys_info_load_info load_info;
1810 
1811 	dg_sys_info((long *)&load_info,
1812 		DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0);
1813 
1814 	if (tTd(3, 1))
1815 		dprintf("getla: %d\n", (int) (load_info.one_minute + 0.5));
1816 
1817 	return ((int) (load_info.one_minute + 0.5));
1818 }
1819 
1820 #endif /* LA_TYPE == LA_DGUX */
1821 
1822 #if LA_TYPE == LA_HPUX
1823 
1824 /* forward declarations to keep gcc from complaining */
1825 struct pst_dynamic;
1826 struct pst_status;
1827 struct pst_static;
1828 struct pst_vminfo;
1829 struct pst_diskinfo;
1830 struct pst_processor;
1831 struct pst_lv;
1832 struct pst_swapinfo;
1833 
1834 # include <sys/param.h>
1835 # include <sys/pstat.h>
1836 
1837 static int
1838 getla()
1839 {
1840 	struct pst_dynamic pstd;
1841 
1842 	if (pstat_getdynamic(&pstd, sizeof(struct pst_dynamic),
1843 			     (size_t) 1, 0) == -1)
1844 		return 0;
1845 
1846 	if (tTd(3, 1))
1847 		dprintf("getla: %d\n", (int) (pstd.psd_avg_1_min + 0.5));
1848 
1849 	return (int) (pstd.psd_avg_1_min + 0.5);
1850 }
1851 
1852 #endif /* LA_TYPE == LA_HPUX */
1853 
1854 #if LA_TYPE == LA_SUBR
1855 
1856 static int
1857 getla()
1858 {
1859 	double avenrun[3];
1860 
1861 	if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0)
1862 	{
1863 		if (tTd(3, 1))
1864 			dprintf("getla: getloadavg failed: %s",
1865 				errstring(errno));
1866 		return -1;
1867 	}
1868 	if (tTd(3, 1))
1869 		dprintf("getla: %d\n", (int) (avenrun[0] +0.5));
1870 	return ((int) (avenrun[0] + 0.5));
1871 }
1872 
1873 #endif /* LA_TYPE == LA_SUBR */
1874 
1875 #if LA_TYPE == LA_MACH
1876 
1877 /*
1878 **  This has been tested on NEXTSTEP release 2.1/3.X.
1879 */
1880 
1881 # if defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0
1882 #  include <mach/mach.h>
1883 # else /* defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0 */
1884 #  include <mach.h>
1885 # endif /* defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0 */
1886 
1887 static int
1888 getla()
1889 {
1890 	processor_set_t default_set;
1891 	kern_return_t error;
1892 	unsigned int info_count;
1893 	struct processor_set_basic_info info;
1894 	host_t host;
1895 
1896 	error = processor_set_default(host_self(), &default_set);
1897 	if (error != KERN_SUCCESS)
1898 	{
1899 		if (tTd(3, 1))
1900 			dprintf("getla: processor_set_default failed: %s",
1901 				errstring(errno));
1902 		return -1;
1903 	}
1904 	info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
1905 	if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO,
1906 			       &host, (processor_set_info_t)&info,
1907 			       &info_count) != KERN_SUCCESS)
1908 	{
1909 		if (tTd(3, 1))
1910 			dprintf("getla: processor_set_info failed: %s",
1911 				errstring(errno));
1912 		return -1;
1913 	}
1914 	if (tTd(3, 1))
1915 		dprintf("getla: %d\n",
1916 			(int) ((info.load_average + (LOAD_SCALE / 2)) /
1917 			       LOAD_SCALE));
1918 	return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE;
1919 }
1920 
1921 #endif /* LA_TYPE == LA_MACH */
1922 
1923 #if LA_TYPE == LA_PROCSTR
1924 
1925 /*
1926 **  Read /proc/loadavg for the load average.  This is assumed to be
1927 **  in a format like "0.15 0.12 0.06".
1928 **
1929 **	Initially intended for Linux.  This has been in the kernel
1930 **	since at least 0.99.15.
1931 */
1932 
1933 # ifndef _PATH_LOADAVG
1934 #  define _PATH_LOADAVG	"/proc/loadavg"
1935 # endif /* ! _PATH_LOADAVG */
1936 
1937 static int
1938 getla()
1939 {
1940 	double avenrun;
1941 	register int result;
1942 	FILE *fp;
1943 
1944 	fp = fopen(_PATH_LOADAVG, "r");
1945 	if (fp == NULL)
1946 	{
1947 		if (tTd(3, 1))
1948 			dprintf("getla: fopen(%s): %s\n",
1949 				_PATH_LOADAVG, errstring(errno));
1950 		return -1;
1951 	}
1952 	result = fscanf(fp, "%lf", &avenrun);
1953 	(void) fclose(fp);
1954 	if (result != 1)
1955 	{
1956 		if (tTd(3, 1))
1957 			dprintf("getla: fscanf() = %d: %s\n",
1958 				result, errstring(errno));
1959 		return -1;
1960 	}
1961 
1962 	if (tTd(3, 1))
1963 		dprintf("getla(): %.2f\n", avenrun);
1964 
1965 	return ((int) (avenrun + 0.5));
1966 }
1967 
1968 #endif /* LA_TYPE == LA_PROCSTR */
1969 
1970 #if LA_TYPE == LA_IRIX6
1971 
1972 # include <sys/sysmp.h>
1973 
1974 int getla(void)
1975 {
1976 	static int kmem = -1;
1977 	int avenrun[3];
1978 
1979 	if (kmem < 0)
1980 	{
1981 		kmem = open(_PATH_KMEM, 0, 0);
1982 		if (kmem < 0)
1983 		{
1984 			if (tTd(3, 1))
1985 				dprintf("getla: open(%s): %s\n", _PATH_KMEM,
1986 					errstring(errno));
1987 			return -1;
1988 		}
1989 		(void) fcntl(kmem, F_SETFD, FD_CLOEXEC);
1990 	}
1991 
1992 	if (lseek(kmem, (sysmp(MP_KERNADDR, MPKA_AVENRUN) & 0x7fffffff), SEEK_SET) == -1 ||
1993 	    read(kmem, (char *)avenrun, sizeof(avenrun)) < sizeof(avenrun))
1994 	{
1995 		if (tTd(3, 1))
1996 			dprintf("getla: lseek or read: %s\n",
1997 				errstring(errno));
1998 		return -1;
1999 	}
2000 	if (tTd(3, 5))
2001 	{
2002 		dprintf("getla: avenrun = %ld", (long int) avenrun[0]);
2003 		if (tTd(3, 15))
2004 			dprintf(", %ld, %ld",
2005 				(long int) avenrun[1], (long int) avenrun[2]);
2006 		dprintf("\n");
2007 	}
2008 
2009 	if (tTd(3, 1))
2010 		dprintf("getla: %d\n",
2011 			(int) (avenrun[0] + FSCALE/2) >> FSHIFT);
2012 	return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
2013 
2014 }
2015 #endif /* LA_TYPE == LA_IRIX6 */
2016 
2017 #if LA_TYPE == LA_KSTAT
2018 
2019 # include <kstat.h>
2020 
2021 static int
2022 getla()
2023 {
2024 	static kstat_ctl_t *kc = NULL;
2025 	static kstat_t *ksp = NULL;
2026 	kstat_named_t *ksn;
2027 	int la;
2028 
2029 	if (kc == NULL)		/* if not initialized before */
2030 		kc = kstat_open();
2031 	if (kc == NULL)
2032 	{
2033 		if (tTd(3, 1))
2034 			dprintf("getla: kstat_open(): %s\n",
2035 				errstring(errno));
2036 		return -1;
2037 	}
2038 	if (ksp == NULL)
2039 		ksp = kstat_lookup(kc, "unix", 0, "system_misc");
2040 	if (ksp == NULL)
2041 	{
2042 		if (tTd(3, 1))
2043 			dprintf("getla: kstat_lookup(): %s\n",
2044 				errstring(errno));
2045 		return -1;
2046 	}
2047 	if (kstat_read(kc, ksp, NULL) < 0)
2048 	{
2049 		if (tTd(3, 1))
2050 			dprintf("getla: kstat_read(): %s\n",
2051 				errstring(errno));
2052 		return -1;
2053 	}
2054 	ksn = (kstat_named_t *) kstat_data_lookup(ksp, "avenrun_1min");
2055 	la = ((double)ksn->value.ul + FSCALE/2) / FSCALE;
2056 	/* kstat_close(kc); /o do not close for fast access */
2057 	return la;
2058 }
2059 
2060 #endif /* LA_TYPE == LA_KSTAT */
2061 
2062 #if LA_TYPE == LA_DEVSHORT
2063 
2064 /*
2065 **  Read /dev/table/avenrun for the load average.  This should contain
2066 **  three shorts for the 1, 5, and 15 minute loads.  We only read the
2067 **  first, since that's all we care about.
2068 **
2069 **	Intended for SCO OpenServer 5.
2070 */
2071 
2072 # ifndef _PATH_AVENRUN
2073 #  define _PATH_AVENRUN	"/dev/table/avenrun"
2074 # endif /* ! _PATH_AVENRUN */
2075 
2076 static int
2077 getla()
2078 {
2079 	static int afd = -1;
2080 	short avenrun;
2081 	int loadav;
2082 	int r;
2083 
2084 	errno = EBADF;
2085 
2086 	if (afd == -1 || lseek(afd, 0L, SEEK_SET) == -1)
2087 	{
2088 		if (errno != EBADF)
2089 			return -1;
2090 		afd = open(_PATH_AVENRUN, O_RDONLY|O_SYNC);
2091 		if (afd < 0)
2092 		{
2093 			sm_syslog(LOG_ERR, NOQID,
2094 				"can't open %s: %m",
2095 				_PATH_AVENRUN);
2096 			return -1;
2097 		}
2098 	}
2099 
2100 	r = read(afd, &avenrun, sizeof avenrun);
2101 
2102 	if (tTd(3, 5))
2103 		dprintf("getla: avenrun = %d\n", avenrun);
2104 	loadav = (int) (avenrun + FSCALE/2) >> FSHIFT;
2105 	if (tTd(3, 1))
2106 		dprintf("getla: %d\n", loadav);
2107 	return loadav;
2108 }
2109 
2110 #endif /* LA_TYPE == LA_DEVSHORT */
2111 
2112 #if LA_TYPE == LA_ALPHAOSF
2113 struct rtentry;
2114 struct mbuf;
2115 # include <sys/table.h>
2116 
2117 int getla()
2118 {
2119 	int ave = 0;
2120 	struct tbl_loadavg tab;
2121 
2122 	if (table(TBL_LOADAVG, 0, &tab, 1, sizeof(tab)) == -1)
2123 	{
2124 		if (tTd(3, 1))
2125 			dprintf("getla: table %s\n", errstring(errno));
2126 		return -1;
2127 	}
2128 
2129 	if (tTd(3, 1))
2130 		dprintf("getla: scale = %d\n", tab.tl_lscale);
2131 
2132 	if (tab.tl_lscale)
2133 		ave = ((tab.tl_avenrun.l[2] + (tab.tl_lscale/2)) /
2134 		       tab.tl_lscale);
2135 	else
2136 		ave = (int) (tab.tl_avenrun.d[2] + 0.5);
2137 
2138 	if (tTd(3, 1))
2139 		dprintf("getla: %d\n", ave);
2140 
2141 	return ave;
2142 }
2143 
2144 #endif /* LA_TYPE == LA_ALPHAOSF */
2145 
2146 #if LA_TYPE == LA_PSET
2147 
2148 static int
2149 getla()
2150 {
2151 	double avenrun[3];
2152 
2153 	if (pset_getloadavg(PS_MYID, avenrun,
2154 			    sizeof(avenrun) / sizeof(avenrun[0])) < 0)
2155 	{
2156 		if (tTd(3, 1))
2157 			dprintf("getla: pset_getloadavg failed: %s",
2158 				errstring(errno));
2159 		return -1;
2160 	}
2161 	if (tTd(3, 1))
2162 		dprintf("getla: %d\n", (int) (avenrun[0] +0.5));
2163 	return ((int) (avenrun[0] + 0.5));
2164 }
2165 
2166 #endif /* LA_TYPE == LA_PSET */
2167 
2168 #if LA_TYPE == LA_ZERO
2169 
2170 static int
2171 getla()
2172 {
2173 	if (tTd(3, 1))
2174 		dprintf("getla: ZERO\n");
2175 	return 0;
2176 }
2177 
2178 #endif /* LA_TYPE == LA_ZERO */
2179 
2180 /*
2181  * Copyright 1989 Massachusetts Institute of Technology
2182  *
2183  * Permission to use, copy, modify, distribute, and sell this software and its
2184  * documentation for any purpose is hereby granted without fee, provided that
2185  * the above copyright notice appear in all copies and that both that
2186  * copyright notice and this permission notice appear in supporting
2187  * documentation, and that the name of M.I.T. not be used in advertising or
2188  * publicity pertaining to distribution of the software without specific,
2189  * written prior permission.  M.I.T. makes no representations about the
2190  * suitability of this software for any purpose.  It is provided "as is"
2191  * without express or implied warranty.
2192  *
2193  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
2194  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
2195  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2196  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
2197  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
2198  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2199  *
2200  * Authors:  Many and varied...
2201  */
2202 
2203 /* Non Apollo stuff removed by Don Lewis 11/15/93 */
2204 #ifndef lint
2205 static char  rcsid[] = "@(#)$OrigId: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp $";
2206 #endif /* ! lint */
2207 
2208 #ifdef apollo
2209 # undef volatile
2210 # include <apollo/base.h>
2211 
2212 /* ARGSUSED */
2213 int getloadavg( call_data )
2214      caddr_t	call_data;	/* pointer to (double) return value */
2215 {
2216      double *avenrun = (double *) call_data;
2217      int i;
2218      status_$t      st;
2219      long loadav[3];
2220      proc1_$get_loadav(loadav, &st);
2221      *avenrun = loadav[0] / (double) (1 << 16);
2222      return 0;
2223 }
2224 #endif /* apollo */
2225 /*
2226 **  SM_GETLA -- get the current load average and set macro
2227 **
2228 **	Parameters:
2229 **		e -- the envelope for the load average macro.
2230 **
2231 **	Returns:
2232 **		The current load average as an integer.
2233 **
2234 **	Side Effects:
2235 **		Sets the load average macro ({load_avg}) if
2236 **		envelope e is not NULL.
2237 */
2238 
2239 int
2240 sm_getla(e)
2241 	ENVELOPE *e;
2242 {
2243 	register int la;
2244 
2245 	la = getla();
2246 	if (e != NULL)
2247 	{
2248 		char labuf[8];
2249 
2250 		snprintf(labuf, sizeof labuf, "%d", la);
2251 		define(macid("{load_avg}", NULL), newstr(labuf), e);
2252 	}
2253 	return la;
2254 }
2255 
2256 /*
2257 **  SHOULDQUEUE -- should this message be queued or sent?
2258 **
2259 **	Compares the message cost to the load average to decide.
2260 **
2261 **	Parameters:
2262 **		pri -- the priority of the message in question.
2263 **		ct -- the message creation time.
2264 **
2265 **	Returns:
2266 **		TRUE -- if this message should be queued up for the
2267 **			time being.
2268 **		FALSE -- if the load is low enough to send this message.
2269 **
2270 **	Side Effects:
2271 **		none.
2272 */
2273 
2274 /* ARGSUSED1 */
2275 bool
2276 shouldqueue(pri, ct)
2277 	long pri;
2278 	time_t ct;
2279 {
2280 	bool rval;
2281 
2282 	if (tTd(3, 30))
2283 		dprintf("shouldqueue: CurrentLA=%d, pri=%ld: ",
2284 			CurrentLA, pri);
2285 	if (CurrentLA < QueueLA)
2286 	{
2287 		if (tTd(3, 30))
2288 			dprintf("FALSE (CurrentLA < QueueLA)\n");
2289 		return FALSE;
2290 	}
2291 #if 0	/* this code is reported to cause oscillation around RefuseLA */
2292 	if (CurrentLA >= RefuseLA && QueueLA < RefuseLA)
2293 	{
2294 		if (tTd(3, 30))
2295 			dprintf("TRUE (CurrentLA >= RefuseLA)\n");
2296 		return TRUE;
2297 	}
2298 #endif /* 0 */
2299 	rval = pri > (QueueFactor / (CurrentLA - QueueLA + 1));
2300 	if (tTd(3, 30))
2301 		dprintf("%s (by calculation)\n", rval ? "TRUE" : "FALSE");
2302 	return rval;
2303 }
2304 /*
2305 **  REFUSECONNECTIONS -- decide if connections should be refused
2306 **
2307 **	Parameters:
2308 **		name -- daemon name (for error messages only)
2309 **		e -- the current envelope.
2310 **		d -- number of daemon
2311 **
2312 **	Returns:
2313 **		TRUE if incoming SMTP connections should be refused
2314 **			(for now).
2315 **		FALSE if we should accept new work.
2316 **
2317 **	Side Effects:
2318 **		Sets process title when it is rejecting connections.
2319 */
2320 
2321 bool
2322 refuseconnections(name, e, d)
2323 	char *name;
2324 	ENVELOPE *e;
2325 	int d;
2326 {
2327 #ifdef XLA
2328 	if (!xla_smtp_ok())
2329 		return TRUE;
2330 #endif /* XLA */
2331 
2332 	CurrentLA = sm_getla(NULL);
2333 	if (RefuseLA > 0 && CurrentLA >= RefuseLA)
2334 	{
2335 		sm_setproctitle(TRUE, e, "rejecting connections on daemon %s: load average: %d",
2336 				name, CurrentLA);
2337 		if (LogLevel >= 9)
2338 			sm_syslog(LOG_INFO, NOQID,
2339 				"rejecting connections on daemon %s: load average: %d",
2340 				name, CurrentLA);
2341 		return TRUE;
2342 	}
2343 
2344 	if (MaxChildren > 0 && CurChildren >= MaxChildren)
2345 	{
2346 		proc_list_probe();
2347 		if (CurChildren >= MaxChildren)
2348 		{
2349 			sm_setproctitle(TRUE, e, "rejecting connections on daemon %s: %d children, max %d",
2350 					name, CurChildren, MaxChildren);
2351 			if (LogLevel >= 9)
2352 				sm_syslog(LOG_INFO, NOQID,
2353 					"rejecting connections on daemon %s: %d children, max %d",
2354 					name, CurChildren, MaxChildren);
2355 			return TRUE;
2356 		}
2357 	}
2358 
2359 	return FALSE;
2360 }
2361 /*
2362 **  SETPROCTITLE -- set process title for ps
2363 **
2364 **	Parameters:
2365 **		fmt -- a printf style format string.
2366 **		a, b, c -- possible parameters to fmt.
2367 **
2368 **	Returns:
2369 **		none.
2370 **
2371 **	Side Effects:
2372 **		Clobbers argv of our main procedure so ps(1) will
2373 **		display the title.
2374 */
2375 
2376 #define SPT_NONE	0	/* don't use it at all */
2377 #define SPT_REUSEARGV	1	/* cover argv with title information */
2378 #define SPT_BUILTIN	2	/* use libc builtin */
2379 #define SPT_PSTAT	3	/* use pstat(PSTAT_SETCMD, ...) */
2380 #define SPT_PSSTRINGS	4	/* use PS_STRINGS->... */
2381 #define SPT_SYSMIPS	5	/* use sysmips() supported by NEWS-OS 6 */
2382 #define SPT_SCO		6	/* write kernel u. area */
2383 #define SPT_CHANGEARGV	7	/* write our own strings into argv[] */
2384 
2385 #ifndef SPT_TYPE
2386 # define SPT_TYPE	SPT_REUSEARGV
2387 #endif /* ! SPT_TYPE */
2388 
2389 
2390 #if SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN
2391 
2392 # if SPT_TYPE == SPT_PSTAT
2393 #  include <sys/pstat.h>
2394 # endif /* SPT_TYPE == SPT_PSTAT */
2395 # if SPT_TYPE == SPT_PSSTRINGS
2396 #  include <machine/vmparam.h>
2397 #  include <sys/exec.h>
2398 #  ifndef PS_STRINGS	/* hmmmm....  apparently not available after all */
2399 #   undef SPT_TYPE
2400 #   define SPT_TYPE	SPT_REUSEARGV
2401 #  else /* ! PS_STRINGS */
2402 #   ifndef NKPDE			/* FreeBSD 2.0 */
2403 #    define NKPDE 63
2404 typedef unsigned int	*pt_entry_t;
2405 #   endif /* ! NKPDE */
2406 #  endif /* ! PS_STRINGS */
2407 # endif /* SPT_TYPE == SPT_PSSTRINGS */
2408 
2409 # if SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV
2410 #  define SETPROC_STATIC	static
2411 # else /* SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV */
2412 #  define SETPROC_STATIC
2413 # endif /* SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV */
2414 
2415 # if SPT_TYPE == SPT_SYSMIPS
2416 #  include <sys/sysmips.h>
2417 #  include <sys/sysnews.h>
2418 # endif /* SPT_TYPE == SPT_SYSMIPS */
2419 
2420 # if SPT_TYPE == SPT_SCO
2421 #  include <sys/immu.h>
2422 #  include <sys/dir.h>
2423 #  include <sys/user.h>
2424 #  include <sys/fs/s5param.h>
2425 #  if PSARGSZ > MAXLINE
2426 #   define SPT_BUFSIZE	PSARGSZ
2427 #  endif /* PSARGSZ > MAXLINE */
2428 # endif /* SPT_TYPE == SPT_SCO */
2429 
2430 # ifndef SPT_PADCHAR
2431 #  define SPT_PADCHAR	' '
2432 # endif /* ! SPT_PADCHAR */
2433 
2434 #endif /* SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN */
2435 
2436 #ifndef SPT_BUFSIZE
2437 # define SPT_BUFSIZE	MAXLINE
2438 #endif /* ! SPT_BUFSIZE */
2439 
2440 /*
2441 **  Pointers for setproctitle.
2442 **	This allows "ps" listings to give more useful information.
2443 */
2444 
2445 static char	**Argv = NULL;		/* pointer to argument vector */
2446 static char	*LastArgv = NULL;	/* end of argv */
2447 #if SPT_TYPE != SPT_BUILTIN
2448 static void	setproctitle __P((const char *, ...));
2449 #endif /* SPT_TYPE != SPT_BUILTIN */
2450 
2451 void
2452 initsetproctitle(argc, argv, envp)
2453 	int argc;
2454 	char **argv;
2455 	char **envp;
2456 {
2457 	register int i, envpsize = 0;
2458 	extern char **environ;
2459 
2460 	/*
2461 	**  Move the environment so setproctitle can use the space at
2462 	**  the top of memory.
2463 	*/
2464 
2465 	for (i = 0; envp[i] != NULL; i++)
2466 		envpsize += strlen(envp[i]) + 1;
2467 	environ = (char **) xalloc(sizeof (char *) * (i + 1));
2468 	for (i = 0; envp[i] != NULL; i++)
2469 		environ[i] = newstr(envp[i]);
2470 	environ[i] = NULL;
2471 
2472 	/*
2473 	**  Save start and extent of argv for setproctitle.
2474 	*/
2475 
2476 	Argv = argv;
2477 
2478 	/*
2479 	**  Determine how much space we can use for setproctitle.
2480 	**  Use all contiguous argv and envp pointers starting at argv[0]
2481 	*/
2482 	for (i = 0; i < argc; i++)
2483 	{
2484 		if (i == 0 || LastArgv + 1 == argv[i])
2485 			LastArgv = argv[i] + strlen(argv[i]);
2486 	}
2487 	for (i = 0; LastArgv != NULL && envp[i] != NULL; i++)
2488 	{
2489 		if (LastArgv + 1 == envp[i])
2490 			LastArgv = envp[i] + strlen(envp[i]);
2491 	}
2492 }
2493 
2494 #if SPT_TYPE != SPT_BUILTIN
2495 
2496 /*VARARGS1*/
2497 static void
2498 # ifdef __STDC__
2499 setproctitle(const char *fmt, ...)
2500 # else /* __STDC__ */
2501 setproctitle(fmt, va_alist)
2502 	const char *fmt;
2503 	va_dcl
2504 # endif /* __STDC__ */
2505 {
2506 # if SPT_TYPE != SPT_NONE
2507 	register int i;
2508 	register char *p;
2509 	SETPROC_STATIC char buf[SPT_BUFSIZE];
2510 	VA_LOCAL_DECL
2511 #  if SPT_TYPE == SPT_PSTAT
2512 	union pstun pst;
2513 #  endif /* SPT_TYPE == SPT_PSTAT */
2514 #  if SPT_TYPE == SPT_SCO
2515 	off_t seek_off;
2516 	static int kmem = -1;
2517 	static pid_t kmempid = -1;
2518 	struct user u;
2519 #  endif /* SPT_TYPE == SPT_SCO */
2520 
2521 	p = buf;
2522 
2523 	/* print sendmail: heading for grep */
2524 	(void) strlcpy(p, "sendmail: ", SPACELEFT(buf, p));
2525 	p += strlen(p);
2526 
2527 	/* print the argument string */
2528 	VA_START(fmt);
2529 	(void) vsnprintf(p, SPACELEFT(buf, p), fmt, ap);
2530 	VA_END;
2531 
2532 	i = strlen(buf);
2533 
2534 #  if SPT_TYPE == SPT_PSTAT
2535 	pst.pst_command = buf;
2536 	pstat(PSTAT_SETCMD, pst, i, 0, 0);
2537 #  endif /* SPT_TYPE == SPT_PSTAT */
2538 #  if SPT_TYPE == SPT_PSSTRINGS
2539 	PS_STRINGS->ps_nargvstr = 1;
2540 	PS_STRINGS->ps_argvstr = buf;
2541 #  endif /* SPT_TYPE == SPT_PSSTRINGS */
2542 #  if SPT_TYPE == SPT_SYSMIPS
2543 	sysmips(SONY_SYSNEWS, NEWS_SETPSARGS, buf);
2544 #  endif /* SPT_TYPE == SPT_SYSMIPS */
2545 #  if SPT_TYPE == SPT_SCO
2546 	if (kmem < 0 || kmempid != getpid())
2547 	{
2548 		if (kmem >= 0)
2549 			(void) close(kmem);
2550 		kmem = open(_PATH_KMEM, O_RDWR, 0);
2551 		if (kmem < 0)
2552 			return;
2553 		(void) fcntl(kmem, F_SETFD, FD_CLOEXEC);
2554 		kmempid = getpid();
2555 	}
2556 	buf[PSARGSZ - 1] = '\0';
2557 	seek_off = UVUBLK + (off_t) u.u_psargs - (off_t) &u;
2558 	if (lseek(kmem, (off_t) seek_off, SEEK_SET) == seek_off)
2559 		(void) write(kmem, buf, PSARGSZ);
2560 #  endif /* SPT_TYPE == SPT_SCO */
2561 #  if SPT_TYPE == SPT_REUSEARGV
2562 	if (LastArgv == NULL)
2563 		return;
2564 
2565 	if (i > LastArgv - Argv[0] - 2)
2566 	{
2567 		i = LastArgv - Argv[0] - 2;
2568 		buf[i] = '\0';
2569 	}
2570 	(void) strlcpy(Argv[0], buf, i + 1);
2571 	p = &Argv[0][i];
2572 	while (p < LastArgv)
2573 		*p++ = SPT_PADCHAR;
2574 	Argv[1] = NULL;
2575 #  endif /* SPT_TYPE == SPT_REUSEARGV */
2576 #  if SPT_TYPE == SPT_CHANGEARGV
2577 	Argv[0] = buf;
2578 	Argv[1] = 0;
2579 #  endif /* SPT_TYPE == SPT_CHANGEARGV */
2580 # endif /* SPT_TYPE != SPT_NONE */
2581 }
2582 
2583 #endif /* SPT_TYPE != SPT_BUILTIN */
2584 /*
2585 **  SM_SETPROCTITLE -- set process task and set process title for ps
2586 **
2587 **	Possibly set process status and call setproctitle() to
2588 **	change the ps display.
2589 **
2590 **	Parameters:
2591 **		status -- whether or not to store as process status
2592 **		e -- the current envelope.
2593 **		fmt -- a printf style format string.
2594 **		a, b, c -- possible parameters to fmt.
2595 **
2596 **	Returns:
2597 **		none.
2598 */
2599 
2600 /*VARARGS2*/
2601 void
2602 #ifdef __STDC__
2603 sm_setproctitle(bool status, ENVELOPE *e, const char *fmt, ...)
2604 #else /* __STDC__ */
2605 sm_setproctitle(status, e, fmt, va_alist)
2606 	bool status;
2607 	ENVELOPE *e;
2608 	const char *fmt;
2609 	va_dcl
2610 #endif /* __STDC__ */
2611 {
2612 	char buf[SPT_BUFSIZE];
2613 	VA_LOCAL_DECL
2614 
2615 	/* print the argument string */
2616 	VA_START(fmt);
2617 	(void) vsnprintf(buf, sizeof buf, fmt, ap);
2618 	VA_END;
2619 
2620 	if (status)
2621 		proc_list_set(getpid(), buf);
2622 
2623 	if (ProcTitlePrefix != NULL)
2624 	{
2625 		char prefix[SPT_BUFSIZE];
2626 
2627 		expand(ProcTitlePrefix, prefix, sizeof prefix, e);
2628 		setproctitle("%s: %s", prefix, buf);
2629 	}
2630 	else
2631 		setproctitle("%s", buf);
2632 }
2633 /*
2634 **  WAITFOR -- wait for a particular process id.
2635 **
2636 **	Parameters:
2637 **		pid -- process id to wait for.
2638 **
2639 **	Returns:
2640 **		status of pid.
2641 **		-1 if pid never shows up.
2642 **
2643 **	Side Effects:
2644 **		none.
2645 */
2646 
2647 int
2648 waitfor(pid)
2649 	pid_t pid;
2650 {
2651 # ifdef WAITUNION
2652 	union wait st;
2653 # else /* WAITUNION */
2654 	auto int st;
2655 # endif /* WAITUNION */
2656 	pid_t i;
2657 # if defined(ISC_UNIX) || defined(_SCO_unix_)
2658 	int savesig;
2659 # endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */
2660 
2661 	do
2662 	{
2663 		errno = 0;
2664 # if defined(ISC_UNIX) || defined(_SCO_unix_)
2665 		savesig = releasesignal(SIGCHLD);
2666 # endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */
2667 		i = wait(&st);
2668 # if defined(ISC_UNIX) || defined(_SCO_unix_)
2669 		if (savesig > 0)
2670 			blocksignal(SIGCHLD);
2671 # endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */
2672 		if (i > 0)
2673 			(void) proc_list_drop(i);
2674 	} while ((i >= 0 || errno == EINTR) && i != pid);
2675 	if (i < 0)
2676 		return -1;
2677 # ifdef WAITUNION
2678 	return st.w_status;
2679 # else /* WAITUNION */
2680 	return st;
2681 # endif /* WAITUNION */
2682 }
2683 /*
2684 **  REAPCHILD -- pick up the body of my child, lest it become a zombie
2685 **
2686 **	Parameters:
2687 **		sig -- the signal that got us here (unused).
2688 **
2689 **	Returns:
2690 **		none.
2691 **
2692 **	Side Effects:
2693 **		Picks up extant zombies.
2694 **		Control socket exits may restart/shutdown daemon.
2695 **
2696 **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
2697 **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
2698 **		DOING.
2699 */
2700 
2701 /* ARGSUSED0 */
2702 SIGFUNC_DECL
2703 reapchild(sig)
2704 	int sig;
2705 {
2706 	int save_errno = errno;
2707 	int st;
2708 	pid_t pid;
2709 # if HASWAITPID
2710 	auto int status;
2711 	int count;
2712 # else /* HASWAITPID */
2713 #  ifdef WNOHANG
2714 	union wait status;
2715 #  else /* WNOHANG */
2716 	auto int status;
2717 #  endif /* WNOHANG */
2718 # endif /* HASWAITPID */
2719 
2720 # if HASWAITPID
2721 	count = 0;
2722 	while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
2723 	{
2724 		st = status;
2725 		if (count++ > 1000)
2726 			break;
2727 # else /* HASWAITPID */
2728 #  ifdef WNOHANG
2729 	while ((pid = wait3(&status, WNOHANG, (struct rusage *) NULL)) > 0)
2730 	{
2731 		st = status.w_status;
2732 #  else /* WNOHANG */
2733 	/*
2734 	**  Catch one zombie -- we will be re-invoked (we hope) if there
2735 	**  are more.  Unreliable signals probably break this, but this
2736 	**  is the "old system" situation -- waitpid or wait3 are to be
2737 	**  strongly preferred.
2738 	*/
2739 
2740 	if ((pid = wait(&status)) > 0)
2741 	{
2742 		st = status;
2743 #  endif /* WNOHANG */
2744 # endif /* HASWAITPID */
2745 		/* Drop PID and check if it was a control socket child */
2746 		if (proc_list_drop(pid) == PROC_CONTROL &&
2747 		    WIFEXITED(st))
2748 		{
2749 			/* if so, see if we need to restart or shutdown */
2750 			if (WEXITSTATUS(st) == EX_RESTART)
2751 			{
2752 				RestartRequest = "control socket";
2753 			}
2754 			else if (WEXITSTATUS(st) == EX_SHUTDOWN)
2755 			{
2756 				/* emulate a SIGTERM shutdown */
2757 				ShutdownRequest = "control socket";
2758 				/* NOTREACHED */
2759 			}
2760 		}
2761 	}
2762 	FIX_SYSV_SIGNAL(sig, reapchild);
2763 	errno = save_errno;
2764 	return SIGFUNC_RETURN;
2765 }
2766 /*
2767 **  PUTENV -- emulation of putenv() in terms of setenv()
2768 **
2769 **	Not needed on Posix-compliant systems.
2770 **	This doesn't have full Posix semantics, but it's good enough
2771 **		for sendmail.
2772 **
2773 **	Parameter:
2774 **		env -- the environment to put.
2775 **
2776 **	Returns:
2777 **		none.
2778 */
2779 
2780 #if NEEDPUTENV
2781 
2782 # if NEEDPUTENV == 2		/* no setenv(3) call available */
2783 
2784 int
2785 putenv(str)
2786 	char *str;
2787 {
2788 	char **current;
2789 	int matchlen, envlen = 0;
2790 	char *tmp;
2791 	char **newenv;
2792 	static bool first = TRUE;
2793 	extern char **environ;
2794 
2795 	/*
2796 	 * find out how much of str to match when searching
2797 	 * for a string to replace.
2798 	 */
2799 	if ((tmp = strchr(str, '=')) == NULL || tmp == str)
2800 		matchlen = strlen(str);
2801 	else
2802 		matchlen = (int) (tmp - str);
2803 	++matchlen;
2804 
2805 	/*
2806 	 * Search for an existing string in the environment and find the
2807 	 * length of environ.  If found, replace and exit.
2808 	 */
2809 	for (current = environ; *current; current++)
2810 	{
2811 		++envlen;
2812 
2813 		if (strncmp(str, *current, matchlen) == 0)
2814 		{
2815 			/* found it, now insert the new version */
2816 			*current = (char *)str;
2817 			return 0;
2818 		}
2819 	}
2820 
2821 	/*
2822 	 * There wasn't already a slot so add space for a new slot.
2823 	 * If this is our first time through, use malloc(), else realloc().
2824 	 */
2825 	if (first)
2826 	{
2827 		newenv = (char **) xalloc(sizeof(char *) * (envlen + 2));
2828 		first = FALSE;
2829 		(void) memcpy(newenv, environ, sizeof(char *) * envlen);
2830 	}
2831 	else
2832 	{
2833 		newenv = (char **) xrealloc((char *)environ,
2834 					    sizeof(char *) * (envlen + 2));
2835 	}
2836 
2837 	/* actually add in the new entry */
2838 	environ = newenv;
2839 	environ[envlen] = (char *)str;
2840 	environ[envlen + 1] = NULL;
2841 
2842 	return 0;
2843 }
2844 
2845 # else /* NEEDPUTENV == 2 */
2846 
2847 int
2848 putenv(env)
2849 	char *env;
2850 {
2851 	char *p;
2852 	int l;
2853 	char nbuf[100];
2854 
2855 	p = strchr(env, '=');
2856 	if (p == NULL)
2857 		return 0;
2858 	l = p - env;
2859 	if (l > sizeof nbuf - 1)
2860 		l = sizeof nbuf - 1;
2861 	memmove(nbuf, env, l);
2862 	nbuf[l] = '\0';
2863 	return setenv(nbuf, ++p, 1);
2864 }
2865 
2866 # endif /* NEEDPUTENV == 2 */
2867 #endif /* NEEDPUTENV */
2868 /*
2869 **  UNSETENV -- remove a variable from the environment
2870 **
2871 **	Not needed on newer systems.
2872 **
2873 **	Parameters:
2874 **		name -- the string name of the environment variable to be
2875 **			deleted from the current environment.
2876 **
2877 **	Returns:
2878 **		none.
2879 **
2880 **	Globals:
2881 **		environ -- a pointer to the current environment.
2882 **
2883 **	Side Effects:
2884 **		Modifies environ.
2885 */
2886 
2887 #if !HASUNSETENV
2888 
2889 void
2890 unsetenv(name)
2891 	char *name;
2892 {
2893 	extern char **environ;
2894 	register char **pp;
2895 	int len = strlen(name);
2896 
2897 	for (pp = environ; *pp != NULL; pp++)
2898 	{
2899 		if (strncmp(name, *pp, len) == 0 &&
2900 		    ((*pp)[len] == '=' || (*pp)[len] == '\0'))
2901 			break;
2902 	}
2903 
2904 	for (; *pp != NULL; pp++)
2905 		*pp = pp[1];
2906 }
2907 
2908 #endif /* !HASUNSETENV */
2909 /*
2910 **  GETDTABLESIZE -- return number of file descriptors
2911 **
2912 **	Only on non-BSD systems
2913 **
2914 **	Parameters:
2915 **		none
2916 **
2917 **	Returns:
2918 **		size of file descriptor table
2919 **
2920 **	Side Effects:
2921 **		none
2922 */
2923 
2924 #ifdef SOLARIS
2925 # include <sys/resource.h>
2926 #endif /* SOLARIS */
2927 
2928 int
2929 getdtsize()
2930 {
2931 # ifdef RLIMIT_NOFILE
2932 	struct rlimit rl;
2933 
2934 	if (getrlimit(RLIMIT_NOFILE, &rl) >= 0)
2935 		return rl.rlim_cur;
2936 # endif /* RLIMIT_NOFILE */
2937 
2938 # if HASGETDTABLESIZE
2939 	return getdtablesize();
2940 # else /* HASGETDTABLESIZE */
2941 #  ifdef _SC_OPEN_MAX
2942 	return sysconf(_SC_OPEN_MAX);
2943 #  else /* _SC_OPEN_MAX */
2944 	return NOFILE;
2945 #  endif /* _SC_OPEN_MAX */
2946 # endif /* HASGETDTABLESIZE */
2947 }
2948 /*
2949 **  UNAME -- get the UUCP name of this system.
2950 */
2951 
2952 #if !HASUNAME
2953 
2954 int
2955 uname(name)
2956 	struct utsname *name;
2957 {
2958 	FILE *file;
2959 	char *n;
2960 
2961 	name->nodename[0] = '\0';
2962 
2963 	/* try /etc/whoami -- one line with the node name */
2964 	if ((file = fopen("/etc/whoami", "r")) != NULL)
2965 	{
2966 		(void) fgets(name->nodename, NODE_LENGTH + 1, file);
2967 		(void) fclose(file);
2968 		n = strchr(name->nodename, '\n');
2969 		if (n != NULL)
2970 			*n = '\0';
2971 		if (name->nodename[0] != '\0')
2972 			return 0;
2973 	}
2974 
2975 	/* try /usr/include/whoami.h -- has a #define somewhere */
2976 	if ((file = fopen("/usr/include/whoami.h", "r")) != NULL)
2977 	{
2978 		char buf[MAXLINE];
2979 
2980 		while (fgets(buf, MAXLINE, file) != NULL)
2981 		{
2982 			if (sscanf(buf, "#define sysname \"%*[^\"]\"",
2983 					NODE_LENGTH, name->nodename) > 0)
2984 				break;
2985 		}
2986 		(void) fclose(file);
2987 		if (name->nodename[0] != '\0')
2988 			return 0;
2989 	}
2990 
2991 #  if 0
2992 	/*
2993 	**  Popen is known to have security holes.
2994 	*/
2995 
2996 	/* try uuname -l to return local name */
2997 	if ((file = popen("uuname -l", "r")) != NULL)
2998 	{
2999 		(void) fgets(name, NODE_LENGTH + 1, file);
3000 		(void) pclose(file);
3001 		n = strchr(name, '\n');
3002 		if (n != NULL)
3003 			*n = '\0';
3004 		if (name->nodename[0] != '\0')
3005 			return 0;
3006 	}
3007 #  endif /* 0 */
3008 
3009 	return -1;
3010 }
3011 #endif /* !HASUNAME */
3012 /*
3013 **  INITGROUPS -- initialize groups
3014 **
3015 **	Stub implementation for System V style systems
3016 */
3017 
3018 #if !HASINITGROUPS
3019 
3020 initgroups(name, basegid)
3021 	char *name;
3022 	int basegid;
3023 {
3024 	return 0;
3025 }
3026 
3027 #endif /* !HASINITGROUPS */
3028 /*
3029 **  SETGROUPS -- set group list
3030 **
3031 **	Stub implementation for systems that don't have group lists
3032 */
3033 
3034 #ifndef NGROUPS_MAX
3035 
3036 int
3037 setgroups(ngroups, grouplist)
3038 	int ngroups;
3039 	GIDSET_T grouplist[];
3040 {
3041 	return 0;
3042 }
3043 
3044 #endif /* ! NGROUPS_MAX */
3045 /*
3046 **  SETSID -- set session id (for non-POSIX systems)
3047 */
3048 
3049 #if !HASSETSID
3050 
3051 pid_t
3052 setsid __P ((void))
3053 {
3054 #  ifdef TIOCNOTTY
3055 	int fd;
3056 
3057 	fd = open("/dev/tty", O_RDWR, 0);
3058 	if (fd >= 0)
3059 	{
3060 		(void) ioctl(fd, TIOCNOTTY, (char *) 0);
3061 		(void) close(fd);
3062 	}
3063 #  endif /* TIOCNOTTY */
3064 #  ifdef SYS5SETPGRP
3065 	return setpgrp();
3066 #  else /* SYS5SETPGRP */
3067 	return setpgid(0, getpid());
3068 #  endif /* SYS5SETPGRP */
3069 }
3070 
3071 #endif /* !HASSETSID */
3072 /*
3073 **  FSYNC -- dummy fsync
3074 */
3075 
3076 #if NEEDFSYNC
3077 
3078 fsync(fd)
3079 	int fd;
3080 {
3081 # ifdef O_SYNC
3082 	return fcntl(fd, F_SETFL, O_SYNC);
3083 # else /* O_SYNC */
3084 	/* nothing we can do */
3085 	return 0;
3086 # endif /* O_SYNC */
3087 }
3088 
3089 #endif /* NEEDFSYNC */
3090 /*
3091 **  DGUX_INET_ADDR -- inet_addr for DG/UX
3092 **
3093 **	Data General DG/UX version of inet_addr returns a struct in_addr
3094 **	instead of a long.  This patches things.  Only needed on versions
3095 **	prior to 5.4.3.
3096 */
3097 
3098 #ifdef DGUX_5_4_2
3099 
3100 # undef inet_addr
3101 
3102 long
3103 dgux_inet_addr(host)
3104 	char *host;
3105 {
3106 	struct in_addr haddr;
3107 
3108 	haddr = inet_addr(host);
3109 	return haddr.s_addr;
3110 }
3111 
3112 #endif /* DGUX_5_4_2 */
3113 /*
3114 **  GETOPT -- for old systems or systems with bogus implementations
3115 */
3116 
3117 #if NEEDGETOPT
3118 
3119 /*
3120  * Copyright (c) 1985 Regents of the University of California.
3121  * All rights reserved.  The Berkeley software License Agreement
3122  * specifies the terms and conditions for redistribution.
3123  */
3124 
3125 
3126 /*
3127 **  this version hacked to add `atend' flag to allow state machine
3128 **  to reset if invoked by the program to scan args for a 2nd time
3129 */
3130 
3131 # if defined(LIBC_SCCS) && !defined(lint)
3132 static char sccsid[] = "@(#)getopt.c	4.3 (Berkeley) 3/9/86";
3133 # endif /* defined(LIBC_SCCS) && !defined(lint) */
3134 
3135 /*
3136  * get option letter from argument vector
3137  */
3138 # ifdef _CONVEX_SOURCE
3139 extern int	optind, opterr, optopt;
3140 extern char	*optarg;
3141 # else /* _CONVEX_SOURCE */
3142 int	opterr = 1;		/* if error message should be printed */
3143 int	optind = 1;		/* index into parent argv vector */
3144 int	optopt = 0;		/* character checked for validity */
3145 char	*optarg = NULL;		/* argument associated with option */
3146 # endif /* _CONVEX_SOURCE */
3147 
3148 # define BADCH	(int)'?'
3149 # define EMSG	""
3150 # define tell(s)	if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \
3151 			fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}
3152 
3153 int
3154 getopt(nargc,nargv,ostr)
3155 	int		nargc;
3156 	char *const	*nargv;
3157 	const char	*ostr;
3158 {
3159 	static char	*place = EMSG;	/* option letter processing */
3160 	static char	atend = 0;
3161 	register char	*oli = NULL;	/* option letter list index */
3162 
3163 	if (atend) {
3164 		atend = 0;
3165 		place = EMSG;
3166 	}
3167 	if(!*place) {			/* update scanning pointer */
3168 		if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) {
3169 			atend++;
3170 			return -1;
3171 		}
3172 		if (*place == '-') {	/* found "--" */
3173 			++optind;
3174 			atend++;
3175 			return -1;
3176 		}
3177 	}				/* option letter okay? */
3178 	if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) {
3179 		if (!*place) ++optind;
3180 		tell(": illegal option -- ");
3181 	}
3182 	if (oli && *++oli != ':') {		/* don't need argument */
3183 		optarg = NULL;
3184 		if (!*place) ++optind;
3185 	}
3186 	else {				/* need an argument */
3187 		if (*place) optarg = place;	/* no white space */
3188 		else if (nargc <= ++optind) {	/* no arg */
3189 			place = EMSG;
3190 			tell(": option requires an argument -- ");
3191 		}
3192 		else optarg = nargv[optind];	/* white space */
3193 		place = EMSG;
3194 		++optind;
3195 	}
3196 	return(optopt);			/* dump back option letter */
3197 }
3198 
3199 #endif /* NEEDGETOPT */
3200 /*
3201 **  VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version
3202 */
3203 
3204 #if NEEDVPRINTF
3205 
3206 # define MAXARG	16
3207 
3208 vfprintf(fp, fmt, ap)
3209 	FILE *fp;
3210 	char *fmt;
3211 	char **ap;
3212 {
3213 	char *bp[MAXARG];
3214 	int i = 0;
3215 
3216 	while (*ap && i < MAXARG)
3217 		bp[i++] = *ap++;
3218 	fprintf(fp, fmt, bp[0], bp[1], bp[2], bp[3],
3219 			 bp[4], bp[5], bp[6], bp[7],
3220 			 bp[8], bp[9], bp[10], bp[11],
3221 			 bp[12], bp[13], bp[14], bp[15]);
3222 }
3223 
3224 vsprintf(s, fmt, ap)
3225 	char *s;
3226 	char *fmt;
3227 	char **ap;
3228 {
3229 	char *bp[MAXARG];
3230 	int i = 0;
3231 
3232 	while (*ap && i < MAXARG)
3233 		bp[i++] = *ap++;
3234 	sprintf(s, fmt, bp[0], bp[1], bp[2], bp[3],
3235 			bp[4], bp[5], bp[6], bp[7],
3236 			bp[8], bp[9], bp[10], bp[11],
3237 			bp[12], bp[13], bp[14], bp[15]);
3238 }
3239 
3240 #endif /* NEEDVPRINTF */
3241 /*
3242 **  USERSHELLOK -- tell if a user's shell is ok for unrestricted use
3243 **
3244 **	Parameters:
3245 **		user -- the name of the user we are checking.
3246 **		shell -- the user's shell from /etc/passwd
3247 **
3248 **	Returns:
3249 **		TRUE -- if it is ok to use this for unrestricted access.
3250 **		FALSE -- if the shell is restricted.
3251 */
3252 
3253 #if !HASGETUSERSHELL
3254 
3255 # ifndef _PATH_SHELLS
3256 #  define _PATH_SHELLS	"/etc/shells"
3257 # endif /* ! _PATH_SHELLS */
3258 
3259 # if defined(_AIX3) || defined(_AIX4)
3260 #  include <userconf.h>
3261 #  if _AIX4 >= 40200
3262 #   include <userpw.h>
3263 #  endif /* _AIX4 >= 40200 */
3264 #  include <usersec.h>
3265 # endif /* defined(_AIX3) || defined(_AIX4) */
3266 
3267 static char	*DefaultUserShells[] =
3268 {
3269 	"/bin/sh",		/* standard shell */
3270 	"/usr/bin/sh",
3271 	"/bin/csh",		/* C shell */
3272 	"/usr/bin/csh",
3273 # ifdef __hpux
3274 #  ifdef V4FS
3275 	"/usr/bin/rsh",		/* restricted Bourne shell */
3276 	"/usr/bin/ksh",		/* Korn shell */
3277 	"/usr/bin/rksh",	/* restricted Korn shell */
3278 	"/usr/bin/pam",
3279 	"/usr/bin/keysh",	/* key shell (extended Korn shell) */
3280 	"/usr/bin/posix/sh",
3281 #  else /* V4FS */
3282 	"/bin/rsh",		/* restricted Bourne shell */
3283 	"/bin/ksh",		/* Korn shell */
3284 	"/bin/rksh",		/* restricted Korn shell */
3285 	"/bin/pam",
3286 	"/usr/bin/keysh",	/* key shell (extended Korn shell) */
3287 	"/bin/posix/sh",
3288 #  endif /* V4FS */
3289 # endif /* __hpux */
3290 # if defined(_AIX3) || defined(_AIX4)
3291 	"/bin/ksh",		/* Korn shell */
3292 	"/usr/bin/ksh",
3293 	"/bin/tsh",		/* trusted shell */
3294 	"/usr/bin/tsh",
3295 	"/bin/bsh",		/* Bourne shell */
3296 	"/usr/bin/bsh",
3297 # endif /* defined(_AIX3) || defined(_AIX4) */
3298 # if defined(__svr4__) || defined(__svr5__)
3299 	"/bin/ksh",		/* Korn shell */
3300 	"/usr/bin/ksh",
3301 # endif /* defined(__svr4__) || defined(__svr5__) */
3302 # ifdef sgi
3303 	"/sbin/sh",		/* SGI's shells really live in /sbin */
3304 	"/sbin/csh",
3305 	"/bin/ksh",		/* Korn shell */
3306 	"/sbin/ksh",
3307 	"/usr/bin/ksh",
3308 	"/bin/tcsh",		/* Extended csh */
3309 	"/usr/bin/tcsh",
3310 # endif /* sgi */
3311 	NULL
3312 };
3313 
3314 #endif /* !HASGETUSERSHELL */
3315 
3316 #define WILDCARD_SHELL	"/SENDMAIL/ANY/SHELL/"
3317 
3318 bool
3319 usershellok(user, shell)
3320 	char *user;
3321 	char *shell;
3322 {
3323 # if HASGETUSERSHELL
3324 	register char *p;
3325 	extern char *getusershell();
3326 
3327 	if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') ||
3328 	    ConfigLevel <= 1)
3329 		return TRUE;
3330 
3331 	setusershell();
3332 	while ((p = getusershell()) != NULL)
3333 		if (strcmp(p, shell) == 0 || strcmp(p, WILDCARD_SHELL) == 0)
3334 			break;
3335 	endusershell();
3336 	return p != NULL;
3337 # else /* HASGETUSERSHELL */
3338 #  if USEGETCONFATTR
3339 	auto char *v;
3340 #  endif /* USEGETCONFATTR */
3341 	register FILE *shellf;
3342 	char buf[MAXLINE];
3343 
3344 	if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') ||
3345 	    ConfigLevel <= 1)
3346 		return TRUE;
3347 
3348 #  if USEGETCONFATTR
3349 	/*
3350 	**  Naturally IBM has a "better" idea.....
3351 	**
3352 	**	What a crock.  This interface isn't documented, it is
3353 	**	considered part of the security library (-ls), and it
3354 	**	only works if you are running as root (since the list
3355 	**	of valid shells is obviously a source of great concern).
3356 	**	I recommend that you do NOT define USEGETCONFATTR,
3357 	**	especially since you are going to have to set up an
3358 	**	/etc/shells anyhow to handle the cases where getconfattr
3359 	**	fails.
3360 	*/
3361 
3362 	if (getconfattr(SC_SYS_LOGIN, SC_SHELLS, &v, SEC_LIST) == 0 && v != NULL)
3363 	{
3364 		while (*v != '\0')
3365 		{
3366 			if (strcmp(v, shell) == 0 || strcmp(v, WILDCARD_SHELL) == 0)
3367 				return TRUE;
3368 			v += strlen(v) + 1;
3369 		}
3370 		return FALSE;
3371 	}
3372 #  endif /* USEGETCONFATTR */
3373 
3374 	shellf = fopen(_PATH_SHELLS, "r");
3375 	if (shellf == NULL)
3376 	{
3377 		/* no /etc/shells; see if it is one of the std shells */
3378 		char **d;
3379 
3380 		if (errno != ENOENT && LogLevel > 3)
3381 			sm_syslog(LOG_ERR, NOQID,
3382 				  "usershellok: cannot open %s: %s",
3383 				  _PATH_SHELLS, errstring(errno));
3384 
3385 		for (d = DefaultUserShells; *d != NULL; d++)
3386 		{
3387 			if (strcmp(shell, *d) == 0)
3388 				return TRUE;
3389 		}
3390 		return FALSE;
3391 	}
3392 
3393 	while (fgets(buf, sizeof buf, shellf) != NULL)
3394 	{
3395 		register char *p, *q;
3396 
3397 		p = buf;
3398 		while (*p != '\0' && *p != '#' && *p != '/')
3399 			p++;
3400 		if (*p == '#' || *p == '\0')
3401 			continue;
3402 		q = p;
3403 		while (*p != '\0' && *p != '#' && !(isascii(*p) && isspace(*p)))
3404 			p++;
3405 		*p = '\0';
3406 		if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0)
3407 		{
3408 			(void) fclose(shellf);
3409 			return TRUE;
3410 		}
3411 	}
3412 	(void) fclose(shellf);
3413 	return FALSE;
3414 # endif /* HASGETUSERSHELL */
3415 }
3416 /*
3417 **  FREEDISKSPACE -- see how much free space is on the queue filesystem
3418 **
3419 **	Only implemented if you have statfs.
3420 **
3421 **	Parameters:
3422 **		dir -- the directory in question.
3423 **		bsize -- a variable into which the filesystem
3424 **			block size is stored.
3425 **
3426 **	Returns:
3427 **		The number of blocks free on the queue filesystem.
3428 **		-1 if the statfs call fails.
3429 **
3430 **	Side effects:
3431 **		Puts the filesystem block size into bsize.
3432 */
3433 
3434 /* statfs types */
3435 #define SFS_NONE	0	/* no statfs implementation */
3436 #define SFS_USTAT	1	/* use ustat */
3437 #define SFS_4ARGS	2	/* use four-argument statfs call */
3438 #define SFS_VFS		3	/* use <sys/vfs.h> implementation */
3439 #define SFS_MOUNT	4	/* use <sys/mount.h> implementation */
3440 #define SFS_STATFS	5	/* use <sys/statfs.h> implementation */
3441 #define SFS_STATVFS	6	/* use <sys/statvfs.h> implementation */
3442 
3443 #ifndef SFS_TYPE
3444 # define SFS_TYPE	SFS_NONE
3445 #endif /* ! SFS_TYPE */
3446 
3447 #if SFS_TYPE == SFS_USTAT
3448 # include <ustat.h>
3449 #endif /* SFS_TYPE == SFS_USTAT */
3450 #if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS
3451 # include <sys/statfs.h>
3452 #endif /* SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS */
3453 #if SFS_TYPE == SFS_VFS
3454 # include <sys/vfs.h>
3455 #endif /* SFS_TYPE == SFS_VFS */
3456 #if SFS_TYPE == SFS_MOUNT
3457 # include <sys/mount.h>
3458 #endif /* SFS_TYPE == SFS_MOUNT */
3459 #if SFS_TYPE == SFS_STATVFS
3460 # include <sys/statvfs.h>
3461 #endif /* SFS_TYPE == SFS_STATVFS */
3462 
3463 long
3464 freediskspace(dir, bsize)
3465 	char *dir;
3466 	long *bsize;
3467 {
3468 # if SFS_TYPE != SFS_NONE
3469 #  if SFS_TYPE == SFS_USTAT
3470 	struct ustat fs;
3471 	struct stat statbuf;
3472 #   define FSBLOCKSIZE	DEV_BSIZE
3473 #   define SFS_BAVAIL	f_tfree
3474 #  else /* SFS_TYPE == SFS_USTAT */
3475 #   if defined(ultrix)
3476 	struct fs_data fs;
3477 #    define SFS_BAVAIL	fd_bfreen
3478 #    define FSBLOCKSIZE	1024L
3479 #   else /* defined(ultrix) */
3480 #    if SFS_TYPE == SFS_STATVFS
3481 	struct statvfs fs;
3482 #     define FSBLOCKSIZE	fs.f_frsize
3483 #    else /* SFS_TYPE == SFS_STATVFS */
3484 	struct statfs fs;
3485 #     define FSBLOCKSIZE	fs.f_bsize
3486 #    endif /* SFS_TYPE == SFS_STATVFS */
3487 #   endif /* defined(ultrix) */
3488 #  endif /* SFS_TYPE == SFS_USTAT */
3489 #  ifndef SFS_BAVAIL
3490 #   define SFS_BAVAIL f_bavail
3491 #  endif /* ! SFS_BAVAIL */
3492 
3493 #  if SFS_TYPE == SFS_USTAT
3494 	if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0)
3495 #  else /* SFS_TYPE == SFS_USTAT */
3496 #   if SFS_TYPE == SFS_4ARGS
3497 	if (statfs(dir, &fs, sizeof fs, 0) == 0)
3498 #   else /* SFS_TYPE == SFS_4ARGS */
3499 #    if SFS_TYPE == SFS_STATVFS
3500 	if (statvfs(dir, &fs) == 0)
3501 #    else /* SFS_TYPE == SFS_STATVFS */
3502 #     if defined(ultrix)
3503 	if (statfs(dir, &fs) > 0)
3504 #     else /* defined(ultrix) */
3505 	if (statfs(dir, &fs) == 0)
3506 #     endif /* defined(ultrix) */
3507 #    endif /* SFS_TYPE == SFS_STATVFS */
3508 #   endif /* SFS_TYPE == SFS_4ARGS */
3509 #  endif /* SFS_TYPE == SFS_USTAT */
3510 	{
3511 		if (bsize != NULL)
3512 			*bsize = FSBLOCKSIZE;
3513 		if (fs.SFS_BAVAIL <= 0)
3514 			return 0;
3515 		else if (fs.SFS_BAVAIL > LONG_MAX)
3516 			return (long) LONG_MAX;
3517 		else
3518 			return (long) fs.SFS_BAVAIL;
3519 	}
3520 # endif /* SFS_TYPE != SFS_NONE */
3521 	return -1;
3522 }
3523 /*
3524 **  ENOUGHDISKSPACE -- is there enough free space on the queue fs?
3525 **
3526 **	Only implemented if you have statfs.
3527 **
3528 **	Parameters:
3529 **		msize -- the size to check against.  If zero, we don't yet
3530 **		know how big the message will be, so just check for
3531 **		a "reasonable" amount.
3532 **		log -- log message?
3533 **
3534 **	Returns:
3535 **		TRUE if there is enough space.
3536 **		FALSE otherwise.
3537 */
3538 
3539 bool
3540 enoughdiskspace(msize, log)
3541 	long msize;
3542 	bool log;
3543 {
3544 	long bfree;
3545 	long bsize;
3546 
3547 	if (MinBlocksFree <= 0 && msize <= 0)
3548 	{
3549 		if (tTd(4, 80))
3550 			dprintf("enoughdiskspace: no threshold\n");
3551 		return TRUE;
3552 	}
3553 
3554 	bfree = freediskspace(QueueDir, &bsize);
3555 	if (bfree >= 0)
3556 	{
3557 		if (tTd(4, 80))
3558 			dprintf("enoughdiskspace: bavail=%ld, need=%ld\n",
3559 				bfree, msize);
3560 
3561 		/* convert msize to block count */
3562 		msize = msize / bsize + 1;
3563 		if (MinBlocksFree >= 0)
3564 			msize += MinBlocksFree;
3565 
3566 		if (bfree < msize)
3567 		{
3568 			if (log && LogLevel > 0)
3569 				sm_syslog(LOG_ALERT, CurEnv->e_id,
3570 					"low on space (have %ld, %s needs %ld in %s)",
3571 					bfree,
3572 					CurHostName == NULL ? "SMTP-DAEMON" : CurHostName,
3573 					msize, QueueDir);
3574 			return FALSE;
3575 		}
3576 	}
3577 	else if (tTd(4, 80))
3578 		dprintf("enoughdiskspace failure: min=%ld, need=%ld: %s\n",
3579 			MinBlocksFree, msize, errstring(errno));
3580 	return TRUE;
3581 }
3582 /*
3583 **  TRANSIENTERROR -- tell if an error code indicates a transient failure
3584 **
3585 **	This looks at an errno value and tells if this is likely to
3586 **	go away if retried later.
3587 **
3588 **	Parameters:
3589 **		err -- the errno code to classify.
3590 **
3591 **	Returns:
3592 **		TRUE if this is probably transient.
3593 **		FALSE otherwise.
3594 */
3595 
3596 bool
3597 transienterror(err)
3598 	int err;
3599 {
3600 	switch (err)
3601 	{
3602 	  case EIO:			/* I/O error */
3603 	  case ENXIO:			/* Device not configured */
3604 	  case EAGAIN:			/* Resource temporarily unavailable */
3605 	  case ENOMEM:			/* Cannot allocate memory */
3606 	  case ENODEV:			/* Operation not supported by device */
3607 	  case ENFILE:			/* Too many open files in system */
3608 	  case EMFILE:			/* Too many open files */
3609 	  case ENOSPC:			/* No space left on device */
3610 #ifdef ETIMEDOUT
3611 	  case ETIMEDOUT:		/* Connection timed out */
3612 #endif /* ETIMEDOUT */
3613 #ifdef ESTALE
3614 	  case ESTALE:			/* Stale NFS file handle */
3615 #endif /* ESTALE */
3616 #ifdef ENETDOWN
3617 	  case ENETDOWN:		/* Network is down */
3618 #endif /* ENETDOWN */
3619 #ifdef ENETUNREACH
3620 	  case ENETUNREACH:		/* Network is unreachable */
3621 #endif /* ENETUNREACH */
3622 #ifdef ENETRESET
3623 	  case ENETRESET:		/* Network dropped connection on reset */
3624 #endif /* ENETRESET */
3625 #ifdef ECONNABORTED
3626 	  case ECONNABORTED:		/* Software caused connection abort */
3627 #endif /* ECONNABORTED */
3628 #ifdef ECONNRESET
3629 	  case ECONNRESET:		/* Connection reset by peer */
3630 #endif /* ECONNRESET */
3631 #ifdef ENOBUFS
3632 	  case ENOBUFS:			/* No buffer space available */
3633 #endif /* ENOBUFS */
3634 #ifdef ESHUTDOWN
3635 	  case ESHUTDOWN:		/* Can't send after socket shutdown */
3636 #endif /* ESHUTDOWN */
3637 #ifdef ECONNREFUSED
3638 	  case ECONNREFUSED:		/* Connection refused */
3639 #endif /* ECONNREFUSED */
3640 #ifdef EHOSTDOWN
3641 	  case EHOSTDOWN:		/* Host is down */
3642 #endif /* EHOSTDOWN */
3643 #ifdef EHOSTUNREACH
3644 	  case EHOSTUNREACH:		/* No route to host */
3645 #endif /* EHOSTUNREACH */
3646 #ifdef EDQUOT
3647 	  case EDQUOT:			/* Disc quota exceeded */
3648 #endif /* EDQUOT */
3649 #ifdef EPROCLIM
3650 	  case EPROCLIM:		/* Too many processes */
3651 #endif /* EPROCLIM */
3652 #ifdef EUSERS
3653 	  case EUSERS:			/* Too many users */
3654 #endif /* EUSERS */
3655 #ifdef EDEADLK
3656 	  case EDEADLK:			/* Resource deadlock avoided */
3657 #endif /* EDEADLK */
3658 #ifdef EISCONN
3659 	  case EISCONN:			/* Socket already connected */
3660 #endif /* EISCONN */
3661 #ifdef EINPROGRESS
3662 	  case EINPROGRESS:		/* Operation now in progress */
3663 #endif /* EINPROGRESS */
3664 #ifdef EALREADY
3665 	  case EALREADY:		/* Operation already in progress */
3666 #endif /* EALREADY */
3667 #ifdef EADDRINUSE
3668 	  case EADDRINUSE:		/* Address already in use */
3669 #endif /* EADDRINUSE */
3670 #ifdef EADDRNOTAVAIL
3671 	  case EADDRNOTAVAIL:		/* Can't assign requested address */
3672 #endif /* EADDRNOTAVAIL */
3673 #ifdef ETXTBSY
3674 	  case ETXTBSY:			/* (Apollo) file locked */
3675 #endif /* ETXTBSY */
3676 #if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR))
3677 	  case ENOSR:			/* Out of streams resources */
3678 #endif /* defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) */
3679 #ifdef ENOLCK
3680 	  case ENOLCK:			/* No locks available */
3681 #endif /* ENOLCK */
3682 	  case E_SM_OPENTIMEOUT:	/* PSEUDO: open timed out */
3683 		return TRUE;
3684 	}
3685 
3686 	/* nope, must be permanent */
3687 	return FALSE;
3688 }
3689 /*
3690 **  LOCKFILE -- lock a file using flock or (shudder) fcntl locking
3691 **
3692 **	Parameters:
3693 **		fd -- the file descriptor of the file.
3694 **		filename -- the file name (for error messages).
3695 **		ext -- the filename extension.
3696 **		type -- type of the lock.  Bits can be:
3697 **			LOCK_EX -- exclusive lock.
3698 **			LOCK_NB -- non-blocking.
3699 **			LOCK_UN -- unlock.
3700 **
3701 **	Returns:
3702 **		TRUE if the lock was acquired.
3703 **		FALSE otherwise.
3704 */
3705 
3706 bool
3707 lockfile(fd, filename, ext, type)
3708 	int fd;
3709 	char *filename;
3710 	char *ext;
3711 	int type;
3712 {
3713 	int i;
3714 	int save_errno;
3715 # if !HASFLOCK
3716 	int action;
3717 	struct flock lfd;
3718 
3719 	if (ext == NULL)
3720 		ext = "";
3721 
3722 	memset(&lfd, '\0', sizeof lfd);
3723 	if (bitset(LOCK_UN, type))
3724 		lfd.l_type = F_UNLCK;
3725 	else if (bitset(LOCK_EX, type))
3726 		lfd.l_type = F_WRLCK;
3727 	else
3728 		lfd.l_type = F_RDLCK;
3729 
3730 	if (bitset(LOCK_NB, type))
3731 		action = F_SETLK;
3732 	else
3733 		action = F_SETLKW;
3734 
3735 	if (tTd(55, 60))
3736 		dprintf("lockfile(%s%s, action=%d, type=%d): ",
3737 			filename, ext, action, lfd.l_type);
3738 
3739 	while ((i = fcntl(fd, action, &lfd)) < 0 && errno == EINTR)
3740 		continue;
3741 	if (i >= 0)
3742 	{
3743 		if (tTd(55, 60))
3744 			dprintf("SUCCESS\n");
3745 		return TRUE;
3746 	}
3747 	save_errno = errno;
3748 
3749 	if (tTd(55, 60))
3750 		dprintf("(%s) ", errstring(save_errno));
3751 
3752 	/*
3753 	**  On SunOS, if you are testing using -oQ/tmp/mqueue or
3754 	**  -oA/tmp/aliases or anything like that, and /tmp is mounted
3755 	**  as type "tmp" (that is, served from swap space), the
3756 	**  previous fcntl will fail with "Invalid argument" errors.
3757 	**  Since this is fairly common during testing, we will assume
3758 	**  that this indicates that the lock is successfully grabbed.
3759 	*/
3760 
3761 	if (save_errno == EINVAL)
3762 	{
3763 		if (tTd(55, 60))
3764 			dprintf("SUCCESS\n");
3765 		return TRUE;
3766 	}
3767 
3768 	if (!bitset(LOCK_NB, type) ||
3769 	    (save_errno != EACCES && save_errno != EAGAIN))
3770 	{
3771 		int omode = -1;
3772 #  ifdef F_GETFL
3773 		(void) fcntl(fd, F_GETFL, &omode);
3774 		errno = save_errno;
3775 #  endif /* F_GETFL */
3776 		syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
3777 			filename, ext, fd, type, omode, geteuid());
3778 		dumpfd(fd, TRUE, TRUE);
3779 	}
3780 # else /* !HASFLOCK */
3781 	if (ext == NULL)
3782 		ext = "";
3783 
3784 	if (tTd(55, 60))
3785 		dprintf("lockfile(%s%s, type=%o): ", filename, ext, type);
3786 
3787 	while ((i = flock(fd, type)) < 0 && errno == EINTR)
3788 		continue;
3789 	if (i >= 0)
3790 	{
3791 		if (tTd(55, 60))
3792 			dprintf("SUCCESS\n");
3793 		return TRUE;
3794 	}
3795 	save_errno = errno;
3796 
3797 	if (tTd(55, 60))
3798 		dprintf("(%s) ", errstring(save_errno));
3799 
3800 	if (!bitset(LOCK_NB, type) || save_errno != EWOULDBLOCK)
3801 	{
3802 		int omode = -1;
3803 #  ifdef F_GETFL
3804 		(void) fcntl(fd, F_GETFL, &omode);
3805 		errno = save_errno;
3806 #  endif /* F_GETFL */
3807 		syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
3808 			filename, ext, fd, type, omode, geteuid());
3809 		dumpfd(fd, TRUE, TRUE);
3810 	}
3811 # endif /* !HASFLOCK */
3812 	if (tTd(55, 60))
3813 		dprintf("FAIL\n");
3814 	errno = save_errno;
3815 	return FALSE;
3816 }
3817 /*
3818 **  CHOWNSAFE -- tell if chown is "safe" (executable only by root)
3819 **
3820 **	Unfortunately, given that we can't predict other systems on which
3821 **	a remote mounted (NFS) filesystem will be mounted, the answer is
3822 **	almost always that this is unsafe.
3823 **
3824 **	Note also that many operating systems have non-compliant
3825 **	implementations of the _POSIX_CHOWN_RESTRICTED variable and the
3826 **	fpathconf() routine.  According to IEEE 1003.1-1990, if
3827 **	_POSIX_CHOWN_RESTRICTED is defined and not equal to -1, then
3828 **	no non-root process can give away the file.  However, vendors
3829 **	don't take NFS into account, so a comfortable value of
3830 **	_POSIX_CHOWN_RESTRICTED tells us nothing.
3831 **
3832 **	Also, some systems (e.g., IRIX 6.2) return 1 from fpathconf()
3833 **	even on files where chown is not restricted.  Many systems get
3834 **	this wrong on NFS-based filesystems (that is, they say that chown
3835 **	is restricted [safe] on NFS filesystems where it may not be, since
3836 **	other systems can access the same filesystem and do file giveaway;
3837 **	only the NFS server knows for sure!)  Hence, it is important to
3838 **	get the value of SAFENFSPATHCONF correct -- it should be defined
3839 **	_only_ after testing (see test/t_pathconf.c) a system on an unsafe
3840 **	NFS-based filesystem to ensure that you can get meaningful results.
3841 **	If in doubt, assume unsafe!
3842 **
3843 **	You may also need to tweak IS_SAFE_CHOWN -- it should be a
3844 **	condition indicating whether the return from pathconf indicates
3845 **	that chown is safe (typically either > 0 or >= 0 -- there isn't
3846 **	even any agreement about whether a zero return means that a file
3847 **	is or is not safe).  It defaults to "> 0".
3848 **
3849 **	If the parent directory is safe (writable only by owner back
3850 **	to the root) then we can relax slightly and trust fpathconf
3851 **	in more circumstances.  This is really a crock -- if this is an
3852 **	NFS mounted filesystem then we really know nothing about the
3853 **	underlying implementation.  However, most systems pessimize and
3854 **	return an error (EINVAL or EOPNOTSUPP) on NFS filesystems, which
3855 **	we interpret as unsafe, as we should.  Thus, this heuristic gets
3856 **	us into a possible problem only on systems that have a broken
3857 **	pathconf implementation and which are also poorly configured
3858 **	(have :include: files in group- or world-writable directories).
3859 **
3860 **	Parameters:
3861 **		fd -- the file descriptor to check.
3862 **		safedir -- set if the parent directory is safe.
3863 **
3864 **	Returns:
3865 **		TRUE -- if the chown(2) operation is "safe" -- that is,
3866 **			only root can chown the file to an arbitrary user.
3867 **		FALSE -- if an arbitrary user can give away a file.
3868 */
3869 
3870 #ifndef IS_SAFE_CHOWN
3871 # define IS_SAFE_CHOWN	> 0
3872 #endif /* ! IS_SAFE_CHOWN */
3873 
3874 bool
3875 chownsafe(fd, safedir)
3876 	int fd;
3877 	bool safedir;
3878 {
3879 # if (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \
3880     (defined(_PC_CHOWN_RESTRICTED) || defined(_GNU_TYPES_H))
3881 	int rval;
3882 
3883 	/* give the system administrator a chance to override */
3884 	if (bitnset(DBS_ASSUMESAFECHOWN, DontBlameSendmail))
3885 		return TRUE;
3886 
3887 	/*
3888 	**  Some systems (e.g., SunOS) seem to have the call and the
3889 	**  #define _PC_CHOWN_RESTRICTED, but don't actually implement
3890 	**  the call.  This heuristic checks for that.
3891 	*/
3892 
3893 	errno = 0;
3894 	rval = fpathconf(fd, _PC_CHOWN_RESTRICTED);
3895 #  if SAFENFSPATHCONF
3896 	return errno == 0 && rval IS_SAFE_CHOWN;
3897 #  else /* SAFENFSPATHCONF */
3898 	return safedir && errno == 0 && rval IS_SAFE_CHOWN;
3899 #  endif /* SAFENFSPATHCONF */
3900 # else /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \ */
3901 	return bitnset(DBS_ASSUMESAFECHOWN, DontBlameSendmail);
3902 # endif /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \ */
3903 }
3904 /*
3905 **  RESETLIMITS -- reset system controlled resource limits
3906 **
3907 **	This is to avoid denial-of-service attacks
3908 **
3909 **	Parameters:
3910 **		none
3911 **
3912 **	Returns:
3913 **		none
3914 */
3915 
3916 #if HASSETRLIMIT
3917 # ifdef RLIMIT_NEEDS_SYS_TIME_H
3918 #  include <sys/time.h>
3919 # endif /* RLIMIT_NEEDS_SYS_TIME_H */
3920 # include <sys/resource.h>
3921 #endif /* HASSETRLIMIT */
3922 #ifndef FD_SETSIZE
3923 # define FD_SETSIZE	256
3924 #endif /* ! FD_SETSIZE */
3925 
3926 void
3927 resetlimits()
3928 {
3929 #if HASSETRLIMIT
3930 	struct rlimit lim;
3931 
3932 	lim.rlim_cur = lim.rlim_max = RLIM_INFINITY;
3933 	(void) setrlimit(RLIMIT_CPU, &lim);
3934 	(void) setrlimit(RLIMIT_FSIZE, &lim);
3935 # ifdef RLIMIT_NOFILE
3936 	lim.rlim_cur = lim.rlim_max = FD_SETSIZE;
3937 	(void) setrlimit(RLIMIT_NOFILE, &lim);
3938 # endif /* RLIMIT_NOFILE */
3939 #else /* HASSETRLIMIT */
3940 # if HASULIMIT
3941 	(void) ulimit(2, 0x3fffff);
3942 	(void) ulimit(4, FD_SETSIZE);
3943 # endif /* HASULIMIT */
3944 #endif /* HASSETRLIMIT */
3945 	errno = 0;
3946 }
3947 /*
3948 **  GETCFNAME -- return the name of the .cf file.
3949 **
3950 **	Some systems (e.g., NeXT) determine this dynamically.
3951 */
3952 
3953 char *
3954 getcfname()
3955 {
3956 
3957 	if (ConfFile != NULL)
3958 		return ConfFile;
3959 #if NETINFO
3960 	{
3961 		char *cflocation;
3962 
3963 		cflocation = ni_propval("/locations", NULL, "sendmail",
3964 					"sendmail.cf", '\0');
3965 		if (cflocation != NULL)
3966 			return cflocation;
3967 	}
3968 #endif /* NETINFO */
3969 
3970 	return _PATH_SENDMAILCF;
3971 }
3972 /*
3973 **  SETVENDOR -- process vendor code from V configuration line
3974 **
3975 **	Parameters:
3976 **		vendor -- string representation of vendor.
3977 **
3978 **	Returns:
3979 **		TRUE -- if ok.
3980 **		FALSE -- if vendor code could not be processed.
3981 **
3982 **	Side Effects:
3983 **		It is reasonable to set mode flags here to tweak
3984 **		processing in other parts of the code if necessary.
3985 **		For example, if you are a vendor that uses $%y to
3986 **		indicate YP lookups, you could enable that here.
3987 */
3988 
3989 bool
3990 setvendor(vendor)
3991 	char *vendor;
3992 {
3993 	if (strcasecmp(vendor, "Berkeley") == 0)
3994 	{
3995 		VendorCode = VENDOR_BERKELEY;
3996 		return TRUE;
3997 	}
3998 
3999 	/* add vendor extensions here */
4000 
4001 #ifdef SUN_EXTENSIONS
4002 	if (strcasecmp(vendor, "Sun") == 0)
4003 	{
4004 		VendorCode = VENDOR_SUN;
4005 		return TRUE;
4006 	}
4007 #endif /* SUN_EXTENSIONS */
4008 
4009 #if defined(VENDOR_NAME) && defined(VENDOR_CODE)
4010 	if (strcasecmp(vendor, VENDOR_NAME) == 0)
4011 	{
4012 		VendorCode = VENDOR_CODE;
4013 		return TRUE;
4014 	}
4015 #endif /* defined(VENDOR_NAME) && defined(VENDOR_CODE) */
4016 
4017 	return FALSE;
4018 }
4019 /*
4020 **  GETVENDOR -- return vendor name based on vendor code
4021 **
4022 **	Parameters:
4023 **		vendorcode -- numeric representation of vendor.
4024 **
4025 **	Returns:
4026 **		string containing vendor name.
4027 */
4028 
4029 char *
4030 getvendor(vendorcode)
4031 	int vendorcode;
4032 {
4033 #if defined(VENDOR_NAME) && defined(VENDOR_CODE)
4034 	/*
4035 	**  Can't have the same switch case twice so need to
4036 	**  handle VENDOR_CODE outside of switch.  It might
4037 	**  match one of the existing VENDOR_* codes.
4038 	*/
4039 
4040 	if (vendorcode == VENDOR_CODE)
4041 		return VENDOR_NAME;
4042 #endif /* defined(VENDOR_NAME) && defined(VENDOR_CODE) */
4043 
4044 	switch (vendorcode)
4045 	{
4046 		case VENDOR_BERKELEY:
4047 			return "Berkeley";
4048 
4049 		case VENDOR_SUN:
4050 			return "Sun";
4051 
4052 		case VENDOR_HP:
4053 			return "HP";
4054 
4055 		case VENDOR_IBM:
4056 			return "IBM";
4057 
4058 		case VENDOR_SENDMAIL:
4059 			return "Sendmail";
4060 
4061 		default:
4062 			return "Unknown";
4063 	}
4064 }
4065 /*
4066 **  VENDOR_PRE_DEFAULTS, VENDOR_POST_DEFAULTS -- set vendor-specific defaults
4067 **
4068 **	Vendor_pre_defaults is called before reading the configuration
4069 **	file; vendor_post_defaults is called immediately after.
4070 **
4071 **	Parameters:
4072 **		e -- the global environment to initialize.
4073 **
4074 **	Returns:
4075 **		none.
4076 */
4077 
4078 #if SHARE_V1
4079 int	DefShareUid;	/* default share uid to run as -- unused??? */
4080 #endif /* SHARE_V1 */
4081 
4082 void
4083 vendor_pre_defaults(e)
4084 	ENVELOPE *e;
4085 {
4086 #if SHARE_V1
4087 	/* OTHERUID is defined in shares.h, do not be alarmed */
4088 	DefShareUid = OTHERUID;
4089 #endif /* SHARE_V1 */
4090 #if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES)
4091 	sun_pre_defaults(e);
4092 #endif /* defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) */
4093 #ifdef apollo
4094 	/*
4095 	**  stupid domain/os can't even open
4096 	**  /etc/mail/sendmail.cf without this
4097 	*/
4098 
4099 	setuserenv("ISP", NULL);
4100 	setuserenv("SYSTYPE", NULL);
4101 #endif /* apollo */
4102 }
4103 
4104 
4105 void
4106 vendor_post_defaults(e)
4107 	ENVELOPE *e;
4108 {
4109 #ifdef __QNX__
4110 	char *p;
4111 
4112 	/* Makes sure the SOCK environment variable remains */
4113 	if (p = getextenv("SOCK"))
4114 		setuserenv("SOCK", p);
4115 #endif /* __QNX__ */
4116 #if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES)
4117 	sun_post_defaults(e);
4118 #endif /* defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) */
4119 }
4120 /*
4121 **  VENDOR_DAEMON_SETUP -- special vendor setup needed for daemon mode
4122 */
4123 
4124 void
4125 vendor_daemon_setup(e)
4126 	ENVELOPE *e;
4127 {
4128 #if HASSETLOGIN
4129 	(void) setlogin(RunAsUserName);
4130 #endif /* HASSETLOGIN */
4131 #if SECUREWARE
4132 	if (getluid() != -1)
4133 	{
4134 		usrerr("Daemon cannot have LUID");
4135 		finis(FALSE, EX_USAGE);
4136 	}
4137 #endif /* SECUREWARE */
4138 }
4139 /*
4140 **  VENDOR_SET_UID -- do setup for setting a user id
4141 **
4142 **	This is called when we are still root.
4143 **
4144 **	Parameters:
4145 **		uid -- the uid we are about to become.
4146 **
4147 **	Returns:
4148 **		none.
4149 */
4150 
4151 void
4152 vendor_set_uid(uid)
4153 	UID_T uid;
4154 {
4155 	/*
4156 	**  We need to setup the share groups (lnodes)
4157 	**  and add auditing information (luid's)
4158 	**  before we loose our ``root''ness.
4159 	*/
4160 #if SHARE_V1
4161 	if (setupshares(uid, syserr) != 0)
4162 		syserr("Unable to set up shares");
4163 #endif /* SHARE_V1 */
4164 #if SECUREWARE
4165 	(void) setup_secure(uid);
4166 #endif /* SECUREWARE */
4167 }
4168 /*
4169 **  VALIDATE_CONNECTION -- check connection for rationality
4170 **
4171 **	If the connection is rejected, this routine should log an
4172 **	appropriate message -- but should never issue any SMTP protocol.
4173 **
4174 **	Parameters:
4175 **		sap -- a pointer to a SOCKADDR naming the peer.
4176 **		hostname -- the name corresponding to sap.
4177 **		e -- the current envelope.
4178 **
4179 **	Returns:
4180 **		error message from rejection.
4181 **		NULL if not rejected.
4182 */
4183 
4184 #if TCPWRAPPERS
4185 # include <tcpd.h>
4186 
4187 /* tcpwrappers does no logging, but you still have to declare these -- ugh */
4188 int	allow_severity	= LOG_INFO;
4189 int	deny_severity	= LOG_NOTICE;
4190 #endif /* TCPWRAPPERS */
4191 
4192 #if DAEMON
4193 char *
4194 validate_connection(sap, hostname, e)
4195 	SOCKADDR *sap;
4196 	char *hostname;
4197 	ENVELOPE *e;
4198 {
4199 # if TCPWRAPPERS
4200 	char *host;
4201 # endif /* TCPWRAPPERS */
4202 
4203 	if (tTd(48, 3))
4204 		dprintf("validate_connection(%s, %s)\n",
4205 			hostname, anynet_ntoa(sap));
4206 
4207 	if (rscheck("check_relay", hostname, anynet_ntoa(sap),
4208 		    e, TRUE, TRUE, 4, NULL) != EX_OK)
4209 	{
4210 		static char reject[BUFSIZ*2];
4211 		extern char MsgBuf[];
4212 
4213 		if (tTd(48, 4))
4214 			dprintf("  ... validate_connection: BAD (rscheck)\n");
4215 
4216 		if (strlen(MsgBuf) >= 3)
4217 			(void) strlcpy(reject, MsgBuf, sizeof reject);
4218 		else
4219 			(void) strlcpy(reject, "Access denied", sizeof reject);
4220 
4221 		return reject;
4222 	}
4223 
4224 # if TCPWRAPPERS
4225 	if (hostname[0] == '[' && hostname[strlen(hostname) - 1] == ']')
4226 		host = "unknown";
4227 	else
4228 		host = hostname;
4229 	if (!hosts_ctl("sendmail", host, anynet_ntoa(sap), STRING_UNKNOWN))
4230 	{
4231 		if (tTd(48, 4))
4232 			dprintf("  ... validate_connection: BAD (tcpwrappers)\n");
4233 		if (LogLevel >= 4)
4234 			sm_syslog(LOG_NOTICE, e->e_id,
4235 				"tcpwrappers (%s, %s) rejection",
4236 				host, anynet_ntoa(sap));
4237 		return "Access denied";
4238 	}
4239 # endif /* TCPWRAPPERS */
4240 	if (tTd(48, 4))
4241 		dprintf("  ... validate_connection: OK\n");
4242 	return NULL;
4243 }
4244 
4245 #endif /* DAEMON */
4246 /*
4247 **  STRTOL -- convert string to long integer
4248 **
4249 **	For systems that don't have it in the C library.
4250 **
4251 **	This is taken verbatim from the 4.4-Lite C library.
4252 */
4253 
4254 #if NEEDSTRTOL
4255 
4256 # if defined(LIBC_SCCS) && !defined(lint)
4257 static char sccsid[] = "@(#)strtol.c	8.1 (Berkeley) 6/4/93";
4258 # endif /* defined(LIBC_SCCS) && !defined(lint) */
4259 
4260 /*
4261  * Convert a string to a long integer.
4262  *
4263  * Ignores `locale' stuff.  Assumes that the upper and lower case
4264  * alphabets and digits are each contiguous.
4265  */
4266 
4267 long
4268 strtol(nptr, endptr, base)
4269 	const char *nptr;
4270 	char **endptr;
4271 	register int base;
4272 {
4273 	register const char *s = nptr;
4274 	register unsigned long acc;
4275 	register int c;
4276 	register unsigned long cutoff;
4277 	register int neg = 0, any, cutlim;
4278 
4279 	/*
4280 	 * Skip white space and pick up leading +/- sign if any.
4281 	 * If base is 0, allow 0x for hex and 0 for octal, else
4282 	 * assume decimal; if base is already 16, allow 0x.
4283 	 */
4284 	do {
4285 		c = *s++;
4286 	} while (isspace(c));
4287 	if (c == '-') {
4288 		neg = 1;
4289 		c = *s++;
4290 	} else if (c == '+')
4291 		c = *s++;
4292 	if ((base == 0 || base == 16) &&
4293 	    c == '0' && (*s == 'x' || *s == 'X')) {
4294 		c = s[1];
4295 		s += 2;
4296 		base = 16;
4297 	}
4298 	if (base == 0)
4299 		base = c == '0' ? 8 : 10;
4300 
4301 	/*
4302 	 * Compute the cutoff value between legal numbers and illegal
4303 	 * numbers.  That is the largest legal value, divided by the
4304 	 * base.  An input number that is greater than this value, if
4305 	 * followed by a legal input character, is too big.  One that
4306 	 * is equal to this value may be valid or not; the limit
4307 	 * between valid and invalid numbers is then based on the last
4308 	 * digit.  For instance, if the range for longs is
4309 	 * [-2147483648..2147483647] and the input base is 10,
4310 	 * cutoff will be set to 214748364 and cutlim to either
4311 	 * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
4312 	 * a value > 214748364, or equal but the next digit is > 7 (or 8),
4313 	 * the number is too big, and we will return a range error.
4314 	 *
4315 	 * Set any if any `digits' consumed; make it negative to indicate
4316 	 * overflow.
4317 	 */
4318 	cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
4319 	cutlim = cutoff % (unsigned long)base;
4320 	cutoff /= (unsigned long)base;
4321 	for (acc = 0, any = 0;; c = *s++) {
4322 		if (isdigit(c))
4323 			c -= '0';
4324 		else if (isalpha(c))
4325 			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
4326 		else
4327 			break;
4328 		if (c >= base)
4329 			break;
4330 		if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
4331 			any = -1;
4332 		else {
4333 			any = 1;
4334 			acc *= base;
4335 			acc += c;
4336 		}
4337 	}
4338 	if (any < 0) {
4339 		acc = neg ? LONG_MIN : LONG_MAX;
4340 		errno = ERANGE;
4341 	} else if (neg)
4342 		acc = -acc;
4343 	if (endptr != 0)
4344 		*endptr = (char *)(any ? s - 1 : nptr);
4345 	return acc;
4346 }
4347 
4348 #endif /* NEEDSTRTOL */
4349 /*
4350 **  STRSTR -- find first substring in string
4351 **
4352 **	Parameters:
4353 **		big -- the big (full) string.
4354 **		little -- the little (sub) string.
4355 **
4356 **	Returns:
4357 **		A pointer to the first instance of little in big.
4358 **		big if little is the null string.
4359 **		NULL if little is not contained in big.
4360 */
4361 
4362 #if NEEDSTRSTR
4363 
4364 char *
4365 strstr(big, little)
4366 	char *big;
4367 	char *little;
4368 {
4369 	register char *p = big;
4370 	int l;
4371 
4372 	if (*little == '\0')
4373 		return big;
4374 	l = strlen(little);
4375 
4376 	while ((p = strchr(p, *little)) != NULL)
4377 	{
4378 		if (strncmp(p, little, l) == 0)
4379 			return p;
4380 		p++;
4381 	}
4382 	return NULL;
4383 }
4384 
4385 #endif /* NEEDSTRSTR */
4386 /*
4387 **  SM_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX
4388 **
4389 **	Some operating systems have wierd problems with the gethostbyXXX
4390 **	routines.  For example, Solaris versions at least through 2.3
4391 **	don't properly deliver a canonical h_name field.  This tries to
4392 **	work around these problems.
4393 **
4394 **	Support IPv6 as well as IPv4.
4395 */
4396 
4397 #if NETINET6 && NEEDSGETIPNODE
4398 
4399 # ifndef AI_DEFAULT
4400 #  define AI_DEFAULT	0	/* dummy */
4401 # endif /* ! AI_DEFAULT */
4402 # ifndef AI_ADDRCONFIG
4403 #  define AI_ADDRCONFIG	0	/* dummy */
4404 # endif /* ! AI_ADDRCONFIG */
4405 # ifndef AI_V4MAPPED
4406 #  define AI_V4MAPPED	0	/* dummy */
4407 # endif /* ! AI_V4MAPPED */
4408 # ifndef AI_ALL
4409 #  define AI_ALL	0	/* dummy */
4410 # endif /* ! AI_ALL */
4411 
4412 static struct hostent *
4413 getipnodebyname(name, family, flags, err)
4414 	char *name;
4415 	int family;
4416 	int flags;
4417 	int *err;
4418 {
4419 	bool resv6 = TRUE;
4420 	struct hostent *h;
4421 
4422 	if (family == AF_INET6)
4423 	{
4424 		/* From RFC2133, section 6.1 */
4425 		resv6 = bitset(RES_USE_INET6, _res.options);
4426 		_res.options |= RES_USE_INET6;
4427 	}
4428 	SM_SET_H_ERRNO(0);
4429 	h = gethostbyname(name);
4430 	*err = h_errno;
4431 	if (family == AF_INET6 && !resv6)
4432 		_res.options &= ~RES_USE_INET6;
4433 	return h;
4434 }
4435 
4436 static struct hostent *
4437 getipnodebyaddr(addr, len, family, err)
4438 	char *addr;
4439 	int len;
4440 	int family;
4441 	int *err;
4442 {
4443 	struct hostent *h;
4444 
4445 	SM_SET_H_ERRNO(0);
4446 	h = gethostbyaddr(addr, len, family);
4447 	*err = h_errno;
4448 	return h;
4449 }
4450 
4451 # if _FFR_FREEHOSTENT
4452 void
4453 freehostent(h)
4454 	struct hostent *h;
4455 {
4456 	/*
4457 	**  Stub routine -- if they don't have getipnodeby*(),
4458 	**  they probably don't have the free routine either.
4459 	*/
4460 
4461 	return;
4462 }
4463 # endif /* _FFR_FREEHOSTENT */
4464 #endif /* NEEDSGETIPNODE && NETINET6 */
4465 
4466 struct hostent *
4467 sm_gethostbyname(name, family)
4468 	char *name;
4469 	int family;
4470 {
4471 	int save_errno;
4472 	struct hostent *h = NULL;
4473 #if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4))
4474 # if SOLARIS == 20300 || SOLARIS == 203
4475 	static struct hostent hp;
4476 	static char buf[1000];
4477 	extern struct hostent *_switch_gethostbyname_r();
4478 
4479 	if (tTd(61, 10))
4480 		dprintf("_switch_gethostbyname_r(%s)... ", name);
4481 	h = _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno);
4482 	save_errno = errno;
4483 # else /* SOLARIS == 20300 || SOLARIS == 203 */
4484 	extern struct hostent *__switch_gethostbyname();
4485 
4486 	if (tTd(61, 10))
4487 		dprintf("__switch_gethostbyname(%s)... ", name);
4488 	h = __switch_gethostbyname(name);
4489 	save_errno = errno;
4490 # endif /* SOLARIS == 20300 || SOLARIS == 203 */
4491 #else /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */
4492 	int nmaps;
4493 # if NETINET6
4494 	int flags = AI_DEFAULT|AI_ALL;
4495 	int err;
4496 # endif /* NETINET6 */
4497 	char *maptype[MAXMAPSTACK];
4498 	short mapreturn[MAXMAPACTIONS];
4499 	char hbuf[MAXNAME];
4500 
4501 	if (tTd(61, 10))
4502 		dprintf("sm_gethostbyname(%s, %d)... ", name, family);
4503 
4504 # if NETINET6
4505 #  if ADDRCONFIG_IS_BROKEN
4506 	flags &= ~AI_ADDRCONFIG;
4507 #  endif /* ADDRCONFIG_IS_BROKEN */
4508 	h = getipnodebyname(name, family, flags, &err);
4509 	SM_SET_H_ERRNO(err);
4510 # else /* NETINET6 */
4511 	h = gethostbyname(name);
4512 # endif /* NETINET6 */
4513 
4514 	save_errno = errno;
4515 	if (h == NULL)
4516 	{
4517 		if (tTd(61, 10))
4518 			dprintf("failure\n");
4519 
4520 		nmaps = switch_map_find("hosts", maptype, mapreturn);
4521 		while (--nmaps >= 0)
4522 		{
4523 			if (strcmp(maptype[nmaps], "nis") == 0 ||
4524 			    strcmp(maptype[nmaps], "files") == 0)
4525 				break;
4526 		}
4527 
4528 		if (nmaps >= 0)
4529 		{
4530 			/* try short name */
4531 			if (strlen(name) > (SIZE_T) sizeof hbuf - 1)
4532 			{
4533 				errno = save_errno;
4534 				return NULL;
4535 			}
4536 			(void) strlcpy(hbuf, name, sizeof hbuf);
4537 			(void) shorten_hostname(hbuf);
4538 
4539 			/* if it hasn't been shortened, there's no point */
4540 			if (strcmp(hbuf, name) != 0)
4541 			{
4542 				if (tTd(61, 10))
4543 					dprintf("sm_gethostbyname(%s, %d)... ",
4544 					       hbuf, family);
4545 
4546 # if NETINET6
4547 				h = getipnodebyname(hbuf, family,
4548 						    AI_V4MAPPED|AI_ALL,
4549 						    &err);
4550 				SM_SET_H_ERRNO(err);
4551 				save_errno = errno;
4552 # else /* NETINET6 */
4553 				h = gethostbyname(hbuf);
4554 				save_errno = errno;
4555 # endif /* NETINET6 */
4556 			}
4557 		}
4558 	}
4559 #endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */
4560 	if (tTd(61, 10))
4561 	{
4562 		if (h == NULL)
4563 			dprintf("failure\n");
4564 		else
4565 		{
4566 			dprintf("%s\n", h->h_name);
4567 			if (tTd(61, 11))
4568 			{
4569 #if NETINET6
4570 				struct in6_addr ia6;
4571 				char buf6[INET6_ADDRSTRLEN];
4572 #else /* NETINET6 */
4573 				struct in_addr ia;
4574 #endif /* NETINET6 */
4575 				int i;
4576 
4577 				if (h->h_aliases != NULL)
4578 					for (i = 0; h->h_aliases[i] != NULL;
4579 					     i++)
4580 						dprintf("\talias: %s\n",
4581 							h->h_aliases[i]);
4582 				for (i = 0; h->h_addr_list[i] != NULL; i++)
4583 				{
4584 					char *addr;
4585 
4586 #if NETINET6
4587 					memmove(&ia6, h->h_addr_list[i],
4588 						IN6ADDRSZ);
4589 					addr = anynet_ntop(&ia6,
4590 							   buf6, sizeof buf6);
4591 #else /* NETINET6 */
4592 					memmove(&ia, h->h_addr_list[i],
4593 						INADDRSZ);
4594 					addr = (char *) inet_ntoa(ia);
4595 #endif /* NETINET6 */
4596 					if (addr != NULL)
4597 						dprintf("\taddr: %s\n", addr);
4598 				}
4599 			}
4600 		}
4601 	}
4602 	errno = save_errno;
4603 	return h;
4604 }
4605 
4606 struct hostent *
4607 sm_gethostbyaddr(addr, len, type)
4608 	char *addr;
4609 	int len;
4610 	int type;
4611 {
4612 	struct hostent *hp;
4613 
4614 #if NETINET6
4615 	if (type == AF_INET6 &&
4616 	    IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *) addr))
4617 	{
4618 		/* Avoid reverse lookup for IPv6 unspecified address */
4619 		SM_SET_H_ERRNO(HOST_NOT_FOUND);
4620 		return NULL;
4621 	}
4622 #endif /* NETINET6 */
4623 
4624 #if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204)
4625 # if SOLARIS == 20300 || SOLARIS == 203
4626 	{
4627 		static struct hostent he;
4628 		static char buf[1000];
4629 		extern struct hostent *_switch_gethostbyaddr_r();
4630 
4631 		hp = _switch_gethostbyaddr_r(addr, len, type, &he,
4632 					     buf, sizeof(buf), &h_errno);
4633 	}
4634 # else /* SOLARIS == 20300 || SOLARIS == 203 */
4635 	{
4636 		extern struct hostent *__switch_gethostbyaddr();
4637 
4638 		hp = __switch_gethostbyaddr(addr, len, type);
4639 	}
4640 # endif /* SOLARIS == 20300 || SOLARIS == 203 */
4641 #else /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) */
4642 # if NETINET6
4643 	{
4644 		int err;
4645 
4646 		hp = getipnodebyaddr(addr, len, type, &err);
4647 		SM_SET_H_ERRNO(err);
4648 	}
4649 # else /* NETINET6 */
4650 	hp = gethostbyaddr(addr, len, type);
4651 # endif /* NETINET6 */
4652 #endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) */
4653 	return hp;
4654 }
4655 /*
4656 **  SM_GETPW{NAM,UID} -- wrapper for getpwnam and getpwuid
4657 */
4658 
4659 
4660 struct passwd *
4661 sm_getpwnam(user)
4662 	char *user;
4663 {
4664 # ifdef _AIX4
4665 	extern struct passwd *_getpwnam_shadow(const char *, const int);
4666 
4667 	return _getpwnam_shadow(user, 0);
4668 # else /* _AIX4 */
4669 	return getpwnam(user);
4670 # endif /* _AIX4 */
4671 }
4672 
4673 struct passwd *
4674 sm_getpwuid(uid)
4675 	UID_T uid;
4676 {
4677 # if defined(_AIX4) && 0
4678 	extern struct passwd *_getpwuid_shadow(const int, const int);
4679 
4680 	return _getpwuid_shadow(uid,0);
4681 # else /* defined(_AIX4) && 0 */
4682 	return getpwuid(uid);
4683 # endif /* defined(_AIX4) && 0 */
4684 }
4685 /*
4686 **  SECUREWARE_SETUP_SECURE -- Convex SecureWare setup
4687 **
4688 **	Set up the trusted computing environment for C2 level security
4689 **	under SecureWare.
4690 **
4691 **	Parameters:
4692 **		uid -- uid of the user to initialize in the TCB
4693 **
4694 **	Returns:
4695 **		none
4696 **
4697 **	Side Effects:
4698 **		Initialized the user in the trusted computing base
4699 */
4700 
4701 #if SECUREWARE
4702 
4703 # include <sys/security.h>
4704 # include <prot.h>
4705 
4706 void
4707 secureware_setup_secure(uid)
4708 	UID_T uid;
4709 {
4710 	int rc;
4711 
4712 	if (getluid() != -1)
4713 		return;
4714 
4715 	if ((rc = set_secure_info(uid)) != SSI_GOOD_RETURN)
4716 	{
4717 		switch (rc)
4718 		{
4719 		  case SSI_NO_PRPW_ENTRY:
4720 			syserr("No protected passwd entry, uid = %d", uid);
4721 			break;
4722 
4723 		  case SSI_LOCKED:
4724 			syserr("Account has been disabled, uid = %d", uid);
4725 			break;
4726 
4727 		  case SSI_RETIRED:
4728 			syserr("Account has been retired, uid = %d", uid);
4729 			break;
4730 
4731 		  case SSI_BAD_SET_LUID:
4732 			syserr("Could not set LUID, uid = %d", uid);
4733 			break;
4734 
4735 		  case SSI_BAD_SET_PRIVS:
4736 			syserr("Could not set kernel privs, uid = %d", uid);
4737 
4738 		  default:
4739 			syserr("Unknown return code (%d) from set_secure_info(%d)",
4740 				rc, uid);
4741 			break;
4742 		}
4743 		finis(FALSE, EX_NOPERM);
4744 	}
4745 }
4746 #endif /* SECUREWARE */
4747 /*
4748 **  ADD_HOSTNAMES -- Add a hostname to class 'w' based on IP address
4749 **
4750 **	Add hostnames to class 'w' based on the IP address read from
4751 **	the network interface.
4752 **
4753 **	Parameters:
4754 **		sa -- a pointer to a SOCKADDR containing the address
4755 **
4756 **	Returns:
4757 **		0 if successful, -1 if host lookup fails.
4758 */
4759 
4760 static int
4761 add_hostnames(sa)
4762 	SOCKADDR *sa;
4763 {
4764 	struct hostent *hp;
4765 	char **ha;
4766 	char hnb[MAXHOSTNAMELEN];
4767 
4768 	/* lookup name with IP address */
4769 	switch (sa->sa.sa_family)
4770 	{
4771 #if NETINET
4772 		case AF_INET:
4773 			hp = sm_gethostbyaddr((char *) &sa->sin.sin_addr,
4774 					      sizeof(sa->sin.sin_addr),
4775 					      sa->sa.sa_family);
4776 			break;
4777 #endif /* NETINET */
4778 
4779 #if NETINET6
4780 		case AF_INET6:
4781 			hp = sm_gethostbyaddr((char *) &sa->sin6.sin6_addr,
4782 					      sizeof(sa->sin6.sin6_addr),
4783 					      sa->sa.sa_family);
4784 			break;
4785 #endif /* NETINET6 */
4786 
4787 		default:
4788 			/* Give warning about unsupported family */
4789 			if (LogLevel > 3)
4790 				sm_syslog(LOG_WARNING, NOQID,
4791 					  "Unsupported address family %d: %.100s",
4792 					  sa->sa.sa_family, anynet_ntoa(sa));
4793 			return -1;
4794 	}
4795 
4796 	if (hp == NULL)
4797 	{
4798 		int save_errno = errno;
4799 
4800 		if (LogLevel > 3 &&
4801 #if NETINET6
4802 		    !(sa->sa.sa_family == AF_INET6 &&
4803 		      IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr)) &&
4804 #endif /* NETINET6 */
4805 		    TRUE)
4806 			sm_syslog(LOG_WARNING, NOQID,
4807 				"gethostbyaddr(%.100s) failed: %d\n",
4808 				anynet_ntoa(sa),
4809 #if NAMED_BIND
4810 				h_errno
4811 #else /* NAMED_BIND */
4812 				-1
4813 #endif /* NAMED_BIND */
4814 				);
4815 		errno = save_errno;
4816 		return -1;
4817 	}
4818 
4819 	/* save its cname */
4820 	if (!wordinclass((char *) hp->h_name, 'w'))
4821 	{
4822 		setclass('w', (char *) hp->h_name);
4823 		if (tTd(0, 4))
4824 			dprintf("\ta.k.a.: %s\n", hp->h_name);
4825 
4826 		if (snprintf(hnb, sizeof hnb, "[%s]", hp->h_name) < sizeof hnb
4827 		    && !wordinclass((char *) hnb, 'w'))
4828 			setclass('w', hnb);
4829 	}
4830 	else
4831 	{
4832 		if (tTd(0, 43))
4833 			dprintf("\ta.k.a.: %s (already in $=w)\n", hp->h_name);
4834 	}
4835 
4836 	/* save all it aliases name */
4837 	for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++)
4838 	{
4839 		if (!wordinclass(*ha, 'w'))
4840 		{
4841 			setclass('w', *ha);
4842 			if (tTd(0, 4))
4843 				dprintf("\ta.k.a.: %s\n", *ha);
4844 			if (snprintf(hnb, sizeof hnb,
4845 				     "[%s]", *ha) < sizeof hnb &&
4846 			    !wordinclass((char *) hnb, 'w'))
4847 				setclass('w', hnb);
4848 		}
4849 		else
4850 		{
4851 			if (tTd(0, 43))
4852 				dprintf("\ta.k.a.: %s (already in $=w)\n",
4853 					*ha);
4854 		}
4855 	}
4856 #if _FFR_FREEHOSTENT && NETINET6
4857 	freehostent(hp);
4858 #endif /* _FFR_FREEHOSTENT && NETINET6 */
4859 	return 0;
4860 }
4861 /*
4862 **  LOAD_IF_NAMES -- load interface-specific names into $=w
4863 **
4864 **	Parameters:
4865 **		none.
4866 **
4867 **	Returns:
4868 **		none.
4869 **
4870 **	Side Effects:
4871 **		Loads $=w with the names of all the interfaces.
4872 */
4873 
4874 #if !NETINET
4875 # define SIOCGIFCONF_IS_BROKEN	1 /* XXX */
4876 #endif /* !NETINET */
4877 
4878 #if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
4879 struct rtentry;
4880 struct mbuf;
4881 # ifndef SUNOS403
4882 #  include <sys/time.h>
4883 # endif /* ! SUNOS403 */
4884 # if (_AIX4 >= 40300) && !defined(_NET_IF_H)
4885 #  undef __P
4886 # endif /* (_AIX4 >= 40300) && !defined(_NET_IF_H) */
4887 # include <net/if.h>
4888 #endif /* defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN */
4889 
4890 void
4891 load_if_names()
4892 {
4893 #if NETINET6 && defined(SIOCGLIFCONF)
4894 	int s;
4895 	int i;
4896 	struct lifconf lifc;
4897 	struct lifnum lifn;
4898 	int numifs;
4899 
4900 	s = socket(InetMode, SOCK_DGRAM, 0);
4901 	if (s == -1)
4902 		return;
4903 
4904 	/* get the list of known IP address from the kernel */
4905 #   ifdef SIOCGLIFNUM
4906 	lifn.lifn_family = AF_UNSPEC;
4907 	lifn.lifn_flags = 0;
4908 	if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0)
4909 	{
4910 		/* can't get number of interfaces -- fall back */
4911 		if (tTd(0, 4))
4912 			dprintf("SIOCGLIFNUM failed: %s\n", errstring(errno));
4913 		numifs = -1;
4914 	}
4915 	else
4916 	{
4917 		numifs = lifn.lifn_count;
4918 		if (tTd(0, 42))
4919 			dprintf("system has %d interfaces\n", numifs);
4920 	}
4921 	if (numifs < 0)
4922 #   endif /* SIOCGLIFNUM */
4923 		numifs = MAXINTERFACES;
4924 
4925 	if (numifs <= 0)
4926 	{
4927 		(void) close(s);
4928 		return;
4929 	}
4930 	lifc.lifc_len = numifs * sizeof (struct lifreq);
4931 	lifc.lifc_buf = xalloc(lifc.lifc_len);
4932 	lifc.lifc_family = AF_UNSPEC;
4933 	lifc.lifc_flags = 0;
4934 	if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0)
4935 	{
4936 		if (tTd(0, 4))
4937 			dprintf("SIOCGLIFCONF failed: %s\n", errstring(errno));
4938 		(void) close(s);
4939 		sm_free(lifc.lifc_buf);
4940 		return;
4941 	}
4942 
4943 	/* scan the list of IP address */
4944 	if (tTd(0, 40))
4945 		dprintf("scanning for interface specific names, lifc_len=%d\n",
4946 			lifc.lifc_len);
4947 
4948 	for (i = 0; i < lifc.lifc_len; )
4949 	{
4950 		struct lifreq *ifr = (struct lifreq *)&lifc.lifc_buf[i];
4951 		SOCKADDR *sa = (SOCKADDR *) &ifr->lifr_addr;
4952 		char *addr;
4953 		struct in6_addr ia6;
4954 		struct in_addr ia;
4955 #   ifdef SIOCGLIFFLAGS
4956 		struct lifreq ifrf;
4957 #   endif /* SIOCGLIFFLAGS */
4958 		char ip_addr[256];
4959 		char buf6[INET6_ADDRSTRLEN];
4960 		int af = ifr->lifr_addr.ss_family;
4961 
4962 		/*
4963 		**  We must close and recreate the socket each time
4964 		**  since we don't know what type of socket it is now
4965 		**  (each status function may change it).
4966 		*/
4967 
4968 		(void) close(s);
4969 
4970 		s = socket(af, SOCK_DGRAM, 0);
4971 		if (s == -1)
4972 		{
4973 			sm_free(lifc.lifc_buf);
4974 			return;
4975 		}
4976 
4977 		/*
4978 		**  If we don't have a complete ifr structure,
4979 		**  don't try to use it.
4980 		*/
4981 
4982 		if ((lifc.lifc_len - i) < sizeof *ifr)
4983 			break;
4984 
4985 #   ifdef BSD4_4_SOCKADDR
4986 		if (sa->sa.sa_len > sizeof ifr->lifr_addr)
4987 			i += sizeof ifr->lifr_name + sa->sa.sa_len;
4988 		else
4989 #   endif /* BSD4_4_SOCKADDR */
4990 			i += sizeof *ifr;
4991 
4992 		if (tTd(0, 20))
4993 			dprintf("%s\n", anynet_ntoa(sa));
4994 
4995 		if (af != AF_INET && af != AF_INET6)
4996 			continue;
4997 
4998 #   ifdef SIOCGLIFFLAGS
4999 		memset(&ifrf, '\0', sizeof(struct lifreq));
5000 		(void) strlcpy(ifrf.lifr_name, ifr->lifr_name,
5001 			       sizeof(ifrf.lifr_name));
5002 		if (ioctl(s, SIOCGLIFFLAGS, (char *) &ifrf) < 0)
5003 		{
5004 			if (tTd(0, 4))
5005 				dprintf("SIOCGLIFFLAGS failed: %s\n",
5006 					errstring(errno));
5007 			continue;
5008 		}
5009 		else if (tTd(0, 41))
5010 			dprintf("\tflags: %lx\n",
5011 				(unsigned long)ifrf.lifr_flags);
5012 
5013 		if (!bitset(IFF_UP, ifrf.lifr_flags))
5014 			continue;
5015 #   endif /* SIOCGLIFFLAGS */
5016 
5017 		ip_addr[0] = '\0';
5018 
5019 		/* extract IP address from the list*/
5020 		switch (af)
5021 		{
5022 		  case AF_INET6:
5023 #  ifdef __KAME__
5024 			/* convert into proper scoped address */
5025 			if ((IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr) ||
5026 			     IN6_IS_ADDR_SITELOCAL(&sa->sin6.sin6_addr)) &&
5027 			    sa->sin6.sin6_scope_id == 0)
5028 			{
5029 				struct in6_addr *ia6p;
5030 
5031 				ia6p = &sa->sin6.sin6_addr;
5032 				sa->sin6.sin6_scope_id = ntohs(ia6p->s6_addr[3] |
5033 							       ((unsigned int)ia6p->s6_addr[2] << 8));
5034 				ia6p->s6_addr[2] = ia6p->s6_addr[3] = 0;
5035 			}
5036 #  endif /* __KAME__ */
5037 			ia6 = sa->sin6.sin6_addr;
5038 			if (IN6_IS_ADDR_UNSPECIFIED(&ia6))
5039 			{
5040 				addr = anynet_ntop(&ia6, buf6, sizeof buf6);
5041 				message("WARNING: interface %s is UP with %s address",
5042 					ifr->lifr_name,
5043 					addr == NULL ? "(NULL)" : addr);
5044 				continue;
5045 			}
5046 
5047 			/* save IP address in text from */
5048 			addr = anynet_ntop(&ia6, buf6, sizeof buf6);
5049 			if (addr != NULL)
5050 				(void) snprintf(ip_addr, sizeof ip_addr,
5051 						"[%.*s]",
5052 						(int) sizeof ip_addr - 3, addr);
5053 			break;
5054 
5055 		  case AF_INET:
5056 			ia = sa->sin.sin_addr;
5057 			if (ia.s_addr == INADDR_ANY ||
5058 			    ia.s_addr == INADDR_NONE)
5059 			{
5060 				message("WARNING: interface %s is UP with %s address",
5061 					ifr->lifr_name, inet_ntoa(ia));
5062 				continue;
5063 			}
5064 
5065 			/* save IP address in text from */
5066 			(void) snprintf(ip_addr, sizeof ip_addr, "[%.*s]",
5067 					(int) sizeof ip_addr - 3, inet_ntoa(ia));
5068 			break;
5069 		}
5070 
5071 		if (*ip_addr == '\0')
5072 			continue;
5073 
5074 		if (!wordinclass(ip_addr, 'w'))
5075 		{
5076 			setclass('w', ip_addr);
5077 			if (tTd(0, 4))
5078 				dprintf("\ta.k.a.: %s\n", ip_addr);
5079 		}
5080 
5081 #   ifdef SIOCGLIFFLAGS
5082 		/* skip "loopback" interface "lo" */
5083 		if (bitset(IFF_LOOPBACK, ifrf.lifr_flags))
5084 			continue;
5085 #   endif /* SIOCGLIFFLAGS */
5086 		(void) add_hostnames(sa);
5087 	}
5088 	sm_free(lifc.lifc_buf);
5089 	(void) close(s);
5090 #else /* NETINET6 && defined(SIOCGLIFCONF) */
5091 # if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
5092 	int s;
5093 	int i;
5094 	struct ifconf ifc;
5095 	int numifs;
5096 
5097 	s = socket(AF_INET, SOCK_DGRAM, 0);
5098 	if (s == -1)
5099 		return;
5100 
5101 	/* get the list of known IP address from the kernel */
5102 #  if defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN
5103 	if (ioctl(s, SIOCGIFNUM, (char *) &numifs) < 0)
5104 	{
5105 		/* can't get number of interfaces -- fall back */
5106 		if (tTd(0, 4))
5107 			dprintf("SIOCGIFNUM failed: %s\n", errstring(errno));
5108 		numifs = -1;
5109 	}
5110 	else if (tTd(0, 42))
5111 		dprintf("system has %d interfaces\n", numifs);
5112 	if (numifs < 0)
5113 #  endif /* defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN */
5114 		numifs = MAXINTERFACES;
5115 
5116 	if (numifs <= 0)
5117 	{
5118 		(void) close(s);
5119 		return;
5120 	}
5121 	ifc.ifc_len = numifs * sizeof (struct ifreq);
5122 	ifc.ifc_buf = xalloc(ifc.ifc_len);
5123 	if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0)
5124 	{
5125 		if (tTd(0, 4))
5126 			dprintf("SIOCGIFCONF failed: %s\n", errstring(errno));
5127 		(void) close(s);
5128 		sm_free(ifc.ifc_buf);
5129 		return;
5130 	}
5131 
5132 	/* scan the list of IP address */
5133 	if (tTd(0, 40))
5134 		dprintf("scanning for interface specific names, ifc_len=%d\n",
5135 			ifc.ifc_len);
5136 
5137 	for (i = 0; i < ifc.ifc_len; )
5138 	{
5139 		int af;
5140 		struct ifreq *ifr = (struct ifreq *) &ifc.ifc_buf[i];
5141 		SOCKADDR *sa = (SOCKADDR *) &ifr->ifr_addr;
5142 #   if NETINET6
5143 		char *addr;
5144 		struct in6_addr ia6;
5145 #   endif /* NETINET6 */
5146 		struct in_addr ia;
5147 #   ifdef SIOCGIFFLAGS
5148 		struct ifreq ifrf;
5149 #   endif /* SIOCGIFFLAGS */
5150 		char ip_addr[256];
5151 #   if NETINET6
5152 		char buf6[INET6_ADDRSTRLEN];
5153 #   endif /* NETINET6 */
5154 
5155 		/*
5156 		**  If we don't have a complete ifr structure,
5157 		**  don't try to use it.
5158 		*/
5159 
5160 		if ((ifc.ifc_len - i) < sizeof *ifr)
5161 			break;
5162 
5163 #   ifdef BSD4_4_SOCKADDR
5164 		if (sa->sa.sa_len > sizeof ifr->ifr_addr)
5165 			i += sizeof ifr->ifr_name + sa->sa.sa_len;
5166 		else
5167 #   endif /* BSD4_4_SOCKADDR */
5168 			i += sizeof *ifr;
5169 
5170 		if (tTd(0, 20))
5171 			dprintf("%s\n", anynet_ntoa(sa));
5172 
5173 		af = ifr->ifr_addr.sa_family;
5174 		if (af != AF_INET
5175 #   if NETINET6
5176 		    && af != AF_INET6
5177 #   endif /* NETINET6 */
5178 		    )
5179 			continue;
5180 
5181 #   ifdef SIOCGIFFLAGS
5182 		memset(&ifrf, '\0', sizeof(struct ifreq));
5183 		(void) strlcpy(ifrf.ifr_name, ifr->ifr_name,
5184 			       sizeof(ifrf.ifr_name));
5185 		(void) ioctl(s, SIOCGIFFLAGS, (char *) &ifrf);
5186 		if (tTd(0, 41))
5187 			dprintf("\tflags: %lx\n",
5188 				(unsigned long) ifrf.ifr_flags);
5189 #    define IFRFREF ifrf
5190 #   else /* SIOCGIFFLAGS */
5191 #    define IFRFREF (*ifr)
5192 #   endif /* SIOCGIFFLAGS */
5193 
5194 		if (!bitset(IFF_UP, IFRFREF.ifr_flags))
5195 			continue;
5196 
5197 		ip_addr[0] = '\0';
5198 
5199 		/* extract IP address from the list*/
5200 		switch (af)
5201 		{
5202 		  case AF_INET:
5203 			ia = sa->sin.sin_addr;
5204 			if (ia.s_addr == INADDR_ANY ||
5205 			    ia.s_addr == INADDR_NONE)
5206 			{
5207 				message("WARNING: interface %s is UP with %s address",
5208 					ifr->ifr_name, inet_ntoa(ia));
5209 				continue;
5210 			}
5211 
5212 			/* save IP address in text from */
5213 			(void) snprintf(ip_addr, sizeof ip_addr, "[%.*s]",
5214 					(int) sizeof ip_addr - 3,
5215 					inet_ntoa(ia));
5216 			break;
5217 
5218 #   if NETINET6
5219 		  case AF_INET6:
5220 #    ifdef __KAME__
5221 			/* convert into proper scoped address */
5222 			if ((IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr) ||
5223 			     IN6_IS_ADDR_SITELOCAL(&sa->sin6.sin6_addr)) &&
5224 			    sa->sin6.sin6_scope_id == 0)
5225 			{
5226 				struct in6_addr *ia6p;
5227 
5228 				ia6p = &sa->sin6.sin6_addr;
5229 				sa->sin6.sin6_scope_id = ntohs(ia6p->s6_addr[3] |
5230 							       ((unsigned int)ia6p->s6_addr[2] << 8));
5231 				ia6p->s6_addr[2] = ia6p->s6_addr[3] = 0;
5232 			}
5233 #    endif /* __KAME__ */
5234 			ia6 = sa->sin6.sin6_addr;
5235 			if (IN6_IS_ADDR_UNSPECIFIED(&ia6))
5236 			{
5237 				addr = anynet_ntop(&ia6, buf6, sizeof buf6);
5238 				message("WARNING: interface %s is UP with %s address",
5239 					ifr->ifr_name,
5240 					addr == NULL ? "(NULL)" : addr);
5241 				continue;
5242 			}
5243 
5244 			/* save IP address in text from */
5245 			addr = anynet_ntop(&ia6, buf6, sizeof buf6);
5246 			if (addr != NULL)
5247 				(void) snprintf(ip_addr, sizeof ip_addr,
5248 						"[%.*s]",
5249 						(int) sizeof ip_addr - 3, addr);
5250 			break;
5251 
5252 #   endif /* NETINET6 */
5253 		}
5254 
5255 		if (ip_addr[0] == '\0')
5256 			continue;
5257 
5258 		if (!wordinclass(ip_addr, 'w'))
5259 		{
5260 			setclass('w', ip_addr);
5261 			if (tTd(0, 4))
5262 				dprintf("\ta.k.a.: %s\n", ip_addr);
5263 		}
5264 
5265 		/* skip "loopback" interface "lo" */
5266 		if (bitset(IFF_LOOPBACK, IFRFREF.ifr_flags))
5267 			continue;
5268 
5269 		(void) add_hostnames(sa);
5270 	}
5271 	sm_free(ifc.ifc_buf);
5272 	(void) close(s);
5273 #  undef IFRFREF
5274 # endif /* defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN */
5275 #endif /* NETINET6 && defined(SIOCGLIFCONF) */
5276 }
5277 /*
5278 **  ISLOOPBACK -- is socket address in the loopback net?
5279 **
5280 **	Parameters:
5281 **		sa -- socket address.
5282 **
5283 **	Returns:
5284 **		TRUE -- is socket address in the loopback net?
5285 **		FALSE -- otherwise
5286 **
5287 */
5288 
5289 bool
5290 isloopback(sa)
5291 	SOCKADDR sa;
5292 {
5293 #if NETINET6
5294 	if (IN6_IS_ADDR_LOOPBACK(&sa.sin6.sin6_addr))
5295 		return TRUE;
5296 #else /* NETINET6 */
5297 	/* XXX how to correctly extract IN_LOOPBACKNET part? */
5298 	if (((ntohl(sa.sin.sin_addr.s_addr) & IN_CLASSA_NET)
5299 	     >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
5300 		return TRUE;
5301 #endif /* NETINET6 */
5302 	return FALSE;
5303 }
5304 /*
5305 **  GET_NUM_PROCS_ONLINE -- return the number of processors currently online
5306 **
5307 **	Parameters:
5308 **		none.
5309 **
5310 **	Returns:
5311 **		The number of processors online.
5312 */
5313 
5314 static int
5315 get_num_procs_online()
5316 {
5317 	int nproc = 0;
5318 
5319 #ifdef USESYSCTL
5320 # if defined(CTL_HW) && defined(HW_NCPU)
5321 	size_t sz;
5322 	int mib[2];
5323 
5324 	mib[0] = CTL_HW;
5325 	mib[1] = HW_NCPU;
5326 	sz = (size_t) sizeof nproc;
5327 	(void) sysctl(mib, 2, &nproc, &sz, NULL, 0);
5328 # endif /* defined(CTL_HW) && defined(HW_NCPUS) */
5329 #else /* USESYSCTL */
5330 # ifdef _SC_NPROCESSORS_ONLN
5331 	nproc = (int) sysconf(_SC_NPROCESSORS_ONLN);
5332 # else /* _SC_NPROCESSORS_ONLN */
5333 #  ifdef __hpux
5334 #   include <sys/pstat.h>
5335 	struct pst_dynamic psd;
5336 
5337 	if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) != -1)
5338 		nproc = psd.psd_proc_cnt;
5339 #  endif /* __hpux */
5340 # endif /* _SC_NPROCESSORS_ONLN */
5341 #endif /* USESYSCTL */
5342 
5343 	if (nproc <= 0)
5344 		nproc = 1;
5345 	return nproc;
5346 }
5347 /*
5348 **  SEED_RANDOM -- seed the random number generator
5349 **
5350 **	Parameters:
5351 **		none
5352 **
5353 **	Returns:
5354 **		none
5355 */
5356 
5357 void
5358 seed_random()
5359 {
5360 #if HASSRANDOMDEV
5361 	srandomdev();
5362 #else /* HASSRANDOMDEV */
5363 	long seed;
5364 	struct timeval t;
5365 
5366 	seed = (long) getpid();
5367 	if (gettimeofday(&t, NULL) >= 0)
5368 		seed += t.tv_sec + t.tv_usec;
5369 
5370 # if HASRANDOM
5371 	(void) srandom(seed);
5372 # else /* HASRANDOM */
5373 	(void) srand((unsigned int) seed);
5374 # endif /* HASRANDOM */
5375 #endif /* HASSRANDOMDEV */
5376 }
5377 /*
5378 **  SM_SYSLOG -- syslog wrapper to keep messages under SYSLOG_BUFSIZE
5379 **
5380 **	Parameters:
5381 **		level -- syslog level
5382 **		id -- envelope ID or NULL (NOQUEUE)
5383 **		fmt -- format string
5384 **		arg... -- arguments as implied by fmt.
5385 **
5386 **	Returns:
5387 **		none
5388 */
5389 
5390 /* VARARGS3 */
5391 void
5392 #ifdef __STDC__
5393 sm_syslog(int level, const char *id, const char *fmt, ...)
5394 #else /* __STDC__ */
5395 sm_syslog(level, id, fmt, va_alist)
5396 	int level;
5397 	const char *id;
5398 	const char *fmt;
5399 	va_dcl
5400 #endif /* __STDC__ */
5401 {
5402 	static char *buf = NULL;
5403 	static size_t bufsize;
5404 	char *begin, *end;
5405 	int save_errno;
5406 	int seq = 1;
5407 	int idlen;
5408 	char buf0[MAXLINE];
5409 	extern int SnprfOverflow;
5410 	extern int SyslogErrno;
5411 	extern char *DoprEnd;
5412 	VA_LOCAL_DECL
5413 
5414 	save_errno = SyslogErrno = errno;
5415 	if (id == NULL)
5416 		id = "NOQUEUE";
5417 	else if (strcmp(id, NOQID) == 0)
5418 		id = "";
5419 	idlen = strlen(id);
5420 
5421 	if (buf == NULL)
5422 	{
5423 		buf = buf0;
5424 		bufsize = sizeof buf0;
5425 	}
5426 
5427 	for (;;)
5428 	{
5429 		/* do a virtual vsnprintf into buf */
5430 		VA_START(fmt);
5431 		buf[0] = 0;
5432 		DoprEnd = buf + bufsize - 1;
5433 		SnprfOverflow = 0;
5434 		sm_dopr(buf, fmt, ap);
5435 		*DoprEnd = '\0';
5436 		VA_END;
5437 		/* end of virtual vsnprintf */
5438 
5439 		if (SnprfOverflow == 0)
5440 			break;
5441 
5442 		/* String too small, redo with correct size */
5443 		bufsize += SnprfOverflow + 1;
5444 		if (buf != buf0)
5445 			sm_free(buf);
5446 		buf = xalloc(bufsize * sizeof (char));
5447 	}
5448 	if ((strlen(buf) + idlen + 1) < SYSLOG_BUFSIZE)
5449 	{
5450 #if LOG
5451 		if (*id == '\0')
5452 			syslog(level, "%s", buf);
5453 		else
5454 			syslog(level, "%s: %s", id, buf);
5455 #else /* LOG */
5456 		/*XXX should do something more sensible */
5457 		if (*id == '\0')
5458 			fprintf(stderr, "%s\n", buf);
5459 		else
5460 			fprintf(stderr, "%s: %s\n", id, buf);
5461 #endif /* LOG */
5462 		if (buf == buf0)
5463 			buf = NULL;
5464 		errno = save_errno;
5465 		return;
5466 	}
5467 
5468 	begin = buf;
5469 	while (*begin != '\0' &&
5470 	       (strlen(begin) + idlen + 5) > SYSLOG_BUFSIZE)
5471 	{
5472 		char save;
5473 
5474 		if (seq == 999)
5475 		{
5476 			/* Too many messages */
5477 			break;
5478 		}
5479 		end = begin + SYSLOG_BUFSIZE - idlen - 12;
5480 		while (end > begin)
5481 		{
5482 			/* Break on comma or space */
5483 			if (*end == ',' || *end == ' ')
5484 			{
5485 				end++;	  /* Include separator */
5486 				break;
5487 			}
5488 			end--;
5489 		}
5490 		/* No separator, break midstring... */
5491 		if (end == begin)
5492 			end = begin + SYSLOG_BUFSIZE - idlen - 12;
5493 		save = *end;
5494 		*end = 0;
5495 #if LOG
5496 		syslog(level, "%s[%d]: %s ...", id, seq++, begin);
5497 #else /* LOG */
5498 		fprintf(stderr, "%s[%d]: %s ...\n", id, seq++, begin);
5499 #endif /* LOG */
5500 		*end = save;
5501 		begin = end;
5502 	}
5503 	if (seq == 999)
5504 #if LOG
5505 		syslog(level, "%s[%d]: log terminated, too many parts",
5506 			id, seq);
5507 #else /* LOG */
5508 		fprintf(stderr, "%s[%d]: log terminated, too many parts\n",
5509 			id, seq);
5510 #endif /* LOG */
5511 	else if (*begin != '\0')
5512 #if LOG
5513 		syslog(level, "%s[%d]: %s", id, seq, begin);
5514 #else /* LOG */
5515 		fprintf(stderr, "%s[%d]: %s\n", id, seq, begin);
5516 #endif /* LOG */
5517 	if (buf == buf0)
5518 		buf = NULL;
5519 	errno = save_errno;
5520 }
5521 /*
5522 **  HARD_SYSLOG -- call syslog repeatedly until it works
5523 **
5524 **	Needed on HP-UX, which apparently doesn't guarantee that
5525 **	syslog succeeds during interrupt handlers.
5526 */
5527 
5528 #if defined(__hpux) && !defined(HPUX11)
5529 
5530 # define MAXSYSLOGTRIES	100
5531 # undef syslog
5532 # ifdef V4FS
5533 #  define XCNST	const
5534 #  define CAST	(const char *)
5535 # else /* V4FS */
5536 #  define XCNST
5537 #  define CAST
5538 # endif /* V4FS */
5539 
5540 void
5541 # ifdef __STDC__
5542 hard_syslog(int pri, XCNST char *msg, ...)
5543 # else /* __STDC__ */
5544 hard_syslog(pri, msg, va_alist)
5545 	int pri;
5546 	XCNST char *msg;
5547 	va_dcl
5548 # endif /* __STDC__ */
5549 {
5550 	int i;
5551 	char buf[SYSLOG_BUFSIZE];
5552 	VA_LOCAL_DECL;
5553 
5554 	VA_START(msg);
5555 	vsnprintf(buf, sizeof buf, msg, ap);
5556 	VA_END;
5557 
5558 	for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, CAST "%s", buf) < 0; )
5559 		continue;
5560 }
5561 
5562 # undef CAST
5563 #endif /* defined(__hpux) && !defined(HPUX11) */
5564 #if NEEDLOCAL_HOSTNAME_LENGTH
5565 /*
5566 **  LOCAL_HOSTNAME_LENGTH
5567 **
5568 **	This is required to get sendmail to compile against BIND 4.9.x
5569 **	on Ultrix.
5570 **
5571 **	Unfortunately, a Compaq Y2K patch kit provides it without
5572 **	bumping __RES in /usr/include/resolv.h so we can't automatically
5573 **	figure out whether it is needed.
5574 */
5575 
5576 int
5577 local_hostname_length(hostname)
5578 	char *hostname;
5579 {
5580 	int len_host, len_domain;
5581 
5582 	if (!*_res.defdname)
5583 		res_init();
5584 	len_host = strlen(hostname);
5585 	len_domain = strlen(_res.defdname);
5586 	if (len_host > len_domain &&
5587 	    (strcasecmp(hostname + len_host - len_domain,
5588 			_res.defdname) == 0) &&
5589 	    hostname[len_host - len_domain - 1] == '.')
5590 		return len_host - len_domain - 1;
5591 	else
5592 		return 0;
5593 }
5594 #endif /* NEEDLOCAL_HOSTNAME_LENGTH */
5595 
5596 /*
5597 **  Compile-Time options
5598 */
5599 
5600 char	*CompileOptions[] =
5601 {
5602 #if EGD
5603 	"EGD",
5604 #endif /* EGD */
5605 #ifdef HESIOD
5606 	"HESIOD",
5607 #endif /* HESIOD */
5608 #if HES_GETMAILHOST
5609 	"HES_GETMAILHOST",
5610 #endif /* HES_GETMAILHOST */
5611 #ifdef LDAPMAP
5612 	"LDAPMAP",
5613 #endif /* LDAPMAP */
5614 #ifdef MAP_NSD
5615 	"MAP_NSD",
5616 #endif /* MAP_NSD */
5617 #ifdef MAP_REGEX
5618 	"MAP_REGEX",
5619 #endif /* MAP_REGEX */
5620 #if LOG
5621 	"LOG",
5622 #endif /* LOG */
5623 #if MATCHGECOS
5624 	"MATCHGECOS",
5625 #endif /* MATCHGECOS */
5626 #if MIME7TO8
5627 	"MIME7TO8",
5628 #endif /* MIME7TO8 */
5629 #if MIME8TO7
5630 	"MIME8TO7",
5631 #endif /* MIME8TO7 */
5632 #if NAMED_BIND
5633 	"NAMED_BIND",
5634 #endif /* NAMED_BIND */
5635 #ifdef NDBM
5636 	"NDBM",
5637 #endif /* NDBM */
5638 #if NETINET
5639 	"NETINET",
5640 #endif /* NETINET */
5641 #if NETINET6
5642 	"NETINET6",
5643 #endif /* NETINET6 */
5644 #if NETINFO
5645 	"NETINFO",
5646 #endif /* NETINFO */
5647 #if NETISO
5648 	"NETISO",
5649 #endif /* NETISO */
5650 #if NETNS
5651 	"NETNS",
5652 #endif /* NETNS */
5653 #if NETUNIX
5654 	"NETUNIX",
5655 #endif /* NETUNIX */
5656 #if NETX25
5657 	"NETX25",
5658 #endif /* NETX25 */
5659 #ifdef NEWDB
5660 	"NEWDB",
5661 #endif /* NEWDB */
5662 #ifdef NIS
5663 	"NIS",
5664 #endif /* NIS */
5665 #ifdef NISPLUS
5666 	"NISPLUS",
5667 #endif /* NISPLUS */
5668 #ifdef PH_MAP
5669 	"PH_MAP",
5670 #endif /* PH_MAP */
5671 #if QUEUE
5672 	"QUEUE",
5673 #endif /* QUEUE */
5674 #if SASL
5675 	"SASL",
5676 #endif /* SASL */
5677 #if SCANF
5678 	"SCANF",
5679 #endif /* SCANF */
5680 #if SFIO
5681 	"SFIO",
5682 #endif /* SFIO */
5683 #if SMTP
5684 	"SMTP",
5685 #endif /* SMTP */
5686 #if SMTPDEBUG
5687 	"SMTPDEBUG",
5688 #endif /* SMTPDEBUG */
5689 #if STARTTLS
5690 	"STARTTLS",
5691 #endif /* STARTTLS */
5692 #ifdef SUID_ROOT_FILES_OK
5693 	"SUID_ROOT_FILES_OK",
5694 #endif /* SUID_ROOT_FILES_OK */
5695 #if TCPWRAPPERS
5696 	"TCPWRAPPERS",
5697 #endif /* TCPWRAPPERS */
5698 #if USERDB
5699 	"USERDB",
5700 #endif /* USERDB */
5701 #if XDEBUG
5702 	"XDEBUG",
5703 #endif /* XDEBUG */
5704 #ifdef XLA
5705 	"XLA",
5706 #endif /* XLA */
5707 	NULL
5708 };
5709 
5710 
5711 /*
5712 **  OS compile options.
5713 */
5714 
5715 char	*OsCompileOptions[] =
5716 {
5717 #if BOGUS_O_EXCL
5718 	"BOGUS_O_EXCL",
5719 #endif /* BOGUS_O_EXCL */
5720 #if FAST_PID_RECYCLE
5721 	"FAST_PID_RECYCLE",
5722 #endif /* FAST_PID_RECYCLE */
5723 #if HASFCHOWN
5724 	"HASFCHOWN",
5725 #endif /* HASFCHOWN */
5726 #if HASFCHMOD
5727 	"HASFCHMOD",
5728 #endif /* HASFCHMOD */
5729 #if HASFLOCK
5730 	"HASFLOCK",
5731 #endif /* HASFLOCK */
5732 #if HASGETDTABLESIZE
5733 	"HASGETDTABLESIZE",
5734 #endif /* HASGETDTABLESIZE */
5735 #if HASGETUSERSHELL
5736 	"HASGETUSERSHELL",
5737 #endif /* HASGETUSERSHELL */
5738 #if HASINITGROUPS
5739 	"HASINITGROUPS",
5740 #endif /* HASINITGROUPS */
5741 #if HASLSTAT
5742 	"HASLSTAT",
5743 #endif /* HASLSTAT */
5744 #if HASRANDOM
5745 	"HASRANDOM",
5746 #endif /* HASRANDOM */
5747 #if HASSETLOGIN
5748 	"HASSETLOGIN",
5749 #endif /* HASSETLOGIN */
5750 #if HASSETREUID
5751 	"HASSETREUID",
5752 #endif /* HASSETREUID */
5753 #if HASSETRLIMIT
5754 	"HASSETRLIMIT",
5755 #endif /* HASSETRLIMIT */
5756 #if HASSETSID
5757 	"HASSETSID",
5758 #endif /* HASSETSID */
5759 #if HASSETUSERCONTEXT
5760 	"HASSETUSERCONTEXT",
5761 #endif /* HASSETUSERCONTEXT */
5762 #if HASSETVBUF
5763 	"HASSETVBUF",
5764 #endif /* HASSETVBUF */
5765 #if HASSNPRINTF
5766 	"HASSNPRINTF",
5767 #endif /* HASSNPRINTF */
5768 #if HAS_ST_GEN
5769 	"HAS_ST_GEN",
5770 #endif /* HAS_ST_GEN */
5771 #if HASSRANDOMDEV
5772 	"HASSRANDOMDEV",
5773 #endif /* HASSRANDOMDEV */
5774 #if HASURANDOMDEV
5775 	"HASURANDOMDEV",
5776 #endif /* HASURANDOMDEV */
5777 #if HASSTRERROR
5778 	"HASSTRERROR",
5779 #endif /* HASSTRERROR */
5780 #if HASULIMIT
5781 	"HASULIMIT",
5782 #endif /* HASULIMIT */
5783 #if HASUNAME
5784 	"HASUNAME",
5785 #endif /* HASUNAME */
5786 #if HASUNSETENV
5787 	"HASUNSETENV",
5788 #endif /* HASUNSETENV */
5789 #if HASWAITPID
5790 	"HASWAITPID",
5791 #endif /* HASWAITPID */
5792 #if IDENTPROTO
5793 	"IDENTPROTO",
5794 #endif /* IDENTPROTO */
5795 #if IP_SRCROUTE
5796 	"IP_SRCROUTE",
5797 #endif /* IP_SRCROUTE */
5798 #if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
5799 	"LOCK_ON_OPEN",
5800 #endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
5801 #if NEEDFSYNC
5802 	"NEEDFSYNC",
5803 #endif /* NEEDFSYNC */
5804 #if NOFTRUNCATE
5805 	"NOFTRUNCATE",
5806 #endif /* NOFTRUNCATE */
5807 #if RLIMIT_NEEDS_SYS_TIME_H
5808 	"RLIMIT_NEEDS_SYS_TIME_H",
5809 #endif /* RLIMIT_NEEDS_SYS_TIME_H */
5810 #if SAFENFSPATHCONF
5811 	"SAFENFSPATHCONF",
5812 #endif /* SAFENFSPATHCONF */
5813 #if SECUREWARE
5814 	"SECUREWARE",
5815 #endif /* SECUREWARE */
5816 #if SHARE_V1
5817 	"SHARE_V1",
5818 #endif /* SHARE_V1 */
5819 #if SIOCGIFCONF_IS_BROKEN
5820 	"SIOCGIFCONF_IS_BROKEN",
5821 #endif /* SIOCGIFCONF_IS_BROKEN */
5822 #if SIOCGIFNUM_IS_BROKEN
5823 	"SIOCGIFNUM_IS_BROKEN",
5824 #endif /* SIOCGIFNUM_IS_BROKEN */
5825 #if SNPRINTF_IS_BROKEN
5826 	"SNPRINTF_IS_BROKEN",
5827 #endif /* SNPRINTF_IS_BROKEN */
5828 #if SO_REUSEADDR_IS_BROKEN
5829 	"SO_REUSEADDR_IS_BROKEN",
5830 #endif /* SO_REUSEADDR_IS_BROKEN */
5831 #if SYS5SETPGRP
5832 	"SYS5SETPGRP",
5833 #endif /* SYS5SETPGRP */
5834 #if SYSTEM5
5835 	"SYSTEM5",
5836 #endif /* SYSTEM5 */
5837 #if USE_SA_SIGACTION
5838 	"USE_SA_SIGACTION",
5839 #endif /* USE_SA_SIGACTION */
5840 #if USE_SIGLONGJMP
5841 	"USE_SIGLONGJMP",
5842 #endif /* USE_SIGLONGJMP */
5843 #if USESETEUID
5844 	"USESETEUID",
5845 #endif /* USESETEUID */
5846 	NULL
5847 };
5848 
5849