2 * Copyright 2000, International Business Machines Corporation and others.
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
10 /* ticket caching code */
12 #include <afsconfig.h>
13 #include <afs/param.h>
20 #include <afs/pthread_glock.h>
21 #include <sys/types.h>
27 #include <afs/smb_iocons.h>
28 #include <afs/pioctl_nt.h>
29 #include "afs/afsrpc.h"
32 #include <afs/afsutil.h>
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);
46 static char AFSConfigKeyName[] =
47 "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters";
49 static char AFSGlobalKTCMutexName[] = "Global\\AFS_KTC_Mutex";
50 static char AFSKTCMutexName[] = "AFS_KTC_Mutex";
53 * Support for RPC's to send and receive session keys
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.
63 void __RPC_FAR *__RPC_USER
64 midl_user_allocate(size_t cBytes)
66 return ((void __RPC_FAR *)malloc(cBytes));
70 midl_user_free(void __RPC_FAR * p)
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().
81 getservername(char **snp, unsigned int snSize)
87 RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0, KEY_QUERY_VALUE,
89 if (code != ERROR_SUCCESS)
91 code = RegQueryValueEx(parmKey, "Gateway", NULL, NULL, *snp, &snSize);
93 if (code == ERROR_SUCCESS)
96 /* No gateway name in registry; use ourself */
101 send_key(afs_uuid_t uuid, char sessionKey[8])
104 char *stringBinding = NULL;
105 ULONG authnLevel, authnSvc;
106 char serverName[256];
107 char *serverNamep = serverName;
109 BOOL encryptionOff = FALSE;
112 /* Encryption on by default */
113 if (GetEnvironmentVariable("AFS_RPC_ENCRYPT", encrypt, sizeof(encrypt)))
114 if (!strcmpi(encrypt, "OFF"))
115 encryptionOff = TRUE;
117 /* Protocol sequence is named pipe by default */
118 if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ", protseq, sizeof(protseq)))
119 strcpy(protseq, "ncacn_np");
122 getservername(&serverNamep, sizeof(serverName));
124 status = RpcStringBindingCompose("", /* obj uuid */
125 protseq, serverNamep, "", /* endpoint */
126 "", /* protocol options */
128 if (status != RPC_S_OK)
131 status = RpcBindingFromStringBinding(stringBinding, &hAfsHandle);
132 if (status != RPC_S_OK)
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.
140 status = RpcEpResolveBinding(hAfsHandle, afsrpc_v1_0_c_ifspec);
141 if (status != RPC_S_OK)
145 authnLevel = RPC_C_AUTHN_LEVEL_NONE;
146 authnSvc = RPC_C_AUTHN_WINNT;
148 authnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
149 authnSvc = RPC_C_AUTHN_WINNT;
153 RpcBindingSetAuthInfo(hAfsHandle, NULL, authnLevel, authnSvc, NULL,
155 if (status != RPC_S_OK)
159 status = AFSRPC_SetToken(uuid, sessionKey);
162 status = RpcExceptionCode();
164 RpcEndExcept cleanup:if (stringBinding)
165 RpcStringFree(&stringBinding);
167 if (hAfsHandle != NULL)
168 RpcBindingFree(&hAfsHandle);
174 receive_key(afs_uuid_t uuid, char sessionKey[8])
177 char *stringBinding = NULL;
178 ULONG authnLevel, authnSvc;
179 char serverName[256];
180 char *serverNamep = serverName;
182 BOOL encryptionOff = FALSE;
185 /* Encryption on by default */
186 if (GetEnvironmentVariable("AFS_RPC_ENCRYPT", encrypt, sizeof(encrypt)))
187 if (!strcmpi(encrypt, "OFF"))
188 encryptionOff = TRUE;
190 /* Protocol sequence is named pipe by default */
191 if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ", protseq, sizeof(protseq)))
192 strcpy(protseq, "ncacn_np");
195 getservername(&serverNamep, sizeof(serverName));
197 status = RpcStringBindingCompose("", /* obj uuid */
198 protseq, serverNamep, "", /* endpoint */
199 "", /* protocol options */
201 if (status != RPC_S_OK)
204 status = RpcBindingFromStringBinding(stringBinding, &hAfsHandle);
205 if (status != RPC_S_OK)
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.
213 status = RpcEpResolveBinding(hAfsHandle, afsrpc_v1_0_c_ifspec);
214 if (status != RPC_S_OK)
218 authnLevel = RPC_C_AUTHN_LEVEL_NONE;
219 authnSvc = RPC_C_AUTHN_WINNT;
221 authnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
222 authnSvc = RPC_C_AUTHN_WINNT;
226 RpcBindingSetAuthInfo(hAfsHandle, NULL, authnLevel, authnSvc, NULL,
228 if (status != RPC_S_OK)
232 status = AFSRPC_GetToken(uuid, sessionKey);
235 status = RpcExceptionCode();
237 RpcEndExcept cleanup:if (stringBinding)
238 RpcStringFree(&stringBinding);
240 if (hAfsHandle != NULL)
241 RpcBindingFree(&hAfsHandle);
247 ktc_SetToken(struct ktc_principal *server, struct ktc_token *token,
248 struct ktc_principal *client, int flags)
250 struct ViceIoctl iob;
253 struct ClearToken ct;
258 HANDLE ktcMutex = NULL;
260 if (token->ticketLen < MINKTCTICKETLEN
261 || token->ticketLen > MAXKTCTICKETLEN)
264 if (strcmp(server->name, "afs")) {
265 return SetLocalToken(server, token, client, flags);
271 memcpy(tp, &token->ticketLen, sizeof(token->ticketLen));
272 tp += sizeof(&token->ticketLen);
275 memcpy(tp, token->ticket, token->ticketLen);
276 tp += token->ticketLen;
279 ct.AuthHandle = token->kvno;
281 * Instead of sending the session key in the clear, we zero it,
282 * and send it later, via RPC, encrypted.
284 #ifndef AFS_WIN95_ENV
286 * memcpy(ct.HandShakeKey, &token->sessionKey, sizeof(token->sessionKey));
288 memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
290 memcpy(ct.HandShakeKey, &token->sessionKey, sizeof(token->sessionKey));
292 ct.BeginTimestamp = token->startTime;
293 ct.EndTimestamp = token->endTime;
294 if (ct.BeginTimestamp == 0)
295 ct.BeginTimestamp = 1;
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 */
302 /* size of clear token */
303 temp = sizeof(struct ClearToken);
304 memcpy(tp, &temp, sizeof(temp));
307 /* clear token itself */
308 memcpy(tp, &ct, sizeof(ct));
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));
318 temp = strlen(server->cell);
319 if (temp >= MAXKTCREALMLEN)
321 strcpy(tp, server->cell);
325 temp = strlen(client->name);
326 if (temp >= MAXKTCNAMELEN)
328 strcpy(tp, client->name);
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)
337 temp = strlen(client->smbname);
338 if (temp == 0 || temp >= MAXKTCNAMELEN)
340 strcpy(tp, client->smbname);
345 status = UuidCreate((UUID *) & uuid);
346 memcpy(tp, &uuid, sizeof(uuid));
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;
361 /* RPC to send session key */
362 status = send_key(uuid, token->sessionKey.data);
363 if (status != RPC_S_OK) {
365 strcpy(rpcErr, "RPC failure in AFS gateway");
367 DceErrorInqText(status, rpcErr);
368 if (status == RPC_S_SERVER_UNAVAILABLE ||
369 status == EPT_S_NOT_REGISTERED)
371 ReleaseMutex(ktcMutex);
372 CloseHandle(ktcMutex);
377 ReleaseMutex(ktcMutex);
378 CloseHandle(ktcMutex);
382 #endif /* AFS_WIN95_ENV */
384 /* set up for pioctl */
386 iob.in_size = tp - tbuffer;
388 iob.out_size = sizeof(tbuffer);
390 code = pioctl(0, VIOCSETTOK, &iob, 0);
392 #ifndef AFS_WIN95_ENV
393 ReleaseMutex(ktcMutex);
394 CloseHandle(ktcMutex);
395 #endif /* AFS_WIN95_ENV */
401 else if (errno == ENODEV)
403 else if (errno == EINVAL)
406 return KTC_PIOCTLFAIL;
408 return KTC_PIOCTLFAIL;
415 ktc_GetToken(struct ktc_principal *server, struct ktc_token *token,
416 int tokenLen, struct ktc_principal *client)
418 struct ViceIoctl iob;
423 struct ClearToken ct;
430 HANDLE ktcMutex = NULL;
434 /* check to see if the user is requesting tokens for a principal
435 * other than afs. If so, check the local token cache.
437 if (strcmp(server->name, "afs")) {
438 return GetLocalToken(server, token, tokenLen, client);
442 strcpy(tp, server->cell);
443 tp += strlen(server->cell) + 1;
446 status = UuidCreate((UUID *) & uuid);
447 memcpy(tp, &uuid, sizeof(uuid));
451 iob.in_size = tp - tbuffer;
453 iob.out_size = sizeof(tbuffer);
455 #ifndef AFS_WIN95_ENV
456 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
457 if ( ktcMutex == NULL )
458 return KTC_PIOCTLFAIL;
459 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
460 if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
461 CloseHandle(ktcMutex);
462 return KTC_PIOCTLFAIL;
465 #endif /* AFS_WIN95_ENV */
467 code = pioctl(0, VIOCNEWGETTOK, &iob, 0);
469 #ifndef AFS_WIN95_ENV
470 ReleaseMutex(ktcMutex);
471 CloseHandle(ktcMutex);
472 #endif /* AFS_WIN95_ENV */
476 else if (errno == ENODEV)
478 else if (errno == EINVAL)
480 else if (errno == EDOM)
483 return KTC_PIOCTLFAIL;
485 return KTC_PIOCTLFAIL;
488 #ifndef AFS_WIN95_ENV
489 /* get rid of RPC for win95 build */
490 /* RPC to receive session key */
491 status = receive_key(uuid, token->sessionKey.data);
493 ReleaseMutex(ktcMutex);
494 CloseHandle(ktcMutex);
496 if (status != RPC_S_OK) {
498 strcpy(rpcErr, "RPC failure in AFS gateway");
500 DceErrorInqText(status, rpcErr);
501 if (status == RPC_S_SERVER_UNAVAILABLE
502 || status == EPT_S_NOT_REGISTERED)
507 #endif /* AFS_WIN95_ENV */
512 memcpy(&ticketLen, cp, sizeof(ticketLen));
513 cp += sizeof(ticketLen);
515 /* remember where ticket is and skip over it */
519 /* size of clear token */
520 memcpy(&temp, cp, sizeof(temp));
522 if (temp != sizeof(ct))
526 memcpy(&ct, cp, temp);
529 /* skip over primary flag */
532 /* remember cell name and skip over it */
534 cellNameSize = strlen(cp);
535 cp += cellNameSize + 1;
537 /* user name is here */
539 /* check that ticket will fit */
540 maxLen = tokenLen - sizeof(struct ktc_token) + MAXKTCTICKETLEN;
541 if (maxLen < ticketLen)
544 /* set return values */
545 memcpy(token->ticket, ticketP, ticketLen);
546 token->startTime = ct.BeginTimestamp;
547 token->endTime = ct.EndTimestamp;
548 if (ct.AuthHandle == -1)
550 token->kvno = ct.AuthHandle;
551 #ifndef AFS_WIN95_ENV
553 * Session key has already been set via RPC
556 memcpy(&token->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
557 #endif /* AFS_WIN95_ENV */
558 token->ticketLen = ticketLen;
560 strcpy(client->name, cp);
561 client->instance[0] = '\0';
562 strcpy(client->cell, cellName);
569 ktc_ListTokens(int cellNum, int *cellNumP, struct ktc_principal *server)
571 struct ViceIoctl iob;
574 int newIter, ticketLen, temp;
576 HANDLE ktcMutex = NULL;
578 #ifndef AFS_WIN95_ENV
579 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
580 if ( ktcMutex == NULL )
581 return KTC_PIOCTLFAIL;
582 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
583 if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
584 CloseHandle(ktcMutex);
585 return KTC_PIOCTLFAIL;
588 #endif /* AFS_WIN95_ENV */
593 memcpy(tp, &cellNum, sizeof(cellNum));
594 tp += sizeof(cellNum);
598 iob.in_size = tp - tbuffer;
600 iob.out_size = sizeof(tbuffer);
602 code = pioctl(0, VIOCGETTOK, &iob, 0);
604 #ifndef AFS_WIN95_ENV
605 ReleaseMutex(ktcMutex);
606 CloseHandle(ktcMutex);
607 #endif /* AFS_WIN95_ENV */
613 else if (errno == ENODEV)
615 else if (errno == EINVAL)
617 else if (errno == EDOM)
620 return KTC_PIOCTLFAIL;
622 return KTC_PIOCTLFAIL;
628 memcpy(&newIter, cp, sizeof(newIter));
629 cp += sizeof(newIter);
632 memcpy(&ticketLen, cp, sizeof(ticketLen));
633 cp += sizeof(ticketLen);
635 /* skip over ticket */
638 /* clear token size */
639 memcpy(&temp, cp, sizeof(temp));
641 if (temp != sizeof(struct ClearToken))
644 /* skip over clear token */
645 cp += sizeof(struct ClearToken);
647 /* skip over primary flag */
650 /* cell name is here */
652 /* set return values */
653 strcpy(server->cell, cp);
654 server->instance[0] = '\0';
655 strcpy(server->name, "afs");
662 ktc_ForgetToken(struct ktc_principal *server)
664 struct ViceIoctl iob;
668 HANDLE ktcMutex = NULL;
670 if (strcmp(server->name, "afs")) {
671 return ForgetOneLocalToken(server);
674 #ifndef AFS_WIN95_ENV
675 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
676 if ( ktcMutex == NULL )
677 return KTC_PIOCTLFAIL;
678 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
679 if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
680 CloseHandle(ktcMutex);
681 return KTC_PIOCTLFAIL;
684 #endif /* AFS_WIN95_ENV */
689 strcpy(tp, server->cell);
690 tp += strlen(tp) + 1;
694 iob.in_size = tp - tbuffer;
696 iob.out_size = sizeof(tbuffer);
698 code = pioctl(0, VIOCDELTOK, &iob, 0);
699 #ifndef AFS_WIN95_ENV
700 ReleaseMutex(ktcMutex);
701 CloseHandle(ktcMutex);
702 #endif /* AFS_WIN95_ENV */
707 else if (errno == EDOM)
709 else if (errno == ENODEV)
712 return KTC_PIOCTLFAIL;
714 return KTC_PIOCTLFAIL;
720 ktc_ForgetAllTokens()
722 struct ViceIoctl iob;
725 HANDLE ktcMutex = NULL;
727 (void)ForgetLocalTokens();
729 #ifndef AFS_WIN95_ENV
730 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
731 if ( ktcMutex == NULL )
732 return KTC_PIOCTLFAIL;
733 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
734 if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
735 CloseHandle(ktcMutex);
736 return KTC_PIOCTLFAIL;
739 #endif /* AFS_WIN95_ENV */
745 iob.out_size = sizeof(tbuffer);
747 code = pioctl(0, VIOCDELALLTOK, &iob, 0);
748 #ifndef AFS_WIN95_ENV
749 ReleaseMutex(ktcMutex);
750 CloseHandle(ktcMutex);
751 #endif /* AFS_WIN95_ENV */
757 return KTC_PIOCTLFAIL;
759 return KTC_PIOCTLFAIL;
771 #define MAXLOCALTOKENS 4
775 struct ktc_principal server;
776 struct ktc_principal client;
777 struct ktc_token token;
778 } local_tokens[MAXLOCALTOKENS] = {
782 SetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
783 struct ktc_principal *aclient, afs_int32 flags)
788 LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++)
789 if (local_tokens[i].valid) {
790 if ((strcmp(local_tokens[i].server.name, aserver->name) == 0)
791 && (strcmp(local_tokens[i].server.instance, aserver->instance)
793 && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
794 found = i; /* replace existing entry */
797 } else if (found == -1)
798 found = i; /* remember empty slot but keep looking for a match */
800 UNLOCK_GLOBAL_MUTEX return KTC_NOENT;
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 return 0;
813 GetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
814 int atokenLen, struct ktc_principal *aclient)
818 LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++)
819 if (local_tokens[i].valid
820 && (strcmp(local_tokens[i].server.name, aserver->name) == 0)
821 && (strcmp(local_tokens[i].server.instance, aserver->instance) ==
823 && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
824 memcpy(atoken, &local_tokens[i].token,
825 min(atokenLen, sizeof(struct ktc_token)));
826 memcpy(aclient, &local_tokens[i].client,
827 sizeof(struct ktc_principal));
828 UNLOCK_GLOBAL_MUTEX return 0;
830 UNLOCK_GLOBAL_MUTEX return KTC_NOENT;
839 LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++) {
840 local_tokens[i].valid = 0;
841 memset(&local_tokens[i].token.sessionKey, 0,
842 sizeof(struct ktc_encryptionKey));
844 UNLOCK_GLOBAL_MUTEX return 0;
849 ForgetOneLocalToken(struct ktc_principal *aserver)
853 LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++) {
854 if (local_tokens[i].valid
855 && (strcmp(local_tokens[i].server.name, aserver->name) == 0)
856 && (strcmp(local_tokens[i].server.instance, aserver->instance) ==
858 && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
859 local_tokens[i].valid = 0;
860 memset(&local_tokens[i].token.sessionKey, 0,
861 sizeof(struct ktc_encryptionKey));
862 UNLOCK_GLOBAL_MUTEX return 0;
865 UNLOCK_GLOBAL_MUTEX return KTC_NOENT;