inetd.c revision 35829
1/* 2 * Copyright (c) 1983, 1991, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static const char copyright[] = 36"@(#) Copyright (c) 1983, 1991, 1993, 1994\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41#if 0 42static char sccsid[] = "@(#)from: inetd.c 8.4 (Berkeley) 4/13/94"; 43#endif 44static const char rcsid[] = 45 "$Id: inetd.c,v 1.30 1998/02/24 21:55:14 pst Exp $"; 46#endif /* not lint */ 47 48/* 49 * Inetd - Internet super-server 50 * 51 * This program invokes all internet services as needed. Connection-oriented 52 * services are invoked each time a connection is made, by creating a process. 53 * This process is passed the connection as file descriptor 0 and is expected 54 * to do a getpeername to find out the source host and port. 55 * 56 * Datagram oriented services are invoked when a datagram 57 * arrives; a process is created and passed a pending message 58 * on file descriptor 0. Datagram servers may either connect 59 * to their peer, freeing up the original socket for inetd 60 * to receive further messages on, or ``take over the socket'', 61 * processing all arriving datagrams and, eventually, timing 62 * out. The first type of server is said to be ``multi-threaded''; 63 * the second type of server ``single-threaded''. 64 * 65 * Inetd uses a configuration file which is read at startup 66 * and, possibly, at some later time in response to a hangup signal. 67 * The configuration file is ``free format'' with fields given in the 68 * order shown below. Continuation lines for an entry must being with 69 * a space or tab. All fields must be present in each entry. 70 * 71 * service name must be in /etc/services or must 72 * name a tcpmux service 73 * socket type stream/dgram/raw/rdm/seqpacket 74 * protocol must be in /etc/protocols 75 * wait/nowait single-threaded/multi-threaded 76 * user user to run daemon as 77 * server program full path name 78 * server program arguments maximum of MAXARGS (20) 79 * 80 * TCP services without official port numbers are handled with the 81 * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for 82 * requests. When a connection is made from a foreign host, the service 83 * requested is passed to tcpmux, which looks it up in the servtab list 84 * and returns the proper entry for the service. Tcpmux returns a 85 * negative reply if the service doesn't exist, otherwise the invoked 86 * server is expected to return the positive reply if the service type in 87 * inetd.conf file has the prefix "tcpmux/". If the service type has the 88 * prefix "tcpmux/+", tcpmux will return the positive reply for the 89 * process; this is for compatibility with older server code, and also 90 * allows you to invoke programs that use stdin/stdout without putting any 91 * special server code in them. Services that use tcpmux are "nowait" 92 * because they do not have a well-known port and hence cannot listen 93 * for new requests. 94 * 95 * For RPC services 96 * service name/version must be in /etc/rpc 97 * socket type stream/dgram/raw/rdm/seqpacket 98 * protocol must be in /etc/protocols 99 * wait/nowait single-threaded/multi-threaded 100 * user user to run daemon as 101 * server program full path name 102 * server program arguments maximum of MAXARGS 103 * 104 * Comment lines are indicated by a `#' in column 1. 105 */ 106#include <sys/param.h> 107#include <sys/stat.h> 108#include <sys/ioctl.h> 109#include <sys/socket.h> 110#include <sys/wait.h> 111#include <sys/time.h> 112#include <sys/resource.h> 113 114#include <netinet/in.h> 115#include <arpa/inet.h> 116#include <rpc/rpc.h> 117#include <rpc/pmap_clnt.h> 118 119#include <errno.h> 120#include <err.h> 121#include <fcntl.h> 122#include <grp.h> 123#include <netdb.h> 124#include <pwd.h> 125#include <signal.h> 126#include <stdio.h> 127#include <stdlib.h> 128#include <string.h> 129#include <syslog.h> 130#include <unistd.h> 131#include <libutil.h> 132#include <sysexits.h> 133 134#ifdef LOGIN_CAP 135#include <login_cap.h> 136 137/* see init.c */ 138#define RESOURCE_RC "daemon" 139 140#endif 141 142#include "pathnames.h" 143 144#ifndef MAXCHILD 145#define MAXCHILD -1 /* maximum number of this service 146 < 0 = no limit */ 147#endif 148 149#ifndef MAXCPM 150#define MAXCPM -1 /* rate limit invocations from a 151 single remote address, 152 < 0 = no limit */ 153#endif 154 155#define TOOMANY 256 /* don't start more than TOOMANY */ 156#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 157#define RETRYTIME (60*10) /* retry after bind or server fail */ 158#define MAX_MAXCHLD 32767 /* max allowable max children */ 159 160#define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 161 162int debug = 0; 163int log = 0; 164int nsock, maxsock; 165fd_set allsock; 166int options; 167int timingout; 168int toomany = TOOMANY; 169int maxchild = MAXCPM; 170int maxcpm = MAXCHILD; 171struct servent *sp; 172struct rpcent *rpc; 173struct in_addr bind_address; 174 175struct servtab { 176 char *se_service; /* name of service */ 177 int se_socktype; /* type of socket to use */ 178 char *se_proto; /* protocol used */ 179 int se_maxchild; /* max number of children */ 180 int se_maxcpm; /* max connects per IP per minute */ 181 int se_numchild; /* current number of children */ 182 pid_t *se_pids; /* array of child pids */ 183 char *se_user; /* user name to run as */ 184 char *se_group; /* group name to run as */ 185#ifdef LOGIN_CAP 186 char *se_class; /* login class name to run with */ 187#endif 188 struct biltin *se_bi; /* if built-in, description */ 189 char *se_server; /* server program */ 190#define MAXARGV 20 191 char *se_argv[MAXARGV+1]; /* program arguments */ 192 int se_fd; /* open descriptor */ 193 struct sockaddr_in se_ctrladdr;/* bound address */ 194 u_char se_type; /* type: normal, mux, or mux+ */ 195 u_char se_checked; /* looked at during merge */ 196 u_char se_accept; /* i.e., wait/nowait mode */ 197 u_char se_rpc; /* ==1 if RPC service */ 198 int se_rpc_prog; /* RPC program number */ 199 u_int se_rpc_lowvers; /* RPC low version */ 200 u_int se_rpc_highvers; /* RPC high version */ 201 int se_count; /* number started since se_time */ 202 struct timeval se_time; /* start of se_count */ 203 struct servtab *se_next; 204} *servtab; 205 206#define NORM_TYPE 0 207#define MUX_TYPE 1 208#define MUXPLUS_TYPE 2 209#define ISMUX(sep) (((sep)->se_type == MUX_TYPE) || \ 210 ((sep)->se_type == MUXPLUS_TYPE)) 211#define ISMUXPLUS(sep) ((sep)->se_type == MUXPLUS_TYPE) 212 213 214void chargen_dg __P((int, struct servtab *)); 215void chargen_stream __P((int, struct servtab *)); 216void close_sep __P((struct servtab *)); 217void config __P((int)); 218void daytime_dg __P((int, struct servtab *)); 219void daytime_stream __P((int, struct servtab *)); 220void discard_dg __P((int, struct servtab *)); 221void discard_stream __P((int, struct servtab *)); 222void echo_dg __P((int, struct servtab *)); 223void echo_stream __P((int, struct servtab *)); 224void endconfig __P((void)); 225struct servtab *enter __P((struct servtab *)); 226void freeconfig __P((struct servtab *)); 227struct servtab *getconfigent __P((void)); 228void machtime_dg __P((int, struct servtab *)); 229void machtime_stream __P((int, struct servtab *)); 230char *newstr __P((char *)); 231char *nextline __P((FILE *)); 232void print_service __P((char *, struct servtab *)); 233void addchild __P((struct servtab *, int)); 234void reapchild __P((int)); 235void enable __P((struct servtab *)); 236void disable __P((struct servtab *)); 237void retry __P((int)); 238int setconfig __P((void)); 239void setup __P((struct servtab *)); 240char *sskip __P((char **)); 241char *skip __P((char **)); 242struct servtab *tcpmux __P((int)); 243int cpmip __P((struct servtab *, int)); 244 245void unregisterrpc __P((register struct servtab *sep)); 246 247struct biltin { 248 char *bi_service; /* internally provided service name */ 249 int bi_socktype; /* type of socket supported */ 250 short bi_fork; /* 1 if should fork before call */ 251 int bi_maxchild; /* max number of children (default) */ 252 void (*bi_fn)(); /* function which performs it */ 253} biltins[] = { 254 /* Echo received data */ 255 { "echo", SOCK_STREAM, 1, 0, echo_stream }, 256 { "echo", SOCK_DGRAM, 0, 0, echo_dg }, 257 258 /* Internet /dev/null */ 259 { "discard", SOCK_STREAM, 1, 0, discard_stream }, 260 { "discard", SOCK_DGRAM, 0, 0, discard_dg }, 261 262 /* Return 32 bit time since 1970 */ 263 { "time", SOCK_STREAM, 0, 0, machtime_stream }, 264 { "time", SOCK_DGRAM, 0, 0, machtime_dg }, 265 266 /* Return human-readable time */ 267 { "daytime", SOCK_STREAM, 0, 0, daytime_stream }, 268 { "daytime", SOCK_DGRAM, 0, 0, daytime_dg }, 269 270 /* Familiar character generator */ 271 { "chargen", SOCK_STREAM, 1, 0, chargen_stream }, 272 { "chargen", SOCK_DGRAM, 0, 0, chargen_dg }, 273 274 { "tcpmux", SOCK_STREAM, 1, 0, (void (*)())tcpmux }, 275 276 { NULL } 277}; 278 279#define NUMINT (sizeof(intab) / sizeof(struct inent)) 280char *CONFIG = _PATH_INETDCONF; 281char *pid_file = _PATH_INETDPID; 282 283#ifdef OLD_SETPROCTITLE 284char **Argv; 285char *LastArg; 286#endif 287 288int 289getvalue(arg, value, whine) 290 char *arg, *whine; 291 int *value; 292{ 293 int tmp; 294 char *p; 295 296 tmp = strtol(arg, &p, 0); 297 if (tmp < 1 || *p) { 298 syslog(LOG_ERR, whine, arg); 299 return 1; /* failure */ 300 } 301 *value = tmp; 302 return 0; /* success */ 303} 304 305int 306main(argc, argv, envp) 307 int argc; 308 char *argv[], *envp[]; 309{ 310 struct servtab *sep; 311 struct passwd *pwd; 312 struct group *grp; 313 struct sigvec sv; 314 int tmpint, ch, dofork; 315 pid_t pid; 316 char buf[50]; 317 struct sockaddr_in peer; 318 int i; 319#ifdef LOGIN_CAP 320 login_cap_t *lc = NULL; 321#endif 322 323 324#ifdef OLD_SETPROCTITLE 325 Argv = argv; 326 if (envp == 0 || *envp == 0) 327 envp = argv; 328 while (*envp) 329 envp++; 330 LastArg = envp[-1] + strlen(envp[-1]); 331#endif 332 333 openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 334 335 bind_address.s_addr = htonl(INADDR_ANY); 336 while ((ch = getopt(argc, argv, "dlR:a:c:C:p:")) != -1) 337 switch(ch) { 338 case 'd': 339 debug = 1; 340 options |= SO_DEBUG; 341 break; 342 case 'l': 343 log = 1; 344 break; 345 case 'R': 346 getvalue(optarg, &toomany, 347 "-R %s: bad value for service invocation rate"); 348 break; 349 case 'c': 350 getvalue(optarg, &maxchild, 351 "-c %s: bad value for maximum children"); 352 break; 353 case 'C': 354 getvalue(optarg, &maxcpm, 355 "-C %s: bad value for maximum children/minute"); 356 break; 357 case 'a': 358 if (!inet_aton(optarg, &bind_address)) { 359 syslog(LOG_ERR, 360 "-a %s: invalid IP address", optarg); 361 exit(EX_USAGE); 362 } 363 break; 364 case 'p': 365 pid_file = optarg; 366 break; 367 case '?': 368 default: 369 syslog(LOG_ERR, 370 "usage: inetd [-dl] [-a address] [-R rate]" 371 " [-c maximum] [-C rate]" 372 " [-p pidfile] [conf-file]"); 373 exit(EX_USAGE); 374 } 375 argc -= optind; 376 argv += optind; 377 378 if (argc > 0) 379 CONFIG = argv[0]; 380 if (debug == 0) { 381 FILE *fp; 382 if (daemon(0, 0) < 0) { 383 syslog(LOG_WARNING, "daemon(0,0) failed: %m"); 384 } 385 /* 386 * In case somebody has started inetd manually, we need to 387 * clear the logname, so that old servers run as root do not 388 * get the user's logname.. 389 */ 390 if (setlogin("") < 0) { 391 syslog(LOG_WARNING, "cannot clear logname: %m"); 392 /* no big deal if it fails.. */ 393 } 394 pid = getpid(); 395 fp = fopen(pid_file, "w"); 396 if (fp) { 397 fprintf(fp, "%ld\n", (long)pid); 398 fclose(fp); 399 } else { 400 syslog(LOG_WARNING, "%s: %m", pid_file); 401 } 402 } 403 memset(&sv, 0, sizeof(sv)); 404 sv.sv_mask = SIGBLOCK; 405 sv.sv_handler = retry; 406 sigvec(SIGALRM, &sv, (struct sigvec *)0); 407 config(SIGHUP); 408 sv.sv_handler = config; 409 sigvec(SIGHUP, &sv, (struct sigvec *)0); 410 sv.sv_handler = reapchild; 411 sigvec(SIGCHLD, &sv, (struct sigvec *)0); 412 sv.sv_handler = SIG_IGN; 413 sigvec(SIGPIPE, &sv, (struct sigvec *)0); 414 415 { 416 /* space for daemons to overwrite environment for ps */ 417#define DUMMYSIZE 100 418 char dummy[DUMMYSIZE]; 419 420 (void)memset(dummy, 'x', DUMMYSIZE - 1); 421 dummy[DUMMYSIZE - 1] = '\0'; 422 (void)setenv("inetd_dummy", dummy, 1); 423 } 424 425 for (;;) { 426 int n, ctrl; 427 fd_set readable; 428 429 if (nsock == 0) { 430 (void) sigblock(SIGBLOCK); 431 while (nsock == 0) 432 sigpause(0L); 433 (void) sigsetmask(0L); 434 } 435 readable = allsock; 436 if ((n = select(maxsock + 1, &readable, (fd_set *)0, 437 (fd_set *)0, (struct timeval *)0)) <= 0) { 438 if (n < 0 && errno != EINTR) { 439 syslog(LOG_WARNING, "select: %m"); 440 sleep(1); 441 } 442 continue; 443 } 444 for (sep = servtab; n && sep; sep = sep->se_next) 445 if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 446 n--; 447 if (debug) 448 warnx("someone wants %s", sep->se_service); 449 if (sep->se_accept && sep->se_socktype == SOCK_STREAM) { 450 ctrl = accept(sep->se_fd, (struct sockaddr *)0, 451 (int *)0); 452 if (debug) 453 warnx("accept, ctrl %d", ctrl); 454 if (ctrl < 0) { 455 if (errno != EINTR) 456 syslog(LOG_WARNING, 457 "accept (for %s): %m", 458 sep->se_service); 459 continue; 460 } 461 if (cpmip(sep, ctrl) < 0) { 462 close(ctrl); 463 continue; 464 } 465 if (log) { 466 i = sizeof peer; 467 if (getpeername(ctrl, (struct sockaddr *) 468 &peer, &i)) { 469 syslog(LOG_WARNING, 470 "getpeername(for %s): %m", 471 sep->se_service); 472 close(ctrl); 473 continue; 474 } 475 syslog(LOG_INFO,"%s from %s", 476 sep->se_service, 477 inet_ntoa(peer.sin_addr)); 478 } 479 } else 480 ctrl = sep->se_fd; 481 (void) sigblock(SIGBLOCK); 482 pid = 0; 483 dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork); 484 if (dofork) { 485 if (sep->se_count++ == 0) 486 (void)gettimeofday(&sep->se_time, 487 (struct timezone *)0); 488 else if (sep->se_count >= toomany) { 489 struct timeval now; 490 491 (void)gettimeofday(&now, (struct timezone *)0); 492 if (now.tv_sec - sep->se_time.tv_sec > 493 CNT_INTVL) { 494 sep->se_time = now; 495 sep->se_count = 1; 496 } else { 497 syslog(LOG_ERR, 498 "%s/%s server failing (looping), service terminated", 499 sep->se_service, sep->se_proto); 500 close_sep(sep); 501 sigsetmask(0L); 502 if (!timingout) { 503 timingout = 1; 504 alarm(RETRYTIME); 505 } 506 continue; 507 } 508 } 509 pid = fork(); 510 } 511 if (pid < 0) { 512 syslog(LOG_ERR, "fork: %m"); 513 if (sep->se_accept && 514 sep->se_socktype == SOCK_STREAM) 515 close(ctrl); 516 sigsetmask(0L); 517 sleep(1); 518 continue; 519 } 520 if (pid) 521 addchild(sep, pid); 522 sigsetmask(0L); 523 if (pid == 0) { 524 if (dofork) { 525 if (debug) 526 warnx("+ closing from %d", maxsock); 527 for (tmpint = maxsock; tmpint > 2; tmpint--) 528 if (tmpint != ctrl) 529 (void) close(tmpint); 530 } 531 /* 532 * Call tcpmux to find the real service to exec. 533 */ 534 if (sep->se_bi && 535 sep->se_bi->bi_fn == (void (*)()) tcpmux) { 536 sep = tcpmux(ctrl); 537 if (sep == NULL) { 538 close(ctrl); 539 _exit(0); 540 } 541 } 542 if (sep->se_bi) { 543 (*sep->se_bi->bi_fn)(ctrl, sep); 544 /* NOTREACHED */ 545 } else { 546 if (debug) 547 warnx("%d execl %s", 548 getpid(), sep->se_server); 549 dup2(ctrl, 0); 550 close(ctrl); 551 dup2(0, 1); 552 dup2(0, 2); 553 if ((pwd = getpwnam(sep->se_user)) == NULL) { 554 syslog(LOG_ERR, 555 "%s/%s: %s: No such user", 556 sep->se_service, sep->se_proto, 557 sep->se_user); 558 if (sep->se_socktype != SOCK_STREAM) 559 recv(0, buf, sizeof (buf), 0); 560 _exit(EX_NOUSER); 561 } 562 grp = NULL; 563 if ( sep->se_group != NULL 564 && (grp = getgrnam(sep->se_group)) == NULL 565 ) { 566 syslog(LOG_ERR, 567 "%s/%s: %s: No such group", 568 sep->se_service, sep->se_proto, 569 sep->se_group); 570 if (sep->se_socktype != SOCK_STREAM) 571 recv(0, buf, sizeof (buf), 0); 572 _exit(EX_NOUSER); 573 } 574 if (grp != NULL) 575 pwd->pw_gid = grp->gr_gid; 576#ifdef LOGIN_CAP 577 if ((lc = login_getclass(sep->se_class)) == NULL) { 578 /* error syslogged by getclass */ 579 syslog(LOG_ERR, 580 "%s/%s: %s: login class error", 581 sep->se_service, sep->se_proto); 582 if (sep->se_socktype != SOCK_STREAM) 583 recv(0, buf, sizeof (buf), 0); 584 _exit(EX_NOUSER); 585 } 586#endif 587 if (setsid() < 0) { 588 syslog(LOG_ERR, 589 "%s: can't setsid(): %m", 590 sep->se_service); 591 /* _exit(EX_OSERR); not fatal yet */ 592 } 593#ifdef LOGIN_CAP 594 if (setusercontext(lc, pwd, pwd->pw_uid, 595 LOGIN_SETALL) != 0) { 596 syslog(LOG_ERR, 597 "%s: can't setusercontext(..%s..): %m", 598 sep->se_service, sep->se_user); 599 _exit(EX_OSERR); 600 } 601#else 602 if (pwd->pw_uid) { 603 if (setlogin(sep->se_user) < 0) { 604 syslog(LOG_ERR, 605 "%s: can't setlogin(%s): %m", 606 sep->se_service, sep->se_user); 607 /* _exit(EX_OSERR); not yet */ 608 } 609 if (setgid(pwd->pw_gid) < 0) { 610 syslog(LOG_ERR, 611 "%s: can't set gid %d: %m", 612 sep->se_service, pwd->pw_gid); 613 _exit(EX_OSERR); 614 } 615 (void) initgroups(pwd->pw_name, 616 pwd->pw_gid); 617 if (setuid(pwd->pw_uid) < 0) { 618 syslog(LOG_ERR, 619 "%s: can't set uid %d: %m", 620 sep->se_service, pwd->pw_uid); 621 _exit(EX_OSERR); 622 } 623 } 624#endif 625 execv(sep->se_server, sep->se_argv); 626 if (sep->se_socktype != SOCK_STREAM) 627 recv(0, buf, sizeof (buf), 0); 628 syslog(LOG_ERR, 629 "cannot execute %s: %m", sep->se_server); 630 _exit(EX_OSERR); 631 } 632 } 633 if (sep->se_accept && sep->se_socktype == SOCK_STREAM) 634 close(ctrl); 635 } 636 } 637} 638 639/* 640 * Record a new child pid for this service. If we've reached the 641 * limit on children, then stop accepting incoming requests. 642 */ 643 644void 645addchild(struct servtab *sep, pid_t pid) 646{ 647#ifdef SANITY_CHECK 648 if (sep->se_numchild >= sep->se_maxchild) { 649 syslog(LOG_ERR, "%s: %d >= %d", 650 __FUNCTION__, sep->se_numchild, sep->se_maxchild); 651 exit(EX_SOFTWARE); 652 } 653#endif 654 if (sep->se_maxchild == 0) 655 return; 656 sep->se_pids[sep->se_numchild++] = pid; 657 if (sep->se_numchild == sep->se_maxchild) 658 disable(sep); 659} 660 661/* 662 * Some child process has exited. See if it's on somebody's list. 663 */ 664 665void 666reapchild(signo) 667 int signo; 668{ 669 int k, status; 670 pid_t pid; 671 struct servtab *sep; 672 673 for (;;) { 674 pid = wait3(&status, WNOHANG, (struct rusage *)0); 675 if (pid <= 0) 676 break; 677 if (debug) 678 warnx("%d reaped, status %#x", pid, status); 679 for (sep = servtab; sep; sep = sep->se_next) { 680 for (k = 0; k < sep->se_numchild; k++) 681 if (sep->se_pids[k] == pid) 682 break; 683 if (k == sep->se_numchild) 684 continue; 685 if (sep->se_numchild == sep->se_maxchild) 686 enable(sep); 687 sep->se_pids[k] = sep->se_pids[--sep->se_numchild]; 688 if (status) 689 syslog(LOG_WARNING, 690 "%s[%d]: exit status 0x%x", 691 sep->se_server, pid, status); 692 break; 693 } 694 } 695} 696 697void 698config(signo) 699 int signo; 700{ 701 struct servtab *sep, *new, **sepp; 702 long omask; 703 704 if (!setconfig()) { 705 syslog(LOG_ERR, "%s: %m", CONFIG); 706 return; 707 } 708 for (sep = servtab; sep; sep = sep->se_next) 709 sep->se_checked = 0; 710 while ((new = getconfigent())) { 711 if (getpwnam(new->se_user) == NULL) { 712 syslog(LOG_ERR, 713 "%s/%s: No such user '%s', service ignored", 714 new->se_service, new->se_proto, new->se_user); 715 continue; 716 } 717 if (new->se_group && getgrnam(new->se_group) == NULL) { 718 syslog(LOG_ERR, 719 "%s/%s: No such group '%s', service ignored", 720 new->se_service, new->se_proto, new->se_group); 721 continue; 722 } 723#ifdef LOGIN_CAP 724 if (login_getclass(new->se_class) == NULL) { 725 /* error syslogged by getclass */ 726 syslog(LOG_ERR, 727 "%s/%s: login class error, service ignored", 728 new->se_service, new->se_proto); 729 continue; 730 } 731#endif 732 for (sep = servtab; sep; sep = sep->se_next) 733 if (strcmp(sep->se_service, new->se_service) == 0 && 734 strcmp(sep->se_proto, new->se_proto) == 0) 735 break; 736 if (sep != 0) { 737 int i; 738 739#define SWAP(a, b) { typeof(a) c = a; a = b; b = c; } 740 omask = sigblock(SIGBLOCK); 741 /* copy over outstanding child pids */ 742 if (sep->se_maxchild && new->se_maxchild) { 743 new->se_numchild = sep->se_numchild; 744 if (new->se_numchild > new->se_maxchild) 745 new->se_numchild = new->se_maxchild; 746 memcpy(new->se_pids, sep->se_pids, 747 new->se_numchild * sizeof(*new->se_pids)); 748 } 749 SWAP(sep->se_pids, new->se_pids); 750 sep->se_maxchild = new->se_maxchild; 751 sep->se_numchild = new->se_numchild; 752 sep->se_maxcpm = new->se_maxcpm; 753 /* might need to turn on or off service now */ 754 if (sep->se_fd >= 0) { 755 if (sep->se_maxchild 756 && sep->se_numchild == sep->se_maxchild) { 757 if (FD_ISSET(sep->se_fd, &allsock)) 758 disable(sep); 759 } else { 760 if (!FD_ISSET(sep->se_fd, &allsock)) 761 enable(sep); 762 } 763 } 764 sep->se_accept = new->se_accept; 765 SWAP(sep->se_user, new->se_user); 766 SWAP(sep->se_group, new->se_group); 767#ifdef LOGIN_CAP 768 SWAP(sep->se_class, new->se_class); 769#endif 770 SWAP(sep->se_server, new->se_server); 771 for (i = 0; i < MAXARGV; i++) 772 SWAP(sep->se_argv[i], new->se_argv[i]); 773 sigsetmask(omask); 774 freeconfig(new); 775 if (debug) 776 print_service("REDO", sep); 777 } else { 778 sep = enter(new); 779 if (debug) 780 print_service("ADD ", sep); 781 } 782 sep->se_checked = 1; 783 if (ISMUX(sep)) { 784 sep->se_fd = -1; 785 continue; 786 } 787 if (!sep->se_rpc) { 788 sp = getservbyname(sep->se_service, sep->se_proto); 789 if (sp == 0) { 790 syslog(LOG_ERR, "%s/%s: unknown service", 791 sep->se_service, sep->se_proto); 792 sep->se_checked = 0; 793 continue; 794 } 795 if (sp->s_port != sep->se_ctrladdr.sin_port) { 796 sep->se_ctrladdr.sin_family = AF_INET; 797 sep->se_ctrladdr.sin_addr = bind_address; 798 sep->se_ctrladdr.sin_port = sp->s_port; 799 if (sep->se_fd >= 0) 800 close_sep(sep); 801 } 802 } else { 803 rpc = getrpcbyname(sep->se_service); 804 if (rpc == 0) { 805 syslog(LOG_ERR, "%s/%s unknown RPC service.", 806 sep->se_service, sep->se_proto); 807 if (sep->se_fd != -1) 808 (void) close(sep->se_fd); 809 sep->se_fd = -1; 810 continue; 811 } 812 if (rpc->r_number != sep->se_rpc_prog) { 813 if (sep->se_rpc_prog) 814 unregisterrpc(sep); 815 sep->se_rpc_prog = rpc->r_number; 816 if (sep->se_fd != -1) 817 (void) close(sep->se_fd); 818 sep->se_fd = -1; 819 } 820 } 821 if (sep->se_fd == -1) 822 setup(sep); 823 } 824 endconfig(); 825 /* 826 * Purge anything not looked at above. 827 */ 828 omask = sigblock(SIGBLOCK); 829 sepp = &servtab; 830 while ((sep = *sepp)) { 831 if (sep->se_checked) { 832 sepp = &sep->se_next; 833 continue; 834 } 835 *sepp = sep->se_next; 836 if (sep->se_fd >= 0) 837 close_sep(sep); 838 if (debug) 839 print_service("FREE", sep); 840 if (sep->se_rpc && sep->se_rpc_prog > 0) 841 unregisterrpc(sep); 842 freeconfig(sep); 843 free((char *)sep); 844 } 845 (void) sigsetmask(omask); 846} 847 848void 849unregisterrpc(sep) 850 struct servtab *sep; 851{ 852 int i; 853 struct servtab *sepp; 854 long omask; 855 856 omask = sigblock(SIGBLOCK); 857 for (sepp = servtab; sepp; sepp = sepp->se_next) { 858 if (sepp == sep) 859 continue; 860 if (sep->se_checked == 0 || 861 !sepp->se_rpc || 862 sep->se_rpc_prog != sepp->se_rpc_prog) 863 continue; 864 return; 865 } 866 if (debug) 867 print_service("UNREG", sep); 868 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) 869 pmap_unset(sep->se_rpc_prog, i); 870 if (sep->se_fd != -1) 871 (void) close(sep->se_fd); 872 sep->se_fd = -1; 873 (void) sigsetmask(omask); 874} 875 876void 877retry(signo) 878 int signo; 879{ 880 struct servtab *sep; 881 882 timingout = 0; 883 for (sep = servtab; sep; sep = sep->se_next) 884 if (sep->se_fd == -1 && !ISMUX(sep)) 885 setup(sep); 886} 887 888void 889setup(sep) 890 struct servtab *sep; 891{ 892 int on = 1; 893 894 if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 895 if (debug) 896 warn("socket failed on %s/%s", 897 sep->se_service, sep->se_proto); 898 syslog(LOG_ERR, "%s/%s: socket: %m", 899 sep->se_service, sep->se_proto); 900 return; 901 } 902#define turnon(fd, opt) \ 903setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 904 if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 905 turnon(sep->se_fd, SO_DEBUG) < 0) 906 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 907 if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 908 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 909#ifdef SO_PRIVSTATE 910 if (turnon(sep->se_fd, SO_PRIVSTATE) < 0) 911 syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m"); 912#endif 913#undef turnon 914 if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 915 sizeof (sep->se_ctrladdr)) < 0) { 916 if (debug) 917 warn("bind failed on %s/%s", 918 sep->se_service, sep->se_proto); 919 syslog(LOG_ERR, "%s/%s: bind: %m", 920 sep->se_service, sep->se_proto); 921 (void) close(sep->se_fd); 922 sep->se_fd = -1; 923 if (!timingout) { 924 timingout = 1; 925 alarm(RETRYTIME); 926 } 927 return; 928 } 929 if (sep->se_rpc) { 930 int i, len = sizeof(struct sockaddr); 931 932 if (getsockname(sep->se_fd, 933 (struct sockaddr*)&sep->se_ctrladdr, &len) < 0){ 934 syslog(LOG_ERR, "%s/%s: getsockname: %m", 935 sep->se_service, sep->se_proto); 936 (void) close(sep->se_fd); 937 sep->se_fd = -1; 938 return; 939 } 940 if (debug) 941 print_service("REG ", sep); 942 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 943 pmap_unset(sep->se_rpc_prog, i); 944 pmap_set(sep->se_rpc_prog, i, 945 (sep->se_socktype == SOCK_DGRAM) 946 ? IPPROTO_UDP : IPPROTO_TCP, 947 ntohs(sep->se_ctrladdr.sin_port)); 948 } 949 950 } 951 if (sep->se_socktype == SOCK_STREAM) 952 listen(sep->se_fd, 64); 953 enable(sep); 954 if (debug) { 955 warnx("registered %s on %d", 956 sep->se_server, sep->se_fd); 957 } 958} 959 960/* 961 * Finish with a service and its socket. 962 */ 963void 964close_sep(sep) 965 struct servtab *sep; 966{ 967 if (sep->se_fd >= 0) { 968 if (FD_ISSET(sep->se_fd, &allsock)) 969 disable(sep); 970 (void) close(sep->se_fd); 971 sep->se_fd = -1; 972 } 973 sep->se_count = 0; 974 sep->se_numchild = 0; /* forget about any existing children */ 975} 976 977struct servtab * 978enter(cp) 979 struct servtab *cp; 980{ 981 struct servtab *sep; 982 long omask; 983 984 sep = (struct servtab *)malloc(sizeof (*sep)); 985 if (sep == (struct servtab *)0) { 986 syslog(LOG_ERR, "Out of memory."); 987 exit(EX_OSERR); 988 } 989 *sep = *cp; 990 sep->se_fd = -1; 991 omask = sigblock(SIGBLOCK); 992 sep->se_next = servtab; 993 servtab = sep; 994 sigsetmask(omask); 995 return (sep); 996} 997 998void 999enable(struct servtab *sep) 1000{ 1001 if (debug) 1002 warnx( 1003 "enabling %s, fd %d", sep->se_service, sep->se_fd); 1004#ifdef SANITY_CHECK 1005 if (sep->se_fd < 0) { 1006 syslog(LOG_ERR, 1007 "%s: %s: bad fd", __FUNCTION__, sep->se_service); 1008 exit(EX_SOFTWARE); 1009 } 1010 if (ISMUX(sep)) { 1011 syslog(LOG_ERR, 1012 "%s: %s: is mux", __FUNCTION__, sep->se_service); 1013 exit(EX_SOFTWARE); 1014 } 1015 if (FD_ISSET(sep->se_fd, &allsock)) { 1016 syslog(LOG_ERR, 1017 "%s: %s: not off", __FUNCTION__, sep->se_service); 1018 exit(EX_SOFTWARE); 1019 } 1020#endif 1021 FD_SET(sep->se_fd, &allsock); 1022 nsock++; 1023 if (sep->se_fd > maxsock) 1024 maxsock = sep->se_fd; 1025} 1026 1027void 1028disable(struct servtab *sep) 1029{ 1030 if (debug) 1031 warnx( 1032 "disabling %s, fd %d", sep->se_service, sep->se_fd); 1033#ifdef SANITY_CHECK 1034 if (sep->se_fd < 0) { 1035 syslog(LOG_ERR, 1036 "%s: %s: bad fd", __FUNCTION__, sep->se_service); 1037 exit(EX_SOFTWARE); 1038 } 1039 if (ISMUX(sep)) { 1040 syslog(LOG_ERR, 1041 "%s: %s: is mux", __FUNCTION__, sep->se_service); 1042 exit(EX_SOFTWARE); 1043 } 1044 if (!FD_ISSET(sep->se_fd, &allsock)) { 1045 syslog(LOG_ERR, 1046 "%s: %s: not on", __FUNCTION__, sep->se_service); 1047 exit(EX_SOFTWARE); 1048 } 1049 if (nsock == 0) { 1050 syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__); 1051 exit(EX_SOFTWARE); 1052 } 1053#endif 1054 FD_CLR(sep->se_fd, &allsock); 1055 nsock--; 1056 if (sep->se_fd == maxsock) 1057 maxsock--; 1058} 1059 1060FILE *fconfig = NULL; 1061struct servtab serv; 1062char line[LINE_MAX]; 1063 1064int 1065setconfig() 1066{ 1067 1068 if (fconfig != NULL) { 1069 fseek(fconfig, 0L, SEEK_SET); 1070 return (1); 1071 } 1072 fconfig = fopen(CONFIG, "r"); 1073 return (fconfig != NULL); 1074} 1075 1076void 1077endconfig() 1078{ 1079 if (fconfig) { 1080 (void) fclose(fconfig); 1081 fconfig = NULL; 1082 } 1083} 1084 1085struct servtab * 1086getconfigent() 1087{ 1088 struct servtab *sep = &serv; 1089 int argc; 1090 char *cp, *arg, *s; 1091 char *versp; 1092 static char TCPMUX_TOKEN[] = "tcpmux/"; 1093#define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 1094 1095more: 1096 while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0')) 1097 ; 1098 if (cp == NULL) 1099 return ((struct servtab *)0); 1100 /* 1101 * clear the static buffer, since some fields (se_ctrladdr, 1102 * for example) don't get initialized here. 1103 */ 1104 memset((caddr_t)sep, 0, sizeof *sep); 1105 arg = skip(&cp); 1106 if (cp == NULL) { 1107 /* got an empty line containing just blanks/tabs. */ 1108 goto more; 1109 } 1110 if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 1111 char *c = arg + MUX_LEN; 1112 if (*c == '+') { 1113 sep->se_type = MUXPLUS_TYPE; 1114 c++; 1115 } else 1116 sep->se_type = MUX_TYPE; 1117 sep->se_service = newstr(c); 1118 } else { 1119 sep->se_service = newstr(arg); 1120 sep->se_type = NORM_TYPE; 1121 } 1122 arg = sskip(&cp); 1123 if (strcmp(arg, "stream") == 0) 1124 sep->se_socktype = SOCK_STREAM; 1125 else if (strcmp(arg, "dgram") == 0) 1126 sep->se_socktype = SOCK_DGRAM; 1127 else if (strcmp(arg, "rdm") == 0) 1128 sep->se_socktype = SOCK_RDM; 1129 else if (strcmp(arg, "seqpacket") == 0) 1130 sep->se_socktype = SOCK_SEQPACKET; 1131 else if (strcmp(arg, "raw") == 0) 1132 sep->se_socktype = SOCK_RAW; 1133 else 1134 sep->se_socktype = -1; 1135 sep->se_proto = newstr(sskip(&cp)); 1136 if (strncmp(sep->se_proto, "rpc/", 4) == 0) { 1137 memmove(sep->se_proto, sep->se_proto + 4, 1138 strlen(sep->se_proto) + 1 - 4); 1139 sep->se_rpc = 1; 1140 sep->se_rpc_prog = sep->se_rpc_lowvers = 1141 sep->se_rpc_lowvers = 0; 1142 sep->se_ctrladdr.sin_family = AF_INET; 1143 sep->se_ctrladdr.sin_port = 0; 1144 sep->se_ctrladdr.sin_addr = bind_address; 1145 if ((versp = rindex(sep->se_service, '/'))) { 1146 *versp++ = '\0'; 1147 switch (sscanf(versp, "%d-%d", 1148 &sep->se_rpc_lowvers, 1149 &sep->se_rpc_highvers)) { 1150 case 2: 1151 break; 1152 case 1: 1153 sep->se_rpc_highvers = 1154 sep->se_rpc_lowvers; 1155 break; 1156 default: 1157 syslog(LOG_ERR, 1158 "bad RPC version specifier; %s\n", 1159 sep->se_service); 1160 freeconfig(sep); 1161 goto more; 1162 } 1163 } 1164 else { 1165 sep->se_rpc_lowvers = 1166 sep->se_rpc_highvers = 1; 1167 } 1168 } 1169 arg = sskip(&cp); 1170 if (!strncmp(arg, "wait", 4)) 1171 sep->se_accept = 0; 1172 else if (!strncmp(arg, "nowait", 6)) 1173 sep->se_accept = 1; 1174 else { 1175 syslog(LOG_ERR, 1176 "%s: bad wait/nowait for service %s", 1177 CONFIG, sep->se_service); 1178 goto more; 1179 } 1180 sep->se_maxchild = maxchild; 1181 sep->se_maxcpm = maxcpm; 1182 if ((s = strchr(arg, '/')) != NULL) { 1183 char *eptr; 1184 u_long val; 1185 1186 val = strtoul(s + 1, &eptr, 10); 1187 if (eptr == s + 1 || val > MAX_MAXCHLD) { 1188 syslog(LOG_ERR, 1189 "%s: bad max-child for service %s", 1190 CONFIG, sep->se_service); 1191 goto more; 1192 } 1193 sep->se_maxchild = val; 1194 if (*eptr == '/') 1195 sep->se_maxcpm = strtol(eptr + 1, &eptr, 10); 1196 /* 1197 * explicitly do not check for \0 for future expansion / 1198 * backwards compatibility 1199 */ 1200 } 1201 if (ISMUX(sep)) { 1202 /* 1203 * Silently enforce "nowait" mode for TCPMUX services 1204 * since they don't have an assigned port to listen on. 1205 */ 1206 sep->se_accept = 1; 1207 if (strcmp(sep->se_proto, "tcp")) { 1208 syslog(LOG_ERR, 1209 "%s: bad protocol for tcpmux service %s", 1210 CONFIG, sep->se_service); 1211 goto more; 1212 } 1213 if (sep->se_socktype != SOCK_STREAM) { 1214 syslog(LOG_ERR, 1215 "%s: bad socket type for tcpmux service %s", 1216 CONFIG, sep->se_service); 1217 goto more; 1218 } 1219 } 1220 sep->se_user = newstr(sskip(&cp)); 1221#ifdef LOGIN_CAP 1222 if ((s = strrchr(sep->se_user, '/')) != NULL) { 1223 *s = '\0'; 1224 sep->se_class = newstr(s + 1); 1225 } else 1226 sep->se_class = newstr(RESOURCE_RC); 1227#endif 1228 if ((s = strrchr(sep->se_user, ':')) != NULL) { 1229 *s = '\0'; 1230 sep->se_group = newstr(s + 1); 1231 } else 1232 sep->se_group = NULL; 1233 sep->se_server = newstr(sskip(&cp)); 1234 if (strcmp(sep->se_server, "internal") == 0) { 1235 struct biltin *bi; 1236 1237 for (bi = biltins; bi->bi_service; bi++) 1238 if (bi->bi_socktype == sep->se_socktype && 1239 strcmp(bi->bi_service, sep->se_service) == 0) 1240 break; 1241 if (bi->bi_service == 0) { 1242 syslog(LOG_ERR, "internal service %s unknown", 1243 sep->se_service); 1244 goto more; 1245 } 1246 sep->se_accept = 1; /* force accept mode for built-ins */ 1247 sep->se_bi = bi; 1248 } else 1249 sep->se_bi = NULL; 1250 if (sep->se_maxchild < 0) /* apply default max-children */ 1251 if (sep->se_bi) 1252 sep->se_maxchild = sep->se_bi->bi_maxchild; 1253 else 1254 sep->se_maxchild = sep->se_accept ? 0 : 1; 1255 if (sep->se_maxchild) { 1256 sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids)); 1257 if (sep->se_pids == NULL) { 1258 syslog(LOG_ERR, "Out of memory."); 1259 exit(EX_OSERR); 1260 } 1261 } 1262 argc = 0; 1263 for (arg = skip(&cp); cp; arg = skip(&cp)) 1264 if (argc < MAXARGV) { 1265 sep->se_argv[argc++] = newstr(arg); 1266 } else { 1267 syslog(LOG_ERR, 1268 "%s: too many arguments for service %s", 1269 CONFIG, sep->se_service); 1270 goto more; 1271 } 1272 while (argc <= MAXARGV) 1273 sep->se_argv[argc++] = NULL; 1274 return (sep); 1275} 1276 1277void 1278freeconfig(cp) 1279 struct servtab *cp; 1280{ 1281 int i; 1282 1283 if (cp->se_service) 1284 free(cp->se_service); 1285 if (cp->se_proto) 1286 free(cp->se_proto); 1287 if (cp->se_user) 1288 free(cp->se_user); 1289 if (cp->se_group) 1290 free(cp->se_group); 1291#ifdef LOGIN_CAP 1292 if (cp->se_class) 1293 free(cp->se_class); 1294#endif 1295 if (cp->se_server) 1296 free(cp->se_server); 1297 if (cp->se_pids) 1298 free(cp->se_pids); 1299 for (i = 0; i < MAXARGV; i++) 1300 if (cp->se_argv[i]) 1301 free(cp->se_argv[i]); 1302} 1303 1304 1305/* 1306 * Safe skip - if skip returns null, log a syntax error in the 1307 * configuration file and exit. 1308 */ 1309char * 1310sskip(cpp) 1311 char **cpp; 1312{ 1313 char *cp; 1314 1315 cp = skip(cpp); 1316 if (cp == NULL) { 1317 syslog(LOG_ERR, "%s: syntax error", CONFIG); 1318 exit(EX_DATAERR); 1319 } 1320 return (cp); 1321} 1322 1323char * 1324skip(cpp) 1325 char **cpp; 1326{ 1327 char *cp = *cpp; 1328 char *start; 1329 char quote = '\0'; 1330 1331again: 1332 while (*cp == ' ' || *cp == '\t') 1333 cp++; 1334 if (*cp == '\0') { 1335 int c; 1336 1337 c = getc(fconfig); 1338 (void) ungetc(c, fconfig); 1339 if (c == ' ' || c == '\t') 1340 if ((cp = nextline(fconfig))) 1341 goto again; 1342 *cpp = (char *)0; 1343 return ((char *)0); 1344 } 1345 if (*cp == '"' || *cp == '\'') 1346 quote = *cp++; 1347 start = cp; 1348 if (quote) 1349 while (*cp && *cp != quote) 1350 cp++; 1351 else 1352 while (*cp && *cp != ' ' && *cp != '\t') 1353 cp++; 1354 if (*cp != '\0') 1355 *cp++ = '\0'; 1356 *cpp = cp; 1357 return (start); 1358} 1359 1360char * 1361nextline(fd) 1362 FILE *fd; 1363{ 1364 char *cp; 1365 1366 if (fgets(line, sizeof (line), fd) == NULL) 1367 return ((char *)0); 1368 cp = strchr(line, '\n'); 1369 if (cp) 1370 *cp = '\0'; 1371 return (line); 1372} 1373 1374char * 1375newstr(cp) 1376 char *cp; 1377{ 1378 if ((cp = strdup(cp ? cp : ""))) 1379 return (cp); 1380 syslog(LOG_ERR, "strdup: %m"); 1381 exit(EX_OSERR); 1382} 1383 1384#ifdef OLD_SETPROCTITLE 1385void 1386inetd_setproctitle(a, s) 1387 char *a; 1388 int s; 1389{ 1390 int size; 1391 char *cp; 1392 struct sockaddr_in sin; 1393 char buf[80]; 1394 1395 cp = Argv[0]; 1396 size = sizeof(sin); 1397 if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 1398 (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 1399 else 1400 (void) sprintf(buf, "-%s", a); 1401 strncpy(cp, buf, LastArg - cp); 1402 cp += strlen(cp); 1403 while (cp < LastArg) 1404 *cp++ = ' '; 1405} 1406#else 1407void 1408inetd_setproctitle(a, s) 1409 char *a; 1410 int s; 1411{ 1412 int size; 1413 struct sockaddr_in sin; 1414 char buf[80]; 1415 1416 size = sizeof(sin); 1417 if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 1418 (void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin.sin_addr)); 1419 else 1420 (void) sprintf(buf, "%s", a); 1421 setproctitle("%s", buf); 1422} 1423#endif 1424 1425 1426/* 1427 * Internet services provided internally by inetd: 1428 */ 1429#define BUFSIZE 8192 1430 1431/* ARGSUSED */ 1432void 1433echo_stream(s, sep) /* Echo service -- echo data back */ 1434 int s; 1435 struct servtab *sep; 1436{ 1437 char buffer[BUFSIZE]; 1438 int i; 1439 1440 inetd_setproctitle(sep->se_service, s); 1441 while ((i = read(s, buffer, sizeof(buffer))) > 0 && 1442 write(s, buffer, i) > 0) 1443 ; 1444 exit(0); 1445} 1446 1447int check_loop(sin, sep) 1448 struct sockaddr_in *sin; 1449 struct servtab *sep; 1450{ 1451 struct servtab *se2; 1452 1453 for (se2 = servtab; se2; se2 = se2->se_next) { 1454 if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM) 1455 continue; 1456 1457 if (sin->sin_port == se2->se_ctrladdr.sin_port) { 1458 syslog(LOG_WARNING, 1459 "%s/%s:%s/%s loop request REFUSED from %s", 1460 sep->se_service, sep->se_proto, 1461 se2->se_service, se2->se_proto, 1462 inet_ntoa(sin->sin_addr)); 1463 return 1; 1464 } 1465 } 1466 return 0; 1467} 1468 1469/* ARGSUSED */ 1470void 1471echo_dg(s, sep) /* Echo service -- echo data back */ 1472 int s; 1473 struct servtab *sep; 1474{ 1475 char buffer[BUFSIZE]; 1476 int i, size; 1477 struct sockaddr_in sin; 1478 1479 size = sizeof(sin); 1480 if ((i = recvfrom(s, buffer, sizeof(buffer), 0, 1481 (struct sockaddr *)&sin, &size)) < 0) 1482 return; 1483 1484 if (check_loop(&sin, sep)) 1485 return; 1486 1487 (void) sendto(s, buffer, i, 0, (struct sockaddr *)&sin, 1488 sizeof(sin)); 1489} 1490 1491/* ARGSUSED */ 1492void 1493discard_stream(s, sep) /* Discard service -- ignore data */ 1494 int s; 1495 struct servtab *sep; 1496{ 1497 int ret; 1498 char buffer[BUFSIZE]; 1499 1500 inetd_setproctitle(sep->se_service, s); 1501 while (1) { 1502 while ((ret = read(s, buffer, sizeof(buffer))) > 0) 1503 ; 1504 if (ret == 0 || errno != EINTR) 1505 break; 1506 } 1507 exit(0); 1508} 1509 1510/* ARGSUSED */ 1511void 1512discard_dg(s, sep) /* Discard service -- ignore data */ 1513 int s; 1514 struct servtab *sep; 1515{ 1516 char buffer[BUFSIZE]; 1517 1518 (void) read(s, buffer, sizeof(buffer)); 1519} 1520 1521#include <ctype.h> 1522#define LINESIZ 72 1523char ring[128]; 1524char *endring; 1525 1526void 1527initring() 1528{ 1529 int i; 1530 1531 endring = ring; 1532 1533 for (i = 0; i <= 128; ++i) 1534 if (isprint(i)) 1535 *endring++ = i; 1536} 1537 1538/* ARGSUSED */ 1539void 1540chargen_stream(s, sep) /* Character generator */ 1541 int s; 1542 struct servtab *sep; 1543{ 1544 int len; 1545 char *rs, text[LINESIZ+2]; 1546 1547 inetd_setproctitle(sep->se_service, s); 1548 1549 if (!endring) { 1550 initring(); 1551 rs = ring; 1552 } 1553 1554 text[LINESIZ] = '\r'; 1555 text[LINESIZ + 1] = '\n'; 1556 for (rs = ring;;) { 1557 if ((len = endring - rs) >= LINESIZ) 1558 memmove(text, rs, LINESIZ); 1559 else { 1560 memmove(text, rs, len); 1561 memmove(text + len, ring, LINESIZ - len); 1562 } 1563 if (++rs == endring) 1564 rs = ring; 1565 if (write(s, text, sizeof(text)) != sizeof(text)) 1566 break; 1567 } 1568 exit(0); 1569} 1570 1571/* ARGSUSED */ 1572void 1573chargen_dg(s, sep) /* Character generator */ 1574 int s; 1575 struct servtab *sep; 1576{ 1577 struct sockaddr_in sin; 1578 static char *rs; 1579 int len, size; 1580 char text[LINESIZ+2]; 1581 1582 if (endring == 0) { 1583 initring(); 1584 rs = ring; 1585 } 1586 1587 size = sizeof(sin); 1588 if (recvfrom(s, text, sizeof(text), 0, 1589 (struct sockaddr *)&sin, &size) < 0) 1590 return; 1591 1592 if (check_loop(&sin, sep)) 1593 return; 1594 1595 if ((len = endring - rs) >= LINESIZ) 1596 memmove(text, rs, LINESIZ); 1597 else { 1598 memmove(text, rs, len); 1599 memmove(text + len, ring, LINESIZ - len); 1600 } 1601 if (++rs == endring) 1602 rs = ring; 1603 text[LINESIZ] = '\r'; 1604 text[LINESIZ + 1] = '\n'; 1605 (void) sendto(s, text, sizeof(text), 0, 1606 (struct sockaddr *)&sin, sizeof(sin)); 1607} 1608 1609/* 1610 * Return a machine readable date and time, in the form of the 1611 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 1612 * returns the number of seconds since midnight, Jan 1, 1970, 1613 * we must add 2208988800 seconds to this figure to make up for 1614 * some seventy years Bell Labs was asleep. 1615 */ 1616 1617long 1618machtime() 1619{ 1620 struct timeval tv; 1621 1622 if (gettimeofday(&tv, (struct timezone *)0) < 0) { 1623 if (debug) 1624 warnx("unable to get time of day"); 1625 return (0L); 1626 } 1627#define OFFSET ((u_long)25567 * 24*60*60) 1628 return (htonl((long)(tv.tv_sec + OFFSET))); 1629#undef OFFSET 1630} 1631 1632/* ARGSUSED */ 1633void 1634machtime_stream(s, sep) 1635 int s; 1636 struct servtab *sep; 1637{ 1638 long result; 1639 1640 result = machtime(); 1641 (void) write(s, (char *) &result, sizeof(result)); 1642} 1643 1644/* ARGSUSED */ 1645void 1646machtime_dg(s, sep) 1647 int s; 1648 struct servtab *sep; 1649{ 1650 long result; 1651 struct sockaddr_in sin; 1652 int size; 1653 1654 size = sizeof(sin); 1655 if (recvfrom(s, (char *)&result, sizeof(result), 0, 1656 (struct sockaddr *)&sin, &size) < 0) 1657 return; 1658 1659 if (check_loop(&sin, sep)) 1660 return; 1661 1662 result = machtime(); 1663 (void) sendto(s, (char *) &result, sizeof(result), 0, 1664 (struct sockaddr *)&sin, sizeof(sin)); 1665} 1666 1667/* ARGSUSED */ 1668void 1669daytime_stream(s, sep) /* Return human-readable time of day */ 1670 int s; 1671 struct servtab *sep; 1672{ 1673 char buffer[256]; 1674 time_t clock; 1675 1676 clock = time((time_t *) 0); 1677 1678 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 1679 (void) write(s, buffer, strlen(buffer)); 1680} 1681 1682/* ARGSUSED */ 1683void 1684daytime_dg(s, sep) /* Return human-readable time of day */ 1685 int s; 1686 struct servtab *sep; 1687{ 1688 char buffer[256]; 1689 time_t clock; 1690 struct sockaddr_in sin; 1691 int size; 1692 1693 clock = time((time_t *) 0); 1694 1695 size = sizeof(sin); 1696 if (recvfrom(s, buffer, sizeof(buffer), 0, 1697 (struct sockaddr *)&sin, &size) < 0) 1698 return; 1699 1700 if (check_loop(&sin, sep)) 1701 return; 1702 1703 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 1704 (void) sendto(s, buffer, strlen(buffer), 0, 1705 (struct sockaddr *)&sin, sizeof(sin)); 1706} 1707 1708/* 1709 * print_service: 1710 * Dump relevant information to stderr 1711 */ 1712void 1713print_service(action, sep) 1714 char *action; 1715 struct servtab *sep; 1716{ 1717 fprintf(stderr, 1718#ifdef LOGIN_CAP 1719 "%s: %s proto=%s accept=%d max=%d user=%s group=%s class=%s builtin=%x server=%s\n", 1720#else 1721 "%s: %s proto=%s accept=%d max=%d user=%s group=%s builtin=%x server=%s\n", 1722#endif 1723 action, sep->se_service, sep->se_proto, 1724 sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group, 1725#ifdef LOGIN_CAP 1726 sep->se_class, 1727#endif 1728 (int)sep->se_bi, sep->se_server); 1729} 1730 1731/* 1732 * Based on TCPMUX.C by Mark K. Lottor November 1988 1733 * sri-nic::ps:<mkl>tcpmux.c 1734 */ 1735 1736 1737static int /* # of characters upto \r,\n or \0 */ 1738getline(fd, buf, len) 1739 int fd; 1740 char *buf; 1741 int len; 1742{ 1743 int count = 0, n; 1744 struct sigvec sv; 1745 1746 memset(&sv, 0, sizeof(sv)); 1747 sv.sv_handler = SIG_DFL; 1748 sigvec(SIGALRM, &sv, (struct sigvec *)0); 1749 do { 1750 alarm(10); 1751 n = read(fd, buf, len-count); 1752 alarm(0); 1753 if (n == 0) 1754 return (count); 1755 if (n < 0) 1756 return (-1); 1757 while (--n >= 0) { 1758 if (*buf == '\r' || *buf == '\n' || *buf == '\0') 1759 return (count); 1760 count++; 1761 buf++; 1762 } 1763 } while (count < len); 1764 return (count); 1765} 1766 1767#define MAX_SERV_LEN (256+2) /* 2 bytes for \r\n */ 1768 1769#define strwrite(fd, buf) (void) write(fd, buf, sizeof(buf)-1) 1770 1771struct servtab * 1772tcpmux(s) 1773 int s; 1774{ 1775 struct servtab *sep; 1776 char service[MAX_SERV_LEN+1]; 1777 int len; 1778 1779 /* Get requested service name */ 1780 if ((len = getline(s, service, MAX_SERV_LEN)) < 0) { 1781 strwrite(s, "-Error reading service name\r\n"); 1782 return (NULL); 1783 } 1784 service[len] = '\0'; 1785 1786 if (debug) 1787 warnx("tcpmux: someone wants %s", service); 1788 1789 /* 1790 * Help is a required command, and lists available services, 1791 * one per line. 1792 */ 1793 if (!strcasecmp(service, "help")) { 1794 for (sep = servtab; sep; sep = sep->se_next) { 1795 if (!ISMUX(sep)) 1796 continue; 1797 (void)write(s,sep->se_service,strlen(sep->se_service)); 1798 strwrite(s, "\r\n"); 1799 } 1800 return (NULL); 1801 } 1802 1803 /* Try matching a service in inetd.conf with the request */ 1804 for (sep = servtab; sep; sep = sep->se_next) { 1805 if (!ISMUX(sep)) 1806 continue; 1807 if (!strcasecmp(service, sep->se_service)) { 1808 if (ISMUXPLUS(sep)) { 1809 strwrite(s, "+Go\r\n"); 1810 } 1811 return (sep); 1812 } 1813 } 1814 strwrite(s, "-Service not available\r\n"); 1815 return (NULL); 1816} 1817 1818#define CPMHSIZE 256 1819#define CPMHMASK (CPMHSIZE-1) 1820#define CHTGRAN 10 1821#define CHTSIZE 6 1822 1823typedef struct CTime { 1824 unsigned long ct_Ticks; 1825 int ct_Count; 1826} CTime; 1827 1828typedef struct CHash { 1829 struct in_addr ch_Addr; 1830 time_t ch_LTime; 1831 char *ch_Service; 1832 CTime ch_Times[CHTSIZE]; 1833} CHash; 1834 1835CHash CHashAry[CPMHSIZE]; 1836 1837int 1838cpmip(sep, ctrl) 1839 struct servtab *sep; 1840 int ctrl; 1841{ 1842 struct sockaddr_in rsin; 1843 int rsinLen = sizeof(rsin); 1844 int r = 0; 1845 1846 /* 1847 * If getpeername() fails, just let it through (if logging is 1848 * enabled the condition is caught elsewhere) 1849 */ 1850 1851 if (sep->se_maxcpm > 0 && 1852 getpeername(ctrl, (struct sockaddr *)&rsin, &rsinLen) == 0 ) { 1853 time_t t = time(NULL); 1854 int hv = 0xABC3D20F; 1855 int i; 1856 int cnt = 0; 1857 CHash *chBest = NULL; 1858 unsigned int ticks = t / CHTGRAN; 1859 1860 { 1861 char *p; 1862 int i; 1863 1864 for (i = 0, p = (char *)&rsin.sin_addr; 1865 i < sizeof(rsin.sin_addr); 1866 ++i, ++p) { 1867 hv = (hv << 5) ^ (hv >> 23) ^ *p; 1868 } 1869 hv = (hv ^ (hv >> 16)); 1870 } 1871 for (i = 0; i < 5; ++i) { 1872 CHash *ch = &CHashAry[(hv + i) & CPMHMASK]; 1873 1874 if (rsin.sin_addr.s_addr == ch->ch_Addr.s_addr && 1875 ch->ch_Service && strcmp(sep->se_service, 1876 ch->ch_Service) == 0) { 1877 chBest = ch; 1878 break; 1879 } 1880 if (chBest == NULL || ch->ch_LTime == 0 || 1881 ch->ch_LTime < chBest->ch_LTime) { 1882 chBest = ch; 1883 } 1884 } 1885 if (rsin.sin_addr.s_addr != chBest->ch_Addr.s_addr || 1886 chBest->ch_Service == NULL || 1887 strcmp(sep->se_service, chBest->ch_Service) != 0) { 1888 chBest->ch_Addr = rsin.sin_addr; 1889 if (chBest->ch_Service) 1890 free(chBest->ch_Service); 1891 chBest->ch_Service = strdup(sep->se_service); 1892 bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 1893 } 1894 chBest->ch_LTime = t; 1895 { 1896 CTime *ct = &chBest->ch_Times[ticks % CHTSIZE]; 1897 if (ct->ct_Ticks != ticks) { 1898 ct->ct_Ticks = ticks; 1899 ct->ct_Count = 0; 1900 } 1901 ++ct->ct_Count; 1902 } 1903 for (i = 0; i < CHTSIZE; ++i) { 1904 CTime *ct = &chBest->ch_Times[i]; 1905 if (ct->ct_Ticks <= ticks && 1906 ct->ct_Ticks >= ticks - CHTSIZE) { 1907 cnt += ct->ct_Count; 1908 } 1909 } 1910 if (cnt * (CHTSIZE * CHTGRAN) / 60 > sep->se_maxcpm) { 1911 r = -1; 1912 syslog(LOG_ERR, 1913 "%s from %s exceeded counts/min (limit %d/min)", 1914 sep->se_service, inet_ntoa(rsin.sin_addr), 1915 sep->se_maxcpm); 1916 } 1917 } 1918 return(r); 1919} 1920