121134Sdist /* 221134Sdist * Copyright (c) 1983 Regents of the University of California. 321134Sdist * All rights reserved. The Berkeley software License Agreement 421134Sdist * specifies the terms and conditions for redistribution. 521134Sdist */ 621134Sdist 716374Skarels #ifndef lint 821134Sdist char copyright[] = 921134Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 1021134Sdist All rights reserved.\n"; 1121134Sdist #endif not lint 1216374Skarels 1321134Sdist #ifndef lint 14*32442Sbostic static char sccsid[] = "@(#)inetd.c 5.11 (Berkeley) 10/22/87"; 1521134Sdist #endif not lint 1621134Sdist 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> 5826921Slepreau #include <sys/time.h> 5926921Slepreau #include <sys/resource.h> 6016374Skarels 6116374Skarels #include <netinet/in.h> 6216374Skarels #include <arpa/inet.h> 6316374Skarels 6416374Skarels #include <errno.h> 6516374Skarels #include <stdio.h> 6616374Skarels #include <signal.h> 6716374Skarels #include <netdb.h> 6816510Sralph #include <syslog.h> 6917346Sbloom #include <pwd.h> 7016374Skarels 7127535Skarels #define TOOMANY 40 /* don't start more than TOOMANY */ 7227535Skarels #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 7327535Skarels #define RETRYTIME (60*10) /* retry after bind or server fail */ 7427535Skarels 7527535Skarels #define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 7627535Skarels 7716374Skarels extern int errno; 7816374Skarels 7927535Skarels int reapchild(), retry(); 8016374Skarels char *index(); 8116374Skarels char *malloc(); 8216374Skarels 8316374Skarels int debug = 0; 8425046Skarels int nsock, maxsock; 8525046Skarels fd_set allsock; 8616374Skarels int options; 8727535Skarels int timingout; 8816374Skarels struct servent *sp; 8916374Skarels 9016374Skarels struct servtab { 9116374Skarels char *se_service; /* name of service */ 9216374Skarels int se_socktype; /* type of socket to use */ 9316374Skarels char *se_proto; /* protocol used */ 9416374Skarels short se_wait; /* single threaded server */ 9516374Skarels short se_checked; /* looked at during merge */ 9617346Sbloom char *se_user; /* user name to run as */ 9726877Skarels struct biltin *se_bi; /* if built-in, description */ 9816374Skarels char *se_server; /* server program */ 9916374Skarels #define MAXARGV 5 10016374Skarels char *se_argv[MAXARGV+1]; /* program arguments */ 10116374Skarels int se_fd; /* open descriptor */ 10216374Skarels struct sockaddr_in se_ctrladdr;/* bound address */ 10327535Skarels int se_count; /* number started since se_time */ 10427535Skarels struct timeval se_time; /* start of se_count */ 10516374Skarels struct servtab *se_next; 10616374Skarels } *servtab; 10716374Skarels 10826877Skarels int echo_stream(), discard_stream(), machtime_stream(); 10926877Skarels int daytime_stream(), chargen_stream(); 11026877Skarels int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg(); 11126877Skarels 11226877Skarels struct biltin { 11326877Skarels char *bi_service; /* internally provided service name */ 11426877Skarels int bi_socktype; /* type of socket supported */ 11526877Skarels short bi_fork; /* 1 if should fork before call */ 11626877Skarels short bi_wait; /* 1 if should wait for child */ 11726877Skarels int (*bi_fn)(); /* function which performs it */ 11826877Skarels } biltins[] = { 11926877Skarels /* Echo received data */ 12026877Skarels "echo", SOCK_STREAM, 1, 0, echo_stream, 12126877Skarels "echo", SOCK_DGRAM, 0, 0, echo_dg, 12226877Skarels 12326877Skarels /* Internet /dev/null */ 12426877Skarels "discard", SOCK_STREAM, 1, 0, discard_stream, 12526877Skarels "discard", SOCK_DGRAM, 0, 0, discard_dg, 12626877Skarels 12726877Skarels /* Return 32 bit time since 1970 */ 12826877Skarels "time", SOCK_STREAM, 0, 0, machtime_stream, 12926877Skarels "time", SOCK_DGRAM, 0, 0, machtime_dg, 13026877Skarels 13126877Skarels /* Return human-readable time */ 13226877Skarels "daytime", SOCK_STREAM, 0, 0, daytime_stream, 13326877Skarels "daytime", SOCK_DGRAM, 0, 0, daytime_dg, 13426877Skarels 13526877Skarels /* Familiar character generator */ 13626877Skarels "chargen", SOCK_STREAM, 1, 0, chargen_stream, 13726877Skarels "chargen", SOCK_DGRAM, 0, 0, chargen_dg, 13826877Skarels 0 13926877Skarels }; 14026877Skarels 14126877Skarels #define NUMINT (sizeof(intab) / sizeof(struct inent)) 14216374Skarels char *CONFIG = "/etc/inetd.conf"; 14326877Skarels char **Argv; 14426877Skarels char *LastArg; 14516374Skarels 14626877Skarels main(argc, argv, envp) 14716374Skarels int argc; 14826877Skarels char *argv[], *envp[]; 14916374Skarels { 15016374Skarels register struct servtab *sep; 15117346Sbloom register struct passwd *pwd; 15216374Skarels char *cp, buf[50]; 15327535Skarels int pid, i, dofork; 15427535Skarels struct sigvec sv; 15516374Skarels 15626877Skarels Argv = argv; 15726877Skarels if (envp == 0 || *envp == 0) 15826877Skarels envp = argv; 15926877Skarels while (*envp) 16026877Skarels envp++; 16126877Skarels LastArg = envp[-1] + strlen(envp[-1]); 16216374Skarels argc--, argv++; 16316374Skarels while (argc > 0 && *argv[0] == '-') { 16416374Skarels for (cp = &argv[0][1]; *cp; cp++) switch (*cp) { 16516374Skarels 16616374Skarels case 'd': 16716374Skarels debug = 1; 16816374Skarels options |= SO_DEBUG; 16916374Skarels break; 17016374Skarels 17116374Skarels default: 17216374Skarels fprintf(stderr, 17316374Skarels "inetd: Unknown flag -%c ignored.\n", *cp); 17416374Skarels break; 17516374Skarels } 17616374Skarels nextopt: 17716374Skarels argc--, argv++; 17816374Skarels } 17916374Skarels if (argc > 0) 18016374Skarels CONFIG = argv[0]; 18132403Skarels if (debug == 0) { 18232403Skarels if (fork()) 18332403Skarels exit(0); 18432403Skarels { int s; 18532403Skarels for (s = 0; s < 10; s++) 18632403Skarels (void) close(s); 18732403Skarels } 18832403Skarels (void) open("/", O_RDONLY); 18932403Skarels (void) dup2(0, 1); 19032403Skarels (void) dup2(0, 2); 19132403Skarels { int tt = open("/dev/tty", O_RDWR); 19232403Skarels if (tt > 0) { 19332403Skarels ioctl(tt, TIOCNOTTY, (char *)0); 19432403Skarels close(tt); 19532403Skarels } 19632403Skarels } 19732403Skarels (void) setpgrp(0, 0); 19832403Skarels signal(SIGTSTP, SIG_IGN); 19932403Skarels signal(SIGTTIN, SIG_IGN); 20032403Skarels signal(SIGTTOU, SIG_IGN); 20116374Skarels } 20227535Skarels openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 20327535Skarels bzero((char *)&sv, sizeof(sv)); 20427535Skarels sv.sv_mask = SIGBLOCK; 20527535Skarels sv.sv_handler = retry; 20627535Skarels sigvec(SIGALRM, &sv, (struct sigvec *)0); 20716374Skarels config(); 20827535Skarels sv.sv_handler = config; 20927535Skarels sigvec(SIGHUP, &sv, (struct sigvec *)0); 21027535Skarels sv.sv_handler = reapchild; 21127535Skarels sigvec(SIGCHLD, &sv, (struct sigvec *)0); 21227535Skarels 21316374Skarels for (;;) { 21427535Skarels int s, ctrl, n; 21527535Skarels fd_set readable; 21616374Skarels 21732091Skarels if (nsock == 0) { 21832091Skarels (void) sigblock(SIGBLOCK); 21932091Skarels while (nsock == 0) 22032246Sbostic sigpause(0L); 22132246Sbostic (void) sigsetmask(0L); 22232091Skarels } 22327535Skarels readable = allsock; 22427535Skarels if ((n = select(maxsock + 1, &readable, (fd_set *)0, 22527535Skarels (fd_set *)0, (struct timeval *)0)) <= 0) { 22627535Skarels if (n < 0 && errno != EINTR) 22732091Skarels syslog(LOG_WARNING, "select: %m\n"); 22827535Skarels sleep(1); 22927535Skarels continue; 23027535Skarels } 23127535Skarels for (sep = servtab; n && sep; sep = sep->se_next) 23227535Skarels if (FD_ISSET(sep->se_fd, &readable)) { 23327535Skarels n--; 23416374Skarels if (debug) 23516374Skarels fprintf(stderr, "someone wants %s\n", sep->se_service); 23625046Skarels if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) { 23727535Skarels ctrl = accept(sep->se_fd, (struct sockaddr *)0, 23827535Skarels (int *)0); 23916510Sralph if (debug) 24016510Sralph fprintf(stderr, "accept, ctrl %d\n", ctrl); 24116374Skarels if (ctrl < 0) { 24216374Skarels if (errno == EINTR) 24316374Skarels continue; 24416510Sralph syslog(LOG_WARNING, "accept: %m"); 24516374Skarels continue; 24616374Skarels } 24716374Skarels } else 24816374Skarels ctrl = sep->se_fd; 24927535Skarels (void) sigblock(SIGBLOCK); 25026877Skarels pid = 0; 25127535Skarels dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork); 25227535Skarels if (dofork) { 25327535Skarels if (sep->se_count++ == 0) 25427535Skarels (void)gettimeofday(&sep->se_time, 25527535Skarels (struct timezone *)0); 25627535Skarels else if (sep->se_count >= TOOMANY) { 25727535Skarels struct timeval now; 25827535Skarels 25927535Skarels (void)gettimeofday(&now, (struct timezone *)0); 26027535Skarels if (now.tv_sec - sep->se_time.tv_sec > 26127535Skarels CNT_INTVL) { 26227535Skarels sep->se_time = now; 26327535Skarels sep->se_count = 1; 26427535Skarels } else { 26527535Skarels syslog(LOG_ERR, 26627535Skarels "%s/%s server failing (looping), service terminated\n", 26727535Skarels sep->se_service, sep->se_proto); 26827535Skarels FD_CLR(sep->se_fd, &allsock); 26927535Skarels (void) close(sep->se_fd); 27027535Skarels sep->se_fd = -1; 27127535Skarels sep->se_count = 0; 27227535Skarels nsock--; 27332246Sbostic sigsetmask(0L); 27427535Skarels if (!timingout) { 27527535Skarels timingout = 1; 27627535Skarels alarm(RETRYTIME); 27727535Skarels } 27827535Skarels continue; 27927535Skarels } 28027535Skarels } 28126877Skarels pid = fork(); 28227535Skarels } 28316374Skarels if (pid < 0) { 28425046Skarels if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 28516374Skarels close(ctrl); 28632246Sbostic sigsetmask(0L); 28716374Skarels sleep(1); 28816374Skarels continue; 28916374Skarels } 29027535Skarels if (pid && sep->se_wait) { 29116374Skarels sep->se_wait = pid; 29227535Skarels FD_CLR(sep->se_fd, &allsock); 29325046Skarels nsock--; 29416374Skarels } 29532246Sbostic sigsetmask(0L); 29616374Skarels if (pid == 0) { 29732403Skarels if (debug) { 29832403Skarels int tt; 29927535Skarels 30032403Skarels if (dofork && (tt = open("/dev/tty", O_RDWR)) > 0) { 30116374Skarels ioctl(tt, TIOCNOTTY, 0); 30216374Skarels close(tt); 30332403Skarels } 30432403Skarels (void) setpgrp(0, 0); 30532403Skarels signal(SIGTSTP, SIG_IGN); 30632403Skarels signal(SIGTTIN, SIG_IGN); 30732403Skarels signal(SIGTTOU, SIG_IGN); 30816374Skarels } 30927535Skarels if (dofork) 31026877Skarels for (i = getdtablesize(); --i > 2; ) 31126877Skarels if (i != ctrl) 31226877Skarels close(i); 31326877Skarels if (sep->se_bi) 31426877Skarels (*sep->se_bi->bi_fn)(ctrl, sep); 31526877Skarels else { 31626877Skarels dup2(ctrl, 0); 31726877Skarels close(ctrl); 31826877Skarels dup2(0, 1); 31926877Skarels dup2(0, 2); 32026877Skarels if ((pwd = getpwnam(sep->se_user)) == NULL) { 32126877Skarels syslog(LOG_ERR, 32226877Skarels "getpwnam: %s: No such user", 32326877Skarels sep->se_user); 32427535Skarels if (sep->se_socktype != SOCK_STREAM) 32527535Skarels recv(0, buf, sizeof (buf), 0); 32626877Skarels _exit(1); 32726877Skarels } 32826877Skarels if (pwd->pw_uid) { 32926921Slepreau (void) setgid((gid_t)pwd->pw_gid); 33026877Skarels initgroups(pwd->pw_name, pwd->pw_gid); 33126921Slepreau (void) setuid((uid_t)pwd->pw_uid); 33226877Skarels } 33326877Skarels if (debug) 33426877Skarels fprintf(stderr, "%d execl %s\n", 33526877Skarels getpid(), sep->se_server); 33626877Skarels execv(sep->se_server, sep->se_argv); 33726877Skarels if (sep->se_socktype != SOCK_STREAM) 33826877Skarels recv(0, buf, sizeof (buf), 0); 33926877Skarels syslog(LOG_ERR, "execv %s: %m", sep->se_server); 34026877Skarels _exit(1); 34117346Sbloom } 34216374Skarels } 34325046Skarels if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 34416374Skarels close(ctrl); 34527535Skarels } 34616374Skarels } 34716374Skarels } 34816374Skarels 34916374Skarels reapchild() 35016374Skarels { 35116374Skarels union wait status; 35216374Skarels int pid; 35316374Skarels register struct servtab *sep; 35416374Skarels 35516374Skarels for (;;) { 35626921Slepreau pid = wait3(&status, WNOHANG, (struct rusage *)0); 35716374Skarels if (pid <= 0) 35816374Skarels break; 35916374Skarels if (debug) 36016374Skarels fprintf(stderr, "%d reaped\n", pid); 36116374Skarels for (sep = servtab; sep; sep = sep->se_next) 36216374Skarels if (sep->se_wait == pid) { 36316374Skarels if (status.w_status) 36416510Sralph syslog(LOG_WARNING, 36516510Sralph "%s: exit status 0x%x", 36616374Skarels sep->se_server, status); 36716374Skarels if (debug) 36816374Skarels fprintf(stderr, "restored %s, fd %d\n", 36916374Skarels sep->se_service, sep->se_fd); 37025046Skarels FD_SET(sep->se_fd, &allsock); 37125046Skarels nsock++; 37216374Skarels sep->se_wait = 1; 37316374Skarels } 37416374Skarels } 37516374Skarels } 37616374Skarels 37716374Skarels config() 37816374Skarels { 37916374Skarels register struct servtab *sep, *cp, **sepp; 38016374Skarels struct servtab *getconfigent(), *enter(); 38132246Sbostic long omask; 38216374Skarels 38316374Skarels if (!setconfig()) { 38416510Sralph syslog(LOG_ERR, "%s: %m", CONFIG); 38516374Skarels return; 38616374Skarels } 38716374Skarels for (sep = servtab; sep; sep = sep->se_next) 38816374Skarels sep->se_checked = 0; 38916374Skarels while (cp = getconfigent()) { 39016374Skarels for (sep = servtab; sep; sep = sep->se_next) 39116374Skarels if (strcmp(sep->se_service, cp->se_service) == 0 && 39216374Skarels strcmp(sep->se_proto, cp->se_proto) == 0) 39316374Skarels break; 39416374Skarels if (sep != 0) { 39516374Skarels int i; 39616374Skarels 39727535Skarels omask = sigblock(SIGBLOCK); 39827535Skarels if (cp->se_bi == 0) 39927535Skarels sep->se_wait = cp->se_wait; 40016374Skarels #define SWAP(a, b) { char *c = a; a = b; b = c; } 40126921Slepreau if (cp->se_user) 40226921Slepreau SWAP(sep->se_user, cp->se_user); 40316374Skarels if (cp->se_server) 40416374Skarels SWAP(sep->se_server, cp->se_server); 40516374Skarels for (i = 0; i < MAXARGV; i++) 40616374Skarels SWAP(sep->se_argv[i], cp->se_argv[i]); 40716374Skarels sigsetmask(omask); 40816374Skarels freeconfig(cp); 40929794Skarels if (debug) 41029794Skarels print_service("REDO", sep); 41129794Skarels } else { 41216374Skarels sep = enter(cp); 41329794Skarels if (debug) 41429794Skarels print_service("ADD ", sep); 41529794Skarels } 41616374Skarels sep->se_checked = 1; 41716374Skarels sp = getservbyname(sep->se_service, sep->se_proto); 41816374Skarels if (sp == 0) { 41916510Sralph syslog(LOG_ERR, "%s/%s: unknown service", 42016374Skarels sep->se_service, sep->se_proto); 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 45727535Skarels retry() 45827535Skarels { 45927535Skarels register struct servtab *sep; 46027535Skarels 46127535Skarels timingout = 0; 46227535Skarels for (sep = servtab; sep; sep = sep->se_next) 46327535Skarels if (sep->se_fd == -1) 46427535Skarels setup(sep); 46527535Skarels } 46627535Skarels 46727535Skarels setup(sep) 46827535Skarels register struct servtab *sep; 46927535Skarels { 47027535Skarels int on = 1; 47127535Skarels 47227535Skarels if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 47327535Skarels syslog(LOG_ERR, "%s/%s: socket: %m", 47427535Skarels sep->se_service, sep->se_proto); 47527535Skarels return; 47627535Skarels } 47727535Skarels #define turnon(fd, opt) \ 47827535Skarels setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 47927535Skarels if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 48027535Skarels turnon(sep->se_fd, SO_DEBUG) < 0) 48127535Skarels syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 48227535Skarels if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 48327535Skarels syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 48427535Skarels #undef turnon 48527535Skarels if (bind(sep->se_fd, &sep->se_ctrladdr, 48627535Skarels sizeof (sep->se_ctrladdr)) < 0) { 48727535Skarels syslog(LOG_ERR, "%s/%s: bind: %m", 48827535Skarels sep->se_service, sep->se_proto); 48927535Skarels (void) close(sep->se_fd); 49027535Skarels sep->se_fd = -1; 49127535Skarels if (!timingout) { 49227535Skarels timingout = 1; 49327535Skarels alarm(RETRYTIME); 49427535Skarels } 49527535Skarels return; 49627535Skarels } 49727535Skarels if (sep->se_socktype == SOCK_STREAM) 49827535Skarels listen(sep->se_fd, 10); 49927535Skarels FD_SET(sep->se_fd, &allsock); 50027535Skarels nsock++; 50127535Skarels if (sep->se_fd > maxsock) 50227535Skarels maxsock = sep->se_fd; 50327535Skarels } 50427535Skarels 50516374Skarels struct servtab * 50616374Skarels enter(cp) 50716374Skarels struct servtab *cp; 50816374Skarels { 50916374Skarels register struct servtab *sep; 51032246Sbostic long omask; 51116374Skarels char *strdup(); 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 { 54516374Skarels 54616374Skarels if (fconfig == NULL) 54716374Skarels return; 54816374Skarels fclose(fconfig); 54916374Skarels fconfig = NULL; 55016374Skarels } 55116374Skarels 55216374Skarels struct servtab * 55316374Skarels getconfigent() 55416374Skarels { 55516374Skarels register struct servtab *sep = &serv; 55616374Skarels char *cp, *arg; 55716374Skarels int argc; 55816374Skarels 55926877Skarels more: 56016374Skarels while ((cp = nextline(fconfig)) && *cp == '#') 56116374Skarels ; 56216374Skarels if (cp == NULL) 56316374Skarels return ((struct servtab *)0); 56416374Skarels sep->se_service = strdup(skip(&cp)); 56516374Skarels arg = skip(&cp); 56616374Skarels if (strcmp(arg, "stream") == 0) 56716374Skarels sep->se_socktype = SOCK_STREAM; 56816374Skarels else if (strcmp(arg, "dgram") == 0) 56916374Skarels sep->se_socktype = SOCK_DGRAM; 57016374Skarels else if (strcmp(arg, "rdm") == 0) 57116374Skarels sep->se_socktype = SOCK_RDM; 57216374Skarels else if (strcmp(arg, "seqpacket") == 0) 57316374Skarels sep->se_socktype = SOCK_SEQPACKET; 57416374Skarels else if (strcmp(arg, "raw") == 0) 57516374Skarels sep->se_socktype = SOCK_RAW; 57616374Skarels else 57716374Skarels sep->se_socktype = -1; 57816374Skarels sep->se_proto = strdup(skip(&cp)); 57916374Skarels arg = skip(&cp); 58016374Skarels sep->se_wait = strcmp(arg, "wait") == 0; 58117346Sbloom sep->se_user = strdup(skip(&cp)); 58216374Skarels sep->se_server = strdup(skip(&cp)); 58326877Skarels if (strcmp(sep->se_server, "internal") == 0) { 58426877Skarels register struct biltin *bi; 58526877Skarels 58626877Skarels for (bi = biltins; bi->bi_service; bi++) 58726877Skarels if (bi->bi_socktype == sep->se_socktype && 58826877Skarels strcmp(bi->bi_service, sep->se_service) == 0) 58926877Skarels break; 59026877Skarels if (bi->bi_service == 0) { 59126877Skarels syslog(LOG_ERR, "internal service %s unknown\n", 59226877Skarels sep->se_service); 59326877Skarels goto more; 59426877Skarels } 59526877Skarels sep->se_bi = bi; 59626877Skarels sep->se_wait = bi->bi_wait; 59729794Skarels } else 59829794Skarels sep->se_bi = NULL; 59916374Skarels argc = 0; 60016374Skarels for (arg = skip(&cp); cp; arg = skip(&cp)) 60116374Skarels if (argc < MAXARGV) 60216374Skarels sep->se_argv[argc++] = strdup(arg); 60316374Skarels while (argc <= MAXARGV) 60416374Skarels sep->se_argv[argc++] = NULL; 60516374Skarels return (sep); 60616374Skarels } 60716374Skarels 60816374Skarels freeconfig(cp) 60916374Skarels register struct servtab *cp; 61016374Skarels { 61116374Skarels int i; 61216374Skarels 61316374Skarels if (cp->se_service) 61416374Skarels free(cp->se_service); 61516374Skarels if (cp->se_proto) 61616374Skarels free(cp->se_proto); 61726921Slepreau if (cp->se_user) 61826921Slepreau free(cp->se_user); 61916374Skarels if (cp->se_server) 62016374Skarels free(cp->se_server); 62116374Skarels for (i = 0; i < MAXARGV; i++) 62216374Skarels if (cp->se_argv[i]) 62316374Skarels free(cp->se_argv[i]); 62416374Skarels } 62516374Skarels 62616374Skarels char * 62716374Skarels skip(cpp) 62816374Skarels char **cpp; 62916374Skarels { 63016374Skarels register char *cp = *cpp; 63116374Skarels char *start; 63216374Skarels 63316374Skarels again: 63416374Skarels while (*cp == ' ' || *cp == '\t') 63516374Skarels cp++; 63616374Skarels if (*cp == '\0') { 63716374Skarels char c; 63816374Skarels 63916374Skarels c = getc(fconfig); 64016374Skarels ungetc(c, fconfig); 64116374Skarels if (c == ' ' || c == '\t') 64216374Skarels if (cp = nextline(fconfig)) 64316374Skarels goto again; 64416374Skarels *cpp = (char *)0; 64516374Skarels return ((char *)0); 64616374Skarels } 64716374Skarels start = cp; 64816374Skarels while (*cp && *cp != ' ' && *cp != '\t') 64916374Skarels cp++; 65016374Skarels if (*cp != '\0') 65116374Skarels *cp++ = '\0'; 65216374Skarels *cpp = cp; 65316374Skarels return (start); 65416374Skarels } 65516374Skarels 65616374Skarels char * 65716374Skarels nextline(fd) 65816374Skarels FILE *fd; 65916374Skarels { 66016374Skarels char *cp; 66116374Skarels 66226921Slepreau if (fgets(line, sizeof (line), fd) == NULL) 66316374Skarels return ((char *)0); 66416374Skarels cp = index(line, '\n'); 66516374Skarels if (cp) 66616374Skarels *cp = '\0'; 66716374Skarels return (line); 66816374Skarels } 66916374Skarels 67016374Skarels char * 67116374Skarels strdup(cp) 67216374Skarels char *cp; 67316374Skarels { 67416374Skarels char *new; 67516374Skarels 67616374Skarels if (cp == NULL) 67716374Skarels cp = ""; 67826921Slepreau new = malloc((unsigned)(strlen(cp) + 1)); 67916374Skarels if (new == (char *)0) { 68016510Sralph syslog(LOG_ERR, "Out of memory."); 68116374Skarels exit(-1); 68216374Skarels } 68316374Skarels strcpy(new, cp); 68416374Skarels return (new); 68516374Skarels } 68626877Skarels 68726877Skarels setproctitle(a, s) 68826877Skarels char *a; 68926877Skarels int s; 69026877Skarels { 69126877Skarels int size; 69226877Skarels register char *cp; 69326877Skarels struct sockaddr_in sin; 69426877Skarels char buf[80]; 69526877Skarels 69626877Skarels cp = Argv[0]; 69726877Skarels size = sizeof(sin); 69826877Skarels if (getpeername(s, &sin, &size) == 0) 699*32442Sbostic (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 70026877Skarels else 701*32442Sbostic (void) sprintf(buf, "-%s", a); 70226877Skarels strncpy(cp, buf, LastArg - cp); 70326877Skarels cp += strlen(cp); 70426877Skarels while (cp < LastArg) 70526877Skarels *cp++ = ' '; 70626877Skarels } 70726877Skarels 70826877Skarels /* 70926877Skarels * Internet services provided internally by inetd: 71026877Skarels */ 71126877Skarels 71226877Skarels /* ARGSUSED */ 71326877Skarels echo_stream(s, sep) /* Echo service -- echo data back */ 71426877Skarels int s; 71526877Skarels struct servtab *sep; 71626877Skarels { 71726877Skarels char buffer[BUFSIZ]; 71826877Skarels int i; 71926877Skarels 72032091Skarels setproctitle(sep->se_service, s); 72126877Skarels while ((i = read(s, buffer, sizeof(buffer))) > 0 && 72226877Skarels write(s, buffer, i) > 0) 72326877Skarels ; 72426877Skarels exit(0); 72526877Skarels } 72626877Skarels 72726877Skarels /* ARGSUSED */ 72826877Skarels echo_dg(s, sep) /* Echo service -- echo data back */ 72926877Skarels int s; 73026877Skarels struct servtab *sep; 73126877Skarels { 73226877Skarels char buffer[BUFSIZ]; 73326877Skarels int i, size; 73426877Skarels struct sockaddr sa; 73526877Skarels 73626877Skarels size = sizeof(sa); 73726877Skarels if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) 73826877Skarels return; 73926877Skarels (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); 74026877Skarels } 74126877Skarels 74226877Skarels /* ARGSUSED */ 74326877Skarels discard_stream(s, sep) /* Discard service -- ignore data */ 74426877Skarels int s; 74526877Skarels struct servtab *sep; 74626877Skarels { 74726877Skarels char buffer[BUFSIZ]; 74826877Skarels 74932091Skarels setproctitle(sep->se_service, s); 75026877Skarels while (1) { 75126877Skarels while (read(s, buffer, sizeof(buffer)) > 0) 75226877Skarels ; 75326877Skarels if (errno != EINTR) 75426877Skarels break; 75526877Skarels } 75626877Skarels exit(0); 75726877Skarels } 75826877Skarels 75926877Skarels /* ARGSUSED */ 76026877Skarels discard_dg(s, sep) /* Discard service -- ignore data */ 76126877Skarels int s; 76226877Skarels struct servtab *sep; 76326877Skarels { 76426877Skarels char buffer[BUFSIZ]; 76526877Skarels 76626877Skarels (void) read(s, buffer, sizeof(buffer)); 76726877Skarels } 76826877Skarels 76926877Skarels #include <ctype.h> 77026877Skarels #define LINESIZ 72 77126877Skarels char ring[128]; 77226877Skarels char *endring; 77326877Skarels 77426877Skarels initring() 77526877Skarels { 77626877Skarels register int i; 77726877Skarels 77826877Skarels endring = ring; 77926877Skarels 78026877Skarels for (i = 0; i <= 128; ++i) 78126877Skarels if (isprint(i)) 78226877Skarels *endring++ = i; 78326877Skarels } 78426877Skarels 78526877Skarels /* ARGSUSED */ 78626877Skarels chargen_stream(s, sep) /* Character generator */ 78726877Skarels int s; 78826877Skarels struct servtab *sep; 78926877Skarels { 79032246Sbostic register char *rs; 79132246Sbostic int len; 79226877Skarels char text[LINESIZ+2]; 79326877Skarels 79432091Skarels setproctitle(sep->se_service, s); 79532246Sbostic 79632246Sbostic if (!endring) { 79726877Skarels initring(); 79832246Sbostic rs = ring; 79932246Sbostic } 80026877Skarels 80132246Sbostic text[LINESIZ] = '\r'; 80232246Sbostic text[LINESIZ + 1] = '\n'; 80332246Sbostic for (rs = ring;;) { 80432246Sbostic if ((len = endring - rs) >= LINESIZ) 80532246Sbostic bcopy(rs, text, LINESIZ); 80632246Sbostic else { 80732246Sbostic bcopy(rs, text, len); 80832246Sbostic bcopy(ring, text + len, LINESIZ - len); 80932246Sbostic } 81032246Sbostic if (++rs == endring) 81126877Skarels rs = ring; 81232246Sbostic if (write(s, text, sizeof(text)) != sizeof(text)) 81326877Skarels break; 81426877Skarels } 81526877Skarels exit(0); 81626877Skarels } 81726877Skarels 81826877Skarels /* ARGSUSED */ 81926877Skarels chargen_dg(s, sep) /* Character generator */ 82026877Skarels int s; 82126877Skarels struct servtab *sep; 82226877Skarels { 82332246Sbostic struct sockaddr sa; 82432246Sbostic static char *rs; 82532246Sbostic int len, size; 82626877Skarels char text[LINESIZ+2]; 82726877Skarels 82832246Sbostic if (endring == 0) { 82926877Skarels initring(); 83032246Sbostic rs = ring; 83132246Sbostic } 83226877Skarels 83326877Skarels size = sizeof(sa); 83426877Skarels if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) 83526877Skarels return; 83632246Sbostic 83732246Sbostic if ((len = endring - rs) >= LINESIZ) 83832246Sbostic bcopy(rs, text, LINESIZ); 83932246Sbostic else { 84032246Sbostic bcopy(rs, text, len); 84132246Sbostic bcopy(ring, text + len, LINESIZ - len); 84232246Sbostic } 84332246Sbostic if (++rs == endring) 84426877Skarels rs = ring; 84532246Sbostic text[LINESIZ] = '\r'; 84632246Sbostic text[LINESIZ + 1] = '\n'; 84726877Skarels (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa)); 84826877Skarels } 84926877Skarels 85026877Skarels /* 85126877Skarels * Return a machine readable date and time, in the form of the 85226877Skarels * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 85326877Skarels * returns the number of seconds since midnight, Jan 1, 1970, 85426877Skarels * we must add 2208988800 seconds to this figure to make up for 85526877Skarels * some seventy years Bell Labs was asleep. 85626877Skarels */ 85726877Skarels 85826877Skarels long 85926877Skarels machtime() 86026877Skarels { 86126877Skarels struct timeval tv; 86226877Skarels 86326921Slepreau if (gettimeofday(&tv, (struct timezone *)0) < 0) { 86426877Skarels fprintf(stderr, "Unable to get time of day\n"); 86526921Slepreau return (0L); 86626877Skarels } 86726877Skarels return (htonl((long)tv.tv_sec + 2208988800)); 86826877Skarels } 86926877Skarels 87026877Skarels /* ARGSUSED */ 87126877Skarels machtime_stream(s, sep) 87226877Skarels int s; 87326877Skarels struct servtab *sep; 87426877Skarels { 87526877Skarels long result; 87626877Skarels 87726877Skarels result = machtime(); 87826877Skarels (void) write(s, (char *) &result, sizeof(result)); 87926877Skarels } 88026877Skarels 88126877Skarels /* ARGSUSED */ 88226877Skarels machtime_dg(s, sep) 88326877Skarels int s; 88426877Skarels struct servtab *sep; 88526877Skarels { 88626877Skarels long result; 88726877Skarels struct sockaddr sa; 88826877Skarels int size; 88926877Skarels 89026877Skarels size = sizeof(sa); 89126921Slepreau if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0) 89226877Skarels return; 89326877Skarels result = machtime(); 89426877Skarels (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa)); 89526877Skarels } 89626877Skarels 89726877Skarels /* ARGSUSED */ 89826877Skarels daytime_stream(s, sep) /* Return human-readable time of day */ 89926877Skarels int s; 90026877Skarels struct servtab *sep; 90126877Skarels { 90226877Skarels char buffer[256]; 90326877Skarels time_t time(), clock; 90426877Skarels char *ctime(); 90526877Skarels 90626877Skarels clock = time((time_t *) 0); 90726877Skarels 908*32442Sbostic (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 90926921Slepreau (void) write(s, buffer, strlen(buffer)); 91026877Skarels } 91126877Skarels 91226877Skarels /* ARGSUSED */ 91326877Skarels daytime_dg(s, sep) /* Return human-readable time of day */ 91426877Skarels int s; 91526877Skarels struct servtab *sep; 91626877Skarels { 91726877Skarels char buffer[256]; 91826877Skarels time_t time(), clock; 91926877Skarels struct sockaddr sa; 92026877Skarels int size; 92126877Skarels char *ctime(); 92226877Skarels 92326877Skarels clock = time((time_t *) 0); 92426877Skarels 92526877Skarels size = sizeof(sa); 92626877Skarels if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) 92726877Skarels return; 928*32442Sbostic (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 92926877Skarels (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa)); 93026877Skarels } 93129794Skarels 93229794Skarels /* 93329794Skarels * print_service: 93429794Skarels * Dump relevant information to stderr 93529794Skarels */ 93629794Skarels print_service(action, sep) 93729794Skarels char *action; 93829794Skarels struct servtab *sep; 93929794Skarels { 94029794Skarels fprintf(stderr, 94129794Skarels "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n", 94229794Skarels action, sep->se_service, sep->se_proto, 94329794Skarels sep->se_wait, sep->se_user, sep->se_bi, sep->se_server); 94429794Skarels } 945