restore-original-size-test-20040402
[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 8192  
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 named pipe by default */
120     if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ", protseq, sizeof(protseq)))
121         strcpy(protseq, "ncacn_np");
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 named pipe by default */
193     if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ", protseq, sizeof(protseq)))
194         strcpy(protseq, "ncacn_np");
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         {
373             ReleaseMutex(ktcMutex);
374             CloseHandle(ktcMutex);
375             return KTC_NOCMRPC;
376         }
377         else 
378         {
379             ReleaseMutex(ktcMutex);
380             CloseHandle(ktcMutex);
381             return KTC_RPC;
382         }
383     }
384 #endif /* AFS_WIN95_ENV */
385
386     /* set up for pioctl */
387     iob.in = tbuffer;
388     iob.in_size = tp - tbuffer;
389     iob.out = tbuffer;
390     iob.out_size = sizeof(tbuffer);
391
392     code = pioctl(0, VIOCSETTOK, &iob, 0);
393
394 #ifndef AFS_WIN95_ENV
395     ReleaseMutex(ktcMutex);
396     CloseHandle(ktcMutex);
397 #endif /* AFS_WIN95_ENV */
398
399     if (code) {
400         if (code == -1) {
401             if (errno == ESRCH)
402                 return KTC_NOCELL;
403             else if (errno == ENODEV)
404                 return KTC_NOCM;
405             else if (errno == EINVAL)
406                 return KTC_INVAL;
407             else
408                 return KTC_PIOCTLFAIL;
409         } else
410             return KTC_PIOCTLFAIL;
411     }
412
413     return 0;
414 }
415
416 int
417 ktc_GetToken(struct ktc_principal *server, struct ktc_token *token,
418              int tokenLen, struct ktc_principal *client)
419 {
420     struct ViceIoctl iob;
421     char tbuffer[TBUFFERSIZE];
422     char *tp, *cp;
423     char *ticketP;
424     int ticketLen, temp;
425     struct ClearToken ct;
426     char *cellName;
427     int cellNameSize;
428     int maxLen;
429     int code;
430     RPC_STATUS status;
431     afs_uuid_t uuid;
432     HANDLE ktcMutex = NULL;
433
434     tp = tbuffer;
435
436     /* check to see if the user is requesting tokens for a principal
437      * other than afs.  If so, check the local token cache.
438      */
439     if (strcmp(server->name, "afs")) {
440         return GetLocalToken(server, token, tokenLen, client);
441     }
442
443     /* cell name */
444     strcpy(tp, server->cell);
445     tp += strlen(server->cell) + 1;
446
447     /* uuid */
448     status = UuidCreate((UUID *) & uuid);
449     memcpy(tp, &uuid, sizeof(uuid));
450     tp += sizeof(uuid);
451
452     iob.in = tbuffer;
453     iob.in_size = tp - tbuffer;
454     iob.out = tbuffer;
455     iob.out_size = sizeof(tbuffer);
456
457 #ifndef AFS_WIN95_ENV           
458     ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
459     if ( ktcMutex == NULL )
460         return KTC_PIOCTLFAIL;
461     if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
462         if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
463             CloseHandle(ktcMutex);
464             return KTC_PIOCTLFAIL;
465         }
466     }
467 #endif /* AFS_WIN95_ENV */
468
469     code = pioctl(0, VIOCNEWGETTOK, &iob, 0);
470     if (code) {
471 #ifndef AFS_WIN95_ENV
472         ReleaseMutex(ktcMutex);
473         CloseHandle(ktcMutex);
474 #endif /* AFS_WIN95_ENV */
475         if (code == -1) {
476             if (errno == ESRCH)
477                 return KTC_NOCELL;
478             else if (errno == ENODEV)
479                 return KTC_NOCM;
480             else if (errno == EINVAL)
481                 return KTC_INVAL;
482             else if (errno == EDOM)
483                 return KTC_NOENT;
484             else
485                 return KTC_PIOCTLFAIL;
486         } else
487             return KTC_PIOCTLFAIL;
488     }                                                             
489
490 #ifndef AFS_WIN95_ENV           
491     /* get rid of RPC for win95 build */
492     /* RPC to receive session key */
493     status = receive_key(uuid, token->sessionKey.data);
494
495     ReleaseMutex(ktcMutex);
496     CloseHandle(ktcMutex);
497
498     if (status != RPC_S_OK) {
499         if (status == 1)
500             strcpy(rpcErr, "RPC failure in AFS gateway");
501         else
502             DceErrorInqText(status, rpcErr);
503         if (status == RPC_S_SERVER_UNAVAILABLE
504              || status == EPT_S_NOT_REGISTERED)
505             return KTC_NOCMRPC;
506         else 
507             return KTC_RPC;
508     }
509 #endif /* AFS_WIN95_ENV */
510
511     cp = tbuffer;
512
513     /* ticket length */
514     memcpy(&ticketLen, cp, sizeof(ticketLen));
515     cp += sizeof(ticketLen);
516
517     /* remember where ticket is and skip over it */
518     ticketP = cp;
519     cp += ticketLen;
520
521     /* size of clear token */
522     memcpy(&temp, cp, sizeof(temp));
523     cp += sizeof(temp);
524     if (temp != sizeof(ct))
525         return KTC_ERROR;
526
527     /* clear token */
528     memcpy(&ct, cp, temp);
529     cp += temp;
530
531     /* skip over primary flag */
532     cp += sizeof(temp);
533
534     /* remember cell name and skip over it */
535     cellName = cp;
536     cellNameSize = strlen(cp);
537     cp += cellNameSize + 1;
538
539     /* user name is here */
540
541     /* check that ticket will fit 
542          * this compares the size of the ktc_token allocated by the app
543          * which might be smaller than the current definition of MAXKTCTICKETLEN
544          */
545         maxLen = tokenLen - sizeof(struct ktc_token) + MAXKTCTICKETLEN;
546         if (maxLen < ticketLen)
547                 return KTC_TOOBIG;
548
549     /* set return values */
550     memcpy(token->ticket, ticketP, ticketLen);
551     token->startTime = ct.BeginTimestamp;
552     token->endTime = ct.EndTimestamp;
553     if (ct.AuthHandle == -1)
554         ct.AuthHandle = 999;
555     token->kvno = ct.AuthHandle;
556 #ifndef AFS_WIN95_ENV
557     /*
558      * Session key has already been set via RPC
559      */
560 #else
561     memcpy(&token->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
562 #endif /* AFS_WIN95_ENV */
563     token->ticketLen = ticketLen;
564     if (client) {
565         strcpy(client->name, cp);
566         client->instance[0] = '\0';
567         strcpy(client->cell, cellName);
568     }
569
570     return 0;
571 }
572
573 int
574 ktc_ListTokens(int cellNum, int *cellNumP, struct ktc_principal *server)
575 {
576     struct ViceIoctl iob;
577     char tbuffer[TBUFFERSIZE];
578     char *tp, *cp;
579     int newIter, ticketLen, temp;
580     int code;
581     HANDLE ktcMutex = NULL;
582
583 #ifndef AFS_WIN95_ENV           
584     ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
585     if ( ktcMutex == NULL )
586         return KTC_PIOCTLFAIL;
587     if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
588         if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
589             CloseHandle(ktcMutex);
590             return KTC_PIOCTLFAIL;
591         }
592     }
593 #endif /* AFS_WIN95_ENV */
594
595     tp = tbuffer;
596
597     /* iterator */
598     memcpy(tp, &cellNum, sizeof(cellNum));
599     tp += sizeof(cellNum);
600
601     /* do pioctl */
602     iob.in = tbuffer;
603     iob.in_size = tp - tbuffer;
604     iob.out = tbuffer;
605     iob.out_size = sizeof(tbuffer);
606
607     code = pioctl(0, VIOCGETTOK, &iob, 0);
608
609 #ifndef AFS_WIN95_ENV
610         ReleaseMutex(ktcMutex);
611         CloseHandle(ktcMutex);
612 #endif /* AFS_WIN95_ENV */
613
614     if (code) {
615         if (code == -1) {
616             if (errno == ESRCH)
617                 return KTC_NOCELL;
618             else if (errno == ENODEV)
619                 return KTC_NOCM;
620             else if (errno == EINVAL)
621                 return KTC_INVAL;
622             else if (errno == EDOM)
623                 return KTC_NOENT;
624             else
625                 return KTC_PIOCTLFAIL;
626         } else
627             return KTC_PIOCTLFAIL;
628     }
629
630     cp = tbuffer;
631
632     /* new iterator */
633     memcpy(&newIter, cp, sizeof(newIter));
634     cp += sizeof(newIter);
635
636     /* ticket length */
637     memcpy(&ticketLen, cp, sizeof(ticketLen));
638     cp += sizeof(ticketLen);
639
640     /* skip over ticket */
641     cp += ticketLen;
642
643     /* clear token size */
644     memcpy(&temp, cp, sizeof(temp));
645     cp += sizeof(temp);
646     if (temp != sizeof(struct ClearToken))
647         return KTC_ERROR;
648
649     /* skip over clear token */
650     cp += sizeof(struct ClearToken);
651
652     /* skip over primary flag */
653     cp += sizeof(temp);
654
655     /* cell name is here */
656
657     /* set return values */
658     strcpy(server->cell, cp);
659     server->instance[0] = '\0';
660     strcpy(server->name, "afs");
661
662     *cellNumP = newIter;
663     return 0;
664 }
665
666 int
667 ktc_ForgetToken(struct ktc_principal *server)
668 {
669     struct ViceIoctl iob;
670     char tbuffer[TBUFFERSIZE];
671     char *tp;
672     int code;
673     HANDLE ktcMutex = NULL;
674
675     if (strcmp(server->name, "afs")) {
676         return ForgetOneLocalToken(server);
677     }
678
679 #ifndef AFS_WIN95_ENV           
680     ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
681     if ( ktcMutex == NULL )
682         return KTC_PIOCTLFAIL;
683     if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
684         if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
685             CloseHandle(ktcMutex);
686             return KTC_PIOCTLFAIL;
687         }
688     }
689 #endif /* AFS_WIN95_ENV */
690
691     tp = tbuffer;
692
693     /* cell name */
694     strcpy(tp, server->cell);
695     tp += strlen(tp) + 1;
696
697     /* do pioctl */
698     iob.in = tbuffer;
699     iob.in_size = tp - tbuffer;
700     iob.out = tbuffer;
701     iob.out_size = sizeof(tbuffer);
702
703     code = pioctl(0, VIOCDELTOK, &iob, 0);
704 #ifndef AFS_WIN95_ENV
705     ReleaseMutex(ktcMutex);
706     CloseHandle(ktcMutex);
707 #endif /* AFS_WIN95_ENV */
708     if (code) {
709         if (code == -1) {
710             if (errno == ESRCH)
711                 return KTC_NOCELL;
712             else if (errno == EDOM)
713                 return KTC_NOENT;
714             else if (errno == ENODEV)
715                 return KTC_NOCM;
716             else
717                 return KTC_PIOCTLFAIL;
718         } else
719             return KTC_PIOCTLFAIL;
720     }
721     return 0;
722 }
723
724 int
725 ktc_ForgetAllTokens()
726 {
727     struct ViceIoctl iob;
728     char tbuffer[TBUFFERSIZE];
729     int code;
730     HANDLE ktcMutex = NULL;
731
732     (void)ForgetLocalTokens();
733
734 #ifndef AFS_WIN95_ENV           
735     ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
736     if ( ktcMutex == NULL )
737         return KTC_PIOCTLFAIL;
738     if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
739         if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
740             CloseHandle(ktcMutex);
741             return KTC_PIOCTLFAIL;
742         }
743     }
744 #endif /* AFS_WIN95_ENV */
745
746     /* do pioctl */
747     iob.in = tbuffer;
748     iob.in_size = 0;
749     iob.out = tbuffer;
750     iob.out_size = sizeof(tbuffer);
751
752     code = pioctl(0, VIOCDELALLTOK, &iob, 0);
753 #ifndef AFS_WIN95_ENV
754     ReleaseMutex(ktcMutex);
755     CloseHandle(ktcMutex);
756 #endif /* AFS_WIN95_ENV */
757     if (code) {
758         if (code == -1) {
759             if (errno == ENODEV)
760                 return KTC_NOCM;
761             else
762                 return KTC_PIOCTLFAIL;
763         } else
764             return KTC_PIOCTLFAIL;
765     }
766     return 0;
767 }
768
769 int
770 ktc_OldPioctl()
771 {
772     return 1;
773 }
774
775
776 #define MAXLOCALTOKENS 4
777
778 static struct {
779     int valid;
780     struct ktc_principal server;
781     struct ktc_principal client;
782     struct ktc_token token;
783 } local_tokens[MAXLOCALTOKENS] = {
784 0};
785
786 static int
787 SetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
788               struct ktc_principal *aclient, afs_int32 flags)
789 {
790     int found = -1;
791     int i;
792
793     LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++)
794         if (local_tokens[i].valid) {
795             if ((strcmp(local_tokens[i].server.name, aserver->name) == 0)
796                 && (strcmp(local_tokens[i].server.instance, aserver->instance)
797                     == 0)
798                 && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
799                 found = i;      /* replace existing entry */
800                 break;
801             }
802         } else if (found == -1)
803             found = i;          /* remember empty slot but keep looking for a match */
804     if (found == -1) {
805         UNLOCK_GLOBAL_MUTEX return KTC_NOENT;
806     }
807     memcpy(&local_tokens[found].token, atoken, sizeof(struct ktc_token));
808     memcpy(&local_tokens[found].server, aserver,
809            sizeof(struct ktc_principal));
810     memcpy(&local_tokens[found].client, aclient,
811            sizeof(struct ktc_principal));
812     local_tokens[found].valid = 1;
813     UNLOCK_GLOBAL_MUTEX return 0;
814 }
815
816
817 static int
818 GetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
819               int atokenLen, struct ktc_principal *aclient)
820 {
821     int i;
822
823     LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++)
824         if (local_tokens[i].valid
825             && (strcmp(local_tokens[i].server.name, aserver->name) == 0)
826             && (strcmp(local_tokens[i].server.instance, aserver->instance) ==
827                 0)
828             && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
829             memcpy(atoken, &local_tokens[i].token,
830                    min(atokenLen, sizeof(struct ktc_token)));
831             memcpy(aclient, &local_tokens[i].client,
832                    sizeof(struct ktc_principal));
833             UNLOCK_GLOBAL_MUTEX return 0;
834         }
835     UNLOCK_GLOBAL_MUTEX return KTC_NOENT;
836 }
837
838
839 static int
840 ForgetLocalTokens()
841 {
842     int i;
843
844     LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++) {
845         local_tokens[i].valid = 0;
846         memset(&local_tokens[i].token.sessionKey, 0,
847                sizeof(struct ktc_encryptionKey));
848     }
849     UNLOCK_GLOBAL_MUTEX return 0;
850 }
851
852
853 static int
854 ForgetOneLocalToken(struct ktc_principal *aserver)
855 {
856     int i;
857
858     LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++) {
859         if (local_tokens[i].valid
860             && (strcmp(local_tokens[i].server.name, aserver->name) == 0)
861             && (strcmp(local_tokens[i].server.instance, aserver->instance) ==
862                 0)
863             && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
864             local_tokens[i].valid = 0;
865             memset(&local_tokens[i].token.sessionKey, 0,
866                    sizeof(struct ktc_encryptionKey));
867             UNLOCK_GLOBAL_MUTEX return 0;
868         }
869     }
870     UNLOCK_GLOBAL_MUTEX return KTC_NOENT;
871 }