122700Sdist /* 234920Sbostic * Copyright (c) 1983 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*68444Seric static char sccsid[] = "@(#)daemon.c 8.70 (Berkeley) 02/24/95 (with daemon mode)"; 1533780Sbostic #else 16*68444Seric static char sccsid[] = "@(#)daemon.c 8.70 (Berkeley) 02/24/95 (without daemon mode)"; 1733780Sbostic #endif 1833780Sbostic #endif /* not lint */ 194535Seric 2033780Sbostic #ifdef DAEMON 2133780Sbostic 2223120Seric # include <netdb.h> 2364338Seric # include <arpa/inet.h> 245978Seric 2566334Seric #if NAMED_BIND 2659042Seric # include <resolv.h> 2759042Seric #endif 2859042Seric 294535Seric /* 304535Seric ** DAEMON.C -- routines to use when running as a daemon. 317556Seric ** 327556Seric ** This entire file is highly dependent on the 4.2 BSD 337556Seric ** interprocess communication primitives. No attempt has 347556Seric ** been made to make this file portable to Version 7, 357556Seric ** Version 6, MPX files, etc. If you should try such a 367556Seric ** thing yourself, I recommend chucking the entire file 377556Seric ** and starting from scratch. Basic semantics are: 387556Seric ** 397556Seric ** getrequests() 407556Seric ** Opens a port and initiates a connection. 417556Seric ** Returns in a child. Must set InChannel and 427556Seric ** OutChannel appropriately. 4310206Seric ** clrdaemon() 4410206Seric ** Close any open files associated with getting 4510206Seric ** the connection; this is used when running the queue, 4610206Seric ** etc., to avoid having extra file descriptors during 4710206Seric ** the queue run and to avoid confusing the network 4810206Seric ** code (if it cares). 4952106Seric ** makeconnection(host, port, outfile, infile, usesecureport) 507556Seric ** Make a connection to the named host on the given 517556Seric ** port. Set *outfile and *infile to the files 527556Seric ** appropriate for communication. Returns zero on 537556Seric ** success, else an exit status describing the 547556Seric ** error. 5560089Seric ** host_map_lookup(map, hbuf, avp, pstat) 5656823Seric ** Convert the entry in hbuf into a canonical form. 574535Seric */ 584535Seric /* 594535Seric ** GETREQUESTS -- open mail IPC port and get requests. 604535Seric ** 614535Seric ** Parameters: 624535Seric ** none. 634535Seric ** 644535Seric ** Returns: 654535Seric ** none. 664535Seric ** 674535Seric ** Side Effects: 684535Seric ** Waits until some interesting activity occurs. When 694535Seric ** it does, a child is created to process it, and the 704535Seric ** parent waits for completion. Return from this 719886Seric ** routine is always in the child. The file pointers 729886Seric ** "InChannel" and "OutChannel" should be set to point 739886Seric ** to the communication channel. 744535Seric */ 754535Seric 7658849Seric int DaemonSocket = -1; /* fd describing socket */ 7758849Seric SOCKADDR DaemonAddr; /* socket for incoming */ 7859783Seric int ListenQueueSize = 10; /* size of listen queue */ 7964381Seric int TcpRcvBufferSize = 0; /* size of TCP receive buffer */ 8064381Seric int TcpSndBufferSize = 0; /* size of TCP send buffer */ 8116144Seric 8268433Seric void 834535Seric getrequests() 844535Seric { 859610Seric int t; 8653751Seric bool refusingconnections = TRUE; 8758419Seric FILE *pidf; 8864828Seric int socksize; 8966793Seric #ifdef XDEBUG 9066793Seric bool j_has_dot; 9166793Seric #endif 9246928Sbostic extern void reapchild(); 937117Seric 949610Seric /* 959610Seric ** Set up the address for the mailer. 969610Seric */ 979610Seric 9858849Seric if (DaemonAddr.sin.sin_family == 0) 9958849Seric DaemonAddr.sin.sin_family = AF_INET; 10058849Seric if (DaemonAddr.sin.sin_addr.s_addr == 0) 10158849Seric DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY; 10258849Seric if (DaemonAddr.sin.sin_port == 0) 1039610Seric { 10465169Seric register struct servent *sp; 10565169Seric 10658849Seric sp = getservbyname("smtp", "tcp"); 10758849Seric if (sp == NULL) 10858849Seric { 10958909Seric syserr("554 service \"smtp\" unknown"); 11065169Seric DaemonAddr.sin.sin_port = htons(25); 11158849Seric } 11265169Seric else 11365169Seric DaemonAddr.sin.sin_port = sp->s_port; 1149610Seric } 1159610Seric 1169610Seric /* 1179610Seric ** Try to actually open the connection. 1189610Seric */ 1199610Seric 1209610Seric if (tTd(15, 1)) 12158849Seric printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port); 1229610Seric 1239610Seric /* get a socket for the SMTP connection */ 12466854Seric socksize = opendaemonsocket(TRUE); 12510347Seric 12664035Seric (void) setsignal(SIGCHLD, reapchild); 12724945Seric 12858419Seric /* write the pid to the log file for posterity */ 12958419Seric pidf = fopen(PidFile, "w"); 13058419Seric if (pidf != NULL) 13158419Seric { 13263863Seric extern char *CommandLineArgs; 13363863Seric 13463863Seric /* write the process id on line 1 */ 13558419Seric fprintf(pidf, "%d\n", getpid()); 13663863Seric 13763863Seric /* line 2 contains all command line flags */ 13863863Seric fprintf(pidf, "%s\n", CommandLineArgs); 13963863Seric 14063863Seric /* flush and close */ 14158419Seric fclose(pidf); 14258419Seric } 14358419Seric 14466793Seric #ifdef XDEBUG 14566793Seric { 14666812Seric char jbuf[MAXHOSTNAMELEN]; 14758419Seric 14866812Seric expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv); 14966812Seric j_has_dot = strchr(jbuf, '.') != NULL; 15066793Seric } 15166793Seric #endif 15266793Seric 1539610Seric if (tTd(15, 1)) 15410206Seric printf("getrequests: %d\n", DaemonSocket); 1559610Seric 1564631Seric for (;;) 1574631Seric { 15814875Seric register int pid; 15911147Seric auto int lotherend; 16053751Seric extern bool refuseconnections(); 16168433Seric extern int getla(); 16211147Seric 16314875Seric /* see if we are rejecting connections */ 16453751Seric CurrentLA = getla(); 16553751Seric if (refuseconnections()) 16636584Sbostic { 16766845Seric if (DaemonSocket >= 0) 16853751Seric { 16966845Seric /* close socket so peer will fail quickly */ 17066845Seric (void) close(DaemonSocket); 17166845Seric DaemonSocket = -1; 17253751Seric } 17366845Seric refusingconnections = TRUE; 17457385Seric setproctitle("rejecting connections: load average: %d", 17557385Seric CurrentLA); 17666845Seric sleep(15); 17753751Seric continue; 17836584Sbostic } 17914875Seric 18068433Seric /* arrange to (re)open the socket if necessary */ 18153751Seric if (refusingconnections) 18253751Seric { 18367690Seric (void) opendaemonsocket(FALSE); 18453751Seric setproctitle("accepting connections"); 18553751Seric refusingconnections = FALSE; 18653751Seric } 18753751Seric 18866793Seric #ifdef XDEBUG 18966793Seric /* check for disaster */ 19066793Seric { 19166812Seric char jbuf[MAXHOSTNAMELEN]; 19266793Seric 19366812Seric expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv); 19468433Seric if (!wordinclass(jbuf, 'w')) 19566793Seric { 19666793Seric dumpstate("daemon lost $j"); 19766793Seric syslog(LOG_ALERT, "daemon process doesn't have $j in $=w; see syslog"); 19866793Seric abort(); 19966793Seric } 20066812Seric else if (j_has_dot && strchr(jbuf, '.') == NULL) 20166793Seric { 20266793Seric dumpstate("daemon $j lost dot"); 20366793Seric syslog(LOG_ALERT, "daemon process $j lost dot; see syslog"); 20466793Seric abort(); 20566793Seric } 20666793Seric } 20766793Seric #endif 20866793Seric 2099610Seric /* wait for a connection */ 2109610Seric do 2119610Seric { 2129610Seric errno = 0; 21364828Seric lotherend = socksize; 21446928Sbostic t = accept(DaemonSocket, 21546928Sbostic (struct sockaddr *)&RealHostAddr, &lotherend); 2169610Seric } while (t < 0 && errno == EINTR); 2179610Seric if (t < 0) 2185978Seric { 2199610Seric syserr("getrequests: accept"); 22068433Seric 22168433Seric /* arrange to re-open the socket next time around */ 22268433Seric (void) close(DaemonSocket); 22368433Seric DaemonSocket = -1; 2249610Seric sleep(5); 2259610Seric continue; 2265978Seric } 2274631Seric 2285978Seric /* 2295978Seric ** Create a subprocess to process the mail. 2305978Seric */ 2315978Seric 2327677Seric if (tTd(15, 2)) 2339610Seric printf("getrequests: forking (fd = %d)\n", t); 2345978Seric 2354636Seric pid = fork(); 2364636Seric if (pid < 0) 2374631Seric { 2384636Seric syserr("daemon: cannot fork"); 2394636Seric sleep(10); 2409610Seric (void) close(t); 2414636Seric continue; 2424631Seric } 2434631Seric 2444636Seric if (pid == 0) 2454631Seric { 24664086Seric char *p; 24758951Seric extern char *hostnamebyanyaddr(); 24868433Seric extern void intsig(); 24911147Seric 2504636Seric /* 2514636Seric ** CHILD -- return to caller. 25211147Seric ** Collect verified idea of sending host. 2534636Seric ** Verify calling user id if possible here. 2544636Seric */ 2554631Seric 25664035Seric (void) setsignal(SIGCHLD, SIG_DFL); 25768433Seric (void) setsignal(SIGHUP, intsig); 25868433Seric (void) close(DaemonSocket); 25966017Seric DisConnected = FALSE; 26024950Seric 26166032Seric setproctitle("startup with %s", 26266032Seric anynet_ntoa(&RealHostAddr)); 26366032Seric 26411147Seric /* determine host name */ 26564086Seric p = hostnamebyanyaddr(&RealHostAddr); 26664086Seric RealHostName = newstr(p); 26766032Seric setproctitle("startup with %s", p); 26858778Seric 26955173Seric #ifdef LOG 27063842Seric if (LogLevel > 11) 27155173Seric { 27255173Seric /* log connection information */ 27355173Seric syslog(LOG_INFO, "connect from %s (%s)", 27458951Seric RealHostName, anynet_ntoa(&RealHostAddr)); 27555173Seric } 27655173Seric #endif 27755173Seric 27864724Seric if ((InChannel = fdopen(t, "r")) == NULL || 27964724Seric (t = dup(t)) < 0 || 28064724Seric (OutChannel = fdopen(t, "w")) == NULL) 28164724Seric { 28264724Seric syserr("cannot open SMTP server channel, fd=%d", t); 28364724Seric exit(0); 28464724Seric } 28559254Seric 28616884Seric /* should we check for illegal connection here? XXX */ 28759156Seric #ifdef XLA 28859156Seric if (!xla_host_ok(RealHostName)) 28959156Seric { 29059254Seric message("421 Too many SMTP sessions for this host"); 29159156Seric exit(0); 29259156Seric } 29359156Seric #endif 29416884Seric 2957677Seric if (tTd(15, 2)) 2965978Seric printf("getreq: returning\n"); 2974636Seric return; 2984631Seric } 2994631Seric 3007117Seric /* close the port so that others will hang (for a while) */ 3019610Seric (void) close(t); 3024631Seric } 3039886Seric /*NOTREACHED*/ 3044631Seric } 3055978Seric /* 30666845Seric ** OPENDAEMONSOCKET -- open the SMTP socket 30766845Seric ** 30866845Seric ** Deals with setting all appropriate options. DaemonAddr must 30966845Seric ** be set up in advance. 31066845Seric ** 31166845Seric ** Parameters: 31266854Seric ** firsttime -- set if this is the initial open. 31366845Seric ** 31466845Seric ** Returns: 31566845Seric ** Size in bytes of the daemon socket addr. 31666845Seric ** 31766845Seric ** Side Effects: 31866845Seric ** Leaves DaemonSocket set to the open socket. 31966845Seric ** Exits if the socket cannot be created. 32066845Seric */ 32166845Seric 32266861Seric #define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 32366861Seric 32466845Seric int 32566854Seric opendaemonsocket(firsttime) 32666854Seric bool firsttime; 32766845Seric { 32866845Seric int on = 1; 32968433Seric int socksize = 0; 33066861Seric int ntries = 0; 33166861Seric int saveerrno; 33266845Seric 33366845Seric if (tTd(15, 2)) 33466845Seric printf("opendaemonsocket()\n"); 33566845Seric 33666861Seric do 33766845Seric { 33866862Seric if (ntries > 0) 33966862Seric sleep(5); 34066861Seric if (firsttime || DaemonSocket < 0) 34166854Seric { 34266861Seric DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0); 34366861Seric if (DaemonSocket < 0) 34466861Seric { 34566861Seric /* probably another daemon already */ 34666861Seric saveerrno = errno; 34766861Seric syserr("opendaemonsocket: can't create server SMTP socket"); 34866861Seric severe: 34966845Seric # ifdef LOG 35066861Seric if (LogLevel > 0) 35166861Seric syslog(LOG_ALERT, "problem creating SMTP socket"); 35266845Seric # endif /* LOG */ 35366861Seric DaemonSocket = -1; 35466861Seric continue; 35566861Seric } 35666845Seric 35766861Seric /* turn on network debugging? */ 35866861Seric if (tTd(15, 101)) 35966861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 36066861Seric SO_DEBUG, (char *)&on, 36166861Seric sizeof on); 36266845Seric 36366861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 36466861Seric SO_REUSEADDR, (char *)&on, sizeof on); 36566861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 36666861Seric SO_KEEPALIVE, (char *)&on, sizeof on); 36766845Seric 36866845Seric #ifdef SO_RCVBUF 36966861Seric if (TcpRcvBufferSize > 0) 37066861Seric { 37166861Seric if (setsockopt(DaemonSocket, SOL_SOCKET, 37266861Seric SO_RCVBUF, 37366861Seric (char *) &TcpRcvBufferSize, 37466861Seric sizeof(TcpRcvBufferSize)) < 0) 37566861Seric syserr("getrequests: setsockopt(SO_RCVBUF)"); 37666861Seric } 37766845Seric #endif 37866845Seric 37966861Seric switch (DaemonAddr.sa.sa_family) 38066861Seric { 38166845Seric # ifdef NETINET 38266861Seric case AF_INET: 38366861Seric socksize = sizeof DaemonAddr.sin; 38466861Seric break; 38566845Seric # endif 38666845Seric 38766845Seric # ifdef NETISO 38866861Seric case AF_ISO: 38966861Seric socksize = sizeof DaemonAddr.siso; 39066861Seric break; 39166845Seric # endif 39266845Seric 39366861Seric default: 39466861Seric socksize = sizeof DaemonAddr; 39566861Seric break; 39666861Seric } 39766861Seric 39866861Seric if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0) 39966861Seric { 40066861Seric saveerrno = errno; 40166861Seric syserr("getrequests: cannot bind"); 40266861Seric (void) close(DaemonSocket); 40366861Seric goto severe; 40466861Seric } 40566854Seric } 40666861Seric if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0) 40766854Seric { 40866861Seric saveerrno = errno; 40966861Seric syserr("getrequests: cannot listen"); 41066854Seric (void) close(DaemonSocket); 41166854Seric goto severe; 41266854Seric } 41366861Seric return socksize; 41466861Seric } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno)); 41568433Seric syserr("!opendaemonsocket: server SMTP socket wedged: exiting"); 41666861Seric finis(); 41766845Seric } 41866845Seric /* 41910206Seric ** CLRDAEMON -- reset the daemon connection 42010206Seric ** 42110206Seric ** Parameters: 42210206Seric ** none. 42310206Seric ** 42410206Seric ** Returns: 42510206Seric ** none. 42610206Seric ** 42710206Seric ** Side Effects: 42810206Seric ** releases any resources used by the passive daemon. 42910206Seric */ 43010206Seric 43168433Seric void 43210206Seric clrdaemon() 43310206Seric { 43410206Seric if (DaemonSocket >= 0) 43510206Seric (void) close(DaemonSocket); 43610206Seric DaemonSocket = -1; 43710206Seric } 43810206Seric /* 43958849Seric ** SETDAEMONOPTIONS -- set options for running the daemon 44058849Seric ** 44158849Seric ** Parameters: 44258849Seric ** p -- the options line. 44358849Seric ** 44458849Seric ** Returns: 44558849Seric ** none. 44658849Seric */ 44758849Seric 44868433Seric void 44958849Seric setdaemonoptions(p) 45058849Seric register char *p; 45158849Seric { 45258873Seric if (DaemonAddr.sa.sa_family == AF_UNSPEC) 45358873Seric DaemonAddr.sa.sa_family = AF_INET; 45458873Seric 45558849Seric while (p != NULL) 45658849Seric { 45758849Seric register char *f; 45858849Seric register char *v; 45958849Seric 46058849Seric while (isascii(*p) && isspace(*p)) 46158849Seric p++; 46258849Seric if (*p == '\0') 46358849Seric break; 46458849Seric f = p; 46558849Seric p = strchr(p, ','); 46658849Seric if (p != NULL) 46758849Seric *p++ = '\0'; 46858849Seric v = strchr(f, '='); 46958849Seric if (v == NULL) 47058849Seric continue; 47158849Seric while (isascii(*++v) && isspace(*v)) 47258849Seric continue; 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)) 50568433Seric 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; 58558849Seric } 58658849Seric } 58758849Seric } 58858849Seric /* 5896039Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 5906039Seric ** 5916039Seric ** Parameters: 5926039Seric ** host -- the name of the host. 5936633Seric ** port -- the port number to connect to. 59453739Seric ** mci -- a pointer to the mail connection information 59553739Seric ** structure to be filled in. 59652106Seric ** usesecureport -- if set, use a low numbered (reserved) 59752106Seric ** port to provide some rudimentary authentication. 5986039Seric ** 5996039Seric ** Returns: 6006039Seric ** An exit code telling whether the connection could be 6016039Seric ** made and if not why not. 6026039Seric ** 6036039Seric ** Side Effects: 6046039Seric ** none. 6056039Seric */ 6065978Seric 60758755Seric SOCKADDR CurHostAddr; /* address of current host */ 60858305Seric 60954967Seric int 61053739Seric makeconnection(host, port, mci, usesecureport) 6116039Seric char *host; 6127286Seric u_short port; 61354967Seric register MCI *mci; 61452106Seric bool usesecureport; 6156039Seric { 61668433Seric register int i = 0; 61768433Seric register int s; 61829430Sbloom register struct hostent *hp = (struct hostent *)NULL; 61958755Seric SOCKADDR addr; 62052106Seric int sav_errno; 62158755Seric int addrlen; 62268433Seric bool firstconnect; 62366334Seric #if NAMED_BIND 62435651Seric extern int h_errno; 62535651Seric #endif 6266039Seric 6276039Seric /* 6286039Seric ** Set up the address for the mailer. 6299308Seric ** Accept "[a.b.c.d]" syntax for host name. 6306039Seric */ 6316039Seric 63266334Seric #if NAMED_BIND 63325475Smiriam h_errno = 0; 63435651Seric #endif 63525475Smiriam errno = 0; 63658864Seric bzero(&CurHostAddr, sizeof CurHostAddr); 63764334Seric SmtpPhase = mci->mci_phase = "initial connection"; 63858906Seric CurHostName = host; 63925475Smiriam 6409308Seric if (host[0] == '[') 6419308Seric { 64211147Seric long hid; 64356795Seric register char *p = strchr(host, ']'); 6449308Seric 64511147Seric if (p != NULL) 6469308Seric { 64711147Seric *p = '\0'; 64859884Seric #ifdef NETINET 64911147Seric hid = inet_addr(&host[1]); 65058360Seric if (hid == -1) 65159884Seric #endif 65258360Seric { 65358360Seric /* try it as a host name (avoid MX lookup) */ 65458360Seric hp = gethostbyname(&host[1]); 65566349Seric if (hp == NULL && p[-1] == '.') 65666349Seric { 65768433Seric #if NAMED_BIND 65868433Seric int oldopts = _res.options; 65968433Seric 66068433Seric _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 66168433Seric #endif 66266349Seric p[-1] = '\0'; 66366349Seric hp = gethostbyname(&host[1]); 66466349Seric p[-1] = '.'; 66568433Seric #if NAMED_BIND 66668433Seric _res.options = oldopts; 66768433Seric #endif 66866349Seric } 66958360Seric *p = ']'; 67058360Seric goto gothostent; 67158360Seric } 67211147Seric *p = ']'; 6739308Seric } 67458360Seric if (p == NULL) 6759308Seric { 67658151Seric usrerr("553 Invalid numeric domain spec \"%s\"", host); 6779308Seric return (EX_NOHOST); 6789308Seric } 67959884Seric #ifdef NETINET 68059884Seric addr.sin.sin_family = AF_INET; /*XXX*/ 68158778Seric addr.sin.sin_addr.s_addr = hid; 68259884Seric #endif 6839308Seric } 6849610Seric else 6859610Seric { 68666349Seric register char *p = &host[strlen(host) - 1]; 68766349Seric 68829430Sbloom hp = gethostbyname(host); 68966349Seric if (hp == NULL && *p == '.') 69066349Seric { 69168433Seric #if NAMED_BIND 69268433Seric int oldopts = _res.options; 69368433Seric 69468433Seric _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 69568433Seric #endif 69666349Seric *p = '\0'; 69766349Seric hp = gethostbyname(host); 69866349Seric *p = '.'; 69968433Seric #if NAMED_BIND 70068433Seric _res.options = oldopts; 70168433Seric #endif 70266349Seric } 70358360Seric gothostent: 70425475Smiriam if (hp == NULL) 70524945Seric { 70666334Seric #if NAMED_BIND 70768433Seric /* check for name server timeouts */ 70868433Seric if (errno == ETIMEDOUT || h_errno == TRY_AGAIN || 70968433Seric (errno == ECONNREFUSED && UseNameServer)) 71068433Seric { 71168433Seric mci->mci_status = "4.4.3"; 71225475Smiriam return (EX_TEMPFAIL); 71368433Seric } 71435651Seric #endif 71525475Smiriam return (EX_NOHOST); 71624945Seric } 71758778Seric addr.sa.sa_family = hp->h_addrtype; 71858778Seric switch (hp->h_addrtype) 71958778Seric { 72058778Seric #ifdef NETINET 72158778Seric case AF_INET: 72258755Seric bcopy(hp->h_addr, 72358778Seric &addr.sin.sin_addr, 72468433Seric INADDRSZ); 72558778Seric break; 72658778Seric #endif 72758778Seric 72858778Seric default: 72958755Seric bcopy(hp->h_addr, 73058778Seric addr.sa.sa_data, 73158755Seric hp->h_length); 73258778Seric break; 73358778Seric } 73429430Sbloom i = 1; 7359610Seric } 7369610Seric 7379610Seric /* 7389610Seric ** Determine the port number. 7399610Seric */ 7409610Seric 74110011Seric if (port != 0) 74258755Seric port = htons(port); 74310011Seric else 7449610Seric { 7459610Seric register struct servent *sp = getservbyname("smtp", "tcp"); 7469610Seric 7479610Seric if (sp == NULL) 7489610Seric { 74958909Seric syserr("554 makeconnection: service \"smtp\" unknown"); 75065169Seric port = htons(25); 7519610Seric } 75265169Seric else 75365169Seric port = sp->s_port; 7549610Seric } 7556039Seric 75658778Seric switch (addr.sa.sa_family) 75758755Seric { 75859884Seric #ifdef NETINET 75958755Seric case AF_INET: 76058778Seric addr.sin.sin_port = port; 76158755Seric addrlen = sizeof (struct sockaddr_in); 76258755Seric break; 76359884Seric #endif 76458755Seric 76558755Seric #ifdef NETISO 76658755Seric case AF_ISO: 76758755Seric /* assume two byte transport selector */ 76858755Seric bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 76958755Seric addrlen = sizeof (struct sockaddr_iso); 77058755Seric break; 77158755Seric #endif 77258755Seric 77358755Seric default: 77458778Seric syserr("Can't connect to address family %d", addr.sa.sa_family); 77558755Seric return (EX_NOHOST); 77658755Seric } 77758755Seric 7786039Seric /* 7796039Seric ** Try to actually open the connection. 7806039Seric */ 7816039Seric 78259156Seric #ifdef XLA 78359156Seric /* if too many connections, don't bother trying */ 78459156Seric if (!xla_noqueue_ok(host)) 78559156Seric return EX_TEMPFAIL; 78659156Seric #endif 78759156Seric 78868433Seric firstconnect = TRUE; 78957736Seric for (;;) 79052106Seric { 79157736Seric if (tTd(16, 1)) 79258755Seric printf("makeconnection (%s [%s])\n", 79358755Seric host, anynet_ntoa(&addr)); 79452106Seric 79558588Seric /* save for logging */ 79658588Seric CurHostAddr = addr; 79758588Seric 79857736Seric if (usesecureport) 79957736Seric { 80057736Seric int rport = IPPORT_RESERVED - 1; 8016039Seric 80257736Seric s = rresvport(&rport); 80357736Seric } 80457736Seric else 80557736Seric { 80657736Seric s = socket(AF_INET, SOCK_STREAM, 0); 80757736Seric } 80857736Seric if (s < 0) 80957736Seric { 81057736Seric sav_errno = errno; 81157736Seric syserr("makeconnection: no socket"); 81257736Seric goto failure; 81357736Seric } 81410347Seric 81564381Seric #ifdef SO_SNDBUF 81664381Seric if (TcpSndBufferSize > 0) 81764381Seric { 81864381Seric if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 81964561Seric (char *) &TcpSndBufferSize, 82064381Seric sizeof(TcpSndBufferSize)) < 0) 82164381Seric syserr("makeconnection: setsockopt(SO_SNDBUF)"); 82264381Seric } 82364381Seric #endif 82464381Seric 82557736Seric if (tTd(16, 1)) 82657736Seric printf("makeconnection: fd=%d\n", s); 82757736Seric 82857736Seric /* turn on network debugging? */ 82957736Seric if (tTd(16, 101)) 83057736Seric { 83157736Seric int on = 1; 83266861Seric (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 83357736Seric (char *)&on, sizeof on); 83457736Seric } 83557736Seric if (CurEnv->e_xfp != NULL) 83657736Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 83757736Seric errno = 0; /* for debugging */ 83858755Seric if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 83957736Seric break; 84057736Seric 84168433Seric /* if running demand-dialed connection, try again */ 84268433Seric if (DialDelay > 0 && firstconnect) 84368433Seric { 84468433Seric if (tTd(16, 1)) 84568433Seric printf("Connect failed (%s); trying again...\n", 84668433Seric errstring(sav_errno)); 84768433Seric firstconnect = FALSE; 84868433Seric sleep(DialDelay); 84968433Seric continue; 85068433Seric } 85168433Seric 85257736Seric /* couldn't connect.... figure out why */ 85327744Sbloom sav_errno = errno; 85427744Sbloom (void) close(s); 85568433Seric if (hp != NULL && hp->h_addr_list[i]) 85629430Sbloom { 85757736Seric if (tTd(16, 1)) 85858755Seric printf("Connect failed (%s); trying new address....\n", 85958755Seric errstring(sav_errno)); 86058778Seric switch (addr.sa.sa_family) 86158778Seric { 86258778Seric #ifdef NETINET 86358778Seric case AF_INET: 86458755Seric bcopy(hp->h_addr_list[i++], 86558778Seric &addr.sin.sin_addr, 86668433Seric INADDRSZ); 86758778Seric break; 86858778Seric #endif 86958778Seric 87058778Seric default: 87158755Seric bcopy(hp->h_addr_list[i++], 87258778Seric addr.sa.sa_data, 87352106Seric hp->h_length); 87458778Seric break; 87558778Seric } 87657736Seric continue; 87729430Sbloom } 87829430Sbloom 8796039Seric /* failure, decide if temporary or not */ 8806039Seric failure: 88159254Seric #ifdef XLA 88259254Seric xla_host_end(host); 88359254Seric #endif 88458542Seric if (transienterror(sav_errno)) 88558542Seric return EX_TEMPFAIL; 88658542Seric else 88758542Seric { 88858542Seric message("%s", errstring(sav_errno)); 88958542Seric return (EX_UNAVAILABLE); 8906039Seric } 8916039Seric } 8926039Seric 8936039Seric /* connection ok, put it into canonical form */ 89464724Seric if ((mci->mci_out = fdopen(s, "w")) == NULL || 89564724Seric (s = dup(s)) < 0 || 89664725Seric (mci->mci_in = fdopen(s, "r")) == NULL) 89764724Seric { 89864724Seric syserr("cannot open SMTP client channel, fd=%d", s); 89964724Seric return EX_TEMPFAIL; 90064724Seric } 9016039Seric 90210098Seric return (EX_OK); 9036039Seric } 90410758Seric /* 90510758Seric ** MYHOSTNAME -- return the name of this host. 90610758Seric ** 90710758Seric ** Parameters: 90810758Seric ** hostbuf -- a place to return the name of this host. 90912313Seric ** size -- the size of hostbuf. 91010758Seric ** 91110758Seric ** Returns: 91210758Seric ** A list of aliases for this host. 91310758Seric ** 91410758Seric ** Side Effects: 91564338Seric ** Adds numeric codes to $=w. 91610758Seric */ 9176039Seric 91868433Seric struct hostent * 91912313Seric myhostname(hostbuf, size) 92010758Seric char hostbuf[]; 92112313Seric int size; 92210758Seric { 92358110Seric register struct hostent *hp; 92410758Seric extern struct hostent *gethostbyname(); 92568433Seric extern bool getcanonname(); 92668433Seric extern int h_errno; 92710758Seric 92823120Seric if (gethostname(hostbuf, size) < 0) 92923120Seric { 93023120Seric (void) strcpy(hostbuf, "localhost"); 93123120Seric } 93211147Seric hp = gethostbyname(hostbuf); 93366853Seric if (hp == NULL) 93468433Seric return NULL; 93568433Seric if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 93667448Seric { 93768433Seric (void) strncpy(hostbuf, hp->h_name, size - 1); 93868433Seric hostbuf[size - 1] = '\0'; 93967448Seric } 94066853Seric 94166853Seric #if NAMED_BIND 94268433Seric /* 94368433Seric ** If still no dot, try DNS directly (i.e., avoid NIS problems). 94468433Seric ** This ought to be driven from the configuration file, but 94568433Seric ** we are called before the configuration is read. We could 94668433Seric ** check for an /etc/resolv.conf file, but that isn't required. 94768433Seric ** All in all, a bit of a mess. 94868433Seric */ 94968433Seric 95068433Seric if (strchr(hostbuf, '.') == NULL && 95168433Seric !getcanonname(hostbuf, size, TRUE) && 95268433Seric h_errno == TRY_AGAIN) 95366853Seric { 95466853Seric /* try twice in case name server not yet started up */ 95568433Seric message("My unqualifed host name (%s) unknown to DNS; sleeping for retry", 95668433Seric hostbuf); 95768433Seric sleep(60); 95868433Seric if (!getcanonname(hostbuf, size, TRUE)) 95966853Seric errno = h_errno + E_DNSBASE; 96066853Seric } 96166777Seric #endif 96268433Seric return (hp); 96310758Seric } 96451315Seric /* 96558951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 96658308Seric ** 96758951Seric ** Uses RFC1413 protocol to try to get info from the other end. 96858951Seric ** 96958308Seric ** Parameters: 97058308Seric ** fd -- the descriptor 97158308Seric ** 97258308Seric ** Returns: 97358951Seric ** The user@host information associated with this descriptor. 97458308Seric */ 97558308Seric 97658951Seric static jmp_buf CtxAuthTimeout; 97758951Seric 97868433Seric static void 97958951Seric authtimeout() 98058951Seric { 98158951Seric longjmp(CtxAuthTimeout, 1); 98258951Seric } 98358951Seric 98458308Seric char * 98558951Seric getauthinfo(fd) 98658308Seric int fd; 98758308Seric { 98858951Seric int falen; 98959104Seric register char *p; 99058951Seric SOCKADDR la; 99158951Seric int lalen; 99258951Seric register struct servent *sp; 99358951Seric int s; 99458951Seric int i; 99558951Seric EVENT *ev; 996*68444Seric int nleft; 99758951Seric static char hbuf[MAXNAME * 2 + 2]; 99858951Seric extern char *hostnamebyanyaddr(); 99958951Seric extern char RealUserName[]; /* main.c */ 100058308Seric 100166761Seric falen = sizeof RealHostAddr; 100268433Seric if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 || 100368433Seric falen <= 0 || RealHostAddr.sa.sa_family == 0) 100458951Seric { 100558951Seric (void) sprintf(hbuf, "%s@localhost", RealUserName); 100658957Seric if (tTd(9, 1)) 100758951Seric printf("getauthinfo: %s\n", hbuf); 100858951Seric return hbuf; 100958951Seric } 101058951Seric 101166761Seric if (RealHostName == NULL) 101266761Seric { 101366761Seric /* translate that to a host name */ 101466761Seric RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 101566761Seric } 101666761Seric 101765831Seric if (TimeOuts.to_ident == 0) 101865831Seric goto noident; 101965831Seric 102058951Seric lalen = sizeof la; 102166761Seric if (RealHostAddr.sa.sa_family != AF_INET || 102258951Seric getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 102358951Seric la.sa.sa_family != AF_INET) 102458951Seric { 102558951Seric /* no ident info */ 102658951Seric goto noident; 102758951Seric } 102858951Seric 102958951Seric /* create ident query */ 103060489Seric (void) sprintf(hbuf, "%d,%d\r\n", 103166761Seric ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port)); 103258951Seric 103358951Seric /* create local address */ 103464747Seric la.sin.sin_port = 0; 103558951Seric 103658951Seric /* create foreign address */ 103758951Seric sp = getservbyname("auth", "tcp"); 103858951Seric if (sp != NULL) 103966761Seric RealHostAddr.sin.sin_port = sp->s_port; 104058308Seric else 104166761Seric RealHostAddr.sin.sin_port = htons(113); 104258951Seric 104358951Seric s = -1; 104458951Seric if (setjmp(CtxAuthTimeout) != 0) 104558951Seric { 104658951Seric if (s >= 0) 104758951Seric (void) close(s); 104858951Seric goto noident; 104958951Seric } 105058951Seric 105158951Seric /* put a timeout around the whole thing */ 105264255Seric ev = setevent(TimeOuts.to_ident, authtimeout, 0); 105358951Seric 105464747Seric /* connect to foreign IDENT server using same address as SMTP socket */ 105558951Seric s = socket(AF_INET, SOCK_STREAM, 0); 105658951Seric if (s < 0) 105758951Seric { 105858951Seric clrevent(ev); 105958951Seric goto noident; 106058951Seric } 106164747Seric if (bind(s, &la.sa, sizeof la.sin) < 0 || 106266761Seric connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0) 106358951Seric { 106466011Seric goto closeident; 106558951Seric } 106658951Seric 106758957Seric if (tTd(9, 10)) 106858951Seric printf("getauthinfo: sent %s", hbuf); 106958951Seric 107058951Seric /* send query */ 107158951Seric if (write(s, hbuf, strlen(hbuf)) < 0) 107258951Seric goto closeident; 107358951Seric 107458951Seric /* get result */ 1075*68444Seric p = &hbuf[0]; 1076*68444Seric nleft = sizeof(hbuf); 1077*68444Seric while ((i = read(s, p, nleft)) > 0) 1078*68444Seric { 1079*68444Seric p += i; 1080*68444Seric nleft -= i; 1081*68444Seric } 108258951Seric (void) close(s); 108358951Seric clrevent(ev); 1084*68444Seric if (i < 0 || p == &hbuf[0]) 108558951Seric goto noident; 108658951Seric 1087*68444Seric if (*--p == '\n' && *--p == '\r') 1088*68444Seric p--; 1089*68444Seric *++p = '\0'; 1090*68444Seric 109158957Seric if (tTd(9, 3)) 109258951Seric printf("getauthinfo: got %s\n", hbuf); 109358951Seric 109458951Seric /* parse result */ 109558951Seric p = strchr(hbuf, ':'); 109658951Seric if (p == NULL) 109758951Seric { 109858951Seric /* malformed response */ 109958951Seric goto noident; 110058951Seric } 110158951Seric while (isascii(*++p) && isspace(*p)) 110258951Seric continue; 110358951Seric if (strncasecmp(p, "userid", 6) != 0) 110458951Seric { 110558951Seric /* presumably an error string */ 110658951Seric goto noident; 110758951Seric } 110858951Seric p += 6; 110958951Seric while (isascii(*p) && isspace(*p)) 111058951Seric p++; 111158951Seric if (*p++ != ':') 111258951Seric { 111358951Seric /* either useridxx or malformed response */ 111458951Seric goto noident; 111558951Seric } 111658951Seric 111758951Seric /* p now points to the OSTYPE field */ 111858951Seric p = strchr(p, ':'); 111958951Seric if (p == NULL) 112058951Seric { 112158951Seric /* malformed response */ 112258951Seric goto noident; 112358951Seric } 112458951Seric 112558957Seric /* 1413 says don't do this -- but it's broken otherwise */ 112658957Seric while (isascii(*++p) && isspace(*p)) 112758957Seric continue; 112858957Seric 112967935Seric /* p now points to the authenticated name -- copy carefully */ 113068433Seric for (i = 0; i < MAXNAME && *p != '\0'; p++) 113168433Seric { 113268433Seric if (isascii(*p) && 113368433Seric (isalnum(*p) || strchr("!#$%&'*+-./^_`{|}~", *p) != NULL)) 113468433Seric hbuf[i++] = *p; 113568433Seric } 113667935Seric hbuf[i++] = '@'; 113767935Seric strcpy(&hbuf[i], RealHostName == NULL ? "localhost" : RealHostName); 113858957Seric goto finish; 113958957Seric 114066011Seric closeident: 114166011Seric (void) close(s); 114266011Seric clrevent(ev); 114366011Seric 114458957Seric noident: 114566003Seric if (RealHostName == NULL) 114666003Seric { 114766003Seric if (tTd(9, 1)) 114866003Seric printf("getauthinfo: NULL\n"); 114966003Seric return NULL; 115066003Seric } 115158957Seric (void) strcpy(hbuf, RealHostName); 115258957Seric 115358957Seric finish: 115466003Seric if (RealHostName != NULL && RealHostName[0] != '[') 115558951Seric { 115658951Seric p = &hbuf[strlen(hbuf)]; 115758951Seric (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 115858951Seric } 115958957Seric if (tTd(9, 1)) 116058951Seric printf("getauthinfo: %s\n", hbuf); 116158308Seric return hbuf; 116258308Seric } 116358308Seric /* 116460089Seric ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 116553751Seric ** 116653751Seric ** Parameters: 116756823Seric ** map -- a pointer to this map (unused). 116860089Seric ** name -- the (presumably unqualified) hostname. 116960257Seric ** av -- unused -- for compatibility with other mapping 117055019Seric ** functions. 117159084Seric ** statp -- an exit status (out parameter) -- set to 117259084Seric ** EX_TEMPFAIL if the name server is unavailable. 117353751Seric ** 117453751Seric ** Returns: 117553751Seric ** The mapping, if found. 117653751Seric ** NULL if no mapping found. 117753751Seric ** 117853751Seric ** Side Effects: 117953751Seric ** Looks up the host specified in hbuf. If it is not 118053751Seric ** the canonical name for that host, return the canonical 118153751Seric ** name. 118253751Seric */ 118351315Seric 118453751Seric char * 118560257Seric host_map_lookup(map, name, av, statp) 118656823Seric MAP *map; 118760089Seric char *name; 118860257Seric char **av; 118959084Seric int *statp; 119016911Seric { 119116911Seric register struct hostent *hp; 119268433Seric struct in_addr in_addr; 119356823Seric char *cp; 119459671Seric register STAB *s; 119560257Seric char hbuf[MAXNAME]; 119659671Seric extern struct hostent *gethostbyaddr(); 119766334Seric #if NAMED_BIND 119859671Seric extern int h_errno; 119966029Seric #endif 120016911Seric 120125574Smiriam /* 120259671Seric ** See if we have already looked up this name. If so, just 120359671Seric ** return it. 120459671Seric */ 120553751Seric 120660089Seric s = stab(name, ST_NAMECANON, ST_ENTER); 120759671Seric if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 120859671Seric { 120959986Seric if (tTd(9, 1)) 121060089Seric printf("host_map_lookup(%s) => CACHE %s\n", 121160089Seric name, s->s_namecanon.nc_cname); 121259671Seric errno = s->s_namecanon.nc_errno; 121366334Seric #if NAMED_BIND 121459671Seric h_errno = s->s_namecanon.nc_herrno; 121566029Seric #endif 121659671Seric *statp = s->s_namecanon.nc_stat; 121764797Seric if (CurEnv->e_message == NULL && *statp == EX_TEMPFAIL) 121865199Seric { 121965199Seric sprintf(hbuf, "%s: Name server timeout", 122065199Seric shortenstring(name, 33)); 122165199Seric CurEnv->e_message = newstr(hbuf); 122265199Seric } 122359671Seric return s->s_namecanon.nc_cname; 122459671Seric } 122559671Seric 122659671Seric /* 122759671Seric ** If first character is a bracket, then it is an address 122859671Seric ** lookup. Address is copied into a temporary buffer to 122960089Seric ** strip the brackets and to preserve name if address is 123059671Seric ** unknown. 123159671Seric */ 123259671Seric 123360089Seric if (*name != '[') 123453751Seric { 123555019Seric extern bool getcanonname(); 123655019Seric 123758798Seric if (tTd(9, 1)) 123860089Seric printf("host_map_lookup(%s) => ", name); 123959671Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 124060089Seric (void) strcpy(hbuf, name); 124163842Seric if (getcanonname(hbuf, sizeof hbuf - 1, TRUE)) 124258796Seric { 124358796Seric if (tTd(9, 1)) 124458796Seric printf("%s\n", hbuf); 124560257Seric cp = map_rewrite(map, hbuf, strlen(hbuf), av); 124660257Seric s->s_namecanon.nc_cname = newstr(cp); 124760257Seric return cp; 124858796Seric } 124953751Seric else 125058796Seric { 125159084Seric register struct hostent *hp; 125259084Seric 125366029Seric s->s_namecanon.nc_errno = errno; 125466334Seric #if NAMED_BIND 125566029Seric s->s_namecanon.nc_herrno = h_errno; 125658796Seric if (tTd(9, 1)) 125759084Seric printf("FAIL (%d)\n", h_errno); 125859084Seric switch (h_errno) 125959084Seric { 126059084Seric case TRY_AGAIN: 126159596Seric if (UseNameServer) 126259734Seric { 126365202Seric sprintf(hbuf, "%s: Name server timeout", 126465199Seric shortenstring(name, 33)); 126565202Seric message("%s", hbuf); 126659734Seric if (CurEnv->e_message == NULL) 126765202Seric CurEnv->e_message = newstr(hbuf); 126859734Seric } 126959084Seric *statp = EX_TEMPFAIL; 127059084Seric break; 127159084Seric 127259084Seric case HOST_NOT_FOUND: 127359084Seric *statp = EX_NOHOST; 127459084Seric break; 127559084Seric 127659084Seric case NO_RECOVERY: 127759084Seric *statp = EX_SOFTWARE; 127859084Seric break; 127959084Seric 128059084Seric default: 128159084Seric *statp = EX_UNAVAILABLE; 128259084Seric break; 128359084Seric } 128466029Seric #else 128566029Seric if (tTd(9, 1)) 128666029Seric printf("FAIL\n"); 128766029Seric *statp = EX_NOHOST; 128866029Seric #endif 128959671Seric s->s_namecanon.nc_stat = *statp; 129068433Seric if ((*statp != EX_TEMPFAIL && *statp != EX_NOHOST) || 129168433Seric UseNameServer) 129259084Seric return NULL; 129359084Seric 129459084Seric /* 129559084Seric ** Try to look it up in /etc/hosts 129659084Seric */ 129759084Seric 129860089Seric hp = gethostbyname(name); 129959084Seric if (hp == NULL) 130059084Seric { 130159084Seric /* no dice there either */ 130259671Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 130359084Seric return NULL; 130459084Seric } 130559084Seric 130659671Seric s->s_namecanon.nc_stat = *statp = EX_OK; 130760257Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 130860257Seric s->s_namecanon.nc_cname = newstr(cp); 130960257Seric return cp; 131058796Seric } 131153751Seric } 131260089Seric if ((cp = strchr(name, ']')) == NULL) 131353751Seric return (NULL); 131440994Sbostic *cp = '\0'; 131568433Seric in_addr.s_addr = inet_addr(&name[1]); 131658110Seric 131758110Seric /* nope -- ask the name server */ 131868433Seric hp = gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET); 131959671Seric s->s_namecanon.nc_errno = errno; 132066334Seric #if NAMED_BIND 132159671Seric s->s_namecanon.nc_herrno = h_errno; 132266029Seric #endif 132359671Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 132433932Sbostic if (hp == NULL) 132559671Seric { 132659671Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 132753751Seric return (NULL); 132859671Seric } 132953751Seric 133058110Seric /* found a match -- copy out */ 133160257Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 133259671Seric s->s_namecanon.nc_stat = *statp = EX_OK; 133360257Seric s->s_namecanon.nc_cname = newstr(cp); 133460257Seric return cp; 133533932Sbostic } 133658755Seric /* 133758755Seric ** ANYNET_NTOA -- convert a network address to printable form. 133858755Seric ** 133958755Seric ** Parameters: 134058755Seric ** sap -- a pointer to a sockaddr structure. 134158755Seric ** 134258755Seric ** Returns: 134358755Seric ** A printable version of that sockaddr. 134458755Seric */ 134516911Seric 134658755Seric char * 134758755Seric anynet_ntoa(sap) 134858755Seric register SOCKADDR *sap; 134958755Seric { 135058755Seric register char *bp; 135158755Seric register char *ap; 135258755Seric int l; 135364734Seric static char buf[100]; 135458755Seric 135558798Seric /* check for null/zero family */ 135658798Seric if (sap == NULL) 135758798Seric return "NULLADDR"; 135858798Seric if (sap->sa.sa_family == 0) 135958798Seric return "0"; 136058798Seric 136164734Seric switch (sap->sa.sa_family) 136264734Seric { 136364821Seric #ifdef NETUNIX 136464734Seric case AF_UNIX: 136564758Seric if (sap->sunix.sun_path[0] != '\0') 136664758Seric sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 136764734Seric else 136864734Seric sprintf(buf, "[UNIX: localhost]"); 136964734Seric return buf; 137064734Seric #endif 137164734Seric 137258778Seric #ifdef NETINET 137364734Seric case AF_INET: 137458755Seric return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 137558778Seric #endif 137658755Seric 137764734Seric default: 137864734Seric /* this case is only to ensure syntactic correctness */ 137964734Seric break; 138064734Seric } 138164734Seric 138258755Seric /* unknown family -- just dump bytes */ 138358778Seric (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 138458755Seric bp = &buf[strlen(buf)]; 138558778Seric ap = sap->sa.sa_data; 138658778Seric for (l = sizeof sap->sa.sa_data; --l >= 0; ) 138758755Seric { 138858755Seric (void) sprintf(bp, "%02x:", *ap++ & 0377); 138958755Seric bp += 3; 139058755Seric } 139158755Seric *--bp = '\0'; 139258755Seric return buf; 139358755Seric } 139458951Seric /* 139558951Seric ** HOSTNAMEBYANYADDR -- return name of host based on address 139658951Seric ** 139758951Seric ** Parameters: 139858951Seric ** sap -- SOCKADDR pointer 139958951Seric ** 140058951Seric ** Returns: 140158951Seric ** text representation of host name. 140258951Seric ** 140358951Seric ** Side Effects: 140458951Seric ** none. 140558951Seric */ 140658755Seric 140758951Seric char * 140858951Seric hostnamebyanyaddr(sap) 140958951Seric register SOCKADDR *sap; 141058951Seric { 141158951Seric register struct hostent *hp; 141264734Seric int saveretry; 141358951Seric 141466334Seric #if NAMED_BIND 141559042Seric /* shorten name server timeout to avoid higher level timeouts */ 141659042Seric saveretry = _res.retry; 141759042Seric _res.retry = 3; 141859042Seric #endif /* NAMED_BIND */ 141959042Seric 142058951Seric switch (sap->sa.sa_family) 142158951Seric { 142258951Seric #ifdef NETINET 142358951Seric case AF_INET: 142458951Seric hp = gethostbyaddr((char *) &sap->sin.sin_addr, 142568433Seric INADDRSZ, 142658951Seric AF_INET); 142758951Seric break; 142858951Seric #endif 142958951Seric 143058951Seric #ifdef NETISO 143158951Seric case AF_ISO: 143258951Seric hp = gethostbyaddr((char *) &sap->siso.siso_addr, 143358951Seric sizeof sap->siso.siso_addr, 143458951Seric AF_ISO); 143558951Seric break; 143658951Seric #endif 143758951Seric 143864734Seric case AF_UNIX: 143964734Seric hp = NULL; 144064734Seric break; 144164734Seric 144258951Seric default: 144358951Seric hp = gethostbyaddr(sap->sa.sa_data, 144458951Seric sizeof sap->sa.sa_data, 144558951Seric sap->sa.sa_family); 144658951Seric break; 144758951Seric } 144858951Seric 144966334Seric #if NAMED_BIND 145059042Seric _res.retry = saveretry; 145159042Seric #endif /* NAMED_BIND */ 145259042Seric 145358951Seric if (hp != NULL) 145458951Seric return hp->h_name; 145558951Seric else 145658951Seric { 145758951Seric /* produce a dotted quad */ 145858951Seric static char buf[512]; 145958951Seric 146058951Seric (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 146158951Seric return buf; 146258951Seric } 146358951Seric } 146458951Seric 146556795Seric # else /* DAEMON */ 146616911Seric /* code for systems without sophisticated networking */ 146710758Seric 146810758Seric /* 146910758Seric ** MYHOSTNAME -- stub version for case of no daemon code. 147011297Seric ** 147111297Seric ** Can't convert to upper case here because might be a UUCP name. 147212313Seric ** 147312313Seric ** Mark, you can change this to be anything you want...... 147410758Seric */ 147510758Seric 147610758Seric char ** 147712313Seric myhostname(hostbuf, size) 147810758Seric char hostbuf[]; 147912313Seric int size; 148010758Seric { 148110758Seric register FILE *f; 148210758Seric 148310758Seric hostbuf[0] = '\0'; 148410758Seric f = fopen("/usr/include/whoami", "r"); 148510758Seric if (f != NULL) 148610758Seric { 148712313Seric (void) fgets(hostbuf, size, f); 148810758Seric fixcrlf(hostbuf, TRUE); 148910758Seric (void) fclose(f); 149010758Seric } 149110758Seric return (NULL); 149210758Seric } 149316911Seric /* 149458951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 149558308Seric ** 149658308Seric ** Parameters: 149758308Seric ** fd -- the descriptor 149858308Seric ** 149958308Seric ** Returns: 150058308Seric ** The host name associated with this descriptor, if it can 150158308Seric ** be determined. 150258308Seric ** NULL otherwise. 150358308Seric ** 150458308Seric ** Side Effects: 150558308Seric ** none 150658308Seric */ 150758308Seric 150858308Seric char * 150958951Seric getauthinfo(fd) 151058308Seric int fd; 151158308Seric { 151258308Seric return NULL; 151358308Seric } 151458308Seric /* 151516911Seric ** MAPHOSTNAME -- turn a hostname into canonical form 151616911Seric ** 151716911Seric ** Parameters: 151856823Seric ** map -- a pointer to the database map. 151960089Seric ** name -- a buffer containing a hostname. 152053751Seric ** avp -- a pointer to a (cf file defined) argument vector. 152159084Seric ** statp -- an exit status (out parameter). 152216911Seric ** 152316911Seric ** Returns: 152453751Seric ** mapped host name 152551315Seric ** FALSE otherwise. 152616911Seric ** 152716911Seric ** Side Effects: 152860089Seric ** Looks up the host specified in name. If it is not 152916911Seric ** the canonical name for that host, replace it with 153016911Seric ** the canonical name. If the name is unknown, or it 153116911Seric ** is already the canonical name, leave it unchanged. 153216911Seric */ 153310758Seric 153416911Seric /*ARGSUSED*/ 153553751Seric char * 153660089Seric host_map_lookup(map, name, avp, statp) 153756823Seric MAP *map; 153860089Seric char *name; 153953751Seric char **avp; 154059084Seric char *statp; 154116911Seric { 154259084Seric register struct hostent *hp; 154359084Seric 154460089Seric hp = gethostbyname(name); 154559084Seric if (hp != NULL) 154659084Seric return hp->h_name; 154759084Seric *statp = EX_NOHOST; 154853751Seric return NULL; 154916911Seric } 155016911Seric 155156795Seric #endif /* DAEMON */ 1552