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