xref: /original-bsd/usr.sbin/sendmail/src/conf.c (revision 614f1308)
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	5.41 (Berkeley) 07/20/92";
11 #endif /* not lint */
12 
13 # include <sys/ioctl.h>
14 # include <sys/param.h>
15 # include <pwd.h>
16 # include "sendmail.h"
17 # include "pathnames.h"
18 
19 /*
20 **  CONF.C -- Sendmail Configuration Tables.
21 **
22 **	Defines the configuration of this installation.
23 **
24 **	Configuration Variables:
25 **		HdrInfo -- a table describing well-known header fields.
26 **			Each entry has the field name and some flags,
27 **			which are described in sendmail.h.
28 **
29 **	Notes:
30 **		I have tried to put almost all the reasonable
31 **		configuration information into the configuration
32 **		file read at runtime.  My intent is that anything
33 **		here is a function of the version of UNIX you
34 **		are running, or is really static -- for example
35 **		the headers are a superset of widely used
36 **		protocols.  If you find yourself playing with
37 **		this file too much, you may be making a mistake!
38 */
39 
40 
41 
42 
43 /*
44 **  Header info table
45 **	Final (null) entry contains the flags used for any other field.
46 **
47 **	Not all of these are actually handled specially by sendmail
48 **	at this time.  They are included as placeholders, to let
49 **	you know that "someday" I intend to have sendmail do
50 **	something with them.
51 */
52 
53 struct hdrinfo	HdrInfo[] =
54 {
55 		/* originator fields, most to least significant  */
56 	"resent-sender",	H_FROM|H_RESENT,
57 	"resent-from",		H_FROM|H_RESENT,
58 	"resent-reply-to",	H_FROM|H_RESENT,
59 	"sender",		H_FROM,
60 	"from",			H_FROM,
61 	"reply-to",		H_FROM,
62 	"full-name",		H_ACHECK,
63 	"return-receipt-to",	H_FROM,
64 	"errors-to",		H_FROM,
65 		/* destination fields */
66 	"to",			H_RCPT,
67 	"resent-to",		H_RCPT|H_RESENT,
68 	"cc",			H_RCPT,
69 	"resent-cc",		H_RCPT|H_RESENT,
70 	"bcc",			H_RCPT|H_ACHECK,
71 	"resent-bcc",		H_RCPT|H_ACHECK|H_RESENT,
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 = 0644;
141 	DefUid = 1;
142 	DefGid = 1;
143 	CheckpointInterval = 10;
144 	MaxHopCount = MAXHOP;
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 	MAPCLASS *hostmapclass;
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 = NULL;
186 	s->s_mapclass.map_lookup = maphostname;
187 	hostmapclass = &s->s_mapclass;
188 
189 	s = stab("host", ST_MAP, ST_ENTER);
190 	s->s_map.map_class = hostmapclass;
191 	s->s_map.map_flags = MF_VALID;
192 
193 	/*
194 	**  Set up other map classes.
195 	*/
196 
197 # ifdef DBM_MAP
198 	/* dbm file access */
199 	{
200 		extern void dbm_map_init();
201 		extern char *dbm_map_lookup();
202 
203 		s = stab("dbm", ST_MAPCLASS, ST_ENTER);
204 		s->s_mapclass.map_init = dbm_map_init;
205 		s->s_mapclass.map_lookup = dbm_map_lookup;
206 	}
207 # endif
208 
209 # ifdef BTREE_MAP
210 	/* new database file access -- btree files */
211 	{
212 		extern void bt_map_init();
213 		extern char *bt_map_lookup();
214 
215 		s = stab("btree", ST_MAPCLASS, ST_ENTER);
216 		s->s_mapclass.map_init = bt_map_init;
217 		s->s_mapclass.map_lookup = bt_map_lookup;
218 	}
219 # endif
220 
221 # ifdef HASH_MAP
222 	/* new database file access -- hash files */
223 	{
224 		extern void hash_map_init();
225 		extern char *hash_map_lookup();
226 
227 		s = stab("hash", ST_MAPCLASS, ST_ENTER);
228 		s->s_mapclass.map_init = hash_map_init;
229 		s->s_mapclass.map_lookup = hash_map_lookup;
230 	}
231 # endif
232 
233 # ifdef USERDB_MAP
234 	/* user database */
235 	{
236 		extern void udb_map_init();
237 		extern char *udb_map_lookup();
238 
239 		s = stab("udb", ST_MAPCLASS, ST_ENTER);
240 		s->s_mapclass.map_init = udb_map_init;
241 		s->s_mapclass.map_lookup = udb_map_lookup;
242 	}
243 # endif
244 }
245 /*
246 **  GETRUID -- get real user id (V7)
247 */
248 
249 getruid()
250 {
251 	if (OpMode == MD_DAEMON)
252 		return (RealUid);
253 	else
254 		return (getuid());
255 }
256 
257 
258 /*
259 **  GETRGID -- get real group id (V7).
260 */
261 
262 getrgid()
263 {
264 	if (OpMode == MD_DAEMON)
265 		return (RealGid);
266 	else
267 		return (getgid());
268 }
269 /*
270 **  USERNAME -- return the user id of the logged in user.
271 **
272 **	Parameters:
273 **		none.
274 **
275 **	Returns:
276 **		The login name of the logged in user.
277 **
278 **	Side Effects:
279 **		none.
280 **
281 **	Notes:
282 **		The return value is statically allocated.
283 */
284 
285 char *
286 username()
287 {
288 	static char *myname = NULL;
289 	extern char *getlogin();
290 	register struct passwd *pw;
291 
292 	/* cache the result */
293 	if (myname == NULL)
294 	{
295 		myname = getlogin();
296 		if (myname == NULL || myname[0] == '\0')
297 		{
298 
299 			pw = getpwuid(getruid());
300 			if (pw != NULL)
301 				myname = newstr(pw->pw_name);
302 		}
303 		else
304 		{
305 
306 			myname = newstr(myname);
307 			if ((pw = getpwnam(myname)) == NULL ||
308 			      getuid() != pw->pw_uid)
309 			{
310 				pw = getpwuid(getuid());
311 				if (pw != NULL)
312 					myname = newstr(pw->pw_name);
313 			}
314 		}
315 		if (myname == NULL || myname[0] == '\0')
316 		{
317 			syserr("Who are you?");
318 			myname = "postmaster";
319 		}
320 	}
321 
322 	return (myname);
323 }
324 /*
325 **  TTYPATH -- Get the path of the user's tty
326 **
327 **	Returns the pathname of the user's tty.  Returns NULL if
328 **	the user is not logged in or if s/he has write permission
329 **	denied.
330 **
331 **	Parameters:
332 **		none
333 **
334 **	Returns:
335 **		pathname of the user's tty.
336 **		NULL if not logged in or write permission denied.
337 **
338 **	Side Effects:
339 **		none.
340 **
341 **	WARNING:
342 **		Return value is in a local buffer.
343 **
344 **	Called By:
345 **		savemail
346 */
347 
348 # include <sys/stat.h>
349 
350 char *
351 ttypath()
352 {
353 	struct stat stbuf;
354 	register char *pathn;
355 	extern char *ttyname();
356 	extern char *getlogin();
357 
358 	/* compute the pathname of the controlling tty */
359 	if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL &&
360 	    (pathn = ttyname(0)) == NULL)
361 	{
362 		errno = 0;
363 		return (NULL);
364 	}
365 
366 	/* see if we have write permission */
367 	if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode))
368 	{
369 		errno = 0;
370 		return (NULL);
371 	}
372 
373 	/* see if the user is logged in */
374 	if (getlogin() == NULL)
375 		return (NULL);
376 
377 	/* looks good */
378 	return (pathn);
379 }
380 /*
381 **  CHECKCOMPAT -- check for From and To person compatible.
382 **
383 **	This routine can be supplied on a per-installation basis
384 **	to determine whether a person is allowed to send a message.
385 **	This allows restriction of certain types of internet
386 **	forwarding or registration of users.
387 **
388 **	If the hosts are found to be incompatible, an error
389 **	message should be given using "usrerr" and FALSE should
390 **	be returned.
391 **
392 **	'NoReturn' can be set to suppress the return-to-sender
393 **	function; this should be done on huge messages.
394 **
395 **	Parameters:
396 **		to -- the person being sent to.
397 **
398 **	Returns:
399 **		TRUE -- ok to send.
400 **		FALSE -- not ok.
401 **
402 **	Side Effects:
403 **		none (unless you include the usrerr stuff)
404 */
405 
406 bool
407 checkcompat(to, e)
408 	register ADDRESS *to;
409 	register ENVELOPE *e;
410 {
411 # ifdef lint
412 	if (to == NULL)
413 		to++;
414 # endif lint
415 # ifdef EXAMPLE_CODE
416 	/* this code is intended as an example only */
417 	register STAB *s;
418 
419 	s = stab("arpa", ST_MAILER, ST_FIND);
420 	if (s != NULL && e->e_from.q_mailer != LocalMailer &&
421 	    to->q_mailer == s->s_mailer)
422 	{
423 		usrerr("No ARPA mail through this machine: see your system administration");
424 		/* NoReturn = TRUE; to supress return copy */
425 		return (FALSE);
426 	}
427 # endif EXAMPLE_CODE
428 	return (TRUE);
429 }
430 /*
431 **  HOLDSIGS -- arrange to hold all signals
432 **
433 **	Parameters:
434 **		none.
435 **
436 **	Returns:
437 **		none.
438 **
439 **	Side Effects:
440 **		Arranges that signals are held.
441 */
442 
443 holdsigs()
444 {
445 }
446 /*
447 **  RLSESIGS -- arrange to release all signals
448 **
449 **	This undoes the effect of holdsigs.
450 **
451 **	Parameters:
452 **		none.
453 **
454 **	Returns:
455 **		none.
456 **
457 **	Side Effects:
458 **		Arranges that signals are released.
459 */
460 
461 rlsesigs()
462 {
463 }
464 /*
465 **  GETLA -- get the current load average
466 **
467 **	This code stolen from la.c.
468 **
469 **	Parameters:
470 **		none.
471 **
472 **	Returns:
473 **		The current load average as an integer.
474 **
475 **	Side Effects:
476 **		none.
477 */
478 
479 /* try to guess what style of load average we have */
480 #define LA_ZERO		1	/* always return load average as zero */
481 #define LA_INT		2	/* read kmem for avenrun; interpret as int */
482 #define LA_FLOAT	3	/* read kmem for avenrun; interpret as float */
483 #define LA_SUBR		4	/* call getloadavg */
484 
485 #ifndef LA_TYPE
486 #  if defined(sun)
487 #    define LA_TYPE		LA_INT
488 #  endif
489 #  if defined(mips)
490      /* Ultrix or RISC/os */
491 #    define LA_TYPE		LA_INT
492 #    define LA_AVENRUN		"avenrun"
493 #  endif
494 #  if defined(hpux)
495 #    define LA_TYPE		LA_FLOAT
496 #  endif
497 #  if defined(BSD)
498 #    define LA_TYPE		LA_SUBR
499 #  endif
500 
501 #  ifndef LA_TYPE
502 #    define LA_TYPE		LA_ZERO
503 #  endif
504 #endif
505 
506 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT)
507 
508 #include <nlist.h>
509 #include <fcntl.h>
510 
511 #ifndef LA_AVENRUN
512 #define LA_AVENRUN	"_avenrun"
513 #endif
514 
515 /* _PATH_UNIX should be defined in <paths.h> */
516 #ifndef _PATH_UNIX
517 #  if defined(hpux)
518 #    define _PATH_UNIX		"/hp-ux"
519 #  endif
520 #  if defined(mips) && !defined(ultrix)
521      /* powerful RISC/os */
522 #    define _PATH_UNIX		"/unix"
523 #  endif
524 #  ifndef _PATH_UNIX
525 #    define _PATH_UNIX		"/vmunix"
526 #  endif
527 #endif
528 
529 struct	nlist Nl[] =
530 {
531 	{ LA_AVENRUN },
532 #define	X_AVENRUN	0
533 	{ 0 },
534 };
535 
536 #if (LA_TYPE == LA_INT) && !defined(FSHIFT)
537 #  define FSHIFT	8
538 #  define FSCALE	(1 << FSHIFT)
539 #endif
540 
541 getla()
542 {
543 	static int kmem = -1;
544 #if LA_TYPE == LA_INT
545 	long avenrun[3];
546 #else
547 	double avenrun[3];
548 #endif
549 	extern off_t lseek();
550 
551 	if (kmem < 0)
552 	{
553 		kmem = open("/dev/kmem", 0, 0);
554 		if (kmem < 0)
555 			return (-1);
556 		(void) fcntl(kmem, F_SETFD, 1);
557 		nlist(_PATH_UNIX, Nl);
558 		if (Nl[0].n_type == 0)
559 			return (-1);
560 	}
561 	if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 ||
562 	    read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
563 	{
564 		/* thank you Ian */
565 		return (-1);
566 	}
567 #if LA_TYPE == LA_INT
568 	return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
569 #else
570 	return ((int) (avenrun[0] + 0.5));
571 #endif
572 }
573 
574 #else
575 #if LA_TYPE == LA_SUBR
576 
577 getla()
578 {
579 	double avenrun[3];
580 
581 	if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0)
582 		return (-1);
583 	return ((int) (avenrun[0] + 0.5));
584 }
585 
586 #else
587 
588 getla()
589 {
590 	return (0);
591 }
592 
593 #endif
594 #endif
595 /*
596 **  SHOULDQUEUE -- should this message be queued or sent?
597 **
598 **	Compares the message cost to the load average to decide.
599 **
600 **	Parameters:
601 **		pri -- the priority of the message in question.
602 **
603 **	Returns:
604 **		TRUE -- if this message should be queued up for the
605 **			time being.
606 **		FALSE -- if the load is low enough to send this message.
607 **
608 **	Side Effects:
609 **		none.
610 */
611 
612 bool
613 shouldqueue(pri)
614 	long pri;
615 {
616 	if (CurrentLA < QueueLA)
617 		return (FALSE);
618 	return (pri > (QueueFactor / (CurrentLA - QueueLA + 1)));
619 }
620 /*
621 **  REFUSECONNECTIONS -- decide if connections should be refused
622 **
623 **	Parameters:
624 **		none.
625 **
626 **	Returns:
627 **		TRUE if incoming SMTP connections should be refused
628 **			(for now).
629 **		FALSE if we should accept new work.
630 **
631 **	Side Effects:
632 **		none.
633 */
634 
635 bool
636 refuseconnections()
637 {
638 	/* this is probably too simplistic */
639 	return (CurrentLA > RefuseLA);
640 }
641 /*
642 **  SETPROCTITLE -- set process title for ps
643 **
644 **	Parameters:
645 **		fmt -- a printf style format string.
646 **		a, b, c -- possible parameters to fmt.
647 **
648 **	Returns:
649 **		none.
650 **
651 **	Side Effects:
652 **		Clobbers argv of our main procedure so ps(1) will
653 **		display the title.
654 */
655 
656 /*VARARGS1*/
657 setproctitle(fmt, a, b, c)
658 	char *fmt;
659 {
660 # ifdef SETPROCTITLE
661 	register char *p;
662 	register int i;
663 	extern char **Argv;
664 	extern char *LastArgv;
665 	char buf[MAXLINE];
666 
667 	p = buf;
668 
669 	/* print sendmail: heading for grep */
670 	(void) strcpy(p, "sendmail: ");
671 	p += strlen(p);
672 
673 	/* print the argument string */
674 	(void) sprintf(p, fmt, a, b, c);
675 
676 	i = strlen(buf);
677 	if (i > LastArgv - Argv[0] - 2)
678 	{
679 		i = LastArgv - Argv[0] - 2;
680 		buf[i] = '\0';
681 	}
682 	(void) strcpy(Argv[0], buf);
683 	p = &Argv[0][i];
684 	while (p < LastArgv)
685 		*p++ = ' ';
686 # endif SETPROCTITLE
687 }
688 /*
689 **  REAPCHILD -- pick up the body of my child, lest it become a zombie
690 **
691 **	Parameters:
692 **		none.
693 **
694 **	Returns:
695 **		none.
696 **
697 **	Side Effects:
698 **		Picks up extant zombies.
699 */
700 
701 # include <sys/wait.h>
702 
703 void
704 reapchild()
705 {
706 # ifdef WNOHANG
707 	union wait status;
708 
709 	while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0)
710 		continue;
711 # else WNOHANG
712 	auto int status;
713 
714 	while (wait((int *)&status) > 0)
715 		continue;
716 # endif WNOHANG
717 }
718 /*
719 **  UNSETENV -- remove a variable from the environment
720 **
721 **	Not needed on newer systems.
722 **
723 **	Parameters:
724 **		name -- the string name of the environment variable to be
725 **			deleted from the current environment.
726 **
727 **	Returns:
728 **		none.
729 **
730 **	Globals:
731 **		environ -- a pointer to the current environment.
732 **
733 **	Side Effects:
734 **		Modifies environ.
735 */
736 
737 #ifdef UNSETENV
738 
739 void
740 unsetenv(name)
741 	char *name;
742 {
743 	extern char **environ;
744 	register char **pp;
745 	int len = strlen(name);
746 
747 	for (pp = environ; *pp != NULL; pp++)
748 	{
749 		if (strncmp(name, *pp, len) == 0 &&
750 		    ((*pp)[len] == '=' || (*pp)[len] == '\0'))
751 			break;
752 	}
753 
754 	for (; *pp != NULL; pp++)
755 		*pp = pp[1];
756 }
757 
758 #endif /* UNSETENV */
759