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