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*67470Seric static char sccsid[] = "@(#)daemon.c 8.58 (Berkeley) 07/02/94 (with daemon mode)"; 1533780Sbostic #else 16*67470Seric static char sccsid[] = "@(#)daemon.c 8.58 (Berkeley) 07/02/94 (without daemon mode)"; 1733780Sbostic #endif 1833780Sbostic #endif /* not lint */ 194535Seric 2033780Sbostic #ifdef DAEMON 2133780Sbostic 2223120Seric # include <netdb.h> 2364338Seric # include <arpa/inet.h> 245978Seric 2566334Seric #if NAMED_BIND 2659042Seric # include <resolv.h> 2759042Seric #endif 2859042Seric 294535Seric /* 304535Seric ** DAEMON.C -- routines to use when running as a daemon. 317556Seric ** 327556Seric ** This entire file is highly dependent on the 4.2 BSD 337556Seric ** interprocess communication primitives. No attempt has 347556Seric ** been made to make this file portable to Version 7, 357556Seric ** Version 6, MPX files, etc. If you should try such a 367556Seric ** thing yourself, I recommend chucking the entire file 377556Seric ** and starting from scratch. Basic semantics are: 387556Seric ** 397556Seric ** getrequests() 407556Seric ** Opens a port and initiates a connection. 417556Seric ** Returns in a child. Must set InChannel and 427556Seric ** OutChannel appropriately. 4310206Seric ** clrdaemon() 4410206Seric ** Close any open files associated with getting 4510206Seric ** the connection; this is used when running the queue, 4610206Seric ** etc., to avoid having extra file descriptors during 4710206Seric ** the queue run and to avoid confusing the network 4810206Seric ** code (if it cares). 4952106Seric ** makeconnection(host, port, outfile, infile, usesecureport) 507556Seric ** Make a connection to the named host on the given 517556Seric ** port. Set *outfile and *infile to the files 527556Seric ** appropriate for communication. Returns zero on 537556Seric ** success, else an exit status describing the 547556Seric ** error. 5560089Seric ** host_map_lookup(map, hbuf, avp, pstat) 5656823Seric ** Convert the entry in hbuf into a canonical form. 574535Seric */ 584535Seric /* 594535Seric ** GETREQUESTS -- open mail IPC port and get requests. 604535Seric ** 614535Seric ** Parameters: 624535Seric ** none. 634535Seric ** 644535Seric ** Returns: 654535Seric ** none. 664535Seric ** 674535Seric ** Side Effects: 684535Seric ** Waits until some interesting activity occurs. When 694535Seric ** it does, a child is created to process it, and the 704535Seric ** parent waits for completion. Return from this 719886Seric ** routine is always in the child. The file pointers 729886Seric ** "InChannel" and "OutChannel" should be set to point 739886Seric ** to the communication channel. 744535Seric */ 754535Seric 7658849Seric int DaemonSocket = -1; /* fd describing socket */ 7758849Seric SOCKADDR DaemonAddr; /* socket for incoming */ 7859783Seric int ListenQueueSize = 10; /* size of listen queue */ 7964381Seric int TcpRcvBufferSize = 0; /* size of TCP receive buffer */ 8064381Seric int TcpSndBufferSize = 0; /* size of TCP send buffer */ 8116144Seric 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 14766812Seric expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], 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(); 16011147Seric 16114875Seric /* see if we are rejecting connections */ 16253751Seric CurrentLA = getla(); 16353751Seric if (refuseconnections()) 16436584Sbostic { 16566845Seric if (DaemonSocket >= 0) 16653751Seric { 16766845Seric /* close socket so peer will fail quickly */ 16866845Seric (void) close(DaemonSocket); 16966845Seric DaemonSocket = -1; 17053751Seric } 17166845Seric refusingconnections = TRUE; 17257385Seric setproctitle("rejecting connections: load average: %d", 17357385Seric CurrentLA); 17466845Seric sleep(15); 17553751Seric continue; 17636584Sbostic } 17714875Seric 178*67470Seric /* arrange to (re)open the socket if necessary */ 179*67470Seric if (DaemonSocket < 0) 180*67470Seric (void) opendaemonsocket(FALSE); 18153751Seric if (refusingconnections) 18253751Seric { 18353751Seric setproctitle("accepting connections"); 18453751Seric refusingconnections = FALSE; 18553751Seric } 18653751Seric 18766793Seric #ifdef XDEBUG 18866793Seric /* check for disaster */ 18966793Seric { 19066793Seric register STAB *s; 19166812Seric char jbuf[MAXHOSTNAMELEN]; 19266793Seric 19366812Seric expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv); 19466812Seric if ((s = stab(jbuf, ST_CLASS, ST_FIND)) == NULL || 19566793Seric !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"); 221*67470Seric 222*67470Seric /* arrange to re-open the socket next time around */ 223*67470Seric (void) close(DaemonSocket); 224*67470Seric DaemonSocket = -1; 2259610Seric sleep(5); 2269610Seric continue; 2275978Seric } 2284631Seric 2295978Seric /* 2305978Seric ** Create a subprocess to process the mail. 2315978Seric */ 2325978Seric 2337677Seric if (tTd(15, 2)) 2349610Seric printf("getrequests: forking (fd = %d)\n", t); 2355978Seric 2364636Seric pid = fork(); 2374636Seric if (pid < 0) 2384631Seric { 2394636Seric syserr("daemon: cannot fork"); 2404636Seric sleep(10); 2419610Seric (void) close(t); 2424636Seric continue; 2434631Seric } 2444631Seric 2454636Seric if (pid == 0) 2464631Seric { 24764086Seric char *p; 24858951Seric extern char *hostnamebyanyaddr(); 24911147Seric 2504636Seric /* 2514636Seric ** CHILD -- return to caller. 25211147Seric ** Collect verified idea of sending host. 2534636Seric ** Verify calling user id if possible here. 2544636Seric */ 2554631Seric 25664035Seric (void) setsignal(SIGCHLD, SIG_DFL); 25767171Seric (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; 32866845Seric int socksize; 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)); 41467448Seric 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 43010206Seric clrdaemon() 43110206Seric { 43210206Seric if (DaemonSocket >= 0) 43310206Seric (void) close(DaemonSocket); 43410206Seric DaemonSocket = -1; 43510206Seric } 43610206Seric /* 43758849Seric ** SETDAEMONOPTIONS -- set options for running the daemon 43858849Seric ** 43958849Seric ** Parameters: 44058849Seric ** p -- the options line. 44158849Seric ** 44258849Seric ** Returns: 44358849Seric ** none. 44458849Seric */ 44558849Seric 44658849Seric setdaemonoptions(p) 44758849Seric register char *p; 44858849Seric { 44958873Seric if (DaemonAddr.sa.sa_family == AF_UNSPEC) 45058873Seric DaemonAddr.sa.sa_family = AF_INET; 45158873Seric 45258849Seric while (p != NULL) 45358849Seric { 45458849Seric register char *f; 45558849Seric register char *v; 45658849Seric 45758849Seric while (isascii(*p) && isspace(*p)) 45858849Seric p++; 45958849Seric if (*p == '\0') 46058849Seric break; 46158849Seric f = p; 46258849Seric p = strchr(p, ','); 46358849Seric if (p != NULL) 46458849Seric *p++ = '\0'; 46558849Seric v = strchr(f, '='); 46658849Seric if (v == NULL) 46758849Seric continue; 46858849Seric while (isascii(*++v) && isspace(*v)) 46958849Seric continue; 47058849Seric 47158849Seric switch (*f) 47258849Seric { 47358873Seric case 'F': /* address family */ 47458849Seric if (isascii(*v) && isdigit(*v)) 47558873Seric DaemonAddr.sa.sa_family = atoi(v); 47658873Seric #ifdef NETINET 47758873Seric else if (strcasecmp(v, "inet") == 0) 47858873Seric DaemonAddr.sa.sa_family = AF_INET; 47958873Seric #endif 48058873Seric #ifdef NETISO 48158873Seric else if (strcasecmp(v, "iso") == 0) 48258873Seric DaemonAddr.sa.sa_family = AF_ISO; 48358873Seric #endif 48458873Seric #ifdef NETNS 48558873Seric else if (strcasecmp(v, "ns") == 0) 48658873Seric DaemonAddr.sa.sa_family = AF_NS; 48758873Seric #endif 48858873Seric #ifdef NETX25 48958873Seric else if (strcasecmp(v, "x.25") == 0) 49058873Seric DaemonAddr.sa.sa_family = AF_CCITT; 49158873Seric #endif 49258849Seric else 49358873Seric syserr("554 Unknown address family %s in Family=option", v); 49458873Seric break; 49558873Seric 49658873Seric case 'A': /* address */ 49758873Seric switch (DaemonAddr.sa.sa_family) 49858849Seric { 49958873Seric #ifdef NETINET 50058873Seric case AF_INET: 50158873Seric if (isascii(*v) && isdigit(*v)) 50258873Seric DaemonAddr.sin.sin_addr.s_addr = inet_network(v); 50358873Seric else 50458873Seric { 50558873Seric register struct netent *np; 50658849Seric 50758873Seric np = getnetbyname(v); 50858873Seric if (np == NULL) 50958873Seric syserr("554 network \"%s\" unknown", v); 51058873Seric else 51158873Seric DaemonAddr.sin.sin_addr.s_addr = np->n_net; 51258873Seric } 51358873Seric break; 51458873Seric #endif 51558873Seric 51658873Seric default: 51758873Seric syserr("554 Address= option unsupported for family %d", 51858873Seric DaemonAddr.sa.sa_family); 51958873Seric break; 52058849Seric } 52158849Seric break; 52258849Seric 52358873Seric case 'P': /* port */ 52458873Seric switch (DaemonAddr.sa.sa_family) 52558849Seric { 52658873Seric short port; 52758849Seric 52858873Seric #ifdef NETINET 52958873Seric case AF_INET: 53058873Seric if (isascii(*v) && isdigit(*v)) 53164366Seric DaemonAddr.sin.sin_port = htons(atoi(v)); 53258849Seric else 53358873Seric { 53458873Seric register struct servent *sp; 53558873Seric 53658873Seric sp = getservbyname(v, "tcp"); 53758873Seric if (sp == NULL) 53858909Seric syserr("554 service \"%s\" unknown", v); 53958873Seric else 54058873Seric DaemonAddr.sin.sin_port = sp->s_port; 54158873Seric } 54258873Seric break; 54358873Seric #endif 54458873Seric 54558873Seric #ifdef NETISO 54658873Seric case AF_ISO: 54758873Seric /* assume two byte transport selector */ 54858873Seric if (isascii(*v) && isdigit(*v)) 54964366Seric port = htons(atoi(v)); 55058873Seric else 55158873Seric { 55258873Seric register struct servent *sp; 55358873Seric 55458873Seric sp = getservbyname(v, "tcp"); 55558873Seric if (sp == NULL) 55658909Seric syserr("554 service \"%s\" unknown", v); 55758873Seric else 55858873Seric port = sp->s_port; 55958873Seric } 56058873Seric bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 56158873Seric break; 56258873Seric #endif 56358873Seric 56458873Seric default: 56558873Seric syserr("554 Port= option unsupported for family %d", 56658873Seric DaemonAddr.sa.sa_family); 56758873Seric break; 56858849Seric } 56958849Seric break; 57059783Seric 57159783Seric case 'L': /* listen queue size */ 57259783Seric ListenQueueSize = atoi(v); 57359783Seric break; 57464381Seric 57564381Seric case 'S': /* send buffer size */ 57664381Seric TcpSndBufferSize = atoi(v); 57764381Seric break; 57864381Seric 57964381Seric case 'R': /* receive buffer size */ 58064381Seric TcpRcvBufferSize = atoi(v); 58164381Seric break; 58258849Seric } 58358849Seric } 58458849Seric } 58558849Seric /* 5866039Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 5876039Seric ** 5886039Seric ** Parameters: 5896039Seric ** host -- the name of the host. 5906633Seric ** port -- the port number to connect to. 59153739Seric ** mci -- a pointer to the mail connection information 59253739Seric ** structure to be filled in. 59352106Seric ** usesecureport -- if set, use a low numbered (reserved) 59452106Seric ** port to provide some rudimentary authentication. 5956039Seric ** 5966039Seric ** Returns: 5976039Seric ** An exit code telling whether the connection could be 5986039Seric ** made and if not why not. 5996039Seric ** 6006039Seric ** Side Effects: 6016039Seric ** none. 6026039Seric */ 6035978Seric 60458755Seric SOCKADDR CurHostAddr; /* address of current host */ 60558305Seric 60654967Seric int 60753739Seric makeconnection(host, port, mci, usesecureport) 6086039Seric char *host; 6097286Seric u_short port; 61054967Seric register MCI *mci; 61152106Seric bool usesecureport; 6126039Seric { 61329430Sbloom register int i, s; 61429430Sbloom register struct hostent *hp = (struct hostent *)NULL; 61558755Seric SOCKADDR addr; 61652106Seric int sav_errno; 61758755Seric int addrlen; 61866334Seric #if NAMED_BIND 61935651Seric extern int h_errno; 62035651Seric #endif 6216039Seric 6226039Seric /* 6236039Seric ** Set up the address for the mailer. 6249308Seric ** Accept "[a.b.c.d]" syntax for host name. 6256039Seric */ 6266039Seric 62766334Seric #if NAMED_BIND 62825475Smiriam h_errno = 0; 62935651Seric #endif 63025475Smiriam errno = 0; 63158864Seric bzero(&CurHostAddr, sizeof CurHostAddr); 63264334Seric SmtpPhase = mci->mci_phase = "initial connection"; 63358906Seric CurHostName = host; 63425475Smiriam 6359308Seric if (host[0] == '[') 6369308Seric { 63711147Seric long hid; 63856795Seric register char *p = strchr(host, ']'); 6399308Seric 64011147Seric if (p != NULL) 6419308Seric { 64211147Seric *p = '\0'; 64359884Seric #ifdef NETINET 64411147Seric hid = inet_addr(&host[1]); 64558360Seric if (hid == -1) 64659884Seric #endif 64758360Seric { 64858360Seric /* try it as a host name (avoid MX lookup) */ 64958360Seric hp = gethostbyname(&host[1]); 65066349Seric if (hp == NULL && p[-1] == '.') 65166349Seric { 65267265Seric #ifdef NAMED_BIND 65367265Seric int oldopts = _res.options; 65467265Seric 65567265Seric _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 65667265Seric #endif 65766349Seric p[-1] = '\0'; 65866349Seric hp = gethostbyname(&host[1]); 65966349Seric p[-1] = '.'; 66067265Seric #ifdef NAMED_BIND 66167265Seric _res.options = oldopts; 66267265Seric #endif 66366349Seric } 66458360Seric *p = ']'; 66558360Seric goto gothostent; 66658360Seric } 66711147Seric *p = ']'; 6689308Seric } 66958360Seric if (p == NULL) 6709308Seric { 67158151Seric usrerr("553 Invalid numeric domain spec \"%s\"", host); 6729308Seric return (EX_NOHOST); 6739308Seric } 67459884Seric #ifdef NETINET 67559884Seric addr.sin.sin_family = AF_INET; /*XXX*/ 67658778Seric addr.sin.sin_addr.s_addr = hid; 67759884Seric #endif 6789308Seric } 6799610Seric else 6809610Seric { 68166349Seric register char *p = &host[strlen(host) - 1]; 68266349Seric 68329430Sbloom hp = gethostbyname(host); 68466349Seric if (hp == NULL && *p == '.') 68566349Seric { 68667265Seric #ifdef NAMED_BIND 68767265Seric int oldopts = _res.options; 68867265Seric 68967265Seric _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 69067265Seric #endif 69166349Seric *p = '\0'; 69266349Seric hp = gethostbyname(host); 69366349Seric *p = '.'; 69467265Seric #ifdef NAMED_BIND 69567265Seric _res.options = oldopts; 69667265Seric #endif 69766349Seric } 69858360Seric gothostent: 69925475Smiriam if (hp == NULL) 70024945Seric { 70166334Seric #if NAMED_BIND 70225475Smiriam if (errno == ETIMEDOUT || h_errno == TRY_AGAIN) 70325475Smiriam return (EX_TEMPFAIL); 70425657Seric 70535651Seric /* if name server is specified, assume temp fail */ 70635651Seric if (errno == ECONNREFUSED && UseNameServer) 70735651Seric return (EX_TEMPFAIL); 70835651Seric #endif 70925475Smiriam return (EX_NOHOST); 71024945Seric } 71158778Seric addr.sa.sa_family = hp->h_addrtype; 71258778Seric switch (hp->h_addrtype) 71358778Seric { 71458778Seric #ifdef NETINET 71558778Seric case AF_INET: 71658755Seric bcopy(hp->h_addr, 71758778Seric &addr.sin.sin_addr, 71867421Seric INADDRSZ); 71958778Seric break; 72058778Seric #endif 72158778Seric 72258778Seric default: 72358755Seric bcopy(hp->h_addr, 72458778Seric addr.sa.sa_data, 72558755Seric hp->h_length); 72658778Seric break; 72758778Seric } 72829430Sbloom i = 1; 7299610Seric } 7309610Seric 7319610Seric /* 7329610Seric ** Determine the port number. 7339610Seric */ 7349610Seric 73510011Seric if (port != 0) 73658755Seric port = htons(port); 73710011Seric else 7389610Seric { 7399610Seric register struct servent *sp = getservbyname("smtp", "tcp"); 7409610Seric 7419610Seric if (sp == NULL) 7429610Seric { 74358909Seric syserr("554 makeconnection: service \"smtp\" unknown"); 74465169Seric port = htons(25); 7459610Seric } 74665169Seric else 74765169Seric port = sp->s_port; 7489610Seric } 7496039Seric 75058778Seric switch (addr.sa.sa_family) 75158755Seric { 75259884Seric #ifdef NETINET 75358755Seric case AF_INET: 75458778Seric addr.sin.sin_port = port; 75558755Seric addrlen = sizeof (struct sockaddr_in); 75658755Seric break; 75759884Seric #endif 75858755Seric 75958755Seric #ifdef NETISO 76058755Seric case AF_ISO: 76158755Seric /* assume two byte transport selector */ 76258755Seric bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 76358755Seric addrlen = sizeof (struct sockaddr_iso); 76458755Seric break; 76558755Seric #endif 76658755Seric 76758755Seric default: 76858778Seric syserr("Can't connect to address family %d", addr.sa.sa_family); 76958755Seric return (EX_NOHOST); 77058755Seric } 77158755Seric 7726039Seric /* 7736039Seric ** Try to actually open the connection. 7746039Seric */ 7756039Seric 77659156Seric #ifdef XLA 77759156Seric /* if too many connections, don't bother trying */ 77859156Seric if (!xla_noqueue_ok(host)) 77959156Seric return EX_TEMPFAIL; 78059156Seric #endif 78159156Seric 78257736Seric for (;;) 78352106Seric { 78457736Seric if (tTd(16, 1)) 78558755Seric printf("makeconnection (%s [%s])\n", 78658755Seric host, anynet_ntoa(&addr)); 78752106Seric 78858588Seric /* save for logging */ 78958588Seric CurHostAddr = addr; 79058588Seric 79157736Seric if (usesecureport) 79257736Seric { 79357736Seric int rport = IPPORT_RESERVED - 1; 7946039Seric 79557736Seric s = rresvport(&rport); 79657736Seric } 79757736Seric else 79857736Seric { 79957736Seric s = socket(AF_INET, SOCK_STREAM, 0); 80057736Seric } 80157736Seric if (s < 0) 80257736Seric { 80357736Seric sav_errno = errno; 80457736Seric syserr("makeconnection: no socket"); 80557736Seric goto failure; 80657736Seric } 80710347Seric 80864381Seric #ifdef SO_SNDBUF 80964381Seric if (TcpSndBufferSize > 0) 81064381Seric { 81164381Seric if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 81264561Seric (char *) &TcpSndBufferSize, 81364381Seric sizeof(TcpSndBufferSize)) < 0) 81464381Seric syserr("makeconnection: setsockopt(SO_SNDBUF)"); 81564381Seric } 81664381Seric #endif 81764381Seric 81857736Seric if (tTd(16, 1)) 81957736Seric printf("makeconnection: fd=%d\n", s); 82057736Seric 82157736Seric /* turn on network debugging? */ 82257736Seric if (tTd(16, 101)) 82357736Seric { 82457736Seric int on = 1; 82566861Seric (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 82657736Seric (char *)&on, sizeof on); 82757736Seric } 82857736Seric if (CurEnv->e_xfp != NULL) 82957736Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 83057736Seric errno = 0; /* for debugging */ 83158755Seric if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 83257736Seric break; 83357736Seric 83457736Seric /* couldn't connect.... figure out why */ 83527744Sbloom sav_errno = errno; 83627744Sbloom (void) close(s); 83729430Sbloom if (hp && hp->h_addr_list[i]) 83829430Sbloom { 83957736Seric if (tTd(16, 1)) 84058755Seric printf("Connect failed (%s); trying new address....\n", 84158755Seric errstring(sav_errno)); 84258778Seric switch (addr.sa.sa_family) 84358778Seric { 84458778Seric #ifdef NETINET 84558778Seric case AF_INET: 84658755Seric bcopy(hp->h_addr_list[i++], 84758778Seric &addr.sin.sin_addr, 84867421Seric INADDRSZ); 84958778Seric break; 85058778Seric #endif 85158778Seric 85258778Seric default: 85358755Seric bcopy(hp->h_addr_list[i++], 85458778Seric addr.sa.sa_data, 85552106Seric hp->h_length); 85658778Seric break; 85758778Seric } 85857736Seric continue; 85929430Sbloom } 86029430Sbloom 8616039Seric /* failure, decide if temporary or not */ 8626039Seric failure: 86359254Seric #ifdef XLA 86459254Seric xla_host_end(host); 86559254Seric #endif 86658542Seric if (transienterror(sav_errno)) 86758542Seric return EX_TEMPFAIL; 86858542Seric else 86958542Seric { 87058542Seric message("%s", errstring(sav_errno)); 87158542Seric return (EX_UNAVAILABLE); 8726039Seric } 8736039Seric } 8746039Seric 8756039Seric /* connection ok, put it into canonical form */ 87664724Seric if ((mci->mci_out = fdopen(s, "w")) == NULL || 87764724Seric (s = dup(s)) < 0 || 87864725Seric (mci->mci_in = fdopen(s, "r")) == NULL) 87964724Seric { 88064724Seric syserr("cannot open SMTP client channel, fd=%d", s); 88164724Seric return EX_TEMPFAIL; 88264724Seric } 8836039Seric 88410098Seric return (EX_OK); 8856039Seric } 88610758Seric /* 88710758Seric ** MYHOSTNAME -- return the name of this host. 88810758Seric ** 88910758Seric ** Parameters: 89010758Seric ** hostbuf -- a place to return the name of this host. 89112313Seric ** size -- the size of hostbuf. 89210758Seric ** 89310758Seric ** Returns: 89410758Seric ** A list of aliases for this host. 89510758Seric ** 89610758Seric ** Side Effects: 89764338Seric ** Adds numeric codes to $=w. 89810758Seric */ 8996039Seric 90067140Seric struct hostent * 90112313Seric myhostname(hostbuf, size) 90210758Seric char hostbuf[]; 90312313Seric int size; 90410758Seric { 90558110Seric register struct hostent *hp; 90610758Seric extern struct hostent *gethostbyname(); 90767448Seric extern bool getcanonname(); 90867448Seric extern int h_errno; 90910758Seric 91023120Seric if (gethostname(hostbuf, size) < 0) 91123120Seric { 91223120Seric (void) strcpy(hostbuf, "localhost"); 91323120Seric } 91411147Seric hp = gethostbyname(hostbuf); 91566853Seric if (hp == NULL) 91616877Seric { 91766853Seric syserr("!My host name (%s) does not seem to exist!", hostbuf); 91866853Seric } 91967448Seric if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 92067448Seric { 92167448Seric (void) strncpy(hostbuf, hp->h_name, size - 1); 92267448Seric hostbuf[size - 1] = '\0'; 92367448Seric } 92466853Seric 92566853Seric #if NAMED_BIND 92667448Seric /* 92767448Seric ** If still no dot, try DNS directly (i.e., avoid NIS problems). 92867448Seric ** This ought to be driven from the configuration file, but 92967448Seric ** we are called before the configuration is read. We could 93067448Seric ** check for an /etc/resolv.conf file, but that isn't required. 93167448Seric ** All in all, a bit of a mess. 93267448Seric */ 93367448Seric 93467448Seric if (strchr(hostbuf, '.') == NULL && 93567448Seric !getcanonname(hostbuf, size, TRUE) && 93667448Seric h_errno == TRY_AGAIN) 93766853Seric { 93867448Seric struct stat stbuf; 93966853Seric 94066853Seric /* try twice in case name server not yet started up */ 94167448Seric message("My unqualifed host name (%s) unknown to DNS; sleeping for retry", 94267448Seric hostbuf); 94367448Seric sleep(60); 94467448Seric if (!getcanonname(hostbuf, size, TRUE)) 94566853Seric errno = h_errno + E_DNSBASE; 94666853Seric } 94766777Seric #endif 94867140Seric return (hp); 94910758Seric } 95051315Seric /* 95158951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 95258308Seric ** 95358951Seric ** Uses RFC1413 protocol to try to get info from the other end. 95458951Seric ** 95558308Seric ** Parameters: 95658308Seric ** fd -- the descriptor 95758308Seric ** 95858308Seric ** Returns: 95958951Seric ** The user@host information associated with this descriptor. 96058308Seric */ 96158308Seric 96264927Seric #if IDENTPROTO 96358951Seric 96458951Seric static jmp_buf CtxAuthTimeout; 96558951Seric 96658951Seric static 96758951Seric authtimeout() 96858951Seric { 96958951Seric longjmp(CtxAuthTimeout, 1); 97058951Seric } 97158951Seric 97258951Seric #endif 97358951Seric 97458308Seric char * 97558951Seric getauthinfo(fd) 97658308Seric int fd; 97758308Seric { 97858951Seric int falen; 97959104Seric register char *p; 98064927Seric #if IDENTPROTO 98158951Seric SOCKADDR la; 98258951Seric int lalen; 98358951Seric register struct servent *sp; 98458951Seric int s; 98558951Seric int i; 98658951Seric EVENT *ev; 98758951Seric #endif 98858951Seric static char hbuf[MAXNAME * 2 + 2]; 98958951Seric extern char *hostnamebyanyaddr(); 99058951Seric extern char RealUserName[]; /* main.c */ 99158308Seric 99266761Seric falen = sizeof RealHostAddr; 99367468Seric if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 || 99467468Seric falen <= 0 || RealHostAddr.sa.sa_family == 0) 99558951Seric { 99658951Seric (void) sprintf(hbuf, "%s@localhost", RealUserName); 99758957Seric if (tTd(9, 1)) 99858951Seric printf("getauthinfo: %s\n", hbuf); 99958951Seric return hbuf; 100058951Seric } 100158951Seric 100266761Seric if (RealHostName == NULL) 100366761Seric { 100466761Seric /* translate that to a host name */ 100566761Seric RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 100666761Seric } 100766761Seric 100864927Seric #if IDENTPROTO 100965831Seric if (TimeOuts.to_ident == 0) 101065831Seric goto noident; 101165831Seric 101258951Seric lalen = sizeof la; 101366761Seric if (RealHostAddr.sa.sa_family != AF_INET || 101458951Seric getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 101558951Seric la.sa.sa_family != AF_INET) 101658951Seric { 101758951Seric /* no ident info */ 101858951Seric goto noident; 101958951Seric } 102058951Seric 102158951Seric /* create ident query */ 102260489Seric (void) sprintf(hbuf, "%d,%d\r\n", 102366761Seric ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port)); 102458951Seric 102558951Seric /* create local address */ 102664747Seric la.sin.sin_port = 0; 102758951Seric 102858951Seric /* create foreign address */ 102958951Seric sp = getservbyname("auth", "tcp"); 103058951Seric if (sp != NULL) 103166761Seric RealHostAddr.sin.sin_port = sp->s_port; 103258308Seric else 103366761Seric RealHostAddr.sin.sin_port = htons(113); 103458951Seric 103558951Seric s = -1; 103658951Seric if (setjmp(CtxAuthTimeout) != 0) 103758951Seric { 103858951Seric if (s >= 0) 103958951Seric (void) close(s); 104058951Seric goto noident; 104158951Seric } 104258951Seric 104358951Seric /* put a timeout around the whole thing */ 104464255Seric ev = setevent(TimeOuts.to_ident, authtimeout, 0); 104558951Seric 104664747Seric /* connect to foreign IDENT server using same address as SMTP socket */ 104758951Seric s = socket(AF_INET, SOCK_STREAM, 0); 104858951Seric if (s < 0) 104958951Seric { 105058951Seric clrevent(ev); 105158951Seric goto noident; 105258951Seric } 105364747Seric if (bind(s, &la.sa, sizeof la.sin) < 0 || 105466761Seric connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0) 105558951Seric { 105666011Seric goto closeident; 105758951Seric } 105858951Seric 105958957Seric if (tTd(9, 10)) 106058951Seric printf("getauthinfo: sent %s", hbuf); 106158951Seric 106258951Seric /* send query */ 106358951Seric if (write(s, hbuf, strlen(hbuf)) < 0) 106458951Seric goto closeident; 106558951Seric 106658951Seric /* get result */ 106758951Seric i = read(s, hbuf, sizeof hbuf); 106858951Seric (void) close(s); 106958951Seric clrevent(ev); 107058951Seric if (i <= 0) 107158951Seric goto noident; 107258951Seric if (hbuf[--i] == '\n' && hbuf[--i] == '\r') 107358951Seric i--; 107458951Seric hbuf[++i] = '\0'; 107558951Seric 107658957Seric if (tTd(9, 3)) 107758951Seric printf("getauthinfo: got %s\n", hbuf); 107858951Seric 107958951Seric /* parse result */ 108058951Seric p = strchr(hbuf, ':'); 108158951Seric if (p == NULL) 108258951Seric { 108358951Seric /* malformed response */ 108458951Seric goto noident; 108558951Seric } 108658951Seric while (isascii(*++p) && isspace(*p)) 108758951Seric continue; 108858951Seric if (strncasecmp(p, "userid", 6) != 0) 108958951Seric { 109058951Seric /* presumably an error string */ 109158951Seric goto noident; 109258951Seric } 109358951Seric p += 6; 109458951Seric while (isascii(*p) && isspace(*p)) 109558951Seric p++; 109658951Seric if (*p++ != ':') 109758951Seric { 109858951Seric /* either useridxx or malformed response */ 109958951Seric goto noident; 110058951Seric } 110158951Seric 110258951Seric /* p now points to the OSTYPE field */ 110358951Seric p = strchr(p, ':'); 110458951Seric if (p == NULL) 110558951Seric { 110658951Seric /* malformed response */ 110758951Seric goto noident; 110858951Seric } 110958951Seric 111058957Seric /* 1413 says don't do this -- but it's broken otherwise */ 111158957Seric while (isascii(*++p) && isspace(*p)) 111258957Seric continue; 111358957Seric 111458951Seric /* p now points to the authenticated name */ 111566003Seric (void) sprintf(hbuf, "%s@%s", 111666003Seric p, RealHostName == NULL ? "localhost" : RealHostName); 111758957Seric goto finish; 111858957Seric 111966011Seric closeident: 112066011Seric (void) close(s); 112166011Seric clrevent(ev); 112266011Seric 112358957Seric #endif /* IDENTPROTO */ 112458957Seric 112558957Seric noident: 112666003Seric if (RealHostName == NULL) 112766003Seric { 112866003Seric if (tTd(9, 1)) 112966003Seric printf("getauthinfo: NULL\n"); 113066003Seric return NULL; 113166003Seric } 113258957Seric (void) strcpy(hbuf, RealHostName); 113358957Seric 113458957Seric finish: 113566003Seric if (RealHostName != NULL && RealHostName[0] != '[') 113658951Seric { 113758951Seric p = &hbuf[strlen(hbuf)]; 113858951Seric (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 113958951Seric } 114058957Seric if (tTd(9, 1)) 114158951Seric printf("getauthinfo: %s\n", hbuf); 114258308Seric return hbuf; 114358308Seric } 114458308Seric /* 114560089Seric ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 114653751Seric ** 114753751Seric ** Parameters: 114856823Seric ** map -- a pointer to this map (unused). 114960089Seric ** name -- the (presumably unqualified) hostname. 115060257Seric ** av -- unused -- for compatibility with other mapping 115155019Seric ** functions. 115259084Seric ** statp -- an exit status (out parameter) -- set to 115359084Seric ** EX_TEMPFAIL if the name server is unavailable. 115453751Seric ** 115553751Seric ** Returns: 115653751Seric ** The mapping, if found. 115753751Seric ** NULL if no mapping found. 115853751Seric ** 115953751Seric ** Side Effects: 116053751Seric ** Looks up the host specified in hbuf. If it is not 116153751Seric ** the canonical name for that host, return the canonical 116253751Seric ** name. 116353751Seric */ 116451315Seric 116553751Seric char * 116660257Seric host_map_lookup(map, name, av, statp) 116756823Seric MAP *map; 116860089Seric char *name; 116960257Seric char **av; 117059084Seric int *statp; 117116911Seric { 117216911Seric register struct hostent *hp; 117367419Seric struct in_addr in_addr; 117456823Seric char *cp; 117558110Seric int i; 117659671Seric register STAB *s; 117760257Seric char hbuf[MAXNAME]; 117859671Seric extern struct hostent *gethostbyaddr(); 117966334Seric #if NAMED_BIND 118059671Seric extern int h_errno; 118166029Seric #endif 118216911Seric 118325574Smiriam /* 118459671Seric ** See if we have already looked up this name. If so, just 118559671Seric ** return it. 118659671Seric */ 118753751Seric 118860089Seric s = stab(name, ST_NAMECANON, ST_ENTER); 118959671Seric if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 119059671Seric { 119159986Seric if (tTd(9, 1)) 119260089Seric printf("host_map_lookup(%s) => CACHE %s\n", 119360089Seric name, s->s_namecanon.nc_cname); 119459671Seric errno = s->s_namecanon.nc_errno; 119566334Seric #if NAMED_BIND 119659671Seric h_errno = s->s_namecanon.nc_herrno; 119766029Seric #endif 119859671Seric *statp = s->s_namecanon.nc_stat; 119964797Seric if (CurEnv->e_message == NULL && *statp == EX_TEMPFAIL) 120065199Seric { 120165199Seric sprintf(hbuf, "%s: Name server timeout", 120265199Seric shortenstring(name, 33)); 120365199Seric CurEnv->e_message = newstr(hbuf); 120465199Seric } 120559671Seric return s->s_namecanon.nc_cname; 120659671Seric } 120759671Seric 120859671Seric /* 120959671Seric ** If first character is a bracket, then it is an address 121059671Seric ** lookup. Address is copied into a temporary buffer to 121160089Seric ** strip the brackets and to preserve name if address is 121259671Seric ** unknown. 121359671Seric */ 121459671Seric 121560089Seric if (*name != '[') 121653751Seric { 121755019Seric extern bool getcanonname(); 121855019Seric 121958798Seric if (tTd(9, 1)) 122060089Seric printf("host_map_lookup(%s) => ", name); 122159671Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 122260089Seric (void) strcpy(hbuf, name); 122363842Seric if (getcanonname(hbuf, sizeof hbuf - 1, TRUE)) 122458796Seric { 122558796Seric if (tTd(9, 1)) 122658796Seric printf("%s\n", hbuf); 122760257Seric cp = map_rewrite(map, hbuf, strlen(hbuf), av); 122860257Seric s->s_namecanon.nc_cname = newstr(cp); 122960257Seric return cp; 123058796Seric } 123153751Seric else 123258796Seric { 123359084Seric register struct hostent *hp; 123459084Seric 123566029Seric s->s_namecanon.nc_errno = errno; 123666334Seric #if NAMED_BIND 123766029Seric s->s_namecanon.nc_herrno = h_errno; 123858796Seric if (tTd(9, 1)) 123959084Seric printf("FAIL (%d)\n", h_errno); 124059084Seric switch (h_errno) 124159084Seric { 124259084Seric case TRY_AGAIN: 124359596Seric if (UseNameServer) 124459734Seric { 124565202Seric sprintf(hbuf, "%s: Name server timeout", 124665199Seric shortenstring(name, 33)); 124765202Seric message("%s", hbuf); 124859734Seric if (CurEnv->e_message == NULL) 124965202Seric CurEnv->e_message = newstr(hbuf); 125059734Seric } 125159084Seric *statp = EX_TEMPFAIL; 125259084Seric break; 125359084Seric 125459084Seric case HOST_NOT_FOUND: 125559084Seric *statp = EX_NOHOST; 125659084Seric break; 125759084Seric 125859084Seric case NO_RECOVERY: 125959084Seric *statp = EX_SOFTWARE; 126059084Seric break; 126159084Seric 126259084Seric default: 126359084Seric *statp = EX_UNAVAILABLE; 126459084Seric break; 126559084Seric } 126666029Seric #else 126766029Seric if (tTd(9, 1)) 126866029Seric printf("FAIL\n"); 126966029Seric *statp = EX_NOHOST; 127066029Seric #endif 127159671Seric s->s_namecanon.nc_stat = *statp; 127267422Seric if ((*statp != EX_TEMPFAIL && *statp != EX_NOHOST) || 127367422Seric UseNameServer) 127459084Seric return NULL; 127559084Seric 127659084Seric /* 127759084Seric ** Try to look it up in /etc/hosts 127859084Seric */ 127959084Seric 128060089Seric hp = gethostbyname(name); 128159084Seric if (hp == NULL) 128259084Seric { 128359084Seric /* no dice there either */ 128459671Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 128559084Seric return NULL; 128659084Seric } 128759084Seric 128859671Seric s->s_namecanon.nc_stat = *statp = EX_OK; 128960257Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 129060257Seric s->s_namecanon.nc_cname = newstr(cp); 129160257Seric return cp; 129258796Seric } 129353751Seric } 129460089Seric if ((cp = strchr(name, ']')) == NULL) 129553751Seric return (NULL); 129640994Sbostic *cp = '\0'; 129767419Seric in_addr.s_addr = inet_addr(&name[1]); 129858110Seric 129958110Seric /* nope -- ask the name server */ 130067421Seric hp = gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET); 130159671Seric s->s_namecanon.nc_errno = errno; 130266334Seric #if NAMED_BIND 130359671Seric s->s_namecanon.nc_herrno = h_errno; 130466029Seric #endif 130559671Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 130633932Sbostic if (hp == NULL) 130759671Seric { 130859671Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 130953751Seric return (NULL); 131059671Seric } 131153751Seric 131258110Seric /* found a match -- copy out */ 131360257Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 131459671Seric s->s_namecanon.nc_stat = *statp = EX_OK; 131560257Seric s->s_namecanon.nc_cname = newstr(cp); 131660257Seric return cp; 131733932Sbostic } 131858755Seric /* 131958755Seric ** ANYNET_NTOA -- convert a network address to printable form. 132058755Seric ** 132158755Seric ** Parameters: 132258755Seric ** sap -- a pointer to a sockaddr structure. 132358755Seric ** 132458755Seric ** Returns: 132558755Seric ** A printable version of that sockaddr. 132658755Seric */ 132716911Seric 132858755Seric char * 132958755Seric anynet_ntoa(sap) 133058755Seric register SOCKADDR *sap; 133158755Seric { 133258755Seric register char *bp; 133358755Seric register char *ap; 133458755Seric int l; 133564734Seric static char buf[100]; 133658755Seric 133758798Seric /* check for null/zero family */ 133858798Seric if (sap == NULL) 133958798Seric return "NULLADDR"; 134058798Seric if (sap->sa.sa_family == 0) 134158798Seric return "0"; 134258798Seric 134364734Seric switch (sap->sa.sa_family) 134464734Seric { 134564821Seric #ifdef NETUNIX 134664734Seric case AF_UNIX: 134764758Seric if (sap->sunix.sun_path[0] != '\0') 134864758Seric sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 134964734Seric else 135064734Seric sprintf(buf, "[UNIX: localhost]"); 135164734Seric return buf; 135264734Seric #endif 135364734Seric 135458778Seric #ifdef NETINET 135564734Seric case AF_INET: 135658755Seric return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 135758778Seric #endif 135858755Seric 135964734Seric default: 136064734Seric /* this case is only to ensure syntactic correctness */ 136164734Seric break; 136264734Seric } 136364734Seric 136458755Seric /* unknown family -- just dump bytes */ 136558778Seric (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 136658755Seric bp = &buf[strlen(buf)]; 136758778Seric ap = sap->sa.sa_data; 136858778Seric for (l = sizeof sap->sa.sa_data; --l >= 0; ) 136958755Seric { 137058755Seric (void) sprintf(bp, "%02x:", *ap++ & 0377); 137158755Seric bp += 3; 137258755Seric } 137358755Seric *--bp = '\0'; 137458755Seric return buf; 137558755Seric } 137658951Seric /* 137758951Seric ** HOSTNAMEBYANYADDR -- return name of host based on address 137858951Seric ** 137958951Seric ** Parameters: 138058951Seric ** sap -- SOCKADDR pointer 138158951Seric ** 138258951Seric ** Returns: 138358951Seric ** text representation of host name. 138458951Seric ** 138558951Seric ** Side Effects: 138658951Seric ** none. 138758951Seric */ 138858755Seric 138958951Seric char * 139058951Seric hostnamebyanyaddr(sap) 139158951Seric register SOCKADDR *sap; 139258951Seric { 139358951Seric register struct hostent *hp; 139464734Seric int saveretry; 139558951Seric 139666334Seric #if NAMED_BIND 139759042Seric /* shorten name server timeout to avoid higher level timeouts */ 139859042Seric saveretry = _res.retry; 139959042Seric _res.retry = 3; 140059042Seric #endif /* NAMED_BIND */ 140159042Seric 140258951Seric switch (sap->sa.sa_family) 140358951Seric { 140458951Seric #ifdef NETINET 140558951Seric case AF_INET: 140658951Seric hp = gethostbyaddr((char *) &sap->sin.sin_addr, 140767421Seric INADDRSZ, 140858951Seric AF_INET); 140958951Seric break; 141058951Seric #endif 141158951Seric 141258951Seric #ifdef NETISO 141358951Seric case AF_ISO: 141458951Seric hp = gethostbyaddr((char *) &sap->siso.siso_addr, 141558951Seric sizeof sap->siso.siso_addr, 141658951Seric AF_ISO); 141758951Seric break; 141858951Seric #endif 141958951Seric 142064734Seric case AF_UNIX: 142164734Seric hp = NULL; 142264734Seric break; 142364734Seric 142458951Seric default: 142558951Seric hp = gethostbyaddr(sap->sa.sa_data, 142658951Seric sizeof sap->sa.sa_data, 142758951Seric sap->sa.sa_family); 142858951Seric break; 142958951Seric } 143058951Seric 143166334Seric #if NAMED_BIND 143259042Seric _res.retry = saveretry; 143359042Seric #endif /* NAMED_BIND */ 143459042Seric 143558951Seric if (hp != NULL) 143658951Seric return hp->h_name; 143758951Seric else 143858951Seric { 143958951Seric /* produce a dotted quad */ 144058951Seric static char buf[512]; 144158951Seric 144258951Seric (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 144358951Seric return buf; 144458951Seric } 144558951Seric } 144658951Seric 144756795Seric # else /* DAEMON */ 144816911Seric /* code for systems without sophisticated networking */ 144910758Seric 145010758Seric /* 145110758Seric ** MYHOSTNAME -- stub version for case of no daemon code. 145211297Seric ** 145311297Seric ** Can't convert to upper case here because might be a UUCP name. 145412313Seric ** 145512313Seric ** Mark, you can change this to be anything you want...... 145610758Seric */ 145710758Seric 145810758Seric char ** 145912313Seric myhostname(hostbuf, size) 146010758Seric char hostbuf[]; 146112313Seric int size; 146210758Seric { 146310758Seric register FILE *f; 146410758Seric 146510758Seric hostbuf[0] = '\0'; 146610758Seric f = fopen("/usr/include/whoami", "r"); 146710758Seric if (f != NULL) 146810758Seric { 146912313Seric (void) fgets(hostbuf, size, f); 147010758Seric fixcrlf(hostbuf, TRUE); 147110758Seric (void) fclose(f); 147210758Seric } 147310758Seric return (NULL); 147410758Seric } 147516911Seric /* 147658951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 147758308Seric ** 147858308Seric ** Parameters: 147958308Seric ** fd -- the descriptor 148058308Seric ** 148158308Seric ** Returns: 148258308Seric ** The host name associated with this descriptor, if it can 148358308Seric ** be determined. 148458308Seric ** NULL otherwise. 148558308Seric ** 148658308Seric ** Side Effects: 148758308Seric ** none 148858308Seric */ 148958308Seric 149058308Seric char * 149158951Seric getauthinfo(fd) 149258308Seric int fd; 149358308Seric { 149458308Seric return NULL; 149558308Seric } 149658308Seric /* 149716911Seric ** MAPHOSTNAME -- turn a hostname into canonical form 149816911Seric ** 149916911Seric ** Parameters: 150056823Seric ** map -- a pointer to the database map. 150160089Seric ** name -- a buffer containing a hostname. 150253751Seric ** avp -- a pointer to a (cf file defined) argument vector. 150359084Seric ** statp -- an exit status (out parameter). 150416911Seric ** 150516911Seric ** Returns: 150653751Seric ** mapped host name 150751315Seric ** FALSE otherwise. 150816911Seric ** 150916911Seric ** Side Effects: 151060089Seric ** Looks up the host specified in name. If it is not 151116911Seric ** the canonical name for that host, replace it with 151216911Seric ** the canonical name. If the name is unknown, or it 151316911Seric ** is already the canonical name, leave it unchanged. 151416911Seric */ 151510758Seric 151616911Seric /*ARGSUSED*/ 151753751Seric char * 151860089Seric host_map_lookup(map, name, avp, statp) 151956823Seric MAP *map; 152060089Seric char *name; 152153751Seric char **avp; 152259084Seric char *statp; 152316911Seric { 152459084Seric register struct hostent *hp; 152559084Seric 152660089Seric hp = gethostbyname(name); 152759084Seric if (hp != NULL) 152859084Seric return hp->h_name; 152959084Seric *statp = EX_NOHOST; 153053751Seric return NULL; 153116911Seric } 153216911Seric 153356795Seric #endif /* DAEMON */ 1534