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*69637Seric static char sccsid[] = "@(#)daemon.c 8.92 (Berkeley) 05/23/95 (with daemon mode)"; 1533780Sbostic #else 16*69637Seric static char sccsid[] = "@(#)daemon.c 8.92 (Berkeley) 05/23/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 2869601Seric #if IP_SRCROUTE 2969601Seric # include <netinet/in_systm.h> 3069601Seric # include <netinet/ip.h> 3169601Seric # include <netinet/ip_var.h> 3269601Seric #endif 3369601Seric 344535Seric /* 354535Seric ** DAEMON.C -- routines to use when running as a daemon. 367556Seric ** 377556Seric ** This entire file is highly dependent on the 4.2 BSD 387556Seric ** interprocess communication primitives. No attempt has 397556Seric ** been made to make this file portable to Version 7, 407556Seric ** Version 6, MPX files, etc. If you should try such a 417556Seric ** thing yourself, I recommend chucking the entire file 427556Seric ** and starting from scratch. Basic semantics are: 437556Seric ** 447556Seric ** getrequests() 457556Seric ** Opens a port and initiates a connection. 467556Seric ** Returns in a child. Must set InChannel and 477556Seric ** OutChannel appropriately. 4810206Seric ** clrdaemon() 4910206Seric ** Close any open files associated with getting 5010206Seric ** the connection; this is used when running the queue, 5110206Seric ** etc., to avoid having extra file descriptors during 5210206Seric ** the queue run and to avoid confusing the network 5310206Seric ** code (if it cares). 5452106Seric ** makeconnection(host, port, outfile, infile, usesecureport) 557556Seric ** Make a connection to the named host on the given 567556Seric ** port. Set *outfile and *infile to the files 577556Seric ** appropriate for communication. Returns zero on 587556Seric ** success, else an exit status describing the 597556Seric ** error. 6060089Seric ** host_map_lookup(map, hbuf, avp, pstat) 6156823Seric ** Convert the entry in hbuf into a canonical form. 624535Seric */ 634535Seric /* 644535Seric ** GETREQUESTS -- open mail IPC port and get requests. 654535Seric ** 664535Seric ** Parameters: 674535Seric ** none. 684535Seric ** 694535Seric ** Returns: 704535Seric ** none. 714535Seric ** 724535Seric ** Side Effects: 734535Seric ** Waits until some interesting activity occurs. When 744535Seric ** it does, a child is created to process it, and the 754535Seric ** parent waits for completion. Return from this 769886Seric ** routine is always in the child. The file pointers 779886Seric ** "InChannel" and "OutChannel" should be set to point 789886Seric ** to the communication channel. 794535Seric */ 804535Seric 8158849Seric int DaemonSocket = -1; /* fd describing socket */ 8258849Seric SOCKADDR DaemonAddr; /* socket for incoming */ 8359783Seric int ListenQueueSize = 10; /* size of listen queue */ 8464381Seric int TcpRcvBufferSize = 0; /* size of TCP receive buffer */ 8564381Seric int TcpSndBufferSize = 0; /* size of TCP send buffer */ 8616144Seric 8768693Seric void 884535Seric getrequests() 894535Seric { 909610Seric int t; 9153751Seric bool refusingconnections = TRUE; 9258419Seric FILE *pidf; 9364828Seric int socksize; 9466793Seric #ifdef XDEBUG 9566793Seric bool j_has_dot; 9666793Seric #endif 9746928Sbostic extern void reapchild(); 987117Seric 999610Seric /* 1009610Seric ** Set up the address for the mailer. 1019610Seric */ 1029610Seric 10358849Seric if (DaemonAddr.sin.sin_family == 0) 10458849Seric DaemonAddr.sin.sin_family = AF_INET; 10558849Seric if (DaemonAddr.sin.sin_addr.s_addr == 0) 10658849Seric DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY; 10758849Seric if (DaemonAddr.sin.sin_port == 0) 1089610Seric { 10965169Seric register struct servent *sp; 11065169Seric 11158849Seric sp = getservbyname("smtp", "tcp"); 11258849Seric if (sp == NULL) 11358849Seric { 11458909Seric syserr("554 service \"smtp\" unknown"); 11565169Seric DaemonAddr.sin.sin_port = htons(25); 11658849Seric } 11765169Seric else 11865169Seric DaemonAddr.sin.sin_port = sp->s_port; 1199610Seric } 1209610Seric 1219610Seric /* 1229610Seric ** Try to actually open the connection. 1239610Seric */ 1249610Seric 1259610Seric if (tTd(15, 1)) 12658849Seric printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port); 1279610Seric 1289610Seric /* get a socket for the SMTP connection */ 12966854Seric socksize = opendaemonsocket(TRUE); 13010347Seric 13164035Seric (void) setsignal(SIGCHLD, reapchild); 13224945Seric 13358419Seric /* write the pid to the log file for posterity */ 13458419Seric pidf = fopen(PidFile, "w"); 13558419Seric if (pidf != NULL) 13658419Seric { 13763863Seric extern char *CommandLineArgs; 13863863Seric 13963863Seric /* write the process id on line 1 */ 14058419Seric fprintf(pidf, "%d\n", getpid()); 14163863Seric 14263863Seric /* line 2 contains all command line flags */ 14363863Seric fprintf(pidf, "%s\n", CommandLineArgs); 14463863Seric 14563863Seric /* flush and close */ 14658419Seric fclose(pidf); 14758419Seric } 14858419Seric 14966793Seric #ifdef XDEBUG 15066793Seric { 15166812Seric char jbuf[MAXHOSTNAMELEN]; 15258419Seric 15368693Seric expand("\201j", jbuf, sizeof jbuf, CurEnv); 15466812Seric j_has_dot = strchr(jbuf, '.') != NULL; 15566793Seric } 15666793Seric #endif 15766793Seric 1589610Seric if (tTd(15, 1)) 15910206Seric printf("getrequests: %d\n", DaemonSocket); 1609610Seric 1614631Seric for (;;) 1624631Seric { 16314875Seric register int pid; 16411147Seric auto int lotherend; 16553751Seric extern bool refuseconnections(); 16668693Seric extern int getla(); 16711147Seric 16814875Seric /* see if we are rejecting connections */ 16953751Seric CurrentLA = getla(); 17053751Seric if (refuseconnections()) 17136584Sbostic { 17266845Seric if (DaemonSocket >= 0) 17353751Seric { 17466845Seric /* close socket so peer will fail quickly */ 17566845Seric (void) close(DaemonSocket); 17666845Seric DaemonSocket = -1; 17753751Seric } 17866845Seric refusingconnections = TRUE; 17957385Seric setproctitle("rejecting connections: load average: %d", 18057385Seric CurrentLA); 18166845Seric sleep(15); 18253751Seric continue; 18336584Sbostic } 18414875Seric 18568693Seric /* arrange to (re)open the socket if necessary */ 18653751Seric if (refusingconnections) 18753751Seric { 18867690Seric (void) opendaemonsocket(FALSE); 18953751Seric setproctitle("accepting connections"); 19053751Seric refusingconnections = FALSE; 19153751Seric } 19253751Seric 19366793Seric #ifdef XDEBUG 19466793Seric /* check for disaster */ 19566793Seric { 19666812Seric char jbuf[MAXHOSTNAMELEN]; 19766793Seric 19868693Seric expand("\201j", jbuf, sizeof jbuf, CurEnv); 19968693Seric if (!wordinclass(jbuf, 'w')) 20066793Seric { 20166793Seric dumpstate("daemon lost $j"); 20266793Seric syslog(LOG_ALERT, "daemon process doesn't have $j in $=w; see syslog"); 20366793Seric abort(); 20466793Seric } 20566812Seric else if (j_has_dot && strchr(jbuf, '.') == NULL) 20666793Seric { 20766793Seric dumpstate("daemon $j lost dot"); 20866793Seric syslog(LOG_ALERT, "daemon process $j lost dot; see syslog"); 20966793Seric abort(); 21066793Seric } 21166793Seric } 21266793Seric #endif 21366793Seric 2149610Seric /* wait for a connection */ 2159610Seric do 2169610Seric { 2179610Seric errno = 0; 21864828Seric lotherend = socksize; 21946928Sbostic t = accept(DaemonSocket, 22046928Sbostic (struct sockaddr *)&RealHostAddr, &lotherend); 2219610Seric } while (t < 0 && errno == EINTR); 2229610Seric if (t < 0) 2235978Seric { 2249610Seric syserr("getrequests: accept"); 22568693Seric 22668693Seric /* arrange to re-open the socket next time around */ 22768693Seric (void) close(DaemonSocket); 22868693Seric DaemonSocket = -1; 2299610Seric sleep(5); 2309610Seric continue; 2315978Seric } 2324631Seric 2335978Seric /* 2345978Seric ** Create a subprocess to process the mail. 2355978Seric */ 2365978Seric 2377677Seric if (tTd(15, 2)) 2389610Seric printf("getrequests: forking (fd = %d)\n", t); 2395978Seric 2404636Seric pid = fork(); 2414636Seric if (pid < 0) 2424631Seric { 2434636Seric syserr("daemon: cannot fork"); 2444636Seric sleep(10); 2459610Seric (void) close(t); 2464636Seric continue; 2474631Seric } 2484631Seric 2494636Seric if (pid == 0) 2504631Seric { 25164086Seric char *p; 25258951Seric extern char *hostnamebyanyaddr(); 25368693Seric extern void intsig(); 25411147Seric 2554636Seric /* 2564636Seric ** CHILD -- return to caller. 25711147Seric ** Collect verified idea of sending host. 2584636Seric ** Verify calling user id if possible here. 2594636Seric */ 2604631Seric 26164035Seric (void) setsignal(SIGCHLD, SIG_DFL); 26268693Seric (void) setsignal(SIGHUP, intsig); 26368693Seric (void) close(DaemonSocket); 26466017Seric DisConnected = FALSE; 26524950Seric 26666032Seric setproctitle("startup with %s", 26766032Seric anynet_ntoa(&RealHostAddr)); 26866032Seric 26911147Seric /* determine host name */ 27064086Seric p = hostnamebyanyaddr(&RealHostAddr); 27169471Seric if (strlen(p) > MAXNAME) 27269471Seric p[MAXNAME] = '\0'; 27364086Seric RealHostName = newstr(p); 27466032Seric setproctitle("startup with %s", p); 27558778Seric 27655173Seric #ifdef LOG 27763842Seric if (LogLevel > 11) 27855173Seric { 27955173Seric /* log connection information */ 28055173Seric syslog(LOG_INFO, "connect from %s (%s)", 28158951Seric RealHostName, anynet_ntoa(&RealHostAddr)); 28255173Seric } 28355173Seric #endif 28455173Seric 28564724Seric if ((InChannel = fdopen(t, "r")) == NULL || 28664724Seric (t = dup(t)) < 0 || 28764724Seric (OutChannel = fdopen(t, "w")) == NULL) 28864724Seric { 28964724Seric syserr("cannot open SMTP server channel, fd=%d", t); 29064724Seric exit(0); 29164724Seric } 29259254Seric 29316884Seric /* should we check for illegal connection here? XXX */ 29459156Seric #ifdef XLA 29559156Seric if (!xla_host_ok(RealHostName)) 29659156Seric { 29759254Seric message("421 Too many SMTP sessions for this host"); 29859156Seric exit(0); 29959156Seric } 30059156Seric #endif 30116884Seric 3027677Seric if (tTd(15, 2)) 3035978Seric printf("getreq: returning\n"); 3044636Seric return; 3054631Seric } 3064631Seric 3077117Seric /* close the port so that others will hang (for a while) */ 3089610Seric (void) close(t); 3094631Seric } 3109886Seric /*NOTREACHED*/ 3114631Seric } 3125978Seric /* 31366845Seric ** OPENDAEMONSOCKET -- open the SMTP socket 31466845Seric ** 31566845Seric ** Deals with setting all appropriate options. DaemonAddr must 31666845Seric ** be set up in advance. 31766845Seric ** 31866845Seric ** Parameters: 31966854Seric ** firsttime -- set if this is the initial open. 32066845Seric ** 32166845Seric ** Returns: 32266845Seric ** Size in bytes of the daemon socket addr. 32366845Seric ** 32466845Seric ** Side Effects: 32566845Seric ** Leaves DaemonSocket set to the open socket. 32666845Seric ** Exits if the socket cannot be created. 32766845Seric */ 32866845Seric 32966861Seric #define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 33066861Seric 33166845Seric int 33266854Seric opendaemonsocket(firsttime) 33366854Seric bool firsttime; 33466845Seric { 33566845Seric int on = 1; 33668693Seric int socksize = 0; 33766861Seric int ntries = 0; 33866861Seric int saveerrno; 33966845Seric 34066845Seric if (tTd(15, 2)) 34166845Seric printf("opendaemonsocket()\n"); 34266845Seric 34366861Seric do 34466845Seric { 34566862Seric if (ntries > 0) 34666862Seric sleep(5); 34766861Seric if (firsttime || DaemonSocket < 0) 34866854Seric { 34966861Seric DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0); 35066861Seric if (DaemonSocket < 0) 35166861Seric { 35266861Seric /* probably another daemon already */ 35366861Seric saveerrno = errno; 35466861Seric syserr("opendaemonsocket: can't create server SMTP socket"); 35566861Seric severe: 35666845Seric # ifdef LOG 35766861Seric if (LogLevel > 0) 35866861Seric syslog(LOG_ALERT, "problem creating SMTP socket"); 35966845Seric # endif /* LOG */ 36066861Seric DaemonSocket = -1; 36166861Seric continue; 36266861Seric } 36366845Seric 36466861Seric /* turn on network debugging? */ 36566861Seric if (tTd(15, 101)) 36666861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 36766861Seric SO_DEBUG, (char *)&on, 36866861Seric sizeof on); 36966845Seric 37066861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 37166861Seric SO_REUSEADDR, (char *)&on, sizeof on); 37266861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 37366861Seric SO_KEEPALIVE, (char *)&on, sizeof on); 37466845Seric 37566845Seric #ifdef SO_RCVBUF 37666861Seric if (TcpRcvBufferSize > 0) 37766861Seric { 37866861Seric if (setsockopt(DaemonSocket, SOL_SOCKET, 37966861Seric SO_RCVBUF, 38066861Seric (char *) &TcpRcvBufferSize, 38166861Seric sizeof(TcpRcvBufferSize)) < 0) 38266861Seric syserr("getrequests: setsockopt(SO_RCVBUF)"); 38366861Seric } 38466845Seric #endif 38566845Seric 38666861Seric switch (DaemonAddr.sa.sa_family) 38766861Seric { 38866845Seric # ifdef NETINET 38966861Seric case AF_INET: 39066861Seric socksize = sizeof DaemonAddr.sin; 39166861Seric break; 39266845Seric # endif 39366845Seric 39466845Seric # ifdef NETISO 39566861Seric case AF_ISO: 39666861Seric socksize = sizeof DaemonAddr.siso; 39766861Seric break; 39866845Seric # endif 39966845Seric 40066861Seric default: 40166861Seric socksize = sizeof DaemonAddr; 40266861Seric break; 40366861Seric } 40466861Seric 40566861Seric if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0) 40666861Seric { 40766861Seric saveerrno = errno; 40866861Seric syserr("getrequests: cannot bind"); 40966861Seric (void) close(DaemonSocket); 41066861Seric goto severe; 41166861Seric } 41266854Seric } 41366861Seric if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0) 41466854Seric { 41566861Seric saveerrno = errno; 41666861Seric syserr("getrequests: cannot listen"); 41766854Seric (void) close(DaemonSocket); 41866854Seric goto severe; 41966854Seric } 42066861Seric return socksize; 42166861Seric } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno)); 42268693Seric syserr("!opendaemonsocket: server SMTP socket wedged: exiting"); 42366861Seric finis(); 42466845Seric } 42566845Seric /* 42610206Seric ** CLRDAEMON -- reset the daemon connection 42710206Seric ** 42810206Seric ** Parameters: 42910206Seric ** none. 43010206Seric ** 43110206Seric ** Returns: 43210206Seric ** none. 43310206Seric ** 43410206Seric ** Side Effects: 43510206Seric ** releases any resources used by the passive daemon. 43610206Seric */ 43710206Seric 43868693Seric void 43910206Seric clrdaemon() 44010206Seric { 44110206Seric if (DaemonSocket >= 0) 44210206Seric (void) close(DaemonSocket); 44310206Seric DaemonSocket = -1; 44410206Seric } 44510206Seric /* 44658849Seric ** SETDAEMONOPTIONS -- set options for running the daemon 44758849Seric ** 44858849Seric ** Parameters: 44958849Seric ** p -- the options line. 45058849Seric ** 45158849Seric ** Returns: 45258849Seric ** none. 45358849Seric */ 45458849Seric 45568693Seric void 45658849Seric setdaemonoptions(p) 45758849Seric register char *p; 45858849Seric { 45958873Seric if (DaemonAddr.sa.sa_family == AF_UNSPEC) 46058873Seric DaemonAddr.sa.sa_family = AF_INET; 46158873Seric 46258849Seric while (p != NULL) 46358849Seric { 46458849Seric register char *f; 46558849Seric register char *v; 46658849Seric 46758849Seric while (isascii(*p) && isspace(*p)) 46858849Seric p++; 46958849Seric if (*p == '\0') 47058849Seric break; 47158849Seric f = p; 47258849Seric p = strchr(p, ','); 47358849Seric if (p != NULL) 47458849Seric *p++ = '\0'; 47558849Seric v = strchr(f, '='); 47658849Seric if (v == NULL) 47758849Seric continue; 47858849Seric while (isascii(*++v) && isspace(*v)) 47958849Seric continue; 48069397Seric if (isascii(*f) && isupper(*f)) 48169397Seric *f = tolower(*f); 48258849Seric 48358849Seric switch (*f) 48458849Seric { 48558873Seric case 'F': /* address family */ 48658849Seric if (isascii(*v) && isdigit(*v)) 48758873Seric DaemonAddr.sa.sa_family = atoi(v); 48858873Seric #ifdef NETINET 48958873Seric else if (strcasecmp(v, "inet") == 0) 49058873Seric DaemonAddr.sa.sa_family = AF_INET; 49158873Seric #endif 49258873Seric #ifdef NETISO 49358873Seric else if (strcasecmp(v, "iso") == 0) 49458873Seric DaemonAddr.sa.sa_family = AF_ISO; 49558873Seric #endif 49658873Seric #ifdef NETNS 49758873Seric else if (strcasecmp(v, "ns") == 0) 49858873Seric DaemonAddr.sa.sa_family = AF_NS; 49958873Seric #endif 50058873Seric #ifdef NETX25 50158873Seric else if (strcasecmp(v, "x.25") == 0) 50258873Seric DaemonAddr.sa.sa_family = AF_CCITT; 50358873Seric #endif 50458849Seric else 50558873Seric syserr("554 Unknown address family %s in Family=option", v); 50658873Seric break; 50758873Seric 50858873Seric case 'A': /* address */ 50958873Seric switch (DaemonAddr.sa.sa_family) 51058849Seric { 51158873Seric #ifdef NETINET 51258873Seric case AF_INET: 51358873Seric if (isascii(*v) && isdigit(*v)) 51468693Seric DaemonAddr.sin.sin_addr.s_addr = htonl(inet_network(v)); 51558873Seric else 51658873Seric { 51758873Seric register struct netent *np; 51858849Seric 51958873Seric np = getnetbyname(v); 52058873Seric if (np == NULL) 52158873Seric syserr("554 network \"%s\" unknown", v); 52258873Seric else 52358873Seric DaemonAddr.sin.sin_addr.s_addr = np->n_net; 52458873Seric } 52558873Seric break; 52658873Seric #endif 52758873Seric 52858873Seric default: 52958873Seric syserr("554 Address= option unsupported for family %d", 53058873Seric DaemonAddr.sa.sa_family); 53158873Seric break; 53258849Seric } 53358849Seric break; 53458849Seric 53558873Seric case 'P': /* port */ 53658873Seric switch (DaemonAddr.sa.sa_family) 53758849Seric { 53858873Seric short port; 53958849Seric 54058873Seric #ifdef NETINET 54158873Seric case AF_INET: 54258873Seric if (isascii(*v) && isdigit(*v)) 54364366Seric DaemonAddr.sin.sin_port = htons(atoi(v)); 54458849Seric else 54558873Seric { 54658873Seric register struct servent *sp; 54758873Seric 54858873Seric sp = getservbyname(v, "tcp"); 54958873Seric if (sp == NULL) 55058909Seric syserr("554 service \"%s\" unknown", v); 55158873Seric else 55258873Seric DaemonAddr.sin.sin_port = sp->s_port; 55358873Seric } 55458873Seric break; 55558873Seric #endif 55658873Seric 55758873Seric #ifdef NETISO 55858873Seric case AF_ISO: 55958873Seric /* assume two byte transport selector */ 56058873Seric if (isascii(*v) && isdigit(*v)) 56164366Seric port = htons(atoi(v)); 56258873Seric else 56358873Seric { 56458873Seric register struct servent *sp; 56558873Seric 56658873Seric sp = getservbyname(v, "tcp"); 56758873Seric if (sp == NULL) 56858909Seric syserr("554 service \"%s\" unknown", v); 56958873Seric else 57058873Seric port = sp->s_port; 57158873Seric } 57258873Seric bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 57358873Seric break; 57458873Seric #endif 57558873Seric 57658873Seric default: 57758873Seric syserr("554 Port= option unsupported for family %d", 57858873Seric DaemonAddr.sa.sa_family); 57958873Seric break; 58058849Seric } 58158849Seric break; 58259783Seric 58359783Seric case 'L': /* listen queue size */ 58459783Seric ListenQueueSize = atoi(v); 58559783Seric break; 58664381Seric 58764381Seric case 'S': /* send buffer size */ 58864381Seric TcpSndBufferSize = atoi(v); 58964381Seric break; 59064381Seric 59164381Seric case 'R': /* receive buffer size */ 59264381Seric TcpRcvBufferSize = atoi(v); 59364381Seric break; 59469397Seric 59569397Seric default: 59669397Seric syserr("554 DaemonPortOptions parameter \"%s\" unknown", f); 59758849Seric } 59858849Seric } 59958849Seric } 60058849Seric /* 6016039Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 6026039Seric ** 6036039Seric ** Parameters: 6046039Seric ** host -- the name of the host. 6056633Seric ** port -- the port number to connect to. 60653739Seric ** mci -- a pointer to the mail connection information 60753739Seric ** structure to be filled in. 60852106Seric ** usesecureport -- if set, use a low numbered (reserved) 60952106Seric ** port to provide some rudimentary authentication. 6106039Seric ** 6116039Seric ** Returns: 6126039Seric ** An exit code telling whether the connection could be 6136039Seric ** made and if not why not. 6146039Seric ** 6156039Seric ** Side Effects: 6166039Seric ** none. 6176039Seric */ 6185978Seric 61958755Seric SOCKADDR CurHostAddr; /* address of current host */ 62058305Seric 62154967Seric int 62253739Seric makeconnection(host, port, mci, usesecureport) 6236039Seric char *host; 6247286Seric u_short port; 62554967Seric register MCI *mci; 62652106Seric bool usesecureport; 6276039Seric { 62868693Seric register int i = 0; 62968693Seric register int s; 63029430Sbloom register struct hostent *hp = (struct hostent *)NULL; 63158755Seric SOCKADDR addr; 63252106Seric int sav_errno; 63358755Seric int addrlen; 63468693Seric bool firstconnect; 63566334Seric #if NAMED_BIND 63635651Seric extern int h_errno; 63735651Seric #endif 6386039Seric 6396039Seric /* 6406039Seric ** Set up the address for the mailer. 6419308Seric ** Accept "[a.b.c.d]" syntax for host name. 6426039Seric */ 6436039Seric 64466334Seric #if NAMED_BIND 64525475Smiriam h_errno = 0; 64635651Seric #endif 64725475Smiriam errno = 0; 64858864Seric bzero(&CurHostAddr, sizeof CurHostAddr); 64964334Seric SmtpPhase = mci->mci_phase = "initial connection"; 65058906Seric CurHostName = host; 65125475Smiriam 6529308Seric if (host[0] == '[') 6539308Seric { 65411147Seric long hid; 65556795Seric register char *p = strchr(host, ']'); 6569308Seric 65711147Seric if (p != NULL) 6589308Seric { 65911147Seric *p = '\0'; 66059884Seric #ifdef NETINET 66111147Seric hid = inet_addr(&host[1]); 66258360Seric if (hid == -1) 66359884Seric #endif 66458360Seric { 66558360Seric /* try it as a host name (avoid MX lookup) */ 66668693Seric hp = sm_gethostbyname(&host[1]); 66766349Seric if (hp == NULL && p[-1] == '.') 66866349Seric { 66968693Seric #if NAMED_BIND 67068693Seric int oldopts = _res.options; 67168693Seric 67268693Seric _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 67368693Seric #endif 67466349Seric p[-1] = '\0'; 67568693Seric hp = sm_gethostbyname(&host[1]); 67666349Seric p[-1] = '.'; 67768693Seric #if NAMED_BIND 67868693Seric _res.options = oldopts; 67968693Seric #endif 68066349Seric } 68158360Seric *p = ']'; 68258360Seric goto gothostent; 68358360Seric } 68411147Seric *p = ']'; 6859308Seric } 68658360Seric if (p == NULL) 6879308Seric { 68858151Seric usrerr("553 Invalid numeric domain spec \"%s\"", host); 68968857Seric mci->mci_status = "5.1.2"; 6909308Seric return (EX_NOHOST); 6919308Seric } 69259884Seric #ifdef NETINET 69359884Seric addr.sin.sin_family = AF_INET; /*XXX*/ 69458778Seric addr.sin.sin_addr.s_addr = hid; 69559884Seric #endif 6969308Seric } 6979610Seric else 6989610Seric { 69966349Seric register char *p = &host[strlen(host) - 1]; 70066349Seric 70168693Seric hp = sm_gethostbyname(host); 70266349Seric if (hp == NULL && *p == '.') 70366349Seric { 70468693Seric #if NAMED_BIND 70568693Seric int oldopts = _res.options; 70668693Seric 70768693Seric _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 70868693Seric #endif 70966349Seric *p = '\0'; 71068693Seric hp = sm_gethostbyname(host); 71166349Seric *p = '.'; 71268693Seric #if NAMED_BIND 71368693Seric _res.options = oldopts; 71468693Seric #endif 71566349Seric } 71658360Seric gothostent: 71725475Smiriam if (hp == NULL) 71824945Seric { 71966334Seric #if NAMED_BIND 72068693Seric /* check for name server timeouts */ 72168693Seric if (errno == ETIMEDOUT || h_errno == TRY_AGAIN || 72268693Seric (errno == ECONNREFUSED && UseNameServer)) 72368693Seric { 72468693Seric mci->mci_status = "4.4.3"; 72525475Smiriam return (EX_TEMPFAIL); 72668693Seric } 72735651Seric #endif 72825475Smiriam return (EX_NOHOST); 72924945Seric } 73058778Seric addr.sa.sa_family = hp->h_addrtype; 73158778Seric switch (hp->h_addrtype) 73258778Seric { 73358778Seric #ifdef NETINET 73458778Seric case AF_INET: 73558755Seric bcopy(hp->h_addr, 73658778Seric &addr.sin.sin_addr, 73768693Seric INADDRSZ); 73858778Seric break; 73958778Seric #endif 74058778Seric 74158778Seric default: 74258755Seric bcopy(hp->h_addr, 74358778Seric addr.sa.sa_data, 74458755Seric hp->h_length); 74558778Seric break; 74658778Seric } 74729430Sbloom i = 1; 7489610Seric } 7499610Seric 7509610Seric /* 7519610Seric ** Determine the port number. 7529610Seric */ 7539610Seric 75410011Seric if (port != 0) 75558755Seric port = htons(port); 75610011Seric else 7579610Seric { 7589610Seric register struct servent *sp = getservbyname("smtp", "tcp"); 7599610Seric 7609610Seric if (sp == NULL) 7619610Seric { 76268745Seric #ifdef LOG 76368745Seric if (LogLevel > 2) 76468745Seric syslog(LOG_ERR, "makeconnection: service \"smtp\" unknown"); 76568745Seric #endif 76665169Seric port = htons(25); 7679610Seric } 76865169Seric else 76965169Seric port = sp->s_port; 7709610Seric } 7716039Seric 77258778Seric switch (addr.sa.sa_family) 77358755Seric { 77459884Seric #ifdef NETINET 77558755Seric case AF_INET: 77658778Seric addr.sin.sin_port = port; 77758755Seric addrlen = sizeof (struct sockaddr_in); 77858755Seric break; 77959884Seric #endif 78058755Seric 78158755Seric #ifdef NETISO 78258755Seric case AF_ISO: 78358755Seric /* assume two byte transport selector */ 78458755Seric bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 78558755Seric addrlen = sizeof (struct sockaddr_iso); 78658755Seric break; 78758755Seric #endif 78858755Seric 78958755Seric default: 79058778Seric syserr("Can't connect to address family %d", addr.sa.sa_family); 79158755Seric return (EX_NOHOST); 79258755Seric } 79358755Seric 7946039Seric /* 7956039Seric ** Try to actually open the connection. 7966039Seric */ 7976039Seric 79859156Seric #ifdef XLA 79959156Seric /* if too many connections, don't bother trying */ 80059156Seric if (!xla_noqueue_ok(host)) 80159156Seric return EX_TEMPFAIL; 80259156Seric #endif 80359156Seric 80468693Seric firstconnect = TRUE; 80557736Seric for (;;) 80652106Seric { 80757736Seric if (tTd(16, 1)) 80858755Seric printf("makeconnection (%s [%s])\n", 80958755Seric host, anynet_ntoa(&addr)); 81052106Seric 81158588Seric /* save for logging */ 81258588Seric CurHostAddr = addr; 81358588Seric 81457736Seric if (usesecureport) 81557736Seric { 81657736Seric int rport = IPPORT_RESERVED - 1; 8176039Seric 81857736Seric s = rresvport(&rport); 81957736Seric } 82057736Seric else 82157736Seric { 82257736Seric s = socket(AF_INET, SOCK_STREAM, 0); 82357736Seric } 82457736Seric if (s < 0) 82557736Seric { 82657736Seric sav_errno = errno; 82757736Seric syserr("makeconnection: no socket"); 82857736Seric goto failure; 82957736Seric } 83010347Seric 83164381Seric #ifdef SO_SNDBUF 83264381Seric if (TcpSndBufferSize > 0) 83364381Seric { 83464381Seric if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 83564561Seric (char *) &TcpSndBufferSize, 83664381Seric sizeof(TcpSndBufferSize)) < 0) 83764381Seric syserr("makeconnection: setsockopt(SO_SNDBUF)"); 83864381Seric } 83964381Seric #endif 84064381Seric 84157736Seric if (tTd(16, 1)) 84257736Seric printf("makeconnection: fd=%d\n", s); 84357736Seric 84457736Seric /* turn on network debugging? */ 84557736Seric if (tTd(16, 101)) 84657736Seric { 84757736Seric int on = 1; 84866861Seric (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 84957736Seric (char *)&on, sizeof on); 85057736Seric } 85157736Seric if (CurEnv->e_xfp != NULL) 85257736Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 85357736Seric errno = 0; /* for debugging */ 85458755Seric if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 85557736Seric break; 85657736Seric 85768693Seric /* if running demand-dialed connection, try again */ 85868693Seric if (DialDelay > 0 && firstconnect) 85968693Seric { 86068693Seric if (tTd(16, 1)) 86168693Seric printf("Connect failed (%s); trying again...\n", 86268693Seric errstring(sav_errno)); 86368693Seric firstconnect = FALSE; 86468693Seric sleep(DialDelay); 86568693Seric continue; 86668693Seric } 86768693Seric 86857736Seric /* couldn't connect.... figure out why */ 86927744Sbloom sav_errno = errno; 87027744Sbloom (void) close(s); 87168693Seric if (hp != NULL && hp->h_addr_list[i]) 87229430Sbloom { 87357736Seric if (tTd(16, 1)) 87458755Seric printf("Connect failed (%s); trying new address....\n", 87558755Seric errstring(sav_errno)); 87658778Seric switch (addr.sa.sa_family) 87758778Seric { 87858778Seric #ifdef NETINET 87958778Seric case AF_INET: 88058755Seric bcopy(hp->h_addr_list[i++], 88158778Seric &addr.sin.sin_addr, 88268693Seric INADDRSZ); 88358778Seric break; 88458778Seric #endif 88558778Seric 88658778Seric default: 88758755Seric bcopy(hp->h_addr_list[i++], 88858778Seric addr.sa.sa_data, 88952106Seric hp->h_length); 89058778Seric break; 89158778Seric } 89257736Seric continue; 89329430Sbloom } 89429430Sbloom 8956039Seric /* failure, decide if temporary or not */ 8966039Seric failure: 89759254Seric #ifdef XLA 89859254Seric xla_host_end(host); 89959254Seric #endif 90058542Seric if (transienterror(sav_errno)) 90158542Seric return EX_TEMPFAIL; 90258542Seric else 90358542Seric { 90458542Seric message("%s", errstring(sav_errno)); 90558542Seric return (EX_UNAVAILABLE); 9066039Seric } 9076039Seric } 9086039Seric 9096039Seric /* connection ok, put it into canonical form */ 91064724Seric if ((mci->mci_out = fdopen(s, "w")) == NULL || 91164724Seric (s = dup(s)) < 0 || 91264725Seric (mci->mci_in = fdopen(s, "r")) == NULL) 91364724Seric { 91464724Seric syserr("cannot open SMTP client channel, fd=%d", s); 91564724Seric return EX_TEMPFAIL; 91664724Seric } 9176039Seric 91810098Seric return (EX_OK); 9196039Seric } 92010758Seric /* 92110758Seric ** MYHOSTNAME -- return the name of this host. 92210758Seric ** 92310758Seric ** Parameters: 92410758Seric ** hostbuf -- a place to return the name of this host. 92512313Seric ** size -- the size of hostbuf. 92610758Seric ** 92710758Seric ** Returns: 92810758Seric ** A list of aliases for this host. 92910758Seric ** 93010758Seric ** Side Effects: 93164338Seric ** Adds numeric codes to $=w. 93210758Seric */ 9336039Seric 93468693Seric struct hostent * 93512313Seric myhostname(hostbuf, size) 93610758Seric char hostbuf[]; 93712313Seric int size; 93810758Seric { 93958110Seric register struct hostent *hp; 94068693Seric extern bool getcanonname(); 94168693Seric extern int h_errno; 94210758Seric 94323120Seric if (gethostname(hostbuf, size) < 0) 94423120Seric { 94523120Seric (void) strcpy(hostbuf, "localhost"); 94623120Seric } 94768693Seric hp = sm_gethostbyname(hostbuf); 94866853Seric if (hp == NULL) 94968693Seric return NULL; 95068693Seric if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 95167448Seric { 95268693Seric (void) strncpy(hostbuf, hp->h_name, size - 1); 95368693Seric hostbuf[size - 1] = '\0'; 95467448Seric } 95566853Seric 95666853Seric #if NAMED_BIND 95768693Seric /* 95868693Seric ** If still no dot, try DNS directly (i.e., avoid NIS problems). 95968693Seric ** This ought to be driven from the configuration file, but 96068693Seric ** we are called before the configuration is read. We could 96168693Seric ** check for an /etc/resolv.conf file, but that isn't required. 96268693Seric ** All in all, a bit of a mess. 96368693Seric */ 96468693Seric 96568693Seric if (strchr(hostbuf, '.') == NULL && 96668693Seric !getcanonname(hostbuf, size, TRUE) && 96768693Seric h_errno == TRY_AGAIN) 96868612Seric { 96966853Seric /* try twice in case name server not yet started up */ 97068693Seric message("My unqualifed host name (%s) unknown to DNS; sleeping for retry", 97168693Seric hostbuf); 97268693Seric sleep(60); 97368693Seric if (!getcanonname(hostbuf, size, TRUE)) 97466853Seric errno = h_errno + E_DNSBASE; 97566853Seric } 97666777Seric #endif 97768693Seric return (hp); 97810758Seric } 97951315Seric /* 98058951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 98158308Seric ** 98258951Seric ** Uses RFC1413 protocol to try to get info from the other end. 98358951Seric ** 98458308Seric ** Parameters: 98558308Seric ** fd -- the descriptor 98658308Seric ** 98758308Seric ** Returns: 98858951Seric ** The user@host information associated with this descriptor. 98958308Seric */ 99058308Seric 99158951Seric static jmp_buf CtxAuthTimeout; 99258951Seric 99368693Seric static void 99458951Seric authtimeout() 99558951Seric { 99658951Seric longjmp(CtxAuthTimeout, 1); 99758951Seric } 99858951Seric 99958308Seric char * 100058951Seric getauthinfo(fd) 100158308Seric int fd; 100258308Seric { 100358951Seric int falen; 100459104Seric register char *p; 100558951Seric SOCKADDR la; 100658951Seric int lalen; 100758951Seric register struct servent *sp; 100858951Seric int s; 100958951Seric int i; 101058951Seric EVENT *ev; 101168444Seric int nleft; 101268462Seric char ibuf[MAXNAME + 1]; 101358951Seric static char hbuf[MAXNAME * 2 + 2]; 101458951Seric extern char *hostnamebyanyaddr(); 101558951Seric extern char RealUserName[]; /* main.c */ 101658308Seric 101766761Seric falen = sizeof RealHostAddr; 101868693Seric if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 || 101968693Seric falen <= 0 || RealHostAddr.sa.sa_family == 0) 102058951Seric { 102158951Seric (void) sprintf(hbuf, "%s@localhost", RealUserName); 102258957Seric if (tTd(9, 1)) 102358951Seric printf("getauthinfo: %s\n", hbuf); 102458951Seric return hbuf; 102558951Seric } 102658951Seric 102766761Seric if (RealHostName == NULL) 102866761Seric { 102966761Seric /* translate that to a host name */ 103066761Seric RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 103166761Seric } 103266761Seric 103365831Seric if (TimeOuts.to_ident == 0) 103465831Seric goto noident; 103565831Seric 103658951Seric lalen = sizeof la; 103766761Seric if (RealHostAddr.sa.sa_family != AF_INET || 103858951Seric getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 103958951Seric la.sa.sa_family != AF_INET) 104058951Seric { 104158951Seric /* no ident info */ 104258951Seric goto noident; 104358951Seric } 104458951Seric 104558951Seric /* create ident query */ 104668457Seric (void) sprintf(ibuf, "%d,%d\r\n", 104766761Seric ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port)); 104858951Seric 104958951Seric /* create local address */ 105064747Seric la.sin.sin_port = 0; 105158951Seric 105258951Seric /* create foreign address */ 105358951Seric sp = getservbyname("auth", "tcp"); 105458951Seric if (sp != NULL) 105566761Seric RealHostAddr.sin.sin_port = sp->s_port; 105658308Seric else 105766761Seric RealHostAddr.sin.sin_port = htons(113); 105858951Seric 105958951Seric s = -1; 106058951Seric if (setjmp(CtxAuthTimeout) != 0) 106158951Seric { 106258951Seric if (s >= 0) 106358951Seric (void) close(s); 106458951Seric goto noident; 106558951Seric } 106658951Seric 106758951Seric /* put a timeout around the whole thing */ 106864255Seric ev = setevent(TimeOuts.to_ident, authtimeout, 0); 106958951Seric 107064747Seric /* connect to foreign IDENT server using same address as SMTP socket */ 107158951Seric s = socket(AF_INET, SOCK_STREAM, 0); 107258951Seric if (s < 0) 107358951Seric { 107458951Seric clrevent(ev); 107558951Seric goto noident; 107658951Seric } 107764747Seric if (bind(s, &la.sa, sizeof la.sin) < 0 || 107866761Seric connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0) 107958951Seric { 108066011Seric goto closeident; 108158951Seric } 108258951Seric 108358957Seric if (tTd(9, 10)) 108468457Seric printf("getauthinfo: sent %s", ibuf); 108558951Seric 108658951Seric /* send query */ 108768457Seric if (write(s, ibuf, strlen(ibuf)) < 0) 108858951Seric goto closeident; 108958951Seric 109058951Seric /* get result */ 109168457Seric p = &ibuf[0]; 109268525Seric nleft = sizeof ibuf - 1; 109368444Seric while ((i = read(s, p, nleft)) > 0) 109468444Seric { 109568444Seric p += i; 109668444Seric nleft -= i; 109768444Seric } 109858951Seric (void) close(s); 109958951Seric clrevent(ev); 110068457Seric if (i < 0 || p == &ibuf[0]) 110158951Seric goto noident; 110258951Seric 110368444Seric if (*--p == '\n' && *--p == '\r') 110468444Seric p--; 110568444Seric *++p = '\0'; 110668444Seric 110758957Seric if (tTd(9, 3)) 110868457Seric printf("getauthinfo: got %s\n", ibuf); 110958951Seric 111058951Seric /* parse result */ 111168457Seric p = strchr(ibuf, ':'); 111258951Seric if (p == NULL) 111358951Seric { 111458951Seric /* malformed response */ 111558951Seric goto noident; 111658951Seric } 111758951Seric while (isascii(*++p) && isspace(*p)) 111858951Seric continue; 111958951Seric if (strncasecmp(p, "userid", 6) != 0) 112058951Seric { 112158951Seric /* presumably an error string */ 112258951Seric goto noident; 112358951Seric } 112458951Seric p += 6; 112558951Seric while (isascii(*p) && isspace(*p)) 112658951Seric p++; 112758951Seric if (*p++ != ':') 112858951Seric { 112958951Seric /* either useridxx or malformed response */ 113058951Seric goto noident; 113158951Seric } 113258951Seric 113358951Seric /* p now points to the OSTYPE field */ 113468693Seric while (isascii(*p) && isspace(*p)) 113568693Seric p++; 113668693Seric if (strncasecmp(p, "other", 5) == 0 && 113768693Seric (p[5] == ':' || p[5] == ' ' || p[5] == ',' || p[5] == '\0')) 113868693Seric { 113968693Seric /* not useful information */ 114068693Seric goto noident; 114168693Seric } 114258951Seric p = strchr(p, ':'); 114358951Seric if (p == NULL) 114458951Seric { 114558951Seric /* malformed response */ 114658951Seric goto noident; 114758951Seric } 114858951Seric 114958957Seric /* 1413 says don't do this -- but it's broken otherwise */ 115058957Seric while (isascii(*++p) && isspace(*p)) 115158957Seric continue; 115258957Seric 115367935Seric /* p now points to the authenticated name -- copy carefully */ 115468457Seric cleanstrcpy(hbuf, p, MAXNAME); 115568875Seric i = strlen(hbuf); 115667935Seric hbuf[i++] = '@'; 115767935Seric strcpy(&hbuf[i], RealHostName == NULL ? "localhost" : RealHostName); 115869601Seric goto postident; 115958957Seric 116066011Seric closeident: 116166011Seric (void) close(s); 116266011Seric clrevent(ev); 116366011Seric 116458957Seric noident: 116566003Seric if (RealHostName == NULL) 116666003Seric { 116766003Seric if (tTd(9, 1)) 116866003Seric printf("getauthinfo: NULL\n"); 116966003Seric return NULL; 117066003Seric } 117158957Seric (void) strcpy(hbuf, RealHostName); 117258957Seric 117369601Seric postident: 117469601Seric #if IP_SRCROUTE 117569601Seric /* 117669601Seric ** Extract IP source routing information. 117769601Seric ** 117869601Seric ** Format of output for a connection from site a through b 117969601Seric ** through c to d: 118069601Seric ** loose: @site-c@site-b:site-a 118169601Seric ** strict: !@site-c@site-b:site-a 118269601Seric ** 118369601Seric ** o - pointer within ipopt_list structure. 118469601Seric ** q - pointer within ls/ss rr route data 118569601Seric ** p - pointer to hbuf 118669601Seric */ 118769601Seric 118869601Seric if (RealHostAddr.sa.sa_family == AF_INET) 118969601Seric { 119069601Seric int ipoptlen, j; 1191*69637Seric u_char *q; 119269601Seric u_char *o; 119369601Seric struct in_addr addr; 119469601Seric struct ipoption ipopt; 119569601Seric 119669601Seric ipoptlen = sizeof ipopt; 119769601Seric if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS, 119869601Seric (char *) &ipopt, &ipoptlen) < 0) 119969601Seric goto noipsr; 120069601Seric if (ipoptlen == 0) 120169601Seric goto noipsr; 1202*69637Seric o = (u_char *) ipopt.ipopt_list; 120369601Seric while (o != NULL && o < (u_char *) (&ipopt + ipoptlen)) 120469601Seric { 120569601Seric switch (*o) 120669601Seric { 120769601Seric case IPOPT_EOL: 120869601Seric o = NULL; 120969601Seric break; 121069601Seric 121169601Seric case IPOPT_NOP: 121269601Seric o++; 121369601Seric break; 121469601Seric 121569601Seric case IPOPT_SSRR: 121669601Seric case IPOPT_LSRR: 121769601Seric p = &hbuf[strlen(hbuf)]; 121869601Seric sprintf(p, " [%s@%s", 121969601Seric *o == IPOPT_SSRR ? "!" : "", 122069601Seric inet_ntoa(ipopt.ipopt_dst)); 122169601Seric p += strlen(p); 122269601Seric 122369601Seric /* o[1] is option length */ 122469601Seric j = *++o / sizeof(struct in_addr) - 1; 122569601Seric 122669601Seric /* q skips length and router pointer to data */ 122769601Seric q = o + 2; 122869601Seric for ( ; j >= 0; j--) 122969601Seric { 123069601Seric memcpy(&addr, q, sizeof(addr)); 1231*69637Seric sprintf(p, "%c%s", 123269601Seric j ? '@' : ':', 123369601Seric inet_ntoa(addr)); 1234*69637Seric p += strlen(p); 1235*69637Seric q += sizeof(struct in_addr); 123669601Seric } 123769601Seric o += *o; 123869601Seric break; 123969601Seric 124069601Seric default: 124169601Seric /* Skip over option */ 124269601Seric o += o[1]; 124369601Seric break; 124469601Seric } 124569601Seric } 124669601Seric strcat(hbuf,"]"); 124769601Seric goto postipsr; 124869601Seric } 124969601Seric #endif 125069601Seric 125169601Seric noipsr: 125266003Seric if (RealHostName != NULL && RealHostName[0] != '[') 125358951Seric { 125458951Seric p = &hbuf[strlen(hbuf)]; 125558951Seric (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 125658951Seric } 125769601Seric 125869601Seric postipsr: 125958957Seric if (tTd(9, 1)) 126058951Seric printf("getauthinfo: %s\n", hbuf); 126158308Seric return hbuf; 126258308Seric } 126358308Seric /* 126460089Seric ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 126553751Seric ** 126653751Seric ** Parameters: 126756823Seric ** map -- a pointer to this map (unused). 126860089Seric ** name -- the (presumably unqualified) hostname. 126960257Seric ** av -- unused -- for compatibility with other mapping 127055019Seric ** functions. 127159084Seric ** statp -- an exit status (out parameter) -- set to 127259084Seric ** EX_TEMPFAIL if the name server is unavailable. 127353751Seric ** 127453751Seric ** Returns: 127553751Seric ** The mapping, if found. 127653751Seric ** NULL if no mapping found. 127753751Seric ** 127853751Seric ** Side Effects: 127953751Seric ** Looks up the host specified in hbuf. If it is not 128053751Seric ** the canonical name for that host, return the canonical 128153751Seric ** name. 128253751Seric */ 128351315Seric 128453751Seric char * 128560257Seric host_map_lookup(map, name, av, statp) 128656823Seric MAP *map; 128760089Seric char *name; 128860257Seric char **av; 128959084Seric int *statp; 129016911Seric { 129116911Seric register struct hostent *hp; 129268693Seric struct in_addr in_addr; 129356823Seric char *cp; 129459671Seric register STAB *s; 129568693Seric char hbuf[MAXNAME + 1]; 129666334Seric #if NAMED_BIND 129759671Seric extern int h_errno; 129866029Seric #endif 129916911Seric 130025574Smiriam /* 130159671Seric ** See if we have already looked up this name. If so, just 130259671Seric ** return it. 130359671Seric */ 130453751Seric 130560089Seric s = stab(name, ST_NAMECANON, ST_ENTER); 130659671Seric if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 130759671Seric { 130859986Seric if (tTd(9, 1)) 130960089Seric printf("host_map_lookup(%s) => CACHE %s\n", 131069511Seric name, 131169511Seric s->s_namecanon.nc_cname == NULL 131269511Seric ? "NULL" 131369512Seric : s->s_namecanon.nc_cname); 131459671Seric errno = s->s_namecanon.nc_errno; 131566334Seric #if NAMED_BIND 131659671Seric h_errno = s->s_namecanon.nc_herrno; 131766029Seric #endif 131859671Seric *statp = s->s_namecanon.nc_stat; 131968817Seric if (*statp == EX_TEMPFAIL) 132065199Seric { 132168857Seric CurEnv->e_status = "4.4.3"; 132268817Seric usrerr("451 %s: Name server timeout", 132365199Seric shortenstring(name, 33)); 132465199Seric } 132559671Seric return s->s_namecanon.nc_cname; 132659671Seric } 132759671Seric 132859671Seric /* 132959671Seric ** If first character is a bracket, then it is an address 133059671Seric ** lookup. Address is copied into a temporary buffer to 133160089Seric ** strip the brackets and to preserve name if address is 133259671Seric ** unknown. 133359671Seric */ 133459671Seric 133560089Seric if (*name != '[') 133653751Seric { 133755019Seric extern bool getcanonname(); 133855019Seric 133958798Seric if (tTd(9, 1)) 134060089Seric printf("host_map_lookup(%s) => ", name); 134159671Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 134268693Seric if (strlen(name) < sizeof hbuf) 134368693Seric (void) strcpy(hbuf, name); 134468693Seric else 134568693Seric { 134668693Seric bcopy(name, hbuf, sizeof hbuf - 1); 134768693Seric hbuf[sizeof hbuf - 1] = '\0'; 134868693Seric } 134968759Seric if (getcanonname(hbuf, sizeof hbuf - 1, !NoMXforCanon)) 135058796Seric { 135158796Seric if (tTd(9, 1)) 135258796Seric printf("%s\n", hbuf); 135360257Seric cp = map_rewrite(map, hbuf, strlen(hbuf), av); 135460257Seric s->s_namecanon.nc_cname = newstr(cp); 135560257Seric return cp; 135658796Seric } 135753751Seric else 135858796Seric { 135959084Seric register struct hostent *hp; 136059084Seric 136166029Seric s->s_namecanon.nc_errno = errno; 136266334Seric #if NAMED_BIND 136366029Seric s->s_namecanon.nc_herrno = h_errno; 136458796Seric if (tTd(9, 1)) 136559084Seric printf("FAIL (%d)\n", h_errno); 136659084Seric switch (h_errno) 136759084Seric { 136859084Seric case TRY_AGAIN: 136959596Seric if (UseNameServer) 137059734Seric { 137168857Seric CurEnv->e_status = "4.4.3"; 137268817Seric usrerr("451 %s: Name server timeout", 137365199Seric shortenstring(name, 33)); 137459734Seric } 137559084Seric *statp = EX_TEMPFAIL; 137659084Seric break; 137759084Seric 137859084Seric case HOST_NOT_FOUND: 137968881Seric case NO_DATA: 138059084Seric *statp = EX_NOHOST; 138159084Seric break; 138259084Seric 138359084Seric case NO_RECOVERY: 138459084Seric *statp = EX_SOFTWARE; 138559084Seric break; 138659084Seric 138759084Seric default: 138859084Seric *statp = EX_UNAVAILABLE; 138959084Seric break; 139059084Seric } 139166029Seric #else 139266029Seric if (tTd(9, 1)) 139366029Seric printf("FAIL\n"); 139466029Seric *statp = EX_NOHOST; 139566029Seric #endif 139659671Seric s->s_namecanon.nc_stat = *statp; 139768693Seric if ((*statp != EX_TEMPFAIL && *statp != EX_NOHOST) || 139868693Seric UseNameServer) 139959084Seric return NULL; 140059084Seric 140159084Seric /* 140259084Seric ** Try to look it up in /etc/hosts 140359084Seric */ 140459084Seric 140568693Seric hp = sm_gethostbyname(name); 140659084Seric if (hp == NULL) 140759084Seric { 140859084Seric /* no dice there either */ 140959671Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 141059084Seric return NULL; 141159084Seric } 141259084Seric 141359671Seric s->s_namecanon.nc_stat = *statp = EX_OK; 141460257Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 141560257Seric s->s_namecanon.nc_cname = newstr(cp); 141660257Seric return cp; 141758796Seric } 141853751Seric } 141960089Seric if ((cp = strchr(name, ']')) == NULL) 142053751Seric return (NULL); 142140994Sbostic *cp = '\0'; 142268693Seric in_addr.s_addr = inet_addr(&name[1]); 142358110Seric 142458110Seric /* nope -- ask the name server */ 142568693Seric hp = sm_gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET); 142659671Seric s->s_namecanon.nc_errno = errno; 142766334Seric #if NAMED_BIND 142859671Seric s->s_namecanon.nc_herrno = h_errno; 142966029Seric #endif 143059671Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 143133932Sbostic if (hp == NULL) 143259671Seric { 143359671Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 143453751Seric return (NULL); 143559671Seric } 143653751Seric 143758110Seric /* found a match -- copy out */ 143860257Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 143959671Seric s->s_namecanon.nc_stat = *statp = EX_OK; 144060257Seric s->s_namecanon.nc_cname = newstr(cp); 144160257Seric return cp; 144233932Sbostic } 144358755Seric /* 144458755Seric ** ANYNET_NTOA -- convert a network address to printable form. 144558755Seric ** 144658755Seric ** Parameters: 144758755Seric ** sap -- a pointer to a sockaddr structure. 144858755Seric ** 144958755Seric ** Returns: 145058755Seric ** A printable version of that sockaddr. 145158755Seric */ 145216911Seric 145369562Seric #ifdef NETLINK 145469516Seric # include <net/if_dl.h> 145569516Seric #endif 145669516Seric 145758755Seric char * 145858755Seric anynet_ntoa(sap) 145958755Seric register SOCKADDR *sap; 146058755Seric { 146158755Seric register char *bp; 146258755Seric register char *ap; 146358755Seric int l; 146464734Seric static char buf[100]; 146558755Seric 146658798Seric /* check for null/zero family */ 146758798Seric if (sap == NULL) 146858798Seric return "NULLADDR"; 146958798Seric if (sap->sa.sa_family == 0) 147058798Seric return "0"; 147158798Seric 147264734Seric switch (sap->sa.sa_family) 147364734Seric { 147464821Seric #ifdef NETUNIX 147564734Seric case AF_UNIX: 147664758Seric if (sap->sunix.sun_path[0] != '\0') 147764758Seric sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 147864734Seric else 147964734Seric sprintf(buf, "[UNIX: localhost]"); 148064734Seric return buf; 148164734Seric #endif 148264734Seric 148358778Seric #ifdef NETINET 148464734Seric case AF_INET: 148568776Seric return inet_ntoa(sap->sin.sin_addr); 148658778Seric #endif 148758755Seric 148869562Seric #ifdef NETLINK 148969516Seric case AF_LINK: 149069516Seric sprintf(buf, "[LINK: %s]", 149169516Seric link_ntoa((struct sockaddr_dl *) &sap->sa)); 149269516Seric return buf; 149369516Seric #endif 149464734Seric default: 149569516Seric /* this case is needed when nothing is #defined */ 149669516Seric /* in order to keep the switch syntactically correct */ 149769516Seric break; 149864734Seric } 149964734Seric 150058755Seric /* unknown family -- just dump bytes */ 150158778Seric (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 150258755Seric bp = &buf[strlen(buf)]; 150358778Seric ap = sap->sa.sa_data; 150458778Seric for (l = sizeof sap->sa.sa_data; --l >= 0; ) 150558755Seric { 150658755Seric (void) sprintf(bp, "%02x:", *ap++ & 0377); 150758755Seric bp += 3; 150858755Seric } 150958755Seric *--bp = '\0'; 151058755Seric return buf; 151158755Seric } 151258951Seric /* 151358951Seric ** HOSTNAMEBYANYADDR -- return name of host based on address 151458951Seric ** 151558951Seric ** Parameters: 151658951Seric ** sap -- SOCKADDR pointer 151758951Seric ** 151858951Seric ** Returns: 151958951Seric ** text representation of host name. 152058951Seric ** 152158951Seric ** Side Effects: 152258951Seric ** none. 152358951Seric */ 152458755Seric 152558951Seric char * 152658951Seric hostnamebyanyaddr(sap) 152758951Seric register SOCKADDR *sap; 152858951Seric { 152958951Seric register struct hostent *hp; 153064734Seric int saveretry; 153158951Seric 153266334Seric #if NAMED_BIND 153359042Seric /* shorten name server timeout to avoid higher level timeouts */ 153459042Seric saveretry = _res.retry; 153559042Seric _res.retry = 3; 153659042Seric #endif /* NAMED_BIND */ 153759042Seric 153858951Seric switch (sap->sa.sa_family) 153958951Seric { 154058951Seric #ifdef NETINET 154158951Seric case AF_INET: 154268693Seric hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr, 154368693Seric INADDRSZ, 154458951Seric AF_INET); 154558951Seric break; 154658951Seric #endif 154758951Seric 154858951Seric #ifdef NETISO 154958951Seric case AF_ISO: 155068693Seric hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr, 155158951Seric sizeof sap->siso.siso_addr, 155258951Seric AF_ISO); 155358951Seric break; 155458951Seric #endif 155558951Seric 155664734Seric case AF_UNIX: 155764734Seric hp = NULL; 155864734Seric break; 155964734Seric 156058951Seric default: 156168693Seric hp = sm_gethostbyaddr(sap->sa.sa_data, 156258951Seric sizeof sap->sa.sa_data, 156358951Seric sap->sa.sa_family); 156458951Seric break; 156558951Seric } 156658951Seric 156766334Seric #if NAMED_BIND 156859042Seric _res.retry = saveretry; 156959042Seric #endif /* NAMED_BIND */ 157059042Seric 157158951Seric if (hp != NULL) 157258951Seric return hp->h_name; 157358951Seric else 157458951Seric { 157558951Seric /* produce a dotted quad */ 157658951Seric static char buf[512]; 157758951Seric 157858951Seric (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 157958951Seric return buf; 158058951Seric } 158158951Seric } 158258951Seric 158356795Seric # else /* DAEMON */ 158416911Seric /* code for systems without sophisticated networking */ 158510758Seric 158610758Seric /* 158710758Seric ** MYHOSTNAME -- stub version for case of no daemon code. 158811297Seric ** 158911297Seric ** Can't convert to upper case here because might be a UUCP name. 159012313Seric ** 159112313Seric ** Mark, you can change this to be anything you want...... 159210758Seric */ 159310758Seric 159410758Seric char ** 159512313Seric myhostname(hostbuf, size) 159610758Seric char hostbuf[]; 159712313Seric int size; 159810758Seric { 159910758Seric register FILE *f; 160010758Seric 160110758Seric hostbuf[0] = '\0'; 160210758Seric f = fopen("/usr/include/whoami", "r"); 160310758Seric if (f != NULL) 160410758Seric { 160512313Seric (void) fgets(hostbuf, size, f); 160610758Seric fixcrlf(hostbuf, TRUE); 160710758Seric (void) fclose(f); 160810758Seric } 160910758Seric return (NULL); 161010758Seric } 161116911Seric /* 161258951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 161358308Seric ** 161458308Seric ** Parameters: 161558308Seric ** fd -- the descriptor 161658308Seric ** 161758308Seric ** Returns: 161858308Seric ** The host name associated with this descriptor, if it can 161958308Seric ** be determined. 162058308Seric ** NULL otherwise. 162158308Seric ** 162258308Seric ** Side Effects: 162358308Seric ** none 162458308Seric */ 162558308Seric 162658308Seric char * 162758951Seric getauthinfo(fd) 162858308Seric int fd; 162958308Seric { 163058308Seric return NULL; 163158308Seric } 163258308Seric /* 163316911Seric ** MAPHOSTNAME -- turn a hostname into canonical form 163416911Seric ** 163516911Seric ** Parameters: 163656823Seric ** map -- a pointer to the database map. 163760089Seric ** name -- a buffer containing a hostname. 163853751Seric ** avp -- a pointer to a (cf file defined) argument vector. 163959084Seric ** statp -- an exit status (out parameter). 164016911Seric ** 164116911Seric ** Returns: 164253751Seric ** mapped host name 164351315Seric ** FALSE otherwise. 164416911Seric ** 164516911Seric ** Side Effects: 164660089Seric ** Looks up the host specified in name. If it is not 164716911Seric ** the canonical name for that host, replace it with 164816911Seric ** the canonical name. If the name is unknown, or it 164916911Seric ** is already the canonical name, leave it unchanged. 165016911Seric */ 165110758Seric 165216911Seric /*ARGSUSED*/ 165353751Seric char * 165460089Seric host_map_lookup(map, name, avp, statp) 165556823Seric MAP *map; 165660089Seric char *name; 165753751Seric char **avp; 165859084Seric char *statp; 165916911Seric { 166059084Seric register struct hostent *hp; 166159084Seric 166268693Seric hp = sm_gethostbyname(name); 166359084Seric if (hp != NULL) 166459084Seric return hp->h_name; 166559084Seric *statp = EX_NOHOST; 166653751Seric return NULL; 166716911Seric } 166816911Seric 166956795Seric #endif /* DAEMON */ 1670