xref: /csrg-svn/usr.sbin/sendmail/src/conf.c (revision 58789)
1 /*
2  * Copyright (c) 1983 Eric P. Allman
3  * Copyright (c) 1988 Regents of the University of California.
4  * All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 static char sccsid[] = "@(#)conf.c	6.41 (Berkeley) 03/23/93";
11 #endif /* not lint */
12 
13 # include <sys/ioctl.h>
14 # include <sys/param.h>
15 # include <signal.h>
16 # include <pwd.h>
17 # include "sendmail.h"
18 # include "pathnames.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 		/* destination fields */
67 	"to",			H_RCPT,
68 	"resent-to",		H_RCPT|H_RESENT,
69 	"cc",			H_RCPT,
70 	"resent-cc",		H_RCPT|H_RESENT,
71 	"bcc",			H_RCPT|H_ACHECK,
72 	"resent-bcc",		H_RCPT|H_ACHECK|H_RESENT,
73 	"apparently-to",	H_RCPT,
74 		/* message identification and control */
75 	"message-id",		0,
76 	"resent-message-id",	H_RESENT,
77 	"message",		H_EOH,
78 	"text",			H_EOH,
79 		/* date fields */
80 	"date",			0,
81 	"resent-date",		H_RESENT,
82 		/* trace fields */
83 	"received",		H_TRACE|H_FORCE,
84 	"via",			H_TRACE|H_FORCE,
85 	"mail-from",		H_TRACE|H_FORCE,
86 
87 	NULL,			0,
88 };
89 
90 
91 
92 /*
93 **  Location of system files/databases/etc.
94 */
95 
96 char	*ConfFile =	_PATH_SENDMAILCF;	/* runtime configuration */
97 char	*FreezeFile =	_PATH_SENDMAILFC;	/* frozen version of above */
98 char	*PidFile =	_PATH_SENDMAILPID;	/* stores daemon proc id */
99 
100 
101 
102 /*
103 **  Privacy values
104 */
105 
106 struct prival PrivacyValues[] =
107 {
108 	"public",		PRIV_PUBLIC,
109 	"needmailhelo",		PRIV_NEEDMAILHELO,
110 	"needexpnhelo",		PRIV_NEEDEXPNHELO,
111 	"needvrfyhelo",		PRIV_NEEDVRFYHELO,
112 	"noexpn",		PRIV_NOEXPN,
113 	"novrfy",		PRIV_NOVRFY,
114 	"restrictmailq",	PRIV_RESTRMAILQ,
115 	"authwarnings",		PRIV_AUTHWARNINGS,
116 	"goaway",		PRIV_GOAWAY,
117 	NULL,			0,
118 };
119 
120 
121 
122 /*
123 **  Miscellaneous stuff.
124 */
125 
126 int	DtableSize =	50;		/* max open files; reset in 4.2bsd */
127 /*
128 **  SETDEFAULTS -- set default values
129 **
130 **	Because of the way freezing is done, these must be initialized
131 **	using direct code.
132 **
133 **	Parameters:
134 **		e -- the default envelope.
135 **
136 **	Returns:
137 **		none.
138 **
139 **	Side Effects:
140 **		Initializes a bunch of global variables to their
141 **		default values.
142 */
143 
144 #define DAYS		* 24 * 60 * 60
145 
146 setdefaults(e)
147 	register ENVELOPE *e;
148 {
149 	SpaceSub = ' ';				/* option B */
150 	QueueLA = 8;				/* option x */
151 	RefuseLA = 12;				/* option X */
152 	WkRecipFact = 30000L;			/* option y */
153 	WkClassFact = 1800L;			/* option z */
154 	WkTimeFact = 90000L;			/* option Z */
155 	QueueFactor = WkRecipFact * 20;		/* option q */
156 	FileMode = (getuid() != geteuid()) ? 0644 : 0600;
157 						/* option F */
158 	DefUid = 1;				/* option u */
159 	DefGid = 1;				/* option g */
160 	CheckpointInterval = 10;		/* option C */
161 	MaxHopCount = 25;			/* option h */
162 	e->e_sendmode = SM_FORK;		/* option d */
163 	e->e_errormode = EM_PRINT;		/* option e */
164 	EightBit = FALSE;			/* option 8 */
165 	MaxMciCache = 1;			/* option k */
166 	MciCacheTimeout = 300;			/* option K */
167 	LogLevel = 9;				/* option L */
168 	settimeouts(NULL);			/* option r */
169 	TimeOuts.to_q_return = 5 DAYS;		/* option T */
170 	TimeOuts.to_q_warning = 0;		/* option T */
171 	PrivacyFlags = PRIV_AUTHWARNINGS;	/* option p */
172 	setdefuser();
173 	setupmaps();
174 	setupmailers();
175 }
176 
177 
178 /*
179 **  SETDEFUSER -- set/reset DefUser using DefUid (for initgroups())
180 */
181 
182 setdefuser()
183 {
184 	struct passwd *defpwent;
185 	static char defuserbuf[40];
186 
187 	DefUser = defuserbuf;
188 	if ((defpwent = getpwuid(DefUid)) != NULL)
189 		strcpy(defuserbuf, defpwent->pw_name);
190 	else
191 		strcpy(defuserbuf, "nobody");
192 }
193 /*
194 **  SETUPMAPS -- set up map classes
195 **
196 **	Since these are compiled in, they cannot be in the config file.
197 **
198 */
199 
200 setupmaps()
201 {
202 	register STAB *s;
203 	extern bool host_map_init();
204 	extern char *maphostname();
205 
206 	/* set up host name lookup map */
207 	s = stab("host", ST_MAPCLASS, ST_ENTER);
208 	s->s_mapclass.map_init = host_map_init;
209 	s->s_mapclass.map_lookup = maphostname;
210 
211 	/*
212 	**  Set up other map classes.
213 	*/
214 
215 # ifdef DBM_MAP
216 	/* dbm file access */
217 	{
218 		extern bool dbm_map_init();
219 		extern char *dbm_map_lookup();
220 
221 		s = stab("dbm", ST_MAPCLASS, ST_ENTER);
222 		s->s_mapclass.map_init = dbm_map_init;
223 		s->s_mapclass.map_lookup = dbm_map_lookup;
224 	}
225 # endif
226 
227 # ifdef BTREE_MAP
228 	/* new database file access -- btree files */
229 	{
230 		extern bool bt_map_init();
231 		extern char *db_map_lookup();
232 
233 		s = stab("btree", ST_MAPCLASS, ST_ENTER);
234 		s->s_mapclass.map_init = bt_map_init;
235 		s->s_mapclass.map_lookup = db_map_lookup;
236 	}
237 # endif
238 
239 # ifdef HASH_MAP
240 	/* new database file access -- hash files */
241 	{
242 		extern bool hash_map_init();
243 		extern char *db_map_lookup();
244 
245 		s = stab("hash", ST_MAPCLASS, ST_ENTER);
246 		s->s_mapclass.map_init = hash_map_init;
247 		s->s_mapclass.map_lookup = db_map_lookup;
248 	}
249 # endif
250 
251 # ifdef NIS_MAP
252 	/* NIS map access */
253 	{
254 		extern bool nis_map_init();
255 		extern char *nis_map_lookup();
256 
257 		s = stab("nis", ST_MAPCLASS, ST_ENTER);
258 		s->s_mapclass.map_init = nis_map_init;
259 		s->s_mapclass.map_lookup = nis_map_lookup;
260 	}
261 # endif
262 
263 # ifdef USERDB_MAP
264 	/* user database */
265 	{
266 		extern bool udb_map_init();
267 		extern char *udb_map_lookup();
268 
269 		s = stab("udb", ST_MAPCLASS, ST_ENTER);
270 		s->s_mapclass.map_init = udb_map_init;
271 		s->s_mapclass.map_lookup = udb_map_lookup;
272 	}
273 # endif
274 }
275 /*
276 **  HOST_MAP_INIT -- initialize host class structures
277 */
278 
279 bool
280 host_map_init(map, mapname, args)
281 	MAP *map;
282 	char *mapname;
283 	char *args;
284 {
285 	register char *p = args;
286 
287 	for (;;)
288 	{
289 		while (isascii(*p) && isspace(*p))
290 			p++;
291 		if (*p != '-')
292 			break;
293 		switch (*++p)
294 		{
295 		  case 'a':
296 			map->map_app = ++p;
297 			break;
298 		}
299 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
300 			p++;
301 		if (*p != '\0')
302 			*p++ = '\0';
303 	}
304 	if (map->map_app != NULL)
305 		map->map_app = newstr(map->map_app);
306 	return TRUE;
307 }
308 /*
309 **  SETUPMAILERS -- initialize default mailers
310 */
311 
312 setupmailers()
313 {
314 	char buf[100];
315 
316 	strcpy(buf, "prog, P=/bin/sh, F=lsD, A=sh -c $u");
317 	makemailer(buf);
318 
319 	strcpy(buf, "*file*, P=/dev/null, F=lsDEu, A=FILE");
320 	makemailer(buf);
321 
322 	strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE");
323 	makemailer(buf);
324 }
325 /*
326 **  GETRUID -- get real user id (V7)
327 */
328 
329 getruid()
330 {
331 	if (OpMode == MD_DAEMON)
332 		return (RealUid);
333 	else
334 		return (getuid());
335 }
336 
337 
338 /*
339 **  GETRGID -- get real group id (V7).
340 */
341 
342 getrgid()
343 {
344 	if (OpMode == MD_DAEMON)
345 		return (RealGid);
346 	else
347 		return (getgid());
348 }
349 /*
350 **  USERNAME -- return the user id of the logged in user.
351 **
352 **	Parameters:
353 **		none.
354 **
355 **	Returns:
356 **		The login name of the logged in user.
357 **
358 **	Side Effects:
359 **		none.
360 **
361 **	Notes:
362 **		The return value is statically allocated.
363 */
364 
365 char *
366 username()
367 {
368 	static char *myname = NULL;
369 	extern char *getlogin();
370 	register struct passwd *pw;
371 
372 	/* cache the result */
373 	if (myname == NULL)
374 	{
375 		myname = getlogin();
376 		if (myname == NULL || myname[0] == '\0')
377 		{
378 			pw = getpwuid(getruid());
379 			if (pw != NULL)
380 				myname = newstr(pw->pw_name);
381 		}
382 		else
383 		{
384 			uid_t uid = getuid();
385 
386 			myname = newstr(myname);
387 			if ((pw = getpwnam(myname)) == NULL ||
388 			      (uid != 0 && uid != pw->pw_uid))
389 			{
390 				pw = getpwuid(uid);
391 				if (pw != NULL)
392 					myname = newstr(pw->pw_name);
393 			}
394 		}
395 		if (myname == NULL || myname[0] == '\0')
396 		{
397 			syserr("554 Who are you?");
398 			myname = "postmaster";
399 		}
400 	}
401 
402 	return (myname);
403 }
404 /*
405 **  TTYPATH -- Get the path of the user's tty
406 **
407 **	Returns the pathname of the user's tty.  Returns NULL if
408 **	the user is not logged in or if s/he has write permission
409 **	denied.
410 **
411 **	Parameters:
412 **		none
413 **
414 **	Returns:
415 **		pathname of the user's tty.
416 **		NULL if not logged in or write permission denied.
417 **
418 **	Side Effects:
419 **		none.
420 **
421 **	WARNING:
422 **		Return value is in a local buffer.
423 **
424 **	Called By:
425 **		savemail
426 */
427 
428 # include <sys/stat.h>
429 
430 char *
431 ttypath()
432 {
433 	struct stat stbuf;
434 	register char *pathn;
435 	extern char *ttyname();
436 	extern char *getlogin();
437 
438 	/* compute the pathname of the controlling tty */
439 	if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL &&
440 	    (pathn = ttyname(0)) == NULL)
441 	{
442 		errno = 0;
443 		return (NULL);
444 	}
445 
446 	/* see if we have write permission */
447 	if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode))
448 	{
449 		errno = 0;
450 		return (NULL);
451 	}
452 
453 	/* see if the user is logged in */
454 	if (getlogin() == NULL)
455 		return (NULL);
456 
457 	/* looks good */
458 	return (pathn);
459 }
460 /*
461 **  CHECKCOMPAT -- check for From and To person compatible.
462 **
463 **	This routine can be supplied on a per-installation basis
464 **	to determine whether a person is allowed to send a message.
465 **	This allows restriction of certain types of internet
466 **	forwarding or registration of users.
467 **
468 **	If the hosts are found to be incompatible, an error
469 **	message should be given using "usrerr" and 0 should
470 **	be returned.
471 **
472 **	'NoReturn' can be set to suppress the return-to-sender
473 **	function; this should be done on huge messages.
474 **
475 **	Parameters:
476 **		to -- the person being sent to.
477 **
478 **	Returns:
479 **		an exit status
480 **
481 **	Side Effects:
482 **		none (unless you include the usrerr stuff)
483 */
484 
485 checkcompat(to, e)
486 	register ADDRESS *to;
487 	register ENVELOPE *e;
488 {
489 # ifdef lint
490 	if (to == NULL)
491 		to++;
492 # endif lint
493 # ifdef EXAMPLE_CODE
494 	/* this code is intended as an example only */
495 	register STAB *s;
496 
497 	s = stab("arpa", ST_MAILER, ST_FIND);
498 	if (s != NULL && e->e_from.q_mailer != LocalMailer &&
499 	    to->q_mailer == s->s_mailer)
500 	{
501 		usrerr("553 No ARPA mail through this machine: see your system administration");
502 		/* NoReturn = TRUE; to supress return copy */
503 		return (EX_UNAVAILABLE);
504 	}
505 # endif /* EXAMPLE_CODE */
506 	return (EX_OK);
507 }
508 /*
509 **  HOLDSIGS -- arrange to hold all signals
510 **
511 **	Parameters:
512 **		none.
513 **
514 **	Returns:
515 **		none.
516 **
517 **	Side Effects:
518 **		Arranges that signals are held.
519 */
520 
521 holdsigs()
522 {
523 }
524 /*
525 **  RLSESIGS -- arrange to release all signals
526 **
527 **	This undoes the effect of holdsigs.
528 **
529 **	Parameters:
530 **		none.
531 **
532 **	Returns:
533 **		none.
534 **
535 **	Side Effects:
536 **		Arranges that signals are released.
537 */
538 
539 rlsesigs()
540 {
541 }
542 /*
543 **  GETLA -- get the current load average
544 **
545 **	This code stolen from la.c.
546 **
547 **	Parameters:
548 **		none.
549 **
550 **	Returns:
551 **		The current load average as an integer.
552 **
553 **	Side Effects:
554 **		none.
555 */
556 
557 /* try to guess what style of load average we have */
558 #define LA_ZERO		1	/* always return load average as zero */
559 #define LA_INT		2	/* read kmem for avenrun; interpret as int */
560 #define LA_FLOAT	3	/* read kmem for avenrun; interpret as float */
561 #define LA_SUBR		4	/* call getloadavg */
562 
563 #ifndef LA_TYPE
564 #  if defined(sun)
565 #    define LA_TYPE		LA_INT
566 #  endif
567 #  if defined(mips) || defined(__alpha)
568      /* Ultrix or OSF/1 or RISC/os */
569 #    define LA_TYPE		LA_INT
570 #    define LA_AVENRUN		"avenrun"
571 #  endif
572 #  if defined(hpux)
573 #    define LA_TYPE		LA_FLOAT
574 #  endif
575 
576 #  ifndef LA_TYPE
577 #   if defined(SYSTEM5)
578 #    define LA_TYPE		LA_INT
579 #    define LA_AVENRUN		"avenrun"
580 #   else
581 #    if defined(BSD)
582 #     define LA_TYPE		LA_SUBR
583 #    else
584 #     define LA_TYPE		LA_ZERO
585 #    endif
586 #   endif
587 #  endif
588 #endif
589 
590 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT)
591 
592 #include <nlist.h>
593 
594 #ifndef LA_AVENRUN
595 #define LA_AVENRUN	"_avenrun"
596 #endif
597 
598 /* _PATH_UNIX should be defined in <paths.h> */
599 #ifndef _PATH_UNIX
600 #  if defined(hpux)
601 #    define _PATH_UNIX		"/hp-ux"
602 #  endif
603 #  if defined(mips) && !defined(ultrix)
604      /* powerful RISC/os */
605 #    define _PATH_UNIX		"/unix"
606 #  endif
607 #  if defined(SYSTEM5)
608 #    ifndef _PATH_UNIX
609 #      define _PATH_UNIX	"/unix"
610 #    endif
611 #  endif
612 #  ifndef _PATH_UNIX
613 #    define _PATH_UNIX		"/vmunix"
614 #  endif
615 #endif
616 
617 struct	nlist Nl[] =
618 {
619 	{ LA_AVENRUN },
620 #define	X_AVENRUN	0
621 	{ 0 },
622 };
623 
624 #if defined(unixpc)
625 # define FSHIFT		5
626 #endif
627 
628 #if defined(__alpha)
629 # define FSHIFT		10
630 #endif
631 
632 #if (LA_TYPE == LA_INT) && !defined(FSHIFT)
633 #  define FSHIFT	8
634 #endif
635 #if (LA_TYPE == LA_INT) && !defined(FSCALE)
636 #  define FSCALE	(1 << FSHIFT)
637 #endif
638 
639 getla()
640 {
641 	static int kmem = -1;
642 #if LA_TYPE == LA_INT
643 	long avenrun[3];
644 #else
645 	double avenrun[3];
646 #endif
647 	extern off_t lseek();
648 	extern char *errstring();
649 	extern int errno;
650 
651 	if (kmem < 0)
652 	{
653 		kmem = open("/dev/kmem", 0, 0);
654 		if (kmem < 0)
655 		{
656 			if (tTd(3, 1))
657 				printf("getla: open(/dev/kmem): %s\n",
658 					errstring(errno));
659 			return (-1);
660 		}
661 		(void) fcntl(kmem, F_SETFD, 1);
662 		if (nlist(_PATH_UNIX, Nl) < 0)
663 		{
664 			if (tTd(3, 1))
665 				printf("getla: nlist(%s): %s\n", _PATH_UNIX,
666 					errstring(errno));
667 			return (-1);
668 		}
669 	}
670 	if (tTd(3, 20))
671 		printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value);
672 	if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 ||
673 	    read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
674 	{
675 		/* thank you Ian */
676 		if (tTd(3, 1))
677 			printf("getla: lseek or read: %s\n", errstring(errno));
678 		return (-1);
679 	}
680 #if LA_TYPE == LA_INT
681 	if (tTd(3, 5))
682 	{
683 		printf("getla: avenrun = %d", avenrun[0]);
684 		if (tTd(3, 15))
685 			printf(", %d, %d", avenrun[1], avenrun[2]);
686 		printf("\n");
687 	}
688 	if (tTd(3, 1))
689 		printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
690 	return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
691 #else
692 	if (tTd(3, 5))
693 	{
694 		printf("getla: avenrun = %g", avenrun[0]);
695 		if (tTd(3, 15))
696 			printf(", %g, %g", avenrun[1], avenrun[2]);
697 		printf("\n");
698 	}
699 	if (tTd(3, 1))
700 		printf("getla: %d\n", (int) (avenrun[0] +0.5));
701 	return ((int) (avenrun[0] + 0.5));
702 #endif
703 }
704 
705 #else
706 #if LA_TYPE == LA_SUBR
707 
708 getla()
709 {
710 	double avenrun[3];
711 
712 	if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0)
713 	{
714 		if (tTd(3, 1))
715 			perror("getla: getloadavg failed:");
716 		return (-1);
717 	}
718 	if (tTd(3, 1))
719 		printf("getla: %d\n", (int) (avenrun[0] +0.5));
720 	return ((int) (avenrun[0] + 0.5));
721 }
722 
723 #else
724 
725 getla()
726 {
727 	if (tTd(3, 1))
728 		printf("getla: ZERO\n");
729 	return (0);
730 }
731 
732 #endif
733 #endif
734 /*
735 **  SHOULDQUEUE -- should this message be queued or sent?
736 **
737 **	Compares the message cost to the load average to decide.
738 **
739 **	Parameters:
740 **		pri -- the priority of the message in question.
741 **		ctime -- the message creation time.
742 **
743 **	Returns:
744 **		TRUE -- if this message should be queued up for the
745 **			time being.
746 **		FALSE -- if the load is low enough to send this message.
747 **
748 **	Side Effects:
749 **		none.
750 */
751 
752 bool
753 shouldqueue(pri, ctime)
754 	long pri;
755 	time_t ctime;
756 {
757 	if (CurrentLA < QueueLA)
758 		return (FALSE);
759 	if (CurrentLA >= RefuseLA)
760 		return (TRUE);
761 	return (pri > (QueueFactor / (CurrentLA - QueueLA + 1)));
762 }
763 /*
764 **  REFUSECONNECTIONS -- decide if connections should be refused
765 **
766 **	Parameters:
767 **		none.
768 **
769 **	Returns:
770 **		TRUE if incoming SMTP connections should be refused
771 **			(for now).
772 **		FALSE if we should accept new work.
773 **
774 **	Side Effects:
775 **		none.
776 */
777 
778 bool
779 refuseconnections()
780 {
781 	/* this is probably too simplistic */
782 	return (CurrentLA >= RefuseLA);
783 }
784 /*
785 **  SETPROCTITLE -- set process title for ps
786 **
787 **	Parameters:
788 **		fmt -- a printf style format string.
789 **		a, b, c -- possible parameters to fmt.
790 **
791 **	Returns:
792 **		none.
793 **
794 **	Side Effects:
795 **		Clobbers argv of our main procedure so ps(1) will
796 **		display the title.
797 */
798 
799 #ifdef SETPROCTITLE
800 # ifdef __hpux
801 #  include <sys/pstat.h>
802 # endif
803 #endif
804 
805 /*VARARGS1*/
806 #ifdef __STDC__
807 setproctitle(char *fmt, ...)
808 #else
809 setproctitle(fmt, va_alist)
810 	char *fmt;
811 	va_dcl
812 #endif
813 {
814 # ifdef SETPROCTITLE
815 	register char *p;
816 	register int i;
817 	char buf[MAXLINE];
818 	VA_LOCAL_DECL
819 #  ifdef __hpux
820 	union pstun pst;
821 #  endif
822 	extern char **Argv;
823 	extern char *LastArgv;
824 
825 	p = buf;
826 
827 	/* print sendmail: heading for grep */
828 	(void) strcpy(p, "sendmail: ");
829 	p += strlen(p);
830 
831 	/* print the argument string */
832 	VA_START(fmt);
833 	(void) vsprintf(p, fmt, ap);
834 	VA_END;
835 
836 	i = strlen(buf);
837 
838 #  ifdef __hpux
839 	pst.pst_command = buf;
840 	pstat(PSTAT_SETCMD, pst, i, 0, 0);
841 #  else
842 
843 	if (i > LastArgv - Argv[0] - 2)
844 	{
845 		i = LastArgv - Argv[0] - 2;
846 		buf[i] = '\0';
847 	}
848 	(void) strcpy(Argv[0], buf);
849 	p = &Argv[0][i];
850 	while (p < LastArgv)
851 		*p++ = ' ';
852 #  endif
853 # endif /* SETPROCTITLE */
854 }
855 /*
856 **  REAPCHILD -- pick up the body of my child, lest it become a zombie
857 **
858 **	Parameters:
859 **		none.
860 **
861 **	Returns:
862 **		none.
863 **
864 **	Side Effects:
865 **		Picks up extant zombies.
866 */
867 
868 # include <sys/wait.h>
869 
870 void
871 reapchild()
872 {
873 # ifdef WNOHANG
874 	union wait status;
875 
876 	while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0)
877 		continue;
878 # else /* WNOHANG */
879 	auto int status;
880 
881 	while (wait((int *)&status) > 0)
882 		continue;
883 # endif /* WNOHANG */
884 # ifdef SYSTEM5
885 	(void) signal(SIGCHLD, reapchild);
886 # endif
887 }
888 /*
889 **  UNSETENV -- remove a variable from the environment
890 **
891 **	Not needed on newer systems.
892 **
893 **	Parameters:
894 **		name -- the string name of the environment variable to be
895 **			deleted from the current environment.
896 **
897 **	Returns:
898 **		none.
899 **
900 **	Globals:
901 **		environ -- a pointer to the current environment.
902 **
903 **	Side Effects:
904 **		Modifies environ.
905 */
906 
907 #ifdef UNSETENV
908 
909 void
910 unsetenv(name)
911 	char *name;
912 {
913 	extern char **environ;
914 	register char **pp;
915 	int len = strlen(name);
916 
917 	for (pp = environ; *pp != NULL; pp++)
918 	{
919 		if (strncmp(name, *pp, len) == 0 &&
920 		    ((*pp)[len] == '=' || (*pp)[len] == '\0'))
921 			break;
922 	}
923 
924 	for (; *pp != NULL; pp++)
925 		*pp = pp[1];
926 }
927 
928 #endif /* UNSETENV */
929 /*
930 **  GETDTABLESIZE -- return number of file descriptors
931 **
932 **	Only on non-BSD systems
933 **
934 **	Parameters:
935 **		none
936 **
937 **	Returns:
938 **		size of file descriptor table
939 **
940 **	Side Effects:
941 **		none
942 */
943 
944 #ifdef SYSTEM5
945 
946 int
947 getdtablesize()
948 {
949 # ifdef _SC_OPEN_MAX
950 	return sysconf(_SC_OPEN_MAX);
951 # else
952 	return NOFILE;
953 # endif
954 }
955 
956 #endif
957 /*
958 **  UNAME -- get the UUCP name of this system.
959 */
960 
961 #ifndef HASUNAME
962 
963 int
964 uname(name)
965 	struct utsname *name;
966 {
967 	FILE *file;
968 	char *n;
969 
970 	name->nodename[0] = '\0';
971 
972 	/* try /etc/whoami -- one line with the node name */
973 	if ((file = fopen("/etc/whoami", "r")) != NULL)
974 	{
975 		(void) fgets(name->nodename, NODE_LENGTH + 1, file);
976 		(void) fclose(file);
977 		n = strchr(name->nodename, '\n');
978 		if (n != NULL)
979 			*n = '\0';
980 		if (name->nodename[0] != '\0')
981 			return (0);
982 	}
983 
984 	/* try /usr/include/whoami.h -- has a #define somewhere */
985 	if ((file = fopen("/usr/include/whoami.h", "r")) != NULL)
986 	{
987 		char buf[MAXLINE];
988 
989 		while (fgets(buf, MAXLINE, file) != NULL)
990 			if (sscanf(buf, "#define sysname \"%*[^\"]\"",
991 					NODE_LENGTH, name->nodename) > 0)
992 				break;
993 		(void) fclose(file);
994 		if (name->nodename[0] != '\0')
995 			return (0);
996 	}
997 
998 #ifdef TRUST_POPEN
999 	/*
1000 	**  Popen is known to have security holes.
1001 	*/
1002 
1003 	/* try uuname -l to return local name */
1004 	if ((file = popen("uuname -l", "r")) != NULL)
1005 	{
1006 		(void) fgets(name, NODE_LENGTH + 1, file);
1007 		(void) pclose(file);
1008 		n = strchr(name, '\n');
1009 		if (n != NULL)
1010 			*n = '\0';
1011 		if (name->nodename[0] != '\0')
1012 			return (0);
1013 	}
1014 #endif
1015 
1016 	return (-1);
1017 }
1018 #endif /* HASUNAME */
1019 /*
1020 **  INITGROUPS -- initialize groups
1021 **
1022 **	Stub implementation for System V style systems
1023 */
1024 
1025 #ifndef HASINITGROUPS
1026 # if !defined(SYSTEM5) || defined(hpux)
1027 #  define HASINITGROUPS
1028 # endif
1029 #endif
1030 
1031 #ifndef HASINITGROUPS
1032 
1033 initgroups(name, basegid)
1034 	char *name;
1035 	int basegid;
1036 {
1037 	return 0;
1038 }
1039 
1040 #endif
1041 /*
1042 **  ENOUGHSPACE -- check to see if there is enough free space on the queue fs
1043 **
1044 **	Only implemented if you have statfs.
1045 **
1046 **	Parameters:
1047 **		msize -- the size to check against.  If zero, we don't yet
1048 **			know how big the message will be, so just check for
1049 **			a "reasonable" amount.
1050 **
1051 **	Returns:
1052 **		TRUE if there is enough space.
1053 **		FALSE otherwise.
1054 */
1055 
1056 #ifndef HASSTATFS
1057 # if defined(BSD4_4) || defined(__osf__)
1058 #  define HASSTATFS
1059 # endif
1060 #endif
1061 
1062 #ifdef HASSTATFS
1063 # undef HASUSTAT
1064 #endif
1065 
1066 #if defined(HASUSTAT)
1067 # include <sys/stat.h>
1068 # include <ustat.h>
1069 #endif
1070 
1071 #ifdef HASSTATFS
1072 # if defined(sgi) || defined(apollo)
1073 #  include <sys/statfs.h>
1074 # else
1075 #  if defined(sun) || defined(hpux)
1076 #   include <sys/vfs.h>
1077 #  else
1078 #   include <sys/mount.h>
1079 #  endif
1080 # endif
1081 #endif
1082 
1083 bool
1084 enoughspace(msize)
1085 	long msize;
1086 {
1087 #if defined(HASSTATFS) || defined(HASUSTAT)
1088 # if defined(HASUSTAT)
1089 	struct ustat fs;
1090 	struct stat statbuf;
1091 #  define FSBLOCKSIZE	DEV_BSIZE
1092 #  define f_bavail	f_tfree
1093 # else
1094 #  if defined(ultrix)
1095 	struct fs_data fs;
1096 #   define f_bavail	fd_bfreen
1097 #   define FSBLOCKSIZE	fs.fd_bsize
1098 #  else
1099 	struct statfs fs;
1100 #   define FSBLOCKSIZE	fs.f_bsize
1101 #  endif
1102 # endif
1103 	long blocksneeded;
1104 	extern int errno;
1105 	extern char *errstring();
1106 
1107 	if (MinBlocksFree <= 0 && msize <= 0)
1108 	{
1109 		if (tTd(4, 80))
1110 			printf("enoughspace: no threshold\n");
1111 		return TRUE;
1112 	}
1113 
1114 # if defined(HASUSTAT)
1115 	if (stat(QueueDir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0)
1116 # else
1117 #  if defined(sgi) || defined(apollo)
1118 	if (statfs(QueueDir, &fs, sizeof fs, 0) == 0)
1119 #  else
1120 #   if defined(ultrix)
1121 	if (statfs(QueueDir, &fs) > 0)
1122 #   else
1123 	if (statfs(QueueDir, &fs) == 0)
1124 #   endif
1125 #  endif
1126 # endif
1127 	{
1128 		if (tTd(4, 80))
1129 			printf("enoughspace: bavail=%ld, need=%ld\n",
1130 				fs.f_bavail, msize);
1131 
1132 		/* convert msize to block count */
1133 		msize = msize / FSBLOCKSIZE + 1;
1134 		if (MinBlocksFree >= 0)
1135 			msize += MinBlocksFree;
1136 
1137 		if (fs.f_bavail < msize)
1138 		{
1139 #ifdef LOG
1140 			if (LogLevel > 0)
1141 				syslog(LOG_ALERT, "%s: low on space (have %ld, need %ld)",
1142 					QueueDir, fs.f_bavail, msize);
1143 #endif
1144 			return FALSE;
1145 		}
1146 	}
1147 	else if (tTd(4, 80))
1148 		printf("enoughspace failure: min=%ld, need=%ld: %s\n",
1149 			MinBlocksFree, msize, errstring(errno));
1150 #endif
1151 	return TRUE;
1152 }
1153 /*
1154 **  TRANSIENTERROR -- tell if an error code indicates a transient failure
1155 **
1156 **	This looks at an errno value and tells if this is likely to
1157 **	go away if retried later.
1158 **
1159 **	Parameters:
1160 **		err -- the errno code to classify.
1161 **
1162 **	Returns:
1163 **		TRUE if this is probably transient.
1164 **		FALSE otherwise.
1165 */
1166 
1167 bool
1168 transienterror(err)
1169 	int err;
1170 {
1171 	switch (err)
1172 	{
1173 	  case EIO:			/* I/O error */
1174 	  case ENXIO:			/* Device not configured */
1175 	  case EAGAIN:			/* Resource temporarily unavailable */
1176 	  case ENOMEM:			/* Cannot allocate memory */
1177 	  case ENODEV:			/* Operation not supported by device */
1178 	  case ENFILE:			/* Too many open files in system */
1179 	  case EMFILE:			/* Too many open files */
1180 	  case ENOSPC:			/* No space left on device */
1181 #ifdef ETIMEDOUT
1182 	  case ETIMEDOUT:		/* Connection timed out */
1183 #endif
1184 #ifdef ESTALE
1185 	  case ESTALE:			/* Stale NFS file handle */
1186 #endif
1187 #ifdef ENETDOWN
1188 	  case ENETDOWN:		/* Network is down */
1189 #endif
1190 #ifdef ENETUNREACH
1191 	  case ENETUNREACH:		/* Network is unreachable */
1192 #endif
1193 #ifdef ENETRESET
1194 	  case ENETRESET:		/* Network dropped connection on reset */
1195 #endif
1196 #ifdef ECONNABORTED
1197 	  case ECONNABORTED:		/* Software caused connection abort */
1198 #endif
1199 #ifdef ECONNRESET
1200 	  case ECONNRESET:		/* Connection reset by peer */
1201 #endif
1202 #ifdef ENOBUFS
1203 	  case ENOBUFS:			/* No buffer space available */
1204 #endif
1205 #ifdef ESHUTDOWN
1206 	  case ESHUTDOWN:		/* Can't send after socket shutdown */
1207 #endif
1208 #ifdef ECONNREFUSED
1209 	  case ECONNREFUSED:		/* Connection refused */
1210 #endif
1211 #ifdef EHOSTDOWN
1212 	  case EHOSTDOWN:		/* Host is down */
1213 #endif
1214 #ifdef EHOSTUNREACH
1215 	  case EHOSTUNREACH:		/* No route to host */
1216 #endif
1217 #ifdef EDQUOT
1218 	  case EDQUOT:			/* Disc quota exceeded */
1219 #endif
1220 #ifdef EPROCLIM
1221 	  case EPROCLIM:		/* Too many processes */
1222 #endif
1223 #ifdef EUSERS
1224 	  case EUSERS:			/* Too many users */
1225 #endif
1226 #ifdef EDEADLK
1227 	  case EDEADLK:			/* Resource deadlock avoided */
1228 #endif
1229 #ifdef EISCONN
1230 	  case EISCONN:			/* Socket already connected */
1231 #endif
1232 #ifdef EINPROGRESS
1233 	  case EINPROGRESS:		/* Operation now in progress */
1234 #endif
1235 #ifdef EALREADY
1236 	  case EALREADY:		/* Operation already in progress */
1237 #endif
1238 #ifdef EADDRINUSE
1239 	  case EADDRINUSE:		/* Address already in use */
1240 #endif
1241 #ifdef EADDRNOTAVAIL
1242 	  case EADDRNOTAVAIL:		/* Can't assign requested address */
1243 #endif
1244 #ifdef ENOSR
1245 	  case ENOSR:			/* Out of streams resources */
1246 #endif
1247 		return TRUE;
1248 	}
1249 
1250 	/* nope, must be permanent */
1251 	return FALSE;
1252 }
1253 /*
1254 **  LOCKFILE -- lock a file using flock or (shudder) lockf
1255 **
1256 **	Parameters:
1257 **		fd -- the file descriptor of the file.
1258 **		filename -- the file name (for error messages).
1259 **		type -- type of the lock.  Bits can be:
1260 **			LOCK_EX -- exclusive lock.
1261 **			LOCK_NB -- non-blocking.
1262 **
1263 **	Returns:
1264 **		TRUE if the lock was acquired.
1265 **		FALSE otherwise.
1266 */
1267 
1268 bool
1269 lockfile(fd, filename, type)
1270 	int fd;
1271 	char *filename;
1272 	int type;
1273 {
1274 # ifdef LOCKF
1275 	int action;
1276 	struct flock lfd;
1277 
1278 	if (bitset(LOCK_EX, type))
1279 		lfd.l_type = F_WRLCK;
1280 	else
1281 		lfd.l_type = F_RDLCK;
1282 
1283 	if (bitset(LOCK_NB, type))
1284 		action = F_SETLK;
1285 	else
1286 		action = F_SETLKW;
1287 
1288 	lfd.l_whence = lfd.l_start = lfd.l_len = 0;
1289 
1290 	if (fcntl(fd, action, &lfd) >= 0)
1291 		return TRUE;
1292 
1293 	if (!bitset(LOCK_NB, type) || (errno != EACCES && errno != EAGAIN))
1294 		syserr("cannot lockf(%s)", filename);
1295 # else
1296 	if (flock(fd, type) >= 0)
1297 		return TRUE;
1298 
1299 	if (!bitset(LOCK_NB, type) || errno != EWOULDBLOCK)
1300 		syserr("cannot flock(%s)", filename);
1301 # endif
1302 	return FALSE;
1303 }
1304