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