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