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