xref: /csrg-svn/usr.sbin/sendmail/src/conf.c (revision 68433)
1 /*
2  * Copyright (c) 1983 Eric P. Allman
3  * Copyright (c) 1988, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 static char sccsid[] = "@(#)conf.c	8.132 (Berkeley) 02/23/95";
11 #endif /* not lint */
12 
13 # include "sendmail.h"
14 # include "pathnames.h"
15 # include <sys/ioctl.h>
16 # include <sys/param.h>
17 # include <netdb.h>
18 # include <pwd.h>
19 
20 /*
21 **  CONF.C -- Sendmail Configuration Tables.
22 **
23 **	Defines the configuration of this installation.
24 **
25 **	Configuration Variables:
26 **		HdrInfo -- a table describing well-known header fields.
27 **			Each entry has the field name and some flags,
28 **			which are described in sendmail.h.
29 **
30 **	Notes:
31 **		I have tried to put almost all the reasonable
32 **		configuration information into the configuration
33 **		file read at runtime.  My intent is that anything
34 **		here is a function of the version of UNIX you
35 **		are running, or is really static -- for example
36 **		the headers are a superset of widely used
37 **		protocols.  If you find yourself playing with
38 **		this file too much, you may be making a mistake!
39 */
40 
41 
42 
43 
44 /*
45 **  Header info table
46 **	Final (null) entry contains the flags used for any other field.
47 **
48 **	Not all of these are actually handled specially by sendmail
49 **	at this time.  They are included as placeholders, to let
50 **	you know that "someday" I intend to have sendmail do
51 **	something with them.
52 */
53 
54 struct hdrinfo	HdrInfo[] =
55 {
56 		/* originator fields, most to least significant  */
57 	"resent-sender",		H_FROM|H_RESENT,
58 	"resent-from",			H_FROM|H_RESENT,
59 	"resent-reply-to",		H_FROM|H_RESENT,
60 	"sender",			H_FROM,
61 	"from",				H_FROM,
62 	"reply-to",			H_FROM,
63 	"full-name",			H_ACHECK,
64 	"return-receipt-to",		H_FROM|H_RECEIPTTO,
65 	"errors-to",			H_FROM|H_ERRORSTO,
66 
67 		/* destination fields */
68 	"to",				H_RCPT,
69 	"resent-to",			H_RCPT|H_RESENT,
70 	"cc",				H_RCPT,
71 	"resent-cc",			H_RCPT|H_RESENT,
72 	"bcc",				H_RCPT|H_ACHECK,
73 	"resent-bcc",			H_RCPT|H_ACHECK|H_RESENT,
74 	"apparently-to",		H_RCPT,
75 
76 		/* message identification and control */
77 	"message-id",			0,
78 	"resent-message-id",		H_RESENT,
79 	"message",			H_EOH,
80 	"text",				H_EOH,
81 
82 		/* date fields */
83 	"date",				0,
84 	"resent-date",			H_RESENT,
85 
86 		/* trace fields */
87 	"received",			H_TRACE|H_FORCE,
88 	"x400-received",		H_TRACE|H_FORCE,
89 	"via",				H_TRACE|H_FORCE,
90 	"mail-from",			H_TRACE|H_FORCE,
91 
92 		/* miscellaneous fields */
93 	"comments",			H_FORCE,
94 	"return-path",			H_FORCE|H_ACHECK,
95 	"content-transfer-encoding",	H_CTE,
96 	"content-type",			H_CTYPE,
97 
98 	NULL,			0,
99 };
100 
101 
102 
103 /*
104 **  Location of system files/databases/etc.
105 */
106 
107 char	*PidFile =	_PATH_SENDMAILPID;	/* stores daemon proc id */
108 
109 
110 
111 /*
112 **  Privacy values
113 */
114 
115 struct prival PrivacyValues[] =
116 {
117 	"public",		PRIV_PUBLIC,
118 	"needmailhelo",		PRIV_NEEDMAILHELO,
119 	"needexpnhelo",		PRIV_NEEDEXPNHELO,
120 	"needvrfyhelo",		PRIV_NEEDVRFYHELO,
121 	"noexpn",		PRIV_NOEXPN,
122 	"novrfy",		PRIV_NOVRFY,
123 	"restrictmailq",	PRIV_RESTRICTMAILQ,
124 	"restrictqrun",		PRIV_RESTRICTQRUN,
125 	"authwarnings",		PRIV_AUTHWARNINGS,
126 	"noreceipts",		PRIV_NORECEIPTS,
127 	"goaway",		PRIV_GOAWAY,
128 	NULL,			0,
129 };
130 
131 
132 
133 /*
134 **  Miscellaneous stuff.
135 */
136 
137 int	DtableSize =	50;		/* max open files; reset in 4.2bsd */
138 /*
139 **  SETDEFAULTS -- set default values
140 **
141 **	Because of the way freezing is done, these must be initialized
142 **	using direct code.
143 **
144 **	Parameters:
145 **		e -- the default envelope.
146 **
147 **	Returns:
148 **		none.
149 **
150 **	Side Effects:
151 **		Initializes a bunch of global variables to their
152 **		default values.
153 */
154 
155 #define DAYS		* 24 * 60 * 60
156 
157 void
158 setdefaults(e)
159 	register ENVELOPE *e;
160 {
161 	int i;
162 	extern void inittimeouts();
163 	extern void setdefuser();
164 	extern void setupmaps();
165 	extern void setupmailers();
166 
167 	SpaceSub = ' ';				/* option B */
168 	QueueLA = 8;				/* option x */
169 	RefuseLA = 12;				/* option X */
170 	WkRecipFact = 30000L;			/* option y */
171 	WkClassFact = 1800L;			/* option z */
172 	WkTimeFact = 90000L;			/* option Z */
173 	QueueFactor = WkRecipFact * 20;		/* option q */
174 	FileMode = (RealUid != geteuid()) ? 0644 : 0600;
175 						/* option F */
176 	DefUid = 1;				/* option u */
177 	DefGid = 1;				/* option g */
178 	CheckpointInterval = 10;		/* option C */
179 	MaxHopCount = 25;			/* option h */
180 	e->e_sendmode = SM_FORK;		/* option d */
181 	e->e_errormode = EM_PRINT;		/* option e */
182 	SevenBitInput = FALSE;			/* option 7 */
183 	MaxMciCache = 1;			/* option k */
184 	MciCacheTimeout = 300;			/* option K */
185 	LogLevel = 9;				/* option L */
186 	inittimeouts(NULL);			/* option r */
187 	PrivacyFlags = 0;			/* option p */
188 	MimeMode = MM_CVTMIME|MM_PASS8BIT;	/* option 8 */
189 	for (i = 0; i < MAXTOCLASS; i++)
190 	{
191 		TimeOuts.to_q_return[i] = 5 DAYS;	/* option T */
192 		TimeOuts.to_q_warning[i] = 0;		/* option T */
193 	}
194 	ServiceSwitchFile = "/etc/service.switch";
195 	setdefuser();
196 	setupmaps();
197 	setupmailers();
198 }
199 
200 
201 /*
202 **  SETDEFUSER -- set/reset DefUser using DefUid (for initgroups())
203 */
204 
205 void
206 setdefuser()
207 {
208 	struct passwd *defpwent;
209 	static char defuserbuf[40];
210 
211 	DefUser = defuserbuf;
212 	if ((defpwent = getpwuid(DefUid)) != NULL)
213 		strcpy(defuserbuf, defpwent->pw_name);
214 	else
215 		strcpy(defuserbuf, "nobody");
216 }
217 /*
218 **  HOST_MAP_INIT -- initialize host class structures
219 */
220 
221 bool	host_map_init __P((MAP *map, char *args));
222 
223 bool
224 host_map_init(map, args)
225 	MAP *map;
226 	char *args;
227 {
228 	register char *p = args;
229 
230 	for (;;)
231 	{
232 		while (isascii(*p) && isspace(*p))
233 			p++;
234 		if (*p != '-')
235 			break;
236 		switch (*++p)
237 		{
238 		  case 'a':
239 			map->map_app = ++p;
240 			break;
241 		}
242 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
243 			p++;
244 		if (*p != '\0')
245 			*p++ = '\0';
246 	}
247 	if (map->map_app != NULL)
248 		map->map_app = newstr(map->map_app);
249 	return TRUE;
250 }
251 /*
252 **  SETUPMAILERS -- initialize default mailers
253 */
254 
255 void
256 setupmailers()
257 {
258 	char buf[100];
259 	extern void makemailer();
260 
261 	strcpy(buf, "prog, P=/bin/sh, F=lsoD, A=sh -c $u");
262 	makemailer(buf);
263 
264 	strcpy(buf, "*file*, P=/dev/null, F=lsDFMPEou, A=FILE");
265 	makemailer(buf);
266 
267 	strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE");
268 	makemailer(buf);
269 }
270 /*
271 **  SETUPMAPS -- set up map classes
272 */
273 
274 #define MAPDEF(name, ext, flags, parse, open, close, lookup, store) \
275 	{ \
276 		extern bool parse __P((MAP *, char *)); \
277 		extern bool open __P((MAP *, int)); \
278 		extern void close __P((MAP *)); \
279 		extern char *lookup __P((MAP *, char *, char **, int *)); \
280 		extern void store __P((MAP *, char *, char *)); \
281 		s = stab(name, ST_MAPCLASS, ST_ENTER); \
282 		s->s_mapclass.map_cname = name; \
283 		s->s_mapclass.map_ext = ext; \
284 		s->s_mapclass.map_cflags = flags; \
285 		s->s_mapclass.map_parse = parse; \
286 		s->s_mapclass.map_open = open; \
287 		s->s_mapclass.map_close = close; \
288 		s->s_mapclass.map_lookup = lookup; \
289 		s->s_mapclass.map_store = store; \
290 	}
291 
292 void
293 setupmaps()
294 {
295 	register STAB *s;
296 
297 #ifdef NEWDB
298 	MAPDEF("hash", ".db", MCF_ALIASOK|MCF_REBUILDABLE,
299 		map_parseargs, hash_map_open, db_map_close,
300 		db_map_lookup, db_map_store);
301 
302 	MAPDEF("btree", ".db", MCF_ALIASOK|MCF_REBUILDABLE,
303 		map_parseargs, bt_map_open, db_map_close,
304 		db_map_lookup, db_map_store);
305 #endif
306 
307 #ifdef NDBM
308 	MAPDEF("dbm", ".dir", MCF_ALIASOK|MCF_REBUILDABLE,
309 		map_parseargs, ndbm_map_open, ndbm_map_close,
310 		ndbm_map_lookup, ndbm_map_store);
311 #endif
312 
313 #ifdef NIS
314 	MAPDEF("nis", NULL, MCF_ALIASOK,
315 		map_parseargs, nis_map_open, null_map_close,
316 		nis_map_lookup, null_map_store);
317 #endif
318 
319 #ifdef NISPLUS
320 	MAPDEF("nisplus", NULL, MCF_ALIASOK,
321 		map_parseargs, nisplus_map_open, null_map_close,
322 		nisplus_map_lookup, null_map_store);
323 #endif
324 
325 #ifdef HESIOD
326 	MAPDEF("hesiod", NULL, MCF_ALIASOK|MCF_ALIASONLY,
327 		map_parseargs, null_map_open, null_map_close,
328 		hes_map_lookup, null_map_store);
329 #endif
330 
331 #ifdef NETINFO
332 	MAPDEF("netinfo", NULL, MCF_ALIASOK,
333 		map_parseargs, ni_map_open, null_map_close,
334 		ni_map_lookup, null_map_store);
335 #endif
336 
337 #if 0
338 	MAPDEF("dns", NULL, 0,
339 		dns_map_init, null_map_open, null_map_close,
340 		dns_map_lookup, null_map_store);
341 #endif
342 
343 #if NAMED_BIND
344 	/* best MX DNS lookup */
345 	MAPDEF("bestmx", NULL, MCF_OPTFILE,
346 		map_parseargs, null_map_open, null_map_close,
347 		bestmx_map_lookup, null_map_store);
348 #endif
349 
350 	MAPDEF("host", NULL, 0,
351 		host_map_init, null_map_open, null_map_close,
352 		host_map_lookup, null_map_store);
353 
354 	MAPDEF("text", NULL, MCF_ALIASOK,
355 		map_parseargs, text_map_open, null_map_close,
356 		text_map_lookup, null_map_store);
357 
358 	MAPDEF("stab", NULL, MCF_ALIASOK|MCF_ALIASONLY,
359 		map_parseargs, stab_map_open, null_map_close,
360 		stab_map_lookup, stab_map_store);
361 
362 	MAPDEF("implicit", NULL, MCF_ALIASOK|MCF_ALIASONLY|MCF_REBUILDABLE,
363 		map_parseargs, impl_map_open, impl_map_close,
364 		impl_map_lookup, impl_map_store);
365 
366 	/* access to system passwd file */
367 	MAPDEF("user", NULL, MCF_OPTFILE,
368 		map_parseargs, user_map_open, null_map_close,
369 		user_map_lookup, null_map_store);
370 
371 	/* dequote map */
372 	MAPDEF("dequote", NULL, 0,
373 		dequote_init, null_map_open, null_map_close,
374 		dequote_map, null_map_store);
375 
376 #if 0
377 # ifdef USERDB
378 	/* user database */
379 	MAPDEF("udb", ".db", 0,
380 		udb_map_parse, null_map_open, null_map_close,
381 		udb_map_lookup, null_map_store);
382 # endif
383 #endif
384 
385 	/* sequenced maps */
386 	MAPDEF("sequence", NULL, MCF_ALIASOK,
387 		seq_map_parse, null_map_open, null_map_close,
388 		seq_map_lookup, seq_map_store);
389 
390 	/* switched interface to sequenced maps */
391 	MAPDEF("switch", NULL, MCF_ALIASOK,
392 		map_parseargs, switch_map_open, null_map_close,
393 		seq_map_lookup, seq_map_store);
394 }
395 
396 #undef MAPDEF
397 /*
398 **  INITHOSTMAPS -- initial host-dependent maps
399 **
400 **	This should act as an interface to any local service switch
401 **	provided by the host operating system.
402 **
403 **	Parameters:
404 **		none
405 **
406 **	Returns:
407 **		none
408 **
409 **	Side Effects:
410 **		Should define maps "host" and "users" as necessary
411 **		for this OS.  If they are not defined, they will get
412 **		a default value later.  It should check to make sure
413 **		they are not defined first, since it's possible that
414 **		the config file has provided an override.
415 */
416 
417 void
418 inithostmaps()
419 {
420 	register int i;
421 	int nmaps;
422 	char *maptype[MAXMAPSTACK];
423 	short mapreturn[MAXMAPACTIONS];
424 	char buf[MAXLINE];
425 
426 	/*
427 	**  Set up default hosts maps.
428 	*/
429 
430 #if 0
431 	nmaps = switch_map_find("hosts", maptype, mapreturn);
432 	for (i = 0; i < nmaps; i++)
433 	{
434 		if (strcmp(maptype[i], "files") == 0 &&
435 		    stab("hosts.files", ST_MAP, ST_FIND) == NULL)
436 		{
437 			strcpy(buf, "hosts.files text -k 0 -v 1 /etc/hosts");
438 			makemapentry(buf);
439 		}
440 #if NAMED_BIND
441 		else if (strcmp(maptype[i], "dns") == 0 &&
442 		    stab("hosts.dns", ST_MAP, ST_FIND) == NULL)
443 		{
444 			strcpy(buf, "hosts.dns dns A");
445 			makemapentry(buf);
446 		}
447 #endif
448 #ifdef NISPLUS
449 		else if (strcmp(maptype[i], "nisplus") == 0 &&
450 		    stab("hosts.nisplus", ST_MAP, ST_FIND) == NULL)
451 		{
452 			strcpy(buf, "hosts.nisplus nisplus -k name -v address -d hosts.org_dir");
453 			makemapentry(buf);
454 		}
455 #endif
456 #ifdef NIS
457 		else if (strcmp(maptype[i], "nis") == 0 &&
458 		    stab("hosts.nis", ST_MAP, ST_FIND) == NULL)
459 		{
460 			strcpy(buf, "hosts.nis nis -d -k 0 -v 1 hosts.byname");
461 			makemapentry(buf);
462 		}
463 #endif
464 	}
465 #endif
466 
467 	/*
468 	**  Make sure we have a host map.
469 	*/
470 
471 	if (stab("host", ST_MAP, ST_FIND) == NULL)
472 	{
473 		/* user didn't initialize: set up host map */
474 		strcpy(buf, "host host");
475 #if NAMED_BIND
476 		if (ConfigLevel >= 2)
477 			strcat(buf, " -a.");
478 #endif
479 		makemapentry(buf);
480 	}
481 
482 	/*
483 	**  Set up default aliases maps
484 	*/
485 
486 	nmaps = switch_map_find("aliases", maptype, mapreturn);
487 	for (i = 0; i < nmaps; i++)
488 	{
489 		if (strcmp(maptype[i], "files") == 0 &&
490 		    stab("aliases.files", ST_MAP, ST_FIND) == NULL)
491 		{
492 			strcpy(buf, "aliases.files implicit /etc/aliases");
493 			makemapentry(buf);
494 		}
495 #ifdef NISPLUS
496 		else if (strcmp(maptype[i], "nisplus") == 0 &&
497 		    stab("aliases.nisplus", ST_MAP, ST_FIND) == NULL)
498 		{
499 			strcpy(buf, "aliases.nisplus nisplus -kalias -vexpansion -d mail_aliases.org_dir");
500 			makemapentry(buf);
501 		}
502 #endif
503 #ifdef NIS
504 		else if (strcmp(maptype[i], "nis") == 0 &&
505 		    stab("aliases.nis", ST_MAP, ST_FIND) == NULL)
506 		{
507 			strcpy(buf, "aliases.nis nis -d mail.aliases");
508 			makemapentry(buf);
509 		}
510 #endif
511 	}
512 	if (stab("aliases", ST_MAP, ST_FIND) == NULL)
513 	{
514 		strcpy(buf, "aliases switch aliases");
515 		makemapentry(buf);
516 	}
517 	strcpy(buf, "switch:aliases");
518 	setalias(buf);
519 
520 #if 0		/* "user" map class is a better choice */
521 	/*
522 	**  Set up default users maps.
523 	*/
524 
525 	nmaps = switch_map_find("passwd", maptype, mapreturn);
526 	for (i = 0; i < nmaps; i++)
527 	{
528 		if (strcmp(maptype[i], "files") == 0 &&
529 		    stab("users.files", ST_MAP, ST_FIND) == NULL)
530 		{
531 			strcpy(buf, "users.files text -m -z: -k0 -v6 /etc/passwd");
532 			makemapentry(buf);
533 		}
534 #ifdef NISPLUS
535 		else if (strcmp(maptype[i], "nisplus") == 0 &&
536 		    stab("users.nisplus", ST_MAP, ST_FIND) == NULL)
537 		{
538 			strcpy(buf, "users.nisplus nisplus -m -kname -vhome -d passwd.org_dir");
539 			makemapentry(buf);
540 		}
541 #endif
542 #ifdef NIS
543 		else if (strcmp(maptype[i], "nis") == 0 &&
544 		    stab("users.nis", ST_MAP, ST_FIND) == NULL)
545 		{
546 			strcpy(buf, "users.nis nis -m -d passwd.byname");
547 			makemapentry(buf);
548 		}
549 #endif
550 #ifdef HESIOD
551 		else if (strcmp(maptype[i], "hesiod") == 0) &&
552 		    stab("users.hesiod", ST_MAP, ST_FIND) == NULL)
553 		{
554 			strcpy(buf, "users.hesiod hesiod");
555 			makemapentry(buf);
556 		}
557 #endif
558 	}
559 	if (stab("users", ST_MAP, ST_FIND) == NULL)
560 	{
561 		strcpy(buf, "users switch -m passwd");
562 		makemapentry(buf);
563 	}
564 #endif
565 }
566 /*
567 **  SWITCH_MAP_FIND -- find the list of types associated with a map
568 **
569 **	This is the system-dependent interface to the service switch.
570 **
571 **	Parameters:
572 **		service -- the name of the service of interest.
573 **		maptype -- an out-array of strings containing the types
574 **			of access to use for this service.  There can
575 **			be at most MAXMAPSTACK types for a single service.
576 **		mapreturn -- an out-array of return information bitmaps
577 **			for the map.
578 **
579 **	Returns:
580 **		The number of map types filled in, or -1 for failure.
581 */
582 
583 #ifdef SOLARIS
584 # include <nsswitch.h>
585 #endif
586 
587 #if defined(ultrix) || defined(__osf__)
588 # include <sys/svcinfo.h>
589 #endif
590 
591 int
592 switch_map_find(service, maptype, mapreturn)
593 	char *service;
594 	char *maptype[MAXMAPSTACK];
595 	short mapreturn[MAXMAPACTIONS];
596 {
597 	register FILE *fp;
598 	int svcno;
599 	static char buf[MAXLINE];
600 
601 #ifdef SOLARIS
602 	struct __nsw_switchconfig *nsw_conf;
603 	enum __nsw_parse_err pserr;
604 	struct __nsw_lookup *lk;
605 	int nsw_rc;
606 	static struct __nsw_lookup lkp0 =
607 		{ "files", {1, 0, 0, 0}, NULL, NULL };
608 	static struct __nsw_switchconfig lkp_default =
609 		{ 0, "sendmail", 3, &lkp0 };
610 
611 	if ((nsw_conf = __nsw_getconfig(service, &pserr)) == NULL)
612 		lk = lkp_default.lookups;
613 	else
614 		lk = nsw_conf->lookups;
615 	svcno = 0;
616 	while (lk != NULL)
617 	{
618 		maptype[svcno] = lk->service_name;
619 		if (lk->actions[__NSW_NOTFOUND] == __NSW_RETURN)
620 			mapreturn[MA_NOTFOUND] |= 1 << svcno;
621 		if (lk->actions[__NSW_TRYAGAIN] == __NSW_RETURN)
622 			mapreturn[MA_TRYAGAIN] |= 1 << svcno;
623 		if (lk->actions[__NSW_UNAVAIL] == __NSW_RETURN)
624 			mapreturn[MA_TRYAGAIN] |= 1 << svcno;
625 		svcno++;
626 		lk = lk->next;
627 	}
628 	return svcno;
629 #endif
630 
631 #if defined(ultrix) || defined(__osf__)
632 	struct svcinfo *svcinfo;
633 	int svc;
634 
635 	svcinfo = getsvc();
636 	if (svcinfo == NULL)
637 		goto punt;
638 	if (strcmp(service, "hosts") == 0)
639 		svc = SVC_HOSTS;
640 	else if (strcmp(service, "aliases") == 0)
641 		svc = SVC_ALIASES;
642 	else if (strcmp(service, "passwd") == 0)
643 		svc = SVC_PASSWD;
644 	else
645 		return -1;
646 	for (svcno = 0; svcno < SVC_PATHSIZE; svcno++)
647 	{
648 		switch (svcinfo->svcpath[svc][svcno])
649 		{
650 		  case SVC_LOCAL:
651 			maptype[svcno] = "files";
652 			break;
653 
654 		  case SVC_YP:
655 			maptype[svcno] = "nis";
656 			break;
657 
658 		  case SVC_BIND:
659 			maptype[svcno] = "dns";
660 			break;
661 
662 #ifdef SVC_HESIOD
663 		  case SVC_HESIOD:
664 			maptype[svcno] = "hesiod";
665 			break;
666 #endif
667 
668 		  case SVC_LAST:
669 			return svcno;
670 		}
671 	}
672 	return svcno;
673 #endif
674 
675 #if !defined(SOLARIS) && !defined(ultrix) && !defined(__osf__)
676 	/*
677 	**  Fall-back mechanism.
678 	*/
679 
680 	svcno = 0;
681 	fp = fopen(ServiceSwitchFile, "r");
682 	if (fp != NULL)
683 	{
684 		while (fgets(buf, sizeof buf, fp) != NULL)
685 		{
686 			register char *p;
687 
688 			p = strpbrk(buf, "#\n");
689 			if (p != NULL)
690 				*p = '\0';
691 			p = strpbrk(buf, " \t");
692 			if (p != NULL)
693 				*p++ = '\0';
694 			if (strcmp(buf, service) != 0)
695 				continue;
696 
697 			/* got the right service -- extract data */
698 			do
699 			{
700 				while (isspace(*p))
701 					p++;
702 				if (*p == '\0')
703 					break;
704 				maptype[svcno++] = p;
705 				p = strpbrk(p, " \t");
706 				if (p != NULL)
707 					*p++ = '\0';
708 			} while (p != NULL);
709 			break;
710 		}
711 		fclose(fp);
712 		return svcno;
713 	}
714 #endif
715 
716 	/* if the service file doesn't work, use an absolute fallback */
717   punt:
718 	if (strcmp(service, "aliases") == 0)
719 	{
720 		maptype[0] = "files";
721 		return 1;
722 	}
723 	if (strcmp(service, "hosts") == 0)
724 	{
725 # if NAMED_BIND
726 		maptype[svcno++] = "dns";
727 # else
728 #  if defined(sun) && !defined(BSD) && !defined(SOLARIS)
729 		/* SunOS */
730 		maptype[svcno++] = "nis";
731 #  endif
732 # endif
733 		maptype[svcno++] = "files";
734 		return svcno;
735 	}
736 	return -1;
737 }
738 /*
739 **  USERNAME -- return the user id of the logged in user.
740 **
741 **	Parameters:
742 **		none.
743 **
744 **	Returns:
745 **		The login name of the logged in user.
746 **
747 **	Side Effects:
748 **		none.
749 **
750 **	Notes:
751 **		The return value is statically allocated.
752 */
753 
754 char *
755 username()
756 {
757 	static char *myname = NULL;
758 	extern char *getlogin();
759 	register struct passwd *pw;
760 
761 	/* cache the result */
762 	if (myname == NULL)
763 	{
764 		myname = getlogin();
765 		if (myname == NULL || myname[0] == '\0')
766 		{
767 			pw = getpwuid(RealUid);
768 			if (pw != NULL)
769 				myname = newstr(pw->pw_name);
770 		}
771 		else
772 		{
773 			uid_t uid = RealUid;
774 
775 			myname = newstr(myname);
776 			if ((pw = getpwnam(myname)) == NULL ||
777 			      (uid != 0 && uid != pw->pw_uid))
778 			{
779 				pw = getpwuid(uid);
780 				if (pw != NULL)
781 					myname = newstr(pw->pw_name);
782 			}
783 		}
784 		if (myname == NULL || myname[0] == '\0')
785 		{
786 			syserr("554 Who are you?");
787 			myname = "postmaster";
788 		}
789 	}
790 
791 	return (myname);
792 }
793 /*
794 **  TTYPATH -- Get the path of the user's tty
795 **
796 **	Returns the pathname of the user's tty.  Returns NULL if
797 **	the user is not logged in or if s/he has write permission
798 **	denied.
799 **
800 **	Parameters:
801 **		none
802 **
803 **	Returns:
804 **		pathname of the user's tty.
805 **		NULL if not logged in or write permission denied.
806 **
807 **	Side Effects:
808 **		none.
809 **
810 **	WARNING:
811 **		Return value is in a local buffer.
812 **
813 **	Called By:
814 **		savemail
815 */
816 
817 char *
818 ttypath()
819 {
820 	struct stat stbuf;
821 	register char *pathn;
822 	extern char *ttyname();
823 	extern char *getlogin();
824 
825 	/* compute the pathname of the controlling tty */
826 	if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL &&
827 	    (pathn = ttyname(0)) == NULL)
828 	{
829 		errno = 0;
830 		return (NULL);
831 	}
832 
833 	/* see if we have write permission */
834 	if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode))
835 	{
836 		errno = 0;
837 		return (NULL);
838 	}
839 
840 	/* see if the user is logged in */
841 	if (getlogin() == NULL)
842 		return (NULL);
843 
844 	/* looks good */
845 	return (pathn);
846 }
847 /*
848 **  CHECKCOMPAT -- check for From and To person compatible.
849 **
850 **	This routine can be supplied on a per-installation basis
851 **	to determine whether a person is allowed to send a message.
852 **	This allows restriction of certain types of internet
853 **	forwarding or registration of users.
854 **
855 **	If the hosts are found to be incompatible, an error
856 **	message should be given using "usrerr" and 0 should
857 **	be returned.
858 **
859 **	EF_NORETURN can be set in e->e_flags to suppress the return-to-sender
860 **	function; this should be done on huge messages.
861 **
862 **	Parameters:
863 **		to -- the person being sent to.
864 **
865 **	Returns:
866 **		an exit status
867 **
868 **	Side Effects:
869 **		none (unless you include the usrerr stuff)
870 */
871 
872 int
873 checkcompat(to, e)
874 	register ADDRESS *to;
875 	register ENVELOPE *e;
876 {
877 # ifdef lint
878 	if (to == NULL)
879 		to++;
880 # endif /* lint */
881 
882 	if (tTd(49, 1))
883 		printf("checkcompat(to=%s, from=%s)\n",
884 			to->q_paddr, e->e_from.q_paddr);
885 
886 # ifdef EXAMPLE_CODE
887 	/* this code is intended as an example only */
888 	register STAB *s;
889 
890 	s = stab("arpa", ST_MAILER, ST_FIND);
891 	if (s != NULL && strcmp(e->e_from.q_mailer->m_name, "local") != 0 &&
892 	    to->q_mailer == s->s_mailer)
893 	{
894 		usrerr("553 No ARPA mail through this machine: see your system administration");
895 		/* e->e_flags |= EF_NORETURN; to supress return copy */
896 		return (EX_UNAVAILABLE);
897 	}
898 # endif /* EXAMPLE_CODE */
899 	return (EX_OK);
900 }
901 /*
902 **  SETSIGNAL -- set a signal handler
903 **
904 **	This is essentially old BSD "signal(3)".
905 */
906 
907 sigfunc_t
908 setsignal(sig, handler)
909 	int sig;
910 	sigfunc_t handler;
911 {
912 #if defined(SYS5SIGNALS) || defined(BSD4_3) || defined(_AUX_SOURCE)
913 	return signal(sig, handler);
914 #else
915 	struct sigaction n, o;
916 
917 	bzero(&n, sizeof n);
918 	n.sa_handler = handler;
919 # ifdef SA_RESTART
920 	n.sa_flags = SA_RESTART;
921 # endif
922 	if (sigaction(sig, &n, &o) < 0)
923 		return SIG_ERR;
924 	return o.sa_handler;
925 #endif
926 }
927 /*
928 **  HOLDSIGS -- arrange to hold all signals
929 **
930 **	Parameters:
931 **		none.
932 **
933 **	Returns:
934 **		none.
935 **
936 **	Side Effects:
937 **		Arranges that signals are held.
938 */
939 
940 void
941 holdsigs()
942 {
943 }
944 /*
945 **  RLSESIGS -- arrange to release all signals
946 **
947 **	This undoes the effect of holdsigs.
948 **
949 **	Parameters:
950 **		none.
951 **
952 **	Returns:
953 **		none.
954 **
955 **	Side Effects:
956 **		Arranges that signals are released.
957 */
958 
959 void
960 rlsesigs()
961 {
962 }
963 /*
964 **  INIT_MD -- do machine dependent initializations
965 **
966 **	Systems that have global modes that should be set should do
967 **	them here rather than in main.
968 */
969 
970 #ifdef _AUX_SOURCE
971 # include	<compat.h>
972 #endif
973 
974 void
975 init_md(argc, argv)
976 	int argc;
977 	char **argv;
978 {
979 #ifdef _AUX_SOURCE
980 	setcompat(getcompat() | COMPAT_BSDPROT);
981 #endif
982 
983 #ifdef VENDOR_DEFAULT
984 	VendorCode = VENDOR_DEFAULT;
985 #else
986 	VendorCode = VENDOR_BERKELEY;
987 #endif
988 }
989 /*
990 **  GETLA -- get the current load average
991 **
992 **	This code stolen from la.c.
993 **
994 **	Parameters:
995 **		none.
996 **
997 **	Returns:
998 **		The current load average as an integer.
999 **
1000 **	Side Effects:
1001 **		none.
1002 */
1003 
1004 /* try to guess what style of load average we have */
1005 #define LA_ZERO		1	/* always return load average as zero */
1006 #define LA_INT		2	/* read kmem for avenrun; interpret as long */
1007 #define LA_FLOAT	3	/* read kmem for avenrun; interpret as float */
1008 #define LA_SUBR		4	/* call getloadavg */
1009 #define LA_MACH		5	/* MACH load averages (as on NeXT boxes) */
1010 #define LA_SHORT	6	/* read kmem for avenrun; interpret as short */
1011 #define LA_PROCSTR	7	/* read string ("1.17") from /proc/loadavg */
1012 
1013 /* do guesses based on general OS type */
1014 #ifndef LA_TYPE
1015 # define LA_TYPE	LA_ZERO
1016 #endif
1017 
1018 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT)
1019 
1020 #include <nlist.h>
1021 
1022 #ifdef IRIX64
1023 # define nlist		nlist64
1024 #endif
1025 
1026 #ifndef LA_AVENRUN
1027 # ifdef SYSTEM5
1028 #  define LA_AVENRUN	"avenrun"
1029 # else
1030 #  define LA_AVENRUN	"_avenrun"
1031 # endif
1032 #endif
1033 
1034 /* _PATH_UNIX should be defined in <paths.h> */
1035 #ifndef _PATH_UNIX
1036 # if defined(SYSTEM5)
1037 #  define _PATH_UNIX	"/unix"
1038 # else
1039 #  define _PATH_UNIX	"/vmunix"
1040 # endif
1041 #endif
1042 
1043 struct	nlist Nl[] =
1044 {
1045 	{ LA_AVENRUN },
1046 #define	X_AVENRUN	0
1047 	{ 0 },
1048 };
1049 
1050 #ifndef FSHIFT
1051 # if defined(unixpc)
1052 #  define FSHIFT	5
1053 # endif
1054 
1055 # if defined(__alpha) || defined(IRIX)
1056 #  define FSHIFT	10
1057 # endif
1058 
1059 # if defined(_AIX3)
1060 #  define FSHIFT	16
1061 # endif
1062 #endif
1063 
1064 #ifndef FSHIFT
1065 # define FSHIFT		8
1066 #endif
1067 
1068 #ifndef FSCALE
1069 # define FSCALE		(1 << FSHIFT)
1070 #endif
1071 
1072 getla()
1073 {
1074 	static int kmem = -1;
1075 #if LA_TYPE == LA_INT
1076 	long avenrun[3];
1077 #else
1078 # if LA_TYPE == LA_SHORT
1079 	short avenrun[3];
1080 # else
1081 	double avenrun[3];
1082 # endif
1083 #endif
1084 	extern off_t lseek();
1085 	extern int errno;
1086 
1087 	if (kmem < 0)
1088 	{
1089 		kmem = open("/dev/kmem", 0, 0);
1090 		if (kmem < 0)
1091 		{
1092 			if (tTd(3, 1))
1093 				printf("getla: open(/dev/kmem): %s\n",
1094 					errstring(errno));
1095 			return (-1);
1096 		}
1097 		(void) fcntl(kmem, F_SETFD, 1);
1098 #ifdef _AIX3
1099 		if (knlist(Nl, 1, sizeof Nl[0]) < 0)
1100 #else
1101 		if (nlist(_PATH_UNIX, Nl) < 0)
1102 #endif
1103 		{
1104 			if (tTd(3, 1))
1105 				printf("getla: nlist(%s): %s\n", _PATH_UNIX,
1106 					errstring(errno));
1107 			return (-1);
1108 		}
1109 		if (Nl[X_AVENRUN].n_value == 0)
1110 		{
1111 			if (tTd(3, 1))
1112 				printf("getla: nlist(%s, %s) ==> 0\n",
1113 					_PATH_UNIX, LA_AVENRUN);
1114 			return (-1);
1115 		}
1116 #ifdef NAMELISTMASK
1117 		Nl[X_AVENRUN].n_value &= NAMELISTMASK;
1118 #endif
1119 	}
1120 	if (tTd(3, 20))
1121 		printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value);
1122 	if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, SEEK_SET) == -1 ||
1123 	    read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
1124 	{
1125 		/* thank you Ian */
1126 		if (tTd(3, 1))
1127 			printf("getla: lseek or read: %s\n", errstring(errno));
1128 		return (-1);
1129 	}
1130 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)
1131 	if (tTd(3, 5))
1132 	{
1133 		printf("getla: avenrun = %d", avenrun[0]);
1134 		if (tTd(3, 15))
1135 			printf(", %d, %d", avenrun[1], avenrun[2]);
1136 		printf("\n");
1137 	}
1138 	if (tTd(3, 1))
1139 		printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1140 	return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1141 #else
1142 	if (tTd(3, 5))
1143 	{
1144 		printf("getla: avenrun = %g", avenrun[0]);
1145 		if (tTd(3, 15))
1146 			printf(", %g, %g", avenrun[1], avenrun[2]);
1147 		printf("\n");
1148 	}
1149 	if (tTd(3, 1))
1150 		printf("getla: %d\n", (int) (avenrun[0] +0.5));
1151 	return ((int) (avenrun[0] + 0.5));
1152 #endif
1153 }
1154 
1155 #else
1156 #if LA_TYPE == LA_SUBR
1157 
1158 #ifdef DGUX
1159 
1160 #include <sys/dg_sys_info.h>
1161 
1162 int
1163 getla()
1164 {
1165 	struct dg_sys_info_load_info load_info;
1166 
1167 	dg_sys_info((long *)&load_info,
1168 		DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0);
1169 
1170         if (tTd(3, 1))
1171                 printf("getla: %d\n", (int) (load_info.one_minute + 0.5));
1172 
1173 	return((int) (load_info.one_minute + 0.5));
1174 }
1175 
1176 #else
1177 # ifdef __hpux
1178 
1179 #  include <sys/param.h>
1180 #  include <sys/pstat.h>
1181 
1182 int
1183 getla()
1184 {
1185 	struct pst_dynamic pstd;
1186 
1187 	if (pstat_getdynamic(&pstd, sizeof(struct pst_dynamic),
1188 			     (size_t) 1 ,0) == -1)
1189 		return 0;
1190 
1191         if (tTd(3, 1))
1192                 printf("getla: %d\n", (int) (pstd.psd_avg_1_min + 0.5));
1193 
1194 	return (int) (pstd.psd_avg_1_min + 0.5);
1195 }
1196 
1197 # else
1198 
1199 int
1200 getla()
1201 {
1202 	double avenrun[3];
1203 
1204 	if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0)
1205 	{
1206 		if (tTd(3, 1))
1207 			perror("getla: getloadavg failed:");
1208 		return (-1);
1209 	}
1210 	if (tTd(3, 1))
1211 		printf("getla: %d\n", (int) (avenrun[0] +0.5));
1212 	return ((int) (avenrun[0] + 0.5));
1213 }
1214 
1215 # endif /* __hpux */
1216 #endif /* DGUX */
1217 #else
1218 #if LA_TYPE == LA_MACH
1219 
1220 /*
1221 **  This has been tested on NEXTSTEP release 2.1/3.X.
1222 */
1223 
1224 #if defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0
1225 # include <mach/mach.h>
1226 #else
1227 # include <mach.h>
1228 #endif
1229 
1230 getla()
1231 {
1232 	processor_set_t default_set;
1233 	kern_return_t error;
1234 	unsigned int info_count;
1235 	struct processor_set_basic_info info;
1236 	host_t host;
1237 
1238 	error = processor_set_default(host_self(), &default_set);
1239 	if (error != KERN_SUCCESS)
1240 		return -1;
1241 	info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
1242 	if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO,
1243 			       &host, (processor_set_info_t)&info,
1244 			       &info_count) != KERN_SUCCESS)
1245 	{
1246 		return -1;
1247 	}
1248 	return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE;
1249 }
1250 
1251 
1252 #else
1253 #if LA_TYPE == LA_PROCSTR
1254 
1255 /*
1256 **  Read /proc/loadavg for the load average.  This is assumed to be
1257 **  in a format like "0.15 0.12 0.06".
1258 **
1259 **	Initially intended for Linux.  This has been in the kernel
1260 **	since at least 0.99.15.
1261 */
1262 
1263 # ifndef _PATH_LOADAVG
1264 #  define _PATH_LOADAVG	"/proc/loadavg"
1265 # endif
1266 
1267 int
1268 getla()
1269 {
1270 	double avenrun;
1271 	register int result;
1272 	FILE *fp;
1273 
1274 	fp = fopen(_PATH_LOADAVG, "r");
1275 	if (fp == NULL)
1276 	{
1277 		if (tTd(3, 1))
1278 			printf("getla: fopen(%s): %s\n",
1279 				_PATH_LOADAVG, errstring(errno));
1280 		return -1;
1281 	}
1282 	result = fscanf(fp, "%lf", &avenrun);
1283 	fclose(fp);
1284 	if (result != 1)
1285 	{
1286 		if (tTd(3, 1))
1287 			printf("getla: fscanf() = %d: %s\n",
1288 				result, errstring(errno));
1289 		return -1;
1290 	}
1291 
1292 	if (tTd(3, 1))
1293 		printf("getla(): %.2f\n", avenrun);
1294 
1295 	return ((int) (avenrun + 0.5));
1296 }
1297 
1298 #else
1299 
1300 getla()
1301 {
1302 	if (tTd(3, 1))
1303 		printf("getla: ZERO\n");
1304 	return (0);
1305 }
1306 
1307 #endif
1308 #endif
1309 #endif
1310 #endif
1311 
1312 
1313 /*
1314  * Copyright 1989 Massachusetts Institute of Technology
1315  *
1316  * Permission to use, copy, modify, distribute, and sell this software and its
1317  * documentation for any purpose is hereby granted without fee, provided that
1318  * the above copyright notice appear in all copies and that both that
1319  * copyright notice and this permission notice appear in supporting
1320  * documentation, and that the name of M.I.T. not be used in advertising or
1321  * publicity pertaining to distribution of the software without specific,
1322  * written prior permission.  M.I.T. makes no representations about the
1323  * suitability of this software for any purpose.  It is provided "as is"
1324  * without express or implied warranty.
1325  *
1326  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
1327  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
1328  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1329  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
1330  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
1331  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1332  *
1333  * Authors:  Many and varied...
1334  */
1335 
1336 /* Non Apollo stuff removed by Don Lewis 11/15/93 */
1337 #ifndef lint
1338 static char  rcsid[] = "@(#)$Id: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp $";
1339 #endif /* !lint */
1340 
1341 #ifdef apollo
1342 # undef volatile
1343 #    include <apollo/base.h>
1344 
1345 /* ARGSUSED */
1346 int getloadavg( call_data )
1347      caddr_t	call_data;	/* pointer to (double) return value */
1348 {
1349      double *avenrun = (double *) call_data;
1350      int i;
1351      status_$t      st;
1352      long loadav[3];
1353      proc1_$get_loadav(loadav, &st);
1354      *avenrun = loadav[0] / (double) (1 << 16);
1355      return(0);
1356 }
1357 #   endif /* apollo */
1358 /*
1359 **  SHOULDQUEUE -- should this message be queued or sent?
1360 **
1361 **	Compares the message cost to the load average to decide.
1362 **
1363 **	Parameters:
1364 **		pri -- the priority of the message in question.
1365 **		ctime -- the message creation time.
1366 **
1367 **	Returns:
1368 **		TRUE -- if this message should be queued up for the
1369 **			time being.
1370 **		FALSE -- if the load is low enough to send this message.
1371 **
1372 **	Side Effects:
1373 **		none.
1374 */
1375 
1376 bool
1377 shouldqueue(pri, ctime)
1378 	long pri;
1379 	time_t ctime;
1380 {
1381 	bool rval;
1382 
1383 	if (tTd(3, 30))
1384 		printf("shouldqueue: CurrentLA=%d, pri=%d: ", CurrentLA, pri);
1385 	if (CurrentLA < QueueLA)
1386 	{
1387 		if (tTd(3, 30))
1388 			printf("FALSE (CurrentLA < QueueLA)\n");
1389 		return (FALSE);
1390 	}
1391 	if (CurrentLA >= RefuseLA)
1392 	{
1393 		if (tTd(3, 30))
1394 			printf("TRUE (CurrentLA >= RefuseLA)\n");
1395 		return (TRUE);
1396 	}
1397 	rval = pri > (QueueFactor / (CurrentLA - QueueLA + 1));
1398 	if (tTd(3, 30))
1399 		printf("%s (by calculation)\n", rval ? "TRUE" : "FALSE");
1400 	return rval;
1401 }
1402 /*
1403 **  REFUSECONNECTIONS -- decide if connections should be refused
1404 **
1405 **	Parameters:
1406 **		none.
1407 **
1408 **	Returns:
1409 **		TRUE if incoming SMTP connections should be refused
1410 **			(for now).
1411 **		FALSE if we should accept new work.
1412 **
1413 **	Side Effects:
1414 **		none.
1415 */
1416 
1417 bool
1418 refuseconnections()
1419 {
1420 	extern bool enoughspace();
1421 
1422 #ifdef XLA
1423 	if (!xla_smtp_ok())
1424 		return TRUE;
1425 #endif
1426 
1427 	/* this is probably too simplistic */
1428 	return CurrentLA >= RefuseLA || !enoughspace(MinBlocksFree + 1);
1429 }
1430 /*
1431 **  SETPROCTITLE -- set process title for ps
1432 **
1433 **	Parameters:
1434 **		fmt -- a printf style format string.
1435 **		a, b, c -- possible parameters to fmt.
1436 **
1437 **	Returns:
1438 **		none.
1439 **
1440 **	Side Effects:
1441 **		Clobbers argv of our main procedure so ps(1) will
1442 **		display the title.
1443 */
1444 
1445 #define SPT_NONE	0	/* don't use it at all */
1446 #define SPT_REUSEARGV	1	/* cover argv with title information */
1447 #define SPT_BUILTIN	2	/* use libc builtin */
1448 #define SPT_PSTAT	3	/* use pstat(PSTAT_SETCMD, ...) */
1449 #define SPT_PSSTRINGS	4	/* use PS_STRINGS->... */
1450 #define SPT_WRITEUDOT	5	/* write u. area in kmem */
1451 
1452 #ifndef SPT_TYPE
1453 # define SPT_TYPE	SPT_REUSEARGV
1454 #endif
1455 
1456 #if SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN
1457 
1458 # if SPT_TYPE == SPT_PSTAT
1459 #  include <sys/pstat.h>
1460 # endif
1461 # if SPT_TYPE == SPT_PSSTRINGS
1462 #  include <machine/vmparam.h>
1463 #  include <sys/exec.h>
1464 #  ifndef PS_STRINGS	/* hmmmm....  apparently not available after all */
1465 #   undef SPT_TYPE
1466 #   define SPT_TYPE	SPT_REUSEARGV
1467 #  endif
1468 # endif
1469 
1470 # if SPT_TYPE == SPT_PSSTRINGS
1471 #  define SETPROC_STATIC	static
1472 # else
1473 #  define SETPROC_STATIC
1474 # endif
1475 
1476 # ifndef SPT_PADCHAR
1477 #  define SPT_PADCHAR	' '
1478 # endif
1479 
1480 #endif /* SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN */
1481 
1482 #if SPT_TYPE != SPT_BUILTIN
1483 
1484 /*VARARGS1*/
1485 void
1486 # ifdef __STDC__
1487 setproctitle(char *fmt, ...)
1488 # else
1489 setproctitle(fmt, va_alist)
1490 	char *fmt;
1491 	va_dcl
1492 # endif
1493 {
1494 # if SPT_TYPE != SPT_NONE
1495 	register char *p;
1496 	register int i;
1497 	SETPROC_STATIC char buf[MAXLINE];
1498 	VA_LOCAL_DECL
1499 #  if SPT_TYPE == SPT_PSTAT
1500 	union pstun pst;
1501 #  endif
1502 	extern char **Argv;
1503 	extern char *LastArgv;
1504 
1505 	p = buf;
1506 
1507 	/* print sendmail: heading for grep */
1508 	(void) strcpy(p, "sendmail: ");
1509 	p += strlen(p);
1510 
1511 	/* print the argument string */
1512 	VA_START(fmt);
1513 	(void) vsprintf(p, fmt, ap);
1514 	VA_END;
1515 
1516 	i = strlen(buf);
1517 
1518 #  if SPT_TYPE == SPT_PSTAT
1519 	pst.pst_command = buf;
1520 	pstat(PSTAT_SETCMD, pst, i, 0, 0);
1521 #  else
1522 #   if SPT_TYPE == SPT_PSSTRINGS
1523 	PS_STRINGS->ps_nargvstr = 1;
1524 	PS_STRINGS->ps_argvstr = buf;
1525 #   else
1526 	if (i > LastArgv - Argv[0] - 2)
1527 	{
1528 		i = LastArgv - Argv[0] - 2;
1529 		buf[i] = '\0';
1530 	}
1531 	(void) strcpy(Argv[0], buf);
1532 	p = &Argv[0][i];
1533 	while (p < LastArgv)
1534 		*p++ = SPT_PADCHAR;
1535 	Argv[1] = NULL;
1536 #   endif /* SPT_TYPE == SPT_PSSTRINGS */
1537 #  endif /* SPT_TYPE == SPT_PSTAT */
1538 # endif /* SPT_TYPE != SPT_NONE */
1539 }
1540 
1541 #endif /* SPT_TYPE != SPT_BUILTIN */
1542 /*
1543 **  REAPCHILD -- pick up the body of my child, lest it become a zombie
1544 **
1545 **	Parameters:
1546 **		sig -- the signal that got us here (unused).
1547 **
1548 **	Returns:
1549 **		none.
1550 **
1551 **	Side Effects:
1552 **		Picks up extant zombies.
1553 */
1554 
1555 void
1556 reapchild(sig)
1557 	int sig;
1558 {
1559 	int olderrno = errno;
1560 # ifdef HASWAITPID
1561 	auto int status;
1562 	int count;
1563 	int pid;
1564 
1565 	count = 0;
1566 	while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
1567 	{
1568 		if (count++ > 1000)
1569 		{
1570 #ifdef LOG
1571 			syslog(LOG_ALERT, "reapchild: waitpid loop: pid=%d, status=%x",
1572 				pid, status);
1573 #endif
1574 			break;
1575 		}
1576 	}
1577 # else
1578 # ifdef WNOHANG
1579 	union wait status;
1580 
1581 	while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0)
1582 		continue;
1583 # else /* WNOHANG */
1584 	auto int status;
1585 
1586 	while (wait(&status) > 0)
1587 		continue;
1588 # endif /* WNOHANG */
1589 # endif
1590 # ifdef SYS5SIGNALS
1591 	(void) setsignal(SIGCHLD, reapchild);
1592 # endif
1593 	errno = olderrno;
1594 }
1595 /*
1596 **  UNSETENV -- remove a variable from the environment
1597 **
1598 **	Not needed on newer systems.
1599 **
1600 **	Parameters:
1601 **		name -- the string name of the environment variable to be
1602 **			deleted from the current environment.
1603 **
1604 **	Returns:
1605 **		none.
1606 **
1607 **	Globals:
1608 **		environ -- a pointer to the current environment.
1609 **
1610 **	Side Effects:
1611 **		Modifies environ.
1612 */
1613 
1614 #ifndef HASUNSETENV
1615 
1616 void
1617 unsetenv(name)
1618 	char *name;
1619 {
1620 	extern char **environ;
1621 	register char **pp;
1622 	int len = strlen(name);
1623 
1624 	for (pp = environ; *pp != NULL; pp++)
1625 	{
1626 		if (strncmp(name, *pp, len) == 0 &&
1627 		    ((*pp)[len] == '=' || (*pp)[len] == '\0'))
1628 			break;
1629 	}
1630 
1631 	for (; *pp != NULL; pp++)
1632 		*pp = pp[1];
1633 }
1634 
1635 #endif
1636 /*
1637 **  GETDTABLESIZE -- return number of file descriptors
1638 **
1639 **	Only on non-BSD systems
1640 **
1641 **	Parameters:
1642 **		none
1643 **
1644 **	Returns:
1645 **		size of file descriptor table
1646 **
1647 **	Side Effects:
1648 **		none
1649 */
1650 
1651 #ifdef SOLARIS
1652 # include <sys/resource.h>
1653 #endif
1654 
1655 int
1656 getdtsize()
1657 {
1658 #ifdef RLIMIT_NOFILE
1659 	struct rlimit rl;
1660 
1661 	if (getrlimit(RLIMIT_NOFILE, &rl) >= 0)
1662 		return rl.rlim_cur;
1663 #endif
1664 
1665 # ifdef HASGETDTABLESIZE
1666 	return getdtablesize();
1667 # else
1668 #  ifdef _SC_OPEN_MAX
1669 	return sysconf(_SC_OPEN_MAX);
1670 #  else
1671 	return NOFILE;
1672 #  endif
1673 # endif
1674 }
1675 /*
1676 **  UNAME -- get the UUCP name of this system.
1677 */
1678 
1679 #ifndef HASUNAME
1680 
1681 int
1682 uname(name)
1683 	struct utsname *name;
1684 {
1685 	FILE *file;
1686 	char *n;
1687 
1688 	name->nodename[0] = '\0';
1689 
1690 	/* try /etc/whoami -- one line with the node name */
1691 	if ((file = fopen("/etc/whoami", "r")) != NULL)
1692 	{
1693 		(void) fgets(name->nodename, NODE_LENGTH + 1, file);
1694 		(void) fclose(file);
1695 		n = strchr(name->nodename, '\n');
1696 		if (n != NULL)
1697 			*n = '\0';
1698 		if (name->nodename[0] != '\0')
1699 			return (0);
1700 	}
1701 
1702 	/* try /usr/include/whoami.h -- has a #define somewhere */
1703 	if ((file = fopen("/usr/include/whoami.h", "r")) != NULL)
1704 	{
1705 		char buf[MAXLINE];
1706 
1707 		while (fgets(buf, MAXLINE, file) != NULL)
1708 			if (sscanf(buf, "#define sysname \"%*[^\"]\"",
1709 					NODE_LENGTH, name->nodename) > 0)
1710 				break;
1711 		(void) fclose(file);
1712 		if (name->nodename[0] != '\0')
1713 			return (0);
1714 	}
1715 
1716 #ifdef TRUST_POPEN
1717 	/*
1718 	**  Popen is known to have security holes.
1719 	*/
1720 
1721 	/* try uuname -l to return local name */
1722 	if ((file = popen("uuname -l", "r")) != NULL)
1723 	{
1724 		(void) fgets(name, NODE_LENGTH + 1, file);
1725 		(void) pclose(file);
1726 		n = strchr(name, '\n');
1727 		if (n != NULL)
1728 			*n = '\0';
1729 		if (name->nodename[0] != '\0')
1730 			return (0);
1731 	}
1732 #endif
1733 
1734 	return (-1);
1735 }
1736 #endif /* HASUNAME */
1737 /*
1738 **  INITGROUPS -- initialize groups
1739 **
1740 **	Stub implementation for System V style systems
1741 */
1742 
1743 #ifndef HASINITGROUPS
1744 
1745 initgroups(name, basegid)
1746 	char *name;
1747 	int basegid;
1748 {
1749 	return 0;
1750 }
1751 
1752 #endif
1753 /*
1754 **  SETSID -- set session id (for non-POSIX systems)
1755 */
1756 
1757 #ifndef HASSETSID
1758 
1759 pid_t
1760 setsid __P ((void))
1761 {
1762 #ifdef TIOCNOTTY
1763 	int fd;
1764 
1765 	fd = open("/dev/tty", O_RDWR, 0);
1766 	if (fd >= 0)
1767 	{
1768 		(void) ioctl(fd, (int) TIOCNOTTY, (char *) 0);
1769 		(void) close(fd);
1770 	}
1771 #endif /* TIOCNOTTY */
1772 # ifdef SYS5SETPGRP
1773 	return setpgrp();
1774 # else
1775 	return setpgid(0, getpid());
1776 # endif
1777 }
1778 
1779 #endif
1780 /*
1781 **  FSYNC -- dummy fsync
1782 */
1783 
1784 #ifdef NEEDFSYNC
1785 
1786 fsync(fd)
1787 	int fd;
1788 {
1789 # ifdef O_SYNC
1790 	return fcntl(fd, F_SETFL, O_SYNC);
1791 # else
1792 	/* nothing we can do */
1793 	return 0;
1794 # endif
1795 }
1796 
1797 #endif
1798 /*
1799 **  DGUX_INET_ADDR -- inet_addr for DG/UX
1800 **
1801 **	Data General DG/UX version of inet_addr returns a struct in_addr
1802 **	instead of a long.  This patches things.  Only needed on versions
1803 **	prior to 5.4.3.
1804 */
1805 
1806 #ifdef DGUX_5_4_2
1807 
1808 #undef inet_addr
1809 
1810 long
1811 dgux_inet_addr(host)
1812 	char *host;
1813 {
1814 	struct in_addr haddr;
1815 
1816 	haddr = inet_addr(host);
1817 	return haddr.s_addr;
1818 }
1819 
1820 #endif
1821 /*
1822 **  GETOPT -- for old systems or systems with bogus implementations
1823 */
1824 
1825 #ifdef NEEDGETOPT
1826 
1827 /*
1828  * Copyright (c) 1985 Regents of the University of California.
1829  * All rights reserved.  The Berkeley software License Agreement
1830  * specifies the terms and conditions for redistribution.
1831  */
1832 
1833 
1834 /*
1835 ** this version hacked to add `atend' flag to allow state machine
1836 ** to reset if invoked by the program to scan args for a 2nd time
1837 */
1838 
1839 #if defined(LIBC_SCCS) && !defined(lint)
1840 static char sccsid[] = "@(#)getopt.c	4.3 (Berkeley) 3/9/86";
1841 #endif /* LIBC_SCCS and not lint */
1842 
1843 #include <stdio.h>
1844 
1845 /*
1846  * get option letter from argument vector
1847  */
1848 #ifdef _CONVEX_SOURCE
1849 extern int	optind, opterr;
1850 #else
1851 int	opterr = 1;		/* if error message should be printed */
1852 int	optind = 1;		/* index into parent argv vector */
1853 #endif
1854 int	optopt;			/* character checked for validity */
1855 char	*optarg;		/* argument associated with option */
1856 
1857 #define BADCH	(int)'?'
1858 #define EMSG	""
1859 #define tell(s)	if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \
1860 		fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}
1861 
1862 getopt(nargc,nargv,ostr)
1863 	int		nargc;
1864 	char *const	*nargv;
1865 	const char	*ostr;
1866 {
1867 	static char	*place = EMSG;	/* option letter processing */
1868 	static char	atend = 0;
1869 	register char	*oli;		/* option letter list index */
1870 
1871 	if (atend) {
1872 		atend = 0;
1873 		place = EMSG;
1874 	}
1875 	if(!*place) {			/* update scanning pointer */
1876 		if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) {
1877 			atend++;
1878 			return(EOF);
1879 		}
1880 		if (*place == '-') {	/* found "--" */
1881 			++optind;
1882 			atend++;
1883 			return(EOF);
1884 		}
1885 	}				/* option letter okay? */
1886 	if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) {
1887 		if (!*place) ++optind;
1888 		tell(": illegal option -- ");
1889 	}
1890 	if (*++oli != ':') {		/* don't need argument */
1891 		optarg = NULL;
1892 		if (!*place) ++optind;
1893 	}
1894 	else {				/* need an argument */
1895 		if (*place) optarg = place;	/* no white space */
1896 		else if (nargc <= ++optind) {	/* no arg */
1897 			place = EMSG;
1898 			tell(": option requires an argument -- ");
1899 		}
1900 	 	else optarg = nargv[optind];	/* white space */
1901 		place = EMSG;
1902 		++optind;
1903 	}
1904 	return(optopt);			/* dump back option letter */
1905 }
1906 
1907 #endif
1908 /*
1909 **  VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version
1910 */
1911 
1912 #ifdef NEEDVPRINTF
1913 
1914 #define MAXARG	16
1915 
1916 vfprintf(fp, fmt, ap)
1917 	FILE *	fp;
1918 	char *	fmt;
1919 	char **	ap;
1920 {
1921 	char *	bp[MAXARG];
1922 	int	i = 0;
1923 
1924 	while (*ap && i < MAXARG)
1925 		bp[i++] = *ap++;
1926 	fprintf(fp, fmt, bp[0], bp[1], bp[2], bp[3],
1927 			 bp[4], bp[5], bp[6], bp[7],
1928 			 bp[8], bp[9], bp[10], bp[11],
1929 			 bp[12], bp[13], bp[14], bp[15]);
1930 }
1931 
1932 vsprintf(s, fmt, ap)
1933 	char *	s;
1934 	char *	fmt;
1935 	char **	ap;
1936 {
1937 	char *	bp[MAXARG];
1938 	int	i = 0;
1939 
1940 	while (*ap && i < MAXARG)
1941 		bp[i++] = *ap++;
1942 	sprintf(s, fmt, bp[0], bp[1], bp[2], bp[3],
1943 			bp[4], bp[5], bp[6], bp[7],
1944 			bp[8], bp[9], bp[10], bp[11],
1945 			bp[12], bp[13], bp[14], bp[15]);
1946 }
1947 
1948 #endif
1949 /*
1950 **  USERSHELLOK -- tell if a user's shell is ok for unrestricted use
1951 **
1952 **	Parameters:
1953 **		shell -- the user's shell from /etc/passwd
1954 **
1955 **	Returns:
1956 **		TRUE -- if it is ok to use this for unrestricted access.
1957 **		FALSE -- if the shell is restricted.
1958 */
1959 
1960 #if !HASGETUSERSHELL
1961 
1962 # ifndef _PATH_SHELLS
1963 #  define _PATH_SHELLS	"/etc/shells"
1964 # endif
1965 
1966 char	*DefaultUserShells[] =
1967 {
1968 	"/bin/sh",		/* standard shell */
1969 	"/usr/bin/sh",
1970 	"/bin/csh",		/* C shell */
1971 	"/usr/bin/csh",
1972 #ifdef __hpux
1973 	"/bin/rsh",		/* restricted Bourne shell */
1974 	"/bin/ksh",		/* Korn shell */
1975 	"/bin/rksh",		/* restricted Korn shell */
1976 	"/bin/pam",
1977 	"/usr/bin/keysh",	/* key shell (extended Korn shell) */
1978 	"/bin/posix/sh",
1979 #endif
1980 #ifdef _AIX3
1981 	"/bin/ksh",		/* Korn shell */
1982 	"/usr/bin/ksh",
1983 	"/bin/tsh",		/* trusted shell */
1984 	"/usr/bin/tsh",
1985 	"/bin/bsh",		/* Bourne shell */
1986 	"/usr/bin/bsh",
1987 #endif
1988 	NULL
1989 };
1990 
1991 #endif
1992 
1993 #define WILDCARD_SHELL	"/SENDMAIL/ANY/SHELL/"
1994 
1995 bool
1996 usershellok(shell)
1997 	char *shell;
1998 {
1999 #if HASGETUSERSHELL
2000 	register char *p;
2001 	extern char *getusershell();
2002 
2003 	setusershell();
2004 	while ((p = getusershell()) != NULL)
2005 		if (strcmp(p, shell) == 0 || strcmp(p, WILDCARD_SHELL) == 0)
2006 			break;
2007 	endusershell();
2008 	return p != NULL;
2009 #else
2010 	register FILE *shellf;
2011 	char buf[MAXLINE];
2012 
2013 	shellf = fopen(_PATH_SHELLS, "r");
2014 	if (shellf == NULL)
2015 	{
2016 		/* no /etc/shells; see if it is one of the std shells */
2017 		char **d;
2018 
2019 		for (d = DefaultUserShells; *d != NULL; d++)
2020 		{
2021 			if (strcmp(shell, *d) == 0)
2022 				return TRUE;
2023 		}
2024 		return FALSE;
2025 	}
2026 
2027 	while (fgets(buf, sizeof buf, shellf) != NULL)
2028 	{
2029 		register char *p, *q;
2030 
2031 		p = buf;
2032 		while (*p != '\0' && *p != '#' && *p != '/')
2033 			p++;
2034 		if (*p == '#' || *p == '\0')
2035 			continue;
2036 		q = p;
2037 		while (*p != '\0' && *p != '#' && !isspace(*p))
2038 			p++;
2039 		*p = '\0';
2040 		if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0)
2041 		{
2042 			fclose(shellf);
2043 			return TRUE;
2044 		}
2045 	}
2046 	fclose(shellf);
2047 	return FALSE;
2048 #endif
2049 }
2050 /*
2051 **  FREESPACE -- see how much free space is on the queue filesystem
2052 **
2053 **	Only implemented if you have statfs.
2054 **
2055 **	Parameters:
2056 **		dir -- the directory in question.
2057 **		bsize -- a variable into which the filesystem
2058 **			block size is stored.
2059 **
2060 **	Returns:
2061 **		The number of bytes free on the queue filesystem.
2062 **		-1 if the statfs call fails.
2063 **
2064 **	Side effects:
2065 **		Puts the filesystem block size into bsize.
2066 */
2067 
2068 /* statfs types */
2069 #define SFS_NONE	0	/* no statfs implementation */
2070 #define SFS_USTAT	1	/* use ustat */
2071 #define SFS_4ARGS	2	/* use four-argument statfs call */
2072 #define SFS_VFS		3	/* use <sys/vfs.h> implementation */
2073 #define SFS_MOUNT	4	/* use <sys/mount.h> implementation */
2074 #define SFS_STATFS	5	/* use <sys/statfs.h> implementation */
2075 #define SFS_STATVFS	6	/* use <sys/statvfs.h> implementation */
2076 
2077 #ifndef SFS_TYPE
2078 # define SFS_TYPE	SFS_NONE
2079 #endif
2080 
2081 #if SFS_TYPE == SFS_USTAT
2082 # include <ustat.h>
2083 #endif
2084 #if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS
2085 # include <sys/statfs.h>
2086 #endif
2087 #if SFS_TYPE == SFS_VFS
2088 # include <sys/vfs.h>
2089 #endif
2090 #if SFS_TYPE == SFS_MOUNT
2091 # include <sys/mount.h>
2092 #endif
2093 #if SFS_TYPE == SFS_STATVFS
2094 # include <sys/statvfs.h>
2095 #endif
2096 
2097 long
2098 freespace(dir, bsize)
2099 	char *dir;
2100 	long *bsize;
2101 {
2102 #if SFS_TYPE != SFS_NONE
2103 # if SFS_TYPE == SFS_USTAT
2104 	struct ustat fs;
2105 	struct stat statbuf;
2106 #  define FSBLOCKSIZE	DEV_BSIZE
2107 #  define f_bavail	f_tfree
2108 # else
2109 #  if defined(ultrix)
2110 	struct fs_data fs;
2111 #   define f_bavail	fd_bfreen
2112 #   define FSBLOCKSIZE	1024L
2113 #  else
2114 #   if SFS_TYPE == SFS_STATVFS
2115 	struct statvfs fs;
2116 #    define FSBLOCKSIZE	fs.f_frsize
2117 #   else
2118 	struct statfs fs;
2119 #    define FSBLOCKSIZE	fs.f_bsize
2120 #    if defined(_SCO_unix_) || defined(IRIX) || defined(apollo) || defined(ALTOS_SYS_V) || defined(_UTS) || defined(_CRAYCOM)
2121 #     define f_bavail f_bfree
2122 #    endif
2123 #   endif
2124 #  endif
2125 # endif
2126 
2127 # if SFS_TYPE == SFS_USTAT
2128 	if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0)
2129 # else
2130 #  if SFS_TYPE == SFS_4ARGS
2131 	if (statfs(dir, &fs, sizeof fs, 0) == 0)
2132 #  else
2133 #   if SFS_TYPE == SFS_STATVFS
2134 	if (statvfs(dir, &fs) == 0)
2135 #   else
2136 #    if defined(ultrix)
2137 	if (statfs(dir, &fs) > 0)
2138 #    else
2139 	if (statfs(dir, &fs) == 0)
2140 #    endif
2141 #   endif
2142 #  endif
2143 # endif
2144 	{
2145 		if (bsize != NULL)
2146 			*bsize = FSBLOCKSIZE;
2147 		return (fs.f_bavail);
2148 	}
2149 #endif
2150 	return (-1);
2151 }
2152 /*
2153 **  ENOUGHSPACE -- check to see if there is enough free space on the queue fs
2154 **
2155 **	Only implemented if you have statfs.
2156 **
2157 **	Parameters:
2158 **		msize -- the size to check against.  If zero, we don't yet
2159 **		know how big the message will be, so just check for
2160 **		a "reasonable" amount.
2161 **
2162 **	Returns:
2163 **		TRUE if there is enough space.
2164 **		FALSE otherwise.
2165 */
2166 
2167 bool
2168 enoughspace(msize)
2169 	long msize;
2170 {
2171 	long bfree, bsize;
2172 
2173 	if (MinBlocksFree <= 0 && msize <= 0)
2174 	{
2175 		if (tTd(4, 80))
2176 			printf("enoughspace: no threshold\n");
2177 		return TRUE;
2178 	}
2179 
2180 	if ((bfree = freespace(QueueDir, &bsize)) >= 0)
2181 	{
2182 		if (tTd(4, 80))
2183 			printf("enoughspace: bavail=%ld, need=%ld\n",
2184 				bfree, msize);
2185 
2186 		/* convert msize to block count */
2187 		msize = msize / bsize + 1;
2188 		if (MinBlocksFree >= 0)
2189 			msize += MinBlocksFree;
2190 
2191 		if (bfree < msize)
2192 		{
2193 #ifdef LOG
2194 			if (LogLevel > 0)
2195 				syslog(LOG_ALERT,
2196 					"%s: low on space (have %ld, %s needs %ld in %s)",
2197 					CurEnv->e_id == NULL ? "[NOQUEUE]" : CurEnv->e_id,
2198 					bfree,
2199 					CurHostName == NULL ? "SMTP-DAEMON" : CurHostName,
2200 					msize, QueueDir);
2201 #endif
2202 			return FALSE;
2203 		}
2204 	}
2205 	else if (tTd(4, 80))
2206 		printf("enoughspace failure: min=%ld, need=%ld: %s\n",
2207 			MinBlocksFree, msize, errstring(errno));
2208 	return TRUE;
2209 }
2210 /*
2211 **  TRANSIENTERROR -- tell if an error code indicates a transient failure
2212 **
2213 **	This looks at an errno value and tells if this is likely to
2214 **	go away if retried later.
2215 **
2216 **	Parameters:
2217 **		err -- the errno code to classify.
2218 **
2219 **	Returns:
2220 **		TRUE if this is probably transient.
2221 **		FALSE otherwise.
2222 */
2223 
2224 bool
2225 transienterror(err)
2226 	int err;
2227 {
2228 	switch (err)
2229 	{
2230 	  case EIO:			/* I/O error */
2231 	  case ENXIO:			/* Device not configured */
2232 	  case EAGAIN:			/* Resource temporarily unavailable */
2233 	  case ENOMEM:			/* Cannot allocate memory */
2234 	  case ENODEV:			/* Operation not supported by device */
2235 	  case ENFILE:			/* Too many open files in system */
2236 	  case EMFILE:			/* Too many open files */
2237 	  case ENOSPC:			/* No space left on device */
2238 #ifdef ETIMEDOUT
2239 	  case ETIMEDOUT:		/* Connection timed out */
2240 #endif
2241 #ifdef ESTALE
2242 	  case ESTALE:			/* Stale NFS file handle */
2243 #endif
2244 #ifdef ENETDOWN
2245 	  case ENETDOWN:		/* Network is down */
2246 #endif
2247 #ifdef ENETUNREACH
2248 	  case ENETUNREACH:		/* Network is unreachable */
2249 #endif
2250 #ifdef ENETRESET
2251 	  case ENETRESET:		/* Network dropped connection on reset */
2252 #endif
2253 #ifdef ECONNABORTED
2254 	  case ECONNABORTED:		/* Software caused connection abort */
2255 #endif
2256 #ifdef ECONNRESET
2257 	  case ECONNRESET:		/* Connection reset by peer */
2258 #endif
2259 #ifdef ENOBUFS
2260 	  case ENOBUFS:			/* No buffer space available */
2261 #endif
2262 #ifdef ESHUTDOWN
2263 	  case ESHUTDOWN:		/* Can't send after socket shutdown */
2264 #endif
2265 #ifdef ECONNREFUSED
2266 	  case ECONNREFUSED:		/* Connection refused */
2267 #endif
2268 #ifdef EHOSTDOWN
2269 	  case EHOSTDOWN:		/* Host is down */
2270 #endif
2271 #ifdef EHOSTUNREACH
2272 	  case EHOSTUNREACH:		/* No route to host */
2273 #endif
2274 #ifdef EDQUOT
2275 	  case EDQUOT:			/* Disc quota exceeded */
2276 #endif
2277 #ifdef EPROCLIM
2278 	  case EPROCLIM:		/* Too many processes */
2279 #endif
2280 #ifdef EUSERS
2281 	  case EUSERS:			/* Too many users */
2282 #endif
2283 #ifdef EDEADLK
2284 	  case EDEADLK:			/* Resource deadlock avoided */
2285 #endif
2286 #ifdef EISCONN
2287 	  case EISCONN:			/* Socket already connected */
2288 #endif
2289 #ifdef EINPROGRESS
2290 	  case EINPROGRESS:		/* Operation now in progress */
2291 #endif
2292 #ifdef EALREADY
2293 	  case EALREADY:		/* Operation already in progress */
2294 #endif
2295 #ifdef EADDRINUSE
2296 	  case EADDRINUSE:		/* Address already in use */
2297 #endif
2298 #ifdef EADDRNOTAVAIL
2299 	  case EADDRNOTAVAIL:		/* Can't assign requested address */
2300 #endif
2301 #ifdef ETXTBSY
2302 	  case ETXTBSY:			/* (Apollo) file locked */
2303 #endif
2304 #if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR))
2305 	  case ENOSR:			/* Out of streams resources */
2306 #endif
2307 		return TRUE;
2308 	}
2309 
2310 	/* nope, must be permanent */
2311 	return FALSE;
2312 }
2313 /*
2314 **  LOCKFILE -- lock a file using flock or (shudder) fcntl locking
2315 **
2316 **	Parameters:
2317 **		fd -- the file descriptor of the file.
2318 **		filename -- the file name (for error messages).
2319 **		ext -- the filename extension.
2320 **		type -- type of the lock.  Bits can be:
2321 **			LOCK_EX -- exclusive lock.
2322 **			LOCK_NB -- non-blocking.
2323 **
2324 **	Returns:
2325 **		TRUE if the lock was acquired.
2326 **		FALSE otherwise.
2327 */
2328 
2329 bool
2330 lockfile(fd, filename, ext, type)
2331 	int fd;
2332 	char *filename;
2333 	char *ext;
2334 	int type;
2335 {
2336 # if !HASFLOCK
2337 	int action;
2338 	struct flock lfd;
2339 
2340 	if (ext == NULL)
2341 		ext = "";
2342 
2343 	bzero(&lfd, sizeof lfd);
2344 	if (bitset(LOCK_UN, type))
2345 		lfd.l_type = F_UNLCK;
2346 	else if (bitset(LOCK_EX, type))
2347 		lfd.l_type = F_WRLCK;
2348 	else
2349 		lfd.l_type = F_RDLCK;
2350 
2351 	if (bitset(LOCK_NB, type))
2352 		action = F_SETLK;
2353 	else
2354 		action = F_SETLKW;
2355 
2356 	if (tTd(55, 60))
2357 		printf("lockfile(%s%s, action=%d, type=%d): ",
2358 			filename, ext, action, lfd.l_type);
2359 
2360 	if (fcntl(fd, action, &lfd) >= 0)
2361 	{
2362 		if (tTd(55, 60))
2363 			printf("SUCCESS\n");
2364 		return TRUE;
2365 	}
2366 
2367 	if (tTd(55, 60))
2368 		printf("(%s) ", errstring(errno));
2369 
2370 	/*
2371 	**  On SunOS, if you are testing using -oQ/tmp/mqueue or
2372 	**  -oA/tmp/aliases or anything like that, and /tmp is mounted
2373 	**  as type "tmp" (that is, served from swap space), the
2374 	**  previous fcntl will fail with "Invalid argument" errors.
2375 	**  Since this is fairly common during testing, we will assume
2376 	**  that this indicates that the lock is successfully grabbed.
2377 	*/
2378 
2379 	if (errno == EINVAL)
2380 	{
2381 		if (tTd(55, 60))
2382 			printf("SUCCESS\n");
2383 		return TRUE;
2384 	}
2385 
2386 	if (!bitset(LOCK_NB, type) || (errno != EACCES && errno != EAGAIN))
2387 	{
2388 		int omode = -1;
2389 #  ifdef F_GETFL
2390 		int oerrno = errno;
2391 
2392 		(void) fcntl(fd, F_GETFL, &omode);
2393 		errno = oerrno;
2394 #  endif
2395 		syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
2396 			filename, ext, fd, type, omode, geteuid());
2397 	}
2398 # else
2399 	if (ext == NULL)
2400 		ext = "";
2401 
2402 	if (tTd(55, 60))
2403 		printf("lockfile(%s%s, type=%o): ", filename, ext, type);
2404 
2405 	if (flock(fd, type) >= 0)
2406 	{
2407 		if (tTd(55, 60))
2408 			printf("SUCCESS\n");
2409 		return TRUE;
2410 	}
2411 
2412 	if (tTd(55, 60))
2413 		printf("(%s) ", errstring(errno));
2414 
2415 	if (!bitset(LOCK_NB, type) || errno != EWOULDBLOCK)
2416 	{
2417 		int omode = -1;
2418 #  ifdef F_GETFL
2419 		int oerrno = errno;
2420 
2421 		(void) fcntl(fd, F_GETFL, &omode);
2422 		errno = oerrno;
2423 #  endif
2424 		syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
2425 			filename, ext, fd, type, omode, geteuid());
2426 	}
2427 # endif
2428 	if (tTd(55, 60))
2429 		printf("FAIL\n");
2430 	return FALSE;
2431 }
2432 /*
2433 **  CHOWNSAFE -- tell if chown is "safe" (executable only by root)
2434 **
2435 **	Parameters:
2436 **		fd -- the file descriptor to check.
2437 **
2438 **	Returns:
2439 **		TRUE -- if only root can chown the file to an arbitrary
2440 **			user.
2441 **		FALSE -- if an arbitrary user can give away a file.
2442 */
2443 
2444 bool
2445 chownsafe(fd)
2446 	int fd;
2447 {
2448 #ifdef __hpux
2449 	char *s;
2450 	int tfd;
2451 	uid_t o_uid, o_euid;
2452 	gid_t o_gid, o_egid;
2453 	bool rval;
2454 	struct stat stbuf;
2455 
2456 	o_uid = getuid();
2457 	o_euid = geteuid();
2458 	o_gid = getgid();
2459 	o_egid = getegid();
2460 	fstat(fd, &stbuf);
2461 	setresuid(stbuf.st_uid, stbuf.st_uid, -1);
2462 	setresgid(stbuf.st_gid, stbuf.st_gid, -1);
2463 	s = tmpnam(NULL);
2464 	tfd = open(s, O_RDONLY|O_CREAT, 0600);
2465 	rval = fchown(tfd, DefUid, DefGid) != 0;
2466 	close(tfd);
2467 	unlink(s);
2468 	setreuid(o_uid, o_euid);
2469 	setresgid(o_gid, o_egid, -1);
2470 	return rval;
2471 #else
2472 # ifdef _POSIX_CHOWN_RESTRICTED
2473 #  if _POSIX_CHOWN_RESTRICTED == -1
2474 	return FALSE;
2475 #  else
2476 	return TRUE;
2477 #  endif
2478 # else
2479 #  ifdef _PC_CHOWN_RESTRICTED
2480 	int rval;
2481 
2482 	/*
2483 	**  Some systems (e.g., SunOS) seem to have the call and the
2484 	**  #define _PC_CHOWN_RESTRICTED, but don't actually implement
2485 	**  the call.  This heuristic checks for that.
2486 	*/
2487 
2488 	errno = 0;
2489 	rval = fpathconf(fd, _PC_CHOWN_RESTRICTED);
2490 	if (errno == 0)
2491 		return rval > 0;
2492 #  endif
2493 #  ifdef BSD
2494 	return TRUE;
2495 #  else
2496 	return FALSE;
2497 #  endif
2498 # endif
2499 #endif
2500 }
2501 /*
2502 **  RESETLIMITS -- reset system controlled resource limits
2503 **
2504 **	This is to avoid denial-of-service attacks
2505 **
2506 **	Parameters:
2507 **		none
2508 **
2509 **	Returns:
2510 **		none
2511 */
2512 
2513 #if HASSETRLIMIT
2514 # include <sys/resource.h>
2515 #endif
2516 
2517 void
2518 resetlimits()
2519 {
2520 #if HASSETRLIMIT
2521 	struct rlimit lim;
2522 
2523 	lim.rlim_cur = lim.rlim_max = RLIM_INFINITY;
2524 	(void) setrlimit(RLIMIT_CPU, &lim);
2525 	(void) setrlimit(RLIMIT_FSIZE, &lim);
2526 #else
2527 # if HASULIMIT
2528 	(void) ulimit(2, 0x3fffff);
2529 # endif
2530 #endif
2531 }
2532 /*
2533 **  GETCFNAME -- return the name of the .cf file.
2534 **
2535 **	Some systems (e.g., NeXT) determine this dynamically.
2536 */
2537 
2538 char *
2539 getcfname()
2540 {
2541 	if (ConfFile != NULL)
2542 		return ConfFile;
2543 #ifdef NETINFO
2544 	{
2545 		extern char *ni_propval();
2546 		char *cflocation;
2547 
2548 		cflocation = ni_propval("/locations", NULL, "sendmail",
2549 					"sendmail.cf", '\0');
2550 		if (cflocation != NULL)
2551 			return cflocation;
2552 	}
2553 #endif
2554 	return _PATH_SENDMAILCF;
2555 }
2556 /*
2557 **  SETVENDOR -- process vendor code from V configuration line
2558 **
2559 **	Parameters:
2560 **		vendor -- string representation of vendor.
2561 **
2562 **	Returns:
2563 **		TRUE -- if ok.
2564 **		FALSE -- if vendor code could not be processed.
2565 **
2566 **	Side Effects:
2567 **		It is reasonable to set mode flags here to tweak
2568 **		processing in other parts of the code if necessary.
2569 **		For example, if you are a vendor that uses $%y to
2570 **		indicate YP lookups, you could enable that here.
2571 */
2572 
2573 bool
2574 setvendor(vendor)
2575 	char *vendor;
2576 {
2577 	if (strcasecmp(vendor, "Berkeley") == 0)
2578 	{
2579 		VendorCode = VENDOR_BERKELEY;
2580 		return TRUE;
2581 	}
2582 
2583 	/* add vendor extensions here */
2584 
2585 #ifdef SUN_EXTENSIONS
2586 	if (strcasecmp(vendor, "Sun") == 0)
2587 	{
2588 		VendorCode = VENDOR_SUN;
2589 		return TRUE;
2590 	}
2591 #endif
2592 
2593 	return FALSE;
2594 }
2595 /*
2596 **  STRTOL -- convert string to long integer
2597 **
2598 **	For systems that don't have it in the C library.
2599 **
2600 **	This is taken verbatim from the 4.4-Lite C library.
2601 */
2602 
2603 #ifdef NEEDSTRTOL
2604 
2605 #if defined(LIBC_SCCS) && !defined(lint)
2606 static char sccsid[] = "@(#)strtol.c	8.1 (Berkeley) 6/4/93";
2607 #endif /* LIBC_SCCS and not lint */
2608 
2609 #include <limits.h>
2610 
2611 /*
2612  * Convert a string to a long integer.
2613  *
2614  * Ignores `locale' stuff.  Assumes that the upper and lower case
2615  * alphabets and digits are each contiguous.
2616  */
2617 
2618 long
2619 strtol(nptr, endptr, base)
2620 	const char *nptr;
2621 	char **endptr;
2622 	register int base;
2623 {
2624 	register const char *s = nptr;
2625 	register unsigned long acc;
2626 	register int c;
2627 	register unsigned long cutoff;
2628 	register int neg = 0, any, cutlim;
2629 
2630 	/*
2631 	 * Skip white space and pick up leading +/- sign if any.
2632 	 * If base is 0, allow 0x for hex and 0 for octal, else
2633 	 * assume decimal; if base is already 16, allow 0x.
2634 	 */
2635 	do {
2636 		c = *s++;
2637 	} while (isspace(c));
2638 	if (c == '-') {
2639 		neg = 1;
2640 		c = *s++;
2641 	} else if (c == '+')
2642 		c = *s++;
2643 	if ((base == 0 || base == 16) &&
2644 	    c == '0' && (*s == 'x' || *s == 'X')) {
2645 		c = s[1];
2646 		s += 2;
2647 		base = 16;
2648 	}
2649 	if (base == 0)
2650 		base = c == '0' ? 8 : 10;
2651 
2652 	/*
2653 	 * Compute the cutoff value between legal numbers and illegal
2654 	 * numbers.  That is the largest legal value, divided by the
2655 	 * base.  An input number that is greater than this value, if
2656 	 * followed by a legal input character, is too big.  One that
2657 	 * is equal to this value may be valid or not; the limit
2658 	 * between valid and invalid numbers is then based on the last
2659 	 * digit.  For instance, if the range for longs is
2660 	 * [-2147483648..2147483647] and the input base is 10,
2661 	 * cutoff will be set to 214748364 and cutlim to either
2662 	 * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
2663 	 * a value > 214748364, or equal but the next digit is > 7 (or 8),
2664 	 * the number is too big, and we will return a range error.
2665 	 *
2666 	 * Set any if any `digits' consumed; make it negative to indicate
2667 	 * overflow.
2668 	 */
2669 	cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
2670 	cutlim = cutoff % (unsigned long)base;
2671 	cutoff /= (unsigned long)base;
2672 	for (acc = 0, any = 0;; c = *s++) {
2673 		if (isdigit(c))
2674 			c -= '0';
2675 		else if (isalpha(c))
2676 			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
2677 		else
2678 			break;
2679 		if (c >= base)
2680 			break;
2681 		if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
2682 			any = -1;
2683 		else {
2684 			any = 1;
2685 			acc *= base;
2686 			acc += c;
2687 		}
2688 	}
2689 	if (any < 0) {
2690 		acc = neg ? LONG_MIN : LONG_MAX;
2691 		errno = ERANGE;
2692 	} else if (neg)
2693 		acc = -acc;
2694 	if (endptr != 0)
2695 		*endptr = (char *)(any ? s - 1 : nptr);
2696 	return (acc);
2697 }
2698 
2699 #endif
2700 /*
2701 **  SOLARIS_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX
2702 **
2703 **	Solaris versions at least through 2.3 don't properly deliver a
2704 **	canonical h_name field.  This tries to work around it.
2705 */
2706 
2707 #ifdef SOLARIS
2708 
2709 extern int	h_errno;
2710 
2711 struct hostent *
2712 solaris_gethostbyname(name)
2713 	const char *name;
2714 {
2715 # ifdef SOLARIS_2_3
2716 	static struct hostent hp;
2717 	static char buf[1000];
2718 	extern struct hostent *_switch_gethostbyname_r();
2719 
2720 	return _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno);
2721 # else
2722 	extern struct hostent *__switch_gethostbyname();
2723 
2724 	return __switch_gethostbyname(name);
2725 # endif
2726 }
2727 
2728 struct hostent *
2729 solaris_gethostbyaddr(addr, len, type)
2730 	const char *addr;
2731 	int len;
2732 	int type;
2733 {
2734 # ifdef SOLARIS_2_3
2735 	static struct hostent hp;
2736 	static char buf[1000];
2737 	extern struct hostent *_switch_gethostbyaddr_r();
2738 
2739 	return _switch_gethostbyaddr_r(addr, len, type, &hp, buf, sizeof(buf), &h_errno);
2740 # else
2741 	extern struct hostent *__switch_gethostbyaddr();
2742 
2743 	return __switch_gethostbyaddr(addr, len, type);
2744 # endif
2745 }
2746 
2747 #endif
2748 /*
2749 **  NI_PROPVAL -- netinfo property value lookup routine
2750 **
2751 **	Parameters:
2752 **		keydir -- the Netinfo directory name in which to search
2753 **			for the key.
2754 **		keyprop -- the name of the property in which to find the
2755 **			property we are interested.  Defaults to "name".
2756 **		keyval -- the value for which we are really searching.
2757 **		valprop -- the property name for the value in which we
2758 **			are interested.
2759 **		sepchar -- if non-nil, this can be multiple-valued, and
2760 **			we should return a string separated by this
2761 **			character.
2762 **
2763 **	Returns:
2764 **		NULL -- if:
2765 **			1. the directory is not found
2766 **			2. the property name is not found
2767 **			3. the property contains multiple values
2768 **			4. some error occured
2769 **		else -- the location of the config file.
2770 **
2771 **	Example:
2772 **		To search for an alias value, use:
2773 **		  ni_propval("/aliases", "name", aliasname, "members", ',')
2774 **
2775 **	Notes:
2776 **      	Caller should free the return value of ni_proval
2777 */
2778 
2779 #ifdef NETINFO
2780 
2781 # include <netinfo/ni.h>
2782 
2783 # define LOCAL_NETINFO_DOMAIN    "."
2784 # define PARENT_NETINFO_DOMAIN   ".."
2785 # define MAX_NI_LEVELS           256
2786 
2787 char *
2788 ni_propval(keydir, keyprop, keyval, valprop, sepchar)
2789 	char *keydir;
2790 	char *keyprop;
2791 	char *keyval;
2792 	char *valprop;
2793 	char sepchar;
2794 {
2795 	char *propval = NULL;
2796 	int i;
2797 	int j, alen;
2798 	void *ni = NULL;
2799 	void *lastni = NULL;
2800 	ni_status nis;
2801 	ni_id nid;
2802 	ni_namelist ninl;
2803 	register char *p;
2804 	char keybuf[1024];
2805 
2806 	/*
2807 	**  Create the full key from the two parts.
2808 	**
2809 	**	Note that directory can end with, e.g., "name=" to specify
2810 	**	an alternate search property.
2811 	*/
2812 
2813 	i = strlen(keydir) + strlen(keyval) + 2;
2814 	if (keyprop != NULL)
2815 		i += strlen(keyprop) + 1;
2816 	if (i > sizeof keybuf)
2817 		return NULL;
2818 	strcpy(keybuf, keydir);
2819 	strcat(keybuf, "/");
2820 	if (keyprop != NULL)
2821 	{
2822 		strcat(keybuf, keyprop);
2823 		strcat(keybuf, "=");
2824 	}
2825 	strcat(keybuf, keyval);
2826 
2827 	/*
2828 	**  If the passed directory and property name are found
2829 	**  in one of netinfo domains we need to search (starting
2830 	**  from the local domain moving all the way back to the
2831 	**  root domain) set propval to the property's value
2832 	**  and return it.
2833 	*/
2834 
2835 	for (i = 0; i < MAX_NI_LEVELS; ++i)
2836 	{
2837 		if (i == 0)
2838 		{
2839 			nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
2840 		}
2841 		else
2842 		{
2843 			if (lastni != NULL)
2844 				ni_free(lastni);
2845 			lastni = ni;
2846 			nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
2847 		}
2848 
2849 		/*
2850 		**  Don't bother if we didn't get a handle on a
2851 		**  proper domain.  This is not necessarily an error.
2852 		**  We would get a positive ni_status if, for instance
2853 		**  we never found the directory or property and tried
2854 		**  to open the parent of the root domain!
2855 		*/
2856 
2857 		if (nis != 0)
2858 			break;
2859 
2860 		/*
2861 		**  Find the path to the server information.
2862 		*/
2863 
2864 		if (ni_pathsearch(ni, &nid, keybuf) != 0)
2865 			continue;
2866 
2867 		/*
2868 		**  Find associated value information.
2869 		*/
2870 
2871 		if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0)
2872 			continue;
2873 
2874 		/*
2875 		**  See if we have an acceptable number of values.
2876 		*/
2877 
2878 		if (ninl.ni_namelist_len <= 0)
2879 			continue;
2880 
2881 		if (sepchar == '\0' && ninl.ni_namelist_len > 1)
2882 		{
2883 			ni_namelist_free(&ninl);
2884 			continue;
2885 		}
2886 
2887 		/*
2888 		**  Calculate number of bytes needed and build result
2889 		*/
2890 
2891 		alen = 1;
2892 		for (j = 0; j < ninl.ni_namelist_len; j++)
2893 			alen += strlen(ninl.ni_namelist_val[j]) + 1;
2894 		propval = p = xalloc(alen);
2895 		for (j = 0; j < ninl.ni_namelist_len; j++)
2896 		{
2897 			strcpy(p, ninl.ni_namelist_val[j]);
2898 			p += strlen(p);
2899 			*p++ = sepchar;
2900 		}
2901 		*--p = '\0';
2902 
2903 		ni_namelist_free(&ninl);
2904 	}
2905 
2906 	/*
2907 	**  Clean up.
2908 	*/
2909 
2910 	if (ni != NULL)
2911 		ni_free(ni);
2912 	if (lastni != NULL && ni != lastni)
2913 		ni_free(lastni);
2914 
2915 	return propval;
2916 }
2917 
2918 #endif /* NETINFO */
2919 /*
2920 **  HARD_SYSLOG -- call syslog repeatedly until it works
2921 **
2922 **	Needed on HP-UX, which apparently doesn't guarantee that
2923 **	syslog succeeds during interrupt handlers.
2924 */
2925 
2926 #ifdef __hpux
2927 
2928 # define MAXSYSLOGTRIES	100
2929 # undef syslog
2930 
2931 # ifdef __STDC__
2932 hard_syslog(int pri, char *msg, ...)
2933 # else
2934 hard_syslog(pri, msg, va_alist)
2935 	int pri;
2936 	char *msg;
2937 	va_dcl
2938 # endif
2939 {
2940 	int i;
2941 	char buf[SYSLOG_BUFSIZE * 2];
2942 	VA_LOCAL_DECL;
2943 
2944 	VA_START(msg);
2945 	vsprintf(buf, msg, ap);
2946 	VA_END;
2947 
2948 	for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, "%s", buf) < 0; )
2949 		continue;
2950 }
2951 
2952 #endif
2953