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