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*68745Seric static char sccsid[] = "@(#)daemon.c 8.77 (Berkeley) 04/08/95 (with daemon mode)"; 1533780Sbostic #else 16*68745Seric static char sccsid[] = "@(#)daemon.c 8.77 (Berkeley) 04/08/95 (without daemon mode)"; 1733780Sbostic #endif 1833780Sbostic #endif /* not lint */ 194535Seric 2033780Sbostic #ifdef DAEMON 2133780Sbostic 2264338Seric # include <arpa/inet.h> 235978Seric 2466334Seric #if NAMED_BIND 2559042Seric # include <resolv.h> 2659042Seric #endif 2759042Seric 284535Seric /* 294535Seric ** DAEMON.C -- routines to use when running as a daemon. 307556Seric ** 317556Seric ** This entire file is highly dependent on the 4.2 BSD 327556Seric ** interprocess communication primitives. No attempt has 337556Seric ** been made to make this file portable to Version 7, 347556Seric ** Version 6, MPX files, etc. If you should try such a 357556Seric ** thing yourself, I recommend chucking the entire file 367556Seric ** and starting from scratch. Basic semantics are: 377556Seric ** 387556Seric ** getrequests() 397556Seric ** Opens a port and initiates a connection. 407556Seric ** Returns in a child. Must set InChannel and 417556Seric ** OutChannel appropriately. 4210206Seric ** clrdaemon() 4310206Seric ** Close any open files associated with getting 4410206Seric ** the connection; this is used when running the queue, 4510206Seric ** etc., to avoid having extra file descriptors during 4610206Seric ** the queue run and to avoid confusing the network 4710206Seric ** code (if it cares). 4852106Seric ** makeconnection(host, port, outfile, infile, usesecureport) 497556Seric ** Make a connection to the named host on the given 507556Seric ** port. Set *outfile and *infile to the files 517556Seric ** appropriate for communication. Returns zero on 527556Seric ** success, else an exit status describing the 537556Seric ** error. 5460089Seric ** host_map_lookup(map, hbuf, avp, pstat) 5556823Seric ** Convert the entry in hbuf into a canonical form. 564535Seric */ 574535Seric /* 584535Seric ** GETREQUESTS -- open mail IPC port and get requests. 594535Seric ** 604535Seric ** Parameters: 614535Seric ** none. 624535Seric ** 634535Seric ** Returns: 644535Seric ** none. 654535Seric ** 664535Seric ** Side Effects: 674535Seric ** Waits until some interesting activity occurs. When 684535Seric ** it does, a child is created to process it, and the 694535Seric ** parent waits for completion. Return from this 709886Seric ** routine is always in the child. The file pointers 719886Seric ** "InChannel" and "OutChannel" should be set to point 729886Seric ** to the communication channel. 734535Seric */ 744535Seric 7558849Seric int DaemonSocket = -1; /* fd describing socket */ 7658849Seric SOCKADDR DaemonAddr; /* socket for incoming */ 7759783Seric int ListenQueueSize = 10; /* size of listen queue */ 7864381Seric int TcpRcvBufferSize = 0; /* size of TCP receive buffer */ 7964381Seric int TcpSndBufferSize = 0; /* size of TCP send buffer */ 8016144Seric 8168693Seric void 824535Seric getrequests() 834535Seric { 849610Seric int t; 8553751Seric bool refusingconnections = TRUE; 8658419Seric FILE *pidf; 8764828Seric int socksize; 8866793Seric #ifdef XDEBUG 8966793Seric bool j_has_dot; 9066793Seric #endif 9146928Sbostic extern void reapchild(); 927117Seric 939610Seric /* 949610Seric ** Set up the address for the mailer. 959610Seric */ 969610Seric 9758849Seric if (DaemonAddr.sin.sin_family == 0) 9858849Seric DaemonAddr.sin.sin_family = AF_INET; 9958849Seric if (DaemonAddr.sin.sin_addr.s_addr == 0) 10058849Seric DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY; 10158849Seric if (DaemonAddr.sin.sin_port == 0) 1029610Seric { 10365169Seric register struct servent *sp; 10465169Seric 10558849Seric sp = getservbyname("smtp", "tcp"); 10658849Seric if (sp == NULL) 10758849Seric { 10858909Seric syserr("554 service \"smtp\" unknown"); 10965169Seric DaemonAddr.sin.sin_port = htons(25); 11058849Seric } 11165169Seric else 11265169Seric DaemonAddr.sin.sin_port = sp->s_port; 1139610Seric } 1149610Seric 1159610Seric /* 1169610Seric ** Try to actually open the connection. 1179610Seric */ 1189610Seric 1199610Seric if (tTd(15, 1)) 12058849Seric printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port); 1219610Seric 1229610Seric /* get a socket for the SMTP connection */ 12366854Seric socksize = opendaemonsocket(TRUE); 12410347Seric 12564035Seric (void) setsignal(SIGCHLD, reapchild); 12624945Seric 12758419Seric /* write the pid to the log file for posterity */ 12858419Seric pidf = fopen(PidFile, "w"); 12958419Seric if (pidf != NULL) 13058419Seric { 13163863Seric extern char *CommandLineArgs; 13263863Seric 13363863Seric /* write the process id on line 1 */ 13458419Seric fprintf(pidf, "%d\n", getpid()); 13563863Seric 13663863Seric /* line 2 contains all command line flags */ 13763863Seric fprintf(pidf, "%s\n", CommandLineArgs); 13863863Seric 13963863Seric /* flush and close */ 14058419Seric fclose(pidf); 14158419Seric } 14258419Seric 14366793Seric #ifdef XDEBUG 14466793Seric { 14566812Seric char jbuf[MAXHOSTNAMELEN]; 14658419Seric 14768693Seric expand("\201j", jbuf, sizeof jbuf, CurEnv); 14866812Seric j_has_dot = strchr(jbuf, '.') != NULL; 14966793Seric } 15066793Seric #endif 15166793Seric 1529610Seric if (tTd(15, 1)) 15310206Seric printf("getrequests: %d\n", DaemonSocket); 1549610Seric 1554631Seric for (;;) 1564631Seric { 15714875Seric register int pid; 15811147Seric auto int lotherend; 15953751Seric extern bool refuseconnections(); 16068693Seric extern int getla(); 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 17968693Seric /* arrange to (re)open the socket if necessary */ 18053751Seric if (refusingconnections) 18153751Seric { 18267690Seric (void) opendaemonsocket(FALSE); 18353751Seric setproctitle("accepting connections"); 18453751Seric refusingconnections = FALSE; 18553751Seric } 18653751Seric 18766793Seric #ifdef XDEBUG 18866793Seric /* check for disaster */ 18966793Seric { 19066812Seric char jbuf[MAXHOSTNAMELEN]; 19166793Seric 19268693Seric expand("\201j", jbuf, sizeof jbuf, CurEnv); 19368693Seric if (!wordinclass(jbuf, 'w')) 19466793Seric { 19566793Seric dumpstate("daemon lost $j"); 19666793Seric syslog(LOG_ALERT, "daemon process doesn't have $j in $=w; see syslog"); 19766793Seric abort(); 19866793Seric } 19966812Seric else if (j_has_dot && strchr(jbuf, '.') == NULL) 20066793Seric { 20166793Seric dumpstate("daemon $j lost dot"); 20266793Seric syslog(LOG_ALERT, "daemon process $j lost dot; see syslog"); 20366793Seric abort(); 20466793Seric } 20566793Seric } 20666793Seric #endif 20766793Seric 2089610Seric /* wait for a connection */ 2099610Seric do 2109610Seric { 2119610Seric errno = 0; 21264828Seric lotherend = socksize; 21346928Sbostic t = accept(DaemonSocket, 21446928Sbostic (struct sockaddr *)&RealHostAddr, &lotherend); 2159610Seric } while (t < 0 && errno == EINTR); 2169610Seric if (t < 0) 2175978Seric { 2189610Seric syserr("getrequests: accept"); 21968693Seric 22068693Seric /* arrange to re-open the socket next time around */ 22168693Seric (void) close(DaemonSocket); 22268693Seric DaemonSocket = -1; 2239610Seric sleep(5); 2249610Seric continue; 2255978Seric } 2264631Seric 2275978Seric /* 2285978Seric ** Create a subprocess to process the mail. 2295978Seric */ 2305978Seric 2317677Seric if (tTd(15, 2)) 2329610Seric printf("getrequests: forking (fd = %d)\n", t); 2335978Seric 2344636Seric pid = fork(); 2354636Seric if (pid < 0) 2364631Seric { 2374636Seric syserr("daemon: cannot fork"); 2384636Seric sleep(10); 2399610Seric (void) close(t); 2404636Seric continue; 2414631Seric } 2424631Seric 2434636Seric if (pid == 0) 2444631Seric { 24564086Seric char *p; 24658951Seric extern char *hostnamebyanyaddr(); 24768693Seric extern void intsig(); 24811147Seric 2494636Seric /* 2504636Seric ** CHILD -- return to caller. 25111147Seric ** Collect verified idea of sending host. 2524636Seric ** Verify calling user id if possible here. 2534636Seric */ 2544631Seric 25564035Seric (void) setsignal(SIGCHLD, SIG_DFL); 25668693Seric (void) setsignal(SIGHUP, intsig); 25768693Seric (void) close(DaemonSocket); 25866017Seric DisConnected = FALSE; 25924950Seric 26066032Seric setproctitle("startup with %s", 26166032Seric anynet_ntoa(&RealHostAddr)); 26266032Seric 26311147Seric /* determine host name */ 26464086Seric p = hostnamebyanyaddr(&RealHostAddr); 26564086Seric RealHostName = newstr(p); 26666032Seric setproctitle("startup with %s", p); 26758778Seric 26855173Seric #ifdef LOG 26963842Seric if (LogLevel > 11) 27055173Seric { 27155173Seric /* log connection information */ 27255173Seric syslog(LOG_INFO, "connect from %s (%s)", 27358951Seric RealHostName, anynet_ntoa(&RealHostAddr)); 27455173Seric } 27555173Seric #endif 27655173Seric 27764724Seric if ((InChannel = fdopen(t, "r")) == NULL || 27864724Seric (t = dup(t)) < 0 || 27964724Seric (OutChannel = fdopen(t, "w")) == NULL) 28064724Seric { 28164724Seric syserr("cannot open SMTP server channel, fd=%d", t); 28264724Seric exit(0); 28364724Seric } 28459254Seric 28516884Seric /* should we check for illegal connection here? XXX */ 28659156Seric #ifdef XLA 28759156Seric if (!xla_host_ok(RealHostName)) 28859156Seric { 28959254Seric message("421 Too many SMTP sessions for this host"); 29059156Seric exit(0); 29159156Seric } 29259156Seric #endif 29316884Seric 2947677Seric if (tTd(15, 2)) 2955978Seric printf("getreq: returning\n"); 2964636Seric return; 2974631Seric } 2984631Seric 2997117Seric /* close the port so that others will hang (for a while) */ 3009610Seric (void) close(t); 3014631Seric } 3029886Seric /*NOTREACHED*/ 3034631Seric } 3045978Seric /* 30566845Seric ** OPENDAEMONSOCKET -- open the SMTP socket 30666845Seric ** 30766845Seric ** Deals with setting all appropriate options. DaemonAddr must 30866845Seric ** be set up in advance. 30966845Seric ** 31066845Seric ** Parameters: 31166854Seric ** firsttime -- set if this is the initial open. 31266845Seric ** 31366845Seric ** Returns: 31466845Seric ** Size in bytes of the daemon socket addr. 31566845Seric ** 31666845Seric ** Side Effects: 31766845Seric ** Leaves DaemonSocket set to the open socket. 31866845Seric ** Exits if the socket cannot be created. 31966845Seric */ 32066845Seric 32166861Seric #define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 32266861Seric 32366845Seric int 32466854Seric opendaemonsocket(firsttime) 32566854Seric bool firsttime; 32666845Seric { 32766845Seric int on = 1; 32868693Seric int socksize = 0; 32966861Seric int ntries = 0; 33066861Seric int saveerrno; 33166845Seric 33266845Seric if (tTd(15, 2)) 33366845Seric printf("opendaemonsocket()\n"); 33466845Seric 33566861Seric do 33666845Seric { 33766862Seric if (ntries > 0) 33866862Seric sleep(5); 33966861Seric if (firsttime || DaemonSocket < 0) 34066854Seric { 34166861Seric DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0); 34266861Seric if (DaemonSocket < 0) 34366861Seric { 34466861Seric /* probably another daemon already */ 34566861Seric saveerrno = errno; 34666861Seric syserr("opendaemonsocket: can't create server SMTP socket"); 34766861Seric severe: 34866845Seric # ifdef LOG 34966861Seric if (LogLevel > 0) 35066861Seric syslog(LOG_ALERT, "problem creating SMTP socket"); 35166845Seric # endif /* LOG */ 35266861Seric DaemonSocket = -1; 35366861Seric continue; 35466861Seric } 35566845Seric 35666861Seric /* turn on network debugging? */ 35766861Seric if (tTd(15, 101)) 35866861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 35966861Seric SO_DEBUG, (char *)&on, 36066861Seric sizeof on); 36166845Seric 36266861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 36366861Seric SO_REUSEADDR, (char *)&on, sizeof on); 36466861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 36566861Seric SO_KEEPALIVE, (char *)&on, sizeof on); 36666845Seric 36766845Seric #ifdef SO_RCVBUF 36866861Seric if (TcpRcvBufferSize > 0) 36966861Seric { 37066861Seric if (setsockopt(DaemonSocket, SOL_SOCKET, 37166861Seric SO_RCVBUF, 37266861Seric (char *) &TcpRcvBufferSize, 37366861Seric sizeof(TcpRcvBufferSize)) < 0) 37466861Seric syserr("getrequests: setsockopt(SO_RCVBUF)"); 37566861Seric } 37666845Seric #endif 37766845Seric 37866861Seric switch (DaemonAddr.sa.sa_family) 37966861Seric { 38066845Seric # ifdef NETINET 38166861Seric case AF_INET: 38266861Seric socksize = sizeof DaemonAddr.sin; 38366861Seric break; 38466845Seric # endif 38566845Seric 38666845Seric # ifdef NETISO 38766861Seric case AF_ISO: 38866861Seric socksize = sizeof DaemonAddr.siso; 38966861Seric break; 39066845Seric # endif 39166845Seric 39266861Seric default: 39366861Seric socksize = sizeof DaemonAddr; 39466861Seric break; 39566861Seric } 39666861Seric 39766861Seric if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0) 39866861Seric { 39966861Seric saveerrno = errno; 40066861Seric syserr("getrequests: cannot bind"); 40166861Seric (void) close(DaemonSocket); 40266861Seric goto severe; 40366861Seric } 40466854Seric } 40566861Seric if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0) 40666854Seric { 40766861Seric saveerrno = errno; 40866861Seric syserr("getrequests: cannot listen"); 40966854Seric (void) close(DaemonSocket); 41066854Seric goto severe; 41166854Seric } 41266861Seric return socksize; 41366861Seric } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno)); 41468693Seric syserr("!opendaemonsocket: server SMTP socket wedged: exiting"); 41566861Seric finis(); 41666845Seric } 41766845Seric /* 41810206Seric ** CLRDAEMON -- reset the daemon connection 41910206Seric ** 42010206Seric ** Parameters: 42110206Seric ** none. 42210206Seric ** 42310206Seric ** Returns: 42410206Seric ** none. 42510206Seric ** 42610206Seric ** Side Effects: 42710206Seric ** releases any resources used by the passive daemon. 42810206Seric */ 42910206Seric 43068693Seric void 43110206Seric clrdaemon() 43210206Seric { 43310206Seric if (DaemonSocket >= 0) 43410206Seric (void) close(DaemonSocket); 43510206Seric DaemonSocket = -1; 43610206Seric } 43710206Seric /* 43858849Seric ** SETDAEMONOPTIONS -- set options for running the daemon 43958849Seric ** 44058849Seric ** Parameters: 44158849Seric ** p -- the options line. 44258849Seric ** 44358849Seric ** Returns: 44458849Seric ** none. 44558849Seric */ 44658849Seric 44768693Seric void 44858849Seric setdaemonoptions(p) 44958849Seric register char *p; 45058849Seric { 45158873Seric if (DaemonAddr.sa.sa_family == AF_UNSPEC) 45258873Seric DaemonAddr.sa.sa_family = AF_INET; 45358873Seric 45458849Seric while (p != NULL) 45558849Seric { 45658849Seric register char *f; 45758849Seric register char *v; 45858849Seric 45958849Seric while (isascii(*p) && isspace(*p)) 46058849Seric p++; 46158849Seric if (*p == '\0') 46258849Seric break; 46358849Seric f = p; 46458849Seric p = strchr(p, ','); 46558849Seric if (p != NULL) 46658849Seric *p++ = '\0'; 46758849Seric v = strchr(f, '='); 46858849Seric if (v == NULL) 46958849Seric continue; 47058849Seric while (isascii(*++v) && isspace(*v)) 47158849Seric continue; 47258849Seric 47358849Seric switch (*f) 47458849Seric { 47558873Seric case 'F': /* address family */ 47658849Seric if (isascii(*v) && isdigit(*v)) 47758873Seric DaemonAddr.sa.sa_family = atoi(v); 47858873Seric #ifdef NETINET 47958873Seric else if (strcasecmp(v, "inet") == 0) 48058873Seric DaemonAddr.sa.sa_family = AF_INET; 48158873Seric #endif 48258873Seric #ifdef NETISO 48358873Seric else if (strcasecmp(v, "iso") == 0) 48458873Seric DaemonAddr.sa.sa_family = AF_ISO; 48558873Seric #endif 48658873Seric #ifdef NETNS 48758873Seric else if (strcasecmp(v, "ns") == 0) 48858873Seric DaemonAddr.sa.sa_family = AF_NS; 48958873Seric #endif 49058873Seric #ifdef NETX25 49158873Seric else if (strcasecmp(v, "x.25") == 0) 49258873Seric DaemonAddr.sa.sa_family = AF_CCITT; 49358873Seric #endif 49458849Seric else 49558873Seric syserr("554 Unknown address family %s in Family=option", v); 49658873Seric break; 49758873Seric 49858873Seric case 'A': /* address */ 49958873Seric switch (DaemonAddr.sa.sa_family) 50058849Seric { 50158873Seric #ifdef NETINET 50258873Seric case AF_INET: 50358873Seric if (isascii(*v) && isdigit(*v)) 50468693Seric DaemonAddr.sin.sin_addr.s_addr = htonl(inet_network(v)); 50558873Seric else 50658873Seric { 50758873Seric register struct netent *np; 50858849Seric 50958873Seric np = getnetbyname(v); 51058873Seric if (np == NULL) 51158873Seric syserr("554 network \"%s\" unknown", v); 51258873Seric else 51358873Seric DaemonAddr.sin.sin_addr.s_addr = np->n_net; 51458873Seric } 51558873Seric break; 51658873Seric #endif 51758873Seric 51858873Seric default: 51958873Seric syserr("554 Address= option unsupported for family %d", 52058873Seric DaemonAddr.sa.sa_family); 52158873Seric break; 52258849Seric } 52358849Seric break; 52458849Seric 52558873Seric case 'P': /* port */ 52658873Seric switch (DaemonAddr.sa.sa_family) 52758849Seric { 52858873Seric short port; 52958849Seric 53058873Seric #ifdef NETINET 53158873Seric case AF_INET: 53258873Seric if (isascii(*v) && isdigit(*v)) 53364366Seric DaemonAddr.sin.sin_port = htons(atoi(v)); 53458849Seric else 53558873Seric { 53658873Seric register struct servent *sp; 53758873Seric 53858873Seric sp = getservbyname(v, "tcp"); 53958873Seric if (sp == NULL) 54058909Seric syserr("554 service \"%s\" unknown", v); 54158873Seric else 54258873Seric DaemonAddr.sin.sin_port = sp->s_port; 54358873Seric } 54458873Seric break; 54558873Seric #endif 54658873Seric 54758873Seric #ifdef NETISO 54858873Seric case AF_ISO: 54958873Seric /* assume two byte transport selector */ 55058873Seric if (isascii(*v) && isdigit(*v)) 55164366Seric port = htons(atoi(v)); 55258873Seric else 55358873Seric { 55458873Seric register struct servent *sp; 55558873Seric 55658873Seric sp = getservbyname(v, "tcp"); 55758873Seric if (sp == NULL) 55858909Seric syserr("554 service \"%s\" unknown", v); 55958873Seric else 56058873Seric port = sp->s_port; 56158873Seric } 56258873Seric bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 56358873Seric break; 56458873Seric #endif 56558873Seric 56658873Seric default: 56758873Seric syserr("554 Port= option unsupported for family %d", 56858873Seric DaemonAddr.sa.sa_family); 56958873Seric break; 57058849Seric } 57158849Seric break; 57259783Seric 57359783Seric case 'L': /* listen queue size */ 57459783Seric ListenQueueSize = atoi(v); 57559783Seric break; 57664381Seric 57764381Seric case 'S': /* send buffer size */ 57864381Seric TcpSndBufferSize = atoi(v); 57964381Seric break; 58064381Seric 58164381Seric case 'R': /* receive buffer size */ 58264381Seric TcpRcvBufferSize = atoi(v); 58364381Seric break; 58458849Seric } 58558849Seric } 58658849Seric } 58758849Seric /* 5886039Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 5896039Seric ** 5906039Seric ** Parameters: 5916039Seric ** host -- the name of the host. 5926633Seric ** port -- the port number to connect to. 59353739Seric ** mci -- a pointer to the mail connection information 59453739Seric ** structure to be filled in. 59552106Seric ** usesecureport -- if set, use a low numbered (reserved) 59652106Seric ** port to provide some rudimentary authentication. 5976039Seric ** 5986039Seric ** Returns: 5996039Seric ** An exit code telling whether the connection could be 6006039Seric ** made and if not why not. 6016039Seric ** 6026039Seric ** Side Effects: 6036039Seric ** none. 6046039Seric */ 6055978Seric 60658755Seric SOCKADDR CurHostAddr; /* address of current host */ 60758305Seric 60854967Seric int 60953739Seric makeconnection(host, port, mci, usesecureport) 6106039Seric char *host; 6117286Seric u_short port; 61254967Seric register MCI *mci; 61352106Seric bool usesecureport; 6146039Seric { 61568693Seric register int i = 0; 61668693Seric register int s; 61729430Sbloom register struct hostent *hp = (struct hostent *)NULL; 61858755Seric SOCKADDR addr; 61952106Seric int sav_errno; 62058755Seric int addrlen; 62168693Seric bool firstconnect; 62266334Seric #if NAMED_BIND 62335651Seric extern int h_errno; 62435651Seric #endif 6256039Seric 6266039Seric /* 6276039Seric ** Set up the address for the mailer. 6289308Seric ** Accept "[a.b.c.d]" syntax for host name. 6296039Seric */ 6306039Seric 63166334Seric #if NAMED_BIND 63225475Smiriam h_errno = 0; 63335651Seric #endif 63425475Smiriam errno = 0; 63558864Seric bzero(&CurHostAddr, sizeof CurHostAddr); 63664334Seric SmtpPhase = mci->mci_phase = "initial connection"; 63758906Seric CurHostName = host; 63825475Smiriam 6399308Seric if (host[0] == '[') 6409308Seric { 64111147Seric long hid; 64256795Seric register char *p = strchr(host, ']'); 6439308Seric 64411147Seric if (p != NULL) 6459308Seric { 64611147Seric *p = '\0'; 64759884Seric #ifdef NETINET 64811147Seric hid = inet_addr(&host[1]); 64958360Seric if (hid == -1) 65059884Seric #endif 65158360Seric { 65258360Seric /* try it as a host name (avoid MX lookup) */ 65368693Seric hp = sm_gethostbyname(&host[1]); 65466349Seric if (hp == NULL && p[-1] == '.') 65566349Seric { 65668693Seric #if NAMED_BIND 65768693Seric int oldopts = _res.options; 65868693Seric 65968693Seric _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 66068693Seric #endif 66166349Seric p[-1] = '\0'; 66268693Seric hp = sm_gethostbyname(&host[1]); 66366349Seric p[-1] = '.'; 66468693Seric #if NAMED_BIND 66568693Seric _res.options = oldopts; 66668693Seric #endif 66766349Seric } 66858360Seric *p = ']'; 66958360Seric goto gothostent; 67058360Seric } 67111147Seric *p = ']'; 6729308Seric } 67358360Seric if (p == NULL) 6749308Seric { 67558151Seric usrerr("553 Invalid numeric domain spec \"%s\"", host); 6769308Seric return (EX_NOHOST); 6779308Seric } 67859884Seric #ifdef NETINET 67959884Seric addr.sin.sin_family = AF_INET; /*XXX*/ 68058778Seric addr.sin.sin_addr.s_addr = hid; 68159884Seric #endif 6829308Seric } 6839610Seric else 6849610Seric { 68566349Seric register char *p = &host[strlen(host) - 1]; 68666349Seric 68768693Seric hp = sm_gethostbyname(host); 68866349Seric if (hp == NULL && *p == '.') 68966349Seric { 69068693Seric #if NAMED_BIND 69168693Seric int oldopts = _res.options; 69268693Seric 69368693Seric _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 69468693Seric #endif 69566349Seric *p = '\0'; 69668693Seric hp = sm_gethostbyname(host); 69766349Seric *p = '.'; 69868693Seric #if NAMED_BIND 69968693Seric _res.options = oldopts; 70068693Seric #endif 70166349Seric } 70258360Seric gothostent: 70325475Smiriam if (hp == NULL) 70424945Seric { 70566334Seric #if NAMED_BIND 70668693Seric /* check for name server timeouts */ 70768693Seric if (errno == ETIMEDOUT || h_errno == TRY_AGAIN || 70868693Seric (errno == ECONNREFUSED && UseNameServer)) 70968693Seric { 71068693Seric mci->mci_status = "4.4.3"; 71125475Smiriam return (EX_TEMPFAIL); 71268693Seric } 71335651Seric #endif 71425475Smiriam return (EX_NOHOST); 71524945Seric } 71658778Seric addr.sa.sa_family = hp->h_addrtype; 71758778Seric switch (hp->h_addrtype) 71858778Seric { 71958778Seric #ifdef NETINET 72058778Seric case AF_INET: 72158755Seric bcopy(hp->h_addr, 72258778Seric &addr.sin.sin_addr, 72368693Seric INADDRSZ); 72458778Seric break; 72558778Seric #endif 72658778Seric 72758778Seric default: 72858755Seric bcopy(hp->h_addr, 72958778Seric addr.sa.sa_data, 73058755Seric hp->h_length); 73158778Seric break; 73258778Seric } 73329430Sbloom i = 1; 7349610Seric } 7359610Seric 7369610Seric /* 7379610Seric ** Determine the port number. 7389610Seric */ 7399610Seric 74010011Seric if (port != 0) 74158755Seric port = htons(port); 74210011Seric else 7439610Seric { 7449610Seric register struct servent *sp = getservbyname("smtp", "tcp"); 7459610Seric 7469610Seric if (sp == NULL) 7479610Seric { 748*68745Seric #ifdef LOG 749*68745Seric if (LogLevel > 2) 750*68745Seric syslog(LOG_ERR, "makeconnection: service \"smtp\" unknown"); 751*68745Seric #endif 75265169Seric port = htons(25); 7539610Seric } 75465169Seric else 75565169Seric port = sp->s_port; 7569610Seric } 7576039Seric 75858778Seric switch (addr.sa.sa_family) 75958755Seric { 76059884Seric #ifdef NETINET 76158755Seric case AF_INET: 76258778Seric addr.sin.sin_port = port; 76358755Seric addrlen = sizeof (struct sockaddr_in); 76458755Seric break; 76559884Seric #endif 76658755Seric 76758755Seric #ifdef NETISO 76858755Seric case AF_ISO: 76958755Seric /* assume two byte transport selector */ 77058755Seric bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 77158755Seric addrlen = sizeof (struct sockaddr_iso); 77258755Seric break; 77358755Seric #endif 77458755Seric 77558755Seric default: 77658778Seric syserr("Can't connect to address family %d", addr.sa.sa_family); 77758755Seric return (EX_NOHOST); 77858755Seric } 77958755Seric 7806039Seric /* 7816039Seric ** Try to actually open the connection. 7826039Seric */ 7836039Seric 78459156Seric #ifdef XLA 78559156Seric /* if too many connections, don't bother trying */ 78659156Seric if (!xla_noqueue_ok(host)) 78759156Seric return EX_TEMPFAIL; 78859156Seric #endif 78959156Seric 79068693Seric firstconnect = TRUE; 79157736Seric for (;;) 79252106Seric { 79357736Seric if (tTd(16, 1)) 79458755Seric printf("makeconnection (%s [%s])\n", 79558755Seric host, anynet_ntoa(&addr)); 79652106Seric 79758588Seric /* save for logging */ 79858588Seric CurHostAddr = addr; 79958588Seric 80057736Seric if (usesecureport) 80157736Seric { 80257736Seric int rport = IPPORT_RESERVED - 1; 8036039Seric 80457736Seric s = rresvport(&rport); 80557736Seric } 80657736Seric else 80757736Seric { 80857736Seric s = socket(AF_INET, SOCK_STREAM, 0); 80957736Seric } 81057736Seric if (s < 0) 81157736Seric { 81257736Seric sav_errno = errno; 81357736Seric syserr("makeconnection: no socket"); 81457736Seric goto failure; 81557736Seric } 81610347Seric 81764381Seric #ifdef SO_SNDBUF 81864381Seric if (TcpSndBufferSize > 0) 81964381Seric { 82064381Seric if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 82164561Seric (char *) &TcpSndBufferSize, 82264381Seric sizeof(TcpSndBufferSize)) < 0) 82364381Seric syserr("makeconnection: setsockopt(SO_SNDBUF)"); 82464381Seric } 82564381Seric #endif 82664381Seric 82757736Seric if (tTd(16, 1)) 82857736Seric printf("makeconnection: fd=%d\n", s); 82957736Seric 83057736Seric /* turn on network debugging? */ 83157736Seric if (tTd(16, 101)) 83257736Seric { 83357736Seric int on = 1; 83466861Seric (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 83557736Seric (char *)&on, sizeof on); 83657736Seric } 83757736Seric if (CurEnv->e_xfp != NULL) 83857736Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 83957736Seric errno = 0; /* for debugging */ 84058755Seric if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 84157736Seric break; 84257736Seric 84368693Seric /* if running demand-dialed connection, try again */ 84468693Seric if (DialDelay > 0 && firstconnect) 84568693Seric { 84668693Seric if (tTd(16, 1)) 84768693Seric printf("Connect failed (%s); trying again...\n", 84868693Seric errstring(sav_errno)); 84968693Seric firstconnect = FALSE; 85068693Seric sleep(DialDelay); 85168693Seric continue; 85268693Seric } 85368693Seric 85457736Seric /* couldn't connect.... figure out why */ 85527744Sbloom sav_errno = errno; 85627744Sbloom (void) close(s); 85768693Seric if (hp != NULL && hp->h_addr_list[i]) 85829430Sbloom { 85957736Seric if (tTd(16, 1)) 86058755Seric printf("Connect failed (%s); trying new address....\n", 86158755Seric errstring(sav_errno)); 86258778Seric switch (addr.sa.sa_family) 86358778Seric { 86458778Seric #ifdef NETINET 86558778Seric case AF_INET: 86658755Seric bcopy(hp->h_addr_list[i++], 86758778Seric &addr.sin.sin_addr, 86868693Seric INADDRSZ); 86958778Seric break; 87058778Seric #endif 87158778Seric 87258778Seric default: 87358755Seric bcopy(hp->h_addr_list[i++], 87458778Seric addr.sa.sa_data, 87552106Seric hp->h_length); 87658778Seric break; 87758778Seric } 87857736Seric continue; 87929430Sbloom } 88029430Sbloom 8816039Seric /* failure, decide if temporary or not */ 8826039Seric failure: 88359254Seric #ifdef XLA 88459254Seric xla_host_end(host); 88559254Seric #endif 88658542Seric if (transienterror(sav_errno)) 88758542Seric return EX_TEMPFAIL; 88858542Seric else 88958542Seric { 89058542Seric message("%s", errstring(sav_errno)); 89158542Seric return (EX_UNAVAILABLE); 8926039Seric } 8936039Seric } 8946039Seric 8956039Seric /* connection ok, put it into canonical form */ 89664724Seric if ((mci->mci_out = fdopen(s, "w")) == NULL || 89764724Seric (s = dup(s)) < 0 || 89864725Seric (mci->mci_in = fdopen(s, "r")) == NULL) 89964724Seric { 90064724Seric syserr("cannot open SMTP client channel, fd=%d", s); 90164724Seric return EX_TEMPFAIL; 90264724Seric } 9036039Seric 90410098Seric return (EX_OK); 9056039Seric } 90610758Seric /* 90710758Seric ** MYHOSTNAME -- return the name of this host. 90810758Seric ** 90910758Seric ** Parameters: 91010758Seric ** hostbuf -- a place to return the name of this host. 91112313Seric ** size -- the size of hostbuf. 91210758Seric ** 91310758Seric ** Returns: 91410758Seric ** A list of aliases for this host. 91510758Seric ** 91610758Seric ** Side Effects: 91764338Seric ** Adds numeric codes to $=w. 91810758Seric */ 9196039Seric 92068693Seric struct hostent * 92112313Seric myhostname(hostbuf, size) 92210758Seric char hostbuf[]; 92312313Seric int size; 92410758Seric { 92558110Seric register struct hostent *hp; 92668693Seric extern bool getcanonname(); 92768693Seric extern int h_errno; 92810758Seric 92923120Seric if (gethostname(hostbuf, size) < 0) 93023120Seric { 93123120Seric (void) strcpy(hostbuf, "localhost"); 93223120Seric } 93368693Seric hp = sm_gethostbyname(hostbuf); 93466853Seric if (hp == NULL) 93568693Seric return NULL; 93668693Seric if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 93767448Seric { 93868693Seric (void) strncpy(hostbuf, hp->h_name, size - 1); 93968693Seric hostbuf[size - 1] = '\0'; 94067448Seric } 94166853Seric 94266853Seric #if NAMED_BIND 94368693Seric /* 94468693Seric ** If still no dot, try DNS directly (i.e., avoid NIS problems). 94568693Seric ** This ought to be driven from the configuration file, but 94668693Seric ** we are called before the configuration is read. We could 94768693Seric ** check for an /etc/resolv.conf file, but that isn't required. 94868693Seric ** All in all, a bit of a mess. 94968693Seric */ 95068693Seric 95168693Seric if (strchr(hostbuf, '.') == NULL && 95268693Seric !getcanonname(hostbuf, size, TRUE) && 95368693Seric h_errno == TRY_AGAIN) 95468612Seric { 95566853Seric /* try twice in case name server not yet started up */ 95668693Seric message("My unqualifed host name (%s) unknown to DNS; sleeping for retry", 95768693Seric hostbuf); 95868693Seric sleep(60); 95968693Seric if (!getcanonname(hostbuf, size, TRUE)) 96066853Seric errno = h_errno + E_DNSBASE; 96166853Seric } 96266777Seric #endif 96368693Seric return (hp); 96410758Seric } 96551315Seric /* 96658951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 96758308Seric ** 96858951Seric ** Uses RFC1413 protocol to try to get info from the other end. 96958951Seric ** 97058308Seric ** Parameters: 97158308Seric ** fd -- the descriptor 97258308Seric ** 97358308Seric ** Returns: 97458951Seric ** The user@host information associated with this descriptor. 97558308Seric */ 97658308Seric 97758951Seric static jmp_buf CtxAuthTimeout; 97858951Seric 97968693Seric static void 98058951Seric authtimeout() 98158951Seric { 98258951Seric longjmp(CtxAuthTimeout, 1); 98358951Seric } 98458951Seric 98558308Seric char * 98658951Seric getauthinfo(fd) 98758308Seric int fd; 98858308Seric { 98958951Seric int falen; 99059104Seric register char *p; 99158951Seric SOCKADDR la; 99258951Seric int lalen; 99358951Seric register struct servent *sp; 99458951Seric int s; 99558951Seric int i; 99658951Seric EVENT *ev; 99768444Seric int nleft; 99868462Seric char ibuf[MAXNAME + 1]; 99958951Seric static char hbuf[MAXNAME * 2 + 2]; 100058951Seric extern char *hostnamebyanyaddr(); 100158951Seric extern char RealUserName[]; /* main.c */ 100258308Seric 100366761Seric falen = sizeof RealHostAddr; 100468693Seric if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 || 100568693Seric falen <= 0 || RealHostAddr.sa.sa_family == 0) 100658951Seric { 100758951Seric (void) sprintf(hbuf, "%s@localhost", RealUserName); 100858957Seric if (tTd(9, 1)) 100958951Seric printf("getauthinfo: %s\n", hbuf); 101058951Seric return hbuf; 101158951Seric } 101258951Seric 101366761Seric if (RealHostName == NULL) 101466761Seric { 101566761Seric /* translate that to a host name */ 101666761Seric RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 101766761Seric } 101866761Seric 101965831Seric if (TimeOuts.to_ident == 0) 102065831Seric goto noident; 102165831Seric 102258951Seric lalen = sizeof la; 102366761Seric if (RealHostAddr.sa.sa_family != AF_INET || 102458951Seric getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 102558951Seric la.sa.sa_family != AF_INET) 102658951Seric { 102758951Seric /* no ident info */ 102858951Seric goto noident; 102958951Seric } 103058951Seric 103158951Seric /* create ident query */ 103268457Seric (void) sprintf(ibuf, "%d,%d\r\n", 103366761Seric ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port)); 103458951Seric 103558951Seric /* create local address */ 103664747Seric la.sin.sin_port = 0; 103758951Seric 103858951Seric /* create foreign address */ 103958951Seric sp = getservbyname("auth", "tcp"); 104058951Seric if (sp != NULL) 104166761Seric RealHostAddr.sin.sin_port = sp->s_port; 104258308Seric else 104366761Seric RealHostAddr.sin.sin_port = htons(113); 104458951Seric 104558951Seric s = -1; 104658951Seric if (setjmp(CtxAuthTimeout) != 0) 104758951Seric { 104858951Seric if (s >= 0) 104958951Seric (void) close(s); 105058951Seric goto noident; 105158951Seric } 105258951Seric 105358951Seric /* put a timeout around the whole thing */ 105464255Seric ev = setevent(TimeOuts.to_ident, authtimeout, 0); 105558951Seric 105664747Seric /* connect to foreign IDENT server using same address as SMTP socket */ 105758951Seric s = socket(AF_INET, SOCK_STREAM, 0); 105858951Seric if (s < 0) 105958951Seric { 106058951Seric clrevent(ev); 106158951Seric goto noident; 106258951Seric } 106364747Seric if (bind(s, &la.sa, sizeof la.sin) < 0 || 106466761Seric connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0) 106558951Seric { 106666011Seric goto closeident; 106758951Seric } 106858951Seric 106958957Seric if (tTd(9, 10)) 107068457Seric printf("getauthinfo: sent %s", ibuf); 107158951Seric 107258951Seric /* send query */ 107368457Seric if (write(s, ibuf, strlen(ibuf)) < 0) 107458951Seric goto closeident; 107558951Seric 107658951Seric /* get result */ 107768457Seric p = &ibuf[0]; 107868525Seric nleft = sizeof ibuf - 1; 107968444Seric while ((i = read(s, p, nleft)) > 0) 108068444Seric { 108168444Seric p += i; 108268444Seric nleft -= i; 108368444Seric } 108458951Seric (void) close(s); 108558951Seric clrevent(ev); 108668457Seric if (i < 0 || p == &ibuf[0]) 108758951Seric goto noident; 108858951Seric 108968444Seric if (*--p == '\n' && *--p == '\r') 109068444Seric p--; 109168444Seric *++p = '\0'; 109268444Seric 109358957Seric if (tTd(9, 3)) 109468457Seric printf("getauthinfo: got %s\n", ibuf); 109558951Seric 109658951Seric /* parse result */ 109768457Seric p = strchr(ibuf, ':'); 109858951Seric if (p == NULL) 109958951Seric { 110058951Seric /* malformed response */ 110158951Seric goto noident; 110258951Seric } 110358951Seric while (isascii(*++p) && isspace(*p)) 110458951Seric continue; 110558951Seric if (strncasecmp(p, "userid", 6) != 0) 110658951Seric { 110758951Seric /* presumably an error string */ 110858951Seric goto noident; 110958951Seric } 111058951Seric p += 6; 111158951Seric while (isascii(*p) && isspace(*p)) 111258951Seric p++; 111358951Seric if (*p++ != ':') 111458951Seric { 111558951Seric /* either useridxx or malformed response */ 111658951Seric goto noident; 111758951Seric } 111858951Seric 111958951Seric /* p now points to the OSTYPE field */ 112068693Seric while (isascii(*p) && isspace(*p)) 112168693Seric p++; 112268693Seric if (strncasecmp(p, "other", 5) == 0 && 112368693Seric (p[5] == ':' || p[5] == ' ' || p[5] == ',' || p[5] == '\0')) 112468693Seric { 112568693Seric /* not useful information */ 112668693Seric goto noident; 112768693Seric } 112858951Seric p = strchr(p, ':'); 112958951Seric if (p == NULL) 113058951Seric { 113158951Seric /* malformed response */ 113258951Seric goto noident; 113358951Seric } 113458951Seric 113558957Seric /* 1413 says don't do this -- but it's broken otherwise */ 113658957Seric while (isascii(*++p) && isspace(*p)) 113758957Seric continue; 113858957Seric 113967935Seric /* p now points to the authenticated name -- copy carefully */ 114068457Seric cleanstrcpy(hbuf, p, MAXNAME); 114167935Seric hbuf[i++] = '@'; 114267935Seric strcpy(&hbuf[i], RealHostName == NULL ? "localhost" : RealHostName); 114358957Seric goto finish; 114458957Seric 114566011Seric closeident: 114666011Seric (void) close(s); 114766011Seric clrevent(ev); 114866011Seric 114958957Seric noident: 115066003Seric if (RealHostName == NULL) 115166003Seric { 115266003Seric if (tTd(9, 1)) 115366003Seric printf("getauthinfo: NULL\n"); 115466003Seric return NULL; 115566003Seric } 115658957Seric (void) strcpy(hbuf, RealHostName); 115758957Seric 115858957Seric finish: 115966003Seric if (RealHostName != NULL && RealHostName[0] != '[') 116058951Seric { 116158951Seric p = &hbuf[strlen(hbuf)]; 116258951Seric (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 116358951Seric } 116458957Seric if (tTd(9, 1)) 116558951Seric printf("getauthinfo: %s\n", hbuf); 116658308Seric return hbuf; 116758308Seric } 116858308Seric /* 116960089Seric ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 117053751Seric ** 117153751Seric ** Parameters: 117256823Seric ** map -- a pointer to this map (unused). 117360089Seric ** name -- the (presumably unqualified) hostname. 117460257Seric ** av -- unused -- for compatibility with other mapping 117555019Seric ** functions. 117659084Seric ** statp -- an exit status (out parameter) -- set to 117759084Seric ** EX_TEMPFAIL if the name server is unavailable. 117853751Seric ** 117953751Seric ** Returns: 118053751Seric ** The mapping, if found. 118153751Seric ** NULL if no mapping found. 118253751Seric ** 118353751Seric ** Side Effects: 118453751Seric ** Looks up the host specified in hbuf. If it is not 118553751Seric ** the canonical name for that host, return the canonical 118653751Seric ** name. 118753751Seric */ 118851315Seric 118953751Seric char * 119060257Seric host_map_lookup(map, name, av, statp) 119156823Seric MAP *map; 119260089Seric char *name; 119360257Seric char **av; 119459084Seric int *statp; 119516911Seric { 119616911Seric register struct hostent *hp; 119768693Seric struct in_addr in_addr; 119856823Seric char *cp; 119959671Seric register STAB *s; 120068693Seric char hbuf[MAXNAME + 1]; 120166334Seric #if NAMED_BIND 120259671Seric extern int h_errno; 120366029Seric #endif 120416911Seric 120525574Smiriam /* 120659671Seric ** See if we have already looked up this name. If so, just 120759671Seric ** return it. 120859671Seric */ 120953751Seric 121060089Seric s = stab(name, ST_NAMECANON, ST_ENTER); 121159671Seric if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 121259671Seric { 121359986Seric if (tTd(9, 1)) 121460089Seric printf("host_map_lookup(%s) => CACHE %s\n", 121560089Seric name, s->s_namecanon.nc_cname); 121659671Seric errno = s->s_namecanon.nc_errno; 121766334Seric #if NAMED_BIND 121859671Seric h_errno = s->s_namecanon.nc_herrno; 121966029Seric #endif 122059671Seric *statp = s->s_namecanon.nc_stat; 122164797Seric if (CurEnv->e_message == NULL && *statp == EX_TEMPFAIL) 122265199Seric { 122365199Seric sprintf(hbuf, "%s: Name server timeout", 122465199Seric shortenstring(name, 33)); 122565199Seric CurEnv->e_message = newstr(hbuf); 122665199Seric } 122759671Seric return s->s_namecanon.nc_cname; 122859671Seric } 122959671Seric 123059671Seric /* 123159671Seric ** If first character is a bracket, then it is an address 123259671Seric ** lookup. Address is copied into a temporary buffer to 123360089Seric ** strip the brackets and to preserve name if address is 123459671Seric ** unknown. 123559671Seric */ 123659671Seric 123760089Seric if (*name != '[') 123853751Seric { 123955019Seric extern bool getcanonname(); 124055019Seric 124158798Seric if (tTd(9, 1)) 124260089Seric printf("host_map_lookup(%s) => ", name); 124359671Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 124468693Seric if (strlen(name) < sizeof hbuf) 124568693Seric (void) strcpy(hbuf, name); 124668693Seric else 124768693Seric { 124868693Seric bcopy(name, hbuf, sizeof hbuf - 1); 124968693Seric hbuf[sizeof hbuf - 1] = '\0'; 125068693Seric } 125163842Seric if (getcanonname(hbuf, sizeof hbuf - 1, TRUE)) 125258796Seric { 125358796Seric if (tTd(9, 1)) 125458796Seric printf("%s\n", hbuf); 125560257Seric cp = map_rewrite(map, hbuf, strlen(hbuf), av); 125660257Seric s->s_namecanon.nc_cname = newstr(cp); 125760257Seric return cp; 125858796Seric } 125953751Seric else 126058796Seric { 126159084Seric register struct hostent *hp; 126259084Seric 126366029Seric s->s_namecanon.nc_errno = errno; 126466334Seric #if NAMED_BIND 126566029Seric s->s_namecanon.nc_herrno = h_errno; 126658796Seric if (tTd(9, 1)) 126759084Seric printf("FAIL (%d)\n", h_errno); 126859084Seric switch (h_errno) 126959084Seric { 127059084Seric case TRY_AGAIN: 127159596Seric if (UseNameServer) 127259734Seric { 127365202Seric sprintf(hbuf, "%s: Name server timeout", 127465199Seric shortenstring(name, 33)); 127565202Seric message("%s", hbuf); 127659734Seric if (CurEnv->e_message == NULL) 127765202Seric CurEnv->e_message = newstr(hbuf); 127859734Seric } 127959084Seric *statp = EX_TEMPFAIL; 128059084Seric break; 128159084Seric 128259084Seric case HOST_NOT_FOUND: 128359084Seric *statp = EX_NOHOST; 128459084Seric break; 128559084Seric 128659084Seric case NO_RECOVERY: 128759084Seric *statp = EX_SOFTWARE; 128859084Seric break; 128959084Seric 129059084Seric default: 129159084Seric *statp = EX_UNAVAILABLE; 129259084Seric break; 129359084Seric } 129466029Seric #else 129566029Seric if (tTd(9, 1)) 129666029Seric printf("FAIL\n"); 129766029Seric *statp = EX_NOHOST; 129866029Seric #endif 129959671Seric s->s_namecanon.nc_stat = *statp; 130068693Seric if ((*statp != EX_TEMPFAIL && *statp != EX_NOHOST) || 130168693Seric UseNameServer) 130259084Seric return NULL; 130359084Seric 130459084Seric /* 130559084Seric ** Try to look it up in /etc/hosts 130659084Seric */ 130759084Seric 130868693Seric hp = sm_gethostbyname(name); 130959084Seric if (hp == NULL) 131059084Seric { 131159084Seric /* no dice there either */ 131259671Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 131359084Seric return NULL; 131459084Seric } 131559084Seric 131659671Seric s->s_namecanon.nc_stat = *statp = EX_OK; 131760257Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 131860257Seric s->s_namecanon.nc_cname = newstr(cp); 131960257Seric return cp; 132058796Seric } 132153751Seric } 132260089Seric if ((cp = strchr(name, ']')) == NULL) 132353751Seric return (NULL); 132440994Sbostic *cp = '\0'; 132568693Seric in_addr.s_addr = inet_addr(&name[1]); 132658110Seric 132758110Seric /* nope -- ask the name server */ 132868693Seric hp = sm_gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET); 132959671Seric s->s_namecanon.nc_errno = errno; 133066334Seric #if NAMED_BIND 133159671Seric s->s_namecanon.nc_herrno = h_errno; 133266029Seric #endif 133359671Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 133433932Sbostic if (hp == NULL) 133559671Seric { 133659671Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 133753751Seric return (NULL); 133859671Seric } 133953751Seric 134058110Seric /* found a match -- copy out */ 134160257Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 134259671Seric s->s_namecanon.nc_stat = *statp = EX_OK; 134360257Seric s->s_namecanon.nc_cname = newstr(cp); 134460257Seric return cp; 134533932Sbostic } 134658755Seric /* 134758755Seric ** ANYNET_NTOA -- convert a network address to printable form. 134858755Seric ** 134958755Seric ** Parameters: 135058755Seric ** sap -- a pointer to a sockaddr structure. 135158755Seric ** 135258755Seric ** Returns: 135358755Seric ** A printable version of that sockaddr. 135458755Seric */ 135516911Seric 135658755Seric char * 135758755Seric anynet_ntoa(sap) 135858755Seric register SOCKADDR *sap; 135958755Seric { 136058755Seric register char *bp; 136158755Seric register char *ap; 136258755Seric int l; 136364734Seric static char buf[100]; 136458755Seric 136558798Seric /* check for null/zero family */ 136658798Seric if (sap == NULL) 136758798Seric return "NULLADDR"; 136858798Seric if (sap->sa.sa_family == 0) 136958798Seric return "0"; 137058798Seric 137164734Seric switch (sap->sa.sa_family) 137264734Seric { 137364821Seric #ifdef NETUNIX 137464734Seric case AF_UNIX: 137564758Seric if (sap->sunix.sun_path[0] != '\0') 137664758Seric sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 137764734Seric else 137864734Seric sprintf(buf, "[UNIX: localhost]"); 137964734Seric return buf; 138064734Seric #endif 138164734Seric 138258778Seric #ifdef NETINET 138364734Seric case AF_INET: 138458755Seric return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 138558778Seric #endif 138658755Seric 138764734Seric default: 138864734Seric /* this case is only to ensure syntactic correctness */ 138964734Seric break; 139064734Seric } 139164734Seric 139258755Seric /* unknown family -- just dump bytes */ 139358778Seric (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 139458755Seric bp = &buf[strlen(buf)]; 139558778Seric ap = sap->sa.sa_data; 139658778Seric for (l = sizeof sap->sa.sa_data; --l >= 0; ) 139758755Seric { 139858755Seric (void) sprintf(bp, "%02x:", *ap++ & 0377); 139958755Seric bp += 3; 140058755Seric } 140158755Seric *--bp = '\0'; 140258755Seric return buf; 140358755Seric } 140458951Seric /* 140558951Seric ** HOSTNAMEBYANYADDR -- return name of host based on address 140658951Seric ** 140758951Seric ** Parameters: 140858951Seric ** sap -- SOCKADDR pointer 140958951Seric ** 141058951Seric ** Returns: 141158951Seric ** text representation of host name. 141258951Seric ** 141358951Seric ** Side Effects: 141458951Seric ** none. 141558951Seric */ 141658755Seric 141758951Seric char * 141858951Seric hostnamebyanyaddr(sap) 141958951Seric register SOCKADDR *sap; 142058951Seric { 142158951Seric register struct hostent *hp; 142264734Seric int saveretry; 142358951Seric 142466334Seric #if NAMED_BIND 142559042Seric /* shorten name server timeout to avoid higher level timeouts */ 142659042Seric saveretry = _res.retry; 142759042Seric _res.retry = 3; 142859042Seric #endif /* NAMED_BIND */ 142959042Seric 143058951Seric switch (sap->sa.sa_family) 143158951Seric { 143258951Seric #ifdef NETINET 143358951Seric case AF_INET: 143468693Seric hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr, 143568693Seric INADDRSZ, 143658951Seric AF_INET); 143758951Seric break; 143858951Seric #endif 143958951Seric 144058951Seric #ifdef NETISO 144158951Seric case AF_ISO: 144268693Seric hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr, 144358951Seric sizeof sap->siso.siso_addr, 144458951Seric AF_ISO); 144558951Seric break; 144658951Seric #endif 144758951Seric 144864734Seric case AF_UNIX: 144964734Seric hp = NULL; 145064734Seric break; 145164734Seric 145258951Seric default: 145368693Seric hp = sm_gethostbyaddr(sap->sa.sa_data, 145458951Seric sizeof sap->sa.sa_data, 145558951Seric sap->sa.sa_family); 145658951Seric break; 145758951Seric } 145858951Seric 145966334Seric #if NAMED_BIND 146059042Seric _res.retry = saveretry; 146159042Seric #endif /* NAMED_BIND */ 146259042Seric 146358951Seric if (hp != NULL) 146458951Seric return hp->h_name; 146558951Seric else 146658951Seric { 146758951Seric /* produce a dotted quad */ 146858951Seric static char buf[512]; 146958951Seric 147058951Seric (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 147158951Seric return buf; 147258951Seric } 147358951Seric } 147458951Seric 147556795Seric # else /* DAEMON */ 147616911Seric /* code for systems without sophisticated networking */ 147710758Seric 147810758Seric /* 147910758Seric ** MYHOSTNAME -- stub version for case of no daemon code. 148011297Seric ** 148111297Seric ** Can't convert to upper case here because might be a UUCP name. 148212313Seric ** 148312313Seric ** Mark, you can change this to be anything you want...... 148410758Seric */ 148510758Seric 148610758Seric char ** 148712313Seric myhostname(hostbuf, size) 148810758Seric char hostbuf[]; 148912313Seric int size; 149010758Seric { 149110758Seric register FILE *f; 149210758Seric 149310758Seric hostbuf[0] = '\0'; 149410758Seric f = fopen("/usr/include/whoami", "r"); 149510758Seric if (f != NULL) 149610758Seric { 149712313Seric (void) fgets(hostbuf, size, f); 149810758Seric fixcrlf(hostbuf, TRUE); 149910758Seric (void) fclose(f); 150010758Seric } 150110758Seric return (NULL); 150210758Seric } 150316911Seric /* 150458951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 150558308Seric ** 150658308Seric ** Parameters: 150758308Seric ** fd -- the descriptor 150858308Seric ** 150958308Seric ** Returns: 151058308Seric ** The host name associated with this descriptor, if it can 151158308Seric ** be determined. 151258308Seric ** NULL otherwise. 151358308Seric ** 151458308Seric ** Side Effects: 151558308Seric ** none 151658308Seric */ 151758308Seric 151858308Seric char * 151958951Seric getauthinfo(fd) 152058308Seric int fd; 152158308Seric { 152258308Seric return NULL; 152358308Seric } 152458308Seric /* 152516911Seric ** MAPHOSTNAME -- turn a hostname into canonical form 152616911Seric ** 152716911Seric ** Parameters: 152856823Seric ** map -- a pointer to the database map. 152960089Seric ** name -- a buffer containing a hostname. 153053751Seric ** avp -- a pointer to a (cf file defined) argument vector. 153159084Seric ** statp -- an exit status (out parameter). 153216911Seric ** 153316911Seric ** Returns: 153453751Seric ** mapped host name 153551315Seric ** FALSE otherwise. 153616911Seric ** 153716911Seric ** Side Effects: 153860089Seric ** Looks up the host specified in name. If it is not 153916911Seric ** the canonical name for that host, replace it with 154016911Seric ** the canonical name. If the name is unknown, or it 154116911Seric ** is already the canonical name, leave it unchanged. 154216911Seric */ 154310758Seric 154416911Seric /*ARGSUSED*/ 154553751Seric char * 154660089Seric host_map_lookup(map, name, avp, statp) 154756823Seric MAP *map; 154860089Seric char *name; 154953751Seric char **avp; 155059084Seric char *statp; 155116911Seric { 155259084Seric register struct hostent *hp; 155359084Seric 155468693Seric hp = sm_gethostbyname(name); 155559084Seric if (hp != NULL) 155659084Seric return hp->h_name; 155759084Seric *statp = EX_NOHOST; 155853751Seric return NULL; 155916911Seric } 156016911Seric 156156795Seric #endif /* DAEMON */ 1562