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