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.
287 memcpy(ct.HandShakeKey, &token->sessionKey, sizeof(token->sessionKey));
289 memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
290 ct.BeginTimestamp = token->startTime;
291 ct.EndTimestamp = token->endTime;
292 if (ct.BeginTimestamp == 0) ct.BeginTimestamp = 1;
294 /* We don't know from Vice ID's yet */
295 ct.ViceId = 37; /* XXX */
296 if (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1)
297 ct.BeginTimestamp++; /* force lifetime to be even */
299 /* size of clear token */
300 temp = sizeof(struct ClearToken);
301 memcpy(tp, &temp, sizeof(temp));
304 /* clear token itself */
305 memcpy(tp, &ct, sizeof(ct));
308 /* flags; on NT there is no setpag flag, but there is an
309 * integrated logon flag */
310 temp = ((flags & AFS_SETTOK_LOGON) ? PIOCTL_LOGON : 0);
311 memcpy(tp, &temp, sizeof(temp));
315 temp = strlen(server->cell);
316 if (temp >= MAXKTCREALMLEN)
318 strcpy(tp, server->cell);
322 temp = strlen(client->name);
323 if (temp >= MAXKTCNAMELEN)
325 strcpy(tp, client->name);
329 status = UuidCreate((UUID *)&uuid);
330 memcpy(tp, &uuid, sizeof(uuid));
333 /* RPC to send session key */
334 status = send_key(uuid, token->sessionKey.data);
335 if (status != RPC_S_OK) {
337 strcpy(rpcErr, "RPC failure in AFS gateway");
339 DceErrorInqText(status, rpcErr);
340 if (status == RPC_S_SERVER_UNAVAILABLE
341 || status == EPT_S_NOT_REGISTERED)
347 /* set up for pioctl */
349 iob.in_size = tp - tbuffer;
351 iob.out_size = sizeof(tbuffer);
353 code = pioctl(0, VIOCSETTOK, &iob, 0);
358 else if (errno == ENODEV)
360 else if (errno == EINVAL)
363 return KTC_PIOCTLFAIL;
366 return KTC_PIOCTLFAIL;
373 struct ktc_principal *server,
374 struct ktc_token *token,
376 struct ktc_principal *client)
378 struct ViceIoctl iob;
383 struct ClearToken ct;
393 /* check to see if the user is requesting tokens for a principal
394 * other than afs. If so, check the local token cache.
396 if (strcmp(server->name, "afs")) {
397 return GetLocalToken(server, token, tokenLen, client);
401 strcpy(tp, server->cell);
402 tp += strlen(server->cell) + 1;
405 status = UuidCreate((UUID *)&uuid);
406 memcpy(tp, &uuid, sizeof(uuid));
410 iob.in_size = tp - tbuffer;
412 iob.out_size = sizeof(tbuffer);
414 code = pioctl(0, VIOCNEWGETTOK, &iob, 0);
419 else if (errno == ENODEV)
421 else if (errno == EINVAL)
423 else if (errno == EDOM)
426 return KTC_PIOCTLFAIL;
429 return KTC_PIOCTLFAIL;
432 /* RPC to receive session key */
433 status = receive_key(uuid, token->sessionKey.data);
434 if (status != RPC_S_OK) {
436 strcpy(rpcErr, "RPC failure in AFS gateway");
438 DceErrorInqText(status, rpcErr);
439 if (status == RPC_S_SERVER_UNAVAILABLE
440 || status == EPT_S_NOT_REGISTERED)
449 memcpy(&ticketLen, cp, sizeof(ticketLen));
450 cp += sizeof(ticketLen);
452 /* remember where ticket is and skip over it */
456 /* size of clear token */
457 memcpy(&temp, cp, sizeof(temp));
459 if (temp != sizeof(ct))
463 memcpy(&ct, cp, temp);
466 /* skip over primary flag */
469 /* remember cell name and skip over it */
471 cellNameSize = strlen(cp);
472 cp += cellNameSize + 1;
474 /* user name is here */
476 /* check that ticket will fit */
477 maxLen = tokenLen - sizeof(struct ktc_token) + MAXKTCTICKETLEN;
478 if (maxLen < ticketLen)
481 /* set return values */
482 memcpy(token->ticket, ticketP, ticketLen);
483 token->startTime = ct.BeginTimestamp;
484 token->endTime = ct.EndTimestamp;
485 if (ct.AuthHandle == -1) ct.AuthHandle = 999;
486 token->kvno = ct.AuthHandle;
488 * Session key has already been set via RPC
491 memcpy(&token->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
493 token->ticketLen = ticketLen;
495 strcpy(client->name, cp);
496 client->instance[0] = '\0';
497 strcpy(client->cell, cellName);
506 struct ktc_principal *server)
508 struct ViceIoctl iob;
511 int newIter, ticketLen, temp;
517 memcpy(tp, &cellNum, sizeof(cellNum));
518 tp += sizeof(cellNum);
522 iob.in_size = tp - tbuffer;
524 iob.out_size = sizeof(tbuffer);
526 code = pioctl(0, VIOCGETTOK, &iob, 0);
531 else if (errno == ENODEV)
533 else if (errno == EINVAL)
535 else if (errno == EDOM)
538 return KTC_PIOCTLFAIL;
541 return KTC_PIOCTLFAIL;
547 memcpy(&newIter, cp, sizeof(newIter));
548 cp += sizeof(newIter);
551 memcpy(&ticketLen, cp, sizeof(ticketLen));
552 cp += sizeof(ticketLen);
554 /* skip over ticket */
557 /* clear token size */
558 memcpy(&temp, cp, sizeof(temp));
560 if (temp != sizeof(struct ClearToken))
563 /* skip over clear token */
564 cp += sizeof(struct ClearToken);
566 /* skip over primary flag */
569 /* cell name is here */
571 /* set return values */
572 strcpy(server->cell, cp);
573 server->instance[0] = '\0';
574 strcpy(server->name, "afs");
581 struct ktc_principal *server)
583 struct ViceIoctl iob;
588 if (strcmp(server->name, "afs")) {
589 return ForgetOneLocalToken(server);
595 strcpy(tp, server->cell);
596 tp += strlen(tp) + 1;
600 iob.in_size = tp - tbuffer;
602 iob.out_size = sizeof(tbuffer);
604 code = pioctl(0, VIOCDELTOK, &iob, 0);
609 else if (errno == EDOM)
611 else if (errno == ENODEV)
614 return KTC_PIOCTLFAIL;
617 return KTC_PIOCTLFAIL;
622 int ktc_ForgetAllTokens()
624 struct ViceIoctl iob;
628 (void) ForgetLocalTokens();
634 iob.out_size = sizeof(tbuffer);
636 code = pioctl(0, VIOCDELALLTOK, &iob, 0);
642 return KTC_PIOCTLFAIL;
645 return KTC_PIOCTLFAIL;
656 #define MAXLOCALTOKENS 4
660 struct ktc_principal server;
661 struct ktc_principal client;
662 struct ktc_token token;
663 } local_tokens[MAXLOCALTOKENS] = {0};
665 static int SetLocalToken(struct ktc_principal *aserver,
666 struct ktc_token *atoken,
667 struct ktc_principal *aclient,
674 for (i = 0; i < MAXLOCALTOKENS; i++)
675 if (local_tokens[i].valid) {
676 if ((strcmp(local_tokens[i].server.name, aserver->name) == 0) &&
677 (strcmp(local_tokens[i].server.instance,
678 aserver->instance) == 0) &&
679 (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
680 found = i; /* replace existing entry */
683 } else if (found == -1)
684 found = i; /* remember empty slot but keep looking for a match */
689 memcpy(&local_tokens[found].token, atoken, sizeof(struct ktc_token));
690 memcpy(&local_tokens[found].server, aserver, sizeof(struct ktc_principal));
691 memcpy(&local_tokens[found].client, aclient, sizeof(struct ktc_principal));
692 local_tokens[found].valid = 1;
698 static int GetLocalToken(struct ktc_principal *aserver,
699 struct ktc_token *atoken,
701 struct ktc_principal *aclient)
706 for (i = 0; i < MAXLOCALTOKENS; i++)
707 if (local_tokens[i].valid &&
708 (strcmp(local_tokens[i].server.name, aserver->name) == 0) &&
709 (strcmp(local_tokens[i].server.instance,aserver->instance) == 0) &&
710 (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
711 memcpy(atoken, &local_tokens[i].token,
712 min(atokenLen, sizeof(struct ktc_token)));
713 memcpy(aclient, &local_tokens[i].client,
714 sizeof(struct ktc_principal));
723 static int ForgetLocalTokens()
728 for (i = 0; i < MAXLOCALTOKENS; i++) {
729 local_tokens[i].valid = 0;
730 memset(&local_tokens[i].token.sessionKey, 0,
731 sizeof(struct ktc_encryptionKey));
738 static int ForgetOneLocalToken(struct ktc_principal *aserver)
743 for (i = 0; i < MAXLOCALTOKENS; i++) {
744 if (local_tokens[i].valid &&
745 (strcmp(local_tokens[i].server.name, aserver->name) == 0) &&
746 (strcmp(local_tokens[i].server.instance,aserver->instance) == 0) &&
747 (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
748 local_tokens[i].valid = 0;
749 memset(&local_tokens[i].token.sessionKey, 0,
750 sizeof(struct ktc_encryptionKey));