Commit | Line | Data |
---|---|---|
805e021f CE |
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 |