121134Sdist /* 2*49986Skarels * Copyright (c) 1983,1991 The Regents of the University of California. 333136Sbostic * All rights reserved. 433136Sbostic * 542799Sbostic * %sccs.include.redist.c% 621134Sdist */ 721134Sdist 816374Skarels #ifndef lint 921134Sdist char copyright[] = 1021134Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 1121134Sdist All rights reserved.\n"; 1233136Sbostic #endif /* not lint */ 1316374Skarels 1421134Sdist #ifndef lint 15*49986Skarels static char sccsid[] = "@(#)inetd.c 5.30 (Berkeley) 06/03/91"; 1633136Sbostic #endif /* not lint */ 1721134Sdist 1816374Skarels /* 1916374Skarels * Inetd - Internet super-server 2016374Skarels * 2116374Skarels * This program invokes all internet services as needed. 2216374Skarels * connection-oriented services are invoked each time a 2316374Skarels * connection is made, by creating a process. This process 2416374Skarels * is passed the connection as file descriptor 0 and is 2516374Skarels * expected to do a getpeername to find out the source host 2616374Skarels * and port. 2716374Skarels * 2816374Skarels * Datagram oriented services are invoked when a datagram 2916374Skarels * arrives; a process is created and passed a pending message 3016374Skarels * on file descriptor 0. Datagram servers may either connect 3116374Skarels * to their peer, freeing up the original socket for inetd 3216374Skarels * to receive further messages on, or ``take over the socket'', 3316374Skarels * processing all arriving datagrams and, eventually, timing 3416374Skarels * out. The first type of server is said to be ``multi-threaded''; 3516374Skarels * the second type of server ``single-threaded''. 3616374Skarels * 3716374Skarels * Inetd uses a configuration file which is read at startup 3816374Skarels * and, possibly, at some later time in response to a hangup signal. 3916374Skarels * The configuration file is ``free format'' with fields given in the 4016374Skarels * order shown below. Continuation lines for an entry must being with 4116374Skarels * a space or tab. All fields must be present in each entry. 4216374Skarels * 4316374Skarels * service name must be in /etc/services 4416374Skarels * socket type stream/dgram/raw/rdm/seqpacket 4516374Skarels * protocol must be in /etc/protocols 4616374Skarels * wait/nowait single-threaded/multi-threaded 4717346Sbloom * user user to run daemon as 4816374Skarels * server program full path name 4940740Sbostic * server program arguments maximum of MAXARGS (20) 5016374Skarels * 5116374Skarels * Comment lines are indicated by a `#' in column 1. 5216374Skarels */ 5316374Skarels #include <sys/param.h> 5416374Skarels #include <sys/stat.h> 5516374Skarels #include <sys/ioctl.h> 5616374Skarels #include <sys/socket.h> 5716374Skarels #include <sys/file.h> 5816374Skarels #include <sys/wait.h> 5926921Slepreau #include <sys/time.h> 6026921Slepreau #include <sys/resource.h> 6116374Skarels 6216374Skarels #include <netinet/in.h> 6316374Skarels #include <arpa/inet.h> 6416374Skarels 6516374Skarels #include <errno.h> 6616374Skarels #include <signal.h> 6716374Skarels #include <netdb.h> 6816510Sralph #include <syslog.h> 6917346Sbloom #include <pwd.h> 7036603Sbostic #include <stdio.h> 7142067Sbostic #include <string.h> 7237282Sbostic #include "pathnames.h" 7316374Skarels 7427535Skarels #define TOOMANY 40 /* don't start more than TOOMANY */ 7527535Skarels #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 7627535Skarels #define RETRYTIME (60*10) /* retry after bind or server fail */ 7727535Skarels 7827535Skarels #define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 7927535Skarels 8016374Skarels extern int errno; 8116374Skarels 8239838Sbostic void config(), reapchild(), retry(); 8316374Skarels char *index(); 8416374Skarels char *malloc(); 8516374Skarels 8616374Skarels int debug = 0; 8725046Skarels int nsock, maxsock; 8825046Skarels fd_set allsock; 8916374Skarels int options; 9027535Skarels int timingout; 9116374Skarels struct servent *sp; 9216374Skarels 9316374Skarels struct servtab { 9416374Skarels char *se_service; /* name of service */ 9516374Skarels int se_socktype; /* type of socket to use */ 9616374Skarels char *se_proto; /* protocol used */ 9716374Skarels short se_wait; /* single threaded server */ 9816374Skarels short se_checked; /* looked at during merge */ 9917346Sbloom char *se_user; /* user name to run as */ 10026877Skarels struct biltin *se_bi; /* if built-in, description */ 10116374Skarels char *se_server; /* server program */ 10240740Sbostic #define MAXARGV 20 10316374Skarels char *se_argv[MAXARGV+1]; /* program arguments */ 10416374Skarels int se_fd; /* open descriptor */ 10516374Skarels struct sockaddr_in se_ctrladdr;/* bound address */ 10627535Skarels int se_count; /* number started since se_time */ 10727535Skarels struct timeval se_time; /* start of se_count */ 10816374Skarels struct servtab *se_next; 10916374Skarels } *servtab; 11016374Skarels 11126877Skarels int echo_stream(), discard_stream(), machtime_stream(); 11226877Skarels int daytime_stream(), chargen_stream(); 11326877Skarels int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg(); 11426877Skarels 11526877Skarels struct biltin { 11626877Skarels char *bi_service; /* internally provided service name */ 11726877Skarels int bi_socktype; /* type of socket supported */ 11826877Skarels short bi_fork; /* 1 if should fork before call */ 11926877Skarels short bi_wait; /* 1 if should wait for child */ 12026877Skarels int (*bi_fn)(); /* function which performs it */ 12126877Skarels } biltins[] = { 12226877Skarels /* Echo received data */ 12326877Skarels "echo", SOCK_STREAM, 1, 0, echo_stream, 12426877Skarels "echo", SOCK_DGRAM, 0, 0, echo_dg, 12526877Skarels 12626877Skarels /* Internet /dev/null */ 12726877Skarels "discard", SOCK_STREAM, 1, 0, discard_stream, 12826877Skarels "discard", SOCK_DGRAM, 0, 0, discard_dg, 12926877Skarels 13026877Skarels /* Return 32 bit time since 1970 */ 13126877Skarels "time", SOCK_STREAM, 0, 0, machtime_stream, 13226877Skarels "time", SOCK_DGRAM, 0, 0, machtime_dg, 13326877Skarels 13426877Skarels /* Return human-readable time */ 13526877Skarels "daytime", SOCK_STREAM, 0, 0, daytime_stream, 13626877Skarels "daytime", SOCK_DGRAM, 0, 0, daytime_dg, 13726877Skarels 13826877Skarels /* Familiar character generator */ 13926877Skarels "chargen", SOCK_STREAM, 1, 0, chargen_stream, 14026877Skarels "chargen", SOCK_DGRAM, 0, 0, chargen_dg, 14126877Skarels 0 14226877Skarels }; 14326877Skarels 14426877Skarels #define NUMINT (sizeof(intab) / sizeof(struct inent)) 14537282Sbostic char *CONFIG = _PATH_INETDCONF; 14626877Skarels char **Argv; 14726877Skarels char *LastArg; 14816374Skarels 14926877Skarels main(argc, argv, envp) 15016374Skarels int argc; 15126877Skarels char *argv[], *envp[]; 15216374Skarels { 15336603Sbostic extern char *optarg; 15436603Sbostic extern int optind; 15516374Skarels register struct servtab *sep; 15617346Sbloom register struct passwd *pwd; 15736603Sbostic register int tmpint; 15827535Skarels struct sigvec sv; 15936603Sbostic int ch, pid, dofork; 16036603Sbostic char buf[50]; 16116374Skarels 16226877Skarels Argv = argv; 16326877Skarels if (envp == 0 || *envp == 0) 16426877Skarels envp = argv; 16526877Skarels while (*envp) 16626877Skarels envp++; 16726877Skarels LastArg = envp[-1] + strlen(envp[-1]); 16816374Skarels 16936603Sbostic while ((ch = getopt(argc, argv, "d")) != EOF) 17036603Sbostic switch(ch) { 17116374Skarels case 'd': 17216374Skarels debug = 1; 17316374Skarels options |= SO_DEBUG; 17416374Skarels break; 17536603Sbostic case '?': 17616374Skarels default: 17736603Sbostic fprintf(stderr, "usage: inetd [-d]"); 17836603Sbostic exit(1); 17916374Skarels } 18036603Sbostic argc -= optind; 18136603Sbostic argv += optind; 18236603Sbostic 18316374Skarels if (argc > 0) 18416374Skarels CONFIG = argv[0]; 18544711Skarels if (debug == 0) 18644711Skarels daemon(0, 0); 18727535Skarels openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 18827535Skarels bzero((char *)&sv, sizeof(sv)); 18927535Skarels sv.sv_mask = SIGBLOCK; 19027535Skarels sv.sv_handler = retry; 19127535Skarels sigvec(SIGALRM, &sv, (struct sigvec *)0); 19216374Skarels config(); 19327535Skarels sv.sv_handler = config; 19427535Skarels sigvec(SIGHUP, &sv, (struct sigvec *)0); 19527535Skarels sv.sv_handler = reapchild; 19627535Skarels sigvec(SIGCHLD, &sv, (struct sigvec *)0); 19727535Skarels 19836603Sbostic { 19936603Sbostic /* space for daemons to overwrite environment for ps */ 20036603Sbostic #define DUMMYSIZE 100 20136603Sbostic char dummy[DUMMYSIZE]; 20236603Sbostic 20336603Sbostic (void)memset(dummy, 'x', sizeof(DUMMYSIZE) - 1); 20436603Sbostic dummy[DUMMYSIZE - 1] = '\0'; 20536603Sbostic (void)setenv("inetd_dummy", dummy, 1); 20636603Sbostic } 20736603Sbostic 20816374Skarels for (;;) { 20936603Sbostic int n, ctrl; 21027535Skarels fd_set readable; 21116374Skarels 21232091Skarels if (nsock == 0) { 21332091Skarels (void) sigblock(SIGBLOCK); 21432091Skarels while (nsock == 0) 21532246Sbostic sigpause(0L); 21632246Sbostic (void) sigsetmask(0L); 21732091Skarels } 21827535Skarels readable = allsock; 21927535Skarels if ((n = select(maxsock + 1, &readable, (fd_set *)0, 22027535Skarels (fd_set *)0, (struct timeval *)0)) <= 0) { 22127535Skarels if (n < 0 && errno != EINTR) 22232091Skarels syslog(LOG_WARNING, "select: %m\n"); 22327535Skarels sleep(1); 22427535Skarels continue; 22527535Skarels } 22627535Skarels for (sep = servtab; n && sep; sep = sep->se_next) 22746973Skarels if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 22846973Skarels n--; 22946973Skarels if (debug) 23046973Skarels fprintf(stderr, "someone wants %s\n", 23146973Skarels sep->se_service); 23246973Skarels if (sep->se_socktype == SOCK_STREAM) { 23346973Skarels ctrl = accept(sep->se_fd, (struct sockaddr *)0, 23446973Skarels (int *)0); 23546973Skarels if (debug) 23646973Skarels fprintf(stderr, "accept, ctrl %d\n", ctrl); 23746973Skarels if (ctrl < 0) { 23846973Skarels if (errno == EINTR) 23946973Skarels continue; 24046973Skarels syslog(LOG_WARNING, "accept (for %s): %m", 24146973Skarels sep->se_service); 24246973Skarels continue; 24346973Skarels } 24446973Skarels } else 24546973Skarels ctrl = sep->se_fd; 24646973Skarels (void) sigblock(SIGBLOCK); 24746973Skarels pid = 0; 24846973Skarels dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork); 24946973Skarels if (dofork) { 25046973Skarels if (sep->se_count++ == 0) 25146973Skarels (void)gettimeofday(&sep->se_time, 25246973Skarels (struct timezone *)0); 25346973Skarels else if (sep->se_count >= TOOMANY) { 25427535Skarels struct timeval now; 25527535Skarels 25627535Skarels (void)gettimeofday(&now, (struct timezone *)0); 25727535Skarels if (now.tv_sec - sep->se_time.tv_sec > 25827535Skarels CNT_INTVL) { 25927535Skarels sep->se_time = now; 26027535Skarels sep->se_count = 1; 26127535Skarels } else { 26227535Skarels syslog(LOG_ERR, 26327535Skarels "%s/%s server failing (looping), service terminated\n", 26427535Skarels sep->se_service, sep->se_proto); 26527535Skarels FD_CLR(sep->se_fd, &allsock); 26627535Skarels (void) close(sep->se_fd); 26727535Skarels sep->se_fd = -1; 26827535Skarels sep->se_count = 0; 26927535Skarels nsock--; 27027535Skarels if (!timingout) { 27127535Skarels timingout = 1; 27227535Skarels alarm(RETRYTIME); 27327535Skarels } 27427535Skarels } 27546973Skarels } 27646973Skarels pid = fork(); 27746973Skarels } 27846973Skarels if (pid < 0) { 27946973Skarels syslog(LOG_ERR, "fork: %m"); 28046973Skarels if (sep->se_socktype == SOCK_STREAM) 28146973Skarels close(ctrl); 28246973Skarels sigsetmask(0L); 28346973Skarels sleep(1); 28446973Skarels continue; 28546973Skarels } 28646973Skarels if (pid && sep->se_wait) { 28746973Skarels sep->se_wait = pid; 28849806Sbostic if (sep->se_fd >= 0) { 28949806Sbostic FD_CLR(sep->se_fd, &allsock); 29049806Sbostic nsock--; 29149806Sbostic } 29246973Skarels } 29346973Skarels sigsetmask(0L); 29446973Skarels if (pid == 0) { 29546973Skarels if (debug && dofork) 29644711Skarels setsid(); 29746973Skarels if (dofork) 29847681Skarels for (tmpint = maxsock; --tmpint > 2; ) 29936603Sbostic if (tmpint != ctrl) 30036603Sbostic close(tmpint); 30146973Skarels if (sep->se_bi) 30226877Skarels (*sep->se_bi->bi_fn)(ctrl, sep); 30346973Skarels else { 30446973Skarels if (debug) 30546973Skarels fprintf(stderr, "%d execl %s\n", 30646973Skarels getpid(), sep->se_server); 30726877Skarels dup2(ctrl, 0); 30826877Skarels close(ctrl); 30926877Skarels dup2(0, 1); 31026877Skarels dup2(0, 2); 31126877Skarels if ((pwd = getpwnam(sep->se_user)) == NULL) { 31226877Skarels syslog(LOG_ERR, 31346973Skarels "getpwnam: %s: No such user", 31446973Skarels sep->se_user); 31527535Skarels if (sep->se_socktype != SOCK_STREAM) 31627535Skarels recv(0, buf, sizeof (buf), 0); 31726877Skarels _exit(1); 31826877Skarels } 31926877Skarels if (pwd->pw_uid) { 32026921Slepreau (void) setgid((gid_t)pwd->pw_gid); 32126877Skarels initgroups(pwd->pw_name, pwd->pw_gid); 32226921Slepreau (void) setuid((uid_t)pwd->pw_uid); 32326877Skarels } 32426877Skarels execv(sep->se_server, sep->se_argv); 32526877Skarels if (sep->se_socktype != SOCK_STREAM) 32626877Skarels recv(0, buf, sizeof (buf), 0); 32726877Skarels syslog(LOG_ERR, "execv %s: %m", sep->se_server); 32826877Skarels _exit(1); 32946973Skarels } 33046973Skarels } 33146973Skarels if (sep->se_socktype == SOCK_STREAM) 33246973Skarels close(ctrl); 33316374Skarels } 33416374Skarels } 33516374Skarels } 33616374Skarels 33739838Sbostic void 33816374Skarels reapchild() 33916374Skarels { 34046973Skarels int status; 34116374Skarels int pid; 34216374Skarels register struct servtab *sep; 34316374Skarels 34416374Skarels for (;;) { 34546973Skarels pid = wait3(&status, WNOHANG, (struct rusage *)0); 34616374Skarels if (pid <= 0) 34716374Skarels break; 34816374Skarels if (debug) 34916374Skarels fprintf(stderr, "%d reaped\n", pid); 35016374Skarels for (sep = servtab; sep; sep = sep->se_next) 35116374Skarels if (sep->se_wait == pid) { 35246973Skarels if (status) 35316510Sralph syslog(LOG_WARNING, 35416510Sralph "%s: exit status 0x%x", 35516374Skarels sep->se_server, status); 35616374Skarels if (debug) 35716374Skarels fprintf(stderr, "restored %s, fd %d\n", 35816374Skarels sep->se_service, sep->se_fd); 35925046Skarels FD_SET(sep->se_fd, &allsock); 36025046Skarels nsock++; 36116374Skarels sep->se_wait = 1; 36216374Skarels } 36316374Skarels } 36416374Skarels } 36516374Skarels 36639838Sbostic void 36716374Skarels config() 36816374Skarels { 36916374Skarels register struct servtab *sep, *cp, **sepp; 37016374Skarels struct servtab *getconfigent(), *enter(); 37132246Sbostic long omask; 37216374Skarels 37316374Skarels if (!setconfig()) { 37416510Sralph syslog(LOG_ERR, "%s: %m", CONFIG); 37516374Skarels return; 37616374Skarels } 37716374Skarels for (sep = servtab; sep; sep = sep->se_next) 37816374Skarels sep->se_checked = 0; 37916374Skarels while (cp = getconfigent()) { 38016374Skarels for (sep = servtab; sep; sep = sep->se_next) 38116374Skarels if (strcmp(sep->se_service, cp->se_service) == 0 && 38216374Skarels strcmp(sep->se_proto, cp->se_proto) == 0) 38316374Skarels break; 38416374Skarels if (sep != 0) { 38516374Skarels int i; 38616374Skarels 38727535Skarels omask = sigblock(SIGBLOCK); 38840745Sbostic /* 38940745Sbostic * sep->se_wait may be holding the pid of a daemon 39040745Sbostic * that we're waiting for. If so, don't overwrite 39140745Sbostic * it unless the config file explicitly says don't 39240745Sbostic * wait. 39340745Sbostic */ 39440745Sbostic if (cp->se_bi == 0 && 39540745Sbostic (sep->se_wait == 1 || cp->se_wait == 0)) 39627535Skarels sep->se_wait = cp->se_wait; 39716374Skarels #define SWAP(a, b) { char *c = a; a = b; b = c; } 39826921Slepreau if (cp->se_user) 39926921Slepreau SWAP(sep->se_user, cp->se_user); 40016374Skarels if (cp->se_server) 40116374Skarels SWAP(sep->se_server, cp->se_server); 40216374Skarels for (i = 0; i < MAXARGV; i++) 40316374Skarels SWAP(sep->se_argv[i], cp->se_argv[i]); 40416374Skarels sigsetmask(omask); 40516374Skarels freeconfig(cp); 40629794Skarels if (debug) 40729794Skarels print_service("REDO", sep); 40829794Skarels } else { 40916374Skarels sep = enter(cp); 41029794Skarels if (debug) 41129794Skarels print_service("ADD ", sep); 41229794Skarels } 41316374Skarels sep->se_checked = 1; 41416374Skarels sp = getservbyname(sep->se_service, sep->se_proto); 41516374Skarels if (sp == 0) { 41616510Sralph syslog(LOG_ERR, "%s/%s: unknown service", 41716374Skarels sep->se_service, sep->se_proto); 41846973Skarels if (sep->se_fd != -1) 41946973Skarels (void) close(sep->se_fd); 42046973Skarels sep->se_fd = -1; 42116374Skarels continue; 42216374Skarels } 42327535Skarels if (sp->s_port != sep->se_ctrladdr.sin_port) { 42427535Skarels sep->se_ctrladdr.sin_port = sp->s_port; 42527535Skarels if (sep->se_fd != -1) 42627535Skarels (void) close(sep->se_fd); 42727535Skarels sep->se_fd = -1; 42816374Skarels } 42927535Skarels if (sep->se_fd == -1) 43027535Skarels setup(sep); 43116374Skarels } 43216374Skarels endconfig(); 43316374Skarels /* 43416374Skarels * Purge anything not looked at above. 43516374Skarels */ 43627535Skarels omask = sigblock(SIGBLOCK); 43716374Skarels sepp = &servtab; 43816374Skarels while (sep = *sepp) { 43916374Skarels if (sep->se_checked) { 44016374Skarels sepp = &sep->se_next; 44116374Skarels continue; 44216374Skarels } 44316374Skarels *sepp = sep->se_next; 44416374Skarels if (sep->se_fd != -1) { 44525046Skarels FD_CLR(sep->se_fd, &allsock); 44625046Skarels nsock--; 44716374Skarels (void) close(sep->se_fd); 44816374Skarels } 44929794Skarels if (debug) 45029794Skarels print_service("FREE", sep); 45116374Skarels freeconfig(sep); 45216374Skarels free((char *)sep); 45316374Skarels } 45416374Skarels (void) sigsetmask(omask); 45516374Skarels } 45616374Skarels 45739838Sbostic void 45827535Skarels retry() 45927535Skarels { 46027535Skarels register struct servtab *sep; 46127535Skarels 46227535Skarels timingout = 0; 46327535Skarels for (sep = servtab; sep; sep = sep->se_next) 46427535Skarels if (sep->se_fd == -1) 46527535Skarels setup(sep); 46627535Skarels } 46727535Skarels 46827535Skarels setup(sep) 46927535Skarels register struct servtab *sep; 47027535Skarels { 47127535Skarels int on = 1; 47227535Skarels 47327535Skarels if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 47427535Skarels syslog(LOG_ERR, "%s/%s: socket: %m", 47527535Skarels sep->se_service, sep->se_proto); 47627535Skarels return; 47727535Skarels } 47827535Skarels #define turnon(fd, opt) \ 47927535Skarels setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 48027535Skarels if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 48127535Skarels turnon(sep->se_fd, SO_DEBUG) < 0) 48227535Skarels syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 48327535Skarels if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 48427535Skarels syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 48527535Skarels #undef turnon 48646907Sbostic if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 48727535Skarels sizeof (sep->se_ctrladdr)) < 0) { 48827535Skarels syslog(LOG_ERR, "%s/%s: bind: %m", 48927535Skarels sep->se_service, sep->se_proto); 49027535Skarels (void) close(sep->se_fd); 49127535Skarels sep->se_fd = -1; 49227535Skarels if (!timingout) { 49327535Skarels timingout = 1; 49427535Skarels alarm(RETRYTIME); 49527535Skarels } 49627535Skarels return; 49727535Skarels } 49827535Skarels if (sep->se_socktype == SOCK_STREAM) 49927535Skarels listen(sep->se_fd, 10); 50027535Skarels FD_SET(sep->se_fd, &allsock); 50127535Skarels nsock++; 50227535Skarels if (sep->se_fd > maxsock) 50327535Skarels maxsock = sep->se_fd; 50427535Skarels } 50527535Skarels 50616374Skarels struct servtab * 50716374Skarels enter(cp) 50816374Skarels struct servtab *cp; 50916374Skarels { 51016374Skarels register struct servtab *sep; 51132246Sbostic long omask; 51216374Skarels 51316374Skarels sep = (struct servtab *)malloc(sizeof (*sep)); 51416374Skarels if (sep == (struct servtab *)0) { 51516510Sralph syslog(LOG_ERR, "Out of memory."); 51616374Skarels exit(-1); 51716374Skarels } 51816374Skarels *sep = *cp; 51916374Skarels sep->se_fd = -1; 52027535Skarels omask = sigblock(SIGBLOCK); 52116374Skarels sep->se_next = servtab; 52216374Skarels servtab = sep; 52316374Skarels sigsetmask(omask); 52416374Skarels return (sep); 52516374Skarels } 52616374Skarels 52716374Skarels FILE *fconfig = NULL; 52816374Skarels struct servtab serv; 52916374Skarels char line[256]; 53016374Skarels char *skip(), *nextline(); 53116374Skarels 53216374Skarels setconfig() 53316374Skarels { 53416374Skarels 53516374Skarels if (fconfig != NULL) { 53626921Slepreau fseek(fconfig, 0L, L_SET); 53716374Skarels return (1); 53816374Skarels } 53916374Skarels fconfig = fopen(CONFIG, "r"); 54016374Skarels return (fconfig != NULL); 54116374Skarels } 54216374Skarels 54316374Skarels endconfig() 54416374Skarels { 54536603Sbostic if (fconfig) { 54636603Sbostic (void) fclose(fconfig); 54736603Sbostic fconfig = NULL; 54836603Sbostic } 54916374Skarels } 55016374Skarels 55116374Skarels struct servtab * 55216374Skarels getconfigent() 55316374Skarels { 55416374Skarels register struct servtab *sep = &serv; 55516374Skarels int argc; 55646907Sbostic char *cp, *arg, *newstr(); 55716374Skarels 55826877Skarels more: 55916374Skarels while ((cp = nextline(fconfig)) && *cp == '#') 56016374Skarels ; 56116374Skarels if (cp == NULL) 56216374Skarels return ((struct servtab *)0); 56346907Sbostic sep->se_service = newstr(skip(&cp)); 56416374Skarels arg = skip(&cp); 56516374Skarels if (strcmp(arg, "stream") == 0) 56616374Skarels sep->se_socktype = SOCK_STREAM; 56716374Skarels else if (strcmp(arg, "dgram") == 0) 56816374Skarels sep->se_socktype = SOCK_DGRAM; 56916374Skarels else if (strcmp(arg, "rdm") == 0) 57016374Skarels sep->se_socktype = SOCK_RDM; 57116374Skarels else if (strcmp(arg, "seqpacket") == 0) 57216374Skarels sep->se_socktype = SOCK_SEQPACKET; 57316374Skarels else if (strcmp(arg, "raw") == 0) 57416374Skarels sep->se_socktype = SOCK_RAW; 57516374Skarels else 57616374Skarels sep->se_socktype = -1; 57746907Sbostic sep->se_proto = newstr(skip(&cp)); 57816374Skarels arg = skip(&cp); 57916374Skarels sep->se_wait = strcmp(arg, "wait") == 0; 58046907Sbostic sep->se_user = newstr(skip(&cp)); 58146907Sbostic sep->se_server = newstr(skip(&cp)); 58226877Skarels if (strcmp(sep->se_server, "internal") == 0) { 58326877Skarels register struct biltin *bi; 58426877Skarels 58526877Skarels for (bi = biltins; bi->bi_service; bi++) 58626877Skarels if (bi->bi_socktype == sep->se_socktype && 58726877Skarels strcmp(bi->bi_service, sep->se_service) == 0) 58826877Skarels break; 58926877Skarels if (bi->bi_service == 0) { 59026877Skarels syslog(LOG_ERR, "internal service %s unknown\n", 59126877Skarels sep->se_service); 59226877Skarels goto more; 59326877Skarels } 59426877Skarels sep->se_bi = bi; 59526877Skarels sep->se_wait = bi->bi_wait; 59629794Skarels } else 59729794Skarels sep->se_bi = NULL; 59816374Skarels argc = 0; 59916374Skarels for (arg = skip(&cp); cp; arg = skip(&cp)) 60016374Skarels if (argc < MAXARGV) 60146907Sbostic sep->se_argv[argc++] = newstr(arg); 60216374Skarels while (argc <= MAXARGV) 60316374Skarels sep->se_argv[argc++] = NULL; 60416374Skarels return (sep); 60516374Skarels } 60616374Skarels 60716374Skarels freeconfig(cp) 60816374Skarels register struct servtab *cp; 60916374Skarels { 61016374Skarels int i; 61116374Skarels 61216374Skarels if (cp->se_service) 61316374Skarels free(cp->se_service); 61416374Skarels if (cp->se_proto) 61516374Skarels free(cp->se_proto); 61626921Slepreau if (cp->se_user) 61726921Slepreau free(cp->se_user); 61816374Skarels if (cp->se_server) 61916374Skarels free(cp->se_server); 62016374Skarels for (i = 0; i < MAXARGV; i++) 62116374Skarels if (cp->se_argv[i]) 62216374Skarels free(cp->se_argv[i]); 62316374Skarels } 62416374Skarels 62516374Skarels char * 62616374Skarels skip(cpp) 62716374Skarels char **cpp; 62816374Skarels { 62916374Skarels register char *cp = *cpp; 63016374Skarels char *start; 63116374Skarels 63216374Skarels again: 63316374Skarels while (*cp == ' ' || *cp == '\t') 63416374Skarels cp++; 63516374Skarels if (*cp == '\0') { 63643455Sbostic int c; 63716374Skarels 63816374Skarels c = getc(fconfig); 63936603Sbostic (void) ungetc(c, fconfig); 64016374Skarels if (c == ' ' || c == '\t') 64116374Skarels if (cp = nextline(fconfig)) 64216374Skarels goto again; 64316374Skarels *cpp = (char *)0; 64416374Skarels return ((char *)0); 64516374Skarels } 64616374Skarels start = cp; 64716374Skarels while (*cp && *cp != ' ' && *cp != '\t') 64816374Skarels cp++; 64916374Skarels if (*cp != '\0') 65016374Skarels *cp++ = '\0'; 65116374Skarels *cpp = cp; 65216374Skarels return (start); 65316374Skarels } 65416374Skarels 65516374Skarels char * 65616374Skarels nextline(fd) 65716374Skarels FILE *fd; 65816374Skarels { 65916374Skarels char *cp; 66016374Skarels 66126921Slepreau if (fgets(line, sizeof (line), fd) == NULL) 66216374Skarels return ((char *)0); 66316374Skarels cp = index(line, '\n'); 66416374Skarels if (cp) 66516374Skarels *cp = '\0'; 66616374Skarels return (line); 66716374Skarels } 66816374Skarels 66916374Skarels char * 67046907Sbostic newstr(cp) 67116374Skarels char *cp; 67216374Skarels { 67346973Skarels if (cp = strdup(cp ? cp : "")) 67446907Sbostic return(cp); 67546973Skarels syslog(LOG_ERR, "strdup: %m"); 67646907Sbostic exit(-1); 67716374Skarels } 67826877Skarels 67926877Skarels setproctitle(a, s) 68026877Skarels char *a; 68126877Skarels int s; 68226877Skarels { 68326877Skarels int size; 68426877Skarels register char *cp; 68526877Skarels struct sockaddr_in sin; 68626877Skarels char buf[80]; 68726877Skarels 68826877Skarels cp = Argv[0]; 68926877Skarels size = sizeof(sin); 69046907Sbostic if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 69132442Sbostic (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 69226877Skarels else 69332442Sbostic (void) sprintf(buf, "-%s", a); 69426877Skarels strncpy(cp, buf, LastArg - cp); 69526877Skarels cp += strlen(cp); 69626877Skarels while (cp < LastArg) 69726877Skarels *cp++ = ' '; 69826877Skarels } 69926877Skarels 70026877Skarels /* 70126877Skarels * Internet services provided internally by inetd: 70226877Skarels */ 703*49986Skarels #define BUFSIZE 8192 70426877Skarels 70526877Skarels /* ARGSUSED */ 70626877Skarels echo_stream(s, sep) /* Echo service -- echo data back */ 70726877Skarels int s; 70826877Skarels struct servtab *sep; 70926877Skarels { 71038573Skarels char buffer[BUFSIZE]; 71126877Skarels int i; 71226877Skarels 71332091Skarels setproctitle(sep->se_service, s); 71426877Skarels while ((i = read(s, buffer, sizeof(buffer))) > 0 && 71526877Skarels write(s, buffer, i) > 0) 71626877Skarels ; 71726877Skarels exit(0); 71826877Skarels } 71926877Skarels 72026877Skarels /* ARGSUSED */ 72126877Skarels echo_dg(s, sep) /* Echo service -- echo data back */ 72226877Skarels int s; 72326877Skarels struct servtab *sep; 72426877Skarels { 72538573Skarels char buffer[BUFSIZE]; 72626877Skarels int i, size; 72726877Skarels struct sockaddr sa; 72826877Skarels 72926877Skarels size = sizeof(sa); 73026877Skarels if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) 73126877Skarels return; 73226877Skarels (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); 73326877Skarels } 73426877Skarels 73526877Skarels /* ARGSUSED */ 73626877Skarels discard_stream(s, sep) /* Discard service -- ignore data */ 73726877Skarels int s; 73826877Skarels struct servtab *sep; 73926877Skarels { 740*49986Skarels int ret; 74138573Skarels char buffer[BUFSIZE]; 74226877Skarels 74332091Skarels setproctitle(sep->se_service, s); 74426877Skarels while (1) { 745*49986Skarels while ((ret = read(s, buffer, sizeof(buffer))) > 0) 74626877Skarels ; 747*49986Skarels if (ret == 0 || errno != EINTR) 74826877Skarels break; 74926877Skarels } 75026877Skarels exit(0); 75126877Skarels } 75226877Skarels 75326877Skarels /* ARGSUSED */ 75426877Skarels discard_dg(s, sep) /* Discard service -- ignore data */ 75526877Skarels int s; 75626877Skarels struct servtab *sep; 75726877Skarels { 75838573Skarels char buffer[BUFSIZE]; 75926877Skarels 76026877Skarels (void) read(s, buffer, sizeof(buffer)); 76126877Skarels } 76226877Skarels 76326877Skarels #include <ctype.h> 76426877Skarels #define LINESIZ 72 76526877Skarels char ring[128]; 76626877Skarels char *endring; 76726877Skarels 76826877Skarels initring() 76926877Skarels { 77026877Skarels register int i; 77126877Skarels 77226877Skarels endring = ring; 77326877Skarels 77426877Skarels for (i = 0; i <= 128; ++i) 77526877Skarels if (isprint(i)) 77626877Skarels *endring++ = i; 77726877Skarels } 77826877Skarels 77926877Skarels /* ARGSUSED */ 78026877Skarels chargen_stream(s, sep) /* Character generator */ 78126877Skarels int s; 78226877Skarels struct servtab *sep; 78326877Skarels { 78432246Sbostic register char *rs; 78532246Sbostic int len; 78626877Skarels char text[LINESIZ+2]; 78726877Skarels 78832091Skarels setproctitle(sep->se_service, s); 78932246Sbostic 79032246Sbostic if (!endring) { 79126877Skarels initring(); 79232246Sbostic rs = ring; 79332246Sbostic } 79426877Skarels 79532246Sbostic text[LINESIZ] = '\r'; 79632246Sbostic text[LINESIZ + 1] = '\n'; 79732246Sbostic for (rs = ring;;) { 79832246Sbostic if ((len = endring - rs) >= LINESIZ) 79932246Sbostic bcopy(rs, text, LINESIZ); 80032246Sbostic else { 80132246Sbostic bcopy(rs, text, len); 80232246Sbostic bcopy(ring, text + len, LINESIZ - len); 80332246Sbostic } 80432246Sbostic if (++rs == endring) 80526877Skarels rs = ring; 80632246Sbostic if (write(s, text, sizeof(text)) != sizeof(text)) 80726877Skarels break; 80826877Skarels } 80926877Skarels exit(0); 81026877Skarels } 81126877Skarels 81226877Skarels /* ARGSUSED */ 81326877Skarels chargen_dg(s, sep) /* Character generator */ 81426877Skarels int s; 81526877Skarels struct servtab *sep; 81626877Skarels { 81732246Sbostic struct sockaddr sa; 81832246Sbostic static char *rs; 81932246Sbostic int len, size; 82026877Skarels char text[LINESIZ+2]; 82126877Skarels 82232246Sbostic if (endring == 0) { 82326877Skarels initring(); 82432246Sbostic rs = ring; 82532246Sbostic } 82626877Skarels 82726877Skarels size = sizeof(sa); 82826877Skarels if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) 82926877Skarels return; 83032246Sbostic 83132246Sbostic if ((len = endring - rs) >= LINESIZ) 83232246Sbostic bcopy(rs, text, LINESIZ); 83332246Sbostic else { 83432246Sbostic bcopy(rs, text, len); 83532246Sbostic bcopy(ring, text + len, LINESIZ - len); 83632246Sbostic } 83732246Sbostic if (++rs == endring) 83826877Skarels rs = ring; 83932246Sbostic text[LINESIZ] = '\r'; 84032246Sbostic text[LINESIZ + 1] = '\n'; 84126877Skarels (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa)); 84226877Skarels } 84326877Skarels 84426877Skarels /* 84526877Skarels * Return a machine readable date and time, in the form of the 84626877Skarels * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 84726877Skarels * returns the number of seconds since midnight, Jan 1, 1970, 84826877Skarels * we must add 2208988800 seconds to this figure to make up for 84926877Skarels * some seventy years Bell Labs was asleep. 85026877Skarels */ 85126877Skarels 85226877Skarels long 85326877Skarels machtime() 85426877Skarels { 85526877Skarels struct timeval tv; 85626877Skarels 85726921Slepreau if (gettimeofday(&tv, (struct timezone *)0) < 0) { 85826877Skarels fprintf(stderr, "Unable to get time of day\n"); 85926921Slepreau return (0L); 86026877Skarels } 86126877Skarels return (htonl((long)tv.tv_sec + 2208988800)); 86226877Skarels } 86326877Skarels 86426877Skarels /* ARGSUSED */ 86526877Skarels machtime_stream(s, sep) 86626877Skarels int s; 86726877Skarels struct servtab *sep; 86826877Skarels { 86926877Skarels long result; 87026877Skarels 87126877Skarels result = machtime(); 87226877Skarels (void) write(s, (char *) &result, sizeof(result)); 87326877Skarels } 87426877Skarels 87526877Skarels /* ARGSUSED */ 87626877Skarels machtime_dg(s, sep) 87726877Skarels int s; 87826877Skarels struct servtab *sep; 87926877Skarels { 88026877Skarels long result; 88126877Skarels struct sockaddr sa; 88226877Skarels int size; 88326877Skarels 88426877Skarels size = sizeof(sa); 88526921Slepreau if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0) 88626877Skarels return; 88726877Skarels result = machtime(); 88826877Skarels (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa)); 88926877Skarels } 89026877Skarels 89126877Skarels /* ARGSUSED */ 89226877Skarels daytime_stream(s, sep) /* Return human-readable time of day */ 89326877Skarels int s; 89426877Skarels struct servtab *sep; 89526877Skarels { 89626877Skarels char buffer[256]; 89726877Skarels time_t time(), clock; 89826877Skarels char *ctime(); 89926877Skarels 90026877Skarels clock = time((time_t *) 0); 90126877Skarels 90232442Sbostic (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 90326921Slepreau (void) write(s, buffer, strlen(buffer)); 90426877Skarels } 90526877Skarels 90626877Skarels /* ARGSUSED */ 90726877Skarels daytime_dg(s, sep) /* Return human-readable time of day */ 90826877Skarels int s; 90926877Skarels struct servtab *sep; 91026877Skarels { 91126877Skarels char buffer[256]; 91226877Skarels time_t time(), clock; 91326877Skarels struct sockaddr sa; 91426877Skarels int size; 91526877Skarels char *ctime(); 91626877Skarels 91726877Skarels clock = time((time_t *) 0); 91826877Skarels 91926877Skarels size = sizeof(sa); 92026877Skarels if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) 92126877Skarels return; 92232442Sbostic (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 92326877Skarels (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa)); 92426877Skarels } 92529794Skarels 92629794Skarels /* 92729794Skarels * print_service: 92829794Skarels * Dump relevant information to stderr 92929794Skarels */ 93029794Skarels print_service(action, sep) 93129794Skarels char *action; 93229794Skarels struct servtab *sep; 93329794Skarels { 93429794Skarels fprintf(stderr, 93529794Skarels "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n", 93629794Skarels action, sep->se_service, sep->se_proto, 93736603Sbostic sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server); 93829794Skarels } 939