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 35 static 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 /* from: @(#)inetd.c 8.4 (Berkeley) 4/13/94"; */ 42 static char inetd_c_rcsid[] = 43 "$Id: inetd.c,v 1.12 1996/07/17 15:00:28 davidg Exp $"; 44 #endif /* not lint */ 45 46 /* 47 * Inetd - Internet super-server 48 * 49 * This program invokes all internet services as needed. Connection-oriented 50 * services are invoked each time a connection is made, by creating a process. 51 * This process is passed the connection as file descriptor 0 and is expected 52 * to do a getpeername to find out the source host and port. 53 * 54 * Datagram oriented services are invoked when a datagram 55 * arrives; a process is created and passed a pending message 56 * on file descriptor 0. Datagram servers may either connect 57 * to their peer, freeing up the original socket for inetd 58 * to receive further messages on, or ``take over the socket'', 59 * processing all arriving datagrams and, eventually, timing 60 * out. The first type of server is said to be ``multi-threaded''; 61 * the second type of server ``single-threaded''. 62 * 63 * Inetd uses a configuration file which is read at startup 64 * and, possibly, at some later time in response to a hangup signal. 65 * The configuration file is ``free format'' with fields given in the 66 * order shown below. Continuation lines for an entry must being with 67 * a space or tab. All fields must be present in each entry. 68 * 69 * service name must be in /etc/services or must 70 * name a tcpmux service 71 * socket type stream/dgram/raw/rdm/seqpacket 72 * protocol must be in /etc/protocols 73 * wait/nowait single-threaded/multi-threaded 74 * user user to run daemon as 75 * server program full path name 76 * server program arguments maximum of MAXARGS (20) 77 * 78 * TCP services without official port numbers are handled with the 79 * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for 80 * requests. When a connection is made from a foreign host, the service 81 * requested is passed to tcpmux, which looks it up in the servtab list 82 * and returns the proper entry for the service. Tcpmux returns a 83 * negative reply if the service doesn't exist, otherwise the invoked 84 * server is expected to return the positive reply if the service type in 85 * inetd.conf file has the prefix "tcpmux/". If the service type has the 86 * prefix "tcpmux/+", tcpmux will return the positive reply for the 87 * process; this is for compatibility with older server code, and also 88 * allows you to invoke programs that use stdin/stdout without putting any 89 * special server code in them. Services that use tcpmux are "nowait" 90 * because they do not have a well-known port and hence cannot listen 91 * for new requests. 92 * 93 * For RPC services 94 * service name/version must be in /etc/rpc 95 * socket type stream/dgram/raw/rdm/seqpacket 96 * protocol must be in /etc/protocols 97 * wait/nowait single-threaded/multi-threaded 98 * user user to run daemon as 99 * server program full path name 100 * server program arguments maximum of MAXARGS 101 * 102 * Comment lines are indicated by a `#' in column 1. 103 */ 104 #include <sys/param.h> 105 #include <sys/stat.h> 106 #include <sys/ioctl.h> 107 #include <sys/socket.h> 108 #include <sys/wait.h> 109 #include <sys/time.h> 110 #include <sys/resource.h> 111 112 #include <netinet/in.h> 113 #include <arpa/inet.h> 114 #include <rpc/rpc.h> 115 116 #include <errno.h> 117 #include <fcntl.h> 118 #include <netdb.h> 119 #include <pwd.h> 120 #include <signal.h> 121 #include <stdio.h> 122 #include <stdlib.h> 123 #include <string.h> 124 #include <syslog.h> 125 #include <unistd.h> 126 #include <libutil.h> 127 128 #include "pathnames.h" 129 130 #define TOOMANY 256 /* don't start more than TOOMANY */ 131 #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 132 #define RETRYTIME (60*10) /* retry after bind or server fail */ 133 134 #define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 135 136 137 int debug = 0; 138 int log = 0; 139 int nsock, maxsock; 140 fd_set allsock; 141 int options; 142 int timingout; 143 int toomany = TOOMANY; 144 struct servent *sp; 145 struct rpcent *rpc; 146 struct in_addr bind_address; 147 148 struct servtab { 149 char *se_service; /* name of service */ 150 int se_socktype; /* type of socket to use */ 151 char *se_proto; /* protocol used */ 152 short se_wait; /* single threaded server */ 153 short se_checked; /* looked at during merge */ 154 char *se_user; /* user name to run as */ 155 struct biltin *se_bi; /* if built-in, description */ 156 char *se_server; /* server program */ 157 #define MAXARGV 20 158 char *se_argv[MAXARGV+1]; /* program arguments */ 159 int se_fd; /* open descriptor */ 160 int se_type; /* type */ 161 struct sockaddr_in se_ctrladdr;/* bound address */ 162 int se_rpc; /* ==1 if RPC service */ 163 int se_rpc_prog; /* RPC program number */ 164 u_int se_rpc_lowvers; /* RPC low version */ 165 u_int se_rpc_highvers; /* RPC high version */ 166 int se_count; /* number started since se_time */ 167 struct timeval se_time; /* start of se_count */ 168 struct servtab *se_next; 169 } *servtab; 170 171 #define NORM_TYPE 0 172 #define MUX_TYPE 1 173 #define MUXPLUS_TYPE 2 174 #define ISMUX(sep) (((sep)->se_type == MUX_TYPE) || \ 175 ((sep)->se_type == MUXPLUS_TYPE)) 176 #define ISMUXPLUS(sep) ((sep)->se_type == MUXPLUS_TYPE) 177 178 179 void chargen_dg __P((int, struct servtab *)); 180 void chargen_stream __P((int, struct servtab *)); 181 void close_sep __P((struct servtab *)); 182 void config __P((int)); 183 void daytime_dg __P((int, struct servtab *)); 184 void daytime_stream __P((int, struct servtab *)); 185 void discard_dg __P((int, struct servtab *)); 186 void discard_stream __P((int, struct servtab *)); 187 void echo_dg __P((int, struct servtab *)); 188 void echo_stream __P((int, struct servtab *)); 189 void endconfig __P((void)); 190 struct servtab *enter __P((struct servtab *)); 191 void freeconfig __P((struct servtab *)); 192 struct servtab *getconfigent __P((void)); 193 void machtime_dg __P((int, struct servtab *)); 194 void machtime_stream __P((int, struct servtab *)); 195 char *newstr __P((char *)); 196 char *nextline __P((FILE *)); 197 void print_service __P((char *, struct servtab *)); 198 void reapchild __P((int)); 199 void retry __P((int)); 200 int setconfig __P((void)); 201 void setup __P((struct servtab *)); 202 char *sskip __P((char **)); 203 char *skip __P((char **)); 204 struct servtab *tcpmux __P((int)); 205 206 void unregisterrpc __P((register struct servtab *sep)); 207 208 struct biltin { 209 char *bi_service; /* internally provided service name */ 210 int bi_socktype; /* type of socket supported */ 211 short bi_fork; /* 1 if should fork before call */ 212 short bi_wait; /* 1 if should wait for child */ 213 void (*bi_fn)(); /* function which performs it */ 214 } biltins[] = { 215 /* Echo received data */ 216 { "echo", SOCK_STREAM, 1, 0, echo_stream }, 217 { "echo", SOCK_DGRAM, 0, 0, echo_dg }, 218 219 /* Internet /dev/null */ 220 { "discard", SOCK_STREAM, 1, 0, discard_stream }, 221 { "discard", SOCK_DGRAM, 0, 0, discard_dg }, 222 223 /* Return 32 bit time since 1970 */ 224 { "time", SOCK_STREAM, 0, 0, machtime_stream }, 225 { "time", SOCK_DGRAM, 0, 0, machtime_dg }, 226 227 /* Return human-readable time */ 228 { "daytime", SOCK_STREAM, 0, 0, daytime_stream }, 229 { "daytime", SOCK_DGRAM, 0, 0, daytime_dg }, 230 231 /* Familiar character generator */ 232 { "chargen", SOCK_STREAM, 1, 0, chargen_stream }, 233 { "chargen", SOCK_DGRAM, 0, 0, chargen_dg }, 234 235 { "tcpmux", SOCK_STREAM, 1, 0, (void (*)())tcpmux }, 236 237 { NULL } 238 }; 239 240 #define NUMINT (sizeof(intab) / sizeof(struct inent)) 241 char *CONFIG = _PATH_INETDCONF; 242 char *pid_file = _PATH_INETDPID; 243 244 #ifdef OLD_SETPROCTITLE 245 char **Argv; 246 char *LastArg; 247 #endif 248 249 int 250 main(argc, argv, envp) 251 int argc; 252 char *argv[], *envp[]; 253 { 254 struct servtab *sep; 255 struct passwd *pwd; 256 struct sigvec sv; 257 int tmpint, ch, dofork; 258 pid_t pid; 259 char buf[50]; 260 struct sockaddr_in peer; 261 int i; 262 263 264 #ifdef OLD_SETPROCTITLE 265 Argv = argv; 266 if (envp == 0 || *envp == 0) 267 envp = argv; 268 while (*envp) 269 envp++; 270 LastArg = envp[-1] + strlen(envp[-1]); 271 #endif 272 273 openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 274 275 bind_address.s_addr = htonl(INADDR_ANY); 276 while ((ch = getopt(argc, argv, "dlR:a:p:")) != EOF) 277 switch(ch) { 278 case 'd': 279 debug = 1; 280 options |= SO_DEBUG; 281 break; 282 case 'l': 283 log = 1; 284 break; 285 case 'R': { /* invocation rate */ 286 char *p; 287 288 tmpint = strtol(optarg, &p, 0); 289 if (tmpint < 1 || *p) 290 syslog(LOG_ERR, 291 "-R %s: bad value for service invocation rate", 292 optarg); 293 else 294 toomany = tmpint; 295 break; 296 } 297 case 'a': 298 if (!inet_aton(optarg, &bind_address)) { 299 syslog(LOG_ERR, 300 "-a %s: invalid IP address", optarg); 301 exit(1); 302 } 303 break; 304 case 'p': 305 pid_file = optarg; 306 break; 307 case '?': 308 default: 309 syslog(LOG_ERR, 310 "usage: inetd [-dl] [-a address] [-R rate]" 311 " [-p pidfile] [conf-file]"); 312 exit(1); 313 } 314 argc -= optind; 315 argv += optind; 316 317 if (argc > 0) 318 CONFIG = argv[0]; 319 if (debug == 0) { 320 FILE *fp; 321 if (daemon(0, 0) < 0) { 322 syslog(LOG_WARNING, "daemon(0,0) failed: %m"); 323 } 324 /* 325 * In case somebody has started inetd manually, we need to 326 * clear the logname, so that old servers run as root do not 327 * get the user's logname.. 328 */ 329 if (setlogin("") < 0) { 330 syslog(LOG_WARNING, "cannot clear logname: %m"); 331 /* no big deal if it fails.. */ 332 } 333 pid = getpid(); 334 fp = fopen(pid_file, "w"); 335 if (fp) { 336 fprintf(fp, "%ld\n", (long)pid); 337 fclose(fp); 338 } else { 339 syslog(LOG_WARNING, "%s: %m", pid_file); 340 } 341 } 342 memset(&sv, 0, sizeof(sv)); 343 sv.sv_mask = SIGBLOCK; 344 sv.sv_handler = retry; 345 sigvec(SIGALRM, &sv, (struct sigvec *)0); 346 config(SIGHUP); 347 sv.sv_handler = config; 348 sigvec(SIGHUP, &sv, (struct sigvec *)0); 349 sv.sv_handler = reapchild; 350 sigvec(SIGCHLD, &sv, (struct sigvec *)0); 351 352 { 353 /* space for daemons to overwrite environment for ps */ 354 #define DUMMYSIZE 100 355 char dummy[DUMMYSIZE]; 356 357 (void)memset(dummy, 'x', sizeof(DUMMYSIZE) - 1); 358 dummy[DUMMYSIZE - 1] = '\0'; 359 (void)setenv("inetd_dummy", dummy, 1); 360 } 361 362 for (;;) { 363 int n, ctrl; 364 fd_set readable; 365 366 if (nsock == 0) { 367 (void) sigblock(SIGBLOCK); 368 while (nsock == 0) 369 sigpause(0L); 370 (void) sigsetmask(0L); 371 } 372 readable = allsock; 373 if ((n = select(maxsock + 1, &readable, (fd_set *)0, 374 (fd_set *)0, (struct timeval *)0)) <= 0) { 375 if (n < 0 && errno != EINTR) 376 syslog(LOG_WARNING, "select: %m"); 377 sleep(1); 378 continue; 379 } 380 for (sep = servtab; n && sep; sep = sep->se_next) 381 if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 382 n--; 383 if (debug) 384 fprintf(stderr, "someone wants %s\n", 385 sep->se_service); 386 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) { 387 ctrl = accept(sep->se_fd, (struct sockaddr *)0, 388 (int *)0); 389 if (debug) 390 fprintf(stderr, "accept, ctrl %d\n", ctrl); 391 if (ctrl < 0) { 392 if (errno != EINTR) 393 syslog(LOG_WARNING, 394 "accept (for %s): %m", 395 sep->se_service); 396 continue; 397 } 398 if(log) { 399 i = sizeof peer; 400 if(getpeername(ctrl, (struct sockaddr *) 401 &peer, &i)) { 402 syslog(LOG_WARNING, 403 "getpeername(for %s): %m", 404 sep->se_service); 405 continue; 406 } 407 syslog(LOG_INFO,"%s from %s", 408 sep->se_service, 409 inet_ntoa(peer.sin_addr)); 410 } 411 /* 412 * Call tcpmux to find the real service to exec. 413 */ 414 if (sep->se_bi && 415 sep->se_bi->bi_fn == (void (*)()) tcpmux) { 416 struct servtab *tsep; 417 418 tsep = tcpmux(ctrl); 419 if (tsep == NULL) { 420 close(ctrl); 421 continue; 422 } 423 sep = tsep; 424 } 425 } else 426 ctrl = sep->se_fd; 427 (void) sigblock(SIGBLOCK); 428 pid = 0; 429 dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork); 430 if (dofork) { 431 if (sep->se_count++ == 0) 432 (void)gettimeofday(&sep->se_time, 433 (struct timezone *)0); 434 else if (sep->se_count >= toomany) { 435 struct timeval now; 436 437 (void)gettimeofday(&now, (struct timezone *)0); 438 if (now.tv_sec - sep->se_time.tv_sec > 439 CNT_INTVL) { 440 sep->se_time = now; 441 sep->se_count = 1; 442 } else { 443 syslog(LOG_ERR, 444 "%s/%s server failing (looping), service terminated", 445 sep->se_service, sep->se_proto); 446 close_sep(sep); 447 sigsetmask(0L); 448 if (!timingout) { 449 timingout = 1; 450 alarm(RETRYTIME); 451 } 452 continue; 453 } 454 } 455 pid = fork(); 456 } 457 if (pid < 0) { 458 syslog(LOG_ERR, "fork: %m"); 459 if (!sep->se_wait && 460 sep->se_socktype == SOCK_STREAM) 461 close(ctrl); 462 sigsetmask(0L); 463 sleep(1); 464 continue; 465 } 466 if (pid && sep->se_wait) { 467 sep->se_wait = pid; 468 if (sep->se_fd >= 0) { 469 FD_CLR(sep->se_fd, &allsock); 470 nsock--; 471 } 472 } 473 sigsetmask(0L); 474 if (pid == 0) { 475 if (dofork) { 476 if (debug) 477 fprintf(stderr, "+ Closing from %d\n", 478 maxsock); 479 for (tmpint = maxsock; tmpint > 2; tmpint--) 480 if (tmpint != ctrl) 481 close(tmpint); 482 } 483 if (sep->se_bi) 484 (*sep->se_bi->bi_fn)(ctrl, sep); 485 else { 486 if (debug) 487 fprintf(stderr, "%d execl %s\n", 488 getpid(), sep->se_server); 489 dup2(ctrl, 0); 490 close(ctrl); 491 dup2(0, 1); 492 dup2(0, 2); 493 if ((pwd = getpwnam(sep->se_user)) == NULL) { 494 syslog(LOG_ERR, 495 "%s/%s: %s: No such user", 496 sep->se_service, sep->se_proto, 497 sep->se_user); 498 if (sep->se_socktype != SOCK_STREAM) 499 recv(0, buf, sizeof (buf), 0); 500 _exit(1); 501 } 502 if (setsid() < 0) { 503 syslog(LOG_ERR, 504 "%s: can't setsid(): %m", 505 sep->se_service); 506 /* _exit(1); not fatal yet */ 507 } 508 if (pwd->pw_uid) { 509 if (setlogin(sep->se_user) < 0) { 510 syslog(LOG_ERR, 511 "%s: can't setlogin(%s): %m", 512 sep->se_service, sep->se_user); 513 /* _exit(1); not fatal yet */ 514 } 515 if (setgid(pwd->pw_gid) < 0) { 516 syslog(LOG_ERR, 517 "%s: can't set gid %d: %m", 518 sep->se_service, pwd->pw_gid); 519 _exit(1); 520 } 521 (void) initgroups(pwd->pw_name, 522 pwd->pw_gid); 523 if (setuid(pwd->pw_uid) < 0) { 524 syslog(LOG_ERR, 525 "%s: can't set uid %d: %m", 526 sep->se_service, pwd->pw_uid); 527 _exit(1); 528 } 529 } 530 execv(sep->se_server, sep->se_argv); 531 if (sep->se_socktype != SOCK_STREAM) 532 recv(0, buf, sizeof (buf), 0); 533 syslog(LOG_ERR, 534 "cannot execute %s: %m", sep->se_server); 535 _exit(1); 536 } 537 } 538 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 539 close(ctrl); 540 } 541 } 542 } 543 544 void 545 reapchild(signo) 546 int signo; 547 { 548 int status; 549 pid_t pid; 550 struct servtab *sep; 551 552 for (;;) { 553 pid = wait3(&status, WNOHANG, (struct rusage *)0); 554 if (pid <= 0) 555 break; 556 if (debug) 557 fprintf(stderr, "%d reaped, status %#x\n", 558 pid, status); 559 for (sep = servtab; sep; sep = sep->se_next) 560 if (sep->se_wait == pid) { 561 if (status) 562 syslog(LOG_WARNING, 563 "%s: exit status 0x%x", 564 sep->se_server, status); 565 if (debug) 566 fprintf(stderr, "restored %s, fd %d\n", 567 sep->se_service, sep->se_fd); 568 FD_SET(sep->se_fd, &allsock); 569 nsock++; 570 sep->se_wait = 1; 571 } 572 } 573 } 574 575 void 576 config(signo) 577 int signo; 578 { 579 struct servtab *sep, *cp, **sepp; 580 struct passwd *pwd; 581 long omask; 582 583 if (!setconfig()) { 584 syslog(LOG_ERR, "%s: %m", CONFIG); 585 return; 586 } 587 for (sep = servtab; sep; sep = sep->se_next) 588 sep->se_checked = 0; 589 while (cp = getconfigent()) { 590 if ((pwd = getpwnam(cp->se_user)) == NULL) { 591 syslog(LOG_ERR, 592 "%s/%s: No such user '%s', service ignored", 593 cp->se_service, cp->se_proto, cp->se_user); 594 continue; 595 } 596 for (sep = servtab; sep; sep = sep->se_next) 597 if (strcmp(sep->se_service, cp->se_service) == 0 && 598 strcmp(sep->se_proto, cp->se_proto) == 0) 599 break; 600 if (sep != 0) { 601 int i; 602 603 omask = sigblock(SIGBLOCK); 604 /* 605 * sep->se_wait may be holding the pid of a daemon 606 * that we're waiting for. If so, don't overwrite 607 * it unless the config file explicitly says don't 608 * wait. 609 */ 610 if (cp->se_bi == 0 && 611 (sep->se_wait == 1 || cp->se_wait == 0)) 612 sep->se_wait = cp->se_wait; 613 #define SWAP(a, b) { char *c = a; a = b; b = c; } 614 if (cp->se_user) 615 SWAP(sep->se_user, cp->se_user); 616 if (cp->se_server) 617 SWAP(sep->se_server, cp->se_server); 618 for (i = 0; i < MAXARGV; i++) 619 SWAP(sep->se_argv[i], cp->se_argv[i]); 620 sigsetmask(omask); 621 freeconfig(cp); 622 if (debug) 623 print_service("REDO", sep); 624 } else { 625 sep = enter(cp); 626 if (debug) 627 print_service("ADD ", sep); 628 } 629 sep->se_checked = 1; 630 if (ISMUX(sep)) { 631 sep->se_fd = -1; 632 continue; 633 } 634 if (!sep->se_rpc) { 635 sp = getservbyname(sep->se_service, sep->se_proto); 636 if (sp == 0) { 637 syslog(LOG_ERR, "%s/%s: unknown service", 638 sep->se_service, sep->se_proto); 639 sep->se_checked = 0; 640 continue; 641 } 642 if (sp->s_port != sep->se_ctrladdr.sin_port) { 643 sep->se_ctrladdr.sin_family = AF_INET; 644 sep->se_ctrladdr.sin_port = sp->s_port; 645 if (sep->se_fd >= 0) 646 close_sep(sep); 647 } 648 } else { 649 rpc = getrpcbyname(sep->se_service); 650 if (rpc == 0) { 651 syslog(LOG_ERR, "%s/%s unknown RPC service.", 652 sep->se_service, sep->se_proto); 653 if (sep->se_fd != -1) 654 (void) close(sep->se_fd); 655 sep->se_fd = -1; 656 continue; 657 } 658 if (rpc->r_number != sep->se_rpc_prog) { 659 if (sep->se_rpc_prog) 660 unregisterrpc(sep); 661 sep->se_rpc_prog = rpc->r_number; 662 if (sep->se_fd != -1) 663 (void) close(sep->se_fd); 664 sep->se_fd = -1; 665 } 666 } 667 if (sep->se_fd == -1) 668 setup(sep); 669 } 670 endconfig(); 671 /* 672 * Purge anything not looked at above. 673 */ 674 omask = sigblock(SIGBLOCK); 675 sepp = &servtab; 676 while (sep = *sepp) { 677 if (sep->se_checked) { 678 sepp = &sep->se_next; 679 continue; 680 } 681 *sepp = sep->se_next; 682 if (sep->se_fd >= 0) 683 close_sep(sep); 684 if (debug) 685 print_service("FREE", sep); 686 if (sep->se_rpc && sep->se_rpc_prog > 0) 687 unregisterrpc(sep); 688 freeconfig(sep); 689 free((char *)sep); 690 } 691 (void) sigsetmask(omask); 692 } 693 694 void 695 unregisterrpc(sep) 696 struct servtab *sep; 697 { 698 int i; 699 struct servtab *sepp; 700 long omask; 701 702 omask = sigblock(SIGBLOCK); 703 for (sepp = servtab; sepp; sepp = sepp->se_next) { 704 if (sepp == sep) 705 continue; 706 if (sep->se_checked == 0 || 707 !sepp->se_rpc || 708 sep->se_rpc_prog != sepp->se_rpc_prog) 709 continue; 710 return; 711 } 712 if (debug) 713 print_service("UNREG", sep); 714 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) 715 pmap_unset(sep->se_rpc_prog, i); 716 if (sep->se_fd != -1) 717 (void) close(sep->se_fd); 718 sep->se_fd = -1; 719 (void) sigsetmask(omask); 720 } 721 722 void 723 retry(signo) 724 int signo; 725 { 726 struct servtab *sep; 727 728 timingout = 0; 729 for (sep = servtab; sep; sep = sep->se_next) 730 if (sep->se_fd == -1) 731 setup(sep); 732 } 733 734 void 735 setup(sep) 736 struct servtab *sep; 737 { 738 int on = 1; 739 740 if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 741 if (debug) 742 fprintf(stderr, "socket failed on %s/%s: %s\n", 743 sep->se_service, sep->se_proto, 744 strerror(errno)); 745 syslog(LOG_ERR, "%s/%s: socket: %m", 746 sep->se_service, sep->se_proto); 747 return; 748 } 749 #define turnon(fd, opt) \ 750 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 751 if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 752 turnon(sep->se_fd, SO_DEBUG) < 0) 753 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 754 if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 755 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 756 if (turnon(sep->se_fd, SO_PRIVSTATE) < 0) 757 syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m"); 758 #undef turnon 759 if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 760 sizeof (sep->se_ctrladdr)) < 0) { 761 if (debug) 762 fprintf(stderr, "bind failed on %s/%s: %s\n", 763 sep->se_service, sep->se_proto, 764 strerror(errno)); 765 syslog(LOG_ERR, "%s/%s: bind: %m", 766 sep->se_service, sep->se_proto); 767 (void) close(sep->se_fd); 768 sep->se_fd = -1; 769 if (!timingout) { 770 timingout = 1; 771 alarm(RETRYTIME); 772 } 773 return; 774 } 775 if (sep->se_rpc) { 776 int i, len = sizeof(struct sockaddr); 777 778 if (getsockname(sep->se_fd, 779 (struct sockaddr*)&sep->se_ctrladdr, &len) < 0){ 780 syslog(LOG_ERR, "%s/%s: getsockname: %m", 781 sep->se_service, sep->se_proto); 782 (void) close(sep->se_fd); 783 sep->se_fd = -1; 784 return; 785 } 786 if (debug) 787 print_service("REG ", sep); 788 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 789 pmap_unset(sep->se_rpc_prog, i); 790 pmap_set(sep->se_rpc_prog, i, 791 (sep->se_socktype == SOCK_DGRAM) 792 ? IPPROTO_UDP : IPPROTO_TCP, 793 ntohs(sep->se_ctrladdr.sin_port)); 794 } 795 796 } 797 if (sep->se_socktype == SOCK_STREAM) 798 listen(sep->se_fd, 64); 799 FD_SET(sep->se_fd, &allsock); 800 nsock++; 801 if (sep->se_fd > maxsock) 802 maxsock = sep->se_fd; 803 if (debug) { 804 fprintf(stderr, "registered %s on %d\n", 805 sep->se_server, sep->se_fd); 806 } 807 } 808 809 /* 810 * Finish with a service and its socket. 811 */ 812 void 813 close_sep(sep) 814 struct servtab *sep; 815 { 816 if (sep->se_fd >= 0) { 817 nsock--; 818 FD_CLR(sep->se_fd, &allsock); 819 (void) close(sep->se_fd); 820 sep->se_fd = -1; 821 } 822 sep->se_count = 0; 823 /* 824 * Don't keep the pid of this running deamon: when reapchild() 825 * reaps this pid, it would erroneously increment nsock. 826 */ 827 if (sep->se_wait > 1) 828 sep->se_wait = 1; 829 } 830 831 struct servtab * 832 enter(cp) 833 struct servtab *cp; 834 { 835 struct servtab *sep; 836 long omask; 837 838 sep = (struct servtab *)malloc(sizeof (*sep)); 839 if (sep == (struct servtab *)0) { 840 syslog(LOG_ERR, "Out of memory."); 841 exit(-1); 842 } 843 *sep = *cp; 844 sep->se_fd = -1; 845 omask = sigblock(SIGBLOCK); 846 sep->se_next = servtab; 847 servtab = sep; 848 sigsetmask(omask); 849 return (sep); 850 } 851 852 FILE *fconfig = NULL; 853 struct servtab serv; 854 char line[LINE_MAX]; 855 856 int 857 setconfig() 858 { 859 860 if (fconfig != NULL) { 861 fseek(fconfig, 0L, SEEK_SET); 862 return (1); 863 } 864 fconfig = fopen(CONFIG, "r"); 865 return (fconfig != NULL); 866 } 867 868 void 869 endconfig() 870 { 871 if (fconfig) { 872 (void) fclose(fconfig); 873 fconfig = NULL; 874 } 875 } 876 877 struct servtab * 878 getconfigent() 879 { 880 struct servtab *sep = &serv; 881 int argc; 882 char *cp, *arg; 883 char *versp; 884 static char TCPMUX_TOKEN[] = "tcpmux/"; 885 #define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 886 887 more: 888 while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0')) 889 ; 890 if (cp == NULL) 891 return ((struct servtab *)0); 892 /* 893 * clear the static buffer, since some fields (se_ctrladdr, 894 * for example) don't get initialized here. 895 */ 896 memset((caddr_t)sep, 0, sizeof *sep); 897 arg = skip(&cp); 898 if (cp == NULL) { 899 /* got an empty line containing just blanks/tabs. */ 900 goto more; 901 } 902 if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 903 char *c = arg + MUX_LEN; 904 if (*c == '+') { 905 sep->se_type = MUXPLUS_TYPE; 906 c++; 907 } else 908 sep->se_type = MUX_TYPE; 909 sep->se_service = newstr(c); 910 } else { 911 sep->se_service = newstr(arg); 912 sep->se_type = NORM_TYPE; 913 } 914 arg = sskip(&cp); 915 if (strcmp(arg, "stream") == 0) 916 sep->se_socktype = SOCK_STREAM; 917 else if (strcmp(arg, "dgram") == 0) 918 sep->se_socktype = SOCK_DGRAM; 919 else if (strcmp(arg, "rdm") == 0) 920 sep->se_socktype = SOCK_RDM; 921 else if (strcmp(arg, "seqpacket") == 0) 922 sep->se_socktype = SOCK_SEQPACKET; 923 else if (strcmp(arg, "raw") == 0) 924 sep->se_socktype = SOCK_RAW; 925 else 926 sep->se_socktype = -1; 927 sep->se_proto = newstr(sskip(&cp)); 928 if (strncmp(sep->se_proto, "rpc/", 4) == 0) { 929 sep->se_proto += 4; 930 sep->se_rpc = 1; 931 sep->se_rpc_prog = sep->se_rpc_lowvers = 932 sep->se_rpc_lowvers = 0; 933 sep->se_ctrladdr.sin_family = AF_INET; 934 sep->se_ctrladdr.sin_port = 0; 935 sep->se_ctrladdr.sin_addr = bind_address; 936 if ((versp = rindex(sep->se_service, '/'))) { 937 *versp++ = '\0'; 938 switch (sscanf(versp, "%d-%d", 939 &sep->se_rpc_lowvers, 940 &sep->se_rpc_highvers)) { 941 case 2: 942 break; 943 case 1: 944 sep->se_rpc_highvers = 945 sep->se_rpc_lowvers; 946 break; 947 default: 948 syslog(LOG_ERR, 949 "bad RPC version specifier; %s\n", 950 sep->se_service); 951 freeconfig(sep); 952 goto more; 953 } 954 } 955 else { 956 sep->se_rpc_lowvers = 957 sep->se_rpc_highvers = 1; 958 } 959 } 960 arg = sskip(&cp); 961 sep->se_wait = strcmp(arg, "wait") == 0; 962 if (ISMUX(sep)) { 963 /* 964 * Silently enforce "nowait" for TCPMUX services since 965 * they don't have an assigned port to listen on. 966 */ 967 sep->se_wait = 0; 968 969 if (strcmp(sep->se_proto, "tcp")) { 970 syslog(LOG_ERR, 971 "%s: bad protocol for tcpmux service %s", 972 CONFIG, sep->se_service); 973 goto more; 974 } 975 if (sep->se_socktype != SOCK_STREAM) { 976 syslog(LOG_ERR, 977 "%s: bad socket type for tcpmux service %s", 978 CONFIG, sep->se_service); 979 goto more; 980 } 981 } 982 sep->se_user = newstr(sskip(&cp)); 983 sep->se_server = newstr(sskip(&cp)); 984 if (strcmp(sep->se_server, "internal") == 0) { 985 struct biltin *bi; 986 987 for (bi = biltins; bi->bi_service; bi++) 988 if (bi->bi_socktype == sep->se_socktype && 989 strcmp(bi->bi_service, sep->se_service) == 0) 990 break; 991 if (bi->bi_service == 0) { 992 syslog(LOG_ERR, "internal service %s unknown", 993 sep->se_service); 994 goto more; 995 } 996 sep->se_bi = bi; 997 sep->se_wait = bi->bi_wait; 998 } else 999 sep->se_bi = NULL; 1000 argc = 0; 1001 for (arg = skip(&cp); cp; arg = skip(&cp)) 1002 if (argc < MAXARGV) 1003 sep->se_argv[argc++] = newstr(arg); 1004 while (argc <= MAXARGV) 1005 sep->se_argv[argc++] = NULL; 1006 return (sep); 1007 } 1008 1009 void 1010 freeconfig(cp) 1011 struct servtab *cp; 1012 { 1013 int i; 1014 1015 if (cp->se_service) 1016 free(cp->se_service); 1017 if (cp->se_proto) 1018 free(cp->se_proto); 1019 if (cp->se_user) 1020 free(cp->se_user); 1021 if (cp->se_server) 1022 free(cp->se_server); 1023 for (i = 0; i < MAXARGV; i++) 1024 if (cp->se_argv[i]) 1025 free(cp->se_argv[i]); 1026 } 1027 1028 1029 /* 1030 * Safe skip - if skip returns null, log a syntax error in the 1031 * configuration file and exit. 1032 */ 1033 char * 1034 sskip(cpp) 1035 char **cpp; 1036 { 1037 char *cp; 1038 1039 cp = skip(cpp); 1040 if (cp == NULL) { 1041 syslog(LOG_ERR, "%s: syntax error", CONFIG); 1042 exit(-1); 1043 } 1044 return (cp); 1045 } 1046 1047 char * 1048 skip(cpp) 1049 char **cpp; 1050 { 1051 char *cp = *cpp; 1052 char *start; 1053 char quote = '\0'; 1054 1055 again: 1056 while (*cp == ' ' || *cp == '\t') 1057 cp++; 1058 if (*cp == '\0') { 1059 int c; 1060 1061 c = getc(fconfig); 1062 (void) ungetc(c, fconfig); 1063 if (c == ' ' || c == '\t') 1064 if (cp = nextline(fconfig)) 1065 goto again; 1066 *cpp = (char *)0; 1067 return ((char *)0); 1068 } 1069 if (*cp == '"' || *cp == '\'') 1070 quote = *cp++; 1071 start = cp; 1072 if (quote) 1073 while (*cp && *cp != quote) 1074 cp++; 1075 else 1076 while (*cp && *cp != ' ' && *cp != '\t') 1077 cp++; 1078 if (*cp != '\0') 1079 *cp++ = '\0'; 1080 *cpp = cp; 1081 return (start); 1082 } 1083 1084 char * 1085 nextline(fd) 1086 FILE *fd; 1087 { 1088 char *cp; 1089 1090 if (fgets(line, sizeof (line), fd) == NULL) 1091 return ((char *)0); 1092 cp = strchr(line, '\n'); 1093 if (cp) 1094 *cp = '\0'; 1095 return (line); 1096 } 1097 1098 char * 1099 newstr(cp) 1100 char *cp; 1101 { 1102 if (cp = strdup(cp ? cp : "")) 1103 return (cp); 1104 syslog(LOG_ERR, "strdup: %m"); 1105 exit(-1); 1106 } 1107 1108 #ifdef OLD_SETPROCTITLE 1109 void 1110 inetd_setproctitle(a, s) 1111 char *a; 1112 int s; 1113 { 1114 int size; 1115 char *cp; 1116 struct sockaddr_in sin; 1117 char buf[80]; 1118 1119 cp = Argv[0]; 1120 size = sizeof(sin); 1121 if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 1122 (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 1123 else 1124 (void) sprintf(buf, "-%s", a); 1125 strncpy(cp, buf, LastArg - cp); 1126 cp += strlen(cp); 1127 while (cp < LastArg) 1128 *cp++ = ' '; 1129 } 1130 #else 1131 void 1132 inetd_setproctitle(a, s) 1133 char *a; 1134 int s; 1135 { 1136 int size; 1137 struct sockaddr_in sin; 1138 char buf[80]; 1139 1140 size = sizeof(sin); 1141 if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 1142 (void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin.sin_addr)); 1143 else 1144 (void) sprintf(buf, "%s", a); 1145 setproctitle("%s", buf); 1146 } 1147 #endif 1148 1149 1150 /* 1151 * Internet services provided internally by inetd: 1152 */ 1153 #define BUFSIZE 8192 1154 1155 /* ARGSUSED */ 1156 void 1157 echo_stream(s, sep) /* Echo service -- echo data back */ 1158 int s; 1159 struct servtab *sep; 1160 { 1161 char buffer[BUFSIZE]; 1162 int i; 1163 1164 inetd_setproctitle(sep->se_service, s); 1165 while ((i = read(s, buffer, sizeof(buffer))) > 0 && 1166 write(s, buffer, i) > 0) 1167 ; 1168 exit(0); 1169 } 1170 1171 int check_loop(sin, sep) 1172 struct sockaddr_in *sin; 1173 struct servtab *sep; 1174 { 1175 struct servtab *se2; 1176 1177 for (se2 = servtab; se2; se2 = se2->se_next) { 1178 if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM) 1179 continue; 1180 1181 if (sin->sin_port == se2->se_ctrladdr.sin_port) { 1182 syslog(LOG_WARNING, 1183 "%s/%s:%s/%s loop request REFUSED from %s", 1184 sep->se_service, sep->se_proto, 1185 se2->se_service, se2->se_proto, 1186 inet_ntoa(sin->sin_addr)); 1187 return 1; 1188 } 1189 } 1190 return 0; 1191 } 1192 1193 /* ARGSUSED */ 1194 void 1195 echo_dg(s, sep) /* Echo service -- echo data back */ 1196 int s; 1197 struct servtab *sep; 1198 { 1199 char buffer[BUFSIZE]; 1200 int i, size; 1201 struct sockaddr_in sin; 1202 1203 size = sizeof(sin); 1204 if ((i = recvfrom(s, buffer, sizeof(buffer), 0, 1205 (struct sockaddr *)&sin, &size)) < 0) 1206 return; 1207 1208 if (check_loop(&sin, sep)) 1209 return; 1210 1211 (void) sendto(s, buffer, i, 0, (struct sockaddr *)&sin, 1212 sizeof(sin)); 1213 } 1214 1215 /* ARGSUSED */ 1216 void 1217 discard_stream(s, sep) /* Discard service -- ignore data */ 1218 int s; 1219 struct servtab *sep; 1220 { 1221 int ret; 1222 char buffer[BUFSIZE]; 1223 1224 inetd_setproctitle(sep->se_service, s); 1225 while (1) { 1226 while ((ret = read(s, buffer, sizeof(buffer))) > 0) 1227 ; 1228 if (ret == 0 || errno != EINTR) 1229 break; 1230 } 1231 exit(0); 1232 } 1233 1234 /* ARGSUSED */ 1235 void 1236 discard_dg(s, sep) /* Discard service -- ignore data */ 1237 int s; 1238 struct servtab *sep; 1239 { 1240 char buffer[BUFSIZE]; 1241 1242 (void) read(s, buffer, sizeof(buffer)); 1243 } 1244 1245 #include <ctype.h> 1246 #define LINESIZ 72 1247 char ring[128]; 1248 char *endring; 1249 1250 void 1251 initring() 1252 { 1253 int i; 1254 1255 endring = ring; 1256 1257 for (i = 0; i <= 128; ++i) 1258 if (isprint(i)) 1259 *endring++ = i; 1260 } 1261 1262 /* ARGSUSED */ 1263 void 1264 chargen_stream(s, sep) /* Character generator */ 1265 int s; 1266 struct servtab *sep; 1267 { 1268 int len; 1269 char *rs, text[LINESIZ+2]; 1270 1271 inetd_setproctitle(sep->se_service, s); 1272 1273 if (!endring) { 1274 initring(); 1275 rs = ring; 1276 } 1277 1278 text[LINESIZ] = '\r'; 1279 text[LINESIZ + 1] = '\n'; 1280 for (rs = ring;;) { 1281 if ((len = endring - rs) >= LINESIZ) 1282 memmove(text, rs, LINESIZ); 1283 else { 1284 memmove(text, rs, len); 1285 memmove(text + len, ring, LINESIZ - len); 1286 } 1287 if (++rs == endring) 1288 rs = ring; 1289 if (write(s, text, sizeof(text)) != sizeof(text)) 1290 break; 1291 } 1292 exit(0); 1293 } 1294 1295 /* ARGSUSED */ 1296 void 1297 chargen_dg(s, sep) /* Character generator */ 1298 int s; 1299 struct servtab *sep; 1300 { 1301 struct sockaddr_in sin; 1302 static char *rs; 1303 int len, size; 1304 char text[LINESIZ+2]; 1305 1306 if (endring == 0) { 1307 initring(); 1308 rs = ring; 1309 } 1310 1311 size = sizeof(sin); 1312 if (recvfrom(s, text, sizeof(text), 0, 1313 (struct sockaddr *)&sin, &size) < 0) 1314 return; 1315 1316 if (check_loop(&sin, sep)) 1317 return; 1318 1319 if ((len = endring - rs) >= LINESIZ) 1320 memmove(text, rs, LINESIZ); 1321 else { 1322 memmove(text, rs, len); 1323 memmove(text + len, ring, LINESIZ - len); 1324 } 1325 if (++rs == endring) 1326 rs = ring; 1327 text[LINESIZ] = '\r'; 1328 text[LINESIZ + 1] = '\n'; 1329 (void) sendto(s, text, sizeof(text), 0, 1330 (struct sockaddr *)&sin, sizeof(sin)); 1331 } 1332 1333 /* 1334 * Return a machine readable date and time, in the form of the 1335 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 1336 * returns the number of seconds since midnight, Jan 1, 1970, 1337 * we must add 2208988800 seconds to this figure to make up for 1338 * some seventy years Bell Labs was asleep. 1339 */ 1340 1341 long 1342 machtime() 1343 { 1344 struct timeval tv; 1345 1346 if (gettimeofday(&tv, (struct timezone *)0) < 0) { 1347 if (debug) 1348 fprintf(stderr, "Unable to get time of day\n"); 1349 return (0L); 1350 } 1351 #define OFFSET ((u_long)25567 * 24*60*60) 1352 return (htonl((long)(tv.tv_sec + OFFSET))); 1353 #undef OFFSET 1354 } 1355 1356 /* ARGSUSED */ 1357 void 1358 machtime_stream(s, sep) 1359 int s; 1360 struct servtab *sep; 1361 { 1362 long result; 1363 1364 result = machtime(); 1365 (void) write(s, (char *) &result, sizeof(result)); 1366 } 1367 1368 /* ARGSUSED */ 1369 void 1370 machtime_dg(s, sep) 1371 int s; 1372 struct servtab *sep; 1373 { 1374 long result; 1375 struct sockaddr_in sin; 1376 int size; 1377 1378 size = sizeof(sin); 1379 if (recvfrom(s, (char *)&result, sizeof(result), 0, 1380 (struct sockaddr *)&sin, &size) < 0) 1381 return; 1382 1383 if (check_loop(&sin, sep)) 1384 return; 1385 1386 result = machtime(); 1387 (void) sendto(s, (char *) &result, sizeof(result), 0, 1388 (struct sockaddr *)&sin, sizeof(sin)); 1389 } 1390 1391 /* ARGSUSED */ 1392 void 1393 daytime_stream(s, sep) /* Return human-readable time of day */ 1394 int s; 1395 struct servtab *sep; 1396 { 1397 char buffer[256]; 1398 time_t clock; 1399 1400 clock = time((time_t *) 0); 1401 1402 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 1403 (void) write(s, buffer, strlen(buffer)); 1404 } 1405 1406 /* ARGSUSED */ 1407 void 1408 daytime_dg(s, sep) /* Return human-readable time of day */ 1409 int s; 1410 struct servtab *sep; 1411 { 1412 char buffer[256]; 1413 time_t clock; 1414 struct sockaddr_in sin; 1415 int size; 1416 1417 clock = time((time_t *) 0); 1418 1419 size = sizeof(sin); 1420 if (recvfrom(s, buffer, sizeof(buffer), 0, 1421 (struct sockaddr *)&sin, &size) < 0) 1422 return; 1423 1424 if (check_loop(&sin, sep)) 1425 return; 1426 1427 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 1428 (void) sendto(s, buffer, strlen(buffer), 0, 1429 (struct sockaddr *)&sin, sizeof(sin)); 1430 } 1431 1432 /* 1433 * print_service: 1434 * Dump relevant information to stderr 1435 */ 1436 void 1437 print_service(action, sep) 1438 char *action; 1439 struct servtab *sep; 1440 { 1441 if(sep->se_rpc) 1442 fprintf(stderr, 1443 "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n", 1444 action, sep->se_service, sep->se_proto, 1445 sep->se_wait, sep->se_user, (int)sep->se_bi, 1446 sep->se_server); 1447 else 1448 fprintf(stderr, 1449 "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n", 1450 action, sep->se_service, sep->se_proto, 1451 sep->se_wait, sep->se_user, (int)sep->se_bi, 1452 sep->se_server); 1453 } 1454 1455 /* 1456 * Based on TCPMUX.C by Mark K. Lottor November 1988 1457 * sri-nic::ps:<mkl>tcpmux.c 1458 */ 1459 1460 1461 static int /* # of characters upto \r,\n or \0 */ 1462 getline(fd, buf, len) 1463 int fd; 1464 char *buf; 1465 int len; 1466 { 1467 int count = 0, n; 1468 1469 do { 1470 n = read(fd, buf, len-count); 1471 if (n == 0) 1472 return (count); 1473 if (n < 0) 1474 return (-1); 1475 while (--n >= 0) { 1476 if (*buf == '\r' || *buf == '\n' || *buf == '\0') 1477 return (count); 1478 count++; 1479 buf++; 1480 } 1481 } while (count < len); 1482 return (count); 1483 } 1484 1485 #define MAX_SERV_LEN (256+2) /* 2 bytes for \r\n */ 1486 1487 #define strwrite(fd, buf) (void) write(fd, buf, sizeof(buf)-1) 1488 1489 struct servtab * 1490 tcpmux(s) 1491 int s; 1492 { 1493 struct servtab *sep; 1494 char service[MAX_SERV_LEN+1]; 1495 int len; 1496 1497 /* Get requested service name */ 1498 if ((len = getline(s, service, MAX_SERV_LEN)) < 0) { 1499 strwrite(s, "-Error reading service name\r\n"); 1500 return (NULL); 1501 } 1502 service[len] = '\0'; 1503 1504 if (debug) 1505 fprintf(stderr, "tcpmux: someone wants %s\n", service); 1506 1507 /* 1508 * Help is a required command, and lists available services, 1509 * one per line. 1510 */ 1511 if (!strcasecmp(service, "help")) { 1512 for (sep = servtab; sep; sep = sep->se_next) { 1513 if (!ISMUX(sep)) 1514 continue; 1515 (void)write(s,sep->se_service,strlen(sep->se_service)); 1516 strwrite(s, "\r\n"); 1517 } 1518 return (NULL); 1519 } 1520 1521 /* Try matching a service in inetd.conf with the request */ 1522 for (sep = servtab; sep; sep = sep->se_next) { 1523 if (!ISMUX(sep)) 1524 continue; 1525 if (!strcasecmp(service, sep->se_service)) { 1526 if (ISMUXPLUS(sep)) { 1527 strwrite(s, "+Go\r\n"); 1528 } 1529 return (sep); 1530 } 1531 } 1532 strwrite(s, "-Service not available\r\n"); 1533 return (NULL); 1534 } 1535