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