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