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