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