xref: /csrg-svn/usr.sbin/sendmail/src/daemon.c (revision 58755)
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 #include <errno.h>
10 #include <signal.h>
11 #include "sendmail.h"
12 
13 #ifndef lint
14 #ifdef DAEMON
15 static char sccsid[] = "@(#)daemon.c	6.20 (Berkeley) 03/19/93 (with daemon mode)";
16 #else
17 static char sccsid[] = "@(#)daemon.c	6.20 (Berkeley) 03/19/93 (without daemon mode)";
18 #endif
19 #endif /* not lint */
20 
21 #ifdef DAEMON
22 
23 # include <netdb.h>
24 # include <sys/wait.h>
25 # include <sys/time.h>
26 
27 #ifdef NETISO
28 # include <netiso/iso.h>
29 #endif
30 
31 /*
32 **  DAEMON.C -- routines to use when running as a daemon.
33 **
34 **	This entire file is highly dependent on the 4.2 BSD
35 **	interprocess communication primitives.  No attempt has
36 **	been made to make this file portable to Version 7,
37 **	Version 6, MPX files, etc.  If you should try such a
38 **	thing yourself, I recommend chucking the entire file
39 **	and starting from scratch.  Basic semantics are:
40 **
41 **	getrequests()
42 **		Opens a port and initiates a connection.
43 **		Returns in a child.  Must set InChannel and
44 **		OutChannel appropriately.
45 **	clrdaemon()
46 **		Close any open files associated with getting
47 **		the connection; this is used when running the queue,
48 **		etc., to avoid having extra file descriptors during
49 **		the queue run and to avoid confusing the network
50 **		code (if it cares).
51 **	makeconnection(host, port, outfile, infile, usesecureport)
52 **		Make a connection to the named host on the given
53 **		port.  Set *outfile and *infile to the files
54 **		appropriate for communication.  Returns zero on
55 **		success, else an exit status describing the
56 **		error.
57 **	maphostname(map, hbuf, hbufsiz, avp)
58 **		Convert the entry in hbuf into a canonical form.
59 */
60 
61 extern char	*anynet_ntoa();
62 /*
63 **  GETREQUESTS -- open mail IPC port and get requests.
64 **
65 **	Parameters:
66 **		none.
67 **
68 **	Returns:
69 **		none.
70 **
71 **	Side Effects:
72 **		Waits until some interesting activity occurs.  When
73 **		it does, a child is created to process it, and the
74 **		parent waits for completion.  Return from this
75 **		routine is always in the child.  The file pointers
76 **		"InChannel" and "OutChannel" should be set to point
77 **		to the communication channel.
78 */
79 
80 int	DaemonSocket	= -1;		/* fd describing socket */
81 
82 getrequests()
83 {
84 	int t;
85 	register struct servent *sp;
86 	int on = 1;
87 	bool refusingconnections = TRUE;
88 	FILE *pidf;
89 	struct sockaddr_in srvraddr;
90 	extern void reapchild();
91 
92 	/*
93 	**  Set up the address for the mailer.
94 	*/
95 
96 	sp = getservbyname("smtp", "tcp");
97 	if (sp == NULL)
98 	{
99 		syserr("554 server \"smtp\" unknown");
100 		goto severe;
101 	}
102 	srvraddr.sin_family = AF_INET;
103 	srvraddr.sin_addr.s_addr = INADDR_ANY;
104 	srvraddr.sin_port = sp->s_port;
105 
106 	/*
107 	**  Try to actually open the connection.
108 	*/
109 
110 	if (tTd(15, 1))
111 		printf("getrequests: port 0x%x\n", srvraddr.sin_port);
112 
113 	/* get a socket for the SMTP connection */
114 	DaemonSocket = socket(AF_INET, SOCK_STREAM, 0);
115 	if (DaemonSocket < 0)
116 	{
117 		/* probably another daemon already */
118 		syserr("getrequests: can't create socket");
119 	  severe:
120 # ifdef LOG
121 		if (LogLevel > 0)
122 			syslog(LOG_ALERT, "problem creating SMTP socket");
123 # endif /* LOG */
124 		finis();
125 	}
126 
127 	/* turn on network debugging? */
128 	if (tTd(15, 101))
129 		(void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);
130 
131 	(void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on);
132 	(void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on);
133 
134 	if (bind(DaemonSocket, (struct sockaddr *)&srvraddr, sizeof srvraddr) < 0)
135 	{
136 		syserr("getrequests: cannot bind");
137 		(void) close(DaemonSocket);
138 		goto severe;
139 	}
140 
141 	(void) signal(SIGCHLD, reapchild);
142 
143 	/* write the pid to the log file for posterity */
144 	pidf = fopen(PidFile, "w");
145 	if (pidf != NULL)
146 	{
147 		fprintf(pidf, "%d\n", getpid());
148 		fclose(pidf);
149 	}
150 
151 
152 	if (tTd(15, 1))
153 		printf("getrequests: %d\n", DaemonSocket);
154 
155 	for (;;)
156 	{
157 		register int pid;
158 		auto int lotherend;
159 		extern bool refuseconnections();
160 
161 		/* see if we are rejecting connections */
162 		CurrentLA = getla();
163 		if (refuseconnections())
164 		{
165 			if (!refusingconnections)
166 			{
167 				/* don't queue so peer will fail quickly */
168 				(void) listen(DaemonSocket, 0);
169 				refusingconnections = TRUE;
170 			}
171 			setproctitle("rejecting connections: load average: %d",
172 				CurrentLA);
173 			sleep(5);
174 			continue;
175 		}
176 
177 		if (refusingconnections)
178 		{
179 			/* start listening again */
180 			if (listen(DaemonSocket, 10) < 0)
181 			{
182 				syserr("getrequests: cannot listen");
183 				(void) close(DaemonSocket);
184 				goto severe;
185 			}
186 			setproctitle("accepting connections");
187 			refusingconnections = FALSE;
188 		}
189 
190 		/* wait for a connection */
191 		do
192 		{
193 			errno = 0;
194 			lotherend = sizeof RealHostAddr;
195 			t = accept(DaemonSocket,
196 			    (struct sockaddr *)&RealHostAddr, &lotherend);
197 		} while (t < 0 && errno == EINTR);
198 		if (t < 0)
199 		{
200 			syserr("getrequests: accept");
201 			sleep(5);
202 			continue;
203 		}
204 
205 		/*
206 		**  Create a subprocess to process the mail.
207 		*/
208 
209 		if (tTd(15, 2))
210 			printf("getrequests: forking (fd = %d)\n", t);
211 
212 		pid = fork();
213 		if (pid < 0)
214 		{
215 			syserr("daemon: cannot fork");
216 			sleep(10);
217 			(void) close(t);
218 			continue;
219 		}
220 
221 		if (pid == 0)
222 		{
223 			extern struct hostent *gethostbyaddr();
224 			register struct hostent *hp;
225 			char buf[MAXNAME];
226 
227 			/*
228 			**  CHILD -- return to caller.
229 			**	Collect verified idea of sending host.
230 			**	Verify calling user id if possible here.
231 			*/
232 
233 			(void) signal(SIGCHLD, SIG_DFL);
234 
235 			/* determine host name */
236 			hp = gethostbyaddr(RealHostAddr.sa_u.sa_data,
237 					   sizeof RealHostAddr.sa_u.sa_data,
238 					   RealHostAddr.sa_family);
239 			if (hp != NULL)
240 				(void) strcpy(buf, hp->h_name);
241 			else
242 			{
243 				/* produce a dotted quad */
244 				(void) sprintf(buf, "[%s]",
245 					anynet_ntoa(&RealHostAddr));
246 			}
247 
248 #ifdef LOG
249 			if (LogLevel > 10)
250 			{
251 				/* log connection information */
252 				syslog(LOG_INFO, "connect from %s (%s)",
253 					buf, anynet_ntoa(&RealHostAddr));
254 			}
255 #endif
256 
257 			/* should we check for illegal connection here? XXX */
258 
259 			RealHostName = newstr(buf);
260 
261 			(void) close(DaemonSocket);
262 			InChannel = fdopen(t, "r");
263 			OutChannel = fdopen(dup(t), "w");
264 			if (tTd(15, 2))
265 				printf("getreq: returning\n");
266 			return;
267 		}
268 
269 		/* close the port so that others will hang (for a while) */
270 		(void) close(t);
271 	}
272 	/*NOTREACHED*/
273 }
274 /*
275 **  CLRDAEMON -- reset the daemon connection
276 **
277 **	Parameters:
278 **		none.
279 **
280 **	Returns:
281 **		none.
282 **
283 **	Side Effects:
284 **		releases any resources used by the passive daemon.
285 */
286 
287 clrdaemon()
288 {
289 	if (DaemonSocket >= 0)
290 		(void) close(DaemonSocket);
291 	DaemonSocket = -1;
292 }
293 /*
294 **  MAKECONNECTION -- make a connection to an SMTP socket on another machine.
295 **
296 **	Parameters:
297 **		host -- the name of the host.
298 **		port -- the port number to connect to.
299 **		mci -- a pointer to the mail connection information
300 **			structure to be filled in.
301 **		usesecureport -- if set, use a low numbered (reserved)
302 **			port to provide some rudimentary authentication.
303 **
304 **	Returns:
305 **		An exit code telling whether the connection could be
306 **			made and if not why not.
307 **
308 **	Side Effects:
309 **		none.
310 */
311 
312 SOCKADDR	CurHostAddr;		/* address of current host */
313 
314 int
315 makeconnection(host, port, mci, usesecureport)
316 	char *host;
317 	u_short port;
318 	register MCI *mci;
319 	bool usesecureport;
320 {
321 	register int i, s;
322 	register struct hostent *hp = (struct hostent *)NULL;
323 	SOCKADDR addr;
324 	int sav_errno;
325 	int addrlen;
326 #ifdef NAMED_BIND
327 	extern int h_errno;
328 #endif
329 
330 	/*
331 	**  Set up the address for the mailer.
332 	**	Accept "[a.b.c.d]" syntax for host name.
333 	*/
334 
335 #ifdef NAMED_BIND
336 	h_errno = 0;
337 #endif
338 	errno = 0;
339 
340 	if (host[0] == '[')
341 	{
342 		long hid;
343 		register char *p = strchr(host, ']');
344 
345 		if (p != NULL)
346 		{
347 			*p = '\0';
348 			hid = inet_addr(&host[1]);
349 			if (hid == -1)
350 			{
351 				/* try it as a host name (avoid MX lookup) */
352 				hp = gethostbyname(&host[1]);
353 				*p = ']';
354 				goto gothostent;
355 			}
356 			*p = ']';
357 		}
358 		if (p == NULL)
359 		{
360 			usrerr("553 Invalid numeric domain spec \"%s\"", host);
361 			return (EX_NOHOST);
362 		}
363 		addr.sa_family = AF_INET;
364 		addr.sa_len = sizeof hid;
365 		addr.sa_u.sa_inet.sin_addr.s_addr = hid;
366 	}
367 	else
368 	{
369 		hp = gethostbyname(host);
370 gothostent:
371 		if (hp == NULL)
372 		{
373 #ifdef NAMED_BIND
374 			if (errno == ETIMEDOUT || h_errno == TRY_AGAIN)
375 				return (EX_TEMPFAIL);
376 
377 			/* if name server is specified, assume temp fail */
378 			if (errno == ECONNREFUSED && UseNameServer)
379 				return (EX_TEMPFAIL);
380 #endif
381 			return (EX_NOHOST);
382 		}
383 		addr.sa_family = hp->h_addrtype;
384 		addr.sa_len = hp->h_length;
385 		if (addr.sa_family == AF_INET)
386 			bcopy(hp->h_addr,
387 				&addr.sa_u.sa_inet.sin_addr,
388 				hp->h_length);
389 		else
390 			bcopy(hp->h_addr,
391 				addr.sa_u.sa_data,
392 				hp->h_length);
393 		i = 1;
394 	}
395 
396 	/*
397 	**  Determine the port number.
398 	*/
399 
400 	if (port != 0)
401 		port = htons(port);
402 	else
403 	{
404 		register struct servent *sp = getservbyname("smtp", "tcp");
405 
406 		if (sp == NULL)
407 		{
408 			syserr("554 makeconnection: server \"smtp\" unknown");
409 			return (EX_OSERR);
410 		}
411 		port = sp->s_port;
412 	}
413 
414 	switch (addr.sa_family)
415 	{
416 	  case AF_INET:
417 		addr.sa_u.sa_inet.sin_port = port;
418 		addrlen = sizeof (struct sockaddr_in);
419 		break;
420 
421 #ifdef NETISO
422 	  case AF_ISO:
423 		/* assume two byte transport selector */
424 		bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2);
425 		addrlen = sizeof (struct sockaddr_iso);
426 		break;
427 #endif
428 
429 	  default:
430 		syserr("Can't connect to address family %d", addr.sa_family);
431 		return (EX_NOHOST);
432 	}
433 
434 	/*
435 	**  Try to actually open the connection.
436 	*/
437 
438 	for (;;)
439 	{
440 		if (tTd(16, 1))
441 			printf("makeconnection (%s [%s])\n",
442 				host, anynet_ntoa(&addr));
443 
444 		/* save for logging */
445 		CurHostAddr = addr;
446 
447 		if (usesecureport)
448 		{
449 			int rport = IPPORT_RESERVED - 1;
450 
451 			s = rresvport(&rport);
452 		}
453 		else
454 		{
455 			s = socket(AF_INET, SOCK_STREAM, 0);
456 		}
457 		if (s < 0)
458 		{
459 			sav_errno = errno;
460 			syserr("makeconnection: no socket");
461 			goto failure;
462 		}
463 
464 		if (tTd(16, 1))
465 			printf("makeconnection: fd=%d\n", s);
466 
467 		/* turn on network debugging? */
468 		if (tTd(16, 101))
469 		{
470 			int on = 1;
471 			(void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG,
472 					  (char *)&on, sizeof on);
473 		}
474 		if (CurEnv->e_xfp != NULL)
475 			(void) fflush(CurEnv->e_xfp);		/* for debugging */
476 		errno = 0;					/* for debugging */
477 		if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0)
478 			break;
479 
480 		/* couldn't connect.... figure out why */
481 		sav_errno = errno;
482 		(void) close(s);
483 		if (hp && hp->h_addr_list[i])
484 		{
485 			extern char *errstring();
486 
487 			if (tTd(16, 1))
488 				printf("Connect failed (%s); trying new address....\n",
489 					errstring(sav_errno));
490 			if (addr.sa_family == AF_INET)
491 				bcopy(hp->h_addr_list[i++],
492 				      &addr.sa_u.sa_inet.sin_addr,
493 				      hp->h_length);
494 			else
495 				bcopy(hp->h_addr_list[i++],
496 					addr.sa_u.sa_data,
497 					hp->h_length);
498 			continue;
499 		}
500 
501 		/* failure, decide if temporary or not */
502 	failure:
503 		if (transienterror(sav_errno))
504 			return EX_TEMPFAIL;
505 		else
506 		{
507 			extern char *errstring();
508 
509 			message("%s", errstring(sav_errno));
510 			return (EX_UNAVAILABLE);
511 		}
512 	}
513 
514 	/* connection ok, put it into canonical form */
515 	mci->mci_out = fdopen(s, "w");
516 	mci->mci_in = fdopen(dup(s), "r");
517 
518 	return (EX_OK);
519 }
520 /*
521 **  MYHOSTNAME -- return the name of this host.
522 **
523 **	Parameters:
524 **		hostbuf -- a place to return the name of this host.
525 **		size -- the size of hostbuf.
526 **
527 **	Returns:
528 **		A list of aliases for this host.
529 **
530 **	Side Effects:
531 **		Sets the MyIpAddrs buffer to a list of my IP addresses.
532 */
533 
534 struct in_addr	MyIpAddrs[MAXIPADDR + 1];
535 
536 char **
537 myhostname(hostbuf, size)
538 	char hostbuf[];
539 	int size;
540 {
541 	register struct hostent *hp;
542 	extern struct hostent *gethostbyname();
543 
544 	if (gethostname(hostbuf, size) < 0)
545 	{
546 		(void) strcpy(hostbuf, "localhost");
547 	}
548 	hp = gethostbyname(hostbuf);
549 	if (hp != NULL)
550 	{
551 		(void) strncpy(hostbuf, hp->h_name, size - 1);
552 		hostbuf[size - 1] = '\0';
553 
554 		if (hp->h_addrtype == AF_INET && hp->h_length == 4)
555 		{
556 			register int i;
557 
558 			for (i = 0; i < MAXIPADDR; i++)
559 			{
560 				if (hp->h_addr_list[i] == NULL)
561 					break;
562 				MyIpAddrs[i].s_addr = *(u_long *) hp->h_addr_list[i];
563 			}
564 			MyIpAddrs[i].s_addr = 0;
565 		}
566 
567 		return (hp->h_aliases);
568 	}
569 	else
570 		return (NULL);
571 }
572 /*
573 **  GETREALHOSTNAME -- get the real host name asociated with a file descriptor
574 **
575 **	Parameters:
576 **		fd -- the descriptor
577 **
578 **	Returns:
579 **		The host name associated with this descriptor, if it can
580 **			be determined.
581 **		NULL otherwise.
582 **
583 **	Side Effects:
584 **		none
585 */
586 
587 char *
588 getrealhostname(fd)
589 	int fd;
590 {
591 	register struct hostent *hp;
592 	struct sockaddr sa;
593 	int salen;
594 	char hbuf[MAXNAME];
595 	extern struct hostent *gethostbyaddr();
596 
597 	salen = sizeof sa;
598 	if (getsockname(fd, &sa, &salen) < 0 || salen <= 0)
599 		return NULL;
600 	hp = gethostbyaddr(sa.sa_data, sa.sa_len,
601 			   sa.sa_family);
602 	if (hp != NULL)
603 		(void) strcpy(hbuf, hp->h_name);
604 	else
605 		(void) sprintf(hbuf, "[%s]", anynet_ntoa(&sa));
606 	return hbuf;
607 }
608 /*
609 **  MAPHOSTNAME -- turn a hostname into canonical form
610 **
611 **	Parameters:
612 **		map -- a pointer to this map (unused).
613 **		hbuf -- a buffer containing a hostname.
614 **		hbsize -- the size of hbuf.
615 **		avp -- unused -- for compatibility with other mapping
616 **			functions.
617 **
618 **	Returns:
619 **		The mapping, if found.
620 **		NULL if no mapping found.
621 **
622 **	Side Effects:
623 **		Looks up the host specified in hbuf.  If it is not
624 **		the canonical name for that host, return the canonical
625 **		name.
626 */
627 
628 char *
629 maphostname(map, hbuf, hbsize, avp)
630 	MAP *map;
631 	char *hbuf;
632 	int hbsize;
633 	char **avp;
634 {
635 	register struct hostent *hp;
636 	u_long in_addr;
637 	char *cp;
638 	int i;
639 	struct hostent *gethostbyaddr();
640 
641 	/* allow room for null */
642 	hbsize--;
643 
644 	/*
645 	 * If first character is a bracket, then it is an address
646 	 * lookup.  Address is copied into a temporary buffer to
647 	 * strip the brackets and to preserve hbuf if address is
648 	 * unknown.
649 	 */
650 
651 	if (*hbuf != '[')
652 	{
653 		extern bool getcanonname();
654 
655 		if (getcanonname(hbuf, hbsize))
656 			return hbuf;
657 		else
658 			return NULL;
659 	}
660 	if ((cp = strchr(hbuf, ']')) == NULL)
661 		return (NULL);
662 	*cp = '\0';
663 	in_addr = inet_addr(&hbuf[1]);
664 
665 	/* check to see if this is one of our addresses */
666 	for (i = 0; MyIpAddrs[i].s_addr != 0; i++)
667 	{
668 		if (MyIpAddrs[i].s_addr == in_addr)
669 		{
670 			strncpy(hbuf, MyHostName, hbsize);
671 			hbuf[hbsize] = '\0';
672 			return hbuf;
673 		}
674 	}
675 
676 	/* nope -- ask the name server */
677 	hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET);
678 	if (hp == NULL)
679 		return (NULL);
680 
681 	/* found a match -- copy out */
682 	if (strlen(hp->h_name) > hbsize)
683 		hp->h_name[hbsize] = '\0';
684 	(void) strcpy(hbuf, hp->h_name);
685 	return hbuf;
686 }
687 /*
688 **  ANYNET_NTOA -- convert a network address to printable form.
689 **
690 **	Parameters:
691 **		sap -- a pointer to a sockaddr structure.
692 **
693 **	Returns:
694 **		A printable version of that sockaddr.
695 */
696 
697 char *
698 anynet_ntoa(sap)
699 	register SOCKADDR *sap;
700 {
701 	register char *bp;
702 	register char *ap;
703 	int l;
704 	static char buf[80];
705 
706 	if (sap->sa_family == AF_INET)
707 	{
708 		extern char *inet_ntoa();
709 
710 		return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr);
711 	}
712 
713 	/* unknown family -- just dump bytes */
714 	(void) sprintf(buf, "Family %d: ", sap->sa_family);
715 	bp = &buf[strlen(buf)];
716 	ap = sap->sa_u.sa_data;
717 	for (l = sap->sa_len; --l >= 0; )
718 	{
719 		(void) sprintf(bp, "%02x:", *ap++ & 0377);
720 		bp += 3;
721 	}
722 	*--bp = '\0';
723 	return buf;
724 }
725 
726 # else /* DAEMON */
727 /* code for systems without sophisticated networking */
728 
729 /*
730 **  MYHOSTNAME -- stub version for case of no daemon code.
731 **
732 **	Can't convert to upper case here because might be a UUCP name.
733 **
734 **	Mark, you can change this to be anything you want......
735 */
736 
737 char **
738 myhostname(hostbuf, size)
739 	char hostbuf[];
740 	int size;
741 {
742 	register FILE *f;
743 
744 	hostbuf[0] = '\0';
745 	f = fopen("/usr/include/whoami", "r");
746 	if (f != NULL)
747 	{
748 		(void) fgets(hostbuf, size, f);
749 		fixcrlf(hostbuf, TRUE);
750 		(void) fclose(f);
751 	}
752 	return (NULL);
753 }
754 /*
755 **  GETREALHOSTNAME -- get the real host name asociated with a file descriptor
756 **
757 **	Parameters:
758 **		fd -- the descriptor
759 **
760 **	Returns:
761 **		The host name associated with this descriptor, if it can
762 **			be determined.
763 **		NULL otherwise.
764 **
765 **	Side Effects:
766 **		none
767 */
768 
769 char *
770 getrealhostname(fd)
771 	int fd;
772 {
773 	return NULL;
774 }
775 /*
776 **  MAPHOSTNAME -- turn a hostname into canonical form
777 **
778 **	Parameters:
779 **		map -- a pointer to the database map.
780 **		hbuf -- a buffer containing a hostname.
781 **		avp -- a pointer to a (cf file defined) argument vector.
782 **
783 **	Returns:
784 **		mapped host name
785 **		FALSE otherwise.
786 **
787 **	Side Effects:
788 **		Looks up the host specified in hbuf.  If it is not
789 **		the canonical name for that host, replace it with
790 **		the canonical name.  If the name is unknown, or it
791 **		is already the canonical name, leave it unchanged.
792 */
793 
794 /*ARGSUSED*/
795 char *
796 maphostname(map, hbuf, hbsize, avp)
797 	MAP *map;
798 	char *hbuf;
799 	int hbsize;
800 	char **avp;
801 {
802 	return NULL;
803 }
804 
805 #endif /* DAEMON */
806