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