inetd.c revision 48958
1/* 2 * Copyright (c) 1983, 1991, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static const char copyright[] = 36"@(#) Copyright (c) 1983, 1991, 1993, 1994\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41#if 0 42static char sccsid[] = "@(#)from: inetd.c 8.4 (Berkeley) 4/13/94"; 43#endif 44static const char rcsid[] = 45 "$Id: inetd.c,v 1.61 1999/07/15 17:01:43 green Exp $"; 46#endif /* not lint */ 47 48/* 49 * Inetd - Internet super-server 50 * 51 * This program invokes all internet services as needed. Connection-oriented 52 * services are invoked each time a connection is made, by creating a process. 53 * This process is passed the connection as file descriptor 0 and is expected 54 * to do a getpeername to find out the source host and port. 55 * 56 * Datagram oriented services are invoked when a datagram 57 * arrives; a process is created and passed a pending message 58 * on file descriptor 0. Datagram servers may either connect 59 * to their peer, freeing up the original socket for inetd 60 * to receive further messages on, or ``take over the socket'', 61 * processing all arriving datagrams and, eventually, timing 62 * out. The first type of server is said to be ``multi-threaded''; 63 * the second type of server ``single-threaded''. 64 * 65 * Inetd uses a configuration file which is read at startup 66 * and, possibly, at some later time in response to a hangup signal. 67 * The configuration file is ``free format'' with fields given in the 68 * order shown below. Continuation lines for an entry must being with 69 * a space or tab. All fields must be present in each entry. 70 * 71 * service name must be in /etc/services or must 72 * name a tcpmux service 73 * socket type stream/dgram/raw/rdm/seqpacket 74 * protocol must be in /etc/protocols 75 * wait/nowait single-threaded/multi-threaded 76 * user user to run daemon as 77 * server program full path name 78 * server program arguments maximum of MAXARGS (20) 79 * 80 * TCP services without official port numbers are handled with the 81 * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for 82 * requests. When a connection is made from a foreign host, the service 83 * requested is passed to tcpmux, which looks it up in the servtab list 84 * and returns the proper entry for the service. Tcpmux returns a 85 * negative reply if the service doesn't exist, otherwise the invoked 86 * server is expected to return the positive reply if the service type in 87 * inetd.conf file has the prefix "tcpmux/". If the service type has the 88 * prefix "tcpmux/+", tcpmux will return the positive reply for the 89 * process; this is for compatibility with older server code, and also 90 * allows you to invoke programs that use stdin/stdout without putting any 91 * special server code in them. Services that use tcpmux are "nowait" 92 * because they do not have a well-known port and hence cannot listen 93 * for new requests. 94 * 95 * For RPC services 96 * service name/version must be in /etc/rpc 97 * socket type stream/dgram/raw/rdm/seqpacket 98 * protocol must be in /etc/protocols 99 * wait/nowait single-threaded/multi-threaded 100 * user user to run daemon as 101 * server program full path name 102 * server program arguments maximum of MAXARGS 103 * 104 * Comment lines are indicated by a `#' in column 1. 105 */ 106#include <sys/param.h> 107#include <sys/stat.h> 108#include <sys/ioctl.h> 109#include <sys/socket.h> 110#include <sys/wait.h> 111#include <sys/time.h> 112#include <sys/resource.h> 113#include <sys/sysctl.h> 114#include <sys/ucred.h> 115 116#include <netinet/in.h> 117#include <netinet/tcp.h> 118#include <arpa/inet.h> 119#include <rpc/rpc.h> 120#include <rpc/pmap_clnt.h> 121 122#include <ctype.h> 123#include <errno.h> 124#include <err.h> 125#include <fcntl.h> 126#include <grp.h> 127#include <netdb.h> 128#include <pwd.h> 129#include <signal.h> 130#include <stdio.h> 131#include <stdlib.h> 132#include <string.h> 133#include <syslog.h> 134#include <tcpd.h> 135#include <unistd.h> 136#include <libutil.h> 137#include <sysexits.h> 138 139#ifndef LIBWRAP_ALLOW_FACILITY 140# define LIBWRAP_ALLOW_FACILITY LOG_AUTH 141#endif 142#ifndef LIBWRAP_ALLOW_SEVERITY 143# define LIBWRAP_ALLOW_SEVERITY LOG_INFO 144#endif 145#ifndef LIBWRAP_DENY_FACILITY 146# define LIBWRAP_DENY_FACILITY LOG_AUTH 147#endif 148#ifndef LIBWRAP_DENY_SEVERITY 149# define LIBWRAP_DENY_SEVERITY LOG_WARNING 150#endif 151 152#define ISWRAP(sep) \ 153 ( ((wrap_ex && !(sep)->se_bi) || (wrap_bi && (sep)->se_bi)) \ 154 && ( ((sep)->se_accept && (sep)->se_socktype == SOCK_STREAM) \ 155 || (sep)->se_socktype == SOCK_DGRAM)) 156 157#ifdef LOGIN_CAP 158#include <login_cap.h> 159 160/* see init.c */ 161#define RESOURCE_RC "daemon" 162 163#endif 164 165#include "pathnames.h" 166 167#ifndef MAXCHILD 168#define MAXCHILD -1 /* maximum number of this service 169 < 0 = no limit */ 170#endif 171 172#ifndef MAXCPM 173#define MAXCPM -1 /* rate limit invocations from a 174 single remote address, 175 < 0 = no limit */ 176#endif 177 178#define TOOMANY 256 /* don't start more than TOOMANY */ 179#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 180#define RETRYTIME (60*10) /* retry after bind or server fail */ 181#define MAX_MAXCHLD 32767 /* max allowable max children */ 182 183#define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 184 185int allow_severity; 186int deny_severity; 187int wrap_ex = 0; 188int wrap_bi = 0; 189int debug = 0; 190int log = 0; 191int nsock, maxsock; 192fd_set allsock; 193int options; 194int timingout; 195int toomany = TOOMANY; 196int maxchild = MAXCHILD; 197int maxcpm = MAXCPM; 198struct servent *sp; 199struct rpcent *rpc; 200struct in_addr bind_address; 201int signalpipe[2]; 202 203struct servtab { 204 char *se_service; /* name of service */ 205 int se_socktype; /* type of socket to use */ 206 char *se_proto; /* protocol used */ 207 int se_maxchild; /* max number of children */ 208 int se_maxcpm; /* max connects per IP per minute */ 209 int se_numchild; /* current number of children */ 210 pid_t *se_pids; /* array of child pids */ 211 char *se_user; /* user name to run as */ 212 char *se_group; /* group name to run as */ 213#ifdef LOGIN_CAP 214 char *se_class; /* login class name to run with */ 215#endif 216 struct biltin *se_bi; /* if built-in, description */ 217 char *se_server; /* server program */ 218 char *se_server_name; /* server program without path */ 219#define MAXARGV 20 220 char *se_argv[MAXARGV+1]; /* program arguments */ 221 int se_fd; /* open descriptor */ 222 struct sockaddr_in se_ctrladdr;/* bound address */ 223 u_char se_type; /* type: normal, mux, or mux+ */ 224 u_char se_checked; /* looked at during merge */ 225 u_char se_accept; /* i.e., wait/nowait mode */ 226 u_char se_rpc; /* ==1 if RPC service */ 227 int se_rpc_prog; /* RPC program number */ 228 u_int se_rpc_lowvers; /* RPC low version */ 229 u_int se_rpc_highvers; /* RPC high version */ 230 int se_count; /* number started since se_time */ 231 struct timeval se_time; /* start of se_count */ 232 struct servtab *se_next; 233} *servtab; 234 235#define NORM_TYPE 0 236#define MUX_TYPE 1 237#define MUXPLUS_TYPE 2 238#define TTCP_TYPE 3 239#define ISMUX(sep) (((sep)->se_type == MUX_TYPE) || \ 240 ((sep)->se_type == MUXPLUS_TYPE)) 241#define ISMUXPLUS(sep) ((sep)->se_type == MUXPLUS_TYPE) 242#define ISTTCP(sep) ((sep)->se_type == TTCP_TYPE) 243 244 245void chargen_dg __P((int, struct servtab *)); 246void chargen_stream __P((int, struct servtab *)); 247void close_sep __P((struct servtab *)); 248void flag_signal __P((char)); 249void flag_config __P((int)); 250void config __P((void)); 251void daytime_dg __P((int, struct servtab *)); 252void daytime_stream __P((int, struct servtab *)); 253void discard_dg __P((int, struct servtab *)); 254void discard_stream __P((int, struct servtab *)); 255void echo_dg __P((int, struct servtab *)); 256void echo_stream __P((int, struct servtab *)); 257void endconfig __P((void)); 258struct servtab *enter __P((struct servtab *)); 259void freeconfig __P((struct servtab *)); 260struct servtab *getconfigent __P((void)); 261void iderror __P((int, int, FILE *, int)); 262void ident_stream __P((int, struct servtab *)); 263void machtime_dg __P((int, struct servtab *)); 264void machtime_stream __P((int, struct servtab *)); 265int matchservent __P((char *, char *, char *)); 266char *newstr __P((char *)); 267char *nextline __P((FILE *)); 268void print_service __P((char *, struct servtab *)); 269void addchild __P((struct servtab *, int)); 270void flag_reapchild __P((int)); 271void reapchild __P((void)); 272void enable __P((struct servtab *)); 273void disable __P((struct servtab *)); 274void flag_retry __P((int)); 275void retry __P((void)); 276int setconfig __P((void)); 277void setup __P((struct servtab *)); 278char *sskip __P((char **)); 279char *skip __P((char **)); 280struct servtab *tcpmux __P((int)); 281int cpmip __P((struct servtab *, int)); 282void inetd_setproctitle __P((char *, int)); 283 284void unregisterrpc __P((register struct servtab *sep)); 285 286struct biltin { 287 char *bi_service; /* internally provided service name */ 288 int bi_socktype; /* type of socket supported */ 289 short bi_fork; /* 1 if should fork before call */ 290 int bi_maxchild; /* max number of children (-1=default) */ 291 void (*bi_fn)(); /* function which performs it */ 292} biltins[] = { 293 /* Echo received data */ 294 { "echo", SOCK_STREAM, 1, -1, echo_stream }, 295 { "echo", SOCK_DGRAM, 0, 1, echo_dg }, 296 297 /* Internet /dev/null */ 298 { "discard", SOCK_STREAM, 1, -1, discard_stream }, 299 { "discard", SOCK_DGRAM, 0, 1, discard_dg }, 300 301 /* Return 32 bit time since 1970 */ 302 { "time", SOCK_STREAM, 0, -1, machtime_stream }, 303 { "time", SOCK_DGRAM, 0, 1, machtime_dg }, 304 305 /* Return human-readable time */ 306 { "daytime", SOCK_STREAM, 0, -1, daytime_stream }, 307 { "daytime", SOCK_DGRAM, 0, 1, daytime_dg }, 308 309 /* Familiar character generator */ 310 { "chargen", SOCK_STREAM, 1, -1, chargen_stream }, 311 { "chargen", SOCK_DGRAM, 0, 1, chargen_dg }, 312 313 { "tcpmux", SOCK_STREAM, 1, -1, (void (*)())tcpmux }, 314 315 { "auth", SOCK_STREAM, 1, -1, ident_stream }, 316 317 { NULL } 318}; 319 320#define NUMINT (sizeof(intab) / sizeof(struct inent)) 321char *CONFIG = _PATH_INETDCONF; 322char *pid_file = _PATH_INETDPID; 323 324#ifdef OLD_SETPROCTITLE 325char **Argv; 326char *LastArg; 327#endif 328 329int 330getvalue(arg, value, whine) 331 char *arg, *whine; 332 int *value; 333{ 334 int tmp; 335 char *p; 336 337 tmp = strtol(arg, &p, 0); 338 if (tmp < 1 || *p) { 339 syslog(LOG_ERR, whine, arg); 340 return 1; /* failure */ 341 } 342 *value = tmp; 343 return 0; /* success */ 344} 345 346int 347main(argc, argv, envp) 348 int argc; 349 char *argv[], *envp[]; 350{ 351 struct servtab *sep; 352 struct passwd *pwd; 353 struct group *grp; 354 struct sigaction sa, sapipe; 355 int tmpint, ch, dofork; 356 pid_t pid; 357 char buf[50]; 358#ifdef LOGIN_CAP 359 login_cap_t *lc = NULL; 360#endif 361 struct request_info req; 362 int denied; 363 char *service = NULL; 364 char *pnm; 365 struct sockaddr_in peer; 366 int i; 367 368 369#ifdef OLD_SETPROCTITLE 370 Argv = argv; 371 if (envp == 0 || *envp == 0) 372 envp = argv; 373 while (*envp) 374 envp++; 375 LastArg = envp[-1] + strlen(envp[-1]); 376#endif 377 378 openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 379 380 bind_address.s_addr = htonl(INADDR_ANY); 381 while ((ch = getopt(argc, argv, "dlwWR:a:c:C:p:")) != -1) 382 switch(ch) { 383 case 'd': 384 debug = 1; 385 options |= SO_DEBUG; 386 break; 387 case 'l': 388 log = 1; 389 break; 390 case 'R': 391 getvalue(optarg, &toomany, 392 "-R %s: bad value for service invocation rate"); 393 break; 394 case 'c': 395 getvalue(optarg, &maxchild, 396 "-c %s: bad value for maximum children"); 397 break; 398 case 'C': 399 getvalue(optarg, &maxcpm, 400 "-C %s: bad value for maximum children/minute"); 401 break; 402 case 'a': 403 if (!inet_aton(optarg, &bind_address)) { 404 syslog(LOG_ERR, 405 "-a %s: invalid IP address", optarg); 406 exit(EX_USAGE); 407 } 408 break; 409 case 'p': 410 pid_file = optarg; 411 break; 412 case 'w': 413 wrap_ex++; 414 break; 415 case 'W': 416 wrap_bi++; 417 break; 418 case '?': 419 default: 420 syslog(LOG_ERR, 421 "usage: inetd [-dlwW] [-a address] [-R rate]" 422 " [-c maximum] [-C rate]" 423 " [-p pidfile] [conf-file]"); 424 exit(EX_USAGE); 425 } 426 argc -= optind; 427 argv += optind; 428 429 if (argc > 0) 430 CONFIG = argv[0]; 431 if (debug == 0) { 432 FILE *fp; 433 if (daemon(0, 0) < 0) { 434 syslog(LOG_WARNING, "daemon(0,0) failed: %m"); 435 } 436 /* 437 * In case somebody has started inetd manually, we need to 438 * clear the logname, so that old servers run as root do not 439 * get the user's logname.. 440 */ 441 if (setlogin("") < 0) { 442 syslog(LOG_WARNING, "cannot clear logname: %m"); 443 /* no big deal if it fails.. */ 444 } 445 pid = getpid(); 446 fp = fopen(pid_file, "w"); 447 if (fp) { 448 fprintf(fp, "%ld\n", (long)pid); 449 fclose(fp); 450 } else { 451 syslog(LOG_WARNING, "%s: %m", pid_file); 452 } 453 } 454 sa.sa_flags = 0; 455 sigemptyset(&sa.sa_mask); 456 sigaddset(&sa.sa_mask, SIGALRM); 457 sigaddset(&sa.sa_mask, SIGCHLD); 458 sigaddset(&sa.sa_mask, SIGHUP); 459 sa.sa_handler = flag_retry; 460 sigaction(SIGALRM, &sa, (struct sigaction *)0); 461 config(); 462 sa.sa_handler = flag_config; 463 sigaction(SIGHUP, &sa, (struct sigaction *)0); 464 sa.sa_handler = flag_reapchild; 465 sigaction(SIGCHLD, &sa, (struct sigaction *)0); 466 sa.sa_handler = SIG_IGN; 467 sigaction(SIGPIPE, &sa, &sapipe); 468 469 { 470 /* space for daemons to overwrite environment for ps */ 471#define DUMMYSIZE 100 472 char dummy[DUMMYSIZE]; 473 474 (void)memset(dummy, 'x', DUMMYSIZE - 1); 475 dummy[DUMMYSIZE - 1] = '\0'; 476 (void)setenv("inetd_dummy", dummy, 1); 477 } 478 479 if (pipe(signalpipe) != 0) { 480 syslog(LOG_ERR, "pipe: %%m"); 481 exit(EX_OSERR); 482 } 483 FD_SET(signalpipe[0], &allsock); 484 nsock++; 485 if (signalpipe[0] > maxsock) 486 maxsock = signalpipe[0]; 487 488 for (;;) { 489 int n, ctrl; 490 fd_set readable; 491 492 if (nsock == 0) { 493 syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__); 494 exit(EX_SOFTWARE); 495 } 496 readable = allsock; 497 if ((n = select(maxsock + 1, &readable, (fd_set *)0, 498 (fd_set *)0, (struct timeval *)0)) <= 0) { 499 if (n < 0 && errno != EINTR) { 500 syslog(LOG_WARNING, "select: %m"); 501 sleep(1); 502 } 503 continue; 504 } 505 /* handle any queued signal flags */ 506 if (FD_ISSET(signalpipe[0], &readable)) { 507 int n; 508 if (ioctl(signalpipe[0], FIONREAD, &n) != 0) { 509 syslog(LOG_ERR, "ioctl: %m"); 510 exit(EX_OSERR); 511 } 512 while (--n >= 0) { 513 char c; 514 if (read(signalpipe[0], &c, 1) != 1) { 515 syslog(LOG_ERR, "read: %m"); 516 exit(EX_OSERR); 517 } 518 if (debug) 519 warnx("Handling signal flag %c", c); 520 switch(c) { 521 case 'A': /* sigalrm */ 522 retry(); 523 break; 524 case 'C': /* sigchld */ 525 reapchild(); 526 break; 527 case 'H': /* sighup */ 528 config(); 529 break; 530 } 531 } 532 } 533 for (sep = servtab; n && sep; sep = sep->se_next) 534 if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 535 n--; 536 if (debug) 537 warnx("someone wants %s", sep->se_service); 538 if (sep->se_accept && sep->se_socktype == SOCK_STREAM) { 539 ctrl = accept(sep->se_fd, (struct sockaddr *)0, 540 (int *)0); 541 if (debug) 542 warnx("accept, ctrl %d", ctrl); 543 if (ctrl < 0) { 544 if (errno != EINTR) 545 syslog(LOG_WARNING, 546 "accept (for %s): %m", 547 sep->se_service); 548 if (sep->se_accept && 549 sep->se_socktype == SOCK_STREAM) 550 close(ctrl); 551 continue; 552 } 553 if (cpmip(sep, ctrl) < 0) { 554 close(ctrl); 555 continue; 556 } 557 } else 558 ctrl = sep->se_fd; 559 if (log && !ISWRAP(sep)) { 560 pnm = "unknown"; 561 i = sizeof peer; 562 if (getpeername(ctrl, (struct sockaddr *) 563 &peer, &i)) { 564 i = sizeof peer; 565 if (recvfrom(ctrl, buf, sizeof(buf), 566 MSG_PEEK, 567 (struct sockaddr *)&peer, &i) >= 0) 568 pnm = inet_ntoa(peer.sin_addr); 569 } 570 else 571 pnm = inet_ntoa(peer.sin_addr); 572 syslog(LOG_INFO,"%s from %s", sep->se_service, pnm); 573 } 574 (void) sigblock(SIGBLOCK); 575 pid = 0; 576 /* 577 * Fork for all external services, builtins which need to 578 * fork and anything we're wrapping (as wrapping might 579 * block or use hosts_options(5) twist). 580 */ 581 dofork = !sep->se_bi || sep->se_bi->bi_fork || ISWRAP(sep); 582 if (dofork) { 583 if (sep->se_count++ == 0) 584 (void)gettimeofday(&sep->se_time, (struct timezone *)NULL); 585 else if (sep->se_count >= toomany) { 586 struct timeval now; 587 588 (void)gettimeofday(&now, (struct timezone *)NULL); 589 if (now.tv_sec - sep->se_time.tv_sec > 590 CNT_INTVL) { 591 sep->se_time = now; 592 sep->se_count = 1; 593 } else { 594 syslog(LOG_ERR, 595 "%s/%s server failing (looping), service terminated", 596 sep->se_service, sep->se_proto); 597 close_sep(sep); 598 sigsetmask(0L); 599 if (!timingout) { 600 timingout = 1; 601 alarm(RETRYTIME); 602 } 603 continue; 604 } 605 } 606 pid = fork(); 607 } 608 if (pid < 0) { 609 syslog(LOG_ERR, "fork: %m"); 610 if (sep->se_accept && 611 sep->se_socktype == SOCK_STREAM) 612 close(ctrl); 613 sigsetmask(0L); 614 sleep(1); 615 continue; 616 } 617 if (pid) 618 addchild(sep, pid); 619 sigsetmask(0L); 620 if (pid == 0) { 621 if (dofork) { 622 if (debug) 623 warnx("+ closing from %d", maxsock); 624 for (tmpint = maxsock; tmpint > 2; tmpint--) 625 if (tmpint != ctrl) 626 (void) close(tmpint); 627 } 628 /* 629 * Call tcpmux to find the real service to exec. 630 */ 631 if (sep->se_bi && 632 sep->se_bi->bi_fn == (void (*)()) tcpmux) { 633 sep = tcpmux(ctrl); 634 if (sep == NULL) { 635 close(ctrl); 636 _exit(0); 637 } 638 } 639 if (ISWRAP(sep)) { 640 inetd_setproctitle("wrapping", ctrl); 641 service = sep->se_server_name ? 642 sep->se_server_name : sep->se_service; 643 request_init(&req, RQ_DAEMON, service, RQ_FILE, ctrl, NULL); 644 fromhost(&req); 645 deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY; 646 allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY; 647 denied = !hosts_access(&req); 648 if (denied) { 649 syslog(deny_severity, 650 "refused connection from %.500s, service %s (%s)", 651 eval_client(&req), service, sep->se_proto); 652 if (sep->se_socktype != SOCK_STREAM) 653 recv(ctrl, buf, sizeof (buf), 0); 654 if (dofork) 655 _exit(0); 656 } 657 if (log) { 658 syslog(allow_severity, 659 "connection from %.500s, service %s (%s)", 660 eval_client(&req), service, sep->se_proto); 661 } 662 } 663 if (sep->se_bi) { 664 (*sep->se_bi->bi_fn)(ctrl, sep); 665 } else { 666 if (debug) 667 warnx("%d execl %s", 668 getpid(), sep->se_server); 669 dup2(ctrl, 0); 670 close(ctrl); 671 dup2(0, 1); 672 dup2(0, 2); 673 if ((pwd = getpwnam(sep->se_user)) == NULL) { 674 syslog(LOG_ERR, 675 "%s/%s: %s: No such user", 676 sep->se_service, sep->se_proto, 677 sep->se_user); 678 if (sep->se_socktype != SOCK_STREAM) 679 recv(0, buf, sizeof (buf), 0); 680 _exit(EX_NOUSER); 681 } 682 grp = NULL; 683 if ( sep->se_group != NULL 684 && (grp = getgrnam(sep->se_group)) == NULL 685 ) { 686 syslog(LOG_ERR, 687 "%s/%s: %s: No such group", 688 sep->se_service, sep->se_proto, 689 sep->se_group); 690 if (sep->se_socktype != SOCK_STREAM) 691 recv(0, buf, sizeof (buf), 0); 692 _exit(EX_NOUSER); 693 } 694 if (grp != NULL) 695 pwd->pw_gid = grp->gr_gid; 696#ifdef LOGIN_CAP 697 if ((lc = login_getclass(sep->se_class)) == NULL) { 698 /* error syslogged by getclass */ 699 syslog(LOG_ERR, 700 "%s/%s: %s: login class error", 701 sep->se_service, sep->se_proto, 702 sep->se_class); 703 if (sep->se_socktype != SOCK_STREAM) 704 recv(0, buf, sizeof (buf), 0); 705 _exit(EX_NOUSER); 706 } 707#endif 708 if (setsid() < 0) { 709 syslog(LOG_ERR, 710 "%s: can't setsid(): %m", 711 sep->se_service); 712 /* _exit(EX_OSERR); not fatal yet */ 713 } 714#ifdef LOGIN_CAP 715 if (setusercontext(lc, pwd, pwd->pw_uid, 716 LOGIN_SETALL) != 0) { 717 syslog(LOG_ERR, 718 "%s: can't setusercontext(..%s..): %m", 719 sep->se_service, sep->se_user); 720 _exit(EX_OSERR); 721 } 722#else 723 if (pwd->pw_uid) { 724 if (setlogin(sep->se_user) < 0) { 725 syslog(LOG_ERR, 726 "%s: can't setlogin(%s): %m", 727 sep->se_service, sep->se_user); 728 /* _exit(EX_OSERR); not yet */ 729 } 730 if (setgid(pwd->pw_gid) < 0) { 731 syslog(LOG_ERR, 732 "%s: can't set gid %d: %m", 733 sep->se_service, pwd->pw_gid); 734 _exit(EX_OSERR); 735 } 736 (void) initgroups(pwd->pw_name, 737 pwd->pw_gid); 738 if (setuid(pwd->pw_uid) < 0) { 739 syslog(LOG_ERR, 740 "%s: can't set uid %d: %m", 741 sep->se_service, pwd->pw_uid); 742 _exit(EX_OSERR); 743 } 744 } 745#endif 746 sigaction(SIGPIPE, &sapipe, 747 (struct sigaction *)0); 748 execv(sep->se_server, sep->se_argv); 749 syslog(LOG_ERR, 750 "cannot execute %s: %m", sep->se_server); 751 if (sep->se_socktype != SOCK_STREAM) 752 recv(0, buf, sizeof (buf), 0); 753 } 754 if (dofork) 755 _exit(0); 756 } 757 if (sep->se_accept && sep->se_socktype == SOCK_STREAM) 758 close(ctrl); 759 } 760 } 761} 762 763/* 764 * Add a signal flag to the signal flag queue for later handling 765 */ 766 767void flag_signal(c) 768 char c; 769{ 770 if (write(signalpipe[1], &c, 1) != 1) { 771 syslog(LOG_ERR, "write: %m"); 772 exit(EX_OSERR); 773 } 774} 775 776/* 777 * Record a new child pid for this service. If we've reached the 778 * limit on children, then stop accepting incoming requests. 779 */ 780 781void 782addchild(struct servtab *sep, pid_t pid) 783{ 784#ifdef SANITY_CHECK 785 if (sep->se_numchild >= sep->se_maxchild) { 786 syslog(LOG_ERR, "%s: %d >= %d", 787 __FUNCTION__, sep->se_numchild, sep->se_maxchild); 788 exit(EX_SOFTWARE); 789 } 790#endif 791 if (sep->se_maxchild == 0) 792 return; 793 sep->se_pids[sep->se_numchild++] = pid; 794 if (sep->se_numchild == sep->se_maxchild) 795 disable(sep); 796} 797 798/* 799 * Some child process has exited. See if it's on somebody's list. 800 */ 801 802void 803flag_reapchild(signo) 804 int signo; 805{ 806 flag_signal('C'); 807} 808 809void 810reapchild() 811{ 812 int k, status; 813 pid_t pid; 814 struct servtab *sep; 815 816 for (;;) { 817 pid = wait3(&status, WNOHANG, (struct rusage *)0); 818 if (pid <= 0) 819 break; 820 if (debug) 821 warnx("%d reaped, status %#x", pid, status); 822 for (sep = servtab; sep; sep = sep->se_next) { 823 for (k = 0; k < sep->se_numchild; k++) 824 if (sep->se_pids[k] == pid) 825 break; 826 if (k == sep->se_numchild) 827 continue; 828 if (sep->se_numchild == sep->se_maxchild) 829 enable(sep); 830 sep->se_pids[k] = sep->se_pids[--sep->se_numchild]; 831 if (status) 832 syslog(LOG_WARNING, 833 "%s[%d]: exit status 0x%x", 834 sep->se_server, pid, status); 835 break; 836 } 837 } 838} 839 840void 841flag_config(signo) 842 int signo; 843{ 844 flag_signal('H'); 845} 846 847void config() 848{ 849 struct servtab *sep, *new, **sepp; 850 long omask; 851 852 if (!setconfig()) { 853 syslog(LOG_ERR, "%s: %m", CONFIG); 854 return; 855 } 856 for (sep = servtab; sep; sep = sep->se_next) 857 sep->se_checked = 0; 858 while ((new = getconfigent())) { 859 if (getpwnam(new->se_user) == NULL) { 860 syslog(LOG_ERR, 861 "%s/%s: No such user '%s', service ignored", 862 new->se_service, new->se_proto, new->se_user); 863 continue; 864 } 865 if (new->se_group && getgrnam(new->se_group) == NULL) { 866 syslog(LOG_ERR, 867 "%s/%s: No such group '%s', service ignored", 868 new->se_service, new->se_proto, new->se_group); 869 continue; 870 } 871#ifdef LOGIN_CAP 872 if (login_getclass(new->se_class) == NULL) { 873 /* error syslogged by getclass */ 874 syslog(LOG_ERR, 875 "%s/%s: %s: login class error, service ignored", 876 new->se_service, new->se_proto, new->se_class); 877 continue; 878 } 879#endif 880 for (sep = servtab; sep; sep = sep->se_next) 881 if (strcmp(sep->se_service, new->se_service) == 0 && 882 strcmp(sep->se_proto, new->se_proto) == 0) 883 break; 884 if (sep != 0) { 885 int i; 886 887#define SWAP(a, b) { typeof(a) c = a; a = b; b = c; } 888 omask = sigblock(SIGBLOCK); 889 /* copy over outstanding child pids */ 890 if (sep->se_maxchild && new->se_maxchild) { 891 new->se_numchild = sep->se_numchild; 892 if (new->se_numchild > new->se_maxchild) 893 new->se_numchild = new->se_maxchild; 894 memcpy(new->se_pids, sep->se_pids, 895 new->se_numchild * sizeof(*new->se_pids)); 896 } 897 SWAP(sep->se_pids, new->se_pids); 898 sep->se_maxchild = new->se_maxchild; 899 sep->se_numchild = new->se_numchild; 900 sep->se_maxcpm = new->se_maxcpm; 901 /* might need to turn on or off service now */ 902 if (sep->se_fd >= 0) { 903 if (sep->se_maxchild 904 && sep->se_numchild == sep->se_maxchild) { 905 if (FD_ISSET(sep->se_fd, &allsock)) 906 disable(sep); 907 } else { 908 if (!FD_ISSET(sep->se_fd, &allsock)) 909 enable(sep); 910 } 911 } 912 sep->se_accept = new->se_accept; 913 SWAP(sep->se_user, new->se_user); 914 SWAP(sep->se_group, new->se_group); 915#ifdef LOGIN_CAP 916 SWAP(sep->se_class, new->se_class); 917#endif 918 SWAP(sep->se_server, new->se_server); 919 SWAP(sep->se_server_name, new->se_server_name); 920 for (i = 0; i < MAXARGV; i++) 921 SWAP(sep->se_argv[i], new->se_argv[i]); 922 sigsetmask(omask); 923 freeconfig(new); 924 if (debug) 925 print_service("REDO", sep); 926 } else { 927 sep = enter(new); 928 if (debug) 929 print_service("ADD ", sep); 930 } 931 sep->se_checked = 1; 932 if (ISMUX(sep)) { 933 sep->se_fd = -1; 934 continue; 935 } 936 if (!sep->se_rpc) { 937 sp = getservbyname(sep->se_service, sep->se_proto); 938 if (sp == 0) { 939 syslog(LOG_ERR, "%s/%s: unknown service", 940 sep->se_service, sep->se_proto); 941 sep->se_checked = 0; 942 continue; 943 } 944 if (sp->s_port != sep->se_ctrladdr.sin_port) { 945 sep->se_ctrladdr.sin_family = AF_INET; 946 sep->se_ctrladdr.sin_addr = bind_address; 947 sep->se_ctrladdr.sin_port = sp->s_port; 948 if (sep->se_fd >= 0) 949 close_sep(sep); 950 } 951 } else { 952 rpc = getrpcbyname(sep->se_service); 953 if (rpc == 0) { 954 syslog(LOG_ERR, "%s/%s unknown RPC service.", 955 sep->se_service, sep->se_proto); 956 if (sep->se_fd != -1) 957 (void) close(sep->se_fd); 958 sep->se_fd = -1; 959 continue; 960 } 961 if (rpc->r_number != sep->se_rpc_prog) { 962 if (sep->se_rpc_prog) 963 unregisterrpc(sep); 964 sep->se_rpc_prog = rpc->r_number; 965 if (sep->se_fd != -1) 966 (void) close(sep->se_fd); 967 sep->se_fd = -1; 968 } 969 } 970 if (sep->se_fd == -1) 971 setup(sep); 972 } 973 endconfig(); 974 /* 975 * Purge anything not looked at above. 976 */ 977 omask = sigblock(SIGBLOCK); 978 sepp = &servtab; 979 while ((sep = *sepp)) { 980 if (sep->se_checked) { 981 sepp = &sep->se_next; 982 continue; 983 } 984 *sepp = sep->se_next; 985 if (sep->se_fd >= 0) 986 close_sep(sep); 987 if (debug) 988 print_service("FREE", sep); 989 if (sep->se_rpc && sep->se_rpc_prog > 0) 990 unregisterrpc(sep); 991 freeconfig(sep); 992 free((char *)sep); 993 } 994 (void) sigsetmask(omask); 995} 996 997void 998unregisterrpc(sep) 999 struct servtab *sep; 1000{ 1001 int i; 1002 struct servtab *sepp; 1003 long omask; 1004 1005 omask = sigblock(SIGBLOCK); 1006 for (sepp = servtab; sepp; sepp = sepp->se_next) { 1007 if (sepp == sep) 1008 continue; 1009 if (sep->se_checked == 0 || 1010 !sepp->se_rpc || 1011 sep->se_rpc_prog != sepp->se_rpc_prog) 1012 continue; 1013 return; 1014 } 1015 if (debug) 1016 print_service("UNREG", sep); 1017 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) 1018 pmap_unset(sep->se_rpc_prog, i); 1019 if (sep->se_fd != -1) 1020 (void) close(sep->se_fd); 1021 sep->se_fd = -1; 1022 (void) sigsetmask(omask); 1023} 1024 1025void 1026flag_retry(signo) 1027 int signo; 1028{ 1029 flag_signal('A'); 1030} 1031 1032void 1033retry() 1034{ 1035 struct servtab *sep; 1036 1037 timingout = 0; 1038 for (sep = servtab; sep; sep = sep->se_next) 1039 if (sep->se_fd == -1 && !ISMUX(sep)) 1040 setup(sep); 1041} 1042 1043void 1044setup(sep) 1045 struct servtab *sep; 1046{ 1047 int on = 1; 1048 1049 if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 1050 if (debug) 1051 warn("socket failed on %s/%s", 1052 sep->se_service, sep->se_proto); 1053 syslog(LOG_ERR, "%s/%s: socket: %m", 1054 sep->se_service, sep->se_proto); 1055 return; 1056 } 1057#define turnon(fd, opt) \ 1058setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 1059 if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 1060 turnon(sep->se_fd, SO_DEBUG) < 0) 1061 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 1062 if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 1063 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 1064#ifdef SO_PRIVSTATE 1065 if (turnon(sep->se_fd, SO_PRIVSTATE) < 0) 1066 syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m"); 1067#endif 1068#undef turnon 1069 if (sep->se_type == TTCP_TYPE) 1070 if (setsockopt(sep->se_fd, IPPROTO_TCP, TCP_NOPUSH, 1071 (char *)&on, sizeof (on)) < 0) 1072 syslog(LOG_ERR, "setsockopt (TCP_NOPUSH): %m"); 1073 if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 1074 sizeof (sep->se_ctrladdr)) < 0) { 1075 if (debug) 1076 warn("bind failed on %s/%s", 1077 sep->se_service, sep->se_proto); 1078 syslog(LOG_ERR, "%s/%s: bind: %m", 1079 sep->se_service, sep->se_proto); 1080 (void) close(sep->se_fd); 1081 sep->se_fd = -1; 1082 if (!timingout) { 1083 timingout = 1; 1084 alarm(RETRYTIME); 1085 } 1086 return; 1087 } 1088 if (sep->se_rpc) { 1089 int i, len = sizeof(struct sockaddr); 1090 1091 if (getsockname(sep->se_fd, 1092 (struct sockaddr*)&sep->se_ctrladdr, &len) < 0){ 1093 syslog(LOG_ERR, "%s/%s: getsockname: %m", 1094 sep->se_service, sep->se_proto); 1095 (void) close(sep->se_fd); 1096 sep->se_fd = -1; 1097 return; 1098 } 1099 if (debug) 1100 print_service("REG ", sep); 1101 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 1102 pmap_unset(sep->se_rpc_prog, i); 1103 pmap_set(sep->se_rpc_prog, i, 1104 (sep->se_socktype == SOCK_DGRAM) 1105 ? IPPROTO_UDP : IPPROTO_TCP, 1106 ntohs(sep->se_ctrladdr.sin_port)); 1107 } 1108 1109 } 1110 if (sep->se_socktype == SOCK_STREAM) 1111 listen(sep->se_fd, 64); 1112 enable(sep); 1113 if (debug) { 1114 warnx("registered %s on %d", 1115 sep->se_server, sep->se_fd); 1116 } 1117} 1118 1119/* 1120 * Finish with a service and its socket. 1121 */ 1122void 1123close_sep(sep) 1124 struct servtab *sep; 1125{ 1126 if (sep->se_fd >= 0) { 1127 if (FD_ISSET(sep->se_fd, &allsock)) 1128 disable(sep); 1129 (void) close(sep->se_fd); 1130 sep->se_fd = -1; 1131 } 1132 sep->se_count = 0; 1133 sep->se_numchild = 0; /* forget about any existing children */ 1134} 1135 1136int 1137matchservent(name1, name2, proto) 1138 char *name1, *name2, *proto; 1139{ 1140 char **alias; 1141 struct servent *se; 1142 1143 if ((se = getservbyname(name1, proto)) != NULL) { 1144 if (strcmp(name2, se->s_name) == 0) 1145 return(1); 1146 for (alias = se->s_aliases; *alias; alias++) 1147 if (strcmp(name2, *alias) == 0) 1148 return(1); 1149 } 1150 return(0); 1151} 1152 1153struct servtab * 1154enter(cp) 1155 struct servtab *cp; 1156{ 1157 struct servtab *sep; 1158 long omask; 1159 1160 sep = (struct servtab *)malloc(sizeof (*sep)); 1161 if (sep == (struct servtab *)0) { 1162 syslog(LOG_ERR, "Out of memory."); 1163 exit(EX_OSERR); 1164 } 1165 *sep = *cp; 1166 sep->se_fd = -1; 1167 omask = sigblock(SIGBLOCK); 1168 sep->se_next = servtab; 1169 servtab = sep; 1170 sigsetmask(omask); 1171 return (sep); 1172} 1173 1174void 1175enable(struct servtab *sep) 1176{ 1177 if (debug) 1178 warnx( 1179 "enabling %s, fd %d", sep->se_service, sep->se_fd); 1180#ifdef SANITY_CHECK 1181 if (sep->se_fd < 0) { 1182 syslog(LOG_ERR, 1183 "%s: %s: bad fd", __FUNCTION__, sep->se_service); 1184 exit(EX_SOFTWARE); 1185 } 1186 if (ISMUX(sep)) { 1187 syslog(LOG_ERR, 1188 "%s: %s: is mux", __FUNCTION__, sep->se_service); 1189 exit(EX_SOFTWARE); 1190 } 1191 if (FD_ISSET(sep->se_fd, &allsock)) { 1192 syslog(LOG_ERR, 1193 "%s: %s: not off", __FUNCTION__, sep->se_service); 1194 exit(EX_SOFTWARE); 1195 } 1196#endif 1197 FD_SET(sep->se_fd, &allsock); 1198 nsock++; 1199 if (sep->se_fd > maxsock) 1200 maxsock = sep->se_fd; 1201} 1202 1203void 1204disable(struct servtab *sep) 1205{ 1206 if (debug) 1207 warnx( 1208 "disabling %s, fd %d", sep->se_service, sep->se_fd); 1209#ifdef SANITY_CHECK 1210 if (sep->se_fd < 0) { 1211 syslog(LOG_ERR, 1212 "%s: %s: bad fd", __FUNCTION__, sep->se_service); 1213 exit(EX_SOFTWARE); 1214 } 1215 if (ISMUX(sep)) { 1216 syslog(LOG_ERR, 1217 "%s: %s: is mux", __FUNCTION__, sep->se_service); 1218 exit(EX_SOFTWARE); 1219 } 1220 if (!FD_ISSET(sep->se_fd, &allsock)) { 1221 syslog(LOG_ERR, 1222 "%s: %s: not on", __FUNCTION__, sep->se_service); 1223 exit(EX_SOFTWARE); 1224 } 1225 if (nsock == 0) { 1226 syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__); 1227 exit(EX_SOFTWARE); 1228 } 1229#endif 1230 FD_CLR(sep->se_fd, &allsock); 1231 nsock--; 1232 if (sep->se_fd == maxsock) 1233 maxsock--; 1234} 1235 1236FILE *fconfig = NULL; 1237struct servtab serv; 1238char line[LINE_MAX]; 1239 1240int 1241setconfig() 1242{ 1243 1244 if (fconfig != NULL) { 1245 fseek(fconfig, 0L, SEEK_SET); 1246 return (1); 1247 } 1248 fconfig = fopen(CONFIG, "r"); 1249 return (fconfig != NULL); 1250} 1251 1252void 1253endconfig() 1254{ 1255 if (fconfig) { 1256 (void) fclose(fconfig); 1257 fconfig = NULL; 1258 } 1259} 1260 1261struct servtab * 1262getconfigent() 1263{ 1264 struct servtab *sep = &serv; 1265 int argc; 1266 char *cp, *arg, *s; 1267 char *versp; 1268 static char TCPMUX_TOKEN[] = "tcpmux/"; 1269#define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 1270 1271more: 1272 while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0')) 1273 ; 1274 if (cp == NULL) 1275 return ((struct servtab *)0); 1276 /* 1277 * clear the static buffer, since some fields (se_ctrladdr, 1278 * for example) don't get initialized here. 1279 */ 1280 memset((caddr_t)sep, 0, sizeof *sep); 1281 arg = skip(&cp); 1282 if (cp == NULL) { 1283 /* got an empty line containing just blanks/tabs. */ 1284 goto more; 1285 } 1286 if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 1287 char *c = arg + MUX_LEN; 1288 if (*c == '+') { 1289 sep->se_type = MUXPLUS_TYPE; 1290 c++; 1291 } else 1292 sep->se_type = MUX_TYPE; 1293 sep->se_service = newstr(c); 1294 } else { 1295 sep->se_service = newstr(arg); 1296 sep->se_type = NORM_TYPE; 1297 } 1298 arg = sskip(&cp); 1299 if (strcmp(arg, "stream") == 0) 1300 sep->se_socktype = SOCK_STREAM; 1301 else if (strcmp(arg, "dgram") == 0) 1302 sep->se_socktype = SOCK_DGRAM; 1303 else if (strcmp(arg, "rdm") == 0) 1304 sep->se_socktype = SOCK_RDM; 1305 else if (strcmp(arg, "seqpacket") == 0) 1306 sep->se_socktype = SOCK_SEQPACKET; 1307 else if (strcmp(arg, "raw") == 0) 1308 sep->se_socktype = SOCK_RAW; 1309 else 1310 sep->se_socktype = -1; 1311 1312 arg = sskip(&cp); 1313 if (strcmp(arg, "tcp/ttcp") == 0) { 1314 sep->se_type = TTCP_TYPE; 1315 sep->se_proto = newstr("tcp"); 1316 } else { 1317 sep->se_proto = newstr(arg); 1318 } 1319 if (strncmp(sep->se_proto, "rpc/", 4) == 0) { 1320 memmove(sep->se_proto, sep->se_proto + 4, 1321 strlen(sep->se_proto) + 1 - 4); 1322 sep->se_rpc = 1; 1323 sep->se_rpc_prog = sep->se_rpc_lowvers = 1324 sep->se_rpc_lowvers = 0; 1325 sep->se_ctrladdr.sin_family = AF_INET; 1326 sep->se_ctrladdr.sin_port = 0; 1327 sep->se_ctrladdr.sin_addr = bind_address; 1328 if ((versp = rindex(sep->se_service, '/'))) { 1329 *versp++ = '\0'; 1330 switch (sscanf(versp, "%d-%d", 1331 &sep->se_rpc_lowvers, 1332 &sep->se_rpc_highvers)) { 1333 case 2: 1334 break; 1335 case 1: 1336 sep->se_rpc_highvers = 1337 sep->se_rpc_lowvers; 1338 break; 1339 default: 1340 syslog(LOG_ERR, 1341 "bad RPC version specifier; %s\n", 1342 sep->se_service); 1343 freeconfig(sep); 1344 goto more; 1345 } 1346 } 1347 else { 1348 sep->se_rpc_lowvers = 1349 sep->se_rpc_highvers = 1; 1350 } 1351 } 1352 arg = sskip(&cp); 1353 if (!strncmp(arg, "wait", 4)) 1354 sep->se_accept = 0; 1355 else if (!strncmp(arg, "nowait", 6)) 1356 sep->se_accept = 1; 1357 else { 1358 syslog(LOG_ERR, 1359 "%s: bad wait/nowait for service %s", 1360 CONFIG, sep->se_service); 1361 goto more; 1362 } 1363 sep->se_maxchild = -1; 1364 sep->se_maxcpm = -1; 1365 if ((s = strchr(arg, '/')) != NULL) { 1366 char *eptr; 1367 u_long val; 1368 1369 val = strtoul(s + 1, &eptr, 10); 1370 if (eptr == s + 1 || val > MAX_MAXCHLD) { 1371 syslog(LOG_ERR, 1372 "%s: bad max-child for service %s", 1373 CONFIG, sep->se_service); 1374 goto more; 1375 } 1376 if (debug) 1377 if (!sep->se_accept && val != 1) 1378 warnx("maxchild=%lu for wait service %s" 1379 " not recommended", val, sep->se_service); 1380 sep->se_maxchild = val; 1381 if (*eptr == '/') 1382 sep->se_maxcpm = strtol(eptr + 1, &eptr, 10); 1383 /* 1384 * explicitly do not check for \0 for future expansion / 1385 * backwards compatibility 1386 */ 1387 } 1388 if (ISMUX(sep)) { 1389 /* 1390 * Silently enforce "nowait" mode for TCPMUX services 1391 * since they don't have an assigned port to listen on. 1392 */ 1393 sep->se_accept = 1; 1394 if (strcmp(sep->se_proto, "tcp")) { 1395 syslog(LOG_ERR, 1396 "%s: bad protocol for tcpmux service %s", 1397 CONFIG, sep->se_service); 1398 goto more; 1399 } 1400 if (sep->se_socktype != SOCK_STREAM) { 1401 syslog(LOG_ERR, 1402 "%s: bad socket type for tcpmux service %s", 1403 CONFIG, sep->se_service); 1404 goto more; 1405 } 1406 } 1407 sep->se_user = newstr(sskip(&cp)); 1408#ifdef LOGIN_CAP 1409 if ((s = strrchr(sep->se_user, '/')) != NULL) { 1410 *s = '\0'; 1411 sep->se_class = newstr(s + 1); 1412 } else 1413 sep->se_class = newstr(RESOURCE_RC); 1414#endif 1415 if ((s = strrchr(sep->se_user, ':')) != NULL) { 1416 *s = '\0'; 1417 sep->se_group = newstr(s + 1); 1418 } else 1419 sep->se_group = NULL; 1420 sep->se_server = newstr(sskip(&cp)); 1421 if ((sep->se_server_name = rindex(sep->se_server, '/'))) 1422 sep->se_server_name++; 1423 if (strcmp(sep->se_server, "internal") == 0) { 1424 struct biltin *bi; 1425 1426 for (bi = biltins; bi->bi_service; bi++) 1427 if ((bi->bi_socktype == sep->se_socktype && 1428 strcmp(bi->bi_service, sep->se_service) == 0) || 1429 matchservent(bi->bi_service, sep->se_service, 1430 sep->se_proto)) 1431 break; 1432 if (bi->bi_service == 0) { 1433 syslog(LOG_ERR, "internal service %s unknown", 1434 sep->se_service); 1435 goto more; 1436 } 1437 sep->se_accept = 1; /* force accept mode for built-ins */ 1438 sep->se_bi = bi; 1439 } else 1440 sep->se_bi = NULL; 1441 if (sep->se_maxcpm < 0) 1442 sep->se_maxcpm = maxcpm; 1443 if (sep->se_maxchild < 0) { /* apply default max-children */ 1444 if (sep->se_bi && sep->se_bi->bi_maxchild >= 0) 1445 sep->se_maxchild = sep->se_bi->bi_maxchild; 1446 else if (sep->se_accept) 1447 sep->se_maxchild = maxchild > 0 ? maxchild : 0; 1448 else 1449 sep->se_maxchild = 1; 1450 } 1451 if (sep->se_maxchild) { 1452 sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids)); 1453 if (sep->se_pids == NULL) { 1454 syslog(LOG_ERR, "Out of memory."); 1455 exit(EX_OSERR); 1456 } 1457 } 1458 argc = 0; 1459 for (arg = skip(&cp); cp; arg = skip(&cp)) 1460 if (argc < MAXARGV) { 1461 sep->se_argv[argc++] = newstr(arg); 1462 } else { 1463 syslog(LOG_ERR, 1464 "%s: too many arguments for service %s", 1465 CONFIG, sep->se_service); 1466 goto more; 1467 } 1468 while (argc <= MAXARGV) 1469 sep->se_argv[argc++] = NULL; 1470 return (sep); 1471} 1472 1473void 1474freeconfig(cp) 1475 struct servtab *cp; 1476{ 1477 int i; 1478 1479 if (cp->se_service) 1480 free(cp->se_service); 1481 if (cp->se_proto) 1482 free(cp->se_proto); 1483 if (cp->se_user) 1484 free(cp->se_user); 1485 if (cp->se_group) 1486 free(cp->se_group); 1487#ifdef LOGIN_CAP 1488 if (cp->se_class) 1489 free(cp->se_class); 1490#endif 1491 if (cp->se_server) 1492 free(cp->se_server); 1493 if (cp->se_pids) 1494 free(cp->se_pids); 1495 for (i = 0; i < MAXARGV; i++) 1496 if (cp->se_argv[i]) 1497 free(cp->se_argv[i]); 1498} 1499 1500 1501/* 1502 * Safe skip - if skip returns null, log a syntax error in the 1503 * configuration file and exit. 1504 */ 1505char * 1506sskip(cpp) 1507 char **cpp; 1508{ 1509 char *cp; 1510 1511 cp = skip(cpp); 1512 if (cp == NULL) { 1513 syslog(LOG_ERR, "%s: syntax error", CONFIG); 1514 exit(EX_DATAERR); 1515 } 1516 return (cp); 1517} 1518 1519char * 1520skip(cpp) 1521 char **cpp; 1522{ 1523 char *cp = *cpp; 1524 char *start; 1525 char quote = '\0'; 1526 1527again: 1528 while (*cp == ' ' || *cp == '\t') 1529 cp++; 1530 if (*cp == '\0') { 1531 int c; 1532 1533 c = getc(fconfig); 1534 (void) ungetc(c, fconfig); 1535 if (c == ' ' || c == '\t') 1536 if ((cp = nextline(fconfig))) 1537 goto again; 1538 *cpp = (char *)0; 1539 return ((char *)0); 1540 } 1541 if (*cp == '"' || *cp == '\'') 1542 quote = *cp++; 1543 start = cp; 1544 if (quote) 1545 while (*cp && *cp != quote) 1546 cp++; 1547 else 1548 while (*cp && *cp != ' ' && *cp != '\t') 1549 cp++; 1550 if (*cp != '\0') 1551 *cp++ = '\0'; 1552 *cpp = cp; 1553 return (start); 1554} 1555 1556char * 1557nextline(fd) 1558 FILE *fd; 1559{ 1560 char *cp; 1561 1562 if (fgets(line, sizeof (line), fd) == NULL) 1563 return ((char *)0); 1564 cp = strchr(line, '\n'); 1565 if (cp) 1566 *cp = '\0'; 1567 return (line); 1568} 1569 1570char * 1571newstr(cp) 1572 char *cp; 1573{ 1574 if ((cp = strdup(cp ? cp : ""))) 1575 return (cp); 1576 syslog(LOG_ERR, "strdup: %m"); 1577 exit(EX_OSERR); 1578} 1579 1580#ifdef OLD_SETPROCTITLE 1581void 1582inetd_setproctitle(a, s) 1583 char *a; 1584 int s; 1585{ 1586 int size; 1587 char *cp; 1588 struct sockaddr_in sin; 1589 char buf[80]; 1590 1591 cp = Argv[0]; 1592 size = sizeof(sin); 1593 if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 1594 (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 1595 else 1596 (void) sprintf(buf, "-%s", a); 1597 strncpy(cp, buf, LastArg - cp); 1598 cp += strlen(cp); 1599 while (cp < LastArg) 1600 *cp++ = ' '; 1601} 1602#else 1603void 1604inetd_setproctitle(a, s) 1605 char *a; 1606 int s; 1607{ 1608 int size; 1609 struct sockaddr_in sin; 1610 char buf[80]; 1611 1612 size = sizeof(sin); 1613 if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 1614 (void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin.sin_addr)); 1615 else 1616 (void) sprintf(buf, "%s", a); 1617 setproctitle("%s", buf); 1618} 1619#endif 1620 1621 1622/* 1623 * Internet services provided internally by inetd: 1624 */ 1625#define BUFSIZE 8192 1626 1627/* ARGSUSED */ 1628void 1629iderror(lport, fport, fp, er) 1630 int lport, fport, er; 1631 FILE *fp; 1632{ 1633 fprintf(fp, "%d , %d : ERROR : %s\r\n", lport, fport, 1634 er == -1 ? "HIDDEN-USER" : er ? strerror(er) : "UNKNOWN-ERROR"); 1635 fflush(fp); 1636 fclose(fp); 1637 1638 exit(0); 1639} 1640 1641/* ARGSUSED */ 1642void 1643ident_stream(s, sep) /* Ident service */ 1644 int s; 1645 struct servtab *sep; 1646{ 1647 struct sockaddr_in sin[2]; 1648 struct ucred uc; 1649 struct passwd *pw; 1650 FILE *fp; 1651 char buf[BUFSIZE], *cp, **av; 1652 int len, c, rflag = 0, fflag = 0, argc = 0; 1653 u_short lport, fport; 1654 1655 inetd_setproctitle(sep->se_service, s); 1656 optind = 1; 1657 optreset = 1; 1658 for (av = sep->se_argv; *av; av++) 1659 argc++; 1660 if (argc) { 1661 while ((c = getopt(argc, sep->se_argv, "fr")) != -1) 1662 switch (c) { 1663 case 'f': 1664 fflag = 1; 1665 break; 1666 case 'r': 1667 rflag = 1; 1668 break; 1669 default: 1670 break; 1671 } 1672 } 1673 fp = fdopen(s, "r+"); 1674 len = sizeof(sin[0]); 1675 if (getsockname(s, (struct sockaddr *)&sin[0], &len) == -1) 1676 iderror(0, 0, fp, errno); 1677 len = sizeof(sin[1]); 1678 if (getpeername(s, (struct sockaddr *)&sin[1], &len) == -1) 1679 iderror(0, 0, fp, errno); 1680 errno = 0; 1681 if (fgets(buf, sizeof(buf), fp) == NULL) 1682 iderror(0, 0, fp, errno); 1683 buf[BUFSIZE - 1] = '\0'; 1684 strtok(buf, "\r\n"); 1685 cp = strtok(buf, ","); 1686 if (cp == NULL || sscanf(cp, "%hu", &lport) != 1) 1687 iderror(0, 0, fp, 0); 1688 cp = strtok(NULL, ","); 1689 if (cp == NULL || sscanf(cp, "%hu", &fport) != 1) 1690 iderror(0, 0, fp, 0); 1691 if (!rflag) 1692 iderror(lport, fport, fp, -1); 1693 sin[0].sin_port = htons(lport); 1694 sin[1].sin_port = htons(fport); 1695 len = sizeof(uc); 1696 if (sysctlbyname("net.inet.tcp.getcred", &uc, &len, sin, 1697 sizeof(sin)) == -1) 1698 iderror(lport, fport, fp, errno); 1699 pw = getpwuid(uc.cr_uid); 1700 if (pw == NULL) 1701 iderror(lport, fport, fp, errno); 1702 if (fflag) { 1703 FILE *fakeid = NULL; 1704 char fakeid_path[PATH_MAX]; 1705 struct stat sb; 1706 seteuid(pw->pw_uid); 1707 setegid(pw->pw_gid); 1708 snprintf(fakeid_path, sizeof(fakeid_path), "%s/.fakeid", 1709 pw->pw_dir); 1710 if ((fakeid = fopen(fakeid_path, "r")) != NULL && 1711 fstat(fileno(fakeid), &sb) != -1 && S_ISREG(sb.st_mode)) { 1712 buf[sizeof(buf) - 1] = '\0'; 1713 if (fgets(buf, sizeof(buf), fakeid) == NULL) { 1714 cp = pw->pw_name; 1715 fclose(fakeid); 1716 goto printit; 1717 } 1718 fclose(fakeid); 1719 strtok(buf, "\r\n"); 1720 if (strlen(buf) > 16) 1721 buf[16] = '\0'; 1722 cp = buf; 1723 while (isspace(*cp)) 1724 cp++; 1725 strtok(cp, " \t"); 1726 if (!*cp || getpwnam(cp)) 1727 cp = getpwuid(uc.cr_uid)->pw_name; 1728 } else 1729 cp = pw->pw_name; 1730 } else 1731 cp = pw->pw_name; 1732printit: 1733 fprintf(fp, "%d , %d : USERID : FreeBSD :%s\r\n", lport, fport, 1734 cp); 1735 fflush(fp); 1736 fclose(fp); 1737 1738 exit(0); 1739} 1740 1741/* ARGSUSED */ 1742void 1743echo_stream(s, sep) /* Echo service -- echo data back */ 1744 int s; 1745 struct servtab *sep; 1746{ 1747 char buffer[BUFSIZE]; 1748 int i; 1749 1750 inetd_setproctitle(sep->se_service, s); 1751 while ((i = read(s, buffer, sizeof(buffer))) > 0 && 1752 write(s, buffer, i) > 0) 1753 ; 1754 exit(0); 1755} 1756 1757int check_loop(sin, sep) 1758 struct sockaddr_in *sin; 1759 struct servtab *sep; 1760{ 1761 struct servtab *se2; 1762 1763 for (se2 = servtab; se2; se2 = se2->se_next) { 1764 if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM) 1765 continue; 1766 1767 if (sin->sin_port == se2->se_ctrladdr.sin_port) { 1768 syslog(LOG_WARNING, 1769 "%s/%s:%s/%s loop request REFUSED from %s", 1770 sep->se_service, sep->se_proto, 1771 se2->se_service, se2->se_proto, 1772 inet_ntoa(sin->sin_addr)); 1773 return 1; 1774 } 1775 } 1776 return 0; 1777} 1778 1779/* ARGSUSED */ 1780void 1781echo_dg(s, sep) /* Echo service -- echo data back */ 1782 int s; 1783 struct servtab *sep; 1784{ 1785 char buffer[BUFSIZE]; 1786 int i, size; 1787 struct sockaddr_in sin; 1788 1789 size = sizeof(sin); 1790 if ((i = recvfrom(s, buffer, sizeof(buffer), 0, 1791 (struct sockaddr *)&sin, &size)) < 0) 1792 return; 1793 1794 if (check_loop(&sin, sep)) 1795 return; 1796 1797 (void) sendto(s, buffer, i, 0, (struct sockaddr *)&sin, 1798 sizeof(sin)); 1799} 1800 1801/* ARGSUSED */ 1802void 1803discard_stream(s, sep) /* Discard service -- ignore data */ 1804 int s; 1805 struct servtab *sep; 1806{ 1807 int ret; 1808 char buffer[BUFSIZE]; 1809 1810 inetd_setproctitle(sep->se_service, s); 1811 while (1) { 1812 while ((ret = read(s, buffer, sizeof(buffer))) > 0) 1813 ; 1814 if (ret == 0 || errno != EINTR) 1815 break; 1816 } 1817 exit(0); 1818} 1819 1820/* ARGSUSED */ 1821void 1822discard_dg(s, sep) /* Discard service -- ignore data */ 1823 int s; 1824 struct servtab *sep; 1825{ 1826 char buffer[BUFSIZE]; 1827 1828 (void) read(s, buffer, sizeof(buffer)); 1829} 1830 1831#include <ctype.h> 1832#define LINESIZ 72 1833char ring[128]; 1834char *endring; 1835 1836void 1837initring() 1838{ 1839 int i; 1840 1841 endring = ring; 1842 1843 for (i = 0; i <= 128; ++i) 1844 if (isprint(i)) 1845 *endring++ = i; 1846} 1847 1848/* ARGSUSED */ 1849void 1850chargen_stream(s, sep) /* Character generator */ 1851 int s; 1852 struct servtab *sep; 1853{ 1854 int len; 1855 char *rs, text[LINESIZ+2]; 1856 1857 inetd_setproctitle(sep->se_service, s); 1858 1859 if (!endring) { 1860 initring(); 1861 rs = ring; 1862 } 1863 1864 text[LINESIZ] = '\r'; 1865 text[LINESIZ + 1] = '\n'; 1866 for (rs = ring;;) { 1867 if ((len = endring - rs) >= LINESIZ) 1868 memmove(text, rs, LINESIZ); 1869 else { 1870 memmove(text, rs, len); 1871 memmove(text + len, ring, LINESIZ - len); 1872 } 1873 if (++rs == endring) 1874 rs = ring; 1875 if (write(s, text, sizeof(text)) != sizeof(text)) 1876 break; 1877 } 1878 exit(0); 1879} 1880 1881/* ARGSUSED */ 1882void 1883chargen_dg(s, sep) /* Character generator */ 1884 int s; 1885 struct servtab *sep; 1886{ 1887 struct sockaddr_in sin; 1888 static char *rs; 1889 int len, size; 1890 char text[LINESIZ+2]; 1891 1892 if (endring == 0) { 1893 initring(); 1894 rs = ring; 1895 } 1896 1897 size = sizeof(sin); 1898 if (recvfrom(s, text, sizeof(text), 0, 1899 (struct sockaddr *)&sin, &size) < 0) 1900 return; 1901 1902 if (check_loop(&sin, sep)) 1903 return; 1904 1905 if ((len = endring - rs) >= LINESIZ) 1906 memmove(text, rs, LINESIZ); 1907 else { 1908 memmove(text, rs, len); 1909 memmove(text + len, ring, LINESIZ - len); 1910 } 1911 if (++rs == endring) 1912 rs = ring; 1913 text[LINESIZ] = '\r'; 1914 text[LINESIZ + 1] = '\n'; 1915 (void) sendto(s, text, sizeof(text), 0, 1916 (struct sockaddr *)&sin, sizeof(sin)); 1917} 1918 1919/* 1920 * Return a machine readable date and time, in the form of the 1921 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 1922 * returns the number of seconds since midnight, Jan 1, 1970, 1923 * we must add 2208988800 seconds to this figure to make up for 1924 * some seventy years Bell Labs was asleep. 1925 */ 1926 1927unsigned long 1928machtime() 1929{ 1930 struct timeval tv; 1931 1932 if (gettimeofday(&tv, (struct timezone *)NULL) < 0) { 1933 if (debug) 1934 warnx("unable to get time of day"); 1935 return (0L); 1936 } 1937#define OFFSET ((u_long)25567 * 24*60*60) 1938 return (htonl((long)(tv.tv_sec + OFFSET))); 1939#undef OFFSET 1940} 1941 1942/* ARGSUSED */ 1943void 1944machtime_stream(s, sep) 1945 int s; 1946 struct servtab *sep; 1947{ 1948 unsigned long result; 1949 1950 result = machtime(); 1951 (void) write(s, (char *) &result, sizeof(result)); 1952} 1953 1954/* ARGSUSED */ 1955void 1956machtime_dg(s, sep) 1957 int s; 1958 struct servtab *sep; 1959{ 1960 unsigned long result; 1961 struct sockaddr_in sin; 1962 int size; 1963 1964 size = sizeof(sin); 1965 if (recvfrom(s, (char *)&result, sizeof(result), 0, 1966 (struct sockaddr *)&sin, &size) < 0) 1967 return; 1968 1969 if (check_loop(&sin, sep)) 1970 return; 1971 1972 result = machtime(); 1973 (void) sendto(s, (char *) &result, sizeof(result), 0, 1974 (struct sockaddr *)&sin, sizeof(sin)); 1975} 1976 1977/* ARGSUSED */ 1978void 1979daytime_stream(s, sep) /* Return human-readable time of day */ 1980 int s; 1981 struct servtab *sep; 1982{ 1983 char buffer[256]; 1984 time_t clock; 1985 1986 clock = time((time_t *) 0); 1987 1988 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 1989 (void) write(s, buffer, strlen(buffer)); 1990} 1991 1992/* ARGSUSED */ 1993void 1994daytime_dg(s, sep) /* Return human-readable time of day */ 1995 int s; 1996 struct servtab *sep; 1997{ 1998 char buffer[256]; 1999 time_t clock; 2000 struct sockaddr_in sin; 2001 int size; 2002 2003 clock = time((time_t *) 0); 2004 2005 size = sizeof(sin); 2006 if (recvfrom(s, buffer, sizeof(buffer), 0, 2007 (struct sockaddr *)&sin, &size) < 0) 2008 return; 2009 2010 if (check_loop(&sin, sep)) 2011 return; 2012 2013 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 2014 (void) sendto(s, buffer, strlen(buffer), 0, 2015 (struct sockaddr *)&sin, sizeof(sin)); 2016} 2017 2018/* 2019 * print_service: 2020 * Dump relevant information to stderr 2021 */ 2022void 2023print_service(action, sep) 2024 char *action; 2025 struct servtab *sep; 2026{ 2027 fprintf(stderr, 2028#ifdef LOGIN_CAP 2029 "%s: %s proto=%s accept=%d max=%d user=%s group=%s class=%s builtin=%p server=%s\n", 2030#else 2031 "%s: %s proto=%s accept=%d max=%d user=%s group=%s builtin=%p server=%s\n", 2032#endif 2033 action, sep->se_service, sep->se_proto, 2034 sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group, 2035#ifdef LOGIN_CAP 2036 sep->se_class, 2037#endif 2038 (void *) sep->se_bi, sep->se_server); 2039} 2040 2041/* 2042 * Based on TCPMUX.C by Mark K. Lottor November 1988 2043 * sri-nic::ps:<mkl>tcpmux.c 2044 */ 2045 2046 2047static int /* # of characters upto \r,\n or \0 */ 2048getline(fd, buf, len) 2049 int fd; 2050 char *buf; 2051 int len; 2052{ 2053 int count = 0, n; 2054 struct sigaction sa; 2055 2056 sa.sa_flags = 0; 2057 sigemptyset(&sa.sa_mask); 2058 sa.sa_handler = SIG_DFL; 2059 sigaction(SIGALRM, &sa, (struct sigaction *)0); 2060 do { 2061 alarm(10); 2062 n = read(fd, buf, len-count); 2063 alarm(0); 2064 if (n == 0) 2065 return (count); 2066 if (n < 0) 2067 return (-1); 2068 while (--n >= 0) { 2069 if (*buf == '\r' || *buf == '\n' || *buf == '\0') 2070 return (count); 2071 count++; 2072 buf++; 2073 } 2074 } while (count < len); 2075 return (count); 2076} 2077 2078#define MAX_SERV_LEN (256+2) /* 2 bytes for \r\n */ 2079 2080#define strwrite(fd, buf) (void) write(fd, buf, sizeof(buf)-1) 2081 2082struct servtab * 2083tcpmux(s) 2084 int s; 2085{ 2086 struct servtab *sep; 2087 char service[MAX_SERV_LEN+1]; 2088 int len; 2089 2090 /* Get requested service name */ 2091 if ((len = getline(s, service, MAX_SERV_LEN)) < 0) { 2092 strwrite(s, "-Error reading service name\r\n"); 2093 return (NULL); 2094 } 2095 service[len] = '\0'; 2096 2097 if (debug) 2098 warnx("tcpmux: someone wants %s", service); 2099 2100 /* 2101 * Help is a required command, and lists available services, 2102 * one per line. 2103 */ 2104 if (!strcasecmp(service, "help")) { 2105 for (sep = servtab; sep; sep = sep->se_next) { 2106 if (!ISMUX(sep)) 2107 continue; 2108 (void)write(s,sep->se_service,strlen(sep->se_service)); 2109 strwrite(s, "\r\n"); 2110 } 2111 return (NULL); 2112 } 2113 2114 /* Try matching a service in inetd.conf with the request */ 2115 for (sep = servtab; sep; sep = sep->se_next) { 2116 if (!ISMUX(sep)) 2117 continue; 2118 if (!strcasecmp(service, sep->se_service)) { 2119 if (ISMUXPLUS(sep)) { 2120 strwrite(s, "+Go\r\n"); 2121 } 2122 return (sep); 2123 } 2124 } 2125 strwrite(s, "-Service not available\r\n"); 2126 return (NULL); 2127} 2128 2129#define CPMHSIZE 256 2130#define CPMHMASK (CPMHSIZE-1) 2131#define CHTGRAN 10 2132#define CHTSIZE 6 2133 2134typedef struct CTime { 2135 unsigned long ct_Ticks; 2136 int ct_Count; 2137} CTime; 2138 2139typedef struct CHash { 2140 struct in_addr ch_Addr; 2141 time_t ch_LTime; 2142 char *ch_Service; 2143 CTime ch_Times[CHTSIZE]; 2144} CHash; 2145 2146CHash CHashAry[CPMHSIZE]; 2147 2148int 2149cpmip(sep, ctrl) 2150 struct servtab *sep; 2151 int ctrl; 2152{ 2153 struct sockaddr_in rsin; 2154 int rsinLen = sizeof(rsin); 2155 int r = 0; 2156 2157 /* 2158 * If getpeername() fails, just let it through (if logging is 2159 * enabled the condition is caught elsewhere) 2160 */ 2161 2162 if (sep->se_maxcpm > 0 && 2163 getpeername(ctrl, (struct sockaddr *)&rsin, &rsinLen) == 0 ) { 2164 time_t t = time(NULL); 2165 int hv = 0xABC3D20F; 2166 int i; 2167 int cnt = 0; 2168 CHash *chBest = NULL; 2169 unsigned int ticks = t / CHTGRAN; 2170 2171 { 2172 char *p; 2173 int i; 2174 2175 for (i = 0, p = (char *)&rsin.sin_addr; 2176 i < sizeof(rsin.sin_addr); 2177 ++i, ++p) { 2178 hv = (hv << 5) ^ (hv >> 23) ^ *p; 2179 } 2180 hv = (hv ^ (hv >> 16)); 2181 } 2182 for (i = 0; i < 5; ++i) { 2183 CHash *ch = &CHashAry[(hv + i) & CPMHMASK]; 2184 2185 if (rsin.sin_addr.s_addr == ch->ch_Addr.s_addr && 2186 ch->ch_Service && strcmp(sep->se_service, 2187 ch->ch_Service) == 0) { 2188 chBest = ch; 2189 break; 2190 } 2191 if (chBest == NULL || ch->ch_LTime == 0 || 2192 ch->ch_LTime < chBest->ch_LTime) { 2193 chBest = ch; 2194 } 2195 } 2196 if (rsin.sin_addr.s_addr != chBest->ch_Addr.s_addr || 2197 chBest->ch_Service == NULL || 2198 strcmp(sep->se_service, chBest->ch_Service) != 0) { 2199 chBest->ch_Addr = rsin.sin_addr; 2200 if (chBest->ch_Service) 2201 free(chBest->ch_Service); 2202 chBest->ch_Service = strdup(sep->se_service); 2203 bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 2204 } 2205 chBest->ch_LTime = t; 2206 { 2207 CTime *ct = &chBest->ch_Times[ticks % CHTSIZE]; 2208 if (ct->ct_Ticks != ticks) { 2209 ct->ct_Ticks = ticks; 2210 ct->ct_Count = 0; 2211 } 2212 ++ct->ct_Count; 2213 } 2214 for (i = 0; i < CHTSIZE; ++i) { 2215 CTime *ct = &chBest->ch_Times[i]; 2216 if (ct->ct_Ticks <= ticks && 2217 ct->ct_Ticks >= ticks - CHTSIZE) { 2218 cnt += ct->ct_Count; 2219 } 2220 } 2221 if (cnt * (CHTSIZE * CHTGRAN) / 60 > sep->se_maxcpm) { 2222 r = -1; 2223 syslog(LOG_ERR, 2224 "%s from %s exceeded counts/min (limit %d/min)", 2225 sep->se_service, inet_ntoa(rsin.sin_addr), 2226 sep->se_maxcpm); 2227 } 2228 } 2229 return(r); 2230} 2231