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