1*16374Skarels #ifndef lint 2*16374Skarels static char sccsid[] = "@(#)inetd.c 4.1 (Berkeley) 04/11/84"; 3*16374Skarels #endif 4*16374Skarels 5*16374Skarels /* 6*16374Skarels * Inetd - Internet super-server 7*16374Skarels * 8*16374Skarels * This program invokes all internet services as needed. 9*16374Skarels * connection-oriented services are invoked each time a 10*16374Skarels * connection is made, by creating a process. This process 11*16374Skarels * is passed the connection as file descriptor 0 and is 12*16374Skarels * expected to do a getpeername to find out the source host 13*16374Skarels * and port. 14*16374Skarels * 15*16374Skarels * Datagram oriented services are invoked when a datagram 16*16374Skarels * arrives; a process is created and passed a pending message 17*16374Skarels * on file descriptor 0. Datagram servers may either connect 18*16374Skarels * to their peer, freeing up the original socket for inetd 19*16374Skarels * to receive further messages on, or ``take over the socket'', 20*16374Skarels * processing all arriving datagrams and, eventually, timing 21*16374Skarels * out. The first type of server is said to be ``multi-threaded''; 22*16374Skarels * the second type of server ``single-threaded''. 23*16374Skarels * 24*16374Skarels * Inetd uses a configuration file which is read at startup 25*16374Skarels * and, possibly, at some later time in response to a hangup signal. 26*16374Skarels * The configuration file is ``free format'' with fields given in the 27*16374Skarels * order shown below. Continuation lines for an entry must being with 28*16374Skarels * a space or tab. All fields must be present in each entry. 29*16374Skarels * 30*16374Skarels * service name must be in /etc/services 31*16374Skarels * socket type stream/dgram/raw/rdm/seqpacket 32*16374Skarels * protocol must be in /etc/protocols 33*16374Skarels * wait/nowait single-threaded/multi-threaded 34*16374Skarels * server program full path name 35*16374Skarels * server program arguments maximum of MAXARGS (5) 36*16374Skarels * 37*16374Skarels * Comment lines are indicated by a `#' in column 1. 38*16374Skarels */ 39*16374Skarels #include <sys/param.h> 40*16374Skarels #include <sys/stat.h> 41*16374Skarels #include <sys/ioctl.h> 42*16374Skarels #include <sys/socket.h> 43*16374Skarels #include <sys/file.h> 44*16374Skarels #include <sys/wait.h> 45*16374Skarels 46*16374Skarels #include <netinet/in.h> 47*16374Skarels #include <arpa/inet.h> 48*16374Skarels 49*16374Skarels #include <errno.h> 50*16374Skarels #include <stdio.h> 51*16374Skarels #include <signal.h> 52*16374Skarels #include <netdb.h> 53*16374Skarels 54*16374Skarels extern int errno; 55*16374Skarels 56*16374Skarels int reapchild(); 57*16374Skarels char *index(); 58*16374Skarels char *malloc(); 59*16374Skarels 60*16374Skarels int debug = 0; 61*16374Skarels int allsock; 62*16374Skarels int options; 63*16374Skarels struct servent *sp; 64*16374Skarels 65*16374Skarels struct servtab { 66*16374Skarels char *se_service; /* name of service */ 67*16374Skarels int se_socktype; /* type of socket to use */ 68*16374Skarels char *se_proto; /* protocol used */ 69*16374Skarels short se_wait; /* single threaded server */ 70*16374Skarels short se_checked; /* looked at during merge */ 71*16374Skarels char *se_server; /* server program */ 72*16374Skarels #define MAXARGV 5 73*16374Skarels char *se_argv[MAXARGV+1]; /* program arguments */ 74*16374Skarels int se_fd; /* open descriptor */ 75*16374Skarels struct sockaddr_in se_ctrladdr;/* bound address */ 76*16374Skarels struct servtab *se_next; 77*16374Skarels } *servtab; 78*16374Skarels 79*16374Skarels char *CONFIG = "/etc/inetd.conf"; 80*16374Skarels 81*16374Skarels main(argc, argv) 82*16374Skarels int argc; 83*16374Skarels char *argv[]; 84*16374Skarels { 85*16374Skarels int ctrl; 86*16374Skarels register struct servtab *sep; 87*16374Skarels char *cp, buf[50]; 88*16374Skarels int pid, i; 89*16374Skarels 90*16374Skarels argc--, argv++; 91*16374Skarels while (argc > 0 && *argv[0] == '-') { 92*16374Skarels for (cp = &argv[0][1]; *cp; cp++) switch (*cp) { 93*16374Skarels 94*16374Skarels case 'd': 95*16374Skarels debug = 1; 96*16374Skarels options |= SO_DEBUG; 97*16374Skarels break; 98*16374Skarels 99*16374Skarels default: 100*16374Skarels fprintf(stderr, 101*16374Skarels "inetd: Unknown flag -%c ignored.\n", *cp); 102*16374Skarels break; 103*16374Skarels } 104*16374Skarels nextopt: 105*16374Skarels argc--, argv++; 106*16374Skarels } 107*16374Skarels if (argc > 0) 108*16374Skarels CONFIG = argv[0]; 109*16374Skarels #ifndef DEBUG 110*16374Skarels if (fork()) 111*16374Skarels exit(0); 112*16374Skarels { int s; 113*16374Skarels for (s = 0; s < 10; s++) 114*16374Skarels (void) close(s); 115*16374Skarels } 116*16374Skarels (void) open("/", O_RDONLY); 117*16374Skarels (void) dup2(0, 1); 118*16374Skarels (void) dup2(0, 2); 119*16374Skarels { int tt = open("/dev/tty", O_RDWR); 120*16374Skarels if (tt > 0) { 121*16374Skarels ioctl(tt, TIOCNOTTY, 0); 122*16374Skarels close(tt); 123*16374Skarels } 124*16374Skarels } 125*16374Skarels #endif 126*16374Skarels config(); 127*16374Skarels signal(SIGHUP, config); 128*16374Skarels signal(SIGCHLD, reapchild); 129*16374Skarels for (;;) { 130*16374Skarels int readable, s, ctrl; 131*16374Skarels 132*16374Skarels while (allsock == 0) 133*16374Skarels sigpause(0); 134*16374Skarels readable = allsock; 135*16374Skarels if (select(32, &readable, 0, 0, 0) <= 0) 136*16374Skarels continue; 137*16374Skarels s = ffs(readable)-1; 138*16374Skarels if (s < 0) 139*16374Skarels continue; 140*16374Skarels for (sep = servtab; sep; sep = sep->se_next) 141*16374Skarels if (s == sep->se_fd) 142*16374Skarels goto found; 143*16374Skarels abort(1); 144*16374Skarels found: 145*16374Skarels if (debug) 146*16374Skarels fprintf(stderr, "someone wants %s\n", sep->se_service); 147*16374Skarels if (sep->se_socktype == SOCK_STREAM) { 148*16374Skarels ctrl = accept(s, 0, 0); 149*16374Skarels if (debug) 150*16374Skarels fprintf(stderr, "accept, ctrl %d\n", ctrl); 151*16374Skarels if (ctrl < 0) { 152*16374Skarels if (errno == EINTR) 153*16374Skarels continue; 154*16374Skarels perror("inetd: accept"); 155*16374Skarels continue; 156*16374Skarels } 157*16374Skarels } else 158*16374Skarels ctrl = sep->se_fd; 159*16374Skarels #define mask(sig) (1 << (sig - 1)) 160*16374Skarels sigblock(mask(SIGCHLD)|mask(SIGHUP)); 161*16374Skarels pid = fork(); 162*16374Skarels if (pid < 0) { 163*16374Skarels if (sep->se_socktype == SOCK_STREAM) 164*16374Skarels close(ctrl); 165*16374Skarels sleep(1); 166*16374Skarels continue; 167*16374Skarels } 168*16374Skarels if (sep->se_wait) { 169*16374Skarels sep->se_wait = pid; 170*16374Skarels allsock &= ~(1 << s); 171*16374Skarels } 172*16374Skarels sigsetmask(0); 173*16374Skarels if (pid == 0) { 174*16374Skarels #ifdef DEBUG 175*16374Skarels int tt = open("/dev/tty", O_RDWR); 176*16374Skarels if (tt > 0) { 177*16374Skarels ioctl(tt, TIOCNOTTY, 0); 178*16374Skarels close(tt); 179*16374Skarels } 180*16374Skarels #endif 181*16374Skarels dup2(ctrl, 0), close(ctrl), dup2(0, 1); 182*16374Skarels for (i = getdtablesize(); --i > 2; ) 183*16374Skarels close(i); 184*16374Skarels if (debug) 185*16374Skarels fprintf(stderr, "%d execl %s\n", 186*16374Skarels getpid(), sep->se_server); 187*16374Skarels execv(sep->se_server, sep->se_argv); 188*16374Skarels if (sep->se_socktype != SOCK_STREAM) 189*16374Skarels recv(0, buf, sizeof (buf)); 190*16374Skarels if (debug) 191*16374Skarels fprintf(stderr, "execl failed\n"); 192*16374Skarels _exit(1); 193*16374Skarels } 194*16374Skarels if (sep->se_socktype == SOCK_STREAM) 195*16374Skarels close(ctrl); 196*16374Skarels } 197*16374Skarels } 198*16374Skarels 199*16374Skarels reapchild() 200*16374Skarels { 201*16374Skarels union wait status; 202*16374Skarels int pid; 203*16374Skarels register struct servtab *sep; 204*16374Skarels 205*16374Skarels for (;;) { 206*16374Skarels pid = wait3(&status, WNOHANG, 0); 207*16374Skarels if (pid <= 0) 208*16374Skarels break; 209*16374Skarels if (debug) 210*16374Skarels fprintf(stderr, "%d reaped\n", pid); 211*16374Skarels for (sep = servtab; sep; sep = sep->se_next) 212*16374Skarels if (sep->se_wait == pid) { 213*16374Skarels if (status.w_status) 214*16374Skarels fprintf(stderr, 215*16374Skarels "inetd: %s: exit status %d\n", 216*16374Skarels sep->se_server, status); 217*16374Skarels if (debug) 218*16374Skarels fprintf(stderr, "restored %s, fd %d\n", 219*16374Skarels sep->se_service, sep->se_fd); 220*16374Skarels allsock |= 1 << sep->se_fd; 221*16374Skarels sep->se_wait = 1; 222*16374Skarels } 223*16374Skarels } 224*16374Skarels } 225*16374Skarels 226*16374Skarels config() 227*16374Skarels { 228*16374Skarels register struct servtab *sep, *cp, **sepp; 229*16374Skarels struct servtab *getconfigent(), *enter(); 230*16374Skarels int omask; 231*16374Skarels 232*16374Skarels if (!setconfig()) { 233*16374Skarels fprintf(stderr, "inetd: "); 234*16374Skarels perror(CONFIG); 235*16374Skarels return; 236*16374Skarels } 237*16374Skarels for (sep = servtab; sep; sep = sep->se_next) 238*16374Skarels sep->se_checked = 0; 239*16374Skarels while (cp = getconfigent()) { 240*16374Skarels for (sep = servtab; sep; sep = sep->se_next) 241*16374Skarels if (strcmp(sep->se_service, cp->se_service) == 0 && 242*16374Skarels strcmp(sep->se_proto, cp->se_proto) == 0) 243*16374Skarels break; 244*16374Skarels if (sep != 0) { 245*16374Skarels int i; 246*16374Skarels 247*16374Skarels omask = sigblock(mask(SIGCHLD)); 248*16374Skarels sep->se_wait = cp->se_wait; 249*16374Skarels #define SWAP(a, b) { char *c = a; a = b; b = c; } 250*16374Skarels if (cp->se_server) 251*16374Skarels SWAP(sep->se_server, cp->se_server); 252*16374Skarels for (i = 0; i < MAXARGV; i++) 253*16374Skarels SWAP(sep->se_argv[i], cp->se_argv[i]); 254*16374Skarels sigsetmask(omask); 255*16374Skarels freeconfig(cp); 256*16374Skarels } else 257*16374Skarels sep = enter(cp); 258*16374Skarels sep->se_checked = 1; 259*16374Skarels if (sep->se_fd != -1) 260*16374Skarels continue; 261*16374Skarels sp = getservbyname(sep->se_service, sep->se_proto); 262*16374Skarels if (sp == 0) { 263*16374Skarels fprintf(stderr, 264*16374Skarels "inetd: %s/%s: unknown service\n", 265*16374Skarels sep->se_service, sep->se_proto); 266*16374Skarels continue; 267*16374Skarels } 268*16374Skarels sep->se_ctrladdr.sin_port = sp->s_port; 269*16374Skarels if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 270*16374Skarels fprintf(stderr, "inetd: %s/%s: ", 271*16374Skarels sep->se_service, sep->se_proto); 272*16374Skarels perror("socket"); 273*16374Skarels continue; 274*16374Skarels } 275*16374Skarels if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 276*16374Skarels setsockopt(sep->se_fd, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 277*16374Skarels perror("inetd: setsockopt (SO_DEBUG)"); 278*16374Skarels if (setsockopt(sep->se_fd, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0) 279*16374Skarels perror("inetd: setsockopt (SO_REUSEADDR)"); 280*16374Skarels if (bind(sep->se_fd, &sep->se_ctrladdr, 281*16374Skarels sizeof (sep->se_ctrladdr), 0) < 0) { 282*16374Skarels fprintf(stderr, "inetd: %s/%s: ", 283*16374Skarels sep->se_service, sep->se_proto); 284*16374Skarels perror("bind"); 285*16374Skarels continue; 286*16374Skarels } 287*16374Skarels if (sep->se_socktype == SOCK_STREAM) 288*16374Skarels listen(sep->se_fd, 10); 289*16374Skarels allsock |= 1 << sep->se_fd; 290*16374Skarels } 291*16374Skarels endconfig(); 292*16374Skarels /* 293*16374Skarels * Purge anything not looked at above. 294*16374Skarels */ 295*16374Skarels omask = sigblock(mask(SIGCHLD)); 296*16374Skarels sepp = &servtab; 297*16374Skarels while (sep = *sepp) { 298*16374Skarels if (sep->se_checked) { 299*16374Skarels sepp = &sep->se_next; 300*16374Skarels continue; 301*16374Skarels } 302*16374Skarels *sepp = sep->se_next; 303*16374Skarels if (sep->se_fd != -1) { 304*16374Skarels allsock &= ~(1 << sep->se_fd); 305*16374Skarels (void) close(sep->se_fd); 306*16374Skarels } 307*16374Skarels freeconfig(sep); 308*16374Skarels free((char *)sep); 309*16374Skarels } 310*16374Skarels (void) sigsetmask(omask); 311*16374Skarels } 312*16374Skarels 313*16374Skarels struct servtab * 314*16374Skarels enter(cp) 315*16374Skarels struct servtab *cp; 316*16374Skarels { 317*16374Skarels register struct servtab *sep; 318*16374Skarels int omask, i; 319*16374Skarels char *strdup(); 320*16374Skarels 321*16374Skarels sep = (struct servtab *)malloc(sizeof (*sep)); 322*16374Skarels if (sep == (struct servtab *)0) { 323*16374Skarels fprintf(stderr, "Out of memory.\n"); 324*16374Skarels exit(-1); 325*16374Skarels } 326*16374Skarels *sep = *cp; 327*16374Skarels sep->se_fd = -1; 328*16374Skarels omask = sigblock(mask(SIGCHLD)); 329*16374Skarels sep->se_next = servtab; 330*16374Skarels servtab = sep; 331*16374Skarels sigsetmask(omask); 332*16374Skarels return (sep); 333*16374Skarels } 334*16374Skarels 335*16374Skarels FILE *fconfig = NULL; 336*16374Skarels struct servtab serv; 337*16374Skarels char line[256]; 338*16374Skarels char *skip(), *nextline(); 339*16374Skarels 340*16374Skarels setconfig() 341*16374Skarels { 342*16374Skarels 343*16374Skarels if (fconfig != NULL) { 344*16374Skarels fseek(fconfig, 0, L_SET); 345*16374Skarels return (1); 346*16374Skarels } 347*16374Skarels fconfig = fopen(CONFIG, "r"); 348*16374Skarels return (fconfig != NULL); 349*16374Skarels } 350*16374Skarels 351*16374Skarels endconfig() 352*16374Skarels { 353*16374Skarels 354*16374Skarels if (fconfig == NULL) 355*16374Skarels return; 356*16374Skarels fclose(fconfig); 357*16374Skarels fconfig = NULL; 358*16374Skarels } 359*16374Skarels 360*16374Skarels struct servtab * 361*16374Skarels getconfigent() 362*16374Skarels { 363*16374Skarels register struct servtab *sep = &serv; 364*16374Skarels char *cp, *arg; 365*16374Skarels int argc; 366*16374Skarels 367*16374Skarels while ((cp = nextline(fconfig)) && *cp == '#') 368*16374Skarels ; 369*16374Skarels if (cp == NULL) 370*16374Skarels return ((struct servtab *)0); 371*16374Skarels sep->se_service = strdup(skip(&cp)); 372*16374Skarels arg = skip(&cp); 373*16374Skarels if (strcmp(arg, "stream") == 0) 374*16374Skarels sep->se_socktype = SOCK_STREAM; 375*16374Skarels else if (strcmp(arg, "dgram") == 0) 376*16374Skarels sep->se_socktype = SOCK_DGRAM; 377*16374Skarels else if (strcmp(arg, "rdm") == 0) 378*16374Skarels sep->se_socktype = SOCK_RDM; 379*16374Skarels else if (strcmp(arg, "seqpacket") == 0) 380*16374Skarels sep->se_socktype = SOCK_SEQPACKET; 381*16374Skarels else if (strcmp(arg, "raw") == 0) 382*16374Skarels sep->se_socktype = SOCK_RAW; 383*16374Skarels else 384*16374Skarels sep->se_socktype = -1; 385*16374Skarels sep->se_proto = strdup(skip(&cp)); 386*16374Skarels arg = skip(&cp); 387*16374Skarels sep->se_wait = strcmp(arg, "wait") == 0; 388*16374Skarels sep->se_server = strdup(skip(&cp)); 389*16374Skarels argc = 0; 390*16374Skarels for (arg = skip(&cp); cp; arg = skip(&cp)) 391*16374Skarels if (argc < MAXARGV) 392*16374Skarels sep->se_argv[argc++] = strdup(arg); 393*16374Skarels while (argc <= MAXARGV) 394*16374Skarels sep->se_argv[argc++] = NULL; 395*16374Skarels return (sep); 396*16374Skarels } 397*16374Skarels 398*16374Skarels freeconfig(cp) 399*16374Skarels register struct servtab *cp; 400*16374Skarels { 401*16374Skarels int i; 402*16374Skarels 403*16374Skarels if (cp->se_service) 404*16374Skarels free(cp->se_service); 405*16374Skarels if (cp->se_proto) 406*16374Skarels free(cp->se_proto); 407*16374Skarels if (cp->se_server) 408*16374Skarels free(cp->se_server); 409*16374Skarels for (i = 0; i < MAXARGV; i++) 410*16374Skarels if (cp->se_argv[i]) 411*16374Skarels free(cp->se_argv[i]); 412*16374Skarels } 413*16374Skarels 414*16374Skarels char * 415*16374Skarels skip(cpp) 416*16374Skarels char **cpp; 417*16374Skarels { 418*16374Skarels register char *cp = *cpp; 419*16374Skarels char *start; 420*16374Skarels 421*16374Skarels again: 422*16374Skarels while (*cp == ' ' || *cp == '\t') 423*16374Skarels cp++; 424*16374Skarels if (*cp == '\0') { 425*16374Skarels char c; 426*16374Skarels 427*16374Skarels c = getc(fconfig); 428*16374Skarels ungetc(c, fconfig); 429*16374Skarels if (c == ' ' || c == '\t') 430*16374Skarels if (cp = nextline(fconfig)) 431*16374Skarels goto again; 432*16374Skarels *cpp = (char *)0; 433*16374Skarels return ((char *)0); 434*16374Skarels } 435*16374Skarels start = cp; 436*16374Skarels while (*cp && *cp != ' ' && *cp != '\t') 437*16374Skarels cp++; 438*16374Skarels if (*cp != '\0') 439*16374Skarels *cp++ = '\0'; 440*16374Skarels *cpp = cp; 441*16374Skarels return (start); 442*16374Skarels } 443*16374Skarels 444*16374Skarels char * 445*16374Skarels nextline(fd) 446*16374Skarels FILE *fd; 447*16374Skarels { 448*16374Skarels char *cp; 449*16374Skarels 450*16374Skarels if (fgets(line, sizeof (line), fconfig) == NULL) 451*16374Skarels return ((char *)0); 452*16374Skarels cp = index(line, '\n'); 453*16374Skarels if (cp) 454*16374Skarels *cp = '\0'; 455*16374Skarels return (line); 456*16374Skarels } 457*16374Skarels 458*16374Skarels char * 459*16374Skarels strdup(cp) 460*16374Skarels char *cp; 461*16374Skarels { 462*16374Skarels char *new; 463*16374Skarels 464*16374Skarels if (cp == NULL) 465*16374Skarels cp = ""; 466*16374Skarels new = malloc(strlen(cp) + 1); 467*16374Skarels if (new == (char *)0) { 468*16374Skarels fprintf(stderr, "Out of memory.\n"); 469*16374Skarels exit(-1); 470*16374Skarels } 471*16374Skarels strcpy(new, cp); 472*16374Skarels return (new); 473*16374Skarels } 474