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";
50 * Support for RPC's to send and receive session keys
52 * Session keys must not be sent and received in the clear. We have no
53 * way to piggyback encryption on SMB, so we use a separate RPC, using
54 * packet privacy (when available). In SetToken, the RPC is done first;
55 * in GetToken, the pioctl is done first.
60 void __RPC_FAR *__RPC_USER
61 midl_user_allocate(size_t cBytes)
63 return ((void __RPC_FAR *)malloc(cBytes));
67 midl_user_free(void __RPC_FAR * p)
73 * Determine the server name to be used in the RPC binding. If it is
74 * the same as the client (i.e. standalone, non-gateway), NULL can be
75 * used, so it is not necessary to call gethostbyname().
78 getservername(char **snp, unsigned int snSize)
84 RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0, KEY_QUERY_VALUE,
86 if (code != ERROR_SUCCESS)
88 code = RegQueryValueEx(parmKey, "Gateway", NULL, NULL, *snp, &snSize);
90 if (code == ERROR_SUCCESS)
93 /* No gateway name in registry; use ourself */
98 send_key(afs_uuid_t uuid, char sessionKey[8])
101 char *stringBinding = NULL;
102 ULONG authnLevel, authnSvc;
103 char serverName[256];
104 char *serverNamep = serverName;
106 BOOL encryptionOff = FALSE;
109 /* Encryption on by default */
110 if (GetEnvironmentVariable("AFS_RPC_ENCRYPT", encrypt, sizeof(encrypt)))
111 if (!strcmpi(encrypt, "OFF"))
112 encryptionOff = TRUE;
114 /* Protocol sequence is named pipe by default */
115 if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ", protseq, sizeof(protseq)))
116 strcpy(protseq, "ncacn_np");
119 getservername(&serverNamep, sizeof(serverName));
121 status = RpcStringBindingCompose("", /* obj uuid */
122 protseq, serverNamep, "", /* endpoint */
123 "", /* protocol options */
125 if (status != RPC_S_OK)
128 status = RpcBindingFromStringBinding(stringBinding, &hAfsHandle);
129 if (status != RPC_S_OK)
133 * On Windows 95/98, we must resolve the binding before calling
134 * SetAuthInfo. On Windows NT, we don't have to resolve yet,
135 * but it does no harm.
137 status = RpcEpResolveBinding(hAfsHandle, afsrpc_v1_0_c_ifspec);
138 if (status != RPC_S_OK)
142 authnLevel = RPC_C_AUTHN_LEVEL_NONE;
143 authnSvc = RPC_C_AUTHN_WINNT;
145 authnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
146 authnSvc = RPC_C_AUTHN_WINNT;
150 RpcBindingSetAuthInfo(hAfsHandle, NULL, authnLevel, authnSvc, NULL,
152 if (status != RPC_S_OK)
156 status = AFSRPC_SetToken(uuid, sessionKey);
159 status = RpcExceptionCode();
161 RpcEndExcept cleanup:if (stringBinding)
162 RpcStringFree(&stringBinding);
164 if (hAfsHandle != NULL)
165 RpcBindingFree(&hAfsHandle);
171 receive_key(afs_uuid_t uuid, char sessionKey[8])
174 char *stringBinding = NULL;
175 ULONG authnLevel, authnSvc;
176 char serverName[256];
177 char *serverNamep = serverName;
179 BOOL encryptionOff = FALSE;
182 /* Encryption on by default */
183 if (GetEnvironmentVariable("AFS_RPC_ENCRYPT", encrypt, sizeof(encrypt)))
184 if (!strcmpi(encrypt, "OFF"))
185 encryptionOff = TRUE;
187 /* Protocol sequence is named pipe by default */
188 if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ", protseq, sizeof(protseq)))
189 strcpy(protseq, "ncacn_np");
192 getservername(&serverNamep, sizeof(serverName));
194 status = RpcStringBindingCompose("", /* obj uuid */
195 protseq, serverNamep, "", /* endpoint */
196 "", /* protocol options */
198 if (status != RPC_S_OK)
201 status = RpcBindingFromStringBinding(stringBinding, &hAfsHandle);
202 if (status != RPC_S_OK)
206 * On Windows 95/98, we must resolve the binding before calling
207 * SetAuthInfo. On Windows NT, we don't have to resolve yet,
208 * but it does no harm.
210 status = RpcEpResolveBinding(hAfsHandle, afsrpc_v1_0_c_ifspec);
211 if (status != RPC_S_OK)
215 authnLevel = RPC_C_AUTHN_LEVEL_NONE;
216 authnSvc = RPC_C_AUTHN_WINNT;
218 authnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
219 authnSvc = RPC_C_AUTHN_WINNT;
223 RpcBindingSetAuthInfo(hAfsHandle, NULL, authnLevel, authnSvc, NULL,
225 if (status != RPC_S_OK)
229 status = AFSRPC_GetToken(uuid, sessionKey);
232 status = RpcExceptionCode();
234 RpcEndExcept cleanup:if (stringBinding)
235 RpcStringFree(&stringBinding);
237 if (hAfsHandle != NULL)
238 RpcBindingFree(&hAfsHandle);
244 ktc_SetToken(struct ktc_principal *server, struct ktc_token *token,
245 struct ktc_principal *client, int flags)
247 struct ViceIoctl iob;
250 struct ClearToken ct;
256 if (token->ticketLen < MINKTCTICKETLEN
257 || token->ticketLen > MAXKTCTICKETLEN)
260 if (strcmp(server->name, "afs")) {
261 return SetLocalToken(server, token, client, flags);
267 memcpy(tp, &token->ticketLen, sizeof(token->ticketLen));
268 tp += sizeof(&token->ticketLen);
271 memcpy(tp, token->ticket, token->ticketLen);
272 tp += token->ticketLen;
275 ct.AuthHandle = token->kvno;
277 * Instead of sending the session key in the clear, we zero it,
278 * and send it later, via RPC, encrypted.
280 #ifndef AFS_WIN95_ENV
282 * memcpy(ct.HandShakeKey, &token->sessionKey, sizeof(token->sessionKey));
284 memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
286 memcpy(ct.HandShakeKey, &token->sessionKey, sizeof(token->sessionKey));
288 ct.BeginTimestamp = token->startTime;
289 ct.EndTimestamp = token->endTime;
290 if (ct.BeginTimestamp == 0)
291 ct.BeginTimestamp = 1;
293 /* We don't know from Vice ID's yet */
294 ct.ViceId = 37; /* XXX */
295 if (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1)
296 ct.BeginTimestamp++; /* force lifetime to be even */
298 /* size of clear token */
299 temp = sizeof(struct ClearToken);
300 memcpy(tp, &temp, sizeof(temp));
303 /* clear token itself */
304 memcpy(tp, &ct, sizeof(ct));
307 /* flags; on NT there is no setpag flag, but there is an
308 * integrated logon flag */
309 temp = ((flags & AFS_SETTOK_LOGON) ? PIOCTL_LOGON : 0);
310 memcpy(tp, &temp, sizeof(temp));
314 temp = strlen(server->cell);
315 if (temp >= MAXKTCREALMLEN)
317 strcpy(tp, server->cell);
321 temp = strlen(client->name);
322 if (temp >= MAXKTCNAMELEN)
324 strcpy(tp, client->name);
327 /* we need the SMB user name to associate the tokens with in the
328 * integrated logon case. */
329 if (flags & AFS_SETTOK_LOGON) {
330 if (client->smbname == NULL)
333 temp = strlen(client->smbname);
334 if (temp == 0 || temp >= MAXKTCNAMELEN)
336 strcpy(tp, client->smbname);
341 status = UuidCreate((UUID *) & uuid);
342 memcpy(tp, &uuid, sizeof(uuid));
345 #ifndef AFS_WIN95_ENV
346 /* RPC to send session key */
347 status = send_key(uuid, token->sessionKey.data);
348 if (status != RPC_S_OK) {
350 strcpy(rpcErr, "RPC failure in AFS gateway");
352 DceErrorInqText(status, rpcErr);
353 if (status == RPC_S_SERVER_UNAVAILABLE
354 || status == EPT_S_NOT_REGISTERED)
359 #endif /* AFS_WIN95_ENV */
361 /* set up for pioctl */
363 iob.in_size = tp - tbuffer;
365 iob.out_size = sizeof(tbuffer);
367 code = pioctl(0, VIOCSETTOK, &iob, 0);
372 else if (errno == ENODEV)
374 else if (errno == EINVAL)
377 return KTC_PIOCTLFAIL;
379 return KTC_PIOCTLFAIL;
386 ktc_GetToken(struct ktc_principal *server, struct ktc_token *token,
387 int tokenLen, struct ktc_principal *client)
389 struct ViceIoctl iob;
394 struct ClearToken ct;
404 /* check to see if the user is requesting tokens for a principal
405 * other than afs. If so, check the local token cache.
407 if (strcmp(server->name, "afs")) {
408 return GetLocalToken(server, token, tokenLen, client);
412 strcpy(tp, server->cell);
413 tp += strlen(server->cell) + 1;
416 status = UuidCreate((UUID *) & uuid);
417 memcpy(tp, &uuid, sizeof(uuid));
421 iob.in_size = tp - tbuffer;
423 iob.out_size = sizeof(tbuffer);
425 code = pioctl(0, VIOCNEWGETTOK, &iob, 0);
430 else if (errno == ENODEV)
432 else if (errno == EINVAL)
434 else if (errno == EDOM)
437 return KTC_PIOCTLFAIL;
439 return KTC_PIOCTLFAIL;
441 #ifndef AFS_WIN95_ENV /* get rid of RPC for win95 build */
442 /* RPC to receive session key */
443 status = receive_key(uuid, token->sessionKey.data);
444 if (status != RPC_S_OK) {
446 strcpy(rpcErr, "RPC failure in AFS gateway");
448 DceErrorInqText(status, rpcErr);
449 if (status == RPC_S_SERVER_UNAVAILABLE
450 || status == EPT_S_NOT_REGISTERED)
455 #endif /* AFS_WIN95_ENV */
460 memcpy(&ticketLen, cp, sizeof(ticketLen));
461 cp += sizeof(ticketLen);
463 /* remember where ticket is and skip over it */
467 /* size of clear token */
468 memcpy(&temp, cp, sizeof(temp));
470 if (temp != sizeof(ct))
474 memcpy(&ct, cp, temp);
477 /* skip over primary flag */
480 /* remember cell name and skip over it */
482 cellNameSize = strlen(cp);
483 cp += cellNameSize + 1;
485 /* user name is here */
487 /* check that ticket will fit */
488 maxLen = tokenLen - sizeof(struct ktc_token) + MAXKTCTICKETLEN;
489 if (maxLen < ticketLen)
492 /* set return values */
493 memcpy(token->ticket, ticketP, ticketLen);
494 token->startTime = ct.BeginTimestamp;
495 token->endTime = ct.EndTimestamp;
496 if (ct.AuthHandle == -1)
498 token->kvno = ct.AuthHandle;
499 #ifndef AFS_WIN95_ENV
501 * Session key has already been set via RPC
504 memcpy(&token->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
505 #endif /* AFS_WIN95_ENV */
506 token->ticketLen = ticketLen;
508 strcpy(client->name, cp);
509 client->instance[0] = '\0';
510 strcpy(client->cell, cellName);
517 ktc_ListTokens(int cellNum, int *cellNumP, struct ktc_principal *server)
519 struct ViceIoctl iob;
522 int newIter, ticketLen, temp;
528 memcpy(tp, &cellNum, sizeof(cellNum));
529 tp += sizeof(cellNum);
533 iob.in_size = tp - tbuffer;
535 iob.out_size = sizeof(tbuffer);
537 code = pioctl(0, VIOCGETTOK, &iob, 0);
542 else if (errno == ENODEV)
544 else if (errno == EINVAL)
546 else if (errno == EDOM)
549 return KTC_PIOCTLFAIL;
551 return KTC_PIOCTLFAIL;
557 memcpy(&newIter, cp, sizeof(newIter));
558 cp += sizeof(newIter);
561 memcpy(&ticketLen, cp, sizeof(ticketLen));
562 cp += sizeof(ticketLen);
564 /* skip over ticket */
567 /* clear token size */
568 memcpy(&temp, cp, sizeof(temp));
570 if (temp != sizeof(struct ClearToken))
573 /* skip over clear token */
574 cp += sizeof(struct ClearToken);
576 /* skip over primary flag */
579 /* cell name is here */
581 /* set return values */
582 strcpy(server->cell, cp);
583 server->instance[0] = '\0';
584 strcpy(server->name, "afs");
591 ktc_ForgetToken(struct ktc_principal *server)
593 struct ViceIoctl iob;
598 if (strcmp(server->name, "afs")) {
599 return ForgetOneLocalToken(server);
605 strcpy(tp, server->cell);
606 tp += strlen(tp) + 1;
610 iob.in_size = tp - tbuffer;
612 iob.out_size = sizeof(tbuffer);
614 code = pioctl(0, VIOCDELTOK, &iob, 0);
619 else if (errno == EDOM)
621 else if (errno == ENODEV)
624 return KTC_PIOCTLFAIL;
626 return KTC_PIOCTLFAIL;
632 ktc_ForgetAllTokens()
634 struct ViceIoctl iob;
638 (void)ForgetLocalTokens();
644 iob.out_size = sizeof(tbuffer);
646 code = pioctl(0, VIOCDELALLTOK, &iob, 0);
652 return KTC_PIOCTLFAIL;
654 return KTC_PIOCTLFAIL;
666 #define MAXLOCALTOKENS 4
670 struct ktc_principal server;
671 struct ktc_principal client;
672 struct ktc_token token;
673 } local_tokens[MAXLOCALTOKENS] = {
677 SetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
678 struct ktc_principal *aclient, afs_int32 flags)
683 LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++)
684 if (local_tokens[i].valid) {
685 if ((strcmp(local_tokens[i].server.name, aserver->name) == 0)
686 && (strcmp(local_tokens[i].server.instance, aserver->instance)
688 && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
689 found = i; /* replace existing entry */
692 } else if (found == -1)
693 found = i; /* remember empty slot but keep looking for a match */
695 UNLOCK_GLOBAL_MUTEX return KTC_NOENT;
697 memcpy(&local_tokens[found].token, atoken, sizeof(struct ktc_token));
698 memcpy(&local_tokens[found].server, aserver,
699 sizeof(struct ktc_principal));
700 memcpy(&local_tokens[found].client, aclient,
701 sizeof(struct ktc_principal));
702 local_tokens[found].valid = 1;
703 UNLOCK_GLOBAL_MUTEX return 0;
708 GetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
709 int atokenLen, struct ktc_principal *aclient)
713 LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++)
714 if (local_tokens[i].valid
715 && (strcmp(local_tokens[i].server.name, aserver->name) == 0)
716 && (strcmp(local_tokens[i].server.instance, aserver->instance) ==
718 && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
719 memcpy(atoken, &local_tokens[i].token,
720 min(atokenLen, sizeof(struct ktc_token)));
721 memcpy(aclient, &local_tokens[i].client,
722 sizeof(struct ktc_principal));
723 UNLOCK_GLOBAL_MUTEX return 0;
725 UNLOCK_GLOBAL_MUTEX return KTC_NOENT;
734 LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++) {
735 local_tokens[i].valid = 0;
736 memset(&local_tokens[i].token.sessionKey, 0,
737 sizeof(struct ktc_encryptionKey));
739 UNLOCK_GLOBAL_MUTEX return 0;
744 ForgetOneLocalToken(struct ktc_principal *aserver)
748 LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++) {
749 if (local_tokens[i].valid
750 && (strcmp(local_tokens[i].server.name, aserver->name) == 0)
751 && (strcmp(local_tokens[i].server.instance, aserver->instance) ==
753 && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
754 local_tokens[i].valid = 0;
755 memset(&local_tokens[i].token.sessionKey, 0,
756 sizeof(struct ktc_encryptionKey));
757 UNLOCK_GLOBAL_MUTEX return 0;
760 UNLOCK_GLOBAL_MUTEX return KTC_NOENT;