122700Sdist /* 268839Seric * Copyright (c) 1983, 1995 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*69511Seric static char sccsid[] = "@(#)daemon.c 8.87 (Berkeley) 05/16/95 (with daemon mode)"; 1533780Sbostic #else 16*69511Seric static char sccsid[] = "@(#)daemon.c 8.87 (Berkeley) 05/16/95 (without daemon mode)"; 1733780Sbostic #endif 1833780Sbostic #endif /* not lint */ 194535Seric 2033780Sbostic #ifdef DAEMON 2133780Sbostic 2264338Seric # include <arpa/inet.h> 235978Seric 2466334Seric #if NAMED_BIND 2559042Seric # include <resolv.h> 2659042Seric #endif 2759042Seric 284535Seric /* 294535Seric ** DAEMON.C -- routines to use when running as a daemon. 307556Seric ** 317556Seric ** This entire file is highly dependent on the 4.2 BSD 327556Seric ** interprocess communication primitives. No attempt has 337556Seric ** been made to make this file portable to Version 7, 347556Seric ** Version 6, MPX files, etc. If you should try such a 357556Seric ** thing yourself, I recommend chucking the entire file 367556Seric ** and starting from scratch. Basic semantics are: 377556Seric ** 387556Seric ** getrequests() 397556Seric ** Opens a port and initiates a connection. 407556Seric ** Returns in a child. Must set InChannel and 417556Seric ** OutChannel appropriately. 4210206Seric ** clrdaemon() 4310206Seric ** Close any open files associated with getting 4410206Seric ** the connection; this is used when running the queue, 4510206Seric ** etc., to avoid having extra file descriptors during 4610206Seric ** the queue run and to avoid confusing the network 4710206Seric ** code (if it cares). 4852106Seric ** makeconnection(host, port, outfile, infile, usesecureport) 497556Seric ** Make a connection to the named host on the given 507556Seric ** port. Set *outfile and *infile to the files 517556Seric ** appropriate for communication. Returns zero on 527556Seric ** success, else an exit status describing the 537556Seric ** error. 5460089Seric ** host_map_lookup(map, hbuf, avp, pstat) 5556823Seric ** Convert the entry in hbuf into a canonical form. 564535Seric */ 574535Seric /* 584535Seric ** GETREQUESTS -- open mail IPC port and get requests. 594535Seric ** 604535Seric ** Parameters: 614535Seric ** none. 624535Seric ** 634535Seric ** Returns: 644535Seric ** none. 654535Seric ** 664535Seric ** Side Effects: 674535Seric ** Waits until some interesting activity occurs. When 684535Seric ** it does, a child is created to process it, and the 694535Seric ** parent waits for completion. Return from this 709886Seric ** routine is always in the child. The file pointers 719886Seric ** "InChannel" and "OutChannel" should be set to point 729886Seric ** to the communication channel. 734535Seric */ 744535Seric 7558849Seric int DaemonSocket = -1; /* fd describing socket */ 7658849Seric SOCKADDR DaemonAddr; /* socket for incoming */ 7759783Seric int ListenQueueSize = 10; /* size of listen queue */ 7864381Seric int TcpRcvBufferSize = 0; /* size of TCP receive buffer */ 7964381Seric int TcpSndBufferSize = 0; /* size of TCP send buffer */ 8016144Seric 8168693Seric void 824535Seric getrequests() 834535Seric { 849610Seric int t; 8553751Seric bool refusingconnections = TRUE; 8658419Seric FILE *pidf; 8764828Seric int socksize; 8866793Seric #ifdef XDEBUG 8966793Seric bool j_has_dot; 9066793Seric #endif 9146928Sbostic extern void reapchild(); 927117Seric 939610Seric /* 949610Seric ** Set up the address for the mailer. 959610Seric */ 969610Seric 9758849Seric if (DaemonAddr.sin.sin_family == 0) 9858849Seric DaemonAddr.sin.sin_family = AF_INET; 9958849Seric if (DaemonAddr.sin.sin_addr.s_addr == 0) 10058849Seric DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY; 10158849Seric if (DaemonAddr.sin.sin_port == 0) 1029610Seric { 10365169Seric register struct servent *sp; 10465169Seric 10558849Seric sp = getservbyname("smtp", "tcp"); 10658849Seric if (sp == NULL) 10758849Seric { 10858909Seric syserr("554 service \"smtp\" unknown"); 10965169Seric DaemonAddr.sin.sin_port = htons(25); 11058849Seric } 11165169Seric else 11265169Seric DaemonAddr.sin.sin_port = sp->s_port; 1139610Seric } 1149610Seric 1159610Seric /* 1169610Seric ** Try to actually open the connection. 1179610Seric */ 1189610Seric 1199610Seric if (tTd(15, 1)) 12058849Seric printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port); 1219610Seric 1229610Seric /* get a socket for the SMTP connection */ 12366854Seric socksize = opendaemonsocket(TRUE); 12410347Seric 12564035Seric (void) setsignal(SIGCHLD, reapchild); 12624945Seric 12758419Seric /* write the pid to the log file for posterity */ 12858419Seric pidf = fopen(PidFile, "w"); 12958419Seric if (pidf != NULL) 13058419Seric { 13163863Seric extern char *CommandLineArgs; 13263863Seric 13363863Seric /* write the process id on line 1 */ 13458419Seric fprintf(pidf, "%d\n", getpid()); 13563863Seric 13663863Seric /* line 2 contains all command line flags */ 13763863Seric fprintf(pidf, "%s\n", CommandLineArgs); 13863863Seric 13963863Seric /* flush and close */ 14058419Seric fclose(pidf); 14158419Seric } 14258419Seric 14366793Seric #ifdef XDEBUG 14466793Seric { 14566812Seric char jbuf[MAXHOSTNAMELEN]; 14658419Seric 14768693Seric expand("\201j", jbuf, sizeof jbuf, CurEnv); 14866812Seric j_has_dot = strchr(jbuf, '.') != NULL; 14966793Seric } 15066793Seric #endif 15166793Seric 1529610Seric if (tTd(15, 1)) 15310206Seric printf("getrequests: %d\n", DaemonSocket); 1549610Seric 1554631Seric for (;;) 1564631Seric { 15714875Seric register int pid; 15811147Seric auto int lotherend; 15953751Seric extern bool refuseconnections(); 16068693Seric extern int getla(); 16111147Seric 16214875Seric /* see if we are rejecting connections */ 16353751Seric CurrentLA = getla(); 16453751Seric if (refuseconnections()) 16536584Sbostic { 16666845Seric if (DaemonSocket >= 0) 16753751Seric { 16866845Seric /* close socket so peer will fail quickly */ 16966845Seric (void) close(DaemonSocket); 17066845Seric DaemonSocket = -1; 17153751Seric } 17266845Seric refusingconnections = TRUE; 17357385Seric setproctitle("rejecting connections: load average: %d", 17457385Seric CurrentLA); 17566845Seric sleep(15); 17653751Seric continue; 17736584Sbostic } 17814875Seric 17968693Seric /* arrange to (re)open the socket if necessary */ 18053751Seric if (refusingconnections) 18153751Seric { 18267690Seric (void) opendaemonsocket(FALSE); 18353751Seric setproctitle("accepting connections"); 18453751Seric refusingconnections = FALSE; 18553751Seric } 18653751Seric 18766793Seric #ifdef XDEBUG 18866793Seric /* check for disaster */ 18966793Seric { 19066812Seric char jbuf[MAXHOSTNAMELEN]; 19166793Seric 19268693Seric expand("\201j", jbuf, sizeof jbuf, CurEnv); 19368693Seric if (!wordinclass(jbuf, 'w')) 19466793Seric { 19566793Seric dumpstate("daemon lost $j"); 19666793Seric syslog(LOG_ALERT, "daemon process doesn't have $j in $=w; see syslog"); 19766793Seric abort(); 19866793Seric } 19966812Seric else if (j_has_dot && strchr(jbuf, '.') == NULL) 20066793Seric { 20166793Seric dumpstate("daemon $j lost dot"); 20266793Seric syslog(LOG_ALERT, "daemon process $j lost dot; see syslog"); 20366793Seric abort(); 20466793Seric } 20566793Seric } 20666793Seric #endif 20766793Seric 2089610Seric /* wait for a connection */ 2099610Seric do 2109610Seric { 2119610Seric errno = 0; 21264828Seric lotherend = socksize; 21346928Sbostic t = accept(DaemonSocket, 21446928Sbostic (struct sockaddr *)&RealHostAddr, &lotherend); 2159610Seric } while (t < 0 && errno == EINTR); 2169610Seric if (t < 0) 2175978Seric { 2189610Seric syserr("getrequests: accept"); 21968693Seric 22068693Seric /* arrange to re-open the socket next time around */ 22168693Seric (void) close(DaemonSocket); 22268693Seric DaemonSocket = -1; 2239610Seric sleep(5); 2249610Seric continue; 2255978Seric } 2264631Seric 2275978Seric /* 2285978Seric ** Create a subprocess to process the mail. 2295978Seric */ 2305978Seric 2317677Seric if (tTd(15, 2)) 2329610Seric printf("getrequests: forking (fd = %d)\n", t); 2335978Seric 2344636Seric pid = fork(); 2354636Seric if (pid < 0) 2364631Seric { 2374636Seric syserr("daemon: cannot fork"); 2384636Seric sleep(10); 2399610Seric (void) close(t); 2404636Seric continue; 2414631Seric } 2424631Seric 2434636Seric if (pid == 0) 2444631Seric { 24564086Seric char *p; 24658951Seric extern char *hostnamebyanyaddr(); 24768693Seric extern void intsig(); 24811147Seric 2494636Seric /* 2504636Seric ** CHILD -- return to caller. 25111147Seric ** Collect verified idea of sending host. 2524636Seric ** Verify calling user id if possible here. 2534636Seric */ 2544631Seric 25564035Seric (void) setsignal(SIGCHLD, SIG_DFL); 25668693Seric (void) setsignal(SIGHUP, intsig); 25768693Seric (void) close(DaemonSocket); 25866017Seric DisConnected = FALSE; 25924950Seric 26066032Seric setproctitle("startup with %s", 26166032Seric anynet_ntoa(&RealHostAddr)); 26266032Seric 26311147Seric /* determine host name */ 26464086Seric p = hostnamebyanyaddr(&RealHostAddr); 26569471Seric if (strlen(p) > MAXNAME) 26669471Seric p[MAXNAME] = '\0'; 26764086Seric RealHostName = newstr(p); 26866032Seric setproctitle("startup with %s", p); 26958778Seric 27055173Seric #ifdef LOG 27163842Seric if (LogLevel > 11) 27255173Seric { 27355173Seric /* log connection information */ 27455173Seric syslog(LOG_INFO, "connect from %s (%s)", 27558951Seric RealHostName, anynet_ntoa(&RealHostAddr)); 27655173Seric } 27755173Seric #endif 27855173Seric 27964724Seric if ((InChannel = fdopen(t, "r")) == NULL || 28064724Seric (t = dup(t)) < 0 || 28164724Seric (OutChannel = fdopen(t, "w")) == NULL) 28264724Seric { 28364724Seric syserr("cannot open SMTP server channel, fd=%d", t); 28464724Seric exit(0); 28564724Seric } 28659254Seric 28716884Seric /* should we check for illegal connection here? XXX */ 28859156Seric #ifdef XLA 28959156Seric if (!xla_host_ok(RealHostName)) 29059156Seric { 29159254Seric message("421 Too many SMTP sessions for this host"); 29259156Seric exit(0); 29359156Seric } 29459156Seric #endif 29516884Seric 2967677Seric if (tTd(15, 2)) 2975978Seric printf("getreq: returning\n"); 2984636Seric return; 2994631Seric } 3004631Seric 3017117Seric /* close the port so that others will hang (for a while) */ 3029610Seric (void) close(t); 3034631Seric } 3049886Seric /*NOTREACHED*/ 3054631Seric } 3065978Seric /* 30766845Seric ** OPENDAEMONSOCKET -- open the SMTP socket 30866845Seric ** 30966845Seric ** Deals with setting all appropriate options. DaemonAddr must 31066845Seric ** be set up in advance. 31166845Seric ** 31266845Seric ** Parameters: 31366854Seric ** firsttime -- set if this is the initial open. 31466845Seric ** 31566845Seric ** Returns: 31666845Seric ** Size in bytes of the daemon socket addr. 31766845Seric ** 31866845Seric ** Side Effects: 31966845Seric ** Leaves DaemonSocket set to the open socket. 32066845Seric ** Exits if the socket cannot be created. 32166845Seric */ 32266845Seric 32366861Seric #define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 32466861Seric 32566845Seric int 32666854Seric opendaemonsocket(firsttime) 32766854Seric bool firsttime; 32866845Seric { 32966845Seric int on = 1; 33068693Seric int socksize = 0; 33166861Seric int ntries = 0; 33266861Seric int saveerrno; 33366845Seric 33466845Seric if (tTd(15, 2)) 33566845Seric printf("opendaemonsocket()\n"); 33666845Seric 33766861Seric do 33866845Seric { 33966862Seric if (ntries > 0) 34066862Seric sleep(5); 34166861Seric if (firsttime || DaemonSocket < 0) 34266854Seric { 34366861Seric DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0); 34466861Seric if (DaemonSocket < 0) 34566861Seric { 34666861Seric /* probably another daemon already */ 34766861Seric saveerrno = errno; 34866861Seric syserr("opendaemonsocket: can't create server SMTP socket"); 34966861Seric severe: 35066845Seric # ifdef LOG 35166861Seric if (LogLevel > 0) 35266861Seric syslog(LOG_ALERT, "problem creating SMTP socket"); 35366845Seric # endif /* LOG */ 35466861Seric DaemonSocket = -1; 35566861Seric continue; 35666861Seric } 35766845Seric 35866861Seric /* turn on network debugging? */ 35966861Seric if (tTd(15, 101)) 36066861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 36166861Seric SO_DEBUG, (char *)&on, 36266861Seric sizeof on); 36366845Seric 36466861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 36566861Seric SO_REUSEADDR, (char *)&on, sizeof on); 36666861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 36766861Seric SO_KEEPALIVE, (char *)&on, sizeof on); 36866845Seric 36966845Seric #ifdef SO_RCVBUF 37066861Seric if (TcpRcvBufferSize > 0) 37166861Seric { 37266861Seric if (setsockopt(DaemonSocket, SOL_SOCKET, 37366861Seric SO_RCVBUF, 37466861Seric (char *) &TcpRcvBufferSize, 37566861Seric sizeof(TcpRcvBufferSize)) < 0) 37666861Seric syserr("getrequests: setsockopt(SO_RCVBUF)"); 37766861Seric } 37866845Seric #endif 37966845Seric 38066861Seric switch (DaemonAddr.sa.sa_family) 38166861Seric { 38266845Seric # ifdef NETINET 38366861Seric case AF_INET: 38466861Seric socksize = sizeof DaemonAddr.sin; 38566861Seric break; 38666845Seric # endif 38766845Seric 38866845Seric # ifdef NETISO 38966861Seric case AF_ISO: 39066861Seric socksize = sizeof DaemonAddr.siso; 39166861Seric break; 39266845Seric # endif 39366845Seric 39466861Seric default: 39566861Seric socksize = sizeof DaemonAddr; 39666861Seric break; 39766861Seric } 39866861Seric 39966861Seric if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0) 40066861Seric { 40166861Seric saveerrno = errno; 40266861Seric syserr("getrequests: cannot bind"); 40366861Seric (void) close(DaemonSocket); 40466861Seric goto severe; 40566861Seric } 40666854Seric } 40766861Seric if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0) 40866854Seric { 40966861Seric saveerrno = errno; 41066861Seric syserr("getrequests: cannot listen"); 41166854Seric (void) close(DaemonSocket); 41266854Seric goto severe; 41366854Seric } 41466861Seric return socksize; 41566861Seric } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno)); 41668693Seric syserr("!opendaemonsocket: server SMTP socket wedged: exiting"); 41766861Seric finis(); 41866845Seric } 41966845Seric /* 42010206Seric ** CLRDAEMON -- reset the daemon connection 42110206Seric ** 42210206Seric ** Parameters: 42310206Seric ** none. 42410206Seric ** 42510206Seric ** Returns: 42610206Seric ** none. 42710206Seric ** 42810206Seric ** Side Effects: 42910206Seric ** releases any resources used by the passive daemon. 43010206Seric */ 43110206Seric 43268693Seric void 43310206Seric clrdaemon() 43410206Seric { 43510206Seric if (DaemonSocket >= 0) 43610206Seric (void) close(DaemonSocket); 43710206Seric DaemonSocket = -1; 43810206Seric } 43910206Seric /* 44058849Seric ** SETDAEMONOPTIONS -- set options for running the daemon 44158849Seric ** 44258849Seric ** Parameters: 44358849Seric ** p -- the options line. 44458849Seric ** 44558849Seric ** Returns: 44658849Seric ** none. 44758849Seric */ 44858849Seric 44968693Seric void 45058849Seric setdaemonoptions(p) 45158849Seric register char *p; 45258849Seric { 45358873Seric if (DaemonAddr.sa.sa_family == AF_UNSPEC) 45458873Seric DaemonAddr.sa.sa_family = AF_INET; 45558873Seric 45658849Seric while (p != NULL) 45758849Seric { 45858849Seric register char *f; 45958849Seric register char *v; 46058849Seric 46158849Seric while (isascii(*p) && isspace(*p)) 46258849Seric p++; 46358849Seric if (*p == '\0') 46458849Seric break; 46558849Seric f = p; 46658849Seric p = strchr(p, ','); 46758849Seric if (p != NULL) 46858849Seric *p++ = '\0'; 46958849Seric v = strchr(f, '='); 47058849Seric if (v == NULL) 47158849Seric continue; 47258849Seric while (isascii(*++v) && isspace(*v)) 47358849Seric continue; 47469397Seric if (isascii(*f) && isupper(*f)) 47569397Seric *f = tolower(*f); 47658849Seric 47758849Seric switch (*f) 47858849Seric { 47958873Seric case 'F': /* address family */ 48058849Seric if (isascii(*v) && isdigit(*v)) 48158873Seric DaemonAddr.sa.sa_family = atoi(v); 48258873Seric #ifdef NETINET 48358873Seric else if (strcasecmp(v, "inet") == 0) 48458873Seric DaemonAddr.sa.sa_family = AF_INET; 48558873Seric #endif 48658873Seric #ifdef NETISO 48758873Seric else if (strcasecmp(v, "iso") == 0) 48858873Seric DaemonAddr.sa.sa_family = AF_ISO; 48958873Seric #endif 49058873Seric #ifdef NETNS 49158873Seric else if (strcasecmp(v, "ns") == 0) 49258873Seric DaemonAddr.sa.sa_family = AF_NS; 49358873Seric #endif 49458873Seric #ifdef NETX25 49558873Seric else if (strcasecmp(v, "x.25") == 0) 49658873Seric DaemonAddr.sa.sa_family = AF_CCITT; 49758873Seric #endif 49858849Seric else 49958873Seric syserr("554 Unknown address family %s in Family=option", v); 50058873Seric break; 50158873Seric 50258873Seric case 'A': /* address */ 50358873Seric switch (DaemonAddr.sa.sa_family) 50458849Seric { 50558873Seric #ifdef NETINET 50658873Seric case AF_INET: 50758873Seric if (isascii(*v) && isdigit(*v)) 50868693Seric DaemonAddr.sin.sin_addr.s_addr = htonl(inet_network(v)); 50958873Seric else 51058873Seric { 51158873Seric register struct netent *np; 51258849Seric 51358873Seric np = getnetbyname(v); 51458873Seric if (np == NULL) 51558873Seric syserr("554 network \"%s\" unknown", v); 51658873Seric else 51758873Seric DaemonAddr.sin.sin_addr.s_addr = np->n_net; 51858873Seric } 51958873Seric break; 52058873Seric #endif 52158873Seric 52258873Seric default: 52358873Seric syserr("554 Address= option unsupported for family %d", 52458873Seric DaemonAddr.sa.sa_family); 52558873Seric break; 52658849Seric } 52758849Seric break; 52858849Seric 52958873Seric case 'P': /* port */ 53058873Seric switch (DaemonAddr.sa.sa_family) 53158849Seric { 53258873Seric short port; 53358849Seric 53458873Seric #ifdef NETINET 53558873Seric case AF_INET: 53658873Seric if (isascii(*v) && isdigit(*v)) 53764366Seric DaemonAddr.sin.sin_port = htons(atoi(v)); 53858849Seric else 53958873Seric { 54058873Seric register struct servent *sp; 54158873Seric 54258873Seric sp = getservbyname(v, "tcp"); 54358873Seric if (sp == NULL) 54458909Seric syserr("554 service \"%s\" unknown", v); 54558873Seric else 54658873Seric DaemonAddr.sin.sin_port = sp->s_port; 54758873Seric } 54858873Seric break; 54958873Seric #endif 55058873Seric 55158873Seric #ifdef NETISO 55258873Seric case AF_ISO: 55358873Seric /* assume two byte transport selector */ 55458873Seric if (isascii(*v) && isdigit(*v)) 55564366Seric port = htons(atoi(v)); 55658873Seric else 55758873Seric { 55858873Seric register struct servent *sp; 55958873Seric 56058873Seric sp = getservbyname(v, "tcp"); 56158873Seric if (sp == NULL) 56258909Seric syserr("554 service \"%s\" unknown", v); 56358873Seric else 56458873Seric port = sp->s_port; 56558873Seric } 56658873Seric bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 56758873Seric break; 56858873Seric #endif 56958873Seric 57058873Seric default: 57158873Seric syserr("554 Port= option unsupported for family %d", 57258873Seric DaemonAddr.sa.sa_family); 57358873Seric break; 57458849Seric } 57558849Seric break; 57659783Seric 57759783Seric case 'L': /* listen queue size */ 57859783Seric ListenQueueSize = atoi(v); 57959783Seric break; 58064381Seric 58164381Seric case 'S': /* send buffer size */ 58264381Seric TcpSndBufferSize = atoi(v); 58364381Seric break; 58464381Seric 58564381Seric case 'R': /* receive buffer size */ 58664381Seric TcpRcvBufferSize = atoi(v); 58764381Seric break; 58869397Seric 58969397Seric default: 59069397Seric syserr("554 DaemonPortOptions parameter \"%s\" unknown", f); 59158849Seric } 59258849Seric } 59358849Seric } 59458849Seric /* 5956039Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 5966039Seric ** 5976039Seric ** Parameters: 5986039Seric ** host -- the name of the host. 5996633Seric ** port -- the port number to connect to. 60053739Seric ** mci -- a pointer to the mail connection information 60153739Seric ** structure to be filled in. 60252106Seric ** usesecureport -- if set, use a low numbered (reserved) 60352106Seric ** port to provide some rudimentary authentication. 6046039Seric ** 6056039Seric ** Returns: 6066039Seric ** An exit code telling whether the connection could be 6076039Seric ** made and if not why not. 6086039Seric ** 6096039Seric ** Side Effects: 6106039Seric ** none. 6116039Seric */ 6125978Seric 61358755Seric SOCKADDR CurHostAddr; /* address of current host */ 61458305Seric 61554967Seric int 61653739Seric makeconnection(host, port, mci, usesecureport) 6176039Seric char *host; 6187286Seric u_short port; 61954967Seric register MCI *mci; 62052106Seric bool usesecureport; 6216039Seric { 62268693Seric register int i = 0; 62368693Seric register int s; 62429430Sbloom register struct hostent *hp = (struct hostent *)NULL; 62558755Seric SOCKADDR addr; 62652106Seric int sav_errno; 62758755Seric int addrlen; 62868693Seric bool firstconnect; 62966334Seric #if NAMED_BIND 63035651Seric extern int h_errno; 63135651Seric #endif 6326039Seric 6336039Seric /* 6346039Seric ** Set up the address for the mailer. 6359308Seric ** Accept "[a.b.c.d]" syntax for host name. 6366039Seric */ 6376039Seric 63866334Seric #if NAMED_BIND 63925475Smiriam h_errno = 0; 64035651Seric #endif 64125475Smiriam errno = 0; 64258864Seric bzero(&CurHostAddr, sizeof CurHostAddr); 64364334Seric SmtpPhase = mci->mci_phase = "initial connection"; 64458906Seric CurHostName = host; 64525475Smiriam 6469308Seric if (host[0] == '[') 6479308Seric { 64811147Seric long hid; 64956795Seric register char *p = strchr(host, ']'); 6509308Seric 65111147Seric if (p != NULL) 6529308Seric { 65311147Seric *p = '\0'; 65459884Seric #ifdef NETINET 65511147Seric hid = inet_addr(&host[1]); 65658360Seric if (hid == -1) 65759884Seric #endif 65858360Seric { 65958360Seric /* try it as a host name (avoid MX lookup) */ 66068693Seric hp = sm_gethostbyname(&host[1]); 66166349Seric if (hp == NULL && p[-1] == '.') 66266349Seric { 66368693Seric #if NAMED_BIND 66468693Seric int oldopts = _res.options; 66568693Seric 66668693Seric _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 66768693Seric #endif 66866349Seric p[-1] = '\0'; 66968693Seric hp = sm_gethostbyname(&host[1]); 67066349Seric p[-1] = '.'; 67168693Seric #if NAMED_BIND 67268693Seric _res.options = oldopts; 67368693Seric #endif 67466349Seric } 67558360Seric *p = ']'; 67658360Seric goto gothostent; 67758360Seric } 67811147Seric *p = ']'; 6799308Seric } 68058360Seric if (p == NULL) 6819308Seric { 68258151Seric usrerr("553 Invalid numeric domain spec \"%s\"", host); 68368857Seric mci->mci_status = "5.1.2"; 6849308Seric return (EX_NOHOST); 6859308Seric } 68659884Seric #ifdef NETINET 68759884Seric addr.sin.sin_family = AF_INET; /*XXX*/ 68858778Seric addr.sin.sin_addr.s_addr = hid; 68959884Seric #endif 6909308Seric } 6919610Seric else 6929610Seric { 69366349Seric register char *p = &host[strlen(host) - 1]; 69466349Seric 69568693Seric hp = sm_gethostbyname(host); 69666349Seric if (hp == NULL && *p == '.') 69766349Seric { 69868693Seric #if NAMED_BIND 69968693Seric int oldopts = _res.options; 70068693Seric 70168693Seric _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 70268693Seric #endif 70366349Seric *p = '\0'; 70468693Seric hp = sm_gethostbyname(host); 70566349Seric *p = '.'; 70668693Seric #if NAMED_BIND 70768693Seric _res.options = oldopts; 70868693Seric #endif 70966349Seric } 71058360Seric gothostent: 71125475Smiriam if (hp == NULL) 71224945Seric { 71366334Seric #if NAMED_BIND 71468693Seric /* check for name server timeouts */ 71568693Seric if (errno == ETIMEDOUT || h_errno == TRY_AGAIN || 71668693Seric (errno == ECONNREFUSED && UseNameServer)) 71768693Seric { 71868693Seric mci->mci_status = "4.4.3"; 71925475Smiriam return (EX_TEMPFAIL); 72068693Seric } 72135651Seric #endif 72225475Smiriam return (EX_NOHOST); 72324945Seric } 72458778Seric addr.sa.sa_family = hp->h_addrtype; 72558778Seric switch (hp->h_addrtype) 72658778Seric { 72758778Seric #ifdef NETINET 72858778Seric case AF_INET: 72958755Seric bcopy(hp->h_addr, 73058778Seric &addr.sin.sin_addr, 73168693Seric INADDRSZ); 73258778Seric break; 73358778Seric #endif 73458778Seric 73558778Seric default: 73658755Seric bcopy(hp->h_addr, 73758778Seric addr.sa.sa_data, 73858755Seric hp->h_length); 73958778Seric break; 74058778Seric } 74129430Sbloom i = 1; 7429610Seric } 7439610Seric 7449610Seric /* 7459610Seric ** Determine the port number. 7469610Seric */ 7479610Seric 74810011Seric if (port != 0) 74958755Seric port = htons(port); 75010011Seric else 7519610Seric { 7529610Seric register struct servent *sp = getservbyname("smtp", "tcp"); 7539610Seric 7549610Seric if (sp == NULL) 7559610Seric { 75668745Seric #ifdef LOG 75768745Seric if (LogLevel > 2) 75868745Seric syslog(LOG_ERR, "makeconnection: service \"smtp\" unknown"); 75968745Seric #endif 76065169Seric port = htons(25); 7619610Seric } 76265169Seric else 76365169Seric port = sp->s_port; 7649610Seric } 7656039Seric 76658778Seric switch (addr.sa.sa_family) 76758755Seric { 76859884Seric #ifdef NETINET 76958755Seric case AF_INET: 77058778Seric addr.sin.sin_port = port; 77158755Seric addrlen = sizeof (struct sockaddr_in); 77258755Seric break; 77359884Seric #endif 77458755Seric 77558755Seric #ifdef NETISO 77658755Seric case AF_ISO: 77758755Seric /* assume two byte transport selector */ 77858755Seric bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 77958755Seric addrlen = sizeof (struct sockaddr_iso); 78058755Seric break; 78158755Seric #endif 78258755Seric 78358755Seric default: 78458778Seric syserr("Can't connect to address family %d", addr.sa.sa_family); 78558755Seric return (EX_NOHOST); 78658755Seric } 78758755Seric 7886039Seric /* 7896039Seric ** Try to actually open the connection. 7906039Seric */ 7916039Seric 79259156Seric #ifdef XLA 79359156Seric /* if too many connections, don't bother trying */ 79459156Seric if (!xla_noqueue_ok(host)) 79559156Seric return EX_TEMPFAIL; 79659156Seric #endif 79759156Seric 79868693Seric firstconnect = TRUE; 79957736Seric for (;;) 80052106Seric { 80157736Seric if (tTd(16, 1)) 80258755Seric printf("makeconnection (%s [%s])\n", 80358755Seric host, anynet_ntoa(&addr)); 80452106Seric 80558588Seric /* save for logging */ 80658588Seric CurHostAddr = addr; 80758588Seric 80857736Seric if (usesecureport) 80957736Seric { 81057736Seric int rport = IPPORT_RESERVED - 1; 8116039Seric 81257736Seric s = rresvport(&rport); 81357736Seric } 81457736Seric else 81557736Seric { 81657736Seric s = socket(AF_INET, SOCK_STREAM, 0); 81757736Seric } 81857736Seric if (s < 0) 81957736Seric { 82057736Seric sav_errno = errno; 82157736Seric syserr("makeconnection: no socket"); 82257736Seric goto failure; 82357736Seric } 82410347Seric 82564381Seric #ifdef SO_SNDBUF 82664381Seric if (TcpSndBufferSize > 0) 82764381Seric { 82864381Seric if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 82964561Seric (char *) &TcpSndBufferSize, 83064381Seric sizeof(TcpSndBufferSize)) < 0) 83164381Seric syserr("makeconnection: setsockopt(SO_SNDBUF)"); 83264381Seric } 83364381Seric #endif 83464381Seric 83557736Seric if (tTd(16, 1)) 83657736Seric printf("makeconnection: fd=%d\n", s); 83757736Seric 83857736Seric /* turn on network debugging? */ 83957736Seric if (tTd(16, 101)) 84057736Seric { 84157736Seric int on = 1; 84266861Seric (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 84357736Seric (char *)&on, sizeof on); 84457736Seric } 84557736Seric if (CurEnv->e_xfp != NULL) 84657736Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 84757736Seric errno = 0; /* for debugging */ 84858755Seric if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 84957736Seric break; 85057736Seric 85168693Seric /* if running demand-dialed connection, try again */ 85268693Seric if (DialDelay > 0 && firstconnect) 85368693Seric { 85468693Seric if (tTd(16, 1)) 85568693Seric printf("Connect failed (%s); trying again...\n", 85668693Seric errstring(sav_errno)); 85768693Seric firstconnect = FALSE; 85868693Seric sleep(DialDelay); 85968693Seric continue; 86068693Seric } 86168693Seric 86257736Seric /* couldn't connect.... figure out why */ 86327744Sbloom sav_errno = errno; 86427744Sbloom (void) close(s); 86568693Seric if (hp != NULL && hp->h_addr_list[i]) 86629430Sbloom { 86757736Seric if (tTd(16, 1)) 86858755Seric printf("Connect failed (%s); trying new address....\n", 86958755Seric errstring(sav_errno)); 87058778Seric switch (addr.sa.sa_family) 87158778Seric { 87258778Seric #ifdef NETINET 87358778Seric case AF_INET: 87458755Seric bcopy(hp->h_addr_list[i++], 87558778Seric &addr.sin.sin_addr, 87668693Seric INADDRSZ); 87758778Seric break; 87858778Seric #endif 87958778Seric 88058778Seric default: 88158755Seric bcopy(hp->h_addr_list[i++], 88258778Seric addr.sa.sa_data, 88352106Seric hp->h_length); 88458778Seric break; 88558778Seric } 88657736Seric continue; 88729430Sbloom } 88829430Sbloom 8896039Seric /* failure, decide if temporary or not */ 8906039Seric failure: 89159254Seric #ifdef XLA 89259254Seric xla_host_end(host); 89359254Seric #endif 89458542Seric if (transienterror(sav_errno)) 89558542Seric return EX_TEMPFAIL; 89658542Seric else 89758542Seric { 89858542Seric message("%s", errstring(sav_errno)); 89958542Seric return (EX_UNAVAILABLE); 9006039Seric } 9016039Seric } 9026039Seric 9036039Seric /* connection ok, put it into canonical form */ 90464724Seric if ((mci->mci_out = fdopen(s, "w")) == NULL || 90564724Seric (s = dup(s)) < 0 || 90664725Seric (mci->mci_in = fdopen(s, "r")) == NULL) 90764724Seric { 90864724Seric syserr("cannot open SMTP client channel, fd=%d", s); 90964724Seric return EX_TEMPFAIL; 91064724Seric } 9116039Seric 91210098Seric return (EX_OK); 9136039Seric } 91410758Seric /* 91510758Seric ** MYHOSTNAME -- return the name of this host. 91610758Seric ** 91710758Seric ** Parameters: 91810758Seric ** hostbuf -- a place to return the name of this host. 91912313Seric ** size -- the size of hostbuf. 92010758Seric ** 92110758Seric ** Returns: 92210758Seric ** A list of aliases for this host. 92310758Seric ** 92410758Seric ** Side Effects: 92564338Seric ** Adds numeric codes to $=w. 92610758Seric */ 9276039Seric 92868693Seric struct hostent * 92912313Seric myhostname(hostbuf, size) 93010758Seric char hostbuf[]; 93112313Seric int size; 93210758Seric { 93358110Seric register struct hostent *hp; 93468693Seric extern bool getcanonname(); 93568693Seric extern int h_errno; 93610758Seric 93723120Seric if (gethostname(hostbuf, size) < 0) 93823120Seric { 93923120Seric (void) strcpy(hostbuf, "localhost"); 94023120Seric } 94168693Seric hp = sm_gethostbyname(hostbuf); 94266853Seric if (hp == NULL) 94368693Seric return NULL; 94468693Seric if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 94567448Seric { 94668693Seric (void) strncpy(hostbuf, hp->h_name, size - 1); 94768693Seric hostbuf[size - 1] = '\0'; 94867448Seric } 94966853Seric 95066853Seric #if NAMED_BIND 95168693Seric /* 95268693Seric ** If still no dot, try DNS directly (i.e., avoid NIS problems). 95368693Seric ** This ought to be driven from the configuration file, but 95468693Seric ** we are called before the configuration is read. We could 95568693Seric ** check for an /etc/resolv.conf file, but that isn't required. 95668693Seric ** All in all, a bit of a mess. 95768693Seric */ 95868693Seric 95968693Seric if (strchr(hostbuf, '.') == NULL && 96068693Seric !getcanonname(hostbuf, size, TRUE) && 96168693Seric h_errno == TRY_AGAIN) 96268612Seric { 96366853Seric /* try twice in case name server not yet started up */ 96468693Seric message("My unqualifed host name (%s) unknown to DNS; sleeping for retry", 96568693Seric hostbuf); 96668693Seric sleep(60); 96768693Seric if (!getcanonname(hostbuf, size, TRUE)) 96866853Seric errno = h_errno + E_DNSBASE; 96966853Seric } 97066777Seric #endif 97168693Seric return (hp); 97210758Seric } 97351315Seric /* 97458951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 97558308Seric ** 97658951Seric ** Uses RFC1413 protocol to try to get info from the other end. 97758951Seric ** 97858308Seric ** Parameters: 97958308Seric ** fd -- the descriptor 98058308Seric ** 98158308Seric ** Returns: 98258951Seric ** The user@host information associated with this descriptor. 98358308Seric */ 98458308Seric 98558951Seric static jmp_buf CtxAuthTimeout; 98658951Seric 98768693Seric static void 98858951Seric authtimeout() 98958951Seric { 99058951Seric longjmp(CtxAuthTimeout, 1); 99158951Seric } 99258951Seric 99358308Seric char * 99458951Seric getauthinfo(fd) 99558308Seric int fd; 99658308Seric { 99758951Seric int falen; 99859104Seric register char *p; 99958951Seric SOCKADDR la; 100058951Seric int lalen; 100158951Seric register struct servent *sp; 100258951Seric int s; 100358951Seric int i; 100458951Seric EVENT *ev; 100568444Seric int nleft; 100668462Seric char ibuf[MAXNAME + 1]; 100758951Seric static char hbuf[MAXNAME * 2 + 2]; 100858951Seric extern char *hostnamebyanyaddr(); 100958951Seric extern char RealUserName[]; /* main.c */ 101058308Seric 101166761Seric falen = sizeof RealHostAddr; 101268693Seric if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 || 101368693Seric falen <= 0 || RealHostAddr.sa.sa_family == 0) 101458951Seric { 101558951Seric (void) sprintf(hbuf, "%s@localhost", RealUserName); 101658957Seric if (tTd(9, 1)) 101758951Seric printf("getauthinfo: %s\n", hbuf); 101858951Seric return hbuf; 101958951Seric } 102058951Seric 102166761Seric if (RealHostName == NULL) 102266761Seric { 102366761Seric /* translate that to a host name */ 102466761Seric RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 102566761Seric } 102666761Seric 102765831Seric if (TimeOuts.to_ident == 0) 102865831Seric goto noident; 102965831Seric 103058951Seric lalen = sizeof la; 103166761Seric if (RealHostAddr.sa.sa_family != AF_INET || 103258951Seric getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 103358951Seric la.sa.sa_family != AF_INET) 103458951Seric { 103558951Seric /* no ident info */ 103658951Seric goto noident; 103758951Seric } 103858951Seric 103958951Seric /* create ident query */ 104068457Seric (void) sprintf(ibuf, "%d,%d\r\n", 104166761Seric ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port)); 104258951Seric 104358951Seric /* create local address */ 104464747Seric la.sin.sin_port = 0; 104558951Seric 104658951Seric /* create foreign address */ 104758951Seric sp = getservbyname("auth", "tcp"); 104858951Seric if (sp != NULL) 104966761Seric RealHostAddr.sin.sin_port = sp->s_port; 105058308Seric else 105166761Seric RealHostAddr.sin.sin_port = htons(113); 105258951Seric 105358951Seric s = -1; 105458951Seric if (setjmp(CtxAuthTimeout) != 0) 105558951Seric { 105658951Seric if (s >= 0) 105758951Seric (void) close(s); 105858951Seric goto noident; 105958951Seric } 106058951Seric 106158951Seric /* put a timeout around the whole thing */ 106264255Seric ev = setevent(TimeOuts.to_ident, authtimeout, 0); 106358951Seric 106464747Seric /* connect to foreign IDENT server using same address as SMTP socket */ 106558951Seric s = socket(AF_INET, SOCK_STREAM, 0); 106658951Seric if (s < 0) 106758951Seric { 106858951Seric clrevent(ev); 106958951Seric goto noident; 107058951Seric } 107164747Seric if (bind(s, &la.sa, sizeof la.sin) < 0 || 107266761Seric connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0) 107358951Seric { 107466011Seric goto closeident; 107558951Seric } 107658951Seric 107758957Seric if (tTd(9, 10)) 107868457Seric printf("getauthinfo: sent %s", ibuf); 107958951Seric 108058951Seric /* send query */ 108168457Seric if (write(s, ibuf, strlen(ibuf)) < 0) 108258951Seric goto closeident; 108358951Seric 108458951Seric /* get result */ 108568457Seric p = &ibuf[0]; 108668525Seric nleft = sizeof ibuf - 1; 108768444Seric while ((i = read(s, p, nleft)) > 0) 108868444Seric { 108968444Seric p += i; 109068444Seric nleft -= i; 109168444Seric } 109258951Seric (void) close(s); 109358951Seric clrevent(ev); 109468457Seric if (i < 0 || p == &ibuf[0]) 109558951Seric goto noident; 109658951Seric 109768444Seric if (*--p == '\n' && *--p == '\r') 109868444Seric p--; 109968444Seric *++p = '\0'; 110068444Seric 110158957Seric if (tTd(9, 3)) 110268457Seric printf("getauthinfo: got %s\n", ibuf); 110358951Seric 110458951Seric /* parse result */ 110568457Seric p = strchr(ibuf, ':'); 110658951Seric if (p == NULL) 110758951Seric { 110858951Seric /* malformed response */ 110958951Seric goto noident; 111058951Seric } 111158951Seric while (isascii(*++p) && isspace(*p)) 111258951Seric continue; 111358951Seric if (strncasecmp(p, "userid", 6) != 0) 111458951Seric { 111558951Seric /* presumably an error string */ 111658951Seric goto noident; 111758951Seric } 111858951Seric p += 6; 111958951Seric while (isascii(*p) && isspace(*p)) 112058951Seric p++; 112158951Seric if (*p++ != ':') 112258951Seric { 112358951Seric /* either useridxx or malformed response */ 112458951Seric goto noident; 112558951Seric } 112658951Seric 112758951Seric /* p now points to the OSTYPE field */ 112868693Seric while (isascii(*p) && isspace(*p)) 112968693Seric p++; 113068693Seric if (strncasecmp(p, "other", 5) == 0 && 113168693Seric (p[5] == ':' || p[5] == ' ' || p[5] == ',' || p[5] == '\0')) 113268693Seric { 113368693Seric /* not useful information */ 113468693Seric goto noident; 113568693Seric } 113658951Seric p = strchr(p, ':'); 113758951Seric if (p == NULL) 113858951Seric { 113958951Seric /* malformed response */ 114058951Seric goto noident; 114158951Seric } 114258951Seric 114358957Seric /* 1413 says don't do this -- but it's broken otherwise */ 114458957Seric while (isascii(*++p) && isspace(*p)) 114558957Seric continue; 114658957Seric 114767935Seric /* p now points to the authenticated name -- copy carefully */ 114868457Seric cleanstrcpy(hbuf, p, MAXNAME); 114968875Seric i = strlen(hbuf); 115067935Seric hbuf[i++] = '@'; 115167935Seric strcpy(&hbuf[i], RealHostName == NULL ? "localhost" : RealHostName); 115258957Seric goto finish; 115358957Seric 115466011Seric closeident: 115566011Seric (void) close(s); 115666011Seric clrevent(ev); 115766011Seric 115858957Seric noident: 115966003Seric if (RealHostName == NULL) 116066003Seric { 116166003Seric if (tTd(9, 1)) 116266003Seric printf("getauthinfo: NULL\n"); 116366003Seric return NULL; 116466003Seric } 116558957Seric (void) strcpy(hbuf, RealHostName); 116658957Seric 116758957Seric finish: 116866003Seric if (RealHostName != NULL && RealHostName[0] != '[') 116958951Seric { 117058951Seric p = &hbuf[strlen(hbuf)]; 117158951Seric (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 117258951Seric } 117358957Seric if (tTd(9, 1)) 117458951Seric printf("getauthinfo: %s\n", hbuf); 117558308Seric return hbuf; 117658308Seric } 117758308Seric /* 117860089Seric ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 117953751Seric ** 118053751Seric ** Parameters: 118156823Seric ** map -- a pointer to this map (unused). 118260089Seric ** name -- the (presumably unqualified) hostname. 118360257Seric ** av -- unused -- for compatibility with other mapping 118455019Seric ** functions. 118559084Seric ** statp -- an exit status (out parameter) -- set to 118659084Seric ** EX_TEMPFAIL if the name server is unavailable. 118753751Seric ** 118853751Seric ** Returns: 118953751Seric ** The mapping, if found. 119053751Seric ** NULL if no mapping found. 119153751Seric ** 119253751Seric ** Side Effects: 119353751Seric ** Looks up the host specified in hbuf. If it is not 119453751Seric ** the canonical name for that host, return the canonical 119553751Seric ** name. 119653751Seric */ 119751315Seric 119853751Seric char * 119960257Seric host_map_lookup(map, name, av, statp) 120056823Seric MAP *map; 120160089Seric char *name; 120260257Seric char **av; 120359084Seric int *statp; 120416911Seric { 120516911Seric register struct hostent *hp; 120668693Seric struct in_addr in_addr; 120756823Seric char *cp; 120859671Seric register STAB *s; 120968693Seric char hbuf[MAXNAME + 1]; 121066334Seric #if NAMED_BIND 121159671Seric extern int h_errno; 121266029Seric #endif 121316911Seric 121425574Smiriam /* 121559671Seric ** See if we have already looked up this name. If so, just 121659671Seric ** return it. 121759671Seric */ 121853751Seric 121960089Seric s = stab(name, ST_NAMECANON, ST_ENTER); 122059671Seric if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 122159671Seric { 122259986Seric if (tTd(9, 1)) 122360089Seric printf("host_map_lookup(%s) => CACHE %s\n", 1224*69511Seric name, 1225*69511Seric s->s_namecanon.nc_cname == NULL 1226*69511Seric ? "NULL" 1227*69511Seric : s->s_namecanon.nc_name); 122859671Seric errno = s->s_namecanon.nc_errno; 122966334Seric #if NAMED_BIND 123059671Seric h_errno = s->s_namecanon.nc_herrno; 123166029Seric #endif 123259671Seric *statp = s->s_namecanon.nc_stat; 123368817Seric if (*statp == EX_TEMPFAIL) 123465199Seric { 123568857Seric CurEnv->e_status = "4.4.3"; 123668817Seric usrerr("451 %s: Name server timeout", 123765199Seric shortenstring(name, 33)); 123865199Seric } 123959671Seric return s->s_namecanon.nc_cname; 124059671Seric } 124159671Seric 124259671Seric /* 124359671Seric ** If first character is a bracket, then it is an address 124459671Seric ** lookup. Address is copied into a temporary buffer to 124560089Seric ** strip the brackets and to preserve name if address is 124659671Seric ** unknown. 124759671Seric */ 124859671Seric 124960089Seric if (*name != '[') 125053751Seric { 125155019Seric extern bool getcanonname(); 125255019Seric 125358798Seric if (tTd(9, 1)) 125460089Seric printf("host_map_lookup(%s) => ", name); 125559671Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 125668693Seric if (strlen(name) < sizeof hbuf) 125768693Seric (void) strcpy(hbuf, name); 125868693Seric else 125968693Seric { 126068693Seric bcopy(name, hbuf, sizeof hbuf - 1); 126168693Seric hbuf[sizeof hbuf - 1] = '\0'; 126268693Seric } 126368759Seric if (getcanonname(hbuf, sizeof hbuf - 1, !NoMXforCanon)) 126458796Seric { 126558796Seric if (tTd(9, 1)) 126658796Seric printf("%s\n", hbuf); 126760257Seric cp = map_rewrite(map, hbuf, strlen(hbuf), av); 126860257Seric s->s_namecanon.nc_cname = newstr(cp); 126960257Seric return cp; 127058796Seric } 127153751Seric else 127258796Seric { 127359084Seric register struct hostent *hp; 127459084Seric 127566029Seric s->s_namecanon.nc_errno = errno; 127666334Seric #if NAMED_BIND 127766029Seric s->s_namecanon.nc_herrno = h_errno; 127858796Seric if (tTd(9, 1)) 127959084Seric printf("FAIL (%d)\n", h_errno); 128059084Seric switch (h_errno) 128159084Seric { 128259084Seric case TRY_AGAIN: 128359596Seric if (UseNameServer) 128459734Seric { 128568857Seric CurEnv->e_status = "4.4.3"; 128668817Seric usrerr("451 %s: Name server timeout", 128765199Seric shortenstring(name, 33)); 128859734Seric } 128959084Seric *statp = EX_TEMPFAIL; 129059084Seric break; 129159084Seric 129259084Seric case HOST_NOT_FOUND: 129368881Seric case NO_DATA: 129459084Seric *statp = EX_NOHOST; 129559084Seric break; 129659084Seric 129759084Seric case NO_RECOVERY: 129859084Seric *statp = EX_SOFTWARE; 129959084Seric break; 130059084Seric 130159084Seric default: 130259084Seric *statp = EX_UNAVAILABLE; 130359084Seric break; 130459084Seric } 130566029Seric #else 130666029Seric if (tTd(9, 1)) 130766029Seric printf("FAIL\n"); 130866029Seric *statp = EX_NOHOST; 130966029Seric #endif 131059671Seric s->s_namecanon.nc_stat = *statp; 131168693Seric if ((*statp != EX_TEMPFAIL && *statp != EX_NOHOST) || 131268693Seric UseNameServer) 131359084Seric return NULL; 131459084Seric 131559084Seric /* 131659084Seric ** Try to look it up in /etc/hosts 131759084Seric */ 131859084Seric 131968693Seric hp = sm_gethostbyname(name); 132059084Seric if (hp == NULL) 132159084Seric { 132259084Seric /* no dice there either */ 132359671Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 132459084Seric return NULL; 132559084Seric } 132659084Seric 132759671Seric s->s_namecanon.nc_stat = *statp = EX_OK; 132860257Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 132960257Seric s->s_namecanon.nc_cname = newstr(cp); 133060257Seric return cp; 133158796Seric } 133253751Seric } 133360089Seric if ((cp = strchr(name, ']')) == NULL) 133453751Seric return (NULL); 133540994Sbostic *cp = '\0'; 133668693Seric in_addr.s_addr = inet_addr(&name[1]); 133758110Seric 133858110Seric /* nope -- ask the name server */ 133968693Seric hp = sm_gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET); 134059671Seric s->s_namecanon.nc_errno = errno; 134166334Seric #if NAMED_BIND 134259671Seric s->s_namecanon.nc_herrno = h_errno; 134366029Seric #endif 134459671Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 134533932Sbostic if (hp == NULL) 134659671Seric { 134759671Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 134853751Seric return (NULL); 134959671Seric } 135053751Seric 135158110Seric /* found a match -- copy out */ 135260257Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 135359671Seric s->s_namecanon.nc_stat = *statp = EX_OK; 135460257Seric s->s_namecanon.nc_cname = newstr(cp); 135560257Seric return cp; 135633932Sbostic } 135758755Seric /* 135858755Seric ** ANYNET_NTOA -- convert a network address to printable form. 135958755Seric ** 136058755Seric ** Parameters: 136158755Seric ** sap -- a pointer to a sockaddr structure. 136258755Seric ** 136358755Seric ** Returns: 136458755Seric ** A printable version of that sockaddr. 136558755Seric */ 136616911Seric 136758755Seric char * 136858755Seric anynet_ntoa(sap) 136958755Seric register SOCKADDR *sap; 137058755Seric { 137158755Seric register char *bp; 137258755Seric register char *ap; 137358755Seric int l; 137464734Seric static char buf[100]; 137558755Seric 137658798Seric /* check for null/zero family */ 137758798Seric if (sap == NULL) 137858798Seric return "NULLADDR"; 137958798Seric if (sap->sa.sa_family == 0) 138058798Seric return "0"; 138158798Seric 138264734Seric switch (sap->sa.sa_family) 138364734Seric { 138464821Seric #ifdef NETUNIX 138564734Seric case AF_UNIX: 138664758Seric if (sap->sunix.sun_path[0] != '\0') 138764758Seric sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 138864734Seric else 138964734Seric sprintf(buf, "[UNIX: localhost]"); 139064734Seric return buf; 139164734Seric #endif 139264734Seric 139358778Seric #ifdef NETINET 139464734Seric case AF_INET: 139568776Seric return inet_ntoa(sap->sin.sin_addr); 139658778Seric #endif 139758755Seric 139864734Seric default: 139964734Seric /* this case is only to ensure syntactic correctness */ 140064734Seric break; 140164734Seric } 140264734Seric 140358755Seric /* unknown family -- just dump bytes */ 140458778Seric (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 140558755Seric bp = &buf[strlen(buf)]; 140658778Seric ap = sap->sa.sa_data; 140758778Seric for (l = sizeof sap->sa.sa_data; --l >= 0; ) 140858755Seric { 140958755Seric (void) sprintf(bp, "%02x:", *ap++ & 0377); 141058755Seric bp += 3; 141158755Seric } 141258755Seric *--bp = '\0'; 141358755Seric return buf; 141458755Seric } 141558951Seric /* 141658951Seric ** HOSTNAMEBYANYADDR -- return name of host based on address 141758951Seric ** 141858951Seric ** Parameters: 141958951Seric ** sap -- SOCKADDR pointer 142058951Seric ** 142158951Seric ** Returns: 142258951Seric ** text representation of host name. 142358951Seric ** 142458951Seric ** Side Effects: 142558951Seric ** none. 142658951Seric */ 142758755Seric 142858951Seric char * 142958951Seric hostnamebyanyaddr(sap) 143058951Seric register SOCKADDR *sap; 143158951Seric { 143258951Seric register struct hostent *hp; 143364734Seric int saveretry; 143458951Seric 143566334Seric #if NAMED_BIND 143659042Seric /* shorten name server timeout to avoid higher level timeouts */ 143759042Seric saveretry = _res.retry; 143859042Seric _res.retry = 3; 143959042Seric #endif /* NAMED_BIND */ 144059042Seric 144158951Seric switch (sap->sa.sa_family) 144258951Seric { 144358951Seric #ifdef NETINET 144458951Seric case AF_INET: 144568693Seric hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr, 144668693Seric INADDRSZ, 144758951Seric AF_INET); 144858951Seric break; 144958951Seric #endif 145058951Seric 145158951Seric #ifdef NETISO 145258951Seric case AF_ISO: 145368693Seric hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr, 145458951Seric sizeof sap->siso.siso_addr, 145558951Seric AF_ISO); 145658951Seric break; 145758951Seric #endif 145858951Seric 145964734Seric case AF_UNIX: 146064734Seric hp = NULL; 146164734Seric break; 146264734Seric 146358951Seric default: 146468693Seric hp = sm_gethostbyaddr(sap->sa.sa_data, 146558951Seric sizeof sap->sa.sa_data, 146658951Seric sap->sa.sa_family); 146758951Seric break; 146858951Seric } 146958951Seric 147066334Seric #if NAMED_BIND 147159042Seric _res.retry = saveretry; 147259042Seric #endif /* NAMED_BIND */ 147359042Seric 147458951Seric if (hp != NULL) 147558951Seric return hp->h_name; 147658951Seric else 147758951Seric { 147858951Seric /* produce a dotted quad */ 147958951Seric static char buf[512]; 148058951Seric 148158951Seric (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 148258951Seric return buf; 148358951Seric } 148458951Seric } 148558951Seric 148656795Seric # else /* DAEMON */ 148716911Seric /* code for systems without sophisticated networking */ 148810758Seric 148910758Seric /* 149010758Seric ** MYHOSTNAME -- stub version for case of no daemon code. 149111297Seric ** 149211297Seric ** Can't convert to upper case here because might be a UUCP name. 149312313Seric ** 149412313Seric ** Mark, you can change this to be anything you want...... 149510758Seric */ 149610758Seric 149710758Seric char ** 149812313Seric myhostname(hostbuf, size) 149910758Seric char hostbuf[]; 150012313Seric int size; 150110758Seric { 150210758Seric register FILE *f; 150310758Seric 150410758Seric hostbuf[0] = '\0'; 150510758Seric f = fopen("/usr/include/whoami", "r"); 150610758Seric if (f != NULL) 150710758Seric { 150812313Seric (void) fgets(hostbuf, size, f); 150910758Seric fixcrlf(hostbuf, TRUE); 151010758Seric (void) fclose(f); 151110758Seric } 151210758Seric return (NULL); 151310758Seric } 151416911Seric /* 151558951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 151658308Seric ** 151758308Seric ** Parameters: 151858308Seric ** fd -- the descriptor 151958308Seric ** 152058308Seric ** Returns: 152158308Seric ** The host name associated with this descriptor, if it can 152258308Seric ** be determined. 152358308Seric ** NULL otherwise. 152458308Seric ** 152558308Seric ** Side Effects: 152658308Seric ** none 152758308Seric */ 152858308Seric 152958308Seric char * 153058951Seric getauthinfo(fd) 153158308Seric int fd; 153258308Seric { 153358308Seric return NULL; 153458308Seric } 153558308Seric /* 153616911Seric ** MAPHOSTNAME -- turn a hostname into canonical form 153716911Seric ** 153816911Seric ** Parameters: 153956823Seric ** map -- a pointer to the database map. 154060089Seric ** name -- a buffer containing a hostname. 154153751Seric ** avp -- a pointer to a (cf file defined) argument vector. 154259084Seric ** statp -- an exit status (out parameter). 154316911Seric ** 154416911Seric ** Returns: 154553751Seric ** mapped host name 154651315Seric ** FALSE otherwise. 154716911Seric ** 154816911Seric ** Side Effects: 154960089Seric ** Looks up the host specified in name. If it is not 155016911Seric ** the canonical name for that host, replace it with 155116911Seric ** the canonical name. If the name is unknown, or it 155216911Seric ** is already the canonical name, leave it unchanged. 155316911Seric */ 155410758Seric 155516911Seric /*ARGSUSED*/ 155653751Seric char * 155760089Seric host_map_lookup(map, name, avp, statp) 155856823Seric MAP *map; 155960089Seric char *name; 156053751Seric char **avp; 156159084Seric char *statp; 156216911Seric { 156359084Seric register struct hostent *hp; 156459084Seric 156568693Seric hp = sm_gethostbyname(name); 156659084Seric if (hp != NULL) 156759084Seric return hp->h_name; 156859084Seric *statp = EX_NOHOST; 156953751Seric return NULL; 157016911Seric } 157116911Seric 157256795Seric #endif /* DAEMON */ 1573