122700Sdist /* 268839Seric * Copyright (c) 1983, 1995 Eric P. Allman 362522Sbostic * Copyright (c) 1988, 1993 462522Sbostic * The Regents of the University of California. All rights reserved. 533780Sbostic * 642825Sbostic * %sccs.include.redist.c% 733780Sbostic */ 822700Sdist 933932Sbostic #include <errno.h> 1040962Sbostic #include "sendmail.h" 114535Seric 1233780Sbostic #ifndef lint 1333780Sbostic #ifdef DAEMON 14*69818Seric static char sccsid[] = "@(#)daemon.c 8.97 (Berkeley) 06/10/95 (with daemon mode)"; 1533780Sbostic #else 16*69818Seric static char sccsid[] = "@(#)daemon.c 8.97 (Berkeley) 06/10/95 (without daemon mode)"; 1733780Sbostic #endif 1833780Sbostic #endif /* not lint */ 194535Seric 2033780Sbostic #ifdef DAEMON 2133780Sbostic 2264338Seric # include <arpa/inet.h> 235978Seric 2466334Seric #if NAMED_BIND 2559042Seric # include <resolv.h> 2659042Seric #endif 2759042Seric 2869601Seric #if IP_SRCROUTE 2969601Seric # include <netinet/in_systm.h> 3069601Seric # include <netinet/ip.h> 3169601Seric # include <netinet/ip_var.h> 3269601Seric #endif 3369601Seric 344535Seric /* 354535Seric ** DAEMON.C -- routines to use when running as a daemon. 367556Seric ** 377556Seric ** This entire file is highly dependent on the 4.2 BSD 387556Seric ** interprocess communication primitives. No attempt has 397556Seric ** been made to make this file portable to Version 7, 407556Seric ** Version 6, MPX files, etc. If you should try such a 417556Seric ** thing yourself, I recommend chucking the entire file 427556Seric ** and starting from scratch. Basic semantics are: 437556Seric ** 447556Seric ** getrequests() 457556Seric ** Opens a port and initiates a connection. 467556Seric ** Returns in a child. Must set InChannel and 477556Seric ** OutChannel appropriately. 4810206Seric ** clrdaemon() 4910206Seric ** Close any open files associated with getting 5010206Seric ** the connection; this is used when running the queue, 5110206Seric ** etc., to avoid having extra file descriptors during 5210206Seric ** the queue run and to avoid confusing the network 5310206Seric ** code (if it cares). 5452106Seric ** makeconnection(host, port, outfile, infile, usesecureport) 557556Seric ** Make a connection to the named host on the given 567556Seric ** port. Set *outfile and *infile to the files 577556Seric ** appropriate for communication. Returns zero on 587556Seric ** success, else an exit status describing the 597556Seric ** error. 6060089Seric ** host_map_lookup(map, hbuf, avp, pstat) 6156823Seric ** Convert the entry in hbuf into a canonical form. 624535Seric */ 634535Seric /* 644535Seric ** GETREQUESTS -- open mail IPC port and get requests. 654535Seric ** 664535Seric ** Parameters: 674535Seric ** none. 684535Seric ** 694535Seric ** Returns: 704535Seric ** none. 714535Seric ** 724535Seric ** Side Effects: 734535Seric ** Waits until some interesting activity occurs. When 744535Seric ** it does, a child is created to process it, and the 754535Seric ** parent waits for completion. Return from this 769886Seric ** routine is always in the child. The file pointers 779886Seric ** "InChannel" and "OutChannel" should be set to point 789886Seric ** to the communication channel. 794535Seric */ 804535Seric 8158849Seric int DaemonSocket = -1; /* fd describing socket */ 8258849Seric SOCKADDR DaemonAddr; /* socket for incoming */ 8359783Seric int ListenQueueSize = 10; /* size of listen queue */ 8464381Seric int TcpRcvBufferSize = 0; /* size of TCP receive buffer */ 8564381Seric int TcpSndBufferSize = 0; /* size of TCP send buffer */ 8616144Seric 8768693Seric void 884535Seric getrequests() 894535Seric { 909610Seric int t; 9153751Seric bool refusingconnections = TRUE; 9258419Seric FILE *pidf; 9364828Seric int socksize; 9466793Seric #ifdef XDEBUG 9566793Seric bool j_has_dot; 9666793Seric #endif 9746928Sbostic extern void reapchild(); 987117Seric 999610Seric /* 1009610Seric ** Set up the address for the mailer. 1019610Seric */ 1029610Seric 10358849Seric if (DaemonAddr.sin.sin_family == 0) 10458849Seric DaemonAddr.sin.sin_family = AF_INET; 10558849Seric if (DaemonAddr.sin.sin_addr.s_addr == 0) 10658849Seric DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY; 10758849Seric if (DaemonAddr.sin.sin_port == 0) 1089610Seric { 10965169Seric register struct servent *sp; 11065169Seric 11158849Seric sp = getservbyname("smtp", "tcp"); 11258849Seric if (sp == NULL) 11358849Seric { 11458909Seric syserr("554 service \"smtp\" unknown"); 11565169Seric DaemonAddr.sin.sin_port = htons(25); 11658849Seric } 11765169Seric else 11865169Seric DaemonAddr.sin.sin_port = sp->s_port; 1199610Seric } 1209610Seric 1219610Seric /* 1229610Seric ** Try to actually open the connection. 1239610Seric */ 1249610Seric 1259610Seric if (tTd(15, 1)) 12658849Seric printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port); 1279610Seric 1289610Seric /* get a socket for the SMTP connection */ 12966854Seric socksize = opendaemonsocket(TRUE); 13010347Seric 13164035Seric (void) setsignal(SIGCHLD, reapchild); 13224945Seric 13358419Seric /* write the pid to the log file for posterity */ 13458419Seric pidf = fopen(PidFile, "w"); 13558419Seric if (pidf != NULL) 13658419Seric { 13763863Seric extern char *CommandLineArgs; 13863863Seric 13963863Seric /* write the process id on line 1 */ 14058419Seric fprintf(pidf, "%d\n", getpid()); 14163863Seric 14263863Seric /* line 2 contains all command line flags */ 14363863Seric fprintf(pidf, "%s\n", CommandLineArgs); 14463863Seric 14563863Seric /* flush and close */ 14658419Seric fclose(pidf); 14758419Seric } 14858419Seric 14966793Seric #ifdef XDEBUG 15066793Seric { 15166812Seric char jbuf[MAXHOSTNAMELEN]; 15258419Seric 15368693Seric expand("\201j", jbuf, sizeof jbuf, CurEnv); 15466812Seric j_has_dot = strchr(jbuf, '.') != NULL; 15566793Seric } 15666793Seric #endif 15766793Seric 1589610Seric if (tTd(15, 1)) 15910206Seric printf("getrequests: %d\n", DaemonSocket); 1609610Seric 1614631Seric for (;;) 1624631Seric { 16314875Seric register int pid; 16411147Seric auto int lotherend; 16553751Seric extern bool refuseconnections(); 16668693Seric extern int getla(); 16711147Seric 16814875Seric /* see if we are rejecting connections */ 16953751Seric CurrentLA = getla(); 17053751Seric if (refuseconnections()) 17136584Sbostic { 17266845Seric if (DaemonSocket >= 0) 17353751Seric { 17466845Seric /* close socket so peer will fail quickly */ 17566845Seric (void) close(DaemonSocket); 17666845Seric DaemonSocket = -1; 17753751Seric } 17866845Seric refusingconnections = TRUE; 17957385Seric setproctitle("rejecting connections: load average: %d", 18057385Seric CurrentLA); 18166845Seric sleep(15); 18253751Seric continue; 18336584Sbostic } 18414875Seric 18568693Seric /* arrange to (re)open the socket if necessary */ 18653751Seric if (refusingconnections) 18753751Seric { 18867690Seric (void) opendaemonsocket(FALSE); 18953751Seric refusingconnections = FALSE; 19053751Seric } 19153751Seric 19266793Seric #ifdef XDEBUG 19366793Seric /* check for disaster */ 19466793Seric { 19566812Seric char jbuf[MAXHOSTNAMELEN]; 19666793Seric 19768693Seric expand("\201j", jbuf, sizeof jbuf, CurEnv); 19868693Seric if (!wordinclass(jbuf, 'w')) 19966793Seric { 20066793Seric dumpstate("daemon lost $j"); 20166793Seric syslog(LOG_ALERT, "daemon process doesn't have $j in $=w; see syslog"); 20266793Seric abort(); 20366793Seric } 20466812Seric else if (j_has_dot && strchr(jbuf, '.') == NULL) 20566793Seric { 20666793Seric dumpstate("daemon $j lost dot"); 20766793Seric syslog(LOG_ALERT, "daemon process $j lost dot; see syslog"); 20866793Seric abort(); 20966793Seric } 21066793Seric } 21166793Seric #endif 21266793Seric 2139610Seric /* wait for a connection */ 21469781Seric setproctitle("accepting connections"); 2159610Seric do 2169610Seric { 2179610Seric errno = 0; 21864828Seric lotherend = socksize; 21946928Sbostic t = accept(DaemonSocket, 22046928Sbostic (struct sockaddr *)&RealHostAddr, &lotherend); 2219610Seric } while (t < 0 && errno == EINTR); 2229610Seric if (t < 0) 2235978Seric { 2249610Seric syserr("getrequests: accept"); 22568693Seric 22668693Seric /* arrange to re-open the socket next time around */ 22768693Seric (void) close(DaemonSocket); 22868693Seric DaemonSocket = -1; 2299610Seric sleep(5); 2309610Seric continue; 2315978Seric } 2324631Seric 2335978Seric /* 2345978Seric ** Create a subprocess to process the mail. 2355978Seric */ 2365978Seric 2377677Seric if (tTd(15, 2)) 2389610Seric printf("getrequests: forking (fd = %d)\n", t); 2395978Seric 2404636Seric pid = fork(); 2414636Seric if (pid < 0) 2424631Seric { 2434636Seric syserr("daemon: cannot fork"); 2444636Seric sleep(10); 2459610Seric (void) close(t); 2464636Seric continue; 2474631Seric } 2484631Seric 2494636Seric if (pid == 0) 2504631Seric { 25164086Seric char *p; 25258951Seric extern char *hostnamebyanyaddr(); 25368693Seric extern void intsig(); 25411147Seric 2554636Seric /* 2564636Seric ** CHILD -- return to caller. 25711147Seric ** Collect verified idea of sending host. 2584636Seric ** Verify calling user id if possible here. 2594636Seric */ 2604631Seric 26164035Seric (void) setsignal(SIGCHLD, SIG_DFL); 26268693Seric (void) setsignal(SIGHUP, intsig); 26368693Seric (void) close(DaemonSocket); 26466017Seric DisConnected = FALSE; 26524950Seric 26666032Seric setproctitle("startup with %s", 26766032Seric anynet_ntoa(&RealHostAddr)); 26866032Seric 26911147Seric /* determine host name */ 27064086Seric p = hostnamebyanyaddr(&RealHostAddr); 27169471Seric if (strlen(p) > MAXNAME) 27269471Seric p[MAXNAME] = '\0'; 27364086Seric RealHostName = newstr(p); 27466032Seric setproctitle("startup with %s", p); 27558778Seric 27664724Seric if ((InChannel = fdopen(t, "r")) == NULL || 27764724Seric (t = dup(t)) < 0 || 27864724Seric (OutChannel = fdopen(t, "w")) == NULL) 27964724Seric { 28064724Seric syserr("cannot open SMTP server channel, fd=%d", t); 28164724Seric exit(0); 28264724Seric } 28359254Seric 28416884Seric /* should we check for illegal connection here? XXX */ 28559156Seric #ifdef XLA 28659156Seric if (!xla_host_ok(RealHostName)) 28759156Seric { 28859254Seric message("421 Too many SMTP sessions for this host"); 28959156Seric exit(0); 29059156Seric } 29159156Seric #endif 29216884Seric 2937677Seric if (tTd(15, 2)) 2945978Seric printf("getreq: returning\n"); 2954636Seric return; 2964631Seric } 2974631Seric 2987117Seric /* close the port so that others will hang (for a while) */ 2999610Seric (void) close(t); 3004631Seric } 3019886Seric /*NOTREACHED*/ 3024631Seric } 3035978Seric /* 30466845Seric ** OPENDAEMONSOCKET -- open the SMTP socket 30566845Seric ** 30666845Seric ** Deals with setting all appropriate options. DaemonAddr must 30766845Seric ** be set up in advance. 30866845Seric ** 30966845Seric ** Parameters: 31066854Seric ** firsttime -- set if this is the initial open. 31166845Seric ** 31266845Seric ** Returns: 31366845Seric ** Size in bytes of the daemon socket addr. 31466845Seric ** 31566845Seric ** Side Effects: 31666845Seric ** Leaves DaemonSocket set to the open socket. 31766845Seric ** Exits if the socket cannot be created. 31866845Seric */ 31966845Seric 32066861Seric #define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 32166861Seric 32266845Seric int 32366854Seric opendaemonsocket(firsttime) 32466854Seric bool firsttime; 32566845Seric { 32666845Seric int on = 1; 32768693Seric int socksize = 0; 32866861Seric int ntries = 0; 32966861Seric int saveerrno; 33066845Seric 33166845Seric if (tTd(15, 2)) 33266845Seric printf("opendaemonsocket()\n"); 33366845Seric 33466861Seric do 33566845Seric { 33666862Seric if (ntries > 0) 33766862Seric sleep(5); 33866861Seric if (firsttime || DaemonSocket < 0) 33966854Seric { 34066861Seric DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0); 34166861Seric if (DaemonSocket < 0) 34266861Seric { 34366861Seric /* probably another daemon already */ 34466861Seric saveerrno = errno; 34566861Seric syserr("opendaemonsocket: can't create server SMTP socket"); 34666861Seric severe: 34766845Seric # ifdef LOG 34866861Seric if (LogLevel > 0) 34966861Seric syslog(LOG_ALERT, "problem creating SMTP socket"); 35066845Seric # endif /* LOG */ 35166861Seric DaemonSocket = -1; 35266861Seric continue; 35366861Seric } 35466845Seric 35566861Seric /* turn on network debugging? */ 35666861Seric if (tTd(15, 101)) 35766861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 35866861Seric SO_DEBUG, (char *)&on, 35966861Seric sizeof on); 36066845Seric 36166861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 36266861Seric SO_REUSEADDR, (char *)&on, sizeof on); 36366861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 36466861Seric SO_KEEPALIVE, (char *)&on, sizeof on); 36566845Seric 36666845Seric #ifdef SO_RCVBUF 36766861Seric if (TcpRcvBufferSize > 0) 36866861Seric { 36966861Seric if (setsockopt(DaemonSocket, SOL_SOCKET, 37066861Seric SO_RCVBUF, 37166861Seric (char *) &TcpRcvBufferSize, 37266861Seric sizeof(TcpRcvBufferSize)) < 0) 37366861Seric syserr("getrequests: setsockopt(SO_RCVBUF)"); 37466861Seric } 37566845Seric #endif 37666845Seric 37766861Seric switch (DaemonAddr.sa.sa_family) 37866861Seric { 37966845Seric # ifdef NETINET 38066861Seric case AF_INET: 38166861Seric socksize = sizeof DaemonAddr.sin; 38266861Seric break; 38366845Seric # endif 38466845Seric 38566845Seric # ifdef NETISO 38666861Seric case AF_ISO: 38766861Seric socksize = sizeof DaemonAddr.siso; 38866861Seric break; 38966845Seric # endif 39066845Seric 39166861Seric default: 39266861Seric socksize = sizeof DaemonAddr; 39366861Seric break; 39466861Seric } 39566861Seric 39666861Seric if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0) 39766861Seric { 39866861Seric saveerrno = errno; 39966861Seric syserr("getrequests: cannot bind"); 40066861Seric (void) close(DaemonSocket); 40166861Seric goto severe; 40266861Seric } 40366854Seric } 40466861Seric if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0) 40566854Seric { 40666861Seric saveerrno = errno; 40766861Seric syserr("getrequests: cannot listen"); 40866854Seric (void) close(DaemonSocket); 40966854Seric goto severe; 41066854Seric } 41166861Seric return socksize; 41266861Seric } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno)); 41368693Seric syserr("!opendaemonsocket: server SMTP socket wedged: exiting"); 41466861Seric finis(); 41566845Seric } 41666845Seric /* 41710206Seric ** CLRDAEMON -- reset the daemon connection 41810206Seric ** 41910206Seric ** Parameters: 42010206Seric ** none. 42110206Seric ** 42210206Seric ** Returns: 42310206Seric ** none. 42410206Seric ** 42510206Seric ** Side Effects: 42610206Seric ** releases any resources used by the passive daemon. 42710206Seric */ 42810206Seric 42968693Seric void 43010206Seric clrdaemon() 43110206Seric { 43210206Seric if (DaemonSocket >= 0) 43310206Seric (void) close(DaemonSocket); 43410206Seric DaemonSocket = -1; 43510206Seric } 43610206Seric /* 43758849Seric ** SETDAEMONOPTIONS -- set options for running the daemon 43858849Seric ** 43958849Seric ** Parameters: 44058849Seric ** p -- the options line. 44158849Seric ** 44258849Seric ** Returns: 44358849Seric ** none. 44458849Seric */ 44558849Seric 44668693Seric void 44758849Seric setdaemonoptions(p) 44858849Seric register char *p; 44958849Seric { 45058873Seric if (DaemonAddr.sa.sa_family == AF_UNSPEC) 45158873Seric DaemonAddr.sa.sa_family = AF_INET; 45258873Seric 45358849Seric while (p != NULL) 45458849Seric { 45558849Seric register char *f; 45658849Seric register char *v; 45758849Seric 45858849Seric while (isascii(*p) && isspace(*p)) 45958849Seric p++; 46058849Seric if (*p == '\0') 46158849Seric break; 46258849Seric f = p; 46358849Seric p = strchr(p, ','); 46458849Seric if (p != NULL) 46558849Seric *p++ = '\0'; 46658849Seric v = strchr(f, '='); 46758849Seric if (v == NULL) 46858849Seric continue; 46958849Seric while (isascii(*++v) && isspace(*v)) 47058849Seric continue; 47169397Seric if (isascii(*f) && isupper(*f)) 47269397Seric *f = tolower(*f); 47358849Seric 47458849Seric switch (*f) 47558849Seric { 47658873Seric case 'F': /* address family */ 47758849Seric if (isascii(*v) && isdigit(*v)) 47858873Seric DaemonAddr.sa.sa_family = atoi(v); 47958873Seric #ifdef NETINET 48058873Seric else if (strcasecmp(v, "inet") == 0) 48158873Seric DaemonAddr.sa.sa_family = AF_INET; 48258873Seric #endif 48358873Seric #ifdef NETISO 48458873Seric else if (strcasecmp(v, "iso") == 0) 48558873Seric DaemonAddr.sa.sa_family = AF_ISO; 48658873Seric #endif 48758873Seric #ifdef NETNS 48858873Seric else if (strcasecmp(v, "ns") == 0) 48958873Seric DaemonAddr.sa.sa_family = AF_NS; 49058873Seric #endif 49158873Seric #ifdef NETX25 49258873Seric else if (strcasecmp(v, "x.25") == 0) 49358873Seric DaemonAddr.sa.sa_family = AF_CCITT; 49458873Seric #endif 49558849Seric else 49658873Seric syserr("554 Unknown address family %s in Family=option", v); 49758873Seric break; 49858873Seric 49958873Seric case 'A': /* address */ 50058873Seric switch (DaemonAddr.sa.sa_family) 50158849Seric { 50258873Seric #ifdef NETINET 50358873Seric case AF_INET: 50458873Seric if (isascii(*v) && isdigit(*v)) 50568693Seric DaemonAddr.sin.sin_addr.s_addr = htonl(inet_network(v)); 50658873Seric else 50758873Seric { 50858873Seric register struct netent *np; 50958849Seric 51058873Seric np = getnetbyname(v); 51158873Seric if (np == NULL) 51258873Seric syserr("554 network \"%s\" unknown", v); 51358873Seric else 51458873Seric DaemonAddr.sin.sin_addr.s_addr = np->n_net; 51558873Seric } 51658873Seric break; 51758873Seric #endif 51858873Seric 51958873Seric default: 52058873Seric syserr("554 Address= option unsupported for family %d", 52158873Seric DaemonAddr.sa.sa_family); 52258873Seric break; 52358849Seric } 52458849Seric break; 52558849Seric 52658873Seric case 'P': /* port */ 52758873Seric switch (DaemonAddr.sa.sa_family) 52858849Seric { 52958873Seric short port; 53058849Seric 53158873Seric #ifdef NETINET 53258873Seric case AF_INET: 53358873Seric if (isascii(*v) && isdigit(*v)) 53464366Seric DaemonAddr.sin.sin_port = htons(atoi(v)); 53558849Seric else 53658873Seric { 53758873Seric register struct servent *sp; 53858873Seric 53958873Seric sp = getservbyname(v, "tcp"); 54058873Seric if (sp == NULL) 54158909Seric syserr("554 service \"%s\" unknown", v); 54258873Seric else 54358873Seric DaemonAddr.sin.sin_port = sp->s_port; 54458873Seric } 54558873Seric break; 54658873Seric #endif 54758873Seric 54858873Seric #ifdef NETISO 54958873Seric case AF_ISO: 55058873Seric /* assume two byte transport selector */ 55158873Seric if (isascii(*v) && isdigit(*v)) 55264366Seric port = htons(atoi(v)); 55358873Seric else 55458873Seric { 55558873Seric register struct servent *sp; 55658873Seric 55758873Seric sp = getservbyname(v, "tcp"); 55858873Seric if (sp == NULL) 55958909Seric syserr("554 service \"%s\" unknown", v); 56058873Seric else 56158873Seric port = sp->s_port; 56258873Seric } 56358873Seric bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 56458873Seric break; 56558873Seric #endif 56658873Seric 56758873Seric default: 56858873Seric syserr("554 Port= option unsupported for family %d", 56958873Seric DaemonAddr.sa.sa_family); 57058873Seric break; 57158849Seric } 57258849Seric break; 57359783Seric 57459783Seric case 'L': /* listen queue size */ 57559783Seric ListenQueueSize = atoi(v); 57659783Seric break; 57764381Seric 57864381Seric case 'S': /* send buffer size */ 57964381Seric TcpSndBufferSize = atoi(v); 58064381Seric break; 58164381Seric 58264381Seric case 'R': /* receive buffer size */ 58364381Seric TcpRcvBufferSize = atoi(v); 58464381Seric break; 58569397Seric 58669397Seric default: 58769397Seric syserr("554 DaemonPortOptions parameter \"%s\" unknown", f); 58858849Seric } 58958849Seric } 59058849Seric } 59158849Seric /* 5926039Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 5936039Seric ** 5946039Seric ** Parameters: 5956039Seric ** host -- the name of the host. 5966633Seric ** port -- the port number to connect to. 59753739Seric ** mci -- a pointer to the mail connection information 59853739Seric ** structure to be filled in. 59952106Seric ** usesecureport -- if set, use a low numbered (reserved) 60052106Seric ** port to provide some rudimentary authentication. 6016039Seric ** 6026039Seric ** Returns: 6036039Seric ** An exit code telling whether the connection could be 6046039Seric ** made and if not why not. 6056039Seric ** 6066039Seric ** Side Effects: 6076039Seric ** none. 6086039Seric */ 6095978Seric 61058755Seric SOCKADDR CurHostAddr; /* address of current host */ 61158305Seric 61254967Seric int 61353739Seric makeconnection(host, port, mci, usesecureport) 6146039Seric char *host; 6157286Seric u_short port; 61654967Seric register MCI *mci; 61752106Seric bool usesecureport; 6186039Seric { 61968693Seric register int i = 0; 62068693Seric register int s; 62129430Sbloom register struct hostent *hp = (struct hostent *)NULL; 62258755Seric SOCKADDR addr; 62352106Seric int sav_errno; 62458755Seric int addrlen; 62568693Seric bool firstconnect; 62666334Seric #if NAMED_BIND 62735651Seric extern int h_errno; 62835651Seric #endif 6296039Seric 6306039Seric /* 6316039Seric ** Set up the address for the mailer. 6329308Seric ** Accept "[a.b.c.d]" syntax for host name. 6336039Seric */ 6346039Seric 63566334Seric #if NAMED_BIND 63625475Smiriam h_errno = 0; 63735651Seric #endif 63825475Smiriam errno = 0; 63958864Seric bzero(&CurHostAddr, sizeof CurHostAddr); 64064334Seric SmtpPhase = mci->mci_phase = "initial connection"; 64158906Seric CurHostName = host; 64225475Smiriam 6439308Seric if (host[0] == '[') 6449308Seric { 64511147Seric long hid; 64656795Seric register char *p = strchr(host, ']'); 6479308Seric 64811147Seric if (p != NULL) 6499308Seric { 65011147Seric *p = '\0'; 65159884Seric #ifdef NETINET 65211147Seric hid = inet_addr(&host[1]); 65358360Seric if (hid == -1) 65459884Seric #endif 65558360Seric { 65658360Seric /* try it as a host name (avoid MX lookup) */ 65768693Seric hp = sm_gethostbyname(&host[1]); 65866349Seric if (hp == NULL && p[-1] == '.') 65966349Seric { 66068693Seric #if NAMED_BIND 66168693Seric int oldopts = _res.options; 66268693Seric 66368693Seric _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 66468693Seric #endif 66566349Seric p[-1] = '\0'; 66668693Seric hp = sm_gethostbyname(&host[1]); 66766349Seric p[-1] = '.'; 66868693Seric #if NAMED_BIND 66968693Seric _res.options = oldopts; 67068693Seric #endif 67166349Seric } 67258360Seric *p = ']'; 67358360Seric goto gothostent; 67458360Seric } 67511147Seric *p = ']'; 6769308Seric } 67758360Seric if (p == NULL) 6789308Seric { 67958151Seric usrerr("553 Invalid numeric domain spec \"%s\"", host); 68068857Seric mci->mci_status = "5.1.2"; 6819308Seric return (EX_NOHOST); 6829308Seric } 68359884Seric #ifdef NETINET 68459884Seric addr.sin.sin_family = AF_INET; /*XXX*/ 68558778Seric addr.sin.sin_addr.s_addr = hid; 68659884Seric #endif 6879308Seric } 6889610Seric else 6899610Seric { 69066349Seric register char *p = &host[strlen(host) - 1]; 69166349Seric 69268693Seric hp = sm_gethostbyname(host); 69366349Seric if (hp == NULL && *p == '.') 69466349Seric { 69568693Seric #if NAMED_BIND 69668693Seric int oldopts = _res.options; 69768693Seric 69868693Seric _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 69968693Seric #endif 70066349Seric *p = '\0'; 70168693Seric hp = sm_gethostbyname(host); 70266349Seric *p = '.'; 70368693Seric #if NAMED_BIND 70468693Seric _res.options = oldopts; 70568693Seric #endif 70666349Seric } 70758360Seric gothostent: 70825475Smiriam if (hp == NULL) 70924945Seric { 71066334Seric #if NAMED_BIND 71168693Seric /* check for name server timeouts */ 71268693Seric if (errno == ETIMEDOUT || h_errno == TRY_AGAIN || 71368693Seric (errno == ECONNREFUSED && UseNameServer)) 71468693Seric { 71568693Seric mci->mci_status = "4.4.3"; 71625475Smiriam return (EX_TEMPFAIL); 71768693Seric } 71835651Seric #endif 71925475Smiriam return (EX_NOHOST); 72024945Seric } 72158778Seric addr.sa.sa_family = hp->h_addrtype; 72258778Seric switch (hp->h_addrtype) 72358778Seric { 72458778Seric #ifdef NETINET 72558778Seric case AF_INET: 72658755Seric bcopy(hp->h_addr, 72758778Seric &addr.sin.sin_addr, 72868693Seric INADDRSZ); 72958778Seric break; 73058778Seric #endif 73158778Seric 73258778Seric default: 73358755Seric bcopy(hp->h_addr, 73458778Seric addr.sa.sa_data, 73558755Seric hp->h_length); 73658778Seric break; 73758778Seric } 73829430Sbloom i = 1; 7399610Seric } 7409610Seric 7419610Seric /* 7429610Seric ** Determine the port number. 7439610Seric */ 7449610Seric 74510011Seric if (port != 0) 74658755Seric port = htons(port); 74710011Seric else 7489610Seric { 7499610Seric register struct servent *sp = getservbyname("smtp", "tcp"); 7509610Seric 7519610Seric if (sp == NULL) 7529610Seric { 75368745Seric #ifdef LOG 75468745Seric if (LogLevel > 2) 75568745Seric syslog(LOG_ERR, "makeconnection: service \"smtp\" unknown"); 75668745Seric #endif 75765169Seric port = htons(25); 7589610Seric } 75965169Seric else 76065169Seric port = sp->s_port; 7619610Seric } 7626039Seric 76358778Seric switch (addr.sa.sa_family) 76458755Seric { 76559884Seric #ifdef NETINET 76658755Seric case AF_INET: 76758778Seric addr.sin.sin_port = port; 76858755Seric addrlen = sizeof (struct sockaddr_in); 76958755Seric break; 77059884Seric #endif 77158755Seric 77258755Seric #ifdef NETISO 77358755Seric case AF_ISO: 77458755Seric /* assume two byte transport selector */ 77558755Seric bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 77658755Seric addrlen = sizeof (struct sockaddr_iso); 77758755Seric break; 77858755Seric #endif 77958755Seric 78058755Seric default: 78158778Seric syserr("Can't connect to address family %d", addr.sa.sa_family); 78258755Seric return (EX_NOHOST); 78358755Seric } 78458755Seric 7856039Seric /* 7866039Seric ** Try to actually open the connection. 7876039Seric */ 7886039Seric 78959156Seric #ifdef XLA 79059156Seric /* if too many connections, don't bother trying */ 79159156Seric if (!xla_noqueue_ok(host)) 79259156Seric return EX_TEMPFAIL; 79359156Seric #endif 79459156Seric 79568693Seric firstconnect = TRUE; 79657736Seric for (;;) 79752106Seric { 79857736Seric if (tTd(16, 1)) 79958755Seric printf("makeconnection (%s [%s])\n", 80058755Seric host, anynet_ntoa(&addr)); 80152106Seric 80258588Seric /* save for logging */ 80358588Seric CurHostAddr = addr; 80458588Seric 80557736Seric if (usesecureport) 80657736Seric { 80757736Seric int rport = IPPORT_RESERVED - 1; 8086039Seric 80957736Seric s = rresvport(&rport); 81057736Seric } 81157736Seric else 81257736Seric { 81357736Seric s = socket(AF_INET, SOCK_STREAM, 0); 81457736Seric } 81557736Seric if (s < 0) 81657736Seric { 81757736Seric sav_errno = errno; 81857736Seric syserr("makeconnection: no socket"); 81957736Seric goto failure; 82057736Seric } 82110347Seric 82264381Seric #ifdef SO_SNDBUF 82364381Seric if (TcpSndBufferSize > 0) 82464381Seric { 82564381Seric if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 82664561Seric (char *) &TcpSndBufferSize, 82764381Seric sizeof(TcpSndBufferSize)) < 0) 82864381Seric syserr("makeconnection: setsockopt(SO_SNDBUF)"); 82964381Seric } 83064381Seric #endif 83164381Seric 83257736Seric if (tTd(16, 1)) 83357736Seric printf("makeconnection: fd=%d\n", s); 83457736Seric 83557736Seric /* turn on network debugging? */ 83657736Seric if (tTd(16, 101)) 83757736Seric { 83857736Seric int on = 1; 83966861Seric (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 84057736Seric (char *)&on, sizeof on); 84157736Seric } 84257736Seric if (CurEnv->e_xfp != NULL) 84357736Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 84457736Seric errno = 0; /* for debugging */ 84558755Seric if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 84657736Seric break; 84757736Seric 84868693Seric /* if running demand-dialed connection, try again */ 84968693Seric if (DialDelay > 0 && firstconnect) 85068693Seric { 85168693Seric if (tTd(16, 1)) 85268693Seric printf("Connect failed (%s); trying again...\n", 85368693Seric errstring(sav_errno)); 85468693Seric firstconnect = FALSE; 85568693Seric sleep(DialDelay); 85668693Seric continue; 85768693Seric } 85868693Seric 85957736Seric /* couldn't connect.... figure out why */ 86027744Sbloom sav_errno = errno; 86127744Sbloom (void) close(s); 86268693Seric if (hp != NULL && hp->h_addr_list[i]) 86329430Sbloom { 86457736Seric if (tTd(16, 1)) 86558755Seric printf("Connect failed (%s); trying new address....\n", 86658755Seric errstring(sav_errno)); 86758778Seric switch (addr.sa.sa_family) 86858778Seric { 86958778Seric #ifdef NETINET 87058778Seric case AF_INET: 87158755Seric bcopy(hp->h_addr_list[i++], 87258778Seric &addr.sin.sin_addr, 87368693Seric INADDRSZ); 87458778Seric break; 87558778Seric #endif 87658778Seric 87758778Seric default: 87858755Seric bcopy(hp->h_addr_list[i++], 87958778Seric addr.sa.sa_data, 88052106Seric hp->h_length); 88158778Seric break; 88258778Seric } 88357736Seric continue; 88429430Sbloom } 88529430Sbloom 8866039Seric /* failure, decide if temporary or not */ 8876039Seric failure: 88859254Seric #ifdef XLA 88959254Seric xla_host_end(host); 89059254Seric #endif 89158542Seric if (transienterror(sav_errno)) 89258542Seric return EX_TEMPFAIL; 89358542Seric else 89458542Seric { 89558542Seric message("%s", errstring(sav_errno)); 89658542Seric return (EX_UNAVAILABLE); 8976039Seric } 8986039Seric } 8996039Seric 9006039Seric /* connection ok, put it into canonical form */ 90164724Seric if ((mci->mci_out = fdopen(s, "w")) == NULL || 90264724Seric (s = dup(s)) < 0 || 90364725Seric (mci->mci_in = fdopen(s, "r")) == NULL) 90464724Seric { 90564724Seric syserr("cannot open SMTP client channel, fd=%d", s); 90664724Seric return EX_TEMPFAIL; 90764724Seric } 9086039Seric 90910098Seric return (EX_OK); 9106039Seric } 91110758Seric /* 91210758Seric ** MYHOSTNAME -- return the name of this host. 91310758Seric ** 91410758Seric ** Parameters: 91510758Seric ** hostbuf -- a place to return the name of this host. 91612313Seric ** size -- the size of hostbuf. 91710758Seric ** 91810758Seric ** Returns: 91910758Seric ** A list of aliases for this host. 92010758Seric ** 92110758Seric ** Side Effects: 92264338Seric ** Adds numeric codes to $=w. 92310758Seric */ 9246039Seric 92568693Seric struct hostent * 92612313Seric myhostname(hostbuf, size) 92710758Seric char hostbuf[]; 92812313Seric int size; 92910758Seric { 93058110Seric register struct hostent *hp; 93168693Seric extern bool getcanonname(); 93268693Seric extern int h_errno; 93310758Seric 93423120Seric if (gethostname(hostbuf, size) < 0) 93523120Seric { 93623120Seric (void) strcpy(hostbuf, "localhost"); 93723120Seric } 93868693Seric hp = sm_gethostbyname(hostbuf); 93966853Seric if (hp == NULL) 94068693Seric return NULL; 94168693Seric if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 94267448Seric { 94368693Seric (void) strncpy(hostbuf, hp->h_name, size - 1); 94468693Seric hostbuf[size - 1] = '\0'; 94567448Seric } 94666853Seric 94766853Seric #if NAMED_BIND 94868693Seric /* 94968693Seric ** If still no dot, try DNS directly (i.e., avoid NIS problems). 95068693Seric ** This ought to be driven from the configuration file, but 95168693Seric ** we are called before the configuration is read. We could 95268693Seric ** check for an /etc/resolv.conf file, but that isn't required. 95368693Seric ** All in all, a bit of a mess. 95468693Seric */ 95568693Seric 956*69818Seric if (strchr(hostbuf, '.') == NULL) 95768612Seric { 958*69818Seric int nmaps; 959*69818Seric int i; 960*69818Seric char *maptype[MAXMAPSTACK]; 961*69818Seric short mapreturn[MAXMAPACTIONS]; 962*69818Seric 963*69818Seric nmaps = switch_map_find("hosts", maptype, mapreturn); 964*69818Seric for (i = 0; i < nmaps; i++) 965*69818Seric if (strcmp(maptype[i], "dns") == 0) 966*69818Seric break; 967*69818Seric if (i < nmaps && 968*69818Seric !dns_getcanonname(hostbuf, size, TRUE) && 969*69818Seric h_errno == TRY_AGAIN) 970*69818Seric { 971*69818Seric /* try twice in case name server not yet started up */ 972*69818Seric message("My unqualifed host name (%s) unknown to DNS; sleeping for retry", 973*69818Seric hostbuf); 974*69818Seric sleep(60); 975*69818Seric if (!dns_getcanonname(hostbuf, size, TRUE)) 976*69818Seric errno = h_errno + E_DNSBASE; 977*69818Seric } 97866853Seric } 97966777Seric #endif 98068693Seric return (hp); 98110758Seric } 98251315Seric /* 98358951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 98458308Seric ** 98558951Seric ** Uses RFC1413 protocol to try to get info from the other end. 98658951Seric ** 98758308Seric ** Parameters: 98858308Seric ** fd -- the descriptor 98958308Seric ** 99058308Seric ** Returns: 99158951Seric ** The user@host information associated with this descriptor. 99258308Seric */ 99358308Seric 99458951Seric static jmp_buf CtxAuthTimeout; 99558951Seric 99668693Seric static void 99758951Seric authtimeout() 99858951Seric { 99958951Seric longjmp(CtxAuthTimeout, 1); 100058951Seric } 100158951Seric 100258308Seric char * 100358951Seric getauthinfo(fd) 100458308Seric int fd; 100558308Seric { 100658951Seric int falen; 100759104Seric register char *p; 100858951Seric SOCKADDR la; 100958951Seric int lalen; 101058951Seric register struct servent *sp; 101158951Seric int s; 101258951Seric int i; 101358951Seric EVENT *ev; 101468444Seric int nleft; 101568462Seric char ibuf[MAXNAME + 1]; 101658951Seric static char hbuf[MAXNAME * 2 + 2]; 101758951Seric extern char *hostnamebyanyaddr(); 101858308Seric 101966761Seric falen = sizeof RealHostAddr; 102068693Seric if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 || 102168693Seric falen <= 0 || RealHostAddr.sa.sa_family == 0) 102258951Seric { 102358951Seric (void) sprintf(hbuf, "%s@localhost", RealUserName); 102458957Seric if (tTd(9, 1)) 102558951Seric printf("getauthinfo: %s\n", hbuf); 102658951Seric return hbuf; 102758951Seric } 102858951Seric 102966761Seric if (RealHostName == NULL) 103066761Seric { 103166761Seric /* translate that to a host name */ 103266761Seric RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 103366761Seric } 103466761Seric 103565831Seric if (TimeOuts.to_ident == 0) 103665831Seric goto noident; 103765831Seric 103858951Seric lalen = sizeof la; 103966761Seric if (RealHostAddr.sa.sa_family != AF_INET || 104058951Seric getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 104158951Seric la.sa.sa_family != AF_INET) 104258951Seric { 104358951Seric /* no ident info */ 104458951Seric goto noident; 104558951Seric } 104658951Seric 104758951Seric /* create ident query */ 104868457Seric (void) sprintf(ibuf, "%d,%d\r\n", 104966761Seric ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port)); 105058951Seric 105158951Seric /* create local address */ 105264747Seric la.sin.sin_port = 0; 105358951Seric 105458951Seric /* create foreign address */ 105558951Seric sp = getservbyname("auth", "tcp"); 105658951Seric if (sp != NULL) 105766761Seric RealHostAddr.sin.sin_port = sp->s_port; 105858308Seric else 105966761Seric RealHostAddr.sin.sin_port = htons(113); 106058951Seric 106158951Seric s = -1; 106258951Seric if (setjmp(CtxAuthTimeout) != 0) 106358951Seric { 106458951Seric if (s >= 0) 106558951Seric (void) close(s); 106658951Seric goto noident; 106758951Seric } 106858951Seric 106958951Seric /* put a timeout around the whole thing */ 107064255Seric ev = setevent(TimeOuts.to_ident, authtimeout, 0); 107158951Seric 107264747Seric /* connect to foreign IDENT server using same address as SMTP socket */ 107358951Seric s = socket(AF_INET, SOCK_STREAM, 0); 107458951Seric if (s < 0) 107558951Seric { 107658951Seric clrevent(ev); 107758951Seric goto noident; 107858951Seric } 107964747Seric if (bind(s, &la.sa, sizeof la.sin) < 0 || 108066761Seric connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0) 108158951Seric { 108266011Seric goto closeident; 108358951Seric } 108458951Seric 108558957Seric if (tTd(9, 10)) 108668457Seric printf("getauthinfo: sent %s", ibuf); 108758951Seric 108858951Seric /* send query */ 108968457Seric if (write(s, ibuf, strlen(ibuf)) < 0) 109058951Seric goto closeident; 109158951Seric 109258951Seric /* get result */ 109368457Seric p = &ibuf[0]; 109468525Seric nleft = sizeof ibuf - 1; 109568444Seric while ((i = read(s, p, nleft)) > 0) 109668444Seric { 109768444Seric p += i; 109868444Seric nleft -= i; 109968444Seric } 110058951Seric (void) close(s); 110158951Seric clrevent(ev); 110268457Seric if (i < 0 || p == &ibuf[0]) 110358951Seric goto noident; 110458951Seric 110568444Seric if (*--p == '\n' && *--p == '\r') 110668444Seric p--; 110768444Seric *++p = '\0'; 110868444Seric 110958957Seric if (tTd(9, 3)) 111068457Seric printf("getauthinfo: got %s\n", ibuf); 111158951Seric 111258951Seric /* parse result */ 111368457Seric p = strchr(ibuf, ':'); 111458951Seric if (p == NULL) 111558951Seric { 111658951Seric /* malformed response */ 111758951Seric goto noident; 111858951Seric } 111958951Seric while (isascii(*++p) && isspace(*p)) 112058951Seric continue; 112158951Seric if (strncasecmp(p, "userid", 6) != 0) 112258951Seric { 112358951Seric /* presumably an error string */ 112458951Seric goto noident; 112558951Seric } 112658951Seric p += 6; 112758951Seric while (isascii(*p) && isspace(*p)) 112858951Seric p++; 112958951Seric if (*p++ != ':') 113058951Seric { 113158951Seric /* either useridxx or malformed response */ 113258951Seric goto noident; 113358951Seric } 113458951Seric 113558951Seric /* p now points to the OSTYPE field */ 113668693Seric while (isascii(*p) && isspace(*p)) 113768693Seric p++; 113868693Seric if (strncasecmp(p, "other", 5) == 0 && 113968693Seric (p[5] == ':' || p[5] == ' ' || p[5] == ',' || p[5] == '\0')) 114068693Seric { 114168693Seric /* not useful information */ 114268693Seric goto noident; 114368693Seric } 114458951Seric p = strchr(p, ':'); 114558951Seric if (p == NULL) 114658951Seric { 114758951Seric /* malformed response */ 114858951Seric goto noident; 114958951Seric } 115058951Seric 115158957Seric /* 1413 says don't do this -- but it's broken otherwise */ 115258957Seric while (isascii(*++p) && isspace(*p)) 115358957Seric continue; 115458957Seric 115567935Seric /* p now points to the authenticated name -- copy carefully */ 115668457Seric cleanstrcpy(hbuf, p, MAXNAME); 115768875Seric i = strlen(hbuf); 115867935Seric hbuf[i++] = '@'; 115967935Seric strcpy(&hbuf[i], RealHostName == NULL ? "localhost" : RealHostName); 116069601Seric goto postident; 116158957Seric 116266011Seric closeident: 116366011Seric (void) close(s); 116466011Seric clrevent(ev); 116566011Seric 116658957Seric noident: 116766003Seric if (RealHostName == NULL) 116866003Seric { 116966003Seric if (tTd(9, 1)) 117066003Seric printf("getauthinfo: NULL\n"); 117166003Seric return NULL; 117266003Seric } 117358957Seric (void) strcpy(hbuf, RealHostName); 117458957Seric 117569601Seric postident: 117669601Seric #if IP_SRCROUTE 117769601Seric /* 117869601Seric ** Extract IP source routing information. 117969601Seric ** 118069601Seric ** Format of output for a connection from site a through b 118169601Seric ** through c to d: 118269601Seric ** loose: @site-c@site-b:site-a 118369601Seric ** strict: !@site-c@site-b:site-a 118469601Seric ** 118569601Seric ** o - pointer within ipopt_list structure. 118669601Seric ** q - pointer within ls/ss rr route data 118769601Seric ** p - pointer to hbuf 118869601Seric */ 118969601Seric 119069601Seric if (RealHostAddr.sa.sa_family == AF_INET) 119169601Seric { 119269601Seric int ipoptlen, j; 119369637Seric u_char *q; 119469601Seric u_char *o; 119569601Seric struct in_addr addr; 119669601Seric struct ipoption ipopt; 119769601Seric 119869601Seric ipoptlen = sizeof ipopt; 119969601Seric if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS, 120069601Seric (char *) &ipopt, &ipoptlen) < 0) 120169601Seric goto noipsr; 120269601Seric if (ipoptlen == 0) 120369601Seric goto noipsr; 120469637Seric o = (u_char *) ipopt.ipopt_list; 120569731Seric while (o != NULL && o < (u_char *) &ipopt + ipoptlen) 120669601Seric { 120769601Seric switch (*o) 120869601Seric { 120969601Seric case IPOPT_EOL: 121069601Seric o = NULL; 121169601Seric break; 121269601Seric 121369601Seric case IPOPT_NOP: 121469601Seric o++; 121569601Seric break; 121669601Seric 121769601Seric case IPOPT_SSRR: 121869601Seric case IPOPT_LSRR: 121969601Seric p = &hbuf[strlen(hbuf)]; 122069601Seric sprintf(p, " [%s@%s", 122169601Seric *o == IPOPT_SSRR ? "!" : "", 122269601Seric inet_ntoa(ipopt.ipopt_dst)); 122369601Seric p += strlen(p); 122469601Seric 122569601Seric /* o[1] is option length */ 122669601Seric j = *++o / sizeof(struct in_addr) - 1; 122769601Seric 122869601Seric /* q skips length and router pointer to data */ 122969601Seric q = o + 2; 123069601Seric for ( ; j >= 0; j--) 123169601Seric { 123269601Seric memcpy(&addr, q, sizeof(addr)); 123369637Seric sprintf(p, "%c%s", 123469601Seric j ? '@' : ':', 123569601Seric inet_ntoa(addr)); 123669637Seric p += strlen(p); 123769637Seric q += sizeof(struct in_addr); 123869601Seric } 123969601Seric o += *o; 124069601Seric break; 124169601Seric 124269601Seric default: 124369601Seric /* Skip over option */ 124469601Seric o += o[1]; 124569601Seric break; 124669601Seric } 124769601Seric } 124869601Seric strcat(hbuf,"]"); 124969601Seric goto postipsr; 125069601Seric } 125169601Seric #endif 125269601Seric 125369601Seric noipsr: 125466003Seric if (RealHostName != NULL && RealHostName[0] != '[') 125558951Seric { 125658951Seric p = &hbuf[strlen(hbuf)]; 125758951Seric (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 125858951Seric } 125969601Seric 126069601Seric postipsr: 126158957Seric if (tTd(9, 1)) 126258951Seric printf("getauthinfo: %s\n", hbuf); 126358308Seric return hbuf; 126458308Seric } 126558308Seric /* 126660089Seric ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 126753751Seric ** 126853751Seric ** Parameters: 126956823Seric ** map -- a pointer to this map (unused). 127060089Seric ** name -- the (presumably unqualified) hostname. 127160257Seric ** av -- unused -- for compatibility with other mapping 127255019Seric ** functions. 127359084Seric ** statp -- an exit status (out parameter) -- set to 127459084Seric ** EX_TEMPFAIL if the name server is unavailable. 127553751Seric ** 127653751Seric ** Returns: 127753751Seric ** The mapping, if found. 127853751Seric ** NULL if no mapping found. 127953751Seric ** 128053751Seric ** Side Effects: 128153751Seric ** Looks up the host specified in hbuf. If it is not 128253751Seric ** the canonical name for that host, return the canonical 128353751Seric ** name. 128453751Seric */ 128551315Seric 128653751Seric char * 128760257Seric host_map_lookup(map, name, av, statp) 128856823Seric MAP *map; 128960089Seric char *name; 129060257Seric char **av; 129159084Seric int *statp; 129216911Seric { 129316911Seric register struct hostent *hp; 129468693Seric struct in_addr in_addr; 129556823Seric char *cp; 129659671Seric register STAB *s; 129768693Seric char hbuf[MAXNAME + 1]; 129866334Seric #if NAMED_BIND 129959671Seric extern int h_errno; 130066029Seric #endif 130116911Seric 130225574Smiriam /* 130359671Seric ** See if we have already looked up this name. If so, just 130459671Seric ** return it. 130559671Seric */ 130653751Seric 130760089Seric s = stab(name, ST_NAMECANON, ST_ENTER); 130859671Seric if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 130959671Seric { 131059986Seric if (tTd(9, 1)) 131160089Seric printf("host_map_lookup(%s) => CACHE %s\n", 131269511Seric name, 131369511Seric s->s_namecanon.nc_cname == NULL 131469511Seric ? "NULL" 131569512Seric : s->s_namecanon.nc_cname); 131659671Seric errno = s->s_namecanon.nc_errno; 131766334Seric #if NAMED_BIND 131859671Seric h_errno = s->s_namecanon.nc_herrno; 131966029Seric #endif 132059671Seric *statp = s->s_namecanon.nc_stat; 132168817Seric if (*statp == EX_TEMPFAIL) 132265199Seric { 132368857Seric CurEnv->e_status = "4.4.3"; 132468817Seric usrerr("451 %s: Name server timeout", 132565199Seric shortenstring(name, 33)); 132665199Seric } 132759671Seric return s->s_namecanon.nc_cname; 132859671Seric } 132959671Seric 133059671Seric /* 133159671Seric ** If first character is a bracket, then it is an address 133259671Seric ** lookup. Address is copied into a temporary buffer to 133360089Seric ** strip the brackets and to preserve name if address is 133459671Seric ** unknown. 133559671Seric */ 133659671Seric 133760089Seric if (*name != '[') 133853751Seric { 133955019Seric extern bool getcanonname(); 134055019Seric 134158798Seric if (tTd(9, 1)) 134260089Seric printf("host_map_lookup(%s) => ", name); 134359671Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 134468693Seric if (strlen(name) < sizeof hbuf) 134568693Seric (void) strcpy(hbuf, name); 134668693Seric else 134768693Seric { 134868693Seric bcopy(name, hbuf, sizeof hbuf - 1); 134968693Seric hbuf[sizeof hbuf - 1] = '\0'; 135068693Seric } 135168759Seric if (getcanonname(hbuf, sizeof hbuf - 1, !NoMXforCanon)) 135258796Seric { 135358796Seric if (tTd(9, 1)) 135458796Seric printf("%s\n", hbuf); 135560257Seric cp = map_rewrite(map, hbuf, strlen(hbuf), av); 135660257Seric s->s_namecanon.nc_cname = newstr(cp); 135760257Seric return cp; 135858796Seric } 135953751Seric else 136058796Seric { 136159084Seric register struct hostent *hp; 136259084Seric 136366029Seric s->s_namecanon.nc_errno = errno; 136466334Seric #if NAMED_BIND 136566029Seric s->s_namecanon.nc_herrno = h_errno; 136658796Seric if (tTd(9, 1)) 136759084Seric printf("FAIL (%d)\n", h_errno); 136859084Seric switch (h_errno) 136959084Seric { 137059084Seric case TRY_AGAIN: 137159596Seric if (UseNameServer) 137259734Seric { 137368857Seric CurEnv->e_status = "4.4.3"; 137468817Seric usrerr("451 %s: Name server timeout", 137565199Seric shortenstring(name, 33)); 137659734Seric } 137759084Seric *statp = EX_TEMPFAIL; 137859084Seric break; 137959084Seric 138059084Seric case HOST_NOT_FOUND: 138168881Seric case NO_DATA: 138259084Seric *statp = EX_NOHOST; 138359084Seric break; 138459084Seric 138559084Seric case NO_RECOVERY: 138659084Seric *statp = EX_SOFTWARE; 138759084Seric break; 138859084Seric 138959084Seric default: 139059084Seric *statp = EX_UNAVAILABLE; 139159084Seric break; 139259084Seric } 139366029Seric #else 139466029Seric if (tTd(9, 1)) 139566029Seric printf("FAIL\n"); 139666029Seric *statp = EX_NOHOST; 139766029Seric #endif 139859671Seric s->s_namecanon.nc_stat = *statp; 139968693Seric if ((*statp != EX_TEMPFAIL && *statp != EX_NOHOST) || 140068693Seric UseNameServer) 140159084Seric return NULL; 140259084Seric 140359084Seric /* 140459084Seric ** Try to look it up in /etc/hosts 140559084Seric */ 140659084Seric 140768693Seric hp = sm_gethostbyname(name); 140859084Seric if (hp == NULL) 140959084Seric { 141059084Seric /* no dice there either */ 141159671Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 141259084Seric return NULL; 141359084Seric } 141459084Seric 141559671Seric s->s_namecanon.nc_stat = *statp = EX_OK; 141660257Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 141760257Seric s->s_namecanon.nc_cname = newstr(cp); 141860257Seric return cp; 141958796Seric } 142053751Seric } 142160089Seric if ((cp = strchr(name, ']')) == NULL) 142253751Seric return (NULL); 142340994Sbostic *cp = '\0'; 142468693Seric in_addr.s_addr = inet_addr(&name[1]); 142558110Seric 142658110Seric /* nope -- ask the name server */ 142768693Seric hp = sm_gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET); 142859671Seric s->s_namecanon.nc_errno = errno; 142966334Seric #if NAMED_BIND 143059671Seric s->s_namecanon.nc_herrno = h_errno; 143166029Seric #endif 143259671Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 143333932Sbostic if (hp == NULL) 143459671Seric { 143559671Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 143653751Seric return (NULL); 143759671Seric } 143853751Seric 143958110Seric /* found a match -- copy out */ 144060257Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 144159671Seric s->s_namecanon.nc_stat = *statp = EX_OK; 144260257Seric s->s_namecanon.nc_cname = newstr(cp); 144360257Seric return cp; 144433932Sbostic } 144558755Seric /* 144658755Seric ** ANYNET_NTOA -- convert a network address to printable form. 144758755Seric ** 144858755Seric ** Parameters: 144958755Seric ** sap -- a pointer to a sockaddr structure. 145058755Seric ** 145158755Seric ** Returns: 145258755Seric ** A printable version of that sockaddr. 145358755Seric */ 145416911Seric 145569562Seric #ifdef NETLINK 145669516Seric # include <net/if_dl.h> 145769516Seric #endif 145869516Seric 145958755Seric char * 146058755Seric anynet_ntoa(sap) 146158755Seric register SOCKADDR *sap; 146258755Seric { 146358755Seric register char *bp; 146458755Seric register char *ap; 146558755Seric int l; 146664734Seric static char buf[100]; 146758755Seric 146858798Seric /* check for null/zero family */ 146958798Seric if (sap == NULL) 147058798Seric return "NULLADDR"; 147158798Seric if (sap->sa.sa_family == 0) 147258798Seric return "0"; 147358798Seric 147464734Seric switch (sap->sa.sa_family) 147564734Seric { 147664821Seric #ifdef NETUNIX 147764734Seric case AF_UNIX: 147864758Seric if (sap->sunix.sun_path[0] != '\0') 147964758Seric sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 148064734Seric else 148164734Seric sprintf(buf, "[UNIX: localhost]"); 148264734Seric return buf; 148364734Seric #endif 148464734Seric 148558778Seric #ifdef NETINET 148664734Seric case AF_INET: 148768776Seric return inet_ntoa(sap->sin.sin_addr); 148858778Seric #endif 148958755Seric 149069562Seric #ifdef NETLINK 149169516Seric case AF_LINK: 149269516Seric sprintf(buf, "[LINK: %s]", 149369516Seric link_ntoa((struct sockaddr_dl *) &sap->sa)); 149469516Seric return buf; 149569516Seric #endif 149664734Seric default: 149769516Seric /* this case is needed when nothing is #defined */ 149869516Seric /* in order to keep the switch syntactically correct */ 149969516Seric break; 150064734Seric } 150164734Seric 150258755Seric /* unknown family -- just dump bytes */ 150358778Seric (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 150458755Seric bp = &buf[strlen(buf)]; 150558778Seric ap = sap->sa.sa_data; 150658778Seric for (l = sizeof sap->sa.sa_data; --l >= 0; ) 150758755Seric { 150858755Seric (void) sprintf(bp, "%02x:", *ap++ & 0377); 150958755Seric bp += 3; 151058755Seric } 151158755Seric *--bp = '\0'; 151258755Seric return buf; 151358755Seric } 151458951Seric /* 151558951Seric ** HOSTNAMEBYANYADDR -- return name of host based on address 151658951Seric ** 151758951Seric ** Parameters: 151858951Seric ** sap -- SOCKADDR pointer 151958951Seric ** 152058951Seric ** Returns: 152158951Seric ** text representation of host name. 152258951Seric ** 152358951Seric ** Side Effects: 152458951Seric ** none. 152558951Seric */ 152658755Seric 152758951Seric char * 152858951Seric hostnamebyanyaddr(sap) 152958951Seric register SOCKADDR *sap; 153058951Seric { 153158951Seric register struct hostent *hp; 153264734Seric int saveretry; 153358951Seric 153466334Seric #if NAMED_BIND 153559042Seric /* shorten name server timeout to avoid higher level timeouts */ 153659042Seric saveretry = _res.retry; 153759042Seric _res.retry = 3; 153859042Seric #endif /* NAMED_BIND */ 153959042Seric 154058951Seric switch (sap->sa.sa_family) 154158951Seric { 154258951Seric #ifdef NETINET 154358951Seric case AF_INET: 154468693Seric hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr, 154568693Seric INADDRSZ, 154658951Seric AF_INET); 154758951Seric break; 154858951Seric #endif 154958951Seric 155058951Seric #ifdef NETISO 155158951Seric case AF_ISO: 155268693Seric hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr, 155358951Seric sizeof sap->siso.siso_addr, 155458951Seric AF_ISO); 155558951Seric break; 155658951Seric #endif 155758951Seric 155864734Seric case AF_UNIX: 155964734Seric hp = NULL; 156064734Seric break; 156164734Seric 156258951Seric default: 156368693Seric hp = sm_gethostbyaddr(sap->sa.sa_data, 156458951Seric sizeof sap->sa.sa_data, 156558951Seric sap->sa.sa_family); 156658951Seric break; 156758951Seric } 156858951Seric 156966334Seric #if NAMED_BIND 157059042Seric _res.retry = saveretry; 157159042Seric #endif /* NAMED_BIND */ 157259042Seric 157358951Seric if (hp != NULL) 157458951Seric return hp->h_name; 157558951Seric else 157658951Seric { 157758951Seric /* produce a dotted quad */ 157858951Seric static char buf[512]; 157958951Seric 158058951Seric (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 158158951Seric return buf; 158258951Seric } 158358951Seric } 158458951Seric 158556795Seric # else /* DAEMON */ 158616911Seric /* code for systems without sophisticated networking */ 158710758Seric 158810758Seric /* 158910758Seric ** MYHOSTNAME -- stub version for case of no daemon code. 159011297Seric ** 159111297Seric ** Can't convert to upper case here because might be a UUCP name. 159212313Seric ** 159312313Seric ** Mark, you can change this to be anything you want...... 159410758Seric */ 159510758Seric 159610758Seric char ** 159712313Seric myhostname(hostbuf, size) 159810758Seric char hostbuf[]; 159912313Seric int size; 160010758Seric { 160110758Seric register FILE *f; 160210758Seric 160310758Seric hostbuf[0] = '\0'; 160410758Seric f = fopen("/usr/include/whoami", "r"); 160510758Seric if (f != NULL) 160610758Seric { 160712313Seric (void) fgets(hostbuf, size, f); 160810758Seric fixcrlf(hostbuf, TRUE); 160910758Seric (void) fclose(f); 161010758Seric } 161110758Seric return (NULL); 161210758Seric } 161316911Seric /* 161458951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 161558308Seric ** 161658308Seric ** Parameters: 161758308Seric ** fd -- the descriptor 161858308Seric ** 161958308Seric ** Returns: 162058308Seric ** The host name associated with this descriptor, if it can 162158308Seric ** be determined. 162258308Seric ** NULL otherwise. 162358308Seric ** 162458308Seric ** Side Effects: 162558308Seric ** none 162658308Seric */ 162758308Seric 162858308Seric char * 162958951Seric getauthinfo(fd) 163058308Seric int fd; 163158308Seric { 163258308Seric return NULL; 163358308Seric } 163458308Seric /* 163516911Seric ** MAPHOSTNAME -- turn a hostname into canonical form 163616911Seric ** 163716911Seric ** Parameters: 163856823Seric ** map -- a pointer to the database map. 163960089Seric ** name -- a buffer containing a hostname. 164053751Seric ** avp -- a pointer to a (cf file defined) argument vector. 164159084Seric ** statp -- an exit status (out parameter). 164216911Seric ** 164316911Seric ** Returns: 164453751Seric ** mapped host name 164551315Seric ** FALSE otherwise. 164616911Seric ** 164716911Seric ** Side Effects: 164860089Seric ** Looks up the host specified in name. If it is not 164916911Seric ** the canonical name for that host, replace it with 165016911Seric ** the canonical name. If the name is unknown, or it 165116911Seric ** is already the canonical name, leave it unchanged. 165216911Seric */ 165310758Seric 165416911Seric /*ARGSUSED*/ 165553751Seric char * 165660089Seric host_map_lookup(map, name, avp, statp) 165756823Seric MAP *map; 165860089Seric char *name; 165953751Seric char **avp; 166059084Seric char *statp; 166116911Seric { 166259084Seric register struct hostent *hp; 166359084Seric 166468693Seric hp = sm_gethostbyname(name); 166559084Seric if (hp != NULL) 166659084Seric return hp->h_name; 166759084Seric *statp = EX_NOHOST; 166853751Seric return NULL; 166916911Seric } 167016911Seric 167156795Seric #endif /* DAEMON */ 1672