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>
34 /* TBUFFERSIZE must be at least 512 larger than KTCMAXTICKETSIZE */
35 #define TBUFFERSIZE 8192
37 /* Forward declarations for local token cache. */
38 static int SetLocalToken(struct ktc_principal *aserver,
39 struct ktc_token *atoken,
40 struct ktc_principal *aclient, afs_int32 flags);
41 static int GetLocalToken(struct ktc_principal *aserver,
42 struct ktc_token *atoken, int atokenLen,
43 struct ktc_principal *aclient);
44 static int ForgetLocalTokens();
45 static int ForgetOneLocalToken(struct ktc_principal *aserver);
48 static char AFSConfigKeyName[] =
49 "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters";
51 static char AFSGlobalKTCMutexName[] = "Global\\AFS_KTC_Mutex";
52 static char AFSKTCMutexName[] = "AFS_KTC_Mutex";
55 * Support for RPC's to send and receive session keys
57 * Session keys must not be sent and received in the clear. We have no
58 * way to piggyback encryption on SMB, so we use a separate RPC, using
59 * packet privacy (when available). In SetToken, the RPC is done first;
60 * in GetToken, the pioctl is done first.
65 void __RPC_FAR *__RPC_USER
66 midl_user_allocate(size_t cBytes)
68 return ((void __RPC_FAR *)malloc(cBytes));
72 midl_user_free(void __RPC_FAR * p)
78 * Determine the server name to be used in the RPC binding. If it is
79 * the same as the client (i.e. standalone, non-gateway), NULL can be
80 * used, so it is not necessary to call gethostbyname().
83 getservername(char **snp, unsigned int snSize)
89 RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0, KEY_QUERY_VALUE,
91 if (code != ERROR_SUCCESS)
93 code = RegQueryValueEx(parmKey, "Gateway", NULL, NULL, *snp, &snSize);
95 if (code == ERROR_SUCCESS)
98 /* No gateway name in registry; use ourself */
103 send_key(afs_uuid_t uuid, char sessionKey[8])
106 char *stringBinding = NULL;
107 ULONG authnLevel, authnSvc;
108 char serverName[256];
109 char *serverNamep = serverName;
111 BOOL encryptionOff = FALSE;
114 /* Encryption on by default */
115 if (GetEnvironmentVariable("AFS_RPC_ENCRYPT", encrypt, sizeof(encrypt)))
116 if (!strcmpi(encrypt, "OFF"))
117 encryptionOff = TRUE;
119 /* Protocol sequence is named pipe by default */
120 if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ", protseq, sizeof(protseq)))
121 strcpy(protseq, "ncacn_np");
124 getservername(&serverNamep, sizeof(serverName));
126 status = RpcStringBindingCompose("", /* obj uuid */
127 protseq, serverNamep, "", /* endpoint */
128 "", /* protocol options */
130 if (status != RPC_S_OK)
133 status = RpcBindingFromStringBinding(stringBinding, &hAfsHandle);
134 if (status != RPC_S_OK)
138 * On Windows 95/98, we must resolve the binding before calling
139 * SetAuthInfo. On Windows NT, we don't have to resolve yet,
140 * but it does no harm.
142 status = RpcEpResolveBinding(hAfsHandle, afsrpc_v1_0_c_ifspec);
143 if (status != RPC_S_OK)
147 authnLevel = RPC_C_AUTHN_LEVEL_NONE;
148 authnSvc = RPC_C_AUTHN_WINNT;
150 authnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
151 authnSvc = RPC_C_AUTHN_WINNT;
155 RpcBindingSetAuthInfo(hAfsHandle, NULL, authnLevel, authnSvc, NULL,
157 if (status != RPC_S_OK)
161 status = AFSRPC_SetToken(uuid, sessionKey);
164 status = RpcExceptionCode();
166 RpcEndExcept cleanup:if (stringBinding)
167 RpcStringFree(&stringBinding);
169 if (hAfsHandle != NULL)
170 RpcBindingFree(&hAfsHandle);
176 receive_key(afs_uuid_t uuid, char sessionKey[8])
179 char *stringBinding = NULL;
180 ULONG authnLevel, authnSvc;
181 char serverName[256];
182 char *serverNamep = serverName;
184 BOOL encryptionOff = FALSE;
187 /* Encryption on by default */
188 if (GetEnvironmentVariable("AFS_RPC_ENCRYPT", encrypt, sizeof(encrypt)))
189 if (!strcmpi(encrypt, "OFF"))
190 encryptionOff = TRUE;
192 /* Protocol sequence is named pipe by default */
193 if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ", protseq, sizeof(protseq)))
194 strcpy(protseq, "ncacn_np");
197 getservername(&serverNamep, sizeof(serverName));
199 status = RpcStringBindingCompose("", /* obj uuid */
200 protseq, serverNamep, "", /* endpoint */
201 "", /* protocol options */
203 if (status != RPC_S_OK)
206 status = RpcBindingFromStringBinding(stringBinding, &hAfsHandle);
207 if (status != RPC_S_OK)
211 * On Windows 95/98, we must resolve the binding before calling
212 * SetAuthInfo. On Windows NT, we don't have to resolve yet,
213 * but it does no harm.
215 status = RpcEpResolveBinding(hAfsHandle, afsrpc_v1_0_c_ifspec);
216 if (status != RPC_S_OK)
220 authnLevel = RPC_C_AUTHN_LEVEL_NONE;
221 authnSvc = RPC_C_AUTHN_WINNT;
223 authnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
224 authnSvc = RPC_C_AUTHN_WINNT;
228 RpcBindingSetAuthInfo(hAfsHandle, NULL, authnLevel, authnSvc, NULL,
230 if (status != RPC_S_OK)
234 status = AFSRPC_GetToken(uuid, sessionKey);
237 status = RpcExceptionCode();
239 RpcEndExcept cleanup:if (stringBinding)
240 RpcStringFree(&stringBinding);
242 if (hAfsHandle != NULL)
243 RpcBindingFree(&hAfsHandle);
249 ktc_SetToken(struct ktc_principal *server, struct ktc_token *token,
250 struct ktc_principal *client, int flags)
252 struct ViceIoctl iob;
253 char tbuffer[TBUFFERSIZE];
255 struct ClearToken ct;
260 HANDLE ktcMutex = NULL;
262 if (token->ticketLen < MINKTCTICKETLEN
263 || token->ticketLen > MAXKTCTICKETLEN)
266 if (strcmp(server->name, "afs")) {
267 return SetLocalToken(server, token, client, flags);
273 memcpy(tp, &token->ticketLen, sizeof(token->ticketLen));
274 tp += sizeof(&token->ticketLen);
277 memcpy(tp, token->ticket, token->ticketLen);
278 tp += token->ticketLen;
281 ct.AuthHandle = token->kvno;
283 * Instead of sending the session key in the clear, we zero it,
284 * and send it later, via RPC, encrypted.
286 #ifndef AFS_WIN95_ENV
288 * memcpy(ct.HandShakeKey, &token->sessionKey, sizeof(token->sessionKey));
290 memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
292 memcpy(ct.HandShakeKey, &token->sessionKey, sizeof(token->sessionKey));
294 ct.BeginTimestamp = token->startTime;
295 ct.EndTimestamp = token->endTime;
296 if (ct.BeginTimestamp == 0)
297 ct.BeginTimestamp = 1;
299 /* We don't know from Vice ID's yet */
300 ct.ViceId = 37; /* XXX */
301 if (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1)
302 ct.BeginTimestamp++; /* force lifetime to be even */
304 /* size of clear token */
305 temp = sizeof(struct ClearToken);
306 memcpy(tp, &temp, sizeof(temp));
309 /* clear token itself */
310 memcpy(tp, &ct, sizeof(ct));
313 /* flags; on NT there is no setpag flag, but there is an
314 * integrated logon flag */
315 temp = ((flags & AFS_SETTOK_LOGON) ? PIOCTL_LOGON : 0);
316 memcpy(tp, &temp, sizeof(temp));
320 temp = strlen(server->cell);
321 if (temp >= MAXKTCREALMLEN)
323 strcpy(tp, server->cell);
327 temp = strlen(client->name);
328 if (temp >= MAXKTCNAMELEN)
330 strcpy(tp, client->name);
333 /* we need the SMB user name to associate the tokens with in the
334 * integrated logon case. */
335 if (flags & AFS_SETTOK_LOGON) {
336 if (client->smbname == NULL)
339 temp = strlen(client->smbname);
340 if (temp == 0 || temp >= MAXKTCNAMELEN)
342 strcpy(tp, client->smbname);
347 status = UuidCreate((UUID *) & uuid);
348 memcpy(tp, &uuid, sizeof(uuid));
352 #ifndef AFS_WIN95_ENV
353 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
354 if ( ktcMutex == NULL )
355 return KTC_PIOCTLFAIL;
356 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
357 if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
358 CloseHandle(ktcMutex);
359 return KTC_PIOCTLFAIL;
363 /* RPC to send session key */
364 status = send_key(uuid, token->sessionKey.data);
365 if (status != RPC_S_OK) {
367 strcpy(rpcErr, "RPC failure in AFS gateway");
369 DceErrorInqText(status, rpcErr);
370 if (status == RPC_S_SERVER_UNAVAILABLE ||
371 status == EPT_S_NOT_REGISTERED)
373 ReleaseMutex(ktcMutex);
374 CloseHandle(ktcMutex);
379 ReleaseMutex(ktcMutex);
380 CloseHandle(ktcMutex);
384 #endif /* AFS_WIN95_ENV */
386 /* set up for pioctl */
388 iob.in_size = tp - tbuffer;
390 iob.out_size = sizeof(tbuffer);
392 code = pioctl(0, VIOCSETTOK, &iob, 0);
394 #ifndef AFS_WIN95_ENV
395 ReleaseMutex(ktcMutex);
396 CloseHandle(ktcMutex);
397 #endif /* AFS_WIN95_ENV */
403 else if (errno == ENODEV)
405 else if (errno == EINVAL)
408 return KTC_PIOCTLFAIL;
410 return KTC_PIOCTLFAIL;
417 ktc_GetToken(struct ktc_principal *server, struct ktc_token *token,
418 int tokenLen, struct ktc_principal *client)
420 struct ViceIoctl iob;
421 char tbuffer[TBUFFERSIZE];
425 struct ClearToken ct;
432 HANDLE ktcMutex = NULL;
436 /* check to see if the user is requesting tokens for a principal
437 * other than afs. If so, check the local token cache.
439 if (strcmp(server->name, "afs")) {
440 return GetLocalToken(server, token, tokenLen, client);
444 strcpy(tp, server->cell);
445 tp += strlen(server->cell) + 1;
448 status = UuidCreate((UUID *) & uuid);
449 memcpy(tp, &uuid, sizeof(uuid));
453 iob.in_size = tp - tbuffer;
455 iob.out_size = sizeof(tbuffer);
457 #ifndef AFS_WIN95_ENV
458 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
459 if ( ktcMutex == NULL )
460 return KTC_PIOCTLFAIL;
461 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
462 if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
463 CloseHandle(ktcMutex);
464 return KTC_PIOCTLFAIL;
467 #endif /* AFS_WIN95_ENV */
469 code = pioctl(0, VIOCNEWGETTOK, &iob, 0);
471 #ifndef AFS_WIN95_ENV
472 ReleaseMutex(ktcMutex);
473 CloseHandle(ktcMutex);
474 #endif /* AFS_WIN95_ENV */
478 else if (errno == ENODEV)
480 else if (errno == EINVAL)
482 else if (errno == EDOM)
485 return KTC_PIOCTLFAIL;
487 return KTC_PIOCTLFAIL;
490 #ifndef AFS_WIN95_ENV
491 /* get rid of RPC for win95 build */
492 /* RPC to receive session key */
493 status = receive_key(uuid, token->sessionKey.data);
495 ReleaseMutex(ktcMutex);
496 CloseHandle(ktcMutex);
498 if (status != RPC_S_OK) {
500 strcpy(rpcErr, "RPC failure in AFS gateway");
502 DceErrorInqText(status, rpcErr);
503 if (status == RPC_S_SERVER_UNAVAILABLE
504 || status == EPT_S_NOT_REGISTERED)
509 #endif /* AFS_WIN95_ENV */
514 memcpy(&ticketLen, cp, sizeof(ticketLen));
515 cp += sizeof(ticketLen);
517 /* remember where ticket is and skip over it */
521 /* size of clear token */
522 memcpy(&temp, cp, sizeof(temp));
524 if (temp != sizeof(ct))
528 memcpy(&ct, cp, temp);
531 /* skip over primary flag */
534 /* remember cell name and skip over it */
536 cellNameSize = strlen(cp);
537 cp += cellNameSize + 1;
539 /* user name is here */
541 /* check that ticket will fit
542 * this compares the size of the ktc_token allocated by the app
543 * which might be smaller than the current definition of MAXKTCTICKETLEN
545 maxLen = tokenLen - sizeof(struct ktc_token) + MAXKTCTICKETLEN;
546 if (maxLen < ticketLen)
549 /* set return values */
550 memcpy(token->ticket, ticketP, ticketLen);
551 token->startTime = ct.BeginTimestamp;
552 token->endTime = ct.EndTimestamp;
553 if (ct.AuthHandle == -1)
555 token->kvno = ct.AuthHandle;
556 #ifndef AFS_WIN95_ENV
558 * Session key has already been set via RPC
561 memcpy(&token->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
562 #endif /* AFS_WIN95_ENV */
563 token->ticketLen = ticketLen;
565 strcpy(client->name, cp);
566 client->instance[0] = '\0';
567 strcpy(client->cell, cellName);
574 ktc_ListTokens(int cellNum, int *cellNumP, struct ktc_principal *server)
576 struct ViceIoctl iob;
577 char tbuffer[TBUFFERSIZE];
579 int newIter, ticketLen, temp;
581 HANDLE ktcMutex = NULL;
583 #ifndef AFS_WIN95_ENV
584 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
585 if ( ktcMutex == NULL )
586 return KTC_PIOCTLFAIL;
587 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
588 if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
589 CloseHandle(ktcMutex);
590 return KTC_PIOCTLFAIL;
593 #endif /* AFS_WIN95_ENV */
598 memcpy(tp, &cellNum, sizeof(cellNum));
599 tp += sizeof(cellNum);
603 iob.in_size = tp - tbuffer;
605 iob.out_size = sizeof(tbuffer);
607 code = pioctl(0, VIOCGETTOK, &iob, 0);
609 #ifndef AFS_WIN95_ENV
610 ReleaseMutex(ktcMutex);
611 CloseHandle(ktcMutex);
612 #endif /* AFS_WIN95_ENV */
618 else if (errno == ENODEV)
620 else if (errno == EINVAL)
622 else if (errno == EDOM)
625 return KTC_PIOCTLFAIL;
627 return KTC_PIOCTLFAIL;
633 memcpy(&newIter, cp, sizeof(newIter));
634 cp += sizeof(newIter);
637 memcpy(&ticketLen, cp, sizeof(ticketLen));
638 cp += sizeof(ticketLen);
640 /* skip over ticket */
643 /* clear token size */
644 memcpy(&temp, cp, sizeof(temp));
646 if (temp != sizeof(struct ClearToken))
649 /* skip over clear token */
650 cp += sizeof(struct ClearToken);
652 /* skip over primary flag */
655 /* cell name is here */
657 /* set return values */
658 strcpy(server->cell, cp);
659 server->instance[0] = '\0';
660 strcpy(server->name, "afs");
667 ktc_ForgetToken(struct ktc_principal *server)
669 struct ViceIoctl iob;
670 char tbuffer[TBUFFERSIZE];
673 HANDLE ktcMutex = NULL;
675 if (strcmp(server->name, "afs")) {
676 return ForgetOneLocalToken(server);
679 #ifndef AFS_WIN95_ENV
680 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
681 if ( ktcMutex == NULL )
682 return KTC_PIOCTLFAIL;
683 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
684 if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
685 CloseHandle(ktcMutex);
686 return KTC_PIOCTLFAIL;
689 #endif /* AFS_WIN95_ENV */
694 strcpy(tp, server->cell);
695 tp += strlen(tp) + 1;
699 iob.in_size = tp - tbuffer;
701 iob.out_size = sizeof(tbuffer);
703 code = pioctl(0, VIOCDELTOK, &iob, 0);
704 #ifndef AFS_WIN95_ENV
705 ReleaseMutex(ktcMutex);
706 CloseHandle(ktcMutex);
707 #endif /* AFS_WIN95_ENV */
712 else if (errno == EDOM)
714 else if (errno == ENODEV)
717 return KTC_PIOCTLFAIL;
719 return KTC_PIOCTLFAIL;
725 ktc_ForgetAllTokens()
727 struct ViceIoctl iob;
728 char tbuffer[TBUFFERSIZE];
730 HANDLE ktcMutex = NULL;
732 (void)ForgetLocalTokens();
734 #ifndef AFS_WIN95_ENV
735 ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
736 if ( ktcMutex == NULL )
737 return KTC_PIOCTLFAIL;
738 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
739 if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
740 CloseHandle(ktcMutex);
741 return KTC_PIOCTLFAIL;
744 #endif /* AFS_WIN95_ENV */
750 iob.out_size = sizeof(tbuffer);
752 code = pioctl(0, VIOCDELALLTOK, &iob, 0);
753 #ifndef AFS_WIN95_ENV
754 ReleaseMutex(ktcMutex);
755 CloseHandle(ktcMutex);
756 #endif /* AFS_WIN95_ENV */
762 return KTC_PIOCTLFAIL;
764 return KTC_PIOCTLFAIL;
776 #define MAXLOCALTOKENS 4
780 struct ktc_principal server;
781 struct ktc_principal client;
782 struct ktc_token token;
783 } local_tokens[MAXLOCALTOKENS] = {
787 SetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
788 struct ktc_principal *aclient, afs_int32 flags)
793 LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++)
794 if (local_tokens[i].valid) {
795 if ((strcmp(local_tokens[i].server.name, aserver->name) == 0)
796 && (strcmp(local_tokens[i].server.instance, aserver->instance)
798 && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
799 found = i; /* replace existing entry */
802 } else if (found == -1)
803 found = i; /* remember empty slot but keep looking for a match */
805 UNLOCK_GLOBAL_MUTEX return KTC_NOENT;
807 memcpy(&local_tokens[found].token, atoken, sizeof(struct ktc_token));
808 memcpy(&local_tokens[found].server, aserver,
809 sizeof(struct ktc_principal));
810 memcpy(&local_tokens[found].client, aclient,
811 sizeof(struct ktc_principal));
812 local_tokens[found].valid = 1;
813 UNLOCK_GLOBAL_MUTEX return 0;
818 GetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
819 int atokenLen, struct ktc_principal *aclient)
823 LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++)
824 if (local_tokens[i].valid
825 && (strcmp(local_tokens[i].server.name, aserver->name) == 0)
826 && (strcmp(local_tokens[i].server.instance, aserver->instance) ==
828 && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
829 memcpy(atoken, &local_tokens[i].token,
830 min(atokenLen, sizeof(struct ktc_token)));
831 memcpy(aclient, &local_tokens[i].client,
832 sizeof(struct ktc_principal));
833 UNLOCK_GLOBAL_MUTEX return 0;
835 UNLOCK_GLOBAL_MUTEX return KTC_NOENT;
844 LOCK_GLOBAL_MUTEX 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));
849 UNLOCK_GLOBAL_MUTEX return 0;
854 ForgetOneLocalToken(struct ktc_principal *aserver)
858 LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++) {
859 if (local_tokens[i].valid
860 && (strcmp(local_tokens[i].server.name, aserver->name) == 0)
861 && (strcmp(local_tokens[i].server.instance, aserver->instance) ==
863 && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
864 local_tokens[i].valid = 0;
865 memset(&local_tokens[i].token.sessionKey, 0,
866 sizeof(struct ktc_encryptionKey));
867 UNLOCK_GLOBAL_MUTEX return 0;
870 UNLOCK_GLOBAL_MUTEX return KTC_NOENT;