4 * Copyright (c) 1983 Regents of the University of California.
7 * Redistribution and use in source and binary forms are permitted
8 * provided that the above copyright notice and this paragraph are
9 * duplicated in all such forms and that any documentation,
10 * advertising materials, and other materials related to such
11 * distribution and use acknowledge that the software was developed
12 * by the University of California, Berkeley. The name of the
13 * University may not be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
23 All rights reserved.\n";
27 static char sccsid[] = "@(#)inetd.c 5.14 (Berkeley) 1/23/89";
31 * Inetd - Internet super-server
33 * This program invokes all internet services as needed.
34 * connection-oriented services are invoked each time a
35 * connection is made, by creating a process. This process
36 * is passed the connection as file descriptor 0 and is
37 * expected to do a getpeername to find out the source host
40 * Datagram oriented services are invoked when a datagram
41 * arrives; a process is created and passed a pending message
42 * on file descriptor 0. Datagram servers may either connect
43 * to their peer, freeing up the original socket for inetd
44 * to receive further messages on, or ``take over the socket'',
45 * processing all arriving datagrams and, eventually, timing
46 * out. The first type of server is said to be ``multi-threaded'';
47 * the second type of server ``single-threaded''.
49 * Inetd uses a configuration file which is read at startup
50 * and, possibly, at some later time in response to a hangup signal.
51 * The configuration file is ``free format'' with fields given in the
52 * order shown below. Continuation lines for an entry must being with
53 * a space or tab. All fields must be present in each entry.
55 * service name must be in /etc/services
56 * socket type stream/dgram/raw/rdm/seqpacket
57 * protocol must be in /etc/protocols
58 * wait/nowait single-threaded/multi-threaded
59 * user user to run daemon as
60 * server program full path name
61 * server program arguments maximum of MAXARGS (5)
63 * Comment lines are indicated by a `#' in column 1.
65 #include <afs/param.h>
66 #include <sys/param.h>
71 #include <sys/ioctl.h>
72 #include <sys/socket.h>
79 #include <sys/resource.h>
81 #include <netinet/in.h>
82 #include <arpa/inet.h>
85 #include <afs/cellconfig.h>
86 #include <afs/afsutil.h>
91 #include <sys/syslog.h>
102 #define TOOMANY 40 /* don't start more than TOOMANY */
103 #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */
104 #define RETRYTIME (60*10) /* retry after bind or server fail */
106 void config(), reapchild(), retry();
116 char *se_service; /* name of service */
117 int se_socktype; /* type of socket to use */
118 char *se_proto; /* protocol used */
119 short se_wait; /* single threaded server */
120 short se_checked; /* looked at during merge */
121 char *se_user; /* user name to run as */
122 struct biltin *se_bi; /* if built-in, description */
123 char *se_server; /* server program */
125 char *se_argv[MAXARGV+1]; /* program arguments */
126 int se_fd; /* open descriptor */
127 struct sockaddr_in se_ctrladdr;/* bound address */
128 int se_count; /* number started since se_time */
129 struct timeval se_time; /* start of se_count */
130 struct servtab *se_next;
133 int echo_stream(), discard_stream(), machtime_stream();
134 int daytime_stream(), chargen_stream();
135 int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg();
136 int auth_stream(), auth_dg();
139 char *bi_service; /* internally provided service name */
140 int bi_socktype; /* type of socket supported */
141 short bi_fork; /* 1 if should fork before call */
142 short bi_wait; /* 1 if should wait for child */
143 int (*bi_fn)(); /* function which performs it */
145 /* Echo received data */
146 "echo", SOCK_STREAM, 1, 0, echo_stream,
147 "echo", SOCK_DGRAM, 0, 0, echo_dg,
149 /* Internet /dev/null */
150 "discard", SOCK_STREAM, 1, 0, discard_stream,
151 "discard", SOCK_DGRAM, 0, 0, discard_dg,
153 /* Return 32 bit time since 1970 */
154 "time", SOCK_STREAM, 0, 0, machtime_stream,
155 "time", SOCK_DGRAM, 0, 0, machtime_dg,
157 /* Return human-readable time */
158 "daytime", SOCK_STREAM, 0, 0, daytime_stream,
159 "daytime", SOCK_DGRAM, 0, 0, daytime_dg,
161 /* Familiar character generator */
162 "chargen", SOCK_STREAM, 1, 0, chargen_stream,
163 "chargen", SOCK_DGRAM, 0, 0, chargen_dg,
165 /* Remote authentication services */
166 "ta-rauth", SOCK_STREAM, 1, 0, auth_stream,
167 "ta-rauth", SOCK_DGRAM, 0, 0, auth_dg,
171 #define NUMINT (sizeof(intab) / sizeof(struct inent))
172 char *CONFIG = "/etc/inetd.conf";
175 int backlog = 10; /* listen() queue length */
177 #include "AFS_component_version_number.c"
183 int afs_didsetpag = 0;
184 main(argc, argv, envp)
186 char *argv[], *envp[];
190 register struct servtab *sep;
191 register struct passwd *pwd;
192 struct passwd *getpwnam();
197 #if defined(AFS_HPUX_ENV)
200 #endif /* defined(AFS_HPUX_ENV) */
202 memset((char *)allZeroes, '\0', sizeof(allZeroes));
203 bzero((char *)allZeroes, sizeof(allZeroes));
205 sigNone = *((sigset_t *) allZeroes);
206 allZeroes[0] = (1<<(SIGCHLD-1)) + (1<<(SIGHUP-1)) + (1<<(SIGALRM-1));
207 sigBlock = *((sigset_t *) allZeroes);
209 setpag(); /* disassociate with PAG of person starting inetd */
212 if (envp == 0 || *envp == 0)
216 LastArg = envp[-1] + strlen(envp[-1]);
218 while ((ch = getopt(argc, argv, "dl:")) != EOF)
225 /* undocumented option to set listen() queue length */
226 backlog = atoi(optarg);
230 fprintf(stderr, "usage: inetd [-d]");
239 #if defined(AFS_OSF_ENV) && !defined(AFS_OSF32_ENV)
247 for (tmpint = 0; tmpint < getnumfds(); tmpint++)
249 for (tmpint = 0; tmpint < 10; tmpint++)
251 (void) close(tmpint);
252 (void) open("/", O_RDONLY);
256 tmpint = open("/dev/tty", O_RDWR);
258 ioctl(tmpint, TIOCNOTTY, (char *)0);
264 * the way to get rid of the controlling terminal in hp-ux, if we
265 * are not a process group leader
267 newSessionID = setsid();
268 if (newSessionID == -1) {
270 * we are already a process group leader, & extensive experimentation
271 * indicates that (contrary to the documentation, once again), there
272 * doesn't seem to be any way to get rid of our control tty, other
273 * than the following ugliness:
275 if ( fork() ) exit(0);
282 (void) setpgrp(0, 0);
286 (void) signal(SIGTSTP, SIG_IGN);
287 (void) signal(SIGTTIN, SIG_IGN);
288 (void) signal(SIGTTOU, SIG_IGN);
289 #endif /* !defined(AIX) */
290 #endif /* AFS_OSF_ENV */
293 openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
295 memset((char *)&sa, '\0', sizeof(sa));
296 sa.sa_mask = sigBlock;
297 sa.sa_handler = retry;
298 sigaction(SIGALRM, &sa, (struct sigaction *)0);
300 sa.sa_handler = config;
301 sigaction(SIGHUP, &sa, (struct sigaction *)0);
302 sa.sa_handler = reapchild;
303 sigaction(SIGCHLD, &sa, (struct sigaction *)0);
305 /* space for daemons to overwrite environment for ps */
306 #define DUMMYSIZE 100
307 char dummy[DUMMYSIZE];
309 (void)memset(dummy, 'x', sizeof(DUMMYSIZE) - 1);
310 dummy[DUMMYSIZE - 1] = '\0';
311 (void)setenv("inetd_dummy", dummy, 1);
319 (void) sigprocmask(SIG_BLOCK, &sigBlock, (sigset_t *)0);
322 (void) sigprocmask(SIG_SETMASK, &sigNone, (sigset_t *)0);
325 if ((n = select(maxsock + 1, &readable, (fd_set *)0,
326 (fd_set *)0, (struct timeval *)0)) <= 0) {
327 if (n < 0 && errno != EINTR)
328 syslog(LOG_WARNING, "select: %m\n");
332 for (sep = servtab; n && sep; sep = sep->se_next)
333 if ((sep->se_fd != -1) && FD_ISSET(sep->se_fd, &readable)) {
336 fprintf(stderr, "someone wants %s\n", sep->se_service);
337 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
338 ctrl = accept(sep->se_fd, (struct sockaddr *)0,
341 fprintf(stderr, "accept, ctrl %d\n", ctrl);
345 syslog(LOG_WARNING, "accept: %m");
350 (void) sigprocmask(SIG_BLOCK, &sigBlock, (sigset_t *)0);
352 dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
355 fprintf(stderr,"forking\n");
356 if (sep->se_socktype == SOCK_DGRAM) {
357 if (sep->se_count++ == 0)
358 (void)gettimeofday(&sep->se_time,
359 (struct timezone *)0);
360 else if (sep->se_count >= TOOMANY) {
363 (void)gettimeofday(&now, (struct timezone *)0);
364 if (now.tv_sec - sep->se_time.tv_sec >
370 "%s/%s server failing (looping), service terminated %d\n",
371 sep->se_service, sep->se_proto, sep->se_socktype);
372 FD_CLR(sep->se_fd, &allsock);
373 (void) close(sep->se_fd);
377 sigprocmask(SIG_SETMASK, &sigNone,
390 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
392 sigprocmask(SIG_SETMASK, &sigNone, (sigset_t *)0);
396 if (pid && sep->se_wait) {
398 FD_CLR(sep->se_fd, &allsock);
401 sigprocmask(SIG_SETMASK, &sigNone, (sigset_t *)0);
408 (tmpint = open("/dev/tty", O_RDWR)) > 0) {
410 ioctl(tmpint, TIOCNOTTY, 0);
414 (void) setpgrp(0, 0);
416 (void) signal(SIGTSTP, SIG_IGN);
417 (void) signal(SIGTTIN, SIG_IGN);
418 (void) signal(SIGTTOU, SIG_IGN);
419 #endif /* !defined(AIX) */
424 /* make child session leader */
428 for (tmpint = getnumfds(); --tmpint > 2; )
430 for (tmpint = getdtablesize(); --tmpint > 2; )
437 (*sep->se_bi->bi_fn)(ctrl, sep);
440 int pgid = -getpid();
443 (void) setpgrp(0, 0);
451 /* make child socket process group leader */
452 ioctl(0, SIOCSPGRP, (char *)&pgid);
454 if ((pwd = getpwnam(sep->se_user)) == NULL) {
455 fprintf(stderr,"getpwnam failed\n");
456 syslog(LOG_ERR, "getpwnam: %s: No such user",sep->se_user);
457 if (sep->se_socktype != SOCK_STREAM)
458 recv(0, buf, sizeof (buf), 0);
463 (void) initgroups((uid_t)pwd->pw_name,(gid_t)pwd->pw_gid);
464 (void) setgid((gid_t)pwd->pw_gid);
466 (void) setgid((gid_t)pwd->pw_gid);
467 initgroups(pwd->pw_name, pwd->pw_gid);
469 (void) setuid((uid_t)pwd->pw_uid);
471 if (!afs_didsetpag && (!strcmp(sep->se_service, "login") ||
472 !strcmp(sep->se_service, "shell"))) {
473 setpag(); /* to disassociate it from current group... */
477 if (sep->se_argv[0] != NULL) {
478 if (!strcmp(sep->se_argv[0], "%A")) {
480 sprintf(addrbuf, "%s.%d",
481 inet_ntoa(his_addr.sin_addr.s_addr),
482 ntohs(his_addr.sin_port));
483 execl(sep->se_server,
484 rindex(sep->se_server, '/')+1,
485 sep->se_socktype == SOCK_DGRAM
486 ? (char *)0 : addrbuf, (char *)0);
488 execv(sep->se_server, sep->se_argv);
492 execv(sep->se_server, sep->se_argv);
494 fprintf(stderr, "%d execl %s\n",
495 getpid(), sep->se_server);
496 if (sep->se_socktype != SOCK_STREAM)
497 recv(0, buf, sizeof (buf), 0);
498 syslog(LOG_ERR, "execv %s: %m", sep->se_server);
502 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
513 register struct servtab *sep;
516 pid = wait3(&status, WNOHANG, (struct rusage *)0);
520 fprintf(stderr, "%d <reaped (status %d)\n", pid,
522 for (sep = servtab; sep; sep = sep->se_next)
523 if (sep->se_wait == pid) {
526 "%s: exit status 0x%x",
527 sep->se_server, status);
529 fprintf(stderr, "restored %s, fd %d\n",
530 sep->se_service, sep->se_fd);
531 FD_SET(sep->se_fd, &allsock);
540 register struct servtab *sep, *cp, **sepp;
541 struct servtab *getconfigent(), *enter();
545 syslog(LOG_ERR, "%s: %m", CONFIG);
548 for (sep = servtab; sep; sep = sep->se_next)
550 while (cp = getconfigent()) {
552 /* fix a bug on rt */
553 if(cp->se_service == 0 || *cp->se_service == '\0')
556 for (sep = servtab; sep; sep = sep->se_next)
557 if (strcmp(sep->se_service, cp->se_service) == 0 &&
558 strcmp(sep->se_proto, cp->se_proto) == 0)
563 sigprocmask(SIG_BLOCK, &sigBlock, &oset);
565 sep->se_wait = cp->se_wait;
566 #define SWAP(a, b) { char *c = a; a = b; b = c; }
568 SWAP(sep->se_user, cp->se_user);
570 SWAP(sep->se_server, cp->se_server);
571 for (i = 0; i < MAXARGV; i++)
572 SWAP(sep->se_argv[i], cp->se_argv[i]);
573 sigprocmask(SIG_SETMASK, &oset, (sigset_t *)0);
576 print_service("REDO", sep);
580 print_service("ADD ", sep);
583 sp = getservbyname(sep->se_service, sep->se_proto);
585 syslog(LOG_ERR, "%s/%s: unknown service",
586 sep->se_service, sep->se_proto);
589 if (sp->s_port != sep->se_ctrladdr.sin_port) {
590 sep->se_ctrladdr.sin_port = sp->s_port;
591 if (sep->se_fd != -1)
592 (void) close(sep->se_fd);
595 if (sep->se_fd == -1)
600 * Purge anything not looked at above.
602 sigprocmask(SIG_BLOCK, &sigBlock, &oset);
604 while (sep = *sepp) {
605 if (sep->se_checked) {
606 sepp = &sep->se_next;
609 *sepp = sep->se_next;
610 if (sep->se_fd != -1) {
611 FD_CLR(sep->se_fd, &allsock);
613 (void) close(sep->se_fd);
616 print_service("FREE", sep);
620 sigprocmask(SIG_SETMASK, &oset, (sigset_t *)0);
626 register struct servtab *sep;
629 for (sep = servtab; sep; sep = sep->se_next)
630 if (sep->se_fd == -1)
635 register struct servtab *sep;
639 if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
640 syslog(LOG_ERR, "%s/%s: socket: %m",
641 sep->se_service, sep->se_proto);
644 #define turnon(fd, opt) \
645 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
646 if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
647 turnon(sep->se_fd, SO_DEBUG) < 0)
648 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
649 if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
650 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
652 if (bind(sep->se_fd, (struct sockaddr *) &sep->se_ctrladdr,
653 sizeof (sep->se_ctrladdr)) < 0) {
654 syslog(LOG_ERR, "%s/%s: bind: %m",
655 sep->se_service, sep->se_proto);
656 (void) close(sep->se_fd);
664 if (sep->se_socktype == SOCK_STREAM)
665 listen(sep->se_fd, backlog);
666 FD_SET(sep->se_fd, &allsock);
668 if (sep->se_fd > maxsock)
669 maxsock = sep->se_fd;
676 register struct servtab *sep;
679 sep = (struct servtab *)malloc(sizeof (*sep));
680 if (sep == (struct servtab *)0) {
681 syslog(LOG_ERR, "Out of memory.");
686 sigprocmask(SIG_BLOCK, &sigBlock, &oset);
687 sep->se_next = servtab;
689 sigprocmask(SIG_SETMASK, &oset, (sigset_t *)0);
693 FILE *fconfig = NULL;
696 char *skip(), *nextline();
701 if (fconfig != NULL) {
702 fseek(fconfig, 0L, L_SET);
705 fconfig = fopen(CONFIG, "r");
706 return (fconfig != NULL);
712 (void) fclose(fconfig);
720 register struct servtab *sep = &serv;
722 char *cp, *arg, *copyofstr();
725 /* modified to skip blank lines... */
726 while ((cp = nextline(fconfig)) && (*cp == '#' || (strlen(cp) < 2)))
729 return ((struct servtab *)0);
730 sep->se_service = copyofstr(skip(&cp));
732 if (strcmp(arg, "stream") == 0)
733 sep->se_socktype = SOCK_STREAM;
734 else if (strcmp(arg, "dgram") == 0)
735 sep->se_socktype = SOCK_DGRAM;
736 else if (strcmp(arg, "rdm") == 0)
737 sep->se_socktype = SOCK_RDM;
738 else if (strcmp(arg, "seqpacket") == 0)
739 sep->se_socktype = SOCK_SEQPACKET;
740 else if (strcmp(arg, "raw") == 0)
741 sep->se_socktype = SOCK_RAW;
743 sep->se_socktype = -1;
744 sep->se_proto = copyofstr(skip(&cp));
746 sep->se_wait = strcmp(arg, "wait") == 0;
747 sep->se_user = copyofstr(skip(&cp));
748 sep->se_server = copyofstr(skip(&cp));
749 if (strcmp(sep->se_server, "internal") == 0) {
750 register struct biltin *bi;
752 for (bi = biltins; bi->bi_service; bi++)
753 if (bi->bi_socktype == sep->se_socktype &&
754 strcmp(bi->bi_service, sep->se_service) == 0)
756 if (bi->bi_service == 0) {
757 syslog(LOG_ERR, "internal service %s unknown\n",
762 sep->se_wait = bi->bi_wait;
766 for (arg = skip(&cp); cp; arg = skip(&cp))
768 sep->se_argv[argc++] = copyofstr(arg);
769 while (argc <= MAXARGV)
770 sep->se_argv[argc++] = NULL;
775 register struct servtab *cp;
780 free(cp->se_service);
787 for (i = 0; i < MAXARGV; i++)
789 free(cp->se_argv[i]);
796 register char *cp = *cpp;
800 while (*cp == ' ' || *cp == '\t')
806 (void) ungetc(c, fconfig);
807 if (c == ' ' || c == '\t')
808 if (cp = nextline(fconfig))
814 while (*cp && *cp != ' ' && *cp != '\t')
828 if (fgets(line, sizeof (line), fd) == NULL)
830 cp = strchr(line, '\n');
844 new = malloc((unsigned)(strlen(cp) + 1));
845 if (new == (char *)0) {
846 syslog(LOG_ERR, "Out of memory.");
849 (void)strcpy(new, cp);
859 struct sockaddr_in sin;
864 if (getpeername(s, (struct sockaddr *) &sin, &size) == 0)
865 (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
867 (void) sprintf(buf, "-%s", a);
868 strncpy(cp, buf, LastArg - cp);
875 * Internet services provided internally by inetd:
879 echo_stream(s, sep) /* Echo service -- echo data back */
886 setproctitle(sep->se_service, s);
887 while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
888 write(s, buffer, i) > 0)
894 echo_dg(s, sep) /* Echo service -- echo data back */
903 if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
905 (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
909 discard_stream(s, sep) /* Discard service -- ignore data */
915 setproctitle(sep->se_service, s);
917 while (read(s, buffer, sizeof(buffer)) > 0)
926 discard_dg(s, sep) /* Discard service -- ignore data */
932 (void) read(s, buffer, sizeof(buffer));
945 for (i = 0; i <= 128; ++i)
951 chargen_stream(s, sep) /* Character generator */
957 char text[LINESIZ+2];
959 setproctitle(sep->se_service, s);
966 text[LINESIZ] = '\r';
967 text[LINESIZ + 1] = '\n';
969 if ((len = endring - rs) >= LINESIZ)
970 memcpy(text, rs, LINESIZ);
972 memcpy(text, rs, len);
973 memcpy(text + len, ring, LINESIZ - len);
977 if (write(s, text, sizeof(text)) != sizeof(text))
984 chargen_dg(s, sep) /* Character generator */
991 char text[LINESIZ+2];
999 if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
1002 if ((len = endring - rs) >= LINESIZ)
1003 memcpy(text, rs, LINESIZ);
1005 memcpy(text, rs, len);
1006 memcpy(text + len, ring, LINESIZ - len);
1008 if (++rs == endring)
1010 text[LINESIZ] = '\r';
1011 text[LINESIZ + 1] = '\n';
1012 (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
1016 * Return a machine readable date and time, in the form of the
1017 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
1018 * returns the number of seconds since midnight, Jan 1, 1970,
1019 * we must add 2208988800 seconds to this figure to make up for
1020 * some seventy years Bell Labs was asleep.
1028 if (gettimeofday(&tv, (struct timezone *)0) < 0) {
1029 fprintf(stderr, "Unable to get time of day\n");
1032 return (htonl((afs_int32)tv.tv_sec + 2208988800U));
1036 machtime_stream(s, sep)
1038 struct servtab *sep;
1042 result = machtime();
1043 (void) write(s, (char *) &result, sizeof(result));
1049 struct servtab *sep;
1056 if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
1058 result = machtime();
1059 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
1063 daytime_stream(s, sep) /* Return human-readable time of day */
1065 struct servtab *sep;
1070 clock = time((time_t *) 0);
1072 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1073 (void) write(s, buffer, strlen(buffer));
1077 daytime_dg(s, sep) /* Return human-readable time of day */
1079 struct servtab *sep;
1086 clock = time((time_t *) 0);
1089 if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
1091 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1092 (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
1097 * Dump relevant information to stderr
1099 print_service(action, sep)
1101 struct servtab *sep;
1104 "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
1105 action, sep->se_service, sep->se_proto,
1106 sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server);
1109 * (C) Copyright 1989 Transarc Corporation. All Rights Reserved.
1113 * This program is a front-end for the various remote access programs
1114 * (e.g. rsh, rcp, rlogin, ftp) to allow for weak remote authentication.
1115 * It will be used by a call to a well-known restricted tcp port; if
1116 * there is a service on that port, we will attempt authentication.
1118 * Note, this only affects the Kerberos portion of the authentication;
1119 * the program still requires its existing authentication (although it
1120 * seems reasonable to change this in the future.)
1122 * The advantage to this scheme (rather than modifying each program to
1123 * incorporate this authentication scheme) is it allows us to modify
1124 * the authentication mechanism without requiring additonal code
1125 * changes to the other programs.
1127 * Current format of authentication packet:
1131 * (3) Token length (null terminated);
1132 * (4) Token (not null terminated).
1134 * The code to add/delete to the AFS ticket cache is taken from the
1135 * authentication library.
1139 * routine to do the actual authentication. At this time, it is
1140 * very simple -- the remote end passes a token length and a token.
1142 * This routine returns the name of the requested service.
1145 #define gettime(tl) do { struct timezone tzp; struct timeval tv; \
1146 gettimeofday(&tv,&tzp); tl = tv.tv_sec; } while(0)
1147 #define RAUTH_TOKENLIFE (60 * 60 * 2) /* 2 hours */
1149 #define NOPAG 0xffffffff
1150 int get_pag_from_groups(g0, g1)
1153 afs_uint32 h, l, result;
1157 if (g0 < 0xc000 && g1 < 0xc000) {
1158 l = ((g0 & 0x3fff) << 14) | (g1 & 0x3fff);
1160 h = (g1 >> 14) + h + h + h;
1161 result = ((h << 28) | l);
1162 /* Additional testing */
1163 if (((result >> 24) & 0xff) == 'A')
1171 auth_stream(s, sepent)
1173 struct servtab *sepent;
1175 char service[100], remoteName[64];
1176 struct sockaddr_in from;
1179 struct afsconf_dir *tdir;
1180 struct ktc_principal tserver, tclient;
1181 struct ktc_token token;
1182 register struct servtab *sep;
1185 * First, obtain information on remote end of connection.
1188 fprintf(stderr,"auth_stream: entered\n");
1189 #ifndef AFS_SUN5_ENV
1190 if (getpeername(s, &from, &fromlen) < 0) {
1191 syslog(LOG_ERR, "getpeername failed");
1193 fprintf(stderr,"auth_stream: getpeername failed\n");
1197 if(intoken(s,&token,service,remoteName) != 0) {
1198 syslog(LOG_ERR,"invalid remote authentication");
1200 fprintf(stderr,"auth_stream: invalid remote authentication\n");
1203 /* lookup the name of the local cell */
1206 fprintf(stderr,"auth_stream: look up local cell name\n");
1208 tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
1210 syslog(LOG_NOTICE, "Can't open dir %s\n", AFSDIR_CLIENT_ETC_DIRPATH);
1212 fprintf(stderr,"Can't open dir %s\n", AFSDIR_CLIENT_ETC_DIRPATH);
1215 /* done with configuration stuff now */
1216 afsconf_Close(tdir);
1217 /* set ticket in local cell */
1218 strcpy(tserver.cell, remoteName);
1219 strcpy(tserver.name, "afs");
1221 /* now, set the token */
1225 "token information: service is %s\ntoken length is %d\n",
1226 service, token. ticketLen);
1227 fprintf(stderr,"token is %s\n",token.ticket);
1228 fprintf(stderr,"cell name is %s\n",remoteName);
1232 code = ktc_SetToken(&tserver, &token, &tclient, 0);
1234 write(s,"0",1); /* say "no" to other side */
1235 printf("Login incorrect.(%d)", code);
1236 syslog(LOG_ERR, "Invalid token from %s",
1237 inet_ntoa(from.sin_addr));
1240 write(s, "1", 1); /* say "yes" to other side */
1243 fprintf(stderr,"Finished authentication code\n");
1244 for (sep = servtab; sep; sep = sep->se_next)
1245 if(strcmp(sep->se_service,service) == 0) {
1246 int dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
1250 for(tmpint = getdtablesize(); --tmpint > 2; )
1255 (*sep->se_bi->bi_fn)(s, sep);
1257 register struct passwd *pwd;
1258 struct passwd *getpwnam();
1261 if ((pwd = getpwnam(sep->se_user)) == NULL) {
1263 "getpwnam: %s: No such user",
1265 if (sep->se_socktype != SOCK_STREAM)
1266 recv(0, buf, sizeof (buf), 0);
1271 (void) setgid((gid_t)pwd->pw_gid);
1272 initgroups(pwd->pw_name, pwd->pw_gid);
1273 (void) setuid((uid_t)pwd->pw_uid);
1279 fprintf(stderr,"going to exec program %s(errno = %d)\n",
1280 sep->se_server,errno);
1285 if (!afs_didsetpag && (!strcmp(sep->se_service, "login") ||
1286 !strcmp(sep->se_service, "shell"))) {
1287 setpag(); /* to disassociate it from current group... */
1289 execv(sep->se_server, sep->se_argv);
1291 if (sep->se_socktype != SOCK_STREAM)
1292 recv(0, buf, sizeof (buf), 0);
1293 syslog(LOG_ERR, "execv %s: %m", sep->se_server);
1297 fprintf(stderr,"service not available\n");
1298 syslog(LOG_ERR, "auth_stream: invalid service requested %s\n",service);
1306 "datagram remote authentication requested, not supported");
1312 * This routine accepts a token on the specified file handle;
1313 * The input format for a token is:
1315 * Field # Contents description
1316 * (0) Service Name char[]
1317 * (1) Version # unsigned integer (< 2^32)
1318 * (2) cellName char[]
1319 * (3) startTime unsigned afs_int32 (< 2^32)
1320 * (4) endTime unsigned afs_int32 (< 2^32)
1321 * (5) sessionKey char[8]
1322 * (6) kvno short (< 2^16)
1323 * (7) ticketLen unsigned integer (< 2^32)
1324 * (8) ticket char[MAXKTCTICKETLEN]
1326 * Each field is comma separated; the last is variable length. The
1327 * converted token is placed into the token structure pointed to by
1328 * the variable "token".
1331 intoken(s,token,svc, cell)
1333 struct ktc_token *token;
1336 char buf[1024], *bp;
1338 unsigned index, version;
1341 fprintf(stderr,"intoken: entered\n");
1343 if((count = recv(s,buf,sizeof buf,0)) == -1) {
1345 fprintf(stderr,"error on fd %d\n",s);
1346 perror("intoken recv");
1351 /* (0) Service Name */
1352 for(index = 0; index < count && buf[index] != ','; index++)
1355 if (index == count) {
1357 fprintf(stderr,"overran buffer while searching for svc name\n");
1361 if (buf[index] != ',') {
1363 fprintf(stderr,"Didn't stop on a comma, searching for svc name\n");
1373 bp = buf + index + 1;
1375 for(; index < count && buf[index] != ','; index++)
1378 if (index == count) {
1380 fprintf(stderr,"overran buffer while searching for version #\n");
1384 if (buf[index] != ',') {
1387 "Didn't stop on a comma, searching for version #\n");
1393 sscanf(bp, "%u", &version);
1397 fprintf(stderr,"Incompatible (newer) version encountered: %d\n",
1403 /* we didn't include cell name in prior versions */
1404 bp = buf + index + 1;
1406 for(index = 0; index < count && buf[index] != ','; index++)
1409 if (index == count) {
1411 fprintf(stderr,"overran buffer while searching for cell\n");
1415 if (buf[index] != ',') {
1417 fprintf(stderr,"Didn't stop on a comma, searching for cell\n");
1426 bp = buf + index + 1;
1428 for(; index < count && buf[index] != ','; index++)
1431 if (index == count) {
1434 "overran buffer while searching for startTime #\n");
1438 if (buf[index] != ',') {
1441 "Didn't stop on a comma, searching for startTime #\n");
1447 sscanf(bp, "%u", &token->startTime);
1451 bp = buf + index + 1;
1453 for(; index < count && buf[index] != ','; index++)
1456 if (index == count) {
1459 "overran buffer while searching for endTime #\n");
1463 if (buf[index] != ',') {
1466 "Didn't stop on a comma, searching for endTime #\n");
1472 sscanf(bp, "%u", &token->endTime);
1474 /* (4) sessionKey */
1476 bp = buf + index + 1;
1477 memcpy(&token->sessionKey, bp, 8);
1482 for(index += 9; index < count && buf[index] != ','; index++)
1485 if (index == count) {
1487 fprintf(stderr,"overran buffer while searching for kvno\n");
1491 if (buf[index] != ',') {
1493 fprintf(stderr,"Didn't stop on a comma, searching for kvno\n");
1499 /* kvno is actually a short, so insist that it scan a short */
1501 sscanf(bp, "%hu", &token->kvno);
1505 bp = buf + index + 1;
1507 for(; index < count && buf[index] != ','; index++)
1510 if (index == count) {
1512 fprintf(stderr,"overran buffer while searching for ticketLen\n");
1516 if (buf[index] != ',') {
1519 "Didn't stop on a comma, searching for ticketLen\n");
1525 sscanf(bp, "%u", &token->ticketLen);
1529 bp = buf + index + 1;
1531 if(index + token->ticketLen > count) {
1533 fprintf(stderr,"overran buffer while copying ticket\n");
1537 memcpy(token->ticket, bp, token->ticketLen);
1545 struct sigaction act, oact;
1548 memset(&act, '\0', sizeof(act));
1549 act.sa_handler = SIG_DFL;
1550 for (sign = 1; sign < NSIG; sign++)
1551 sigaction(sign, &act, &oact);