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