Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / auth / ktc_nt.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 #include <afs/stds.h>
15
16 #include <roken.h>
17
18 #include <ctype.h>
19
20 #include <afs/pthread_glock.h>
21 #include <rpc.h>
22 #include <afs/smb_iocons.h>
23 #include <afs/pioctl_nt.h>
24 #include "afs/afsrpc.h"
25 #include <afs/vice.h>
26 #include "auth.h"
27 #include <afs/afsutil.h>
28 #include "token.h"
29
30 /* TBUFFERSIZE must be at least 512 larger than KTCMAXTICKETSIZE */
31 #define TBUFFERSIZE 12512
32
33 /* Forward declarations for local token cache. */
34 static int SetLocalToken(struct ktc_principal *aserver,
35 struct ktc_token *atoken,
36 struct ktc_principal *aclient, afs_int32 flags);
37 static int GetLocalToken(struct ktc_principal *aserver,
38 struct ktc_token *atoken, int atokenLen,
39 struct ktc_principal *aclient);
40 static int ForgetLocalTokens();
41 static int ForgetOneLocalToken(struct ktc_principal *aserver);
42
43
44 static char AFSConfigKeyName[] =
45 "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters";
46
47 static char AFSGlobalKTCMutexName[] = "Global\\AFS_KTC_Mutex";
48 static char AFSKTCMutexName[] = "AFS_KTC_Mutex";
49
50 #define MAXPIOCTLTOKENLEN \
51 (3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
52
53 /*
54 * Support for RPC's to send and receive session keys
55 *
56 * Session keys must not be sent and received in the clear. We have no
57 * way to piggyback encryption on SMB, so we use a separate RPC, using
58 * packet privacy (when available). In SetToken, the RPC is done first;
59 * in GetToken, the pioctl is done first.
60 */
61
62 char rpcErr[256];
63
64 void __RPC_FAR *__RPC_USER
65 midl_user_allocate(size_t cBytes)
66 {
67 return malloc(cBytes);
68 }
69
70 void __RPC_USER
71 midl_user_free(void __RPC_FAR * p)
72 {
73 free(p);
74 }
75
76 /*
77 * Determine the server name to be used in the RPC binding. If it is
78 * the same as the client (i.e. standalone, non-gateway), NULL can be
79 * used, so it is not necessary to call gethostbyname().
80 */
81 void
82 getservername(char **snp, unsigned int snSize)
83 {
84 HKEY parmKey;
85 long code;
86
87 code =
88 RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0, KEY_QUERY_VALUE,
89 &parmKey);
90 if (code != ERROR_SUCCESS)
91 goto nogateway;
92 code = RegQueryValueEx(parmKey, "Gateway", NULL, NULL, *snp, &snSize);
93 RegCloseKey(parmKey);
94 if (code == ERROR_SUCCESS)
95 return;
96 nogateway:
97 /* No gateway name in registry; use ourself */
98 *snp = NULL;
99 }
100
101 RPC_STATUS
102 send_key(afs_uuid_t uuid, char sessionKey[8])
103 {
104 RPC_STATUS status;
105 char *stringBinding = NULL;
106 ULONG authnLevel, authnSvc;
107 char serverName[256];
108 char *serverNamep = serverName;
109 char encrypt[32];
110 BOOL encryptionOff = FALSE;
111 char protseq[32];
112
113 /* Encryption on by default */
114 if (GetEnvironmentVariable("AFS_RPC_ENCRYPT", encrypt, sizeof(encrypt)))
115 if (!_stricmp(encrypt, "OFF"))
116 encryptionOff = TRUE;
117
118 /* Protocol sequence is local by default */
119 if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ", protseq, sizeof(protseq)))
120 strcpy(protseq, "ncalrpc");
121
122 /* Server name */
123 getservername(&serverNamep, sizeof(serverName));
124
125 status = RpcStringBindingCompose("", /* obj uuid */
126 protseq, serverNamep, "", /* endpoint */
127 "", /* protocol options */
128 &stringBinding);
129 if (status != RPC_S_OK)
130 goto cleanup;
131
132 status = RpcBindingFromStringBinding(stringBinding, &hAfsHandle);
133 if (status != RPC_S_OK)
134 goto cleanup;
135
136 /*
137 * On Windows 95/98, we must resolve the binding before calling
138 * SetAuthInfo. On Windows NT, we don't have to resolve yet,
139 * but it does no harm.
140 */
141 status = RpcEpResolveBinding(hAfsHandle, afsrpc_v1_0_c_ifspec);
142 if (status != RPC_S_OK)
143 goto cleanup;
144
145 if (encryptionOff) {
146 authnLevel = RPC_C_AUTHN_LEVEL_NONE;
147 authnSvc = RPC_C_AUTHN_WINNT;
148 } else {
149 authnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
150 authnSvc = RPC_C_AUTHN_WINNT;
151 }
152
153 status =
154 RpcBindingSetAuthInfo(hAfsHandle, NULL, authnLevel, authnSvc, NULL,
155 RPC_C_AUTHZ_NONE);
156 if (status != RPC_S_OK)
157 goto cleanup;
158
159 RpcTryExcept {
160 status = AFSRPC_SetToken(uuid, sessionKey);
161 }
162 RpcExcept(1) {
163 status = RpcExceptionCode();
164 }
165 RpcEndExcept cleanup:if (stringBinding)
166 RpcStringFree(&stringBinding);
167
168 if (hAfsHandle != NULL)
169 RpcBindingFree(&hAfsHandle);
170
171 return status;
172 }
173
174 RPC_STATUS
175 receive_key(afs_uuid_t uuid, char sessionKey[8])
176 {
177 RPC_STATUS status;
178 char *stringBinding = NULL;
179 ULONG authnLevel, authnSvc;
180 char serverName[256];
181 char *serverNamep = serverName;
182 char encrypt[32];
183 BOOL encryptionOff = FALSE;
184 char protseq[32];
185
186 /* Encryption on by default */
187 if (GetEnvironmentVariable("AFS_RPC_ENCRYPT", encrypt, sizeof(encrypt)))
188 if (!_stricmp(encrypt, "OFF"))
189 encryptionOff = TRUE;
190
191 /* Protocol sequence is local by default */
192 if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ", protseq, sizeof(protseq)))
193 strcpy(protseq, "ncalrpc");
194
195 /* Server name */
196 getservername(&serverNamep, sizeof(serverName));
197
198 status = RpcStringBindingCompose("", /* obj uuid */
199 protseq, serverNamep, "", /* endpoint */
200 "", /* protocol options */
201 &stringBinding);
202 if (status != RPC_S_OK)
203 goto cleanup;
204
205 status = RpcBindingFromStringBinding(stringBinding, &hAfsHandle);
206 if (status != RPC_S_OK)
207 goto cleanup;
208
209 /*
210 * On Windows 95/98, we must resolve the binding before calling
211 * SetAuthInfo. On Windows NT, we don't have to resolve yet,
212 * but it does no harm.
213 */
214 status = RpcEpResolveBinding(hAfsHandle, afsrpc_v1_0_c_ifspec);
215 if (status != RPC_S_OK)
216 goto cleanup;
217
218 if (encryptionOff) {
219 authnLevel = RPC_C_AUTHN_LEVEL_NONE;
220 authnSvc = RPC_C_AUTHN_WINNT;
221 } else {
222 authnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
223 authnSvc = RPC_C_AUTHN_WINNT;
224 }
225
226 status =
227 RpcBindingSetAuthInfo(hAfsHandle, NULL, authnLevel, authnSvc, NULL,
228 RPC_C_AUTHZ_NONE);
229 if (status != RPC_S_OK)
230 goto cleanup;
231
232 RpcTryExcept {
233 status = AFSRPC_GetToken(uuid, sessionKey);
234 }
235 RpcExcept(1) {
236 status = RpcExceptionCode();
237 }
238 RpcEndExcept cleanup:if (stringBinding)
239 RpcStringFree(&stringBinding);
240
241 if (hAfsHandle != NULL)
242 RpcBindingFree(&hAfsHandle);
243
244 return status;
245 }
246
247 int
248 ktc_SetToken(struct ktc_principal *server, struct ktc_token *token,
249 struct ktc_principal *client, int flags)
250 {
251 struct ViceIoctl iob;
252 char tbuffer[TBUFFERSIZE];
253 int len;
254 char *tp;
255 struct ClearToken ct;
256 int temp;
257 int code;
258 RPC_STATUS status;
259 afs_uuid_t uuid;
260 HANDLE ktcMutex = NULL;
261
262 if (token->ticketLen < MINKTCTICKETLEN
263 || token->ticketLen > MAXKTCTICKETLEN)
264 return KTC_INVAL;
265
266 if (strcmp(server->name, "afs")) {
267 return SetLocalToken(server, token, client, flags);
268 }
269
270 tp = tbuffer;
271
272 /* ticket length */
273 memcpy(tp, &token->ticketLen, sizeof(token->ticketLen));
274 tp += sizeof(token->ticketLen);
275 len = sizeof(token->ticketLen);
276
277 /* ticket */
278 if (len + token->ticketLen > TBUFFERSIZE)
279 return KTC_INVAL;
280 memcpy(tp, token->ticket, token->ticketLen);
281 tp += token->ticketLen;
282 len += token->ticketLen;
283
284 /* clear token */
285 ct.AuthHandle = token->kvno;
286 /*
287 * Instead of sending the session key in the clear, we zero it,
288 * and send it later, via RPC, encrypted.
289 */
290 #ifndef AFS_WIN95_ENV
291 /*
292 * memcpy(ct.HandShakeKey, &token->sessionKey, sizeof(token->sessionKey));
293 */
294 memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
295 #else
296 memcpy(ct.HandShakeKey, &token->sessionKey, sizeof(token->sessionKey));
297 #endif
298 ct.BeginTimestamp = token->startTime;
299 ct.EndTimestamp = token->endTime;
300 if (ct.BeginTimestamp == 0)
301 ct.BeginTimestamp = 1;
302
303 /* We don't know from Vice ID's yet */
304 ct.ViceId = 37; /* XXX */
305 if (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1)
306 ct.BeginTimestamp++; /* force lifetime to be even */
307
308 /* size of clear token */
309 if (len + sizeof(temp) > TBUFFERSIZE)
310 return KTC_INVAL;
311 temp = sizeof(struct ClearToken);
312 memcpy(tp, &temp, sizeof(temp));
313 tp += sizeof(temp);
314 len += sizeof(temp);
315
316 /* clear token itself */
317 if (len + sizeof(ct) > TBUFFERSIZE)
318 return KTC_INVAL;
319 memcpy(tp, &ct, sizeof(ct));
320 tp += sizeof(ct);
321 len += sizeof(ct);
322
323 /* flags; on NT there is no setpag flag, but there is an
324 * integrated logon flag */
325 if (len + sizeof(temp) > TBUFFERSIZE)
326 return KTC_INVAL;
327 temp = ((flags & AFS_SETTOK_LOGON) ? PIOCTL_LOGON : 0);
328 memcpy(tp, &temp, sizeof(temp));
329 tp += sizeof(temp);
330 len += sizeof(temp);
331
332 /* cell name */
333 temp = (int)strlen(server->cell) + 1;
334 if (len + temp > TBUFFERSIZE ||
335 temp > MAXKTCREALMLEN)
336 return KTC_INVAL;
337 strcpy(tp, server->cell);
338 tp += temp;
339 len += temp;
340
341 /* user name */
342 temp = (int)strlen(client->name) + 1;
343 if (len + temp > TBUFFERSIZE ||
344 temp > MAXKTCNAMELEN)
345 return KTC_INVAL;
346 strcpy(tp, client->name);
347 tp += temp;
348 len += temp;
349
350 /* we need the SMB user name to associate the tokens with in the
351 * integrated logon case. */
352 if (flags & AFS_SETTOK_LOGON) {
353 if (client->smbname == NULL)
354 temp = 1;
355 else
356 temp = (int)strlen(client->smbname) + 1;
357 if (temp == 1 ||
358 len + temp > TBUFFERSIZE ||
359 temp > MAXKTCNAMELEN)
360 return KTC_INVAL;
361 strcpy(tp, client->smbname);
362 tp += temp;
363 len += temp;
364 }
365
366 /* uuid */
367 if (len + sizeof(uuid) > TBUFFERSIZE)
368 return KTC_INVAL;
369 status = UuidCreate((UUID *) & uuid);
370 memcpy(tp, &uuid, sizeof(uuid));
371 tp += sizeof(uuid);
372 len += sizeof(uuid);
373
374 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
375 if (ktcMutex == NULL)
376 return KTC_TOKEN_MUTEX_FAIL;
377 if (GetLastError() == ERROR_ALREADY_EXISTS) {
378 if (WaitForSingleObject(ktcMutex, INFINITE) != WAIT_OBJECT_0) {
379 CloseHandle(ktcMutex);
380 return KTC_TOKEN_MUTEX_FAIL;
381 }
382 }
383
384 /* RPC to send session key */
385 status = send_key(uuid, token->sessionKey.data);
386 if (status != RPC_S_OK) {
387 if (status == 1)
388 strcpy(rpcErr, "RPC failure in AFS gateway");
389 else
390 DceErrorInqText(status, rpcErr);
391
392 ReleaseMutex(ktcMutex);
393 CloseHandle(ktcMutex);
394
395 if (status == RPC_S_SERVER_UNAVAILABLE ||
396 status == EPT_S_NOT_REGISTERED) {
397 return KTC_NOCMRPC;
398 } else {
399 return KTC_RPC;
400 }
401 }
402
403 /* set up for pioctl */
404 iob.in = tbuffer;
405 iob.in_size = (long)(tp - tbuffer);
406 iob.out = tbuffer;
407 iob.out_size = sizeof(tbuffer);
408
409 code = pioctl(0, VIOCSETTOK, &iob, 0);
410
411 ReleaseMutex(ktcMutex);
412 CloseHandle(ktcMutex);
413
414 if (code) {
415 if (code == -1) {
416 if (errno == ESRCH)
417 return KTC_NOCELL;
418 else if (errno == ENODEV)
419 return KTC_NOCM;
420 else if (errno == EINVAL)
421 return KTC_INVAL;
422 else
423 return KTC_PIOCTLFAIL;
424 } else
425 return KTC_PIOCTLFAIL;
426 }
427
428 return 0;
429 }
430
431 int
432 ktc_SetTokenEx(struct ktc_setTokenData *token)
433 {
434 /* Not yet implemented */
435 return KTC_PIOCTLFAIL;
436 }
437
438 int
439 ktc_GetToken(struct ktc_principal *server, struct ktc_token *token,
440 int tokenLen, struct ktc_principal *client)
441 {
442 struct ViceIoctl iob;
443 char tbuffer[TBUFFERSIZE];
444 size_t len;
445 char *tp, *cp;
446 char *ticketP;
447 int ticketLen, temp;
448 struct ClearToken ct;
449 char *cellName;
450 int cellNameSize;
451 int maxLen;
452 int code;
453 RPC_STATUS status;
454 afs_uuid_t uuid;
455 HANDLE ktcMutex = NULL;
456
457 tp = tbuffer;
458
459 /* check to see if the user is requesting tokens for a principal
460 * other than afs. If so, check the local token cache.
461 */
462 if (strcmp(server->name, "afs")) {
463 return GetLocalToken(server, token, tokenLen, client);
464 }
465
466 /* cell name */
467 len = strlen(server->cell) + 1;
468 strcpy(tp, server->cell);
469 tp += len;
470
471 /* uuid */
472 status = UuidCreate((UUID *) & uuid);
473 memcpy(tp, &uuid, sizeof(uuid));
474 tp += sizeof(uuid);
475 len += sizeof(uuid);
476
477 iob.in = tbuffer;
478 iob.in_size = (long)(tp - tbuffer);
479 iob.out = tbuffer;
480 iob.out_size = sizeof(tbuffer);
481
482 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
483 if (ktcMutex == NULL)
484 return KTC_TOKEN_MUTEX_FAIL;
485 if (GetLastError() == ERROR_ALREADY_EXISTS) {
486 if (WaitForSingleObject(ktcMutex, INFINITE) != WAIT_OBJECT_0) {
487 CloseHandle(ktcMutex);
488 return KTC_TOKEN_MUTEX_FAIL;
489 }
490 }
491
492 code = pioctl(0, VIOCNEWGETTOK, &iob, 0);
493 if (code) {
494 ReleaseMutex(ktcMutex);
495 CloseHandle(ktcMutex);
496
497 if (code == -1) {
498 if (errno == ESRCH)
499 return KTC_NOCELL;
500 else if (errno == ENODEV)
501 return KTC_NOCM;
502 else if (errno == EINVAL)
503 return KTC_INVAL;
504 else if (errno == EDOM)
505 return KTC_NOENT;
506 else
507 return KTC_PIOCTLFAIL;
508 } else
509 return KTC_PIOCTLFAIL;
510 }
511
512 /* RPC to receive session key */
513 status = receive_key(uuid, token->sessionKey.data);
514
515 ReleaseMutex(ktcMutex);
516 CloseHandle(ktcMutex);
517
518 if (status != RPC_S_OK) {
519 if (status == 1)
520 strcpy(rpcErr, "RPC failure in AFS gateway");
521 else
522 DceErrorInqText(status, rpcErr);
523
524 if (status == RPC_S_SERVER_UNAVAILABLE ||
525 status == EPT_S_NOT_REGISTERED)
526 return KTC_NOCMRPC;
527 else
528 return KTC_RPC;
529 }
530
531 cp = tbuffer;
532
533 /* ticket length */
534 memcpy(&ticketLen, cp, sizeof(ticketLen));
535 cp += sizeof(ticketLen);
536 len = sizeof(ticketLen);
537
538 /* remember where ticket is and skip over it */
539 if (len + ticketLen > TBUFFERSIZE ||
540 len + ticketLen > iob.out_size)
541 return KTC_ERROR;
542 ticketP = cp;
543 cp += ticketLen;
544 len += ticketLen;
545
546 /* size of clear token */
547 if (len + sizeof(temp) > TBUFFERSIZE ||
548 len + sizeof(temp) > iob.out_size)
549 return KTC_ERROR;
550 memcpy(&temp, cp, sizeof(temp));
551 cp += sizeof(temp);
552 len += sizeof(temp);
553 if (temp != sizeof(ct))
554 return KTC_ERROR;
555
556 /* clear token */
557 if (len + temp > TBUFFERSIZE ||
558 len + temp > iob.out_size)
559 return KTC_ERROR;
560 memcpy(&ct, cp, temp);
561 cp += temp;
562 len += temp;
563
564 /* skip over primary flag */
565 if (len + sizeof(temp) > TBUFFERSIZE ||
566 len + sizeof(temp) > iob.out_size)
567 return KTC_ERROR;
568 cp += sizeof(temp);
569 len += sizeof(temp);
570
571 /* remember cell name and skip over it */
572 cellName = cp;
573 cellNameSize = (int)strlen(cp);
574 if (len + cellNameSize + 1 > TBUFFERSIZE ||
575 len + cellNameSize + 1 > iob.out_size)
576 return KTC_ERROR;
577 cp += cellNameSize + 1;
578 len += cellNameSize + 1;
579
580 /* user name is here */
581
582 /* check that ticket will fit
583 * this compares the size of the ktc_token allocated by the app
584 * which might be smaller than the current definition of MAXKTCTICKETLEN
585 */
586 maxLen = tokenLen - sizeof(struct ktc_token) + MAXKTCTICKETLEN;
587 if (maxLen < ticketLen)
588 return KTC_TOOBIG;
589
590 /* set return values */
591 memcpy(token->ticket, ticketP, ticketLen);
592 token->startTime = ct.BeginTimestamp;
593 token->endTime = ct.EndTimestamp;
594 if (ct.AuthHandle == -1)
595 ct.AuthHandle = 999;
596 token->kvno = ct.AuthHandle;
597 #ifndef AFS_WIN95_ENV
598 /*
599 * Session key has already been set via RPC
600 */
601 #else
602 memcpy(&token->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
603 #endif /* AFS_WIN95_ENV */
604 token->ticketLen = ticketLen;
605 if (client) {
606 strcpy(client->name, cp);
607 client->instance[0] = '\0';
608 strcpy(client->cell, cellName);
609 }
610
611 return 0;
612 }
613
614 /*!
615 * Get a token, given the cell that we need to get information for
616 *
617 * @param cellName
618 * The name of the cell we're getting the token for - if NULL, we'll
619 * get information for the primary cell
620 */
621 int
622 ktc_GetTokenEx(char *cellName, struct ktc_setTokenData **tokenSet) {
623 struct ViceIoctl iob;
624 char tbuffer[MAXPIOCTLTOKENLEN];
625 char *tp;
626 afs_int32 code;
627 XDR xdrs;
628 HANDLE ktcMutex = NULL;
629
630 tp = tbuffer;
631
632 /* If we have a cellName, write it out here */
633 if (cellName) {
634 memcpy(tp, cellName, strlen(cellName) +1);
635 tp += strlen(cellName)+1;
636 }
637
638 iob.in = tbuffer;
639 iob.in_size = tp - tbuffer;
640 iob.out = tbuffer;
641 iob.out_size = sizeof(tbuffer);
642
643 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
644 if (ktcMutex == NULL)
645 return KTC_TOKEN_MUTEX_FAIL;
646 if (GetLastError() == ERROR_ALREADY_EXISTS) {
647 if (WaitForSingleObject(ktcMutex, INFINITE) != WAIT_OBJECT_0) {
648 CloseHandle(ktcMutex);
649 return KTC_TOKEN_MUTEX_FAIL;
650 }
651 }
652
653 #if 0
654 code = pioctl(0, VIOC_GETTOK2, &iob, 0);
655 #else
656 code = -1; /* not yet implemented */
657 errno = EINVAL;
658 #endif
659
660 ReleaseMutex(ktcMutex);
661 CloseHandle(ktcMutex);
662
663 /* If we can't use the new pioctl, the fall back to the old one. We then
664 * need to convert the rxkad token we get back into the new format
665 */
666 if (code == -1 && errno == EINVAL) {
667 struct ktc_principal server;
668 struct ktc_principal client;
669 struct ktc_tokenUnion token;
670 struct ktc_token *ktcToken; /* too huge for the stack */
671
672 memset(&server, 0, sizeof(server));
673 ktcToken = malloc(sizeof(struct ktc_token));
674 if (ktcToken == NULL)
675 return ENOMEM;
676 memset(ktcToken, 0, sizeof(struct ktc_token));
677
678 strcpy(server.name, "afs");
679 strcpy(server.cell, cellName);
680 code = ktc_GetToken(&server, ktcToken, sizeof(struct ktc_token),
681 &client);
682 if (code == 0) {
683 *tokenSet = token_buildTokenJar(cellName);
684 token.at_type = AFSTOKEN_UNION_KAD;
685 token.ktc_tokenUnion_u.at_kad.rk_kvno = ktcToken->kvno;
686 memcpy(token.ktc_tokenUnion_u.at_kad.rk_key,
687 ktcToken->sessionKey.data, 8);
688
689 token.ktc_tokenUnion_u.at_kad.rk_begintime = ktcToken->startTime;
690 token.ktc_tokenUnion_u.at_kad.rk_endtime = ktcToken->endTime;
691 token.ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_len
692 = ktcToken->ticketLen;
693 token.ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_val
694 = ktcToken->ticket;
695
696 token_addToken(*tokenSet, &token);
697
698 memset(ktcToken, 0, sizeof(struct ktc_token));
699 }
700 free(ktcToken);
701 return code;
702 }
703 if (code)
704 return KTC_PIOCTLFAIL;
705
706 *tokenSet = malloc(sizeof(struct ktc_setTokenData));
707 if (*tokenSet == NULL)
708 return ENOMEM;
709 memset(*tokenSet, 0, sizeof(struct ktc_setTokenData));
710
711 xdrmem_create(&xdrs, iob.out, iob.out_size, XDR_DECODE);
712 if (!xdr_ktc_setTokenData(&xdrs, *tokenSet)) {
713 free(*tokenSet);
714 *tokenSet = NULL;
715 xdr_destroy(&xdrs);
716 return EINVAL;
717 }
718 xdr_destroy(&xdrs);
719 return 0;
720 }
721
722 int
723 ktc_ListTokens(int cellNum, int *cellNumP, struct ktc_principal *server)
724 {
725 struct ViceIoctl iob;
726 char tbuffer[TBUFFERSIZE];
727 int len;
728 char *tp, *cp;
729 int newIter, ticketLen, temp;
730 int code;
731 HANDLE ktcMutex = NULL;
732
733 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
734 if (ktcMutex == NULL)
735 return KTC_TOKEN_MUTEX_FAIL;
736 if (GetLastError() == ERROR_ALREADY_EXISTS) {
737 if (WaitForSingleObject(ktcMutex, INFINITE) != WAIT_OBJECT_0) {
738 CloseHandle(ktcMutex);
739 return KTC_TOKEN_MUTEX_FAIL;
740 }
741 }
742
743 tp = tbuffer;
744
745 /* iterator */
746 memcpy(tp, &cellNum, sizeof(cellNum));
747 tp += sizeof(cellNum);
748
749 /* do pioctl */
750 iob.in = tbuffer;
751 iob.in_size = (long)(tp - tbuffer);
752 iob.out = tbuffer;
753 iob.out_size = sizeof(tbuffer);
754
755 code = pioctl(0, VIOCGETTOK, &iob, 0);
756
757 ReleaseMutex(ktcMutex);
758 CloseHandle(ktcMutex);
759
760 if (code) {
761 if (code == -1) {
762 if (errno == ESRCH)
763 return KTC_NOCELL;
764 else if (errno == ENODEV)
765 return KTC_NOCM;
766 else if (errno == EINVAL)
767 return KTC_INVAL;
768 else if (errno == EDOM)
769 return KTC_NOENT;
770 else
771 return KTC_PIOCTLFAIL;
772 } else
773 return KTC_PIOCTLFAIL;
774 }
775
776 cp = tbuffer;
777
778 /* new iterator */
779 memcpy(&newIter, cp, sizeof(newIter));
780 cp += sizeof(newIter);
781 len = sizeof(newIter);
782
783 /* ticket length */
784 if (len + sizeof(ticketLen) > TBUFFERSIZE ||
785 len + sizeof(ticketLen) > iob.out_size)
786 return KTC_ERROR;
787 memcpy(&ticketLen, cp, sizeof(ticketLen));
788 cp += sizeof(ticketLen);
789 len += sizeof(ticketLen);
790
791 /* skip over ticket */
792 cp += ticketLen;
793 len += ticketLen;
794
795 /* clear token size */
796 if (len + sizeof(temp) > TBUFFERSIZE ||
797 len + sizeof(temp) > iob.out_size)
798 return KTC_ERROR;
799 memcpy(&temp, cp, sizeof(temp));
800 cp += sizeof(temp);
801 len += sizeof(temp);
802 if (temp != sizeof(struct ClearToken))
803 return KTC_ERROR;
804
805 /* skip over clear token */
806 cp += sizeof(struct ClearToken);
807 len += sizeof(struct ClearToken);
808
809 /* skip over primary flag */
810 cp += sizeof(temp);
811 len += sizeof(temp);
812 if (len > TBUFFERSIZE ||
813 len > iob.out_size)
814 return KTC_ERROR;
815
816 /* cell name is here */
817
818 /* set return values */
819 if (len + temp > TBUFFERSIZE ||
820 temp > MAXKTCREALMLEN)
821 return KTC_ERROR;
822 strcpy(server->cell, cp);
823 server->instance[0] = '\0';
824 strcpy(server->name, "afs");
825
826 *cellNumP = newIter;
827 return 0;
828 }
829
830 int
831 ktc_ForgetToken(struct ktc_principal *server)
832 {
833 struct ViceIoctl iob;
834 char tbuffer[TBUFFERSIZE];
835 char *tp;
836 int code;
837 HANDLE ktcMutex = NULL;
838
839 if (strcmp(server->name, "afs")) {
840 return ForgetOneLocalToken(server);
841 }
842 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
843 if (ktcMutex == NULL)
844 return KTC_TOKEN_MUTEX_FAIL;
845 if (GetLastError() == ERROR_ALREADY_EXISTS) {
846 if (WaitForSingleObject(ktcMutex, INFINITE) != WAIT_OBJECT_0) {
847 CloseHandle(ktcMutex);
848 return KTC_TOKEN_MUTEX_FAIL;
849 }
850 }
851
852 tp = tbuffer;
853
854 /* cell name */
855 strcpy(tp, server->cell);
856 tp += strlen(tp) + 1;
857
858 /* do pioctl */
859 iob.in = tbuffer;
860 iob.in_size = (long)(tp - tbuffer);
861 iob.out = tbuffer;
862 iob.out_size = sizeof(tbuffer);
863
864 code = pioctl(0, VIOCDELTOK, &iob, 0);
865 ReleaseMutex(ktcMutex);
866 CloseHandle(ktcMutex);
867
868 if (code) {
869 if (code == -1) {
870 if (errno == ESRCH)
871 return KTC_NOCELL;
872 else if (errno == EDOM)
873 return KTC_NOENT;
874 else if (errno == ENODEV)
875 return KTC_NOCM;
876 else
877 return KTC_PIOCTLFAIL;
878 } else
879 return KTC_PIOCTLFAIL;
880 }
881 return 0;
882 }
883
884 int
885 ktc_ForgetAllTokens()
886 {
887 struct ViceIoctl iob;
888 char tbuffer[TBUFFERSIZE];
889 int code;
890 HANDLE ktcMutex = NULL;
891
892 (void)ForgetLocalTokens();
893
894 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
895 if (ktcMutex == NULL)
896 return KTC_TOKEN_MUTEX_FAIL;
897 if (GetLastError() == ERROR_ALREADY_EXISTS) {
898 if (WaitForSingleObject(ktcMutex, INFINITE) != WAIT_OBJECT_0) {
899 CloseHandle(ktcMutex);
900 return KTC_TOKEN_MUTEX_FAIL;
901 }
902 }
903
904 /* do pioctl */
905 iob.in = tbuffer;
906 iob.in_size = 0;
907 iob.out = tbuffer;
908 iob.out_size = sizeof(tbuffer);
909
910 code = pioctl(0, VIOCDELALLTOK, &iob, 0);
911 ReleaseMutex(ktcMutex);
912 CloseHandle(ktcMutex);
913
914 if (code) {
915 if (code == -1) {
916 if (errno == ENODEV)
917 return KTC_NOCM;
918 else
919 return KTC_PIOCTLFAIL;
920 } else
921 return KTC_PIOCTLFAIL;
922 }
923 return 0;
924 }
925
926 int
927 ktc_OldPioctl()
928 {
929 return 1;
930 }
931
932
933 #define MAXLOCALTOKENS 4
934
935 static struct {
936 int valid;
937 struct ktc_principal server;
938 struct ktc_principal client;
939 struct ktc_token token;
940 } local_tokens[MAXLOCALTOKENS] = {
941 0};
942
943 static int
944 SetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
945 struct ktc_principal *aclient, afs_int32 flags)
946 {
947 int found = -1;
948 int i;
949
950 LOCK_GLOBAL_MUTEX;
951 for (i = 0; i < MAXLOCALTOKENS; i++)
952 if (local_tokens[i].valid) {
953 if ((strcmp(local_tokens[i].server.name, aserver->name) == 0)
954 && (strcmp(local_tokens[i].server.instance, aserver->instance)
955 == 0)
956 && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
957 found = i; /* replace existing entry */
958 break;
959 }
960 } else if (found == -1)
961 found = i; /* remember empty slot but keep looking for a match */
962 if (found == -1) {
963 UNLOCK_GLOBAL_MUTEX;
964 return KTC_NOENT;
965 }
966 memcpy(&local_tokens[found].token, atoken, sizeof(struct ktc_token));
967 memcpy(&local_tokens[found].server, aserver,
968 sizeof(struct ktc_principal));
969 memcpy(&local_tokens[found].client, aclient,
970 sizeof(struct ktc_principal));
971 local_tokens[found].valid = 1;
972 UNLOCK_GLOBAL_MUTEX;
973 return 0;
974 }
975
976
977 static int
978 GetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
979 int atokenLen, struct ktc_principal *aclient)
980 {
981 int i;
982
983 LOCK_GLOBAL_MUTEX;
984 for (i = 0; i < MAXLOCALTOKENS; i++)
985 if (local_tokens[i].valid
986 && (strcmp(local_tokens[i].server.name, aserver->name) == 0)
987 && (strcmp(local_tokens[i].server.instance, aserver->instance) ==
988 0)
989 && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
990 memcpy(atoken, &local_tokens[i].token,
991 min(atokenLen, sizeof(struct ktc_token)));
992 memcpy(aclient, &local_tokens[i].client,
993 sizeof(struct ktc_principal));
994 UNLOCK_GLOBAL_MUTEX;
995 return 0;
996 }
997 UNLOCK_GLOBAL_MUTEX;
998 return KTC_NOENT;
999 }
1000
1001
1002 static int
1003 ForgetLocalTokens()
1004 {
1005 int i;
1006
1007 LOCK_GLOBAL_MUTEX;
1008 for (i = 0; i < MAXLOCALTOKENS; i++) {
1009 local_tokens[i].valid = 0;
1010 memset(&local_tokens[i].token.sessionKey, 0,
1011 sizeof(struct ktc_encryptionKey));
1012 }
1013 UNLOCK_GLOBAL_MUTEX;
1014 return 0;
1015 }
1016
1017
1018 static int
1019 ForgetOneLocalToken(struct ktc_principal *aserver)
1020 {
1021 int i;
1022
1023 LOCK_GLOBAL_MUTEX;
1024 for (i = 0; i < MAXLOCALTOKENS; i++) {
1025 if (local_tokens[i].valid
1026 && (strcmp(local_tokens[i].server.name, aserver->name) == 0)
1027 && (strcmp(local_tokens[i].server.instance, aserver->instance) ==
1028 0)
1029 && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
1030 local_tokens[i].valid = 0;
1031 memset(&local_tokens[i].token.sessionKey, 0,
1032 sizeof(struct ktc_encryptionKey));
1033 UNLOCK_GLOBAL_MUTEX;
1034 return 0;
1035 }
1036 }
1037 UNLOCK_GLOBAL_MUTEX;
1038 return KTC_NOENT;
1039 }
1040
1041 /*!
1042 * An iterator which can list all cells with tokens in the cache
1043 *
1044 * This function may be used to list the names of all cells for which
1045 * tokens exist in the current cache. The first time that it is called,
1046 * prevIndex should be set to 0. On all subsequent calls, prevIndex
1047 * should be set to the value returned in newIndex by the last call
1048 * to the function. Note that there is no guarantee that the index value
1049 * is monotonically increasing.
1050 *
1051 * @param prevIndex
1052 * The index returned by the last call, or 0 if this is the first
1053 * call in an iteration
1054 * @param newIndex
1055 * A pointer to an int which, upon return, will hold the next value
1056 * to be used.
1057 * @param cellName
1058 * A pointer to a char * which, upon return, will hold a cellname.
1059 * This must be freed by the caller using free()
1060 */
1061
1062 int
1063 ktc_ListTokensEx(int prevIndex, int *newIndex, char **cellName) {
1064 struct ViceIoctl iob;
1065 char tbuffer[MAXPIOCTLTOKENLEN];
1066 afs_int32 code;
1067 afs_int32 index;
1068 struct ktc_setTokenData tokenSet;
1069 XDR xdrs;
1070 HANDLE ktcMutex = NULL;
1071
1072 memset(&tokenSet, 0, sizeof(tokenSet));
1073
1074 *cellName = NULL;
1075 *newIndex = prevIndex;
1076
1077 index = prevIndex;
1078
1079 while (index<100) { /* Safety, incase of pioctl failure */
1080 memset(tbuffer, 0, sizeof(tbuffer));
1081 iob.in = tbuffer;
1082 memcpy(tbuffer, &index, sizeof(afs_int32));
1083 iob.in_size = sizeof(afs_int32);
1084 iob.out = tbuffer;
1085 iob.out_size = sizeof(tbuffer);
1086
1087 #if 0
1088 code = pioctl(0, VIOC_GETTOK2, &iob, 0);
1089 #else
1090 code = -1; /* not yet implemented */
1091 errno = EINVAL;
1092 #endif
1093
1094 /* Can't use new pioctl, so must use old one */
1095 if (code == -1 && errno == EINVAL) {
1096 struct ktc_principal server;
1097
1098 code = ktc_ListTokens(index, newIndex, &server);
1099 if (code == 0)
1100 *cellName = strdup(server.cell);
1101 return code;
1102 }
1103
1104 if (code == 0) {
1105 /* Got a token from the pioctl. Now we throw it away,
1106 * so we can return just a cellname. This is rather wasteful,
1107 * but it's what the old API does. Ho hum. */
1108
1109 xdrmem_create(&xdrs, iob.out, iob.out_size, XDR_DECODE);
1110 if (!xdr_ktc_setTokenData(&xdrs, &tokenSet)) {
1111 xdr_destroy(&xdrs);
1112 return EINVAL;
1113 }
1114 xdr_destroy(&xdrs);
1115 *cellName = strdup(tokenSet.cell);
1116 xdr_free((xdrproc_t)xdr_ktc_setTokenData, &tokenSet);
1117 *newIndex = index + 1;
1118 return 0;
1119 }
1120 index++;
1121 }
1122 return KTC_PIOCTLFAIL;
1123 }
1124