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