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