xref: /csrg-svn/usr.sbin/sendmail/src/conf.c (revision 57252)
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.1 (Berkeley) 12/21/92";
11 #endif /* not lint */
12 
13 # include <sys/ioctl.h>
14 # include <pwd.h>
15 # include "sendmail.h"
16 # include "pathnames.h"
17 
18 /*
19 **  CONF.C -- Sendmail Configuration Tables.
20 **
21 **	Defines the configuration of this installation.
22 **
23 **	Configuration Variables:
24 **		HdrInfo -- a table describing well-known header fields.
25 **			Each entry has the field name and some flags,
26 **			which are described in sendmail.h.
27 **
28 **	Notes:
29 **		I have tried to put almost all the reasonable
30 **		configuration information into the configuration
31 **		file read at runtime.  My intent is that anything
32 **		here is a function of the version of UNIX you
33 **		are running, or is really static -- for example
34 **		the headers are a superset of widely used
35 **		protocols.  If you find yourself playing with
36 **		this file too much, you may be making a mistake!
37 */
38 
39 
40 
41 
42 /*
43 **  Header info table
44 **	Final (null) entry contains the flags used for any other field.
45 **
46 **	Not all of these are actually handled specially by sendmail
47 **	at this time.  They are included as placeholders, to let
48 **	you know that "someday" I intend to have sendmail do
49 **	something with them.
50 */
51 
52 struct hdrinfo	HdrInfo[] =
53 {
54 		/* originator fields, most to least significant  */
55 	"resent-sender",	H_FROM|H_RESENT,
56 	"resent-from",		H_FROM|H_RESENT,
57 	"resent-reply-to",	H_FROM|H_RESENT,
58 	"sender",		H_FROM,
59 	"from",			H_FROM,
60 	"reply-to",		H_FROM,
61 	"full-name",		H_ACHECK,
62 	"return-receipt-to",	H_FROM,
63 	"errors-to",		H_FROM,
64 		/* destination fields */
65 	"to",			H_RCPT,
66 	"resent-to",		H_RCPT|H_RESENT,
67 	"cc",			H_RCPT,
68 	"resent-cc",		H_RCPT|H_RESENT,
69 	"bcc",			H_RCPT|H_ACHECK,
70 	"resent-bcc",		H_RCPT|H_ACHECK|H_RESENT,
71 	"apparently-to",	H_RCPT,
72 		/* message identification and control */
73 	"message-id",		0,
74 	"resent-message-id",	H_RESENT,
75 	"message",		H_EOH,
76 	"text",			H_EOH,
77 		/* date fields */
78 	"date",			0,
79 	"resent-date",		H_RESENT,
80 		/* trace fields */
81 	"received",		H_TRACE|H_FORCE,
82 	"via",			H_TRACE|H_FORCE,
83 	"mail-from",		H_TRACE|H_FORCE,
84 
85 	NULL,			0,
86 };
87 
88 
89 /*
90 **  ARPANET error message numbers.
91 */
92 
93 char	Arpa_Info[] =		"050";	/* arbitrary info */
94 char	Arpa_TSyserr[] =	"451";	/* some (transient) system error */
95 char	Arpa_PSyserr[] =	"554";	/* some (permanent) system error */
96 char	Arpa_Usrerr[] =		"554";	/* some (fatal) user error */
97 
98 
99 
100 /*
101 **  Location of system files/databases/etc.
102 */
103 
104 char	*ConfFile =	_PATH_SENDMAILCF;	/* runtime configuration */
105 char	*FreezeFile =	_PATH_SENDMAILFC;	/* frozen version of above */
106 
107 
108 
109 /*
110 **  Miscellaneous stuff.
111 */
112 
113 int	DtableSize =	50;		/* max open files; reset in 4.2bsd */
114 /*
115 **  SETDEFAULTS -- set default values
116 **
117 **	Because of the way freezing is done, these must be initialized
118 **	using direct code.
119 **
120 **	Parameters:
121 **		none.
122 **
123 **	Returns:
124 **		none.
125 **
126 **	Side Effects:
127 **		Initializes a bunch of global variables to their
128 **		default values.
129 */
130 
131 setdefaults()
132 {
133 	QueueLA = 8;
134 	QueueFactor = 10000;
135 	RefuseLA = 12;
136 	SpaceSub = ' ';
137 	WkRecipFact = 1000;
138 	WkClassFact = 1800;
139 	WkTimeFact = 9000;
140 	FileMode = (getuid() != geteuid()) ? 0644 : 0600;
141 	DefUid = 1;
142 	DefGid = 1;
143 	CheckpointInterval = 10;
144 	MaxHopCount = 17;
145 	SendMode = SM_FORK;
146 	ErrorMode = EM_PRINT;
147 	EightBit = FALSE;
148 	MaxMciCache = 1;
149 	MciCacheTimeout = 300;
150 	setdefuser();
151 	setupmaps();
152 }
153 
154 
155 /*
156 **  SETDEFUSER -- set/reset DefUser using DefUid (for initgroups())
157 */
158 
159 setdefuser()
160 {
161 	struct passwd *defpwent;
162 
163 	if (DefUser != NULL)
164 		free(DefUser);
165 	if ((defpwent = getpwuid(DefUid)) != NULL)
166 		DefUser = newstr(defpwent->pw_name);
167 	else
168 		DefUser = newstr("nobody");
169 }
170 /*
171 **  SETUPMAPS -- set up map classes
172 **
173 **	Since these are compiled in, they cannot be in the config file.
174 **
175 */
176 
177 setupmaps()
178 {
179 	register STAB *s;
180 	extern bool host_map_init();
181 	extern char *maphostname();
182 
183 	/* set up host name lookup map */
184 	s = stab("host", ST_MAPCLASS, ST_ENTER);
185 	s->s_mapclass.map_init = host_map_init;
186 	s->s_mapclass.map_lookup = maphostname;
187 
188 	/*
189 	**  Set up other map classes.
190 	*/
191 
192 # ifdef DBM_MAP
193 	/* dbm file access */
194 	{
195 		extern bool dbm_map_init();
196 		extern char *dbm_map_lookup();
197 
198 		s = stab("dbm", ST_MAPCLASS, ST_ENTER);
199 		s->s_mapclass.map_init = dbm_map_init;
200 		s->s_mapclass.map_lookup = dbm_map_lookup;
201 	}
202 # endif
203 
204 # ifdef BTREE_MAP
205 	/* new database file access -- btree files */
206 	{
207 		extern bool bt_map_init();
208 		extern char *db_map_lookup();
209 
210 		s = stab("btree", ST_MAPCLASS, ST_ENTER);
211 		s->s_mapclass.map_init = bt_map_init;
212 		s->s_mapclass.map_lookup = db_map_lookup;
213 	}
214 # endif
215 
216 # ifdef HASH_MAP
217 	/* new database file access -- hash files */
218 	{
219 		extern bool hash_map_init();
220 		extern char *db_map_lookup();
221 
222 		s = stab("hash", ST_MAPCLASS, ST_ENTER);
223 		s->s_mapclass.map_init = hash_map_init;
224 		s->s_mapclass.map_lookup = db_map_lookup;
225 	}
226 # endif
227 
228 # ifdef NIS_MAP
229 	/* NIS map access */
230 	{
231 		extern bool nis_map_init();
232 		extern char *nis_map_lookup();
233 
234 		s = stab("nis", ST_MAPCLASS, ST_ENTER);
235 		s->s_mapclass.map_init = nis_map_init;
236 		s->s_mapclass.map_lookup = nis_map_lookup;
237 	}
238 # endif
239 
240 # ifdef USERDB_MAP
241 	/* user database */
242 	{
243 		extern bool udb_map_init();
244 		extern char *udb_map_lookup();
245 
246 		s = stab("udb", ST_MAPCLASS, ST_ENTER);
247 		s->s_mapclass.map_init = udb_map_init;
248 		s->s_mapclass.map_lookup = udb_map_lookup;
249 	}
250 # endif
251 }
252 /*
253 **  HOST_MAP_INIT -- initialize host class structures
254 */
255 
256 bool
257 host_map_init(map, mapname, args)
258 	MAP *map;
259 	char *mapname;
260 	char *args;
261 {
262 	register char *p = args;
263 
264 	for (;;)
265 	{
266 		while (isspace(*p))
267 			p++;
268 		if (*p != '-')
269 			break;
270 		switch (*++p)
271 		{
272 		  case 'a':
273 			map->map_app = ++p;
274 			break;
275 		}
276 		while (*p != '\0' && !isspace(*p))
277 			p++;
278 		if (*p != '\0')
279 			*p++ = '\0';
280 	}
281 	if (map->map_app != NULL)
282 		map->map_app = newstr(map->map_app);
283 	return TRUE;
284 }
285 
286 /*
287 **  GETRUID -- get real user id (V7)
288 */
289 
290 getruid()
291 {
292 	if (OpMode == MD_DAEMON)
293 		return (RealUid);
294 	else
295 		return (getuid());
296 }
297 
298 
299 /*
300 **  GETRGID -- get real group id (V7).
301 */
302 
303 getrgid()
304 {
305 	if (OpMode == MD_DAEMON)
306 		return (RealGid);
307 	else
308 		return (getgid());
309 }
310 /*
311 **  USERNAME -- return the user id of the logged in user.
312 **
313 **	Parameters:
314 **		none.
315 **
316 **	Returns:
317 **		The login name of the logged in user.
318 **
319 **	Side Effects:
320 **		none.
321 **
322 **	Notes:
323 **		The return value is statically allocated.
324 */
325 
326 char *
327 username()
328 {
329 	static char *myname = NULL;
330 	extern char *getlogin();
331 	register struct passwd *pw;
332 
333 	/* cache the result */
334 	if (myname == NULL)
335 	{
336 		myname = getlogin();
337 		if (myname == NULL || myname[0] == '\0')
338 		{
339 
340 			pw = getpwuid(getruid());
341 			if (pw != NULL)
342 				myname = newstr(pw->pw_name);
343 		}
344 		else
345 		{
346 
347 			myname = newstr(myname);
348 			if ((pw = getpwnam(myname)) == NULL ||
349 			      getuid() != pw->pw_uid)
350 			{
351 				pw = getpwuid(getuid());
352 				if (pw != NULL)
353 					myname = newstr(pw->pw_name);
354 			}
355 		}
356 		if (myname == NULL || myname[0] == '\0')
357 		{
358 			syserr("Who are you?");
359 			myname = "postmaster";
360 		}
361 	}
362 
363 	return (myname);
364 }
365 /*
366 **  TTYPATH -- Get the path of the user's tty
367 **
368 **	Returns the pathname of the user's tty.  Returns NULL if
369 **	the user is not logged in or if s/he has write permission
370 **	denied.
371 **
372 **	Parameters:
373 **		none
374 **
375 **	Returns:
376 **		pathname of the user's tty.
377 **		NULL if not logged in or write permission denied.
378 **
379 **	Side Effects:
380 **		none.
381 **
382 **	WARNING:
383 **		Return value is in a local buffer.
384 **
385 **	Called By:
386 **		savemail
387 */
388 
389 # include <sys/stat.h>
390 
391 char *
392 ttypath()
393 {
394 	struct stat stbuf;
395 	register char *pathn;
396 	extern char *ttyname();
397 	extern char *getlogin();
398 
399 	/* compute the pathname of the controlling tty */
400 	if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL &&
401 	    (pathn = ttyname(0)) == NULL)
402 	{
403 		errno = 0;
404 		return (NULL);
405 	}
406 
407 	/* see if we have write permission */
408 	if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode))
409 	{
410 		errno = 0;
411 		return (NULL);
412 	}
413 
414 	/* see if the user is logged in */
415 	if (getlogin() == NULL)
416 		return (NULL);
417 
418 	/* looks good */
419 	return (pathn);
420 }
421 /*
422 **  CHECKCOMPAT -- check for From and To person compatible.
423 **
424 **	This routine can be supplied on a per-installation basis
425 **	to determine whether a person is allowed to send a message.
426 **	This allows restriction of certain types of internet
427 **	forwarding or registration of users.
428 **
429 **	If the hosts are found to be incompatible, an error
430 **	message should be given using "usrerr" and FALSE should
431 **	be returned.
432 **
433 **	'NoReturn' can be set to suppress the return-to-sender
434 **	function; this should be done on huge messages.
435 **
436 **	Parameters:
437 **		to -- the person being sent to.
438 **
439 **	Returns:
440 **		TRUE -- ok to send.
441 **		FALSE -- not ok.
442 **
443 **	Side Effects:
444 **		none (unless you include the usrerr stuff)
445 */
446 
447 bool
448 checkcompat(to, e)
449 	register ADDRESS *to;
450 	register ENVELOPE *e;
451 {
452 # ifdef lint
453 	if (to == NULL)
454 		to++;
455 # endif lint
456 # ifdef EXAMPLE_CODE
457 	/* this code is intended as an example only */
458 	register STAB *s;
459 
460 	s = stab("arpa", ST_MAILER, ST_FIND);
461 	if (s != NULL && e->e_from.q_mailer != LocalMailer &&
462 	    to->q_mailer == s->s_mailer)
463 	{
464 		usrerr("No ARPA mail through this machine: see your system administration");
465 		/* NoReturn = TRUE; to supress return copy */
466 		return (FALSE);
467 	}
468 # endif /* EXAMPLE_CODE */
469 	return (TRUE);
470 }
471 /*
472 **  HOLDSIGS -- arrange to hold all signals
473 **
474 **	Parameters:
475 **		none.
476 **
477 **	Returns:
478 **		none.
479 **
480 **	Side Effects:
481 **		Arranges that signals are held.
482 */
483 
484 holdsigs()
485 {
486 }
487 /*
488 **  RLSESIGS -- arrange to release all signals
489 **
490 **	This undoes the effect of holdsigs.
491 **
492 **	Parameters:
493 **		none.
494 **
495 **	Returns:
496 **		none.
497 **
498 **	Side Effects:
499 **		Arranges that signals are released.
500 */
501 
502 rlsesigs()
503 {
504 }
505 /*
506 **  GETLA -- get the current load average
507 **
508 **	This code stolen from la.c.
509 **
510 **	Parameters:
511 **		none.
512 **
513 **	Returns:
514 **		The current load average as an integer.
515 **
516 **	Side Effects:
517 **		none.
518 */
519 
520 /* try to guess what style of load average we have */
521 #define LA_ZERO		1	/* always return load average as zero */
522 #define LA_INT		2	/* read kmem for avenrun; interpret as int */
523 #define LA_FLOAT	3	/* read kmem for avenrun; interpret as float */
524 #define LA_SUBR		4	/* call getloadavg */
525 
526 #ifndef LA_TYPE
527 #  if defined(sun)
528 #    define LA_TYPE		LA_INT
529 #  endif
530 #  if defined(mips)
531      /* Ultrix or RISC/os */
532 #    define LA_TYPE		LA_INT
533 #    define LA_AVENRUN		"avenrun"
534 #  endif
535 #  if defined(hpux)
536 #    define LA_TYPE		LA_FLOAT
537 #  endif
538 #  if defined(BSD)
539 #    define LA_TYPE		LA_SUBR
540 #  endif
541 
542 #  ifndef LA_TYPE
543 #    define LA_TYPE		LA_ZERO
544 #  endif
545 #endif
546 
547 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT)
548 
549 #include <nlist.h>
550 #include <fcntl.h>
551 
552 #ifndef LA_AVENRUN
553 #define LA_AVENRUN	"_avenrun"
554 #endif
555 
556 /* _PATH_UNIX should be defined in <paths.h> */
557 #ifndef _PATH_UNIX
558 #  if defined(hpux)
559 #    define _PATH_UNIX		"/hp-ux"
560 #  endif
561 #  if defined(mips) && !defined(ultrix)
562      /* powerful RISC/os */
563 #    define _PATH_UNIX		"/unix"
564 #  endif
565 #  ifndef _PATH_UNIX
566 #    define _PATH_UNIX		"/vmunix"
567 #  endif
568 #endif
569 
570 struct	nlist Nl[] =
571 {
572 	{ LA_AVENRUN },
573 #define	X_AVENRUN	0
574 	{ 0 },
575 };
576 
577 #if (LA_TYPE == LA_INT) && !defined(FSHIFT)
578 #  define FSHIFT	8
579 #  define FSCALE	(1 << FSHIFT)
580 #endif
581 
582 getla()
583 {
584 	static int kmem = -1;
585 #if LA_TYPE == LA_INT
586 	long avenrun[3];
587 #else
588 	double avenrun[3];
589 #endif
590 	extern off_t lseek();
591 
592 	if (kmem < 0)
593 	{
594 		kmem = open("/dev/kmem", 0, 0);
595 		if (kmem < 0)
596 			return (-1);
597 		(void) fcntl(kmem, F_SETFD, 1);
598 		nlist(_PATH_UNIX, Nl);
599 		if (Nl[0].n_type == 0)
600 			return (-1);
601 	}
602 	if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 ||
603 	    read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
604 	{
605 		/* thank you Ian */
606 		return (-1);
607 	}
608 #if LA_TYPE == LA_INT
609 	return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
610 #else
611 	return ((int) (avenrun[0] + 0.5));
612 #endif
613 }
614 
615 #else
616 #if LA_TYPE == LA_SUBR
617 
618 getla()
619 {
620 	double avenrun[3];
621 
622 	if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0)
623 		return (-1);
624 	return ((int) (avenrun[0] + 0.5));
625 }
626 
627 #else
628 
629 getla()
630 {
631 	return (0);
632 }
633 
634 #endif
635 #endif
636 /*
637 **  SHOULDQUEUE -- should this message be queued or sent?
638 **
639 **	Compares the message cost to the load average to decide.
640 **
641 **	Parameters:
642 **		pri -- the priority of the message in question.
643 **
644 **	Returns:
645 **		TRUE -- if this message should be queued up for the
646 **			time being.
647 **		FALSE -- if the load is low enough to send this message.
648 **
649 **	Side Effects:
650 **		none.
651 */
652 
653 bool
654 shouldqueue(pri)
655 	long pri;
656 {
657 	if (CurrentLA < QueueLA)
658 		return (FALSE);
659 	return (pri > (QueueFactor / (CurrentLA - QueueLA + 1)));
660 }
661 /*
662 **  REFUSECONNECTIONS -- decide if connections should be refused
663 **
664 **	Parameters:
665 **		none.
666 **
667 **	Returns:
668 **		TRUE if incoming SMTP connections should be refused
669 **			(for now).
670 **		FALSE if we should accept new work.
671 **
672 **	Side Effects:
673 **		none.
674 */
675 
676 bool
677 refuseconnections()
678 {
679 	/* this is probably too simplistic */
680 	return (CurrentLA > RefuseLA);
681 }
682 /*
683 **  SETPROCTITLE -- set process title for ps
684 **
685 **	Parameters:
686 **		fmt -- a printf style format string.
687 **		a, b, c -- possible parameters to fmt.
688 **
689 **	Returns:
690 **		none.
691 **
692 **	Side Effects:
693 **		Clobbers argv of our main procedure so ps(1) will
694 **		display the title.
695 */
696 
697 /*VARARGS1*/
698 setproctitle(fmt VA_ARG_FORMAL)
699 	char *fmt;
700 	VA_ARG_DECL
701 {
702 # ifdef SETPROCTITLE
703 	register char *p;
704 	register int i;
705 	char buf[MAXLINE];
706 	VA_LOCAL_DECL
707 	extern char **Argv;
708 	extern char *LastArgv;
709 
710 	p = buf;
711 
712 	/* print sendmail: heading for grep */
713 	(void) strcpy(p, "sendmail: ");
714 	p += strlen(p);
715 
716 	/* print the argument string */
717 	VA_START(fmt);
718 	(void) vsprintf(p, fmt, ap);
719 	VA_END;
720 
721 	i = strlen(buf);
722 	if (i > LastArgv - Argv[0] - 2)
723 	{
724 		i = LastArgv - Argv[0] - 2;
725 		buf[i] = '\0';
726 	}
727 	(void) strcpy(Argv[0], buf);
728 	p = &Argv[0][i];
729 	while (p < LastArgv)
730 		*p++ = ' ';
731 # endif /* SETPROCTITLE */
732 }
733 /*
734 **  REAPCHILD -- pick up the body of my child, lest it become a zombie
735 **
736 **	Parameters:
737 **		none.
738 **
739 **	Returns:
740 **		none.
741 **
742 **	Side Effects:
743 **		Picks up extant zombies.
744 */
745 
746 # include <sys/wait.h>
747 
748 void
749 reapchild()
750 {
751 # ifdef WNOHANG
752 	union wait status;
753 
754 	while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0)
755 		continue;
756 # else /* WNOHANG */
757 	auto int status;
758 
759 	while (wait((int *)&status) > 0)
760 		continue;
761 # endif /* WNOHANG */
762 }
763 /*
764 **  UNSETENV -- remove a variable from the environment
765 **
766 **	Not needed on newer systems.
767 **
768 **	Parameters:
769 **		name -- the string name of the environment variable to be
770 **			deleted from the current environment.
771 **
772 **	Returns:
773 **		none.
774 **
775 **	Globals:
776 **		environ -- a pointer to the current environment.
777 **
778 **	Side Effects:
779 **		Modifies environ.
780 */
781 
782 #ifdef UNSETENV
783 
784 void
785 unsetenv(name)
786 	char *name;
787 {
788 	extern char **environ;
789 	register char **pp;
790 	int len = strlen(name);
791 
792 	for (pp = environ; *pp != NULL; pp++)
793 	{
794 		if (strncmp(name, *pp, len) == 0 &&
795 		    ((*pp)[len] == '=' || (*pp)[len] == '\0'))
796 			break;
797 	}
798 
799 	for (; *pp != NULL; pp++)
800 		*pp = pp[1];
801 }
802 
803 #endif /* UNSETENV */
804 /*
805 **  GETDTABLESIZE -- return number of file descriptors
806 **
807 **	Only on non-BSD systems
808 **
809 **	Parameters:
810 **		none
811 **
812 **	Returns:
813 **		size of file descriptor table
814 **
815 **	Side Effects:
816 **		none
817 */
818 
819 #ifdef SYSTEM5
820 
821 int
822 getdtablesize()
823 {
824 	return NOFILE;
825 }
826 
827 #endif
828