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