1*21134Sdist /* 2*21134Sdist * Copyright (c) 1983 Regents of the University of California. 3*21134Sdist * All rights reserved. The Berkeley software License Agreement 4*21134Sdist * specifies the terms and conditions for redistribution. 5*21134Sdist */ 6*21134Sdist 716374Skarels #ifndef lint 8*21134Sdist char copyright[] = 9*21134Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 10*21134Sdist All rights reserved.\n"; 11*21134Sdist #endif not lint 1216374Skarels 13*21134Sdist #ifndef lint 14*21134Sdist static char sccsid[] = "@(#)inetd.c 5.1 (Berkeley) 05/28/85"; 15*21134Sdist #endif not lint 16*21134Sdist 1716374Skarels /* 1816374Skarels * Inetd - Internet super-server 1916374Skarels * 2016374Skarels * This program invokes all internet services as needed. 2116374Skarels * connection-oriented services are invoked each time a 2216374Skarels * connection is made, by creating a process. This process 2316374Skarels * is passed the connection as file descriptor 0 and is 2416374Skarels * expected to do a getpeername to find out the source host 2516374Skarels * and port. 2616374Skarels * 2716374Skarels * Datagram oriented services are invoked when a datagram 2816374Skarels * arrives; a process is created and passed a pending message 2916374Skarels * on file descriptor 0. Datagram servers may either connect 3016374Skarels * to their peer, freeing up the original socket for inetd 3116374Skarels * to receive further messages on, or ``take over the socket'', 3216374Skarels * processing all arriving datagrams and, eventually, timing 3316374Skarels * out. The first type of server is said to be ``multi-threaded''; 3416374Skarels * the second type of server ``single-threaded''. 3516374Skarels * 3616374Skarels * Inetd uses a configuration file which is read at startup 3716374Skarels * and, possibly, at some later time in response to a hangup signal. 3816374Skarels * The configuration file is ``free format'' with fields given in the 3916374Skarels * order shown below. Continuation lines for an entry must being with 4016374Skarels * a space or tab. All fields must be present in each entry. 4116374Skarels * 4216374Skarels * service name must be in /etc/services 4316374Skarels * socket type stream/dgram/raw/rdm/seqpacket 4416374Skarels * protocol must be in /etc/protocols 4516374Skarels * wait/nowait single-threaded/multi-threaded 4617346Sbloom * user user to run daemon as 4716374Skarels * server program full path name 4816374Skarels * server program arguments maximum of MAXARGS (5) 4916374Skarels * 5016374Skarels * Comment lines are indicated by a `#' in column 1. 5116374Skarels */ 5216374Skarels #include <sys/param.h> 5316374Skarels #include <sys/stat.h> 5416374Skarels #include <sys/ioctl.h> 5516374Skarels #include <sys/socket.h> 5616374Skarels #include <sys/file.h> 5716374Skarels #include <sys/wait.h> 5816374Skarels 5916374Skarels #include <netinet/in.h> 6016374Skarels #include <arpa/inet.h> 6116374Skarels 6216374Skarels #include <errno.h> 6316374Skarels #include <stdio.h> 6416374Skarels #include <signal.h> 6516374Skarels #include <netdb.h> 6616510Sralph #include <syslog.h> 6717346Sbloom #include <pwd.h> 6816374Skarels 6916374Skarels extern int errno; 7016374Skarels 7116374Skarels int reapchild(); 7216374Skarels char *index(); 7316374Skarels char *malloc(); 7416374Skarels 7516374Skarels int debug = 0; 7616374Skarels int allsock; 7716374Skarels int options; 7816374Skarels struct servent *sp; 7916374Skarels 8016374Skarels struct servtab { 8116374Skarels char *se_service; /* name of service */ 8216374Skarels int se_socktype; /* type of socket to use */ 8316374Skarels char *se_proto; /* protocol used */ 8416374Skarels short se_wait; /* single threaded server */ 8516374Skarels short se_checked; /* looked at during merge */ 8617346Sbloom char *se_user; /* user name to run as */ 8716374Skarels char *se_server; /* server program */ 8816374Skarels #define MAXARGV 5 8916374Skarels char *se_argv[MAXARGV+1]; /* program arguments */ 9016374Skarels int se_fd; /* open descriptor */ 9116374Skarels struct sockaddr_in se_ctrladdr;/* bound address */ 9216374Skarels struct servtab *se_next; 9316374Skarels } *servtab; 9416374Skarels 9516374Skarels char *CONFIG = "/etc/inetd.conf"; 9616374Skarels 9716374Skarels main(argc, argv) 9816374Skarels int argc; 9916374Skarels char *argv[]; 10016374Skarels { 10116374Skarels int ctrl; 10216374Skarels register struct servtab *sep; 10317346Sbloom register struct passwd *pwd; 10416374Skarels char *cp, buf[50]; 10516374Skarels int pid, i; 10616374Skarels 10716374Skarels argc--, argv++; 10816374Skarels while (argc > 0 && *argv[0] == '-') { 10916374Skarels for (cp = &argv[0][1]; *cp; cp++) switch (*cp) { 11016374Skarels 11116374Skarels case 'd': 11216374Skarels debug = 1; 11316374Skarels options |= SO_DEBUG; 11416374Skarels break; 11516374Skarels 11616374Skarels default: 11716374Skarels fprintf(stderr, 11816374Skarels "inetd: Unknown flag -%c ignored.\n", *cp); 11916374Skarels break; 12016374Skarels } 12116374Skarels nextopt: 12216374Skarels argc--, argv++; 12316374Skarels } 12416374Skarels if (argc > 0) 12516374Skarels CONFIG = argv[0]; 12616374Skarels #ifndef DEBUG 12716374Skarels if (fork()) 12816374Skarels exit(0); 12916374Skarels { int s; 13016374Skarels for (s = 0; s < 10; s++) 13116374Skarels (void) close(s); 13216374Skarels } 13316374Skarels (void) open("/", O_RDONLY); 13416374Skarels (void) dup2(0, 1); 13516374Skarels (void) dup2(0, 2); 13616374Skarels { int tt = open("/dev/tty", O_RDWR); 13716374Skarels if (tt > 0) { 13816374Skarels ioctl(tt, TIOCNOTTY, 0); 13916374Skarels close(tt); 14016374Skarels } 14116374Skarels } 14216374Skarels #endif 14316510Sralph openlog("inetd", LOG_PID, 0); 14416374Skarels config(); 14516374Skarels signal(SIGHUP, config); 14616374Skarels signal(SIGCHLD, reapchild); 14716374Skarels for (;;) { 14816374Skarels int readable, s, ctrl; 14916374Skarels 15016374Skarels while (allsock == 0) 15116374Skarels sigpause(0); 15216374Skarels readable = allsock; 15316374Skarels if (select(32, &readable, 0, 0, 0) <= 0) 15416374Skarels continue; 15516374Skarels s = ffs(readable)-1; 15616374Skarels if (s < 0) 15716374Skarels continue; 15816374Skarels for (sep = servtab; sep; sep = sep->se_next) 15916374Skarels if (s == sep->se_fd) 16016374Skarels goto found; 16116374Skarels abort(1); 16216374Skarels found: 16316374Skarels if (debug) 16416374Skarels fprintf(stderr, "someone wants %s\n", sep->se_service); 16516374Skarels if (sep->se_socktype == SOCK_STREAM) { 16616374Skarels ctrl = accept(s, 0, 0); 16716510Sralph if (debug) 16816510Sralph fprintf(stderr, "accept, ctrl %d\n", ctrl); 16916374Skarels if (ctrl < 0) { 17016374Skarels if (errno == EINTR) 17116374Skarels continue; 17216510Sralph syslog(LOG_WARNING, "accept: %m"); 17316374Skarels continue; 17416374Skarels } 17516374Skarels } else 17616374Skarels ctrl = sep->se_fd; 17716374Skarels #define mask(sig) (1 << (sig - 1)) 17816374Skarels sigblock(mask(SIGCHLD)|mask(SIGHUP)); 17916374Skarels pid = fork(); 18016374Skarels if (pid < 0) { 18116374Skarels if (sep->se_socktype == SOCK_STREAM) 18216374Skarels close(ctrl); 18316374Skarels sleep(1); 18416374Skarels continue; 18516374Skarels } 18616374Skarels if (sep->se_wait) { 18716374Skarels sep->se_wait = pid; 18816374Skarels allsock &= ~(1 << s); 18916374Skarels } 19016374Skarels sigsetmask(0); 19116374Skarels if (pid == 0) { 19216374Skarels #ifdef DEBUG 19316374Skarels int tt = open("/dev/tty", O_RDWR); 19416374Skarels if (tt > 0) { 19516374Skarels ioctl(tt, TIOCNOTTY, 0); 19616374Skarels close(tt); 19716374Skarels } 19816374Skarels #endif 19916374Skarels dup2(ctrl, 0), close(ctrl), dup2(0, 1); 20016374Skarels for (i = getdtablesize(); --i > 2; ) 20116374Skarels close(i); 20217346Sbloom if ((pwd = getpwnam(sep->se_user)) == NULL) { 20317346Sbloom syslog(LOG_ERR, "getpwnam: %s: No such user" 20417346Sbloom ,sep->se_user); 20517346Sbloom exit(1); 20617346Sbloom } 20717346Sbloom (void) setgid(pwd->pw_gid); 20817346Sbloom initgroups(pwd->pw_name, pwd->pw_gid); 20917346Sbloom (void) setuid(pwd->pw_uid); 21016374Skarels if (debug) 21116374Skarels fprintf(stderr, "%d execl %s\n", 21216374Skarels getpid(), sep->se_server); 21316374Skarels execv(sep->se_server, sep->se_argv); 21416374Skarels if (sep->se_socktype != SOCK_STREAM) 21516510Sralph recv(0, buf, sizeof (buf), 0); 21616510Sralph syslog(LOG_ERR, "execv %s: %m", sep->se_server); 21716374Skarels _exit(1); 21816374Skarels } 21916374Skarels if (sep->se_socktype == SOCK_STREAM) 22016374Skarels close(ctrl); 22116374Skarels } 22216374Skarels } 22316374Skarels 22416374Skarels reapchild() 22516374Skarels { 22616374Skarels union wait status; 22716374Skarels int pid; 22816374Skarels register struct servtab *sep; 22916374Skarels 23016374Skarels for (;;) { 23116374Skarels pid = wait3(&status, WNOHANG, 0); 23216374Skarels if (pid <= 0) 23316374Skarels break; 23416374Skarels if (debug) 23516374Skarels fprintf(stderr, "%d reaped\n", pid); 23616374Skarels for (sep = servtab; sep; sep = sep->se_next) 23716374Skarels if (sep->se_wait == pid) { 23816374Skarels if (status.w_status) 23916510Sralph syslog(LOG_WARNING, 24016510Sralph "%s: exit status 0x%x", 24116374Skarels sep->se_server, status); 24216374Skarels if (debug) 24316374Skarels fprintf(stderr, "restored %s, fd %d\n", 24416374Skarels sep->se_service, sep->se_fd); 24516374Skarels allsock |= 1 << sep->se_fd; 24616374Skarels sep->se_wait = 1; 24716374Skarels } 24816374Skarels } 24916374Skarels } 25016374Skarels 25116374Skarels config() 25216374Skarels { 25316374Skarels register struct servtab *sep, *cp, **sepp; 25416374Skarels struct servtab *getconfigent(), *enter(); 25517156Ssam int omask, on = 1; 25616374Skarels 25716374Skarels if (!setconfig()) { 25816510Sralph syslog(LOG_ERR, "%s: %m", CONFIG); 25916374Skarels return; 26016374Skarels } 26116374Skarels for (sep = servtab; sep; sep = sep->se_next) 26216374Skarels sep->se_checked = 0; 26316374Skarels while (cp = getconfigent()) { 26416374Skarels for (sep = servtab; sep; sep = sep->se_next) 26516374Skarels if (strcmp(sep->se_service, cp->se_service) == 0 && 26616374Skarels strcmp(sep->se_proto, cp->se_proto) == 0) 26716374Skarels break; 26816374Skarels if (sep != 0) { 26916374Skarels int i; 27016374Skarels 27116374Skarels omask = sigblock(mask(SIGCHLD)); 27216374Skarels sep->se_wait = cp->se_wait; 27316374Skarels #define SWAP(a, b) { char *c = a; a = b; b = c; } 27416374Skarels if (cp->se_server) 27516374Skarels SWAP(sep->se_server, cp->se_server); 27616374Skarels for (i = 0; i < MAXARGV; i++) 27716374Skarels SWAP(sep->se_argv[i], cp->se_argv[i]); 27816374Skarels sigsetmask(omask); 27916374Skarels freeconfig(cp); 28016374Skarels } else 28116374Skarels sep = enter(cp); 28216374Skarels sep->se_checked = 1; 28316374Skarels if (sep->se_fd != -1) 28416374Skarels continue; 28516374Skarels sp = getservbyname(sep->se_service, sep->se_proto); 28616374Skarels if (sp == 0) { 28716510Sralph syslog(LOG_ERR, "%s/%s: unknown service", 28816374Skarels sep->se_service, sep->se_proto); 28916374Skarels continue; 29016374Skarels } 29116374Skarels sep->se_ctrladdr.sin_port = sp->s_port; 29216374Skarels if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 29316510Sralph syslog(LOG_ERR, "%s/%s: socket: %m", 29416374Skarels sep->se_service, sep->se_proto); 29516374Skarels continue; 29616374Skarels } 29717156Ssam #define turnon(fd, opt) \ 29817156Ssam setsockopt(fd, SOL_SOCKET, opt, &on, sizeof (on)) 29916374Skarels if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 30017156Ssam turnon(sep->se_fd, SO_DEBUG) < 0) 30116510Sralph syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 30217156Ssam if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 30316510Sralph syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 30417156Ssam #undef turnon 30516374Skarels if (bind(sep->se_fd, &sep->se_ctrladdr, 30616374Skarels sizeof (sep->se_ctrladdr), 0) < 0) { 30716510Sralph syslog(LOG_ERR, "%s/%s: bind: %m", 30816374Skarels sep->se_service, sep->se_proto); 30916374Skarels continue; 31016374Skarels } 31116374Skarels if (sep->se_socktype == SOCK_STREAM) 31216374Skarels listen(sep->se_fd, 10); 31316374Skarels allsock |= 1 << sep->se_fd; 31416374Skarels } 31516374Skarels endconfig(); 31616374Skarels /* 31716374Skarels * Purge anything not looked at above. 31816374Skarels */ 31916374Skarels omask = sigblock(mask(SIGCHLD)); 32016374Skarels sepp = &servtab; 32116374Skarels while (sep = *sepp) { 32216374Skarels if (sep->se_checked) { 32316374Skarels sepp = &sep->se_next; 32416374Skarels continue; 32516374Skarels } 32616374Skarels *sepp = sep->se_next; 32716374Skarels if (sep->se_fd != -1) { 32816374Skarels allsock &= ~(1 << sep->se_fd); 32916374Skarels (void) close(sep->se_fd); 33016374Skarels } 33116374Skarels freeconfig(sep); 33216374Skarels free((char *)sep); 33316374Skarels } 33416374Skarels (void) sigsetmask(omask); 33516374Skarels } 33616374Skarels 33716374Skarels struct servtab * 33816374Skarels enter(cp) 33916374Skarels struct servtab *cp; 34016374Skarels { 34116374Skarels register struct servtab *sep; 34216374Skarels int omask, i; 34316374Skarels char *strdup(); 34416374Skarels 34516374Skarels sep = (struct servtab *)malloc(sizeof (*sep)); 34616374Skarels if (sep == (struct servtab *)0) { 34716510Sralph syslog(LOG_ERR, "Out of memory."); 34816374Skarels exit(-1); 34916374Skarels } 35016374Skarels *sep = *cp; 35116374Skarels sep->se_fd = -1; 35216374Skarels omask = sigblock(mask(SIGCHLD)); 35316374Skarels sep->se_next = servtab; 35416374Skarels servtab = sep; 35516374Skarels sigsetmask(omask); 35616374Skarels return (sep); 35716374Skarels } 35816374Skarels 35916374Skarels FILE *fconfig = NULL; 36016374Skarels struct servtab serv; 36116374Skarels char line[256]; 36216374Skarels char *skip(), *nextline(); 36316374Skarels 36416374Skarels setconfig() 36516374Skarels { 36616374Skarels 36716374Skarels if (fconfig != NULL) { 36816374Skarels fseek(fconfig, 0, L_SET); 36916374Skarels return (1); 37016374Skarels } 37116374Skarels fconfig = fopen(CONFIG, "r"); 37216374Skarels return (fconfig != NULL); 37316374Skarels } 37416374Skarels 37516374Skarels endconfig() 37616374Skarels { 37716374Skarels 37816374Skarels if (fconfig == NULL) 37916374Skarels return; 38016374Skarels fclose(fconfig); 38116374Skarels fconfig = NULL; 38216374Skarels } 38316374Skarels 38416374Skarels struct servtab * 38516374Skarels getconfigent() 38616374Skarels { 38716374Skarels register struct servtab *sep = &serv; 38816374Skarels char *cp, *arg; 38916374Skarels int argc; 39016374Skarels 39116374Skarels while ((cp = nextline(fconfig)) && *cp == '#') 39216374Skarels ; 39316374Skarels if (cp == NULL) 39416374Skarels return ((struct servtab *)0); 39516374Skarels sep->se_service = strdup(skip(&cp)); 39616374Skarels arg = skip(&cp); 39716374Skarels if (strcmp(arg, "stream") == 0) 39816374Skarels sep->se_socktype = SOCK_STREAM; 39916374Skarels else if (strcmp(arg, "dgram") == 0) 40016374Skarels sep->se_socktype = SOCK_DGRAM; 40116374Skarels else if (strcmp(arg, "rdm") == 0) 40216374Skarels sep->se_socktype = SOCK_RDM; 40316374Skarels else if (strcmp(arg, "seqpacket") == 0) 40416374Skarels sep->se_socktype = SOCK_SEQPACKET; 40516374Skarels else if (strcmp(arg, "raw") == 0) 40616374Skarels sep->se_socktype = SOCK_RAW; 40716374Skarels else 40816374Skarels sep->se_socktype = -1; 40916374Skarels sep->se_proto = strdup(skip(&cp)); 41016374Skarels arg = skip(&cp); 41116374Skarels sep->se_wait = strcmp(arg, "wait") == 0; 41217346Sbloom sep->se_user = strdup(skip(&cp)); 41316374Skarels sep->se_server = strdup(skip(&cp)); 41416374Skarels argc = 0; 41516374Skarels for (arg = skip(&cp); cp; arg = skip(&cp)) 41616374Skarels if (argc < MAXARGV) 41716374Skarels sep->se_argv[argc++] = strdup(arg); 41816374Skarels while (argc <= MAXARGV) 41916374Skarels sep->se_argv[argc++] = NULL; 42016374Skarels return (sep); 42116374Skarels } 42216374Skarels 42316374Skarels freeconfig(cp) 42416374Skarels register struct servtab *cp; 42516374Skarels { 42616374Skarels int i; 42716374Skarels 42816374Skarels if (cp->se_service) 42916374Skarels free(cp->se_service); 43016374Skarels if (cp->se_proto) 43116374Skarels free(cp->se_proto); 43216374Skarels if (cp->se_server) 43316374Skarels free(cp->se_server); 43416374Skarels for (i = 0; i < MAXARGV; i++) 43516374Skarels if (cp->se_argv[i]) 43616374Skarels free(cp->se_argv[i]); 43716374Skarels } 43816374Skarels 43916374Skarels char * 44016374Skarels skip(cpp) 44116374Skarels char **cpp; 44216374Skarels { 44316374Skarels register char *cp = *cpp; 44416374Skarels char *start; 44516374Skarels 44616374Skarels again: 44716374Skarels while (*cp == ' ' || *cp == '\t') 44816374Skarels cp++; 44916374Skarels if (*cp == '\0') { 45016374Skarels char c; 45116374Skarels 45216374Skarels c = getc(fconfig); 45316374Skarels ungetc(c, fconfig); 45416374Skarels if (c == ' ' || c == '\t') 45516374Skarels if (cp = nextline(fconfig)) 45616374Skarels goto again; 45716374Skarels *cpp = (char *)0; 45816374Skarels return ((char *)0); 45916374Skarels } 46016374Skarels start = cp; 46116374Skarels while (*cp && *cp != ' ' && *cp != '\t') 46216374Skarels cp++; 46316374Skarels if (*cp != '\0') 46416374Skarels *cp++ = '\0'; 46516374Skarels *cpp = cp; 46616374Skarels return (start); 46716374Skarels } 46816374Skarels 46916374Skarels char * 47016374Skarels nextline(fd) 47116374Skarels FILE *fd; 47216374Skarels { 47316374Skarels char *cp; 47416374Skarels 47516374Skarels if (fgets(line, sizeof (line), fconfig) == NULL) 47616374Skarels return ((char *)0); 47716374Skarels cp = index(line, '\n'); 47816374Skarels if (cp) 47916374Skarels *cp = '\0'; 48016374Skarels return (line); 48116374Skarels } 48216374Skarels 48316374Skarels char * 48416374Skarels strdup(cp) 48516374Skarels char *cp; 48616374Skarels { 48716374Skarels char *new; 48816374Skarels 48916374Skarels if (cp == NULL) 49016374Skarels cp = ""; 49116374Skarels new = malloc(strlen(cp) + 1); 49216374Skarels if (new == (char *)0) { 49316510Sralph syslog(LOG_ERR, "Out of memory."); 49416374Skarels exit(-1); 49516374Skarels } 49616374Skarels strcpy(new, cp); 49716374Skarels return (new); 49816374Skarels } 499