121134Sdist /* 221134Sdist * Copyright (c) 1983 Regents of the University of California. 333136Sbostic * All rights reserved. 433136Sbostic * 533136Sbostic * Redistribution and use in source and binary forms are permitted 634778Sbostic * provided that the above copyright notice and this paragraph are 734778Sbostic * duplicated in all such forms and that any documentation, 834778Sbostic * advertising materials, and other materials related to such 934778Sbostic * distribution and use acknowledge that the software was developed 1034778Sbostic * by the University of California, Berkeley. The name of the 1134778Sbostic * University may not be used to endorse or promote products derived 1234778Sbostic * from this software without specific prior written permission. 1334778Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434778Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534778Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621134Sdist */ 1721134Sdist 1816374Skarels #ifndef lint 1921134Sdist char copyright[] = 2021134Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 2121134Sdist All rights reserved.\n"; 2233136Sbostic #endif /* not lint */ 2316374Skarels 2421134Sdist #ifndef lint 25*42067Sbostic static char sccsid[] = "@(#)inetd.c 5.21 (Berkeley) 05/15/90"; 2633136Sbostic #endif /* not lint */ 2721134Sdist 2816374Skarels /* 2916374Skarels * Inetd - Internet super-server 3016374Skarels * 3116374Skarels * This program invokes all internet services as needed. 3216374Skarels * connection-oriented services are invoked each time a 3316374Skarels * connection is made, by creating a process. This process 3416374Skarels * is passed the connection as file descriptor 0 and is 3516374Skarels * expected to do a getpeername to find out the source host 3616374Skarels * and port. 3716374Skarels * 3816374Skarels * Datagram oriented services are invoked when a datagram 3916374Skarels * arrives; a process is created and passed a pending message 4016374Skarels * on file descriptor 0. Datagram servers may either connect 4116374Skarels * to their peer, freeing up the original socket for inetd 4216374Skarels * to receive further messages on, or ``take over the socket'', 4316374Skarels * processing all arriving datagrams and, eventually, timing 4416374Skarels * out. The first type of server is said to be ``multi-threaded''; 4516374Skarels * the second type of server ``single-threaded''. 4616374Skarels * 4716374Skarels * Inetd uses a configuration file which is read at startup 4816374Skarels * and, possibly, at some later time in response to a hangup signal. 4916374Skarels * The configuration file is ``free format'' with fields given in the 5016374Skarels * order shown below. Continuation lines for an entry must being with 5116374Skarels * a space or tab. All fields must be present in each entry. 5216374Skarels * 5316374Skarels * service name must be in /etc/services 5416374Skarels * socket type stream/dgram/raw/rdm/seqpacket 5516374Skarels * protocol must be in /etc/protocols 5616374Skarels * wait/nowait single-threaded/multi-threaded 5717346Sbloom * user user to run daemon as 5816374Skarels * server program full path name 5940740Sbostic * server program arguments maximum of MAXARGS (20) 6016374Skarels * 6116374Skarels * Comment lines are indicated by a `#' in column 1. 6216374Skarels */ 6316374Skarels #include <sys/param.h> 6416374Skarels #include <sys/stat.h> 6516374Skarels #include <sys/ioctl.h> 6616374Skarels #include <sys/socket.h> 6716374Skarels #include <sys/file.h> 6816374Skarels #include <sys/wait.h> 6926921Slepreau #include <sys/time.h> 7026921Slepreau #include <sys/resource.h> 7116374Skarels 7216374Skarels #include <netinet/in.h> 7316374Skarels #include <arpa/inet.h> 7416374Skarels 7516374Skarels #include <errno.h> 7616374Skarels #include <signal.h> 7716374Skarels #include <netdb.h> 7816510Sralph #include <syslog.h> 7917346Sbloom #include <pwd.h> 8036603Sbostic #include <stdio.h> 81*42067Sbostic #include <string.h> 8237282Sbostic #include "pathnames.h" 8316374Skarels 8427535Skarels #define TOOMANY 40 /* don't start more than TOOMANY */ 8527535Skarels #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 8627535Skarels #define RETRYTIME (60*10) /* retry after bind or server fail */ 8727535Skarels 8827535Skarels #define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 8927535Skarels 9016374Skarels extern int errno; 9116374Skarels 9239838Sbostic void config(), reapchild(), retry(); 9316374Skarels char *index(); 9416374Skarels char *malloc(); 9516374Skarels 9616374Skarels int debug = 0; 9725046Skarels int nsock, maxsock; 9825046Skarels fd_set allsock; 9916374Skarels int options; 10027535Skarels int timingout; 10116374Skarels struct servent *sp; 10216374Skarels 10316374Skarels struct servtab { 10416374Skarels char *se_service; /* name of service */ 10516374Skarels int se_socktype; /* type of socket to use */ 10616374Skarels char *se_proto; /* protocol used */ 10716374Skarels short se_wait; /* single threaded server */ 10816374Skarels short se_checked; /* looked at during merge */ 10917346Sbloom char *se_user; /* user name to run as */ 11026877Skarels struct biltin *se_bi; /* if built-in, description */ 11116374Skarels char *se_server; /* server program */ 11240740Sbostic #define MAXARGV 20 11316374Skarels char *se_argv[MAXARGV+1]; /* program arguments */ 11416374Skarels int se_fd; /* open descriptor */ 11516374Skarels struct sockaddr_in se_ctrladdr;/* bound address */ 11627535Skarels int se_count; /* number started since se_time */ 11727535Skarels struct timeval se_time; /* start of se_count */ 11816374Skarels struct servtab *se_next; 11916374Skarels } *servtab; 12016374Skarels 12126877Skarels int echo_stream(), discard_stream(), machtime_stream(); 12226877Skarels int daytime_stream(), chargen_stream(); 12326877Skarels int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg(); 12426877Skarels 12526877Skarels struct biltin { 12626877Skarels char *bi_service; /* internally provided service name */ 12726877Skarels int bi_socktype; /* type of socket supported */ 12826877Skarels short bi_fork; /* 1 if should fork before call */ 12926877Skarels short bi_wait; /* 1 if should wait for child */ 13026877Skarels int (*bi_fn)(); /* function which performs it */ 13126877Skarels } biltins[] = { 13226877Skarels /* Echo received data */ 13326877Skarels "echo", SOCK_STREAM, 1, 0, echo_stream, 13426877Skarels "echo", SOCK_DGRAM, 0, 0, echo_dg, 13526877Skarels 13626877Skarels /* Internet /dev/null */ 13726877Skarels "discard", SOCK_STREAM, 1, 0, discard_stream, 13826877Skarels "discard", SOCK_DGRAM, 0, 0, discard_dg, 13926877Skarels 14026877Skarels /* Return 32 bit time since 1970 */ 14126877Skarels "time", SOCK_STREAM, 0, 0, machtime_stream, 14226877Skarels "time", SOCK_DGRAM, 0, 0, machtime_dg, 14326877Skarels 14426877Skarels /* Return human-readable time */ 14526877Skarels "daytime", SOCK_STREAM, 0, 0, daytime_stream, 14626877Skarels "daytime", SOCK_DGRAM, 0, 0, daytime_dg, 14726877Skarels 14826877Skarels /* Familiar character generator */ 14926877Skarels "chargen", SOCK_STREAM, 1, 0, chargen_stream, 15026877Skarels "chargen", SOCK_DGRAM, 0, 0, chargen_dg, 15126877Skarels 0 15226877Skarels }; 15326877Skarels 15426877Skarels #define NUMINT (sizeof(intab) / sizeof(struct inent)) 15537282Sbostic char *CONFIG = _PATH_INETDCONF; 15626877Skarels char **Argv; 15726877Skarels char *LastArg; 15816374Skarels 15926877Skarels main(argc, argv, envp) 16016374Skarels int argc; 16126877Skarels char *argv[], *envp[]; 16216374Skarels { 16336603Sbostic extern char *optarg; 16436603Sbostic extern int optind; 16516374Skarels register struct servtab *sep; 16617346Sbloom register struct passwd *pwd; 16736603Sbostic register int tmpint; 16827535Skarels struct sigvec sv; 16936603Sbostic int ch, pid, dofork; 17036603Sbostic char buf[50]; 17116374Skarels 17226877Skarels Argv = argv; 17326877Skarels if (envp == 0 || *envp == 0) 17426877Skarels envp = argv; 17526877Skarels while (*envp) 17626877Skarels envp++; 17726877Skarels LastArg = envp[-1] + strlen(envp[-1]); 17816374Skarels 17936603Sbostic while ((ch = getopt(argc, argv, "d")) != EOF) 18036603Sbostic switch(ch) { 18116374Skarels case 'd': 18216374Skarels debug = 1; 18316374Skarels options |= SO_DEBUG; 18416374Skarels break; 18536603Sbostic case '?': 18616374Skarels default: 18736603Sbostic fprintf(stderr, "usage: inetd [-d]"); 18836603Sbostic exit(1); 18916374Skarels } 19036603Sbostic argc -= optind; 19136603Sbostic argv += optind; 19236603Sbostic 19316374Skarels if (argc > 0) 19416374Skarels CONFIG = argv[0]; 19532403Skarels if (debug == 0) { 19632403Skarels if (fork()) 19732403Skarels exit(0); 19836603Sbostic for (tmpint = 0; tmpint < 10; tmpint++) 19936603Sbostic (void) close(tmpint); 20032403Skarels (void) open("/", O_RDONLY); 20132403Skarels (void) dup2(0, 1); 20232403Skarels (void) dup2(0, 2); 20337965Sbostic tmpint = open(_PATH_TTY, O_RDWR); 20436603Sbostic if (tmpint > 0) { 20536603Sbostic ioctl(tmpint, TIOCNOTTY, (char *)0); 20636603Sbostic close(tmpint); 20732403Skarels } 20832403Skarels (void) setpgrp(0, 0); 20936603Sbostic (void) signal(SIGTSTP, SIG_IGN); 21036603Sbostic (void) signal(SIGTTIN, SIG_IGN); 21136603Sbostic (void) signal(SIGTTOU, SIG_IGN); 21216374Skarels } 21327535Skarels openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 21427535Skarels bzero((char *)&sv, sizeof(sv)); 21527535Skarels sv.sv_mask = SIGBLOCK; 21627535Skarels sv.sv_handler = retry; 21727535Skarels sigvec(SIGALRM, &sv, (struct sigvec *)0); 21816374Skarels config(); 21927535Skarels sv.sv_handler = config; 22027535Skarels sigvec(SIGHUP, &sv, (struct sigvec *)0); 22127535Skarels sv.sv_handler = reapchild; 22227535Skarels sigvec(SIGCHLD, &sv, (struct sigvec *)0); 22327535Skarels 22436603Sbostic { 22536603Sbostic /* space for daemons to overwrite environment for ps */ 22636603Sbostic #define DUMMYSIZE 100 22736603Sbostic char dummy[DUMMYSIZE]; 22836603Sbostic 22936603Sbostic (void)memset(dummy, 'x', sizeof(DUMMYSIZE) - 1); 23036603Sbostic dummy[DUMMYSIZE - 1] = '\0'; 23136603Sbostic (void)setenv("inetd_dummy", dummy, 1); 23236603Sbostic } 23336603Sbostic 23416374Skarels for (;;) { 23536603Sbostic int n, ctrl; 23627535Skarels fd_set readable; 23716374Skarels 23832091Skarels if (nsock == 0) { 23932091Skarels (void) sigblock(SIGBLOCK); 24032091Skarels while (nsock == 0) 24132246Sbostic sigpause(0L); 24232246Sbostic (void) sigsetmask(0L); 24332091Skarels } 24427535Skarels readable = allsock; 24527535Skarels if ((n = select(maxsock + 1, &readable, (fd_set *)0, 24627535Skarels (fd_set *)0, (struct timeval *)0)) <= 0) { 24727535Skarels if (n < 0 && errno != EINTR) 24832091Skarels syslog(LOG_WARNING, "select: %m\n"); 24927535Skarels sleep(1); 25027535Skarels continue; 25127535Skarels } 25227535Skarels for (sep = servtab; n && sep; sep = sep->se_next) 25327535Skarels if (FD_ISSET(sep->se_fd, &readable)) { 25427535Skarels n--; 25516374Skarels if (debug) 25616374Skarels fprintf(stderr, "someone wants %s\n", sep->se_service); 25725046Skarels if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) { 25827535Skarels ctrl = accept(sep->se_fd, (struct sockaddr *)0, 25927535Skarels (int *)0); 26016510Sralph if (debug) 26116510Sralph fprintf(stderr, "accept, ctrl %d\n", ctrl); 26216374Skarels if (ctrl < 0) { 26316374Skarels if (errno == EINTR) 26416374Skarels continue; 26516510Sralph syslog(LOG_WARNING, "accept: %m"); 26616374Skarels continue; 26716374Skarels } 26816374Skarels } else 26916374Skarels ctrl = sep->se_fd; 27027535Skarels (void) sigblock(SIGBLOCK); 27126877Skarels pid = 0; 27227535Skarels dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork); 27327535Skarels if (dofork) { 27427535Skarels if (sep->se_count++ == 0) 27527535Skarels (void)gettimeofday(&sep->se_time, 27627535Skarels (struct timezone *)0); 27727535Skarels else if (sep->se_count >= TOOMANY) { 27827535Skarels struct timeval now; 27927535Skarels 28027535Skarels (void)gettimeofday(&now, (struct timezone *)0); 28127535Skarels if (now.tv_sec - sep->se_time.tv_sec > 28227535Skarels CNT_INTVL) { 28327535Skarels sep->se_time = now; 28427535Skarels sep->se_count = 1; 28527535Skarels } else { 28627535Skarels syslog(LOG_ERR, 28727535Skarels "%s/%s server failing (looping), service terminated\n", 28827535Skarels sep->se_service, sep->se_proto); 28927535Skarels FD_CLR(sep->se_fd, &allsock); 29027535Skarels (void) close(sep->se_fd); 29127535Skarels sep->se_fd = -1; 29227535Skarels sep->se_count = 0; 29327535Skarels nsock--; 29432246Sbostic sigsetmask(0L); 29527535Skarels if (!timingout) { 29627535Skarels timingout = 1; 29727535Skarels alarm(RETRYTIME); 29827535Skarels } 29927535Skarels continue; 30027535Skarels } 30127535Skarels } 30226877Skarels pid = fork(); 30327535Skarels } 30416374Skarels if (pid < 0) { 30525046Skarels if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 30616374Skarels close(ctrl); 30732246Sbostic sigsetmask(0L); 30816374Skarels sleep(1); 30916374Skarels continue; 31016374Skarels } 31127535Skarels if (pid && sep->se_wait) { 31216374Skarels sep->se_wait = pid; 31327535Skarels FD_CLR(sep->se_fd, &allsock); 31425046Skarels nsock--; 31516374Skarels } 31632246Sbostic sigsetmask(0L); 31716374Skarels if (pid == 0) { 31832403Skarels if (debug) { 31936603Sbostic if (dofork && 32037965Sbostic (tmpint = open(_PATH_TTY, O_RDWR)) > 0) { 32136603Sbostic ioctl(tmpint, TIOCNOTTY, 0); 32236603Sbostic close(tmpint); 32336603Sbostic } 32436603Sbostic (void) setpgrp(0, 0); 32536603Sbostic (void) signal(SIGTSTP, SIG_IGN); 32636603Sbostic (void) signal(SIGTTIN, SIG_IGN); 32736603Sbostic (void) signal(SIGTTOU, SIG_IGN); 32816374Skarels } 32927535Skarels if (dofork) 33036603Sbostic for (tmpint = getdtablesize(); --tmpint > 2; ) 33136603Sbostic if (tmpint != ctrl) 33236603Sbostic close(tmpint); 33326877Skarels if (sep->se_bi) 33426877Skarels (*sep->se_bi->bi_fn)(ctrl, sep); 33526877Skarels else { 33626877Skarels dup2(ctrl, 0); 33726877Skarels close(ctrl); 33826877Skarels dup2(0, 1); 33926877Skarels dup2(0, 2); 34026877Skarels if ((pwd = getpwnam(sep->se_user)) == NULL) { 34126877Skarels syslog(LOG_ERR, 34226877Skarels "getpwnam: %s: No such user", 34326877Skarels sep->se_user); 34427535Skarels if (sep->se_socktype != SOCK_STREAM) 34527535Skarels recv(0, buf, sizeof (buf), 0); 34626877Skarels _exit(1); 34726877Skarels } 34826877Skarels if (pwd->pw_uid) { 34926921Slepreau (void) setgid((gid_t)pwd->pw_gid); 35026877Skarels initgroups(pwd->pw_name, pwd->pw_gid); 35126921Slepreau (void) setuid((uid_t)pwd->pw_uid); 35226877Skarels } 35326877Skarels if (debug) 35426877Skarels fprintf(stderr, "%d execl %s\n", 35526877Skarels getpid(), sep->se_server); 35626877Skarels execv(sep->se_server, sep->se_argv); 35726877Skarels if (sep->se_socktype != SOCK_STREAM) 35826877Skarels recv(0, buf, sizeof (buf), 0); 35926877Skarels syslog(LOG_ERR, "execv %s: %m", sep->se_server); 36026877Skarels _exit(1); 36117346Sbloom } 36216374Skarels } 36325046Skarels if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 36416374Skarels close(ctrl); 36527535Skarels } 36616374Skarels } 36716374Skarels } 36816374Skarels 36939838Sbostic void 37016374Skarels reapchild() 37116374Skarels { 37216374Skarels union wait status; 37316374Skarels int pid; 37416374Skarels register struct servtab *sep; 37516374Skarels 37616374Skarels for (;;) { 37726921Slepreau pid = wait3(&status, WNOHANG, (struct rusage *)0); 37816374Skarels if (pid <= 0) 37916374Skarels break; 38016374Skarels if (debug) 38116374Skarels fprintf(stderr, "%d reaped\n", pid); 38216374Skarels for (sep = servtab; sep; sep = sep->se_next) 38316374Skarels if (sep->se_wait == pid) { 38416374Skarels if (status.w_status) 38516510Sralph syslog(LOG_WARNING, 38616510Sralph "%s: exit status 0x%x", 38716374Skarels sep->se_server, status); 38816374Skarels if (debug) 38916374Skarels fprintf(stderr, "restored %s, fd %d\n", 39016374Skarels sep->se_service, sep->se_fd); 39125046Skarels FD_SET(sep->se_fd, &allsock); 39225046Skarels nsock++; 39316374Skarels sep->se_wait = 1; 39416374Skarels } 39516374Skarels } 39616374Skarels } 39716374Skarels 39839838Sbostic void 39916374Skarels config() 40016374Skarels { 40116374Skarels register struct servtab *sep, *cp, **sepp; 40216374Skarels struct servtab *getconfigent(), *enter(); 40332246Sbostic long omask; 40416374Skarels 40516374Skarels if (!setconfig()) { 40616510Sralph syslog(LOG_ERR, "%s: %m", CONFIG); 40716374Skarels return; 40816374Skarels } 40916374Skarels for (sep = servtab; sep; sep = sep->se_next) 41016374Skarels sep->se_checked = 0; 41116374Skarels while (cp = getconfigent()) { 41216374Skarels for (sep = servtab; sep; sep = sep->se_next) 41316374Skarels if (strcmp(sep->se_service, cp->se_service) == 0 && 41416374Skarels strcmp(sep->se_proto, cp->se_proto) == 0) 41516374Skarels break; 41616374Skarels if (sep != 0) { 41716374Skarels int i; 41816374Skarels 41927535Skarels omask = sigblock(SIGBLOCK); 42040745Sbostic /* 42140745Sbostic * sep->se_wait may be holding the pid of a daemon 42240745Sbostic * that we're waiting for. If so, don't overwrite 42340745Sbostic * it unless the config file explicitly says don't 42440745Sbostic * wait. 42540745Sbostic */ 42640745Sbostic if (cp->se_bi == 0 && 42740745Sbostic (sep->se_wait == 1 || cp->se_wait == 0)) 42827535Skarels sep->se_wait = cp->se_wait; 42916374Skarels #define SWAP(a, b) { char *c = a; a = b; b = c; } 43026921Slepreau if (cp->se_user) 43126921Slepreau SWAP(sep->se_user, cp->se_user); 43216374Skarels if (cp->se_server) 43316374Skarels SWAP(sep->se_server, cp->se_server); 43416374Skarels for (i = 0; i < MAXARGV; i++) 43516374Skarels SWAP(sep->se_argv[i], cp->se_argv[i]); 43616374Skarels sigsetmask(omask); 43716374Skarels freeconfig(cp); 43829794Skarels if (debug) 43929794Skarels print_service("REDO", sep); 44029794Skarels } else { 44116374Skarels sep = enter(cp); 44229794Skarels if (debug) 44329794Skarels print_service("ADD ", sep); 44429794Skarels } 44516374Skarels sep->se_checked = 1; 44616374Skarels sp = getservbyname(sep->se_service, sep->se_proto); 44716374Skarels if (sp == 0) { 44816510Sralph syslog(LOG_ERR, "%s/%s: unknown service", 44916374Skarels sep->se_service, sep->se_proto); 45016374Skarels continue; 45116374Skarels } 45227535Skarels if (sp->s_port != sep->se_ctrladdr.sin_port) { 45327535Skarels sep->se_ctrladdr.sin_port = sp->s_port; 45427535Skarels if (sep->se_fd != -1) 45527535Skarels (void) close(sep->se_fd); 45627535Skarels sep->se_fd = -1; 45716374Skarels } 45827535Skarels if (sep->se_fd == -1) 45927535Skarels setup(sep); 46016374Skarels } 46116374Skarels endconfig(); 46216374Skarels /* 46316374Skarels * Purge anything not looked at above. 46416374Skarels */ 46527535Skarels omask = sigblock(SIGBLOCK); 46616374Skarels sepp = &servtab; 46716374Skarels while (sep = *sepp) { 46816374Skarels if (sep->se_checked) { 46916374Skarels sepp = &sep->se_next; 47016374Skarels continue; 47116374Skarels } 47216374Skarels *sepp = sep->se_next; 47316374Skarels if (sep->se_fd != -1) { 47425046Skarels FD_CLR(sep->se_fd, &allsock); 47525046Skarels nsock--; 47616374Skarels (void) close(sep->se_fd); 47716374Skarels } 47829794Skarels if (debug) 47929794Skarels print_service("FREE", sep); 48016374Skarels freeconfig(sep); 48116374Skarels free((char *)sep); 48216374Skarels } 48316374Skarels (void) sigsetmask(omask); 48416374Skarels } 48516374Skarels 48639838Sbostic void 48727535Skarels retry() 48827535Skarels { 48927535Skarels register struct servtab *sep; 49027535Skarels 49127535Skarels timingout = 0; 49227535Skarels for (sep = servtab; sep; sep = sep->se_next) 49327535Skarels if (sep->se_fd == -1) 49427535Skarels setup(sep); 49527535Skarels } 49627535Skarels 49727535Skarels setup(sep) 49827535Skarels register struct servtab *sep; 49927535Skarels { 50027535Skarels int on = 1; 50127535Skarels 50227535Skarels if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 50327535Skarels syslog(LOG_ERR, "%s/%s: socket: %m", 50427535Skarels sep->se_service, sep->se_proto); 50527535Skarels return; 50627535Skarels } 50727535Skarels #define turnon(fd, opt) \ 50827535Skarels setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 50927535Skarels if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 51027535Skarels turnon(sep->se_fd, SO_DEBUG) < 0) 51127535Skarels syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 51227535Skarels if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 51327535Skarels syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 51427535Skarels #undef turnon 51527535Skarels if (bind(sep->se_fd, &sep->se_ctrladdr, 51627535Skarels sizeof (sep->se_ctrladdr)) < 0) { 51727535Skarels syslog(LOG_ERR, "%s/%s: bind: %m", 51827535Skarels sep->se_service, sep->se_proto); 51927535Skarels (void) close(sep->se_fd); 52027535Skarels sep->se_fd = -1; 52127535Skarels if (!timingout) { 52227535Skarels timingout = 1; 52327535Skarels alarm(RETRYTIME); 52427535Skarels } 52527535Skarels return; 52627535Skarels } 52727535Skarels if (sep->se_socktype == SOCK_STREAM) 52827535Skarels listen(sep->se_fd, 10); 52927535Skarels FD_SET(sep->se_fd, &allsock); 53027535Skarels nsock++; 53127535Skarels if (sep->se_fd > maxsock) 53227535Skarels maxsock = sep->se_fd; 53327535Skarels } 53427535Skarels 53516374Skarels struct servtab * 53616374Skarels enter(cp) 53716374Skarels struct servtab *cp; 53816374Skarels { 53916374Skarels register struct servtab *sep; 54032246Sbostic long omask; 54116374Skarels 54216374Skarels sep = (struct servtab *)malloc(sizeof (*sep)); 54316374Skarels if (sep == (struct servtab *)0) { 54416510Sralph syslog(LOG_ERR, "Out of memory."); 54516374Skarels exit(-1); 54616374Skarels } 54716374Skarels *sep = *cp; 54816374Skarels sep->se_fd = -1; 54927535Skarels omask = sigblock(SIGBLOCK); 55016374Skarels sep->se_next = servtab; 55116374Skarels servtab = sep; 55216374Skarels sigsetmask(omask); 55316374Skarels return (sep); 55416374Skarels } 55516374Skarels 55616374Skarels FILE *fconfig = NULL; 55716374Skarels struct servtab serv; 55816374Skarels char line[256]; 55916374Skarels char *skip(), *nextline(); 56016374Skarels 56116374Skarels setconfig() 56216374Skarels { 56316374Skarels 56416374Skarels if (fconfig != NULL) { 56526921Slepreau fseek(fconfig, 0L, L_SET); 56616374Skarels return (1); 56716374Skarels } 56816374Skarels fconfig = fopen(CONFIG, "r"); 56916374Skarels return (fconfig != NULL); 57016374Skarels } 57116374Skarels 57216374Skarels endconfig() 57316374Skarels { 57436603Sbostic if (fconfig) { 57536603Sbostic (void) fclose(fconfig); 57636603Sbostic fconfig = NULL; 57736603Sbostic } 57816374Skarels } 57916374Skarels 58016374Skarels struct servtab * 58116374Skarels getconfigent() 58216374Skarels { 58316374Skarels register struct servtab *sep = &serv; 58416374Skarels int argc; 58533136Sbostic char *cp, *arg, *strdup(); 58616374Skarels 58726877Skarels more: 58816374Skarels while ((cp = nextline(fconfig)) && *cp == '#') 58916374Skarels ; 59016374Skarels if (cp == NULL) 59116374Skarels return ((struct servtab *)0); 59216374Skarels sep->se_service = strdup(skip(&cp)); 59316374Skarels arg = skip(&cp); 59416374Skarels if (strcmp(arg, "stream") == 0) 59516374Skarels sep->se_socktype = SOCK_STREAM; 59616374Skarels else if (strcmp(arg, "dgram") == 0) 59716374Skarels sep->se_socktype = SOCK_DGRAM; 59816374Skarels else if (strcmp(arg, "rdm") == 0) 59916374Skarels sep->se_socktype = SOCK_RDM; 60016374Skarels else if (strcmp(arg, "seqpacket") == 0) 60116374Skarels sep->se_socktype = SOCK_SEQPACKET; 60216374Skarels else if (strcmp(arg, "raw") == 0) 60316374Skarels sep->se_socktype = SOCK_RAW; 60416374Skarels else 60516374Skarels sep->se_socktype = -1; 60616374Skarels sep->se_proto = strdup(skip(&cp)); 60716374Skarels arg = skip(&cp); 60816374Skarels sep->se_wait = strcmp(arg, "wait") == 0; 60917346Sbloom sep->se_user = strdup(skip(&cp)); 61016374Skarels sep->se_server = strdup(skip(&cp)); 61126877Skarels if (strcmp(sep->se_server, "internal") == 0) { 61226877Skarels register struct biltin *bi; 61326877Skarels 61426877Skarels for (bi = biltins; bi->bi_service; bi++) 61526877Skarels if (bi->bi_socktype == sep->se_socktype && 61626877Skarels strcmp(bi->bi_service, sep->se_service) == 0) 61726877Skarels break; 61826877Skarels if (bi->bi_service == 0) { 61926877Skarels syslog(LOG_ERR, "internal service %s unknown\n", 62026877Skarels sep->se_service); 62126877Skarels goto more; 62226877Skarels } 62326877Skarels sep->se_bi = bi; 62426877Skarels sep->se_wait = bi->bi_wait; 62529794Skarels } else 62629794Skarels sep->se_bi = NULL; 62716374Skarels argc = 0; 62816374Skarels for (arg = skip(&cp); cp; arg = skip(&cp)) 62916374Skarels if (argc < MAXARGV) 63016374Skarels sep->se_argv[argc++] = strdup(arg); 63116374Skarels while (argc <= MAXARGV) 63216374Skarels sep->se_argv[argc++] = NULL; 63316374Skarels return (sep); 63416374Skarels } 63516374Skarels 63616374Skarels freeconfig(cp) 63716374Skarels register struct servtab *cp; 63816374Skarels { 63916374Skarels int i; 64016374Skarels 64116374Skarels if (cp->se_service) 64216374Skarels free(cp->se_service); 64316374Skarels if (cp->se_proto) 64416374Skarels free(cp->se_proto); 64526921Slepreau if (cp->se_user) 64626921Slepreau free(cp->se_user); 64716374Skarels if (cp->se_server) 64816374Skarels free(cp->se_server); 64916374Skarels for (i = 0; i < MAXARGV; i++) 65016374Skarels if (cp->se_argv[i]) 65116374Skarels free(cp->se_argv[i]); 65216374Skarels } 65316374Skarels 65416374Skarels char * 65516374Skarels skip(cpp) 65616374Skarels char **cpp; 65716374Skarels { 65816374Skarels register char *cp = *cpp; 65916374Skarels char *start; 66016374Skarels 66116374Skarels again: 66216374Skarels while (*cp == ' ' || *cp == '\t') 66316374Skarels cp++; 66416374Skarels if (*cp == '\0') { 66516374Skarels char c; 66616374Skarels 66716374Skarels c = getc(fconfig); 66836603Sbostic (void) ungetc(c, fconfig); 66916374Skarels if (c == ' ' || c == '\t') 67016374Skarels if (cp = nextline(fconfig)) 67116374Skarels goto again; 67216374Skarels *cpp = (char *)0; 67316374Skarels return ((char *)0); 67416374Skarels } 67516374Skarels start = cp; 67616374Skarels while (*cp && *cp != ' ' && *cp != '\t') 67716374Skarels cp++; 67816374Skarels if (*cp != '\0') 67916374Skarels *cp++ = '\0'; 68016374Skarels *cpp = cp; 68116374Skarels return (start); 68216374Skarels } 68316374Skarels 68416374Skarels char * 68516374Skarels nextline(fd) 68616374Skarels FILE *fd; 68716374Skarels { 68816374Skarels char *cp; 68916374Skarels 69026921Slepreau if (fgets(line, sizeof (line), fd) == NULL) 69116374Skarels return ((char *)0); 69216374Skarels cp = index(line, '\n'); 69316374Skarels if (cp) 69416374Skarels *cp = '\0'; 69516374Skarels return (line); 69616374Skarels } 69716374Skarels 69816374Skarels char * 69916374Skarels strdup(cp) 70016374Skarels char *cp; 70116374Skarels { 70216374Skarels char *new; 70316374Skarels 70416374Skarels if (cp == NULL) 70516374Skarels cp = ""; 70626921Slepreau new = malloc((unsigned)(strlen(cp) + 1)); 70716374Skarels if (new == (char *)0) { 70816510Sralph syslog(LOG_ERR, "Out of memory."); 70916374Skarels exit(-1); 71016374Skarels } 71136603Sbostic (void)strcpy(new, cp); 71216374Skarels return (new); 71316374Skarels } 71426877Skarels 71526877Skarels setproctitle(a, s) 71626877Skarels char *a; 71726877Skarels int s; 71826877Skarels { 71926877Skarels int size; 72026877Skarels register char *cp; 72126877Skarels struct sockaddr_in sin; 72226877Skarels char buf[80]; 72326877Skarels 72426877Skarels cp = Argv[0]; 72526877Skarels size = sizeof(sin); 72626877Skarels if (getpeername(s, &sin, &size) == 0) 72732442Sbostic (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 72826877Skarels else 72932442Sbostic (void) sprintf(buf, "-%s", a); 73026877Skarels strncpy(cp, buf, LastArg - cp); 73126877Skarels cp += strlen(cp); 73226877Skarels while (cp < LastArg) 73326877Skarels *cp++ = ' '; 73426877Skarels } 73526877Skarels 73626877Skarels /* 73726877Skarels * Internet services provided internally by inetd: 73826877Skarels */ 73938573Skarels #define BUFSIZE 4096 74026877Skarels 74126877Skarels /* ARGSUSED */ 74226877Skarels echo_stream(s, sep) /* Echo service -- echo data back */ 74326877Skarels int s; 74426877Skarels struct servtab *sep; 74526877Skarels { 74638573Skarels char buffer[BUFSIZE]; 74726877Skarels int i; 74826877Skarels 74932091Skarels setproctitle(sep->se_service, s); 75026877Skarels while ((i = read(s, buffer, sizeof(buffer))) > 0 && 75126877Skarels write(s, buffer, i) > 0) 75226877Skarels ; 75326877Skarels exit(0); 75426877Skarels } 75526877Skarels 75626877Skarels /* ARGSUSED */ 75726877Skarels echo_dg(s, sep) /* Echo service -- echo data back */ 75826877Skarels int s; 75926877Skarels struct servtab *sep; 76026877Skarels { 76138573Skarels char buffer[BUFSIZE]; 76226877Skarels int i, size; 76326877Skarels struct sockaddr sa; 76426877Skarels 76526877Skarels size = sizeof(sa); 76626877Skarels if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) 76726877Skarels return; 76826877Skarels (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); 76926877Skarels } 77026877Skarels 77126877Skarels /* ARGSUSED */ 77226877Skarels discard_stream(s, sep) /* Discard service -- ignore data */ 77326877Skarels int s; 77426877Skarels struct servtab *sep; 77526877Skarels { 77638573Skarels char buffer[BUFSIZE]; 77726877Skarels 77832091Skarels setproctitle(sep->se_service, s); 77926877Skarels while (1) { 78026877Skarels while (read(s, buffer, sizeof(buffer)) > 0) 78126877Skarels ; 78226877Skarels if (errno != EINTR) 78326877Skarels break; 78426877Skarels } 78526877Skarels exit(0); 78626877Skarels } 78726877Skarels 78826877Skarels /* ARGSUSED */ 78926877Skarels discard_dg(s, sep) /* Discard service -- ignore data */ 79026877Skarels int s; 79126877Skarels struct servtab *sep; 79226877Skarels { 79338573Skarels char buffer[BUFSIZE]; 79426877Skarels 79526877Skarels (void) read(s, buffer, sizeof(buffer)); 79626877Skarels } 79726877Skarels 79826877Skarels #include <ctype.h> 79926877Skarels #define LINESIZ 72 80026877Skarels char ring[128]; 80126877Skarels char *endring; 80226877Skarels 80326877Skarels initring() 80426877Skarels { 80526877Skarels register int i; 80626877Skarels 80726877Skarels endring = ring; 80826877Skarels 80926877Skarels for (i = 0; i <= 128; ++i) 81026877Skarels if (isprint(i)) 81126877Skarels *endring++ = i; 81226877Skarels } 81326877Skarels 81426877Skarels /* ARGSUSED */ 81526877Skarels chargen_stream(s, sep) /* Character generator */ 81626877Skarels int s; 81726877Skarels struct servtab *sep; 81826877Skarels { 81932246Sbostic register char *rs; 82032246Sbostic int len; 82126877Skarels char text[LINESIZ+2]; 82226877Skarels 82332091Skarels setproctitle(sep->se_service, s); 82432246Sbostic 82532246Sbostic if (!endring) { 82626877Skarels initring(); 82732246Sbostic rs = ring; 82832246Sbostic } 82926877Skarels 83032246Sbostic text[LINESIZ] = '\r'; 83132246Sbostic text[LINESIZ + 1] = '\n'; 83232246Sbostic for (rs = ring;;) { 83332246Sbostic if ((len = endring - rs) >= LINESIZ) 83432246Sbostic bcopy(rs, text, LINESIZ); 83532246Sbostic else { 83632246Sbostic bcopy(rs, text, len); 83732246Sbostic bcopy(ring, text + len, LINESIZ - len); 83832246Sbostic } 83932246Sbostic if (++rs == endring) 84026877Skarels rs = ring; 84132246Sbostic if (write(s, text, sizeof(text)) != sizeof(text)) 84226877Skarels break; 84326877Skarels } 84426877Skarels exit(0); 84526877Skarels } 84626877Skarels 84726877Skarels /* ARGSUSED */ 84826877Skarels chargen_dg(s, sep) /* Character generator */ 84926877Skarels int s; 85026877Skarels struct servtab *sep; 85126877Skarels { 85232246Sbostic struct sockaddr sa; 85332246Sbostic static char *rs; 85432246Sbostic int len, size; 85526877Skarels char text[LINESIZ+2]; 85626877Skarels 85732246Sbostic if (endring == 0) { 85826877Skarels initring(); 85932246Sbostic rs = ring; 86032246Sbostic } 86126877Skarels 86226877Skarels size = sizeof(sa); 86326877Skarels if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) 86426877Skarels return; 86532246Sbostic 86632246Sbostic if ((len = endring - rs) >= LINESIZ) 86732246Sbostic bcopy(rs, text, LINESIZ); 86832246Sbostic else { 86932246Sbostic bcopy(rs, text, len); 87032246Sbostic bcopy(ring, text + len, LINESIZ - len); 87132246Sbostic } 87232246Sbostic if (++rs == endring) 87326877Skarels rs = ring; 87432246Sbostic text[LINESIZ] = '\r'; 87532246Sbostic text[LINESIZ + 1] = '\n'; 87626877Skarels (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa)); 87726877Skarels } 87826877Skarels 87926877Skarels /* 88026877Skarels * Return a machine readable date and time, in the form of the 88126877Skarels * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 88226877Skarels * returns the number of seconds since midnight, Jan 1, 1970, 88326877Skarels * we must add 2208988800 seconds to this figure to make up for 88426877Skarels * some seventy years Bell Labs was asleep. 88526877Skarels */ 88626877Skarels 88726877Skarels long 88826877Skarels machtime() 88926877Skarels { 89026877Skarels struct timeval tv; 89126877Skarels 89226921Slepreau if (gettimeofday(&tv, (struct timezone *)0) < 0) { 89326877Skarels fprintf(stderr, "Unable to get time of day\n"); 89426921Slepreau return (0L); 89526877Skarels } 89626877Skarels return (htonl((long)tv.tv_sec + 2208988800)); 89726877Skarels } 89826877Skarels 89926877Skarels /* ARGSUSED */ 90026877Skarels machtime_stream(s, sep) 90126877Skarels int s; 90226877Skarels struct servtab *sep; 90326877Skarels { 90426877Skarels long result; 90526877Skarels 90626877Skarels result = machtime(); 90726877Skarels (void) write(s, (char *) &result, sizeof(result)); 90826877Skarels } 90926877Skarels 91026877Skarels /* ARGSUSED */ 91126877Skarels machtime_dg(s, sep) 91226877Skarels int s; 91326877Skarels struct servtab *sep; 91426877Skarels { 91526877Skarels long result; 91626877Skarels struct sockaddr sa; 91726877Skarels int size; 91826877Skarels 91926877Skarels size = sizeof(sa); 92026921Slepreau if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0) 92126877Skarels return; 92226877Skarels result = machtime(); 92326877Skarels (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa)); 92426877Skarels } 92526877Skarels 92626877Skarels /* ARGSUSED */ 92726877Skarels daytime_stream(s, sep) /* Return human-readable time of day */ 92826877Skarels int s; 92926877Skarels struct servtab *sep; 93026877Skarels { 93126877Skarels char buffer[256]; 93226877Skarels time_t time(), clock; 93326877Skarels char *ctime(); 93426877Skarels 93526877Skarels clock = time((time_t *) 0); 93626877Skarels 93732442Sbostic (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 93826921Slepreau (void) write(s, buffer, strlen(buffer)); 93926877Skarels } 94026877Skarels 94126877Skarels /* ARGSUSED */ 94226877Skarels daytime_dg(s, sep) /* Return human-readable time of day */ 94326877Skarels int s; 94426877Skarels struct servtab *sep; 94526877Skarels { 94626877Skarels char buffer[256]; 94726877Skarels time_t time(), clock; 94826877Skarels struct sockaddr sa; 94926877Skarels int size; 95026877Skarels char *ctime(); 95126877Skarels 95226877Skarels clock = time((time_t *) 0); 95326877Skarels 95426877Skarels size = sizeof(sa); 95526877Skarels if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) 95626877Skarels return; 95732442Sbostic (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 95826877Skarels (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa)); 95926877Skarels } 96029794Skarels 96129794Skarels /* 96229794Skarels * print_service: 96329794Skarels * Dump relevant information to stderr 96429794Skarels */ 96529794Skarels print_service(action, sep) 96629794Skarels char *action; 96729794Skarels struct servtab *sep; 96829794Skarels { 96929794Skarels fprintf(stderr, 97029794Skarels "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n", 97129794Skarels action, sep->se_service, sep->se_proto, 97236603Sbostic sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server); 97329794Skarels } 974