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