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