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