121134Sdist /* 2*66778Spendry * Copyright (c) 1983, 1991, 1993, 1994 361830Sbostic * The Regents of the University of California. All rights reserved. 433136Sbostic * 542799Sbostic * %sccs.include.redist.c% 621134Sdist */ 721134Sdist 816374Skarels #ifndef lint 961830Sbostic static char copyright[] = 10*66778Spendry "@(#) Copyright (c) 1983, 1991, 1993, 1994\n\ 1161830Sbostic The Regents of the University of California. All rights reserved.\n"; 1233136Sbostic #endif /* not lint */ 1316374Skarels 1421134Sdist #ifndef lint 15*66778Spendry static char sccsid[] = "@(#)inetd.c 8.3 (Berkeley) 04/13/94"; 1633136Sbostic #endif /* not lint */ 1721134Sdist 1816374Skarels /* 1916374Skarels * Inetd - Internet super-server 2016374Skarels * 2157769Sandrew * This program invokes all internet services as needed. Connection-oriented 2257769Sandrew * services are invoked each time a connection is made, by creating a process. 2357769Sandrew * This process is passed the connection as file descriptor 0 and is expected 2457769Sandrew * to do a getpeername to find out the source host and port. 2516374Skarels * 2616374Skarels * Datagram oriented services are invoked when a datagram 2716374Skarels * arrives; a process is created and passed a pending message 2816374Skarels * on file descriptor 0. Datagram servers may either connect 2916374Skarels * to their peer, freeing up the original socket for inetd 3016374Skarels * to receive further messages on, or ``take over the socket'', 3116374Skarels * processing all arriving datagrams and, eventually, timing 3216374Skarels * out. The first type of server is said to be ``multi-threaded''; 3316374Skarels * the second type of server ``single-threaded''. 3416374Skarels * 3516374Skarels * Inetd uses a configuration file which is read at startup 3616374Skarels * and, possibly, at some later time in response to a hangup signal. 3716374Skarels * The configuration file is ``free format'' with fields given in the 3816374Skarels * order shown below. Continuation lines for an entry must being with 3916374Skarels * a space or tab. All fields must be present in each entry. 4016374Skarels * 4157769Sandrew * service name must be in /etc/services or must 4257769Sandrew * name a tcpmux service 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 4840740Sbostic * server program arguments maximum of MAXARGS (20) 4916374Skarels * 5057769Sandrew * TCP services without official port numbers are handled with the 5157769Sandrew * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for 5257769Sandrew * requests. When a connection is made from a foreign host, the service 5357769Sandrew * requested is passed to tcpmux, which looks it up in the servtab list 5457769Sandrew * and returns the proper entry for the service. Tcpmux returns a 5557769Sandrew * negative reply if the service doesn't exist, otherwise the invoked 5657769Sandrew * server is expected to return the positive reply if the service type in 5757769Sandrew * inetd.conf file has the prefix "tcpmux/". If the service type has the 5857769Sandrew * prefix "tcpmux/+", tcpmux will return the positive reply for the 5957769Sandrew * process; this is for compatibility with older server code, and also 6057769Sandrew * allows you to invoke programs that use stdin/stdout without putting any 6157769Sandrew * special server code in them. Services that use tcpmux are "nowait" 6257769Sandrew * because they do not have a well-known port and hence cannot listen 6357769Sandrew * for new requests. 6457769Sandrew * 6516374Skarels * Comment lines are indicated by a `#' in column 1. 6616374Skarels */ 6716374Skarels #include <sys/param.h> 6816374Skarels #include <sys/stat.h> 6916374Skarels #include <sys/ioctl.h> 7016374Skarels #include <sys/socket.h> 7116374Skarels #include <sys/wait.h> 7226921Slepreau #include <sys/time.h> 7326921Slepreau #include <sys/resource.h> 7416374Skarels 7516374Skarels #include <netinet/in.h> 7616374Skarels #include <arpa/inet.h> 7716374Skarels 7816374Skarels #include <errno.h> 7957769Sandrew #include <fcntl.h> 8016374Skarels #include <netdb.h> 8117346Sbloom #include <pwd.h> 8257769Sandrew #include <signal.h> 8336603Sbostic #include <stdio.h> 8457769Sandrew #include <stdlib.h> 8542067Sbostic #include <string.h> 8657769Sandrew #include <syslog.h> 8757769Sandrew #include <unistd.h> 8857769Sandrew 8937282Sbostic #include "pathnames.h" 9016374Skarels 9127535Skarels #define TOOMANY 40 /* don't start more than TOOMANY */ 9227535Skarels #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 9327535Skarels #define RETRYTIME (60*10) /* retry after bind or server fail */ 9427535Skarels 9527535Skarels #define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 9627535Skarels 9716374Skarels 9816374Skarels int debug = 0; 9925046Skarels int nsock, maxsock; 10025046Skarels fd_set allsock; 10116374Skarels int options; 10227535Skarels int timingout; 10357769Sandrew int toomany = TOOMANY; 10416374Skarels struct servent *sp; 10516374Skarels 10616374Skarels struct servtab { 10716374Skarels char *se_service; /* name of service */ 10816374Skarels int se_socktype; /* type of socket to use */ 10916374Skarels char *se_proto; /* protocol used */ 11016374Skarels short se_wait; /* single threaded server */ 11116374Skarels short se_checked; /* looked at during merge */ 11217346Sbloom char *se_user; /* user name to run as */ 11326877Skarels struct biltin *se_bi; /* if built-in, description */ 11416374Skarels char *se_server; /* server program */ 11540740Sbostic #define MAXARGV 20 11616374Skarels char *se_argv[MAXARGV+1]; /* program arguments */ 11716374Skarels int se_fd; /* open descriptor */ 11857769Sandrew int se_type; /* type */ 11916374Skarels struct sockaddr_in se_ctrladdr;/* bound address */ 12027535Skarels int se_count; /* number started since se_time */ 12127535Skarels struct timeval se_time; /* start of se_count */ 12216374Skarels struct servtab *se_next; 12316374Skarels } *servtab; 12416374Skarels 12557769Sandrew #define NORM_TYPE 0 12657769Sandrew #define MUX_TYPE 1 12757769Sandrew #define MUXPLUS_TYPE 2 12857769Sandrew #define ISMUX(sep) (((sep)->se_type == MUX_TYPE) || \ 12957769Sandrew ((sep)->se_type == MUXPLUS_TYPE)) 13057769Sandrew #define ISMUXPLUS(sep) ((sep)->se_type == MUXPLUS_TYPE) 13157769Sandrew 13226877Skarels 13366696Spendry void chargen_dg __P((int, struct servtab *)); 13466696Spendry void chargen_stream __P((int, struct servtab *)); 13566696Spendry void close_sep __P((struct servtab *)); 13666696Spendry void config __P((int)); 13766696Spendry void daytime_dg __P((int, struct servtab *)); 13866696Spendry void daytime_stream __P((int, struct servtab *)); 13966696Spendry void discard_dg __P((int, struct servtab *)); 14066696Spendry void discard_stream __P((int, struct servtab *)); 14166696Spendry void echo_dg __P((int, struct servtab *)); 14266696Spendry void echo_stream __P((int, struct servtab *)); 14366696Spendry void endconfig __P((void)); 14466696Spendry struct servtab *enter __P((struct servtab *)); 14566696Spendry void freeconfig __P((struct servtab *)); 14666696Spendry struct servtab *getconfigent __P((void)); 14766696Spendry void machtime_dg __P((int, struct servtab *)); 14866696Spendry void machtime_stream __P((int, struct servtab *)); 14966696Spendry char *newstr __P((char *)); 15066696Spendry char *nextline __P((FILE *)); 15166696Spendry void print_service __P((char *, struct servtab *)); 15266696Spendry void reapchild __P((int)); 15366696Spendry void retry __P((int)); 15466696Spendry int setconfig __P((void)); 15566696Spendry void setup __P((struct servtab *)); 15666696Spendry char *sskip __P((char **)); 15766696Spendry char *skip __P((char **)); 15866696Spendry struct servtab *tcpmux __P((int)); 15966696Spendry 16026877Skarels struct biltin { 16126877Skarels char *bi_service; /* internally provided service name */ 16226877Skarels int bi_socktype; /* type of socket supported */ 16326877Skarels short bi_fork; /* 1 if should fork before call */ 16426877Skarels short bi_wait; /* 1 if should wait for child */ 16566696Spendry void (*bi_fn)(); /* function which performs it */ 16626877Skarels } biltins[] = { 16726877Skarels /* Echo received data */ 16866696Spendry { "echo", SOCK_STREAM, 1, 0, echo_stream }, 16966696Spendry { "echo", SOCK_DGRAM, 0, 0, echo_dg }, 17026877Skarels 17126877Skarels /* Internet /dev/null */ 17266696Spendry { "discard", SOCK_STREAM, 1, 0, discard_stream }, 17366696Spendry { "discard", SOCK_DGRAM, 0, 0, discard_dg }, 17426877Skarels 17526877Skarels /* Return 32 bit time since 1970 */ 17666696Spendry { "time", SOCK_STREAM, 0, 0, machtime_stream }, 17766696Spendry { "time", SOCK_DGRAM, 0, 0, machtime_dg }, 17826877Skarels 17926877Skarels /* Return human-readable time */ 18066696Spendry { "daytime", SOCK_STREAM, 0, 0, daytime_stream }, 18166696Spendry { "daytime", SOCK_DGRAM, 0, 0, daytime_dg }, 18226877Skarels 18326877Skarels /* Familiar character generator */ 18466696Spendry { "chargen", SOCK_STREAM, 1, 0, chargen_stream }, 18566696Spendry { "chargen", SOCK_DGRAM, 0, 0, chargen_dg }, 18657769Sandrew 18766696Spendry { "tcpmux", SOCK_STREAM, 1, 0, (void (*)())tcpmux }, 18857769Sandrew 18966696Spendry { NULL } 19026877Skarels }; 19126877Skarels 19226877Skarels #define NUMINT (sizeof(intab) / sizeof(struct inent)) 19337282Sbostic char *CONFIG = _PATH_INETDCONF; 19426877Skarels char **Argv; 19526877Skarels char *LastArg; 19616374Skarels 19766696Spendry int 19826877Skarels main(argc, argv, envp) 19916374Skarels int argc; 20026877Skarels char *argv[], *envp[]; 20116374Skarels { 20266696Spendry struct servtab *sep; 20366696Spendry struct passwd *pwd; 20427535Skarels struct sigvec sv; 20566696Spendry int tmpint, ch, dofork; 20666696Spendry pid_t pid; 20736603Sbostic char buf[50]; 20816374Skarels 20926877Skarels Argv = argv; 21026877Skarels if (envp == 0 || *envp == 0) 21126877Skarels envp = argv; 21226877Skarels while (*envp) 21326877Skarels envp++; 21426877Skarels LastArg = envp[-1] + strlen(envp[-1]); 21516374Skarels 21657769Sandrew openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 21757769Sandrew 21857769Sandrew while ((ch = getopt(argc, argv, "dR:")) != EOF) 21936603Sbostic switch(ch) { 22016374Skarels case 'd': 22116374Skarels debug = 1; 22216374Skarels options |= SO_DEBUG; 22316374Skarels break; 22457769Sandrew case 'R': { /* invocation rate */ 22557769Sandrew char *p; 22657769Sandrew 22757769Sandrew tmpint = strtol(optarg, &p, 0); 22857769Sandrew if (tmpint < 1 || *p) 22957769Sandrew syslog(LOG_ERR, 23057769Sandrew "-R %s: bad value for service invocation rate", 23157769Sandrew optarg); 23257769Sandrew else 23357769Sandrew toomany = tmpint; 23457769Sandrew break; 23557769Sandrew } 23636603Sbostic case '?': 23716374Skarels default: 23857769Sandrew syslog(LOG_ERR, 23957769Sandrew "usage: inetd [-d] [-R rate] [conf-file]"); 24036603Sbostic exit(1); 24116374Skarels } 24236603Sbostic argc -= optind; 24336603Sbostic argv += optind; 24436603Sbostic 24516374Skarels if (argc > 0) 24616374Skarels CONFIG = argv[0]; 24757769Sandrew if (debug == 0) { 24844711Skarels daemon(0, 0); 24957769Sandrew } 25066696Spendry memset(&sv, 0, sizeof(sv)); 25127535Skarels sv.sv_mask = SIGBLOCK; 25227535Skarels sv.sv_handler = retry; 25327535Skarels sigvec(SIGALRM, &sv, (struct sigvec *)0); 25466696Spendry config(SIGHUP); 25527535Skarels sv.sv_handler = config; 25627535Skarels sigvec(SIGHUP, &sv, (struct sigvec *)0); 25727535Skarels sv.sv_handler = reapchild; 25827535Skarels sigvec(SIGCHLD, &sv, (struct sigvec *)0); 25927535Skarels 26036603Sbostic { 26136603Sbostic /* space for daemons to overwrite environment for ps */ 26236603Sbostic #define DUMMYSIZE 100 26336603Sbostic char dummy[DUMMYSIZE]; 26436603Sbostic 26536603Sbostic (void)memset(dummy, 'x', sizeof(DUMMYSIZE) - 1); 26636603Sbostic dummy[DUMMYSIZE - 1] = '\0'; 26736603Sbostic (void)setenv("inetd_dummy", dummy, 1); 26836603Sbostic } 26936603Sbostic 27016374Skarels for (;;) { 27136603Sbostic int n, ctrl; 27227535Skarels fd_set readable; 27316374Skarels 27432091Skarels if (nsock == 0) { 27532091Skarels (void) sigblock(SIGBLOCK); 27632091Skarels while (nsock == 0) 27732246Sbostic sigpause(0L); 27832246Sbostic (void) sigsetmask(0L); 27932091Skarels } 28027535Skarels readable = allsock; 28127535Skarels if ((n = select(maxsock + 1, &readable, (fd_set *)0, 28227535Skarels (fd_set *)0, (struct timeval *)0)) <= 0) { 28327535Skarels if (n < 0 && errno != EINTR) 28457769Sandrew syslog(LOG_WARNING, "select: %m"); 28527535Skarels sleep(1); 28627535Skarels continue; 28727535Skarels } 28827535Skarels for (sep = servtab; n && sep; sep = sep->se_next) 28946973Skarels if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 29046973Skarels n--; 29146973Skarels if (debug) 29246973Skarels fprintf(stderr, "someone wants %s\n", 29346973Skarels sep->se_service); 29446973Skarels if (sep->se_socktype == SOCK_STREAM) { 29546973Skarels ctrl = accept(sep->se_fd, (struct sockaddr *)0, 29646973Skarels (int *)0); 29746973Skarels if (debug) 29846973Skarels fprintf(stderr, "accept, ctrl %d\n", ctrl); 29946973Skarels if (ctrl < 0) { 30057769Sandrew if (errno != EINTR) 30157769Sandrew syslog(LOG_WARNING, 30257769Sandrew "accept (for %s): %m", 30357769Sandrew sep->se_service); 30446973Skarels continue; 30546973Skarels } 30657769Sandrew /* 30757769Sandrew * Call tcpmux to find the real service to exec. 30857769Sandrew */ 30957769Sandrew if (sep->se_bi && 31066696Spendry sep->se_bi->bi_fn == (void (*)()) tcpmux) { 31157769Sandrew sep = tcpmux(ctrl); 31257769Sandrew if (sep == NULL) { 31357769Sandrew close(ctrl); 31457769Sandrew continue; 31557769Sandrew } 31657769Sandrew } 31746973Skarels } else 31846973Skarels ctrl = sep->se_fd; 31946973Skarels (void) sigblock(SIGBLOCK); 32046973Skarels pid = 0; 32146973Skarels dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork); 32246973Skarels if (dofork) { 32346973Skarels if (sep->se_count++ == 0) 32446973Skarels (void)gettimeofday(&sep->se_time, 32546973Skarels (struct timezone *)0); 32657769Sandrew else if (sep->se_count >= toomany) { 32727535Skarels struct timeval now; 32827535Skarels 32927535Skarels (void)gettimeofday(&now, (struct timezone *)0); 33027535Skarels if (now.tv_sec - sep->se_time.tv_sec > 33127535Skarels CNT_INTVL) { 33227535Skarels sep->se_time = now; 33327535Skarels sep->se_count = 1; 33427535Skarels } else { 33527535Skarels syslog(LOG_ERR, 33657769Sandrew "%s/%s server failing (looping), service terminated", 33727535Skarels sep->se_service, sep->se_proto); 33857769Sandrew close_sep(sep); 33957769Sandrew sigsetmask(0L); 34027535Skarels if (!timingout) { 34127535Skarels timingout = 1; 34227535Skarels alarm(RETRYTIME); 34327535Skarels } 34457769Sandrew continue; 34527535Skarels } 34646973Skarels } 34746973Skarels pid = fork(); 34846973Skarels } 34946973Skarels if (pid < 0) { 35046973Skarels syslog(LOG_ERR, "fork: %m"); 35146973Skarels if (sep->se_socktype == SOCK_STREAM) 35246973Skarels close(ctrl); 35346973Skarels sigsetmask(0L); 35446973Skarels sleep(1); 35546973Skarels continue; 35646973Skarels } 35746973Skarels if (pid && sep->se_wait) { 35846973Skarels sep->se_wait = pid; 35949806Sbostic if (sep->se_fd >= 0) { 36049806Sbostic FD_CLR(sep->se_fd, &allsock); 36149806Sbostic nsock--; 36249806Sbostic } 36346973Skarels } 36446973Skarels sigsetmask(0L); 36546973Skarels if (pid == 0) { 36646973Skarels if (debug && dofork) 36744711Skarels setsid(); 36857769Sandrew if (dofork) { 36957769Sandrew if (debug) 37057769Sandrew fprintf(stderr, "+ Closing from %d\n", 37157769Sandrew maxsock); 37257769Sandrew for (tmpint = maxsock; tmpint > 2; tmpint--) 37336603Sbostic if (tmpint != ctrl) 37436603Sbostic close(tmpint); 37557769Sandrew } 37646973Skarels if (sep->se_bi) 37726877Skarels (*sep->se_bi->bi_fn)(ctrl, sep); 37846973Skarels else { 37946973Skarels if (debug) 38046973Skarels fprintf(stderr, "%d execl %s\n", 38146973Skarels getpid(), sep->se_server); 38226877Skarels dup2(ctrl, 0); 38326877Skarels close(ctrl); 38426877Skarels dup2(0, 1); 38526877Skarels dup2(0, 2); 38626877Skarels if ((pwd = getpwnam(sep->se_user)) == NULL) { 38726877Skarels syslog(LOG_ERR, 38857769Sandrew "%s/%s: %s: No such user", 38957769Sandrew sep->se_service, sep->se_proto, 39057769Sandrew sep->se_user); 39127535Skarels if (sep->se_socktype != SOCK_STREAM) 39227535Skarels recv(0, buf, sizeof (buf), 0); 39326877Skarels _exit(1); 39426877Skarels } 39526877Skarels if (pwd->pw_uid) { 39657769Sandrew if (setgid(pwd->pw_gid) < 0) { 39757769Sandrew syslog(LOG_ERR, 39857769Sandrew "%s: can't set gid %d: %m", 39957769Sandrew sep->se_service, pwd->pw_gid); 40057769Sandrew _exit(1); 40157769Sandrew } 40257769Sandrew (void) initgroups(pwd->pw_name, 40357769Sandrew pwd->pw_gid); 40457769Sandrew if (setuid(pwd->pw_uid) < 0) { 40557769Sandrew syslog(LOG_ERR, 40657769Sandrew "%s: can't set uid %d: %m", 40757769Sandrew sep->se_service, pwd->pw_uid); 40857769Sandrew _exit(1); 40957769Sandrew } 41026877Skarels } 41126877Skarels execv(sep->se_server, sep->se_argv); 41226877Skarels if (sep->se_socktype != SOCK_STREAM) 41326877Skarels recv(0, buf, sizeof (buf), 0); 41457769Sandrew syslog(LOG_ERR, 41557769Sandrew "cannot execute %s: %m", sep->se_server); 41626877Skarels _exit(1); 41746973Skarels } 41846973Skarels } 41946973Skarels if (sep->se_socktype == SOCK_STREAM) 42046973Skarels close(ctrl); 42116374Skarels } 42216374Skarels } 42316374Skarels } 42416374Skarels 42539838Sbostic void 42666696Spendry reapchild(signo) 42766696Spendry int signo; 42816374Skarels { 42946973Skarels int status; 43066696Spendry pid_t pid; 43166696Spendry struct servtab *sep; 43216374Skarels 43316374Skarels for (;;) { 43446973Skarels pid = wait3(&status, WNOHANG, (struct rusage *)0); 43516374Skarels if (pid <= 0) 43616374Skarels break; 43716374Skarels if (debug) 43857769Sandrew fprintf(stderr, "%d reaped, status %#x\n", 43957769Sandrew pid, status); 44016374Skarels for (sep = servtab; sep; sep = sep->se_next) 44116374Skarels if (sep->se_wait == pid) { 44246973Skarels if (status) 44316510Sralph syslog(LOG_WARNING, 44416510Sralph "%s: exit status 0x%x", 44516374Skarels sep->se_server, status); 44616374Skarels if (debug) 44716374Skarels fprintf(stderr, "restored %s, fd %d\n", 44816374Skarels sep->se_service, sep->se_fd); 44925046Skarels FD_SET(sep->se_fd, &allsock); 45025046Skarels nsock++; 45116374Skarels sep->se_wait = 1; 45216374Skarels } 45316374Skarels } 45416374Skarels } 45516374Skarels 45639838Sbostic void 45766696Spendry config(signo) 45866696Spendry int signo; 45916374Skarels { 46066696Spendry struct servtab *sep, *cp, **sepp; 46157769Sandrew struct passwd *pwd; 46232246Sbostic long omask; 46316374Skarels 46416374Skarels if (!setconfig()) { 46516510Sralph syslog(LOG_ERR, "%s: %m", CONFIG); 46616374Skarels return; 46716374Skarels } 46816374Skarels for (sep = servtab; sep; sep = sep->se_next) 46916374Skarels sep->se_checked = 0; 47016374Skarels while (cp = getconfigent()) { 47157769Sandrew if ((pwd = getpwnam(cp->se_user)) == NULL) { 47257769Sandrew syslog(LOG_ERR, 47357769Sandrew "%s/%s: No such user '%s', service ignored", 47457769Sandrew cp->se_service, cp->se_proto, cp->se_user); 47557769Sandrew continue; 47657769Sandrew } 47716374Skarels for (sep = servtab; sep; sep = sep->se_next) 47816374Skarels if (strcmp(sep->se_service, cp->se_service) == 0 && 47916374Skarels strcmp(sep->se_proto, cp->se_proto) == 0) 48016374Skarels break; 48116374Skarels if (sep != 0) { 48216374Skarels int i; 48316374Skarels 48427535Skarels omask = sigblock(SIGBLOCK); 48540745Sbostic /* 48640745Sbostic * sep->se_wait may be holding the pid of a daemon 48740745Sbostic * that we're waiting for. If so, don't overwrite 48840745Sbostic * it unless the config file explicitly says don't 48940745Sbostic * wait. 49040745Sbostic */ 49140745Sbostic if (cp->se_bi == 0 && 49240745Sbostic (sep->se_wait == 1 || cp->se_wait == 0)) 49327535Skarels sep->se_wait = cp->se_wait; 49416374Skarels #define SWAP(a, b) { char *c = a; a = b; b = c; } 49526921Slepreau if (cp->se_user) 49626921Slepreau SWAP(sep->se_user, cp->se_user); 49716374Skarels if (cp->se_server) 49816374Skarels SWAP(sep->se_server, cp->se_server); 49916374Skarels for (i = 0; i < MAXARGV; i++) 50016374Skarels SWAP(sep->se_argv[i], cp->se_argv[i]); 50116374Skarels sigsetmask(omask); 50216374Skarels freeconfig(cp); 50329794Skarels if (debug) 50429794Skarels print_service("REDO", sep); 50529794Skarels } else { 50616374Skarels sep = enter(cp); 50729794Skarels if (debug) 50829794Skarels print_service("ADD ", sep); 50929794Skarels } 51016374Skarels sep->se_checked = 1; 51157769Sandrew if (ISMUX(sep)) { 51257769Sandrew sep->se_fd = -1; 51357769Sandrew continue; 51457769Sandrew } 51516374Skarels sp = getservbyname(sep->se_service, sep->se_proto); 51616374Skarels if (sp == 0) { 51716510Sralph syslog(LOG_ERR, "%s/%s: unknown service", 51816374Skarels sep->se_service, sep->se_proto); 51957769Sandrew sep->se_checked = 0; 52016374Skarels continue; 52116374Skarels } 52227535Skarels if (sp->s_port != sep->se_ctrladdr.sin_port) { 52360924Smckusick sep->se_ctrladdr.sin_family = AF_INET; 52427535Skarels sep->se_ctrladdr.sin_port = sp->s_port; 52557769Sandrew if (sep->se_fd >= 0) 52657769Sandrew close_sep(sep); 52716374Skarels } 52827535Skarels if (sep->se_fd == -1) 52927535Skarels setup(sep); 53016374Skarels } 53116374Skarels endconfig(); 53216374Skarels /* 53316374Skarels * Purge anything not looked at above. 53416374Skarels */ 53527535Skarels omask = sigblock(SIGBLOCK); 53616374Skarels sepp = &servtab; 53716374Skarels while (sep = *sepp) { 53816374Skarels if (sep->se_checked) { 53916374Skarels sepp = &sep->se_next; 54016374Skarels continue; 54116374Skarels } 54216374Skarels *sepp = sep->se_next; 54357769Sandrew if (sep->se_fd >= 0) 54457769Sandrew close_sep(sep); 54529794Skarels if (debug) 54629794Skarels print_service("FREE", sep); 54716374Skarels freeconfig(sep); 54816374Skarels free((char *)sep); 54916374Skarels } 55016374Skarels (void) sigsetmask(omask); 55116374Skarels } 55216374Skarels 55339838Sbostic void 55466696Spendry retry(signo) 55566696Spendry int signo; 55627535Skarels { 55766696Spendry struct servtab *sep; 55827535Skarels 55927535Skarels timingout = 0; 56027535Skarels for (sep = servtab; sep; sep = sep->se_next) 56127535Skarels if (sep->se_fd == -1) 56227535Skarels setup(sep); 56327535Skarels } 56427535Skarels 56566696Spendry void 56627535Skarels setup(sep) 56766696Spendry struct servtab *sep; 56827535Skarels { 56927535Skarels int on = 1; 57027535Skarels 57127535Skarels if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 57257769Sandrew if (debug) 57357769Sandrew fprintf(stderr, "socket failed on %s/%s: %s\n", 57457769Sandrew sep->se_service, sep->se_proto, 57557769Sandrew strerror(errno)); 57627535Skarels syslog(LOG_ERR, "%s/%s: socket: %m", 57727535Skarels sep->se_service, sep->se_proto); 57827535Skarels return; 57927535Skarels } 58027535Skarels #define turnon(fd, opt) \ 58127535Skarels setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 58227535Skarels if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 58327535Skarels turnon(sep->se_fd, SO_DEBUG) < 0) 58427535Skarels syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 58527535Skarels if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 58627535Skarels syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 58727535Skarels #undef turnon 58846907Sbostic if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 58927535Skarels sizeof (sep->se_ctrladdr)) < 0) { 59057769Sandrew if (debug) 59157769Sandrew fprintf(stderr, "bind failed on %s/%s: %s\n", 59257769Sandrew sep->se_service, sep->se_proto, 59357769Sandrew strerror(errno)); 59427535Skarels syslog(LOG_ERR, "%s/%s: bind: %m", 59527535Skarels sep->se_service, sep->se_proto); 59627535Skarels (void) close(sep->se_fd); 59727535Skarels sep->se_fd = -1; 59827535Skarels if (!timingout) { 59927535Skarels timingout = 1; 60027535Skarels alarm(RETRYTIME); 60127535Skarels } 60227535Skarels return; 60327535Skarels } 60427535Skarels if (sep->se_socktype == SOCK_STREAM) 60527535Skarels listen(sep->se_fd, 10); 60627535Skarels FD_SET(sep->se_fd, &allsock); 60727535Skarels nsock++; 60827535Skarels if (sep->se_fd > maxsock) 60927535Skarels maxsock = sep->se_fd; 61057769Sandrew if (debug) { 61157769Sandrew fprintf(stderr, "registered %s on %d\n", 61257769Sandrew sep->se_server, sep->se_fd); 61357769Sandrew } 61427535Skarels } 61527535Skarels 61657769Sandrew /* 61757769Sandrew * Finish with a service and its socket. 61857769Sandrew */ 61966696Spendry void 62057769Sandrew close_sep(sep) 62166696Spendry struct servtab *sep; 62257769Sandrew { 62357769Sandrew if (sep->se_fd >= 0) { 62457769Sandrew nsock--; 62557769Sandrew FD_CLR(sep->se_fd, &allsock); 62657769Sandrew (void) close(sep->se_fd); 62757769Sandrew sep->se_fd = -1; 62857769Sandrew } 62957769Sandrew sep->se_count = 0; 63057769Sandrew /* 63157769Sandrew * Don't keep the pid of this running deamon: when reapchild() 63257769Sandrew * reaps this pid, it would erroneously increment nsock. 63357769Sandrew */ 63457769Sandrew if (sep->se_wait > 1) 63557769Sandrew sep->se_wait = 1; 63657769Sandrew } 63757769Sandrew 63816374Skarels struct servtab * 63916374Skarels enter(cp) 64016374Skarels struct servtab *cp; 64116374Skarels { 64266696Spendry struct servtab *sep; 64332246Sbostic long omask; 64416374Skarels 64516374Skarels sep = (struct servtab *)malloc(sizeof (*sep)); 64616374Skarels if (sep == (struct servtab *)0) { 64716510Sralph syslog(LOG_ERR, "Out of memory."); 64816374Skarels exit(-1); 64916374Skarels } 65016374Skarels *sep = *cp; 65116374Skarels sep->se_fd = -1; 65227535Skarels omask = sigblock(SIGBLOCK); 65316374Skarels sep->se_next = servtab; 65416374Skarels servtab = sep; 65516374Skarels sigsetmask(omask); 65616374Skarels return (sep); 65716374Skarels } 65816374Skarels 65916374Skarels FILE *fconfig = NULL; 66016374Skarels struct servtab serv; 66166696Spendry char line[LINE_MAX]; 66216374Skarels 66366696Spendry int 66416374Skarels setconfig() 66516374Skarels { 66616374Skarels 66716374Skarels if (fconfig != NULL) { 66857769Sandrew fseek(fconfig, 0L, SEEK_SET); 66916374Skarels return (1); 67016374Skarels } 67116374Skarels fconfig = fopen(CONFIG, "r"); 67216374Skarels return (fconfig != NULL); 67316374Skarels } 67416374Skarels 67566696Spendry void 67616374Skarels endconfig() 67716374Skarels { 67836603Sbostic if (fconfig) { 67936603Sbostic (void) fclose(fconfig); 68036603Sbostic fconfig = NULL; 68136603Sbostic } 68216374Skarels } 68316374Skarels 68416374Skarels struct servtab * 68516374Skarels getconfigent() 68616374Skarels { 68766696Spendry struct servtab *sep = &serv; 68816374Skarels int argc; 68966696Spendry char *cp, *arg; 69057769Sandrew static char TCPMUX_TOKEN[] = "tcpmux/"; 69157769Sandrew #define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 69216374Skarels 69326877Skarels more: 69457769Sandrew while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0')) 69516374Skarels ; 69616374Skarels if (cp == NULL) 69716374Skarels return ((struct servtab *)0); 69857769Sandrew /* 69957769Sandrew * clear the static buffer, since some fields (se_ctrladdr, 70057769Sandrew * for example) don't get initialized here. 70157769Sandrew */ 70266696Spendry memset((caddr_t)sep, 0, sizeof *sep); 70316374Skarels arg = skip(&cp); 70457769Sandrew if (cp == NULL) { 70557769Sandrew /* got an empty line containing just blanks/tabs. */ 70657769Sandrew goto more; 70757769Sandrew } 70857769Sandrew if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 70957769Sandrew char *c = arg + MUX_LEN; 71057769Sandrew if (*c == '+') { 71157769Sandrew sep->se_type = MUXPLUS_TYPE; 71257769Sandrew c++; 71357769Sandrew } else 71457769Sandrew sep->se_type = MUX_TYPE; 71557769Sandrew sep->se_service = newstr(c); 71657769Sandrew } else { 71757769Sandrew sep->se_service = newstr(arg); 71857769Sandrew sep->se_type = NORM_TYPE; 71957769Sandrew } 72057769Sandrew arg = sskip(&cp); 72116374Skarels if (strcmp(arg, "stream") == 0) 72216374Skarels sep->se_socktype = SOCK_STREAM; 72316374Skarels else if (strcmp(arg, "dgram") == 0) 72416374Skarels sep->se_socktype = SOCK_DGRAM; 72516374Skarels else if (strcmp(arg, "rdm") == 0) 72616374Skarels sep->se_socktype = SOCK_RDM; 72716374Skarels else if (strcmp(arg, "seqpacket") == 0) 72816374Skarels sep->se_socktype = SOCK_SEQPACKET; 72916374Skarels else if (strcmp(arg, "raw") == 0) 73016374Skarels sep->se_socktype = SOCK_RAW; 73116374Skarels else 73216374Skarels sep->se_socktype = -1; 73357769Sandrew sep->se_proto = newstr(sskip(&cp)); 73457769Sandrew arg = sskip(&cp); 73516374Skarels sep->se_wait = strcmp(arg, "wait") == 0; 73657769Sandrew if (ISMUX(sep)) { 73757769Sandrew /* 73857769Sandrew * Silently enforce "nowait" for TCPMUX services since 73957769Sandrew * they don't have an assigned port to listen on. 74057769Sandrew */ 74157769Sandrew sep->se_wait = 0; 74257769Sandrew 74357769Sandrew if (strcmp(sep->se_proto, "tcp")) { 74457769Sandrew syslog(LOG_ERR, 74557769Sandrew "%s: bad protocol for tcpmux service %s", 74657769Sandrew CONFIG, sep->se_service); 74757769Sandrew goto more; 74857769Sandrew } 74957769Sandrew if (sep->se_socktype != SOCK_STREAM) { 75057769Sandrew syslog(LOG_ERR, 75157769Sandrew "%s: bad socket type for tcpmux service %s", 75257769Sandrew CONFIG, sep->se_service); 75357769Sandrew goto more; 75457769Sandrew } 75557769Sandrew } 75657769Sandrew sep->se_user = newstr(sskip(&cp)); 75757769Sandrew sep->se_server = newstr(sskip(&cp)); 75826877Skarels if (strcmp(sep->se_server, "internal") == 0) { 75966696Spendry struct biltin *bi; 76026877Skarels 76126877Skarels for (bi = biltins; bi->bi_service; bi++) 76226877Skarels if (bi->bi_socktype == sep->se_socktype && 76326877Skarels strcmp(bi->bi_service, sep->se_service) == 0) 76426877Skarels break; 76526877Skarels if (bi->bi_service == 0) { 76657769Sandrew syslog(LOG_ERR, "internal service %s unknown", 76726877Skarels sep->se_service); 76826877Skarels goto more; 76926877Skarels } 77026877Skarels sep->se_bi = bi; 77126877Skarels sep->se_wait = bi->bi_wait; 77229794Skarels } else 77329794Skarels sep->se_bi = NULL; 77416374Skarels argc = 0; 77516374Skarels for (arg = skip(&cp); cp; arg = skip(&cp)) 77616374Skarels if (argc < MAXARGV) 77746907Sbostic sep->se_argv[argc++] = newstr(arg); 77816374Skarels while (argc <= MAXARGV) 77916374Skarels sep->se_argv[argc++] = NULL; 78016374Skarels return (sep); 78116374Skarels } 78216374Skarels 78366696Spendry void 78416374Skarels freeconfig(cp) 78566696Spendry struct servtab *cp; 78616374Skarels { 78716374Skarels int i; 78816374Skarels 78916374Skarels if (cp->se_service) 79016374Skarels free(cp->se_service); 79116374Skarels if (cp->se_proto) 79216374Skarels free(cp->se_proto); 79326921Slepreau if (cp->se_user) 79426921Slepreau free(cp->se_user); 79516374Skarels if (cp->se_server) 79616374Skarels free(cp->se_server); 79716374Skarels for (i = 0; i < MAXARGV; i++) 79816374Skarels if (cp->se_argv[i]) 79916374Skarels free(cp->se_argv[i]); 80016374Skarels } 80116374Skarels 80257769Sandrew 80357769Sandrew /* 80457769Sandrew * Safe skip - if skip returns null, log a syntax error in the 80557769Sandrew * configuration file and exit. 80657769Sandrew */ 80716374Skarels char * 80857769Sandrew sskip(cpp) 80957769Sandrew char **cpp; 81057769Sandrew { 81166696Spendry char *cp; 81257769Sandrew 81357769Sandrew cp = skip(cpp); 81457769Sandrew if (cp == NULL) { 81557769Sandrew syslog(LOG_ERR, "%s: syntax error", CONFIG); 81657769Sandrew exit(-1); 81757769Sandrew } 81857769Sandrew return (cp); 81957769Sandrew } 82057769Sandrew 82157769Sandrew char * 82216374Skarels skip(cpp) 82316374Skarels char **cpp; 82416374Skarels { 82566696Spendry char *cp = *cpp; 82616374Skarels char *start; 82716374Skarels 82816374Skarels again: 82916374Skarels while (*cp == ' ' || *cp == '\t') 83016374Skarels cp++; 83116374Skarels if (*cp == '\0') { 83243455Sbostic int c; 83316374Skarels 83416374Skarels c = getc(fconfig); 83536603Sbostic (void) ungetc(c, fconfig); 83616374Skarels if (c == ' ' || c == '\t') 83716374Skarels if (cp = nextline(fconfig)) 83816374Skarels goto again; 83916374Skarels *cpp = (char *)0; 84016374Skarels return ((char *)0); 84116374Skarels } 84216374Skarels start = cp; 84316374Skarels while (*cp && *cp != ' ' && *cp != '\t') 84416374Skarels cp++; 84516374Skarels if (*cp != '\0') 84616374Skarels *cp++ = '\0'; 84716374Skarels *cpp = cp; 84816374Skarels return (start); 84916374Skarels } 85016374Skarels 85116374Skarels char * 85216374Skarels nextline(fd) 85316374Skarels FILE *fd; 85416374Skarels { 85516374Skarels char *cp; 85616374Skarels 85726921Slepreau if (fgets(line, sizeof (line), fd) == NULL) 85816374Skarels return ((char *)0); 85966696Spendry cp = strchr(line, '\n'); 86016374Skarels if (cp) 86116374Skarels *cp = '\0'; 86216374Skarels return (line); 86316374Skarels } 86416374Skarels 86516374Skarels char * 86646907Sbostic newstr(cp) 86716374Skarels char *cp; 86816374Skarels { 86946973Skarels if (cp = strdup(cp ? cp : "")) 87066696Spendry return (cp); 87146973Skarels syslog(LOG_ERR, "strdup: %m"); 87246907Sbostic exit(-1); 87316374Skarels } 87426877Skarels 87566696Spendry void 87626877Skarels setproctitle(a, s) 87726877Skarels char *a; 87826877Skarels int s; 87926877Skarels { 88026877Skarels int size; 88166696Spendry char *cp; 88226877Skarels struct sockaddr_in sin; 88326877Skarels char buf[80]; 88426877Skarels 88526877Skarels cp = Argv[0]; 88626877Skarels size = sizeof(sin); 88746907Sbostic if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 88832442Sbostic (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 88926877Skarels else 89032442Sbostic (void) sprintf(buf, "-%s", a); 89126877Skarels strncpy(cp, buf, LastArg - cp); 89226877Skarels cp += strlen(cp); 89326877Skarels while (cp < LastArg) 89426877Skarels *cp++ = ' '; 89526877Skarels } 89626877Skarels 89726877Skarels /* 89826877Skarels * Internet services provided internally by inetd: 89926877Skarels */ 90049986Skarels #define BUFSIZE 8192 90126877Skarels 90226877Skarels /* ARGSUSED */ 90366696Spendry void 90426877Skarels echo_stream(s, sep) /* Echo service -- echo data back */ 90526877Skarels int s; 90626877Skarels struct servtab *sep; 90726877Skarels { 90838573Skarels char buffer[BUFSIZE]; 90926877Skarels int i; 91026877Skarels 91132091Skarels setproctitle(sep->se_service, s); 91226877Skarels while ((i = read(s, buffer, sizeof(buffer))) > 0 && 91326877Skarels write(s, buffer, i) > 0) 91426877Skarels ; 91526877Skarels exit(0); 91626877Skarels } 91726877Skarels 91826877Skarels /* ARGSUSED */ 91966696Spendry void 92026877Skarels echo_dg(s, sep) /* Echo service -- echo data back */ 92126877Skarels int s; 92226877Skarels struct servtab *sep; 92326877Skarels { 92438573Skarels char buffer[BUFSIZE]; 92526877Skarels int i, size; 92626877Skarels struct sockaddr sa; 92726877Skarels 92826877Skarels size = sizeof(sa); 92926877Skarels if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) 93026877Skarels return; 93126877Skarels (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); 93226877Skarels } 93326877Skarels 93426877Skarels /* ARGSUSED */ 93566696Spendry void 93626877Skarels discard_stream(s, sep) /* Discard service -- ignore data */ 93726877Skarels int s; 93826877Skarels struct servtab *sep; 93926877Skarels { 94049986Skarels int ret; 94138573Skarels char buffer[BUFSIZE]; 94226877Skarels 94332091Skarels setproctitle(sep->se_service, s); 94426877Skarels while (1) { 94549986Skarels while ((ret = read(s, buffer, sizeof(buffer))) > 0) 94626877Skarels ; 94749986Skarels if (ret == 0 || errno != EINTR) 94826877Skarels break; 94926877Skarels } 95026877Skarels exit(0); 95126877Skarels } 95226877Skarels 95326877Skarels /* ARGSUSED */ 95466696Spendry void 95526877Skarels discard_dg(s, sep) /* Discard service -- ignore data */ 95626877Skarels int s; 95726877Skarels struct servtab *sep; 95826877Skarels { 95938573Skarels char buffer[BUFSIZE]; 96026877Skarels 96126877Skarels (void) read(s, buffer, sizeof(buffer)); 96226877Skarels } 96326877Skarels 96426877Skarels #include <ctype.h> 96526877Skarels #define LINESIZ 72 96626877Skarels char ring[128]; 96726877Skarels char *endring; 96826877Skarels 96966696Spendry void 97026877Skarels initring() 97126877Skarels { 97266696Spendry int i; 97326877Skarels 97426877Skarels endring = ring; 97526877Skarels 97626877Skarels for (i = 0; i <= 128; ++i) 97726877Skarels if (isprint(i)) 97826877Skarels *endring++ = i; 97926877Skarels } 98026877Skarels 98126877Skarels /* ARGSUSED */ 98266696Spendry void 98326877Skarels chargen_stream(s, sep) /* Character generator */ 98426877Skarels int s; 98526877Skarels struct servtab *sep; 98626877Skarels { 98732246Sbostic int len; 98866696Spendry char *rs, text[LINESIZ+2]; 98926877Skarels 99032091Skarels setproctitle(sep->se_service, s); 99132246Sbostic 99232246Sbostic if (!endring) { 99326877Skarels initring(); 99432246Sbostic rs = ring; 99532246Sbostic } 99626877Skarels 99732246Sbostic text[LINESIZ] = '\r'; 99832246Sbostic text[LINESIZ + 1] = '\n'; 99932246Sbostic for (rs = ring;;) { 100032246Sbostic if ((len = endring - rs) >= LINESIZ) 100166696Spendry memmove(text, rs, LINESIZ); 100232246Sbostic else { 100366696Spendry memmove(text, rs, len); 100466696Spendry memmove(text + len, ring, LINESIZ - len); 100532246Sbostic } 100632246Sbostic if (++rs == endring) 100726877Skarels rs = ring; 100832246Sbostic if (write(s, text, sizeof(text)) != sizeof(text)) 100926877Skarels break; 101026877Skarels } 101126877Skarels exit(0); 101226877Skarels } 101326877Skarels 101426877Skarels /* ARGSUSED */ 101566696Spendry void 101626877Skarels chargen_dg(s, sep) /* Character generator */ 101726877Skarels int s; 101826877Skarels struct servtab *sep; 101926877Skarels { 102032246Sbostic struct sockaddr sa; 102132246Sbostic static char *rs; 102232246Sbostic int len, size; 102326877Skarels char text[LINESIZ+2]; 102426877Skarels 102532246Sbostic if (endring == 0) { 102626877Skarels initring(); 102732246Sbostic rs = ring; 102832246Sbostic } 102926877Skarels 103026877Skarels size = sizeof(sa); 103126877Skarels if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) 103226877Skarels return; 103332246Sbostic 103432246Sbostic if ((len = endring - rs) >= LINESIZ) 103566696Spendry memmove(text, rs, LINESIZ); 103632246Sbostic else { 103766696Spendry memmove(text, rs, len); 103866696Spendry memmove(text + len, ring, LINESIZ - len); 103932246Sbostic } 104032246Sbostic if (++rs == endring) 104126877Skarels rs = ring; 104232246Sbostic text[LINESIZ] = '\r'; 104332246Sbostic text[LINESIZ + 1] = '\n'; 104426877Skarels (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa)); 104526877Skarels } 104626877Skarels 104726877Skarels /* 104826877Skarels * Return a machine readable date and time, in the form of the 104926877Skarels * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 105026877Skarels * returns the number of seconds since midnight, Jan 1, 1970, 105126877Skarels * we must add 2208988800 seconds to this figure to make up for 105226877Skarels * some seventy years Bell Labs was asleep. 105326877Skarels */ 105426877Skarels 105526877Skarels long 105626877Skarels machtime() 105726877Skarels { 105826877Skarels struct timeval tv; 105926877Skarels 106026921Slepreau if (gettimeofday(&tv, (struct timezone *)0) < 0) { 106157769Sandrew if (debug) 106257769Sandrew fprintf(stderr, "Unable to get time of day\n"); 106326921Slepreau return (0L); 106426877Skarels } 106560073Storek #define OFFSET ((u_long)25567 * 24*60*60) 106660073Storek return (htonl((long)(tv.tv_sec + OFFSET))); 106760073Storek #undef OFFSET 106826877Skarels } 106926877Skarels 107026877Skarels /* ARGSUSED */ 107166696Spendry void 107226877Skarels machtime_stream(s, sep) 107326877Skarels int s; 107426877Skarels struct servtab *sep; 107526877Skarels { 107626877Skarels long result; 107726877Skarels 107826877Skarels result = machtime(); 107926877Skarels (void) write(s, (char *) &result, sizeof(result)); 108026877Skarels } 108126877Skarels 108226877Skarels /* ARGSUSED */ 108366696Spendry void 108426877Skarels machtime_dg(s, sep) 108526877Skarels int s; 108626877Skarels struct servtab *sep; 108726877Skarels { 108826877Skarels long result; 108926877Skarels struct sockaddr sa; 109026877Skarels int size; 109126877Skarels 109226877Skarels size = sizeof(sa); 109326921Slepreau if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0) 109426877Skarels return; 109526877Skarels result = machtime(); 109626877Skarels (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa)); 109726877Skarels } 109826877Skarels 109926877Skarels /* ARGSUSED */ 110066696Spendry void 110126877Skarels daytime_stream(s, sep) /* Return human-readable time of day */ 110226877Skarels int s; 110326877Skarels struct servtab *sep; 110426877Skarels { 110526877Skarels char buffer[256]; 110657769Sandrew time_t clock; 110726877Skarels 110826877Skarels clock = time((time_t *) 0); 110926877Skarels 111032442Sbostic (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 111126921Slepreau (void) write(s, buffer, strlen(buffer)); 111226877Skarels } 111326877Skarels 111426877Skarels /* ARGSUSED */ 111566696Spendry void 111626877Skarels daytime_dg(s, sep) /* Return human-readable time of day */ 111726877Skarels int s; 111826877Skarels struct servtab *sep; 111926877Skarels { 112026877Skarels char buffer[256]; 112157769Sandrew time_t clock; 112226877Skarels struct sockaddr sa; 112326877Skarels int size; 112426877Skarels 112526877Skarels clock = time((time_t *) 0); 112626877Skarels 112726877Skarels size = sizeof(sa); 112826877Skarels if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) 112926877Skarels return; 113032442Sbostic (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 113126877Skarels (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa)); 113226877Skarels } 113329794Skarels 113429794Skarels /* 113529794Skarels * print_service: 113629794Skarels * Dump relevant information to stderr 113729794Skarels */ 113866696Spendry void 113929794Skarels print_service(action, sep) 114029794Skarels char *action; 114129794Skarels struct servtab *sep; 114229794Skarels { 114329794Skarels fprintf(stderr, 114429794Skarels "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n", 114529794Skarels action, sep->se_service, sep->se_proto, 114636603Sbostic sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server); 114729794Skarels } 114857769Sandrew 114957769Sandrew /* 115057769Sandrew * Based on TCPMUX.C by Mark K. Lottor November 1988 115157769Sandrew * sri-nic::ps:<mkl>tcpmux.c 115257769Sandrew */ 115357769Sandrew 115457769Sandrew 115557769Sandrew static int /* # of characters upto \r,\n or \0 */ 115657769Sandrew getline(fd, buf, len) 115757769Sandrew int fd; 115857769Sandrew char *buf; 115957769Sandrew int len; 116057769Sandrew { 116157769Sandrew int count = 0, n; 116257769Sandrew 116357769Sandrew do { 116457769Sandrew n = read(fd, buf, len-count); 116557769Sandrew if (n == 0) 116666696Spendry return (count); 116757769Sandrew if (n < 0) 116857769Sandrew return (-1); 116957769Sandrew while (--n >= 0) { 117057769Sandrew if (*buf == '\r' || *buf == '\n' || *buf == '\0') 117166696Spendry return (count); 117257769Sandrew count++; 117357769Sandrew buf++; 117457769Sandrew } 117557769Sandrew } while (count < len); 117657769Sandrew return (count); 117757769Sandrew } 117857769Sandrew 117957769Sandrew #define MAX_SERV_LEN (256+2) /* 2 bytes for \r\n */ 118057769Sandrew 118157769Sandrew #define strwrite(fd, buf) (void) write(fd, buf, sizeof(buf)-1) 118257769Sandrew 118357769Sandrew struct servtab * 118457769Sandrew tcpmux(s) 118557769Sandrew int s; 118657769Sandrew { 118766696Spendry struct servtab *sep; 118857769Sandrew char service[MAX_SERV_LEN+1]; 118957769Sandrew int len; 119057769Sandrew 119157769Sandrew /* Get requested service name */ 119257769Sandrew if ((len = getline(s, service, MAX_SERV_LEN)) < 0) { 119366696Spendry strwrite(s, "-Error reading service name\r\n"); 119466696Spendry return (NULL); 119557769Sandrew } 119657769Sandrew service[len] = '\0'; 119757769Sandrew 119857769Sandrew if (debug) 119966696Spendry fprintf(stderr, "tcpmux: someone wants %s\n", service); 120057769Sandrew 120157769Sandrew /* 120257769Sandrew * Help is a required command, and lists available services, 120357769Sandrew * one per line. 120457769Sandrew */ 120566696Spendry if (!strcasecmp(service, "help")) { 120666696Spendry for (sep = servtab; sep; sep = sep->se_next) { 120766696Spendry if (!ISMUX(sep)) 120866696Spendry continue; 120966696Spendry (void)write(s,sep->se_service,strlen(sep->se_service)); 121066696Spendry strwrite(s, "\r\n"); 121166696Spendry } 121266696Spendry return (NULL); 121357769Sandrew } 121457769Sandrew 121557769Sandrew /* Try matching a service in inetd.conf with the request */ 121657769Sandrew for (sep = servtab; sep; sep = sep->se_next) { 121766696Spendry if (!ISMUX(sep)) 121866696Spendry continue; 121966696Spendry if (!strcasecmp(service, sep->se_service)) { 122066696Spendry if (ISMUXPLUS(sep)) { 122166696Spendry strwrite(s, "+Go\r\n"); 122266696Spendry } 122366696Spendry return (sep); 122457769Sandrew } 122557769Sandrew } 122657769Sandrew strwrite(s, "-Service not available\r\n"); 122766696Spendry return (NULL); 122857769Sandrew } 1229