121134Sdist /* 2*61830Sbostic * Copyright (c) 1983, 1991, 1993 3*61830Sbostic * The Regents of the University of California. All rights reserved. 433136Sbostic * 542799Sbostic * %sccs.include.redist.c% 621134Sdist */ 721134Sdist 816374Skarels #ifndef lint 9*61830Sbostic static char copyright[] = 10*61830Sbostic "@(#) Copyright (c) 1983, 1991, 1993\n\ 11*61830Sbostic The Regents of the University of California. All rights reserved.\n"; 1233136Sbostic #endif /* not lint */ 1316374Skarels 1421134Sdist #ifndef lint 15*61830Sbostic static char sccsid[] = "@(#)inetd.c 8.1 (Berkeley) 06/06/93"; 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 9839838Sbostic void config(), reapchild(), retry(); 9916374Skarels 10016374Skarels int debug = 0; 10125046Skarels int nsock, maxsock; 10225046Skarels fd_set allsock; 10316374Skarels int options; 10427535Skarels int timingout; 10557769Sandrew int toomany = TOOMANY; 10616374Skarels struct servent *sp; 10716374Skarels 10816374Skarels struct servtab { 10916374Skarels char *se_service; /* name of service */ 11016374Skarels int se_socktype; /* type of socket to use */ 11116374Skarels char *se_proto; /* protocol used */ 11216374Skarels short se_wait; /* single threaded server */ 11316374Skarels short se_checked; /* looked at during merge */ 11417346Sbloom char *se_user; /* user name to run as */ 11526877Skarels struct biltin *se_bi; /* if built-in, description */ 11616374Skarels char *se_server; /* server program */ 11740740Sbostic #define MAXARGV 20 11816374Skarels char *se_argv[MAXARGV+1]; /* program arguments */ 11916374Skarels int se_fd; /* open descriptor */ 12057769Sandrew int se_type; /* type */ 12116374Skarels struct sockaddr_in se_ctrladdr;/* bound address */ 12227535Skarels int se_count; /* number started since se_time */ 12327535Skarels struct timeval se_time; /* start of se_count */ 12416374Skarels struct servtab *se_next; 12516374Skarels } *servtab; 12616374Skarels 12757769Sandrew #define NORM_TYPE 0 12857769Sandrew #define MUX_TYPE 1 12957769Sandrew #define MUXPLUS_TYPE 2 13057769Sandrew #define ISMUX(sep) (((sep)->se_type == MUX_TYPE) || \ 13157769Sandrew ((sep)->se_type == MUXPLUS_TYPE)) 13257769Sandrew #define ISMUXPLUS(sep) ((sep)->se_type == MUXPLUS_TYPE) 13357769Sandrew 13426877Skarels int echo_stream(), discard_stream(), machtime_stream(); 13526877Skarels int daytime_stream(), chargen_stream(); 13626877Skarels int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg(); 13757769Sandrew struct servtab *tcpmux(); 13826877Skarels 13926877Skarels struct biltin { 14026877Skarels char *bi_service; /* internally provided service name */ 14126877Skarels int bi_socktype; /* type of socket supported */ 14226877Skarels short bi_fork; /* 1 if should fork before call */ 14326877Skarels short bi_wait; /* 1 if should wait for child */ 14426877Skarels int (*bi_fn)(); /* function which performs it */ 14526877Skarels } biltins[] = { 14626877Skarels /* Echo received data */ 14726877Skarels "echo", SOCK_STREAM, 1, 0, echo_stream, 14826877Skarels "echo", SOCK_DGRAM, 0, 0, echo_dg, 14926877Skarels 15026877Skarels /* Internet /dev/null */ 15126877Skarels "discard", SOCK_STREAM, 1, 0, discard_stream, 15226877Skarels "discard", SOCK_DGRAM, 0, 0, discard_dg, 15326877Skarels 15426877Skarels /* Return 32 bit time since 1970 */ 15526877Skarels "time", SOCK_STREAM, 0, 0, machtime_stream, 15626877Skarels "time", SOCK_DGRAM, 0, 0, machtime_dg, 15726877Skarels 15826877Skarels /* Return human-readable time */ 15926877Skarels "daytime", SOCK_STREAM, 0, 0, daytime_stream, 16026877Skarels "daytime", SOCK_DGRAM, 0, 0, daytime_dg, 16126877Skarels 16226877Skarels /* Familiar character generator */ 16326877Skarels "chargen", SOCK_STREAM, 1, 0, chargen_stream, 16426877Skarels "chargen", SOCK_DGRAM, 0, 0, chargen_dg, 16557769Sandrew 16657769Sandrew "tcpmux", SOCK_STREAM, 1, 0, (int (*)())tcpmux, 16757769Sandrew 16857769Sandrew NULL 16926877Skarels }; 17026877Skarels 17126877Skarels #define NUMINT (sizeof(intab) / sizeof(struct inent)) 17237282Sbostic char *CONFIG = _PATH_INETDCONF; 17326877Skarels char **Argv; 17426877Skarels char *LastArg; 17516374Skarels 17626877Skarels main(argc, argv, envp) 17716374Skarels int argc; 17826877Skarels char *argv[], *envp[]; 17916374Skarels { 18016374Skarels register struct servtab *sep; 18117346Sbloom register struct passwd *pwd; 18236603Sbostic register int tmpint; 18327535Skarels struct sigvec sv; 18436603Sbostic int ch, pid, dofork; 18536603Sbostic char buf[50]; 18616374Skarels 18726877Skarels Argv = argv; 18826877Skarels if (envp == 0 || *envp == 0) 18926877Skarels envp = argv; 19026877Skarels while (*envp) 19126877Skarels envp++; 19226877Skarels LastArg = envp[-1] + strlen(envp[-1]); 19316374Skarels 19457769Sandrew openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 19557769Sandrew 19657769Sandrew while ((ch = getopt(argc, argv, "dR:")) != EOF) 19736603Sbostic switch(ch) { 19816374Skarels case 'd': 19916374Skarels debug = 1; 20016374Skarels options |= SO_DEBUG; 20116374Skarels break; 20257769Sandrew case 'R': { /* invocation rate */ 20357769Sandrew char *p; 20457769Sandrew 20557769Sandrew tmpint = strtol(optarg, &p, 0); 20657769Sandrew if (tmpint < 1 || *p) 20757769Sandrew syslog(LOG_ERR, 20857769Sandrew "-R %s: bad value for service invocation rate", 20957769Sandrew optarg); 21057769Sandrew else 21157769Sandrew toomany = tmpint; 21257769Sandrew break; 21357769Sandrew } 21436603Sbostic case '?': 21516374Skarels default: 21657769Sandrew syslog(LOG_ERR, 21757769Sandrew "usage: inetd [-d] [-R rate] [conf-file]"); 21836603Sbostic exit(1); 21916374Skarels } 22036603Sbostic argc -= optind; 22136603Sbostic argv += optind; 22236603Sbostic 22316374Skarels if (argc > 0) 22416374Skarels CONFIG = argv[0]; 22557769Sandrew if (debug == 0) { 22644711Skarels daemon(0, 0); 22757769Sandrew } 22857769Sandrew bzero(&sv, sizeof(sv)); 22927535Skarels sv.sv_mask = SIGBLOCK; 23027535Skarels sv.sv_handler = retry; 23127535Skarels sigvec(SIGALRM, &sv, (struct sigvec *)0); 23216374Skarels config(); 23327535Skarels sv.sv_handler = config; 23427535Skarels sigvec(SIGHUP, &sv, (struct sigvec *)0); 23527535Skarels sv.sv_handler = reapchild; 23627535Skarels sigvec(SIGCHLD, &sv, (struct sigvec *)0); 23727535Skarels 23836603Sbostic { 23936603Sbostic /* space for daemons to overwrite environment for ps */ 24036603Sbostic #define DUMMYSIZE 100 24136603Sbostic char dummy[DUMMYSIZE]; 24236603Sbostic 24336603Sbostic (void)memset(dummy, 'x', sizeof(DUMMYSIZE) - 1); 24436603Sbostic dummy[DUMMYSIZE - 1] = '\0'; 24536603Sbostic (void)setenv("inetd_dummy", dummy, 1); 24636603Sbostic } 24736603Sbostic 24816374Skarels for (;;) { 24936603Sbostic int n, ctrl; 25027535Skarels fd_set readable; 25116374Skarels 25232091Skarels if (nsock == 0) { 25332091Skarels (void) sigblock(SIGBLOCK); 25432091Skarels while (nsock == 0) 25532246Sbostic sigpause(0L); 25632246Sbostic (void) sigsetmask(0L); 25732091Skarels } 25827535Skarels readable = allsock; 25927535Skarels if ((n = select(maxsock + 1, &readable, (fd_set *)0, 26027535Skarels (fd_set *)0, (struct timeval *)0)) <= 0) { 26127535Skarels if (n < 0 && errno != EINTR) 26257769Sandrew syslog(LOG_WARNING, "select: %m"); 26327535Skarels sleep(1); 26427535Skarels continue; 26527535Skarels } 26627535Skarels for (sep = servtab; n && sep; sep = sep->se_next) 26746973Skarels if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 26846973Skarels n--; 26946973Skarels if (debug) 27046973Skarels fprintf(stderr, "someone wants %s\n", 27146973Skarels sep->se_service); 27246973Skarels if (sep->se_socktype == SOCK_STREAM) { 27346973Skarels ctrl = accept(sep->se_fd, (struct sockaddr *)0, 27446973Skarels (int *)0); 27546973Skarels if (debug) 27646973Skarels fprintf(stderr, "accept, ctrl %d\n", ctrl); 27746973Skarels if (ctrl < 0) { 27857769Sandrew if (errno != EINTR) 27957769Sandrew syslog(LOG_WARNING, 28057769Sandrew "accept (for %s): %m", 28157769Sandrew sep->se_service); 28246973Skarels continue; 28346973Skarels } 28457769Sandrew /* 28557769Sandrew * Call tcpmux to find the real service to exec. 28657769Sandrew */ 28757769Sandrew if (sep->se_bi && 28857769Sandrew sep->se_bi->bi_fn == (int (*)()) tcpmux) { 28957769Sandrew sep = tcpmux(ctrl); 29057769Sandrew if (sep == NULL) { 29157769Sandrew close(ctrl); 29257769Sandrew continue; 29357769Sandrew } 29457769Sandrew } 29546973Skarels } else 29646973Skarels ctrl = sep->se_fd; 29746973Skarels (void) sigblock(SIGBLOCK); 29846973Skarels pid = 0; 29946973Skarels dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork); 30046973Skarels if (dofork) { 30146973Skarels if (sep->se_count++ == 0) 30246973Skarels (void)gettimeofday(&sep->se_time, 30346973Skarels (struct timezone *)0); 30457769Sandrew else if (sep->se_count >= toomany) { 30527535Skarels struct timeval now; 30627535Skarels 30727535Skarels (void)gettimeofday(&now, (struct timezone *)0); 30827535Skarels if (now.tv_sec - sep->se_time.tv_sec > 30927535Skarels CNT_INTVL) { 31027535Skarels sep->se_time = now; 31127535Skarels sep->se_count = 1; 31227535Skarels } else { 31327535Skarels syslog(LOG_ERR, 31457769Sandrew "%s/%s server failing (looping), service terminated", 31527535Skarels sep->se_service, sep->se_proto); 31657769Sandrew close_sep(sep); 31757769Sandrew sigsetmask(0L); 31827535Skarels if (!timingout) { 31927535Skarels timingout = 1; 32027535Skarels alarm(RETRYTIME); 32127535Skarels } 32257769Sandrew continue; 32327535Skarels } 32446973Skarels } 32546973Skarels pid = fork(); 32646973Skarels } 32746973Skarels if (pid < 0) { 32846973Skarels syslog(LOG_ERR, "fork: %m"); 32946973Skarels if (sep->se_socktype == SOCK_STREAM) 33046973Skarels close(ctrl); 33146973Skarels sigsetmask(0L); 33246973Skarels sleep(1); 33346973Skarels continue; 33446973Skarels } 33546973Skarels if (pid && sep->se_wait) { 33646973Skarels sep->se_wait = pid; 33749806Sbostic if (sep->se_fd >= 0) { 33849806Sbostic FD_CLR(sep->se_fd, &allsock); 33949806Sbostic nsock--; 34049806Sbostic } 34146973Skarels } 34246973Skarels sigsetmask(0L); 34346973Skarels if (pid == 0) { 34446973Skarels if (debug && dofork) 34544711Skarels setsid(); 34657769Sandrew if (dofork) { 34757769Sandrew if (debug) 34857769Sandrew fprintf(stderr, "+ Closing from %d\n", 34957769Sandrew maxsock); 35057769Sandrew for (tmpint = maxsock; tmpint > 2; tmpint--) 35136603Sbostic if (tmpint != ctrl) 35236603Sbostic close(tmpint); 35357769Sandrew } 35446973Skarels if (sep->se_bi) 35526877Skarels (*sep->se_bi->bi_fn)(ctrl, sep); 35646973Skarels else { 35746973Skarels if (debug) 35846973Skarels fprintf(stderr, "%d execl %s\n", 35946973Skarels getpid(), sep->se_server); 36026877Skarels dup2(ctrl, 0); 36126877Skarels close(ctrl); 36226877Skarels dup2(0, 1); 36326877Skarels dup2(0, 2); 36426877Skarels if ((pwd = getpwnam(sep->se_user)) == NULL) { 36526877Skarels syslog(LOG_ERR, 36657769Sandrew "%s/%s: %s: No such user", 36757769Sandrew sep->se_service, sep->se_proto, 36857769Sandrew sep->se_user); 36927535Skarels if (sep->se_socktype != SOCK_STREAM) 37027535Skarels recv(0, buf, sizeof (buf), 0); 37126877Skarels _exit(1); 37226877Skarels } 37326877Skarels if (pwd->pw_uid) { 37457769Sandrew if (setgid(pwd->pw_gid) < 0) { 37557769Sandrew syslog(LOG_ERR, 37657769Sandrew "%s: can't set gid %d: %m", 37757769Sandrew sep->se_service, pwd->pw_gid); 37857769Sandrew _exit(1); 37957769Sandrew } 38057769Sandrew (void) initgroups(pwd->pw_name, 38157769Sandrew pwd->pw_gid); 38257769Sandrew if (setuid(pwd->pw_uid) < 0) { 38357769Sandrew syslog(LOG_ERR, 38457769Sandrew "%s: can't set uid %d: %m", 38557769Sandrew sep->se_service, pwd->pw_uid); 38657769Sandrew _exit(1); 38757769Sandrew } 38826877Skarels } 38926877Skarels execv(sep->se_server, sep->se_argv); 39026877Skarels if (sep->se_socktype != SOCK_STREAM) 39126877Skarels recv(0, buf, sizeof (buf), 0); 39257769Sandrew syslog(LOG_ERR, 39357769Sandrew "cannot execute %s: %m", sep->se_server); 39426877Skarels _exit(1); 39546973Skarels } 39646973Skarels } 39746973Skarels if (sep->se_socktype == SOCK_STREAM) 39846973Skarels close(ctrl); 39916374Skarels } 40016374Skarels } 40116374Skarels } 40216374Skarels 40339838Sbostic void 40416374Skarels reapchild() 40516374Skarels { 40646973Skarels int status; 40716374Skarels int pid; 40816374Skarels register struct servtab *sep; 40916374Skarels 41016374Skarels for (;;) { 41146973Skarels pid = wait3(&status, WNOHANG, (struct rusage *)0); 41216374Skarels if (pid <= 0) 41316374Skarels break; 41416374Skarels if (debug) 41557769Sandrew fprintf(stderr, "%d reaped, status %#x\n", 41657769Sandrew pid, status); 41716374Skarels for (sep = servtab; sep; sep = sep->se_next) 41816374Skarels if (sep->se_wait == pid) { 41946973Skarels if (status) 42016510Sralph syslog(LOG_WARNING, 42116510Sralph "%s: exit status 0x%x", 42216374Skarels sep->se_server, status); 42316374Skarels if (debug) 42416374Skarels fprintf(stderr, "restored %s, fd %d\n", 42516374Skarels sep->se_service, sep->se_fd); 42625046Skarels FD_SET(sep->se_fd, &allsock); 42725046Skarels nsock++; 42816374Skarels sep->se_wait = 1; 42916374Skarels } 43016374Skarels } 43116374Skarels } 43216374Skarels 43339838Sbostic void 43416374Skarels config() 43516374Skarels { 43616374Skarels register struct servtab *sep, *cp, **sepp; 43716374Skarels struct servtab *getconfigent(), *enter(); 43857769Sandrew struct passwd *pwd; 43932246Sbostic long omask; 44016374Skarels 44116374Skarels if (!setconfig()) { 44216510Sralph syslog(LOG_ERR, "%s: %m", CONFIG); 44316374Skarels return; 44416374Skarels } 44516374Skarels for (sep = servtab; sep; sep = sep->se_next) 44616374Skarels sep->se_checked = 0; 44716374Skarels while (cp = getconfigent()) { 44857769Sandrew if ((pwd = getpwnam(cp->se_user)) == NULL) { 44957769Sandrew syslog(LOG_ERR, 45057769Sandrew "%s/%s: No such user '%s', service ignored", 45157769Sandrew cp->se_service, cp->se_proto, cp->se_user); 45257769Sandrew continue; 45357769Sandrew } 45416374Skarels for (sep = servtab; sep; sep = sep->se_next) 45516374Skarels if (strcmp(sep->se_service, cp->se_service) == 0 && 45616374Skarels strcmp(sep->se_proto, cp->se_proto) == 0) 45716374Skarels break; 45816374Skarels if (sep != 0) { 45916374Skarels int i; 46016374Skarels 46127535Skarels omask = sigblock(SIGBLOCK); 46240745Sbostic /* 46340745Sbostic * sep->se_wait may be holding the pid of a daemon 46440745Sbostic * that we're waiting for. If so, don't overwrite 46540745Sbostic * it unless the config file explicitly says don't 46640745Sbostic * wait. 46740745Sbostic */ 46840745Sbostic if (cp->se_bi == 0 && 46940745Sbostic (sep->se_wait == 1 || cp->se_wait == 0)) 47027535Skarels sep->se_wait = cp->se_wait; 47116374Skarels #define SWAP(a, b) { char *c = a; a = b; b = c; } 47226921Slepreau if (cp->se_user) 47326921Slepreau SWAP(sep->se_user, cp->se_user); 47416374Skarels if (cp->se_server) 47516374Skarels SWAP(sep->se_server, cp->se_server); 47616374Skarels for (i = 0; i < MAXARGV; i++) 47716374Skarels SWAP(sep->se_argv[i], cp->se_argv[i]); 47816374Skarels sigsetmask(omask); 47916374Skarels freeconfig(cp); 48029794Skarels if (debug) 48129794Skarels print_service("REDO", sep); 48229794Skarels } else { 48316374Skarels sep = enter(cp); 48429794Skarels if (debug) 48529794Skarels print_service("ADD ", sep); 48629794Skarels } 48716374Skarels sep->se_checked = 1; 48857769Sandrew if (ISMUX(sep)) { 48957769Sandrew sep->se_fd = -1; 49057769Sandrew continue; 49157769Sandrew } 49216374Skarels sp = getservbyname(sep->se_service, sep->se_proto); 49316374Skarels if (sp == 0) { 49416510Sralph syslog(LOG_ERR, "%s/%s: unknown service", 49516374Skarels sep->se_service, sep->se_proto); 49657769Sandrew sep->se_checked = 0; 49716374Skarels continue; 49816374Skarels } 49927535Skarels if (sp->s_port != sep->se_ctrladdr.sin_port) { 50060924Smckusick sep->se_ctrladdr.sin_family = AF_INET; 50127535Skarels sep->se_ctrladdr.sin_port = sp->s_port; 50257769Sandrew if (sep->se_fd >= 0) 50357769Sandrew close_sep(sep); 50416374Skarels } 50527535Skarels if (sep->se_fd == -1) 50627535Skarels setup(sep); 50716374Skarels } 50816374Skarels endconfig(); 50916374Skarels /* 51016374Skarels * Purge anything not looked at above. 51116374Skarels */ 51227535Skarels omask = sigblock(SIGBLOCK); 51316374Skarels sepp = &servtab; 51416374Skarels while (sep = *sepp) { 51516374Skarels if (sep->se_checked) { 51616374Skarels sepp = &sep->se_next; 51716374Skarels continue; 51816374Skarels } 51916374Skarels *sepp = sep->se_next; 52057769Sandrew if (sep->se_fd >= 0) 52157769Sandrew close_sep(sep); 52229794Skarels if (debug) 52329794Skarels print_service("FREE", sep); 52416374Skarels freeconfig(sep); 52516374Skarels free((char *)sep); 52616374Skarels } 52716374Skarels (void) sigsetmask(omask); 52816374Skarels } 52916374Skarels 53039838Sbostic void 53127535Skarels retry() 53227535Skarels { 53327535Skarels register struct servtab *sep; 53427535Skarels 53527535Skarels timingout = 0; 53627535Skarels for (sep = servtab; sep; sep = sep->se_next) 53727535Skarels if (sep->se_fd == -1) 53827535Skarels setup(sep); 53927535Skarels } 54027535Skarels 54127535Skarels setup(sep) 54227535Skarels register struct servtab *sep; 54327535Skarels { 54427535Skarels int on = 1; 54527535Skarels 54627535Skarels if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 54757769Sandrew if (debug) 54857769Sandrew fprintf(stderr, "socket failed on %s/%s: %s\n", 54957769Sandrew sep->se_service, sep->se_proto, 55057769Sandrew strerror(errno)); 55127535Skarels syslog(LOG_ERR, "%s/%s: socket: %m", 55227535Skarels sep->se_service, sep->se_proto); 55327535Skarels return; 55427535Skarels } 55527535Skarels #define turnon(fd, opt) \ 55627535Skarels setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 55727535Skarels if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 55827535Skarels turnon(sep->se_fd, SO_DEBUG) < 0) 55927535Skarels syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 56027535Skarels if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 56127535Skarels syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 56227535Skarels #undef turnon 56346907Sbostic if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 56427535Skarels sizeof (sep->se_ctrladdr)) < 0) { 56557769Sandrew if (debug) 56657769Sandrew fprintf(stderr, "bind failed on %s/%s: %s\n", 56757769Sandrew sep->se_service, sep->se_proto, 56857769Sandrew strerror(errno)); 56927535Skarels syslog(LOG_ERR, "%s/%s: bind: %m", 57027535Skarels sep->se_service, sep->se_proto); 57127535Skarels (void) close(sep->se_fd); 57227535Skarels sep->se_fd = -1; 57327535Skarels if (!timingout) { 57427535Skarels timingout = 1; 57527535Skarels alarm(RETRYTIME); 57627535Skarels } 57727535Skarels return; 57827535Skarels } 57927535Skarels if (sep->se_socktype == SOCK_STREAM) 58027535Skarels listen(sep->se_fd, 10); 58127535Skarels FD_SET(sep->se_fd, &allsock); 58227535Skarels nsock++; 58327535Skarels if (sep->se_fd > maxsock) 58427535Skarels maxsock = sep->se_fd; 58557769Sandrew if (debug) { 58657769Sandrew fprintf(stderr, "registered %s on %d\n", 58757769Sandrew sep->se_server, sep->se_fd); 58857769Sandrew } 58927535Skarels } 59027535Skarels 59157769Sandrew /* 59257769Sandrew * Finish with a service and its socket. 59357769Sandrew */ 59457769Sandrew close_sep(sep) 59557769Sandrew register struct servtab *sep; 59657769Sandrew { 59757769Sandrew if (sep->se_fd >= 0) { 59857769Sandrew nsock--; 59957769Sandrew FD_CLR(sep->se_fd, &allsock); 60057769Sandrew (void) close(sep->se_fd); 60157769Sandrew sep->se_fd = -1; 60257769Sandrew } 60357769Sandrew sep->se_count = 0; 60457769Sandrew /* 60557769Sandrew * Don't keep the pid of this running deamon: when reapchild() 60657769Sandrew * reaps this pid, it would erroneously increment nsock. 60757769Sandrew */ 60857769Sandrew if (sep->se_wait > 1) 60957769Sandrew sep->se_wait = 1; 61057769Sandrew } 61157769Sandrew 61216374Skarels struct servtab * 61316374Skarels enter(cp) 61416374Skarels struct servtab *cp; 61516374Skarels { 61616374Skarels register struct servtab *sep; 61732246Sbostic long omask; 61816374Skarels 61916374Skarels sep = (struct servtab *)malloc(sizeof (*sep)); 62016374Skarels if (sep == (struct servtab *)0) { 62116510Sralph syslog(LOG_ERR, "Out of memory."); 62216374Skarels exit(-1); 62316374Skarels } 62416374Skarels *sep = *cp; 62516374Skarels sep->se_fd = -1; 62627535Skarels omask = sigblock(SIGBLOCK); 62716374Skarels sep->se_next = servtab; 62816374Skarels servtab = sep; 62916374Skarels sigsetmask(omask); 63016374Skarels return (sep); 63116374Skarels } 63216374Skarels 63316374Skarels FILE *fconfig = NULL; 63416374Skarels struct servtab serv; 63516374Skarels char line[256]; 63657769Sandrew char *sskip(), *skip(), *nextline(); 63716374Skarels 63816374Skarels setconfig() 63916374Skarels { 64016374Skarels 64116374Skarels if (fconfig != NULL) { 64257769Sandrew fseek(fconfig, 0L, SEEK_SET); 64316374Skarels return (1); 64416374Skarels } 64516374Skarels fconfig = fopen(CONFIG, "r"); 64616374Skarels return (fconfig != NULL); 64716374Skarels } 64816374Skarels 64916374Skarels endconfig() 65016374Skarels { 65136603Sbostic if (fconfig) { 65236603Sbostic (void) fclose(fconfig); 65336603Sbostic fconfig = NULL; 65436603Sbostic } 65516374Skarels } 65616374Skarels 65716374Skarels struct servtab * 65816374Skarels getconfigent() 65916374Skarels { 66016374Skarels register struct servtab *sep = &serv; 66116374Skarels int argc; 66246907Sbostic char *cp, *arg, *newstr(); 66357769Sandrew static char TCPMUX_TOKEN[] = "tcpmux/"; 66457769Sandrew #define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 66516374Skarels 66626877Skarels more: 66757769Sandrew while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0')) 66816374Skarels ; 66916374Skarels if (cp == NULL) 67016374Skarels return ((struct servtab *)0); 67157769Sandrew /* 67257769Sandrew * clear the static buffer, since some fields (se_ctrladdr, 67357769Sandrew * for example) don't get initialized here. 67457769Sandrew */ 67557769Sandrew bzero((caddr_t)sep, sizeof *sep); 67616374Skarels arg = skip(&cp); 67757769Sandrew if (cp == NULL) { 67857769Sandrew /* got an empty line containing just blanks/tabs. */ 67957769Sandrew goto more; 68057769Sandrew } 68157769Sandrew if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 68257769Sandrew char *c = arg + MUX_LEN; 68357769Sandrew if (*c == '+') { 68457769Sandrew sep->se_type = MUXPLUS_TYPE; 68557769Sandrew c++; 68657769Sandrew } else 68757769Sandrew sep->se_type = MUX_TYPE; 68857769Sandrew sep->se_service = newstr(c); 68957769Sandrew } else { 69057769Sandrew sep->se_service = newstr(arg); 69157769Sandrew sep->se_type = NORM_TYPE; 69257769Sandrew } 69357769Sandrew arg = sskip(&cp); 69416374Skarels if (strcmp(arg, "stream") == 0) 69516374Skarels sep->se_socktype = SOCK_STREAM; 69616374Skarels else if (strcmp(arg, "dgram") == 0) 69716374Skarels sep->se_socktype = SOCK_DGRAM; 69816374Skarels else if (strcmp(arg, "rdm") == 0) 69916374Skarels sep->se_socktype = SOCK_RDM; 70016374Skarels else if (strcmp(arg, "seqpacket") == 0) 70116374Skarels sep->se_socktype = SOCK_SEQPACKET; 70216374Skarels else if (strcmp(arg, "raw") == 0) 70316374Skarels sep->se_socktype = SOCK_RAW; 70416374Skarels else 70516374Skarels sep->se_socktype = -1; 70657769Sandrew sep->se_proto = newstr(sskip(&cp)); 70757769Sandrew arg = sskip(&cp); 70816374Skarels sep->se_wait = strcmp(arg, "wait") == 0; 70957769Sandrew if (ISMUX(sep)) { 71057769Sandrew /* 71157769Sandrew * Silently enforce "nowait" for TCPMUX services since 71257769Sandrew * they don't have an assigned port to listen on. 71357769Sandrew */ 71457769Sandrew sep->se_wait = 0; 71557769Sandrew 71657769Sandrew if (strcmp(sep->se_proto, "tcp")) { 71757769Sandrew syslog(LOG_ERR, 71857769Sandrew "%s: bad protocol for tcpmux service %s", 71957769Sandrew CONFIG, sep->se_service); 72057769Sandrew goto more; 72157769Sandrew } 72257769Sandrew if (sep->se_socktype != SOCK_STREAM) { 72357769Sandrew syslog(LOG_ERR, 72457769Sandrew "%s: bad socket type for tcpmux service %s", 72557769Sandrew CONFIG, sep->se_service); 72657769Sandrew goto more; 72757769Sandrew } 72857769Sandrew } 72957769Sandrew sep->se_user = newstr(sskip(&cp)); 73057769Sandrew sep->se_server = newstr(sskip(&cp)); 73126877Skarels if (strcmp(sep->se_server, "internal") == 0) { 73226877Skarels register struct biltin *bi; 73326877Skarels 73426877Skarels for (bi = biltins; bi->bi_service; bi++) 73526877Skarels if (bi->bi_socktype == sep->se_socktype && 73626877Skarels strcmp(bi->bi_service, sep->se_service) == 0) 73726877Skarels break; 73826877Skarels if (bi->bi_service == 0) { 73957769Sandrew syslog(LOG_ERR, "internal service %s unknown", 74026877Skarels sep->se_service); 74126877Skarels goto more; 74226877Skarels } 74326877Skarels sep->se_bi = bi; 74426877Skarels sep->se_wait = bi->bi_wait; 74529794Skarels } else 74629794Skarels sep->se_bi = NULL; 74716374Skarels argc = 0; 74816374Skarels for (arg = skip(&cp); cp; arg = skip(&cp)) 74916374Skarels if (argc < MAXARGV) 75046907Sbostic sep->se_argv[argc++] = newstr(arg); 75116374Skarels while (argc <= MAXARGV) 75216374Skarels sep->se_argv[argc++] = NULL; 75316374Skarels return (sep); 75416374Skarels } 75516374Skarels 75616374Skarels freeconfig(cp) 75716374Skarels register struct servtab *cp; 75816374Skarels { 75916374Skarels int i; 76016374Skarels 76116374Skarels if (cp->se_service) 76216374Skarels free(cp->se_service); 76316374Skarels if (cp->se_proto) 76416374Skarels free(cp->se_proto); 76526921Slepreau if (cp->se_user) 76626921Slepreau free(cp->se_user); 76716374Skarels if (cp->se_server) 76816374Skarels free(cp->se_server); 76916374Skarels for (i = 0; i < MAXARGV; i++) 77016374Skarels if (cp->se_argv[i]) 77116374Skarels free(cp->se_argv[i]); 77216374Skarels } 77316374Skarels 77457769Sandrew 77557769Sandrew /* 77657769Sandrew * Safe skip - if skip returns null, log a syntax error in the 77757769Sandrew * configuration file and exit. 77857769Sandrew */ 77916374Skarels char * 78057769Sandrew sskip(cpp) 78157769Sandrew char **cpp; 78257769Sandrew { 78357769Sandrew register char *cp; 78457769Sandrew 78557769Sandrew cp = skip(cpp); 78657769Sandrew if (cp == NULL) { 78757769Sandrew syslog(LOG_ERR, "%s: syntax error", CONFIG); 78857769Sandrew exit(-1); 78957769Sandrew } 79057769Sandrew return (cp); 79157769Sandrew } 79257769Sandrew 79357769Sandrew char * 79416374Skarels skip(cpp) 79516374Skarels char **cpp; 79616374Skarels { 79716374Skarels register char *cp = *cpp; 79816374Skarels char *start; 79916374Skarels 80016374Skarels again: 80116374Skarels while (*cp == ' ' || *cp == '\t') 80216374Skarels cp++; 80316374Skarels if (*cp == '\0') { 80443455Sbostic int c; 80516374Skarels 80616374Skarels c = getc(fconfig); 80736603Sbostic (void) ungetc(c, fconfig); 80816374Skarels if (c == ' ' || c == '\t') 80916374Skarels if (cp = nextline(fconfig)) 81016374Skarels goto again; 81116374Skarels *cpp = (char *)0; 81216374Skarels return ((char *)0); 81316374Skarels } 81416374Skarels start = cp; 81516374Skarels while (*cp && *cp != ' ' && *cp != '\t') 81616374Skarels cp++; 81716374Skarels if (*cp != '\0') 81816374Skarels *cp++ = '\0'; 81916374Skarels *cpp = cp; 82016374Skarels return (start); 82116374Skarels } 82216374Skarels 82316374Skarels char * 82416374Skarels nextline(fd) 82516374Skarels FILE *fd; 82616374Skarels { 82716374Skarels char *cp; 82816374Skarels 82926921Slepreau if (fgets(line, sizeof (line), fd) == NULL) 83016374Skarels return ((char *)0); 83116374Skarels cp = index(line, '\n'); 83216374Skarels if (cp) 83316374Skarels *cp = '\0'; 83416374Skarels return (line); 83516374Skarels } 83616374Skarels 83716374Skarels char * 83846907Sbostic newstr(cp) 83916374Skarels char *cp; 84016374Skarels { 84146973Skarels if (cp = strdup(cp ? cp : "")) 84246907Sbostic return(cp); 84346973Skarels syslog(LOG_ERR, "strdup: %m"); 84446907Sbostic exit(-1); 84516374Skarels } 84626877Skarels 84726877Skarels setproctitle(a, s) 84826877Skarels char *a; 84926877Skarels int s; 85026877Skarels { 85126877Skarels int size; 85226877Skarels register char *cp; 85326877Skarels struct sockaddr_in sin; 85426877Skarels char buf[80]; 85526877Skarels 85626877Skarels cp = Argv[0]; 85726877Skarels size = sizeof(sin); 85846907Sbostic if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 85932442Sbostic (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 86026877Skarels else 86132442Sbostic (void) sprintf(buf, "-%s", a); 86226877Skarels strncpy(cp, buf, LastArg - cp); 86326877Skarels cp += strlen(cp); 86426877Skarels while (cp < LastArg) 86526877Skarels *cp++ = ' '; 86626877Skarels } 86726877Skarels 86826877Skarels /* 86926877Skarels * Internet services provided internally by inetd: 87026877Skarels */ 87149986Skarels #define BUFSIZE 8192 87226877Skarels 87326877Skarels /* ARGSUSED */ 87426877Skarels echo_stream(s, sep) /* Echo service -- echo data back */ 87526877Skarels int s; 87626877Skarels struct servtab *sep; 87726877Skarels { 87838573Skarels char buffer[BUFSIZE]; 87926877Skarels int i; 88026877Skarels 88132091Skarels setproctitle(sep->se_service, s); 88226877Skarels while ((i = read(s, buffer, sizeof(buffer))) > 0 && 88326877Skarels write(s, buffer, i) > 0) 88426877Skarels ; 88526877Skarels exit(0); 88626877Skarels } 88726877Skarels 88826877Skarels /* ARGSUSED */ 88926877Skarels echo_dg(s, sep) /* Echo service -- echo data back */ 89026877Skarels int s; 89126877Skarels struct servtab *sep; 89226877Skarels { 89338573Skarels char buffer[BUFSIZE]; 89426877Skarels int i, size; 89526877Skarels struct sockaddr sa; 89626877Skarels 89726877Skarels size = sizeof(sa); 89826877Skarels if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) 89926877Skarels return; 90026877Skarels (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); 90126877Skarels } 90226877Skarels 90326877Skarels /* ARGSUSED */ 90426877Skarels discard_stream(s, sep) /* Discard service -- ignore data */ 90526877Skarels int s; 90626877Skarels struct servtab *sep; 90726877Skarels { 90849986Skarels int ret; 90938573Skarels char buffer[BUFSIZE]; 91026877Skarels 91132091Skarels setproctitle(sep->se_service, s); 91226877Skarels while (1) { 91349986Skarels while ((ret = read(s, buffer, sizeof(buffer))) > 0) 91426877Skarels ; 91549986Skarels if (ret == 0 || errno != EINTR) 91626877Skarels break; 91726877Skarels } 91826877Skarels exit(0); 91926877Skarels } 92026877Skarels 92126877Skarels /* ARGSUSED */ 92226877Skarels discard_dg(s, sep) /* Discard service -- ignore data */ 92326877Skarels int s; 92426877Skarels struct servtab *sep; 92526877Skarels { 92638573Skarels char buffer[BUFSIZE]; 92726877Skarels 92826877Skarels (void) read(s, buffer, sizeof(buffer)); 92926877Skarels } 93026877Skarels 93126877Skarels #include <ctype.h> 93226877Skarels #define LINESIZ 72 93326877Skarels char ring[128]; 93426877Skarels char *endring; 93526877Skarels 93626877Skarels initring() 93726877Skarels { 93826877Skarels register int i; 93926877Skarels 94026877Skarels endring = ring; 94126877Skarels 94226877Skarels for (i = 0; i <= 128; ++i) 94326877Skarels if (isprint(i)) 94426877Skarels *endring++ = i; 94526877Skarels } 94626877Skarels 94726877Skarels /* ARGSUSED */ 94826877Skarels chargen_stream(s, sep) /* Character generator */ 94926877Skarels int s; 95026877Skarels struct servtab *sep; 95126877Skarels { 95232246Sbostic register char *rs; 95332246Sbostic int len; 95426877Skarels char text[LINESIZ+2]; 95526877Skarels 95632091Skarels setproctitle(sep->se_service, s); 95732246Sbostic 95832246Sbostic if (!endring) { 95926877Skarels initring(); 96032246Sbostic rs = ring; 96132246Sbostic } 96226877Skarels 96332246Sbostic text[LINESIZ] = '\r'; 96432246Sbostic text[LINESIZ + 1] = '\n'; 96532246Sbostic for (rs = ring;;) { 96632246Sbostic if ((len = endring - rs) >= LINESIZ) 96732246Sbostic bcopy(rs, text, LINESIZ); 96832246Sbostic else { 96932246Sbostic bcopy(rs, text, len); 97032246Sbostic bcopy(ring, text + len, LINESIZ - len); 97132246Sbostic } 97232246Sbostic if (++rs == endring) 97326877Skarels rs = ring; 97432246Sbostic if (write(s, text, sizeof(text)) != sizeof(text)) 97526877Skarels break; 97626877Skarels } 97726877Skarels exit(0); 97826877Skarels } 97926877Skarels 98026877Skarels /* ARGSUSED */ 98126877Skarels chargen_dg(s, sep) /* Character generator */ 98226877Skarels int s; 98326877Skarels struct servtab *sep; 98426877Skarels { 98532246Sbostic struct sockaddr sa; 98632246Sbostic static char *rs; 98732246Sbostic int len, size; 98826877Skarels char text[LINESIZ+2]; 98926877Skarels 99032246Sbostic if (endring == 0) { 99126877Skarels initring(); 99232246Sbostic rs = ring; 99332246Sbostic } 99426877Skarels 99526877Skarels size = sizeof(sa); 99626877Skarels if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) 99726877Skarels return; 99832246Sbostic 99932246Sbostic if ((len = endring - rs) >= LINESIZ) 100032246Sbostic bcopy(rs, text, LINESIZ); 100132246Sbostic else { 100232246Sbostic bcopy(rs, text, len); 100332246Sbostic bcopy(ring, text + len, LINESIZ - len); 100432246Sbostic } 100532246Sbostic if (++rs == endring) 100626877Skarels rs = ring; 100732246Sbostic text[LINESIZ] = '\r'; 100832246Sbostic text[LINESIZ + 1] = '\n'; 100926877Skarels (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa)); 101026877Skarels } 101126877Skarels 101226877Skarels /* 101326877Skarels * Return a machine readable date and time, in the form of the 101426877Skarels * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 101526877Skarels * returns the number of seconds since midnight, Jan 1, 1970, 101626877Skarels * we must add 2208988800 seconds to this figure to make up for 101726877Skarels * some seventy years Bell Labs was asleep. 101826877Skarels */ 101926877Skarels 102026877Skarels long 102126877Skarels machtime() 102226877Skarels { 102326877Skarels struct timeval tv; 102426877Skarels 102526921Slepreau if (gettimeofday(&tv, (struct timezone *)0) < 0) { 102657769Sandrew if (debug) 102757769Sandrew fprintf(stderr, "Unable to get time of day\n"); 102826921Slepreau return (0L); 102926877Skarels } 103060073Storek #define OFFSET ((u_long)25567 * 24*60*60) 103160073Storek return (htonl((long)(tv.tv_sec + OFFSET))); 103260073Storek #undef OFFSET 103326877Skarels } 103426877Skarels 103526877Skarels /* ARGSUSED */ 103626877Skarels machtime_stream(s, sep) 103726877Skarels int s; 103826877Skarels struct servtab *sep; 103926877Skarels { 104026877Skarels long result; 104126877Skarels 104226877Skarels result = machtime(); 104326877Skarels (void) write(s, (char *) &result, sizeof(result)); 104426877Skarels } 104526877Skarels 104626877Skarels /* ARGSUSED */ 104726877Skarels machtime_dg(s, sep) 104826877Skarels int s; 104926877Skarels struct servtab *sep; 105026877Skarels { 105126877Skarels long result; 105226877Skarels struct sockaddr sa; 105326877Skarels int size; 105426877Skarels 105526877Skarels size = sizeof(sa); 105626921Slepreau if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0) 105726877Skarels return; 105826877Skarels result = machtime(); 105926877Skarels (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa)); 106026877Skarels } 106126877Skarels 106226877Skarels /* ARGSUSED */ 106326877Skarels daytime_stream(s, sep) /* Return human-readable time of day */ 106426877Skarels int s; 106526877Skarels struct servtab *sep; 106626877Skarels { 106726877Skarels char buffer[256]; 106857769Sandrew time_t clock; 106926877Skarels 107026877Skarels clock = time((time_t *) 0); 107126877Skarels 107232442Sbostic (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 107326921Slepreau (void) write(s, buffer, strlen(buffer)); 107426877Skarels } 107526877Skarels 107626877Skarels /* ARGSUSED */ 107726877Skarels daytime_dg(s, sep) /* Return human-readable time of day */ 107826877Skarels int s; 107926877Skarels struct servtab *sep; 108026877Skarels { 108126877Skarels char buffer[256]; 108257769Sandrew time_t clock; 108326877Skarels struct sockaddr sa; 108426877Skarels int size; 108526877Skarels 108626877Skarels clock = time((time_t *) 0); 108726877Skarels 108826877Skarels size = sizeof(sa); 108926877Skarels if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) 109026877Skarels return; 109132442Sbostic (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 109226877Skarels (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa)); 109326877Skarels } 109429794Skarels 109529794Skarels /* 109629794Skarels * print_service: 109729794Skarels * Dump relevant information to stderr 109829794Skarels */ 109929794Skarels print_service(action, sep) 110029794Skarels char *action; 110129794Skarels struct servtab *sep; 110229794Skarels { 110329794Skarels fprintf(stderr, 110429794Skarels "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n", 110529794Skarels action, sep->se_service, sep->se_proto, 110636603Sbostic sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server); 110729794Skarels } 110857769Sandrew 110957769Sandrew /* 111057769Sandrew * Based on TCPMUX.C by Mark K. Lottor November 1988 111157769Sandrew * sri-nic::ps:<mkl>tcpmux.c 111257769Sandrew */ 111357769Sandrew 111457769Sandrew 111557769Sandrew static int /* # of characters upto \r,\n or \0 */ 111657769Sandrew getline(fd, buf, len) 111757769Sandrew int fd; 111857769Sandrew char *buf; 111957769Sandrew int len; 112057769Sandrew { 112157769Sandrew int count = 0, n; 112257769Sandrew 112357769Sandrew do { 112457769Sandrew n = read(fd, buf, len-count); 112557769Sandrew if (n == 0) 112657769Sandrew return count; 112757769Sandrew if (n < 0) 112857769Sandrew return (-1); 112957769Sandrew while (--n >= 0) { 113057769Sandrew if (*buf == '\r' || *buf == '\n' || *buf == '\0') 113157769Sandrew return count; 113257769Sandrew count++; 113357769Sandrew buf++; 113457769Sandrew } 113557769Sandrew } while (count < len); 113657769Sandrew return (count); 113757769Sandrew } 113857769Sandrew 113957769Sandrew #define MAX_SERV_LEN (256+2) /* 2 bytes for \r\n */ 114057769Sandrew 114157769Sandrew #define strwrite(fd, buf) (void) write(fd, buf, sizeof(buf)-1) 114257769Sandrew 114357769Sandrew struct servtab * 114457769Sandrew tcpmux(s) 114557769Sandrew int s; 114657769Sandrew { 114757769Sandrew register struct servtab *sep; 114857769Sandrew char service[MAX_SERV_LEN+1]; 114957769Sandrew int len; 115057769Sandrew 115157769Sandrew /* Get requested service name */ 115257769Sandrew if ((len = getline(s, service, MAX_SERV_LEN)) < 0) { 115357769Sandrew strwrite(s, "-Error reading service name\r\n"); 115457769Sandrew return(NULL); 115557769Sandrew } 115657769Sandrew service[len] = '\0'; 115757769Sandrew 115857769Sandrew if (debug) 115957769Sandrew fprintf(stderr, "tcpmux: someone wants %s\n", service); 116057769Sandrew 116157769Sandrew /* 116257769Sandrew * Help is a required command, and lists available services, 116357769Sandrew * one per line. 116457769Sandrew */ 116557769Sandrew if (!strcasecmp(service,"help")) { 116657769Sandrew for (sep = servtab; sep; sep = sep->se_next) { 116757769Sandrew if (!ISMUX(sep)) 116857769Sandrew continue; 116957769Sandrew (void) write(s, sep->se_service, strlen(sep->se_service)); 117057769Sandrew strwrite(s, "\r\n"); 117157769Sandrew } 117257769Sandrew return(NULL); 117357769Sandrew } 117457769Sandrew 117557769Sandrew /* Try matching a service in inetd.conf with the request */ 117657769Sandrew for (sep = servtab; sep; sep = sep->se_next) { 117757769Sandrew if (!ISMUX(sep)) 117857769Sandrew continue; 117957769Sandrew if (!strcasecmp(service,sep->se_service)) { 118057769Sandrew if (ISMUXPLUS(sep)) { 118157769Sandrew strwrite(s, "+Go\r\n"); 118257769Sandrew } 118357769Sandrew return(sep); 118457769Sandrew } 118557769Sandrew } 118657769Sandrew strwrite(s, "-Service not available\r\n"); 118757769Sandrew return(NULL); 118857769Sandrew } 1189