afsconfig-and-rcsid-all-around-20010705
[openafs.git] / src / inetd / inetd.c
1 /* inetd.c */
2
3 /*
4  * Copyright (c) 1983 Regents of the University of California.
5  * All rights reserved.
6  *
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.
18  */
19
20 /*
21  * Inetd - Internet super-server
22  *
23  * This program invokes all internet services as needed.
24  * connection-oriented services are invoked each time a
25  * connection is made, by creating a process.  This process
26  * is passed the connection as file descriptor 0 and is
27  * expected to do a getpeername to find out the source host
28  * and port.
29  *
30  * Datagram oriented services are invoked when a datagram
31  * arrives; a process is created and passed a pending message
32  * on file descriptor 0.  Datagram servers may either connect
33  * to their peer, freeing up the original socket for inetd
34  * to receive further messages on, or ``take over the socket'',
35  * processing all arriving datagrams and, eventually, timing
36  * out.  The first type of server is said to be ``multi-threaded'';
37  * the second type of server ``single-threaded''. 
38  *
39  * Inetd uses a configuration file which is read at startup
40  * and, possibly, at some later time in response to a hangup signal.
41  * The configuration file is ``free format'' with fields given in the
42  * order shown below.  Continuation lines for an entry must being with
43  * a space or tab.  All fields must be present in each entry.
44  *
45  *      service name                    must be in /etc/services
46  *      socket type                     stream/dgram/raw/rdm/seqpacket
47  *      protocol                        must be in /etc/protocols
48  *      wait/nowait                     single-threaded/multi-threaded
49  *      user                            user to run daemon as
50  *      server program                  full path name
51  *      server program arguments        maximum of MAXARGS (5)
52  *
53  * Comment lines are indicated by a `#' in column 1.
54  */
55 #include <afs/param.h>
56 #include <afsconfig.h>
57
58 RCSID("$Header$");
59
60 #include <sys/param.h>
61 #include <sys/stat.h>
62 #ifdef AFS_SUN5_ENV
63 #define BSD_COMP
64 #endif
65 #include <sys/ioctl.h>
66 #include <sys/socket.h>
67 #include <sys/file.h>
68 #ifdef AFS_SUN5_ENV
69 #include <fcntl.h>
70 #endif
71 #include <sys/wait.h>
72 #include <sys/time.h>
73 #include <sys/resource.h>
74
75 #include <netinet/in.h>
76 #include <arpa/inet.h>
77
78 #include <afs/auth.h>
79 #include <afs/cellconfig.h>
80 #include <afs/afsutil.h>
81 #include <errno.h>
82 #include <signal.h>
83 #include <netdb.h>
84 #ifdef AIX
85 #include <sys/syslog.h>
86 #else
87 #include <syslog.h>
88 #endif /* AIX */
89 #include <pwd.h>
90 #include <stdio.h>
91 #include <ctype.h>
92 #include <string.h>
93 #include <stdlib.h>
94 #include <time.h>
95
96 #define TOOMANY         40              /* don't start more than TOOMANY */
97 #define CNT_INTVL       60              /* servers in CNT_INTVL sec. */
98 #define RETRYTIME       (60*10)         /* retry after bind or server fail */
99
100 void    config(), reapchild(), retry();
101
102 int     debug = 0;
103 int     nsock, maxsock;
104 fd_set  allsock;
105 int     options;
106 int     timingout;
107 struct  servent *sp;
108
109 struct  servtab {
110         char    *se_service;            /* name of service */
111         int     se_socktype;            /* type of socket to use */
112         char    *se_proto;              /* protocol used */
113         short   se_wait;                /* single threaded server */
114         short   se_checked;             /* looked at during merge */
115         char    *se_user;               /* user name to run as */
116         struct  biltin *se_bi;          /* if built-in, description */
117         char    *se_server;             /* server program */
118 #define MAXARGV 5
119         char    *se_argv[MAXARGV+1];    /* program arguments */
120         int     se_fd;                  /* open descriptor */
121         struct  sockaddr_in se_ctrladdr;/* bound address */
122         int     se_count;               /* number started since se_time */
123         struct  timeval se_time;        /* start of se_count */
124         struct  servtab *se_next;
125 } *servtab;
126
127 int echo_stream(), discard_stream(), machtime_stream();
128 int daytime_stream(), chargen_stream();
129 int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg();
130 int auth_stream(), auth_dg();
131
132 struct biltin {
133         char    *bi_service;            /* internally provided service name */
134         int     bi_socktype;            /* type of socket supported */
135         short   bi_fork;                /* 1 if should fork before call */
136         short   bi_wait;                /* 1 if should wait for child */
137         int     (*bi_fn)();             /* function which performs it */
138 } biltins[] = {
139         /* Echo received data */
140         "echo",         SOCK_STREAM,    1, 0,   echo_stream,
141         "echo",         SOCK_DGRAM,     0, 0,   echo_dg,
142
143         /* Internet /dev/null */
144         "discard",      SOCK_STREAM,    1, 0,   discard_stream,
145         "discard",      SOCK_DGRAM,     0, 0,   discard_dg,
146
147         /* Return 32 bit time since 1970 */
148         "time",         SOCK_STREAM,    0, 0,   machtime_stream,
149         "time",         SOCK_DGRAM,     0, 0,   machtime_dg,
150
151         /* Return human-readable time */
152         "daytime",      SOCK_STREAM,    0, 0,   daytime_stream,
153         "daytime",      SOCK_DGRAM,     0, 0,   daytime_dg,
154
155         /* Familiar character generator */
156         "chargen",      SOCK_STREAM,    1, 0,   chargen_stream,
157         "chargen",      SOCK_DGRAM,     0, 0,   chargen_dg,
158
159         /* Remote authentication services */
160         "ta-rauth",        SOCK_STREAM,    1, 0,   auth_stream,
161         "ta-rauth",        SOCK_DGRAM,     0, 0,   auth_dg,
162         0
163 };
164
165 #define NUMINT  (sizeof(intab) / sizeof(struct inent))
166 char    *CONFIG = "/etc/inetd.conf";
167 char    **Argv;
168 char    *LastArg;
169 int     backlog = 10;   /* listen() queue length */
170
171 #include "AFS_component_version_number.c"
172
173 long allZeroes[100];
174 sigset_t sigNone;
175 sigset_t sigBlock;
176
177 int afs_didsetpag = 0;
178 main(argc, argv, envp)
179         int argc;
180         char *argv[], *envp[];
181 {
182         extern char *optarg;
183         extern int optind;
184         register struct servtab *sep;
185         register struct passwd *pwd;
186         struct passwd *getpwnam();
187         register int tmpint;
188         struct sigaction sa;
189         int ch, pid, dofork;
190         char buf[50];
191 #if defined(AFS_HPUX_ENV)
192         int     consoleFid;
193         pid_t   newSessionID;
194 #endif /* defined(AFS_HPUX_ENV) */
195
196         memset((char *)allZeroes, '\0', sizeof(allZeroes));
197         bzero((char *)allZeroes, sizeof(allZeroes));
198
199         sigNone = *((sigset_t *) allZeroes);
200         allZeroes[0] = (1<<(SIGCHLD-1)) + (1<<(SIGHUP-1)) + (1<<(SIGALRM-1));
201         sigBlock = *((sigset_t *) allZeroes);
202
203         setpag();  /* disassociate with PAG of person starting inetd */
204
205         Argv = argv;
206         if (envp == 0 || *envp == 0)
207                 envp = argv;
208         while (*envp)
209                 envp++;
210         LastArg = envp[-1] + strlen(envp[-1]);
211
212         while ((ch = getopt(argc, argv, "dl:")) != EOF)
213                 switch(ch) {
214                 case 'd':
215                         debug = 1;
216                         options |= SO_DEBUG;
217                         break;
218                 case 'l':
219                         /* undocumented option to set listen() queue length */
220                         backlog = atoi(optarg);
221                         break;
222                 case '?':
223                 default:
224                         fprintf(stderr, "usage: inetd [-d]");
225                         exit(1);
226                 }
227         argc -= optind;
228         argv += optind;
229
230         if (argc > 0)
231                 CONFIG = argv[0];
232         if (debug == 0) {
233 #if     defined(AFS_OSF_ENV) && !defined(AFS_OSF32_ENV)
234                 daemon(0,0);
235 #else
236                 if (fork()) {
237                         exit(0);
238                 }
239                 
240 #ifdef AFS_HPUX_ENV
241                 for (tmpint = 0; tmpint < getnumfds(); tmpint++)
242 #else
243                 for (tmpint = 0; tmpint < 10; tmpint++)
244 #endif
245                         (void) close(tmpint);
246                 (void) open("/", O_RDONLY);
247                 (void) dup2(0, 1);
248                 (void) dup2(0, 2);
249 #ifndef AFS_HPUX_ENV
250                 tmpint = open("/dev/tty", O_RDWR);
251                 if (tmpint > 0) {
252                         ioctl(tmpint, TIOCNOTTY, (char *)0);
253                         close(tmpint);
254                 }
255 #else
256 #ifdef  notdef
257                 /*
258                  * the way to get rid of the controlling terminal in hp-ux, if we
259                  * are not a process group leader
260                  */
261                 newSessionID = setsid();
262                 if (newSessionID == -1) {
263                   /*
264                    * we are already a process group leader, & extensive experimentation
265                    * indicates that (contrary to the documentation, once again), there
266                    * doesn't seem to be any way to get rid of our control tty, other
267                    * than the following ugliness:
268                    */
269                   if ( fork() ) exit(0);
270                 }
271 #endif
272 #endif
273 #ifdef  AFS_HPUX_ENV
274                 (void) setpgrp();
275 #else
276                 (void) setpgrp(0, 0);
277 #endif
278
279 #if !defined(AIX)
280                 (void) signal(SIGTSTP, SIG_IGN);
281                 (void) signal(SIGTTIN, SIG_IGN);
282                 (void) signal(SIGTTOU, SIG_IGN);
283 #endif /* !defined(AIX) */
284 #endif  /* AFS_OSF_ENV */
285         }
286
287         openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
288
289         memset((char *)&sa, '\0', sizeof(sa));
290         sa.sa_mask = sigBlock;
291         sa.sa_handler = retry;
292         sigaction(SIGALRM, &sa, (struct sigaction *)0);
293         config();
294         sa.sa_handler = config;
295         sigaction(SIGHUP, &sa, (struct sigaction *)0);
296         sa.sa_handler = reapchild;
297         sigaction(SIGCHLD, &sa, (struct sigaction *)0);
298         {
299                 /* space for daemons to overwrite environment for ps */
300 #define DUMMYSIZE       100
301                 char dummy[DUMMYSIZE];
302
303                 (void)memset(dummy, 'x', sizeof(DUMMYSIZE) - 1);
304                 dummy[DUMMYSIZE - 1] = '\0';
305                 (void)setenv("inetd_dummy", dummy, 1);
306         }
307
308         for (;;) {
309             int n, ctrl;
310             fd_set readable;
311
312             if (nsock == 0) {
313                 (void) sigprocmask(SIG_BLOCK, &sigBlock, (sigset_t *)0);
314                 while (nsock == 0)
315                     sigpause(0L);
316                 (void) sigprocmask(SIG_SETMASK, &sigNone, (sigset_t *)0);
317             }
318             readable = allsock;
319             if ((n = select(maxsock + 1, &readable, (fd_set *)0,
320                 (fd_set *)0, (struct timeval *)0)) <= 0) {
321                     if (n < 0 && errno != EINTR)
322                         syslog(LOG_WARNING, "select: %m\n");
323                     sleep(1);
324                     continue;
325             }
326             for (sep = servtab; n && sep; sep = sep->se_next)
327             if ((sep->se_fd != -1) && FD_ISSET(sep->se_fd, &readable)) {
328                 n--;
329                 if (debug)
330                         fprintf(stderr, "someone wants %s\n", sep->se_service);
331                 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
332                         ctrl = accept(sep->se_fd, (struct sockaddr *)0,
333                             (int *)0);
334                         if (debug)
335                                 fprintf(stderr, "accept, ctrl %d\n", ctrl);
336                         if (ctrl < 0) {
337                                 if (errno == EINTR)
338                                         continue;
339                                 syslog(LOG_WARNING, "accept: %m");
340                                 continue;
341                         }
342                 } else
343                         ctrl = sep->se_fd;
344                 (void) sigprocmask(SIG_BLOCK, &sigBlock, (sigset_t *)0);
345                 pid = 0;
346                 dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
347                 if (dofork) {
348                     if(debug)
349                         fprintf(stderr,"forking\n");
350                     if (sep->se_socktype == SOCK_DGRAM) {
351                         if (sep->se_count++ == 0)
352                             (void)gettimeofday(&sep->se_time,
353                                 (struct timezone *)0);
354                         else if (sep->se_count >= TOOMANY) {
355                                 struct timeval now;
356
357                                 (void)gettimeofday(&now, (struct timezone *)0);
358                                 if (now.tv_sec - sep->se_time.tv_sec >
359                                     CNT_INTVL) {
360                                         sep->se_time = now;
361                                         sep->se_count = 1;
362                                 } else {
363                                         syslog(LOG_ERR,
364                         "%s/%s server failing (looping), service terminated %d\n",
365                                             sep->se_service, sep->se_proto, sep->se_socktype);
366                                         FD_CLR(sep->se_fd, &allsock);
367                                         (void) close(sep->se_fd);
368                                         sep->se_fd = -1;
369                                         sep->se_count = 0;
370                                         nsock--;
371                                         sigprocmask(SIG_SETMASK, &sigNone,
372                                                     (sigset_t *)0);
373                                         if (!timingout) {
374                                                 timingout = 1;
375                                                 alarm(RETRYTIME);
376                                         }
377                                         continue;
378                                 }
379                         }
380                     }
381                     pid = fork();
382                 }
383                 if (pid < 0) {
384                         if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
385                                 close(ctrl);
386                         sigprocmask(SIG_SETMASK, &sigNone, (sigset_t *)0);
387                         sleep(1);
388                         continue;
389                 }
390                 if (pid && sep->se_wait) {
391                         sep->se_wait = pid;
392                         FD_CLR(sep->se_fd, &allsock);
393                         nsock--;
394                 }
395                 sigprocmask(SIG_SETMASK, &sigNone, (sigset_t *)0);
396                 if (pid == 0) {
397                         if (debug) {
398 #ifdef  AFS_OSF_ENV
399                             setsid();
400 #else
401                                 if (dofork &&
402                                     (tmpint = open("/dev/tty", O_RDWR)) > 0) {
403 #ifndef AFS_HPUX_ENV
404                                         ioctl(tmpint, TIOCNOTTY, 0);
405 #endif
406                                         close(tmpint);
407                                 }
408                                 (void) setpgrp(0, 0);
409 #if !defined(AIX)
410                                 (void) signal(SIGTSTP, SIG_IGN);
411                                 (void) signal(SIGTTIN, SIG_IGN);
412                                 (void) signal(SIGTTOU, SIG_IGN);
413 #endif /* !defined(AIX) */
414 #endif
415                         }
416                         if (dofork) {
417 #ifdef  AFS_HPUX_ENV
418                             /* make child session leader */
419                             setsid();
420                             resetsignals();
421                             sigsetmask(0L);
422                             for (tmpint = getnumfds(); --tmpint > 2; )
423 #else
424                             for (tmpint = getdtablesize(); --tmpint > 2; )
425 #endif
426                                 if (tmpint != ctrl)
427                                     close(tmpint);
428                         }
429                         afs_didsetpag = 0;
430                         if (sep->se_bi)
431                                 (*sep->se_bi->bi_fn)(ctrl, sep);
432                         else {
433 #ifdef  AFS_HPUX_ENV
434                                  int pgid = -getpid();
435 #else
436 #ifndef AFS_OSF_ENV
437                                 (void) setpgrp(0, 0);
438 #endif
439 #endif
440                                 dup2(ctrl, 0);
441                                 close(ctrl);
442                                 dup2(0, 1);
443                                 dup2(0, 2);
444 #ifdef  AFS_HPUX_ENV
445                                  /* make child socket process group leader */
446                                  ioctl(0, SIOCSPGRP, (char *)&pgid);
447 #endif
448                                 if ((pwd = getpwnam(sep->se_user)) == NULL) {
449                                     fprintf(stderr,"getpwnam failed\n");
450                                         syslog(LOG_ERR, "getpwnam: %s: No such user",sep->se_user);
451                                         if (sep->se_socktype != SOCK_STREAM)
452                                                 recv(0, buf, sizeof (buf), 0);
453                                         _exit(1);
454                                 }
455                                 if (pwd->pw_uid) {
456 #ifdef  AFS_HPUX_ENV
457                                         (void) initgroups((uid_t)pwd->pw_name,(gid_t)pwd->pw_gid);
458                                         (void) setgid((gid_t)pwd->pw_gid);
459 #else
460                                         (void) setgid((gid_t)pwd->pw_gid);
461                                         initgroups(pwd->pw_name, pwd->pw_gid);
462 #endif
463                                         (void) setuid((uid_t)pwd->pw_uid);
464                                 }
465                                 if (!afs_didsetpag && (!strcmp(sep->se_service, "login") || 
466                                                        !strcmp(sep->se_service, "shell"))) {
467                                     setpag(); /* to disassociate it from current group... */
468                                 }
469 #ifdef  AFS_HPUX_ENV
470 #ifdef  notdef
471                                 if (sep->se_argv[0] != NULL) {
472                                     if (!strcmp(sep->se_argv[0], "%A")) {
473                                         char addrbuf[32];
474                                         sprintf(addrbuf, "%s.%d", 
475                                                 inet_ntoa(his_addr.sin_addr.s_addr),
476                                                 ntohs(his_addr.sin_port));
477                                         execl(sep->se_server,
478                                               rindex(sep->se_server, '/')+1,
479                                               sep->se_socktype == SOCK_DGRAM
480                                               ? (char *)0 : addrbuf, (char *)0);
481                                     } else
482                                         execv(sep->se_server, sep->se_argv);
483                                 } else
484 #endif
485 #endif
486                                 execv(sep->se_server, sep->se_argv);
487                                 if (debug)
488                                         fprintf(stderr, "%d execl %s\n",
489                                             getpid(), sep->se_server);
490                                 if (sep->se_socktype != SOCK_STREAM)
491                                         recv(0, buf, sizeof (buf), 0);
492                                 syslog(LOG_ERR, "execv %s: %m", sep->se_server);
493                                 _exit(1);
494                         }
495                 }
496                 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
497                         close(ctrl);
498             }
499         }
500 }
501
502 void
503 reapchild()
504 {
505         int status;
506         int pid;
507         register struct servtab *sep;
508
509         for (;;) {
510                 pid = wait3(&status, WNOHANG, (struct rusage *)0);
511                 if (pid <= 0)
512                         break;
513                 if (debug)
514                         fprintf(stderr, "%d <reaped (status %d)\n", pid,
515                                 status);
516                 for (sep = servtab; sep; sep = sep->se_next)
517                         if (sep->se_wait == pid) {
518                                 if (status)
519                                         syslog(LOG_WARNING,
520                                             "%s: exit status 0x%x",
521                                             sep->se_server, status);
522                                 if (debug)
523                                         fprintf(stderr, "restored %s, fd %d\n",
524                                             sep->se_service, sep->se_fd);
525                                 FD_SET(sep->se_fd, &allsock);
526                                 nsock++;
527                                 sep->se_wait = 1;
528                         }
529         }
530 }
531
532 void config()
533 {
534         register struct servtab *sep, *cp, **sepp;
535         struct servtab *getconfigent(), *enter();
536         sigset_t oset;
537
538         if (!setconfig()) {
539                 syslog(LOG_ERR, "%s: %m", CONFIG);
540                 return;
541         }
542         for (sep = servtab; sep; sep = sep->se_next)
543                 sep->se_checked = 0;
544         while (cp = getconfigent()) {
545 #if 0
546                 /* fix a bug on rt */
547                 if(cp->se_service == 0 || *cp->se_service == '\0')
548                         break;
549 #endif /* 0 */
550                 for (sep = servtab; sep; sep = sep->se_next)
551                         if (strcmp(sep->se_service, cp->se_service) == 0 &&
552                             strcmp(sep->se_proto, cp->se_proto) == 0)
553                                 break;
554                 if (sep != 0 ) {
555                         int i;
556
557                         sigprocmask(SIG_BLOCK, &sigBlock, &oset);
558                         if (cp->se_bi == 0)
559                                 sep->se_wait = cp->se_wait;
560 #define SWAP(a, b) { char *c = a; a = b; b = c; }
561                         if (cp->se_user)
562                                 SWAP(sep->se_user, cp->se_user);
563                         if (cp->se_server)
564                                 SWAP(sep->se_server, cp->se_server);
565                         for (i = 0; i < MAXARGV; i++)
566                                 SWAP(sep->se_argv[i], cp->se_argv[i]);
567                         sigprocmask(SIG_SETMASK, &oset, (sigset_t *)0);
568                         freeconfig(cp);
569                         if (debug)
570                                 print_service("REDO", sep);
571                 } else {
572                         sep = enter(cp);
573                         if (debug)
574                                 print_service("ADD ", sep);
575                 }
576                 sep->se_checked = 1;
577                 sp = getservbyname(sep->se_service, sep->se_proto);
578                 if (sp == 0) {
579                         syslog(LOG_ERR, "%s/%s: unknown service",
580                             sep->se_service, sep->se_proto);
581                         continue;
582                 }
583                 if (sp->s_port != sep->se_ctrladdr.sin_port) {
584                         sep->se_ctrladdr.sin_port = sp->s_port;
585                         if (sep->se_fd != -1)
586                                 (void) close(sep->se_fd);
587                         sep->se_fd = -1;
588                 }
589                 if (sep->se_fd == -1)
590                         setup(sep);
591         }
592         endconfig();
593         /*
594          * Purge anything not looked at above.
595          */
596         sigprocmask(SIG_BLOCK, &sigBlock, &oset);
597         sepp = &servtab;
598         while (sep = *sepp) {
599                 if (sep->se_checked) {
600                         sepp = &sep->se_next;
601                         continue;
602                 }
603                 *sepp = sep->se_next;
604                 if (sep->se_fd != -1) {
605                         FD_CLR(sep->se_fd, &allsock);
606                         nsock--;
607                         (void) close(sep->se_fd);
608                 }
609                 if (debug)
610                         print_service("FREE", sep);
611                 freeconfig(sep);
612                 free((char *)sep);
613         }
614         sigprocmask(SIG_SETMASK, &oset, (sigset_t *)0);
615 }
616
617 void
618 retry()
619 {
620         register struct servtab *sep;
621
622         timingout = 0;
623         for (sep = servtab; sep; sep = sep->se_next)
624                 if (sep->se_fd == -1)
625                         setup(sep);
626 }
627
628 setup(sep)
629         register struct servtab *sep;
630 {
631         int on = 1;
632
633         if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
634                 syslog(LOG_ERR, "%s/%s: socket: %m",
635                     sep->se_service, sep->se_proto);
636                 return;
637         }
638 #define turnon(fd, opt) \
639 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
640         if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
641             turnon(sep->se_fd, SO_DEBUG) < 0)
642                 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
643         if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
644                 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
645 #undef turnon
646         if (bind(sep->se_fd, (struct sockaddr *) &sep->se_ctrladdr,
647             sizeof (sep->se_ctrladdr)) < 0) {
648                 syslog(LOG_ERR, "%s/%s: bind: %m",
649                     sep->se_service, sep->se_proto);
650                 (void) close(sep->se_fd);
651                 sep->se_fd = -1;
652                 if (!timingout) {
653                         timingout = 1;
654                         alarm(RETRYTIME);
655                 }
656                 return;
657         }
658         if (sep->se_socktype == SOCK_STREAM)
659                 listen(sep->se_fd, backlog);
660         FD_SET(sep->se_fd, &allsock);
661         nsock++;
662         if (sep->se_fd > maxsock)
663                 maxsock = sep->se_fd;
664 }
665
666 struct servtab *
667 enter(cp)
668         struct servtab *cp;
669 {
670         register struct servtab *sep;
671         sigset_t oset;
672
673         sep = (struct servtab *)malloc(sizeof (*sep));
674         if (sep == (struct servtab *)0) {
675                 syslog(LOG_ERR, "Out of memory.");
676                 exit(-1);
677         }
678         *sep = *cp;
679         sep->se_fd = -1;
680         sigprocmask(SIG_BLOCK, &sigBlock, &oset);
681         sep->se_next = servtab;
682         servtab = sep;
683         sigprocmask(SIG_SETMASK, &oset, (sigset_t *)0);
684         return (sep);
685 }
686
687 FILE    *fconfig = NULL;
688 struct  servtab serv;
689 char    line[256];
690 char    *skip(), *nextline();
691
692 setconfig()
693 {
694
695         if (fconfig != NULL) {
696                 fseek(fconfig, 0L, L_SET);
697                 return (1);
698         }
699         fconfig = fopen(CONFIG, "r");
700         return (fconfig != NULL);
701 }
702
703 endconfig()
704 {
705         if (fconfig) {
706                 (void) fclose(fconfig);
707                 fconfig = NULL;
708         }
709 }
710
711 struct servtab *
712 getconfigent()
713 {
714         register struct servtab *sep = &serv;
715         int argc;
716         char *cp, *arg, *copyofstr();
717
718 more:
719         /* modified to skip blank lines... */
720         while ((cp = nextline(fconfig)) && (*cp == '#' || (strlen(cp) < 2)))
721                 ;
722         if (cp == NULL)
723                 return ((struct servtab *)0);
724         sep->se_service = copyofstr(skip(&cp));
725         arg = skip(&cp);
726         if (strcmp(arg, "stream") == 0)
727                 sep->se_socktype = SOCK_STREAM;
728         else if (strcmp(arg, "dgram") == 0)
729                 sep->se_socktype = SOCK_DGRAM;
730         else if (strcmp(arg, "rdm") == 0)
731                 sep->se_socktype = SOCK_RDM;
732         else if (strcmp(arg, "seqpacket") == 0)
733                 sep->se_socktype = SOCK_SEQPACKET;
734         else if (strcmp(arg, "raw") == 0)
735                 sep->se_socktype = SOCK_RAW;
736         else
737                 sep->se_socktype = -1;
738         sep->se_proto = copyofstr(skip(&cp));
739         arg = skip(&cp);
740         sep->se_wait = strcmp(arg, "wait") == 0;
741         sep->se_user = copyofstr(skip(&cp));
742         sep->se_server = copyofstr(skip(&cp));
743         if (strcmp(sep->se_server, "internal") == 0) {
744                 register struct biltin *bi;
745
746                 for (bi = biltins; bi->bi_service; bi++)
747                         if (bi->bi_socktype == sep->se_socktype &&
748                             strcmp(bi->bi_service, sep->se_service) == 0)
749                                 break;
750                 if (bi->bi_service == 0) {
751                         syslog(LOG_ERR, "internal service %s unknown\n",
752                                 sep->se_service);
753                         goto more;
754                 }
755                 sep->se_bi = bi;
756                 sep->se_wait = bi->bi_wait;
757         } else
758                 sep->se_bi = NULL;
759         argc = 0;
760         for (arg = skip(&cp); cp; arg = skip(&cp))
761                 if (argc < MAXARGV)
762                         sep->se_argv[argc++] = copyofstr(arg);
763         while (argc <= MAXARGV)
764                 sep->se_argv[argc++] = NULL;
765         return (sep);
766 }
767
768 freeconfig(cp)
769         register struct servtab *cp;
770 {
771         int i;
772
773         if (cp->se_service)
774                 free(cp->se_service);
775         if (cp->se_proto)
776                 free(cp->se_proto);
777         if (cp->se_user)
778                 free(cp->se_user);
779         if (cp->se_server)
780                 free(cp->se_server);
781         for (i = 0; i < MAXARGV; i++)
782                 if (cp->se_argv[i])
783                         free(cp->se_argv[i]);
784 }
785
786 char *
787 skip(cpp)
788         char **cpp;
789 {
790         register char *cp = *cpp;
791         char *start;
792
793 again:
794         while (*cp == ' ' || *cp == '\t')
795                 cp++;
796         if (*cp == '\0') {
797                 char c;
798
799                 c = getc(fconfig);
800                 (void) ungetc(c, fconfig);
801                 if (c == ' ' || c == '\t')
802                         if (cp = nextline(fconfig))
803                                 goto again;
804                 *cpp = (char *)0;
805                 return ((char *)0);
806         }
807         start = cp;
808         while (*cp && *cp != ' ' && *cp != '\t')
809                 cp++;
810         if (*cp != '\0')
811                 *cp++ = '\0';
812         *cpp = cp;
813         return (start);
814 }
815
816 char *
817 nextline(fd)
818         FILE *fd;
819 {
820         char *cp;
821
822         if (fgets(line, sizeof (line), fd) == NULL)
823                 return ((char *)0);
824         cp = strchr(line, '\n');
825         if (cp)
826                 *cp = '\0';
827         return (line);
828 }
829
830 char *
831 copyofstr(cp)
832         const char *cp;
833 {
834         char *new;
835
836         if (cp == NULL)
837                 cp = "";
838         new = malloc((unsigned)(strlen(cp) + 1));
839         if (new == (char *)0) {
840                 syslog(LOG_ERR, "Out of memory.");
841                 exit(-1);
842         }
843         (void)strcpy(new, cp);
844         return (new);
845 }
846
847 setproctitle(a, s)
848         char *a;
849         int s;
850 {
851         int size;
852         register char *cp;
853         struct sockaddr_in sin;
854         char buf[80];
855
856         cp = Argv[0];
857         size = sizeof(sin);
858         if (getpeername(s, (struct sockaddr *) &sin, &size) == 0)
859                 (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 
860         else
861                 (void) sprintf(buf, "-%s", a); 
862         strncpy(cp, buf, LastArg - cp);
863         cp += strlen(cp);
864         while (cp < LastArg)
865                 *cp++ = ' ';
866 }
867
868 /*
869  * Internet services provided internally by inetd:
870  */
871
872 /* ARGSUSED */
873 echo_stream(s, sep)             /* Echo service -- echo data back */
874         int s;
875         struct servtab *sep;
876 {
877         char buffer[BUFSIZ];
878         int i;
879
880         setproctitle(sep->se_service, s);
881         while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
882             write(s, buffer, i) > 0)
883                 ;
884         exit(0);
885 }
886
887 /* ARGSUSED */
888 echo_dg(s, sep)                 /* Echo service -- echo data back */
889         int s;
890         struct servtab *sep;
891 {
892         char buffer[BUFSIZ];
893         int i, size;
894         struct sockaddr sa;
895
896         size = sizeof(sa);
897         if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
898                 return;
899         (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
900 }
901
902 /* ARGSUSED */
903 discard_stream(s, sep)          /* Discard service -- ignore data */
904         int s;
905         struct servtab *sep;
906 {
907         char buffer[BUFSIZ];
908
909         setproctitle(sep->se_service, s);
910         while (1) {
911                 while (read(s, buffer, sizeof(buffer)) > 0)
912                         ;
913                 if (errno != EINTR)
914                         break;
915         }
916         exit(0);
917 }
918
919 /* ARGSUSED */
920 discard_dg(s, sep)              /* Discard service -- ignore data */
921         int s;
922         struct servtab *sep;
923 {
924         char buffer[BUFSIZ];
925
926         (void) read(s, buffer, sizeof(buffer));
927 }
928
929 #define LINESIZ 72
930 char ring[128];
931 char *endring;
932
933 initring()
934 {
935         register int i;
936
937         endring = ring;
938
939         for (i = 0; i <= 128; ++i)
940                 if (isprint(i))
941                         *endring++ = i;
942 }
943
944 /* ARGSUSED */
945 chargen_stream(s, sep)          /* Character generator */
946         int s;
947         struct servtab *sep;
948 {
949         register char *rs;
950         int len;
951         char text[LINESIZ+2];
952
953         setproctitle(sep->se_service, s);
954
955         if (!endring) {
956                 initring();
957                 rs = ring;
958         }
959
960         text[LINESIZ] = '\r';
961         text[LINESIZ + 1] = '\n';
962         for (rs = ring;;) {
963                 if ((len = endring - rs) >= LINESIZ)
964                         memcpy(text, rs, LINESIZ);
965                 else {
966                         memcpy(text, rs, len);
967                         memcpy(text + len, ring, LINESIZ - len);
968                 }
969                 if (++rs == endring)
970                         rs = ring;
971                 if (write(s, text, sizeof(text)) != sizeof(text))
972                         break;
973         }
974         exit(0);
975 }
976
977 /* ARGSUSED */
978 chargen_dg(s, sep)              /* Character generator */
979         int s;
980         struct servtab *sep;
981 {
982         struct sockaddr sa;
983         static char *rs;
984         int len, size;
985         char text[LINESIZ+2];
986
987         if (endring == 0) {
988                 initring();
989                 rs = ring;
990         }
991
992         size = sizeof(sa);
993         if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
994                 return;
995
996         if ((len = endring - rs) >= LINESIZ)
997                 memcpy(text, rs, LINESIZ);
998         else {
999                 memcpy(text, rs, len);
1000                 memcpy(text + len, ring, LINESIZ - len);
1001         }
1002         if (++rs == endring)
1003                 rs = ring;
1004         text[LINESIZ] = '\r';
1005         text[LINESIZ + 1] = '\n';
1006         (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
1007 }
1008
1009 /*
1010  * Return a machine readable date and time, in the form of the
1011  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
1012  * returns the number of seconds since midnight, Jan 1, 1970,
1013  * we must add 2208988800 seconds to this figure to make up for
1014  * some seventy years Bell Labs was asleep.
1015  */
1016
1017 afs_int32
1018 machtime()
1019 {
1020         struct timeval tv;
1021
1022         if (gettimeofday(&tv, (struct timezone *)0) < 0) {
1023                 fprintf(stderr, "Unable to get time of day\n");
1024                 return (0L);
1025         }
1026         return (htonl((afs_int32)tv.tv_sec + 2208988800U));
1027 }
1028
1029 /* ARGSUSED */
1030 machtime_stream(s, sep)
1031         int s;
1032         struct servtab *sep;
1033 {
1034         afs_int32 result;
1035
1036         result = machtime();
1037         (void) write(s, (char *) &result, sizeof(result));
1038 }
1039
1040 /* ARGSUSED */
1041 machtime_dg(s, sep)
1042         int s;
1043         struct servtab *sep;
1044 {
1045         afs_int32 result;
1046         struct sockaddr sa;
1047         int size;
1048
1049         size = sizeof(sa);
1050         if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
1051                 return;
1052         result = machtime();
1053         (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
1054 }
1055
1056 /* ARGSUSED */
1057 daytime_stream(s, sep)          /* Return human-readable time of day */
1058         int s;
1059         struct servtab *sep;
1060 {
1061         char buffer[256];
1062         time_t clock;
1063
1064         clock = time((time_t *) 0);
1065
1066         (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1067         (void) write(s, buffer, strlen(buffer));
1068 }
1069
1070 /* ARGSUSED */
1071 daytime_dg(s, sep)              /* Return human-readable time of day */
1072         int s;
1073         struct servtab *sep;
1074 {
1075         char buffer[256];
1076         time_t clock;
1077         struct sockaddr sa;
1078         int size;
1079
1080         clock = time((time_t *) 0);
1081
1082         size = sizeof(sa);
1083         if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
1084                 return;
1085         (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1086         (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
1087 }
1088
1089 /*
1090  * print_service:
1091  *      Dump relevant information to stderr
1092  */
1093 print_service(action, sep)
1094         char *action;
1095         struct servtab *sep;
1096 {
1097         fprintf(stderr,
1098             "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
1099             action, sep->se_service, sep->se_proto,
1100             sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server);
1101 }
1102 /*
1103  * (C) Copyright 1989 Transarc Corporation.  All Rights Reserved.
1104  */
1105
1106 /*
1107  * This program is a front-end for the various remote access programs
1108  * (e.g. rsh, rcp, rlogin, ftp) to allow for weak remote authentication.
1109  * It will be used by a call to a well-known restricted tcp port;  if
1110  * there is a service on that port, we will attempt authentication.
1111  *
1112  * Note, this only affects the Kerberos portion of the authentication;
1113  * the program still requires its existing authentication (although it
1114  * seems reasonable to change this in the future.)
1115  *
1116  * The advantage to this scheme (rather than modifying each program to
1117  * incorporate this authentication scheme) is it allows us to modify
1118  * the authentication mechanism without requiring additonal code
1119  * changes to the other programs.
1120  *
1121  * Current format of authentication packet:
1122  *
1123  *   (1) User;
1124  *   (2) Service;
1125  *   (3) Token length (null terminated);
1126  *   (4) Token (not null terminated).
1127  *
1128  * The code to add/delete to the AFS ticket cache is taken from the
1129  * authentication library.
1130  */
1131
1132 /*
1133  * routine to do the actual authentication.  At this time, it is
1134  * very simple -- the remote end passes a token length and a token.
1135  *
1136  * This routine returns the name of the requested service.
1137  */
1138
1139 #define gettime(tl) do { struct timezone tzp; struct timeval tv; \
1140                          gettimeofday(&tv,&tzp); tl = tv.tv_sec; } while(0)
1141 #define RAUTH_TOKENLIFE (60 * 60 * 2) /* 2 hours */
1142
1143 #define NOPAG   0xffffffff
1144 int get_pag_from_groups(g0, g1)
1145 afs_uint32 g0, g1;
1146 {
1147         afs_uint32 h, l, result;
1148
1149         g0 -= 0x3f00;
1150         g1 -= 0x3f00;
1151         if (g0 < 0xc000 && g1 < 0xc000) {
1152                 l = ((g0 & 0x3fff) << 14) | (g1 & 0x3fff);
1153                 h = (g0 >> 14);
1154                 h = (g1 >> 14) + h + h + h;
1155                 result =  ((h << 28) | l);
1156                 /* Additional testing */        
1157                 if (((result >> 24) & 0xff) == 'A')
1158                         return result;
1159                 else
1160                         return NOPAG;
1161         }
1162         return NOPAG;
1163 }
1164
1165 auth_stream(s, sepent)
1166    int s;
1167    struct servtab *sepent;
1168   {
1169     char service[100], remoteName[64];
1170     struct sockaddr_in from;
1171     int fromlen;
1172     int code;
1173     struct afsconf_dir *tdir;
1174     struct ktc_principal tserver, tclient;
1175     struct ktc_token token;
1176     register struct servtab *sep;
1177
1178     /*
1179      * First, obtain information on remote end of connection.
1180      */
1181     if(debug)
1182         fprintf(stderr,"auth_stream: entered\n");
1183 #ifndef AFS_SUN5_ENV
1184     if (getpeername(s, &from, &fromlen) < 0) {
1185         syslog(LOG_ERR, "getpeername failed");
1186         if(debug)
1187             fprintf(stderr,"auth_stream: getpeername failed\n");
1188         exit(1);
1189       }
1190 #endif
1191     if(intoken(s,&token,service,remoteName) != 0) {
1192         syslog(LOG_ERR,"invalid remote authentication");
1193         if(debug)
1194             fprintf(stderr,"auth_stream: invalid remote authentication\n");
1195         exit(1);
1196       }
1197     /* lookup the name of the local cell */
1198
1199     if(debug)
1200         fprintf(stderr,"auth_stream: look up local cell name\n");
1201
1202     tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
1203     if (!tdir) {
1204         syslog(LOG_NOTICE, "Can't open dir %s\n", AFSDIR_CLIENT_ETC_DIRPATH);
1205         if(debug)
1206             fprintf(stderr,"Can't open dir %s\n", AFSDIR_CLIENT_ETC_DIRPATH);
1207         exit(1);
1208       }
1209     /* done with configuration stuff now */
1210     afsconf_Close(tdir);
1211     /* set ticket in local cell */
1212     strcpy(tserver.cell, remoteName);
1213     strcpy(tserver.name, "afs");
1214     tclient = tserver;
1215     /* now, set the token */
1216
1217     if(debug) {
1218         fprintf(stderr,
1219                 "token information: service is %s\ntoken length is %d\n",
1220                 service, token. ticketLen);
1221         fprintf(stderr,"token is %s\n",token.ticket);
1222         fprintf(stderr,"cell name is %s\n",remoteName);
1223       }
1224     setpag();
1225     afs_didsetpag = 1;
1226     code = ktc_SetToken(&tserver, &token, &tclient, 0);
1227     if (code) {
1228         write(s,"0",1); /* say "no" to other side */
1229         printf("Login incorrect.(%d)", code);
1230         syslog(LOG_ERR, "Invalid token from %s",
1231                inet_ntoa(from.sin_addr));
1232         exit(1);
1233       }
1234     write(s, "1", 1); /* say "yes" to other side */
1235     
1236     if(debug)
1237         fprintf(stderr,"Finished authentication code\n");
1238     for (sep = servtab; sep; sep = sep->se_next)
1239         if(strcmp(sep->se_service,service) == 0) {
1240             int dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
1241             int tmpint;
1242
1243             if(dofork) {
1244                 for(tmpint = getdtablesize(); --tmpint > 2; )
1245                     if(tmpint != s)
1246                         close(tmpint);
1247             }
1248             if(sep->se_bi) {
1249                 (*sep->se_bi->bi_fn)(s, sep);
1250             } else {
1251                 register struct passwd *pwd;
1252                 struct passwd *getpwnam();
1253                 char buf[BUFSIZ];
1254                     
1255                 if ((pwd = getpwnam(sep->se_user)) == NULL) {
1256                     syslog(LOG_ERR,
1257                            "getpwnam: %s: No such user",
1258                            sep->se_user);
1259                     if (sep->se_socktype != SOCK_STREAM)
1260                         recv(0, buf, sizeof (buf), 0);
1261                     abort();
1262                     _exit(1);
1263                   }
1264                 if (pwd->pw_uid) {
1265                     (void) setgid((gid_t)pwd->pw_gid);
1266                     initgroups(pwd->pw_name, pwd->pw_gid);
1267                     (void) setuid((uid_t)pwd->pw_uid);
1268                   }
1269                 dup2(s,0);
1270                 close(s);
1271                 dup2(0,1);
1272                 if(debug)
1273                     fprintf(stderr,"going to exec program %s(errno = %d)\n",
1274                             sep->se_server,errno);
1275                 errno = 0;
1276                 debug = 0;
1277                 dup2(0,2);
1278
1279                 if (!afs_didsetpag && (!strcmp(sep->se_service, "login") || 
1280                                        !strcmp(sep->se_service, "shell"))) {
1281                     setpag(); /* to disassociate it from current group... */
1282                 }
1283                 execv(sep->se_server, sep->se_argv);
1284                 abort();
1285                 if (sep->se_socktype != SOCK_STREAM)
1286                     recv(0, buf, sizeof (buf), 0);
1287                 syslog(LOG_ERR, "execv %s: %m", sep->se_server);
1288                 _exit(1);
1289               }
1290         }
1291     fprintf(stderr,"service not available\n");
1292     syslog(LOG_ERR, "auth_stream: invalid service requested %s\n",service);
1293     exit(0);
1294   }
1295  
1296    
1297 auth_dg()
1298   {
1299     syslog(LOG_NOTICE,
1300            "datagram remote authentication requested, not supported"); 
1301   }
1302    
1303 /*
1304  * intoken:
1305  *
1306  * This routine accepts a token on the specified file handle;
1307  * The input format for a token is:
1308  *
1309  *   Field #    Contents         description
1310  *    (0)       Service Name     char[]
1311  *    (1)       Version #        unsigned integer (< 2^32)
1312  *    (2)       cellName         char[]
1313  *    (3)       startTime        unsigned afs_int32 (< 2^32)
1314  *    (4)       endTime          unsigned afs_int32 (< 2^32)
1315  *    (5)       sessionKey       char[8]
1316  *    (6)       kvno             short (< 2^16)
1317  *    (7)       ticketLen        unsigned integer (< 2^32)
1318  *    (8)       ticket           char[MAXKTCTICKETLEN]
1319  *
1320  * Each field is comma separated;  the last is variable length.  The
1321  * converted token is placed into the token structure pointed to by
1322  * the variable "token".
1323  */  
1324
1325 intoken(s,token,svc, cell)
1326    int s;
1327    struct ktc_token *token;
1328    char *svc, *cell;
1329   {
1330     char buf[1024], *bp;
1331     int count;
1332     unsigned index, version;
1333
1334     if(debug)
1335         fprintf(stderr,"intoken: entered\n");
1336
1337     if((count = recv(s,buf,sizeof buf,0)) == -1) {
1338         if(debug) {
1339             fprintf(stderr,"error on fd %d\n",s);
1340             perror("intoken recv");
1341           }
1342         return(-1);
1343       }
1344
1345     /* (0) Service Name */
1346     for(index = 0; index < count && buf[index] != ','; index++)
1347         ;
1348
1349     if (index == count) {
1350         if(debug)
1351             fprintf(stderr,"overran buffer while searching for svc name\n");
1352         return(-1);
1353       }
1354
1355     if (buf[index] != ',') {
1356         if(debug)
1357             fprintf(stderr,"Didn't stop on a comma, searching for svc name\n");
1358         return(-1);
1359       }
1360
1361     buf[index] = '\0';
1362
1363     strcpy(svc, buf);
1364     
1365     /* (1) Version # */
1366
1367     bp = buf + index + 1;
1368
1369     for(; index < count && buf[index] != ','; index++)
1370         ;
1371
1372     if (index == count) {
1373         if(debug)
1374             fprintf(stderr,"overran buffer while searching for version #\n");
1375         return(-1);
1376       }
1377
1378     if (buf[index] != ',') {
1379         if(debug)
1380             fprintf(stderr,
1381                     "Didn't stop on a comma, searching for version #\n");
1382         return(-1);
1383       }
1384
1385     buf[index] = '\0';
1386     
1387     sscanf(bp, "%u", &version);
1388
1389     if(version > 2) {
1390         if(debug)
1391             fprintf(stderr,"Incompatible (newer) version encountered: %d\n",
1392                     version);
1393         return(-1);
1394       }
1395
1396     if(version > 1) {
1397         /* we didn't include cell name in prior versions */
1398         bp = buf + index + 1;
1399         
1400         for(index = 0; index < count && buf[index] != ','; index++)
1401             ;
1402         
1403         if (index == count) {
1404             if(debug)
1405                 fprintf(stderr,"overran buffer while searching for cell\n");
1406             return(-1);
1407         }
1408         
1409         if (buf[index] != ',') {
1410             if(debug)
1411                 fprintf(stderr,"Didn't stop on a comma, searching for cell\n");
1412             return(-1);
1413         }
1414         buf[index] = '\0';
1415         strcpy(cell, bp);
1416     }
1417
1418     /* (2) startTime */
1419     
1420     bp = buf + index + 1;
1421
1422     for(; index < count && buf[index] != ','; index++)
1423         ;
1424
1425     if (index == count) {
1426         if(debug)
1427             fprintf(stderr,
1428                     "overran buffer while searching for startTime #\n");
1429         exit(1);
1430       }
1431
1432     if (buf[index] != ',') {
1433         if(debug)
1434             fprintf(stderr,
1435                     "Didn't stop on a comma, searching for startTime #\n");
1436         return(-1);
1437       }
1438
1439     buf[index] = '\0';
1440     
1441     sscanf(bp, "%u", &token->startTime);
1442     
1443     /* (3) endTime */
1444     
1445     bp = buf + index + 1;
1446
1447     for(; index < count && buf[index] != ','; index++)
1448         ;
1449
1450     if (index == count) {
1451         if(debug)
1452             fprintf(stderr,
1453                     "overran buffer while searching for endTime #\n");
1454         return(-1);
1455       }
1456
1457     if (buf[index] != ',') {
1458         if(debug)
1459             fprintf(stderr,
1460                     "Didn't stop on a comma, searching for endTime #\n");
1461         return(-1);
1462       }
1463
1464     buf[index] = '\0';
1465     
1466     sscanf(bp, "%u", &token->endTime);
1467     
1468     /* (4) sessionKey */
1469
1470     bp = buf + index + 1;
1471     memcpy(&token->sessionKey, bp, 8);
1472     
1473     /* (5) kvno */
1474     
1475     bp += 8;
1476     for(index += 9; index < count && buf[index] != ','; index++)
1477         ;
1478
1479     if (index == count) {
1480         if(debug)
1481             fprintf(stderr,"overran buffer while searching for kvno\n");
1482         return(-1);
1483       }
1484
1485     if (buf[index] != ',') {
1486         if(debug)
1487             fprintf(stderr,"Didn't stop on a comma, searching for kvno\n");
1488         return(-1);
1489       }
1490
1491     buf[index] = '\0';
1492     
1493     /* kvno is actually a short, so insist that it scan a short */
1494     
1495     sscanf(bp, "%hu", &token->kvno);
1496
1497     /* (6) ticketLen */
1498     
1499     bp = buf + index + 1;
1500     
1501     for(; index < count && buf[index] != ','; index++)
1502         ;
1503
1504     if (index == count) {
1505         if(debug)
1506             fprintf(stderr,"overran buffer while searching for ticketLen\n");
1507         return(-1);
1508       }
1509
1510     if (buf[index] != ',') {
1511         if(debug)
1512             fprintf(stderr,
1513                     "Didn't stop on a comma, searching for ticketLen\n");
1514         return(-1);
1515       }
1516
1517     buf[index] = '\0';
1518
1519     sscanf(bp, "%u", &token->ticketLen);
1520     
1521     /* (7) ticketLen */
1522     
1523     bp = buf + index + 1;
1524
1525     if(index + token->ticketLen > count) {
1526         if(debug)
1527             fprintf(stderr,"overran buffer while copying ticket\n");
1528         return(-1);
1529       }
1530
1531     memcpy(token->ticket, bp, token->ticketLen);
1532
1533     return 0;
1534   }
1535
1536 #ifdef  AFS_HPUX_ENV
1537 resetsignals()
1538
1539     struct sigaction act, oact;
1540     int sign;
1541
1542     memset(&act, '\0', sizeof(act));
1543     act.sa_handler = SIG_DFL;
1544     for (sign = 1; sign < NSIG; sign++)
1545         sigaction(sign, &act, &oact);
1546 }
1547 #endif
1548