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*59104Seric static char sccsid[] = "@(#)daemon.c 6.39 (Berkeley) 04/16/93 (with daemon mode)"; 1633780Sbostic #else 17*59104Seric static char sccsid[] = "@(#)daemon.c 6.39 (Berkeley) 04/16/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 2759042Seric #ifdef NAMED_BIND 2859042Seric # include <arpa/nameser.h> 2959042Seric # include <resolv.h> 3059042Seric #endif 3159042Seric 324535Seric /* 334535Seric ** DAEMON.C -- routines to use when running as a daemon. 347556Seric ** 357556Seric ** This entire file is highly dependent on the 4.2 BSD 367556Seric ** interprocess communication primitives. No attempt has 377556Seric ** been made to make this file portable to Version 7, 387556Seric ** Version 6, MPX files, etc. If you should try such a 397556Seric ** thing yourself, I recommend chucking the entire file 407556Seric ** and starting from scratch. Basic semantics are: 417556Seric ** 427556Seric ** getrequests() 437556Seric ** Opens a port and initiates a connection. 447556Seric ** Returns in a child. Must set InChannel and 457556Seric ** OutChannel appropriately. 4610206Seric ** clrdaemon() 4710206Seric ** Close any open files associated with getting 4810206Seric ** the connection; this is used when running the queue, 4910206Seric ** etc., to avoid having extra file descriptors during 5010206Seric ** the queue run and to avoid confusing the network 5110206Seric ** code (if it cares). 5252106Seric ** makeconnection(host, port, outfile, infile, usesecureport) 537556Seric ** Make a connection to the named host on the given 547556Seric ** port. Set *outfile and *infile to the files 557556Seric ** appropriate for communication. Returns zero on 567556Seric ** success, else an exit status describing the 577556Seric ** error. 5856823Seric ** maphostname(map, hbuf, hbufsiz, avp) 5956823Seric ** Convert the entry in hbuf into a canonical form. 604535Seric */ 6158755Seric 6258755Seric extern char *anynet_ntoa(); 634535Seric /* 644535Seric ** GETREQUESTS -- open mail IPC port and get requests. 654535Seric ** 664535Seric ** Parameters: 674535Seric ** none. 684535Seric ** 694535Seric ** Returns: 704535Seric ** none. 714535Seric ** 724535Seric ** Side Effects: 734535Seric ** Waits until some interesting activity occurs. When 744535Seric ** it does, a child is created to process it, and the 754535Seric ** parent waits for completion. Return from this 769886Seric ** routine is always in the child. The file pointers 779886Seric ** "InChannel" and "OutChannel" should be set to point 789886Seric ** to the communication channel. 794535Seric */ 804535Seric 8158849Seric int DaemonSocket = -1; /* fd describing socket */ 8258849Seric SOCKADDR DaemonAddr; /* socket for incoming */ 8316144Seric 844535Seric getrequests() 854535Seric { 869610Seric int t; 879610Seric register struct servent *sp; 8825027Seric int on = 1; 8953751Seric bool refusingconnections = TRUE; 9058419Seric FILE *pidf; 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 { 10358849Seric sp = getservbyname("smtp", "tcp"); 10458849Seric if (sp == NULL) 10558849Seric { 10658909Seric syserr("554 service \"smtp\" unknown"); 10758849Seric goto severe; 10858849Seric } 10958849Seric DaemonAddr.sin.sin_port = sp->s_port; 1109610Seric } 1119610Seric 1129610Seric /* 1139610Seric ** Try to actually open the connection. 1149610Seric */ 1159610Seric 1169610Seric if (tTd(15, 1)) 11758849Seric printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port); 1189610Seric 1199610Seric /* get a socket for the SMTP connection */ 12059041Seric DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0); 12110206Seric if (DaemonSocket < 0) 1229610Seric { 1239610Seric /* probably another daemon already */ 1249610Seric syserr("getrequests: can't create socket"); 1259610Seric severe: 1269610Seric # ifdef LOG 1279610Seric if (LogLevel > 0) 12857663Seric syslog(LOG_ALERT, "problem creating SMTP socket"); 12956795Seric # endif /* LOG */ 1309610Seric finis(); 1319610Seric } 13210347Seric 13310347Seric /* turn on network debugging? */ 13456328Seric if (tTd(15, 101)) 13524945Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on); 13610347Seric 13725027Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on); 13825027Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on); 13925027Seric 14059041Seric switch (DaemonAddr.sa.sa_family) 1419610Seric { 14259041Seric # ifdef NETINET 14359041Seric case AF_INET: 14459041Seric t = sizeof DaemonAddr.sin; 14559041Seric break; 14659041Seric # endif 14759041Seric 14859041Seric # ifdef NETISO 14959041Seric case AF_ISO: 15059041Seric t = sizeof DaemonAddr.siso; 15159041Seric break; 15259041Seric # endif 15359041Seric 15459041Seric default: 15559041Seric t = sizeof DaemonAddr; 15659041Seric break; 15759041Seric } 15859041Seric 15959041Seric if (bind(DaemonSocket, &DaemonAddr.sa, t) < 0) 16059041Seric { 1619610Seric syserr("getrequests: cannot bind"); 16210206Seric (void) close(DaemonSocket); 1639610Seric goto severe; 1649610Seric } 1659610Seric 16624955Seric (void) signal(SIGCHLD, reapchild); 16724945Seric 16858419Seric /* write the pid to the log file for posterity */ 16958419Seric pidf = fopen(PidFile, "w"); 17058419Seric if (pidf != NULL) 17158419Seric { 17258419Seric fprintf(pidf, "%d\n", getpid()); 17358419Seric fclose(pidf); 17458419Seric } 17558419Seric 17658419Seric 1779610Seric if (tTd(15, 1)) 17810206Seric printf("getrequests: %d\n", DaemonSocket); 1799610Seric 1804631Seric for (;;) 1814631Seric { 18214875Seric register int pid; 18311147Seric auto int lotherend; 18453751Seric extern bool refuseconnections(); 18511147Seric 18614875Seric /* see if we are rejecting connections */ 18753751Seric CurrentLA = getla(); 18853751Seric if (refuseconnections()) 18936584Sbostic { 19053751Seric if (!refusingconnections) 19153751Seric { 19253751Seric /* don't queue so peer will fail quickly */ 19353751Seric (void) listen(DaemonSocket, 0); 19453751Seric refusingconnections = TRUE; 19553751Seric } 19657385Seric setproctitle("rejecting connections: load average: %d", 19757385Seric CurrentLA); 19814875Seric sleep(5); 19953751Seric continue; 20036584Sbostic } 20114875Seric 20253751Seric if (refusingconnections) 20353751Seric { 20453751Seric /* start listening again */ 20553751Seric if (listen(DaemonSocket, 10) < 0) 20653751Seric { 20753751Seric syserr("getrequests: cannot listen"); 20853751Seric (void) close(DaemonSocket); 20953751Seric goto severe; 21053751Seric } 21153751Seric setproctitle("accepting connections"); 21253751Seric refusingconnections = FALSE; 21353751Seric } 21453751Seric 2159610Seric /* wait for a connection */ 2169610Seric do 2179610Seric { 2189610Seric errno = 0; 21936230Skarels lotherend = sizeof RealHostAddr; 22046928Sbostic t = accept(DaemonSocket, 22146928Sbostic (struct sockaddr *)&RealHostAddr, &lotherend); 2229610Seric } while (t < 0 && errno == EINTR); 2239610Seric if (t < 0) 2245978Seric { 2259610Seric syserr("getrequests: accept"); 2269610Seric sleep(5); 2279610Seric continue; 2285978Seric } 2294631Seric 2305978Seric /* 2315978Seric ** Create a subprocess to process the mail. 2325978Seric */ 2335978Seric 2347677Seric if (tTd(15, 2)) 2359610Seric printf("getrequests: forking (fd = %d)\n", t); 2365978Seric 2374636Seric pid = fork(); 2384636Seric if (pid < 0) 2394631Seric { 2404636Seric syserr("daemon: cannot fork"); 2414636Seric sleep(10); 2429610Seric (void) close(t); 2434636Seric continue; 2444631Seric } 2454631Seric 2464636Seric if (pid == 0) 2474631Seric { 24858951Seric extern char *hostnamebyanyaddr(); 24911147Seric 2504636Seric /* 2514636Seric ** CHILD -- return to caller. 25211147Seric ** Collect verified idea of sending host. 2534636Seric ** Verify calling user id if possible here. 2544636Seric */ 2554631Seric 25624955Seric (void) signal(SIGCHLD, SIG_DFL); 25724950Seric 25811147Seric /* determine host name */ 25958951Seric RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 26058778Seric 26155173Seric #ifdef LOG 26257977Seric if (LogLevel > 10) 26355173Seric { 26455173Seric /* log connection information */ 26555173Seric syslog(LOG_INFO, "connect from %s (%s)", 26658951Seric RealHostName, anynet_ntoa(&RealHostAddr)); 26755173Seric } 26855173Seric #endif 26955173Seric 27016884Seric /* should we check for illegal connection here? XXX */ 27116884Seric 27211147Seric 27310206Seric (void) close(DaemonSocket); 2749610Seric InChannel = fdopen(t, "r"); 27521062Seric OutChannel = fdopen(dup(t), "w"); 2767677Seric if (tTd(15, 2)) 2775978Seric printf("getreq: returning\n"); 2784636Seric return; 2794631Seric } 2804631Seric 2817117Seric /* close the port so that others will hang (for a while) */ 2829610Seric (void) close(t); 2834631Seric } 2849886Seric /*NOTREACHED*/ 2854631Seric } 2865978Seric /* 28710206Seric ** CLRDAEMON -- reset the daemon connection 28810206Seric ** 28910206Seric ** Parameters: 29010206Seric ** none. 29110206Seric ** 29210206Seric ** Returns: 29310206Seric ** none. 29410206Seric ** 29510206Seric ** Side Effects: 29610206Seric ** releases any resources used by the passive daemon. 29710206Seric */ 29810206Seric 29910206Seric clrdaemon() 30010206Seric { 30110206Seric if (DaemonSocket >= 0) 30210206Seric (void) close(DaemonSocket); 30310206Seric DaemonSocket = -1; 30410206Seric } 30510206Seric /* 30658849Seric ** SETDAEMONOPTIONS -- set options for running the daemon 30758849Seric ** 30858849Seric ** Parameters: 30958849Seric ** p -- the options line. 31058849Seric ** 31158849Seric ** Returns: 31258849Seric ** none. 31358849Seric */ 31458849Seric 31558849Seric setdaemonoptions(p) 31658849Seric register char *p; 31758849Seric { 31858873Seric if (DaemonAddr.sa.sa_family == AF_UNSPEC) 31958873Seric DaemonAddr.sa.sa_family = AF_INET; 32058873Seric 32158849Seric while (p != NULL) 32258849Seric { 32358849Seric register char *f; 32458849Seric register char *v; 32558849Seric 32658849Seric while (isascii(*p) && isspace(*p)) 32758849Seric p++; 32858849Seric if (*p == '\0') 32958849Seric break; 33058849Seric f = p; 33158849Seric p = strchr(p, ','); 33258849Seric if (p != NULL) 33358849Seric *p++ = '\0'; 33458849Seric v = strchr(f, '='); 33558849Seric if (v == NULL) 33658849Seric continue; 33758849Seric while (isascii(*++v) && isspace(*v)) 33858849Seric continue; 33958849Seric 34058849Seric switch (*f) 34158849Seric { 34258873Seric case 'F': /* address family */ 34358849Seric if (isascii(*v) && isdigit(*v)) 34458873Seric DaemonAddr.sa.sa_family = atoi(v); 34558873Seric #ifdef NETINET 34658873Seric else if (strcasecmp(v, "inet") == 0) 34758873Seric DaemonAddr.sa.sa_family = AF_INET; 34858873Seric #endif 34958873Seric #ifdef NETISO 35058873Seric else if (strcasecmp(v, "iso") == 0) 35158873Seric DaemonAddr.sa.sa_family = AF_ISO; 35258873Seric #endif 35358873Seric #ifdef NETNS 35458873Seric else if (strcasecmp(v, "ns") == 0) 35558873Seric DaemonAddr.sa.sa_family = AF_NS; 35658873Seric #endif 35758873Seric #ifdef NETX25 35858873Seric else if (strcasecmp(v, "x.25") == 0) 35958873Seric DaemonAddr.sa.sa_family = AF_CCITT; 36058873Seric #endif 36158849Seric else 36258873Seric syserr("554 Unknown address family %s in Family=option", v); 36358873Seric break; 36458873Seric 36558873Seric case 'A': /* address */ 36658873Seric switch (DaemonAddr.sa.sa_family) 36758849Seric { 36858873Seric #ifdef NETINET 36958873Seric case AF_INET: 37058873Seric if (isascii(*v) && isdigit(*v)) 37158873Seric DaemonAddr.sin.sin_addr.s_addr = inet_network(v); 37258873Seric else 37358873Seric { 37458873Seric register struct netent *np; 37558849Seric 37658873Seric np = getnetbyname(v); 37758873Seric if (np == NULL) 37858873Seric syserr("554 network \"%s\" unknown", v); 37958873Seric else 38058873Seric DaemonAddr.sin.sin_addr.s_addr = np->n_net; 38158873Seric } 38258873Seric break; 38358873Seric #endif 38458873Seric 38558873Seric default: 38658873Seric syserr("554 Address= option unsupported for family %d", 38758873Seric DaemonAddr.sa.sa_family); 38858873Seric break; 38958849Seric } 39058849Seric break; 39158849Seric 39258873Seric case 'P': /* port */ 39358873Seric switch (DaemonAddr.sa.sa_family) 39458849Seric { 39558873Seric short port; 39658849Seric 39758873Seric #ifdef NETINET 39858873Seric case AF_INET: 39958873Seric if (isascii(*v) && isdigit(*v)) 40058873Seric DaemonAddr.sin.sin_port = atoi(v); 40158849Seric else 40258873Seric { 40358873Seric register struct servent *sp; 40458873Seric 40558873Seric sp = getservbyname(v, "tcp"); 40658873Seric if (sp == NULL) 40758909Seric syserr("554 service \"%s\" unknown", v); 40858873Seric else 40958873Seric DaemonAddr.sin.sin_port = sp->s_port; 41058873Seric } 41158873Seric break; 41258873Seric #endif 41358873Seric 41458873Seric #ifdef NETISO 41558873Seric case AF_ISO: 41658873Seric /* assume two byte transport selector */ 41758873Seric if (isascii(*v) && isdigit(*v)) 41858873Seric port = atoi(v); 41958873Seric else 42058873Seric { 42158873Seric register struct servent *sp; 42258873Seric 42358873Seric sp = getservbyname(v, "tcp"); 42458873Seric if (sp == NULL) 42558909Seric syserr("554 service \"%s\" unknown", v); 42658873Seric else 42758873Seric port = sp->s_port; 42858873Seric } 42958873Seric bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 43058873Seric break; 43158873Seric #endif 43258873Seric 43358873Seric default: 43458873Seric syserr("554 Port= option unsupported for family %d", 43558873Seric DaemonAddr.sa.sa_family); 43658873Seric break; 43758849Seric } 43858849Seric break; 43958849Seric } 44058849Seric } 44158849Seric } 44258849Seric /* 4436039Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 4446039Seric ** 4456039Seric ** Parameters: 4466039Seric ** host -- the name of the host. 4476633Seric ** port -- the port number to connect to. 44853739Seric ** mci -- a pointer to the mail connection information 44953739Seric ** structure to be filled in. 45052106Seric ** usesecureport -- if set, use a low numbered (reserved) 45152106Seric ** port to provide some rudimentary authentication. 4526039Seric ** 4536039Seric ** Returns: 4546039Seric ** An exit code telling whether the connection could be 4556039Seric ** made and if not why not. 4566039Seric ** 4576039Seric ** Side Effects: 4586039Seric ** none. 4596039Seric */ 4605978Seric 46158755Seric SOCKADDR CurHostAddr; /* address of current host */ 46258305Seric 46354967Seric int 46453739Seric makeconnection(host, port, mci, usesecureport) 4656039Seric char *host; 4667286Seric u_short port; 46754967Seric register MCI *mci; 46852106Seric bool usesecureport; 4696039Seric { 47029430Sbloom register int i, s; 47129430Sbloom register struct hostent *hp = (struct hostent *)NULL; 47258755Seric SOCKADDR addr; 47352106Seric int sav_errno; 47458755Seric int addrlen; 47535651Seric #ifdef NAMED_BIND 47635651Seric extern int h_errno; 47735651Seric #endif 4786039Seric 4796039Seric /* 4806039Seric ** Set up the address for the mailer. 4819308Seric ** Accept "[a.b.c.d]" syntax for host name. 4826039Seric */ 4836039Seric 48435651Seric #ifdef NAMED_BIND 48525475Smiriam h_errno = 0; 48635651Seric #endif 48725475Smiriam errno = 0; 48858864Seric bzero(&CurHostAddr, sizeof CurHostAddr); 48958906Seric CurHostName = host; 49025475Smiriam 4919308Seric if (host[0] == '[') 4929308Seric { 49311147Seric long hid; 49456795Seric register char *p = strchr(host, ']'); 4959308Seric 49611147Seric if (p != NULL) 4979308Seric { 49811147Seric *p = '\0'; 49911147Seric hid = inet_addr(&host[1]); 50058360Seric if (hid == -1) 50158360Seric { 50258360Seric /* try it as a host name (avoid MX lookup) */ 50358360Seric hp = gethostbyname(&host[1]); 50458360Seric *p = ']'; 50558360Seric goto gothostent; 50658360Seric } 50711147Seric *p = ']'; 5089308Seric } 50958360Seric if (p == NULL) 5109308Seric { 51158151Seric usrerr("553 Invalid numeric domain spec \"%s\"", host); 5129308Seric return (EX_NOHOST); 5139308Seric } 51458778Seric addr.sin.sin_family = AF_INET; 51558778Seric addr.sin.sin_addr.s_addr = hid; 5169308Seric } 5179610Seric else 5189610Seric { 51929430Sbloom hp = gethostbyname(host); 52058360Seric gothostent: 52125475Smiriam if (hp == NULL) 52224945Seric { 52335651Seric #ifdef NAMED_BIND 52425475Smiriam if (errno == ETIMEDOUT || h_errno == TRY_AGAIN) 52525475Smiriam return (EX_TEMPFAIL); 52625657Seric 52735651Seric /* if name server is specified, assume temp fail */ 52835651Seric if (errno == ECONNREFUSED && UseNameServer) 52935651Seric return (EX_TEMPFAIL); 53035651Seric #endif 53125475Smiriam return (EX_NOHOST); 53224945Seric } 53358778Seric addr.sa.sa_family = hp->h_addrtype; 53458778Seric switch (hp->h_addrtype) 53558778Seric { 53658778Seric #ifdef NETINET 53758778Seric case AF_INET: 53858755Seric bcopy(hp->h_addr, 53958778Seric &addr.sin.sin_addr, 54058755Seric hp->h_length); 54158778Seric break; 54258778Seric #endif 54358778Seric 54458778Seric default: 54558755Seric bcopy(hp->h_addr, 54658778Seric addr.sa.sa_data, 54758755Seric hp->h_length); 54858778Seric break; 54958778Seric } 55029430Sbloom i = 1; 5519610Seric } 5529610Seric 5539610Seric /* 5549610Seric ** Determine the port number. 5559610Seric */ 5569610Seric 55710011Seric if (port != 0) 55858755Seric port = htons(port); 55910011Seric else 5609610Seric { 5619610Seric register struct servent *sp = getservbyname("smtp", "tcp"); 5629610Seric 5639610Seric if (sp == NULL) 5649610Seric { 56558909Seric syserr("554 makeconnection: service \"smtp\" unknown"); 56657977Seric return (EX_OSERR); 5679610Seric } 56858755Seric port = sp->s_port; 5699610Seric } 5706039Seric 57158778Seric switch (addr.sa.sa_family) 57258755Seric { 57358755Seric case AF_INET: 57458778Seric addr.sin.sin_port = port; 57558755Seric addrlen = sizeof (struct sockaddr_in); 57658755Seric break; 57758755Seric 57858755Seric #ifdef NETISO 57958755Seric case AF_ISO: 58058755Seric /* assume two byte transport selector */ 58158755Seric bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 58258755Seric addrlen = sizeof (struct sockaddr_iso); 58358755Seric break; 58458755Seric #endif 58558755Seric 58658755Seric default: 58758778Seric syserr("Can't connect to address family %d", addr.sa.sa_family); 58858755Seric return (EX_NOHOST); 58958755Seric } 59058755Seric 5916039Seric /* 5926039Seric ** Try to actually open the connection. 5936039Seric */ 5946039Seric 59557736Seric for (;;) 59652106Seric { 59757736Seric if (tTd(16, 1)) 59858755Seric printf("makeconnection (%s [%s])\n", 59958755Seric host, anynet_ntoa(&addr)); 60052106Seric 60158588Seric /* save for logging */ 60258588Seric CurHostAddr = addr; 60358588Seric 60457736Seric if (usesecureport) 60557736Seric { 60657736Seric int rport = IPPORT_RESERVED - 1; 6076039Seric 60857736Seric s = rresvport(&rport); 60957736Seric } 61057736Seric else 61157736Seric { 61257736Seric s = socket(AF_INET, SOCK_STREAM, 0); 61357736Seric } 61457736Seric if (s < 0) 61557736Seric { 61657736Seric sav_errno = errno; 61757736Seric syserr("makeconnection: no socket"); 61857736Seric goto failure; 61957736Seric } 62010347Seric 62157736Seric if (tTd(16, 1)) 62257736Seric printf("makeconnection: fd=%d\n", s); 62357736Seric 62457736Seric /* turn on network debugging? */ 62557736Seric if (tTd(16, 101)) 62657736Seric { 62757736Seric int on = 1; 62857736Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, 62957736Seric (char *)&on, sizeof on); 63057736Seric } 63157736Seric if (CurEnv->e_xfp != NULL) 63257736Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 63357736Seric errno = 0; /* for debugging */ 63458755Seric if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 63557736Seric break; 63657736Seric 63757736Seric /* couldn't connect.... figure out why */ 63827744Sbloom sav_errno = errno; 63927744Sbloom (void) close(s); 64029430Sbloom if (hp && hp->h_addr_list[i]) 64129430Sbloom { 64258755Seric extern char *errstring(); 64358755Seric 64457736Seric if (tTd(16, 1)) 64558755Seric printf("Connect failed (%s); trying new address....\n", 64658755Seric errstring(sav_errno)); 64758778Seric switch (addr.sa.sa_family) 64858778Seric { 64958778Seric #ifdef NETINET 65058778Seric case AF_INET: 65158755Seric bcopy(hp->h_addr_list[i++], 65258778Seric &addr.sin.sin_addr, 65358755Seric hp->h_length); 65458778Seric break; 65558778Seric #endif 65658778Seric 65758778Seric default: 65858755Seric bcopy(hp->h_addr_list[i++], 65958778Seric addr.sa.sa_data, 66052106Seric hp->h_length); 66158778Seric break; 66258778Seric } 66357736Seric continue; 66429430Sbloom } 66529430Sbloom 6666039Seric /* failure, decide if temporary or not */ 6676039Seric failure: 66858542Seric if (transienterror(sav_errno)) 66958542Seric return EX_TEMPFAIL; 67058542Seric else 67158542Seric { 67258542Seric extern char *errstring(); 67311147Seric 67458542Seric message("%s", errstring(sav_errno)); 67558542Seric return (EX_UNAVAILABLE); 6766039Seric } 6776039Seric } 6786039Seric 6796039Seric /* connection ok, put it into canonical form */ 68053739Seric mci->mci_out = fdopen(s, "w"); 68153739Seric mci->mci_in = fdopen(dup(s), "r"); 6826039Seric 68310098Seric return (EX_OK); 6846039Seric } 68510758Seric /* 68610758Seric ** MYHOSTNAME -- return the name of this host. 68710758Seric ** 68810758Seric ** Parameters: 68910758Seric ** hostbuf -- a place to return the name of this host. 69012313Seric ** size -- the size of hostbuf. 69110758Seric ** 69210758Seric ** Returns: 69310758Seric ** A list of aliases for this host. 69410758Seric ** 69510758Seric ** Side Effects: 69658110Seric ** Sets the MyIpAddrs buffer to a list of my IP addresses. 69710758Seric */ 6986039Seric 69958110Seric struct in_addr MyIpAddrs[MAXIPADDR + 1]; 70058110Seric 70110758Seric char ** 70212313Seric myhostname(hostbuf, size) 70310758Seric char hostbuf[]; 70412313Seric int size; 70510758Seric { 70658110Seric register struct hostent *hp; 70710758Seric extern struct hostent *gethostbyname(); 70810758Seric 70923120Seric if (gethostname(hostbuf, size) < 0) 71023120Seric { 71123120Seric (void) strcpy(hostbuf, "localhost"); 71223120Seric } 71311147Seric hp = gethostbyname(hostbuf); 71411147Seric if (hp != NULL) 71516877Seric { 71658110Seric (void) strncpy(hostbuf, hp->h_name, size - 1); 71758110Seric hostbuf[size - 1] = '\0'; 71858110Seric 71958110Seric if (hp->h_addrtype == AF_INET && hp->h_length == 4) 72058110Seric { 72158110Seric register int i; 72258110Seric 72358110Seric for (i = 0; i < MAXIPADDR; i++) 72458110Seric { 72558110Seric if (hp->h_addr_list[i] == NULL) 72658110Seric break; 72758110Seric MyIpAddrs[i].s_addr = *(u_long *) hp->h_addr_list[i]; 72858110Seric } 72958110Seric MyIpAddrs[i].s_addr = 0; 73058110Seric } 73158110Seric 73211147Seric return (hp->h_aliases); 73316877Seric } 73410758Seric else 73510758Seric return (NULL); 73610758Seric } 73751315Seric /* 73858951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 73958308Seric ** 74058951Seric ** Uses RFC1413 protocol to try to get info from the other end. 74158951Seric ** 74258308Seric ** Parameters: 74358308Seric ** fd -- the descriptor 74458308Seric ** 74558308Seric ** Returns: 74658951Seric ** The user@host information associated with this descriptor. 74758308Seric ** 74858308Seric ** Side Effects: 74958951Seric ** Sets RealHostName to the name of the host at the other end. 75058308Seric */ 75158308Seric 75258951Seric #ifdef IDENTPROTO 75358951Seric 75458951Seric static jmp_buf CtxAuthTimeout; 75558951Seric 75658951Seric static 75758951Seric authtimeout() 75858951Seric { 75958951Seric longjmp(CtxAuthTimeout, 1); 76058951Seric } 76158951Seric 76258951Seric #endif 76358951Seric 76458308Seric char * 76558951Seric getauthinfo(fd) 76658308Seric int fd; 76758308Seric { 76858951Seric SOCKADDR fa; 76958951Seric int falen; 770*59104Seric register char *p; 77158951Seric #ifdef IDENTPROTO 77258951Seric SOCKADDR la; 77358951Seric int lalen; 77458951Seric register struct servent *sp; 77558951Seric int s; 77658951Seric int i; 77758951Seric EVENT *ev; 77858951Seric #endif 77958951Seric static char hbuf[MAXNAME * 2 + 2]; 78058951Seric extern char *hostnamebyanyaddr(); 78158951Seric extern char RealUserName[]; /* main.c */ 78258308Seric 78358951Seric falen = sizeof fa; 78458951Seric if (getpeername(fd, &fa.sa, &falen) < 0 || falen <= 0) 78558951Seric { 78658951Seric RealHostName = "localhost"; 78758951Seric (void) sprintf(hbuf, "%s@localhost", RealUserName); 78858957Seric if (tTd(9, 1)) 78958951Seric printf("getauthinfo: %s\n", hbuf); 79058951Seric return hbuf; 79158951Seric } 79258951Seric 79358951Seric RealHostName = newstr(hostnamebyanyaddr(&fa)); 79458951Seric RealHostAddr = fa; 79558951Seric 79658951Seric #ifdef IDENTPROTO 79758951Seric lalen = sizeof la; 79858951Seric if (fa.sa.sa_family != AF_INET || 79958951Seric getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 80058951Seric la.sa.sa_family != AF_INET) 80158951Seric { 80258951Seric /* no ident info */ 80358951Seric goto noident; 80458951Seric } 80558951Seric 80658951Seric /* create ident query */ 80758951Seric (void) sprintf(hbuf, "%d,%d\r\n", fa.sin.sin_port, la.sin.sin_port); 80858951Seric 80958951Seric /* create local address */ 81058951Seric bzero(&la, sizeof la); 81158951Seric 81258951Seric /* create foreign address */ 81358951Seric sp = getservbyname("auth", "tcp"); 81458951Seric if (sp != NULL) 81558951Seric fa.sin.sin_port = sp->s_port; 81658308Seric else 81759097Seric fa.sin.sin_port = htons(113); 81858951Seric 81958951Seric s = -1; 82058951Seric if (setjmp(CtxAuthTimeout) != 0) 82158951Seric { 82258951Seric if (s >= 0) 82358951Seric (void) close(s); 82458951Seric goto noident; 82558951Seric } 82658951Seric 82758951Seric /* put a timeout around the whole thing */ 82858951Seric ev = setevent((time_t) 30, authtimeout, 0); 82958951Seric 83058951Seric /* connect to foreign IDENT server */ 83158951Seric s = socket(AF_INET, SOCK_STREAM, 0); 83258951Seric if (s < 0) 83358951Seric { 83458951Seric clrevent(ev); 83558951Seric goto noident; 83658951Seric } 83758951Seric if (connect(s, &fa.sa, sizeof fa.sin) < 0) 83858951Seric { 83958951Seric closeident: 84058951Seric (void) close(s); 84158951Seric clrevent(ev); 84258951Seric goto noident; 84358951Seric } 84458951Seric 84558957Seric if (tTd(9, 10)) 84658951Seric printf("getauthinfo: sent %s", hbuf); 84758951Seric 84858951Seric /* send query */ 84958951Seric if (write(s, hbuf, strlen(hbuf)) < 0) 85058951Seric goto closeident; 85158951Seric 85258951Seric /* get result */ 85358951Seric i = read(s, hbuf, sizeof hbuf); 85458951Seric (void) close(s); 85558951Seric clrevent(ev); 85658951Seric if (i <= 0) 85758951Seric goto noident; 85858951Seric if (hbuf[--i] == '\n' && hbuf[--i] == '\r') 85958951Seric i--; 86058951Seric hbuf[++i] = '\0'; 86158951Seric 86258957Seric if (tTd(9, 3)) 86358951Seric printf("getauthinfo: got %s\n", hbuf); 86458951Seric 86558951Seric /* parse result */ 86658951Seric p = strchr(hbuf, ':'); 86758951Seric if (p == NULL) 86858951Seric { 86958951Seric /* malformed response */ 87058951Seric goto noident; 87158951Seric } 87258951Seric while (isascii(*++p) && isspace(*p)) 87358951Seric continue; 87458951Seric if (strncasecmp(p, "userid", 6) != 0) 87558951Seric { 87658951Seric /* presumably an error string */ 87758951Seric goto noident; 87858951Seric } 87958951Seric p += 6; 88058951Seric while (isascii(*p) && isspace(*p)) 88158951Seric p++; 88258951Seric if (*p++ != ':') 88358951Seric { 88458951Seric /* either useridxx or malformed response */ 88558951Seric goto noident; 88658951Seric } 88758951Seric 88858951Seric /* p now points to the OSTYPE field */ 88958951Seric p = strchr(p, ':'); 89058951Seric if (p == NULL) 89158951Seric { 89258951Seric /* malformed response */ 89358951Seric goto noident; 89458951Seric } 89558951Seric 89658957Seric /* 1413 says don't do this -- but it's broken otherwise */ 89758957Seric while (isascii(*++p) && isspace(*p)) 89858957Seric continue; 89958957Seric 90058951Seric /* p now points to the authenticated name */ 90158951Seric (void) sprintf(hbuf, "%s@%s", p, RealHostName); 90258957Seric goto finish; 90358957Seric 90458957Seric #endif /* IDENTPROTO */ 90558957Seric 90658957Seric noident: 90758957Seric (void) strcpy(hbuf, RealHostName); 90858957Seric 90958957Seric finish: 91058951Seric if (RealHostName[0] != '[') 91158951Seric { 91258951Seric p = &hbuf[strlen(hbuf)]; 91358951Seric (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 91458951Seric } 91558957Seric if (tTd(9, 1)) 91658951Seric printf("getauthinfo: %s\n", hbuf); 91758308Seric return hbuf; 91858308Seric } 91958308Seric /* 92053751Seric ** MAPHOSTNAME -- turn a hostname into canonical form 92153751Seric ** 92253751Seric ** Parameters: 92356823Seric ** map -- a pointer to this map (unused). 92453751Seric ** hbuf -- a buffer containing a hostname. 92553751Seric ** hbsize -- the size of hbuf. 92655019Seric ** avp -- unused -- for compatibility with other mapping 92755019Seric ** functions. 92859084Seric ** statp -- an exit status (out parameter) -- set to 92959084Seric ** EX_TEMPFAIL if the name server is unavailable. 93053751Seric ** 93153751Seric ** Returns: 93253751Seric ** The mapping, if found. 93353751Seric ** NULL if no mapping found. 93453751Seric ** 93553751Seric ** Side Effects: 93653751Seric ** Looks up the host specified in hbuf. If it is not 93753751Seric ** the canonical name for that host, return the canonical 93853751Seric ** name. 93953751Seric */ 94051315Seric 94153751Seric char * 94259084Seric maphostname(map, hbuf, hbsize, avp, statp) 94356823Seric MAP *map; 94416911Seric char *hbuf; 94516911Seric int hbsize; 94653751Seric char **avp; 94759084Seric int *statp; 94816911Seric { 94916911Seric register struct hostent *hp; 95033932Sbostic u_long in_addr; 95156823Seric char *cp; 95258110Seric int i; 95333932Sbostic struct hostent *gethostbyaddr(); 95416911Seric 95556836Seric /* allow room for null */ 95656823Seric hbsize--; 95753751Seric 95825574Smiriam /* 95933932Sbostic * If first character is a bracket, then it is an address 96033932Sbostic * lookup. Address is copied into a temporary buffer to 96133932Sbostic * strip the brackets and to preserve hbuf if address is 96233932Sbostic * unknown. 96333932Sbostic */ 96453751Seric 96551315Seric if (*hbuf != '[') 96653751Seric { 96755019Seric extern bool getcanonname(); 96855019Seric 96958798Seric if (tTd(9, 1)) 97058798Seric printf("maphostname(%s, %d) => ", hbuf, hbsize); 97158674Seric if (getcanonname(hbuf, hbsize)) 97258796Seric { 97358796Seric if (tTd(9, 1)) 97458796Seric printf("%s\n", hbuf); 97553751Seric return hbuf; 97658796Seric } 97753751Seric else 97858796Seric { 97959084Seric register struct hostent *hp; 98059084Seric extern int h_errno; 98159084Seric 98258796Seric if (tTd(9, 1)) 98359084Seric printf("FAIL (%d)\n", h_errno); 98459084Seric switch (h_errno) 98559084Seric { 98659084Seric case TRY_AGAIN: 98759084Seric *statp = EX_TEMPFAIL; 98859084Seric break; 98959084Seric 99059084Seric case HOST_NOT_FOUND: 99159084Seric *statp = EX_NOHOST; 99259084Seric break; 99359084Seric 99459084Seric case NO_RECOVERY: 99559084Seric *statp = EX_SOFTWARE; 99659084Seric break; 99759084Seric 99859084Seric default: 99959084Seric *statp = EX_UNAVAILABLE; 100059084Seric break; 100159084Seric } 100259084Seric if (*statp != EX_TEMPFAIL || UseNameServer) 100359084Seric return NULL; 100459084Seric 100559084Seric /* 100659084Seric ** Try to look it up in /etc/hosts 100759084Seric */ 100859084Seric 100959084Seric hp = gethostbyname(hbuf); 101059084Seric if (hp == NULL) 101159084Seric { 101259084Seric /* no dice there either */ 101359084Seric *statp = EX_NOHOST; 101459084Seric return NULL; 101559084Seric } 101659084Seric 101759084Seric *statp = EX_OK; 101859084Seric return hp->h_name; 101958796Seric } 102053751Seric } 102156823Seric if ((cp = strchr(hbuf, ']')) == NULL) 102253751Seric return (NULL); 102340994Sbostic *cp = '\0'; 102456823Seric in_addr = inet_addr(&hbuf[1]); 102558110Seric 102658110Seric /* check to see if this is one of our addresses */ 102758110Seric for (i = 0; MyIpAddrs[i].s_addr != 0; i++) 102858110Seric { 102958110Seric if (MyIpAddrs[i].s_addr == in_addr) 103058110Seric { 103158110Seric strncpy(hbuf, MyHostName, hbsize); 103258110Seric hbuf[hbsize] = '\0'; 103358110Seric return hbuf; 103458110Seric } 103558110Seric } 103658110Seric 103758110Seric /* nope -- ask the name server */ 103833932Sbostic hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET); 103933932Sbostic if (hp == NULL) 104053751Seric return (NULL); 104153751Seric 104258110Seric /* found a match -- copy out */ 104356823Seric if (strlen(hp->h_name) > hbsize) 104456823Seric hp->h_name[hbsize] = '\0'; 104553751Seric (void) strcpy(hbuf, hp->h_name); 104653751Seric return hbuf; 104733932Sbostic } 104858755Seric /* 104958755Seric ** ANYNET_NTOA -- convert a network address to printable form. 105058755Seric ** 105158755Seric ** Parameters: 105258755Seric ** sap -- a pointer to a sockaddr structure. 105358755Seric ** 105458755Seric ** Returns: 105558755Seric ** A printable version of that sockaddr. 105658755Seric */ 105716911Seric 105858755Seric char * 105958755Seric anynet_ntoa(sap) 106058755Seric register SOCKADDR *sap; 106158755Seric { 106258755Seric register char *bp; 106358755Seric register char *ap; 106458755Seric int l; 106558755Seric static char buf[80]; 106658755Seric 106758798Seric /* check for null/zero family */ 106858798Seric if (sap == NULL) 106958798Seric return "NULLADDR"; 107058798Seric if (sap->sa.sa_family == 0) 107158798Seric return "0"; 107258798Seric 107358778Seric #ifdef NETINET 107458778Seric if (sap->sa.sa_family == AF_INET) 107558755Seric { 107658755Seric extern char *inet_ntoa(); 107758755Seric 107858755Seric return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 107958755Seric } 108058778Seric #endif 108158755Seric 108258755Seric /* unknown family -- just dump bytes */ 108358778Seric (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 108458755Seric bp = &buf[strlen(buf)]; 108558778Seric ap = sap->sa.sa_data; 108658778Seric for (l = sizeof sap->sa.sa_data; --l >= 0; ) 108758755Seric { 108858755Seric (void) sprintf(bp, "%02x:", *ap++ & 0377); 108958755Seric bp += 3; 109058755Seric } 109158755Seric *--bp = '\0'; 109258755Seric return buf; 109358755Seric } 109458951Seric /* 109558951Seric ** HOSTNAMEBYANYADDR -- return name of host based on address 109658951Seric ** 109758951Seric ** Parameters: 109858951Seric ** sap -- SOCKADDR pointer 109958951Seric ** 110058951Seric ** Returns: 110158951Seric ** text representation of host name. 110258951Seric ** 110358951Seric ** Side Effects: 110458951Seric ** none. 110558951Seric */ 110658755Seric 110758951Seric char * 110858951Seric hostnamebyanyaddr(sap) 110958951Seric register SOCKADDR *sap; 111058951Seric { 111158951Seric register struct hostent *hp; 111258951Seric 111359042Seric #ifdef NAMED_BIND 111459042Seric int saveretry; 111559042Seric 111659042Seric /* shorten name server timeout to avoid higher level timeouts */ 111759042Seric saveretry = _res.retry; 111859042Seric _res.retry = 3; 111959042Seric #endif /* NAMED_BIND */ 112059042Seric 112158951Seric switch (sap->sa.sa_family) 112258951Seric { 112358951Seric #ifdef NETINET 112458951Seric case AF_INET: 112558951Seric hp = gethostbyaddr((char *) &sap->sin.sin_addr, 112658951Seric sizeof sap->sin.sin_addr, 112758951Seric AF_INET); 112858951Seric break; 112958951Seric #endif 113058951Seric 113158951Seric #ifdef NETISO 113258951Seric case AF_ISO: 113358951Seric hp = gethostbyaddr((char *) &sap->siso.siso_addr, 113458951Seric sizeof sap->siso.siso_addr, 113558951Seric AF_ISO); 113658951Seric break; 113758951Seric #endif 113858951Seric 113958951Seric default: 114058951Seric hp = gethostbyaddr(sap->sa.sa_data, 114158951Seric sizeof sap->sa.sa_data, 114258951Seric sap->sa.sa_family); 114358951Seric break; 114458951Seric } 114558951Seric 114659042Seric #ifdef NAMED_BIND 114759042Seric _res.retry = saveretry; 114859042Seric #endif /* NAMED_BIND */ 114959042Seric 115058951Seric if (hp != NULL) 115158951Seric return hp->h_name; 115258951Seric else 115358951Seric { 115458951Seric /* produce a dotted quad */ 115558951Seric static char buf[512]; 115658951Seric 115758951Seric (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 115858951Seric return buf; 115958951Seric } 116058951Seric } 116158951Seric 116256795Seric # else /* DAEMON */ 116316911Seric /* code for systems without sophisticated networking */ 116410758Seric 116510758Seric /* 116610758Seric ** MYHOSTNAME -- stub version for case of no daemon code. 116711297Seric ** 116811297Seric ** Can't convert to upper case here because might be a UUCP name. 116912313Seric ** 117012313Seric ** Mark, you can change this to be anything you want...... 117110758Seric */ 117210758Seric 117310758Seric char ** 117412313Seric myhostname(hostbuf, size) 117510758Seric char hostbuf[]; 117612313Seric int size; 117710758Seric { 117810758Seric register FILE *f; 117910758Seric 118010758Seric hostbuf[0] = '\0'; 118110758Seric f = fopen("/usr/include/whoami", "r"); 118210758Seric if (f != NULL) 118310758Seric { 118412313Seric (void) fgets(hostbuf, size, f); 118510758Seric fixcrlf(hostbuf, TRUE); 118610758Seric (void) fclose(f); 118710758Seric } 118810758Seric return (NULL); 118910758Seric } 119016911Seric /* 119158951Seric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 119258308Seric ** 119358308Seric ** Parameters: 119458308Seric ** fd -- the descriptor 119558308Seric ** 119658308Seric ** Returns: 119758308Seric ** The host name associated with this descriptor, if it can 119858308Seric ** be determined. 119958308Seric ** NULL otherwise. 120058308Seric ** 120158308Seric ** Side Effects: 120258308Seric ** none 120358308Seric */ 120458308Seric 120558308Seric char * 120658951Seric getauthinfo(fd) 120758308Seric int fd; 120858308Seric { 120958308Seric return NULL; 121058308Seric } 121158308Seric /* 121216911Seric ** MAPHOSTNAME -- turn a hostname into canonical form 121316911Seric ** 121416911Seric ** Parameters: 121556823Seric ** map -- a pointer to the database map. 121616911Seric ** hbuf -- a buffer containing a hostname. 121759084Seric ** hbsize -- size of hbuf. 121853751Seric ** avp -- a pointer to a (cf file defined) argument vector. 121959084Seric ** statp -- an exit status (out parameter). 122016911Seric ** 122116911Seric ** Returns: 122253751Seric ** mapped host name 122351315Seric ** FALSE otherwise. 122416911Seric ** 122516911Seric ** Side Effects: 122616911Seric ** Looks up the host specified in hbuf. If it is not 122716911Seric ** the canonical name for that host, replace it with 122816911Seric ** the canonical name. If the name is unknown, or it 122916911Seric ** is already the canonical name, leave it unchanged. 123016911Seric */ 123110758Seric 123216911Seric /*ARGSUSED*/ 123353751Seric char * 123459084Seric maphostname(map, hbuf, hbsize, avp, statp) 123556823Seric MAP *map; 123616911Seric char *hbuf; 123716911Seric int hbsize; 123853751Seric char **avp; 123959084Seric char *statp; 124016911Seric { 124159084Seric register struct hostent *hp; 124259084Seric 124359084Seric hp = gethostbyname(hbuf); 124459084Seric if (hp != NULL) 124559084Seric return hp->h_name; 124659084Seric *statp = EX_NOHOST; 124753751Seric return NULL; 124816911Seric } 124916911Seric 125056795Seric #endif /* DAEMON */ 1251