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