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