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