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