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