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