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>
19 #include <afs/pthread_glock.h>
20 #include <sys/types.h>
26 #include <afs/smb_iocons.h>
27 #include <afs/pioctl_nt.h>
28 #include "WINNT/afsd/afsrpc.h"
31 #include <afs/afsutil.h>
34 /* Forward declarations for local token cache. */
35 static int SetLocalToken(struct ktc_principal *aserver,
36 struct ktc_token *atoken,
37 struct ktc_principal *aclient,
39 static int GetLocalToken(struct ktc_principal *aserver,
40 struct ktc_token *atoken,
42 struct ktc_principal *aclient);
43 static int ForgetLocalTokens();
44 static int ForgetOneLocalToken(struct ktc_principal *aserver);
47 static char AFSConfigKeyName[] =
48 "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters";
51 * Support for RPC's to send and receive session keys
53 * Session keys must not be sent and received in the clear. We have no
54 * way to piggyback encryption on SMB, so we use a separate RPC, using
55 * packet privacy (when available). In SetToken, the RPC is done first;
56 * in GetToken, the pioctl is done first.
61 void __RPC_FAR * __RPC_USER midl_user_allocate (size_t cBytes)
63 return ((void __RPC_FAR *) malloc(cBytes));
66 void __RPC_USER midl_user_free(void __RPC_FAR * p)
72 * Determine the server name to be used in the RPC binding. If it is
73 * the same as the client (i.e. standalone, non-gateway), NULL can be
74 * used, so it is not necessary to call gethostbyname().
76 void getservername(char **snp, unsigned int snSize)
81 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
82 0, KEY_QUERY_VALUE, &parmKey);
83 if (code != ERROR_SUCCESS)
85 code = RegQueryValueEx(parmKey, "Gateway", NULL, NULL,
87 RegCloseKey (parmKey);
88 if (code == ERROR_SUCCESS)
91 /* No gateway name in registry; use ourself */
95 RPC_STATUS send_key(afs_uuid_t uuid, char sessionKey[8])
98 char *stringBinding = NULL;
99 ULONG authnLevel, authnSvc;
100 char serverName[256];
101 char *serverNamep = serverName;
103 BOOL encryptionOff = FALSE;
106 /* Encryption on by default */
107 if (GetEnvironmentVariable("AFS_RPC_ENCRYPT",
108 encrypt, sizeof(encrypt)))
109 if (!strcmpi(encrypt, "OFF"))
110 encryptionOff = TRUE;
112 /* Protocol sequence is named pipe by default */
113 if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ",
114 protseq, sizeof(protseq)))
115 strcpy(protseq, "ncacn_np");
118 getservername(&serverNamep, sizeof(serverName));
120 status = RpcStringBindingCompose("", /* obj uuid */
124 "", /* protocol options */
126 if (status != RPC_S_OK)
129 status = RpcBindingFromStringBinding(stringBinding, &hAfsHandle);
130 if (status != RPC_S_OK)
134 * On Windows 95/98, we must resolve the binding before calling
135 * SetAuthInfo. On Windows NT, we don't have to resolve yet,
136 * but it does no harm.
138 status = RpcEpResolveBinding(hAfsHandle, afsrpc_v1_0_c_ifspec);
139 if (status != RPC_S_OK)
143 authnLevel = RPC_C_AUTHN_LEVEL_NONE;
144 authnSvc = RPC_C_AUTHN_WINNT;
146 authnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
147 authnSvc = RPC_C_AUTHN_WINNT;
150 status = RpcBindingSetAuthInfo(hAfsHandle, NULL, authnLevel, authnSvc,
151 NULL, RPC_C_AUTHZ_NONE);
152 if (status != RPC_S_OK)
156 status = AFSRPC_SetToken(uuid, sessionKey);
159 status = RpcExceptionCode();
165 RpcStringFree(&stringBinding);
167 if (hAfsHandle != NULL)
168 RpcBindingFree(&hAfsHandle);
173 RPC_STATUS receive_key(afs_uuid_t uuid, char sessionKey[8])
176 char *stringBinding = NULL;
177 ULONG authnLevel, authnSvc;
178 char serverName[256];
179 char *serverNamep = serverName;
181 BOOL encryptionOff = FALSE;
184 /* Encryption on by default */
185 if (GetEnvironmentVariable("AFS_RPC_ENCRYPT",
186 encrypt, sizeof(encrypt)))
187 if (!strcmpi(encrypt, "OFF"))
188 encryptionOff = TRUE;
190 /* Protocol sequence is named pipe by default */
191 if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ",
192 protseq, sizeof(protseq)))
193 strcpy(protseq, "ncacn_np");
196 getservername(&serverNamep, sizeof(serverName));
198 status = RpcStringBindingCompose("", /* obj uuid */
202 "", /* protocol options */
204 if (status != RPC_S_OK)
207 status = RpcBindingFromStringBinding(stringBinding, &hAfsHandle);
208 if (status != RPC_S_OK)
212 * On Windows 95/98, we must resolve the binding before calling
213 * SetAuthInfo. On Windows NT, we don't have to resolve yet,
214 * but it does no harm.
216 status = RpcEpResolveBinding(hAfsHandle, afsrpc_v1_0_c_ifspec);
217 if (status != RPC_S_OK)
221 authnLevel = RPC_C_AUTHN_LEVEL_NONE;
222 authnSvc = RPC_C_AUTHN_WINNT;
224 authnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
225 authnSvc = RPC_C_AUTHN_WINNT;
228 status = RpcBindingSetAuthInfo(hAfsHandle, NULL, authnLevel, authnSvc,
229 NULL, RPC_C_AUTHZ_NONE);
230 if (status != RPC_S_OK)
234 status = AFSRPC_GetToken(uuid, sessionKey);
237 status = RpcExceptionCode();
243 RpcStringFree(&stringBinding);
245 if (hAfsHandle != NULL)
246 RpcBindingFree(&hAfsHandle);
252 struct ktc_principal *server,
253 struct ktc_token *token,
254 struct ktc_principal *client,
257 struct ViceIoctl iob;
260 struct ClearToken ct;
266 if (token->ticketLen < MINKTCTICKETLEN
267 || token->ticketLen > MAXKTCTICKETLEN)
270 if (strcmp(server->name, "afs")) {
271 return SetLocalToken(server, token, client, flags);
277 memcpy(tp, &token->ticketLen, sizeof(token->ticketLen));
278 tp += sizeof(&token->ticketLen);
281 memcpy(tp, token->ticket, token->ticketLen);
282 tp += token->ticketLen;
285 ct.AuthHandle = token->kvno;
287 * Instead of sending the session key in the clear, we zero it,
288 * and send it later, via RPC, encrypted.
290 #ifndef AFS_WIN95_ENV
292 memcpy(ct.HandShakeKey, &token->sessionKey, sizeof(token->sessionKey));
294 memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
296 memcpy(ct.HandShakeKey, &token->sessionKey, sizeof(token->sessionKey));
298 ct.BeginTimestamp = token->startTime;
299 ct.EndTimestamp = token->endTime;
300 if (ct.BeginTimestamp == 0) 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 temp = sizeof(struct ClearToken);
309 memcpy(tp, &temp, sizeof(temp));
312 /* clear token itself */
313 memcpy(tp, &ct, sizeof(ct));
316 /* flags; on NT there is no setpag flag, but there is an
317 * integrated logon flag */
318 temp = ((flags & AFS_SETTOK_LOGON) ? PIOCTL_LOGON : 0);
319 memcpy(tp, &temp, sizeof(temp));
323 temp = strlen(server->cell);
324 if (temp >= MAXKTCREALMLEN)
326 strcpy(tp, server->cell);
330 temp = strlen(client->name);
331 if (temp >= MAXKTCNAMELEN)
333 strcpy(tp, client->name);
336 /* we need the SMB user name to associate the tokens with in the
337 integrated logon case. */
338 if (flags & AFS_SETTOK_LOGON) {
339 if (client->smbname == NULL)
342 temp = strlen(client->smbname);
343 if (temp == 0 || temp >= MAXKTCNAMELEN)
345 strcpy(tp, client->smbname);
350 status = UuidCreate((UUID *)&uuid);
351 memcpy(tp, &uuid, sizeof(uuid));
354 #ifndef AFS_WIN95_ENV
355 /* RPC to send session key */
356 status = send_key(uuid, token->sessionKey.data);
357 if (status != RPC_S_OK) {
359 strcpy(rpcErr, "RPC failure in AFS gateway");
361 DceErrorInqText(status, rpcErr);
362 if (status == RPC_S_SERVER_UNAVAILABLE
363 || status == EPT_S_NOT_REGISTERED)
368 #endif /* AFS_WIN95_ENV */
370 /* set up for pioctl */
372 iob.in_size = tp - tbuffer;
374 iob.out_size = sizeof(tbuffer);
376 code = pioctl(0, VIOCSETTOK, &iob, 0);
381 else if (errno == ENODEV)
383 else if (errno == EINVAL)
386 return KTC_PIOCTLFAIL;
389 return KTC_PIOCTLFAIL;
396 struct ktc_principal *server,
397 struct ktc_token *token,
399 struct ktc_principal *client)
401 struct ViceIoctl iob;
406 struct ClearToken ct;
416 /* check to see if the user is requesting tokens for a principal
417 * other than afs. If so, check the local token cache.
419 if (strcmp(server->name, "afs")) {
420 return GetLocalToken(server, token, tokenLen, client);
424 strcpy(tp, server->cell);
425 tp += strlen(server->cell) + 1;
428 status = UuidCreate((UUID *)&uuid);
429 memcpy(tp, &uuid, sizeof(uuid));
433 iob.in_size = tp - tbuffer;
435 iob.out_size = sizeof(tbuffer);
437 code = pioctl(0, VIOCNEWGETTOK, &iob, 0);
442 else if (errno == ENODEV)
444 else if (errno == EINVAL)
446 else if (errno == EDOM)
449 return KTC_PIOCTLFAIL;
452 return KTC_PIOCTLFAIL;
455 #ifndef AFS_WIN95_ENV /* get rid of RPC for win95 build */
456 /* RPC to receive session key */
457 status = receive_key(uuid, token->sessionKey.data);
458 if (status != RPC_S_OK) {
460 strcpy(rpcErr, "RPC failure in AFS gateway");
462 DceErrorInqText(status, rpcErr);
463 if (status == RPC_S_SERVER_UNAVAILABLE
464 || status == EPT_S_NOT_REGISTERED)
469 #endif /* AFS_WIN95_ENV */
474 memcpy(&ticketLen, cp, sizeof(ticketLen));
475 cp += sizeof(ticketLen);
477 /* remember where ticket is and skip over it */
481 /* size of clear token */
482 memcpy(&temp, cp, sizeof(temp));
484 if (temp != sizeof(ct))
488 memcpy(&ct, cp, temp);
491 /* skip over primary flag */
494 /* remember cell name and skip over it */
496 cellNameSize = strlen(cp);
497 cp += cellNameSize + 1;
499 /* user name is here */
501 /* check that ticket will fit */
502 maxLen = tokenLen - sizeof(struct ktc_token) + MAXKTCTICKETLEN;
503 if (maxLen < ticketLen)
506 /* set return values */
507 memcpy(token->ticket, ticketP, ticketLen);
508 token->startTime = ct.BeginTimestamp;
509 token->endTime = ct.EndTimestamp;
510 if (ct.AuthHandle == -1) ct.AuthHandle = 999;
511 token->kvno = ct.AuthHandle;
512 #ifndef AFS_WIN95_ENV
514 * Session key has already been set via RPC
517 memcpy(&token->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
518 #endif /* AFS_WIN95_ENV */
519 token->ticketLen = ticketLen;
521 strcpy(client->name, cp);
522 client->instance[0] = '\0';
523 strcpy(client->cell, cellName);
532 struct ktc_principal *server)
534 struct ViceIoctl iob;
537 int newIter, ticketLen, temp;
543 memcpy(tp, &cellNum, sizeof(cellNum));
544 tp += sizeof(cellNum);
548 iob.in_size = tp - tbuffer;
550 iob.out_size = sizeof(tbuffer);
552 code = pioctl(0, VIOCGETTOK, &iob, 0);
557 else if (errno == ENODEV)
559 else if (errno == EINVAL)
561 else if (errno == EDOM)
564 return KTC_PIOCTLFAIL;
567 return KTC_PIOCTLFAIL;
573 memcpy(&newIter, cp, sizeof(newIter));
574 cp += sizeof(newIter);
577 memcpy(&ticketLen, cp, sizeof(ticketLen));
578 cp += sizeof(ticketLen);
580 /* skip over ticket */
583 /* clear token size */
584 memcpy(&temp, cp, sizeof(temp));
586 if (temp != sizeof(struct ClearToken))
589 /* skip over clear token */
590 cp += sizeof(struct ClearToken);
592 /* skip over primary flag */
595 /* cell name is here */
597 /* set return values */
598 strcpy(server->cell, cp);
599 server->instance[0] = '\0';
600 strcpy(server->name, "afs");
607 struct ktc_principal *server)
609 struct ViceIoctl iob;
614 if (strcmp(server->name, "afs")) {
615 return ForgetOneLocalToken(server);
621 strcpy(tp, server->cell);
622 tp += strlen(tp) + 1;
626 iob.in_size = tp - tbuffer;
628 iob.out_size = sizeof(tbuffer);
630 code = pioctl(0, VIOCDELTOK, &iob, 0);
635 else if (errno == EDOM)
637 else if (errno == ENODEV)
640 return KTC_PIOCTLFAIL;
643 return KTC_PIOCTLFAIL;
648 int ktc_ForgetAllTokens()
650 struct ViceIoctl iob;
654 (void) ForgetLocalTokens();
660 iob.out_size = sizeof(tbuffer);
662 code = pioctl(0, VIOCDELALLTOK, &iob, 0);
668 return KTC_PIOCTLFAIL;
671 return KTC_PIOCTLFAIL;
682 #define MAXLOCALTOKENS 4
686 struct ktc_principal server;
687 struct ktc_principal client;
688 struct ktc_token token;
689 } local_tokens[MAXLOCALTOKENS] = {0};
691 static int SetLocalToken(struct ktc_principal *aserver,
692 struct ktc_token *atoken,
693 struct ktc_principal *aclient,
700 for (i = 0; i < MAXLOCALTOKENS; i++)
701 if (local_tokens[i].valid) {
702 if ((strcmp(local_tokens[i].server.name, aserver->name) == 0) &&
703 (strcmp(local_tokens[i].server.instance,
704 aserver->instance) == 0) &&
705 (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
706 found = i; /* replace existing entry */
709 } else if (found == -1)
710 found = i; /* remember empty slot but keep looking for a match */
715 memcpy(&local_tokens[found].token, atoken, sizeof(struct ktc_token));
716 memcpy(&local_tokens[found].server, aserver, sizeof(struct ktc_principal));
717 memcpy(&local_tokens[found].client, aclient, sizeof(struct ktc_principal));
718 local_tokens[found].valid = 1;
724 static int GetLocalToken(struct ktc_principal *aserver,
725 struct ktc_token *atoken,
727 struct ktc_principal *aclient)
732 for (i = 0; i < MAXLOCALTOKENS; i++)
733 if (local_tokens[i].valid &&
734 (strcmp(local_tokens[i].server.name, aserver->name) == 0) &&
735 (strcmp(local_tokens[i].server.instance,aserver->instance) == 0) &&
736 (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
737 memcpy(atoken, &local_tokens[i].token,
738 min(atokenLen, sizeof(struct ktc_token)));
739 memcpy(aclient, &local_tokens[i].client,
740 sizeof(struct ktc_principal));
749 static int ForgetLocalTokens()
754 for (i = 0; i < MAXLOCALTOKENS; i++) {
755 local_tokens[i].valid = 0;
756 memset(&local_tokens[i].token.sessionKey, 0,
757 sizeof(struct ktc_encryptionKey));
764 static int ForgetOneLocalToken(struct ktc_principal *aserver)
769 for (i = 0; i < MAXLOCALTOKENS; i++) {
770 if (local_tokens[i].valid &&
771 (strcmp(local_tokens[i].server.name, aserver->name) == 0) &&
772 (strcmp(local_tokens[i].server.instance,aserver->instance) == 0) &&
773 (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
774 local_tokens[i].valid = 0;
775 memset(&local_tokens[i].token.sessionKey, 0,
776 sizeof(struct ktc_encryptionKey));