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*68612Seric static char sccsid[] = "@(#)daemon.c 8.48.1.5 (Berkeley) 03/28/95 (with daemon mode)"; 1533780Sbostic #else 16*68612Seric static char sccsid[] = "@(#)daemon.c 8.48.1.5 (Berkeley) 03/28/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 26*68612Seric # include <arpa/nameser.h> 2759042Seric # include <resolv.h> 2859042Seric #endif 2959042Seric 304535Seric /* 314535Seric ** DAEMON.C -- routines to use when running as a daemon. 327556Seric ** 337556Seric ** This entire file is highly dependent on the 4.2 BSD 347556Seric ** interprocess communication primitives. No attempt has 357556Seric ** been made to make this file portable to Version 7, 367556Seric ** Version 6, MPX files, etc. If you should try such a 377556Seric ** thing yourself, I recommend chucking the entire file 387556Seric ** and starting from scratch. Basic semantics are: 397556Seric ** 407556Seric ** getrequests() 417556Seric ** Opens a port and initiates a connection. 427556Seric ** Returns in a child. Must set InChannel and 437556Seric ** OutChannel appropriately. 4410206Seric ** clrdaemon() 4510206Seric ** Close any open files associated with getting 4610206Seric ** the connection; this is used when running the queue, 4710206Seric ** etc., to avoid having extra file descriptors during 4810206Seric ** the queue run and to avoid confusing the network 4910206Seric ** code (if it cares). 5052106Seric ** makeconnection(host, port, outfile, infile, usesecureport) 517556Seric ** Make a connection to the named host on the given 527556Seric ** port. Set *outfile and *infile to the files 537556Seric ** appropriate for communication. Returns zero on 547556Seric ** success, else an exit status describing the 557556Seric ** error. 5660089Seric ** host_map_lookup(map, hbuf, avp, pstat) 5756823Seric ** Convert the entry in hbuf into a canonical form. 584535Seric */ 594535Seric /* 604535Seric ** GETREQUESTS -- open mail IPC port and get requests. 614535Seric ** 624535Seric ** Parameters: 634535Seric ** none. 644535Seric ** 654535Seric ** Returns: 664535Seric ** none. 674535Seric ** 684535Seric ** Side Effects: 694535Seric ** Waits until some interesting activity occurs. When 704535Seric ** it does, a child is created to process it, and the 714535Seric ** parent waits for completion. Return from this 729886Seric ** routine is always in the child. The file pointers 739886Seric ** "InChannel" and "OutChannel" should be set to point 749886Seric ** to the communication channel. 754535Seric */ 764535Seric 7758849Seric int DaemonSocket = -1; /* fd describing socket */ 7858849Seric SOCKADDR DaemonAddr; /* socket for incoming */ 7959783Seric int ListenQueueSize = 10; /* size of listen queue */ 8064381Seric int TcpRcvBufferSize = 0; /* size of TCP receive buffer */ 8164381Seric int TcpSndBufferSize = 0; /* size of TCP send buffer */ 8216144Seric 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 148*68612Seric 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(); 16111147Seric 16214875Seric /* see if we are rejecting connections */ 16353751Seric CurrentLA = getla(); 16453751Seric if (refuseconnections()) 16536584Sbostic { 16666845Seric if (DaemonSocket >= 0) 16753751Seric { 16866845Seric /* close socket so peer will fail quickly */ 16966845Seric (void) close(DaemonSocket); 17066845Seric DaemonSocket = -1; 17153751Seric } 17266845Seric refusingconnections = TRUE; 17357385Seric setproctitle("rejecting connections: load average: %d", 17457385Seric CurrentLA); 17566845Seric sleep(15); 17653751Seric continue; 17736584Sbostic } 17814875Seric 17953751Seric if (refusingconnections) 18053751Seric { 181*68612Seric /* start listening again */ 18267690Seric (void) opendaemonsocket(FALSE); 18353751Seric setproctitle("accepting connections"); 18453751Seric refusingconnections = FALSE; 18553751Seric } 18653751Seric 18766793Seric #ifdef XDEBUG 18866793Seric /* check for disaster */ 18966793Seric { 190*68612Seric register STAB *s; 19166812Seric char jbuf[MAXHOSTNAMELEN]; 19266793Seric 193*68612Seric expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv); 194*68612Seric if ((s = stab(jbuf, ST_CLASS, ST_FIND)) == NULL || 195*68612Seric !bitnset('w', s->s_class)) 19666793Seric { 19766793Seric dumpstate("daemon lost $j"); 19866793Seric syslog(LOG_ALERT, "daemon process doesn't have $j in $=w; see syslog"); 19966793Seric abort(); 20066793Seric } 20166812Seric else if (j_has_dot && strchr(jbuf, '.') == NULL) 20266793Seric { 20366793Seric dumpstate("daemon $j lost dot"); 20466793Seric syslog(LOG_ALERT, "daemon process $j lost dot; see syslog"); 20566793Seric abort(); 20666793Seric } 20766793Seric } 20866793Seric #endif 20966793Seric 2109610Seric /* wait for a connection */ 2119610Seric do 2129610Seric { 2139610Seric errno = 0; 21464828Seric lotherend = socksize; 21546928Sbostic t = accept(DaemonSocket, 21646928Sbostic (struct sockaddr *)&RealHostAddr, &lotherend); 2179610Seric } while (t < 0 && errno == EINTR); 2189610Seric if (t < 0) 2195978Seric { 2209610Seric syserr("getrequests: accept"); 2219610Seric sleep(5); 2229610Seric continue; 2235978Seric } 2244631Seric 2255978Seric /* 2265978Seric ** Create a subprocess to process the mail. 2275978Seric */ 2285978Seric 2297677Seric if (tTd(15, 2)) 2309610Seric printf("getrequests: forking (fd = %d)\n", t); 2315978Seric 2324636Seric pid = fork(); 2334636Seric if (pid < 0) 2344631Seric { 2354636Seric syserr("daemon: cannot fork"); 2364636Seric sleep(10); 2379610Seric (void) close(t); 2384636Seric continue; 2394631Seric } 2404631Seric 2414636Seric if (pid == 0) 2424631Seric { 24364086Seric char *p; 24458951Seric extern char *hostnamebyanyaddr(); 24511147Seric 2464636Seric /* 2474636Seric ** CHILD -- return to caller. 24811147Seric ** Collect verified idea of sending host. 2494636Seric ** Verify calling user id if possible here. 2504636Seric */ 2514631Seric 25264035Seric (void) setsignal(SIGCHLD, SIG_DFL); 25366017Seric DisConnected = FALSE; 25424950Seric 25566032Seric setproctitle("startup with %s", 25666032Seric anynet_ntoa(&RealHostAddr)); 25766032Seric 25811147Seric /* determine host name */ 25964086Seric p = hostnamebyanyaddr(&RealHostAddr); 26064086Seric RealHostName = newstr(p); 26166032Seric setproctitle("startup with %s", p); 26258778Seric 26355173Seric #ifdef LOG 26463842Seric if (LogLevel > 11) 26555173Seric { 26655173Seric /* log connection information */ 26755173Seric syslog(LOG_INFO, "connect from %s (%s)", 26858951Seric RealHostName, anynet_ntoa(&RealHostAddr)); 26955173Seric } 27055173Seric #endif 27155173Seric 272*68612Seric (void) close(DaemonSocket); 27364724Seric if ((InChannel = fdopen(t, "r")) == NULL || 27464724Seric (t = dup(t)) < 0 || 27564724Seric (OutChannel = fdopen(t, "w")) == NULL) 27664724Seric { 27764724Seric syserr("cannot open SMTP server channel, fd=%d", t); 27864724Seric exit(0); 27964724Seric } 28059254Seric 28116884Seric /* should we check for illegal connection here? XXX */ 28259156Seric #ifdef XLA 28359156Seric if (!xla_host_ok(RealHostName)) 28459156Seric { 28559254Seric message("421 Too many SMTP sessions for this host"); 28659156Seric exit(0); 28759156Seric } 28859156Seric #endif 28916884Seric 2907677Seric if (tTd(15, 2)) 2915978Seric printf("getreq: returning\n"); 2924636Seric return; 2934631Seric } 2944631Seric 2957117Seric /* close the port so that others will hang (for a while) */ 2969610Seric (void) close(t); 2974631Seric } 2989886Seric /*NOTREACHED*/ 2994631Seric } 3005978Seric /* 30166845Seric ** OPENDAEMONSOCKET -- open the SMTP socket 30266845Seric ** 30366845Seric ** Deals with setting all appropriate options. DaemonAddr must 30466845Seric ** be set up in advance. 30566845Seric ** 30666845Seric ** Parameters: 30766854Seric ** firsttime -- set if this is the initial open. 30866845Seric ** 30966845Seric ** Returns: 31066845Seric ** Size in bytes of the daemon socket addr. 31166845Seric ** 31266845Seric ** Side Effects: 31366845Seric ** Leaves DaemonSocket set to the open socket. 31466845Seric ** Exits if the socket cannot be created. 31566845Seric */ 31666845Seric 31766861Seric #define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 31866861Seric 31966845Seric int 32066854Seric opendaemonsocket(firsttime) 32166854Seric bool firsttime; 32266845Seric { 32366845Seric int on = 1; 324*68612Seric int socksize; 32566861Seric int ntries = 0; 32666861Seric int saveerrno; 32766845Seric 32866845Seric if (tTd(15, 2)) 32966845Seric printf("opendaemonsocket()\n"); 33066845Seric 33166861Seric do 33266845Seric { 33366862Seric if (ntries > 0) 33466862Seric sleep(5); 33566861Seric if (firsttime || DaemonSocket < 0) 33666854Seric { 33766861Seric DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0); 33866861Seric if (DaemonSocket < 0) 33966861Seric { 34066861Seric /* probably another daemon already */ 34166861Seric saveerrno = errno; 34266861Seric syserr("opendaemonsocket: can't create server SMTP socket"); 34366861Seric severe: 34466845Seric # ifdef LOG 34566861Seric if (LogLevel > 0) 34666861Seric syslog(LOG_ALERT, "problem creating SMTP socket"); 34766845Seric # endif /* LOG */ 34866861Seric DaemonSocket = -1; 34966861Seric continue; 35066861Seric } 35166845Seric 35266861Seric /* turn on network debugging? */ 35366861Seric if (tTd(15, 101)) 35466861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 35566861Seric SO_DEBUG, (char *)&on, 35666861Seric sizeof on); 35766845Seric 35866861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 35966861Seric SO_REUSEADDR, (char *)&on, sizeof on); 36066861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 36166861Seric SO_KEEPALIVE, (char *)&on, sizeof on); 36266845Seric 36366845Seric #ifdef SO_RCVBUF 36466861Seric if (TcpRcvBufferSize > 0) 36566861Seric { 36666861Seric if (setsockopt(DaemonSocket, SOL_SOCKET, 36766861Seric SO_RCVBUF, 36866861Seric (char *) &TcpRcvBufferSize, 36966861Seric sizeof(TcpRcvBufferSize)) < 0) 37066861Seric syserr("getrequests: setsockopt(SO_RCVBUF)"); 37166861Seric } 37266845Seric #endif 37366845Seric 37466861Seric switch (DaemonAddr.sa.sa_family) 37566861Seric { 37666845Seric # ifdef NETINET 37766861Seric case AF_INET: 37866861Seric socksize = sizeof DaemonAddr.sin; 37966861Seric break; 38066845Seric # endif 38166845Seric 38266845Seric # ifdef NETISO 38366861Seric case AF_ISO: 38466861Seric socksize = sizeof DaemonAddr.siso; 38566861Seric break; 38666845Seric # endif 38766845Seric 38866861Seric default: 38966861Seric socksize = sizeof DaemonAddr; 39066861Seric break; 39166861Seric } 39266861Seric 39366861Seric if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0) 39466861Seric { 39566861Seric saveerrno = errno; 39666861Seric syserr("getrequests: cannot bind"); 39766861Seric (void) close(DaemonSocket); 39866861Seric goto severe; 39966861Seric } 40066854Seric } 40166861Seric if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0) 40266854Seric { 40366861Seric saveerrno = errno; 40466861Seric syserr("getrequests: cannot listen"); 40566854Seric (void) close(DaemonSocket); 40666854Seric goto severe; 40766854Seric } 40866861Seric return socksize; 40966861Seric } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno)); 41066861Seric finis(); 41166845Seric } 41266845Seric /* 41310206Seric ** CLRDAEMON -- reset the daemon connection 41410206Seric ** 41510206Seric ** Parameters: 41610206Seric ** none. 41710206Seric ** 41810206Seric ** Returns: 41910206Seric ** none. 42010206Seric ** 42110206Seric ** Side Effects: 42210206Seric ** releases any resources used by the passive daemon. 42310206Seric */ 42410206Seric 42510206Seric clrdaemon() 42610206Seric { 42710206Seric if (DaemonSocket >= 0) 42810206Seric (void) close(DaemonSocket); 42910206Seric DaemonSocket = -1; 43010206Seric } 43110206Seric /* 43258849Seric ** SETDAEMONOPTIONS -- set options for running the daemon 43358849Seric ** 43458849Seric ** Parameters: 43558849Seric ** p -- the options line. 43658849Seric ** 43758849Seric ** Returns: 43858849Seric ** none. 43958849Seric */ 44058849Seric 44158849Seric setdaemonoptions(p) 44258849Seric register char *p; 44358849Seric { 44458873Seric if (DaemonAddr.sa.sa_family == AF_UNSPEC) 44558873Seric DaemonAddr.sa.sa_family = AF_INET; 44658873Seric 44758849Seric while (p != NULL) 44858849Seric { 44958849Seric register char *f; 45058849Seric register char *v; 45158849Seric 45258849Seric while (isascii(*p) && isspace(*p)) 45358849Seric p++; 45458849Seric if (*p == '\0') 45558849Seric break; 45658849Seric f = p; 45758849Seric p = strchr(p, ','); 45858849Seric if (p != NULL) 45958849Seric *p++ = '\0'; 46058849Seric v = strchr(f, '='); 46158849Seric if (v == NULL) 46258849Seric continue; 46358849Seric while (isascii(*++v) && isspace(*v)) 46458849Seric continue; 46558849Seric 46658849Seric switch (*f) 46758849Seric { 46858873Seric case 'F': /* address family */ 46958849Seric if (isascii(*v) && isdigit(*v)) 47058873Seric DaemonAddr.sa.sa_family = atoi(v); 47158873Seric #ifdef NETINET 47258873Seric else if (strcasecmp(v, "inet") == 0) 47358873Seric DaemonAddr.sa.sa_family = AF_INET; 47458873Seric #endif 47558873Seric #ifdef NETISO 47658873Seric else if (strcasecmp(v, "iso") == 0) 47758873Seric DaemonAddr.sa.sa_family = AF_ISO; 47858873Seric #endif 47958873Seric #ifdef NETNS 48058873Seric else if (strcasecmp(v, "ns") == 0) 48158873Seric DaemonAddr.sa.sa_family = AF_NS; 48258873Seric #endif 48358873Seric #ifdef NETX25 48458873Seric else if (strcasecmp(v, "x.25") == 0) 48558873Seric DaemonAddr.sa.sa_family = AF_CCITT; 48658873Seric #endif 48758849Seric else 48858873Seric syserr("554 Unknown address family %s in Family=option", v); 48958873Seric break; 49058873Seric 49158873Seric case 'A': /* address */ 49258873Seric switch (DaemonAddr.sa.sa_family) 49358849Seric { 49458873Seric #ifdef NETINET 49558873Seric case AF_INET: 49658873Seric if (isascii(*v) && isdigit(*v)) 497*68612Seric DaemonAddr.sin.sin_addr.s_addr = inet_network(v); 49858873Seric else 49958873Seric { 50058873Seric register struct netent *np; 50158849Seric 50258873Seric np = getnetbyname(v); 50358873Seric if (np == NULL) 50458873Seric syserr("554 network \"%s\" unknown", v); 50558873Seric else 50658873Seric DaemonAddr.sin.sin_addr.s_addr = np->n_net; 50758873Seric } 50858873Seric break; 50958873Seric #endif 51058873Seric 51158873Seric default: 51258873Seric syserr("554 Address= option unsupported for family %d", 51358873Seric DaemonAddr.sa.sa_family); 51458873Seric break; 51558849Seric } 51658849Seric break; 51758849Seric 51858873Seric case 'P': /* port */ 51958873Seric switch (DaemonAddr.sa.sa_family) 52058849Seric { 52158873Seric short port; 52258849Seric 52358873Seric #ifdef NETINET 52458873Seric case AF_INET: 52558873Seric if (isascii(*v) && isdigit(*v)) 52664366Seric DaemonAddr.sin.sin_port = htons(atoi(v)); 52758849Seric else 52858873Seric { 52958873Seric register struct servent *sp; 53058873Seric 53158873Seric sp = getservbyname(v, "tcp"); 53258873Seric if (sp == NULL) 53358909Seric syserr("554 service \"%s\" unknown", v); 53458873Seric else 53558873Seric DaemonAddr.sin.sin_port = sp->s_port; 53658873Seric } 53758873Seric break; 53858873Seric #endif 53958873Seric 54058873Seric #ifdef NETISO 54158873Seric case AF_ISO: 54258873Seric /* assume two byte transport selector */ 54358873Seric if (isascii(*v) && isdigit(*v)) 54464366Seric port = htons(atoi(v)); 54558873Seric else 54658873Seric { 54758873Seric register struct servent *sp; 54858873Seric 54958873Seric sp = getservbyname(v, "tcp"); 55058873Seric if (sp == NULL) 55158909Seric syserr("554 service \"%s\" unknown", v); 55258873Seric else 55358873Seric port = sp->s_port; 55458873Seric } 55558873Seric bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 55658873Seric break; 55758873Seric #endif 55858873Seric 55958873Seric default: 56058873Seric syserr("554 Port= option unsupported for family %d", 56158873Seric DaemonAddr.sa.sa_family); 56258873Seric break; 56358849Seric } 56458849Seric break; 56559783Seric 56659783Seric case 'L': /* listen queue size */ 56759783Seric ListenQueueSize = atoi(v); 56859783Seric break; 56964381Seric 57064381Seric case 'S': /* send buffer size */ 57164381Seric TcpSndBufferSize = atoi(v); 57264381Seric break; 57364381Seric 57464381Seric case 'R': /* receive buffer size */ 57564381Seric TcpRcvBufferSize = atoi(v); 57664381Seric break; 57758849Seric } 57858849Seric } 57958849Seric } 58058849Seric /* 5816039Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 5826039Seric ** 5836039Seric ** Parameters: 5846039Seric ** host -- the name of the host. 5856633Seric ** port -- the port number to connect to. 58653739Seric ** mci -- a pointer to the mail connection information 58753739Seric ** structure to be filled in. 58852106Seric ** usesecureport -- if set, use a low numbered (reserved) 58952106Seric ** port to provide some rudimentary authentication. 5906039Seric ** 5916039Seric ** Returns: 5926039Seric ** An exit code telling whether the connection could be 5936039Seric ** made and if not why not. 5946039Seric ** 5956039Seric ** Side Effects: 5966039Seric ** none. 5976039Seric */ 5985978Seric 59958755Seric SOCKADDR CurHostAddr; /* address of current host */ 60058305Seric 60154967Seric int 60253739Seric makeconnection(host, port, mci, usesecureport) 6036039Seric char *host; 6047286Seric u_short port; 60554967Seric register MCI *mci; 60652106Seric bool usesecureport; 6076039Seric { 608*68612Seric register int i, s; 60929430Sbloom register struct hostent *hp = (struct hostent *)NULL; 61058755Seric SOCKADDR addr; 61152106Seric int sav_errno; 61258755Seric int addrlen; 61366334Seric #if NAMED_BIND 61435651Seric extern int h_errno; 61535651Seric #endif 6166039Seric 6176039Seric /* 6186039Seric ** Set up the address for the mailer. 6199308Seric ** Accept "[a.b.c.d]" syntax for host name. 6206039Seric */ 6216039Seric 62266334Seric #if NAMED_BIND 62325475Smiriam h_errno = 0; 62435651Seric #endif 62525475Smiriam errno = 0; 62658864Seric bzero(&CurHostAddr, sizeof CurHostAddr); 62764334Seric SmtpPhase = mci->mci_phase = "initial connection"; 62858906Seric CurHostName = host; 62925475Smiriam 6309308Seric if (host[0] == '[') 6319308Seric { 63211147Seric long hid; 63356795Seric register char *p = strchr(host, ']'); 6349308Seric 63511147Seric if (p != NULL) 6369308Seric { 63711147Seric *p = '\0'; 63859884Seric #ifdef NETINET 63911147Seric hid = inet_addr(&host[1]); 64058360Seric if (hid == -1) 64159884Seric #endif 64258360Seric { 64358360Seric /* try it as a host name (avoid MX lookup) */ 64458360Seric hp = gethostbyname(&host[1]); 64566349Seric if (hp == NULL && p[-1] == '.') 64666349Seric { 64766349Seric p[-1] = '\0'; 64866349Seric hp = gethostbyname(&host[1]); 64966349Seric p[-1] = '.'; 65066349Seric } 65158360Seric *p = ']'; 65258360Seric goto gothostent; 65358360Seric } 65411147Seric *p = ']'; 6559308Seric } 65658360Seric if (p == NULL) 6579308Seric { 65858151Seric usrerr("553 Invalid numeric domain spec \"%s\"", host); 6599308Seric return (EX_NOHOST); 6609308Seric } 66159884Seric #ifdef NETINET 66259884Seric addr.sin.sin_family = AF_INET; /*XXX*/ 66358778Seric addr.sin.sin_addr.s_addr = hid; 66459884Seric #endif 6659308Seric } 6669610Seric else 6679610Seric { 66866349Seric register char *p = &host[strlen(host) - 1]; 66966349Seric 67029430Sbloom hp = gethostbyname(host); 67166349Seric if (hp == NULL && *p == '.') 67266349Seric { 67366349Seric *p = '\0'; 67466349Seric hp = gethostbyname(host); 67566349Seric *p = '.'; 67666349Seric } 67758360Seric gothostent: 67825475Smiriam if (hp == NULL) 67924945Seric { 68066334Seric #if NAMED_BIND 681*68612Seric if (errno == ETIMEDOUT || h_errno == TRY_AGAIN) 68225475Smiriam return (EX_TEMPFAIL); 683*68612Seric 684*68612Seric /* if name server is specified, assume temp fail */ 685*68612Seric if (errno == ECONNREFUSED && UseNameServer) 686*68612Seric return (EX_TEMPFAIL); 68735651Seric #endif 68825475Smiriam return (EX_NOHOST); 68924945Seric } 69058778Seric addr.sa.sa_family = hp->h_addrtype; 69158778Seric switch (hp->h_addrtype) 69258778Seric { 69358778Seric #ifdef NETINET 69458778Seric case AF_INET: 69558755Seric bcopy(hp->h_addr, 69658778Seric &addr.sin.sin_addr, 697*68612Seric sizeof addr.sin.sin_addr); 69858778Seric break; 69958778Seric #endif 70058778Seric 70158778Seric default: 70258755Seric bcopy(hp->h_addr, 70358778Seric addr.sa.sa_data, 70458755Seric hp->h_length); 70558778Seric break; 70658778Seric } 70729430Sbloom i = 1; 7089610Seric } 7099610Seric 7109610Seric /* 7119610Seric ** Determine the port number. 7129610Seric */ 7139610Seric 71410011Seric if (port != 0) 71558755Seric port = htons(port); 71610011Seric else 7179610Seric { 7189610Seric register struct servent *sp = getservbyname("smtp", "tcp"); 7199610Seric 7209610Seric if (sp == NULL) 7219610Seric { 72258909Seric syserr("554 makeconnection: service \"smtp\" unknown"); 72365169Seric port = htons(25); 7249610Seric } 72565169Seric else 72665169Seric port = sp->s_port; 7279610Seric } 7286039Seric 72958778Seric switch (addr.sa.sa_family) 73058755Seric { 73159884Seric #ifdef NETINET 73258755Seric case AF_INET: 73358778Seric addr.sin.sin_port = port; 73458755Seric addrlen = sizeof (struct sockaddr_in); 73558755Seric break; 73659884Seric #endif 73758755Seric 73858755Seric #ifdef NETISO 73958755Seric case AF_ISO: 74058755Seric /* assume two byte transport selector */ 74158755Seric bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 74258755Seric addrlen = sizeof (struct sockaddr_iso); 74358755Seric break; 74458755Seric #endif 74558755Seric 74658755Seric default: 74758778Seric syserr("Can't connect to address family %d", addr.sa.sa_family); 74858755Seric return (EX_NOHOST); 74958755Seric } 75058755Seric 7516039Seric /* 7526039Seric ** Try to actually open the connection. 7536039Seric */ 7546039Seric 75559156Seric #ifdef XLA 75659156Seric /* if too many connections, don't bother trying */ 75759156Seric if (!xla_noqueue_ok(host)) 75859156Seric return EX_TEMPFAIL; 75959156Seric #endif 76059156Seric 76157736Seric for (;;) 76252106Seric { 76357736Seric if (tTd(16, 1)) 76458755Seric printf("makeconnection (%s [%s])\n", 76558755Seric host, anynet_ntoa(&addr)); 76652106Seric 76758588Seric /* save for logging */ 76858588Seric CurHostAddr = addr; 76958588Seric 77057736Seric if (usesecureport) 77157736Seric { 77257736Seric int rport = IPPORT_RESERVED - 1; 7736039Seric 77457736Seric s = rresvport(&rport); 77557736Seric } 77657736Seric else 77757736Seric { 77857736Seric s = socket(AF_INET, SOCK_STREAM, 0); 77957736Seric } 78057736Seric if (s < 0) 78157736Seric { 78257736Seric sav_errno = errno; 78357736Seric syserr("makeconnection: no socket"); 78457736Seric goto failure; 78557736Seric } 78610347Seric 78764381Seric #ifdef SO_SNDBUF 78864381Seric if (TcpSndBufferSize > 0) 78964381Seric { 79064381Seric if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 79164561Seric (char *) &TcpSndBufferSize, 79264381Seric sizeof(TcpSndBufferSize)) < 0) 79364381Seric syserr("makeconnection: setsockopt(SO_SNDBUF)"); 79464381Seric } 79564381Seric #endif 79664381Seric 79757736Seric if (tTd(16, 1)) 79857736Seric printf("makeconnection: fd=%d\n", s); 79957736Seric 80057736Seric /* turn on network debugging? */ 80157736Seric if (tTd(16, 101)) 80257736Seric { 80357736Seric int on = 1; 80466861Seric (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 80557736Seric (char *)&on, sizeof on); 80657736Seric } 80757736Seric if (CurEnv->e_xfp != NULL) 80857736Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 80957736Seric errno = 0; /* for debugging */ 81058755Seric if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 81157736Seric break; 81257736Seric 81357736Seric /* couldn't connect.... figure out why */ 81427744Sbloom sav_errno = errno; 81527744Sbloom (void) close(s); 816*68612Seric if (hp && hp->h_addr_list[i]) 81729430Sbloom { 81857736Seric if (tTd(16, 1)) 81958755Seric printf("Connect failed (%s); trying new address....\n", 82058755Seric errstring(sav_errno)); 82158778Seric switch (addr.sa.sa_family) 82258778Seric { 82358778Seric #ifdef NETINET 82458778Seric case AF_INET: 82558755Seric bcopy(hp->h_addr_list[i++], 82658778Seric &addr.sin.sin_addr, 827*68612Seric sizeof addr.sin.sin_addr); 82858778Seric break; 82958778Seric #endif 83058778Seric 83158778Seric default: 83258755Seric bcopy(hp->h_addr_list[i++], 83358778Seric addr.sa.sa_data, 83452106Seric hp->h_length); 83558778Seric break; 83658778Seric } 83757736Seric continue; 83829430Sbloom } 83929430Sbloom 8406039Seric /* failure, decide if temporary or not */ 8416039Seric failure: 84259254Seric #ifdef XLA 84359254Seric xla_host_end(host); 84459254Seric #endif 84558542Seric if (transienterror(sav_errno)) 84658542Seric return EX_TEMPFAIL; 84758542Seric else 84858542Seric { 84958542Seric message("%s", errstring(sav_errno)); 85058542Seric return (EX_UNAVAILABLE); 8516039Seric } 8526039Seric } 8536039Seric 8546039Seric /* connection ok, put it into canonical form */ 85564724Seric if ((mci->mci_out = fdopen(s, "w")) == NULL || 85664724Seric (s = dup(s)) < 0 || 85764725Seric (mci->mci_in = fdopen(s, "r")) == NULL) 85864724Seric { 85964724Seric syserr("cannot open SMTP client channel, fd=%d", s); 86064724Seric return EX_TEMPFAIL; 86164724Seric } 8626039Seric 86310098Seric return (EX_OK); 8646039Seric } 86510758Seric /* 86610758Seric ** MYHOSTNAME -- return the name of this host. 86710758Seric ** 86810758Seric ** Parameters: 86910758Seric ** hostbuf -- a place to return the name of this host. 87012313Seric ** size -- the size of hostbuf. 87110758Seric ** 87210758Seric ** Returns: 87310758Seric ** A list of aliases for this host. 87410758Seric ** 87510758Seric ** Side Effects: 87664338Seric ** Adds numeric codes to $=w. 87710758Seric */ 8786039Seric 879*68612Seric char ** 88012313Seric myhostname(hostbuf, size) 88110758Seric char hostbuf[]; 88212313Seric int size; 88310758Seric { 88458110Seric register struct hostent *hp; 88510758Seric extern struct hostent *gethostbyname(); 88610758Seric 88723120Seric if (gethostname(hostbuf, size) < 0) 88823120Seric { 88923120Seric (void) strcpy(hostbuf, "localhost"); 89023120Seric } 89111147Seric hp = gethostbyname(hostbuf); 89266853Seric if (hp == NULL) 89367448Seric { 894*68612Seric syserr("!My host name (%s) does not seem to exist!", hostbuf); 89567448Seric } 896*68612Seric (void) strncpy(hostbuf, hp->h_name, size - 1); 897*68612Seric hostbuf[size - 1] = '\0'; 89866853Seric 89966853Seric #if NAMED_BIND 900*68612Seric /* if still no dot, try DNS directly (i.e., avoid NIS problems) */ 901*68612Seric if (strchr(hostbuf, '.') == NULL) 902*68612Seric { 903*68612Seric extern bool getcanonname(); 904*68612Seric extern int h_errno; 90568525Seric 90666853Seric /* try twice in case name server not yet started up */ 907*68612Seric if (!getcanonname(hostbuf, size, TRUE) && 908*68612Seric UseNameServer && 909*68612Seric (h_errno != TRY_AGAIN || 910*68612Seric (sleep(30), !getcanonname(hostbuf, size, TRUE)))) 911*68612Seric { 91266853Seric errno = h_errno + E_DNSBASE; 913*68612Seric syserr("!My host name (%s) not known to DNS", 914*68612Seric hostbuf); 915*68612Seric } 91666853Seric } 91766777Seric #endif 918*68612Seric 919*68612Seric if (hp->h_addrtype == AF_INET && hp->h_length == 4) 920*68612Seric { 921*68612Seric register int i; 922*68612Seric 923*68612Seric for (i = 0; hp->h_addr_list[i] != NULL; i++) 924*68612Seric { 925*68612Seric char ipbuf[100]; 926*68612Seric 927*68612Seric sprintf(ipbuf, "[%s]", 928*68612Seric inet_ntoa(*((struct in_addr *) hp->h_addr_list[i]))); 929*68612Seric setclass('w', ipbuf); 930*68612Seric } 931*68612Seric } 932*68612Seric 933*68612Seric return (hp->h_aliases); 93410758Seric } 93551315Seric /* 93658951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 93758308Seric ** 93858951Seric ** Uses RFC1413 protocol to try to get info from the other end. 93958951Seric ** 94058308Seric ** Parameters: 94158308Seric ** fd -- the descriptor 94258308Seric ** 94358308Seric ** Returns: 94458951Seric ** The user@host information associated with this descriptor. 94558308Seric */ 94658308Seric 947*68612Seric #if IDENTPROTO 948*68612Seric 94958951Seric static jmp_buf CtxAuthTimeout; 95058951Seric 951*68612Seric static 95258951Seric authtimeout() 95358951Seric { 95458951Seric longjmp(CtxAuthTimeout, 1); 95558951Seric } 95658951Seric 957*68612Seric #endif 958*68612Seric 95958308Seric char * 96058951Seric getauthinfo(fd) 96158308Seric int fd; 96258308Seric { 96358951Seric int falen; 96459104Seric register char *p; 965*68612Seric #if IDENTPROTO 96658951Seric SOCKADDR la; 96758951Seric int lalen; 96858951Seric register struct servent *sp; 96958951Seric int s; 97058951Seric int i; 97158951Seric EVENT *ev; 97268444Seric int nleft; 97368462Seric char ibuf[MAXNAME + 1]; 974*68612Seric #endif 97558951Seric static char hbuf[MAXNAME * 2 + 2]; 97658951Seric extern char *hostnamebyanyaddr(); 97758951Seric extern char RealUserName[]; /* main.c */ 97858308Seric 97966761Seric falen = sizeof RealHostAddr; 980*68612Seric if (getpeername(fd, &RealHostAddr.sa, &falen) < 0 || falen <= 0 || 981*68612Seric RealHostAddr.sa.sa_family == 0) 98258951Seric { 98358951Seric (void) sprintf(hbuf, "%s@localhost", RealUserName); 98458957Seric if (tTd(9, 1)) 98558951Seric printf("getauthinfo: %s\n", hbuf); 98658951Seric return hbuf; 98758951Seric } 98858951Seric 98966761Seric if (RealHostName == NULL) 99066761Seric { 99166761Seric /* translate that to a host name */ 99266761Seric RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 99366761Seric } 99466761Seric 995*68612Seric #if IDENTPROTO 99665831Seric if (TimeOuts.to_ident == 0) 99765831Seric goto noident; 99865831Seric 99958951Seric lalen = sizeof la; 100066761Seric if (RealHostAddr.sa.sa_family != AF_INET || 100158951Seric getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 100258951Seric la.sa.sa_family != AF_INET) 100358951Seric { 100458951Seric /* no ident info */ 100558951Seric goto noident; 100658951Seric } 100758951Seric 100858951Seric /* create ident query */ 100968457Seric (void) sprintf(ibuf, "%d,%d\r\n", 101066761Seric ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port)); 101158951Seric 101258951Seric /* create local address */ 101364747Seric la.sin.sin_port = 0; 101458951Seric 101558951Seric /* create foreign address */ 101658951Seric sp = getservbyname("auth", "tcp"); 101758951Seric if (sp != NULL) 101866761Seric RealHostAddr.sin.sin_port = sp->s_port; 101958308Seric else 102066761Seric RealHostAddr.sin.sin_port = htons(113); 102158951Seric 102258951Seric s = -1; 102358951Seric if (setjmp(CtxAuthTimeout) != 0) 102458951Seric { 102558951Seric if (s >= 0) 102658951Seric (void) close(s); 102758951Seric goto noident; 102858951Seric } 102958951Seric 103058951Seric /* put a timeout around the whole thing */ 103164255Seric ev = setevent(TimeOuts.to_ident, authtimeout, 0); 103258951Seric 103364747Seric /* connect to foreign IDENT server using same address as SMTP socket */ 103458951Seric s = socket(AF_INET, SOCK_STREAM, 0); 103558951Seric if (s < 0) 103658951Seric { 103758951Seric clrevent(ev); 103858951Seric goto noident; 103958951Seric } 104064747Seric if (bind(s, &la.sa, sizeof la.sin) < 0 || 104166761Seric connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0) 104258951Seric { 104366011Seric goto closeident; 104458951Seric } 104558951Seric 104658957Seric if (tTd(9, 10)) 104768457Seric printf("getauthinfo: sent %s", ibuf); 104858951Seric 104958951Seric /* send query */ 105068457Seric if (write(s, ibuf, strlen(ibuf)) < 0) 105158951Seric goto closeident; 105258951Seric 105358951Seric /* get result */ 105468457Seric p = &ibuf[0]; 105568525Seric nleft = sizeof ibuf - 1; 105668444Seric while ((i = read(s, p, nleft)) > 0) 105768444Seric { 105868444Seric p += i; 105968444Seric nleft -= i; 106068444Seric } 106158951Seric (void) close(s); 106258951Seric clrevent(ev); 106368457Seric if (i < 0 || p == &ibuf[0]) 106458951Seric goto noident; 106558951Seric 106668444Seric if (*--p == '\n' && *--p == '\r') 106768444Seric p--; 106868444Seric *++p = '\0'; 106968444Seric 107058957Seric if (tTd(9, 3)) 107168457Seric printf("getauthinfo: got %s\n", ibuf); 107258951Seric 107358951Seric /* parse result */ 107468457Seric p = strchr(ibuf, ':'); 107558951Seric if (p == NULL) 107658951Seric { 107758951Seric /* malformed response */ 107858951Seric goto noident; 107958951Seric } 108058951Seric while (isascii(*++p) && isspace(*p)) 108158951Seric continue; 108258951Seric if (strncasecmp(p, "userid", 6) != 0) 108358951Seric { 108458951Seric /* presumably an error string */ 108558951Seric goto noident; 108658951Seric } 108758951Seric p += 6; 108858951Seric while (isascii(*p) && isspace(*p)) 108958951Seric p++; 109058951Seric if (*p++ != ':') 109158951Seric { 109258951Seric /* either useridxx or malformed response */ 109358951Seric goto noident; 109458951Seric } 109558951Seric 109658951Seric /* p now points to the OSTYPE field */ 109758951Seric p = strchr(p, ':'); 109858951Seric if (p == NULL) 109958951Seric { 110058951Seric /* malformed response */ 110158951Seric goto noident; 110258951Seric } 110358951Seric 110458957Seric /* 1413 says don't do this -- but it's broken otherwise */ 110558957Seric while (isascii(*++p) && isspace(*p)) 110658957Seric continue; 110758957Seric 110867935Seric /* p now points to the authenticated name -- copy carefully */ 110968457Seric cleanstrcpy(hbuf, p, MAXNAME); 1110*68612Seric i = strlen(hbuf); 111167935Seric hbuf[i++] = '@'; 111267935Seric strcpy(&hbuf[i], RealHostName == NULL ? "localhost" : RealHostName); 111358957Seric goto finish; 111458957Seric 111566011Seric closeident: 111666011Seric (void) close(s); 111766011Seric clrevent(ev); 111866011Seric 1119*68612Seric #endif /* IDENTPROTO */ 1120*68612Seric 112158957Seric noident: 112266003Seric if (RealHostName == NULL) 112366003Seric { 112466003Seric if (tTd(9, 1)) 112566003Seric printf("getauthinfo: NULL\n"); 112666003Seric return NULL; 112766003Seric } 112858957Seric (void) strcpy(hbuf, RealHostName); 112958957Seric 113058957Seric finish: 113166003Seric if (RealHostName != NULL && RealHostName[0] != '[') 113258951Seric { 113358951Seric p = &hbuf[strlen(hbuf)]; 113458951Seric (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 113558951Seric } 113658957Seric if (tTd(9, 1)) 113758951Seric printf("getauthinfo: %s\n", hbuf); 113858308Seric return hbuf; 113958308Seric } 114058308Seric /* 114160089Seric ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 114253751Seric ** 114353751Seric ** Parameters: 114456823Seric ** map -- a pointer to this map (unused). 114560089Seric ** name -- the (presumably unqualified) hostname. 114660257Seric ** av -- unused -- for compatibility with other mapping 114755019Seric ** functions. 114859084Seric ** statp -- an exit status (out parameter) -- set to 114959084Seric ** EX_TEMPFAIL if the name server is unavailable. 115053751Seric ** 115153751Seric ** Returns: 115253751Seric ** The mapping, if found. 115353751Seric ** NULL if no mapping found. 115453751Seric ** 115553751Seric ** Side Effects: 115653751Seric ** Looks up the host specified in hbuf. If it is not 115753751Seric ** the canonical name for that host, return the canonical 115853751Seric ** name. 115953751Seric */ 116051315Seric 116153751Seric char * 116260257Seric host_map_lookup(map, name, av, statp) 116356823Seric MAP *map; 116460089Seric char *name; 116560257Seric char **av; 116659084Seric int *statp; 116716911Seric { 116816911Seric register struct hostent *hp; 1169*68612Seric u_long in_addr; 117056823Seric char *cp; 1171*68612Seric int i; 117259671Seric register STAB *s; 1173*68612Seric char hbuf[MAXNAME]; 117459671Seric extern struct hostent *gethostbyaddr(); 117566334Seric #if NAMED_BIND 117659671Seric extern int h_errno; 117766029Seric #endif 117816911Seric 117925574Smiriam /* 118059671Seric ** See if we have already looked up this name. If so, just 118159671Seric ** return it. 118259671Seric */ 118353751Seric 118460089Seric s = stab(name, ST_NAMECANON, ST_ENTER); 118559671Seric if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 118659671Seric { 118759986Seric if (tTd(9, 1)) 118860089Seric printf("host_map_lookup(%s) => CACHE %s\n", 118960089Seric name, s->s_namecanon.nc_cname); 119059671Seric errno = s->s_namecanon.nc_errno; 119166334Seric #if NAMED_BIND 119259671Seric h_errno = s->s_namecanon.nc_herrno; 119366029Seric #endif 119459671Seric *statp = s->s_namecanon.nc_stat; 119564797Seric if (CurEnv->e_message == NULL && *statp == EX_TEMPFAIL) 119665199Seric { 119765199Seric sprintf(hbuf, "%s: Name server timeout", 119865199Seric shortenstring(name, 33)); 119965199Seric CurEnv->e_message = newstr(hbuf); 120065199Seric } 120159671Seric return s->s_namecanon.nc_cname; 120259671Seric } 120359671Seric 120459671Seric /* 120559671Seric ** If first character is a bracket, then it is an address 120659671Seric ** lookup. Address is copied into a temporary buffer to 120760089Seric ** strip the brackets and to preserve name if address is 120859671Seric ** unknown. 120959671Seric */ 121059671Seric 121160089Seric if (*name != '[') 121253751Seric { 121355019Seric extern bool getcanonname(); 121455019Seric 121558798Seric if (tTd(9, 1)) 121660089Seric printf("host_map_lookup(%s) => ", name); 121759671Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 1218*68612Seric (void) strcpy(hbuf, name); 121963842Seric if (getcanonname(hbuf, sizeof hbuf - 1, TRUE)) 122058796Seric { 122158796Seric if (tTd(9, 1)) 122258796Seric printf("%s\n", hbuf); 122360257Seric cp = map_rewrite(map, hbuf, strlen(hbuf), av); 122460257Seric s->s_namecanon.nc_cname = newstr(cp); 122560257Seric return cp; 122658796Seric } 122753751Seric else 122858796Seric { 122959084Seric register struct hostent *hp; 123059084Seric 123166029Seric s->s_namecanon.nc_errno = errno; 123266334Seric #if NAMED_BIND 123366029Seric s->s_namecanon.nc_herrno = h_errno; 123458796Seric if (tTd(9, 1)) 123559084Seric printf("FAIL (%d)\n", h_errno); 123659084Seric switch (h_errno) 123759084Seric { 123859084Seric case TRY_AGAIN: 123959596Seric if (UseNameServer) 124059734Seric { 124165202Seric sprintf(hbuf, "%s: Name server timeout", 124265199Seric shortenstring(name, 33)); 124365202Seric message("%s", hbuf); 124459734Seric if (CurEnv->e_message == NULL) 124565202Seric CurEnv->e_message = newstr(hbuf); 124659734Seric } 124759084Seric *statp = EX_TEMPFAIL; 124859084Seric break; 124959084Seric 125059084Seric case HOST_NOT_FOUND: 125159084Seric *statp = EX_NOHOST; 125259084Seric break; 125359084Seric 125459084Seric case NO_RECOVERY: 125559084Seric *statp = EX_SOFTWARE; 125659084Seric break; 125759084Seric 125859084Seric default: 125959084Seric *statp = EX_UNAVAILABLE; 126059084Seric break; 126159084Seric } 126266029Seric #else 126366029Seric if (tTd(9, 1)) 126466029Seric printf("FAIL\n"); 126566029Seric *statp = EX_NOHOST; 126666029Seric #endif 126759671Seric s->s_namecanon.nc_stat = *statp; 1268*68612Seric if (*statp != EX_TEMPFAIL || UseNameServer) 126959084Seric return NULL; 127059084Seric 127159084Seric /* 127259084Seric ** Try to look it up in /etc/hosts 127359084Seric */ 127459084Seric 127560089Seric hp = gethostbyname(name); 127659084Seric if (hp == NULL) 127759084Seric { 127859084Seric /* no dice there either */ 127959671Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 128059084Seric return NULL; 128159084Seric } 128259084Seric 128359671Seric s->s_namecanon.nc_stat = *statp = EX_OK; 128460257Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 128560257Seric s->s_namecanon.nc_cname = newstr(cp); 128660257Seric return cp; 128758796Seric } 128853751Seric } 128960089Seric if ((cp = strchr(name, ']')) == NULL) 129053751Seric return (NULL); 129140994Sbostic *cp = '\0'; 1292*68612Seric in_addr = inet_addr(&name[1]); 129358110Seric 129458110Seric /* nope -- ask the name server */ 1295*68612Seric hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET); 129659671Seric s->s_namecanon.nc_errno = errno; 129766334Seric #if NAMED_BIND 129859671Seric s->s_namecanon.nc_herrno = h_errno; 129966029Seric #endif 130059671Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 130133932Sbostic if (hp == NULL) 130259671Seric { 130359671Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 130453751Seric return (NULL); 130559671Seric } 130653751Seric 130758110Seric /* found a match -- copy out */ 130860257Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 130959671Seric s->s_namecanon.nc_stat = *statp = EX_OK; 131060257Seric s->s_namecanon.nc_cname = newstr(cp); 131160257Seric return cp; 131233932Sbostic } 131358755Seric /* 131458755Seric ** ANYNET_NTOA -- convert a network address to printable form. 131558755Seric ** 131658755Seric ** Parameters: 131758755Seric ** sap -- a pointer to a sockaddr structure. 131858755Seric ** 131958755Seric ** Returns: 132058755Seric ** A printable version of that sockaddr. 132158755Seric */ 132216911Seric 132358755Seric char * 132458755Seric anynet_ntoa(sap) 132558755Seric register SOCKADDR *sap; 132658755Seric { 132758755Seric register char *bp; 132858755Seric register char *ap; 132958755Seric int l; 133064734Seric static char buf[100]; 133158755Seric 133258798Seric /* check for null/zero family */ 133358798Seric if (sap == NULL) 133458798Seric return "NULLADDR"; 133558798Seric if (sap->sa.sa_family == 0) 133658798Seric return "0"; 133758798Seric 133864734Seric switch (sap->sa.sa_family) 133964734Seric { 1340*68612Seric #ifdef MAYBENEXTRELEASE /*** UNTESTED *** UNTESTED *** UNTESTED ***/ 134164821Seric #ifdef NETUNIX 134264734Seric case AF_UNIX: 134364758Seric if (sap->sunix.sun_path[0] != '\0') 134464758Seric sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 134564734Seric else 134664734Seric sprintf(buf, "[UNIX: localhost]"); 134764734Seric return buf; 134864734Seric #endif 1349*68612Seric #endif 135064734Seric 135158778Seric #ifdef NETINET 135264734Seric case AF_INET: 135358755Seric return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 135458778Seric #endif 135558755Seric 135664734Seric default: 135764734Seric /* this case is only to ensure syntactic correctness */ 135864734Seric break; 135964734Seric } 136064734Seric 136158755Seric /* unknown family -- just dump bytes */ 136258778Seric (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 136358755Seric bp = &buf[strlen(buf)]; 136458778Seric ap = sap->sa.sa_data; 136558778Seric for (l = sizeof sap->sa.sa_data; --l >= 0; ) 136658755Seric { 136758755Seric (void) sprintf(bp, "%02x:", *ap++ & 0377); 136858755Seric bp += 3; 136958755Seric } 137058755Seric *--bp = '\0'; 137158755Seric return buf; 137258755Seric } 137358951Seric /* 137458951Seric ** HOSTNAMEBYANYADDR -- return name of host based on address 137558951Seric ** 137658951Seric ** Parameters: 137758951Seric ** sap -- SOCKADDR pointer 137858951Seric ** 137958951Seric ** Returns: 138058951Seric ** text representation of host name. 138158951Seric ** 138258951Seric ** Side Effects: 138358951Seric ** none. 138458951Seric */ 138558755Seric 138658951Seric char * 138758951Seric hostnamebyanyaddr(sap) 138858951Seric register SOCKADDR *sap; 138958951Seric { 139058951Seric register struct hostent *hp; 139164734Seric int saveretry; 139258951Seric 139366334Seric #if NAMED_BIND 139459042Seric /* shorten name server timeout to avoid higher level timeouts */ 139559042Seric saveretry = _res.retry; 139659042Seric _res.retry = 3; 139759042Seric #endif /* NAMED_BIND */ 139859042Seric 139958951Seric switch (sap->sa.sa_family) 140058951Seric { 140158951Seric #ifdef NETINET 140258951Seric case AF_INET: 140358951Seric hp = gethostbyaddr((char *) &sap->sin.sin_addr, 1404*68612Seric sizeof sap->sin.sin_addr, 140558951Seric AF_INET); 140658951Seric break; 140758951Seric #endif 140858951Seric 140958951Seric #ifdef NETISO 141058951Seric case AF_ISO: 141158951Seric hp = gethostbyaddr((char *) &sap->siso.siso_addr, 141258951Seric sizeof sap->siso.siso_addr, 141358951Seric AF_ISO); 141458951Seric break; 141558951Seric #endif 141658951Seric 1417*68612Seric #ifdef MAYBENEXTRELEASE /*** UNTESTED *** UNTESTED *** UNTESTED ***/ 141864734Seric case AF_UNIX: 141964734Seric hp = NULL; 142064734Seric break; 1421*68612Seric #endif 142264734Seric 142358951Seric default: 142458951Seric hp = gethostbyaddr(sap->sa.sa_data, 142558951Seric sizeof sap->sa.sa_data, 142658951Seric sap->sa.sa_family); 142758951Seric break; 142858951Seric } 142958951Seric 143066334Seric #if NAMED_BIND 143159042Seric _res.retry = saveretry; 143259042Seric #endif /* NAMED_BIND */ 143359042Seric 143458951Seric if (hp != NULL) 143558951Seric return hp->h_name; 143658951Seric else 143758951Seric { 143858951Seric /* produce a dotted quad */ 143958951Seric static char buf[512]; 144058951Seric 144158951Seric (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 144258951Seric return buf; 144358951Seric } 144458951Seric } 144558951Seric 144656795Seric # else /* DAEMON */ 144716911Seric /* code for systems without sophisticated networking */ 144810758Seric 144910758Seric /* 145010758Seric ** MYHOSTNAME -- stub version for case of no daemon code. 145111297Seric ** 145211297Seric ** Can't convert to upper case here because might be a UUCP name. 145312313Seric ** 145412313Seric ** Mark, you can change this to be anything you want...... 145510758Seric */ 145610758Seric 145710758Seric char ** 145812313Seric myhostname(hostbuf, size) 145910758Seric char hostbuf[]; 146012313Seric int size; 146110758Seric { 146210758Seric register FILE *f; 146310758Seric 146410758Seric hostbuf[0] = '\0'; 146510758Seric f = fopen("/usr/include/whoami", "r"); 146610758Seric if (f != NULL) 146710758Seric { 146812313Seric (void) fgets(hostbuf, size, f); 146910758Seric fixcrlf(hostbuf, TRUE); 147010758Seric (void) fclose(f); 147110758Seric } 147210758Seric return (NULL); 147310758Seric } 147416911Seric /* 147558951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 147658308Seric ** 147758308Seric ** Parameters: 147858308Seric ** fd -- the descriptor 147958308Seric ** 148058308Seric ** Returns: 148158308Seric ** The host name associated with this descriptor, if it can 148258308Seric ** be determined. 148358308Seric ** NULL otherwise. 148458308Seric ** 148558308Seric ** Side Effects: 148658308Seric ** none 148758308Seric */ 148858308Seric 148958308Seric char * 149058951Seric getauthinfo(fd) 149158308Seric int fd; 149258308Seric { 149358308Seric return NULL; 149458308Seric } 149558308Seric /* 149616911Seric ** MAPHOSTNAME -- turn a hostname into canonical form 149716911Seric ** 149816911Seric ** Parameters: 149956823Seric ** map -- a pointer to the database map. 150060089Seric ** name -- a buffer containing a hostname. 150153751Seric ** avp -- a pointer to a (cf file defined) argument vector. 150259084Seric ** statp -- an exit status (out parameter). 150316911Seric ** 150416911Seric ** Returns: 150553751Seric ** mapped host name 150651315Seric ** FALSE otherwise. 150716911Seric ** 150816911Seric ** Side Effects: 150960089Seric ** Looks up the host specified in name. If it is not 151016911Seric ** the canonical name for that host, replace it with 151116911Seric ** the canonical name. If the name is unknown, or it 151216911Seric ** is already the canonical name, leave it unchanged. 151316911Seric */ 151410758Seric 151516911Seric /*ARGSUSED*/ 151653751Seric char * 151760089Seric host_map_lookup(map, name, avp, statp) 151856823Seric MAP *map; 151960089Seric char *name; 152053751Seric char **avp; 152159084Seric char *statp; 152216911Seric { 152359084Seric register struct hostent *hp; 152459084Seric 152560089Seric hp = gethostbyname(name); 152659084Seric if (hp != NULL) 152759084Seric return hp->h_name; 152859084Seric *statp = EX_NOHOST; 152953751Seric return NULL; 153016911Seric } 153116911Seric 153256795Seric #endif /* DAEMON */ 1533