This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / usr.sbin / sendmail / src / daemon.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1983 Eric P. Allman
78ed81a3 3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
15637ed4
RG
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include <errno.h>
78ed81a3 36#include <signal.h>
15637ed4
RG
37#include "sendmail.h"
38
39#ifndef lint
40#ifdef DAEMON
78ed81a3 41static char sccsid[] = "@(#)daemon.c 8.2 (Berkeley) 7/13/93 (with daemon mode)";
15637ed4 42#else
78ed81a3 43static char sccsid[] = "@(#)daemon.c 8.2 (Berkeley) 7/13/93 (without daemon mode)";
15637ed4
RG
44#endif
45#endif /* not lint */
46
15637ed4
RG
47#ifdef DAEMON
48
49# include <netdb.h>
15637ed4
RG
50# include <sys/wait.h>
51# include <sys/time.h>
78ed81a3 52
53#ifdef NAMED_BIND
54# include <arpa/nameser.h>
55# include <resolv.h>
56#endif
15637ed4
RG
57
58/*
59** DAEMON.C -- routines to use when running as a daemon.
60**
61** This entire file is highly dependent on the 4.2 BSD
62** interprocess communication primitives. No attempt has
63** been made to make this file portable to Version 7,
64** Version 6, MPX files, etc. If you should try such a
65** thing yourself, I recommend chucking the entire file
66** and starting from scratch. Basic semantics are:
67**
68** getrequests()
69** Opens a port and initiates a connection.
70** Returns in a child. Must set InChannel and
71** OutChannel appropriately.
72** clrdaemon()
73** Close any open files associated with getting
74** the connection; this is used when running the queue,
75** etc., to avoid having extra file descriptors during
76** the queue run and to avoid confusing the network
77** code (if it cares).
78ed81a3 78** makeconnection(host, port, outfile, infile, usesecureport)
15637ed4
RG
79** Make a connection to the named host on the given
80** port. Set *outfile and *infile to the files
81** appropriate for communication. Returns zero on
82** success, else an exit status describing the
83** error.
78ed81a3 84** host_map_lookup(map, hbuf, avp, pstat)
85** Convert the entry in hbuf into a canonical form.
15637ed4
RG
86*/
87\f/*
88** GETREQUESTS -- open mail IPC port and get requests.
89**
90** Parameters:
91** none.
92**
93** Returns:
94** none.
95**
96** Side Effects:
97** Waits until some interesting activity occurs. When
98** it does, a child is created to process it, and the
99** parent waits for completion. Return from this
100** routine is always in the child. The file pointers
101** "InChannel" and "OutChannel" should be set to point
102** to the communication channel.
103*/
104
78ed81a3 105int DaemonSocket = -1; /* fd describing socket */
106SOCKADDR DaemonAddr; /* socket for incoming */
107int ListenQueueSize = 10; /* size of listen queue */
15637ed4
RG
108
109getrequests()
110{
111 int t;
112 register struct servent *sp;
113 int on = 1;
78ed81a3 114 bool refusingconnections = TRUE;
115 FILE *pidf;
15637ed4
RG
116 extern void reapchild();
117
118 /*
119 ** Set up the address for the mailer.
120 */
121
78ed81a3 122 if (DaemonAddr.sin.sin_family == 0)
123 DaemonAddr.sin.sin_family = AF_INET;
124 if (DaemonAddr.sin.sin_addr.s_addr == 0)
125 DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY;
126 if (DaemonAddr.sin.sin_port == 0)
15637ed4 127 {
78ed81a3 128 sp = getservbyname("smtp", "tcp");
129 if (sp == NULL)
130 {
131 syserr("554 service \"smtp\" unknown");
132 goto severe;
133 }
134#ifdef _SCO_unix_
135 DaemonAddr.sin.sin_port = htons(sp->s_port);
136#else
137 DaemonAddr.sin.sin_port = sp->s_port;
138#endif
15637ed4 139 }
15637ed4
RG
140
141 /*
142 ** Try to actually open the connection.
143 */
144
145 if (tTd(15, 1))
78ed81a3 146 printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port);
15637ed4
RG
147
148 /* get a socket for the SMTP connection */
78ed81a3 149 DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0);
15637ed4
RG
150 if (DaemonSocket < 0)
151 {
152 /* probably another daemon already */
153 syserr("getrequests: can't create socket");
154 severe:
155# ifdef LOG
156 if (LogLevel > 0)
78ed81a3 157 syslog(LOG_ALERT, "problem creating SMTP socket");
158# endif /* LOG */
15637ed4
RG
159 finis();
160 }
161
162 /* turn on network debugging? */
78ed81a3 163 if (tTd(15, 101))
15637ed4
RG
164 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);
165
166 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on);
167 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on);
168
78ed81a3 169 switch (DaemonAddr.sa.sa_family)
15637ed4 170 {
78ed81a3 171# ifdef NETINET
172 case AF_INET:
173 t = sizeof DaemonAddr.sin;
174 break;
175# endif
176
177# ifdef NETISO
178 case AF_ISO:
179 t = sizeof DaemonAddr.siso;
180 break;
181# endif
182
183 default:
184 t = sizeof DaemonAddr;
185 break;
15637ed4 186 }
78ed81a3 187
188 if (bind(DaemonSocket, &DaemonAddr.sa, t) < 0)
15637ed4 189 {
78ed81a3 190 syserr("getrequests: cannot bind");
15637ed4
RG
191 (void) close(DaemonSocket);
192 goto severe;
193 }
194
195 (void) signal(SIGCHLD, reapchild);
196
78ed81a3 197 /* write the pid to the log file for posterity */
198 pidf = fopen(PidFile, "w");
199 if (pidf != NULL)
200 {
201 fprintf(pidf, "%d\n", getpid());
202 fclose(pidf);
203 }
204
205
15637ed4
RG
206 if (tTd(15, 1))
207 printf("getrequests: %d\n", DaemonSocket);
208
209 for (;;)
210 {
211 register int pid;
212 auto int lotherend;
78ed81a3 213 extern bool refuseconnections();
15637ed4
RG
214
215 /* see if we are rejecting connections */
78ed81a3 216 CurrentLA = getla();
217 if (refuseconnections())
15637ed4 218 {
78ed81a3 219 if (!refusingconnections)
220 {
221 /* don't queue so peer will fail quickly */
222 (void) listen(DaemonSocket, 0);
223 refusingconnections = TRUE;
224 }
225 setproctitle("rejecting connections: load average: %d",
226 CurrentLA);
15637ed4 227 sleep(5);
78ed81a3 228 continue;
229 }
230
231 if (refusingconnections)
232 {
233 /* start listening again */
234 if (listen(DaemonSocket, ListenQueueSize) < 0)
235 {
236 syserr("getrequests: cannot listen");
237 (void) close(DaemonSocket);
238 goto severe;
239 }
240 setproctitle("accepting connections");
241 refusingconnections = FALSE;
15637ed4
RG
242 }
243
244 /* wait for a connection */
15637ed4
RG
245 do
246 {
247 errno = 0;
248 lotherend = sizeof RealHostAddr;
249 t = accept(DaemonSocket,
250 (struct sockaddr *)&RealHostAddr, &lotherend);
251 } while (t < 0 && errno == EINTR);
252 if (t < 0)
253 {
254 syserr("getrequests: accept");
255 sleep(5);
256 continue;
257 }
258
259 /*
260 ** Create a subprocess to process the mail.
261 */
262
263 if (tTd(15, 2))
264 printf("getrequests: forking (fd = %d)\n", t);
265
266 pid = fork();
267 if (pid < 0)
268 {
269 syserr("daemon: cannot fork");
270 sleep(10);
271 (void) close(t);
272 continue;
273 }
274
275 if (pid == 0)
276 {
78ed81a3 277 extern char *hostnamebyanyaddr();
15637ed4
RG
278
279 /*
280 ** CHILD -- return to caller.
281 ** Collect verified idea of sending host.
282 ** Verify calling user id if possible here.
283 */
284
285 (void) signal(SIGCHLD, SIG_DFL);
78ed81a3 286 OpMode = MD_SMTP;
15637ed4
RG
287
288 /* determine host name */
78ed81a3 289 RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
15637ed4 290
78ed81a3 291#ifdef LOG
292 if (LogLevel > 10)
293 {
294 /* log connection information */
295 syslog(LOG_INFO, "connect from %s (%s)",
296 RealHostName, anynet_ntoa(&RealHostAddr));
15637ed4 297 }
78ed81a3 298#endif
15637ed4
RG
299
300 (void) close(DaemonSocket);
301 InChannel = fdopen(t, "r");
302 OutChannel = fdopen(dup(t), "w");
78ed81a3 303
304 /* should we check for illegal connection here? XXX */
305#ifdef XLA
306 if (!xla_host_ok(RealHostName))
307 {
308 message("421 Too many SMTP sessions for this host");
309 exit(0);
310 }
311#endif
312
15637ed4
RG
313 if (tTd(15, 2))
314 printf("getreq: returning\n");
15637ed4
RG
315 return;
316 }
317
318 /* close the port so that others will hang (for a while) */
319 (void) close(t);
320 }
321 /*NOTREACHED*/
322}
323\f/*
324** CLRDAEMON -- reset the daemon connection
325**
326** Parameters:
327** none.
328**
329** Returns:
330** none.
331**
332** Side Effects:
333** releases any resources used by the passive daemon.
334*/
335
336clrdaemon()
337{
338 if (DaemonSocket >= 0)
339 (void) close(DaemonSocket);
340 DaemonSocket = -1;
341}
342\f/*
78ed81a3 343** SETDAEMONOPTIONS -- set options for running the daemon
344**
345** Parameters:
346** p -- the options line.
347**
348** Returns:
349** none.
350*/
351
352setdaemonoptions(p)
353 register char *p;
354{
355 if (DaemonAddr.sa.sa_family == AF_UNSPEC)
356 DaemonAddr.sa.sa_family = AF_INET;
357
358 while (p != NULL)
359 {
360 register char *f;
361 register char *v;
362
363 while (isascii(*p) && isspace(*p))
364 p++;
365 if (*p == '\0')
366 break;
367 f = p;
368 p = strchr(p, ',');
369 if (p != NULL)
370 *p++ = '\0';
371 v = strchr(f, '=');
372 if (v == NULL)
373 continue;
374 while (isascii(*++v) && isspace(*v))
375 continue;
376
377 switch (*f)
378 {
379 case 'F': /* address family */
380 if (isascii(*v) && isdigit(*v))
381 DaemonAddr.sa.sa_family = atoi(v);
382#ifdef NETINET
383 else if (strcasecmp(v, "inet") == 0)
384 DaemonAddr.sa.sa_family = AF_INET;
385#endif
386#ifdef NETISO
387 else if (strcasecmp(v, "iso") == 0)
388 DaemonAddr.sa.sa_family = AF_ISO;
389#endif
390#ifdef NETNS
391 else if (strcasecmp(v, "ns") == 0)
392 DaemonAddr.sa.sa_family = AF_NS;
393#endif
394#ifdef NETX25
395 else if (strcasecmp(v, "x.25") == 0)
396 DaemonAddr.sa.sa_family = AF_CCITT;
397#endif
398 else
399 syserr("554 Unknown address family %s in Family=option", v);
400 break;
401
402 case 'A': /* address */
403 switch (DaemonAddr.sa.sa_family)
404 {
405#ifdef NETINET
406 case AF_INET:
407 if (isascii(*v) && isdigit(*v))
408 DaemonAddr.sin.sin_addr.s_addr = inet_network(v);
409 else
410 {
411 register struct netent *np;
412
413 np = getnetbyname(v);
414 if (np == NULL)
415 syserr("554 network \"%s\" unknown", v);
416 else
417 DaemonAddr.sin.sin_addr.s_addr = np->n_net;
418 }
419 break;
420#endif
421
422 default:
423 syserr("554 Address= option unsupported for family %d",
424 DaemonAddr.sa.sa_family);
425 break;
426 }
427 break;
428
429 case 'P': /* port */
430 switch (DaemonAddr.sa.sa_family)
431 {
432 short port;
433
434#ifdef NETINET
435 case AF_INET:
436 if (isascii(*v) && isdigit(*v))
437 DaemonAddr.sin.sin_port = atoi(v);
438 else
439 {
440 register struct servent *sp;
441
442 sp = getservbyname(v, "tcp");
443 if (sp == NULL)
444 syserr("554 service \"%s\" unknown", v);
445 else
446 {
447#ifdef _SCO_unix_
448 DaemonAddr.sin.sin_port = htons(sp->s_port);
449#else
450 DaemonAddr.sin.sin_port = sp->s_port;
451#endif
452 }
453 }
454 break;
455#endif
456
457#ifdef NETISO
458 case AF_ISO:
459 /* assume two byte transport selector */
460 if (isascii(*v) && isdigit(*v))
461 port = atoi(v);
462 else
463 {
464 register struct servent *sp;
465
466 sp = getservbyname(v, "tcp");
467 if (sp == NULL)
468 syserr("554 service \"%s\" unknown", v);
469 else
470 port = sp->s_port;
471 }
472 bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2);
473 break;
474#endif
475
476 default:
477 syserr("554 Port= option unsupported for family %d",
478 DaemonAddr.sa.sa_family);
479 break;
480 }
481 break;
482
483 case 'L': /* listen queue size */
484 ListenQueueSize = atoi(v);
485 break;
486 }
487 }
488}
489\f/*
15637ed4
RG
490** MAKECONNECTION -- make a connection to an SMTP socket on another machine.
491**
492** Parameters:
493** host -- the name of the host.
494** port -- the port number to connect to.
78ed81a3 495** mci -- a pointer to the mail connection information
496** structure to be filled in.
497** usesecureport -- if set, use a low numbered (reserved)
498** port to provide some rudimentary authentication.
15637ed4
RG
499**
500** Returns:
501** An exit code telling whether the connection could be
502** made and if not why not.
503**
504** Side Effects:
505** none.
506*/
507
78ed81a3 508SOCKADDR CurHostAddr; /* address of current host */
509
510int
511makeconnection(host, port, mci, usesecureport)
15637ed4
RG
512 char *host;
513 u_short port;
78ed81a3 514 register MCI *mci;
515 bool usesecureport;
15637ed4
RG
516{
517 register int i, s;
518 register struct hostent *hp = (struct hostent *)NULL;
78ed81a3 519 SOCKADDR addr;
15637ed4 520 int sav_errno;
78ed81a3 521 int addrlen;
15637ed4
RG
522#ifdef NAMED_BIND
523 extern int h_errno;
524#endif
525
526 /*
527 ** Set up the address for the mailer.
528 ** Accept "[a.b.c.d]" syntax for host name.
529 */
530
531#ifdef NAMED_BIND
532 h_errno = 0;
533#endif
534 errno = 0;
78ed81a3 535 bzero(&CurHostAddr, sizeof CurHostAddr);
536 CurHostName = host;
15637ed4
RG
537
538 if (host[0] == '[')
539 {
540 long hid;
78ed81a3 541 register char *p = strchr(host, ']');
15637ed4
RG
542
543 if (p != NULL)
544 {
545 *p = '\0';
78ed81a3 546#ifdef NETINET
15637ed4 547 hid = inet_addr(&host[1]);
78ed81a3 548 if (hid == -1)
549#endif
550 {
551 /* try it as a host name (avoid MX lookup) */
552 hp = gethostbyname(&host[1]);
553 *p = ']';
554 goto gothostent;
555 }
15637ed4
RG
556 *p = ']';
557 }
78ed81a3 558 if (p == NULL)
15637ed4 559 {
78ed81a3 560 usrerr("553 Invalid numeric domain spec \"%s\"", host);
15637ed4
RG
561 return (EX_NOHOST);
562 }
78ed81a3 563#ifdef NETINET
564 addr.sin.sin_family = AF_INET; /*XXX*/
565 addr.sin.sin_addr.s_addr = hid;
566#endif
15637ed4
RG
567 }
568 else
569 {
570 hp = gethostbyname(host);
78ed81a3 571gothostent:
15637ed4
RG
572 if (hp == NULL)
573 {
574#ifdef NAMED_BIND
575 if (errno == ETIMEDOUT || h_errno == TRY_AGAIN)
576 return (EX_TEMPFAIL);
577
578 /* if name server is specified, assume temp fail */
579 if (errno == ECONNREFUSED && UseNameServer)
580 return (EX_TEMPFAIL);
581#endif
15637ed4
RG
582 return (EX_NOHOST);
583 }
78ed81a3 584 addr.sa.sa_family = hp->h_addrtype;
585 switch (hp->h_addrtype)
586 {
587#ifdef NETINET
588 case AF_INET:
589 bcopy(hp->h_addr,
590 &addr.sin.sin_addr,
591 hp->h_length);
592 break;
593#endif
594
595 default:
596 bcopy(hp->h_addr,
597 addr.sa.sa_data,
598 hp->h_length);
599 break;
600 }
15637ed4
RG
601 i = 1;
602 }
603
604 /*
605 ** Determine the port number.
606 */
607
608 if (port != 0)
78ed81a3 609 port = htons(port);
15637ed4
RG
610 else
611 {
612 register struct servent *sp = getservbyname("smtp", "tcp");
613
614 if (sp == NULL)
615 {
78ed81a3 616 syserr("554 makeconnection: service \"smtp\" unknown");
617 return (EX_OSERR);
15637ed4 618 }
78ed81a3 619#ifdef _SCO_unix_
620 port = htons(sp->s_port);
621#else
622 port = sp->s_port;
623#endif
624 }
625
626 switch (addr.sa.sa_family)
627 {
628#ifdef NETINET
629 case AF_INET:
630 addr.sin.sin_port = port;
631 addrlen = sizeof (struct sockaddr_in);
632 break;
633#endif
634
635#ifdef NETISO
636 case AF_ISO:
637 /* assume two byte transport selector */
638 bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2);
639 addrlen = sizeof (struct sockaddr_iso);
640 break;
641#endif
642
643 default:
644 syserr("Can't connect to address family %d", addr.sa.sa_family);
645 return (EX_NOHOST);
15637ed4
RG
646 }
647
648 /*
649 ** Try to actually open the connection.
650 */
651
78ed81a3 652#ifdef XLA
653 /* if too many connections, don't bother trying */
654 if (!xla_noqueue_ok(host))
655 return EX_TEMPFAIL;
656#endif
15637ed4 657
78ed81a3 658 for (;;)
15637ed4 659 {
78ed81a3 660 if (tTd(16, 1))
661 printf("makeconnection (%s [%s])\n",
662 host, anynet_ntoa(&addr));
15637ed4 663
78ed81a3 664 /* save for logging */
665 CurHostAddr = addr;
15637ed4 666
78ed81a3 667 if (usesecureport)
668 {
669 int rport = IPPORT_RESERVED - 1;
670
671 s = rresvport(&rport);
672 }
673 else
674 {
675 s = socket(AF_INET, SOCK_STREAM, 0);
676 }
677 if (s < 0)
678 {
679 sav_errno = errno;
680 syserr("makeconnection: no socket");
681 goto failure;
682 }
683
684 if (tTd(16, 1))
685 printf("makeconnection: fd=%d\n", s);
686
687 /* turn on network debugging? */
688 if (tTd(16, 101))
689 {
690 int on = 1;
691 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG,
692 (char *)&on, sizeof on);
693 }
694 if (CurEnv->e_xfp != NULL)
695 (void) fflush(CurEnv->e_xfp); /* for debugging */
696 errno = 0; /* for debugging */
697 if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0)
698 break;
699
700 /* couldn't connect.... figure out why */
15637ed4
RG
701 sav_errno = errno;
702 (void) close(s);
703 if (hp && hp->h_addr_list[i])
704 {
78ed81a3 705 if (tTd(16, 1))
706 printf("Connect failed (%s); trying new address....\n",
707 errstring(sav_errno));
708 switch (addr.sa.sa_family)
709 {
710#ifdef NETINET
711 case AF_INET:
712 bcopy(hp->h_addr_list[i++],
713 &addr.sin.sin_addr,
714 hp->h_length);
715 break;
716#endif
717
718 default:
719 bcopy(hp->h_addr_list[i++],
720 addr.sa.sa_data,
721 hp->h_length);
722 break;
723 }
724 continue;
15637ed4
RG
725 }
726
727 /* failure, decide if temporary or not */
728 failure:
78ed81a3 729#ifdef XLA
730 xla_host_end(host);
731#endif
732 if (transienterror(sav_errno))
733 return EX_TEMPFAIL;
734 else
15637ed4 735 {
78ed81a3 736 message("%s", errstring(sav_errno));
737 return (EX_UNAVAILABLE);
15637ed4
RG
738 }
739 }
740
741 /* connection ok, put it into canonical form */
78ed81a3 742 mci->mci_out = fdopen(s, "w");
743 mci->mci_in = fdopen(dup(s), "r");
15637ed4
RG
744
745 return (EX_OK);
746}
747\f/*
748** MYHOSTNAME -- return the name of this host.
749**
750** Parameters:
751** hostbuf -- a place to return the name of this host.
752** size -- the size of hostbuf.
753**
754** Returns:
755** A list of aliases for this host.
756**
757** Side Effects:
78ed81a3 758** Sets the MyIpAddrs buffer to a list of my IP addresses.
15637ed4
RG
759*/
760
78ed81a3 761struct in_addr MyIpAddrs[MAXIPADDR + 1];
762
15637ed4
RG
763char **
764myhostname(hostbuf, size)
765 char hostbuf[];
766 int size;
767{
78ed81a3 768 register struct hostent *hp;
15637ed4 769 extern struct hostent *gethostbyname();
15637ed4
RG
770
771 if (gethostname(hostbuf, size) < 0)
772 {
773 (void) strcpy(hostbuf, "localhost");
774 }
775 hp = gethostbyname(hostbuf);
776 if (hp != NULL)
777 {
78ed81a3 778 (void) strncpy(hostbuf, hp->h_name, size - 1);
779 hostbuf[size - 1] = '\0';
780
781 if (hp->h_addrtype == AF_INET && hp->h_length == 4)
782 {
783 register int i;
784
785 for (i = 0; i < MAXIPADDR; i++)
786 {
787 if (hp->h_addr_list[i] == NULL)
788 break;
789 MyIpAddrs[i].s_addr = *(u_long *) hp->h_addr_list[i];
790 }
791 MyIpAddrs[i].s_addr = 0;
792 }
793
15637ed4
RG
794 return (hp->h_aliases);
795 }
796 else
797 return (NULL);
798}
78ed81a3 799\f/*
800** GETAUTHINFO -- get the real host name asociated with a file descriptor
801**
802** Uses RFC1413 protocol to try to get info from the other end.
803**
804** Parameters:
805** fd -- the descriptor
806**
807** Returns:
808** The user@host information associated with this descriptor.
809**
810** Side Effects:
811** Sets RealHostName to the name of the host at the other end.
812*/
15637ed4 813
78ed81a3 814#ifdef IDENTPROTO
815
816static jmp_buf CtxAuthTimeout;
817
818static
819authtimeout()
820{
821 longjmp(CtxAuthTimeout, 1);
822}
823
824#endif
825
826char *
827getauthinfo(fd)
828 int fd;
829{
830 SOCKADDR fa;
831 int falen;
832 register char *p;
833#ifdef IDENTPROTO
834 SOCKADDR la;
835 int lalen;
836 register struct servent *sp;
837 int s;
838 int i;
839 EVENT *ev;
840#endif
841 static char hbuf[MAXNAME * 2 + 2];
842 extern char *hostnamebyanyaddr();
843 extern char RealUserName[]; /* main.c */
844
845 falen = sizeof fa;
846 if (getpeername(fd, &fa.sa, &falen) < 0 || falen <= 0)
847 {
848 RealHostName = "localhost";
849 (void) sprintf(hbuf, "%s@localhost", RealUserName);
850 if (tTd(9, 1))
851 printf("getauthinfo: %s\n", hbuf);
852 return hbuf;
853 }
854
855 RealHostName = newstr(hostnamebyanyaddr(&fa));
856 RealHostAddr = fa;
857
858#ifdef IDENTPROTO
859 lalen = sizeof la;
860 if (fa.sa.sa_family != AF_INET ||
861 getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 ||
862 la.sa.sa_family != AF_INET)
863 {
864 /* no ident info */
865 goto noident;
866 }
867
868 /* create ident query */
869 (void) sprintf(hbuf, "%d,%d\r\n",
870 ntohs(fa.sin.sin_port), ntohs(la.sin.sin_port));
871
872 /* create local address */
873 bzero(&la, sizeof la);
874
875 /* create foreign address */
876 sp = getservbyname("auth", "tcp");
877 if (sp != NULL)
878 {
879#ifdef _SCO_unix_
880 fa.sin.sin_port = htons(sp->s_port);
881#else
882 fa.sin.sin_port = sp->s_port;
883#endif
884 }
885 else
886 fa.sin.sin_port = htons(113);
887
888 s = -1;
889 if (setjmp(CtxAuthTimeout) != 0)
890 {
891 if (s >= 0)
892 (void) close(s);
893 goto noident;
894 }
895
896 /* put a timeout around the whole thing */
897 ev = setevent((time_t) 30, authtimeout, 0);
898
899 /* connect to foreign IDENT server */
900 s = socket(AF_INET, SOCK_STREAM, 0);
901 if (s < 0)
902 {
903 clrevent(ev);
904 goto noident;
905 }
906 if (connect(s, &fa.sa, sizeof fa.sin) < 0)
907 {
908closeident:
909 (void) close(s);
910 clrevent(ev);
911 goto noident;
912 }
913
914 if (tTd(9, 10))
915 printf("getauthinfo: sent %s", hbuf);
916
917 /* send query */
918 if (write(s, hbuf, strlen(hbuf)) < 0)
919 goto closeident;
920
921 /* get result */
922 i = read(s, hbuf, sizeof hbuf);
923 (void) close(s);
924 clrevent(ev);
925 if (i <= 0)
926 goto noident;
927 if (hbuf[--i] == '\n' && hbuf[--i] == '\r')
928 i--;
929 hbuf[++i] = '\0';
930
931 if (tTd(9, 3))
932 printf("getauthinfo: got %s\n", hbuf);
933
934 /* parse result */
935 p = strchr(hbuf, ':');
936 if (p == NULL)
937 {
938 /* malformed response */
939 goto noident;
940 }
941 while (isascii(*++p) && isspace(*p))
942 continue;
943 if (strncasecmp(p, "userid", 6) != 0)
944 {
945 /* presumably an error string */
946 goto noident;
947 }
948 p += 6;
949 while (isascii(*p) && isspace(*p))
950 p++;
951 if (*p++ != ':')
952 {
953 /* either useridxx or malformed response */
954 goto noident;
955 }
956
957 /* p now points to the OSTYPE field */
958 p = strchr(p, ':');
959 if (p == NULL)
960 {
961 /* malformed response */
962 goto noident;
963 }
964
965 /* 1413 says don't do this -- but it's broken otherwise */
966 while (isascii(*++p) && isspace(*p))
967 continue;
968
969 /* p now points to the authenticated name */
970 (void) sprintf(hbuf, "%s@%s", p, RealHostName);
971 goto finish;
972
973#endif /* IDENTPROTO */
974
975noident:
976 (void) strcpy(hbuf, RealHostName);
977
978finish:
979 if (RealHostName[0] != '[')
980 {
981 p = &hbuf[strlen(hbuf)];
982 (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr));
983 }
984 if (tTd(9, 1))
985 printf("getauthinfo: %s\n", hbuf);
986 return hbuf;
987}
988\f/*
989** HOST_MAP_LOOKUP -- turn a hostname into canonical form
990**
991** Parameters:
992** map -- a pointer to this map (unused).
993** name -- the (presumably unqualified) hostname.
994** av -- unused -- for compatibility with other mapping
995** functions.
996** statp -- an exit status (out parameter) -- set to
997** EX_TEMPFAIL if the name server is unavailable.
998**
999** Returns:
1000** The mapping, if found.
1001** NULL if no mapping found.
1002**
1003** Side Effects:
1004** Looks up the host specified in hbuf. If it is not
1005** the canonical name for that host, return the canonical
1006** name.
1007*/
1008
1009char *
1010host_map_lookup(map, name, av, statp)
1011 MAP *map;
1012 char *name;
1013 char **av;
1014 int *statp;
15637ed4
RG
1015{
1016 register struct hostent *hp;
1017 u_long in_addr;
78ed81a3 1018 char *cp;
1019 int i;
1020 register STAB *s;
1021 char hbuf[MAXNAME];
1022 extern struct hostent *gethostbyaddr();
1023 extern int h_errno;
1024
1025 /*
1026 ** See if we have already looked up this name. If so, just
1027 ** return it.
1028 */
1029
1030 s = stab(name, ST_NAMECANON, ST_ENTER);
1031 if (bitset(NCF_VALID, s->s_namecanon.nc_flags))
1032 {
1033 if (tTd(9, 1))
1034 printf("host_map_lookup(%s) => CACHE %s\n",
1035 name, s->s_namecanon.nc_cname);
1036 errno = s->s_namecanon.nc_errno;
1037 h_errno = s->s_namecanon.nc_herrno;
1038 *statp = s->s_namecanon.nc_stat;
1039 return s->s_namecanon.nc_cname;
1040 }
15637ed4
RG
1041
1042 /*
78ed81a3 1043 ** If first character is a bracket, then it is an address
1044 ** lookup. Address is copied into a temporary buffer to
1045 ** strip the brackets and to preserve name if address is
1046 ** unknown.
1047 */
1048
1049 if (*name != '[')
1050 {
1051 extern bool getcanonname();
1052
1053 if (tTd(9, 1))
1054 printf("host_map_lookup(%s) => ", name);
1055 s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */
1056 (void) strcpy(hbuf, name);
1057 if (getcanonname(hbuf, sizeof hbuf - 1))
1058 {
1059 if (tTd(9, 1))
1060 printf("%s\n", hbuf);
1061 cp = map_rewrite(map, hbuf, strlen(hbuf), av);
1062 s->s_namecanon.nc_cname = newstr(cp);
1063 return cp;
1064 }
1065 else
1066 {
1067 register struct hostent *hp;
1068
1069 if (tTd(9, 1))
1070 printf("FAIL (%d)\n", h_errno);
1071 s->s_namecanon.nc_errno = errno;
1072 s->s_namecanon.nc_herrno = h_errno;
1073 switch (h_errno)
1074 {
1075 case TRY_AGAIN:
1076 if (UseNameServer)
1077 {
1078 char *msg = "Recipient domain nameserver timed out";
1079
1080 message(msg);
1081 if (CurEnv->e_message == NULL)
1082 CurEnv->e_message = newstr(msg);
1083 }
1084 *statp = EX_TEMPFAIL;
1085 break;
1086
1087 case HOST_NOT_FOUND:
1088 *statp = EX_NOHOST;
1089 break;
1090
1091 case NO_RECOVERY:
1092 *statp = EX_SOFTWARE;
1093 break;
1094
1095 default:
1096 *statp = EX_UNAVAILABLE;
1097 break;
1098 }
1099 s->s_namecanon.nc_stat = *statp;
1100 if (*statp != EX_TEMPFAIL || UseNameServer)
1101 return NULL;
1102
1103 /*
1104 ** Try to look it up in /etc/hosts
1105 */
1106
1107 hp = gethostbyname(name);
1108 if (hp == NULL)
1109 {
1110 /* no dice there either */
1111 s->s_namecanon.nc_stat = *statp = EX_NOHOST;
1112 return NULL;
1113 }
1114
1115 s->s_namecanon.nc_stat = *statp = EX_OK;
1116 cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av);
1117 s->s_namecanon.nc_cname = newstr(cp);
1118 return cp;
1119 }
1120 }
1121 if ((cp = strchr(name, ']')) == NULL)
1122 return (NULL);
15637ed4 1123 *cp = '\0';
78ed81a3 1124 in_addr = inet_addr(&name[1]);
1125
1126 /* check to see if this is one of our addresses */
1127 for (i = 0; MyIpAddrs[i].s_addr != 0; i++)
1128 {
1129 if (MyIpAddrs[i].s_addr == in_addr)
1130 {
1131 return map_rewrite(map, MyHostName, strlen(MyHostName), av);
1132 }
1133 }
1134
1135 /* nope -- ask the name server */
15637ed4 1136 hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET);
78ed81a3 1137 s->s_namecanon.nc_errno = errno;
1138 s->s_namecanon.nc_herrno = h_errno;
1139 s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */
15637ed4 1140 if (hp == NULL)
78ed81a3 1141 {
1142 s->s_namecanon.nc_stat = *statp = EX_NOHOST;
1143 return (NULL);
1144 }
1145
1146 /* found a match -- copy out */
1147 cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av);
1148 s->s_namecanon.nc_stat = *statp = EX_OK;
1149 s->s_namecanon.nc_cname = newstr(cp);
1150 return cp;
1151}
1152\f/*
1153** ANYNET_NTOA -- convert a network address to printable form.
1154**
1155** Parameters:
1156** sap -- a pointer to a sockaddr structure.
1157**
1158** Returns:
1159** A printable version of that sockaddr.
1160*/
1161
1162char *
1163anynet_ntoa(sap)
1164 register SOCKADDR *sap;
1165{
1166 register char *bp;
1167 register char *ap;
1168 int l;
1169 static char buf[80];
1170
1171 /* check for null/zero family */
1172 if (sap == NULL)
1173 return "NULLADDR";
1174 if (sap->sa.sa_family == 0)
1175 return "0";
1176
1177#ifdef NETINET
1178 if (sap->sa.sa_family == AF_INET)
1179 {
1180 extern char *inet_ntoa();
1181
1182 return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr);
1183 }
1184#endif
1185
1186 /* unknown family -- just dump bytes */
1187 (void) sprintf(buf, "Family %d: ", sap->sa.sa_family);
1188 bp = &buf[strlen(buf)];
1189 ap = sap->sa.sa_data;
1190 for (l = sizeof sap->sa.sa_data; --l >= 0; )
1191 {
1192 (void) sprintf(bp, "%02x:", *ap++ & 0377);
1193 bp += 3;
1194 }
1195 *--bp = '\0';
1196 return buf;
1197}
1198\f/*
1199** HOSTNAMEBYANYADDR -- return name of host based on address
1200**
1201** Parameters:
1202** sap -- SOCKADDR pointer
1203**
1204** Returns:
1205** text representation of host name.
1206**
1207** Side Effects:
1208** none.
1209*/
1210
1211char *
1212hostnamebyanyaddr(sap)
1213 register SOCKADDR *sap;
1214{
1215 register struct hostent *hp;
1216
1217#ifdef NAMED_BIND
1218 int saveretry;
1219
1220 /* shorten name server timeout to avoid higher level timeouts */
1221 saveretry = _res.retry;
1222 _res.retry = 3;
1223#endif /* NAMED_BIND */
1224
1225 switch (sap->sa.sa_family)
1226 {
1227#ifdef NETINET
1228 case AF_INET:
1229 hp = gethostbyaddr((char *) &sap->sin.sin_addr,
1230 sizeof sap->sin.sin_addr,
1231 AF_INET);
1232 break;
1233#endif
1234
1235#ifdef NETISO
1236 case AF_ISO:
1237 hp = gethostbyaddr((char *) &sap->siso.siso_addr,
1238 sizeof sap->siso.siso_addr,
1239 AF_ISO);
1240 break;
1241#endif
1242
1243 default:
1244 hp = gethostbyaddr(sap->sa.sa_data,
1245 sizeof sap->sa.sa_data,
1246 sap->sa.sa_family);
1247 break;
1248 }
1249
1250#ifdef NAMED_BIND
1251 _res.retry = saveretry;
1252#endif /* NAMED_BIND */
1253
1254 if (hp != NULL)
1255 return hp->h_name;
1256 else
1257 {
1258 /* produce a dotted quad */
1259 static char buf[512];
1260
1261 (void) sprintf(buf, "[%s]", anynet_ntoa(sap));
1262 return buf;
1263 }
15637ed4
RG
1264}
1265
78ed81a3 1266# else /* DAEMON */
15637ed4
RG
1267/* code for systems without sophisticated networking */
1268
1269/*
1270** MYHOSTNAME -- stub version for case of no daemon code.
1271**
1272** Can't convert to upper case here because might be a UUCP name.
1273**
1274** Mark, you can change this to be anything you want......
1275*/
1276
1277char **
1278myhostname(hostbuf, size)
1279 char hostbuf[];
1280 int size;
1281{
1282 register FILE *f;
1283
1284 hostbuf[0] = '\0';
1285 f = fopen("/usr/include/whoami", "r");
1286 if (f != NULL)
1287 {
1288 (void) fgets(hostbuf, size, f);
1289 fixcrlf(hostbuf, TRUE);
1290 (void) fclose(f);
1291 }
1292 return (NULL);
1293}
1294\f/*
78ed81a3 1295** GETAUTHINFO -- get the real host name asociated with a file descriptor
1296**
1297** Parameters:
1298** fd -- the descriptor
1299**
1300** Returns:
1301** The host name associated with this descriptor, if it can
1302** be determined.
1303** NULL otherwise.
1304**
1305** Side Effects:
1306** none
1307*/
1308
1309char *
1310getauthinfo(fd)
1311 int fd;
1312{
1313 return NULL;
1314}
1315\f/*
15637ed4
RG
1316** MAPHOSTNAME -- turn a hostname into canonical form
1317**
1318** Parameters:
78ed81a3 1319** map -- a pointer to the database map.
1320** name -- a buffer containing a hostname.
1321** avp -- a pointer to a (cf file defined) argument vector.
1322** statp -- an exit status (out parameter).
15637ed4
RG
1323**
1324** Returns:
78ed81a3 1325** mapped host name
1326** FALSE otherwise.
15637ed4
RG
1327**
1328** Side Effects:
78ed81a3 1329** Looks up the host specified in name. If it is not
15637ed4
RG
1330** the canonical name for that host, replace it with
1331** the canonical name. If the name is unknown, or it
1332** is already the canonical name, leave it unchanged.
1333*/
1334
1335/*ARGSUSED*/
78ed81a3 1336char *
1337host_map_lookup(map, name, avp, statp)
1338 MAP *map;
1339 char *name;
1340 char **avp;
1341 char *statp;
15637ed4 1342{
78ed81a3 1343 register struct hostent *hp;
1344
1345 hp = gethostbyname(name);
1346 if (hp != NULL)
1347 return hp->h_name;
1348 *statp = EX_NOHOST;
1349 return NULL;
15637ed4
RG
1350}
1351
78ed81a3 1352#endif /* DAEMON */