Standardize License information
[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 <afs/param.h>
13 #include <afs/stds.h>
14 #include <stdio.h>
15 #include <afs/pthread_glock.h>
16 #include <sys/types.h>
17 #include <ctype.h>
18 #include <sys/stat.h>
19 #include <signal.h>
20 #include <errno.h>
21 #include <rpc.h>
22 #include <afs/smb_iocons.h>
23 #include <afs/pioctl_nt.h>
24 #include "../WINNT/afsd/afsrpc.h"
25 #include <afs/vice.h>
26 #include "auth.h"
27 #include <afs/afsutil.h>
28
29
30 /* Forward declarations for local token cache. */
31 static int SetLocalToken(struct ktc_principal *aserver,
32                          struct ktc_token *atoken,
33                          struct ktc_principal *aclient,
34                          afs_int32 flags);
35 static int GetLocalToken(struct ktc_principal *aserver,
36                          struct ktc_token *atoken,
37                          int atokenLen,
38                          struct ktc_principal *aclient);
39 static int ForgetLocalTokens();
40 static int ForgetOneLocalToken(struct ktc_principal *aserver);
41
42
43 static char AFSConfigKeyName[] =
44         "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters";
45
46 /*
47  * Support for RPC's to send and receive session keys
48  *
49  * Session keys must not be sent and received in the clear.  We have no
50  * way to piggyback encryption on SMB, so we use a separate RPC, using
51  * packet privacy (when available).  In SetToken, the RPC is done first;
52  * in GetToken, the pioctl is done first.
53  */
54
55 char rpcErr[256];
56
57 void __RPC_FAR * __RPC_USER midl_user_allocate (size_t cBytes)
58 {
59         return ((void __RPC_FAR *) malloc(cBytes));
60 }
61
62 void __RPC_USER midl_user_free(void __RPC_FAR * p)
63 {
64         free(p);
65 }
66
67 /*
68  * Determine the server name to be used in the RPC binding.  If it is
69  * the same as the client (i.e. standalone, non-gateway), NULL can be
70  * used, so it is not necessary to call gethostbyname().
71  */
72 void getservername(char **snp, unsigned int snSize)
73 {
74         HKEY parmKey;
75         long code;
76
77         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
78                             0, KEY_QUERY_VALUE, &parmKey);
79         if (code != ERROR_SUCCESS)
80                 goto nogateway;
81         code = RegQueryValueEx(parmKey, "Gateway", NULL, NULL,
82                                 *snp, &snSize);
83         RegCloseKey (parmKey);
84         if (code == ERROR_SUCCESS)
85                 return;
86 nogateway:
87         /* No gateway name in registry; use ourself */
88         *snp = NULL;
89 }
90
91 RPC_STATUS send_key(afs_uuid_t uuid, char sessionKey[8])
92 {
93         RPC_STATUS status;
94         char *stringBinding = NULL;
95         ULONG authnLevel, authnSvc;
96         char serverName[256];
97         char *serverNamep = serverName;
98         char encrypt[32];
99         BOOL encryptionOff = FALSE;
100         char protseq[32];
101
102         /* Encryption on by default */
103         if (GetEnvironmentVariable("AFS_RPC_ENCRYPT",
104                                    encrypt, sizeof(encrypt)))
105                 if (!strcmpi(encrypt, "OFF"))
106                         encryptionOff = TRUE;
107
108         /* Protocol sequence is named pipe by default */
109         if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ",
110                                     protseq, sizeof(protseq)))
111                 strcpy(protseq, "ncacn_np");
112
113         /* Server name */
114         getservername(&serverNamep, sizeof(serverName));
115
116         status = RpcStringBindingCompose("",    /* obj uuid */
117                                          protseq,
118                                          serverNamep,
119                                          "",    /* endpoint */
120                                          "",    /* protocol options */
121                                          &stringBinding);
122         if (status != RPC_S_OK)
123                 goto cleanup;
124
125         status = RpcBindingFromStringBinding(stringBinding, &hAfsHandle);
126         if (status != RPC_S_OK)
127                 goto cleanup;
128
129         /*
130          * On Windows 95/98, we must resolve the binding before calling
131          * SetAuthInfo.  On Windows NT, we don't have to resolve yet,
132          * but it does no harm.
133          */
134         status = RpcEpResolveBinding(hAfsHandle, afsrpc_v1_0_c_ifspec);
135         if (status != RPC_S_OK)
136                 goto cleanup;
137
138         if (encryptionOff) {
139                 authnLevel = RPC_C_AUTHN_LEVEL_NONE;
140                 authnSvc = RPC_C_AUTHN_WINNT;
141         } else {
142                 authnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
143                 authnSvc = RPC_C_AUTHN_WINNT;
144         }
145
146         status = RpcBindingSetAuthInfo(hAfsHandle, NULL, authnLevel, authnSvc,
147                                         NULL, RPC_C_AUTHZ_NONE);
148         if (status != RPC_S_OK)
149                 goto cleanup;
150
151         RpcTryExcept {
152                 status = AFSRPC_SetToken(uuid, sessionKey);
153         }
154         RpcExcept(1) {
155                 status = RpcExceptionCode();
156         }
157         RpcEndExcept
158
159 cleanup:
160         if (stringBinding)
161                 RpcStringFree(&stringBinding);
162
163         if (hAfsHandle != NULL)
164                 RpcBindingFree(&hAfsHandle);
165
166         return status;
167 }
168
169 RPC_STATUS receive_key(afs_uuid_t uuid, char sessionKey[8])
170 {
171         RPC_STATUS status;
172         char *stringBinding = NULL;
173         ULONG authnLevel, authnSvc;
174         char serverName[256];
175         char *serverNamep = serverName;
176         char encrypt[32];
177         BOOL encryptionOff = FALSE;
178         char protseq[32];
179
180         /* Encryption on by default */
181         if (GetEnvironmentVariable("AFS_RPC_ENCRYPT",
182                                    encrypt, sizeof(encrypt)))
183                 if (!strcmpi(encrypt, "OFF"))
184                         encryptionOff = TRUE;
185
186         /* Protocol sequence is named pipe by default */
187         if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ",
188                                     protseq, sizeof(protseq)))
189                 strcpy(protseq, "ncacn_np");
190
191         /* Server name */
192         getservername(&serverNamep, sizeof(serverName));
193
194         status = RpcStringBindingCompose("",    /* obj uuid */
195                                          protseq,
196                                          serverNamep,
197                                          "",    /* endpoint */
198                                          "",    /* protocol options */
199                                          &stringBinding);
200         if (status != RPC_S_OK)
201                 goto cleanup;
202
203         status = RpcBindingFromStringBinding(stringBinding, &hAfsHandle);
204         if (status != RPC_S_OK)
205                 goto cleanup;
206
207         /*
208          * On Windows 95/98, we must resolve the binding before calling
209          * SetAuthInfo.  On Windows NT, we don't have to resolve yet,
210          * but it does no harm.
211          */
212         status = RpcEpResolveBinding(hAfsHandle, afsrpc_v1_0_c_ifspec);
213         if (status != RPC_S_OK)
214                 goto cleanup;
215
216         if (encryptionOff) {
217                 authnLevel = RPC_C_AUTHN_LEVEL_NONE;
218                 authnSvc = RPC_C_AUTHN_WINNT;
219         } else {
220                 authnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
221                 authnSvc = RPC_C_AUTHN_WINNT;
222         }
223
224         status = RpcBindingSetAuthInfo(hAfsHandle, NULL, authnLevel, authnSvc,
225                                         NULL, RPC_C_AUTHZ_NONE);
226         if (status != RPC_S_OK)
227                 goto cleanup;
228
229         RpcTryExcept {
230                 status = AFSRPC_GetToken(uuid, sessionKey);
231         }
232         RpcExcept(1) {
233                 status = RpcExceptionCode();
234         }
235         RpcEndExcept
236
237 cleanup:
238         if (stringBinding)
239                 RpcStringFree(&stringBinding);
240
241         if (hAfsHandle != NULL)
242                 RpcBindingFree(&hAfsHandle);
243
244         return status;
245 }
246
247 int ktc_SetToken(
248         struct ktc_principal *server,
249         struct ktc_token *token,
250         struct ktc_principal *client,
251         int flags)
252 {
253         struct ViceIoctl iob;
254         char tbuffer[1024];
255         char *tp;
256         struct ClearToken ct;
257         int temp;
258         int code;
259         RPC_STATUS status;
260         afs_uuid_t uuid;
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
276         /* ticket */
277         memcpy(tp, token->ticket, token->ticketLen);
278         tp += token->ticketLen;
279
280         /* clear token */
281         ct.AuthHandle = token->kvno;
282         /*
283          * Instead of sending the session key in the clear, we zero it,
284          * and send it later, via RPC, encrypted.
285          */
286         /*
287         memcpy(ct.HandShakeKey, &token->sessionKey, sizeof(token->sessionKey));
288          */
289         memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
290         ct.BeginTimestamp = token->startTime;
291         ct.EndTimestamp = token->endTime;
292         if (ct.BeginTimestamp == 0) ct.BeginTimestamp = 1;
293
294         /* We don't know from Vice ID's yet */
295         ct.ViceId = 37;                 /* XXX */
296         if (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1)
297                 ct.BeginTimestamp++;            /* force lifetime to be even */
298
299         /* size of clear token */
300         temp = sizeof(struct ClearToken);
301         memcpy(tp, &temp, sizeof(temp));
302         tp += sizeof(temp);
303
304         /* clear token itself */
305         memcpy(tp, &ct, sizeof(ct));
306         tp += sizeof(ct);
307
308         /* flags; on NT there is no setpag flag, but there is an
309          * integrated logon flag */
310         temp = ((flags & AFS_SETTOK_LOGON) ? PIOCTL_LOGON : 0);
311         memcpy(tp, &temp, sizeof(temp));
312         tp += sizeof(temp);
313
314         /* cell name */
315         temp = strlen(server->cell);
316         if (temp >= MAXKTCREALMLEN)
317                 return KTC_INVAL;
318         strcpy(tp, server->cell);
319         tp += temp+1;
320
321         /* user name */
322         temp = strlen(client->name);
323         if (temp >= MAXKTCNAMELEN)
324                 return KTC_INVAL;
325         strcpy(tp, client->name);
326         tp += temp+1;
327
328         /* uuid */
329         status = UuidCreate((UUID *)&uuid);
330         memcpy(tp, &uuid, sizeof(uuid));
331         tp += sizeof(uuid);
332
333         /* RPC to send session key */
334         status = send_key(uuid, token->sessionKey.data);
335         if (status != RPC_S_OK) {
336                 if (status == 1)
337                         strcpy(rpcErr, "RPC failure in AFS gateway");
338                 else
339                         DceErrorInqText(status, rpcErr);
340                 if (status == RPC_S_SERVER_UNAVAILABLE
341                     || status == EPT_S_NOT_REGISTERED)
342                         return KTC_NOCMRPC;
343                 else
344                         return KTC_RPC;
345         }
346
347         /* set up for pioctl */
348         iob.in = tbuffer;
349         iob.in_size = tp - tbuffer;
350         iob.out = tbuffer;
351         iob.out_size = sizeof(tbuffer);
352
353         code = pioctl(0, VIOCSETTOK, &iob, 0);
354         if (code) {
355                 if (code == -1) {
356                         if (errno == ESRCH)
357                                 return KTC_NOCELL;
358                         else if (errno == ENODEV)
359                                 return KTC_NOCM;
360                         else if (errno == EINVAL)
361                                 return KTC_INVAL;
362                         else
363                                 return KTC_PIOCTLFAIL;
364                 }
365                 else
366                         return KTC_PIOCTLFAIL;
367         }
368
369         return 0;
370 }
371
372 int ktc_GetToken(
373         struct ktc_principal *server,
374         struct ktc_token *token,
375         int tokenLen,
376         struct ktc_principal *client)
377 {
378         struct ViceIoctl iob;
379         char tbuffer[1024];
380         char *tp, *cp;
381         char *ticketP;
382         int ticketLen, temp;
383         struct ClearToken ct;
384         char *cellName;
385         int cellNameSize;
386         int maxLen;
387         int code;
388         RPC_STATUS status;
389         afs_uuid_t uuid;
390
391         tp = tbuffer;
392
393         /* check to see if the user is requesting tokens for a principal
394          * other than afs.  If so, check the local token cache.
395          */
396         if (strcmp(server->name, "afs")) {
397             return GetLocalToken(server, token, tokenLen, client);
398         }
399
400         /* cell name */
401         strcpy(tp, server->cell);
402         tp += strlen(server->cell) + 1;
403
404         /* uuid */
405         status = UuidCreate((UUID *)&uuid);
406         memcpy(tp, &uuid, sizeof(uuid));
407         tp += sizeof(uuid);
408
409         iob.in = tbuffer;
410         iob.in_size = tp - tbuffer;
411         iob.out = tbuffer;
412         iob.out_size = sizeof(tbuffer);
413
414         code = pioctl(0, VIOCNEWGETTOK, &iob, 0);
415         if (code) {
416                 if (code == -1) {
417                         if (errno == ESRCH)
418                                 return KTC_NOCELL;
419                         else if (errno == ENODEV)
420                                 return KTC_NOCM;
421                         else if (errno == EINVAL)
422                                 return KTC_INVAL;
423                         else if (errno == EDOM)
424                                 return KTC_NOENT;
425                         else
426                                 return KTC_PIOCTLFAIL;
427                 }
428                 else
429                         return KTC_PIOCTLFAIL;
430         }
431
432         /* RPC to receive session key */
433         status = receive_key(uuid, token->sessionKey.data);
434         if (status != RPC_S_OK) {
435                 if (status == 1)
436                         strcpy(rpcErr, "RPC failure in AFS gateway");
437                 else
438                         DceErrorInqText(status, rpcErr);
439                 if (status == RPC_S_SERVER_UNAVAILABLE
440                     || status == EPT_S_NOT_REGISTERED)
441                         return KTC_NOCMRPC;
442                 else
443                         return KTC_RPC;
444         }
445
446         cp = tbuffer;
447
448         /* ticket length */
449         memcpy(&ticketLen, cp, sizeof(ticketLen));
450         cp += sizeof(ticketLen);
451
452         /* remember where ticket is and skip over it */
453         ticketP = cp;
454         cp += ticketLen;
455
456         /* size of clear token */
457         memcpy(&temp, cp, sizeof(temp));
458         cp += sizeof(temp);
459         if (temp != sizeof(ct))
460                 return KTC_ERROR;
461
462         /* clear token */
463         memcpy(&ct, cp, temp);
464         cp += temp;
465
466         /* skip over primary flag */
467         cp += sizeof(temp);
468
469         /* remember cell name and skip over it */
470         cellName = cp;
471         cellNameSize = strlen(cp);
472         cp += cellNameSize + 1;
473
474         /* user name is here */
475
476         /* check that ticket will fit */
477         maxLen = tokenLen - sizeof(struct ktc_token) + MAXKTCTICKETLEN;
478         if (maxLen < ticketLen)
479                 return KTC_TOOBIG;
480
481         /* set return values */
482         memcpy(token->ticket, ticketP, ticketLen);
483         token->startTime = ct.BeginTimestamp;
484         token->endTime = ct.EndTimestamp;
485         if (ct.AuthHandle == -1) ct.AuthHandle = 999;
486         token->kvno = ct.AuthHandle;
487         /*
488          * Session key has already been set via RPC
489          */
490         /*
491         memcpy(&token->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
492          */
493         token->ticketLen = ticketLen;
494         if (client) {
495                 strcpy(client->name, cp);
496                 client->instance[0] = '\0';
497                 strcpy(client->cell, cellName);
498         }
499
500         return 0;
501 }
502
503 int ktc_ListTokens(
504         int cellNum,
505         int *cellNumP,
506         struct ktc_principal *server)
507 {
508         struct ViceIoctl iob;
509         char tbuffer[1024];
510         char *tp, *cp;
511         int newIter, ticketLen, temp;
512         int code;
513
514         tp = tbuffer;
515
516         /* iterator */
517         memcpy(tp, &cellNum, sizeof(cellNum));
518         tp += sizeof(cellNum);
519
520         /* do pioctl */
521         iob.in = tbuffer;
522         iob.in_size = tp - tbuffer;
523         iob.out = tbuffer;
524         iob.out_size = sizeof(tbuffer);
525
526         code = pioctl(0, VIOCGETTOK, &iob, 0);
527         if (code) {
528                 if (code == -1) {
529                         if (errno == ESRCH)
530                                 return KTC_NOCELL;
531                         else if (errno == ENODEV)
532                                 return KTC_NOCM;
533                         else if (errno == EINVAL)
534                                 return KTC_INVAL;
535                         else if (errno == EDOM)
536                                 return KTC_NOENT;
537                         else
538                                 return KTC_PIOCTLFAIL;
539                 }
540                 else
541                         return KTC_PIOCTLFAIL;
542         }
543
544         cp = tbuffer;
545
546         /* new iterator */
547         memcpy(&newIter, cp, sizeof(newIter));
548         cp += sizeof(newIter);
549
550         /* ticket length */
551         memcpy(&ticketLen, cp, sizeof(ticketLen));
552         cp += sizeof(ticketLen);
553
554         /* skip over ticket */
555         cp += ticketLen;
556
557         /* clear token size */
558         memcpy(&temp, cp, sizeof(temp));
559         cp += sizeof(temp);
560         if (temp != sizeof(struct ClearToken))
561                 return KTC_ERROR;
562
563         /* skip over clear token */
564         cp += sizeof(struct ClearToken);
565
566         /* skip over primary flag */
567         cp += sizeof(temp);
568
569         /* cell name is here */
570
571         /* set return values */
572         strcpy(server->cell, cp);
573         server->instance[0] = '\0';
574         strcpy(server->name, "afs");
575
576         *cellNumP = newIter;
577         return 0;
578 }
579
580 int ktc_ForgetToken(
581         struct ktc_principal *server)
582 {
583         struct ViceIoctl iob;
584         char tbuffer[1024];
585         char *tp;
586         int code;
587
588         if (strcmp(server->name, "afs")) {
589             return ForgetOneLocalToken(server);
590         }
591
592         tp = tbuffer;
593
594         /* cell name */
595         strcpy(tp, server->cell);
596         tp += strlen(tp) + 1;
597
598         /* do pioctl */
599         iob.in = tbuffer;
600         iob.in_size = tp - tbuffer;
601         iob.out = tbuffer;
602         iob.out_size = sizeof(tbuffer);
603
604         code = pioctl(0, VIOCDELTOK, &iob, 0);
605         if (code) {
606                 if (code == -1) {
607                         if (errno == ESRCH)
608                                 return KTC_NOCELL;
609                         else if (errno == EDOM)
610                                 return KTC_NOENT;
611                         else if (errno == ENODEV)
612                                 return KTC_NOCM;
613                         else
614                                 return KTC_PIOCTLFAIL;
615                 }
616                 else
617                         return KTC_PIOCTLFAIL;
618         }
619         return 0;
620 }
621
622 int ktc_ForgetAllTokens()
623 {
624         struct ViceIoctl iob;
625         char tbuffer[1024];
626         int code;
627
628         (void) ForgetLocalTokens();
629
630         /* do pioctl */
631         iob.in = tbuffer;
632         iob.in_size = 0;
633         iob.out = tbuffer;
634         iob.out_size = sizeof(tbuffer);
635
636         code = pioctl(0, VIOCDELALLTOK, &iob, 0);
637         if (code) {
638                 if (code == -1) {
639                         if (errno == ENODEV)
640                                 return KTC_NOCM;
641                         else
642                                 return KTC_PIOCTLFAIL;
643                 }
644                 else
645                         return KTC_PIOCTLFAIL;
646         }
647         return 0;
648 }
649
650 int ktc_OldPioctl ()
651 {
652     return 1;
653 }
654
655
656 #define MAXLOCALTOKENS 4
657
658 static struct {
659     int valid;
660     struct ktc_principal server;
661     struct ktc_principal client;
662     struct ktc_token token;
663 } local_tokens[MAXLOCALTOKENS] = {0};
664
665 static int SetLocalToken(struct ktc_principal *aserver,
666                          struct ktc_token *atoken,
667                          struct ktc_principal *aclient,
668                          afs_int32 flags)
669 {
670     int found = -1;
671     int i;
672
673     LOCK_GLOBAL_MUTEX
674     for (i = 0; i < MAXLOCALTOKENS; i++)
675         if (local_tokens[i].valid) {
676             if ((strcmp(local_tokens[i].server.name, aserver->name) == 0) &&
677                 (strcmp(local_tokens[i].server.instance,
678                         aserver->instance) == 0) &&
679                 (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
680                 found = i;      /* replace existing entry */
681                 break;
682             }
683         } else if (found == -1)
684             found = i; /* remember empty slot but keep looking for a match */
685     if (found == -1) {
686         UNLOCK_GLOBAL_MUTEX
687         return KTC_NOENT;
688     }
689     memcpy(&local_tokens[found].token, atoken, sizeof(struct ktc_token));
690     memcpy(&local_tokens[found].server, aserver, sizeof(struct ktc_principal));
691     memcpy(&local_tokens[found].client, aclient, sizeof(struct ktc_principal));
692     local_tokens[found].valid = 1;
693     UNLOCK_GLOBAL_MUTEX
694     return 0;
695 }
696
697
698 static int GetLocalToken(struct ktc_principal *aserver,
699                          struct ktc_token *atoken,
700                          int atokenLen,
701                          struct ktc_principal *aclient)
702 {
703     int i;
704
705     LOCK_GLOBAL_MUTEX
706     for (i = 0; i < MAXLOCALTOKENS; i++)
707         if (local_tokens[i].valid &&
708             (strcmp(local_tokens[i].server.name, aserver->name) == 0) &&
709             (strcmp(local_tokens[i].server.instance,aserver->instance) == 0) &&
710             (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
711             memcpy(atoken, &local_tokens[i].token,
712                    min(atokenLen, sizeof(struct ktc_token)));
713             memcpy(aclient, &local_tokens[i].client,
714                    sizeof(struct ktc_principal));
715             UNLOCK_GLOBAL_MUTEX
716             return 0;
717         }
718     UNLOCK_GLOBAL_MUTEX
719     return KTC_NOENT;
720 }
721
722
723 static int ForgetLocalTokens()
724 {
725     int i;
726
727     LOCK_GLOBAL_MUTEX
728     for (i = 0; i < MAXLOCALTOKENS; i++) {
729         local_tokens[i].valid = 0;
730         memset(&local_tokens[i].token.sessionKey, 0,
731                sizeof(struct ktc_encryptionKey));
732     }
733     UNLOCK_GLOBAL_MUTEX
734     return 0;
735 }
736
737
738 static int ForgetOneLocalToken(struct ktc_principal *aserver)
739 {
740     int i;
741
742     LOCK_GLOBAL_MUTEX
743     for (i = 0; i < MAXLOCALTOKENS; i++) {
744         if (local_tokens[i].valid &&
745             (strcmp(local_tokens[i].server.name, aserver->name) == 0) &&
746             (strcmp(local_tokens[i].server.instance,aserver->instance) == 0) &&
747             (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
748             local_tokens[i].valid = 0;
749             memset(&local_tokens[i].token.sessionKey, 0,
750                    sizeof(struct ktc_encryptionKey));
751             UNLOCK_GLOBAL_MUTEX
752             return 0;
753         }
754     }
755     UNLOCK_GLOBAL_MUTEX
756     return KTC_NOENT;
757 }