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