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