122700Sdist /* 234920Sbostic * Copyright (c) 1983 Eric P. Allman 333780Sbostic * Copyright (c) 1988 Regents of the University of California. 433780Sbostic * All rights reserved. 533780Sbostic * 642825Sbostic * %sccs.include.redist.c% 733780Sbostic */ 822700Sdist 933932Sbostic #include <errno.h> 1058153Seric #include <signal.h> 1140962Sbostic #include "sendmail.h" 124535Seric 1333780Sbostic #ifndef lint 1433780Sbostic #ifdef DAEMON 15*58957Seric static char sccsid[] = "@(#)daemon.c 6.33 (Berkeley) 04/04/93 (with daemon mode)"; 1633780Sbostic #else 17*58957Seric static char sccsid[] = "@(#)daemon.c 6.33 (Berkeley) 04/04/93 (without daemon mode)"; 1833780Sbostic #endif 1933780Sbostic #endif /* not lint */ 204535Seric 2133780Sbostic #ifdef DAEMON 2233780Sbostic 2323120Seric # include <netdb.h> 2423120Seric # include <sys/wait.h> 2523120Seric # include <sys/time.h> 265978Seric 274535Seric /* 284535Seric ** DAEMON.C -- routines to use when running as a daemon. 297556Seric ** 307556Seric ** This entire file is highly dependent on the 4.2 BSD 317556Seric ** interprocess communication primitives. No attempt has 327556Seric ** been made to make this file portable to Version 7, 337556Seric ** Version 6, MPX files, etc. If you should try such a 347556Seric ** thing yourself, I recommend chucking the entire file 357556Seric ** and starting from scratch. Basic semantics are: 367556Seric ** 377556Seric ** getrequests() 387556Seric ** Opens a port and initiates a connection. 397556Seric ** Returns in a child. Must set InChannel and 407556Seric ** OutChannel appropriately. 4110206Seric ** clrdaemon() 4210206Seric ** Close any open files associated with getting 4310206Seric ** the connection; this is used when running the queue, 4410206Seric ** etc., to avoid having extra file descriptors during 4510206Seric ** the queue run and to avoid confusing the network 4610206Seric ** code (if it cares). 4752106Seric ** makeconnection(host, port, outfile, infile, usesecureport) 487556Seric ** Make a connection to the named host on the given 497556Seric ** port. Set *outfile and *infile to the files 507556Seric ** appropriate for communication. Returns zero on 517556Seric ** success, else an exit status describing the 527556Seric ** error. 5356823Seric ** maphostname(map, hbuf, hbufsiz, avp) 5456823Seric ** Convert the entry in hbuf into a canonical form. 554535Seric */ 5658755Seric 5758755Seric extern char *anynet_ntoa(); 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 */ 7816144Seric 794535Seric getrequests() 804535Seric { 819610Seric int t; 829610Seric register struct servent *sp; 8325027Seric int on = 1; 8453751Seric bool refusingconnections = TRUE; 8558419Seric FILE *pidf; 8646928Sbostic extern void reapchild(); 877117Seric 889610Seric /* 899610Seric ** Set up the address for the mailer. 909610Seric */ 919610Seric 9258849Seric if (DaemonAddr.sin.sin_family == 0) 9358849Seric DaemonAddr.sin.sin_family = AF_INET; 9458849Seric if (DaemonAddr.sin.sin_addr.s_addr == 0) 9558849Seric DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY; 9658849Seric if (DaemonAddr.sin.sin_port == 0) 979610Seric { 9858849Seric sp = getservbyname("smtp", "tcp"); 9958849Seric if (sp == NULL) 10058849Seric { 10158909Seric syserr("554 service \"smtp\" unknown"); 10258849Seric goto severe; 10358849Seric } 10458849Seric DaemonAddr.sin.sin_port = sp->s_port; 1059610Seric } 1069610Seric 1079610Seric /* 1089610Seric ** Try to actually open the connection. 1099610Seric */ 1109610Seric 1119610Seric if (tTd(15, 1)) 11258849Seric printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port); 1139610Seric 1149610Seric /* get a socket for the SMTP connection */ 11523120Seric DaemonSocket = socket(AF_INET, SOCK_STREAM, 0); 11610206Seric if (DaemonSocket < 0) 1179610Seric { 1189610Seric /* probably another daemon already */ 1199610Seric syserr("getrequests: can't create socket"); 1209610Seric severe: 1219610Seric # ifdef LOG 1229610Seric if (LogLevel > 0) 12357663Seric syslog(LOG_ALERT, "problem creating SMTP socket"); 12456795Seric # endif /* LOG */ 1259610Seric finis(); 1269610Seric } 12710347Seric 12810347Seric /* turn on network debugging? */ 12956328Seric if (tTd(15, 101)) 13024945Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on); 13110347Seric 13225027Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on); 13325027Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on); 13425027Seric 13558849Seric if (bind(DaemonSocket, &DaemonAddr.sa, sizeof DaemonAddr) < 0) 1369610Seric { 1379610Seric syserr("getrequests: cannot bind"); 13810206Seric (void) close(DaemonSocket); 1399610Seric goto severe; 1409610Seric } 1419610Seric 14224955Seric (void) signal(SIGCHLD, reapchild); 14324945Seric 14458419Seric /* write the pid to the log file for posterity */ 14558419Seric pidf = fopen(PidFile, "w"); 14658419Seric if (pidf != NULL) 14758419Seric { 14858419Seric fprintf(pidf, "%d\n", getpid()); 14958419Seric fclose(pidf); 15058419Seric } 15158419Seric 15258419Seric 1539610Seric if (tTd(15, 1)) 15410206Seric printf("getrequests: %d\n", DaemonSocket); 1559610Seric 1564631Seric for (;;) 1574631Seric { 15814875Seric register int pid; 15911147Seric auto int lotherend; 16053751Seric extern bool refuseconnections(); 16111147Seric 16214875Seric /* see if we are rejecting connections */ 16353751Seric CurrentLA = getla(); 16453751Seric if (refuseconnections()) 16536584Sbostic { 16653751Seric if (!refusingconnections) 16753751Seric { 16853751Seric /* don't queue so peer will fail quickly */ 16953751Seric (void) listen(DaemonSocket, 0); 17053751Seric refusingconnections = TRUE; 17153751Seric } 17257385Seric setproctitle("rejecting connections: load average: %d", 17357385Seric CurrentLA); 17414875Seric sleep(5); 17553751Seric continue; 17636584Sbostic } 17714875Seric 17853751Seric if (refusingconnections) 17953751Seric { 18053751Seric /* start listening again */ 18153751Seric if (listen(DaemonSocket, 10) < 0) 18253751Seric { 18353751Seric syserr("getrequests: cannot listen"); 18453751Seric (void) close(DaemonSocket); 18553751Seric goto severe; 18653751Seric } 18753751Seric setproctitle("accepting connections"); 18853751Seric refusingconnections = FALSE; 18953751Seric } 19053751Seric 1919610Seric /* wait for a connection */ 1929610Seric do 1939610Seric { 1949610Seric errno = 0; 19536230Skarels lotherend = sizeof RealHostAddr; 19646928Sbostic t = accept(DaemonSocket, 19746928Sbostic (struct sockaddr *)&RealHostAddr, &lotherend); 1989610Seric } while (t < 0 && errno == EINTR); 1999610Seric if (t < 0) 2005978Seric { 2019610Seric syserr("getrequests: accept"); 2029610Seric sleep(5); 2039610Seric continue; 2045978Seric } 2054631Seric 2065978Seric /* 2075978Seric ** Create a subprocess to process the mail. 2085978Seric */ 2095978Seric 2107677Seric if (tTd(15, 2)) 2119610Seric printf("getrequests: forking (fd = %d)\n", t); 2125978Seric 2134636Seric pid = fork(); 2144636Seric if (pid < 0) 2154631Seric { 2164636Seric syserr("daemon: cannot fork"); 2174636Seric sleep(10); 2189610Seric (void) close(t); 2194636Seric continue; 2204631Seric } 2214631Seric 2224636Seric if (pid == 0) 2234631Seric { 22458951Seric extern char *hostnamebyanyaddr(); 22511147Seric 2264636Seric /* 2274636Seric ** CHILD -- return to caller. 22811147Seric ** Collect verified idea of sending host. 2294636Seric ** Verify calling user id if possible here. 2304636Seric */ 2314631Seric 23224955Seric (void) signal(SIGCHLD, SIG_DFL); 23324950Seric 23411147Seric /* determine host name */ 23558951Seric RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 23658778Seric 23755173Seric #ifdef LOG 23857977Seric if (LogLevel > 10) 23955173Seric { 24055173Seric /* log connection information */ 24155173Seric syslog(LOG_INFO, "connect from %s (%s)", 24258951Seric RealHostName, anynet_ntoa(&RealHostAddr)); 24355173Seric } 24455173Seric #endif 24555173Seric 24616884Seric /* should we check for illegal connection here? XXX */ 24716884Seric 24811147Seric 24910206Seric (void) close(DaemonSocket); 2509610Seric InChannel = fdopen(t, "r"); 25121062Seric OutChannel = fdopen(dup(t), "w"); 2527677Seric if (tTd(15, 2)) 2535978Seric printf("getreq: returning\n"); 2544636Seric return; 2554631Seric } 2564631Seric 2577117Seric /* close the port so that others will hang (for a while) */ 2589610Seric (void) close(t); 2594631Seric } 2609886Seric /*NOTREACHED*/ 2614631Seric } 2625978Seric /* 26310206Seric ** CLRDAEMON -- reset the daemon connection 26410206Seric ** 26510206Seric ** Parameters: 26610206Seric ** none. 26710206Seric ** 26810206Seric ** Returns: 26910206Seric ** none. 27010206Seric ** 27110206Seric ** Side Effects: 27210206Seric ** releases any resources used by the passive daemon. 27310206Seric */ 27410206Seric 27510206Seric clrdaemon() 27610206Seric { 27710206Seric if (DaemonSocket >= 0) 27810206Seric (void) close(DaemonSocket); 27910206Seric DaemonSocket = -1; 28010206Seric } 28110206Seric /* 28258849Seric ** SETDAEMONOPTIONS -- set options for running the daemon 28358849Seric ** 28458849Seric ** Parameters: 28558849Seric ** p -- the options line. 28658849Seric ** 28758849Seric ** Returns: 28858849Seric ** none. 28958849Seric */ 29058849Seric 29158849Seric setdaemonoptions(p) 29258849Seric register char *p; 29358849Seric { 29458873Seric if (DaemonAddr.sa.sa_family == AF_UNSPEC) 29558873Seric DaemonAddr.sa.sa_family = AF_INET; 29658873Seric 29758849Seric while (p != NULL) 29858849Seric { 29958849Seric register char *f; 30058849Seric register char *v; 30158849Seric 30258849Seric while (isascii(*p) && isspace(*p)) 30358849Seric p++; 30458849Seric if (*p == '\0') 30558849Seric break; 30658849Seric f = p; 30758849Seric p = strchr(p, ','); 30858849Seric if (p != NULL) 30958849Seric *p++ = '\0'; 31058849Seric v = strchr(f, '='); 31158849Seric if (v == NULL) 31258849Seric continue; 31358849Seric while (isascii(*++v) && isspace(*v)) 31458849Seric continue; 31558849Seric 31658849Seric switch (*f) 31758849Seric { 31858873Seric case 'F': /* address family */ 31958849Seric if (isascii(*v) && isdigit(*v)) 32058873Seric DaemonAddr.sa.sa_family = atoi(v); 32158873Seric #ifdef NETINET 32258873Seric else if (strcasecmp(v, "inet") == 0) 32358873Seric DaemonAddr.sa.sa_family = AF_INET; 32458873Seric #endif 32558873Seric #ifdef NETISO 32658873Seric else if (strcasecmp(v, "iso") == 0) 32758873Seric DaemonAddr.sa.sa_family = AF_ISO; 32858873Seric #endif 32958873Seric #ifdef NETNS 33058873Seric else if (strcasecmp(v, "ns") == 0) 33158873Seric DaemonAddr.sa.sa_family = AF_NS; 33258873Seric #endif 33358873Seric #ifdef NETX25 33458873Seric else if (strcasecmp(v, "x.25") == 0) 33558873Seric DaemonAddr.sa.sa_family = AF_CCITT; 33658873Seric #endif 33758849Seric else 33858873Seric syserr("554 Unknown address family %s in Family=option", v); 33958873Seric break; 34058873Seric 34158873Seric case 'A': /* address */ 34258873Seric switch (DaemonAddr.sa.sa_family) 34358849Seric { 34458873Seric #ifdef NETINET 34558873Seric case AF_INET: 34658873Seric if (isascii(*v) && isdigit(*v)) 34758873Seric DaemonAddr.sin.sin_addr.s_addr = inet_network(v); 34858873Seric else 34958873Seric { 35058873Seric register struct netent *np; 35158849Seric 35258873Seric np = getnetbyname(v); 35358873Seric if (np == NULL) 35458873Seric syserr("554 network \"%s\" unknown", v); 35558873Seric else 35658873Seric DaemonAddr.sin.sin_addr.s_addr = np->n_net; 35758873Seric } 35858873Seric break; 35958873Seric #endif 36058873Seric 36158873Seric default: 36258873Seric syserr("554 Address= option unsupported for family %d", 36358873Seric DaemonAddr.sa.sa_family); 36458873Seric break; 36558849Seric } 36658849Seric break; 36758849Seric 36858873Seric case 'P': /* port */ 36958873Seric switch (DaemonAddr.sa.sa_family) 37058849Seric { 37158873Seric short port; 37258849Seric 37358873Seric #ifdef NETINET 37458873Seric case AF_INET: 37558873Seric if (isascii(*v) && isdigit(*v)) 37658873Seric DaemonAddr.sin.sin_port = atoi(v); 37758849Seric else 37858873Seric { 37958873Seric register struct servent *sp; 38058873Seric 38158873Seric sp = getservbyname(v, "tcp"); 38258873Seric if (sp == NULL) 38358909Seric syserr("554 service \"%s\" unknown", v); 38458873Seric else 38558873Seric DaemonAddr.sin.sin_port = sp->s_port; 38658873Seric } 38758873Seric break; 38858873Seric #endif 38958873Seric 39058873Seric #ifdef NETISO 39158873Seric case AF_ISO: 39258873Seric /* assume two byte transport selector */ 39358873Seric if (isascii(*v) && isdigit(*v)) 39458873Seric port = atoi(v); 39558873Seric else 39658873Seric { 39758873Seric register struct servent *sp; 39858873Seric 39958873Seric sp = getservbyname(v, "tcp"); 40058873Seric if (sp == NULL) 40158909Seric syserr("554 service \"%s\" unknown", v); 40258873Seric else 40358873Seric port = sp->s_port; 40458873Seric } 40558873Seric bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 40658873Seric break; 40758873Seric #endif 40858873Seric 40958873Seric default: 41058873Seric syserr("554 Port= option unsupported for family %d", 41158873Seric DaemonAddr.sa.sa_family); 41258873Seric break; 41358849Seric } 41458849Seric break; 41558849Seric } 41658849Seric } 41758849Seric } 41858849Seric /* 4196039Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 4206039Seric ** 4216039Seric ** Parameters: 4226039Seric ** host -- the name of the host. 4236633Seric ** port -- the port number to connect to. 42453739Seric ** mci -- a pointer to the mail connection information 42553739Seric ** structure to be filled in. 42652106Seric ** usesecureport -- if set, use a low numbered (reserved) 42752106Seric ** port to provide some rudimentary authentication. 4286039Seric ** 4296039Seric ** Returns: 4306039Seric ** An exit code telling whether the connection could be 4316039Seric ** made and if not why not. 4326039Seric ** 4336039Seric ** Side Effects: 4346039Seric ** none. 4356039Seric */ 4365978Seric 43758755Seric SOCKADDR CurHostAddr; /* address of current host */ 43858305Seric 43954967Seric int 44053739Seric makeconnection(host, port, mci, usesecureport) 4416039Seric char *host; 4427286Seric u_short port; 44354967Seric register MCI *mci; 44452106Seric bool usesecureport; 4456039Seric { 44629430Sbloom register int i, s; 44729430Sbloom register struct hostent *hp = (struct hostent *)NULL; 44858755Seric SOCKADDR addr; 44952106Seric int sav_errno; 45058755Seric int addrlen; 45135651Seric #ifdef NAMED_BIND 45235651Seric extern int h_errno; 45335651Seric #endif 4546039Seric 4556039Seric /* 4566039Seric ** Set up the address for the mailer. 4579308Seric ** Accept "[a.b.c.d]" syntax for host name. 4586039Seric */ 4596039Seric 46035651Seric #ifdef NAMED_BIND 46125475Smiriam h_errno = 0; 46235651Seric #endif 46325475Smiriam errno = 0; 46458864Seric bzero(&CurHostAddr, sizeof CurHostAddr); 46558906Seric CurHostName = host; 46625475Smiriam 4679308Seric if (host[0] == '[') 4689308Seric { 46911147Seric long hid; 47056795Seric register char *p = strchr(host, ']'); 4719308Seric 47211147Seric if (p != NULL) 4739308Seric { 47411147Seric *p = '\0'; 47511147Seric hid = inet_addr(&host[1]); 47658360Seric if (hid == -1) 47758360Seric { 47858360Seric /* try it as a host name (avoid MX lookup) */ 47958360Seric hp = gethostbyname(&host[1]); 48058360Seric *p = ']'; 48158360Seric goto gothostent; 48258360Seric } 48311147Seric *p = ']'; 4849308Seric } 48558360Seric if (p == NULL) 4869308Seric { 48758151Seric usrerr("553 Invalid numeric domain spec \"%s\"", host); 4889308Seric return (EX_NOHOST); 4899308Seric } 49058778Seric addr.sin.sin_family = AF_INET; 49158778Seric addr.sin.sin_addr.s_addr = hid; 4929308Seric } 4939610Seric else 4949610Seric { 49529430Sbloom hp = gethostbyname(host); 49658360Seric gothostent: 49725475Smiriam if (hp == NULL) 49824945Seric { 49935651Seric #ifdef NAMED_BIND 50025475Smiriam if (errno == ETIMEDOUT || h_errno == TRY_AGAIN) 50125475Smiriam return (EX_TEMPFAIL); 50225657Seric 50335651Seric /* if name server is specified, assume temp fail */ 50435651Seric if (errno == ECONNREFUSED && UseNameServer) 50535651Seric return (EX_TEMPFAIL); 50635651Seric #endif 50725475Smiriam return (EX_NOHOST); 50824945Seric } 50958778Seric addr.sa.sa_family = hp->h_addrtype; 51058778Seric switch (hp->h_addrtype) 51158778Seric { 51258778Seric #ifdef NETINET 51358778Seric case AF_INET: 51458755Seric bcopy(hp->h_addr, 51558778Seric &addr.sin.sin_addr, 51658755Seric hp->h_length); 51758778Seric break; 51858778Seric #endif 51958778Seric 52058778Seric default: 52158755Seric bcopy(hp->h_addr, 52258778Seric addr.sa.sa_data, 52358755Seric hp->h_length); 52458778Seric break; 52558778Seric } 52629430Sbloom i = 1; 5279610Seric } 5289610Seric 5299610Seric /* 5309610Seric ** Determine the port number. 5319610Seric */ 5329610Seric 53310011Seric if (port != 0) 53458755Seric port = htons(port); 53510011Seric else 5369610Seric { 5379610Seric register struct servent *sp = getservbyname("smtp", "tcp"); 5389610Seric 5399610Seric if (sp == NULL) 5409610Seric { 54158909Seric syserr("554 makeconnection: service \"smtp\" unknown"); 54257977Seric return (EX_OSERR); 5439610Seric } 54458755Seric port = sp->s_port; 5459610Seric } 5466039Seric 54758778Seric switch (addr.sa.sa_family) 54858755Seric { 54958755Seric case AF_INET: 55058778Seric addr.sin.sin_port = port; 55158755Seric addrlen = sizeof (struct sockaddr_in); 55258755Seric break; 55358755Seric 55458755Seric #ifdef NETISO 55558755Seric case AF_ISO: 55658755Seric /* assume two byte transport selector */ 55758755Seric bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 55858755Seric addrlen = sizeof (struct sockaddr_iso); 55958755Seric break; 56058755Seric #endif 56158755Seric 56258755Seric default: 56358778Seric syserr("Can't connect to address family %d", addr.sa.sa_family); 56458755Seric return (EX_NOHOST); 56558755Seric } 56658755Seric 5676039Seric /* 5686039Seric ** Try to actually open the connection. 5696039Seric */ 5706039Seric 57157736Seric for (;;) 57252106Seric { 57357736Seric if (tTd(16, 1)) 57458755Seric printf("makeconnection (%s [%s])\n", 57558755Seric host, anynet_ntoa(&addr)); 57652106Seric 57758588Seric /* save for logging */ 57858588Seric CurHostAddr = addr; 57958588Seric 58057736Seric if (usesecureport) 58157736Seric { 58257736Seric int rport = IPPORT_RESERVED - 1; 5836039Seric 58457736Seric s = rresvport(&rport); 58557736Seric } 58657736Seric else 58757736Seric { 58857736Seric s = socket(AF_INET, SOCK_STREAM, 0); 58957736Seric } 59057736Seric if (s < 0) 59157736Seric { 59257736Seric sav_errno = errno; 59357736Seric syserr("makeconnection: no socket"); 59457736Seric goto failure; 59557736Seric } 59610347Seric 59757736Seric if (tTd(16, 1)) 59857736Seric printf("makeconnection: fd=%d\n", s); 59957736Seric 60057736Seric /* turn on network debugging? */ 60157736Seric if (tTd(16, 101)) 60257736Seric { 60357736Seric int on = 1; 60457736Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, 60557736Seric (char *)&on, sizeof on); 60657736Seric } 60757736Seric if (CurEnv->e_xfp != NULL) 60857736Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 60957736Seric errno = 0; /* for debugging */ 61058755Seric if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 61157736Seric break; 61257736Seric 61357736Seric /* couldn't connect.... figure out why */ 61427744Sbloom sav_errno = errno; 61527744Sbloom (void) close(s); 61629430Sbloom if (hp && hp->h_addr_list[i]) 61729430Sbloom { 61858755Seric extern char *errstring(); 61958755Seric 62057736Seric if (tTd(16, 1)) 62158755Seric printf("Connect failed (%s); trying new address....\n", 62258755Seric errstring(sav_errno)); 62358778Seric switch (addr.sa.sa_family) 62458778Seric { 62558778Seric #ifdef NETINET 62658778Seric case AF_INET: 62758755Seric bcopy(hp->h_addr_list[i++], 62858778Seric &addr.sin.sin_addr, 62958755Seric hp->h_length); 63058778Seric break; 63158778Seric #endif 63258778Seric 63358778Seric default: 63458755Seric bcopy(hp->h_addr_list[i++], 63558778Seric addr.sa.sa_data, 63652106Seric hp->h_length); 63758778Seric break; 63858778Seric } 63957736Seric continue; 64029430Sbloom } 64129430Sbloom 6426039Seric /* failure, decide if temporary or not */ 6436039Seric failure: 64458542Seric if (transienterror(sav_errno)) 64558542Seric return EX_TEMPFAIL; 64658542Seric else 64758542Seric { 64858542Seric extern char *errstring(); 64911147Seric 65058542Seric message("%s", errstring(sav_errno)); 65158542Seric return (EX_UNAVAILABLE); 6526039Seric } 6536039Seric } 6546039Seric 6556039Seric /* connection ok, put it into canonical form */ 65653739Seric mci->mci_out = fdopen(s, "w"); 65753739Seric mci->mci_in = fdopen(dup(s), "r"); 6586039Seric 65910098Seric return (EX_OK); 6606039Seric } 66110758Seric /* 66210758Seric ** MYHOSTNAME -- return the name of this host. 66310758Seric ** 66410758Seric ** Parameters: 66510758Seric ** hostbuf -- a place to return the name of this host. 66612313Seric ** size -- the size of hostbuf. 66710758Seric ** 66810758Seric ** Returns: 66910758Seric ** A list of aliases for this host. 67010758Seric ** 67110758Seric ** Side Effects: 67258110Seric ** Sets the MyIpAddrs buffer to a list of my IP addresses. 67310758Seric */ 6746039Seric 67558110Seric struct in_addr MyIpAddrs[MAXIPADDR + 1]; 67658110Seric 67710758Seric char ** 67812313Seric myhostname(hostbuf, size) 67910758Seric char hostbuf[]; 68012313Seric int size; 68110758Seric { 68258110Seric register struct hostent *hp; 68310758Seric extern struct hostent *gethostbyname(); 68410758Seric 68523120Seric if (gethostname(hostbuf, size) < 0) 68623120Seric { 68723120Seric (void) strcpy(hostbuf, "localhost"); 68823120Seric } 68911147Seric hp = gethostbyname(hostbuf); 69011147Seric if (hp != NULL) 69116877Seric { 69258110Seric (void) strncpy(hostbuf, hp->h_name, size - 1); 69358110Seric hostbuf[size - 1] = '\0'; 69458110Seric 69558110Seric if (hp->h_addrtype == AF_INET && hp->h_length == 4) 69658110Seric { 69758110Seric register int i; 69858110Seric 69958110Seric for (i = 0; i < MAXIPADDR; i++) 70058110Seric { 70158110Seric if (hp->h_addr_list[i] == NULL) 70258110Seric break; 70358110Seric MyIpAddrs[i].s_addr = *(u_long *) hp->h_addr_list[i]; 70458110Seric } 70558110Seric MyIpAddrs[i].s_addr = 0; 70658110Seric } 70758110Seric 70811147Seric return (hp->h_aliases); 70916877Seric } 71010758Seric else 71110758Seric return (NULL); 71210758Seric } 71351315Seric /* 71458951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 71558308Seric ** 71658951Seric ** Uses RFC1413 protocol to try to get info from the other end. 71758951Seric ** 71858308Seric ** Parameters: 71958308Seric ** fd -- the descriptor 72058308Seric ** 72158308Seric ** Returns: 72258951Seric ** The user@host information associated with this descriptor. 72358308Seric ** 72458308Seric ** Side Effects: 72558951Seric ** Sets RealHostName to the name of the host at the other end. 72658308Seric */ 72758308Seric 72858951Seric #define IDENTPROTO 1 72958951Seric 73058951Seric #ifdef IDENTPROTO 73158951Seric 73258951Seric static jmp_buf CtxAuthTimeout; 73358951Seric 73458951Seric static 73558951Seric authtimeout() 73658951Seric { 73758951Seric longjmp(CtxAuthTimeout, 1); 73858951Seric } 73958951Seric 74058951Seric #endif 74158951Seric 74258308Seric char * 74358951Seric getauthinfo(fd) 74458308Seric int fd; 74558308Seric { 74658951Seric SOCKADDR fa; 74758951Seric int falen; 74858951Seric #ifdef IDENTPROTO 74958951Seric SOCKADDR la; 75058951Seric int lalen; 75158951Seric register struct servent *sp; 75258951Seric int s; 75358951Seric int i; 75458951Seric register char *p; 75558951Seric EVENT *ev; 75658951Seric #endif 75758951Seric static char hbuf[MAXNAME * 2 + 2]; 75858951Seric extern char *hostnamebyanyaddr(); 75958951Seric extern char RealUserName[]; /* main.c */ 76058308Seric 76158951Seric falen = sizeof fa; 76258951Seric if (getpeername(fd, &fa.sa, &falen) < 0 || falen <= 0) 76358951Seric { 76458951Seric RealHostName = "localhost"; 76558951Seric (void) sprintf(hbuf, "%s@localhost", RealUserName); 766*58957Seric if (tTd(9, 1)) 76758951Seric printf("getauthinfo: %s\n", hbuf); 76858951Seric return hbuf; 76958951Seric } 77058951Seric 77158951Seric RealHostName = newstr(hostnamebyanyaddr(&fa)); 77258951Seric RealHostAddr = fa; 77358951Seric 77458951Seric #ifdef IDENTPROTO 77558951Seric lalen = sizeof la; 77658951Seric if (fa.sa.sa_family != AF_INET || 77758951Seric getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 77858951Seric la.sa.sa_family != AF_INET) 77958951Seric { 78058951Seric /* no ident info */ 78158951Seric goto noident; 78258951Seric } 78358951Seric 78458951Seric /* create ident query */ 78558951Seric (void) sprintf(hbuf, "%d,%d\r\n", fa.sin.sin_port, la.sin.sin_port); 78658951Seric 78758951Seric /* create local address */ 78858951Seric bzero(&la, sizeof la); 78958951Seric 79058951Seric /* create foreign address */ 79158951Seric sp = getservbyname("auth", "tcp"); 79258951Seric if (sp != NULL) 79358951Seric fa.sin.sin_port = sp->s_port; 79458308Seric else 79558951Seric fa.sin.sin_port = 113; 79658951Seric 79758951Seric s = -1; 79858951Seric if (setjmp(CtxAuthTimeout) != 0) 79958951Seric { 80058951Seric if (s >= 0) 80158951Seric (void) close(s); 80258951Seric goto noident; 80358951Seric } 80458951Seric 80558951Seric /* put a timeout around the whole thing */ 80658951Seric ev = setevent((time_t) 30, authtimeout, 0); 80758951Seric 80858951Seric /* connect to foreign IDENT server */ 80958951Seric s = socket(AF_INET, SOCK_STREAM, 0); 81058951Seric if (s < 0) 81158951Seric { 81258951Seric clrevent(ev); 81358951Seric goto noident; 81458951Seric } 81558951Seric if (connect(s, &fa.sa, sizeof fa.sin) < 0) 81658951Seric { 81758951Seric closeident: 81858951Seric (void) close(s); 81958951Seric clrevent(ev); 82058951Seric goto noident; 82158951Seric } 82258951Seric 823*58957Seric if (tTd(9, 10)) 82458951Seric printf("getauthinfo: sent %s", hbuf); 82558951Seric 82658951Seric /* send query */ 82758951Seric if (write(s, hbuf, strlen(hbuf)) < 0) 82858951Seric goto closeident; 82958951Seric 83058951Seric /* get result */ 83158951Seric i = read(s, hbuf, sizeof hbuf); 83258951Seric (void) close(s); 83358951Seric clrevent(ev); 83458951Seric if (i <= 0) 83558951Seric goto noident; 83658951Seric if (hbuf[--i] == '\n' && hbuf[--i] == '\r') 83758951Seric i--; 83858951Seric hbuf[++i] = '\0'; 83958951Seric 840*58957Seric if (tTd(9, 3)) 84158951Seric printf("getauthinfo: got %s\n", hbuf); 84258951Seric 84358951Seric /* parse result */ 84458951Seric p = strchr(hbuf, ':'); 84558951Seric if (p == NULL) 84658951Seric { 84758951Seric /* malformed response */ 84858951Seric goto noident; 84958951Seric } 85058951Seric while (isascii(*++p) && isspace(*p)) 85158951Seric continue; 85258951Seric if (strncasecmp(p, "userid", 6) != 0) 85358951Seric { 85458951Seric /* presumably an error string */ 85558951Seric goto noident; 85658951Seric } 85758951Seric p += 6; 85858951Seric while (isascii(*p) && isspace(*p)) 85958951Seric p++; 86058951Seric if (*p++ != ':') 86158951Seric { 86258951Seric /* either useridxx or malformed response */ 86358951Seric goto noident; 86458951Seric } 86558951Seric 86658951Seric /* p now points to the OSTYPE field */ 86758951Seric p = strchr(p, ':'); 86858951Seric if (p == NULL) 86958951Seric { 87058951Seric /* malformed response */ 87158951Seric goto noident; 87258951Seric } 87358951Seric 874*58957Seric /* 1413 says don't do this -- but it's broken otherwise */ 875*58957Seric while (isascii(*++p) && isspace(*p)) 876*58957Seric continue; 877*58957Seric 87858951Seric /* p now points to the authenticated name */ 87958951Seric (void) sprintf(hbuf, "%s@%s", p, RealHostName); 880*58957Seric goto finish; 881*58957Seric 882*58957Seric #endif /* IDENTPROTO */ 883*58957Seric 884*58957Seric noident: 885*58957Seric (void) strcpy(hbuf, RealHostName); 886*58957Seric 887*58957Seric finish: 88858951Seric if (RealHostName[0] != '[') 88958951Seric { 89058951Seric p = &hbuf[strlen(hbuf)]; 89158951Seric (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 89258951Seric } 893*58957Seric if (tTd(9, 1)) 89458951Seric printf("getauthinfo: %s\n", hbuf); 89558308Seric return hbuf; 89658308Seric } 89758308Seric /* 89853751Seric ** MAPHOSTNAME -- turn a hostname into canonical form 89953751Seric ** 90053751Seric ** Parameters: 90156823Seric ** map -- a pointer to this map (unused). 90253751Seric ** hbuf -- a buffer containing a hostname. 90353751Seric ** hbsize -- the size of hbuf. 90455019Seric ** avp -- unused -- for compatibility with other mapping 90555019Seric ** functions. 90653751Seric ** 90753751Seric ** Returns: 90853751Seric ** The mapping, if found. 90953751Seric ** NULL if no mapping found. 91053751Seric ** 91153751Seric ** Side Effects: 91253751Seric ** Looks up the host specified in hbuf. If it is not 91353751Seric ** the canonical name for that host, return the canonical 91453751Seric ** name. 91553751Seric */ 91651315Seric 91753751Seric char * 91856823Seric maphostname(map, hbuf, hbsize, avp) 91956823Seric MAP *map; 92016911Seric char *hbuf; 92116911Seric int hbsize; 92253751Seric char **avp; 92316911Seric { 92416911Seric register struct hostent *hp; 92533932Sbostic u_long in_addr; 92656823Seric char *cp; 92758110Seric int i; 92833932Sbostic struct hostent *gethostbyaddr(); 92916911Seric 93056836Seric /* allow room for null */ 93156823Seric hbsize--; 93253751Seric 93325574Smiriam /* 93433932Sbostic * If first character is a bracket, then it is an address 93533932Sbostic * lookup. Address is copied into a temporary buffer to 93633932Sbostic * strip the brackets and to preserve hbuf if address is 93733932Sbostic * unknown. 93833932Sbostic */ 93953751Seric 94051315Seric if (*hbuf != '[') 94153751Seric { 94255019Seric extern bool getcanonname(); 94355019Seric 94458798Seric if (tTd(9, 1)) 94558798Seric printf("maphostname(%s, %d) => ", hbuf, hbsize); 94658674Seric if (getcanonname(hbuf, hbsize)) 94758796Seric { 94858796Seric if (tTd(9, 1)) 94958796Seric printf("%s\n", hbuf); 95053751Seric return hbuf; 95158796Seric } 95253751Seric else 95358796Seric { 95458796Seric if (tTd(9, 1)) 95558796Seric printf("FAIL\n"); 95653751Seric return NULL; 95758796Seric } 95853751Seric } 95956823Seric if ((cp = strchr(hbuf, ']')) == NULL) 96053751Seric return (NULL); 96140994Sbostic *cp = '\0'; 96256823Seric in_addr = inet_addr(&hbuf[1]); 96358110Seric 96458110Seric /* check to see if this is one of our addresses */ 96558110Seric for (i = 0; MyIpAddrs[i].s_addr != 0; i++) 96658110Seric { 96758110Seric if (MyIpAddrs[i].s_addr == in_addr) 96858110Seric { 96958110Seric strncpy(hbuf, MyHostName, hbsize); 97058110Seric hbuf[hbsize] = '\0'; 97158110Seric return hbuf; 97258110Seric } 97358110Seric } 97458110Seric 97558110Seric /* nope -- ask the name server */ 97633932Sbostic hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET); 97733932Sbostic if (hp == NULL) 97853751Seric return (NULL); 97953751Seric 98058110Seric /* found a match -- copy out */ 98156823Seric if (strlen(hp->h_name) > hbsize) 98256823Seric hp->h_name[hbsize] = '\0'; 98353751Seric (void) strcpy(hbuf, hp->h_name); 98453751Seric return hbuf; 98533932Sbostic } 98658755Seric /* 98758755Seric ** ANYNET_NTOA -- convert a network address to printable form. 98858755Seric ** 98958755Seric ** Parameters: 99058755Seric ** sap -- a pointer to a sockaddr structure. 99158755Seric ** 99258755Seric ** Returns: 99358755Seric ** A printable version of that sockaddr. 99458755Seric */ 99516911Seric 99658755Seric char * 99758755Seric anynet_ntoa(sap) 99858755Seric register SOCKADDR *sap; 99958755Seric { 100058755Seric register char *bp; 100158755Seric register char *ap; 100258755Seric int l; 100358755Seric static char buf[80]; 100458755Seric 100558798Seric /* check for null/zero family */ 100658798Seric if (sap == NULL) 100758798Seric return "NULLADDR"; 100858798Seric if (sap->sa.sa_family == 0) 100958798Seric return "0"; 101058798Seric 101158778Seric #ifdef NETINET 101258778Seric if (sap->sa.sa_family == AF_INET) 101358755Seric { 101458755Seric extern char *inet_ntoa(); 101558755Seric 101658755Seric return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 101758755Seric } 101858778Seric #endif 101958755Seric 102058755Seric /* unknown family -- just dump bytes */ 102158778Seric (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 102258755Seric bp = &buf[strlen(buf)]; 102358778Seric ap = sap->sa.sa_data; 102458778Seric for (l = sizeof sap->sa.sa_data; --l >= 0; ) 102558755Seric { 102658755Seric (void) sprintf(bp, "%02x:", *ap++ & 0377); 102758755Seric bp += 3; 102858755Seric } 102958755Seric *--bp = '\0'; 103058755Seric return buf; 103158755Seric } 103258951Seric /* 103358951Seric ** HOSTNAMEBYANYADDR -- return name of host based on address 103458951Seric ** 103558951Seric ** Parameters: 103658951Seric ** sap -- SOCKADDR pointer 103758951Seric ** 103858951Seric ** Returns: 103958951Seric ** text representation of host name. 104058951Seric ** 104158951Seric ** Side Effects: 104258951Seric ** none. 104358951Seric */ 104458755Seric 104558951Seric char * 104658951Seric hostnamebyanyaddr(sap) 104758951Seric register SOCKADDR *sap; 104858951Seric { 104958951Seric register struct hostent *hp; 105058951Seric 105158951Seric switch (sap->sa.sa_family) 105258951Seric { 105358951Seric #ifdef NETINET 105458951Seric case AF_INET: 105558951Seric hp = gethostbyaddr((char *) &sap->sin.sin_addr, 105658951Seric sizeof sap->sin.sin_addr, 105758951Seric AF_INET); 105858951Seric break; 105958951Seric #endif 106058951Seric 106158951Seric #ifdef NETISO 106258951Seric case AF_ISO: 106358951Seric hp = gethostbyaddr((char *) &sap->siso.siso_addr, 106458951Seric sizeof sap->siso.siso_addr, 106558951Seric AF_ISO); 106658951Seric break; 106758951Seric #endif 106858951Seric 106958951Seric default: 107058951Seric hp = gethostbyaddr(sap->sa.sa_data, 107158951Seric sizeof sap->sa.sa_data, 107258951Seric sap->sa.sa_family); 107358951Seric break; 107458951Seric } 107558951Seric 107658951Seric if (hp != NULL) 107758951Seric return hp->h_name; 107858951Seric else 107958951Seric { 108058951Seric /* produce a dotted quad */ 108158951Seric static char buf[512]; 108258951Seric 108358951Seric (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 108458951Seric return buf; 108558951Seric } 108658951Seric } 108758951Seric 108856795Seric # else /* DAEMON */ 108916911Seric /* code for systems without sophisticated networking */ 109010758Seric 109110758Seric /* 109210758Seric ** MYHOSTNAME -- stub version for case of no daemon code. 109311297Seric ** 109411297Seric ** Can't convert to upper case here because might be a UUCP name. 109512313Seric ** 109612313Seric ** Mark, you can change this to be anything you want...... 109710758Seric */ 109810758Seric 109910758Seric char ** 110012313Seric myhostname(hostbuf, size) 110110758Seric char hostbuf[]; 110212313Seric int size; 110310758Seric { 110410758Seric register FILE *f; 110510758Seric 110610758Seric hostbuf[0] = '\0'; 110710758Seric f = fopen("/usr/include/whoami", "r"); 110810758Seric if (f != NULL) 110910758Seric { 111012313Seric (void) fgets(hostbuf, size, f); 111110758Seric fixcrlf(hostbuf, TRUE); 111210758Seric (void) fclose(f); 111310758Seric } 111410758Seric return (NULL); 111510758Seric } 111616911Seric /* 111758951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 111858308Seric ** 111958308Seric ** Parameters: 112058308Seric ** fd -- the descriptor 112158308Seric ** 112258308Seric ** Returns: 112358308Seric ** The host name associated with this descriptor, if it can 112458308Seric ** be determined. 112558308Seric ** NULL otherwise. 112658308Seric ** 112758308Seric ** Side Effects: 112858308Seric ** none 112958308Seric */ 113058308Seric 113158308Seric char * 113258951Seric getauthinfo(fd) 113358308Seric int fd; 113458308Seric { 113558308Seric return NULL; 113658308Seric } 113758308Seric /* 113816911Seric ** MAPHOSTNAME -- turn a hostname into canonical form 113916911Seric ** 114016911Seric ** Parameters: 114156823Seric ** map -- a pointer to the database map. 114216911Seric ** hbuf -- a buffer containing a hostname. 114353751Seric ** avp -- a pointer to a (cf file defined) argument vector. 114416911Seric ** 114516911Seric ** Returns: 114653751Seric ** mapped host name 114751315Seric ** FALSE otherwise. 114816911Seric ** 114916911Seric ** Side Effects: 115016911Seric ** Looks up the host specified in hbuf. If it is not 115116911Seric ** the canonical name for that host, replace it with 115216911Seric ** the canonical name. If the name is unknown, or it 115316911Seric ** is already the canonical name, leave it unchanged. 115416911Seric */ 115510758Seric 115616911Seric /*ARGSUSED*/ 115753751Seric char * 115856823Seric maphostname(map, hbuf, hbsize, avp) 115956823Seric MAP *map; 116016911Seric char *hbuf; 116116911Seric int hbsize; 116253751Seric char **avp; 116316911Seric { 116453751Seric return NULL; 116516911Seric } 116616911Seric 116756795Seric #endif /* DAEMON */ 1168