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