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 <afs/param.h>
15 #include <afs/pthread_glock.h>
16 #include <sys/types.h>
22 #include <afs/smb_iocons.h>
23 #include <afs/pioctl_nt.h>
24 #include "../WINNT/afsd/afsrpc.h"
27 #include <afs/afsutil.h>
30 /* Forward declarations for local token cache. */
31 static int SetLocalToken(struct ktc_principal *aserver,
32 struct ktc_token *atoken,
33 struct ktc_principal *aclient,
35 static int GetLocalToken(struct ktc_principal *aserver,
36 struct ktc_token *atoken,
38 struct ktc_principal *aclient);
39 static int ForgetLocalTokens();
40 static int ForgetOneLocalToken(struct ktc_principal *aserver);
43 static char AFSConfigKeyName[] =
44 "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters";
47 * Support for RPC's to send and receive session keys
49 * Session keys must not be sent and received in the clear. We have no
50 * way to piggyback encryption on SMB, so we use a separate RPC, using
51 * packet privacy (when available). In SetToken, the RPC is done first;
52 * in GetToken, the pioctl is done first.
57 void __RPC_FAR * __RPC_USER midl_user_allocate (size_t cBytes)
59 return ((void __RPC_FAR *) malloc(cBytes));
62 void __RPC_USER midl_user_free(void __RPC_FAR * p)
68 * Determine the server name to be used in the RPC binding. If it is
69 * the same as the client (i.e. standalone, non-gateway), NULL can be
70 * used, so it is not necessary to call gethostbyname().
72 void getservername(char **snp, unsigned int snSize)
77 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
78 0, KEY_QUERY_VALUE, &parmKey);
79 if (code != ERROR_SUCCESS)
81 code = RegQueryValueEx(parmKey, "Gateway", NULL, NULL,
83 RegCloseKey (parmKey);
84 if (code == ERROR_SUCCESS)
87 /* No gateway name in registry; use ourself */
91 RPC_STATUS send_key(afs_uuid_t uuid, char sessionKey[8])
94 char *stringBinding = NULL;
95 ULONG authnLevel, authnSvc;
97 char *serverNamep = serverName;
99 BOOL encryptionOff = FALSE;
102 /* Encryption on by default */
103 if (GetEnvironmentVariable("AFS_RPC_ENCRYPT",
104 encrypt, sizeof(encrypt)))
105 if (!strcmpi(encrypt, "OFF"))
106 encryptionOff = TRUE;
108 /* Protocol sequence is named pipe by default */
109 if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ",
110 protseq, sizeof(protseq)))
111 strcpy(protseq, "ncacn_np");
114 getservername(&serverNamep, sizeof(serverName));
116 status = RpcStringBindingCompose("", /* obj uuid */
120 "", /* protocol options */
122 if (status != RPC_S_OK)
125 status = RpcBindingFromStringBinding(stringBinding, &hAfsHandle);
126 if (status != RPC_S_OK)
130 * On Windows 95/98, we must resolve the binding before calling
131 * SetAuthInfo. On Windows NT, we don't have to resolve yet,
132 * but it does no harm.
134 status = RpcEpResolveBinding(hAfsHandle, afsrpc_v1_0_c_ifspec);
135 if (status != RPC_S_OK)
139 authnLevel = RPC_C_AUTHN_LEVEL_NONE;
140 authnSvc = RPC_C_AUTHN_WINNT;
142 authnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
143 authnSvc = RPC_C_AUTHN_WINNT;
146 status = RpcBindingSetAuthInfo(hAfsHandle, NULL, authnLevel, authnSvc,
147 NULL, RPC_C_AUTHZ_NONE);
148 if (status != RPC_S_OK)
152 status = AFSRPC_SetToken(uuid, sessionKey);
155 status = RpcExceptionCode();
161 RpcStringFree(&stringBinding);
163 if (hAfsHandle != NULL)
164 RpcBindingFree(&hAfsHandle);
169 RPC_STATUS receive_key(afs_uuid_t uuid, char sessionKey[8])
172 char *stringBinding = NULL;
173 ULONG authnLevel, authnSvc;
174 char serverName[256];
175 char *serverNamep = serverName;
177 BOOL encryptionOff = FALSE;
180 /* Encryption on by default */
181 if (GetEnvironmentVariable("AFS_RPC_ENCRYPT",
182 encrypt, sizeof(encrypt)))
183 if (!strcmpi(encrypt, "OFF"))
184 encryptionOff = TRUE;
186 /* Protocol sequence is named pipe by default */
187 if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ",
188 protseq, sizeof(protseq)))
189 strcpy(protseq, "ncacn_np");
192 getservername(&serverNamep, sizeof(serverName));
194 status = RpcStringBindingCompose("", /* obj uuid */
198 "", /* protocol options */
200 if (status != RPC_S_OK)
203 status = RpcBindingFromStringBinding(stringBinding, &hAfsHandle);
204 if (status != RPC_S_OK)
208 * On Windows 95/98, we must resolve the binding before calling
209 * SetAuthInfo. On Windows NT, we don't have to resolve yet,
210 * but it does no harm.
212 status = RpcEpResolveBinding(hAfsHandle, afsrpc_v1_0_c_ifspec);
213 if (status != RPC_S_OK)
217 authnLevel = RPC_C_AUTHN_LEVEL_NONE;
218 authnSvc = RPC_C_AUTHN_WINNT;
220 authnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
221 authnSvc = RPC_C_AUTHN_WINNT;
224 status = RpcBindingSetAuthInfo(hAfsHandle, NULL, authnLevel, authnSvc,
225 NULL, RPC_C_AUTHZ_NONE);
226 if (status != RPC_S_OK)
230 status = AFSRPC_GetToken(uuid, sessionKey);
233 status = RpcExceptionCode();
239 RpcStringFree(&stringBinding);
241 if (hAfsHandle != NULL)
242 RpcBindingFree(&hAfsHandle);
248 struct ktc_principal *server,
249 struct ktc_token *token,
250 struct ktc_principal *client,
253 struct ViceIoctl iob;
256 struct ClearToken ct;
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) ct.BeginTimestamp = 1;
298 /* We don't know from Vice ID's yet */
299 ct.ViceId = 37; /* XXX */
300 if (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1)
301 ct.BeginTimestamp++; /* force lifetime to be even */
303 /* size of clear token */
304 temp = sizeof(struct ClearToken);
305 memcpy(tp, &temp, sizeof(temp));
308 /* clear token itself */
309 memcpy(tp, &ct, sizeof(ct));
312 /* flags; on NT there is no setpag flag, but there is an
313 * integrated logon flag */
314 temp = ((flags & AFS_SETTOK_LOGON) ? PIOCTL_LOGON : 0);
315 memcpy(tp, &temp, sizeof(temp));
319 temp = strlen(server->cell);
320 if (temp >= MAXKTCREALMLEN)
322 strcpy(tp, server->cell);
326 temp = strlen(client->name);
327 if (temp >= MAXKTCNAMELEN)
329 strcpy(tp, client->name);
333 status = UuidCreate((UUID *)&uuid);
334 memcpy(tp, &uuid, sizeof(uuid));
337 #ifndef AFS_WIN95_ENV
338 /* RPC to send session key */
339 status = send_key(uuid, token->sessionKey.data);
340 if (status != RPC_S_OK) {
342 strcpy(rpcErr, "RPC failure in AFS gateway");
344 DceErrorInqText(status, rpcErr);
345 if (status == RPC_S_SERVER_UNAVAILABLE
346 || status == EPT_S_NOT_REGISTERED)
351 #endif /* AFS_WIN95_ENV */
353 /* set up for pioctl */
355 iob.in_size = tp - tbuffer;
357 iob.out_size = sizeof(tbuffer);
359 code = pioctl(0, VIOCSETTOK, &iob, 0);
364 else if (errno == ENODEV)
366 else if (errno == EINVAL)
369 return KTC_PIOCTLFAIL;
372 return KTC_PIOCTLFAIL;
379 struct ktc_principal *server,
380 struct ktc_token *token,
382 struct ktc_principal *client)
384 struct ViceIoctl iob;
389 struct ClearToken ct;
399 /* check to see if the user is requesting tokens for a principal
400 * other than afs. If so, check the local token cache.
402 if (strcmp(server->name, "afs")) {
403 return GetLocalToken(server, token, tokenLen, client);
407 strcpy(tp, server->cell);
408 tp += strlen(server->cell) + 1;
411 status = UuidCreate((UUID *)&uuid);
412 memcpy(tp, &uuid, sizeof(uuid));
416 iob.in_size = tp - tbuffer;
418 iob.out_size = sizeof(tbuffer);
420 code = pioctl(0, VIOCNEWGETTOK, &iob, 0);
425 else if (errno == ENODEV)
427 else if (errno == EINVAL)
429 else if (errno == EDOM)
432 return KTC_PIOCTLFAIL;
435 return KTC_PIOCTLFAIL;
438 #ifndef AFS_WIN95_ENV /* get rid of RPC for win95 build */
439 /* RPC to receive session key */
440 status = receive_key(uuid, token->sessionKey.data);
441 if (status != RPC_S_OK) {
443 strcpy(rpcErr, "RPC failure in AFS gateway");
445 DceErrorInqText(status, rpcErr);
446 if (status == RPC_S_SERVER_UNAVAILABLE
447 || status == EPT_S_NOT_REGISTERED)
452 #endif /* AFS_WIN95_ENV */
457 memcpy(&ticketLen, cp, sizeof(ticketLen));
458 cp += sizeof(ticketLen);
460 /* remember where ticket is and skip over it */
464 /* size of clear token */
465 memcpy(&temp, cp, sizeof(temp));
467 if (temp != sizeof(ct))
471 memcpy(&ct, cp, temp);
474 /* skip over primary flag */
477 /* remember cell name and skip over it */
479 cellNameSize = strlen(cp);
480 cp += cellNameSize + 1;
482 /* user name is here */
484 /* check that ticket will fit */
485 maxLen = tokenLen - sizeof(struct ktc_token) + MAXKTCTICKETLEN;
486 if (maxLen < ticketLen)
489 /* set return values */
490 memcpy(token->ticket, ticketP, ticketLen);
491 token->startTime = ct.BeginTimestamp;
492 token->endTime = ct.EndTimestamp;
493 if (ct.AuthHandle == -1) ct.AuthHandle = 999;
494 token->kvno = ct.AuthHandle;
495 #ifndef AFS_WIN95_ENV
497 * Session key has already been set via RPC
500 memcpy(&token->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
501 #endif /* AFS_WIN95_ENV */
502 token->ticketLen = ticketLen;
504 strcpy(client->name, cp);
505 client->instance[0] = '\0';
506 strcpy(client->cell, cellName);
515 struct ktc_principal *server)
517 struct ViceIoctl iob;
520 int newIter, ticketLen, temp;
526 memcpy(tp, &cellNum, sizeof(cellNum));
527 tp += sizeof(cellNum);
531 iob.in_size = tp - tbuffer;
533 iob.out_size = sizeof(tbuffer);
535 code = pioctl(0, VIOCGETTOK, &iob, 0);
540 else if (errno == ENODEV)
542 else if (errno == EINVAL)
544 else if (errno == EDOM)
547 return KTC_PIOCTLFAIL;
550 return KTC_PIOCTLFAIL;
556 memcpy(&newIter, cp, sizeof(newIter));
557 cp += sizeof(newIter);
560 memcpy(&ticketLen, cp, sizeof(ticketLen));
561 cp += sizeof(ticketLen);
563 /* skip over ticket */
566 /* clear token size */
567 memcpy(&temp, cp, sizeof(temp));
569 if (temp != sizeof(struct ClearToken))
572 /* skip over clear token */
573 cp += sizeof(struct ClearToken);
575 /* skip over primary flag */
578 /* cell name is here */
580 /* set return values */
581 strcpy(server->cell, cp);
582 server->instance[0] = '\0';
583 strcpy(server->name, "afs");
590 struct ktc_principal *server)
592 struct ViceIoctl iob;
597 if (strcmp(server->name, "afs")) {
598 return ForgetOneLocalToken(server);
604 strcpy(tp, server->cell);
605 tp += strlen(tp) + 1;
609 iob.in_size = tp - tbuffer;
611 iob.out_size = sizeof(tbuffer);
613 code = pioctl(0, VIOCDELTOK, &iob, 0);
618 else if (errno == EDOM)
620 else if (errno == ENODEV)
623 return KTC_PIOCTLFAIL;
626 return KTC_PIOCTLFAIL;
631 int ktc_ForgetAllTokens()
633 struct ViceIoctl iob;
637 (void) ForgetLocalTokens();
643 iob.out_size = sizeof(tbuffer);
645 code = pioctl(0, VIOCDELALLTOK, &iob, 0);
651 return KTC_PIOCTLFAIL;
654 return KTC_PIOCTLFAIL;
665 #define MAXLOCALTOKENS 4
669 struct ktc_principal server;
670 struct ktc_principal client;
671 struct ktc_token token;
672 } local_tokens[MAXLOCALTOKENS] = {0};
674 static int SetLocalToken(struct ktc_principal *aserver,
675 struct ktc_token *atoken,
676 struct ktc_principal *aclient,
683 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,
687 aserver->instance) == 0) &&
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 */
698 memcpy(&local_tokens[found].token, atoken, sizeof(struct ktc_token));
699 memcpy(&local_tokens[found].server, aserver, sizeof(struct ktc_principal));
700 memcpy(&local_tokens[found].client, aclient, sizeof(struct ktc_principal));
701 local_tokens[found].valid = 1;
707 static int GetLocalToken(struct ktc_principal *aserver,
708 struct ktc_token *atoken,
710 struct ktc_principal *aclient)
715 for (i = 0; i < MAXLOCALTOKENS; i++)
716 if (local_tokens[i].valid &&
717 (strcmp(local_tokens[i].server.name, aserver->name) == 0) &&
718 (strcmp(local_tokens[i].server.instance,aserver->instance) == 0) &&
719 (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
720 memcpy(atoken, &local_tokens[i].token,
721 min(atokenLen, sizeof(struct ktc_token)));
722 memcpy(aclient, &local_tokens[i].client,
723 sizeof(struct ktc_principal));
732 static int ForgetLocalTokens()
737 for (i = 0; i < MAXLOCALTOKENS; i++) {
738 local_tokens[i].valid = 0;
739 memset(&local_tokens[i].token.sessionKey, 0,
740 sizeof(struct ktc_encryptionKey));
747 static int ForgetOneLocalToken(struct ktc_principal *aserver)
752 for (i = 0; i < MAXLOCALTOKENS; i++) {
753 if (local_tokens[i].valid &&
754 (strcmp(local_tokens[i].server.name, aserver->name) == 0) &&
755 (strcmp(local_tokens[i].server.instance,aserver->instance) == 0) &&
756 (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
757 local_tokens[i].valid = 0;
758 memset(&local_tokens[i].token.sessionKey, 0,
759 sizeof(struct ktc_encryptionKey));