something-weird-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     if (MAXKTCTICKETLEN < 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
675 #ifndef AFS_WIN95_ENV           
676     ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
677     if ( ktcMutex == NULL )
678         return KTC_PIOCTLFAIL;
679     if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
680         if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
681             CloseHandle(ktcMutex);
682             return KTC_PIOCTLFAIL;
683         }
684     }
685 #endif /* AFS_WIN95_ENV */
686
687     tp = tbuffer;
688
689     /* cell name */
690     strcpy(tp, server->cell);
691     tp += strlen(tp) + 1;
692
693     /* do pioctl */
694     iob.in = tbuffer;
695     iob.in_size = tp - tbuffer;
696     iob.out = tbuffer;
697     iob.out_size = sizeof(tbuffer);
698
699     code = pioctl(0, VIOCDELTOK, &iob, 0);
700 #ifndef AFS_WIN95_ENV
701     ReleaseMutex(ktcMutex);
702     CloseHandle(ktcMutex);
703 #endif /* AFS_WIN95_ENV */
704     if (code) {
705         if (code == -1) {
706             if (errno == ESRCH)
707                 return KTC_NOCELL;
708             else if (errno == EDOM)
709                 return KTC_NOENT;
710             else if (errno == ENODEV)
711                 return KTC_NOCM;
712             else
713                 return KTC_PIOCTLFAIL;
714         } else
715             return KTC_PIOCTLFAIL;
716     }
717     return 0;
718 }
719
720 int
721 ktc_ForgetAllTokens()
722 {
723     struct ViceIoctl iob;
724     char tbuffer[TBUFFERSIZE];
725     int code;
726     HANDLE ktcMutex = NULL;
727
728     (void)ForgetLocalTokens();
729
730 #ifndef AFS_WIN95_ENV           
731     ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
732     if ( ktcMutex == NULL )
733         return KTC_PIOCTLFAIL;
734     if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
735         if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
736             CloseHandle(ktcMutex);
737             return KTC_PIOCTLFAIL;
738         }
739     }
740 #endif /* AFS_WIN95_ENV */
741
742     /* do pioctl */
743     iob.in = tbuffer;
744     iob.in_size = 0;
745     iob.out = tbuffer;
746     iob.out_size = sizeof(tbuffer);
747
748     code = pioctl(0, VIOCDELALLTOK, &iob, 0);
749 #ifndef AFS_WIN95_ENV
750     ReleaseMutex(ktcMutex);
751     CloseHandle(ktcMutex);
752 #endif /* AFS_WIN95_ENV */
753     if (code) {
754         if (code == -1) {
755             if (errno == ENODEV)
756                 return KTC_NOCM;
757             else
758                 return KTC_PIOCTLFAIL;
759         } else
760             return KTC_PIOCTLFAIL;
761     }
762     return 0;
763 }
764
765 int
766 ktc_OldPioctl()
767 {
768     return 1;
769 }
770
771
772 #define MAXLOCALTOKENS 4
773
774 static struct {
775     int valid;
776     struct ktc_principal server;
777     struct ktc_principal client;
778     struct ktc_token token;
779 } local_tokens[MAXLOCALTOKENS] = {
780 0};
781
782 static int
783 SetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
784               struct ktc_principal *aclient, afs_int32 flags)
785 {
786     int found = -1;
787     int i;
788
789     LOCK_GLOBAL_MUTEX 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 return KTC_NOENT;
802     }
803     memcpy(&local_tokens[found].token, atoken, sizeof(struct ktc_token));
804     memcpy(&local_tokens[found].server, aserver,
805            sizeof(struct ktc_principal));
806     memcpy(&local_tokens[found].client, aclient,
807            sizeof(struct ktc_principal));
808     local_tokens[found].valid = 1;
809     UNLOCK_GLOBAL_MUTEX return 0;
810 }
811
812
813 static int
814 GetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
815               int atokenLen, struct ktc_principal *aclient)
816 {
817     int i;
818
819     LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++)
820         if (local_tokens[i].valid
821             && (strcmp(local_tokens[i].server.name, aserver->name) == 0)
822             && (strcmp(local_tokens[i].server.instance, aserver->instance) ==
823                 0)
824             && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
825             memcpy(atoken, &local_tokens[i].token,
826                    min(atokenLen, sizeof(struct ktc_token)));
827             memcpy(aclient, &local_tokens[i].client,
828                    sizeof(struct ktc_principal));
829             UNLOCK_GLOBAL_MUTEX return 0;
830         }
831     UNLOCK_GLOBAL_MUTEX return KTC_NOENT;
832 }
833
834
835 static int
836 ForgetLocalTokens()
837 {
838     int i;
839
840     LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++) {
841         local_tokens[i].valid = 0;
842         memset(&local_tokens[i].token.sessionKey, 0,
843                sizeof(struct ktc_encryptionKey));
844     }
845     UNLOCK_GLOBAL_MUTEX return 0;
846 }
847
848
849 static int
850 ForgetOneLocalToken(struct ktc_principal *aserver)
851 {
852     int i;
853
854     LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++) {
855         if (local_tokens[i].valid
856             && (strcmp(local_tokens[i].server.name, aserver->name) == 0)
857             && (strcmp(local_tokens[i].server.instance, aserver->instance) ==
858                 0)
859             && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
860             local_tokens[i].valid = 0;
861             memset(&local_tokens[i].token.sessionKey, 0,
862                    sizeof(struct ktc_encryptionKey));
863             UNLOCK_GLOBAL_MUTEX return 0;
864         }
865     }
866     UNLOCK_GLOBAL_MUTEX return KTC_NOENT;
867 }