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