auth: Add documentation for ktc_ListTokensEx
[openafs.git] / src / auth / ktc.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /* ticket caching code */
11
12 #include <afsconfig.h>
13 #include <afs/param.h>
14
15 #if defined(UKERNEL)
16 #include "afsincludes.h"
17 #endif
18
19 #ifdef  AFS_SUN5_ENV
20 #include <unistd.h>
21 #endif
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <afs/stds.h>
25 #include <afs/pthread_glock.h>
26 #include <sys/types.h>
27 #include <ctype.h>
28 #include <sys/stat.h>
29 #include <signal.h>
30 #include <errno.h>
31 #include <sys/ioctl.h>
32 #include <netinet/in.h>
33 #include <string.h>
34 #include <afs/vice.h>
35 #ifdef  AFS_AIX_ENV
36 #include <sys/lockf.h>
37 #ifdef AFS_AIX51_ENV
38 #include <sys/cred.h>
39 #ifdef HAVE_SYS_PAG_H
40 #include <sys/pag.h>
41 #endif
42 #endif
43 #endif
44 #ifdef HAVE_CRT_EXTERNS_H
45 #include <crt_externs.h>
46 #endif
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50 #include <afs/auth.h>
51 #include <afs/venus.h>
52 #include <afs/afsutil.h>
53
54 #if !defined(UKERNEL)
55 #include <afs/sys_prototypes.h>
56 #endif
57
58 #include "token.h"
59
60 #if defined(LINUX_KEYRING_SUPPORT) && defined(HAVE_SESSION_TO_PARENT)
61 #include <sys/syscall.h>
62 #define KEYCTL_SESSION_TO_PARENT        18
63 #endif
64
65 /* For malloc() */
66 #include <stdlib.h>
67 #include "ktc.h"
68
69 #ifdef  notdef
70 /* AFS_KERBEROS_ENV is now conditionally defined in the Makefile */
71 #define AFS_KERBEROS_ENV
72 #endif
73
74 #ifdef AFS_KERBEROS_ENV
75 #include <fcntl.h>
76 #include <sys/file.h>
77 #include <afs/cellconfig.h>
78 static char lcell[MAXCELLCHARS];
79
80 #define TKT_ROOT "/tmp/tkt"
81
82 #define KSUCCESS 0
83 #define KFAILURE 255
84
85 /* Definitions for ticket file utilities */
86 #define R_TKT_FIL       0
87 #define W_TKT_FIL       1
88
89 /* Error codes returned by ticket file utilities */
90 #define         NO_TKT_FIL      76      /* No ticket file found */
91 #define         TKT_FIL_ACC     77      /* Couldn't access tkt file */
92 #define         TKT_FIL_LCK     78      /* Couldn't lock ticket file */
93 #define         TKT_FIL_FMT     79      /* Bad ticket file format */
94 #define         TKT_FIL_INI     80      /* afs_tf_init not called first */
95
96 /* Values returned by get_credentials */
97 #define         RET_TKFIL      21       /* Can't read ticket file */
98
99 #ifndef BUFSIZ
100 #define BUFSIZ 4096
101 #endif
102
103 #ifdef  AFS_HPUX_ENV
104 #include <unistd.h>
105 #endif
106 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV)
107 static struct flock fileWlock = { F_WRLCK, 0, 0, 0, 0, 0 };
108 static struct flock fileRlock = { F_RDLCK, 0, 0, 0, 0, 0 };
109 static struct flock fileUlock = { F_UNLCK, 0, 0, 0, 0, 0 };
110 #endif
111 #ifdef AFS_HPUX_ENV
112 static struct flock fileWlock = { F_WRLCK, 0, 0, 0, 0 };
113 static struct flock fileRlock = { F_RDLCK, 0, 0, 0, 0 };
114 static struct flock fileUlock = { F_UNLCK, 0, 0, 0, 0 };
115 #endif
116
117 #ifndef EOF
118 #define EOF (-1)
119 #endif
120
121 /* the following routines aren't static anymore on behalf of the kerberos IV
122  * compatibility library built in subtree krb.
123  */
124 int afs_tf_init(char *, int);
125 int afs_tf_get_pname(char *);
126 int afs_tf_get_pinst(char *);
127 int afs_tf_get_cred(struct ktc_principal *, struct ktc_token *);
128 int afs_tf_save_cred(struct ktc_principal *, struct ktc_token *,
129                      struct ktc_principal *);
130 int afs_tf_close(void);
131 int afs_tf_create(char *, char *);
132 int afs_tf_dest_tkt(void);
133 static void ktc_LocalCell(void);
134 #endif /* AFS_KERBEROS_ENV */
135
136 #ifdef AFS_DUX40_ENV
137 #define PIOCTL afs_pioctl
138 #elif defined(UKERNEL)
139 #define PIOCTL(A,B,C,D) call_syscall(AFSCALL_PIOCTL,A,B,C,D)
140 #else
141 #define PIOCTL pioctl
142 #endif
143
144 #if !defined(UKERNEL)
145 /* this is a structure used to communicate with the afs cache mgr, but is
146  * otherwise irrelevant */
147 struct ClearToken {
148     afs_int32 AuthHandle;
149     char HandShakeKey[8];
150     afs_int32 ViceId;
151     afs_int32 BeginTimestamp;
152     afs_int32 EndTimestamp;
153 };
154 #endif /* !defined(UKERNEL) */
155
156 #define MAXLOCALTOKENS 4
157
158 static struct {
159     int valid;
160     struct ktc_principal server;
161     struct ktc_principal client;
162     struct ktc_token token;
163 } local_tokens[MAXLOCALTOKENS] = { {
164 0}, {
165 0}, {
166 0}, {
167 0}};
168
169
170 #define MAXPIOCTLTOKENLEN \
171 (3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
172
173 static int
174 SetToken(struct ktc_principal *aserver, struct ktc_token *atoken,
175             struct ktc_principal *aclient, afs_int32 flags)
176 {
177     struct ViceIoctl iob;
178     char tbuffer[MAXPIOCTLTOKENLEN];
179     char *tp;
180     struct ClearToken ct;
181     afs_int32 code;
182     afs_int32 temp;
183
184     if (strcmp(aserver->name, "afs") != 0) {
185         int found = -1;
186         int i;
187         for (i = 0; i < MAXLOCALTOKENS; i++)
188             if (local_tokens[i].valid) {
189                 if ((strcmp(local_tokens[i].server.name, aserver->name) == 0)
190                     &&
191                     (strcmp
192                      (local_tokens[i].server.instance,
193                       aserver->instance) == 0)
194                     && (strcmp(local_tokens[i].server.cell, aserver->cell) ==
195                         0)) {
196                     found = i;  /* replace existing entry */
197                     break;
198                 } else          /* valid, but no match */
199                     ;
200             } else
201                 found = i;      /* remember this empty slot */
202         if (found == -1)
203             return KTC_NOENT;
204         memcpy(&local_tokens[found].token, atoken, sizeof(struct ktc_token));
205         local_tokens[found].server = *aserver;
206         local_tokens[found].client = *aclient;
207         local_tokens[found].valid = 1;
208         return 0;
209     }
210     tp = tbuffer;               /* start copying here */
211     if ((atoken->ticketLen < MINKTCTICKETLEN)
212         || (atoken->ticketLen > MAXKTCTICKETLEN))
213         return KTC_TOOBIG;
214     memcpy(tp, &atoken->ticketLen, sizeof(afs_int32));  /* copy in ticket length */
215     tp += sizeof(afs_int32);
216     memcpy(tp, atoken->ticket, atoken->ticketLen);      /* copy in ticket */
217     tp += atoken->ticketLen;
218     /* next, copy in the "clear token", describing who we are */
219     ct.AuthHandle = atoken->kvno;       /* hide auth handle here */
220     memcpy(ct.HandShakeKey, &atoken->sessionKey, 8);
221
222     ct.BeginTimestamp = atoken->startTime;
223     ct.EndTimestamp = atoken->endTime;
224     if (ct.BeginTimestamp == 0)
225         ct.BeginTimestamp = 1;
226
227     if ((strlen(aclient->name) > strlen("AFS ID "))
228         && (aclient->instance[0] == 0)) {
229         int sign = 1;
230         afs_int32 viceId = 0;
231         char *cp = aclient->name + strlen("AFS ID ");
232         if (*cp == '-') {
233             sign = -1;
234             cp++;
235         }
236         while (*cp) {
237             if (isdigit(*cp))
238                 viceId = viceId * 10 + (int)(*cp - '0');
239             else
240                 goto not_vice_id;
241             cp++;
242         }
243         ct.ViceId = viceId * sign;      /* OK to let any value here? */
244         if (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 0)
245             ct.BeginTimestamp++;        /* force lifetime to be odd */
246     } else {
247       not_vice_id:
248         ct.ViceId = getuid();   /* wrong, but works in primary cell */
249         if (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1)
250             ct.BeginTimestamp++;        /* force lifetime to be even */
251     }
252
253 #ifdef UKERNEL
254     /*
255      * Information needed by the user space cache manager
256      */
257     get_user_struct()->u_expiration = ct.EndTimestamp;
258     get_user_struct()->u_viceid = ct.ViceId;
259 #endif
260
261     temp = sizeof(struct ClearToken);
262     memcpy(tp, &temp, sizeof(afs_int32));
263     tp += sizeof(afs_int32);
264     memcpy(tp, &ct, sizeof(struct ClearToken));
265     tp += sizeof(struct ClearToken);
266
267     /* next copy in primary flag */
268     temp = 0;
269
270     /*
271      * The following means that setpag will happen inside afs just before
272      * the authentication to prevent the setpag/klog race condition.
273      *
274      * The following means that setpag will affect the parent process as
275      * well as the current process.
276      */
277     if (flags & AFS_SETTOK_SETPAG)
278         temp |= 0x8000;
279
280     memcpy(tp, &temp, sizeof(afs_int32));
281     tp += sizeof(afs_int32);
282
283     /* finally copy in the cell name */
284     temp = strlen(aserver->cell);
285     if (temp >= MAXKTCREALMLEN)
286         return KTC_TOOBIG;
287     strcpy(tp, aserver->cell);
288     tp += temp + 1;
289
290     /* now setup for the pioctl */
291     iob.in = tbuffer;
292     iob.in_size = tp - tbuffer;
293     iob.out = tbuffer;
294     iob.out_size = sizeof(tbuffer);
295
296 #if defined(NO_AFS_CLIENT)
297     {
298         int fd;                 /* DEBUG */
299         char *tkfile;
300         if ((tkfile = getenv("TKTFILE"))
301             &&
302             ((fd =
303               open(tkfile, O_WRONLY | O_APPEND | O_TRUNC | O_CREAT,
304                    0644)) >= 0)) {
305             printf("Writing ticket to: %s\n", tkfile);
306             code = (write(fd, iob.in, iob.in_size) != iob.in_size);
307             close(fd);
308         } else
309             code = KTC_PIOCTLFAIL;
310     }
311 #else /* NO_AFS_CLIENT */
312     code = PIOCTL(0, VIOCSETTOK, &iob, 0);
313 #if defined(LINUX_KEYRING_SUPPORT) && defined(HAVE_SESSION_TO_PARENT)
314     /*
315      * If we're using keyring based PAGs and the SESSION_TO_PARENT keyctl
316      * is available, use it to copy the session keyring to the parent process
317      */
318     if (flags & AFS_SETTOK_SETPAG)
319         syscall(SYS_keyctl, KEYCTL_SESSION_TO_PARENT);
320 #endif
321 #endif /* NO_AFS_CLIENT */
322     if (code)
323         return KTC_PIOCTLFAIL;
324     return 0;
325 }
326
327 int
328 ktc_SetTokenEx(struct ktc_setTokenData *token) {
329     struct ViceIoctl iob;
330     afs_int32 code;
331     XDR xdrs;
332
333     xdrlen_create(&xdrs);
334     if (!xdr_ktc_setTokenData(&xdrs, token))
335         return EINVAL;
336     iob.in_size = xdr_getpos(&xdrs);
337     xdr_destroy(&xdrs);
338
339     iob.in = malloc(iob.in_size);
340     if (iob.in == NULL)
341         return ENOMEM;
342
343     xdrmem_create(&xdrs, iob.in, iob.in_size, XDR_ENCODE);
344     if (!xdr_ktc_setTokenData(&xdrs, token))
345         return KTC_INVAL;
346     xdr_destroy(&xdrs);
347
348     iob.out = NULL;
349     iob.out_size = 0;
350
351     code = PIOCTL(0, VIOC_SETTOK2, &iob, 0);
352
353     free(iob.in);
354
355     /* If we can't use the new pioctl, then fallback to using the old
356      * one, with just the rxkad portion of the token we're being asked to
357      * set
358      */
359     if (code == -1 && errno == EINVAL) {
360         struct ktc_principal server, client;
361         struct ktc_token *rxkadToken;
362         afs_int32 flags;
363
364         /* With the growth of ticket sizes, a ktc_token is now 12k. Don't
365          * allocate it on the stack! */
366         rxkadToken = malloc(sizeof(*rxkadToken));
367         if (rxkadToken == NULL)
368             return ENOMEM;
369
370         code = token_extractRxkad(token, rxkadToken, &flags, &client);
371         if (code) {
372             free(rxkadToken);
373             return KTC_INVAL;
374         }
375
376         memset(&server, 0, sizeof(server));
377         strcpy(server.name, "afs");
378         strcpy(server.cell, token->cell);
379         code = ktc_SetToken(&server, rxkadToken, &client, flags);
380         free(rxkadToken);
381         return code;
382     }
383
384     if (code)
385         return KTC_PIOCTLFAIL;
386
387     return 0;
388 }
389
390 int
391 ktc_SetToken(struct ktc_principal *aserver,
392     struct ktc_token *atoken,
393     struct ktc_principal *aclient,
394     afs_int32 flags)
395 {
396     int code;
397
398     LOCK_GLOBAL_MUTEX;
399 #ifdef AFS_KERBEROS_ENV
400     if (!lcell[0])
401         ktc_LocalCell();
402
403     if (                        /*!strcmp(aclient->cell, lcell) && this would only store local creds */
404            (strcmp(aserver->name, "AuthServer")
405             || strcmp(aserver->instance, "Admin"))) {
406         if (strcmp(aserver->name, "krbtgt") == 0) {
407             static char lrealm[MAXKTCREALMLEN];
408
409             if (!lrealm[0])
410                 ucstring(lrealm, lcell, MAXKTCREALMLEN);
411             if (strcmp(aserver->instance, lrealm) == 0) {
412                 afs_tf_create(aclient->name, aclient->instance);
413             }
414         }
415
416         code = afs_tf_init(ktc_tkt_string(), W_TKT_FIL);
417         if (code == NO_TKT_FIL) {
418             (void)afs_tf_create(aclient->name, aclient->instance);
419             code = afs_tf_init(ktc_tkt_string(), W_TKT_FIL);
420         }
421
422         if (!code) {
423             afs_tf_save_cred(aserver, atoken, aclient);
424         }
425         afs_tf_close();
426 #ifdef NO_AFS_CLIENT
427         UNLOCK_GLOBAL_MUTEX;
428         return code;
429 #endif /* NO_AFS_CLIENT */
430     }
431 #endif
432
433 #ifndef NO_AFS_CLIENT
434     code = SetToken(aserver, atoken, aclient, flags);
435     if (code) {
436         UNLOCK_GLOBAL_MUTEX;
437         if (code == -1)
438             code = errno;
439         else if (code == KTC_PIOCTLFAIL)
440             code = errno;
441         if (code == ESRCH)
442             return KTC_NOCELL;
443         if (code == EINVAL)
444             return KTC_NOPIOCTL;
445         if (code == EIO)
446             return KTC_NOCM;
447         return KTC_PIOCTLFAIL;
448     }
449 #endif /* NO_AFS_CLIENT */
450     UNLOCK_GLOBAL_MUTEX;
451     return 0;
452 }
453
454 /*!
455  * Get a token, given the cell that we need to get information for
456  *
457  * @param cellName
458  *      The name of the cell we're getting the token for - if NULL, we'll
459  *      get information for the primary cell
460  */
461 int
462 ktc_GetTokenEx(char *cellName, struct ktc_setTokenData **tokenSet) {
463     struct ViceIoctl iob;
464     char tbuffer[MAXPIOCTLTOKENLEN];
465     char *tp;
466     afs_int32 code;
467     XDR xdrs;
468
469     tp = tbuffer;
470
471     /* If we have a cellName, write it out here */
472     if (cellName) {
473         memcpy(tp, cellName, strlen(cellName) +1);
474         tp += strlen(cellName)+1;
475     }
476
477     iob.in = tbuffer;
478     iob.in_size = tp - tbuffer;
479     iob.out = tbuffer;
480     iob.out_size = sizeof(tbuffer);
481
482     code = PIOCTL(0, VIOC_GETTOK2, &iob, 0);
483
484     /* If we can't use the new pioctl, the fall back to the old one. We then
485      * need to convert the rxkad token we get back into the new format
486      */
487     if (code == -1 && errno == EINVAL) {
488         struct ktc_principal server;
489         struct ktc_principal client;
490         struct ktc_tokenUnion token;
491         struct ktc_token *ktcToken; /* too huge for the stack */
492
493         memset(&server, 0, sizeof(server));
494         ktcToken = malloc(sizeof(struct ktc_token));
495         if (ktcToken == NULL)
496             return ENOMEM;
497         memset(ktcToken, 0, sizeof(struct ktc_token));
498
499         strcpy(server.name, "afs");
500         strcpy(server.cell, cellName);
501         code = ktc_GetToken(&server, ktcToken, sizeof(struct ktc_token),
502                             &client);
503         if (code == 0) {
504             *tokenSet = token_buildTokenJar(cellName);
505             token.at_type = AFSTOKEN_UNION_KAD;
506             token.ktc_tokenUnion_u.at_kad.rk_kvno = ktcToken->kvno;
507             memcpy(token.ktc_tokenUnion_u.at_kad.rk_key,
508                    ktcToken->sessionKey.data, 8);
509
510             token.ktc_tokenUnion_u.at_kad.rk_begintime = ktcToken->startTime;
511             token.ktc_tokenUnion_u.at_kad.rk_endtime   = ktcToken->endTime;
512             token.ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_len
513                 = ktcToken->ticketLen;
514             token.ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_val
515                 = ktcToken->ticket;
516
517             token_addToken(*tokenSet, &token);
518
519             memset(ktcToken, 0, sizeof(struct ktc_token));
520         }
521         free(ktcToken);
522     }
523     if (code)
524         return KTC_PIOCTLFAIL;
525
526     *tokenSet = malloc(sizeof(struct ktc_setTokenData));
527     if (*tokenSet == NULL)
528         return ENOMEM;
529     memset(*tokenSet, 0, sizeof(struct ktc_setTokenData));
530
531     xdrmem_create(&xdrs, iob.out, iob.out_size, XDR_DECODE);
532     if (!xdr_ktc_setTokenData(&xdrs, *tokenSet)) {
533         free(*tokenSet);
534         *tokenSet = NULL;
535         xdr_destroy(&xdrs);
536         return EINVAL;
537     }
538     xdr_destroy(&xdrs);
539     return 0;
540 }
541
542 /* get token, given server we need and token buffer.  aclient will eventually
543  * be set to our identity to the server.
544  */
545 int
546 ktc_GetToken(struct ktc_principal *aserver, struct ktc_token *atoken,
547              int atokenLen, struct ktc_principal *aclient)
548 {
549     struct ViceIoctl iob;
550     char tbuffer[MAXPIOCTLTOKENLEN];
551     afs_int32 code = 0;
552     int index;
553     char *stp, *cellp;          /* secret token ptr */
554     struct ClearToken ct;
555     char *tp;
556     afs_int32 temp;
557     int maxLen;                 /* biggest ticket we can copy */
558     int tktLen;                 /* server ticket length */
559 #ifdef AFS_KERBEROS_ENV
560     char found = 0;
561 #endif
562
563     LOCK_GLOBAL_MUTEX;
564
565 #ifdef AFS_KERBEROS_ENV
566     if (!lcell[0])
567         ktc_LocalCell();
568 #endif
569 #ifndef NO_AFS_CLIENT
570     if (strcmp(aserver->name, "afs") != 0)
571 #endif /* NO_AFS_CLIENT */
572     {
573         int i;
574         /* try the local tokens */
575         for (i = 0; i < MAXLOCALTOKENS; i++)
576             if (local_tokens[i].valid
577                 && (strcmp(local_tokens[i].server.name, aserver->name) == 0)
578                 && (strcmp(local_tokens[i].server.instance, aserver->instance)
579                     == 0)
580                 && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
581                 memcpy(atoken, &local_tokens[i].token,
582                        min(atokenLen, sizeof(struct ktc_token)));
583                 if (aclient)
584                     *aclient = local_tokens[i].client;
585                 UNLOCK_GLOBAL_MUTEX;
586                 return 0;
587             }
588 #ifdef AFS_KERBEROS_ENV
589         if (!afs_tf_init(ktc_tkt_string(), R_TKT_FIL)) {
590             if (aclient) {
591                 if (!afs_tf_get_pname(aclient->name)
592                     && !afs_tf_get_pinst(aclient->instance))
593                     found = 1;
594             } else {
595                 char tmpstring[MAXHOSTCHARS];
596                 afs_tf_get_pname(tmpstring);
597                 afs_tf_get_pinst(tmpstring);
598                 found = 1;
599             }
600         }
601         if (found) {
602             struct ktc_principal cprincipal;
603             struct ktc_token ctoken;
604
605             while (!afs_tf_get_cred(&cprincipal, &ctoken)) {
606                 if (strcmp(cprincipal.name, aserver->name) == 0
607                     && strcmp(cprincipal.instance, aserver->instance) == 0
608                     && strcmp(cprincipal.cell, aserver->cell) == 0) {
609
610                     if (aclient)
611                         strcpy(aclient->cell, lcell);
612                     memcpy(atoken, &ctoken,
613                            min(atokenLen, sizeof(struct ktc_token)));
614
615                     afs_tf_close();
616                     UNLOCK_GLOBAL_MUTEX;
617                     return 0;
618                 }
619             }
620         }
621         afs_tf_close();
622 #endif
623         UNLOCK_GLOBAL_MUTEX;
624         return KTC_NOENT;
625     }
626 #ifndef NO_AFS_CLIENT
627     for (index = 0; index < 200; index++) {     /* sanity check in case pioctl fails */
628         iob.in = (char *)&index;
629         iob.in_size = sizeof(afs_int32);
630         iob.out = tbuffer;
631         iob.out_size = sizeof(tbuffer);
632
633         code = PIOCTL(0, VIOCGETTOK, &iob, 0);
634
635         if (code) {
636             /* failed to retrieve specified token */
637             if (code < 0 && errno == EDOM) {
638                 UNLOCK_GLOBAL_MUTEX;
639                 return KTC_NOENT;
640             }
641         } else {
642             /* token retrieved; parse buffer */
643             tp = tbuffer;
644
645             /* get ticket length */
646             memcpy(&temp, tp, sizeof(afs_int32));
647             tktLen = temp;
648             tp += sizeof(afs_int32);
649
650             /* remember where ticket is and skip over it */
651             stp = tp;
652             tp += tktLen;
653
654             /* get size of clear token and verify */
655             memcpy(&temp, tp, sizeof(afs_int32));
656             if (temp != sizeof(struct ClearToken)) {
657                 UNLOCK_GLOBAL_MUTEX;
658                 return KTC_ERROR;
659             }
660             tp += sizeof(afs_int32);
661
662             /* copy clear token */
663             memcpy(&ct, tp, temp);
664             tp += temp;
665
666             /* skip over primary flag */
667             tp += sizeof(afs_int32);
668
669             /* remember where cell name is */
670             cellp = tp;
671
672             if ((strcmp(cellp, aserver->cell) == 0)
673 #ifdef  AFS_KERBEROS_ENV
674                 || (*aserver->cell == '\0' && strcmp(cellp, lcell) == 0)
675 #endif
676                 ) {
677                 /* got token for cell; check that it will fit */
678                 maxLen =
679                     atokenLen - sizeof(struct ktc_token) + MAXKTCTICKETLEN;
680                 if (maxLen < tktLen) {
681                     UNLOCK_GLOBAL_MUTEX;
682                     return KTC_TOOBIG;
683                 }
684
685                 /* set return values */
686                 memcpy(atoken->ticket, stp, tktLen);
687                 atoken->startTime = ct.BeginTimestamp;
688                 atoken->endTime = ct.EndTimestamp;
689                 if (ct.AuthHandle == -1) {
690                     ct.AuthHandle = 999;
691                 }
692                 atoken->kvno = ct.AuthHandle;
693                 memcpy(&atoken->sessionKey, ct.HandShakeKey,
694                        sizeof(struct ktc_encryptionKey));
695                 atoken->ticketLen = tktLen;
696
697                 if (aclient) {
698                     strcpy(aclient->cell, cellp);
699                     aclient->instance[0] = 0;
700
701                     if ((atoken->kvno == 999) ||        /* old style bcrypt ticket */
702                         (ct.BeginTimestamp &&   /* new w/ prserver lookup */
703                          (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1))) {
704                         sprintf(aclient->name, "AFS ID %d", ct.ViceId);
705                     } else {
706                         sprintf(aclient->name, "Unix UID %d", ct.ViceId);
707                     }
708                 }
709                 UNLOCK_GLOBAL_MUTEX;
710                 return 0;
711             }
712         }
713     }
714 #endif /* NO_AFS_CLIENT */
715
716     UNLOCK_GLOBAL_MUTEX;
717     if ((code < 0) && (errno == EINVAL))
718         return KTC_NOPIOCTL;
719     return KTC_PIOCTLFAIL;      /* probable cause */
720 }
721
722 /*
723  * Forget tokens for this server and the calling user.
724  * NOT IMPLEMENTED YET!
725  */
726 #ifndef NO_AFS_CLIENT
727 int
728 ktc_ForgetToken(struct ktc_principal *aserver)
729 {
730     int rc;
731
732     LOCK_GLOBAL_MUTEX;
733     rc = ktc_ForgetAllTokens(); /* bogus, but better */
734     UNLOCK_GLOBAL_MUTEX;
735     return rc;
736 }
737 #endif /* NO_AFS_CLIENT */
738
739 /*!
740  * An iterator which can list all cells with tokens in the cache
741  *
742  * This function may be used to list the names of all cells for which
743  * tokens exist in the current cache. The first time that it is called,
744  * prevIndex should be set to 0. On all subsequent calls, prevIndex
745  * should be set to the value returned in newIndex by the last call
746  * to the function. Note that there is no guarantee that the index value
747  * is monotonically increasing.
748  *
749  * @param prevIndex
750  *      The index returned by the last call, or 0 if this is the first
751  *      call in an iteration
752  * @param newIndex
753  *      A pointer to an int which, upon return, will hold the next value
754  *      to be used.
755  * @param cellName
756  *      A pointer to a char * which, upon return, will hold a cellname.
757  *      This must be freed by the caller using free()
758  */
759
760 int
761 ktc_ListTokensEx(int prevIndex, int *newIndex, char **cellName) {
762     struct ViceIoctl iob;
763     char tbuffer[MAXPIOCTLTOKENLEN];
764     afs_int32 code;
765     afs_int32 index;
766     struct ktc_setTokenData tokenSet;
767     XDR xdrs;
768
769     memset(&tokenSet, 0, sizeof(tokenSet));
770
771     *cellName = NULL;
772     *newIndex = prevIndex;
773
774     index = prevIndex;
775
776     while (index<100) { /* Safety, incase of pioctl failure */
777         memset(tbuffer, 0, sizeof(tbuffer));
778         iob.in = tbuffer;
779         memcpy(tbuffer, &index, sizeof(afs_int32));
780         iob.in_size = sizeof(afs_int32);
781         iob.out = tbuffer;
782         iob.out_size = sizeof(tbuffer);
783
784         code = PIOCTL(0, VIOC_GETTOK2, &iob, 0);
785
786         /* Can't use new pioctl, so must use old one */
787         if (code == -1 && errno == EINVAL) {
788             struct ktc_principal server;
789
790             code = ktc_ListTokens(index, newIndex, &server);
791             if (code == 0)
792                 *cellName = strdup(server.cell);
793             return code;
794         }
795
796         if (code == 0) {
797             /* Got a token from the pioctl. Now we throw it away,
798              * so we can return just a cellname. This is rather wasteful,
799              * but it's what the old API does. Ho hum.  */
800
801             xdrmem_create(&xdrs, iob.out, iob.out_size, XDR_DECODE);
802             if (!xdr_ktc_setTokenData(&xdrs, &tokenSet)) {
803                 xdr_destroy(&xdrs);
804                 return EINVAL;
805             }
806             xdr_destroy(&xdrs);
807             *cellName = strdup(tokenSet.cell);
808             xdr_free((xdrproc_t)xdr_ktc_setTokenData, &tokenSet);
809             *newIndex = index + 1;
810             return 0;
811         }
812         index++;
813     }
814     return KTC_PIOCTLFAIL;
815 }
816
817 /* ktc_ListTokens - list all tokens.  start aprevIndex at 0, it returns the
818  * next rock in (*aindex).  (*aserver) is set to the relevant ticket on
819  * success.  */
820
821 int
822 ktc_ListTokens(int aprevIndex,
823     int *aindex,
824     struct ktc_principal *aserver)
825 {
826     struct ViceIoctl iob;
827     char tbuffer[MAXPIOCTLTOKENLEN];
828     afs_int32 code = 0 ;
829     char *tp;
830     afs_int32 temp, index;
831
832     memset(tbuffer, 0, sizeof(tbuffer));
833
834     LOCK_GLOBAL_MUTEX;
835
836     index = aprevIndex;
837 #ifdef NO_AFS_CLIENT
838     if (index < 214)
839         index = 214;
840 #endif /* NO_AFS_CLIENT */
841 #ifdef AFS_KERBEROS_ENV
842     if (index >= 214) {
843         int i;
844         struct ktc_principal cprincipal;
845         struct ktc_token ctoken;
846
847         if (afs_tf_init(ktc_tkt_string(), R_TKT_FIL)
848             || afs_tf_get_pname(tbuffer) || afs_tf_get_pinst(tbuffer)) {
849             afs_tf_close();
850             UNLOCK_GLOBAL_MUTEX;
851             return KTC_NOENT;
852         }
853
854         for (i = 214; i < index; i++) {
855             if (afs_tf_get_cred(&cprincipal, &ctoken)) {
856                 afs_tf_close();
857                 UNLOCK_GLOBAL_MUTEX;
858                 return KTC_NOENT;
859             }
860         }
861
862       again:
863         if (afs_tf_get_cred(&cprincipal, &ctoken)) {
864             afs_tf_close();
865             UNLOCK_GLOBAL_MUTEX;
866             return KTC_NOENT;
867         }
868         index++;
869
870 #ifndef NO_AFS_CLIENT
871         if (!strcmp(cprincipal.name, "afs") && cprincipal.instance[0] == 0) {
872             goto again;
873         }
874 #endif /* NO_AFS_CLIENT */
875
876         for (i = 0; i < MAXLOCALTOKENS; i++) {
877             if (!strcmp(cprincipal.name, local_tokens[i].server.name)
878                 && !strcmp(cprincipal.instance,
879                            local_tokens[i].server.instance)
880                 && !strcmp(cprincipal.cell, local_tokens[i].server.cell)) {
881                 goto again;
882             }
883         }
884
885         *aserver = cprincipal;
886         *aindex = index;
887         afs_tf_close();
888         UNLOCK_GLOBAL_MUTEX;
889         return 0;
890     }
891 #endif
892
893 #ifndef NO_AFS_CLIENT
894     if (index >= 123) {         /* special hack for returning TCS */
895         while (index - 123 < MAXLOCALTOKENS) {
896             if (local_tokens[index - 123].valid) {
897                 *aserver = local_tokens[index - 123].server;
898                 *aindex = index + 1;
899                 UNLOCK_GLOBAL_MUTEX;
900                 return 0;
901             }
902             index++;
903         }
904         UNLOCK_GLOBAL_MUTEX;
905 #ifdef AFS_KERBEROS_ENV
906         return ktc_ListTokens(214, aindex, aserver);
907 #else
908         return KTC_NOENT;
909 #endif
910     }
911
912     /* get tokens from the kernel */
913     while (index < 200) {       /* sanity check in case pioctl fails */
914         iob.in = (char *)&index;
915         iob.in_size = sizeof(afs_int32);
916         iob.out = tbuffer;
917         iob.out_size = sizeof(tbuffer);
918         code = PIOCTL(0, VIOCGETTOK, &iob, 0);
919         if (code < 0 && errno == EDOM) {
920             if (index < 123) {
921                 int rc;
922                 rc = ktc_ListTokens(123, aindex, aserver);
923                 UNLOCK_GLOBAL_MUTEX;
924                 return rc;
925             } else {
926                 UNLOCK_GLOBAL_MUTEX;
927                 return KTC_NOENT;
928             }
929         }
930         if (code == 0)
931             break;              /* got a ticket */
932         /* otherwise we should skip this ticket slot */
933         index++;
934     }
935     if (code < 0) {
936         UNLOCK_GLOBAL_MUTEX;
937         if (errno == EINVAL)
938             return KTC_NOPIOCTL;
939         return KTC_PIOCTLFAIL;
940     }
941
942     /* parse buffer */
943     tp = tbuffer;
944
945     /* next iterator determined by earlier loop */
946     *aindex = index + 1;
947
948     memcpy(&temp, tp, sizeof(afs_int32));       /* get size of secret token */
949     tp += sizeof(afs_int32);
950     tp += temp;                 /* skip ticket for now */
951     memcpy(&temp, tp, sizeof(afs_int32));       /* get size of clear token */
952     if (temp != sizeof(struct ClearToken)) {
953         UNLOCK_GLOBAL_MUTEX;
954         return KTC_ERROR;
955     }
956     tp += sizeof(afs_int32);    /* skip length */
957     tp += temp;                 /* skip clear token itself */
958     tp += sizeof(afs_int32);    /* skip primary flag */
959     /* tp now points to the cell name */
960     strcpy(aserver->cell, tp);
961     aserver->instance[0] = 0;
962     strcpy(aserver->name, "afs");
963 #endif /* NO_AFS_CLIENT */
964     UNLOCK_GLOBAL_MUTEX;
965     return 0;
966 }
967
968 static int
969 ForgetAll(void)
970 {
971     struct ViceIoctl iob;
972     afs_int32 code;
973     int i;
974
975     for (i = 0; i < MAXLOCALTOKENS; i++)
976         local_tokens[i].valid = 0;
977
978     iob.in = 0;
979     iob.in_size = 0;
980     iob.out = 0;
981     iob.out_size = 0;
982 #ifndef NO_AFS_CLIENT
983     code = PIOCTL(0, VIOCUNPAG, &iob, 0);
984     if (code)
985         return KTC_PIOCTLFAIL;
986 #endif /* NO_AFS_CLIENT */
987     return 0;
988 }
989
990 int
991 ktc_ForgetAllTokens(void)
992 {
993     int ocode;
994
995     LOCK_GLOBAL_MUTEX;
996 #ifdef AFS_KERBEROS_ENV
997     (void)afs_tf_dest_tkt();
998 #endif
999
1000     ocode = ForgetAll();
1001     if (ocode) {
1002         if (ocode == -1)
1003             ocode = errno;
1004         else if (ocode == KTC_PIOCTLFAIL)
1005             ocode = errno;
1006         UNLOCK_GLOBAL_MUTEX;
1007         if (ocode == EINVAL)
1008             return KTC_NOPIOCTL;
1009         return KTC_PIOCTLFAIL;
1010     }
1011     UNLOCK_GLOBAL_MUTEX;
1012     return 0;
1013 }
1014
1015 /* ktc_OldPioctl - returns a boolean true if the kernel supports only the old
1016  * pioctl interface for delivering AFS tickets to the cache manager. */
1017
1018 int
1019 ktc_OldPioctl(void)
1020 {
1021     return 1;
1022 }
1023
1024 afs_uint32
1025 ktc_curpag(void)
1026 {
1027     int code;
1028     struct ViceIoctl iob;
1029     afs_uint32 pag;
1030
1031     /* now setup for the pioctl */
1032     iob.in = NULL;
1033     iob.in_size = 0;
1034     iob.out = (caddr_t) &pag;
1035     iob.out_size = sizeof(afs_uint32);
1036
1037     code = PIOCTL(0, VIOC_GETPAG, &iob, 0);
1038     if (code < 0) {
1039 #if defined(AFS_AIX52_ENV)
1040         code = getpagvalue("afs");
1041         if (code < 0 && errno == EINVAL)
1042             code = 0;
1043         return code;
1044 #elif defined(AFS_AIX51_ENV)
1045         return -1;
1046 #else
1047         gid_t groups[NGROUPS_MAX];
1048         afs_uint32 g0, g1;
1049         afs_uint32 h, l, ret;
1050         int ngroups;
1051 #ifdef AFS_LINUX26_ENV
1052         int i;
1053 #endif
1054
1055         ngroups = getgroups(sizeof groups / sizeof groups[0], groups);
1056
1057 #ifdef AFS_LINUX26_ENV
1058         /* check for AFS_LINUX26_ONEGROUP_ENV PAGs */
1059         for (i = 0; i < ngroups; i++) {
1060             if (((groups[i] >> 24) & 0xff) == 'A') {
1061                 return groups[i];
1062             }
1063         }
1064 #endif
1065
1066         if (ngroups < 2)
1067             return 0;
1068
1069         g0 = groups[0] & 0xffff;
1070         g1 = groups[1] & 0xffff;
1071         g0 -= 0x3f00;
1072         g1 -= 0x3f00;
1073         if (g0 < 0xc000 && g1 < 0xc000) {
1074             l = ((g0 & 0x3fff) << 14) | (g1 & 0x3fff);
1075             h = (g0 >> 14);
1076             h = (g1 >> 14) + h + h + h;
1077             ret = ((h << 28) | l);
1078             /* Additional testing */
1079             if (((ret >> 24) & 0xff) == 'A')
1080                 return ret;
1081             else
1082                 return -1;
1083         }
1084         return -1;
1085 #endif
1086     }
1087     return pag;
1088 }
1089
1090
1091 #ifdef AFS_KERBEROS_ENV
1092  /*
1093   * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
1094   *
1095   * For copying and distribution information, please see the file
1096   * <mit-copyright.h>.
1097   */
1098
1099 #if 0
1100 #include <stdio.h>
1101 #include <errno.h>
1102 #include <sys/types.h>
1103 #include <sys/stat.h>
1104 #include <sys/file.h>
1105 #include <krb.h>
1106 #endif
1107
1108 #define TOO_BIG -1
1109 #define TF_LCK_RETRY ((unsigned)2)      /* seconds to sleep before
1110                                          * retry if ticket file is
1111                                          * locked */
1112
1113 /*
1114  * fd must be initialized to something that won't ever occur as a real
1115  * file descriptor. Since open(2) returns only non-negative numbers as
1116  * valid file descriptors, and afs_tf_init always stuffs the return value
1117  * from open in here even if it is an error flag, we must
1118  *      a. Initialize fd to a negative number, to indicate that it is
1119  *         not initially valid.
1120  *      b. When checking for a valid fd, assume that negative values
1121  *         are invalid (ie. when deciding whether afs_tf_init has been
1122  *         called.)
1123  *      c. In tf_close, be sure it gets reinitialized to a negative
1124  *         number.
1125  */
1126 static int fd = -1;
1127 static int curpos;                      /* Position in tfbfr */
1128 static int lastpos;                     /* End of tfbfr */
1129 static char tfbfr[BUFSIZ];      /* Buffer for ticket data */
1130
1131 static int tf_gets(char *, int);
1132 static int tf_read(char *, int);
1133
1134 /*
1135  * This file contains routines for manipulating the ticket cache file.
1136  *
1137  * The ticket file is in the following format:
1138  *
1139  *      principal's name        (null-terminated string)
1140  *      principal's instance    (null-terminated string)
1141  *      CREDENTIAL_1
1142  *      CREDENTIAL_2
1143  *      ...
1144  *      CREDENTIAL_n
1145  *      EOF
1146  *
1147  *      Where "CREDENTIAL_x" consists of the following fixed-length
1148  *      fields from the CREDENTIALS structure (see "krb.h"):
1149  *
1150  *              char            service[MAXKTCNAMELEN]
1151  *              char            instance[MAXKTCNAMELEN]
1152  *              char            realm[REALM_SZ]
1153  *              C_Block         session
1154  *              int             lifetime
1155  *              int             kvno
1156  *              KTEXT_ST        ticket_st
1157  *              afs_int32            issue_date
1158  *
1159  * Short description of routines:
1160  *
1161  * afs_tf_init() opens the ticket file and locks it.
1162  *
1163  * afs_tf_get_pname() returns the principal's name.
1164  *
1165  * afs_tf_get_pinst() returns the principal's instance (may be null).
1166  *
1167  * afs_tf_get_cred() returns the next CREDENTIALS record.
1168  *
1169  * afs_tf_save_cred() appends a new CREDENTIAL record to the ticket file.
1170  *
1171  * afs_tf_close() closes the ticket file and releases the lock.
1172  *
1173  * tf_gets() returns the next null-terminated string.  It's an internal
1174  * routine used by afs_tf_get_pname(), afs_tf_get_pinst(), and
1175  * afs_tf_get_cred().
1176  *
1177  * tf_read() reads a given number of bytes.  It's an internal routine
1178  * used by afs_tf_get_cred().
1179  */
1180
1181 /*
1182  * afs_tf_init() should be called before the other ticket file routines.
1183  * It takes the name of the ticket file to use, "tf_name", and a
1184  * read/write flag "rw" as arguments.
1185  *
1186  * It tries to open the ticket file, checks the mode, and if everything
1187  * is okay, locks the file.  If it's opened for reading, the lock is
1188  * shared.  If it's opened for writing, the lock is exclusive.
1189  *
1190  * Returns 0 if all went well, otherwise one of the following:
1191  *
1192  * NO_TKT_FIL   - file wasn't there
1193  * TKT_FIL_ACC  - file was in wrong mode, etc.
1194  * TKT_FIL_LCK  - couldn't lock the file, even after a retry
1195  */
1196
1197 int
1198 afs_tf_init(char *tf_name, int rw)
1199 {
1200     int wflag;
1201     int me;
1202     struct stat stat_buf;
1203
1204     switch (rw) {
1205     case R_TKT_FIL:
1206         wflag = 0;
1207         break;
1208     case W_TKT_FIL:
1209         wflag = 1;
1210         break;
1211     default:
1212         return TKT_FIL_ACC;
1213     }
1214     if (lstat(tf_name, &stat_buf) < 0)
1215         switch (errno) {
1216         case ENOENT:
1217             return NO_TKT_FIL;
1218         default:
1219             return TKT_FIL_ACC;
1220         }
1221     me = getuid();
1222     if ((stat_buf.st_uid != me && me != 0)
1223         || ((stat_buf.st_mode & S_IFMT) != S_IFREG))
1224         return TKT_FIL_ACC;
1225
1226     /*
1227      * If "wflag" is set, open the ticket file in append-writeonly mode
1228      * and lock the ticket file in exclusive mode.  If unable to lock
1229      * the file, sleep and try again.  If we fail again, return with the
1230      * proper error message.
1231      */
1232
1233     curpos = sizeof(tfbfr);
1234
1235     if (wflag) {
1236         fd = open(tf_name, O_RDWR, 0600);
1237         if (fd < 0) {
1238             return TKT_FIL_ACC;
1239         }
1240 #if defined(AFS_AIX_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV)
1241         if (fcntl(fd, F_SETLK, &fileWlock) == -1) {
1242             sleep(TF_LCK_RETRY);
1243             if (fcntl(fd, F_SETLK, &fileWlock) == -1) {
1244 #else
1245         if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
1246             sleep(TF_LCK_RETRY);
1247             if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
1248 #endif
1249                 (void)close(fd);
1250                 fd = -1;
1251                 return TKT_FIL_LCK;
1252             }
1253         }
1254         return 0;
1255     }
1256     /*
1257      * Otherwise "wflag" is not set and the ticket file should be opened
1258      * for read-only operations and locked for shared access.
1259      */
1260
1261     fd = open(tf_name, O_RDONLY, 0600);
1262     if (fd < 0) {
1263         return TKT_FIL_ACC;
1264     }
1265 #if defined(AFS_AIX_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV)
1266     if (fcntl(fd, F_SETLK, &fileRlock) == -1) {
1267         sleep(TF_LCK_RETRY);
1268         if (fcntl(fd, F_SETLK, &fileRlock) == -1) {
1269 #else
1270     if (flock(fd, LOCK_SH | LOCK_NB) < 0) {
1271         sleep(TF_LCK_RETRY);
1272         if (flock(fd, LOCK_SH | LOCK_NB) < 0) {
1273 #endif
1274             (void)close(fd);
1275             fd = -1;
1276             return TKT_FIL_LCK;
1277         }
1278     }
1279     return 0;
1280 }
1281
1282 /*
1283  * afs_tf_get_pname() reads the principal's name from the ticket file. It
1284  * should only be called after afs_tf_init() has been called.  The
1285  * principal's name is filled into the "p" parameter.  If all goes well,
1286  * 0 is returned.  If afs_tf_init() wasn't called, TKT_FIL_INI is
1287  * returned.  If the name was null, or EOF was encountered, or the name
1288  * was longer than MAXKTCNAMELEN, TKT_FIL_FMT is returned.
1289  */
1290
1291 int
1292 afs_tf_get_pname(char *p)
1293 {
1294     if (fd < 0) {
1295         return TKT_FIL_INI;
1296     }
1297     if (tf_gets(p, MAXKTCNAMELEN) < 2)  /* can't be just a null */
1298         return TKT_FIL_FMT;
1299     return 0;
1300 }
1301
1302 /*
1303  * afs_tf_get_pinst() reads the principal's instance from a ticket file.
1304  * It should only be called after afs_tf_init() and afs_tf_get_pname() have
1305  * been called.  The instance is filled into the "inst" parameter.  If all
1306  * goes well, 0 is returned.  If afs_tf_init() wasn't called,
1307  * TKT_FIL_INI is returned.  If EOF was encountered, or the instance
1308  * was longer than MAXKTCNAMELEN, TKT_FIL_FMT is returned.  Note that the
1309  * instance may be null.
1310  */
1311
1312 int
1313 afs_tf_get_pinst(char *inst)
1314 {
1315     if (fd < 0) {
1316         return TKT_FIL_INI;
1317     }
1318     if (tf_gets(inst, MAXKTCNAMELEN) < 1)
1319         return TKT_FIL_FMT;
1320     return 0;
1321 }
1322
1323 /*
1324  * afs_tf_get_cred() reads a CREDENTIALS record from a ticket file and fills
1325  * in the given structure "c".  It should only be called after afs_tf_init(),
1326  * afs_tf_get_pname(), and afs_tf_get_pinst() have been called. If all goes
1327  * well, 0 is returned.  Possible error codes are:
1328  *
1329  * TKT_FIL_INI  - afs_tf_init wasn't called first
1330  * TKT_FIL_FMT  - bad format
1331  * EOF          - end of file encountered
1332  */
1333
1334 int
1335 afs_tf_get_cred(struct ktc_principal *principal, struct ktc_token *token)
1336 {
1337     int k_errno;
1338     int kvno, lifetime;
1339     long mit_compat;            /* MIT Kerberos 5 with Krb4 uses a "long" for issue_date */
1340
1341     if (fd < 0) {
1342         return TKT_FIL_INI;
1343     }
1344     if ((k_errno = tf_gets(principal->name, MAXKTCNAMELEN)) < 2)
1345         switch (k_errno) {
1346         case TOO_BIG:
1347         case 1:         /* can't be just a null */
1348             return TKT_FIL_FMT;
1349         case 0:
1350             return EOF;
1351         }
1352     if ((k_errno = tf_gets(principal->instance, MAXKTCNAMELEN)) < 1)
1353         switch (k_errno) {
1354         case TOO_BIG:
1355             return TKT_FIL_FMT;
1356         case 0:
1357             return EOF;
1358         }
1359     if ((k_errno = tf_gets(principal->cell, MAXKTCREALMLEN)) < 2)
1360         switch (k_errno) {
1361         case TOO_BIG:
1362         case 1:         /* can't be just a null */
1363             return TKT_FIL_FMT;
1364         case 0:
1365             return EOF;
1366         }
1367     lcstring(principal->cell, principal->cell, MAXKTCREALMLEN);
1368     if (tf_read((char *)&(token->sessionKey), 8) < 1
1369         || tf_read((char *)&(lifetime), sizeof(lifetime)) < 1
1370         || tf_read((char *)&(kvno), sizeof(kvno)) < 1
1371         || tf_read((char *)&(token->ticketLen), sizeof(token->ticketLen))
1372         < 1 ||
1373         /* don't try to read a silly amount into ticket->dat */
1374         token->ticketLen > MAXKTCTICKETLEN
1375         || tf_read((char *)(token->ticket), token->ticketLen) < 1
1376         || tf_read((char *)&mit_compat, sizeof(mit_compat)) < 1) {
1377         return TKT_FIL_FMT;
1378     }
1379     token->startTime = mit_compat;
1380     token->endTime = life_to_time(token->startTime, lifetime);
1381     token->kvno = kvno;
1382     return 0;
1383 }
1384
1385 /*
1386  * tf_close() closes the ticket file and sets "fd" to -1. If "fd" is
1387  * not a valid file descriptor, it just returns.  It also clears the
1388  * buffer used to read tickets.
1389  *
1390  * The return value is not defined.
1391  */
1392
1393 int
1394 afs_tf_close(void)
1395 {
1396     if (!(fd < 0)) {
1397 #if defined(AFS_AIX_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV)
1398         (void)fcntl(fd, F_SETLK, &fileUlock);
1399 #else
1400         (void)flock(fd, LOCK_UN);
1401 #endif
1402         (void)close(fd);
1403         fd = -1;                /* see declaration of fd above */
1404     }
1405     memset(tfbfr, 0, sizeof(tfbfr));
1406     return 0;
1407 }
1408
1409 /*
1410  * tf_gets() is an internal routine.  It takes a string "s" and a count
1411  * "n", and reads from the file until either it has read "n" characters,
1412  * or until it reads a null byte. When finished, what has been read exists
1413  * in "s".
1414  *
1415  * Possible return values are:
1416  *
1417  * n            the number of bytes read (including null terminator)
1418  *              when all goes well
1419  *
1420  * 0            end of file or read error
1421  *
1422  * TOO_BIG      if "count" characters are read and no null is
1423  *              encountered. This is an indication that the ticket
1424  *              file is seriously ill.
1425  */
1426
1427 static int
1428 tf_gets(char *s, int n)
1429 {
1430     int count;
1431
1432     if (fd < 0) {
1433         return TKT_FIL_INI;
1434     }
1435     for (count = n - 1; count > 0; --count) {
1436         if (curpos >= sizeof(tfbfr)) {
1437             lastpos = read(fd, tfbfr, sizeof(tfbfr));
1438             curpos = 0;
1439         }
1440         if (curpos == lastpos) {
1441             return 0;
1442         }
1443         *s = tfbfr[curpos++];
1444         if (*s++ == '\0')
1445             return (n - count);
1446     }
1447     return TOO_BIG;
1448 }
1449
1450 /*
1451  * tf_read() is an internal routine.  It takes a string "s" and a count
1452  * "n", and reads from the file until "n" bytes have been read.  When
1453  * finished, what has been read exists in "s".
1454  *
1455  * Possible return values are:
1456  *
1457  * n            the number of bytes read when all goes well
1458  *
1459  * 0            on end of file or read error
1460  */
1461
1462 static int
1463 tf_read(char *s, int n)
1464 {
1465     int count;
1466
1467     for (count = n; count > 0; --count) {
1468         if (curpos >= sizeof(tfbfr)) {
1469             lastpos = read(fd, tfbfr, sizeof(tfbfr));
1470             curpos = 0;
1471         }
1472         if (curpos == lastpos) {
1473             return 0;
1474         }
1475         *s++ = tfbfr[curpos++];
1476     }
1477     return n;
1478 }
1479
1480 /*
1481  * afs_tf_save_cred() appends an incoming ticket to the end of the ticket
1482  * file.  You must call afs_tf_init() before calling afs_tf_save_cred().
1483  *
1484  * The "service", "instance", and "realm" arguments specify the
1485  * server's name; "aticket" contains the credential.
1486  *
1487  * Returns 0 if all goes well, TKT_FIL_INI if afs_tf_init() wasn't
1488  * called previously, and KFAILURE for anything else that went wrong.
1489  */
1490
1491 int
1492 afs_tf_save_cred(struct ktc_principal *aserver,
1493                  struct ktc_token *atoken,
1494                  struct ktc_principal *aclient)
1495 {
1496     char realm[MAXKTCREALMLEN + 1];
1497     char junk[MAXKTCNAMELEN];
1498     struct ktc_principal principal;
1499     struct ktc_token token;
1500     int status;
1501     off_t start;
1502     int lifetime, kvno;
1503     int count;                  /* count for write */
1504     long mit_compat;            /* MIT Kerberos 5 with Krb4 uses a "long" for issue_date */
1505
1506     if (fd < 0) {               /* fd is ticket file as set by afs_tf_init */
1507         return TKT_FIL_INI;
1508     }
1509
1510     ucstring(realm, aserver->cell, MAXKTCREALMLEN);
1511     realm[MAXKTCREALMLEN] = '\0';
1512
1513     /* Look for a duplicate ticket */
1514     (void)lseek(fd, (off_t) 0L, 0);
1515     curpos = sizeof(tfbfr);
1516
1517     if (afs_tf_get_pname(junk) || strcmp(junk, aclient->name)
1518         || afs_tf_get_pinst(junk) || strcmp(junk, aclient->instance))
1519         goto bad;
1520
1521     do {
1522         start = lseek(fd, (off_t) 0L, 1) - lastpos + curpos;
1523         status = afs_tf_get_cred(&principal, &token);
1524     } while (status == 0
1525              && (strcmp(aserver->name, principal.name) != 0
1526                  || strcmp(aserver->instance, principal.instance) != 0
1527                  || strcmp(aserver->cell, principal.cell) != 0));
1528
1529     /*
1530      * Two tickets for the same user authenticating to the same service
1531      * should be the same length, but we check here just to make sure.
1532      */
1533     if (status == 0 && token.ticketLen != atoken->ticketLen)
1534         return KFAILURE;
1535     if (status && status != EOF)
1536         return status;
1537
1538     /* Position over the credential we just matched (or the EOF) */
1539     lseek(fd, start, 0);
1540     curpos = lastpos = sizeof(tfbfr);
1541
1542     /* Write the ticket and associated data */
1543     /* Service */
1544     count = strlen(aserver->name) + 1;
1545     if (write(fd, aserver->name, count) != count)
1546         goto bad;
1547     /* Instance */
1548     count = strlen(aserver->instance) + 1;
1549     if (write(fd, aserver->instance, count) != count)
1550         goto bad;
1551     /* Realm */
1552     count = strlen(realm) + 1;
1553     if (write(fd, realm, count) != count)
1554         goto bad;
1555     /* Session key */
1556     if (write(fd, (char *)&atoken->sessionKey, 8) != 8)
1557         goto bad;
1558     /* Lifetime */
1559     lifetime = time_to_life(atoken->startTime, atoken->endTime);
1560     if (write(fd, (char *)&lifetime, sizeof(int)) != sizeof(int))
1561         goto bad;
1562     /* Key vno */
1563     kvno = atoken->kvno;
1564     if (write(fd, (char *)&kvno, sizeof(int)) != sizeof(int))
1565         goto bad;
1566     /* Tkt length */
1567     if (write(fd, (char *)&(atoken->ticketLen), sizeof(int)) != sizeof(int))
1568         goto bad;
1569     /* Ticket */
1570     count = atoken->ticketLen;
1571     if (write(fd, atoken->ticket, count) != count)
1572         goto bad;
1573     /* Issue date */
1574     mit_compat = atoken->startTime;
1575     if (write(fd, (char *)&mit_compat, sizeof(mit_compat))
1576         != sizeof(mit_compat))
1577         goto bad;
1578
1579     /* Actually, we should check each write for success */
1580     return (0);
1581   bad:
1582     return (KFAILURE);
1583 }
1584
1585 /*
1586  * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
1587  * of Technology.
1588  *
1589  * For copying and distribution information, please see the file
1590  * <mit-copyright.h>.
1591  */
1592
1593 /*
1594  * This routine is used to generate the name of the file that holds
1595  * the user's cache of server tickets and associated session keys.
1596  *
1597  * If it is set, krb_ticket_string contains the ticket file name.
1598  * Otherwise, the filename is constructed as follows:
1599  *
1600  * If it is set, the environment variable "KRBTKFILE" will be used as
1601  * the ticket file name.  Otherwise TKT_ROOT (defined in "krb.h") and
1602  * the user's uid are concatenated to produce the ticket file name
1603  * (e.g., "/tmp/tkt123").  A pointer to the string containing the ticket
1604  * file name is returned.
1605  */
1606
1607 static char krb_ticket_string[4096] = "";
1608
1609 char *
1610 ktc_tkt_string(void)
1611 {
1612     return ktc_tkt_string_uid(getuid());
1613 }
1614
1615 char *
1616 ktc_tkt_string_uid(afs_uint32 uid)
1617 {
1618     char *env;
1619
1620     LOCK_GLOBAL_MUTEX;
1621     if (!*krb_ticket_string) {
1622         if ((env = getenv("KRBTKFILE"))) {
1623             (void)strncpy(krb_ticket_string, env,
1624                           sizeof(krb_ticket_string) - 1);
1625             krb_ticket_string[sizeof(krb_ticket_string) - 1] = '\0';
1626         } else {
1627             /* 32 bits of signed integer will always fit in 11 characters
1628              * (including the sign), so no need to worry about overflow */
1629             (void)sprintf(krb_ticket_string, "%s%d", TKT_ROOT, uid);
1630         }
1631     }
1632     UNLOCK_GLOBAL_MUTEX;
1633     return krb_ticket_string;
1634 }
1635
1636 /*
1637  * This routine is used to set the name of the file that holds the user's
1638  * cache of server tickets and associated session keys.
1639  *
1640  * The value passed in is copied into local storage.
1641  *
1642  * NOTE:  This routine should be called during initialization, before other
1643  * Kerberos routines are called; otherwise tkt_string() above may be called
1644  * and return an undesired ticket file name until this routine is called.
1645  */
1646
1647 void
1648 ktc_set_tkt_string(char * val)
1649 {
1650
1651     LOCK_GLOBAL_MUTEX;
1652     (void)strncpy(krb_ticket_string, val, sizeof(krb_ticket_string) - 1);
1653     krb_ticket_string[sizeof(krb_ticket_string) - 1] = '\0';
1654     UNLOCK_GLOBAL_MUTEX;
1655     return;
1656 }
1657
1658 /*
1659  * tf_create() is used to initialize the ticket store.  It creates the
1660  * file to contain the tickets and writes the given user's name "pname"
1661  * and instance "pinst" in the file.  in_tkt() returns KSUCCESS on
1662  * success, or KFAILURE if something goes wrong.
1663  */
1664
1665 int
1666 afs_tf_create(char *pname, char *pinst)
1667 {
1668     int tktfile;
1669     int me, metoo;
1670     int count;
1671     char *file = ktc_tkt_string();
1672     int fd;
1673     int i;
1674     char zerobuf[1024];
1675     struct stat sbuf;
1676
1677     me = getuid();
1678     metoo = geteuid();
1679
1680     if (lstat(file, &sbuf) == 0) {
1681         if ((sbuf.st_uid != me && me != 0)
1682             || ((sbuf.st_mode & S_IFMT) != S_IFREG) || sbuf.st_mode & 077) {
1683             return KFAILURE;
1684         }
1685         /* file already exists, and permissions appear ok, so nuke it */
1686         if ((fd = open(file, O_RDWR, 0)) < 0)
1687             goto out;           /* can't zero it, but we can still try truncating it */
1688
1689         memset(zerobuf, 0, sizeof(zerobuf));
1690
1691         for (i = 0; i < sbuf.st_size; i += sizeof(zerobuf))
1692             if (write(fd, zerobuf, sizeof(zerobuf)) != sizeof(zerobuf)) {
1693                 (void)fsync(fd);
1694                 (void)close(fd);
1695                 goto out;
1696             }
1697
1698         (void)fsync(fd);
1699         (void)close(fd);
1700     }
1701
1702   out:
1703     /* arrange so the file is owned by the ruid
1704      * (swap real & effective uid if necessary).
1705      * This isn't a security problem, since the ticket file, if it already
1706      * exists, has the right uid (== ruid) and mode. */
1707     if (me != metoo) {
1708         if (setreuid(metoo, me) < 0) {
1709             return (KFAILURE);
1710         }
1711     }
1712     tktfile = creat(file, 0600);
1713     if (me != metoo) {
1714         if (setreuid(me, metoo) < 0) {
1715             /* can't switch??? fail! */
1716             return (KFAILURE);
1717         }
1718     }
1719     if (tktfile < 0) {
1720         return (KFAILURE);
1721     }
1722     count = strlen(pname) + 1;
1723     if (write(tktfile, pname, count) != count) {
1724         (void)close(tktfile);
1725         return (KFAILURE);
1726     }
1727     count = strlen(pinst) + 1;
1728     if (write(tktfile, pinst, count) != count) {
1729         (void)close(tktfile);
1730         return (KFAILURE);
1731     }
1732     (void)close(tktfile);
1733     return (KSUCCESS);
1734 }
1735
1736 /*
1737  * dest_tkt() is used to destroy the ticket store upon logout.
1738  * If the ticket file does not exist, dest_tkt() returns RET_TKFIL.
1739  * Otherwise the function returns 0 on success, KFAILURE on
1740  * failure.
1741  */
1742
1743 int
1744 afs_tf_dest_tkt(void)
1745 {
1746     char *file = ktc_tkt_string();
1747     int i, fd;
1748     struct stat statb;
1749     char buf[BUFSIZ];
1750
1751     errno = 0;
1752     if (lstat(file, &statb) < 0)
1753         goto out;
1754
1755     if (!(statb.st_mode & S_IFREG))
1756         goto out;
1757
1758     if ((fd = open(file, O_RDWR, 0)) < 0)
1759         goto out;
1760
1761     memset(buf, 0, BUFSIZ);
1762
1763     for (i = 0; i < statb.st_size; i += BUFSIZ)
1764         if (write(fd, buf, BUFSIZ) != BUFSIZ) {
1765             (void)fsync(fd);
1766             (void)close(fd);
1767             goto out;
1768         }
1769
1770     (void)fsync(fd);
1771     (void)close(fd);
1772
1773     (void)unlink(file);
1774
1775   out:
1776     if (errno == ENOENT)
1777         return RET_TKFIL;
1778     else if (errno != 0)
1779         return KFAILURE;
1780     return 0;
1781 }
1782
1783 int
1784 ktc_newpag(void)
1785 {
1786 #if !defined(AFS_DARWIN100_ENV) || defined(HAVE_CRT_EXTERNS_H)
1787 # if defined(AFS_DARWIN100_ENV)
1788 #  define environ (*_NSGetEnviron())
1789 # else
1790 extern char **environ;
1791 # endif
1792
1793     afs_uint32 pag;
1794     struct stat sbuf;
1795     char fname[256], *prefix = "/ticket/";
1796     char fname5[256], *prefix5 = "FILE:/ticket/krb5cc_";
1797     int numenv;
1798     char **newenv, **senv, **denv;
1799
1800     LOCK_GLOBAL_MUTEX;
1801     if (stat("/ticket", &sbuf) == -1) {
1802         prefix = "/tmp/tkt";
1803         prefix5 = "FILE:/tmp/krb5cc_";
1804     }
1805
1806     pag = ktc_curpag() & 0xffffffff;
1807     if (pag == -1) {
1808         sprintf(fname, "%s%d", prefix, getuid());
1809         sprintf(fname5, "%s%d", prefix5, getuid());
1810     } else {
1811         sprintf(fname, "%sp%lu", prefix, afs_printable_uint32_lu(pag));
1812         sprintf(fname5, "%sp%lud", prefix5, afs_printable_uint32_lu(pag));
1813     }
1814     ktc_set_tkt_string(fname);
1815
1816     for (senv = environ, numenv = 0; *senv; senv++)
1817         numenv++;
1818     newenv = (char **)malloc((numenv + 2) * sizeof(char *));
1819
1820     for (senv = environ, denv = newenv; *senv; senv++) {
1821         if (strncmp(*senv, "KRBTKFILE=", 10) != 0 &&
1822             strncmp(*senv, "KRB5CCNAME=", 11) != 0)
1823             *denv++ = *senv;
1824     }
1825
1826     *denv = malloc(10+11 + strlen(fname) + strlen(fname5) + 2);
1827     strcpy(*denv, "KRBTKFILE=");
1828     strcat(*denv, fname);
1829     *(denv+1) = *denv + strlen(*denv) + 1;
1830     denv++;
1831     strcpy(*denv, "KRB5CCNAME=");
1832     strcat(*denv, fname5);
1833     *++denv = 0;
1834     environ = newenv;
1835     UNLOCK_GLOBAL_MUTEX;
1836 #endif
1837     return 0;
1838 }
1839
1840 /*
1841  * BLETCH!  We have to invoke the entire afsconf package just to
1842  * find out what the local cell is.
1843  */
1844 static void
1845 ktc_LocalCell(void)
1846 {
1847     int code = 0;
1848     struct afsconf_dir *conf;
1849
1850     if ((conf = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH))
1851         || (conf = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH))) {
1852         code = afsconf_GetLocalCell(conf, lcell, sizeof(lcell));
1853         afsconf_Close(conf);
1854     }
1855     if (!conf || code) {
1856         printf("** Can't determine local cell name!\n");
1857     }
1858 }
1859
1860 #endif