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*67935Seric static char sccsid[] = "@(#)daemon.c 8.60 (Berkeley) 11/19/94 (with daemon mode)"; 1533780Sbostic #else 16*67935Seric static char sccsid[] = "@(#)daemon.c 8.60 (Berkeley) 11/19/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 17867470Seric /* arrange to (re)open the socket if necessary */ 17953751Seric if (refusingconnections) 18053751Seric { 18167690Seric (void) opendaemonsocket(FALSE); 18253751Seric setproctitle("accepting connections"); 18353751Seric refusingconnections = FALSE; 18453751Seric } 18553751Seric 18666793Seric #ifdef XDEBUG 18766793Seric /* check for disaster */ 18866793Seric { 18966793Seric register STAB *s; 19066812Seric char jbuf[MAXHOSTNAMELEN]; 19166793Seric 19266812Seric expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv); 19366812Seric if ((s = stab(jbuf, ST_CLASS, ST_FIND)) == NULL || 19466793Seric !bitnset('w', s->s_class)) 19566793Seric { 19666793Seric dumpstate("daemon lost $j"); 19766793Seric syslog(LOG_ALERT, "daemon process doesn't have $j in $=w; see syslog"); 19866793Seric abort(); 19966793Seric } 20066812Seric else if (j_has_dot && strchr(jbuf, '.') == NULL) 20166793Seric { 20266793Seric dumpstate("daemon $j lost dot"); 20366793Seric syslog(LOG_ALERT, "daemon process $j lost dot; see syslog"); 20466793Seric abort(); 20566793Seric } 20666793Seric } 20766793Seric #endif 20866793Seric 2099610Seric /* wait for a connection */ 2109610Seric do 2119610Seric { 2129610Seric errno = 0; 21364828Seric lotherend = socksize; 21446928Sbostic t = accept(DaemonSocket, 21546928Sbostic (struct sockaddr *)&RealHostAddr, &lotherend); 2169610Seric } while (t < 0 && errno == EINTR); 2179610Seric if (t < 0) 2185978Seric { 2199610Seric syserr("getrequests: accept"); 22067470Seric 22167470Seric /* arrange to re-open the socket next time around */ 22267470Seric (void) close(DaemonSocket); 22367470Seric DaemonSocket = -1; 2249610Seric sleep(5); 2259610Seric continue; 2265978Seric } 2274631Seric 2285978Seric /* 2295978Seric ** Create a subprocess to process the mail. 2305978Seric */ 2315978Seric 2327677Seric if (tTd(15, 2)) 2339610Seric printf("getrequests: forking (fd = %d)\n", t); 2345978Seric 2354636Seric pid = fork(); 2364636Seric if (pid < 0) 2374631Seric { 2384636Seric syserr("daemon: cannot fork"); 2394636Seric sleep(10); 2409610Seric (void) close(t); 2414636Seric continue; 2424631Seric } 2434631Seric 2444636Seric if (pid == 0) 2454631Seric { 24664086Seric char *p; 24758951Seric extern char *hostnamebyanyaddr(); 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); 25667171Seric (void) close(DaemonSocket); 25766017Seric DisConnected = FALSE; 25824950Seric 25966032Seric setproctitle("startup with %s", 26066032Seric anynet_ntoa(&RealHostAddr)); 26166032Seric 26211147Seric /* determine host name */ 26364086Seric p = hostnamebyanyaddr(&RealHostAddr); 26464086Seric RealHostName = newstr(p); 26566032Seric setproctitle("startup with %s", p); 26658778Seric 26755173Seric #ifdef LOG 26863842Seric if (LogLevel > 11) 26955173Seric { 27055173Seric /* log connection information */ 27155173Seric syslog(LOG_INFO, "connect from %s (%s)", 27258951Seric RealHostName, anynet_ntoa(&RealHostAddr)); 27355173Seric } 27455173Seric #endif 27555173Seric 27664724Seric if ((InChannel = fdopen(t, "r")) == NULL || 27764724Seric (t = dup(t)) < 0 || 27864724Seric (OutChannel = fdopen(t, "w")) == NULL) 27964724Seric { 28064724Seric syserr("cannot open SMTP server channel, fd=%d", t); 28164724Seric exit(0); 28264724Seric } 28359254Seric 28416884Seric /* should we check for illegal connection here? XXX */ 28559156Seric #ifdef XLA 28659156Seric if (!xla_host_ok(RealHostName)) 28759156Seric { 28859254Seric message("421 Too many SMTP sessions for this host"); 28959156Seric exit(0); 29059156Seric } 29159156Seric #endif 29216884Seric 2937677Seric if (tTd(15, 2)) 2945978Seric printf("getreq: returning\n"); 2954636Seric return; 2964631Seric } 2974631Seric 2987117Seric /* close the port so that others will hang (for a while) */ 2999610Seric (void) close(t); 3004631Seric } 3019886Seric /*NOTREACHED*/ 3024631Seric } 3035978Seric /* 30466845Seric ** OPENDAEMONSOCKET -- open the SMTP socket 30566845Seric ** 30666845Seric ** Deals with setting all appropriate options. DaemonAddr must 30766845Seric ** be set up in advance. 30866845Seric ** 30966845Seric ** Parameters: 31066854Seric ** firsttime -- set if this is the initial open. 31166845Seric ** 31266845Seric ** Returns: 31366845Seric ** Size in bytes of the daemon socket addr. 31466845Seric ** 31566845Seric ** Side Effects: 31666845Seric ** Leaves DaemonSocket set to the open socket. 31766845Seric ** Exits if the socket cannot be created. 31866845Seric */ 31966845Seric 32066861Seric #define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 32166861Seric 32266845Seric int 32366854Seric opendaemonsocket(firsttime) 32466854Seric bool firsttime; 32566845Seric { 32666845Seric int on = 1; 32766845Seric int socksize; 32866861Seric int ntries = 0; 32966861Seric int saveerrno; 33066845Seric 33166845Seric if (tTd(15, 2)) 33266845Seric printf("opendaemonsocket()\n"); 33366845Seric 33466861Seric do 33566845Seric { 33666862Seric if (ntries > 0) 33766862Seric sleep(5); 33866861Seric if (firsttime || DaemonSocket < 0) 33966854Seric { 34066861Seric DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0); 34166861Seric if (DaemonSocket < 0) 34266861Seric { 34366861Seric /* probably another daemon already */ 34466861Seric saveerrno = errno; 34566861Seric syserr("opendaemonsocket: can't create server SMTP socket"); 34666861Seric severe: 34766845Seric # ifdef LOG 34866861Seric if (LogLevel > 0) 34966861Seric syslog(LOG_ALERT, "problem creating SMTP socket"); 35066845Seric # endif /* LOG */ 35166861Seric DaemonSocket = -1; 35266861Seric continue; 35366861Seric } 35466845Seric 35566861Seric /* turn on network debugging? */ 35666861Seric if (tTd(15, 101)) 35766861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 35866861Seric SO_DEBUG, (char *)&on, 35966861Seric sizeof on); 36066845Seric 36166861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 36266861Seric SO_REUSEADDR, (char *)&on, sizeof on); 36366861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 36466861Seric SO_KEEPALIVE, (char *)&on, sizeof on); 36566845Seric 36666845Seric #ifdef SO_RCVBUF 36766861Seric if (TcpRcvBufferSize > 0) 36866861Seric { 36966861Seric if (setsockopt(DaemonSocket, SOL_SOCKET, 37066861Seric SO_RCVBUF, 37166861Seric (char *) &TcpRcvBufferSize, 37266861Seric sizeof(TcpRcvBufferSize)) < 0) 37366861Seric syserr("getrequests: setsockopt(SO_RCVBUF)"); 37466861Seric } 37566845Seric #endif 37666845Seric 37766861Seric switch (DaemonAddr.sa.sa_family) 37866861Seric { 37966845Seric # ifdef NETINET 38066861Seric case AF_INET: 38166861Seric socksize = sizeof DaemonAddr.sin; 38266861Seric break; 38366845Seric # endif 38466845Seric 38566845Seric # ifdef NETISO 38666861Seric case AF_ISO: 38766861Seric socksize = sizeof DaemonAddr.siso; 38866861Seric break; 38966845Seric # endif 39066845Seric 39166861Seric default: 39266861Seric socksize = sizeof DaemonAddr; 39366861Seric break; 39466861Seric } 39566861Seric 39666861Seric if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0) 39766861Seric { 39866861Seric saveerrno = errno; 39966861Seric syserr("getrequests: cannot bind"); 40066861Seric (void) close(DaemonSocket); 40166861Seric goto severe; 40266861Seric } 40366854Seric } 40466861Seric if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0) 40566854Seric { 40666861Seric saveerrno = errno; 40766861Seric syserr("getrequests: cannot listen"); 40866854Seric (void) close(DaemonSocket); 40966854Seric goto severe; 41066854Seric } 41166861Seric return socksize; 41266861Seric } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno)); 41367448Seric syserr("!opendaemonsocket: server SMTP socket wedged: exiting"); 41466861Seric finis(); 41566845Seric } 41666845Seric /* 41710206Seric ** CLRDAEMON -- reset the daemon connection 41810206Seric ** 41910206Seric ** Parameters: 42010206Seric ** none. 42110206Seric ** 42210206Seric ** Returns: 42310206Seric ** none. 42410206Seric ** 42510206Seric ** Side Effects: 42610206Seric ** releases any resources used by the passive daemon. 42710206Seric */ 42810206Seric 42910206Seric clrdaemon() 43010206Seric { 43110206Seric if (DaemonSocket >= 0) 43210206Seric (void) close(DaemonSocket); 43310206Seric DaemonSocket = -1; 43410206Seric } 43510206Seric /* 43658849Seric ** SETDAEMONOPTIONS -- set options for running the daemon 43758849Seric ** 43858849Seric ** Parameters: 43958849Seric ** p -- the options line. 44058849Seric ** 44158849Seric ** Returns: 44258849Seric ** none. 44358849Seric */ 44458849Seric 44558849Seric setdaemonoptions(p) 44658849Seric register char *p; 44758849Seric { 44858873Seric if (DaemonAddr.sa.sa_family == AF_UNSPEC) 44958873Seric DaemonAddr.sa.sa_family = AF_INET; 45058873Seric 45158849Seric while (p != NULL) 45258849Seric { 45358849Seric register char *f; 45458849Seric register char *v; 45558849Seric 45658849Seric while (isascii(*p) && isspace(*p)) 45758849Seric p++; 45858849Seric if (*p == '\0') 45958849Seric break; 46058849Seric f = p; 46158849Seric p = strchr(p, ','); 46258849Seric if (p != NULL) 46358849Seric *p++ = '\0'; 46458849Seric v = strchr(f, '='); 46558849Seric if (v == NULL) 46658849Seric continue; 46758849Seric while (isascii(*++v) && isspace(*v)) 46858849Seric continue; 46958849Seric 47058849Seric switch (*f) 47158849Seric { 47258873Seric case 'F': /* address family */ 47358849Seric if (isascii(*v) && isdigit(*v)) 47458873Seric DaemonAddr.sa.sa_family = atoi(v); 47558873Seric #ifdef NETINET 47658873Seric else if (strcasecmp(v, "inet") == 0) 47758873Seric DaemonAddr.sa.sa_family = AF_INET; 47858873Seric #endif 47958873Seric #ifdef NETISO 48058873Seric else if (strcasecmp(v, "iso") == 0) 48158873Seric DaemonAddr.sa.sa_family = AF_ISO; 48258873Seric #endif 48358873Seric #ifdef NETNS 48458873Seric else if (strcasecmp(v, "ns") == 0) 48558873Seric DaemonAddr.sa.sa_family = AF_NS; 48658873Seric #endif 48758873Seric #ifdef NETX25 48858873Seric else if (strcasecmp(v, "x.25") == 0) 48958873Seric DaemonAddr.sa.sa_family = AF_CCITT; 49058873Seric #endif 49158849Seric else 49258873Seric syserr("554 Unknown address family %s in Family=option", v); 49358873Seric break; 49458873Seric 49558873Seric case 'A': /* address */ 49658873Seric switch (DaemonAddr.sa.sa_family) 49758849Seric { 49858873Seric #ifdef NETINET 49958873Seric case AF_INET: 50058873Seric if (isascii(*v) && isdigit(*v)) 50158873Seric DaemonAddr.sin.sin_addr.s_addr = inet_network(v); 50258873Seric else 50358873Seric { 50458873Seric register struct netent *np; 50558849Seric 50658873Seric np = getnetbyname(v); 50758873Seric if (np == NULL) 50858873Seric syserr("554 network \"%s\" unknown", v); 50958873Seric else 51058873Seric DaemonAddr.sin.sin_addr.s_addr = np->n_net; 51158873Seric } 51258873Seric break; 51358873Seric #endif 51458873Seric 51558873Seric default: 51658873Seric syserr("554 Address= option unsupported for family %d", 51758873Seric DaemonAddr.sa.sa_family); 51858873Seric break; 51958849Seric } 52058849Seric break; 52158849Seric 52258873Seric case 'P': /* port */ 52358873Seric switch (DaemonAddr.sa.sa_family) 52458849Seric { 52558873Seric short port; 52658849Seric 52758873Seric #ifdef NETINET 52858873Seric case AF_INET: 52958873Seric if (isascii(*v) && isdigit(*v)) 53064366Seric DaemonAddr.sin.sin_port = htons(atoi(v)); 53158849Seric else 53258873Seric { 53358873Seric register struct servent *sp; 53458873Seric 53558873Seric sp = getservbyname(v, "tcp"); 53658873Seric if (sp == NULL) 53758909Seric syserr("554 service \"%s\" unknown", v); 53858873Seric else 53958873Seric DaemonAddr.sin.sin_port = sp->s_port; 54058873Seric } 54158873Seric break; 54258873Seric #endif 54358873Seric 54458873Seric #ifdef NETISO 54558873Seric case AF_ISO: 54658873Seric /* assume two byte transport selector */ 54758873Seric if (isascii(*v) && isdigit(*v)) 54864366Seric port = htons(atoi(v)); 54958873Seric else 55058873Seric { 55158873Seric register struct servent *sp; 55258873Seric 55358873Seric sp = getservbyname(v, "tcp"); 55458873Seric if (sp == NULL) 55558909Seric syserr("554 service \"%s\" unknown", v); 55658873Seric else 55758873Seric port = sp->s_port; 55858873Seric } 55958873Seric bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 56058873Seric break; 56158873Seric #endif 56258873Seric 56358873Seric default: 56458873Seric syserr("554 Port= option unsupported for family %d", 56558873Seric DaemonAddr.sa.sa_family); 56658873Seric break; 56758849Seric } 56858849Seric break; 56959783Seric 57059783Seric case 'L': /* listen queue size */ 57159783Seric ListenQueueSize = atoi(v); 57259783Seric break; 57364381Seric 57464381Seric case 'S': /* send buffer size */ 57564381Seric TcpSndBufferSize = atoi(v); 57664381Seric break; 57764381Seric 57864381Seric case 'R': /* receive buffer size */ 57964381Seric TcpRcvBufferSize = atoi(v); 58064381Seric break; 58158849Seric } 58258849Seric } 58358849Seric } 58458849Seric /* 5856039Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 5866039Seric ** 5876039Seric ** Parameters: 5886039Seric ** host -- the name of the host. 5896633Seric ** port -- the port number to connect to. 59053739Seric ** mci -- a pointer to the mail connection information 59153739Seric ** structure to be filled in. 59252106Seric ** usesecureport -- if set, use a low numbered (reserved) 59352106Seric ** port to provide some rudimentary authentication. 5946039Seric ** 5956039Seric ** Returns: 5966039Seric ** An exit code telling whether the connection could be 5976039Seric ** made and if not why not. 5986039Seric ** 5996039Seric ** Side Effects: 6006039Seric ** none. 6016039Seric */ 6025978Seric 60358755Seric SOCKADDR CurHostAddr; /* address of current host */ 60458305Seric 60554967Seric int 60653739Seric makeconnection(host, port, mci, usesecureport) 6076039Seric char *host; 6087286Seric u_short port; 60954967Seric register MCI *mci; 61052106Seric bool usesecureport; 6116039Seric { 61229430Sbloom register int i, s; 61329430Sbloom register struct hostent *hp = (struct hostent *)NULL; 61458755Seric SOCKADDR addr; 61552106Seric int sav_errno; 61658755Seric int addrlen; 61766334Seric #if NAMED_BIND 61835651Seric extern int h_errno; 61935651Seric #endif 6206039Seric 6216039Seric /* 6226039Seric ** Set up the address for the mailer. 6239308Seric ** Accept "[a.b.c.d]" syntax for host name. 6246039Seric */ 6256039Seric 62666334Seric #if NAMED_BIND 62725475Smiriam h_errno = 0; 62835651Seric #endif 62925475Smiriam errno = 0; 63058864Seric bzero(&CurHostAddr, sizeof CurHostAddr); 63164334Seric SmtpPhase = mci->mci_phase = "initial connection"; 63258906Seric CurHostName = host; 63325475Smiriam 6349308Seric if (host[0] == '[') 6359308Seric { 63611147Seric long hid; 63756795Seric register char *p = strchr(host, ']'); 6389308Seric 63911147Seric if (p != NULL) 6409308Seric { 64111147Seric *p = '\0'; 64259884Seric #ifdef NETINET 64311147Seric hid = inet_addr(&host[1]); 64458360Seric if (hid == -1) 64559884Seric #endif 64658360Seric { 64758360Seric /* try it as a host name (avoid MX lookup) */ 64858360Seric hp = gethostbyname(&host[1]); 64966349Seric if (hp == NULL && p[-1] == '.') 65066349Seric { 65167265Seric #ifdef NAMED_BIND 65267265Seric int oldopts = _res.options; 65367265Seric 65467265Seric _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 65567265Seric #endif 65666349Seric p[-1] = '\0'; 65766349Seric hp = gethostbyname(&host[1]); 65866349Seric p[-1] = '.'; 65967265Seric #ifdef NAMED_BIND 66067265Seric _res.options = oldopts; 66167265Seric #endif 66266349Seric } 66358360Seric *p = ']'; 66458360Seric goto gothostent; 66558360Seric } 66611147Seric *p = ']'; 6679308Seric } 66858360Seric if (p == NULL) 6699308Seric { 67058151Seric usrerr("553 Invalid numeric domain spec \"%s\"", host); 6719308Seric return (EX_NOHOST); 6729308Seric } 67359884Seric #ifdef NETINET 67459884Seric addr.sin.sin_family = AF_INET; /*XXX*/ 67558778Seric addr.sin.sin_addr.s_addr = hid; 67659884Seric #endif 6779308Seric } 6789610Seric else 6799610Seric { 68066349Seric register char *p = &host[strlen(host) - 1]; 68166349Seric 68229430Sbloom hp = gethostbyname(host); 68366349Seric if (hp == NULL && *p == '.') 68466349Seric { 68567265Seric #ifdef NAMED_BIND 68667265Seric int oldopts = _res.options; 68767265Seric 68867265Seric _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 68967265Seric #endif 69066349Seric *p = '\0'; 69166349Seric hp = gethostbyname(host); 69266349Seric *p = '.'; 69367265Seric #ifdef NAMED_BIND 69467265Seric _res.options = oldopts; 69567265Seric #endif 69666349Seric } 69758360Seric gothostent: 69825475Smiriam if (hp == NULL) 69924945Seric { 70066334Seric #if NAMED_BIND 70125475Smiriam if (errno == ETIMEDOUT || h_errno == TRY_AGAIN) 70225475Smiriam return (EX_TEMPFAIL); 70325657Seric 70435651Seric /* if name server is specified, assume temp fail */ 70535651Seric if (errno == ECONNREFUSED && UseNameServer) 70635651Seric return (EX_TEMPFAIL); 70735651Seric #endif 70825475Smiriam return (EX_NOHOST); 70924945Seric } 71058778Seric addr.sa.sa_family = hp->h_addrtype; 71158778Seric switch (hp->h_addrtype) 71258778Seric { 71358778Seric #ifdef NETINET 71458778Seric case AF_INET: 71558755Seric bcopy(hp->h_addr, 71658778Seric &addr.sin.sin_addr, 71767421Seric INADDRSZ); 71858778Seric break; 71958778Seric #endif 72058778Seric 72158778Seric default: 72258755Seric bcopy(hp->h_addr, 72358778Seric addr.sa.sa_data, 72458755Seric hp->h_length); 72558778Seric break; 72658778Seric } 72729430Sbloom i = 1; 7289610Seric } 7299610Seric 7309610Seric /* 7319610Seric ** Determine the port number. 7329610Seric */ 7339610Seric 73410011Seric if (port != 0) 73558755Seric port = htons(port); 73610011Seric else 7379610Seric { 7389610Seric register struct servent *sp = getservbyname("smtp", "tcp"); 7399610Seric 7409610Seric if (sp == NULL) 7419610Seric { 74258909Seric syserr("554 makeconnection: service \"smtp\" unknown"); 74365169Seric port = htons(25); 7449610Seric } 74565169Seric else 74665169Seric port = sp->s_port; 7479610Seric } 7486039Seric 74958778Seric switch (addr.sa.sa_family) 75058755Seric { 75159884Seric #ifdef NETINET 75258755Seric case AF_INET: 75358778Seric addr.sin.sin_port = port; 75458755Seric addrlen = sizeof (struct sockaddr_in); 75558755Seric break; 75659884Seric #endif 75758755Seric 75858755Seric #ifdef NETISO 75958755Seric case AF_ISO: 76058755Seric /* assume two byte transport selector */ 76158755Seric bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 76258755Seric addrlen = sizeof (struct sockaddr_iso); 76358755Seric break; 76458755Seric #endif 76558755Seric 76658755Seric default: 76758778Seric syserr("Can't connect to address family %d", addr.sa.sa_family); 76858755Seric return (EX_NOHOST); 76958755Seric } 77058755Seric 7716039Seric /* 7726039Seric ** Try to actually open the connection. 7736039Seric */ 7746039Seric 77559156Seric #ifdef XLA 77659156Seric /* if too many connections, don't bother trying */ 77759156Seric if (!xla_noqueue_ok(host)) 77859156Seric return EX_TEMPFAIL; 77959156Seric #endif 78059156Seric 78157736Seric for (;;) 78252106Seric { 78357736Seric if (tTd(16, 1)) 78458755Seric printf("makeconnection (%s [%s])\n", 78558755Seric host, anynet_ntoa(&addr)); 78652106Seric 78758588Seric /* save for logging */ 78858588Seric CurHostAddr = addr; 78958588Seric 79057736Seric if (usesecureport) 79157736Seric { 79257736Seric int rport = IPPORT_RESERVED - 1; 7936039Seric 79457736Seric s = rresvport(&rport); 79557736Seric } 79657736Seric else 79757736Seric { 79857736Seric s = socket(AF_INET, SOCK_STREAM, 0); 79957736Seric } 80057736Seric if (s < 0) 80157736Seric { 80257736Seric sav_errno = errno; 80357736Seric syserr("makeconnection: no socket"); 80457736Seric goto failure; 80557736Seric } 80610347Seric 80764381Seric #ifdef SO_SNDBUF 80864381Seric if (TcpSndBufferSize > 0) 80964381Seric { 81064381Seric if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 81164561Seric (char *) &TcpSndBufferSize, 81264381Seric sizeof(TcpSndBufferSize)) < 0) 81364381Seric syserr("makeconnection: setsockopt(SO_SNDBUF)"); 81464381Seric } 81564381Seric #endif 81664381Seric 81757736Seric if (tTd(16, 1)) 81857736Seric printf("makeconnection: fd=%d\n", s); 81957736Seric 82057736Seric /* turn on network debugging? */ 82157736Seric if (tTd(16, 101)) 82257736Seric { 82357736Seric int on = 1; 82466861Seric (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 82557736Seric (char *)&on, sizeof on); 82657736Seric } 82757736Seric if (CurEnv->e_xfp != NULL) 82857736Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 82957736Seric errno = 0; /* for debugging */ 83058755Seric if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 83157736Seric break; 83257736Seric 83357736Seric /* couldn't connect.... figure out why */ 83427744Sbloom sav_errno = errno; 83527744Sbloom (void) close(s); 83629430Sbloom if (hp && hp->h_addr_list[i]) 83729430Sbloom { 83857736Seric if (tTd(16, 1)) 83958755Seric printf("Connect failed (%s); trying new address....\n", 84058755Seric errstring(sav_errno)); 84158778Seric switch (addr.sa.sa_family) 84258778Seric { 84358778Seric #ifdef NETINET 84458778Seric case AF_INET: 84558755Seric bcopy(hp->h_addr_list[i++], 84658778Seric &addr.sin.sin_addr, 84767421Seric INADDRSZ); 84858778Seric break; 84958778Seric #endif 85058778Seric 85158778Seric default: 85258755Seric bcopy(hp->h_addr_list[i++], 85358778Seric addr.sa.sa_data, 85452106Seric hp->h_length); 85558778Seric break; 85658778Seric } 85757736Seric continue; 85829430Sbloom } 85929430Sbloom 8606039Seric /* failure, decide if temporary or not */ 8616039Seric failure: 86259254Seric #ifdef XLA 86359254Seric xla_host_end(host); 86459254Seric #endif 86558542Seric if (transienterror(sav_errno)) 86658542Seric return EX_TEMPFAIL; 86758542Seric else 86858542Seric { 86958542Seric message("%s", errstring(sav_errno)); 87058542Seric return (EX_UNAVAILABLE); 8716039Seric } 8726039Seric } 8736039Seric 8746039Seric /* connection ok, put it into canonical form */ 87564724Seric if ((mci->mci_out = fdopen(s, "w")) == NULL || 87664724Seric (s = dup(s)) < 0 || 87764725Seric (mci->mci_in = fdopen(s, "r")) == NULL) 87864724Seric { 87964724Seric syserr("cannot open SMTP client channel, fd=%d", s); 88064724Seric return EX_TEMPFAIL; 88164724Seric } 8826039Seric 88310098Seric return (EX_OK); 8846039Seric } 88510758Seric /* 88610758Seric ** MYHOSTNAME -- return the name of this host. 88710758Seric ** 88810758Seric ** Parameters: 88910758Seric ** hostbuf -- a place to return the name of this host. 89012313Seric ** size -- the size of hostbuf. 89110758Seric ** 89210758Seric ** Returns: 89310758Seric ** A list of aliases for this host. 89410758Seric ** 89510758Seric ** Side Effects: 89664338Seric ** Adds numeric codes to $=w. 89710758Seric */ 8986039Seric 89967140Seric struct hostent * 90012313Seric myhostname(hostbuf, size) 90110758Seric char hostbuf[]; 90212313Seric int size; 90310758Seric { 90458110Seric register struct hostent *hp; 90510758Seric extern struct hostent *gethostbyname(); 90667448Seric extern bool getcanonname(); 90767448Seric extern int h_errno; 90810758Seric 90923120Seric if (gethostname(hostbuf, size) < 0) 91023120Seric { 91123120Seric (void) strcpy(hostbuf, "localhost"); 91223120Seric } 91311147Seric hp = gethostbyname(hostbuf); 91466853Seric if (hp == NULL) 91516877Seric { 91666853Seric syserr("!My host name (%s) does not seem to exist!", hostbuf); 91766853Seric } 91867448Seric if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 91967448Seric { 92067448Seric (void) strncpy(hostbuf, hp->h_name, size - 1); 92167448Seric hostbuf[size - 1] = '\0'; 92267448Seric } 92366853Seric 92466853Seric #if NAMED_BIND 92567448Seric /* 92667448Seric ** If still no dot, try DNS directly (i.e., avoid NIS problems). 92767448Seric ** This ought to be driven from the configuration file, but 92867448Seric ** we are called before the configuration is read. We could 92967448Seric ** check for an /etc/resolv.conf file, but that isn't required. 93067448Seric ** All in all, a bit of a mess. 93167448Seric */ 93267448Seric 93367448Seric if (strchr(hostbuf, '.') == NULL && 93467448Seric !getcanonname(hostbuf, size, TRUE) && 93567448Seric h_errno == TRY_AGAIN) 93666853Seric { 93767448Seric struct stat stbuf; 93866853Seric 93966853Seric /* try twice in case name server not yet started up */ 94067448Seric message("My unqualifed host name (%s) unknown to DNS; sleeping for retry", 94167448Seric hostbuf); 94267448Seric sleep(60); 94367448Seric if (!getcanonname(hostbuf, size, TRUE)) 94466853Seric errno = h_errno + E_DNSBASE; 94566853Seric } 94666777Seric #endif 94767140Seric return (hp); 94810758Seric } 94951315Seric /* 95058951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 95158308Seric ** 95258951Seric ** Uses RFC1413 protocol to try to get info from the other end. 95358951Seric ** 95458308Seric ** Parameters: 95558308Seric ** fd -- the descriptor 95658308Seric ** 95758308Seric ** Returns: 95858951Seric ** The user@host information associated with this descriptor. 95958308Seric */ 96058308Seric 96164927Seric #if IDENTPROTO 96258951Seric 96358951Seric static jmp_buf CtxAuthTimeout; 96458951Seric 96558951Seric static 96658951Seric authtimeout() 96758951Seric { 96858951Seric longjmp(CtxAuthTimeout, 1); 96958951Seric } 97058951Seric 97158951Seric #endif 97258951Seric 97358308Seric char * 97458951Seric getauthinfo(fd) 97558308Seric int fd; 97658308Seric { 97758951Seric int falen; 97859104Seric register char *p; 97964927Seric #if IDENTPROTO 98058951Seric SOCKADDR la; 98158951Seric int lalen; 98258951Seric register struct servent *sp; 98358951Seric int s; 98458951Seric int i; 98558951Seric EVENT *ev; 98658951Seric #endif 98758951Seric static char hbuf[MAXNAME * 2 + 2]; 98858951Seric extern char *hostnamebyanyaddr(); 98958951Seric extern char RealUserName[]; /* main.c */ 99058308Seric 99166761Seric falen = sizeof RealHostAddr; 99267468Seric if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 || 99367468Seric falen <= 0 || RealHostAddr.sa.sa_family == 0) 99458951Seric { 99558951Seric (void) sprintf(hbuf, "%s@localhost", RealUserName); 99658957Seric if (tTd(9, 1)) 99758951Seric printf("getauthinfo: %s\n", hbuf); 99858951Seric return hbuf; 99958951Seric } 100058951Seric 100166761Seric if (RealHostName == NULL) 100266761Seric { 100366761Seric /* translate that to a host name */ 100466761Seric RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 100566761Seric } 100666761Seric 100764927Seric #if IDENTPROTO 100865831Seric if (TimeOuts.to_ident == 0) 100965831Seric goto noident; 101065831Seric 101158951Seric lalen = sizeof la; 101266761Seric if (RealHostAddr.sa.sa_family != AF_INET || 101358951Seric getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 101458951Seric la.sa.sa_family != AF_INET) 101558951Seric { 101658951Seric /* no ident info */ 101758951Seric goto noident; 101858951Seric } 101958951Seric 102058951Seric /* create ident query */ 102160489Seric (void) sprintf(hbuf, "%d,%d\r\n", 102266761Seric ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port)); 102358951Seric 102458951Seric /* create local address */ 102564747Seric la.sin.sin_port = 0; 102658951Seric 102758951Seric /* create foreign address */ 102858951Seric sp = getservbyname("auth", "tcp"); 102958951Seric if (sp != NULL) 103066761Seric RealHostAddr.sin.sin_port = sp->s_port; 103158308Seric else 103266761Seric RealHostAddr.sin.sin_port = htons(113); 103358951Seric 103458951Seric s = -1; 103558951Seric if (setjmp(CtxAuthTimeout) != 0) 103658951Seric { 103758951Seric if (s >= 0) 103858951Seric (void) close(s); 103958951Seric goto noident; 104058951Seric } 104158951Seric 104258951Seric /* put a timeout around the whole thing */ 104364255Seric ev = setevent(TimeOuts.to_ident, authtimeout, 0); 104458951Seric 104564747Seric /* connect to foreign IDENT server using same address as SMTP socket */ 104658951Seric s = socket(AF_INET, SOCK_STREAM, 0); 104758951Seric if (s < 0) 104858951Seric { 104958951Seric clrevent(ev); 105058951Seric goto noident; 105158951Seric } 105264747Seric if (bind(s, &la.sa, sizeof la.sin) < 0 || 105366761Seric connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0) 105458951Seric { 105566011Seric goto closeident; 105658951Seric } 105758951Seric 105858957Seric if (tTd(9, 10)) 105958951Seric printf("getauthinfo: sent %s", hbuf); 106058951Seric 106158951Seric /* send query */ 106258951Seric if (write(s, hbuf, strlen(hbuf)) < 0) 106358951Seric goto closeident; 106458951Seric 106558951Seric /* get result */ 106658951Seric i = read(s, hbuf, sizeof hbuf); 106758951Seric (void) close(s); 106858951Seric clrevent(ev); 106958951Seric if (i <= 0) 107058951Seric goto noident; 107158951Seric if (hbuf[--i] == '\n' && hbuf[--i] == '\r') 107258951Seric i--; 107358951Seric hbuf[++i] = '\0'; 107458951Seric 107558957Seric if (tTd(9, 3)) 107658951Seric printf("getauthinfo: got %s\n", hbuf); 107758951Seric 107858951Seric /* parse result */ 107958951Seric p = strchr(hbuf, ':'); 108058951Seric if (p == NULL) 108158951Seric { 108258951Seric /* malformed response */ 108358951Seric goto noident; 108458951Seric } 108558951Seric while (isascii(*++p) && isspace(*p)) 108658951Seric continue; 108758951Seric if (strncasecmp(p, "userid", 6) != 0) 108858951Seric { 108958951Seric /* presumably an error string */ 109058951Seric goto noident; 109158951Seric } 109258951Seric p += 6; 109358951Seric while (isascii(*p) && isspace(*p)) 109458951Seric p++; 109558951Seric if (*p++ != ':') 109658951Seric { 109758951Seric /* either useridxx or malformed response */ 109858951Seric goto noident; 109958951Seric } 110058951Seric 110158951Seric /* p now points to the OSTYPE field */ 110258951Seric p = strchr(p, ':'); 110358951Seric if (p == NULL) 110458951Seric { 110558951Seric /* malformed response */ 110658951Seric goto noident; 110758951Seric } 110858951Seric 110958957Seric /* 1413 says don't do this -- but it's broken otherwise */ 111058957Seric while (isascii(*++p) && isspace(*p)) 111158957Seric continue; 111258957Seric 1113*67935Seric /* p now points to the authenticated name -- copy carefully */ 1114*67935Seric for (i = 0; i < MAXNAME && *p != '\0'; p++) 1115*67935Seric { 1116*67935Seric if (isascii(*p) && 1117*67935Seric (isalnum(*p) || strchr("!#$%&'*+-./^_`{|}~", *p) != NULL)) 1118*67935Seric hbuf[i++] = *p; 1119*67935Seric } 1120*67935Seric hbuf[i++] = '@'; 1121*67935Seric strcpy(&hbuf[i], RealHostName == NULL ? "localhost" : RealHostName); 112258957Seric goto finish; 112358957Seric 112466011Seric closeident: 112566011Seric (void) close(s); 112666011Seric clrevent(ev); 112766011Seric 112858957Seric #endif /* IDENTPROTO */ 112958957Seric 113058957Seric noident: 113166003Seric if (RealHostName == NULL) 113266003Seric { 113366003Seric if (tTd(9, 1)) 113466003Seric printf("getauthinfo: NULL\n"); 113566003Seric return NULL; 113666003Seric } 113758957Seric (void) strcpy(hbuf, RealHostName); 113858957Seric 113958957Seric finish: 114066003Seric if (RealHostName != NULL && RealHostName[0] != '[') 114158951Seric { 114258951Seric p = &hbuf[strlen(hbuf)]; 114358951Seric (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 114458951Seric } 114558957Seric if (tTd(9, 1)) 114658951Seric printf("getauthinfo: %s\n", hbuf); 114758308Seric return hbuf; 114858308Seric } 114958308Seric /* 115060089Seric ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 115153751Seric ** 115253751Seric ** Parameters: 115356823Seric ** map -- a pointer to this map (unused). 115460089Seric ** name -- the (presumably unqualified) hostname. 115560257Seric ** av -- unused -- for compatibility with other mapping 115655019Seric ** functions. 115759084Seric ** statp -- an exit status (out parameter) -- set to 115859084Seric ** EX_TEMPFAIL if the name server is unavailable. 115953751Seric ** 116053751Seric ** Returns: 116153751Seric ** The mapping, if found. 116253751Seric ** NULL if no mapping found. 116353751Seric ** 116453751Seric ** Side Effects: 116553751Seric ** Looks up the host specified in hbuf. If it is not 116653751Seric ** the canonical name for that host, return the canonical 116753751Seric ** name. 116853751Seric */ 116951315Seric 117053751Seric char * 117160257Seric host_map_lookup(map, name, av, statp) 117256823Seric MAP *map; 117360089Seric char *name; 117460257Seric char **av; 117559084Seric int *statp; 117616911Seric { 117716911Seric register struct hostent *hp; 117867419Seric struct in_addr in_addr; 117956823Seric char *cp; 118058110Seric int i; 118159671Seric register STAB *s; 118260257Seric char hbuf[MAXNAME]; 118359671Seric extern struct hostent *gethostbyaddr(); 118466334Seric #if NAMED_BIND 118559671Seric extern int h_errno; 118666029Seric #endif 118716911Seric 118825574Smiriam /* 118959671Seric ** See if we have already looked up this name. If so, just 119059671Seric ** return it. 119159671Seric */ 119253751Seric 119360089Seric s = stab(name, ST_NAMECANON, ST_ENTER); 119459671Seric if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 119559671Seric { 119659986Seric if (tTd(9, 1)) 119760089Seric printf("host_map_lookup(%s) => CACHE %s\n", 119860089Seric name, s->s_namecanon.nc_cname); 119959671Seric errno = s->s_namecanon.nc_errno; 120066334Seric #if NAMED_BIND 120159671Seric h_errno = s->s_namecanon.nc_herrno; 120266029Seric #endif 120359671Seric *statp = s->s_namecanon.nc_stat; 120464797Seric if (CurEnv->e_message == NULL && *statp == EX_TEMPFAIL) 120565199Seric { 120665199Seric sprintf(hbuf, "%s: Name server timeout", 120765199Seric shortenstring(name, 33)); 120865199Seric CurEnv->e_message = newstr(hbuf); 120965199Seric } 121059671Seric return s->s_namecanon.nc_cname; 121159671Seric } 121259671Seric 121359671Seric /* 121459671Seric ** If first character is a bracket, then it is an address 121559671Seric ** lookup. Address is copied into a temporary buffer to 121660089Seric ** strip the brackets and to preserve name if address is 121759671Seric ** unknown. 121859671Seric */ 121959671Seric 122060089Seric if (*name != '[') 122153751Seric { 122255019Seric extern bool getcanonname(); 122355019Seric 122458798Seric if (tTd(9, 1)) 122560089Seric printf("host_map_lookup(%s) => ", name); 122659671Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 122760089Seric (void) strcpy(hbuf, name); 122863842Seric if (getcanonname(hbuf, sizeof hbuf - 1, TRUE)) 122958796Seric { 123058796Seric if (tTd(9, 1)) 123158796Seric printf("%s\n", hbuf); 123260257Seric cp = map_rewrite(map, hbuf, strlen(hbuf), av); 123360257Seric s->s_namecanon.nc_cname = newstr(cp); 123460257Seric return cp; 123558796Seric } 123653751Seric else 123758796Seric { 123859084Seric register struct hostent *hp; 123959084Seric 124066029Seric s->s_namecanon.nc_errno = errno; 124166334Seric #if NAMED_BIND 124266029Seric s->s_namecanon.nc_herrno = h_errno; 124358796Seric if (tTd(9, 1)) 124459084Seric printf("FAIL (%d)\n", h_errno); 124559084Seric switch (h_errno) 124659084Seric { 124759084Seric case TRY_AGAIN: 124859596Seric if (UseNameServer) 124959734Seric { 125065202Seric sprintf(hbuf, "%s: Name server timeout", 125165199Seric shortenstring(name, 33)); 125265202Seric message("%s", hbuf); 125359734Seric if (CurEnv->e_message == NULL) 125465202Seric CurEnv->e_message = newstr(hbuf); 125559734Seric } 125659084Seric *statp = EX_TEMPFAIL; 125759084Seric break; 125859084Seric 125959084Seric case HOST_NOT_FOUND: 126059084Seric *statp = EX_NOHOST; 126159084Seric break; 126259084Seric 126359084Seric case NO_RECOVERY: 126459084Seric *statp = EX_SOFTWARE; 126559084Seric break; 126659084Seric 126759084Seric default: 126859084Seric *statp = EX_UNAVAILABLE; 126959084Seric break; 127059084Seric } 127166029Seric #else 127266029Seric if (tTd(9, 1)) 127366029Seric printf("FAIL\n"); 127466029Seric *statp = EX_NOHOST; 127566029Seric #endif 127659671Seric s->s_namecanon.nc_stat = *statp; 127767422Seric if ((*statp != EX_TEMPFAIL && *statp != EX_NOHOST) || 127867422Seric UseNameServer) 127959084Seric return NULL; 128059084Seric 128159084Seric /* 128259084Seric ** Try to look it up in /etc/hosts 128359084Seric */ 128459084Seric 128560089Seric hp = gethostbyname(name); 128659084Seric if (hp == NULL) 128759084Seric { 128859084Seric /* no dice there either */ 128959671Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 129059084Seric return NULL; 129159084Seric } 129259084Seric 129359671Seric s->s_namecanon.nc_stat = *statp = EX_OK; 129460257Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 129560257Seric s->s_namecanon.nc_cname = newstr(cp); 129660257Seric return cp; 129758796Seric } 129853751Seric } 129960089Seric if ((cp = strchr(name, ']')) == NULL) 130053751Seric return (NULL); 130140994Sbostic *cp = '\0'; 130267419Seric in_addr.s_addr = inet_addr(&name[1]); 130358110Seric 130458110Seric /* nope -- ask the name server */ 130567421Seric hp = gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET); 130659671Seric s->s_namecanon.nc_errno = errno; 130766334Seric #if NAMED_BIND 130859671Seric s->s_namecanon.nc_herrno = h_errno; 130966029Seric #endif 131059671Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 131133932Sbostic if (hp == NULL) 131259671Seric { 131359671Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 131453751Seric return (NULL); 131559671Seric } 131653751Seric 131758110Seric /* found a match -- copy out */ 131860257Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 131959671Seric s->s_namecanon.nc_stat = *statp = EX_OK; 132060257Seric s->s_namecanon.nc_cname = newstr(cp); 132160257Seric return cp; 132233932Sbostic } 132358755Seric /* 132458755Seric ** ANYNET_NTOA -- convert a network address to printable form. 132558755Seric ** 132658755Seric ** Parameters: 132758755Seric ** sap -- a pointer to a sockaddr structure. 132858755Seric ** 132958755Seric ** Returns: 133058755Seric ** A printable version of that sockaddr. 133158755Seric */ 133216911Seric 133358755Seric char * 133458755Seric anynet_ntoa(sap) 133558755Seric register SOCKADDR *sap; 133658755Seric { 133758755Seric register char *bp; 133858755Seric register char *ap; 133958755Seric int l; 134064734Seric static char buf[100]; 134158755Seric 134258798Seric /* check for null/zero family */ 134358798Seric if (sap == NULL) 134458798Seric return "NULLADDR"; 134558798Seric if (sap->sa.sa_family == 0) 134658798Seric return "0"; 134758798Seric 134864734Seric switch (sap->sa.sa_family) 134964734Seric { 135064821Seric #ifdef NETUNIX 135164734Seric case AF_UNIX: 135264758Seric if (sap->sunix.sun_path[0] != '\0') 135364758Seric sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 135464734Seric else 135564734Seric sprintf(buf, "[UNIX: localhost]"); 135664734Seric return buf; 135764734Seric #endif 135864734Seric 135958778Seric #ifdef NETINET 136064734Seric case AF_INET: 136158755Seric return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 136258778Seric #endif 136358755Seric 136464734Seric default: 136564734Seric /* this case is only to ensure syntactic correctness */ 136664734Seric break; 136764734Seric } 136864734Seric 136958755Seric /* unknown family -- just dump bytes */ 137058778Seric (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 137158755Seric bp = &buf[strlen(buf)]; 137258778Seric ap = sap->sa.sa_data; 137358778Seric for (l = sizeof sap->sa.sa_data; --l >= 0; ) 137458755Seric { 137558755Seric (void) sprintf(bp, "%02x:", *ap++ & 0377); 137658755Seric bp += 3; 137758755Seric } 137858755Seric *--bp = '\0'; 137958755Seric return buf; 138058755Seric } 138158951Seric /* 138258951Seric ** HOSTNAMEBYANYADDR -- return name of host based on address 138358951Seric ** 138458951Seric ** Parameters: 138558951Seric ** sap -- SOCKADDR pointer 138658951Seric ** 138758951Seric ** Returns: 138858951Seric ** text representation of host name. 138958951Seric ** 139058951Seric ** Side Effects: 139158951Seric ** none. 139258951Seric */ 139358755Seric 139458951Seric char * 139558951Seric hostnamebyanyaddr(sap) 139658951Seric register SOCKADDR *sap; 139758951Seric { 139858951Seric register struct hostent *hp; 139964734Seric int saveretry; 140058951Seric 140166334Seric #if NAMED_BIND 140259042Seric /* shorten name server timeout to avoid higher level timeouts */ 140359042Seric saveretry = _res.retry; 140459042Seric _res.retry = 3; 140559042Seric #endif /* NAMED_BIND */ 140659042Seric 140758951Seric switch (sap->sa.sa_family) 140858951Seric { 140958951Seric #ifdef NETINET 141058951Seric case AF_INET: 141158951Seric hp = gethostbyaddr((char *) &sap->sin.sin_addr, 141267421Seric INADDRSZ, 141358951Seric AF_INET); 141458951Seric break; 141558951Seric #endif 141658951Seric 141758951Seric #ifdef NETISO 141858951Seric case AF_ISO: 141958951Seric hp = gethostbyaddr((char *) &sap->siso.siso_addr, 142058951Seric sizeof sap->siso.siso_addr, 142158951Seric AF_ISO); 142258951Seric break; 142358951Seric #endif 142458951Seric 142564734Seric case AF_UNIX: 142664734Seric hp = NULL; 142764734Seric break; 142864734Seric 142958951Seric default: 143058951Seric hp = gethostbyaddr(sap->sa.sa_data, 143158951Seric sizeof sap->sa.sa_data, 143258951Seric sap->sa.sa_family); 143358951Seric break; 143458951Seric } 143558951Seric 143666334Seric #if NAMED_BIND 143759042Seric _res.retry = saveretry; 143859042Seric #endif /* NAMED_BIND */ 143959042Seric 144058951Seric if (hp != NULL) 144158951Seric return hp->h_name; 144258951Seric else 144358951Seric { 144458951Seric /* produce a dotted quad */ 144558951Seric static char buf[512]; 144658951Seric 144758951Seric (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 144858951Seric return buf; 144958951Seric } 145058951Seric } 145158951Seric 145256795Seric # else /* DAEMON */ 145316911Seric /* code for systems without sophisticated networking */ 145410758Seric 145510758Seric /* 145610758Seric ** MYHOSTNAME -- stub version for case of no daemon code. 145711297Seric ** 145811297Seric ** Can't convert to upper case here because might be a UUCP name. 145912313Seric ** 146012313Seric ** Mark, you can change this to be anything you want...... 146110758Seric */ 146210758Seric 146310758Seric char ** 146412313Seric myhostname(hostbuf, size) 146510758Seric char hostbuf[]; 146612313Seric int size; 146710758Seric { 146810758Seric register FILE *f; 146910758Seric 147010758Seric hostbuf[0] = '\0'; 147110758Seric f = fopen("/usr/include/whoami", "r"); 147210758Seric if (f != NULL) 147310758Seric { 147412313Seric (void) fgets(hostbuf, size, f); 147510758Seric fixcrlf(hostbuf, TRUE); 147610758Seric (void) fclose(f); 147710758Seric } 147810758Seric return (NULL); 147910758Seric } 148016911Seric /* 148158951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 148258308Seric ** 148358308Seric ** Parameters: 148458308Seric ** fd -- the descriptor 148558308Seric ** 148658308Seric ** Returns: 148758308Seric ** The host name associated with this descriptor, if it can 148858308Seric ** be determined. 148958308Seric ** NULL otherwise. 149058308Seric ** 149158308Seric ** Side Effects: 149258308Seric ** none 149358308Seric */ 149458308Seric 149558308Seric char * 149658951Seric getauthinfo(fd) 149758308Seric int fd; 149858308Seric { 149958308Seric return NULL; 150058308Seric } 150158308Seric /* 150216911Seric ** MAPHOSTNAME -- turn a hostname into canonical form 150316911Seric ** 150416911Seric ** Parameters: 150556823Seric ** map -- a pointer to the database map. 150660089Seric ** name -- a buffer containing a hostname. 150753751Seric ** avp -- a pointer to a (cf file defined) argument vector. 150859084Seric ** statp -- an exit status (out parameter). 150916911Seric ** 151016911Seric ** Returns: 151153751Seric ** mapped host name 151251315Seric ** FALSE otherwise. 151316911Seric ** 151416911Seric ** Side Effects: 151560089Seric ** Looks up the host specified in name. If it is not 151616911Seric ** the canonical name for that host, replace it with 151716911Seric ** the canonical name. If the name is unknown, or it 151816911Seric ** is already the canonical name, leave it unchanged. 151916911Seric */ 152010758Seric 152116911Seric /*ARGSUSED*/ 152253751Seric char * 152360089Seric host_map_lookup(map, name, avp, statp) 152456823Seric MAP *map; 152560089Seric char *name; 152653751Seric char **avp; 152759084Seric char *statp; 152816911Seric { 152959084Seric register struct hostent *hp; 153059084Seric 153160089Seric hp = gethostbyname(name); 153259084Seric if (hp != NULL) 153359084Seric return hp->h_name; 153459084Seric *statp = EX_NOHOST; 153553751Seric return NULL; 153616911Seric } 153716911Seric 153856795Seric #endif /* DAEMON */ 1539