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