1*22700Sdist /* 2*22700Sdist ** Sendmail 3*22700Sdist ** Copyright (c) 1983 Eric P. Allman 4*22700Sdist ** Berkeley, California 5*22700Sdist ** 6*22700Sdist ** Copyright (c) 1983 Regents of the University of California. 7*22700Sdist ** All rights reserved. The Berkeley software License Agreement 8*22700Sdist ** specifies the terms and conditions for redistribution. 9*22700Sdist */ 10*22700Sdist 11*22700Sdist #ifndef lint 12*22700Sdist static char SccsId[] = "@(#)daemon.c 5.1 (Berkeley) 06/07/85"; 13*22700Sdist #endif not lint 14*22700Sdist 156039Seric # include <errno.h> 164535Seric # include "sendmail.h" 174535Seric 185978Seric #ifndef DAEMON 19*22700Sdist SCCSID(@(#)daemon.c 5.1 06/07/85 (w/o daemon mode)); 205978Seric #else 214535Seric 229610Seric #include <sys/socket.h> 239610Seric #include <netinet/in.h> 249610Seric #include <netdb.h> 2513586Swnj #include <sys/wait.h> 265978Seric 27*22700Sdist SCCSID(@(#)daemon.c 5.1 06/07/85 (with daemon mode)); 285978Seric 294535Seric /* 304535Seric ** DAEMON.C -- routines to use when running as a daemon. 317556Seric ** 327556Seric ** This entire file is highly dependent on the 4.2 BSD 337556Seric ** interprocess communication primitives. No attempt has 347556Seric ** been made to make this file portable to Version 7, 357556Seric ** Version 6, MPX files, etc. If you should try such a 367556Seric ** thing yourself, I recommend chucking the entire file 377556Seric ** and starting from scratch. Basic semantics are: 387556Seric ** 397556Seric ** getrequests() 407556Seric ** Opens a port and initiates a connection. 417556Seric ** Returns in a child. Must set InChannel and 427556Seric ** OutChannel appropriately. 4310206Seric ** clrdaemon() 4410206Seric ** Close any open files associated with getting 4510206Seric ** the connection; this is used when running the queue, 4610206Seric ** etc., to avoid having extra file descriptors during 4710206Seric ** the queue run and to avoid confusing the network 4810206Seric ** code (if it cares). 497556Seric ** makeconnection(host, port, outfile, infile) 507556Seric ** Make a connection to the named host on the given 517556Seric ** port. Set *outfile and *infile to the files 527556Seric ** appropriate for communication. Returns zero on 537556Seric ** success, else an exit status describing the 547556Seric ** error. 557556Seric ** 567556Seric ** The semantics of both of these should be clean. 574535Seric */ 584535Seric /* 594535Seric ** GETREQUESTS -- open mail IPC port and get requests. 604535Seric ** 614535Seric ** Parameters: 624535Seric ** none. 634535Seric ** 644535Seric ** Returns: 654535Seric ** none. 664535Seric ** 674535Seric ** Side Effects: 684535Seric ** Waits until some interesting activity occurs. When 694535Seric ** it does, a child is created to process it, and the 704535Seric ** parent waits for completion. Return from this 719886Seric ** routine is always in the child. The file pointers 729886Seric ** "InChannel" and "OutChannel" should be set to point 739886Seric ** to the communication channel. 744535Seric */ 754535Seric 7610206Seric struct sockaddr_in SendmailAddress;/* internet address of sendmail */ 779610Seric 7816144Seric int DaemonSocket = -1; /* fd describing socket */ 7916890Seric char *NetName; /* name of home (local?) network */ 8016144Seric 814535Seric getrequests() 824535Seric { 839610Seric int t; 847117Seric union wait status; 859610Seric register struct servent *sp; 867117Seric 879610Seric /* 889610Seric ** Set up the address for the mailer. 899610Seric */ 909610Seric 919610Seric sp = getservbyname("smtp", "tcp"); 929610Seric if (sp == NULL) 939610Seric { 949610Seric syserr("server \"smtp\" unknown"); 9510167Seric goto severe; 969610Seric } 979610Seric SendmailAddress.sin_family = AF_INET; 989610Seric SendmailAddress.sin_addr.s_addr = INADDR_ANY; 999740Ssam SendmailAddress.sin_port = sp->s_port; 1009610Seric 1019610Seric /* 1029610Seric ** Try to actually open the connection. 1039610Seric */ 1049610Seric 1059610Seric # ifdef DEBUG 1069610Seric if (tTd(15, 1)) 1079610Seric printf("getrequests: port 0x%x\n", SendmailAddress.sin_port); 1089610Seric # endif DEBUG 1099610Seric 1109610Seric /* get a socket for the SMTP connection */ 11110206Seric DaemonSocket = socket(AF_INET, SOCK_STREAM, 0, 0); 11210206Seric if (DaemonSocket < 0) 1139610Seric { 1149610Seric /* probably another daemon already */ 1159610Seric syserr("getrequests: can't create socket"); 1169610Seric severe: 1179610Seric # ifdef LOG 1189610Seric if (LogLevel > 0) 1199610Seric syslog(LOG_SALERT, "cannot get connection"); 1209610Seric # endif LOG 1219610Seric finis(); 1229610Seric } 12310347Seric 12410347Seric #ifdef DEBUG 12510347Seric /* turn on network debugging? */ 12610347Seric if (tTd(15, 15)) 12710347Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, 0, 0); 12810347Seric #endif DEBUG 12910347Seric 13010206Seric if (bind(DaemonSocket, &SendmailAddress, sizeof SendmailAddress, 0) < 0) 1319610Seric { 1329610Seric syserr("getrequests: cannot bind"); 13310206Seric (void) close(DaemonSocket); 1349610Seric goto severe; 1359610Seric } 13610206Seric listen(DaemonSocket, 10); 1379610Seric 1389610Seric # ifdef DEBUG 1399610Seric if (tTd(15, 1)) 14010206Seric printf("getrequests: %d\n", DaemonSocket); 1419610Seric # endif DEBUG 1429610Seric 1434631Seric for (;;) 1444631Seric { 14514875Seric register int pid; 14611147Seric auto int lotherend; 14711147Seric struct sockaddr_in otherend; 14814875Seric extern int RefuseLA; 14911147Seric 15014875Seric /* see if we are rejecting connections */ 15114875Seric while (getla() > RefuseLA) 15214875Seric sleep(5); 15314875Seric 1549610Seric /* wait for a connection */ 1559610Seric do 1569610Seric { 1579610Seric errno = 0; 1589610Seric lotherend = sizeof otherend; 15910206Seric t = accept(DaemonSocket, &otherend, &lotherend, 0); 1609610Seric } while (t < 0 && errno == EINTR); 1619610Seric if (t < 0) 1625978Seric { 1639610Seric syserr("getrequests: accept"); 1649610Seric sleep(5); 1659610Seric continue; 1665978Seric } 1674631Seric 1685978Seric /* 1695978Seric ** Create a subprocess to process the mail. 1705978Seric */ 1715978Seric 1725978Seric # ifdef DEBUG 1737677Seric if (tTd(15, 2)) 1749610Seric printf("getrequests: forking (fd = %d)\n", t); 1755978Seric # endif DEBUG 1765978Seric 1774636Seric pid = fork(); 1784636Seric if (pid < 0) 1794631Seric { 1804636Seric syserr("daemon: cannot fork"); 1814636Seric sleep(10); 1829610Seric (void) close(t); 1834636Seric continue; 1844631Seric } 1854631Seric 1864636Seric if (pid == 0) 1874631Seric { 18811147Seric extern struct hostent *gethostbyaddr(); 18911147Seric register struct hostent *hp; 19011147Seric extern char *RealHostName; /* srvrsmtp.c */ 19111147Seric char buf[MAXNAME]; 19211147Seric 1934636Seric /* 1944636Seric ** CHILD -- return to caller. 19511147Seric ** Collect verified idea of sending host. 1964636Seric ** Verify calling user id if possible here. 1974636Seric */ 1984631Seric 19911147Seric /* determine host name */ 20011147Seric hp = gethostbyaddr(&otherend.sin_addr, sizeof otherend.sin_addr, AF_INET); 20111147Seric if (hp != NULL) 20216890Seric { 20316890Seric strcpy(buf, hp->h_name); 20416890Seric if (NetName != NULL && NetName[0] != '\0' && 20516894Seric index(hp->h_name, '.') == NULL) 20616890Seric { 20716890Seric strcat(buf, "."); 20816890Seric strcat(buf, NetName); 20916890Seric } 21016890Seric } 21111147Seric else 21216884Seric { 21316884Seric extern char *inet_ntoa(); 21416884Seric 21516884Seric /* produce a dotted quad */ 21616884Seric (void) sprintf(buf, "[%s]", 21716884Seric inet_ntoa(otherend.sin_addr)); 21816884Seric } 21916884Seric 22016884Seric /* should we check for illegal connection here? XXX */ 22116884Seric 22211147Seric RealHostName = newstr(buf); 22311147Seric 22410206Seric (void) close(DaemonSocket); 2259610Seric InChannel = fdopen(t, "r"); 22621062Seric OutChannel = fdopen(dup(t), "w"); 2275978Seric # ifdef DEBUG 2287677Seric if (tTd(15, 2)) 2295978Seric printf("getreq: returning\n"); 2305978Seric # endif DEBUG 2317876Seric # ifdef LOG 2327876Seric if (LogLevel > 11) 2337876Seric syslog(LOG_DEBUG, "connected, pid=%d", getpid()); 2347876Seric # endif LOG 2354636Seric return; 2364631Seric } 2374631Seric 2384636Seric /* 2394636Seric ** PARENT -- wait for child to terminate. 2404636Seric ** Perhaps we should allow concurrent processing? 2414636Seric */ 2424631Seric 2435978Seric # ifdef DEBUG 2447677Seric if (tTd(15, 2)) 2455978Seric { 2465978Seric sleep(2); 2475978Seric printf("getreq: parent waiting\n"); 2485978Seric } 2495978Seric # endif DEBUG 2505978Seric 2517117Seric /* close the port so that others will hang (for a while) */ 2529610Seric (void) close(t); 2537117Seric 25413933Seric /* pick up old zombies */ 25513933Seric while (wait3(&status, WNOHANG, 0) > 0) 25613933Seric continue; 2574631Seric } 2589886Seric /*NOTREACHED*/ 2594631Seric } 2605978Seric /* 26110206Seric ** CLRDAEMON -- reset the daemon connection 26210206Seric ** 26310206Seric ** Parameters: 26410206Seric ** none. 26510206Seric ** 26610206Seric ** Returns: 26710206Seric ** none. 26810206Seric ** 26910206Seric ** Side Effects: 27010206Seric ** releases any resources used by the passive daemon. 27110206Seric */ 27210206Seric 27310206Seric clrdaemon() 27410206Seric { 27510206Seric if (DaemonSocket >= 0) 27610206Seric (void) close(DaemonSocket); 27710206Seric DaemonSocket = -1; 27810206Seric } 27910206Seric /* 2806039Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 2816039Seric ** 2826039Seric ** Parameters: 2836039Seric ** host -- the name of the host. 2846633Seric ** port -- the port number to connect to. 2856039Seric ** outfile -- a pointer to a place to put the outfile 2866039Seric ** descriptor. 2876039Seric ** infile -- ditto for infile. 2886039Seric ** 2896039Seric ** Returns: 2906039Seric ** An exit code telling whether the connection could be 2916039Seric ** made and if not why not. 2926039Seric ** 2936039Seric ** Side Effects: 2946039Seric ** none. 2956039Seric */ 2965978Seric 2976633Seric makeconnection(host, port, outfile, infile) 2986039Seric char *host; 2997286Seric u_short port; 3006039Seric FILE **outfile; 3016039Seric FILE **infile; 3026039Seric { 3036039Seric register int s; 3046039Seric 3056039Seric /* 3066039Seric ** Set up the address for the mailer. 3079308Seric ** Accept "[a.b.c.d]" syntax for host name. 3086039Seric */ 3096039Seric 3109308Seric if (host[0] == '[') 3119308Seric { 31211147Seric long hid; 31311147Seric register char *p = index(host, ']'); 3149308Seric 31511147Seric if (p != NULL) 3169308Seric { 31711147Seric *p = '\0'; 31811147Seric hid = inet_addr(&host[1]); 31911147Seric *p = ']'; 3209308Seric } 32111147Seric if (p == NULL || hid == -1) 3229308Seric { 3239308Seric usrerr("Invalid numeric domain spec \"%s\"", host); 3249308Seric return (EX_NOHOST); 3259308Seric } 3269308Seric SendmailAddress.sin_addr.s_addr = hid; 3279308Seric } 3289610Seric else 3299610Seric { 3309610Seric register struct hostent *hp = gethostbyname(host); 3319610Seric 33211147Seric if (hp == NULL) 3339610Seric return (EX_NOHOST); 33416884Seric bcopy(hp->h_addr, (char *) &SendmailAddress.sin_addr, hp->h_length); 3359610Seric } 3369610Seric 3379610Seric /* 3389610Seric ** Determine the port number. 3399610Seric */ 3409610Seric 34110011Seric if (port != 0) 34210011Seric SendmailAddress.sin_port = htons(port); 34310011Seric else 3449610Seric { 3459610Seric register struct servent *sp = getservbyname("smtp", "tcp"); 3469610Seric 3479610Seric if (sp == NULL) 3489610Seric { 3499610Seric syserr("makeconnection: server \"smtp\" unknown"); 3509610Seric return (EX_OSFILE); 3519610Seric } 35210011Seric SendmailAddress.sin_port = sp->s_port; 3539610Seric } 3546039Seric 3556039Seric /* 3566039Seric ** Try to actually open the connection. 3576039Seric */ 3586039Seric 3596039Seric # ifdef DEBUG 3607677Seric if (tTd(16, 1)) 3616039Seric printf("makeconnection (%s)\n", host); 3626039Seric # endif DEBUG 3636039Seric 3649310Seric s = socket(AF_INET, SOCK_STREAM, 0, 0); 3656039Seric if (s < 0) 3666039Seric { 3676039Seric syserr("makeconnection: no socket"); 3686039Seric goto failure; 3696039Seric } 3706039Seric 3716039Seric # ifdef DEBUG 3727677Seric if (tTd(16, 1)) 3736039Seric printf("makeconnection: %d\n", s); 37410347Seric 37510347Seric /* turn on network debugging? */ 37610347Seric if (tTd(16, 14)) 37710347Seric (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 0, 0); 3786039Seric # endif DEBUG 3799546Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 38014383Seric errno = 0; /* for debugging */ 3819610Seric SendmailAddress.sin_family = AF_INET; 3829310Seric if (connect(s, &SendmailAddress, sizeof SendmailAddress, 0) < 0) 3836039Seric { 3846039Seric /* failure, decide if temporary or not */ 3856039Seric failure: 3866039Seric switch (errno) 3876039Seric { 3886039Seric case EISCONN: 3896039Seric case ETIMEDOUT: 3906897Seric case EINPROGRESS: 3916897Seric case EALREADY: 3926897Seric case EADDRINUSE: 39310123Seric case EHOSTDOWN: 3946897Seric case ENETDOWN: 3956897Seric case ENETRESET: 3966897Seric case ENOBUFS: 3977204Seric case ECONNREFUSED: 39811546Seric case ECONNRESET: 39910081Seric case EHOSTUNREACH: 40010098Seric case ENETUNREACH: 4016039Seric /* there are others, I'm sure..... */ 40216884Seric CurEnv->e_flags &= ~EF_FATALERRS; 4036039Seric return (EX_TEMPFAIL); 4046039Seric 40511147Seric case EPERM: 40611147Seric /* why is this happening? */ 40711147Seric syserr("makeconnection: funny failure, addr=%lx, port=%x", 40811147Seric SendmailAddress.sin_addr.s_addr, SendmailAddress.sin_port); 40914383Seric return (EX_TEMPFAIL); 41011147Seric 4116039Seric default: 4126039Seric return (EX_UNAVAILABLE); 4136039Seric } 4146039Seric } 4156039Seric 4166039Seric /* connection ok, put it into canonical form */ 4176039Seric *outfile = fdopen(s, "w"); 4186039Seric *infile = fdopen(s, "r"); 4196039Seric 42010098Seric return (EX_OK); 4216039Seric } 42210758Seric /* 42310758Seric ** MYHOSTNAME -- return the name of this host. 42410758Seric ** 42510758Seric ** Parameters: 42610758Seric ** hostbuf -- a place to return the name of this host. 42712313Seric ** size -- the size of hostbuf. 42810758Seric ** 42910758Seric ** Returns: 43010758Seric ** A list of aliases for this host. 43110758Seric ** 43210758Seric ** Side Effects: 43310758Seric ** none. 43410758Seric */ 4356039Seric 43610758Seric char ** 43712313Seric myhostname(hostbuf, size) 43810758Seric char hostbuf[]; 43912313Seric int size; 44010758Seric { 44110758Seric extern struct hostent *gethostbyname(); 44211147Seric struct hostent *hp; 44310758Seric 44416163Seric gethostname(hostbuf, size); 44511147Seric hp = gethostbyname(hostbuf); 44611147Seric if (hp != NULL) 44716877Seric { 44816877Seric strcpy(hostbuf, hp->h_name); 44911147Seric return (hp->h_aliases); 45016877Seric } 45110758Seric else 45210758Seric return (NULL); 45310758Seric } 45416911Seric /* 45516911Seric ** MAPHOSTNAME -- turn a hostname into canonical form 45616911Seric ** 45716911Seric ** Parameters: 45816911Seric ** hbuf -- a buffer containing a hostname. 45916911Seric ** hbsize -- the size of hbuf. 46016911Seric ** 46116911Seric ** Returns: 46216911Seric ** none. 46316911Seric ** 46416911Seric ** Side Effects: 46516911Seric ** Looks up the host specified in hbuf. If it is not 46616911Seric ** the canonical name for that host, replace it with 46716911Seric ** the canonical name. If the name is unknown, or it 46816911Seric ** is already the canonical name, leave it unchanged. 46916911Seric */ 47010758Seric 47116911Seric maphostname(hbuf, hbsize) 47216911Seric char *hbuf; 47316911Seric int hbsize; 47416911Seric { 47516911Seric register struct hostent *hp; 47616911Seric extern struct hostent *gethostbyname(); 47716911Seric 47816911Seric makelower(hbuf); 47916911Seric hp = gethostbyname(hbuf); 48016911Seric if (hp != NULL) 48116911Seric { 48216911Seric int i = strlen(hp->h_name); 48316911Seric 48416911Seric if (i >= hbsize) 48516911Seric hp->h_name[--i] = '\0'; 48616911Seric strcpy(hbuf, hp->h_name); 48716911Seric } 48816911Seric } 48916911Seric 49010758Seric # else DAEMON 49116911Seric /* code for systems without sophisticated networking */ 49210758Seric 49310758Seric /* 49410758Seric ** MYHOSTNAME -- stub version for case of no daemon code. 49511297Seric ** 49611297Seric ** Can't convert to upper case here because might be a UUCP name. 49712313Seric ** 49812313Seric ** Mark, you can change this to be anything you want...... 49910758Seric */ 50010758Seric 50110758Seric char ** 50212313Seric myhostname(hostbuf, size) 50310758Seric char hostbuf[]; 50412313Seric int size; 50510758Seric { 50610758Seric register FILE *f; 50710758Seric 50810758Seric hostbuf[0] = '\0'; 50910758Seric f = fopen("/usr/include/whoami", "r"); 51010758Seric if (f != NULL) 51110758Seric { 51212313Seric (void) fgets(hostbuf, size, f); 51310758Seric fixcrlf(hostbuf, TRUE); 51410758Seric (void) fclose(f); 51510758Seric } 51610758Seric return (NULL); 51710758Seric } 51816911Seric /* 51916911Seric ** MAPHOSTNAME -- turn a hostname into canonical form 52016911Seric ** 52116911Seric ** Parameters: 52216911Seric ** hbuf -- a buffer containing a hostname. 52316911Seric ** hbsize -- the size of hbuf. 52416911Seric ** 52516911Seric ** Returns: 52616911Seric ** none. 52716911Seric ** 52816911Seric ** Side Effects: 52916911Seric ** Looks up the host specified in hbuf. If it is not 53016911Seric ** the canonical name for that host, replace it with 53116911Seric ** the canonical name. If the name is unknown, or it 53216911Seric ** is already the canonical name, leave it unchanged. 53316911Seric */ 53410758Seric 53516911Seric /*ARGSUSED*/ 53616911Seric maphostname(hbuf, hbsize) 53716911Seric char *hbuf; 53816911Seric int hbsize; 53916911Seric { 54016911Seric return; 54116911Seric } 54216911Seric 54316911Seric 5445978Seric #endif DAEMON 545