122700Sdist /* 234920Sbostic * Copyright (c) 1983 Eric P. Allman 362522Sbostic * Copyright (c) 1988, 1993 462522Sbostic * The Regents of the University of California. All rights reserved. 533780Sbostic * 642825Sbostic * %sccs.include.redist.c% 733780Sbostic */ 822700Sdist 933932Sbostic #include <errno.h> 1040962Sbostic #include "sendmail.h" 114535Seric 1233780Sbostic #ifndef lint 1333780Sbostic #ifdef DAEMON 14*67468Seric static char sccsid[] = "@(#)daemon.c 8.57 (Berkeley) 07/02/94 (with daemon mode)"; 1533780Sbostic #else 16*67468Seric static char sccsid[] = "@(#)daemon.c 8.57 (Berkeley) 07/02/94 (without daemon mode)"; 1733780Sbostic #endif 1833780Sbostic #endif /* not lint */ 194535Seric 2033780Sbostic #ifdef DAEMON 2133780Sbostic 2223120Seric # include <netdb.h> 2364338Seric # include <arpa/inet.h> 245978Seric 2566334Seric #if NAMED_BIND 2659042Seric # include <resolv.h> 2759042Seric #endif 2859042Seric 294535Seric /* 304535Seric ** DAEMON.C -- routines to use when running as a daemon. 317556Seric ** 327556Seric ** This entire file is highly dependent on the 4.2 BSD 337556Seric ** interprocess communication primitives. No attempt has 347556Seric ** been made to make this file portable to Version 7, 357556Seric ** Version 6, MPX files, etc. If you should try such a 367556Seric ** thing yourself, I recommend chucking the entire file 377556Seric ** and starting from scratch. Basic semantics are: 387556Seric ** 397556Seric ** getrequests() 407556Seric ** Opens a port and initiates a connection. 417556Seric ** Returns in a child. Must set InChannel and 427556Seric ** OutChannel appropriately. 4310206Seric ** clrdaemon() 4410206Seric ** Close any open files associated with getting 4510206Seric ** the connection; this is used when running the queue, 4610206Seric ** etc., to avoid having extra file descriptors during 4710206Seric ** the queue run and to avoid confusing the network 4810206Seric ** code (if it cares). 4952106Seric ** makeconnection(host, port, outfile, infile, usesecureport) 507556Seric ** Make a connection to the named host on the given 517556Seric ** port. Set *outfile and *infile to the files 527556Seric ** appropriate for communication. Returns zero on 537556Seric ** success, else an exit status describing the 547556Seric ** error. 5560089Seric ** host_map_lookup(map, hbuf, avp, pstat) 5656823Seric ** Convert the entry in hbuf into a canonical form. 574535Seric */ 584535Seric /* 594535Seric ** GETREQUESTS -- open mail IPC port and get requests. 604535Seric ** 614535Seric ** Parameters: 624535Seric ** none. 634535Seric ** 644535Seric ** Returns: 654535Seric ** none. 664535Seric ** 674535Seric ** Side Effects: 684535Seric ** Waits until some interesting activity occurs. When 694535Seric ** it does, a child is created to process it, and the 704535Seric ** parent waits for completion. Return from this 719886Seric ** routine is always in the child. The file pointers 729886Seric ** "InChannel" and "OutChannel" should be set to point 739886Seric ** to the communication channel. 744535Seric */ 754535Seric 7658849Seric int DaemonSocket = -1; /* fd describing socket */ 7758849Seric SOCKADDR DaemonAddr; /* socket for incoming */ 7859783Seric int ListenQueueSize = 10; /* size of listen queue */ 7964381Seric int TcpRcvBufferSize = 0; /* size of TCP receive buffer */ 8064381Seric int TcpSndBufferSize = 0; /* size of TCP send buffer */ 8116144Seric 824535Seric getrequests() 834535Seric { 849610Seric int t; 8553751Seric bool refusingconnections = TRUE; 8658419Seric FILE *pidf; 8764828Seric int socksize; 8866793Seric #ifdef XDEBUG 8966793Seric bool j_has_dot; 9066793Seric #endif 9146928Sbostic extern void reapchild(); 927117Seric 939610Seric /* 949610Seric ** Set up the address for the mailer. 959610Seric */ 969610Seric 9758849Seric if (DaemonAddr.sin.sin_family == 0) 9858849Seric DaemonAddr.sin.sin_family = AF_INET; 9958849Seric if (DaemonAddr.sin.sin_addr.s_addr == 0) 10058849Seric DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY; 10158849Seric if (DaemonAddr.sin.sin_port == 0) 1029610Seric { 10365169Seric register struct servent *sp; 10465169Seric 10558849Seric sp = getservbyname("smtp", "tcp"); 10658849Seric if (sp == NULL) 10758849Seric { 10858909Seric syserr("554 service \"smtp\" unknown"); 10965169Seric DaemonAddr.sin.sin_port = htons(25); 11058849Seric } 11165169Seric else 11265169Seric DaemonAddr.sin.sin_port = sp->s_port; 1139610Seric } 1149610Seric 1159610Seric /* 1169610Seric ** Try to actually open the connection. 1179610Seric */ 1189610Seric 1199610Seric if (tTd(15, 1)) 12058849Seric printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port); 1219610Seric 1229610Seric /* get a socket for the SMTP connection */ 12366854Seric socksize = opendaemonsocket(TRUE); 12410347Seric 12564035Seric (void) setsignal(SIGCHLD, reapchild); 12624945Seric 12758419Seric /* write the pid to the log file for posterity */ 12858419Seric pidf = fopen(PidFile, "w"); 12958419Seric if (pidf != NULL) 13058419Seric { 13163863Seric extern char *CommandLineArgs; 13263863Seric 13363863Seric /* write the process id on line 1 */ 13458419Seric fprintf(pidf, "%d\n", getpid()); 13563863Seric 13663863Seric /* line 2 contains all command line flags */ 13763863Seric fprintf(pidf, "%s\n", CommandLineArgs); 13863863Seric 13963863Seric /* flush and close */ 14058419Seric fclose(pidf); 14158419Seric } 14258419Seric 14366793Seric #ifdef XDEBUG 14466793Seric { 14566812Seric char jbuf[MAXHOSTNAMELEN]; 14658419Seric 14766812Seric expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv); 14866812Seric j_has_dot = strchr(jbuf, '.') != NULL; 14966793Seric } 15066793Seric #endif 15166793Seric 1529610Seric if (tTd(15, 1)) 15310206Seric printf("getrequests: %d\n", DaemonSocket); 1549610Seric 1554631Seric for (;;) 1564631Seric { 15714875Seric register int pid; 15811147Seric auto int lotherend; 15953751Seric extern bool refuseconnections(); 16011147Seric 16114875Seric /* see if we are rejecting connections */ 16253751Seric CurrentLA = getla(); 16353751Seric if (refuseconnections()) 16436584Sbostic { 16566845Seric if (DaemonSocket >= 0) 16653751Seric { 16766845Seric /* close socket so peer will fail quickly */ 16866845Seric (void) close(DaemonSocket); 16966845Seric DaemonSocket = -1; 17053751Seric } 17166845Seric refusingconnections = TRUE; 17257385Seric setproctitle("rejecting connections: load average: %d", 17357385Seric CurrentLA); 17466845Seric sleep(15); 17553751Seric continue; 17636584Sbostic } 17714875Seric 17853751Seric if (refusingconnections) 17953751Seric { 18053751Seric /* start listening again */ 18166854Seric (void) opendaemonsocket(FALSE); 18253751Seric setproctitle("accepting connections"); 18353751Seric refusingconnections = FALSE; 18453751Seric } 18553751Seric 18666793Seric #ifdef XDEBUG 18766793Seric /* check for disaster */ 18866793Seric { 18966793Seric register STAB *s; 19066812Seric char jbuf[MAXHOSTNAMELEN]; 19166793Seric 19266812Seric expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv); 19366812Seric if ((s = stab(jbuf, ST_CLASS, ST_FIND)) == NULL || 19466793Seric !bitnset('w', s->s_class)) 19566793Seric { 19666793Seric dumpstate("daemon lost $j"); 19766793Seric syslog(LOG_ALERT, "daemon process doesn't have $j in $=w; see syslog"); 19866793Seric abort(); 19966793Seric } 20066812Seric else if (j_has_dot && strchr(jbuf, '.') == NULL) 20166793Seric { 20266793Seric dumpstate("daemon $j lost dot"); 20366793Seric syslog(LOG_ALERT, "daemon process $j lost dot; see syslog"); 20466793Seric abort(); 20566793Seric } 20666793Seric } 20766793Seric #endif 20866793Seric 2099610Seric /* wait for a connection */ 2109610Seric do 2119610Seric { 2129610Seric errno = 0; 21364828Seric lotherend = socksize; 21446928Sbostic t = accept(DaemonSocket, 21546928Sbostic (struct sockaddr *)&RealHostAddr, &lotherend); 2169610Seric } while (t < 0 && errno == EINTR); 2179610Seric if (t < 0) 2185978Seric { 2199610Seric syserr("getrequests: accept"); 2209610Seric sleep(5); 2219610Seric continue; 2225978Seric } 2234631Seric 2245978Seric /* 2255978Seric ** Create a subprocess to process the mail. 2265978Seric */ 2275978Seric 2287677Seric if (tTd(15, 2)) 2299610Seric printf("getrequests: forking (fd = %d)\n", t); 2305978Seric 2314636Seric pid = fork(); 2324636Seric if (pid < 0) 2334631Seric { 2344636Seric syserr("daemon: cannot fork"); 2354636Seric sleep(10); 2369610Seric (void) close(t); 2374636Seric continue; 2384631Seric } 2394631Seric 2404636Seric if (pid == 0) 2414631Seric { 24264086Seric char *p; 24358951Seric extern char *hostnamebyanyaddr(); 24411147Seric 2454636Seric /* 2464636Seric ** CHILD -- return to caller. 24711147Seric ** Collect verified idea of sending host. 2484636Seric ** Verify calling user id if possible here. 2494636Seric */ 2504631Seric 25164035Seric (void) setsignal(SIGCHLD, SIG_DFL); 25267171Seric (void) close(DaemonSocket); 25366017Seric DisConnected = FALSE; 25424950Seric 25566032Seric setproctitle("startup with %s", 25666032Seric anynet_ntoa(&RealHostAddr)); 25766032Seric 25811147Seric /* determine host name */ 25964086Seric p = hostnamebyanyaddr(&RealHostAddr); 26064086Seric RealHostName = newstr(p); 26166032Seric setproctitle("startup with %s", p); 26258778Seric 26355173Seric #ifdef LOG 26463842Seric if (LogLevel > 11) 26555173Seric { 26655173Seric /* log connection information */ 26755173Seric syslog(LOG_INFO, "connect from %s (%s)", 26858951Seric RealHostName, anynet_ntoa(&RealHostAddr)); 26955173Seric } 27055173Seric #endif 27155173Seric 27264724Seric if ((InChannel = fdopen(t, "r")) == NULL || 27364724Seric (t = dup(t)) < 0 || 27464724Seric (OutChannel = fdopen(t, "w")) == NULL) 27564724Seric { 27664724Seric syserr("cannot open SMTP server channel, fd=%d", t); 27764724Seric exit(0); 27864724Seric } 27959254Seric 28016884Seric /* should we check for illegal connection here? XXX */ 28159156Seric #ifdef XLA 28259156Seric if (!xla_host_ok(RealHostName)) 28359156Seric { 28459254Seric message("421 Too many SMTP sessions for this host"); 28559156Seric exit(0); 28659156Seric } 28759156Seric #endif 28816884Seric 2897677Seric if (tTd(15, 2)) 2905978Seric printf("getreq: returning\n"); 2914636Seric return; 2924631Seric } 2934631Seric 2947117Seric /* close the port so that others will hang (for a while) */ 2959610Seric (void) close(t); 2964631Seric } 2979886Seric /*NOTREACHED*/ 2984631Seric } 2995978Seric /* 30066845Seric ** OPENDAEMONSOCKET -- open the SMTP socket 30166845Seric ** 30266845Seric ** Deals with setting all appropriate options. DaemonAddr must 30366845Seric ** be set up in advance. 30466845Seric ** 30566845Seric ** Parameters: 30666854Seric ** firsttime -- set if this is the initial open. 30766845Seric ** 30866845Seric ** Returns: 30966845Seric ** Size in bytes of the daemon socket addr. 31066845Seric ** 31166845Seric ** Side Effects: 31266845Seric ** Leaves DaemonSocket set to the open socket. 31366845Seric ** Exits if the socket cannot be created. 31466845Seric */ 31566845Seric 31666861Seric #define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 31766861Seric 31866845Seric int 31966854Seric opendaemonsocket(firsttime) 32066854Seric bool firsttime; 32166845Seric { 32266845Seric int on = 1; 32366845Seric int socksize; 32466861Seric int ntries = 0; 32566861Seric int saveerrno; 32666845Seric 32766845Seric if (tTd(15, 2)) 32866845Seric printf("opendaemonsocket()\n"); 32966845Seric 33066861Seric do 33166845Seric { 33266862Seric if (ntries > 0) 33366862Seric sleep(5); 33466861Seric if (firsttime || DaemonSocket < 0) 33566854Seric { 33666861Seric DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0); 33766861Seric if (DaemonSocket < 0) 33866861Seric { 33966861Seric /* probably another daemon already */ 34066861Seric saveerrno = errno; 34166861Seric syserr("opendaemonsocket: can't create server SMTP socket"); 34266861Seric severe: 34366845Seric # ifdef LOG 34466861Seric if (LogLevel > 0) 34566861Seric syslog(LOG_ALERT, "problem creating SMTP socket"); 34666845Seric # endif /* LOG */ 34766861Seric DaemonSocket = -1; 34866861Seric continue; 34966861Seric } 35066845Seric 35166861Seric /* turn on network debugging? */ 35266861Seric if (tTd(15, 101)) 35366861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 35466861Seric SO_DEBUG, (char *)&on, 35566861Seric sizeof on); 35666845Seric 35766861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 35866861Seric SO_REUSEADDR, (char *)&on, sizeof on); 35966861Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, 36066861Seric SO_KEEPALIVE, (char *)&on, sizeof on); 36166845Seric 36266845Seric #ifdef SO_RCVBUF 36366861Seric if (TcpRcvBufferSize > 0) 36466861Seric { 36566861Seric if (setsockopt(DaemonSocket, SOL_SOCKET, 36666861Seric SO_RCVBUF, 36766861Seric (char *) &TcpRcvBufferSize, 36866861Seric sizeof(TcpRcvBufferSize)) < 0) 36966861Seric syserr("getrequests: setsockopt(SO_RCVBUF)"); 37066861Seric } 37166845Seric #endif 37266845Seric 37366861Seric switch (DaemonAddr.sa.sa_family) 37466861Seric { 37566845Seric # ifdef NETINET 37666861Seric case AF_INET: 37766861Seric socksize = sizeof DaemonAddr.sin; 37866861Seric break; 37966845Seric # endif 38066845Seric 38166845Seric # ifdef NETISO 38266861Seric case AF_ISO: 38366861Seric socksize = sizeof DaemonAddr.siso; 38466861Seric break; 38566845Seric # endif 38666845Seric 38766861Seric default: 38866861Seric socksize = sizeof DaemonAddr; 38966861Seric break; 39066861Seric } 39166861Seric 39266861Seric if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0) 39366861Seric { 39466861Seric saveerrno = errno; 39566861Seric syserr("getrequests: cannot bind"); 39666861Seric (void) close(DaemonSocket); 39766861Seric goto severe; 39866861Seric } 39966854Seric } 40066861Seric if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0) 40166854Seric { 40266861Seric saveerrno = errno; 40366861Seric syserr("getrequests: cannot listen"); 40466854Seric (void) close(DaemonSocket); 40566854Seric goto severe; 40666854Seric } 40766861Seric return socksize; 40866861Seric } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno)); 40967448Seric syserr("!opendaemonsocket: server SMTP socket wedged: exiting"); 41066861Seric finis(); 41166845Seric } 41266845Seric /* 41310206Seric ** CLRDAEMON -- reset the daemon connection 41410206Seric ** 41510206Seric ** Parameters: 41610206Seric ** none. 41710206Seric ** 41810206Seric ** Returns: 41910206Seric ** none. 42010206Seric ** 42110206Seric ** Side Effects: 42210206Seric ** releases any resources used by the passive daemon. 42310206Seric */ 42410206Seric 42510206Seric clrdaemon() 42610206Seric { 42710206Seric if (DaemonSocket >= 0) 42810206Seric (void) close(DaemonSocket); 42910206Seric DaemonSocket = -1; 43010206Seric } 43110206Seric /* 43258849Seric ** SETDAEMONOPTIONS -- set options for running the daemon 43358849Seric ** 43458849Seric ** Parameters: 43558849Seric ** p -- the options line. 43658849Seric ** 43758849Seric ** Returns: 43858849Seric ** none. 43958849Seric */ 44058849Seric 44158849Seric setdaemonoptions(p) 44258849Seric register char *p; 44358849Seric { 44458873Seric if (DaemonAddr.sa.sa_family == AF_UNSPEC) 44558873Seric DaemonAddr.sa.sa_family = AF_INET; 44658873Seric 44758849Seric while (p != NULL) 44858849Seric { 44958849Seric register char *f; 45058849Seric register char *v; 45158849Seric 45258849Seric while (isascii(*p) && isspace(*p)) 45358849Seric p++; 45458849Seric if (*p == '\0') 45558849Seric break; 45658849Seric f = p; 45758849Seric p = strchr(p, ','); 45858849Seric if (p != NULL) 45958849Seric *p++ = '\0'; 46058849Seric v = strchr(f, '='); 46158849Seric if (v == NULL) 46258849Seric continue; 46358849Seric while (isascii(*++v) && isspace(*v)) 46458849Seric continue; 46558849Seric 46658849Seric switch (*f) 46758849Seric { 46858873Seric case 'F': /* address family */ 46958849Seric if (isascii(*v) && isdigit(*v)) 47058873Seric DaemonAddr.sa.sa_family = atoi(v); 47158873Seric #ifdef NETINET 47258873Seric else if (strcasecmp(v, "inet") == 0) 47358873Seric DaemonAddr.sa.sa_family = AF_INET; 47458873Seric #endif 47558873Seric #ifdef NETISO 47658873Seric else if (strcasecmp(v, "iso") == 0) 47758873Seric DaemonAddr.sa.sa_family = AF_ISO; 47858873Seric #endif 47958873Seric #ifdef NETNS 48058873Seric else if (strcasecmp(v, "ns") == 0) 48158873Seric DaemonAddr.sa.sa_family = AF_NS; 48258873Seric #endif 48358873Seric #ifdef NETX25 48458873Seric else if (strcasecmp(v, "x.25") == 0) 48558873Seric DaemonAddr.sa.sa_family = AF_CCITT; 48658873Seric #endif 48758849Seric else 48858873Seric syserr("554 Unknown address family %s in Family=option", v); 48958873Seric break; 49058873Seric 49158873Seric case 'A': /* address */ 49258873Seric switch (DaemonAddr.sa.sa_family) 49358849Seric { 49458873Seric #ifdef NETINET 49558873Seric case AF_INET: 49658873Seric if (isascii(*v) && isdigit(*v)) 49758873Seric DaemonAddr.sin.sin_addr.s_addr = inet_network(v); 49858873Seric else 49958873Seric { 50058873Seric register struct netent *np; 50158849Seric 50258873Seric np = getnetbyname(v); 50358873Seric if (np == NULL) 50458873Seric syserr("554 network \"%s\" unknown", v); 50558873Seric else 50658873Seric DaemonAddr.sin.sin_addr.s_addr = np->n_net; 50758873Seric } 50858873Seric break; 50958873Seric #endif 51058873Seric 51158873Seric default: 51258873Seric syserr("554 Address= option unsupported for family %d", 51358873Seric DaemonAddr.sa.sa_family); 51458873Seric break; 51558849Seric } 51658849Seric break; 51758849Seric 51858873Seric case 'P': /* port */ 51958873Seric switch (DaemonAddr.sa.sa_family) 52058849Seric { 52158873Seric short port; 52258849Seric 52358873Seric #ifdef NETINET 52458873Seric case AF_INET: 52558873Seric if (isascii(*v) && isdigit(*v)) 52664366Seric DaemonAddr.sin.sin_port = htons(atoi(v)); 52758849Seric else 52858873Seric { 52958873Seric register struct servent *sp; 53058873Seric 53158873Seric sp = getservbyname(v, "tcp"); 53258873Seric if (sp == NULL) 53358909Seric syserr("554 service \"%s\" unknown", v); 53458873Seric else 53558873Seric DaemonAddr.sin.sin_port = sp->s_port; 53658873Seric } 53758873Seric break; 53858873Seric #endif 53958873Seric 54058873Seric #ifdef NETISO 54158873Seric case AF_ISO: 54258873Seric /* assume two byte transport selector */ 54358873Seric if (isascii(*v) && isdigit(*v)) 54464366Seric port = htons(atoi(v)); 54558873Seric else 54658873Seric { 54758873Seric register struct servent *sp; 54858873Seric 54958873Seric sp = getservbyname(v, "tcp"); 55058873Seric if (sp == NULL) 55158909Seric syserr("554 service \"%s\" unknown", v); 55258873Seric else 55358873Seric port = sp->s_port; 55458873Seric } 55558873Seric bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 55658873Seric break; 55758873Seric #endif 55858873Seric 55958873Seric default: 56058873Seric syserr("554 Port= option unsupported for family %d", 56158873Seric DaemonAddr.sa.sa_family); 56258873Seric break; 56358849Seric } 56458849Seric break; 56559783Seric 56659783Seric case 'L': /* listen queue size */ 56759783Seric ListenQueueSize = atoi(v); 56859783Seric break; 56964381Seric 57064381Seric case 'S': /* send buffer size */ 57164381Seric TcpSndBufferSize = atoi(v); 57264381Seric break; 57364381Seric 57464381Seric case 'R': /* receive buffer size */ 57564381Seric TcpRcvBufferSize = atoi(v); 57664381Seric break; 57758849Seric } 57858849Seric } 57958849Seric } 58058849Seric /* 5816039Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 5826039Seric ** 5836039Seric ** Parameters: 5846039Seric ** host -- the name of the host. 5856633Seric ** port -- the port number to connect to. 58653739Seric ** mci -- a pointer to the mail connection information 58753739Seric ** structure to be filled in. 58852106Seric ** usesecureport -- if set, use a low numbered (reserved) 58952106Seric ** port to provide some rudimentary authentication. 5906039Seric ** 5916039Seric ** Returns: 5926039Seric ** An exit code telling whether the connection could be 5936039Seric ** made and if not why not. 5946039Seric ** 5956039Seric ** Side Effects: 5966039Seric ** none. 5976039Seric */ 5985978Seric 59958755Seric SOCKADDR CurHostAddr; /* address of current host */ 60058305Seric 60154967Seric int 60253739Seric makeconnection(host, port, mci, usesecureport) 6036039Seric char *host; 6047286Seric u_short port; 60554967Seric register MCI *mci; 60652106Seric bool usesecureport; 6076039Seric { 60829430Sbloom register int i, s; 60929430Sbloom register struct hostent *hp = (struct hostent *)NULL; 61058755Seric SOCKADDR addr; 61152106Seric int sav_errno; 61258755Seric int addrlen; 61366334Seric #if NAMED_BIND 61435651Seric extern int h_errno; 61535651Seric #endif 6166039Seric 6176039Seric /* 6186039Seric ** Set up the address for the mailer. 6199308Seric ** Accept "[a.b.c.d]" syntax for host name. 6206039Seric */ 6216039Seric 62266334Seric #if NAMED_BIND 62325475Smiriam h_errno = 0; 62435651Seric #endif 62525475Smiriam errno = 0; 62658864Seric bzero(&CurHostAddr, sizeof CurHostAddr); 62764334Seric SmtpPhase = mci->mci_phase = "initial connection"; 62858906Seric CurHostName = host; 62925475Smiriam 6309308Seric if (host[0] == '[') 6319308Seric { 63211147Seric long hid; 63356795Seric register char *p = strchr(host, ']'); 6349308Seric 63511147Seric if (p != NULL) 6369308Seric { 63711147Seric *p = '\0'; 63859884Seric #ifdef NETINET 63911147Seric hid = inet_addr(&host[1]); 64058360Seric if (hid == -1) 64159884Seric #endif 64258360Seric { 64358360Seric /* try it as a host name (avoid MX lookup) */ 64458360Seric hp = gethostbyname(&host[1]); 64566349Seric if (hp == NULL && p[-1] == '.') 64666349Seric { 64767265Seric #ifdef NAMED_BIND 64867265Seric int oldopts = _res.options; 64967265Seric 65067265Seric _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 65167265Seric #endif 65266349Seric p[-1] = '\0'; 65366349Seric hp = gethostbyname(&host[1]); 65466349Seric p[-1] = '.'; 65567265Seric #ifdef NAMED_BIND 65667265Seric _res.options = oldopts; 65767265Seric #endif 65866349Seric } 65958360Seric *p = ']'; 66058360Seric goto gothostent; 66158360Seric } 66211147Seric *p = ']'; 6639308Seric } 66458360Seric if (p == NULL) 6659308Seric { 66658151Seric usrerr("553 Invalid numeric domain spec \"%s\"", host); 6679308Seric return (EX_NOHOST); 6689308Seric } 66959884Seric #ifdef NETINET 67059884Seric addr.sin.sin_family = AF_INET; /*XXX*/ 67158778Seric addr.sin.sin_addr.s_addr = hid; 67259884Seric #endif 6739308Seric } 6749610Seric else 6759610Seric { 67666349Seric register char *p = &host[strlen(host) - 1]; 67766349Seric 67829430Sbloom hp = gethostbyname(host); 67966349Seric if (hp == NULL && *p == '.') 68066349Seric { 68167265Seric #ifdef NAMED_BIND 68267265Seric int oldopts = _res.options; 68367265Seric 68467265Seric _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 68567265Seric #endif 68666349Seric *p = '\0'; 68766349Seric hp = gethostbyname(host); 68866349Seric *p = '.'; 68967265Seric #ifdef NAMED_BIND 69067265Seric _res.options = oldopts; 69167265Seric #endif 69266349Seric } 69358360Seric gothostent: 69425475Smiriam if (hp == NULL) 69524945Seric { 69666334Seric #if NAMED_BIND 69725475Smiriam if (errno == ETIMEDOUT || h_errno == TRY_AGAIN) 69825475Smiriam return (EX_TEMPFAIL); 69925657Seric 70035651Seric /* if name server is specified, assume temp fail */ 70135651Seric if (errno == ECONNREFUSED && UseNameServer) 70235651Seric return (EX_TEMPFAIL); 70335651Seric #endif 70425475Smiriam return (EX_NOHOST); 70524945Seric } 70658778Seric addr.sa.sa_family = hp->h_addrtype; 70758778Seric switch (hp->h_addrtype) 70858778Seric { 70958778Seric #ifdef NETINET 71058778Seric case AF_INET: 71158755Seric bcopy(hp->h_addr, 71258778Seric &addr.sin.sin_addr, 71367421Seric INADDRSZ); 71458778Seric break; 71558778Seric #endif 71658778Seric 71758778Seric default: 71858755Seric bcopy(hp->h_addr, 71958778Seric addr.sa.sa_data, 72058755Seric hp->h_length); 72158778Seric break; 72258778Seric } 72329430Sbloom i = 1; 7249610Seric } 7259610Seric 7269610Seric /* 7279610Seric ** Determine the port number. 7289610Seric */ 7299610Seric 73010011Seric if (port != 0) 73158755Seric port = htons(port); 73210011Seric else 7339610Seric { 7349610Seric register struct servent *sp = getservbyname("smtp", "tcp"); 7359610Seric 7369610Seric if (sp == NULL) 7379610Seric { 73858909Seric syserr("554 makeconnection: service \"smtp\" unknown"); 73965169Seric port = htons(25); 7409610Seric } 74165169Seric else 74265169Seric port = sp->s_port; 7439610Seric } 7446039Seric 74558778Seric switch (addr.sa.sa_family) 74658755Seric { 74759884Seric #ifdef NETINET 74858755Seric case AF_INET: 74958778Seric addr.sin.sin_port = port; 75058755Seric addrlen = sizeof (struct sockaddr_in); 75158755Seric break; 75259884Seric #endif 75358755Seric 75458755Seric #ifdef NETISO 75558755Seric case AF_ISO: 75658755Seric /* assume two byte transport selector */ 75758755Seric bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 75858755Seric addrlen = sizeof (struct sockaddr_iso); 75958755Seric break; 76058755Seric #endif 76158755Seric 76258755Seric default: 76358778Seric syserr("Can't connect to address family %d", addr.sa.sa_family); 76458755Seric return (EX_NOHOST); 76558755Seric } 76658755Seric 7676039Seric /* 7686039Seric ** Try to actually open the connection. 7696039Seric */ 7706039Seric 77159156Seric #ifdef XLA 77259156Seric /* if too many connections, don't bother trying */ 77359156Seric if (!xla_noqueue_ok(host)) 77459156Seric return EX_TEMPFAIL; 77559156Seric #endif 77659156Seric 77757736Seric for (;;) 77852106Seric { 77957736Seric if (tTd(16, 1)) 78058755Seric printf("makeconnection (%s [%s])\n", 78158755Seric host, anynet_ntoa(&addr)); 78252106Seric 78358588Seric /* save for logging */ 78458588Seric CurHostAddr = addr; 78558588Seric 78657736Seric if (usesecureport) 78757736Seric { 78857736Seric int rport = IPPORT_RESERVED - 1; 7896039Seric 79057736Seric s = rresvport(&rport); 79157736Seric } 79257736Seric else 79357736Seric { 79457736Seric s = socket(AF_INET, SOCK_STREAM, 0); 79557736Seric } 79657736Seric if (s < 0) 79757736Seric { 79857736Seric sav_errno = errno; 79957736Seric syserr("makeconnection: no socket"); 80057736Seric goto failure; 80157736Seric } 80210347Seric 80364381Seric #ifdef SO_SNDBUF 80464381Seric if (TcpSndBufferSize > 0) 80564381Seric { 80664381Seric if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 80764561Seric (char *) &TcpSndBufferSize, 80864381Seric sizeof(TcpSndBufferSize)) < 0) 80964381Seric syserr("makeconnection: setsockopt(SO_SNDBUF)"); 81064381Seric } 81164381Seric #endif 81264381Seric 81357736Seric if (tTd(16, 1)) 81457736Seric printf("makeconnection: fd=%d\n", s); 81557736Seric 81657736Seric /* turn on network debugging? */ 81757736Seric if (tTd(16, 101)) 81857736Seric { 81957736Seric int on = 1; 82066861Seric (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 82157736Seric (char *)&on, sizeof on); 82257736Seric } 82357736Seric if (CurEnv->e_xfp != NULL) 82457736Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 82557736Seric errno = 0; /* for debugging */ 82658755Seric if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 82757736Seric break; 82857736Seric 82957736Seric /* couldn't connect.... figure out why */ 83027744Sbloom sav_errno = errno; 83127744Sbloom (void) close(s); 83229430Sbloom if (hp && hp->h_addr_list[i]) 83329430Sbloom { 83457736Seric if (tTd(16, 1)) 83558755Seric printf("Connect failed (%s); trying new address....\n", 83658755Seric errstring(sav_errno)); 83758778Seric switch (addr.sa.sa_family) 83858778Seric { 83958778Seric #ifdef NETINET 84058778Seric case AF_INET: 84158755Seric bcopy(hp->h_addr_list[i++], 84258778Seric &addr.sin.sin_addr, 84367421Seric INADDRSZ); 84458778Seric break; 84558778Seric #endif 84658778Seric 84758778Seric default: 84858755Seric bcopy(hp->h_addr_list[i++], 84958778Seric addr.sa.sa_data, 85052106Seric hp->h_length); 85158778Seric break; 85258778Seric } 85357736Seric continue; 85429430Sbloom } 85529430Sbloom 8566039Seric /* failure, decide if temporary or not */ 8576039Seric failure: 85859254Seric #ifdef XLA 85959254Seric xla_host_end(host); 86059254Seric #endif 86158542Seric if (transienterror(sav_errno)) 86258542Seric return EX_TEMPFAIL; 86358542Seric else 86458542Seric { 86558542Seric message("%s", errstring(sav_errno)); 86658542Seric return (EX_UNAVAILABLE); 8676039Seric } 8686039Seric } 8696039Seric 8706039Seric /* connection ok, put it into canonical form */ 87164724Seric if ((mci->mci_out = fdopen(s, "w")) == NULL || 87264724Seric (s = dup(s)) < 0 || 87364725Seric (mci->mci_in = fdopen(s, "r")) == NULL) 87464724Seric { 87564724Seric syserr("cannot open SMTP client channel, fd=%d", s); 87664724Seric return EX_TEMPFAIL; 87764724Seric } 8786039Seric 87910098Seric return (EX_OK); 8806039Seric } 88110758Seric /* 88210758Seric ** MYHOSTNAME -- return the name of this host. 88310758Seric ** 88410758Seric ** Parameters: 88510758Seric ** hostbuf -- a place to return the name of this host. 88612313Seric ** size -- the size of hostbuf. 88710758Seric ** 88810758Seric ** Returns: 88910758Seric ** A list of aliases for this host. 89010758Seric ** 89110758Seric ** Side Effects: 89264338Seric ** Adds numeric codes to $=w. 89310758Seric */ 8946039Seric 89567140Seric struct hostent * 89612313Seric myhostname(hostbuf, size) 89710758Seric char hostbuf[]; 89812313Seric int size; 89910758Seric { 90058110Seric register struct hostent *hp; 90110758Seric extern struct hostent *gethostbyname(); 90267448Seric extern bool getcanonname(); 90367448Seric extern int h_errno; 90410758Seric 90523120Seric if (gethostname(hostbuf, size) < 0) 90623120Seric { 90723120Seric (void) strcpy(hostbuf, "localhost"); 90823120Seric } 90911147Seric hp = gethostbyname(hostbuf); 91066853Seric if (hp == NULL) 91116877Seric { 91266853Seric syserr("!My host name (%s) does not seem to exist!", hostbuf); 91366853Seric } 91467448Seric if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 91567448Seric { 91667448Seric (void) strncpy(hostbuf, hp->h_name, size - 1); 91767448Seric hostbuf[size - 1] = '\0'; 91867448Seric } 91966853Seric 92066853Seric #if NAMED_BIND 92167448Seric /* 92267448Seric ** If still no dot, try DNS directly (i.e., avoid NIS problems). 92367448Seric ** This ought to be driven from the configuration file, but 92467448Seric ** we are called before the configuration is read. We could 92567448Seric ** check for an /etc/resolv.conf file, but that isn't required. 92667448Seric ** All in all, a bit of a mess. 92767448Seric */ 92867448Seric 92967448Seric if (strchr(hostbuf, '.') == NULL && 93067448Seric !getcanonname(hostbuf, size, TRUE) && 93167448Seric h_errno == TRY_AGAIN) 93266853Seric { 93367448Seric struct stat stbuf; 93466853Seric 93566853Seric /* try twice in case name server not yet started up */ 93667448Seric message("My unqualifed host name (%s) unknown to DNS; sleeping for retry", 93767448Seric hostbuf); 93867448Seric sleep(60); 93967448Seric if (!getcanonname(hostbuf, size, TRUE)) 94066853Seric errno = h_errno + E_DNSBASE; 94166853Seric } 94266777Seric #endif 94367140Seric return (hp); 94410758Seric } 94551315Seric /* 94658951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 94758308Seric ** 94858951Seric ** Uses RFC1413 protocol to try to get info from the other end. 94958951Seric ** 95058308Seric ** Parameters: 95158308Seric ** fd -- the descriptor 95258308Seric ** 95358308Seric ** Returns: 95458951Seric ** The user@host information associated with this descriptor. 95558308Seric */ 95658308Seric 95764927Seric #if IDENTPROTO 95858951Seric 95958951Seric static jmp_buf CtxAuthTimeout; 96058951Seric 96158951Seric static 96258951Seric authtimeout() 96358951Seric { 96458951Seric longjmp(CtxAuthTimeout, 1); 96558951Seric } 96658951Seric 96758951Seric #endif 96858951Seric 96958308Seric char * 97058951Seric getauthinfo(fd) 97158308Seric int fd; 97258308Seric { 97358951Seric int falen; 97459104Seric register char *p; 97564927Seric #if IDENTPROTO 97658951Seric SOCKADDR la; 97758951Seric int lalen; 97858951Seric register struct servent *sp; 97958951Seric int s; 98058951Seric int i; 98158951Seric EVENT *ev; 98258951Seric #endif 98358951Seric static char hbuf[MAXNAME * 2 + 2]; 98458951Seric extern char *hostnamebyanyaddr(); 98558951Seric extern char RealUserName[]; /* main.c */ 98658308Seric 98766761Seric falen = sizeof RealHostAddr; 988*67468Seric if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 || 989*67468Seric falen <= 0 || RealHostAddr.sa.sa_family == 0) 99058951Seric { 99158951Seric (void) sprintf(hbuf, "%s@localhost", RealUserName); 99258957Seric if (tTd(9, 1)) 99358951Seric printf("getauthinfo: %s\n", hbuf); 99458951Seric return hbuf; 99558951Seric } 99658951Seric 99766761Seric if (RealHostName == NULL) 99866761Seric { 99966761Seric /* translate that to a host name */ 100066761Seric RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 100166761Seric } 100266761Seric 100364927Seric #if IDENTPROTO 100465831Seric if (TimeOuts.to_ident == 0) 100565831Seric goto noident; 100665831Seric 100758951Seric lalen = sizeof la; 100866761Seric if (RealHostAddr.sa.sa_family != AF_INET || 100958951Seric getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 101058951Seric la.sa.sa_family != AF_INET) 101158951Seric { 101258951Seric /* no ident info */ 101358951Seric goto noident; 101458951Seric } 101558951Seric 101658951Seric /* create ident query */ 101760489Seric (void) sprintf(hbuf, "%d,%d\r\n", 101866761Seric ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port)); 101958951Seric 102058951Seric /* create local address */ 102164747Seric la.sin.sin_port = 0; 102258951Seric 102358951Seric /* create foreign address */ 102458951Seric sp = getservbyname("auth", "tcp"); 102558951Seric if (sp != NULL) 102666761Seric RealHostAddr.sin.sin_port = sp->s_port; 102758308Seric else 102866761Seric RealHostAddr.sin.sin_port = htons(113); 102958951Seric 103058951Seric s = -1; 103158951Seric if (setjmp(CtxAuthTimeout) != 0) 103258951Seric { 103358951Seric if (s >= 0) 103458951Seric (void) close(s); 103558951Seric goto noident; 103658951Seric } 103758951Seric 103858951Seric /* put a timeout around the whole thing */ 103964255Seric ev = setevent(TimeOuts.to_ident, authtimeout, 0); 104058951Seric 104164747Seric /* connect to foreign IDENT server using same address as SMTP socket */ 104258951Seric s = socket(AF_INET, SOCK_STREAM, 0); 104358951Seric if (s < 0) 104458951Seric { 104558951Seric clrevent(ev); 104658951Seric goto noident; 104758951Seric } 104864747Seric if (bind(s, &la.sa, sizeof la.sin) < 0 || 104966761Seric connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0) 105058951Seric { 105166011Seric goto closeident; 105258951Seric } 105358951Seric 105458957Seric if (tTd(9, 10)) 105558951Seric printf("getauthinfo: sent %s", hbuf); 105658951Seric 105758951Seric /* send query */ 105858951Seric if (write(s, hbuf, strlen(hbuf)) < 0) 105958951Seric goto closeident; 106058951Seric 106158951Seric /* get result */ 106258951Seric i = read(s, hbuf, sizeof hbuf); 106358951Seric (void) close(s); 106458951Seric clrevent(ev); 106558951Seric if (i <= 0) 106658951Seric goto noident; 106758951Seric if (hbuf[--i] == '\n' && hbuf[--i] == '\r') 106858951Seric i--; 106958951Seric hbuf[++i] = '\0'; 107058951Seric 107158957Seric if (tTd(9, 3)) 107258951Seric printf("getauthinfo: got %s\n", hbuf); 107358951Seric 107458951Seric /* parse result */ 107558951Seric p = strchr(hbuf, ':'); 107658951Seric if (p == NULL) 107758951Seric { 107858951Seric /* malformed response */ 107958951Seric goto noident; 108058951Seric } 108158951Seric while (isascii(*++p) && isspace(*p)) 108258951Seric continue; 108358951Seric if (strncasecmp(p, "userid", 6) != 0) 108458951Seric { 108558951Seric /* presumably an error string */ 108658951Seric goto noident; 108758951Seric } 108858951Seric p += 6; 108958951Seric while (isascii(*p) && isspace(*p)) 109058951Seric p++; 109158951Seric if (*p++ != ':') 109258951Seric { 109358951Seric /* either useridxx or malformed response */ 109458951Seric goto noident; 109558951Seric } 109658951Seric 109758951Seric /* p now points to the OSTYPE field */ 109858951Seric p = strchr(p, ':'); 109958951Seric if (p == NULL) 110058951Seric { 110158951Seric /* malformed response */ 110258951Seric goto noident; 110358951Seric } 110458951Seric 110558957Seric /* 1413 says don't do this -- but it's broken otherwise */ 110658957Seric while (isascii(*++p) && isspace(*p)) 110758957Seric continue; 110858957Seric 110958951Seric /* p now points to the authenticated name */ 111066003Seric (void) sprintf(hbuf, "%s@%s", 111166003Seric p, RealHostName == NULL ? "localhost" : RealHostName); 111258957Seric goto finish; 111358957Seric 111466011Seric closeident: 111566011Seric (void) close(s); 111666011Seric clrevent(ev); 111766011Seric 111858957Seric #endif /* IDENTPROTO */ 111958957Seric 112058957Seric noident: 112166003Seric if (RealHostName == NULL) 112266003Seric { 112366003Seric if (tTd(9, 1)) 112466003Seric printf("getauthinfo: NULL\n"); 112566003Seric return NULL; 112666003Seric } 112758957Seric (void) strcpy(hbuf, RealHostName); 112858957Seric 112958957Seric finish: 113066003Seric if (RealHostName != NULL && RealHostName[0] != '[') 113158951Seric { 113258951Seric p = &hbuf[strlen(hbuf)]; 113358951Seric (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 113458951Seric } 113558957Seric if (tTd(9, 1)) 113658951Seric printf("getauthinfo: %s\n", hbuf); 113758308Seric return hbuf; 113858308Seric } 113958308Seric /* 114060089Seric ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 114153751Seric ** 114253751Seric ** Parameters: 114356823Seric ** map -- a pointer to this map (unused). 114460089Seric ** name -- the (presumably unqualified) hostname. 114560257Seric ** av -- unused -- for compatibility with other mapping 114655019Seric ** functions. 114759084Seric ** statp -- an exit status (out parameter) -- set to 114859084Seric ** EX_TEMPFAIL if the name server is unavailable. 114953751Seric ** 115053751Seric ** Returns: 115153751Seric ** The mapping, if found. 115253751Seric ** NULL if no mapping found. 115353751Seric ** 115453751Seric ** Side Effects: 115553751Seric ** Looks up the host specified in hbuf. If it is not 115653751Seric ** the canonical name for that host, return the canonical 115753751Seric ** name. 115853751Seric */ 115951315Seric 116053751Seric char * 116160257Seric host_map_lookup(map, name, av, statp) 116256823Seric MAP *map; 116360089Seric char *name; 116460257Seric char **av; 116559084Seric int *statp; 116616911Seric { 116716911Seric register struct hostent *hp; 116867419Seric struct in_addr in_addr; 116956823Seric char *cp; 117058110Seric int i; 117159671Seric register STAB *s; 117260257Seric char hbuf[MAXNAME]; 117359671Seric extern struct hostent *gethostbyaddr(); 117466334Seric #if NAMED_BIND 117559671Seric extern int h_errno; 117666029Seric #endif 117716911Seric 117825574Smiriam /* 117959671Seric ** See if we have already looked up this name. If so, just 118059671Seric ** return it. 118159671Seric */ 118253751Seric 118360089Seric s = stab(name, ST_NAMECANON, ST_ENTER); 118459671Seric if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 118559671Seric { 118659986Seric if (tTd(9, 1)) 118760089Seric printf("host_map_lookup(%s) => CACHE %s\n", 118860089Seric name, s->s_namecanon.nc_cname); 118959671Seric errno = s->s_namecanon.nc_errno; 119066334Seric #if NAMED_BIND 119159671Seric h_errno = s->s_namecanon.nc_herrno; 119266029Seric #endif 119359671Seric *statp = s->s_namecanon.nc_stat; 119464797Seric if (CurEnv->e_message == NULL && *statp == EX_TEMPFAIL) 119565199Seric { 119665199Seric sprintf(hbuf, "%s: Name server timeout", 119765199Seric shortenstring(name, 33)); 119865199Seric CurEnv->e_message = newstr(hbuf); 119965199Seric } 120059671Seric return s->s_namecanon.nc_cname; 120159671Seric } 120259671Seric 120359671Seric /* 120459671Seric ** If first character is a bracket, then it is an address 120559671Seric ** lookup. Address is copied into a temporary buffer to 120660089Seric ** strip the brackets and to preserve name if address is 120759671Seric ** unknown. 120859671Seric */ 120959671Seric 121060089Seric if (*name != '[') 121153751Seric { 121255019Seric extern bool getcanonname(); 121355019Seric 121458798Seric if (tTd(9, 1)) 121560089Seric printf("host_map_lookup(%s) => ", name); 121659671Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 121760089Seric (void) strcpy(hbuf, name); 121863842Seric if (getcanonname(hbuf, sizeof hbuf - 1, TRUE)) 121958796Seric { 122058796Seric if (tTd(9, 1)) 122158796Seric printf("%s\n", hbuf); 122260257Seric cp = map_rewrite(map, hbuf, strlen(hbuf), av); 122360257Seric s->s_namecanon.nc_cname = newstr(cp); 122460257Seric return cp; 122558796Seric } 122653751Seric else 122758796Seric { 122859084Seric register struct hostent *hp; 122959084Seric 123066029Seric s->s_namecanon.nc_errno = errno; 123166334Seric #if NAMED_BIND 123266029Seric s->s_namecanon.nc_herrno = h_errno; 123358796Seric if (tTd(9, 1)) 123459084Seric printf("FAIL (%d)\n", h_errno); 123559084Seric switch (h_errno) 123659084Seric { 123759084Seric case TRY_AGAIN: 123859596Seric if (UseNameServer) 123959734Seric { 124065202Seric sprintf(hbuf, "%s: Name server timeout", 124165199Seric shortenstring(name, 33)); 124265202Seric message("%s", hbuf); 124359734Seric if (CurEnv->e_message == NULL) 124465202Seric CurEnv->e_message = newstr(hbuf); 124559734Seric } 124659084Seric *statp = EX_TEMPFAIL; 124759084Seric break; 124859084Seric 124959084Seric case HOST_NOT_FOUND: 125059084Seric *statp = EX_NOHOST; 125159084Seric break; 125259084Seric 125359084Seric case NO_RECOVERY: 125459084Seric *statp = EX_SOFTWARE; 125559084Seric break; 125659084Seric 125759084Seric default: 125859084Seric *statp = EX_UNAVAILABLE; 125959084Seric break; 126059084Seric } 126166029Seric #else 126266029Seric if (tTd(9, 1)) 126366029Seric printf("FAIL\n"); 126466029Seric *statp = EX_NOHOST; 126566029Seric #endif 126659671Seric s->s_namecanon.nc_stat = *statp; 126767422Seric if ((*statp != EX_TEMPFAIL && *statp != EX_NOHOST) || 126867422Seric UseNameServer) 126959084Seric return NULL; 127059084Seric 127159084Seric /* 127259084Seric ** Try to look it up in /etc/hosts 127359084Seric */ 127459084Seric 127560089Seric hp = gethostbyname(name); 127659084Seric if (hp == NULL) 127759084Seric { 127859084Seric /* no dice there either */ 127959671Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 128059084Seric return NULL; 128159084Seric } 128259084Seric 128359671Seric s->s_namecanon.nc_stat = *statp = EX_OK; 128460257Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 128560257Seric s->s_namecanon.nc_cname = newstr(cp); 128660257Seric return cp; 128758796Seric } 128853751Seric } 128960089Seric if ((cp = strchr(name, ']')) == NULL) 129053751Seric return (NULL); 129140994Sbostic *cp = '\0'; 129267419Seric in_addr.s_addr = inet_addr(&name[1]); 129358110Seric 129458110Seric /* nope -- ask the name server */ 129567421Seric hp = gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET); 129659671Seric s->s_namecanon.nc_errno = errno; 129766334Seric #if NAMED_BIND 129859671Seric s->s_namecanon.nc_herrno = h_errno; 129966029Seric #endif 130059671Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 130133932Sbostic if (hp == NULL) 130259671Seric { 130359671Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 130453751Seric return (NULL); 130559671Seric } 130653751Seric 130758110Seric /* found a match -- copy out */ 130860257Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 130959671Seric s->s_namecanon.nc_stat = *statp = EX_OK; 131060257Seric s->s_namecanon.nc_cname = newstr(cp); 131160257Seric return cp; 131233932Sbostic } 131358755Seric /* 131458755Seric ** ANYNET_NTOA -- convert a network address to printable form. 131558755Seric ** 131658755Seric ** Parameters: 131758755Seric ** sap -- a pointer to a sockaddr structure. 131858755Seric ** 131958755Seric ** Returns: 132058755Seric ** A printable version of that sockaddr. 132158755Seric */ 132216911Seric 132358755Seric char * 132458755Seric anynet_ntoa(sap) 132558755Seric register SOCKADDR *sap; 132658755Seric { 132758755Seric register char *bp; 132858755Seric register char *ap; 132958755Seric int l; 133064734Seric static char buf[100]; 133158755Seric 133258798Seric /* check for null/zero family */ 133358798Seric if (sap == NULL) 133458798Seric return "NULLADDR"; 133558798Seric if (sap->sa.sa_family == 0) 133658798Seric return "0"; 133758798Seric 133864734Seric switch (sap->sa.sa_family) 133964734Seric { 134064821Seric #ifdef NETUNIX 134164734Seric case AF_UNIX: 134264758Seric if (sap->sunix.sun_path[0] != '\0') 134364758Seric sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 134464734Seric else 134564734Seric sprintf(buf, "[UNIX: localhost]"); 134664734Seric return buf; 134764734Seric #endif 134864734Seric 134958778Seric #ifdef NETINET 135064734Seric case AF_INET: 135158755Seric return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 135258778Seric #endif 135358755Seric 135464734Seric default: 135564734Seric /* this case is only to ensure syntactic correctness */ 135664734Seric break; 135764734Seric } 135864734Seric 135958755Seric /* unknown family -- just dump bytes */ 136058778Seric (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 136158755Seric bp = &buf[strlen(buf)]; 136258778Seric ap = sap->sa.sa_data; 136358778Seric for (l = sizeof sap->sa.sa_data; --l >= 0; ) 136458755Seric { 136558755Seric (void) sprintf(bp, "%02x:", *ap++ & 0377); 136658755Seric bp += 3; 136758755Seric } 136858755Seric *--bp = '\0'; 136958755Seric return buf; 137058755Seric } 137158951Seric /* 137258951Seric ** HOSTNAMEBYANYADDR -- return name of host based on address 137358951Seric ** 137458951Seric ** Parameters: 137558951Seric ** sap -- SOCKADDR pointer 137658951Seric ** 137758951Seric ** Returns: 137858951Seric ** text representation of host name. 137958951Seric ** 138058951Seric ** Side Effects: 138158951Seric ** none. 138258951Seric */ 138358755Seric 138458951Seric char * 138558951Seric hostnamebyanyaddr(sap) 138658951Seric register SOCKADDR *sap; 138758951Seric { 138858951Seric register struct hostent *hp; 138964734Seric int saveretry; 139058951Seric 139166334Seric #if NAMED_BIND 139259042Seric /* shorten name server timeout to avoid higher level timeouts */ 139359042Seric saveretry = _res.retry; 139459042Seric _res.retry = 3; 139559042Seric #endif /* NAMED_BIND */ 139659042Seric 139758951Seric switch (sap->sa.sa_family) 139858951Seric { 139958951Seric #ifdef NETINET 140058951Seric case AF_INET: 140158951Seric hp = gethostbyaddr((char *) &sap->sin.sin_addr, 140267421Seric INADDRSZ, 140358951Seric AF_INET); 140458951Seric break; 140558951Seric #endif 140658951Seric 140758951Seric #ifdef NETISO 140858951Seric case AF_ISO: 140958951Seric hp = gethostbyaddr((char *) &sap->siso.siso_addr, 141058951Seric sizeof sap->siso.siso_addr, 141158951Seric AF_ISO); 141258951Seric break; 141358951Seric #endif 141458951Seric 141564734Seric case AF_UNIX: 141664734Seric hp = NULL; 141764734Seric break; 141864734Seric 141958951Seric default: 142058951Seric hp = gethostbyaddr(sap->sa.sa_data, 142158951Seric sizeof sap->sa.sa_data, 142258951Seric sap->sa.sa_family); 142358951Seric break; 142458951Seric } 142558951Seric 142666334Seric #if NAMED_BIND 142759042Seric _res.retry = saveretry; 142859042Seric #endif /* NAMED_BIND */ 142959042Seric 143058951Seric if (hp != NULL) 143158951Seric return hp->h_name; 143258951Seric else 143358951Seric { 143458951Seric /* produce a dotted quad */ 143558951Seric static char buf[512]; 143658951Seric 143758951Seric (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 143858951Seric return buf; 143958951Seric } 144058951Seric } 144158951Seric 144256795Seric # else /* DAEMON */ 144316911Seric /* code for systems without sophisticated networking */ 144410758Seric 144510758Seric /* 144610758Seric ** MYHOSTNAME -- stub version for case of no daemon code. 144711297Seric ** 144811297Seric ** Can't convert to upper case here because might be a UUCP name. 144912313Seric ** 145012313Seric ** Mark, you can change this to be anything you want...... 145110758Seric */ 145210758Seric 145310758Seric char ** 145412313Seric myhostname(hostbuf, size) 145510758Seric char hostbuf[]; 145612313Seric int size; 145710758Seric { 145810758Seric register FILE *f; 145910758Seric 146010758Seric hostbuf[0] = '\0'; 146110758Seric f = fopen("/usr/include/whoami", "r"); 146210758Seric if (f != NULL) 146310758Seric { 146412313Seric (void) fgets(hostbuf, size, f); 146510758Seric fixcrlf(hostbuf, TRUE); 146610758Seric (void) fclose(f); 146710758Seric } 146810758Seric return (NULL); 146910758Seric } 147016911Seric /* 147158951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 147258308Seric ** 147358308Seric ** Parameters: 147458308Seric ** fd -- the descriptor 147558308Seric ** 147658308Seric ** Returns: 147758308Seric ** The host name associated with this descriptor, if it can 147858308Seric ** be determined. 147958308Seric ** NULL otherwise. 148058308Seric ** 148158308Seric ** Side Effects: 148258308Seric ** none 148358308Seric */ 148458308Seric 148558308Seric char * 148658951Seric getauthinfo(fd) 148758308Seric int fd; 148858308Seric { 148958308Seric return NULL; 149058308Seric } 149158308Seric /* 149216911Seric ** MAPHOSTNAME -- turn a hostname into canonical form 149316911Seric ** 149416911Seric ** Parameters: 149556823Seric ** map -- a pointer to the database map. 149660089Seric ** name -- a buffer containing a hostname. 149753751Seric ** avp -- a pointer to a (cf file defined) argument vector. 149859084Seric ** statp -- an exit status (out parameter). 149916911Seric ** 150016911Seric ** Returns: 150153751Seric ** mapped host name 150251315Seric ** FALSE otherwise. 150316911Seric ** 150416911Seric ** Side Effects: 150560089Seric ** Looks up the host specified in name. If it is not 150616911Seric ** the canonical name for that host, replace it with 150716911Seric ** the canonical name. If the name is unknown, or it 150816911Seric ** is already the canonical name, leave it unchanged. 150916911Seric */ 151010758Seric 151116911Seric /*ARGSUSED*/ 151253751Seric char * 151360089Seric host_map_lookup(map, name, avp, statp) 151456823Seric MAP *map; 151560089Seric char *name; 151653751Seric char **avp; 151759084Seric char *statp; 151816911Seric { 151959084Seric register struct hostent *hp; 152059084Seric 152160089Seric hp = gethostbyname(name); 152259084Seric if (hp != NULL) 152359084Seric return hp->h_name; 152459084Seric *statp = EX_NOHOST; 152553751Seric return NULL; 152616911Seric } 152716911Seric 152856795Seric #endif /* DAEMON */ 1529