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