121134Sdist /* 2*57769Sandrew * Copyright (c) 1983, 1991, 1993 The Regents of the University of California. 333136Sbostic * All rights reserved. 433136Sbostic * 542799Sbostic * %sccs.include.redist.c% 621134Sdist */ 721134Sdist 816374Skarels #ifndef lint 921134Sdist char copyright[] = 10*57769Sandrew "@(#) Copyright (c) 1983, 1991, 1993 Regents of the University of California.\n\ 1121134Sdist All rights reserved.\n"; 1233136Sbostic #endif /* not lint */ 1316374Skarels 1421134Sdist #ifndef lint 15*57769Sandrew static char sccsid[] = "@(#)inetd.c 5.31 (Berkeley) 02/01/93"; 1633136Sbostic #endif /* not lint */ 1721134Sdist 1816374Skarels /* 1916374Skarels * Inetd - Internet super-server 2016374Skarels * 21*57769Sandrew * This program invokes all internet services as needed. Connection-oriented 22*57769Sandrew * services are invoked each time a connection is made, by creating a process. 23*57769Sandrew * This process is passed the connection as file descriptor 0 and is expected 24*57769Sandrew * 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 * 41*57769Sandrew * service name must be in /etc/services or must 42*57769Sandrew * 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 * 50*57769Sandrew * TCP services without official port numbers are handled with the 51*57769Sandrew * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for 52*57769Sandrew * requests. When a connection is made from a foreign host, the service 53*57769Sandrew * requested is passed to tcpmux, which looks it up in the servtab list 54*57769Sandrew * and returns the proper entry for the service. Tcpmux returns a 55*57769Sandrew * negative reply if the service doesn't exist, otherwise the invoked 56*57769Sandrew * server is expected to return the positive reply if the service type in 57*57769Sandrew * inetd.conf file has the prefix "tcpmux/". If the service type has the 58*57769Sandrew * prefix "tcpmux/+", tcpmux will return the positive reply for the 59*57769Sandrew * process; this is for compatibility with older server code, and also 60*57769Sandrew * allows you to invoke programs that use stdin/stdout without putting any 61*57769Sandrew * special server code in them. Services that use tcpmux are "nowait" 62*57769Sandrew * because they do not have a well-known port and hence cannot listen 63*57769Sandrew * for new requests. 64*57769Sandrew * 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> 79*57769Sandrew #include <fcntl.h> 8016374Skarels #include <netdb.h> 8117346Sbloom #include <pwd.h> 82*57769Sandrew #include <signal.h> 8336603Sbostic #include <stdio.h> 84*57769Sandrew #include <stdlib.h> 8542067Sbostic #include <string.h> 86*57769Sandrew #include <syslog.h> 87*57769Sandrew #include <unistd.h> 88*57769Sandrew 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; 105*57769Sandrew 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 */ 120*57769Sandrew 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 127*57769Sandrew #define NORM_TYPE 0 128*57769Sandrew #define MUX_TYPE 1 129*57769Sandrew #define MUXPLUS_TYPE 2 130*57769Sandrew #define ISMUX(sep) (((sep)->se_type == MUX_TYPE) || \ 131*57769Sandrew ((sep)->se_type == MUXPLUS_TYPE)) 132*57769Sandrew #define ISMUXPLUS(sep) ((sep)->se_type == MUXPLUS_TYPE) 133*57769Sandrew 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(); 137*57769Sandrew 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, 165*57769Sandrew 166*57769Sandrew "tcpmux", SOCK_STREAM, 1, 0, (int (*)())tcpmux, 167*57769Sandrew 168*57769Sandrew 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 194*57769Sandrew openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 195*57769Sandrew 196*57769Sandrew while ((ch = getopt(argc, argv, "dR:")) != EOF) 19736603Sbostic switch(ch) { 19816374Skarels case 'd': 19916374Skarels debug = 1; 20016374Skarels options |= SO_DEBUG; 20116374Skarels break; 202*57769Sandrew case 'R': { /* invocation rate */ 203*57769Sandrew char *p; 204*57769Sandrew 205*57769Sandrew tmpint = strtol(optarg, &p, 0); 206*57769Sandrew if (tmpint < 1 || *p) 207*57769Sandrew syslog(LOG_ERR, 208*57769Sandrew "-R %s: bad value for service invocation rate", 209*57769Sandrew optarg); 210*57769Sandrew else 211*57769Sandrew toomany = tmpint; 212*57769Sandrew break; 213*57769Sandrew } 21436603Sbostic case '?': 21516374Skarels default: 216*57769Sandrew syslog(LOG_ERR, 217*57769Sandrew "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]; 225*57769Sandrew if (debug == 0) { 22644711Skarels daemon(0, 0); 227*57769Sandrew } 228*57769Sandrew 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) 262*57769Sandrew 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) { 278*57769Sandrew if (errno != EINTR) 279*57769Sandrew syslog(LOG_WARNING, 280*57769Sandrew "accept (for %s): %m", 281*57769Sandrew sep->se_service); 28246973Skarels continue; 28346973Skarels } 284*57769Sandrew /* 285*57769Sandrew * Call tcpmux to find the real service to exec. 286*57769Sandrew */ 287*57769Sandrew if (sep->se_bi && 288*57769Sandrew sep->se_bi->bi_fn == (int (*)()) tcpmux) { 289*57769Sandrew sep = tcpmux(ctrl); 290*57769Sandrew if (sep == NULL) { 291*57769Sandrew close(ctrl); 292*57769Sandrew continue; 293*57769Sandrew } 294*57769Sandrew } 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); 304*57769Sandrew 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, 314*57769Sandrew "%s/%s server failing (looping), service terminated", 31527535Skarels sep->se_service, sep->se_proto); 316*57769Sandrew close_sep(sep); 317*57769Sandrew sigsetmask(0L); 31827535Skarels if (!timingout) { 31927535Skarels timingout = 1; 32027535Skarels alarm(RETRYTIME); 32127535Skarels } 322*57769Sandrew 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(); 346*57769Sandrew if (dofork) { 347*57769Sandrew if (debug) 348*57769Sandrew fprintf(stderr, "+ Closing from %d\n", 349*57769Sandrew maxsock); 350*57769Sandrew for (tmpint = maxsock; tmpint > 2; tmpint--) 35136603Sbostic if (tmpint != ctrl) 35236603Sbostic close(tmpint); 353*57769Sandrew } 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, 366*57769Sandrew "%s/%s: %s: No such user", 367*57769Sandrew sep->se_service, sep->se_proto, 368*57769Sandrew 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) { 374*57769Sandrew if (setgid(pwd->pw_gid) < 0) { 375*57769Sandrew syslog(LOG_ERR, 376*57769Sandrew "%s: can't set gid %d: %m", 377*57769Sandrew sep->se_service, pwd->pw_gid); 378*57769Sandrew _exit(1); 379*57769Sandrew } 380*57769Sandrew (void) initgroups(pwd->pw_name, 381*57769Sandrew pwd->pw_gid); 382*57769Sandrew if (setuid(pwd->pw_uid) < 0) { 383*57769Sandrew syslog(LOG_ERR, 384*57769Sandrew "%s: can't set uid %d: %m", 385*57769Sandrew sep->se_service, pwd->pw_uid); 386*57769Sandrew _exit(1); 387*57769Sandrew } 38826877Skarels } 38926877Skarels execv(sep->se_server, sep->se_argv); 39026877Skarels if (sep->se_socktype != SOCK_STREAM) 39126877Skarels recv(0, buf, sizeof (buf), 0); 392*57769Sandrew syslog(LOG_ERR, 393*57769Sandrew "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) 415*57769Sandrew fprintf(stderr, "%d reaped, status %#x\n", 416*57769Sandrew 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(); 438*57769Sandrew 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()) { 448*57769Sandrew if ((pwd = getpwnam(cp->se_user)) == NULL) { 449*57769Sandrew syslog(LOG_ERR, 450*57769Sandrew "%s/%s: No such user '%s', service ignored", 451*57769Sandrew cp->se_service, cp->se_proto, cp->se_user); 452*57769Sandrew continue; 453*57769Sandrew } 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; 488*57769Sandrew if (ISMUX(sep)) { 489*57769Sandrew sep->se_fd = -1; 490*57769Sandrew continue; 491*57769Sandrew } 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); 496*57769Sandrew sep->se_checked = 0; 49716374Skarels continue; 49816374Skarels } 49927535Skarels if (sp->s_port != sep->se_ctrladdr.sin_port) { 50027535Skarels sep->se_ctrladdr.sin_port = sp->s_port; 501*57769Sandrew if (sep->se_fd >= 0) 502*57769Sandrew close_sep(sep); 50316374Skarels } 50427535Skarels if (sep->se_fd == -1) 50527535Skarels setup(sep); 50616374Skarels } 50716374Skarels endconfig(); 50816374Skarels /* 50916374Skarels * Purge anything not looked at above. 51016374Skarels */ 51127535Skarels omask = sigblock(SIGBLOCK); 51216374Skarels sepp = &servtab; 51316374Skarels while (sep = *sepp) { 51416374Skarels if (sep->se_checked) { 51516374Skarels sepp = &sep->se_next; 51616374Skarels continue; 51716374Skarels } 51816374Skarels *sepp = sep->se_next; 519*57769Sandrew if (sep->se_fd >= 0) 520*57769Sandrew close_sep(sep); 52129794Skarels if (debug) 52229794Skarels print_service("FREE", sep); 52316374Skarels freeconfig(sep); 52416374Skarels free((char *)sep); 52516374Skarels } 52616374Skarels (void) sigsetmask(omask); 52716374Skarels } 52816374Skarels 52939838Sbostic void 53027535Skarels retry() 53127535Skarels { 53227535Skarels register struct servtab *sep; 53327535Skarels 53427535Skarels timingout = 0; 53527535Skarels for (sep = servtab; sep; sep = sep->se_next) 53627535Skarels if (sep->se_fd == -1) 53727535Skarels setup(sep); 53827535Skarels } 53927535Skarels 54027535Skarels setup(sep) 54127535Skarels register struct servtab *sep; 54227535Skarels { 54327535Skarels int on = 1; 54427535Skarels 54527535Skarels if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 546*57769Sandrew if (debug) 547*57769Sandrew fprintf(stderr, "socket failed on %s/%s: %s\n", 548*57769Sandrew sep->se_service, sep->se_proto, 549*57769Sandrew strerror(errno)); 55027535Skarels syslog(LOG_ERR, "%s/%s: socket: %m", 55127535Skarels sep->se_service, sep->se_proto); 55227535Skarels return; 55327535Skarels } 55427535Skarels #define turnon(fd, opt) \ 55527535Skarels setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 55627535Skarels if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 55727535Skarels turnon(sep->se_fd, SO_DEBUG) < 0) 55827535Skarels syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 55927535Skarels if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 56027535Skarels syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 56127535Skarels #undef turnon 56246907Sbostic if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 56327535Skarels sizeof (sep->se_ctrladdr)) < 0) { 564*57769Sandrew if (debug) 565*57769Sandrew fprintf(stderr, "bind failed on %s/%s: %s\n", 566*57769Sandrew sep->se_service, sep->se_proto, 567*57769Sandrew strerror(errno)); 56827535Skarels syslog(LOG_ERR, "%s/%s: bind: %m", 56927535Skarels sep->se_service, sep->se_proto); 57027535Skarels (void) close(sep->se_fd); 57127535Skarels sep->se_fd = -1; 57227535Skarels if (!timingout) { 57327535Skarels timingout = 1; 57427535Skarels alarm(RETRYTIME); 57527535Skarels } 57627535Skarels return; 57727535Skarels } 57827535Skarels if (sep->se_socktype == SOCK_STREAM) 57927535Skarels listen(sep->se_fd, 10); 58027535Skarels FD_SET(sep->se_fd, &allsock); 58127535Skarels nsock++; 58227535Skarels if (sep->se_fd > maxsock) 58327535Skarels maxsock = sep->se_fd; 584*57769Sandrew if (debug) { 585*57769Sandrew fprintf(stderr, "registered %s on %d\n", 586*57769Sandrew sep->se_server, sep->se_fd); 587*57769Sandrew } 58827535Skarels } 58927535Skarels 590*57769Sandrew /* 591*57769Sandrew * Finish with a service and its socket. 592*57769Sandrew */ 593*57769Sandrew close_sep(sep) 594*57769Sandrew register struct servtab *sep; 595*57769Sandrew { 596*57769Sandrew if (sep->se_fd >= 0) { 597*57769Sandrew nsock--; 598*57769Sandrew FD_CLR(sep->se_fd, &allsock); 599*57769Sandrew (void) close(sep->se_fd); 600*57769Sandrew sep->se_fd = -1; 601*57769Sandrew } 602*57769Sandrew sep->se_count = 0; 603*57769Sandrew /* 604*57769Sandrew * Don't keep the pid of this running deamon: when reapchild() 605*57769Sandrew * reaps this pid, it would erroneously increment nsock. 606*57769Sandrew */ 607*57769Sandrew if (sep->se_wait > 1) 608*57769Sandrew sep->se_wait = 1; 609*57769Sandrew } 610*57769Sandrew 61116374Skarels struct servtab * 61216374Skarels enter(cp) 61316374Skarels struct servtab *cp; 61416374Skarels { 61516374Skarels register struct servtab *sep; 61632246Sbostic long omask; 61716374Skarels 61816374Skarels sep = (struct servtab *)malloc(sizeof (*sep)); 61916374Skarels if (sep == (struct servtab *)0) { 62016510Sralph syslog(LOG_ERR, "Out of memory."); 62116374Skarels exit(-1); 62216374Skarels } 62316374Skarels *sep = *cp; 62416374Skarels sep->se_fd = -1; 62527535Skarels omask = sigblock(SIGBLOCK); 62616374Skarels sep->se_next = servtab; 62716374Skarels servtab = sep; 62816374Skarels sigsetmask(omask); 62916374Skarels return (sep); 63016374Skarels } 63116374Skarels 63216374Skarels FILE *fconfig = NULL; 63316374Skarels struct servtab serv; 63416374Skarels char line[256]; 635*57769Sandrew char *sskip(), *skip(), *nextline(); 63616374Skarels 63716374Skarels setconfig() 63816374Skarels { 63916374Skarels 64016374Skarels if (fconfig != NULL) { 641*57769Sandrew fseek(fconfig, 0L, SEEK_SET); 64216374Skarels return (1); 64316374Skarels } 64416374Skarels fconfig = fopen(CONFIG, "r"); 64516374Skarels return (fconfig != NULL); 64616374Skarels } 64716374Skarels 64816374Skarels endconfig() 64916374Skarels { 65036603Sbostic if (fconfig) { 65136603Sbostic (void) fclose(fconfig); 65236603Sbostic fconfig = NULL; 65336603Sbostic } 65416374Skarels } 65516374Skarels 65616374Skarels struct servtab * 65716374Skarels getconfigent() 65816374Skarels { 65916374Skarels register struct servtab *sep = &serv; 66016374Skarels int argc; 66146907Sbostic char *cp, *arg, *newstr(); 662*57769Sandrew static char TCPMUX_TOKEN[] = "tcpmux/"; 663*57769Sandrew #define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 66416374Skarels 66526877Skarels more: 666*57769Sandrew while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0')) 66716374Skarels ; 66816374Skarels if (cp == NULL) 66916374Skarels return ((struct servtab *)0); 670*57769Sandrew /* 671*57769Sandrew * clear the static buffer, since some fields (se_ctrladdr, 672*57769Sandrew * for example) don't get initialized here. 673*57769Sandrew */ 674*57769Sandrew bzero((caddr_t)sep, sizeof *sep); 67516374Skarels arg = skip(&cp); 676*57769Sandrew if (cp == NULL) { 677*57769Sandrew /* got an empty line containing just blanks/tabs. */ 678*57769Sandrew goto more; 679*57769Sandrew } 680*57769Sandrew if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 681*57769Sandrew char *c = arg + MUX_LEN; 682*57769Sandrew if (*c == '+') { 683*57769Sandrew sep->se_type = MUXPLUS_TYPE; 684*57769Sandrew c++; 685*57769Sandrew } else 686*57769Sandrew sep->se_type = MUX_TYPE; 687*57769Sandrew sep->se_service = newstr(c); 688*57769Sandrew } else { 689*57769Sandrew sep->se_service = newstr(arg); 690*57769Sandrew sep->se_type = NORM_TYPE; 691*57769Sandrew } 692*57769Sandrew arg = sskip(&cp); 69316374Skarels if (strcmp(arg, "stream") == 0) 69416374Skarels sep->se_socktype = SOCK_STREAM; 69516374Skarels else if (strcmp(arg, "dgram") == 0) 69616374Skarels sep->se_socktype = SOCK_DGRAM; 69716374Skarels else if (strcmp(arg, "rdm") == 0) 69816374Skarels sep->se_socktype = SOCK_RDM; 69916374Skarels else if (strcmp(arg, "seqpacket") == 0) 70016374Skarels sep->se_socktype = SOCK_SEQPACKET; 70116374Skarels else if (strcmp(arg, "raw") == 0) 70216374Skarels sep->se_socktype = SOCK_RAW; 70316374Skarels else 70416374Skarels sep->se_socktype = -1; 705*57769Sandrew sep->se_proto = newstr(sskip(&cp)); 706*57769Sandrew arg = sskip(&cp); 70716374Skarels sep->se_wait = strcmp(arg, "wait") == 0; 708*57769Sandrew if (ISMUX(sep)) { 709*57769Sandrew /* 710*57769Sandrew * Silently enforce "nowait" for TCPMUX services since 711*57769Sandrew * they don't have an assigned port to listen on. 712*57769Sandrew */ 713*57769Sandrew sep->se_wait = 0; 714*57769Sandrew 715*57769Sandrew if (strcmp(sep->se_proto, "tcp")) { 716*57769Sandrew syslog(LOG_ERR, 717*57769Sandrew "%s: bad protocol for tcpmux service %s", 718*57769Sandrew CONFIG, sep->se_service); 719*57769Sandrew goto more; 720*57769Sandrew } 721*57769Sandrew if (sep->se_socktype != SOCK_STREAM) { 722*57769Sandrew syslog(LOG_ERR, 723*57769Sandrew "%s: bad socket type for tcpmux service %s", 724*57769Sandrew CONFIG, sep->se_service); 725*57769Sandrew goto more; 726*57769Sandrew } 727*57769Sandrew } 728*57769Sandrew sep->se_user = newstr(sskip(&cp)); 729*57769Sandrew sep->se_server = newstr(sskip(&cp)); 73026877Skarels if (strcmp(sep->se_server, "internal") == 0) { 73126877Skarels register struct biltin *bi; 73226877Skarels 73326877Skarels for (bi = biltins; bi->bi_service; bi++) 73426877Skarels if (bi->bi_socktype == sep->se_socktype && 73526877Skarels strcmp(bi->bi_service, sep->se_service) == 0) 73626877Skarels break; 73726877Skarels if (bi->bi_service == 0) { 738*57769Sandrew syslog(LOG_ERR, "internal service %s unknown", 73926877Skarels sep->se_service); 74026877Skarels goto more; 74126877Skarels } 74226877Skarels sep->se_bi = bi; 74326877Skarels sep->se_wait = bi->bi_wait; 74429794Skarels } else 74529794Skarels sep->se_bi = NULL; 74616374Skarels argc = 0; 74716374Skarels for (arg = skip(&cp); cp; arg = skip(&cp)) 74816374Skarels if (argc < MAXARGV) 74946907Sbostic sep->se_argv[argc++] = newstr(arg); 75016374Skarels while (argc <= MAXARGV) 75116374Skarels sep->se_argv[argc++] = NULL; 75216374Skarels return (sep); 75316374Skarels } 75416374Skarels 75516374Skarels freeconfig(cp) 75616374Skarels register struct servtab *cp; 75716374Skarels { 75816374Skarels int i; 75916374Skarels 76016374Skarels if (cp->se_service) 76116374Skarels free(cp->se_service); 76216374Skarels if (cp->se_proto) 76316374Skarels free(cp->se_proto); 76426921Slepreau if (cp->se_user) 76526921Slepreau free(cp->se_user); 76616374Skarels if (cp->se_server) 76716374Skarels free(cp->se_server); 76816374Skarels for (i = 0; i < MAXARGV; i++) 76916374Skarels if (cp->se_argv[i]) 77016374Skarels free(cp->se_argv[i]); 77116374Skarels } 77216374Skarels 773*57769Sandrew 774*57769Sandrew /* 775*57769Sandrew * Safe skip - if skip returns null, log a syntax error in the 776*57769Sandrew * configuration file and exit. 777*57769Sandrew */ 77816374Skarels char * 779*57769Sandrew sskip(cpp) 780*57769Sandrew char **cpp; 781*57769Sandrew { 782*57769Sandrew register char *cp; 783*57769Sandrew 784*57769Sandrew cp = skip(cpp); 785*57769Sandrew if (cp == NULL) { 786*57769Sandrew syslog(LOG_ERR, "%s: syntax error", CONFIG); 787*57769Sandrew exit(-1); 788*57769Sandrew } 789*57769Sandrew return (cp); 790*57769Sandrew } 791*57769Sandrew 792*57769Sandrew char * 79316374Skarels skip(cpp) 79416374Skarels char **cpp; 79516374Skarels { 79616374Skarels register char *cp = *cpp; 79716374Skarels char *start; 79816374Skarels 79916374Skarels again: 80016374Skarels while (*cp == ' ' || *cp == '\t') 80116374Skarels cp++; 80216374Skarels if (*cp == '\0') { 80343455Sbostic int c; 80416374Skarels 80516374Skarels c = getc(fconfig); 80636603Sbostic (void) ungetc(c, fconfig); 80716374Skarels if (c == ' ' || c == '\t') 80816374Skarels if (cp = nextline(fconfig)) 80916374Skarels goto again; 81016374Skarels *cpp = (char *)0; 81116374Skarels return ((char *)0); 81216374Skarels } 81316374Skarels start = cp; 81416374Skarels while (*cp && *cp != ' ' && *cp != '\t') 81516374Skarels cp++; 81616374Skarels if (*cp != '\0') 81716374Skarels *cp++ = '\0'; 81816374Skarels *cpp = cp; 81916374Skarels return (start); 82016374Skarels } 82116374Skarels 82216374Skarels char * 82316374Skarels nextline(fd) 82416374Skarels FILE *fd; 82516374Skarels { 82616374Skarels char *cp; 82716374Skarels 82826921Slepreau if (fgets(line, sizeof (line), fd) == NULL) 82916374Skarels return ((char *)0); 83016374Skarels cp = index(line, '\n'); 83116374Skarels if (cp) 83216374Skarels *cp = '\0'; 83316374Skarels return (line); 83416374Skarels } 83516374Skarels 83616374Skarels char * 83746907Sbostic newstr(cp) 83816374Skarels char *cp; 83916374Skarels { 84046973Skarels if (cp = strdup(cp ? cp : "")) 84146907Sbostic return(cp); 84246973Skarels syslog(LOG_ERR, "strdup: %m"); 84346907Sbostic exit(-1); 84416374Skarels } 84526877Skarels 84626877Skarels setproctitle(a, s) 84726877Skarels char *a; 84826877Skarels int s; 84926877Skarels { 85026877Skarels int size; 85126877Skarels register char *cp; 85226877Skarels struct sockaddr_in sin; 85326877Skarels char buf[80]; 85426877Skarels 85526877Skarels cp = Argv[0]; 85626877Skarels size = sizeof(sin); 85746907Sbostic if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 85832442Sbostic (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 85926877Skarels else 86032442Sbostic (void) sprintf(buf, "-%s", a); 86126877Skarels strncpy(cp, buf, LastArg - cp); 86226877Skarels cp += strlen(cp); 86326877Skarels while (cp < LastArg) 86426877Skarels *cp++ = ' '; 86526877Skarels } 86626877Skarels 86726877Skarels /* 86826877Skarels * Internet services provided internally by inetd: 86926877Skarels */ 87049986Skarels #define BUFSIZE 8192 87126877Skarels 87226877Skarels /* ARGSUSED */ 87326877Skarels echo_stream(s, sep) /* Echo service -- echo data back */ 87426877Skarels int s; 87526877Skarels struct servtab *sep; 87626877Skarels { 87738573Skarels char buffer[BUFSIZE]; 87826877Skarels int i; 87926877Skarels 88032091Skarels setproctitle(sep->se_service, s); 88126877Skarels while ((i = read(s, buffer, sizeof(buffer))) > 0 && 88226877Skarels write(s, buffer, i) > 0) 88326877Skarels ; 88426877Skarels exit(0); 88526877Skarels } 88626877Skarels 88726877Skarels /* ARGSUSED */ 88826877Skarels echo_dg(s, sep) /* Echo service -- echo data back */ 88926877Skarels int s; 89026877Skarels struct servtab *sep; 89126877Skarels { 89238573Skarels char buffer[BUFSIZE]; 89326877Skarels int i, size; 89426877Skarels struct sockaddr sa; 89526877Skarels 89626877Skarels size = sizeof(sa); 89726877Skarels if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) 89826877Skarels return; 89926877Skarels (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); 90026877Skarels } 90126877Skarels 90226877Skarels /* ARGSUSED */ 90326877Skarels discard_stream(s, sep) /* Discard service -- ignore data */ 90426877Skarels int s; 90526877Skarels struct servtab *sep; 90626877Skarels { 90749986Skarels int ret; 90838573Skarels char buffer[BUFSIZE]; 90926877Skarels 91032091Skarels setproctitle(sep->se_service, s); 91126877Skarels while (1) { 91249986Skarels while ((ret = read(s, buffer, sizeof(buffer))) > 0) 91326877Skarels ; 91449986Skarels if (ret == 0 || errno != EINTR) 91526877Skarels break; 91626877Skarels } 91726877Skarels exit(0); 91826877Skarels } 91926877Skarels 92026877Skarels /* ARGSUSED */ 92126877Skarels discard_dg(s, sep) /* Discard service -- ignore data */ 92226877Skarels int s; 92326877Skarels struct servtab *sep; 92426877Skarels { 92538573Skarels char buffer[BUFSIZE]; 92626877Skarels 92726877Skarels (void) read(s, buffer, sizeof(buffer)); 92826877Skarels } 92926877Skarels 93026877Skarels #include <ctype.h> 93126877Skarels #define LINESIZ 72 93226877Skarels char ring[128]; 93326877Skarels char *endring; 93426877Skarels 93526877Skarels initring() 93626877Skarels { 93726877Skarels register int i; 93826877Skarels 93926877Skarels endring = ring; 94026877Skarels 94126877Skarels for (i = 0; i <= 128; ++i) 94226877Skarels if (isprint(i)) 94326877Skarels *endring++ = i; 94426877Skarels } 94526877Skarels 94626877Skarels /* ARGSUSED */ 94726877Skarels chargen_stream(s, sep) /* Character generator */ 94826877Skarels int s; 94926877Skarels struct servtab *sep; 95026877Skarels { 95132246Sbostic register char *rs; 95232246Sbostic int len; 95326877Skarels char text[LINESIZ+2]; 95426877Skarels 95532091Skarels setproctitle(sep->se_service, s); 95632246Sbostic 95732246Sbostic if (!endring) { 95826877Skarels initring(); 95932246Sbostic rs = ring; 96032246Sbostic } 96126877Skarels 96232246Sbostic text[LINESIZ] = '\r'; 96332246Sbostic text[LINESIZ + 1] = '\n'; 96432246Sbostic for (rs = ring;;) { 96532246Sbostic if ((len = endring - rs) >= LINESIZ) 96632246Sbostic bcopy(rs, text, LINESIZ); 96732246Sbostic else { 96832246Sbostic bcopy(rs, text, len); 96932246Sbostic bcopy(ring, text + len, LINESIZ - len); 97032246Sbostic } 97132246Sbostic if (++rs == endring) 97226877Skarels rs = ring; 97332246Sbostic if (write(s, text, sizeof(text)) != sizeof(text)) 97426877Skarels break; 97526877Skarels } 97626877Skarels exit(0); 97726877Skarels } 97826877Skarels 97926877Skarels /* ARGSUSED */ 98026877Skarels chargen_dg(s, sep) /* Character generator */ 98126877Skarels int s; 98226877Skarels struct servtab *sep; 98326877Skarels { 98432246Sbostic struct sockaddr sa; 98532246Sbostic static char *rs; 98632246Sbostic int len, size; 98726877Skarels char text[LINESIZ+2]; 98826877Skarels 98932246Sbostic if (endring == 0) { 99026877Skarels initring(); 99132246Sbostic rs = ring; 99232246Sbostic } 99326877Skarels 99426877Skarels size = sizeof(sa); 99526877Skarels if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) 99626877Skarels return; 99732246Sbostic 99832246Sbostic if ((len = endring - rs) >= LINESIZ) 99932246Sbostic bcopy(rs, text, LINESIZ); 100032246Sbostic else { 100132246Sbostic bcopy(rs, text, len); 100232246Sbostic bcopy(ring, text + len, LINESIZ - len); 100332246Sbostic } 100432246Sbostic if (++rs == endring) 100526877Skarels rs = ring; 100632246Sbostic text[LINESIZ] = '\r'; 100732246Sbostic text[LINESIZ + 1] = '\n'; 100826877Skarels (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa)); 100926877Skarels } 101026877Skarels 101126877Skarels /* 101226877Skarels * Return a machine readable date and time, in the form of the 101326877Skarels * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 101426877Skarels * returns the number of seconds since midnight, Jan 1, 1970, 101526877Skarels * we must add 2208988800 seconds to this figure to make up for 101626877Skarels * some seventy years Bell Labs was asleep. 101726877Skarels */ 101826877Skarels 101926877Skarels long 102026877Skarels machtime() 102126877Skarels { 102226877Skarels struct timeval tv; 102326877Skarels 102426921Slepreau if (gettimeofday(&tv, (struct timezone *)0) < 0) { 1025*57769Sandrew if (debug) 1026*57769Sandrew fprintf(stderr, "Unable to get time of day\n"); 102726921Slepreau return (0L); 102826877Skarels } 102926877Skarels return (htonl((long)tv.tv_sec + 2208988800)); 103026877Skarels } 103126877Skarels 103226877Skarels /* ARGSUSED */ 103326877Skarels machtime_stream(s, sep) 103426877Skarels int s; 103526877Skarels struct servtab *sep; 103626877Skarels { 103726877Skarels long result; 103826877Skarels 103926877Skarels result = machtime(); 104026877Skarels (void) write(s, (char *) &result, sizeof(result)); 104126877Skarels } 104226877Skarels 104326877Skarels /* ARGSUSED */ 104426877Skarels machtime_dg(s, sep) 104526877Skarels int s; 104626877Skarels struct servtab *sep; 104726877Skarels { 104826877Skarels long result; 104926877Skarels struct sockaddr sa; 105026877Skarels int size; 105126877Skarels 105226877Skarels size = sizeof(sa); 105326921Slepreau if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0) 105426877Skarels return; 105526877Skarels result = machtime(); 105626877Skarels (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa)); 105726877Skarels } 105826877Skarels 105926877Skarels /* ARGSUSED */ 106026877Skarels daytime_stream(s, sep) /* Return human-readable time of day */ 106126877Skarels int s; 106226877Skarels struct servtab *sep; 106326877Skarels { 106426877Skarels char buffer[256]; 1065*57769Sandrew time_t clock; 106626877Skarels 106726877Skarels clock = time((time_t *) 0); 106826877Skarels 106932442Sbostic (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 107026921Slepreau (void) write(s, buffer, strlen(buffer)); 107126877Skarels } 107226877Skarels 107326877Skarels /* ARGSUSED */ 107426877Skarels daytime_dg(s, sep) /* Return human-readable time of day */ 107526877Skarels int s; 107626877Skarels struct servtab *sep; 107726877Skarels { 107826877Skarels char buffer[256]; 1079*57769Sandrew time_t clock; 108026877Skarels struct sockaddr sa; 108126877Skarels int size; 108226877Skarels 108326877Skarels clock = time((time_t *) 0); 108426877Skarels 108526877Skarels size = sizeof(sa); 108626877Skarels if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) 108726877Skarels return; 108832442Sbostic (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 108926877Skarels (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa)); 109026877Skarels } 109129794Skarels 109229794Skarels /* 109329794Skarels * print_service: 109429794Skarels * Dump relevant information to stderr 109529794Skarels */ 109629794Skarels print_service(action, sep) 109729794Skarels char *action; 109829794Skarels struct servtab *sep; 109929794Skarels { 110029794Skarels fprintf(stderr, 110129794Skarels "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n", 110229794Skarels action, sep->se_service, sep->se_proto, 110336603Sbostic sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server); 110429794Skarels } 1105*57769Sandrew 1106*57769Sandrew /* 1107*57769Sandrew * Based on TCPMUX.C by Mark K. Lottor November 1988 1108*57769Sandrew * sri-nic::ps:<mkl>tcpmux.c 1109*57769Sandrew */ 1110*57769Sandrew 1111*57769Sandrew 1112*57769Sandrew static int /* # of characters upto \r,\n or \0 */ 1113*57769Sandrew getline(fd, buf, len) 1114*57769Sandrew int fd; 1115*57769Sandrew char *buf; 1116*57769Sandrew int len; 1117*57769Sandrew { 1118*57769Sandrew int count = 0, n; 1119*57769Sandrew 1120*57769Sandrew do { 1121*57769Sandrew n = read(fd, buf, len-count); 1122*57769Sandrew if (n == 0) 1123*57769Sandrew return count; 1124*57769Sandrew if (n < 0) 1125*57769Sandrew return (-1); 1126*57769Sandrew while (--n >= 0) { 1127*57769Sandrew if (*buf == '\r' || *buf == '\n' || *buf == '\0') 1128*57769Sandrew return count; 1129*57769Sandrew count++; 1130*57769Sandrew buf++; 1131*57769Sandrew } 1132*57769Sandrew } while (count < len); 1133*57769Sandrew return (count); 1134*57769Sandrew } 1135*57769Sandrew 1136*57769Sandrew #define MAX_SERV_LEN (256+2) /* 2 bytes for \r\n */ 1137*57769Sandrew 1138*57769Sandrew #define strwrite(fd, buf) (void) write(fd, buf, sizeof(buf)-1) 1139*57769Sandrew 1140*57769Sandrew struct servtab * 1141*57769Sandrew tcpmux(s) 1142*57769Sandrew int s; 1143*57769Sandrew { 1144*57769Sandrew register struct servtab *sep; 1145*57769Sandrew char service[MAX_SERV_LEN+1]; 1146*57769Sandrew int len; 1147*57769Sandrew 1148*57769Sandrew /* Get requested service name */ 1149*57769Sandrew if ((len = getline(s, service, MAX_SERV_LEN)) < 0) { 1150*57769Sandrew strwrite(s, "-Error reading service name\r\n"); 1151*57769Sandrew return(NULL); 1152*57769Sandrew } 1153*57769Sandrew service[len] = '\0'; 1154*57769Sandrew 1155*57769Sandrew if (debug) 1156*57769Sandrew fprintf(stderr, "tcpmux: someone wants %s\n", service); 1157*57769Sandrew 1158*57769Sandrew /* 1159*57769Sandrew * Help is a required command, and lists available services, 1160*57769Sandrew * one per line. 1161*57769Sandrew */ 1162*57769Sandrew if (!strcasecmp(service,"help")) { 1163*57769Sandrew for (sep = servtab; sep; sep = sep->se_next) { 1164*57769Sandrew if (!ISMUX(sep)) 1165*57769Sandrew continue; 1166*57769Sandrew (void) write(s, sep->se_service, strlen(sep->se_service)); 1167*57769Sandrew strwrite(s, "\r\n"); 1168*57769Sandrew } 1169*57769Sandrew return(NULL); 1170*57769Sandrew } 1171*57769Sandrew 1172*57769Sandrew /* Try matching a service in inetd.conf with the request */ 1173*57769Sandrew for (sep = servtab; sep; sep = sep->se_next) { 1174*57769Sandrew if (!ISMUX(sep)) 1175*57769Sandrew continue; 1176*57769Sandrew if (!strcasecmp(service,sep->se_service)) { 1177*57769Sandrew if (ISMUXPLUS(sep)) { 1178*57769Sandrew strwrite(s, "+Go\r\n"); 1179*57769Sandrew } 1180*57769Sandrew return(sep); 1181*57769Sandrew } 1182*57769Sandrew } 1183*57769Sandrew strwrite(s, "-Service not available\r\n"); 1184*57769Sandrew return(NULL); 1185*57769Sandrew } 1186