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