use newstr for e_message consistently
[unix-history] / usr / src / usr.sbin / sendmail / src / daemon.c
CommitLineData
d185cb11 1/*
dc45ba8c 2 * Copyright (c) 1983 Eric P. Allman
710322bb
KB
3 * Copyright (c) 1988 Regents of the University of California.
4 * All rights reserved.
5 *
417f7a11 6 * %sccs.include.redist.c%
710322bb 7 */
d185cb11 8
d0432129 9#include <errno.h>
49c069a9 10#include <signal.h>
97543758 11#include "sendmail.h"
6b6d57eb 12# include <sys/mx.h>
ef34cbda 13
710322bb
KB
14#ifndef lint
15#ifdef DAEMON
f10d3e38 16static char sccsid[] = "@(#)daemon.c 6.48 (Berkeley) %G% (with daemon mode)";
710322bb 17#else
f10d3e38 18static char sccsid[] = "@(#)daemon.c 6.48 (Berkeley) %G% (without daemon mode)";
710322bb
KB
19#endif
20#endif /* not lint */
21
22#ifdef DAEMON
17a67c62 23
17a67c62
EA
24# include <netdb.h>
25# include <sys/wait.h>
26# include <sys/time.h>
17a67c62 27
ab6ca5e5
EA
28#ifdef NAMED_BIND
29# include <arpa/nameser.h>
30# include <resolv.h>
31#endif
32
ef34cbda
EA
33/*
34** DAEMON.C -- routines to use when running as a daemon.
2a16bae3
EA
35**
36** This entire file is highly dependent on the 4.2 BSD
37** interprocess communication primitives. No attempt has
38** been made to make this file portable to Version 7,
39** Version 6, MPX files, etc. If you should try such a
40** thing yourself, I recommend chucking the entire file
41** and starting from scratch. Basic semantics are:
42**
43** getrequests()
44** Opens a port and initiates a connection.
45** Returns in a child. Must set InChannel and
46** OutChannel appropriately.
eb8af3ce
EA
47** clrdaemon()
48** Close any open files associated with getting
49** the connection; this is used when running the queue,
50** etc., to avoid having extra file descriptors during
51** the queue run and to avoid confusing the network
52** code (if it cares).
8657d05f 53** makeconnection(host, port, outfile, infile, usesecureport)
2a16bae3
EA
54** Make a connection to the named host on the given
55** port. Set *outfile and *infile to the files
56** appropriate for communication. Returns zero on
57** success, else an exit status describing the
58** error.
5a4c03c6
EA
59** maphostname(map, hbuf, hbufsiz, avp)
60** Convert the entry in hbuf into a canonical form.
ef34cbda 61*/
6b6d57eb 62
3341995c
EA
63extern char *anynet_ntoa();
64
6b6d57eb 65static FILE *MailPort; /* port that mail comes in on */
ef34cbda
EA
66\f/*
67** GETREQUESTS -- open mail IPC port and get requests.
68**
69** Parameters:
70** none.
71**
72** Returns:
73** none.
74**
75** Side Effects:
76** Waits until some interesting activity occurs. When
77** it does, a child is created to process it, and the
78** parent waits for completion. Return from this
40d27fed
EA
79** routine is always in the child. The file pointers
80** "InChannel" and "OutChannel" should be set to point
81** to the communication channel.
ef34cbda
EA
82*/
83
8829f52e
EA
84int DaemonSocket = -1; /* fd describing socket */
85SOCKADDR DaemonAddr; /* socket for incoming */
278c561a 86int ListenQueueSize = 10; /* size of listen queue */
14a39063 87
7f108496 88getrequests()
14a39063 89{
7e3417e6 90 int t;
7f108496 91 register struct servent *sp;
4ff794a3 92 int on = 1;
a90a7c55 93 bool refusingconnections = TRUE;
654398d7 94 FILE *pidf;
0df908a9 95 extern void reapchild();
14a39063
EA
96
97 /*
98 ** Set up the address for the mailer.
99 */
100
8829f52e
EA
101 if (DaemonAddr.sin.sin_family == 0)
102 DaemonAddr.sin.sin_family = AF_INET;
103 if (DaemonAddr.sin.sin_addr.s_addr == 0)
104 DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY;
105 if (DaemonAddr.sin.sin_port == 0)
7f108496 106 {
8829f52e
EA
107 sp = getservbyname("smtp", "tcp");
108 if (sp == NULL)
109 {
9964213c 110 syserr("554 service \"smtp\" unknown");
8829f52e
EA
111 goto severe;
112 }
113 DaemonAddr.sin.sin_port = sp->s_port;
7f108496 114 }
14a39063
EA
115
116 /*
117 ** Try to actually open the connection.
118 */
119
9678c96d 120 if (tTd(15, 1))
8829f52e 121 printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port);
14a39063 122
7f108496 123 /* get a socket for the SMTP connection */
4a50272d 124 DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0);
eb8af3ce 125 if (DaemonSocket < 0)
4b5cf74c 126 {
7f108496
EA
127 /* probably another daemon already */
128 syserr("getrequests: can't create socket");
129 severe:
130# ifdef LOG
131 if (LogLevel > 0)
f3d8f6d6 132# endif /* LOG */
7f108496
EA
133 finis();
134 }
78c9dc29 135
78c9dc29 136 /* turn on network debugging? */
d0a69620 137 if (tTd(15, 101))
bb812c0b 138 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);
78c9dc29 139
4ff794a3
EA
140 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on);
141 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on);
142
4a50272d
EA
143 switch (DaemonAddr.sa.sa_family)
144 {
145# ifdef NETINET
146 case AF_INET:
147 t = sizeof DaemonAddr.sin;
148 break;
149# endif
150
151# ifdef NETISO
152 case AF_ISO:
153 t = sizeof DaemonAddr.siso;
154 break;
155# endif
156
157 default:
158 t = sizeof DaemonAddr;
159 break;
160 }
161
162 if (bind(DaemonSocket, &DaemonAddr.sa, t) < 0)
7f108496
EA
163 {
164 syserr("getrequests: cannot bind");
eb8af3ce 165 (void) close(DaemonSocket);
7f108496
EA
166 goto severe;
167 }
14a39063 168
8ff78b51 169 (void) signal(SIGCHLD, reapchild);
199d34eb 170
654398d7
EA
171 /* write the pid to the log file for posterity */
172 pidf = fopen(PidFile, "w");
173 if (pidf != NULL)
174 {
175 fprintf(pidf, "%d\n", getpid());
176 fclose(pidf);
177 }
178
179
7f108496 180 if (tTd(15, 1))
eb8af3ce 181 printf("getrequests: %d\n", DaemonSocket);
2a16bae3 182
7f108496
EA
183 struct wh wbuf;
184
185 wbuf.index = index;
186 wbuf.count = 0;
187 wbuf.ccount = cnt;
188 wbuf.data = buf;
189 write(MailPort, &wbuf, sizeof wbuf);
14a39063 190}
1ab402f2
EA
191\f/*
192** MAKECONNECTION -- make a connection to an SMTP socket on another machine.
193**
194** Parameters:
195** host -- the name of the host.
e2d7c32a 196** port -- the port number to connect to.
2ae0e0ed
EA
197** mci -- a pointer to the mail connection information
198** structure to be filled in.
8657d05f
EA
199** usesecureport -- if set, use a low numbered (reserved)
200** port to provide some rudimentary authentication.
1ab402f2
EA
201**
202** Returns:
203** An exit code telling whether the connection could be
204** made and if not why not.
205**
206** Side Effects:
207** none.
208*/
209
3341995c 210SOCKADDR CurHostAddr; /* address of current host */
9b95d94a 211
f2e44ded 212int
2ae0e0ed 213makeconnection(host, port, mci, usesecureport)
1ab402f2 214 char *host;
f7eb07a3 215 u_short port;
f2e44ded 216 register MCI *mci;
8657d05f 217 bool usesecureport;
1ab402f2 218{
9e881165
JB
219 register int i, s;
220 register struct hostent *hp = (struct hostent *)NULL;
3341995c 221 SOCKADDR addr;
fa163d3c 222 int sav_errno;
3341995c 223 int addrlen;
35af2f06
EA
224#ifdef NAMED_BIND
225 extern int h_errno;
226#endif
1ab402f2
EA
227
228 /*
229 ** Set up the address for the mailer.
b3e29341 230 ** Accept "[a.b.c.d]" syntax for host name.
1ab402f2
EA
231 */
232
35af2f06 233#ifdef NAMED_BIND
459e21be 234 h_errno = 0;
35af2f06 235#endif
459e21be 236 errno = 0;
f66cc88e 237 bzero(&CurHostAddr, sizeof CurHostAddr);
f53bb556 238 CurHostName = host;
459e21be 239
b3e29341
EA
240 if (host[0] == '[')
241 {
e56baaff 242 long hid;
f3d8f6d6 243 register char *p = strchr(host, ']');
b3e29341 244
e56baaff 245 if (p != NULL)
b3e29341 246 {
e56baaff 247 *p = '\0';
69d3adf7 248#ifdef NETINET
e56baaff 249 hid = inet_addr(&host[1]);
b120ff69 250 if (hid == -1)
69d3adf7 251#endif
b120ff69
EA
252 {
253 /* try it as a host name (avoid MX lookup) */
254 hp = gethostbyname(&host[1]);
255 *p = ']';
256 goto gothostent;
257 }
e56baaff 258 *p = ']';
b3e29341 259 }
b120ff69 260 if (p == NULL)
b3e29341 261 {
b6edea3d 262 usrerr("553 Invalid numeric domain spec \"%s\"", host);
b3e29341
EA
263 return (EX_NOHOST);
264 }
69d3adf7
EA
265#ifdef NETINET
266 addr.sin.sin_family = AF_INET; /*XXX*/
3356c77c 267 addr.sin.sin_addr.s_addr = hid;
69d3adf7 268#endif
b3e29341 269 }
7f108496
EA
270 else
271 {
9e881165 272 hp = gethostbyname(host);
b120ff69 273gothostent:
e56baaff 274 if (hp == NULL)
459e21be 275 {
35af2f06 276#ifdef NAMED_BIND
459e21be 277 if (errno == ETIMEDOUT || h_errno == TRY_AGAIN)
459e21be 278 return (EX_TEMPFAIL);
8da74c93 279
35af2f06
EA
280 /* if name server is specified, assume temp fail */
281 if (errno == ECONNREFUSED && UseNameServer)
282 return (EX_TEMPFAIL);
283#endif
7f108496 284 return (EX_NOHOST);
459e21be 285 }
3356c77c
EA
286 addr.sa.sa_family = hp->h_addrtype;
287 switch (hp->h_addrtype)
288 {
289#ifdef NETINET
290 case AF_INET:
3341995c 291 bcopy(hp->h_addr,
3356c77c 292 &addr.sin.sin_addr,
3341995c 293 hp->h_length);
3356c77c
EA
294 break;
295#endif
296
297 default:
3341995c 298 bcopy(hp->h_addr,
3356c77c 299 addr.sa.sa_data,
3341995c 300 hp->h_length);
3356c77c
EA
301 break;
302 }
9e881165 303 i = 1;
7f108496
EA
304 }
305
306 /*
307 ** Determine the port number.
308 */
309
372c9e7f 310 if (port != 0)
3341995c 311 port = htons(port);
372c9e7f 312 else
7f108496
EA
313 {
314 register struct servent *sp = getservbyname("smtp", "tcp");
315
316 if (sp == NULL)
317 {
9964213c 318 syserr("554 makeconnection: service \"smtp\" unknown");
aa102c71 319 return (EX_OSERR);
7f108496 320 }
3341995c
EA
321 port = sp->s_port;
322 }
323
3356c77c 324 switch (addr.sa.sa_family)
3341995c 325 {
69d3adf7 326#ifdef NETINET
3341995c 327 case AF_INET:
3356c77c 328 addr.sin.sin_port = port;
3341995c
EA
329 addrlen = sizeof (struct sockaddr_in);
330 break;
69d3adf7 331#endif
3341995c
EA
332
333#ifdef NETISO
334 case AF_ISO:
335 /* assume two byte transport selector */
336 bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2);
337 addrlen = sizeof (struct sockaddr_iso);
338 break;
339#endif
340
341 default:
3356c77c 342 syserr("Can't connect to address family %d", addr.sa.sa_family);
3341995c 343 return (EX_NOHOST);
7f108496 344 }
1ab402f2
EA
345
346 /*
347 ** Try to actually open the connection.
348 */
349
b4f81c5d
EA
350#ifdef XLA
351 /* if too many connections, don't bother trying */
352 if (!xla_noqueue_ok(host))
353 return EX_TEMPFAIL;
354#endif
355
6feb509e 356 for (;;)
8657d05f 357 {
6feb509e 358 if (tTd(16, 1))
3341995c
EA
359 printf("makeconnection (%s [%s])\n",
360 host, anynet_ntoa(&addr));
8657d05f 361
83c07d72
EA
362 /* save for logging */
363 CurHostAddr = addr;
364
6feb509e
EA
365 if (usesecureport)
366 {
367 int rport = IPPORT_RESERVED - 1;
368
369 s = rresvport(&rport);
370 }
371 else
372 {
373 s = socket(AF_INET, SOCK_STREAM, 0);
374 }
375 if (s < 0)
376 {
377 sav_errno = errno;
378 syserr("makeconnection: no socket");
379 goto failure;
380 }
1ab402f2 381
6feb509e
EA
382 if (tTd(16, 1))
383 printf("makeconnection: fd=%d\n", s);
78c9dc29 384
6feb509e
EA
385 /* turn on network debugging? */
386 if (tTd(16, 101))
387 {
388 int on = 1;
389 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG,
390 (char *)&on, sizeof on);
391 }
392 if (CurEnv->e_xfp != NULL)
393 (void) fflush(CurEnv->e_xfp); /* for debugging */
394 errno = 0; /* for debugging */
3341995c 395 if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0)
6feb509e
EA
396 break;
397
398 /* couldn't connect.... figure out why */
fa163d3c
JB
399 sav_errno = errno;
400 (void) close(s);
9e881165
JB
401 if (hp && hp->h_addr_list[i])
402 {
3341995c
EA
403 extern char *errstring();
404
6feb509e 405 if (tTd(16, 1))
3341995c
EA
406 printf("Connect failed (%s); trying new address....\n",
407 errstring(sav_errno));
3356c77c
EA
408 switch (addr.sa.sa_family)
409 {
410#ifdef NETINET
411 case AF_INET:
3341995c 412 bcopy(hp->h_addr_list[i++],
3356c77c 413 &addr.sin.sin_addr,
3341995c 414 hp->h_length);
3356c77c
EA
415 break;
416#endif
417
418 default:
3341995c 419 bcopy(hp->h_addr_list[i++],
3356c77c 420 addr.sa.sa_data,
8657d05f 421 hp->h_length);
3356c77c
EA
422 break;
423 }
6feb509e 424 continue;
9e881165
JB
425 }
426
1ab402f2
EA
427 /* failure, decide if temporary or not */
428 failure:
46500bf5
EA
429#ifdef XLA
430 xla_host_end(host);
431#endif
1eaa5615
EA
432 if (transienterror(sav_errno))
433 return EX_TEMPFAIL;
1eaa5615
EA
434 else
435 {
436 extern char *errstring();
e56baaff 437
1eaa5615
EA
438 message("%s", errstring(sav_errno));
439 return (EX_UNAVAILABLE);
1ab402f2
EA
440 }
441 }
442
443 /* connection ok, put it into canonical form */
06771186
EA
444 mci->mci_out = fdopen(s, "w");
445 mci->mci_in = fdopen(dup(s), "r");
1ab402f2 446
1aaa7dec 447 return (EX_OK);
1ab402f2 448}
2ec2faaa
EA
449\f/*
450** MYHOSTNAME -- return the name of this host.
451**
452** Parameters:
453** hostbuf -- a place to return the name of this host.
05894fc6 454** size -- the size of hostbuf.
2ec2faaa
EA
455**
456** Returns:
457** A list of aliases for this host.
458**
459** Side Effects:
740d17b3 460** Sets the MyIpAddrs buffer to a list of my IP addresses.
2ec2faaa
EA
461*/
462
740d17b3
EA
463struct in_addr MyIpAddrs[MAXIPADDR + 1];
464
2ec2faaa 465char **
05894fc6 466myhostname(hostbuf, size)
2ec2faaa 467 char hostbuf[];
05894fc6 468 int size;
2ec2faaa 469{
740d17b3 470 register struct hostent *hp;
2ec2faaa 471 extern struct hostent *gethostbyname();
2ec2faaa 472
17a67c62
EA
473 if (gethostname(hostbuf, size) < 0)
474 {
475 (void) strcpy(hostbuf, "localhost");
476 }
e56baaff
EA
477 hp = gethostbyname(hostbuf);
478 if (hp != NULL)
b9b481e2 479 {
740d17b3
EA
480 (void) strncpy(hostbuf, hp->h_name, size - 1);
481 hostbuf[size - 1] = '\0';
482
483 if (hp->h_addrtype == AF_INET && hp->h_length == 4)
484 {
485 register int i;
486
487 for (i = 0; i < MAXIPADDR; i++)
488 {
489 if (hp->h_addr_list[i] == NULL)
490 break;
491 MyIpAddrs[i].s_addr = *(u_long *) hp->h_addr_list[i];
492 }
493 MyIpAddrs[i].s_addr = 0;
494 }
495
e56baaff 496 return (hp->h_aliases);
b9b481e2 497 }
2ec2faaa
EA
498 else
499 return (NULL);
500}
bbfde42f 501\f/*
3f03d7a7
EA
502** GETAUTHINFO -- get the real host name asociated with a file descriptor
503**
504** Uses RFC1413 protocol to try to get info from the other end.
5973222c
EA
505**
506** Parameters:
507** fd -- the descriptor
508**
509** Returns:
3f03d7a7 510** The user@host information associated with this descriptor.
5973222c
EA
511**
512** Side Effects:
3f03d7a7 513** Sets RealHostName to the name of the host at the other end.
5973222c
EA
514*/
515
3f03d7a7
EA
516#ifdef IDENTPROTO
517
518static jmp_buf CtxAuthTimeout;
519
520static
521authtimeout()
522{
523 longjmp(CtxAuthTimeout, 1);
524}
525
526#endif
527
5973222c 528char *
3f03d7a7 529getauthinfo(fd)
5973222c
EA
530 int fd;
531{
3f03d7a7
EA
532 SOCKADDR fa;
533 int falen;
72bc63d1 534 register char *p;
3f03d7a7
EA
535#ifdef IDENTPROTO
536 SOCKADDR la;
537 int lalen;
538 register struct servent *sp;
539 int s;
540 int i;
3f03d7a7
EA
541 EVENT *ev;
542#endif
543 static char hbuf[MAXNAME * 2 + 2];
544 extern char *hostnamebyanyaddr();
545 extern char RealUserName[]; /* main.c */
546
547 falen = sizeof fa;
548 if (getpeername(fd, &fa.sa, &falen) < 0 || falen <= 0)
549 {
550 RealHostName = "localhost";
551 (void) sprintf(hbuf, "%s@localhost", RealUserName);
a9bac7a9 552 if (tTd(9, 1))
3f03d7a7
EA
553 printf("getauthinfo: %s\n", hbuf);
554 return hbuf;
555 }
556
557 RealHostName = newstr(hostnamebyanyaddr(&fa));
558 RealHostAddr = fa;
559
560#ifdef IDENTPROTO
561 lalen = sizeof la;
562 if (fa.sa.sa_family != AF_INET ||
563 getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 ||
564 la.sa.sa_family != AF_INET)
565 {
566 /* no ident info */
567 goto noident;
568 }
569
570 /* create ident query */
571 (void) sprintf(hbuf, "%d,%d\r\n", fa.sin.sin_port, la.sin.sin_port);
572
573 /* create local address */
574 bzero(&la, sizeof la);
575
576 /* create foreign address */
577 sp = getservbyname("auth", "tcp");
578 if (sp != NULL)
579 fa.sin.sin_port = sp->s_port;
5973222c 580 else
696f60e3 581 fa.sin.sin_port = htons(113);
3f03d7a7
EA
582
583 s = -1;
584 if (setjmp(CtxAuthTimeout) != 0)
585 {
586 if (s >= 0)
587 (void) close(s);
588 goto noident;
589 }
590
591 /* put a timeout around the whole thing */
592 ev = setevent((time_t) 30, authtimeout, 0);
593
594 /* connect to foreign IDENT server */
595 s = socket(AF_INET, SOCK_STREAM, 0);
596 if (s < 0)
597 {
598 clrevent(ev);
599 goto noident;
600 }
601 if (connect(s, &fa.sa, sizeof fa.sin) < 0)
602 {
603closeident:
604 (void) close(s);
605 clrevent(ev);
606 goto noident;
607 }
608
a9bac7a9 609 if (tTd(9, 10))
3f03d7a7
EA
610 printf("getauthinfo: sent %s", hbuf);
611
612 /* send query */
613 if (write(s, hbuf, strlen(hbuf)) < 0)
614 goto closeident;
615
616 /* get result */
617 i = read(s, hbuf, sizeof hbuf);
618 (void) close(s);
619 clrevent(ev);
620 if (i <= 0)
621 goto noident;
622 if (hbuf[--i] == '\n' && hbuf[--i] == '\r')
623 i--;
624 hbuf[++i] = '\0';
625
a9bac7a9 626 if (tTd(9, 3))
3f03d7a7
EA
627 printf("getauthinfo: got %s\n", hbuf);
628
629 /* parse result */
630 p = strchr(hbuf, ':');
631 if (p == NULL)
632 {
633 /* malformed response */
634 goto noident;
635 }
636 while (isascii(*++p) && isspace(*p))
637 continue;
638 if (strncasecmp(p, "userid", 6) != 0)
639 {
640 /* presumably an error string */
641 goto noident;
642 }
643 p += 6;
644 while (isascii(*p) && isspace(*p))
645 p++;
646 if (*p++ != ':')
647 {
648 /* either useridxx or malformed response */
649 goto noident;
650 }
651
652 /* p now points to the OSTYPE field */
653 p = strchr(p, ':');
654 if (p == NULL)
655 {
656 /* malformed response */
657 goto noident;
658 }
a9bac7a9
EA
659
660 /* 1413 says don't do this -- but it's broken otherwise */
661 while (isascii(*++p) && isspace(*p))
662 continue;
3f03d7a7
EA
663
664 /* p now points to the authenticated name */
665 (void) sprintf(hbuf, "%s@%s", p, RealHostName);
a9bac7a9
EA
666 goto finish;
667
668#endif /* IDENTPROTO */
669
670noident:
671 (void) strcpy(hbuf, RealHostName);
672
673finish:
3f03d7a7
EA
674 if (RealHostName[0] != '[')
675 {
676 p = &hbuf[strlen(hbuf)];
677 (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr));
678 }
a9bac7a9 679 if (tTd(9, 1))
3f03d7a7 680 printf("getauthinfo: %s\n", hbuf);
5973222c
EA
681 return hbuf;
682}
683\f/*
42fa5d67
EA
684** MAPHOSTNAME -- turn a hostname into canonical form
685**
686** Parameters:
5a4c03c6 687** map -- a pointer to this map (unused).
42fa5d67
EA
688** hbuf -- a buffer containing a hostname.
689** hbsize -- the size of hbuf.
0cf5a7ba
EA
690** avp -- unused -- for compatibility with other mapping
691** functions.
d1db7a89
EA
692** statp -- an exit status (out parameter) -- set to
693** EX_TEMPFAIL if the name server is unavailable.
42fa5d67
EA
694**
695** Returns:
696** The mapping, if found.
697** NULL if no mapping found.
698**
699** Side Effects:
700** Looks up the host specified in hbuf. If it is not
701** the canonical name for that host, return the canonical
702** name.
703*/
bbfde42f 704
42fa5d67 705char *
d1db7a89 706maphostname(map, hbuf, hbsize, avp, statp)
5a4c03c6 707 MAP *map;
217a0102
EA
708 char *hbuf;
709 int hbsize;
42fa5d67 710 char **avp;
d1db7a89 711 int *statp;
217a0102
EA
712{
713 register struct hostent *hp;
d0432129 714 u_long in_addr;
5a4c03c6 715 char *cp;
740d17b3 716 int i;
b97dd58b
EA
717 register STAB *s;
718 extern struct hostent *gethostbyaddr();
719 extern int h_errno;
217a0102 720
32fd13db 721 /* allow room for null */
5a4c03c6 722 hbsize--;
42fa5d67 723
33e4da31 724 /*
b97dd58b
EA
725 ** See if we have already looked up this name. If so, just
726 ** return it.
727 */
728
729 s = stab(hbuf, ST_NAMECANON, ST_ENTER);
730 if (bitset(NCF_VALID, s->s_namecanon.nc_flags))
731 {
d3b6a883
EA
732 if (tTd(9, 1))
733 printf("maphostname(%s, %d) => CACHE %s\n",
734 hbuf, hbsize, s->s_namecanon.nc_cname);
b97dd58b
EA
735 errno = s->s_namecanon.nc_errno;
736 h_errno = s->s_namecanon.nc_herrno;
737 *statp = s->s_namecanon.nc_stat;
738 return s->s_namecanon.nc_cname;
739 }
740
741 /*
742 ** If first character is a bracket, then it is an address
743 ** lookup. Address is copied into a temporary buffer to
744 ** strip the brackets and to preserve hbuf if address is
745 ** unknown.
746 */
42fa5d67 747
bbfde42f 748 if (*hbuf != '[')
42fa5d67 749 {
0cf5a7ba
EA
750 extern bool getcanonname();
751
a97feb13
EA
752 if (tTd(9, 1))
753 printf("maphostname(%s, %d) => ", hbuf, hbsize);
b97dd58b 754 s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */
b32ed404 755 if (getcanonname(hbuf, hbsize))
1d136a1f
EA
756 {
757 if (tTd(9, 1))
758 printf("%s\n", hbuf);
b97dd58b 759 s->s_namecanon.nc_cname = newstr(hbuf);
42fa5d67 760 return hbuf;
1d136a1f 761 }
42fa5d67 762 else
1d136a1f 763 {
d1db7a89 764 register struct hostent *hp;
d1db7a89 765
1d136a1f 766 if (tTd(9, 1))
d1db7a89 767 printf("FAIL (%d)\n", h_errno);
b97dd58b
EA
768 s->s_namecanon.nc_errno = errno;
769 s->s_namecanon.nc_herrno = h_errno;
d1db7a89
EA
770 switch (h_errno)
771 {
772 case TRY_AGAIN:
c281eee3 773 if (UseNameServer)
7ffb494c
EA
774 {
775 char *msg = "Recipient domain nameserver timed out";
776
777 message(msg);
778 if (CurEnv->e_message == NULL)
f10d3e38 779 CurEnv->e_message = newstr(msg);
7ffb494c 780 }
d1db7a89
EA
781 *statp = EX_TEMPFAIL;
782 break;
783
784 case HOST_NOT_FOUND:
785 *statp = EX_NOHOST;
786 break;
787
788 case NO_RECOVERY:
789 *statp = EX_SOFTWARE;
790 break;
791
792 default:
793 *statp = EX_UNAVAILABLE;
794 break;
795 }
b97dd58b 796 s->s_namecanon.nc_stat = *statp;
d1db7a89
EA
797 if (*statp != EX_TEMPFAIL || UseNameServer)
798 return NULL;
799
800 /*
801 ** Try to look it up in /etc/hosts
802 */
803
804 hp = gethostbyname(hbuf);
805 if (hp == NULL)
806 {
807 /* no dice there either */
b97dd58b 808 s->s_namecanon.nc_stat = *statp = EX_NOHOST;
d1db7a89
EA
809 return NULL;
810 }
811
b97dd58b
EA
812 s->s_namecanon.nc_stat = *statp = EX_OK;
813 s->s_namecanon.nc_cname = newstr(hp->h_name);
d1db7a89 814 return hp->h_name;
1d136a1f 815 }
42fa5d67 816 }
5a4c03c6 817 if ((cp = strchr(hbuf, ']')) == NULL)
42fa5d67 818 return (NULL);
bd974b31 819 *cp = '\0';
5a4c03c6 820 in_addr = inet_addr(&hbuf[1]);
740d17b3
EA
821
822 /* check to see if this is one of our addresses */
823 for (i = 0; MyIpAddrs[i].s_addr != 0; i++)
824 {
825 if (MyIpAddrs[i].s_addr == in_addr)
826 {
827 strncpy(hbuf, MyHostName, hbsize);
828 hbuf[hbsize] = '\0';
829 return hbuf;
830 }
831 }
832
833 /* nope -- ask the name server */
d0432129 834 hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET);
b97dd58b
EA
835 s->s_namecanon.nc_errno = errno;
836 s->s_namecanon.nc_herrno = h_errno;
837 s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */
d0432129 838 if (hp == NULL)
b97dd58b
EA
839 {
840 s->s_namecanon.nc_stat = *statp = EX_NOHOST;
42fa5d67 841 return (NULL);
b97dd58b 842 }
42fa5d67 843
740d17b3 844 /* found a match -- copy out */
b97dd58b 845 s->s_namecanon.nc_cname = newstr(hp->h_name);
5a4c03c6
EA
846 if (strlen(hp->h_name) > hbsize)
847 hp->h_name[hbsize] = '\0';
42fa5d67 848 (void) strcpy(hbuf, hp->h_name);
b97dd58b 849 s->s_namecanon.nc_stat = *statp = EX_OK;
42fa5d67 850 return hbuf;
217a0102 851}
3341995c
EA
852\f/*
853** ANYNET_NTOA -- convert a network address to printable form.
854**
855** Parameters:
856** sap -- a pointer to a sockaddr structure.
857**
858** Returns:
859** A printable version of that sockaddr.
860*/
861
862char *
863anynet_ntoa(sap)
864 register SOCKADDR *sap;
865{
866 register char *bp;
867 register char *ap;
868 int l;
869 static char buf[80];
870
a97feb13
EA
871 /* check for null/zero family */
872 if (sap == NULL)
873 return "NULLADDR";
874 if (sap->sa.sa_family == 0)
875 return "0";
876
3356c77c
EA
877#ifdef NETINET
878 if (sap->sa.sa_family == AF_INET)
3341995c
EA
879 {
880 extern char *inet_ntoa();
881
882 return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr);
883 }
3356c77c 884#endif
3341995c
EA
885
886 /* unknown family -- just dump bytes */
3356c77c 887 (void) sprintf(buf, "Family %d: ", sap->sa.sa_family);
3341995c 888 bp = &buf[strlen(buf)];
3356c77c
EA
889 ap = sap->sa.sa_data;
890 for (l = sizeof sap->sa.sa_data; --l >= 0; )
3341995c
EA
891 {
892 (void) sprintf(bp, "%02x:", *ap++ & 0377);
893 bp += 3;
894 }
895 *--bp = '\0';
896 return buf;
897}
3f03d7a7
EA
898\f/*
899** HOSTNAMEBYANYADDR -- return name of host based on address
900**
901** Parameters:
902** sap -- SOCKADDR pointer
903**
904** Returns:
905** text representation of host name.
906**
907** Side Effects:
908** none.
909*/
910
911char *
912hostnamebyanyaddr(sap)
913 register SOCKADDR *sap;
914{
915 register struct hostent *hp;
916
ab6ca5e5
EA
917#ifdef NAMED_BIND
918 int saveretry;
919
920 /* shorten name server timeout to avoid higher level timeouts */
921 saveretry = _res.retry;
922 _res.retry = 3;
923#endif /* NAMED_BIND */
924
3f03d7a7
EA
925 switch (sap->sa.sa_family)
926 {
927#ifdef NETINET
928 case AF_INET:
929 hp = gethostbyaddr((char *) &sap->sin.sin_addr,
930 sizeof sap->sin.sin_addr,
931 AF_INET);
932 break;
933#endif
934
935#ifdef NETISO
936 case AF_ISO:
937 hp = gethostbyaddr((char *) &sap->siso.siso_addr,
938 sizeof sap->siso.siso_addr,
939 AF_ISO);
940 break;
941#endif
942
943 default:
944 hp = gethostbyaddr(sap->sa.sa_data,
945 sizeof sap->sa.sa_data,
946 sap->sa.sa_family);
947 break;
948 }
949
ab6ca5e5
EA
950#ifdef NAMED_BIND
951 _res.retry = saveretry;
952#endif /* NAMED_BIND */
953
3f03d7a7
EA
954 if (hp != NULL)
955 return hp->h_name;
956 else
957 {
958 /* produce a dotted quad */
959 static char buf[512];
960
961 (void) sprintf(buf, "[%s]", anynet_ntoa(sap));
962 return buf;
963 }
964}
d0432129 965
f3d8f6d6 966# else /* DAEMON */
217a0102 967/* code for systems without sophisticated networking */
2ec2faaa
EA
968
969/*
970** MYHOSTNAME -- stub version for case of no daemon code.
69f904e0
EA
971**
972** Can't convert to upper case here because might be a UUCP name.
05894fc6
EA
973**
974** Mark, you can change this to be anything you want......
2ec2faaa
EA
975*/
976
977char **
05894fc6 978myhostname(hostbuf, size)
2ec2faaa 979 char hostbuf[];
05894fc6 980 int size;
2ec2faaa
EA
981{
982 register FILE *f;
983
984 hostbuf[0] = '\0';
985 f = fopen("/usr/include/whoami", "r");
986 if (f != NULL)
987 {
05894fc6 988 (void) fgets(hostbuf, size, f);
2ec2faaa
EA
989 fixcrlf(hostbuf, TRUE);
990 (void) fclose(f);
991 }
992 return (NULL);
993}
217a0102 994\f/*
3f03d7a7 995** GETAUTHINFO -- get the real host name asociated with a file descriptor
5973222c
EA
996**
997** Parameters:
998** fd -- the descriptor
999**
1000** Returns:
1001** The host name associated with this descriptor, if it can
1002** be determined.
1003** NULL otherwise.
1004**
1005** Side Effects:
1006** none
1007*/
1008
1009char *
3f03d7a7 1010getauthinfo(fd)
5973222c
EA
1011 int fd;
1012{
1013 return NULL;
1014}
1015\f/*
217a0102
EA
1016** MAPHOSTNAME -- turn a hostname into canonical form
1017**
1018** Parameters:
5a4c03c6 1019** map -- a pointer to the database map.
217a0102 1020** hbuf -- a buffer containing a hostname.
d1db7a89 1021** hbsize -- size of hbuf.
42fa5d67 1022** avp -- a pointer to a (cf file defined) argument vector.
d1db7a89 1023** statp -- an exit status (out parameter).
217a0102
EA
1024**
1025** Returns:
42fa5d67 1026** mapped host name
bbfde42f 1027** FALSE otherwise.
217a0102
EA
1028**
1029** Side Effects:
1030** Looks up the host specified in hbuf. If it is not
1031** the canonical name for that host, replace it with
1032** the canonical name. If the name is unknown, or it
1033** is already the canonical name, leave it unchanged.
1034*/
1035
1036/*ARGSUSED*/
42fa5d67 1037char *
d1db7a89 1038maphostname(map, hbuf, hbsize, avp, statp)
5a4c03c6 1039 MAP *map;
217a0102
EA
1040 char *hbuf;
1041 int hbsize;
42fa5d67 1042 char **avp;
d1db7a89 1043 char *statp;
217a0102 1044{
d1db7a89
EA
1045 register struct hostent *hp;
1046
1047 hp = gethostbyname(hbuf);
1048 if (hp != NULL)
1049 return hp->h_name;
1050 *statp = EX_NOHOST;
42fa5d67 1051 return NULL;
217a0102
EA
1052}
1053
f3d8f6d6 1054#endif /* DAEMON */