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*59041Seric static char sccsid[] = "@(#)daemon.c 6.34 (Berkeley) 04/12/93 (with daemon mode)"; 1633780Sbostic #else 17*59041Seric static char sccsid[] = "@(#)daemon.c 6.34 (Berkeley) 04/12/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 */ 115*59041Seric DaemonSocket = socket(DaemonAddr.sa.sa_family, 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 135*59041Seric switch (DaemonAddr.sa.sa_family) 1369610Seric { 137*59041Seric # ifdef NETINET 138*59041Seric case AF_INET: 139*59041Seric t = sizeof DaemonAddr.sin; 140*59041Seric break; 141*59041Seric # endif 142*59041Seric 143*59041Seric # ifdef NETISO 144*59041Seric case AF_ISO: 145*59041Seric t = sizeof DaemonAddr.siso; 146*59041Seric break; 147*59041Seric # endif 148*59041Seric 149*59041Seric default: 150*59041Seric t = sizeof DaemonAddr; 151*59041Seric break; 152*59041Seric } 153*59041Seric 154*59041Seric if (bind(DaemonSocket, &DaemonAddr.sa, t) < 0) 155*59041Seric { 1569610Seric syserr("getrequests: cannot bind"); 15710206Seric (void) close(DaemonSocket); 1589610Seric goto severe; 1599610Seric } 1609610Seric 16124955Seric (void) signal(SIGCHLD, reapchild); 16224945Seric 16358419Seric /* write the pid to the log file for posterity */ 16458419Seric pidf = fopen(PidFile, "w"); 16558419Seric if (pidf != NULL) 16658419Seric { 16758419Seric fprintf(pidf, "%d\n", getpid()); 16858419Seric fclose(pidf); 16958419Seric } 17058419Seric 17158419Seric 1729610Seric if (tTd(15, 1)) 17310206Seric printf("getrequests: %d\n", DaemonSocket); 1749610Seric 1754631Seric for (;;) 1764631Seric { 17714875Seric register int pid; 17811147Seric auto int lotherend; 17953751Seric extern bool refuseconnections(); 18011147Seric 18114875Seric /* see if we are rejecting connections */ 18253751Seric CurrentLA = getla(); 18353751Seric if (refuseconnections()) 18436584Sbostic { 18553751Seric if (!refusingconnections) 18653751Seric { 18753751Seric /* don't queue so peer will fail quickly */ 18853751Seric (void) listen(DaemonSocket, 0); 18953751Seric refusingconnections = TRUE; 19053751Seric } 19157385Seric setproctitle("rejecting connections: load average: %d", 19257385Seric CurrentLA); 19314875Seric sleep(5); 19453751Seric continue; 19536584Sbostic } 19614875Seric 19753751Seric if (refusingconnections) 19853751Seric { 19953751Seric /* start listening again */ 20053751Seric if (listen(DaemonSocket, 10) < 0) 20153751Seric { 20253751Seric syserr("getrequests: cannot listen"); 20353751Seric (void) close(DaemonSocket); 20453751Seric goto severe; 20553751Seric } 20653751Seric setproctitle("accepting connections"); 20753751Seric refusingconnections = FALSE; 20853751Seric } 20953751Seric 2109610Seric /* wait for a connection */ 2119610Seric do 2129610Seric { 2139610Seric errno = 0; 21436230Skarels lotherend = sizeof RealHostAddr; 21546928Sbostic t = accept(DaemonSocket, 21646928Sbostic (struct sockaddr *)&RealHostAddr, &lotherend); 2179610Seric } while (t < 0 && errno == EINTR); 2189610Seric if (t < 0) 2195978Seric { 2209610Seric syserr("getrequests: accept"); 2219610Seric sleep(5); 2229610Seric continue; 2235978Seric } 2244631Seric 2255978Seric /* 2265978Seric ** Create a subprocess to process the mail. 2275978Seric */ 2285978Seric 2297677Seric if (tTd(15, 2)) 2309610Seric printf("getrequests: forking (fd = %d)\n", t); 2315978Seric 2324636Seric pid = fork(); 2334636Seric if (pid < 0) 2344631Seric { 2354636Seric syserr("daemon: cannot fork"); 2364636Seric sleep(10); 2379610Seric (void) close(t); 2384636Seric continue; 2394631Seric } 2404631Seric 2414636Seric if (pid == 0) 2424631Seric { 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 25124955Seric (void) signal(SIGCHLD, SIG_DFL); 25224950Seric 25311147Seric /* determine host name */ 25458951Seric RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 25558778Seric 25655173Seric #ifdef LOG 25757977Seric if (LogLevel > 10) 25855173Seric { 25955173Seric /* log connection information */ 26055173Seric syslog(LOG_INFO, "connect from %s (%s)", 26158951Seric RealHostName, anynet_ntoa(&RealHostAddr)); 26255173Seric } 26355173Seric #endif 26455173Seric 26516884Seric /* should we check for illegal connection here? XXX */ 26616884Seric 26711147Seric 26810206Seric (void) close(DaemonSocket); 2699610Seric InChannel = fdopen(t, "r"); 27021062Seric OutChannel = fdopen(dup(t), "w"); 2717677Seric if (tTd(15, 2)) 2725978Seric printf("getreq: returning\n"); 2734636Seric return; 2744631Seric } 2754631Seric 2767117Seric /* close the port so that others will hang (for a while) */ 2779610Seric (void) close(t); 2784631Seric } 2799886Seric /*NOTREACHED*/ 2804631Seric } 2815978Seric /* 28210206Seric ** CLRDAEMON -- reset the daemon connection 28310206Seric ** 28410206Seric ** Parameters: 28510206Seric ** none. 28610206Seric ** 28710206Seric ** Returns: 28810206Seric ** none. 28910206Seric ** 29010206Seric ** Side Effects: 29110206Seric ** releases any resources used by the passive daemon. 29210206Seric */ 29310206Seric 29410206Seric clrdaemon() 29510206Seric { 29610206Seric if (DaemonSocket >= 0) 29710206Seric (void) close(DaemonSocket); 29810206Seric DaemonSocket = -1; 29910206Seric } 30010206Seric /* 30158849Seric ** SETDAEMONOPTIONS -- set options for running the daemon 30258849Seric ** 30358849Seric ** Parameters: 30458849Seric ** p -- the options line. 30558849Seric ** 30658849Seric ** Returns: 30758849Seric ** none. 30858849Seric */ 30958849Seric 31058849Seric setdaemonoptions(p) 31158849Seric register char *p; 31258849Seric { 31358873Seric if (DaemonAddr.sa.sa_family == AF_UNSPEC) 31458873Seric DaemonAddr.sa.sa_family = AF_INET; 31558873Seric 31658849Seric while (p != NULL) 31758849Seric { 31858849Seric register char *f; 31958849Seric register char *v; 32058849Seric 32158849Seric while (isascii(*p) && isspace(*p)) 32258849Seric p++; 32358849Seric if (*p == '\0') 32458849Seric break; 32558849Seric f = p; 32658849Seric p = strchr(p, ','); 32758849Seric if (p != NULL) 32858849Seric *p++ = '\0'; 32958849Seric v = strchr(f, '='); 33058849Seric if (v == NULL) 33158849Seric continue; 33258849Seric while (isascii(*++v) && isspace(*v)) 33358849Seric continue; 33458849Seric 33558849Seric switch (*f) 33658849Seric { 33758873Seric case 'F': /* address family */ 33858849Seric if (isascii(*v) && isdigit(*v)) 33958873Seric DaemonAddr.sa.sa_family = atoi(v); 34058873Seric #ifdef NETINET 34158873Seric else if (strcasecmp(v, "inet") == 0) 34258873Seric DaemonAddr.sa.sa_family = AF_INET; 34358873Seric #endif 34458873Seric #ifdef NETISO 34558873Seric else if (strcasecmp(v, "iso") == 0) 34658873Seric DaemonAddr.sa.sa_family = AF_ISO; 34758873Seric #endif 34858873Seric #ifdef NETNS 34958873Seric else if (strcasecmp(v, "ns") == 0) 35058873Seric DaemonAddr.sa.sa_family = AF_NS; 35158873Seric #endif 35258873Seric #ifdef NETX25 35358873Seric else if (strcasecmp(v, "x.25") == 0) 35458873Seric DaemonAddr.sa.sa_family = AF_CCITT; 35558873Seric #endif 35658849Seric else 35758873Seric syserr("554 Unknown address family %s in Family=option", v); 35858873Seric break; 35958873Seric 36058873Seric case 'A': /* address */ 36158873Seric switch (DaemonAddr.sa.sa_family) 36258849Seric { 36358873Seric #ifdef NETINET 36458873Seric case AF_INET: 36558873Seric if (isascii(*v) && isdigit(*v)) 36658873Seric DaemonAddr.sin.sin_addr.s_addr = inet_network(v); 36758873Seric else 36858873Seric { 36958873Seric register struct netent *np; 37058849Seric 37158873Seric np = getnetbyname(v); 37258873Seric if (np == NULL) 37358873Seric syserr("554 network \"%s\" unknown", v); 37458873Seric else 37558873Seric DaemonAddr.sin.sin_addr.s_addr = np->n_net; 37658873Seric } 37758873Seric break; 37858873Seric #endif 37958873Seric 38058873Seric default: 38158873Seric syserr("554 Address= option unsupported for family %d", 38258873Seric DaemonAddr.sa.sa_family); 38358873Seric break; 38458849Seric } 38558849Seric break; 38658849Seric 38758873Seric case 'P': /* port */ 38858873Seric switch (DaemonAddr.sa.sa_family) 38958849Seric { 39058873Seric short port; 39158849Seric 39258873Seric #ifdef NETINET 39358873Seric case AF_INET: 39458873Seric if (isascii(*v) && isdigit(*v)) 39558873Seric DaemonAddr.sin.sin_port = atoi(v); 39658849Seric else 39758873Seric { 39858873Seric register struct servent *sp; 39958873Seric 40058873Seric sp = getservbyname(v, "tcp"); 40158873Seric if (sp == NULL) 40258909Seric syserr("554 service \"%s\" unknown", v); 40358873Seric else 40458873Seric DaemonAddr.sin.sin_port = sp->s_port; 40558873Seric } 40658873Seric break; 40758873Seric #endif 40858873Seric 40958873Seric #ifdef NETISO 41058873Seric case AF_ISO: 41158873Seric /* assume two byte transport selector */ 41258873Seric if (isascii(*v) && isdigit(*v)) 41358873Seric port = atoi(v); 41458873Seric else 41558873Seric { 41658873Seric register struct servent *sp; 41758873Seric 41858873Seric sp = getservbyname(v, "tcp"); 41958873Seric if (sp == NULL) 42058909Seric syserr("554 service \"%s\" unknown", v); 42158873Seric else 42258873Seric port = sp->s_port; 42358873Seric } 42458873Seric bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 42558873Seric break; 42658873Seric #endif 42758873Seric 42858873Seric default: 42958873Seric syserr("554 Port= option unsupported for family %d", 43058873Seric DaemonAddr.sa.sa_family); 43158873Seric break; 43258849Seric } 43358849Seric break; 43458849Seric } 43558849Seric } 43658849Seric } 43758849Seric /* 4386039Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 4396039Seric ** 4406039Seric ** Parameters: 4416039Seric ** host -- the name of the host. 4426633Seric ** port -- the port number to connect to. 44353739Seric ** mci -- a pointer to the mail connection information 44453739Seric ** structure to be filled in. 44552106Seric ** usesecureport -- if set, use a low numbered (reserved) 44652106Seric ** port to provide some rudimentary authentication. 4476039Seric ** 4486039Seric ** Returns: 4496039Seric ** An exit code telling whether the connection could be 4506039Seric ** made and if not why not. 4516039Seric ** 4526039Seric ** Side Effects: 4536039Seric ** none. 4546039Seric */ 4555978Seric 45658755Seric SOCKADDR CurHostAddr; /* address of current host */ 45758305Seric 45854967Seric int 45953739Seric makeconnection(host, port, mci, usesecureport) 4606039Seric char *host; 4617286Seric u_short port; 46254967Seric register MCI *mci; 46352106Seric bool usesecureport; 4646039Seric { 46529430Sbloom register int i, s; 46629430Sbloom register struct hostent *hp = (struct hostent *)NULL; 46758755Seric SOCKADDR addr; 46852106Seric int sav_errno; 46958755Seric int addrlen; 47035651Seric #ifdef NAMED_BIND 47135651Seric extern int h_errno; 47235651Seric #endif 4736039Seric 4746039Seric /* 4756039Seric ** Set up the address for the mailer. 4769308Seric ** Accept "[a.b.c.d]" syntax for host name. 4776039Seric */ 4786039Seric 47935651Seric #ifdef NAMED_BIND 48025475Smiriam h_errno = 0; 48135651Seric #endif 48225475Smiriam errno = 0; 48358864Seric bzero(&CurHostAddr, sizeof CurHostAddr); 48458906Seric CurHostName = host; 48525475Smiriam 4869308Seric if (host[0] == '[') 4879308Seric { 48811147Seric long hid; 48956795Seric register char *p = strchr(host, ']'); 4909308Seric 49111147Seric if (p != NULL) 4929308Seric { 49311147Seric *p = '\0'; 49411147Seric hid = inet_addr(&host[1]); 49558360Seric if (hid == -1) 49658360Seric { 49758360Seric /* try it as a host name (avoid MX lookup) */ 49858360Seric hp = gethostbyname(&host[1]); 49958360Seric *p = ']'; 50058360Seric goto gothostent; 50158360Seric } 50211147Seric *p = ']'; 5039308Seric } 50458360Seric if (p == NULL) 5059308Seric { 50658151Seric usrerr("553 Invalid numeric domain spec \"%s\"", host); 5079308Seric return (EX_NOHOST); 5089308Seric } 50958778Seric addr.sin.sin_family = AF_INET; 51058778Seric addr.sin.sin_addr.s_addr = hid; 5119308Seric } 5129610Seric else 5139610Seric { 51429430Sbloom hp = gethostbyname(host); 51558360Seric gothostent: 51625475Smiriam if (hp == NULL) 51724945Seric { 51835651Seric #ifdef NAMED_BIND 51925475Smiriam if (errno == ETIMEDOUT || h_errno == TRY_AGAIN) 52025475Smiriam return (EX_TEMPFAIL); 52125657Seric 52235651Seric /* if name server is specified, assume temp fail */ 52335651Seric if (errno == ECONNREFUSED && UseNameServer) 52435651Seric return (EX_TEMPFAIL); 52535651Seric #endif 52625475Smiriam return (EX_NOHOST); 52724945Seric } 52858778Seric addr.sa.sa_family = hp->h_addrtype; 52958778Seric switch (hp->h_addrtype) 53058778Seric { 53158778Seric #ifdef NETINET 53258778Seric case AF_INET: 53358755Seric bcopy(hp->h_addr, 53458778Seric &addr.sin.sin_addr, 53558755Seric hp->h_length); 53658778Seric break; 53758778Seric #endif 53858778Seric 53958778Seric default: 54058755Seric bcopy(hp->h_addr, 54158778Seric addr.sa.sa_data, 54258755Seric hp->h_length); 54358778Seric break; 54458778Seric } 54529430Sbloom i = 1; 5469610Seric } 5479610Seric 5489610Seric /* 5499610Seric ** Determine the port number. 5509610Seric */ 5519610Seric 55210011Seric if (port != 0) 55358755Seric port = htons(port); 55410011Seric else 5559610Seric { 5569610Seric register struct servent *sp = getservbyname("smtp", "tcp"); 5579610Seric 5589610Seric if (sp == NULL) 5599610Seric { 56058909Seric syserr("554 makeconnection: service \"smtp\" unknown"); 56157977Seric return (EX_OSERR); 5629610Seric } 56358755Seric port = sp->s_port; 5649610Seric } 5656039Seric 56658778Seric switch (addr.sa.sa_family) 56758755Seric { 56858755Seric case AF_INET: 56958778Seric addr.sin.sin_port = port; 57058755Seric addrlen = sizeof (struct sockaddr_in); 57158755Seric break; 57258755Seric 57358755Seric #ifdef NETISO 57458755Seric case AF_ISO: 57558755Seric /* assume two byte transport selector */ 57658755Seric bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 57758755Seric addrlen = sizeof (struct sockaddr_iso); 57858755Seric break; 57958755Seric #endif 58058755Seric 58158755Seric default: 58258778Seric syserr("Can't connect to address family %d", addr.sa.sa_family); 58358755Seric return (EX_NOHOST); 58458755Seric } 58558755Seric 5866039Seric /* 5876039Seric ** Try to actually open the connection. 5886039Seric */ 5896039Seric 59057736Seric for (;;) 59152106Seric { 59257736Seric if (tTd(16, 1)) 59358755Seric printf("makeconnection (%s [%s])\n", 59458755Seric host, anynet_ntoa(&addr)); 59552106Seric 59658588Seric /* save for logging */ 59758588Seric CurHostAddr = addr; 59858588Seric 59957736Seric if (usesecureport) 60057736Seric { 60157736Seric int rport = IPPORT_RESERVED - 1; 6026039Seric 60357736Seric s = rresvport(&rport); 60457736Seric } 60557736Seric else 60657736Seric { 60757736Seric s = socket(AF_INET, SOCK_STREAM, 0); 60857736Seric } 60957736Seric if (s < 0) 61057736Seric { 61157736Seric sav_errno = errno; 61257736Seric syserr("makeconnection: no socket"); 61357736Seric goto failure; 61457736Seric } 61510347Seric 61657736Seric if (tTd(16, 1)) 61757736Seric printf("makeconnection: fd=%d\n", s); 61857736Seric 61957736Seric /* turn on network debugging? */ 62057736Seric if (tTd(16, 101)) 62157736Seric { 62257736Seric int on = 1; 62357736Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, 62457736Seric (char *)&on, sizeof on); 62557736Seric } 62657736Seric if (CurEnv->e_xfp != NULL) 62757736Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 62857736Seric errno = 0; /* for debugging */ 62958755Seric if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 63057736Seric break; 63157736Seric 63257736Seric /* couldn't connect.... figure out why */ 63327744Sbloom sav_errno = errno; 63427744Sbloom (void) close(s); 63529430Sbloom if (hp && hp->h_addr_list[i]) 63629430Sbloom { 63758755Seric extern char *errstring(); 63858755Seric 63957736Seric if (tTd(16, 1)) 64058755Seric printf("Connect failed (%s); trying new address....\n", 64158755Seric errstring(sav_errno)); 64258778Seric switch (addr.sa.sa_family) 64358778Seric { 64458778Seric #ifdef NETINET 64558778Seric case AF_INET: 64658755Seric bcopy(hp->h_addr_list[i++], 64758778Seric &addr.sin.sin_addr, 64858755Seric hp->h_length); 64958778Seric break; 65058778Seric #endif 65158778Seric 65258778Seric default: 65358755Seric bcopy(hp->h_addr_list[i++], 65458778Seric addr.sa.sa_data, 65552106Seric hp->h_length); 65658778Seric break; 65758778Seric } 65857736Seric continue; 65929430Sbloom } 66029430Sbloom 6616039Seric /* failure, decide if temporary or not */ 6626039Seric failure: 66358542Seric if (transienterror(sav_errno)) 66458542Seric return EX_TEMPFAIL; 66558542Seric else 66658542Seric { 66758542Seric extern char *errstring(); 66811147Seric 66958542Seric message("%s", errstring(sav_errno)); 67058542Seric return (EX_UNAVAILABLE); 6716039Seric } 6726039Seric } 6736039Seric 6746039Seric /* connection ok, put it into canonical form */ 67553739Seric mci->mci_out = fdopen(s, "w"); 67653739Seric mci->mci_in = fdopen(dup(s), "r"); 6776039Seric 67810098Seric return (EX_OK); 6796039Seric } 68010758Seric /* 68110758Seric ** MYHOSTNAME -- return the name of this host. 68210758Seric ** 68310758Seric ** Parameters: 68410758Seric ** hostbuf -- a place to return the name of this host. 68512313Seric ** size -- the size of hostbuf. 68610758Seric ** 68710758Seric ** Returns: 68810758Seric ** A list of aliases for this host. 68910758Seric ** 69010758Seric ** Side Effects: 69158110Seric ** Sets the MyIpAddrs buffer to a list of my IP addresses. 69210758Seric */ 6936039Seric 69458110Seric struct in_addr MyIpAddrs[MAXIPADDR + 1]; 69558110Seric 69610758Seric char ** 69712313Seric myhostname(hostbuf, size) 69810758Seric char hostbuf[]; 69912313Seric int size; 70010758Seric { 70158110Seric register struct hostent *hp; 70210758Seric extern struct hostent *gethostbyname(); 70310758Seric 70423120Seric if (gethostname(hostbuf, size) < 0) 70523120Seric { 70623120Seric (void) strcpy(hostbuf, "localhost"); 70723120Seric } 70811147Seric hp = gethostbyname(hostbuf); 70911147Seric if (hp != NULL) 71016877Seric { 71158110Seric (void) strncpy(hostbuf, hp->h_name, size - 1); 71258110Seric hostbuf[size - 1] = '\0'; 71358110Seric 71458110Seric if (hp->h_addrtype == AF_INET && hp->h_length == 4) 71558110Seric { 71658110Seric register int i; 71758110Seric 71858110Seric for (i = 0; i < MAXIPADDR; i++) 71958110Seric { 72058110Seric if (hp->h_addr_list[i] == NULL) 72158110Seric break; 72258110Seric MyIpAddrs[i].s_addr = *(u_long *) hp->h_addr_list[i]; 72358110Seric } 72458110Seric MyIpAddrs[i].s_addr = 0; 72558110Seric } 72658110Seric 72711147Seric return (hp->h_aliases); 72816877Seric } 72910758Seric else 73010758Seric return (NULL); 73110758Seric } 73251315Seric /* 73358951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 73458308Seric ** 73558951Seric ** Uses RFC1413 protocol to try to get info from the other end. 73658951Seric ** 73758308Seric ** Parameters: 73858308Seric ** fd -- the descriptor 73958308Seric ** 74058308Seric ** Returns: 74158951Seric ** The user@host information associated with this descriptor. 74258308Seric ** 74358308Seric ** Side Effects: 74458951Seric ** Sets RealHostName to the name of the host at the other end. 74558308Seric */ 74658308Seric 74758951Seric #define IDENTPROTO 1 74858951Seric 74958951Seric #ifdef IDENTPROTO 75058951Seric 75158951Seric static jmp_buf CtxAuthTimeout; 75258951Seric 75358951Seric static 75458951Seric authtimeout() 75558951Seric { 75658951Seric longjmp(CtxAuthTimeout, 1); 75758951Seric } 75858951Seric 75958951Seric #endif 76058951Seric 76158308Seric char * 76258951Seric getauthinfo(fd) 76358308Seric int fd; 76458308Seric { 76558951Seric SOCKADDR fa; 76658951Seric int falen; 76758951Seric #ifdef IDENTPROTO 76858951Seric SOCKADDR la; 76958951Seric int lalen; 77058951Seric register struct servent *sp; 77158951Seric int s; 77258951Seric int i; 77358951Seric register char *p; 77458951Seric EVENT *ev; 77558951Seric #endif 77658951Seric static char hbuf[MAXNAME * 2 + 2]; 77758951Seric extern char *hostnamebyanyaddr(); 77858951Seric extern char RealUserName[]; /* main.c */ 77958308Seric 78058951Seric falen = sizeof fa; 78158951Seric if (getpeername(fd, &fa.sa, &falen) < 0 || falen <= 0) 78258951Seric { 78358951Seric RealHostName = "localhost"; 78458951Seric (void) sprintf(hbuf, "%s@localhost", RealUserName); 78558957Seric if (tTd(9, 1)) 78658951Seric printf("getauthinfo: %s\n", hbuf); 78758951Seric return hbuf; 78858951Seric } 78958951Seric 79058951Seric RealHostName = newstr(hostnamebyanyaddr(&fa)); 79158951Seric RealHostAddr = fa; 79258951Seric 79358951Seric #ifdef IDENTPROTO 79458951Seric lalen = sizeof la; 79558951Seric if (fa.sa.sa_family != AF_INET || 79658951Seric getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 79758951Seric la.sa.sa_family != AF_INET) 79858951Seric { 79958951Seric /* no ident info */ 80058951Seric goto noident; 80158951Seric } 80258951Seric 80358951Seric /* create ident query */ 80458951Seric (void) sprintf(hbuf, "%d,%d\r\n", fa.sin.sin_port, la.sin.sin_port); 80558951Seric 80658951Seric /* create local address */ 80758951Seric bzero(&la, sizeof la); 80858951Seric 80958951Seric /* create foreign address */ 81058951Seric sp = getservbyname("auth", "tcp"); 81158951Seric if (sp != NULL) 81258951Seric fa.sin.sin_port = sp->s_port; 81358308Seric else 81458951Seric fa.sin.sin_port = 113; 81558951Seric 81658951Seric s = -1; 81758951Seric if (setjmp(CtxAuthTimeout) != 0) 81858951Seric { 81958951Seric if (s >= 0) 82058951Seric (void) close(s); 82158951Seric goto noident; 82258951Seric } 82358951Seric 82458951Seric /* put a timeout around the whole thing */ 82558951Seric ev = setevent((time_t) 30, authtimeout, 0); 82658951Seric 82758951Seric /* connect to foreign IDENT server */ 82858951Seric s = socket(AF_INET, SOCK_STREAM, 0); 82958951Seric if (s < 0) 83058951Seric { 83158951Seric clrevent(ev); 83258951Seric goto noident; 83358951Seric } 83458951Seric if (connect(s, &fa.sa, sizeof fa.sin) < 0) 83558951Seric { 83658951Seric closeident: 83758951Seric (void) close(s); 83858951Seric clrevent(ev); 83958951Seric goto noident; 84058951Seric } 84158951Seric 84258957Seric if (tTd(9, 10)) 84358951Seric printf("getauthinfo: sent %s", hbuf); 84458951Seric 84558951Seric /* send query */ 84658951Seric if (write(s, hbuf, strlen(hbuf)) < 0) 84758951Seric goto closeident; 84858951Seric 84958951Seric /* get result */ 85058951Seric i = read(s, hbuf, sizeof hbuf); 85158951Seric (void) close(s); 85258951Seric clrevent(ev); 85358951Seric if (i <= 0) 85458951Seric goto noident; 85558951Seric if (hbuf[--i] == '\n' && hbuf[--i] == '\r') 85658951Seric i--; 85758951Seric hbuf[++i] = '\0'; 85858951Seric 85958957Seric if (tTd(9, 3)) 86058951Seric printf("getauthinfo: got %s\n", hbuf); 86158951Seric 86258951Seric /* parse result */ 86358951Seric p = strchr(hbuf, ':'); 86458951Seric if (p == NULL) 86558951Seric { 86658951Seric /* malformed response */ 86758951Seric goto noident; 86858951Seric } 86958951Seric while (isascii(*++p) && isspace(*p)) 87058951Seric continue; 87158951Seric if (strncasecmp(p, "userid", 6) != 0) 87258951Seric { 87358951Seric /* presumably an error string */ 87458951Seric goto noident; 87558951Seric } 87658951Seric p += 6; 87758951Seric while (isascii(*p) && isspace(*p)) 87858951Seric p++; 87958951Seric if (*p++ != ':') 88058951Seric { 88158951Seric /* either useridxx or malformed response */ 88258951Seric goto noident; 88358951Seric } 88458951Seric 88558951Seric /* p now points to the OSTYPE field */ 88658951Seric p = strchr(p, ':'); 88758951Seric if (p == NULL) 88858951Seric { 88958951Seric /* malformed response */ 89058951Seric goto noident; 89158951Seric } 89258951Seric 89358957Seric /* 1413 says don't do this -- but it's broken otherwise */ 89458957Seric while (isascii(*++p) && isspace(*p)) 89558957Seric continue; 89658957Seric 89758951Seric /* p now points to the authenticated name */ 89858951Seric (void) sprintf(hbuf, "%s@%s", p, RealHostName); 89958957Seric goto finish; 90058957Seric 90158957Seric #endif /* IDENTPROTO */ 90258957Seric 90358957Seric noident: 90458957Seric (void) strcpy(hbuf, RealHostName); 90558957Seric 90658957Seric finish: 90758951Seric if (RealHostName[0] != '[') 90858951Seric { 90958951Seric p = &hbuf[strlen(hbuf)]; 91058951Seric (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 91158951Seric } 91258957Seric if (tTd(9, 1)) 91358951Seric printf("getauthinfo: %s\n", hbuf); 91458308Seric return hbuf; 91558308Seric } 91658308Seric /* 91753751Seric ** MAPHOSTNAME -- turn a hostname into canonical form 91853751Seric ** 91953751Seric ** Parameters: 92056823Seric ** map -- a pointer to this map (unused). 92153751Seric ** hbuf -- a buffer containing a hostname. 92253751Seric ** hbsize -- the size of hbuf. 92355019Seric ** avp -- unused -- for compatibility with other mapping 92455019Seric ** functions. 92553751Seric ** 92653751Seric ** Returns: 92753751Seric ** The mapping, if found. 92853751Seric ** NULL if no mapping found. 92953751Seric ** 93053751Seric ** Side Effects: 93153751Seric ** Looks up the host specified in hbuf. If it is not 93253751Seric ** the canonical name for that host, return the canonical 93353751Seric ** name. 93453751Seric */ 93551315Seric 93653751Seric char * 93756823Seric maphostname(map, hbuf, hbsize, avp) 93856823Seric MAP *map; 93916911Seric char *hbuf; 94016911Seric int hbsize; 94153751Seric char **avp; 94216911Seric { 94316911Seric register struct hostent *hp; 94433932Sbostic u_long in_addr; 94556823Seric char *cp; 94658110Seric int i; 94733932Sbostic struct hostent *gethostbyaddr(); 94816911Seric 94956836Seric /* allow room for null */ 95056823Seric hbsize--; 95153751Seric 95225574Smiriam /* 95333932Sbostic * If first character is a bracket, then it is an address 95433932Sbostic * lookup. Address is copied into a temporary buffer to 95533932Sbostic * strip the brackets and to preserve hbuf if address is 95633932Sbostic * unknown. 95733932Sbostic */ 95853751Seric 95951315Seric if (*hbuf != '[') 96053751Seric { 96155019Seric extern bool getcanonname(); 96255019Seric 96358798Seric if (tTd(9, 1)) 96458798Seric printf("maphostname(%s, %d) => ", hbuf, hbsize); 96558674Seric if (getcanonname(hbuf, hbsize)) 96658796Seric { 96758796Seric if (tTd(9, 1)) 96858796Seric printf("%s\n", hbuf); 96953751Seric return hbuf; 97058796Seric } 97153751Seric else 97258796Seric { 97358796Seric if (tTd(9, 1)) 97458796Seric printf("FAIL\n"); 97553751Seric return NULL; 97658796Seric } 97753751Seric } 97856823Seric if ((cp = strchr(hbuf, ']')) == NULL) 97953751Seric return (NULL); 98040994Sbostic *cp = '\0'; 98156823Seric in_addr = inet_addr(&hbuf[1]); 98258110Seric 98358110Seric /* check to see if this is one of our addresses */ 98458110Seric for (i = 0; MyIpAddrs[i].s_addr != 0; i++) 98558110Seric { 98658110Seric if (MyIpAddrs[i].s_addr == in_addr) 98758110Seric { 98858110Seric strncpy(hbuf, MyHostName, hbsize); 98958110Seric hbuf[hbsize] = '\0'; 99058110Seric return hbuf; 99158110Seric } 99258110Seric } 99358110Seric 99458110Seric /* nope -- ask the name server */ 99533932Sbostic hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET); 99633932Sbostic if (hp == NULL) 99753751Seric return (NULL); 99853751Seric 99958110Seric /* found a match -- copy out */ 100056823Seric if (strlen(hp->h_name) > hbsize) 100156823Seric hp->h_name[hbsize] = '\0'; 100253751Seric (void) strcpy(hbuf, hp->h_name); 100353751Seric return hbuf; 100433932Sbostic } 100558755Seric /* 100658755Seric ** ANYNET_NTOA -- convert a network address to printable form. 100758755Seric ** 100858755Seric ** Parameters: 100958755Seric ** sap -- a pointer to a sockaddr structure. 101058755Seric ** 101158755Seric ** Returns: 101258755Seric ** A printable version of that sockaddr. 101358755Seric */ 101416911Seric 101558755Seric char * 101658755Seric anynet_ntoa(sap) 101758755Seric register SOCKADDR *sap; 101858755Seric { 101958755Seric register char *bp; 102058755Seric register char *ap; 102158755Seric int l; 102258755Seric static char buf[80]; 102358755Seric 102458798Seric /* check for null/zero family */ 102558798Seric if (sap == NULL) 102658798Seric return "NULLADDR"; 102758798Seric if (sap->sa.sa_family == 0) 102858798Seric return "0"; 102958798Seric 103058778Seric #ifdef NETINET 103158778Seric if (sap->sa.sa_family == AF_INET) 103258755Seric { 103358755Seric extern char *inet_ntoa(); 103458755Seric 103558755Seric return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 103658755Seric } 103758778Seric #endif 103858755Seric 103958755Seric /* unknown family -- just dump bytes */ 104058778Seric (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 104158755Seric bp = &buf[strlen(buf)]; 104258778Seric ap = sap->sa.sa_data; 104358778Seric for (l = sizeof sap->sa.sa_data; --l >= 0; ) 104458755Seric { 104558755Seric (void) sprintf(bp, "%02x:", *ap++ & 0377); 104658755Seric bp += 3; 104758755Seric } 104858755Seric *--bp = '\0'; 104958755Seric return buf; 105058755Seric } 105158951Seric /* 105258951Seric ** HOSTNAMEBYANYADDR -- return name of host based on address 105358951Seric ** 105458951Seric ** Parameters: 105558951Seric ** sap -- SOCKADDR pointer 105658951Seric ** 105758951Seric ** Returns: 105858951Seric ** text representation of host name. 105958951Seric ** 106058951Seric ** Side Effects: 106158951Seric ** none. 106258951Seric */ 106358755Seric 106458951Seric char * 106558951Seric hostnamebyanyaddr(sap) 106658951Seric register SOCKADDR *sap; 106758951Seric { 106858951Seric register struct hostent *hp; 106958951Seric 107058951Seric switch (sap->sa.sa_family) 107158951Seric { 107258951Seric #ifdef NETINET 107358951Seric case AF_INET: 107458951Seric hp = gethostbyaddr((char *) &sap->sin.sin_addr, 107558951Seric sizeof sap->sin.sin_addr, 107658951Seric AF_INET); 107758951Seric break; 107858951Seric #endif 107958951Seric 108058951Seric #ifdef NETISO 108158951Seric case AF_ISO: 108258951Seric hp = gethostbyaddr((char *) &sap->siso.siso_addr, 108358951Seric sizeof sap->siso.siso_addr, 108458951Seric AF_ISO); 108558951Seric break; 108658951Seric #endif 108758951Seric 108858951Seric default: 108958951Seric hp = gethostbyaddr(sap->sa.sa_data, 109058951Seric sizeof sap->sa.sa_data, 109158951Seric sap->sa.sa_family); 109258951Seric break; 109358951Seric } 109458951Seric 109558951Seric if (hp != NULL) 109658951Seric return hp->h_name; 109758951Seric else 109858951Seric { 109958951Seric /* produce a dotted quad */ 110058951Seric static char buf[512]; 110158951Seric 110258951Seric (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 110358951Seric return buf; 110458951Seric } 110558951Seric } 110658951Seric 110756795Seric # else /* DAEMON */ 110816911Seric /* code for systems without sophisticated networking */ 110910758Seric 111010758Seric /* 111110758Seric ** MYHOSTNAME -- stub version for case of no daemon code. 111211297Seric ** 111311297Seric ** Can't convert to upper case here because might be a UUCP name. 111412313Seric ** 111512313Seric ** Mark, you can change this to be anything you want...... 111610758Seric */ 111710758Seric 111810758Seric char ** 111912313Seric myhostname(hostbuf, size) 112010758Seric char hostbuf[]; 112112313Seric int size; 112210758Seric { 112310758Seric register FILE *f; 112410758Seric 112510758Seric hostbuf[0] = '\0'; 112610758Seric f = fopen("/usr/include/whoami", "r"); 112710758Seric if (f != NULL) 112810758Seric { 112912313Seric (void) fgets(hostbuf, size, f); 113010758Seric fixcrlf(hostbuf, TRUE); 113110758Seric (void) fclose(f); 113210758Seric } 113310758Seric return (NULL); 113410758Seric } 113516911Seric /* 113658951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 113758308Seric ** 113858308Seric ** Parameters: 113958308Seric ** fd -- the descriptor 114058308Seric ** 114158308Seric ** Returns: 114258308Seric ** The host name associated with this descriptor, if it can 114358308Seric ** be determined. 114458308Seric ** NULL otherwise. 114558308Seric ** 114658308Seric ** Side Effects: 114758308Seric ** none 114858308Seric */ 114958308Seric 115058308Seric char * 115158951Seric getauthinfo(fd) 115258308Seric int fd; 115358308Seric { 115458308Seric return NULL; 115558308Seric } 115658308Seric /* 115716911Seric ** MAPHOSTNAME -- turn a hostname into canonical form 115816911Seric ** 115916911Seric ** Parameters: 116056823Seric ** map -- a pointer to the database map. 116116911Seric ** hbuf -- a buffer containing a hostname. 116253751Seric ** avp -- a pointer to a (cf file defined) argument vector. 116316911Seric ** 116416911Seric ** Returns: 116553751Seric ** mapped host name 116651315Seric ** FALSE otherwise. 116716911Seric ** 116816911Seric ** Side Effects: 116916911Seric ** Looks up the host specified in hbuf. If it is not 117016911Seric ** the canonical name for that host, replace it with 117116911Seric ** the canonical name. If the name is unknown, or it 117216911Seric ** is already the canonical name, leave it unchanged. 117316911Seric */ 117410758Seric 117516911Seric /*ARGSUSED*/ 117653751Seric char * 117756823Seric maphostname(map, hbuf, hbsize, avp) 117856823Seric MAP *map; 117916911Seric char *hbuf; 118016911Seric int hbsize; 118153751Seric char **avp; 118216911Seric { 118353751Seric return NULL; 118416911Seric } 118516911Seric 118656795Seric #endif /* DAEMON */ 1187