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