inetd.c revision 35948
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.32 1998/05/08 19:15:44 guido 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 sigaction sa, sapipe; 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 sa.sa_flags = 0; 404 sigemptyset(&sa.sa_mask); 405 sigaddset(&sa.sa_mask, SIGALRM); 406 sigaddset(&sa.sa_mask, SIGCHLD); 407 sigaddset(&sa.sa_mask, SIGHUP); 408 sa.sa_handler = retry; 409 sigaction(SIGALRM, &sa, (struct sigaction *)0); 410 config(SIGHUP); 411 sa.sa_handler = config; 412 sigaction(SIGHUP, &sa, (struct sigaction *)0); 413 sa.sa_handler = reapchild; 414 sigaction(SIGCHLD, &sa, (struct sigaction *)0); 415 sa.sa_handler = SIG_IGN; 416 sigaction(SIGPIPE, &sa, &sapipe); 417 418 { 419 /* space for daemons to overwrite environment for ps */ 420#define DUMMYSIZE 100 421 char dummy[DUMMYSIZE]; 422 423 (void)memset(dummy, 'x', DUMMYSIZE - 1); 424 dummy[DUMMYSIZE - 1] = '\0'; 425 (void)setenv("inetd_dummy", dummy, 1); 426 } 427 428 for (;;) { 429 int n, ctrl; 430 fd_set readable; 431 432 if (nsock == 0) { 433 (void) sigblock(SIGBLOCK); 434 while (nsock == 0) 435 sigpause(0L); 436 (void) sigsetmask(0L); 437 } 438 readable = allsock; 439 if ((n = select(maxsock + 1, &readable, (fd_set *)0, 440 (fd_set *)0, (struct timeval *)0)) <= 0) { 441 if (n < 0 && errno != EINTR) { 442 syslog(LOG_WARNING, "select: %m"); 443 sleep(1); 444 } 445 continue; 446 } 447 for (sep = servtab; n && sep; sep = sep->se_next) 448 if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 449 n--; 450 if (debug) 451 warnx("someone wants %s", sep->se_service); 452 if (sep->se_accept && sep->se_socktype == SOCK_STREAM) { 453 ctrl = accept(sep->se_fd, (struct sockaddr *)0, 454 (int *)0); 455 if (debug) 456 warnx("accept, ctrl %d", ctrl); 457 if (ctrl < 0) { 458 if (errno != EINTR) 459 syslog(LOG_WARNING, 460 "accept (for %s): %m", 461 sep->se_service); 462 continue; 463 } 464 if (cpmip(sep, ctrl) < 0) { 465 close(ctrl); 466 continue; 467 } 468 if (log) { 469 i = sizeof peer; 470 if (getpeername(ctrl, (struct sockaddr *) 471 &peer, &i)) { 472 syslog(LOG_WARNING, 473 "getpeername(for %s): %m", 474 sep->se_service); 475 close(ctrl); 476 continue; 477 } 478 syslog(LOG_INFO,"%s from %s", 479 sep->se_service, 480 inet_ntoa(peer.sin_addr)); 481 } 482 } else 483 ctrl = sep->se_fd; 484 (void) sigblock(SIGBLOCK); 485 pid = 0; 486 dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork); 487 if (dofork) { 488 if (sep->se_count++ == 0) 489 (void)gettimeofday(&sep->se_time, 490 (struct timezone *)0); 491 else if (sep->se_count >= toomany) { 492 struct timeval now; 493 494 (void)gettimeofday(&now, (struct timezone *)0); 495 if (now.tv_sec - sep->se_time.tv_sec > 496 CNT_INTVL) { 497 sep->se_time = now; 498 sep->se_count = 1; 499 } else { 500 syslog(LOG_ERR, 501 "%s/%s server failing (looping), service terminated", 502 sep->se_service, sep->se_proto); 503 close_sep(sep); 504 sigsetmask(0L); 505 if (!timingout) { 506 timingout = 1; 507 alarm(RETRYTIME); 508 } 509 continue; 510 } 511 } 512 pid = fork(); 513 } 514 if (pid < 0) { 515 syslog(LOG_ERR, "fork: %m"); 516 if (sep->se_accept && 517 sep->se_socktype == SOCK_STREAM) 518 close(ctrl); 519 sigsetmask(0L); 520 sleep(1); 521 continue; 522 } 523 if (pid) 524 addchild(sep, pid); 525 sigsetmask(0L); 526 if (pid == 0) { 527 if (dofork) { 528 if (debug) 529 warnx("+ closing from %d", maxsock); 530 for (tmpint = maxsock; tmpint > 2; tmpint--) 531 if (tmpint != ctrl) 532 (void) close(tmpint); 533 } 534 /* 535 * Call tcpmux to find the real service to exec. 536 */ 537 if (sep->se_bi && 538 sep->se_bi->bi_fn == (void (*)()) tcpmux) { 539 sep = tcpmux(ctrl); 540 if (sep == NULL) { 541 close(ctrl); 542 _exit(0); 543 } 544 } 545 if (sep->se_bi) { 546 (*sep->se_bi->bi_fn)(ctrl, sep); 547 /* NOTREACHED */ 548 } else { 549 if (debug) 550 warnx("%d execl %s", 551 getpid(), sep->se_server); 552 dup2(ctrl, 0); 553 close(ctrl); 554 dup2(0, 1); 555 dup2(0, 2); 556 if ((pwd = getpwnam(sep->se_user)) == NULL) { 557 syslog(LOG_ERR, 558 "%s/%s: %s: No such user", 559 sep->se_service, sep->se_proto, 560 sep->se_user); 561 if (sep->se_socktype != SOCK_STREAM) 562 recv(0, buf, sizeof (buf), 0); 563 _exit(EX_NOUSER); 564 } 565 grp = NULL; 566 if ( sep->se_group != NULL 567 && (grp = getgrnam(sep->se_group)) == NULL 568 ) { 569 syslog(LOG_ERR, 570 "%s/%s: %s: No such group", 571 sep->se_service, sep->se_proto, 572 sep->se_group); 573 if (sep->se_socktype != SOCK_STREAM) 574 recv(0, buf, sizeof (buf), 0); 575 _exit(EX_NOUSER); 576 } 577 if (grp != NULL) 578 pwd->pw_gid = grp->gr_gid; 579#ifdef LOGIN_CAP 580 if ((lc = login_getclass(sep->se_class)) == NULL) { 581 /* error syslogged by getclass */ 582 syslog(LOG_ERR, 583 "%s/%s: %s: login class error", 584 sep->se_service, sep->se_proto); 585 if (sep->se_socktype != SOCK_STREAM) 586 recv(0, buf, sizeof (buf), 0); 587 _exit(EX_NOUSER); 588 } 589#endif 590 if (setsid() < 0) { 591 syslog(LOG_ERR, 592 "%s: can't setsid(): %m", 593 sep->se_service); 594 /* _exit(EX_OSERR); not fatal yet */ 595 } 596#ifdef LOGIN_CAP 597 if (setusercontext(lc, pwd, pwd->pw_uid, 598 LOGIN_SETALL) != 0) { 599 syslog(LOG_ERR, 600 "%s: can't setusercontext(..%s..): %m", 601 sep->se_service, sep->se_user); 602 _exit(EX_OSERR); 603 } 604#else 605 if (pwd->pw_uid) { 606 if (setlogin(sep->se_user) < 0) { 607 syslog(LOG_ERR, 608 "%s: can't setlogin(%s): %m", 609 sep->se_service, sep->se_user); 610 /* _exit(EX_OSERR); not yet */ 611 } 612 if (setgid(pwd->pw_gid) < 0) { 613 syslog(LOG_ERR, 614 "%s: can't set gid %d: %m", 615 sep->se_service, pwd->pw_gid); 616 _exit(EX_OSERR); 617 } 618 (void) initgroups(pwd->pw_name, 619 pwd->pw_gid); 620 if (setuid(pwd->pw_uid) < 0) { 621 syslog(LOG_ERR, 622 "%s: can't set uid %d: %m", 623 sep->se_service, pwd->pw_uid); 624 _exit(EX_OSERR); 625 } 626 } 627#endif 628 sigaction(SIGPIPE, &sapipe, 629 (struct sigaction *)0); 630 execv(sep->se_server, sep->se_argv); 631 if (sep->se_socktype != SOCK_STREAM) 632 recv(0, buf, sizeof (buf), 0); 633 syslog(LOG_ERR, 634 "cannot execute %s: %m", sep->se_server); 635 _exit(EX_OSERR); 636 } 637 } 638 if (sep->se_accept && sep->se_socktype == SOCK_STREAM) 639 close(ctrl); 640 } 641 } 642} 643 644/* 645 * Record a new child pid for this service. If we've reached the 646 * limit on children, then stop accepting incoming requests. 647 */ 648 649void 650addchild(struct servtab *sep, pid_t pid) 651{ 652#ifdef SANITY_CHECK 653 if (sep->se_numchild >= sep->se_maxchild) { 654 syslog(LOG_ERR, "%s: %d >= %d", 655 __FUNCTION__, sep->se_numchild, sep->se_maxchild); 656 exit(EX_SOFTWARE); 657 } 658#endif 659 if (sep->se_maxchild == 0) 660 return; 661 sep->se_pids[sep->se_numchild++] = pid; 662 if (sep->se_numchild == sep->se_maxchild) 663 disable(sep); 664} 665 666/* 667 * Some child process has exited. See if it's on somebody's list. 668 */ 669 670void 671reapchild(signo) 672 int signo; 673{ 674 int k, status; 675 pid_t pid; 676 struct servtab *sep; 677 678 for (;;) { 679 pid = wait3(&status, WNOHANG, (struct rusage *)0); 680 if (pid <= 0) 681 break; 682 if (debug) 683 warnx("%d reaped, status %#x", pid, status); 684 for (sep = servtab; sep; sep = sep->se_next) { 685 for (k = 0; k < sep->se_numchild; k++) 686 if (sep->se_pids[k] == pid) 687 break; 688 if (k == sep->se_numchild) 689 continue; 690 if (sep->se_numchild == sep->se_maxchild) 691 enable(sep); 692 sep->se_pids[k] = sep->se_pids[--sep->se_numchild]; 693 if (status) 694 syslog(LOG_WARNING, 695 "%s[%d]: exit status 0x%x", 696 sep->se_server, pid, status); 697 break; 698 } 699 } 700} 701 702void 703config(signo) 704 int signo; 705{ 706 struct servtab *sep, *new, **sepp; 707 long omask; 708 709 if (!setconfig()) { 710 syslog(LOG_ERR, "%s: %m", CONFIG); 711 return; 712 } 713 for (sep = servtab; sep; sep = sep->se_next) 714 sep->se_checked = 0; 715 while ((new = getconfigent())) { 716 if (getpwnam(new->se_user) == NULL) { 717 syslog(LOG_ERR, 718 "%s/%s: No such user '%s', service ignored", 719 new->se_service, new->se_proto, new->se_user); 720 continue; 721 } 722 if (new->se_group && getgrnam(new->se_group) == NULL) { 723 syslog(LOG_ERR, 724 "%s/%s: No such group '%s', service ignored", 725 new->se_service, new->se_proto, new->se_group); 726 continue; 727 } 728#ifdef LOGIN_CAP 729 if (login_getclass(new->se_class) == NULL) { 730 /* error syslogged by getclass */ 731 syslog(LOG_ERR, 732 "%s/%s: login class error, service ignored", 733 new->se_service, new->se_proto); 734 continue; 735 } 736#endif 737 for (sep = servtab; sep; sep = sep->se_next) 738 if (strcmp(sep->se_service, new->se_service) == 0 && 739 strcmp(sep->se_proto, new->se_proto) == 0) 740 break; 741 if (sep != 0) { 742 int i; 743 744#define SWAP(a, b) { typeof(a) c = a; a = b; b = c; } 745 omask = sigblock(SIGBLOCK); 746 /* copy over outstanding child pids */ 747 if (sep->se_maxchild && new->se_maxchild) { 748 new->se_numchild = sep->se_numchild; 749 if (new->se_numchild > new->se_maxchild) 750 new->se_numchild = new->se_maxchild; 751 memcpy(new->se_pids, sep->se_pids, 752 new->se_numchild * sizeof(*new->se_pids)); 753 } 754 SWAP(sep->se_pids, new->se_pids); 755 sep->se_maxchild = new->se_maxchild; 756 sep->se_numchild = new->se_numchild; 757 sep->se_maxcpm = new->se_maxcpm; 758 /* might need to turn on or off service now */ 759 if (sep->se_fd >= 0) { 760 if (sep->se_maxchild 761 && sep->se_numchild == sep->se_maxchild) { 762 if (FD_ISSET(sep->se_fd, &allsock)) 763 disable(sep); 764 } else { 765 if (!FD_ISSET(sep->se_fd, &allsock)) 766 enable(sep); 767 } 768 } 769 sep->se_accept = new->se_accept; 770 SWAP(sep->se_user, new->se_user); 771 SWAP(sep->se_group, new->se_group); 772#ifdef LOGIN_CAP 773 SWAP(sep->se_class, new->se_class); 774#endif 775 SWAP(sep->se_server, new->se_server); 776 for (i = 0; i < MAXARGV; i++) 777 SWAP(sep->se_argv[i], new->se_argv[i]); 778 sigsetmask(omask); 779 freeconfig(new); 780 if (debug) 781 print_service("REDO", sep); 782 } else { 783 sep = enter(new); 784 if (debug) 785 print_service("ADD ", sep); 786 } 787 sep->se_checked = 1; 788 if (ISMUX(sep)) { 789 sep->se_fd = -1; 790 continue; 791 } 792 if (!sep->se_rpc) { 793 sp = getservbyname(sep->se_service, sep->se_proto); 794 if (sp == 0) { 795 syslog(LOG_ERR, "%s/%s: unknown service", 796 sep->se_service, sep->se_proto); 797 sep->se_checked = 0; 798 continue; 799 } 800 if (sp->s_port != sep->se_ctrladdr.sin_port) { 801 sep->se_ctrladdr.sin_family = AF_INET; 802 sep->se_ctrladdr.sin_addr = bind_address; 803 sep->se_ctrladdr.sin_port = sp->s_port; 804 if (sep->se_fd >= 0) 805 close_sep(sep); 806 } 807 } else { 808 rpc = getrpcbyname(sep->se_service); 809 if (rpc == 0) { 810 syslog(LOG_ERR, "%s/%s unknown RPC service.", 811 sep->se_service, sep->se_proto); 812 if (sep->se_fd != -1) 813 (void) close(sep->se_fd); 814 sep->se_fd = -1; 815 continue; 816 } 817 if (rpc->r_number != sep->se_rpc_prog) { 818 if (sep->se_rpc_prog) 819 unregisterrpc(sep); 820 sep->se_rpc_prog = rpc->r_number; 821 if (sep->se_fd != -1) 822 (void) close(sep->se_fd); 823 sep->se_fd = -1; 824 } 825 } 826 if (sep->se_fd == -1) 827 setup(sep); 828 } 829 endconfig(); 830 /* 831 * Purge anything not looked at above. 832 */ 833 omask = sigblock(SIGBLOCK); 834 sepp = &servtab; 835 while ((sep = *sepp)) { 836 if (sep->se_checked) { 837 sepp = &sep->se_next; 838 continue; 839 } 840 *sepp = sep->se_next; 841 if (sep->se_fd >= 0) 842 close_sep(sep); 843 if (debug) 844 print_service("FREE", sep); 845 if (sep->se_rpc && sep->se_rpc_prog > 0) 846 unregisterrpc(sep); 847 freeconfig(sep); 848 free((char *)sep); 849 } 850 (void) sigsetmask(omask); 851} 852 853void 854unregisterrpc(sep) 855 struct servtab *sep; 856{ 857 int i; 858 struct servtab *sepp; 859 long omask; 860 861 omask = sigblock(SIGBLOCK); 862 for (sepp = servtab; sepp; sepp = sepp->se_next) { 863 if (sepp == sep) 864 continue; 865 if (sep->se_checked == 0 || 866 !sepp->se_rpc || 867 sep->se_rpc_prog != sepp->se_rpc_prog) 868 continue; 869 return; 870 } 871 if (debug) 872 print_service("UNREG", sep); 873 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) 874 pmap_unset(sep->se_rpc_prog, i); 875 if (sep->se_fd != -1) 876 (void) close(sep->se_fd); 877 sep->se_fd = -1; 878 (void) sigsetmask(omask); 879} 880 881void 882retry(signo) 883 int signo; 884{ 885 struct servtab *sep; 886 887 timingout = 0; 888 for (sep = servtab; sep; sep = sep->se_next) 889 if (sep->se_fd == -1 && !ISMUX(sep)) 890 setup(sep); 891} 892 893void 894setup(sep) 895 struct servtab *sep; 896{ 897 int on = 1; 898 899 if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 900 if (debug) 901 warn("socket failed on %s/%s", 902 sep->se_service, sep->se_proto); 903 syslog(LOG_ERR, "%s/%s: socket: %m", 904 sep->se_service, sep->se_proto); 905 return; 906 } 907#define turnon(fd, opt) \ 908setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 909 if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 910 turnon(sep->se_fd, SO_DEBUG) < 0) 911 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 912 if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 913 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 914#ifdef SO_PRIVSTATE 915 if (turnon(sep->se_fd, SO_PRIVSTATE) < 0) 916 syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m"); 917#endif 918#undef turnon 919 if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 920 sizeof (sep->se_ctrladdr)) < 0) { 921 if (debug) 922 warn("bind failed on %s/%s", 923 sep->se_service, sep->se_proto); 924 syslog(LOG_ERR, "%s/%s: bind: %m", 925 sep->se_service, sep->se_proto); 926 (void) close(sep->se_fd); 927 sep->se_fd = -1; 928 if (!timingout) { 929 timingout = 1; 930 alarm(RETRYTIME); 931 } 932 return; 933 } 934 if (sep->se_rpc) { 935 int i, len = sizeof(struct sockaddr); 936 937 if (getsockname(sep->se_fd, 938 (struct sockaddr*)&sep->se_ctrladdr, &len) < 0){ 939 syslog(LOG_ERR, "%s/%s: getsockname: %m", 940 sep->se_service, sep->se_proto); 941 (void) close(sep->se_fd); 942 sep->se_fd = -1; 943 return; 944 } 945 if (debug) 946 print_service("REG ", sep); 947 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 948 pmap_unset(sep->se_rpc_prog, i); 949 pmap_set(sep->se_rpc_prog, i, 950 (sep->se_socktype == SOCK_DGRAM) 951 ? IPPROTO_UDP : IPPROTO_TCP, 952 ntohs(sep->se_ctrladdr.sin_port)); 953 } 954 955 } 956 if (sep->se_socktype == SOCK_STREAM) 957 listen(sep->se_fd, 64); 958 enable(sep); 959 if (debug) { 960 warnx("registered %s on %d", 961 sep->se_server, sep->se_fd); 962 } 963} 964 965/* 966 * Finish with a service and its socket. 967 */ 968void 969close_sep(sep) 970 struct servtab *sep; 971{ 972 if (sep->se_fd >= 0) { 973 if (FD_ISSET(sep->se_fd, &allsock)) 974 disable(sep); 975 (void) close(sep->se_fd); 976 sep->se_fd = -1; 977 } 978 sep->se_count = 0; 979 sep->se_numchild = 0; /* forget about any existing children */ 980} 981 982struct servtab * 983enter(cp) 984 struct servtab *cp; 985{ 986 struct servtab *sep; 987 long omask; 988 989 sep = (struct servtab *)malloc(sizeof (*sep)); 990 if (sep == (struct servtab *)0) { 991 syslog(LOG_ERR, "Out of memory."); 992 exit(EX_OSERR); 993 } 994 *sep = *cp; 995 sep->se_fd = -1; 996 omask = sigblock(SIGBLOCK); 997 sep->se_next = servtab; 998 servtab = sep; 999 sigsetmask(omask); 1000 return (sep); 1001} 1002 1003void 1004enable(struct servtab *sep) 1005{ 1006 if (debug) 1007 warnx( 1008 "enabling %s, fd %d", sep->se_service, sep->se_fd); 1009#ifdef SANITY_CHECK 1010 if (sep->se_fd < 0) { 1011 syslog(LOG_ERR, 1012 "%s: %s: bad fd", __FUNCTION__, sep->se_service); 1013 exit(EX_SOFTWARE); 1014 } 1015 if (ISMUX(sep)) { 1016 syslog(LOG_ERR, 1017 "%s: %s: is mux", __FUNCTION__, sep->se_service); 1018 exit(EX_SOFTWARE); 1019 } 1020 if (FD_ISSET(sep->se_fd, &allsock)) { 1021 syslog(LOG_ERR, 1022 "%s: %s: not off", __FUNCTION__, sep->se_service); 1023 exit(EX_SOFTWARE); 1024 } 1025#endif 1026 FD_SET(sep->se_fd, &allsock); 1027 nsock++; 1028 if (sep->se_fd > maxsock) 1029 maxsock = sep->se_fd; 1030} 1031 1032void 1033disable(struct servtab *sep) 1034{ 1035 if (debug) 1036 warnx( 1037 "disabling %s, fd %d", sep->se_service, sep->se_fd); 1038#ifdef SANITY_CHECK 1039 if (sep->se_fd < 0) { 1040 syslog(LOG_ERR, 1041 "%s: %s: bad fd", __FUNCTION__, sep->se_service); 1042 exit(EX_SOFTWARE); 1043 } 1044 if (ISMUX(sep)) { 1045 syslog(LOG_ERR, 1046 "%s: %s: is mux", __FUNCTION__, sep->se_service); 1047 exit(EX_SOFTWARE); 1048 } 1049 if (!FD_ISSET(sep->se_fd, &allsock)) { 1050 syslog(LOG_ERR, 1051 "%s: %s: not on", __FUNCTION__, sep->se_service); 1052 exit(EX_SOFTWARE); 1053 } 1054 if (nsock == 0) { 1055 syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__); 1056 exit(EX_SOFTWARE); 1057 } 1058#endif 1059 FD_CLR(sep->se_fd, &allsock); 1060 nsock--; 1061 if (sep->se_fd == maxsock) 1062 maxsock--; 1063} 1064 1065FILE *fconfig = NULL; 1066struct servtab serv; 1067char line[LINE_MAX]; 1068 1069int 1070setconfig() 1071{ 1072 1073 if (fconfig != NULL) { 1074 fseek(fconfig, 0L, SEEK_SET); 1075 return (1); 1076 } 1077 fconfig = fopen(CONFIG, "r"); 1078 return (fconfig != NULL); 1079} 1080 1081void 1082endconfig() 1083{ 1084 if (fconfig) { 1085 (void) fclose(fconfig); 1086 fconfig = NULL; 1087 } 1088} 1089 1090struct servtab * 1091getconfigent() 1092{ 1093 struct servtab *sep = &serv; 1094 int argc; 1095 char *cp, *arg, *s; 1096 char *versp; 1097 static char TCPMUX_TOKEN[] = "tcpmux/"; 1098#define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 1099 1100more: 1101 while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0')) 1102 ; 1103 if (cp == NULL) 1104 return ((struct servtab *)0); 1105 /* 1106 * clear the static buffer, since some fields (se_ctrladdr, 1107 * for example) don't get initialized here. 1108 */ 1109 memset((caddr_t)sep, 0, sizeof *sep); 1110 arg = skip(&cp); 1111 if (cp == NULL) { 1112 /* got an empty line containing just blanks/tabs. */ 1113 goto more; 1114 } 1115 if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 1116 char *c = arg + MUX_LEN; 1117 if (*c == '+') { 1118 sep->se_type = MUXPLUS_TYPE; 1119 c++; 1120 } else 1121 sep->se_type = MUX_TYPE; 1122 sep->se_service = newstr(c); 1123 } else { 1124 sep->se_service = newstr(arg); 1125 sep->se_type = NORM_TYPE; 1126 } 1127 arg = sskip(&cp); 1128 if (strcmp(arg, "stream") == 0) 1129 sep->se_socktype = SOCK_STREAM; 1130 else if (strcmp(arg, "dgram") == 0) 1131 sep->se_socktype = SOCK_DGRAM; 1132 else if (strcmp(arg, "rdm") == 0) 1133 sep->se_socktype = SOCK_RDM; 1134 else if (strcmp(arg, "seqpacket") == 0) 1135 sep->se_socktype = SOCK_SEQPACKET; 1136 else if (strcmp(arg, "raw") == 0) 1137 sep->se_socktype = SOCK_RAW; 1138 else 1139 sep->se_socktype = -1; 1140 sep->se_proto = newstr(sskip(&cp)); 1141 if (strncmp(sep->se_proto, "rpc/", 4) == 0) { 1142 memmove(sep->se_proto, sep->se_proto + 4, 1143 strlen(sep->se_proto) + 1 - 4); 1144 sep->se_rpc = 1; 1145 sep->se_rpc_prog = sep->se_rpc_lowvers = 1146 sep->se_rpc_lowvers = 0; 1147 sep->se_ctrladdr.sin_family = AF_INET; 1148 sep->se_ctrladdr.sin_port = 0; 1149 sep->se_ctrladdr.sin_addr = bind_address; 1150 if ((versp = rindex(sep->se_service, '/'))) { 1151 *versp++ = '\0'; 1152 switch (sscanf(versp, "%d-%d", 1153 &sep->se_rpc_lowvers, 1154 &sep->se_rpc_highvers)) { 1155 case 2: 1156 break; 1157 case 1: 1158 sep->se_rpc_highvers = 1159 sep->se_rpc_lowvers; 1160 break; 1161 default: 1162 syslog(LOG_ERR, 1163 "bad RPC version specifier; %s\n", 1164 sep->se_service); 1165 freeconfig(sep); 1166 goto more; 1167 } 1168 } 1169 else { 1170 sep->se_rpc_lowvers = 1171 sep->se_rpc_highvers = 1; 1172 } 1173 } 1174 arg = sskip(&cp); 1175 if (!strncmp(arg, "wait", 4)) 1176 sep->se_accept = 0; 1177 else if (!strncmp(arg, "nowait", 6)) 1178 sep->se_accept = 1; 1179 else { 1180 syslog(LOG_ERR, 1181 "%s: bad wait/nowait for service %s", 1182 CONFIG, sep->se_service); 1183 goto more; 1184 } 1185 sep->se_maxchild = maxchild; 1186 sep->se_maxcpm = maxcpm; 1187 if ((s = strchr(arg, '/')) != NULL) { 1188 char *eptr; 1189 u_long val; 1190 1191 val = strtoul(s + 1, &eptr, 10); 1192 if (eptr == s + 1 || val > MAX_MAXCHLD) { 1193 syslog(LOG_ERR, 1194 "%s: bad max-child for service %s", 1195 CONFIG, sep->se_service); 1196 goto more; 1197 } 1198 sep->se_maxchild = val; 1199 if (*eptr == '/') 1200 sep->se_maxcpm = strtol(eptr + 1, &eptr, 10); 1201 /* 1202 * explicitly do not check for \0 for future expansion / 1203 * backwards compatibility 1204 */ 1205 } 1206 if (ISMUX(sep)) { 1207 /* 1208 * Silently enforce "nowait" mode for TCPMUX services 1209 * since they don't have an assigned port to listen on. 1210 */ 1211 sep->se_accept = 1; 1212 if (strcmp(sep->se_proto, "tcp")) { 1213 syslog(LOG_ERR, 1214 "%s: bad protocol for tcpmux service %s", 1215 CONFIG, sep->se_service); 1216 goto more; 1217 } 1218 if (sep->se_socktype != SOCK_STREAM) { 1219 syslog(LOG_ERR, 1220 "%s: bad socket type for tcpmux service %s", 1221 CONFIG, sep->se_service); 1222 goto more; 1223 } 1224 } 1225 sep->se_user = newstr(sskip(&cp)); 1226#ifdef LOGIN_CAP 1227 if ((s = strrchr(sep->se_user, '/')) != NULL) { 1228 *s = '\0'; 1229 sep->se_class = newstr(s + 1); 1230 } else 1231 sep->se_class = newstr(RESOURCE_RC); 1232#endif 1233 if ((s = strrchr(sep->se_user, ':')) != NULL) { 1234 *s = '\0'; 1235 sep->se_group = newstr(s + 1); 1236 } else 1237 sep->se_group = NULL; 1238 sep->se_server = newstr(sskip(&cp)); 1239 if (strcmp(sep->se_server, "internal") == 0) { 1240 struct biltin *bi; 1241 1242 for (bi = biltins; bi->bi_service; bi++) 1243 if (bi->bi_socktype == sep->se_socktype && 1244 strcmp(bi->bi_service, sep->se_service) == 0) 1245 break; 1246 if (bi->bi_service == 0) { 1247 syslog(LOG_ERR, "internal service %s unknown", 1248 sep->se_service); 1249 goto more; 1250 } 1251 sep->se_accept = 1; /* force accept mode for built-ins */ 1252 sep->se_bi = bi; 1253 } else 1254 sep->se_bi = NULL; 1255 if (sep->se_maxchild < 0) /* apply default max-children */ 1256 if (sep->se_bi) 1257 sep->se_maxchild = sep->se_bi->bi_maxchild; 1258 else 1259 sep->se_maxchild = sep->se_accept ? 0 : 1; 1260 if (sep->se_maxchild) { 1261 sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids)); 1262 if (sep->se_pids == NULL) { 1263 syslog(LOG_ERR, "Out of memory."); 1264 exit(EX_OSERR); 1265 } 1266 } 1267 argc = 0; 1268 for (arg = skip(&cp); cp; arg = skip(&cp)) 1269 if (argc < MAXARGV) { 1270 sep->se_argv[argc++] = newstr(arg); 1271 } else { 1272 syslog(LOG_ERR, 1273 "%s: too many arguments for service %s", 1274 CONFIG, sep->se_service); 1275 goto more; 1276 } 1277 while (argc <= MAXARGV) 1278 sep->se_argv[argc++] = NULL; 1279 return (sep); 1280} 1281 1282void 1283freeconfig(cp) 1284 struct servtab *cp; 1285{ 1286 int i; 1287 1288 if (cp->se_service) 1289 free(cp->se_service); 1290 if (cp->se_proto) 1291 free(cp->se_proto); 1292 if (cp->se_user) 1293 free(cp->se_user); 1294 if (cp->se_group) 1295 free(cp->se_group); 1296#ifdef LOGIN_CAP 1297 if (cp->se_class) 1298 free(cp->se_class); 1299#endif 1300 if (cp->se_server) 1301 free(cp->se_server); 1302 if (cp->se_pids) 1303 free(cp->se_pids); 1304 for (i = 0; i < MAXARGV; i++) 1305 if (cp->se_argv[i]) 1306 free(cp->se_argv[i]); 1307} 1308 1309 1310/* 1311 * Safe skip - if skip returns null, log a syntax error in the 1312 * configuration file and exit. 1313 */ 1314char * 1315sskip(cpp) 1316 char **cpp; 1317{ 1318 char *cp; 1319 1320 cp = skip(cpp); 1321 if (cp == NULL) { 1322 syslog(LOG_ERR, "%s: syntax error", CONFIG); 1323 exit(EX_DATAERR); 1324 } 1325 return (cp); 1326} 1327 1328char * 1329skip(cpp) 1330 char **cpp; 1331{ 1332 char *cp = *cpp; 1333 char *start; 1334 char quote = '\0'; 1335 1336again: 1337 while (*cp == ' ' || *cp == '\t') 1338 cp++; 1339 if (*cp == '\0') { 1340 int c; 1341 1342 c = getc(fconfig); 1343 (void) ungetc(c, fconfig); 1344 if (c == ' ' || c == '\t') 1345 if ((cp = nextline(fconfig))) 1346 goto again; 1347 *cpp = (char *)0; 1348 return ((char *)0); 1349 } 1350 if (*cp == '"' || *cp == '\'') 1351 quote = *cp++; 1352 start = cp; 1353 if (quote) 1354 while (*cp && *cp != quote) 1355 cp++; 1356 else 1357 while (*cp && *cp != ' ' && *cp != '\t') 1358 cp++; 1359 if (*cp != '\0') 1360 *cp++ = '\0'; 1361 *cpp = cp; 1362 return (start); 1363} 1364 1365char * 1366nextline(fd) 1367 FILE *fd; 1368{ 1369 char *cp; 1370 1371 if (fgets(line, sizeof (line), fd) == NULL) 1372 return ((char *)0); 1373 cp = strchr(line, '\n'); 1374 if (cp) 1375 *cp = '\0'; 1376 return (line); 1377} 1378 1379char * 1380newstr(cp) 1381 char *cp; 1382{ 1383 if ((cp = strdup(cp ? cp : ""))) 1384 return (cp); 1385 syslog(LOG_ERR, "strdup: %m"); 1386 exit(EX_OSERR); 1387} 1388 1389#ifdef OLD_SETPROCTITLE 1390void 1391inetd_setproctitle(a, s) 1392 char *a; 1393 int s; 1394{ 1395 int size; 1396 char *cp; 1397 struct sockaddr_in sin; 1398 char buf[80]; 1399 1400 cp = Argv[0]; 1401 size = sizeof(sin); 1402 if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 1403 (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 1404 else 1405 (void) sprintf(buf, "-%s", a); 1406 strncpy(cp, buf, LastArg - cp); 1407 cp += strlen(cp); 1408 while (cp < LastArg) 1409 *cp++ = ' '; 1410} 1411#else 1412void 1413inetd_setproctitle(a, s) 1414 char *a; 1415 int s; 1416{ 1417 int size; 1418 struct sockaddr_in sin; 1419 char buf[80]; 1420 1421 size = sizeof(sin); 1422 if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 1423 (void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin.sin_addr)); 1424 else 1425 (void) sprintf(buf, "%s", a); 1426 setproctitle("%s", buf); 1427} 1428#endif 1429 1430 1431/* 1432 * Internet services provided internally by inetd: 1433 */ 1434#define BUFSIZE 8192 1435 1436/* ARGSUSED */ 1437void 1438echo_stream(s, sep) /* Echo service -- echo data back */ 1439 int s; 1440 struct servtab *sep; 1441{ 1442 char buffer[BUFSIZE]; 1443 int i; 1444 1445 inetd_setproctitle(sep->se_service, s); 1446 while ((i = read(s, buffer, sizeof(buffer))) > 0 && 1447 write(s, buffer, i) > 0) 1448 ; 1449 exit(0); 1450} 1451 1452int check_loop(sin, sep) 1453 struct sockaddr_in *sin; 1454 struct servtab *sep; 1455{ 1456 struct servtab *se2; 1457 1458 for (se2 = servtab; se2; se2 = se2->se_next) { 1459 if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM) 1460 continue; 1461 1462 if (sin->sin_port == se2->se_ctrladdr.sin_port) { 1463 syslog(LOG_WARNING, 1464 "%s/%s:%s/%s loop request REFUSED from %s", 1465 sep->se_service, sep->se_proto, 1466 se2->se_service, se2->se_proto, 1467 inet_ntoa(sin->sin_addr)); 1468 return 1; 1469 } 1470 } 1471 return 0; 1472} 1473 1474/* ARGSUSED */ 1475void 1476echo_dg(s, sep) /* Echo service -- echo data back */ 1477 int s; 1478 struct servtab *sep; 1479{ 1480 char buffer[BUFSIZE]; 1481 int i, size; 1482 struct sockaddr_in sin; 1483 1484 size = sizeof(sin); 1485 if ((i = recvfrom(s, buffer, sizeof(buffer), 0, 1486 (struct sockaddr *)&sin, &size)) < 0) 1487 return; 1488 1489 if (check_loop(&sin, sep)) 1490 return; 1491 1492 (void) sendto(s, buffer, i, 0, (struct sockaddr *)&sin, 1493 sizeof(sin)); 1494} 1495 1496/* ARGSUSED */ 1497void 1498discard_stream(s, sep) /* Discard service -- ignore data */ 1499 int s; 1500 struct servtab *sep; 1501{ 1502 int ret; 1503 char buffer[BUFSIZE]; 1504 1505 inetd_setproctitle(sep->se_service, s); 1506 while (1) { 1507 while ((ret = read(s, buffer, sizeof(buffer))) > 0) 1508 ; 1509 if (ret == 0 || errno != EINTR) 1510 break; 1511 } 1512 exit(0); 1513} 1514 1515/* ARGSUSED */ 1516void 1517discard_dg(s, sep) /* Discard service -- ignore data */ 1518 int s; 1519 struct servtab *sep; 1520{ 1521 char buffer[BUFSIZE]; 1522 1523 (void) read(s, buffer, sizeof(buffer)); 1524} 1525 1526#include <ctype.h> 1527#define LINESIZ 72 1528char ring[128]; 1529char *endring; 1530 1531void 1532initring() 1533{ 1534 int i; 1535 1536 endring = ring; 1537 1538 for (i = 0; i <= 128; ++i) 1539 if (isprint(i)) 1540 *endring++ = i; 1541} 1542 1543/* ARGSUSED */ 1544void 1545chargen_stream(s, sep) /* Character generator */ 1546 int s; 1547 struct servtab *sep; 1548{ 1549 int len; 1550 char *rs, text[LINESIZ+2]; 1551 1552 inetd_setproctitle(sep->se_service, s); 1553 1554 if (!endring) { 1555 initring(); 1556 rs = ring; 1557 } 1558 1559 text[LINESIZ] = '\r'; 1560 text[LINESIZ + 1] = '\n'; 1561 for (rs = ring;;) { 1562 if ((len = endring - rs) >= LINESIZ) 1563 memmove(text, rs, LINESIZ); 1564 else { 1565 memmove(text, rs, len); 1566 memmove(text + len, ring, LINESIZ - len); 1567 } 1568 if (++rs == endring) 1569 rs = ring; 1570 if (write(s, text, sizeof(text)) != sizeof(text)) 1571 break; 1572 } 1573 exit(0); 1574} 1575 1576/* ARGSUSED */ 1577void 1578chargen_dg(s, sep) /* Character generator */ 1579 int s; 1580 struct servtab *sep; 1581{ 1582 struct sockaddr_in sin; 1583 static char *rs; 1584 int len, size; 1585 char text[LINESIZ+2]; 1586 1587 if (endring == 0) { 1588 initring(); 1589 rs = ring; 1590 } 1591 1592 size = sizeof(sin); 1593 if (recvfrom(s, text, sizeof(text), 0, 1594 (struct sockaddr *)&sin, &size) < 0) 1595 return; 1596 1597 if (check_loop(&sin, sep)) 1598 return; 1599 1600 if ((len = endring - rs) >= LINESIZ) 1601 memmove(text, rs, LINESIZ); 1602 else { 1603 memmove(text, rs, len); 1604 memmove(text + len, ring, LINESIZ - len); 1605 } 1606 if (++rs == endring) 1607 rs = ring; 1608 text[LINESIZ] = '\r'; 1609 text[LINESIZ + 1] = '\n'; 1610 (void) sendto(s, text, sizeof(text), 0, 1611 (struct sockaddr *)&sin, sizeof(sin)); 1612} 1613 1614/* 1615 * Return a machine readable date and time, in the form of the 1616 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 1617 * returns the number of seconds since midnight, Jan 1, 1970, 1618 * we must add 2208988800 seconds to this figure to make up for 1619 * some seventy years Bell Labs was asleep. 1620 */ 1621 1622long 1623machtime() 1624{ 1625 struct timeval tv; 1626 1627 if (gettimeofday(&tv, (struct timezone *)0) < 0) { 1628 if (debug) 1629 warnx("unable to get time of day"); 1630 return (0L); 1631 } 1632#define OFFSET ((u_long)25567 * 24*60*60) 1633 return (htonl((long)(tv.tv_sec + OFFSET))); 1634#undef OFFSET 1635} 1636 1637/* ARGSUSED */ 1638void 1639machtime_stream(s, sep) 1640 int s; 1641 struct servtab *sep; 1642{ 1643 long result; 1644 1645 result = machtime(); 1646 (void) write(s, (char *) &result, sizeof(result)); 1647} 1648 1649/* ARGSUSED */ 1650void 1651machtime_dg(s, sep) 1652 int s; 1653 struct servtab *sep; 1654{ 1655 long result; 1656 struct sockaddr_in sin; 1657 int size; 1658 1659 size = sizeof(sin); 1660 if (recvfrom(s, (char *)&result, sizeof(result), 0, 1661 (struct sockaddr *)&sin, &size) < 0) 1662 return; 1663 1664 if (check_loop(&sin, sep)) 1665 return; 1666 1667 result = machtime(); 1668 (void) sendto(s, (char *) &result, sizeof(result), 0, 1669 (struct sockaddr *)&sin, sizeof(sin)); 1670} 1671 1672/* ARGSUSED */ 1673void 1674daytime_stream(s, sep) /* Return human-readable time of day */ 1675 int s; 1676 struct servtab *sep; 1677{ 1678 char buffer[256]; 1679 time_t clock; 1680 1681 clock = time((time_t *) 0); 1682 1683 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 1684 (void) write(s, buffer, strlen(buffer)); 1685} 1686 1687/* ARGSUSED */ 1688void 1689daytime_dg(s, sep) /* Return human-readable time of day */ 1690 int s; 1691 struct servtab *sep; 1692{ 1693 char buffer[256]; 1694 time_t clock; 1695 struct sockaddr_in sin; 1696 int size; 1697 1698 clock = time((time_t *) 0); 1699 1700 size = sizeof(sin); 1701 if (recvfrom(s, buffer, sizeof(buffer), 0, 1702 (struct sockaddr *)&sin, &size) < 0) 1703 return; 1704 1705 if (check_loop(&sin, sep)) 1706 return; 1707 1708 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 1709 (void) sendto(s, buffer, strlen(buffer), 0, 1710 (struct sockaddr *)&sin, sizeof(sin)); 1711} 1712 1713/* 1714 * print_service: 1715 * Dump relevant information to stderr 1716 */ 1717void 1718print_service(action, sep) 1719 char *action; 1720 struct servtab *sep; 1721{ 1722 fprintf(stderr, 1723#ifdef LOGIN_CAP 1724 "%s: %s proto=%s accept=%d max=%d user=%s group=%s class=%s builtin=%x server=%s\n", 1725#else 1726 "%s: %s proto=%s accept=%d max=%d user=%s group=%s builtin=%x server=%s\n", 1727#endif 1728 action, sep->se_service, sep->se_proto, 1729 sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group, 1730#ifdef LOGIN_CAP 1731 sep->se_class, 1732#endif 1733 (int)sep->se_bi, sep->se_server); 1734} 1735 1736/* 1737 * Based on TCPMUX.C by Mark K. Lottor November 1988 1738 * sri-nic::ps:<mkl>tcpmux.c 1739 */ 1740 1741 1742static int /* # of characters upto \r,\n or \0 */ 1743getline(fd, buf, len) 1744 int fd; 1745 char *buf; 1746 int len; 1747{ 1748 int count = 0, n; 1749 struct sigaction sa; 1750 1751 sa.sa_flags = 0; 1752 sigemptyset(&sa.sa_mask); 1753 sa.sa_handler = SIG_DFL; 1754 sigaction(SIGALRM, &sa, (struct sigaction *)0); 1755 do { 1756 alarm(10); 1757 n = read(fd, buf, len-count); 1758 alarm(0); 1759 if (n == 0) 1760 return (count); 1761 if (n < 0) 1762 return (-1); 1763 while (--n >= 0) { 1764 if (*buf == '\r' || *buf == '\n' || *buf == '\0') 1765 return (count); 1766 count++; 1767 buf++; 1768 } 1769 } while (count < len); 1770 return (count); 1771} 1772 1773#define MAX_SERV_LEN (256+2) /* 2 bytes for \r\n */ 1774 1775#define strwrite(fd, buf) (void) write(fd, buf, sizeof(buf)-1) 1776 1777struct servtab * 1778tcpmux(s) 1779 int s; 1780{ 1781 struct servtab *sep; 1782 char service[MAX_SERV_LEN+1]; 1783 int len; 1784 1785 /* Get requested service name */ 1786 if ((len = getline(s, service, MAX_SERV_LEN)) < 0) { 1787 strwrite(s, "-Error reading service name\r\n"); 1788 return (NULL); 1789 } 1790 service[len] = '\0'; 1791 1792 if (debug) 1793 warnx("tcpmux: someone wants %s", service); 1794 1795 /* 1796 * Help is a required command, and lists available services, 1797 * one per line. 1798 */ 1799 if (!strcasecmp(service, "help")) { 1800 for (sep = servtab; sep; sep = sep->se_next) { 1801 if (!ISMUX(sep)) 1802 continue; 1803 (void)write(s,sep->se_service,strlen(sep->se_service)); 1804 strwrite(s, "\r\n"); 1805 } 1806 return (NULL); 1807 } 1808 1809 /* Try matching a service in inetd.conf with the request */ 1810 for (sep = servtab; sep; sep = sep->se_next) { 1811 if (!ISMUX(sep)) 1812 continue; 1813 if (!strcasecmp(service, sep->se_service)) { 1814 if (ISMUXPLUS(sep)) { 1815 strwrite(s, "+Go\r\n"); 1816 } 1817 return (sep); 1818 } 1819 } 1820 strwrite(s, "-Service not available\r\n"); 1821 return (NULL); 1822} 1823 1824#define CPMHSIZE 256 1825#define CPMHMASK (CPMHSIZE-1) 1826#define CHTGRAN 10 1827#define CHTSIZE 6 1828 1829typedef struct CTime { 1830 unsigned long ct_Ticks; 1831 int ct_Count; 1832} CTime; 1833 1834typedef struct CHash { 1835 struct in_addr ch_Addr; 1836 time_t ch_LTime; 1837 char *ch_Service; 1838 CTime ch_Times[CHTSIZE]; 1839} CHash; 1840 1841CHash CHashAry[CPMHSIZE]; 1842 1843int 1844cpmip(sep, ctrl) 1845 struct servtab *sep; 1846 int ctrl; 1847{ 1848 struct sockaddr_in rsin; 1849 int rsinLen = sizeof(rsin); 1850 int r = 0; 1851 1852 /* 1853 * If getpeername() fails, just let it through (if logging is 1854 * enabled the condition is caught elsewhere) 1855 */ 1856 1857 if (sep->se_maxcpm > 0 && 1858 getpeername(ctrl, (struct sockaddr *)&rsin, &rsinLen) == 0 ) { 1859 time_t t = time(NULL); 1860 int hv = 0xABC3D20F; 1861 int i; 1862 int cnt = 0; 1863 CHash *chBest = NULL; 1864 unsigned int ticks = t / CHTGRAN; 1865 1866 { 1867 char *p; 1868 int i; 1869 1870 for (i = 0, p = (char *)&rsin.sin_addr; 1871 i < sizeof(rsin.sin_addr); 1872 ++i, ++p) { 1873 hv = (hv << 5) ^ (hv >> 23) ^ *p; 1874 } 1875 hv = (hv ^ (hv >> 16)); 1876 } 1877 for (i = 0; i < 5; ++i) { 1878 CHash *ch = &CHashAry[(hv + i) & CPMHMASK]; 1879 1880 if (rsin.sin_addr.s_addr == ch->ch_Addr.s_addr && 1881 ch->ch_Service && strcmp(sep->se_service, 1882 ch->ch_Service) == 0) { 1883 chBest = ch; 1884 break; 1885 } 1886 if (chBest == NULL || ch->ch_LTime == 0 || 1887 ch->ch_LTime < chBest->ch_LTime) { 1888 chBest = ch; 1889 } 1890 } 1891 if (rsin.sin_addr.s_addr != chBest->ch_Addr.s_addr || 1892 chBest->ch_Service == NULL || 1893 strcmp(sep->se_service, chBest->ch_Service) != 0) { 1894 chBest->ch_Addr = rsin.sin_addr; 1895 if (chBest->ch_Service) 1896 free(chBest->ch_Service); 1897 chBest->ch_Service = strdup(sep->se_service); 1898 bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 1899 } 1900 chBest->ch_LTime = t; 1901 { 1902 CTime *ct = &chBest->ch_Times[ticks % CHTSIZE]; 1903 if (ct->ct_Ticks != ticks) { 1904 ct->ct_Ticks = ticks; 1905 ct->ct_Count = 0; 1906 } 1907 ++ct->ct_Count; 1908 } 1909 for (i = 0; i < CHTSIZE; ++i) { 1910 CTime *ct = &chBest->ch_Times[i]; 1911 if (ct->ct_Ticks <= ticks && 1912 ct->ct_Ticks >= ticks - CHTSIZE) { 1913 cnt += ct->ct_Count; 1914 } 1915 } 1916 if (cnt * (CHTSIZE * CHTGRAN) / 60 > sep->se_maxcpm) { 1917 r = -1; 1918 syslog(LOG_ERR, 1919 "%s from %s exceeded counts/min (limit %d/min)", 1920 sep->se_service, inet_ntoa(rsin.sin_addr), 1921 sep->se_maxcpm); 1922 } 1923 } 1924 return(r); 1925} 1926