121134Sdist /* 221134Sdist * Copyright (c) 1983 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*46907Sbostic static char sccsid[] = "@(#)inetd.c 5.26 (Berkeley) 03/02/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) 22727535Skarels if (FD_ISSET(sep->se_fd, &readable)) { 22827535Skarels n--; 22916374Skarels if (debug) 23016374Skarels fprintf(stderr, "someone wants %s\n", sep->se_service); 23143456Sbostic if (sep->se_socktype == SOCK_STREAM) { 23227535Skarels ctrl = accept(sep->se_fd, (struct sockaddr *)0, 23327535Skarels (int *)0); 23416510Sralph if (debug) 23516510Sralph fprintf(stderr, "accept, ctrl %d\n", ctrl); 23616374Skarels if (ctrl < 0) { 23716374Skarels if (errno == EINTR) 23816374Skarels continue; 23943456Sbostic syslog(LOG_WARNING, "accept (for %s): %m", 24043456Sbostic sep->se_service); 24116374Skarels continue; 24216374Skarels } 24316374Skarels } else 24416374Skarels ctrl = sep->se_fd; 24527535Skarels (void) sigblock(SIGBLOCK); 24626877Skarels pid = 0; 24727535Skarels dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork); 24827535Skarels if (dofork) { 24927535Skarels if (sep->se_count++ == 0) 25027535Skarels (void)gettimeofday(&sep->se_time, 25127535Skarels (struct timezone *)0); 25227535Skarels else if (sep->se_count >= TOOMANY) { 25327535Skarels struct timeval now; 25427535Skarels 25527535Skarels (void)gettimeofday(&now, (struct timezone *)0); 25627535Skarels if (now.tv_sec - sep->se_time.tv_sec > 25727535Skarels CNT_INTVL) { 25827535Skarels sep->se_time = now; 25927535Skarels sep->se_count = 1; 26027535Skarels } else { 26127535Skarels syslog(LOG_ERR, 26227535Skarels "%s/%s server failing (looping), service terminated\n", 26327535Skarels sep->se_service, sep->se_proto); 26427535Skarels FD_CLR(sep->se_fd, &allsock); 26527535Skarels (void) close(sep->se_fd); 26627535Skarels sep->se_fd = -1; 26727535Skarels sep->se_count = 0; 26827535Skarels nsock--; 26932246Sbostic sigsetmask(0L); 27027535Skarels if (!timingout) { 27127535Skarels timingout = 1; 27227535Skarels alarm(RETRYTIME); 27327535Skarels } 27427535Skarels continue; 27527535Skarels } 27627535Skarels } 27726877Skarels pid = fork(); 27827535Skarels } 27916374Skarels if (pid < 0) { 28043456Sbostic if (sep->se_socktype == SOCK_STREAM) 28116374Skarels close(ctrl); 28232246Sbostic sigsetmask(0L); 28316374Skarels sleep(1); 28416374Skarels continue; 28516374Skarels } 28627535Skarels if (pid && sep->se_wait) { 28716374Skarels sep->se_wait = pid; 28827535Skarels FD_CLR(sep->se_fd, &allsock); 28925046Skarels nsock--; 29016374Skarels } 29132246Sbostic sigsetmask(0L); 29216374Skarels if (pid == 0) { 29344711Skarels if (debug && dofork) 29444711Skarels setsid(); 29527535Skarels if (dofork) 29636603Sbostic for (tmpint = getdtablesize(); --tmpint > 2; ) 29736603Sbostic if (tmpint != ctrl) 29836603Sbostic close(tmpint); 29926877Skarels if (sep->se_bi) 30026877Skarels (*sep->se_bi->bi_fn)(ctrl, sep); 30126877Skarels else { 30226877Skarels dup2(ctrl, 0); 30326877Skarels close(ctrl); 30426877Skarels dup2(0, 1); 30526877Skarels dup2(0, 2); 30626877Skarels if ((pwd = getpwnam(sep->se_user)) == NULL) { 30726877Skarels syslog(LOG_ERR, 30826877Skarels "getpwnam: %s: No such user", 30926877Skarels sep->se_user); 31027535Skarels if (sep->se_socktype != SOCK_STREAM) 31127535Skarels recv(0, buf, sizeof (buf), 0); 31226877Skarels _exit(1); 31326877Skarels } 31426877Skarels if (pwd->pw_uid) { 31526921Slepreau (void) setgid((gid_t)pwd->pw_gid); 31626877Skarels initgroups(pwd->pw_name, pwd->pw_gid); 31726921Slepreau (void) setuid((uid_t)pwd->pw_uid); 31826877Skarels } 31926877Skarels if (debug) 32026877Skarels fprintf(stderr, "%d execl %s\n", 32126877Skarels getpid(), sep->se_server); 32226877Skarels execv(sep->se_server, sep->se_argv); 32326877Skarels if (sep->se_socktype != SOCK_STREAM) 32426877Skarels recv(0, buf, sizeof (buf), 0); 32526877Skarels syslog(LOG_ERR, "execv %s: %m", sep->se_server); 32626877Skarels _exit(1); 32717346Sbloom } 32816374Skarels } 32943456Sbostic if (sep->se_socktype == SOCK_STREAM) 33016374Skarels close(ctrl); 33127535Skarels } 33216374Skarels } 33316374Skarels } 33416374Skarels 33539838Sbostic void 33616374Skarels reapchild() 33716374Skarels { 33816374Skarels union wait status; 33916374Skarels int pid; 34016374Skarels register struct servtab *sep; 34116374Skarels 34216374Skarels for (;;) { 343*46907Sbostic pid = wait3((int *)&status, WNOHANG, (struct rusage *)0); 34416374Skarels if (pid <= 0) 34516374Skarels break; 34616374Skarels if (debug) 34716374Skarels fprintf(stderr, "%d reaped\n", pid); 34816374Skarels for (sep = servtab; sep; sep = sep->se_next) 34916374Skarels if (sep->se_wait == pid) { 35016374Skarels if (status.w_status) 35116510Sralph syslog(LOG_WARNING, 35216510Sralph "%s: exit status 0x%x", 35316374Skarels sep->se_server, status); 35416374Skarels if (debug) 35516374Skarels fprintf(stderr, "restored %s, fd %d\n", 35616374Skarels sep->se_service, sep->se_fd); 35725046Skarels FD_SET(sep->se_fd, &allsock); 35825046Skarels nsock++; 35916374Skarels sep->se_wait = 1; 36016374Skarels } 36116374Skarels } 36216374Skarels } 36316374Skarels 36439838Sbostic void 36516374Skarels config() 36616374Skarels { 36716374Skarels register struct servtab *sep, *cp, **sepp; 36816374Skarels struct servtab *getconfigent(), *enter(); 36932246Sbostic long omask; 37016374Skarels 37116374Skarels if (!setconfig()) { 37216510Sralph syslog(LOG_ERR, "%s: %m", CONFIG); 37316374Skarels return; 37416374Skarels } 37516374Skarels for (sep = servtab; sep; sep = sep->se_next) 37616374Skarels sep->se_checked = 0; 37716374Skarels while (cp = getconfigent()) { 37816374Skarels for (sep = servtab; sep; sep = sep->se_next) 37916374Skarels if (strcmp(sep->se_service, cp->se_service) == 0 && 38016374Skarels strcmp(sep->se_proto, cp->se_proto) == 0) 38116374Skarels break; 38216374Skarels if (sep != 0) { 38316374Skarels int i; 38416374Skarels 38527535Skarels omask = sigblock(SIGBLOCK); 38640745Sbostic /* 38740745Sbostic * sep->se_wait may be holding the pid of a daemon 38840745Sbostic * that we're waiting for. If so, don't overwrite 38940745Sbostic * it unless the config file explicitly says don't 39040745Sbostic * wait. 39140745Sbostic */ 39240745Sbostic if (cp->se_bi == 0 && 39340745Sbostic (sep->se_wait == 1 || cp->se_wait == 0)) 39427535Skarels sep->se_wait = cp->se_wait; 39516374Skarels #define SWAP(a, b) { char *c = a; a = b; b = c; } 39626921Slepreau if (cp->se_user) 39726921Slepreau SWAP(sep->se_user, cp->se_user); 39816374Skarels if (cp->se_server) 39916374Skarels SWAP(sep->se_server, cp->se_server); 40016374Skarels for (i = 0; i < MAXARGV; i++) 40116374Skarels SWAP(sep->se_argv[i], cp->se_argv[i]); 40216374Skarels sigsetmask(omask); 40316374Skarels freeconfig(cp); 40429794Skarels if (debug) 40529794Skarels print_service("REDO", sep); 40629794Skarels } else { 40716374Skarels sep = enter(cp); 40829794Skarels if (debug) 40929794Skarels print_service("ADD ", sep); 41029794Skarels } 41116374Skarels sep->se_checked = 1; 41216374Skarels sp = getservbyname(sep->se_service, sep->se_proto); 41316374Skarels if (sp == 0) { 41416510Sralph syslog(LOG_ERR, "%s/%s: unknown service", 41516374Skarels sep->se_service, sep->se_proto); 41616374Skarels continue; 41716374Skarels } 41827535Skarels if (sp->s_port != sep->se_ctrladdr.sin_port) { 41927535Skarels sep->se_ctrladdr.sin_port = sp->s_port; 42027535Skarels if (sep->se_fd != -1) 42127535Skarels (void) close(sep->se_fd); 42227535Skarels sep->se_fd = -1; 42316374Skarels } 42427535Skarels if (sep->se_fd == -1) 42527535Skarels setup(sep); 42616374Skarels } 42716374Skarels endconfig(); 42816374Skarels /* 42916374Skarels * Purge anything not looked at above. 43016374Skarels */ 43127535Skarels omask = sigblock(SIGBLOCK); 43216374Skarels sepp = &servtab; 43316374Skarels while (sep = *sepp) { 43416374Skarels if (sep->se_checked) { 43516374Skarels sepp = &sep->se_next; 43616374Skarels continue; 43716374Skarels } 43816374Skarels *sepp = sep->se_next; 43916374Skarels if (sep->se_fd != -1) { 44025046Skarels FD_CLR(sep->se_fd, &allsock); 44125046Skarels nsock--; 44216374Skarels (void) close(sep->se_fd); 44316374Skarels } 44429794Skarels if (debug) 44529794Skarels print_service("FREE", sep); 44616374Skarels freeconfig(sep); 44716374Skarels free((char *)sep); 44816374Skarels } 44916374Skarels (void) sigsetmask(omask); 45016374Skarels } 45116374Skarels 45239838Sbostic void 45327535Skarels retry() 45427535Skarels { 45527535Skarels register struct servtab *sep; 45627535Skarels 45727535Skarels timingout = 0; 45827535Skarels for (sep = servtab; sep; sep = sep->se_next) 45927535Skarels if (sep->se_fd == -1) 46027535Skarels setup(sep); 46127535Skarels } 46227535Skarels 46327535Skarels setup(sep) 46427535Skarels register struct servtab *sep; 46527535Skarels { 46627535Skarels int on = 1; 46727535Skarels 46827535Skarels if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 46927535Skarels syslog(LOG_ERR, "%s/%s: socket: %m", 47027535Skarels sep->se_service, sep->se_proto); 47127535Skarels return; 47227535Skarels } 47327535Skarels #define turnon(fd, opt) \ 47427535Skarels setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 47527535Skarels if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 47627535Skarels turnon(sep->se_fd, SO_DEBUG) < 0) 47727535Skarels syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 47827535Skarels if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 47927535Skarels syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 48027535Skarels #undef turnon 481*46907Sbostic if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 48227535Skarels sizeof (sep->se_ctrladdr)) < 0) { 48327535Skarels syslog(LOG_ERR, "%s/%s: bind: %m", 48427535Skarels sep->se_service, sep->se_proto); 48527535Skarels (void) close(sep->se_fd); 48627535Skarels sep->se_fd = -1; 48727535Skarels if (!timingout) { 48827535Skarels timingout = 1; 48927535Skarels alarm(RETRYTIME); 49027535Skarels } 49127535Skarels return; 49227535Skarels } 49327535Skarels if (sep->se_socktype == SOCK_STREAM) 49427535Skarels listen(sep->se_fd, 10); 49527535Skarels FD_SET(sep->se_fd, &allsock); 49627535Skarels nsock++; 49727535Skarels if (sep->se_fd > maxsock) 49827535Skarels maxsock = sep->se_fd; 49927535Skarels } 50027535Skarels 50116374Skarels struct servtab * 50216374Skarels enter(cp) 50316374Skarels struct servtab *cp; 50416374Skarels { 50516374Skarels register struct servtab *sep; 50632246Sbostic long omask; 50716374Skarels 50816374Skarels sep = (struct servtab *)malloc(sizeof (*sep)); 50916374Skarels if (sep == (struct servtab *)0) { 51016510Sralph syslog(LOG_ERR, "Out of memory."); 51116374Skarels exit(-1); 51216374Skarels } 51316374Skarels *sep = *cp; 51416374Skarels sep->se_fd = -1; 51527535Skarels omask = sigblock(SIGBLOCK); 51616374Skarels sep->se_next = servtab; 51716374Skarels servtab = sep; 51816374Skarels sigsetmask(omask); 51916374Skarels return (sep); 52016374Skarels } 52116374Skarels 52216374Skarels FILE *fconfig = NULL; 52316374Skarels struct servtab serv; 52416374Skarels char line[256]; 52516374Skarels char *skip(), *nextline(); 52616374Skarels 52716374Skarels setconfig() 52816374Skarels { 52916374Skarels 53016374Skarels if (fconfig != NULL) { 53126921Slepreau fseek(fconfig, 0L, L_SET); 53216374Skarels return (1); 53316374Skarels } 53416374Skarels fconfig = fopen(CONFIG, "r"); 53516374Skarels return (fconfig != NULL); 53616374Skarels } 53716374Skarels 53816374Skarels endconfig() 53916374Skarels { 54036603Sbostic if (fconfig) { 54136603Sbostic (void) fclose(fconfig); 54236603Sbostic fconfig = NULL; 54336603Sbostic } 54416374Skarels } 54516374Skarels 54616374Skarels struct servtab * 54716374Skarels getconfigent() 54816374Skarels { 54916374Skarels register struct servtab *sep = &serv; 55016374Skarels int argc; 551*46907Sbostic char *cp, *arg, *newstr(); 55216374Skarels 55326877Skarels more: 55416374Skarels while ((cp = nextline(fconfig)) && *cp == '#') 55516374Skarels ; 55616374Skarels if (cp == NULL) 55716374Skarels return ((struct servtab *)0); 558*46907Sbostic sep->se_service = newstr(skip(&cp)); 55916374Skarels arg = skip(&cp); 56016374Skarels if (strcmp(arg, "stream") == 0) 56116374Skarels sep->se_socktype = SOCK_STREAM; 56216374Skarels else if (strcmp(arg, "dgram") == 0) 56316374Skarels sep->se_socktype = SOCK_DGRAM; 56416374Skarels else if (strcmp(arg, "rdm") == 0) 56516374Skarels sep->se_socktype = SOCK_RDM; 56616374Skarels else if (strcmp(arg, "seqpacket") == 0) 56716374Skarels sep->se_socktype = SOCK_SEQPACKET; 56816374Skarels else if (strcmp(arg, "raw") == 0) 56916374Skarels sep->se_socktype = SOCK_RAW; 57016374Skarels else 57116374Skarels sep->se_socktype = -1; 572*46907Sbostic sep->se_proto = newstr(skip(&cp)); 57316374Skarels arg = skip(&cp); 57416374Skarels sep->se_wait = strcmp(arg, "wait") == 0; 575*46907Sbostic sep->se_user = newstr(skip(&cp)); 576*46907Sbostic sep->se_server = newstr(skip(&cp)); 57726877Skarels if (strcmp(sep->se_server, "internal") == 0) { 57826877Skarels register struct biltin *bi; 57926877Skarels 58026877Skarels for (bi = biltins; bi->bi_service; bi++) 58126877Skarels if (bi->bi_socktype == sep->se_socktype && 58226877Skarels strcmp(bi->bi_service, sep->se_service) == 0) 58326877Skarels break; 58426877Skarels if (bi->bi_service == 0) { 58526877Skarels syslog(LOG_ERR, "internal service %s unknown\n", 58626877Skarels sep->se_service); 58726877Skarels goto more; 58826877Skarels } 58926877Skarels sep->se_bi = bi; 59026877Skarels sep->se_wait = bi->bi_wait; 59129794Skarels } else 59229794Skarels sep->se_bi = NULL; 59316374Skarels argc = 0; 59416374Skarels for (arg = skip(&cp); cp; arg = skip(&cp)) 59516374Skarels if (argc < MAXARGV) 596*46907Sbostic sep->se_argv[argc++] = newstr(arg); 59716374Skarels while (argc <= MAXARGV) 59816374Skarels sep->se_argv[argc++] = NULL; 59916374Skarels return (sep); 60016374Skarels } 60116374Skarels 60216374Skarels freeconfig(cp) 60316374Skarels register struct servtab *cp; 60416374Skarels { 60516374Skarels int i; 60616374Skarels 60716374Skarels if (cp->se_service) 60816374Skarels free(cp->se_service); 60916374Skarels if (cp->se_proto) 61016374Skarels free(cp->se_proto); 61126921Slepreau if (cp->se_user) 61226921Slepreau free(cp->se_user); 61316374Skarels if (cp->se_server) 61416374Skarels free(cp->se_server); 61516374Skarels for (i = 0; i < MAXARGV; i++) 61616374Skarels if (cp->se_argv[i]) 61716374Skarels free(cp->se_argv[i]); 61816374Skarels } 61916374Skarels 62016374Skarels char * 62116374Skarels skip(cpp) 62216374Skarels char **cpp; 62316374Skarels { 62416374Skarels register char *cp = *cpp; 62516374Skarels char *start; 62616374Skarels 62716374Skarels again: 62816374Skarels while (*cp == ' ' || *cp == '\t') 62916374Skarels cp++; 63016374Skarels if (*cp == '\0') { 63143455Sbostic int c; 63216374Skarels 63316374Skarels c = getc(fconfig); 63436603Sbostic (void) ungetc(c, fconfig); 63516374Skarels if (c == ' ' || c == '\t') 63616374Skarels if (cp = nextline(fconfig)) 63716374Skarels goto again; 63816374Skarels *cpp = (char *)0; 63916374Skarels return ((char *)0); 64016374Skarels } 64116374Skarels start = cp; 64216374Skarels while (*cp && *cp != ' ' && *cp != '\t') 64316374Skarels cp++; 64416374Skarels if (*cp != '\0') 64516374Skarels *cp++ = '\0'; 64616374Skarels *cpp = cp; 64716374Skarels return (start); 64816374Skarels } 64916374Skarels 65016374Skarels char * 65116374Skarels nextline(fd) 65216374Skarels FILE *fd; 65316374Skarels { 65416374Skarels char *cp; 65516374Skarels 65626921Slepreau if (fgets(line, sizeof (line), fd) == NULL) 65716374Skarels return ((char *)0); 65816374Skarels cp = index(line, '\n'); 65916374Skarels if (cp) 66016374Skarels *cp = '\0'; 66116374Skarels return (line); 66216374Skarels } 66316374Skarels 66416374Skarels char * 665*46907Sbostic newstr(cp) 66616374Skarels char *cp; 66716374Skarels { 668*46907Sbostic if (cp = strdup(cp)) 669*46907Sbostic return(cp); 670*46907Sbostic syslog(LOG_ERR, "%m"); 671*46907Sbostic exit(-1); 67216374Skarels } 67326877Skarels 67426877Skarels setproctitle(a, s) 67526877Skarels char *a; 67626877Skarels int s; 67726877Skarels { 67826877Skarels int size; 67926877Skarels register char *cp; 68026877Skarels struct sockaddr_in sin; 68126877Skarels char buf[80]; 68226877Skarels 68326877Skarels cp = Argv[0]; 68426877Skarels size = sizeof(sin); 685*46907Sbostic if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 68632442Sbostic (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 68726877Skarels else 68832442Sbostic (void) sprintf(buf, "-%s", a); 68926877Skarels strncpy(cp, buf, LastArg - cp); 69026877Skarels cp += strlen(cp); 69126877Skarels while (cp < LastArg) 69226877Skarels *cp++ = ' '; 69326877Skarels } 69426877Skarels 69526877Skarels /* 69626877Skarels * Internet services provided internally by inetd: 69726877Skarels */ 69838573Skarels #define BUFSIZE 4096 69926877Skarels 70026877Skarels /* ARGSUSED */ 70126877Skarels echo_stream(s, sep) /* Echo service -- echo data back */ 70226877Skarels int s; 70326877Skarels struct servtab *sep; 70426877Skarels { 70538573Skarels char buffer[BUFSIZE]; 70626877Skarels int i; 70726877Skarels 70832091Skarels setproctitle(sep->se_service, s); 70926877Skarels while ((i = read(s, buffer, sizeof(buffer))) > 0 && 71026877Skarels write(s, buffer, i) > 0) 71126877Skarels ; 71226877Skarels exit(0); 71326877Skarels } 71426877Skarels 71526877Skarels /* ARGSUSED */ 71626877Skarels echo_dg(s, sep) /* Echo service -- echo data back */ 71726877Skarels int s; 71826877Skarels struct servtab *sep; 71926877Skarels { 72038573Skarels char buffer[BUFSIZE]; 72126877Skarels int i, size; 72226877Skarels struct sockaddr sa; 72326877Skarels 72426877Skarels size = sizeof(sa); 72526877Skarels if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) 72626877Skarels return; 72726877Skarels (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); 72826877Skarels } 72926877Skarels 73026877Skarels /* ARGSUSED */ 73126877Skarels discard_stream(s, sep) /* Discard service -- ignore data */ 73226877Skarels int s; 73326877Skarels struct servtab *sep; 73426877Skarels { 73538573Skarels char buffer[BUFSIZE]; 73626877Skarels 73732091Skarels setproctitle(sep->se_service, s); 73826877Skarels while (1) { 73926877Skarels while (read(s, buffer, sizeof(buffer)) > 0) 74026877Skarels ; 74126877Skarels if (errno != EINTR) 74226877Skarels break; 74326877Skarels } 74426877Skarels exit(0); 74526877Skarels } 74626877Skarels 74726877Skarels /* ARGSUSED */ 74826877Skarels discard_dg(s, sep) /* Discard service -- ignore data */ 74926877Skarels int s; 75026877Skarels struct servtab *sep; 75126877Skarels { 75238573Skarels char buffer[BUFSIZE]; 75326877Skarels 75426877Skarels (void) read(s, buffer, sizeof(buffer)); 75526877Skarels } 75626877Skarels 75726877Skarels #include <ctype.h> 75826877Skarels #define LINESIZ 72 75926877Skarels char ring[128]; 76026877Skarels char *endring; 76126877Skarels 76226877Skarels initring() 76326877Skarels { 76426877Skarels register int i; 76526877Skarels 76626877Skarels endring = ring; 76726877Skarels 76826877Skarels for (i = 0; i <= 128; ++i) 76926877Skarels if (isprint(i)) 77026877Skarels *endring++ = i; 77126877Skarels } 77226877Skarels 77326877Skarels /* ARGSUSED */ 77426877Skarels chargen_stream(s, sep) /* Character generator */ 77526877Skarels int s; 77626877Skarels struct servtab *sep; 77726877Skarels { 77832246Sbostic register char *rs; 77932246Sbostic int len; 78026877Skarels char text[LINESIZ+2]; 78126877Skarels 78232091Skarels setproctitle(sep->se_service, s); 78332246Sbostic 78432246Sbostic if (!endring) { 78526877Skarels initring(); 78632246Sbostic rs = ring; 78732246Sbostic } 78826877Skarels 78932246Sbostic text[LINESIZ] = '\r'; 79032246Sbostic text[LINESIZ + 1] = '\n'; 79132246Sbostic for (rs = ring;;) { 79232246Sbostic if ((len = endring - rs) >= LINESIZ) 79332246Sbostic bcopy(rs, text, LINESIZ); 79432246Sbostic else { 79532246Sbostic bcopy(rs, text, len); 79632246Sbostic bcopy(ring, text + len, LINESIZ - len); 79732246Sbostic } 79832246Sbostic if (++rs == endring) 79926877Skarels rs = ring; 80032246Sbostic if (write(s, text, sizeof(text)) != sizeof(text)) 80126877Skarels break; 80226877Skarels } 80326877Skarels exit(0); 80426877Skarels } 80526877Skarels 80626877Skarels /* ARGSUSED */ 80726877Skarels chargen_dg(s, sep) /* Character generator */ 80826877Skarels int s; 80926877Skarels struct servtab *sep; 81026877Skarels { 81132246Sbostic struct sockaddr sa; 81232246Sbostic static char *rs; 81332246Sbostic int len, size; 81426877Skarels char text[LINESIZ+2]; 81526877Skarels 81632246Sbostic if (endring == 0) { 81726877Skarels initring(); 81832246Sbostic rs = ring; 81932246Sbostic } 82026877Skarels 82126877Skarels size = sizeof(sa); 82226877Skarels if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) 82326877Skarels return; 82432246Sbostic 82532246Sbostic if ((len = endring - rs) >= LINESIZ) 82632246Sbostic bcopy(rs, text, LINESIZ); 82732246Sbostic else { 82832246Sbostic bcopy(rs, text, len); 82932246Sbostic bcopy(ring, text + len, LINESIZ - len); 83032246Sbostic } 83132246Sbostic if (++rs == endring) 83226877Skarels rs = ring; 83332246Sbostic text[LINESIZ] = '\r'; 83432246Sbostic text[LINESIZ + 1] = '\n'; 83526877Skarels (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa)); 83626877Skarels } 83726877Skarels 83826877Skarels /* 83926877Skarels * Return a machine readable date and time, in the form of the 84026877Skarels * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 84126877Skarels * returns the number of seconds since midnight, Jan 1, 1970, 84226877Skarels * we must add 2208988800 seconds to this figure to make up for 84326877Skarels * some seventy years Bell Labs was asleep. 84426877Skarels */ 84526877Skarels 84626877Skarels long 84726877Skarels machtime() 84826877Skarels { 84926877Skarels struct timeval tv; 85026877Skarels 85126921Slepreau if (gettimeofday(&tv, (struct timezone *)0) < 0) { 85226877Skarels fprintf(stderr, "Unable to get time of day\n"); 85326921Slepreau return (0L); 85426877Skarels } 85526877Skarels return (htonl((long)tv.tv_sec + 2208988800)); 85626877Skarels } 85726877Skarels 85826877Skarels /* ARGSUSED */ 85926877Skarels machtime_stream(s, sep) 86026877Skarels int s; 86126877Skarels struct servtab *sep; 86226877Skarels { 86326877Skarels long result; 86426877Skarels 86526877Skarels result = machtime(); 86626877Skarels (void) write(s, (char *) &result, sizeof(result)); 86726877Skarels } 86826877Skarels 86926877Skarels /* ARGSUSED */ 87026877Skarels machtime_dg(s, sep) 87126877Skarels int s; 87226877Skarels struct servtab *sep; 87326877Skarels { 87426877Skarels long result; 87526877Skarels struct sockaddr sa; 87626877Skarels int size; 87726877Skarels 87826877Skarels size = sizeof(sa); 87926921Slepreau if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0) 88026877Skarels return; 88126877Skarels result = machtime(); 88226877Skarels (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa)); 88326877Skarels } 88426877Skarels 88526877Skarels /* ARGSUSED */ 88626877Skarels daytime_stream(s, sep) /* Return human-readable time of day */ 88726877Skarels int s; 88826877Skarels struct servtab *sep; 88926877Skarels { 89026877Skarels char buffer[256]; 89126877Skarels time_t time(), clock; 89226877Skarels char *ctime(); 89326877Skarels 89426877Skarels clock = time((time_t *) 0); 89526877Skarels 89632442Sbostic (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 89726921Slepreau (void) write(s, buffer, strlen(buffer)); 89826877Skarels } 89926877Skarels 90026877Skarels /* ARGSUSED */ 90126877Skarels daytime_dg(s, sep) /* Return human-readable time of day */ 90226877Skarels int s; 90326877Skarels struct servtab *sep; 90426877Skarels { 90526877Skarels char buffer[256]; 90626877Skarels time_t time(), clock; 90726877Skarels struct sockaddr sa; 90826877Skarels int size; 90926877Skarels char *ctime(); 91026877Skarels 91126877Skarels clock = time((time_t *) 0); 91226877Skarels 91326877Skarels size = sizeof(sa); 91426877Skarels if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) 91526877Skarels return; 91632442Sbostic (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 91726877Skarels (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa)); 91826877Skarels } 91929794Skarels 92029794Skarels /* 92129794Skarels * print_service: 92229794Skarels * Dump relevant information to stderr 92329794Skarels */ 92429794Skarels print_service(action, sep) 92529794Skarels char *action; 92629794Skarels struct servtab *sep; 92729794Skarels { 92829794Skarels fprintf(stderr, 92929794Skarels "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n", 93029794Skarels action, sep->se_service, sep->se_proto, 93136603Sbostic sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server); 93229794Skarels } 933