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>
18 #include <afs/pthread_glock.h>
19 #include <sys/types.h>
25 #include <afs/smb_iocons.h>
26 #include <afs/pioctl_nt.h>
27 #include "afs/afsrpc.h"
30 #include <afs/afsutil.h>
32 /* TBUFFERSIZE must be at least 512 larger than KTCMAXTICKETSIZE */
33 #define TBUFFERSIZE 12512
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 (!_stricmp(encrypt, "OFF"))
115 encryptionOff = TRUE;
117 /* Protocol sequence is local by default */
118 if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ", protseq, sizeof(protseq)))
119 strcpy(protseq, "ncalrpc");
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 (!_stricmp(encrypt, "OFF"))
188 encryptionOff = TRUE;
190 /* Protocol sequence is local by default */
191 if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ", protseq, sizeof(protseq)))
192 strcpy(protseq, "ncalrpc");
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;
251 char tbuffer[TBUFFERSIZE];
254 struct ClearToken ct;
259 HANDLE ktcMutex = NULL;
261 if (token->ticketLen < MINKTCTICKETLEN
262 || token->ticketLen > MAXKTCTICKETLEN)
265 if (strcmp(server->name, "afs")) {
266 return SetLocalToken(server, token, client, flags);
272 memcpy(tp, &token->ticketLen, sizeof(token->ticketLen));
273 tp += sizeof(token->ticketLen);
274 len = sizeof(token->ticketLen);
277 if (len + token->ticketLen > TBUFFERSIZE)
279 memcpy(tp, token->ticket, token->ticketLen);
280 tp += token->ticketLen;
281 len += token->ticketLen;
284 ct.AuthHandle = token->kvno;
286 * Instead of sending the session key in the clear, we zero it,
287 * and send it later, via RPC, encrypted.
289 #ifndef AFS_WIN95_ENV
291 * memcpy(ct.HandShakeKey, &token->sessionKey, sizeof(token->sessionKey));
293 memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
295 memcpy(ct.HandShakeKey, &token->sessionKey, sizeof(token->sessionKey));
297 ct.BeginTimestamp = token->startTime;
298 ct.EndTimestamp = token->endTime;
299 if (ct.BeginTimestamp == 0)
300 ct.BeginTimestamp = 1;
302 /* We don't know from Vice ID's yet */
303 ct.ViceId = 37; /* XXX */
304 if (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1)
305 ct.BeginTimestamp++; /* force lifetime to be even */
307 /* size of clear token */
308 if (len + sizeof(temp) > TBUFFERSIZE)
310 temp = sizeof(struct ClearToken);
311 memcpy(tp, &temp, sizeof(temp));
315 /* clear token itself */
316 if (len + sizeof(ct) > TBUFFERSIZE)
318 memcpy(tp, &ct, sizeof(ct));
322 /* flags; on NT there is no setpag flag, but there is an
323 * integrated logon flag */
324 if (len + sizeof(temp) > TBUFFERSIZE)
326 temp = ((flags & AFS_SETTOK_LOGON) ? PIOCTL_LOGON : 0);
327 memcpy(tp, &temp, sizeof(temp));
332 temp = (int)strlen(server->cell) + 1;
333 if (len + temp > TBUFFERSIZE ||
334 temp > MAXKTCREALMLEN)
336 strcpy(tp, server->cell);
341 temp = (int)strlen(client->name) + 1;
342 if (len + temp > TBUFFERSIZE ||
343 temp > MAXKTCNAMELEN)
345 strcpy(tp, client->name);
349 /* we need the SMB user name to associate the tokens with in the
350 * integrated logon case. */
351 if (flags & AFS_SETTOK_LOGON) {
352 if (client->smbname == NULL)
355 temp = (int)strlen(client->smbname) + 1;
357 len + temp > TBUFFERSIZE ||
358 temp > MAXKTCNAMELEN)
360 strcpy(tp, client->smbname);
366 if (len + sizeof(uuid) > TBUFFERSIZE)
368 status = UuidCreate((UUID *) & uuid);
369 memcpy(tp, &uuid, sizeof(uuid));
373 #ifndef AFS_WIN95_ENV
374 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
375 if (ktcMutex == NULL)
376 return KTC_PIOCTLFAIL;
377 if (GetLastError() == ERROR_ALREADY_EXISTS) {
378 if (WaitForSingleObject(ktcMutex, INFINITE) != WAIT_OBJECT_0) {
379 CloseHandle(ktcMutex);
380 return KTC_PIOCTLFAIL;
384 /* RPC to send session key */
385 status = send_key(uuid, token->sessionKey.data);
386 if (status != RPC_S_OK) {
388 strcpy(rpcErr, "RPC failure in AFS gateway");
390 DceErrorInqText(status, rpcErr);
391 if (status == RPC_S_SERVER_UNAVAILABLE ||
392 status == EPT_S_NOT_REGISTERED) {
393 ReleaseMutex(ktcMutex);
394 CloseHandle(ktcMutex);
397 ReleaseMutex(ktcMutex);
398 CloseHandle(ktcMutex);
402 #endif /* AFS_WIN95_ENV */
404 /* set up for pioctl */
406 iob.in_size = (long)(tp - tbuffer);
408 iob.out_size = sizeof(tbuffer);
410 code = pioctl(0, VIOCSETTOK, &iob, 0);
412 #ifndef AFS_WIN95_ENV
413 ReleaseMutex(ktcMutex);
414 CloseHandle(ktcMutex);
415 #endif /* AFS_WIN95_ENV */
421 else if (errno == ENODEV)
423 else if (errno == EINVAL)
426 return KTC_PIOCTLFAIL;
428 return KTC_PIOCTLFAIL;
435 ktc_GetToken(struct ktc_principal *server, struct ktc_token *token,
436 int tokenLen, struct ktc_principal *client)
438 struct ViceIoctl iob;
439 char tbuffer[TBUFFERSIZE];
444 struct ClearToken ct;
451 HANDLE ktcMutex = NULL;
455 /* check to see if the user is requesting tokens for a principal
456 * other than afs. If so, check the local token cache.
458 if (strcmp(server->name, "afs")) {
459 return GetLocalToken(server, token, tokenLen, client);
463 len = strlen(server->cell) + 1;
464 strcpy(tp, server->cell);
468 status = UuidCreate((UUID *) & uuid);
469 memcpy(tp, &uuid, sizeof(uuid));
474 iob.in_size = (long)(tp - tbuffer);
476 iob.out_size = sizeof(tbuffer);
478 #ifndef AFS_WIN95_ENV
479 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
480 if (ktcMutex == NULL)
481 return KTC_PIOCTLFAIL;
482 if (GetLastError() == ERROR_ALREADY_EXISTS) {
483 if (WaitForSingleObject(ktcMutex, INFINITE) != WAIT_OBJECT_0) {
484 CloseHandle(ktcMutex);
485 return KTC_PIOCTLFAIL;
488 #endif /* AFS_WIN95_ENV */
490 code = pioctl(0, VIOCNEWGETTOK, &iob, 0);
492 #ifndef AFS_WIN95_ENV
493 ReleaseMutex(ktcMutex);
494 CloseHandle(ktcMutex);
495 #endif /* AFS_WIN95_ENV */
499 else if (errno == ENODEV)
501 else if (errno == EINVAL)
503 else if (errno == EDOM)
506 return KTC_PIOCTLFAIL;
508 return KTC_PIOCTLFAIL;
510 #ifndef AFS_WIN95_ENV
511 /* get rid of RPC for win95 build */
512 /* RPC to receive session key */
513 status = receive_key(uuid, token->sessionKey.data);
515 ReleaseMutex(ktcMutex);
516 CloseHandle(ktcMutex);
518 if (status != RPC_S_OK) {
520 strcpy(rpcErr, "RPC failure in AFS gateway");
522 DceErrorInqText(status, rpcErr);
523 if (status == RPC_S_SERVER_UNAVAILABLE
524 || status == EPT_S_NOT_REGISTERED)
529 #endif /* AFS_WIN95_ENV */
534 memcpy(&ticketLen, cp, sizeof(ticketLen));
535 cp += sizeof(ticketLen);
536 len = sizeof(ticketLen);
538 /* remember where ticket is and skip over it */
539 if (len + ticketLen > TBUFFERSIZE ||
540 len + ticketLen > iob.out_size)
546 /* size of clear token */
547 if (len + sizeof(temp) > TBUFFERSIZE ||
548 len + sizeof(temp) > iob.out_size)
550 memcpy(&temp, cp, sizeof(temp));
553 if (temp != sizeof(ct))
557 if (len + temp > TBUFFERSIZE ||
558 len + temp > iob.out_size)
560 memcpy(&ct, cp, temp);
564 /* skip over primary flag */
565 if (len + sizeof(temp) > TBUFFERSIZE ||
566 len + sizeof(temp) > iob.out_size)
571 /* remember cell name and skip over it */
573 cellNameSize = (int)strlen(cp);
574 if (len + cellNameSize + 1 > TBUFFERSIZE ||
575 len + cellNameSize + 1 > iob.out_size)
577 cp += cellNameSize + 1;
578 len += cellNameSize + 1;
580 /* user name is here */
582 /* check that ticket will fit
583 * this compares the size of the ktc_token allocated by the app
584 * which might be smaller than the current definition of MAXKTCTICKETLEN
586 maxLen = tokenLen - sizeof(struct ktc_token) + MAXKTCTICKETLEN;
587 if (maxLen < ticketLen)
590 /* set return values */
591 memcpy(token->ticket, ticketP, ticketLen);
592 token->startTime = ct.BeginTimestamp;
593 token->endTime = ct.EndTimestamp;
594 if (ct.AuthHandle == -1)
596 token->kvno = ct.AuthHandle;
597 #ifndef AFS_WIN95_ENV
599 * Session key has already been set via RPC
602 memcpy(&token->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
603 #endif /* AFS_WIN95_ENV */
604 token->ticketLen = ticketLen;
606 strcpy(client->name, cp);
607 client->instance[0] = '\0';
608 strcpy(client->cell, cellName);
615 ktc_ListTokens(int cellNum, int *cellNumP, struct ktc_principal *server)
617 struct ViceIoctl iob;
618 char tbuffer[TBUFFERSIZE];
621 int newIter, ticketLen, temp;
623 HANDLE ktcMutex = NULL;
625 #ifndef AFS_WIN95_ENV
626 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
627 if (ktcMutex == NULL)
628 return KTC_PIOCTLFAIL;
629 if (GetLastError() == ERROR_ALREADY_EXISTS) {
630 if (WaitForSingleObject(ktcMutex, INFINITE) != WAIT_OBJECT_0) {
631 CloseHandle(ktcMutex);
632 return KTC_PIOCTLFAIL;
635 #endif /* AFS_WIN95_ENV */
640 memcpy(tp, &cellNum, sizeof(cellNum));
641 tp += sizeof(cellNum);
645 iob.in_size = (long)(tp - tbuffer);
647 iob.out_size = sizeof(tbuffer);
649 code = pioctl(0, VIOCGETTOK, &iob, 0);
651 #ifndef AFS_WIN95_ENV
652 ReleaseMutex(ktcMutex);
653 CloseHandle(ktcMutex);
654 #endif /* AFS_WIN95_ENV */
660 else if (errno == ENODEV)
662 else if (errno == EINVAL)
664 else if (errno == EDOM)
667 return KTC_PIOCTLFAIL;
669 return KTC_PIOCTLFAIL;
675 memcpy(&newIter, cp, sizeof(newIter));
676 cp += sizeof(newIter);
677 len = sizeof(newIter);
680 if (len + sizeof(ticketLen) > TBUFFERSIZE ||
681 len + sizeof(ticketLen) > iob.out_size)
683 memcpy(&ticketLen, cp, sizeof(ticketLen));
684 cp += sizeof(ticketLen);
685 len += sizeof(ticketLen);
687 /* skip over ticket */
691 /* clear token size */
692 if (len + sizeof(temp) > TBUFFERSIZE ||
693 len + sizeof(temp) > iob.out_size)
695 memcpy(&temp, cp, sizeof(temp));
698 if (temp != sizeof(struct ClearToken))
701 /* skip over clear token */
702 cp += sizeof(struct ClearToken);
703 len += sizeof(struct ClearToken);
705 /* skip over primary flag */
708 if (len > TBUFFERSIZE ||
712 /* cell name is here */
714 /* set return values */
715 if (len + temp > TBUFFERSIZE ||
716 temp > MAXKTCREALMLEN)
718 strcpy(server->cell, cp);
719 server->instance[0] = '\0';
720 strcpy(server->name, "afs");
727 ktc_ForgetToken(struct ktc_principal *server)
729 struct ViceIoctl iob;
730 char tbuffer[TBUFFERSIZE];
733 HANDLE ktcMutex = NULL;
735 if (strcmp(server->name, "afs")) {
736 return ForgetOneLocalToken(server);
738 #ifndef AFS_WIN95_ENV
739 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
740 if (ktcMutex == NULL)
741 return KTC_PIOCTLFAIL;
742 if (GetLastError() == ERROR_ALREADY_EXISTS) {
743 if (WaitForSingleObject(ktcMutex, INFINITE) != WAIT_OBJECT_0) {
744 CloseHandle(ktcMutex);
745 return KTC_PIOCTLFAIL;
748 #endif /* AFS_WIN95_ENV */
753 strcpy(tp, server->cell);
754 tp += strlen(tp) + 1;
758 iob.in_size = (long)(tp - tbuffer);
760 iob.out_size = sizeof(tbuffer);
762 code = pioctl(0, VIOCDELTOK, &iob, 0);
763 #ifndef AFS_WIN95_ENV
764 ReleaseMutex(ktcMutex);
765 CloseHandle(ktcMutex);
766 #endif /* AFS_WIN95_ENV */
771 else if (errno == EDOM)
773 else if (errno == ENODEV)
776 return KTC_PIOCTLFAIL;
778 return KTC_PIOCTLFAIL;
784 ktc_ForgetAllTokens()
786 struct ViceIoctl iob;
787 char tbuffer[TBUFFERSIZE];
789 HANDLE ktcMutex = NULL;
791 (void)ForgetLocalTokens();
793 #ifndef AFS_WIN95_ENV
794 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
795 if (ktcMutex == NULL)
796 return KTC_PIOCTLFAIL;
797 if (GetLastError() == ERROR_ALREADY_EXISTS) {
798 if (WaitForSingleObject(ktcMutex, INFINITE) != WAIT_OBJECT_0) {
799 CloseHandle(ktcMutex);
800 return KTC_PIOCTLFAIL;
803 #endif /* AFS_WIN95_ENV */
809 iob.out_size = sizeof(tbuffer);
811 code = pioctl(0, VIOCDELALLTOK, &iob, 0);
812 #ifndef AFS_WIN95_ENV
813 ReleaseMutex(ktcMutex);
814 CloseHandle(ktcMutex);
815 #endif /* AFS_WIN95_ENV */
821 return KTC_PIOCTLFAIL;
823 return KTC_PIOCTLFAIL;
835 #define MAXLOCALTOKENS 4
839 struct ktc_principal server;
840 struct ktc_principal client;
841 struct ktc_token token;
842 } local_tokens[MAXLOCALTOKENS] = {
846 SetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
847 struct ktc_principal *aclient, afs_int32 flags)
853 for (i = 0; i < MAXLOCALTOKENS; i++)
854 if (local_tokens[i].valid) {
855 if ((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 found = i; /* replace existing entry */
862 } else if (found == -1)
863 found = i; /* remember empty slot but keep looking for a match */
868 memcpy(&local_tokens[found].token, atoken, sizeof(struct ktc_token));
869 memcpy(&local_tokens[found].server, aserver,
870 sizeof(struct ktc_principal));
871 memcpy(&local_tokens[found].client, aclient,
872 sizeof(struct ktc_principal));
873 local_tokens[found].valid = 1;
880 GetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
881 int atokenLen, struct ktc_principal *aclient)
886 for (i = 0; i < MAXLOCALTOKENS; i++)
887 if (local_tokens[i].valid
888 && (strcmp(local_tokens[i].server.name, aserver->name) == 0)
889 && (strcmp(local_tokens[i].server.instance, aserver->instance) ==
891 && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
892 memcpy(atoken, &local_tokens[i].token,
893 min(atokenLen, sizeof(struct ktc_token)));
894 memcpy(aclient, &local_tokens[i].client,
895 sizeof(struct ktc_principal));
910 for (i = 0; i < MAXLOCALTOKENS; i++) {
911 local_tokens[i].valid = 0;
912 memset(&local_tokens[i].token.sessionKey, 0,
913 sizeof(struct ktc_encryptionKey));
921 ForgetOneLocalToken(struct ktc_principal *aserver)
926 for (i = 0; i < MAXLOCALTOKENS; i++) {
927 if (local_tokens[i].valid
928 && (strcmp(local_tokens[i].server.name, aserver->name) == 0)
929 && (strcmp(local_tokens[i].server.instance, aserver->instance) ==
931 && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
932 local_tokens[i].valid = 0;
933 memset(&local_tokens[i].token.sessionKey, 0,
934 sizeof(struct ktc_encryptionKey));