Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / auth / token.c
CommitLineData
805e021f
CE
1/*
2 * Copyright (c) 2010 Your Filesystem Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include <afsconfig.h>
26#include <afs/param.h>
27
28#include <roken.h>
29
30#include "auth.h"
31#include <rx/rxkad.h>
32
33#include "ktc.h"
34#include "token.h"
35
36
37/* Routines for processing tokens in the new XDR format
38 *
39 * The code here is inspired by work done by Jeffrey Hutzelman et al
40 * at the AFSSIG.se hackathon and further refined by Matt
41 * Benjamin and Marcus Watts as part of rxk5. However, unless
42 * otherwise noted, the implementation is new
43 */
44
45/* Take a peak at the enumerator in a given encoded token, in order to
46 * return its type
47 */
48static int
49tokenType(struct token_opaque *opaque) {
50 XDR xdrs;
51 int type;
52
53 xdrmem_create(&xdrs, opaque->token_opaque_val, opaque->token_opaque_len,
54 XDR_DECODE);
55
56 if (!xdr_enum(&xdrs, &type))
57 type = -1;
58
59 xdr_destroy(&xdrs);
60
61 return type;
62}
63
64static int
65decodeToken(struct token_opaque *opaque, struct ktc_tokenUnion *token) {
66 XDR xdrs;
67 int code;
68
69 memset(token, 0, sizeof(struct ktc_tokenUnion));
70 xdrmem_create(&xdrs, opaque->token_opaque_val, opaque->token_opaque_len,
71 XDR_DECODE);
72 code = xdr_ktc_tokenUnion(&xdrs, token);
73 xdr_destroy(&xdrs);
74
75 return code;
76}
77
78static int
79rxkadTokenEqual(struct ktc_tokenUnion *tokenA, struct ktc_tokenUnion *tokenB) {
80 return (tokenA->ktc_tokenUnion_u.at_kad.rk_kvno ==
81 tokenB->ktc_tokenUnion_u.at_kad.rk_kvno
82 && tokenA->ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_len ==
83 tokenB->ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_len
84 && !memcmp(tokenA->ktc_tokenUnion_u.at_kad.rk_key,
85 tokenB->ktc_tokenUnion_u.at_kad.rk_key, 8)
86 && !memcmp(tokenA->ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_val,
87 tokenB->ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_val,
88 tokenA->ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_len));
89}
90
91static int
92tokenEqual(struct ktc_tokenUnion *tokenA,
93 struct ktc_tokenUnion *tokenB) {
94 switch (tokenA->at_type) {
95 case AFSTOKEN_UNION_KAD:
96 return rxkadTokenEqual(tokenA, tokenB);
97 }
98 return 0;
99}
100
101static int
102rawTokenEqual(struct token_opaque *tokenA, struct token_opaque *tokenB) {
103 return (tokenA->token_opaque_len == tokenB->token_opaque_len &&
104 !memcmp(tokenA->token_opaque_val, tokenB->token_opaque_val,
105 tokenA->token_opaque_len));
106}
107
108/* Given a token type, return the entry number of the first token of that
109 * type */
110static int
111findTokenEntry(struct ktc_setTokenData *token,
112 int targetType)
113{
114 int i;
115
116 for (i = 0; i < token->tokens.tokens_len; i++) {
117 if (tokenType(&token->tokens.tokens_val[i]) == targetType)
118 return i;
119 }
120 return -1;
121}
122
123/* XDR encode a token union structure, and return data and length information
124 * suitable for stuffing into a token_opaque structure
125 */
126static int
127encodeTokenUnion(struct ktc_tokenUnion *token,
128 char **dataPtr, size_t *lenPtr) {
129 char *data = NULL;
130 size_t len;
131 XDR xdrs;
132 int code = 0;
133
134 *dataPtr = NULL;
135 *lenPtr = 0;
136
137 xdrlen_create(&xdrs);
138 if (!xdr_ktc_tokenUnion(&xdrs, token)) {
139 code = EINVAL;
140 goto out;
141 }
142
143 len = xdr_getpos(&xdrs);
144 data = malloc(len);
145 if (data == NULL) {
146 code = ENOMEM;
147 goto out;
148 }
149 xdr_destroy(&xdrs);
150
151 xdrmem_create(&xdrs, data, len, XDR_ENCODE);
152 if (!xdr_ktc_tokenUnion(&xdrs, token)) {
153 code = EINVAL;
154 goto out;
155 }
156
157 *dataPtr = data;
158 *lenPtr = len;
159
160out:
161 xdr_destroy(&xdrs);
162 if (code) {
163 if (data)
164 free(data);
165 }
166
167 return code;
168}
169
170static void
171addOpaque(struct ktc_setTokenData *jar, char *data, size_t len)
172{
173 int entry;
174
175 entry = jar->tokens.tokens_len;
176 jar->tokens.tokens_val = realloc(jar->tokens.tokens_val,
177 (entry + 1) * sizeof(token_opaque));
178 jar->tokens.tokens_len++;
179 jar->tokens.tokens_val[entry].token_opaque_val = data;
180 jar->tokens.tokens_val[entry].token_opaque_len = len;
181}
182
183/*!
184 * Extract a specific token element from a unified token structure
185 *
186 * This routine extracts an afsTokenUnion structure from the tokenData
187 * structure used by the SetTokenEx and GetTokenEx pioctls
188 *
189 * @param[in] token
190 * A ktc_setTokenData structure containing the token to extract from
191 * @param[in] targetType
192 * The securityClass index of the token to be extracted
193 * @param[out] output
194 * The decoded token. On entry, this must point to a block of memory
195 * of sufficient size to contain an afsTokenUnion structure. Upon
196 * completion, this block must be passed to xdr_free(), using the
197 * xdr_afsTokenUnion xdrproc_t.
198 */
199int
200token_findByType(struct ktc_setTokenData *token,
201 int targetType,
202 struct ktc_tokenUnion *output)
203{
204 int entry;
205
206 memset(output, 0, sizeof *output);
207 entry = findTokenEntry(token, targetType);
208 if (entry == -1)
209 return EINVAL;
210
211 if (!decodeToken(&token->tokens.tokens_val[entry], output))
212 return EINVAL;
213
214 if (output->at_type != targetType) {
215 xdr_free((xdrproc_t)xdr_ktc_tokenUnion, output);
216 return EINVAL;
217 }
218
219 return 0;
220}
221
222static void
223SetRxkadViceId(struct token_rxkad *rxkadToken, afs_int32 viceId)
224{
225 rxkadToken->rk_viceid = viceId;
226 if (viceId) {
227 if (((rxkadToken->rk_endtime - rxkadToken->rk_begintime) & 1) == 0) {
228 rxkadToken->rk_begintime++; /* force lifetime to be odd */
229 }
230 } else {
231 if (((rxkadToken->rk_endtime - rxkadToken->rk_begintime) & 1) == 1) {
232 rxkadToken->rk_begintime++; /* force lifetime to be even */
233 }
234 }
235}
236
237/**
238 * Import an rxkad token with a ViceId into a unified token.
239 *
240 * @param[out] atoken
241 * The resultant unified token. Free with token_freeToken.
242 * @param[in] oldToken
243 * The rxkad token to import.
244 * @param[in] viceId
245 * The optional rxkad ViceId to use. Specify 0 to explicitly not
246 * specify a ViceId.
247 *
248 * @return operation status
249 * @retval 0 success
250 */
251int
252token_importRxkadViceId(struct ktc_tokenUnion **atoken,
253 struct ktc_token *oldToken,
254 afs_int32 viceId)
255{
256 struct ktc_tokenUnion *token;
257 struct token_rxkad *rxkadToken;
258
259 token = malloc(sizeof(struct ktc_tokenUnion));
260 if (!token)
261 return ENOMEM;
262
263 token->at_type = AFSTOKEN_UNION_KAD;
264 rxkadToken = &token->ktc_tokenUnion_u.at_kad;
265
266 rxkadToken->rk_kvno = oldToken->kvno;
267 rxkadToken->rk_begintime = oldToken->startTime;
268 rxkadToken->rk_endtime = oldToken->endTime;
269 memcpy(&rxkadToken->rk_key, &oldToken->sessionKey,
270 sizeof(oldToken->sessionKey));
271 rxkadToken->rk_ticket.rk_ticket_len = oldToken->ticketLen;
272
273 rxkadToken->rk_ticket.rk_ticket_val = xdr_alloc(oldToken->ticketLen);
274 if (!rxkadToken->rk_ticket.rk_ticket_val) {
275 free(token);
276 return ENOMEM;
277 }
278 memcpy(rxkadToken->rk_ticket.rk_ticket_val, oldToken->ticket, oldToken->ticketLen);
279
280 SetRxkadViceId(rxkadToken, viceId);
281
282 *atoken = token;
283
284 return 0;
285}
286
287/**
288 * Set the optional ViceId for an rxkad token.
289 *
290 * @param[in] token
291 * The token union to change.
292 * @param[in] viceId
293 * The ViceId to set. Specify 0 to explicitly set no ViceId.
294 *
295 * @return operation status
296 * @retval EINVAL The given token union is not an rxkad token
297 * @retval 0 success
298 */
299int
300token_setRxkadViceId(struct ktc_tokenUnion *token,
301 afs_int32 viceId)
302{
303 struct token_rxkad *rxkadToken;
304
305 if (token->at_type != AFSTOKEN_UNION_KAD) {
306 return EINVAL;
307 }
308
309 rxkadToken = &token->ktc_tokenUnion_u.at_kad;
310 SetRxkadViceId(rxkadToken, viceId);
311
312 return 0;
313}
314
315/*!
316 * Given an unified token, populate an rxkad token from it
317 *
318 * This routine populates an rxkad token using information contained
319 * in the tokenData structure used by the SetTokenEx and GetTokenEX
320 * pioctls.
321 *
322 * @param[in] token
323 * The new format token to extract information from.
324 * @param[out] rxkadToken
325 * The old-style rxkad token. This must be a pointer to an existing
326 * data block of sufficient size
327 * @param[out] flags
328 * The set of token flags
329 * @param[out] aclient
330 * The client owning the token. This must be a pointer to an existing
331 * data block of sufficient size, or NULL.
332 */
333
334int
335token_extractRxkad(struct ktc_setTokenData *token,
336 struct ktc_token *rxkadToken,
337 int *flags,
338 struct ktc_principal *aclient)
339{
340 struct ktc_tokenUnion uToken;
341 int code;
342
343 memset(&uToken, 0, sizeof(uToken));
344 if (aclient)
345 memset(aclient, 0, sizeof(*aclient));
346
347 code = token_findByType(token, AFSTOKEN_UNION_KAD, &uToken);
348 if (code)
349 return code;
350
351 rxkadToken->kvno = uToken.ktc_tokenUnion_u.at_kad.rk_kvno;
352 memcpy(rxkadToken->sessionKey.data,
353 uToken.ktc_tokenUnion_u.at_kad.rk_key, 8);
354 rxkadToken->startTime = uToken.ktc_tokenUnion_u.at_kad.rk_begintime;
355 rxkadToken->endTime = uToken.ktc_tokenUnion_u.at_kad.rk_endtime;
356 rxkadToken->ticketLen = uToken.ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_len;
357
358 if (rxkadToken->ticketLen > MAXKTCTICKETLEN) {
359 code = E2BIG;
360 goto out;
361 }
362
363 memcpy(rxkadToken->ticket,
364 uToken.ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_val,
365 rxkadToken->ticketLen);
366
367 if (flags) {
368 *flags = 0;
369 if ((token->flags & AFSTOKEN_EX_SETPAG)) {
370 *flags |= AFS_SETTOK_SETPAG;
371 }
372 }
373
374 if (aclient) {
375 strncpy(aclient->cell, token->cell, MAXKTCREALMLEN-1);
376 aclient->cell[MAXKTCREALMLEN-1] = '\0';
377
378 if ((rxkadToken->kvno == 999) || /* old style bcrypt ticket */
379 (rxkadToken->startTime && /* new w/ prserver lookup */
380 (((rxkadToken->endTime - rxkadToken->startTime) & 1) == 1))) {
381 sprintf(aclient->name, "AFS ID %d",
382 uToken.ktc_tokenUnion_u.at_kad.rk_viceid);
383 } else {
384 sprintf(aclient->name, "Unix UID %d",
385 uToken.ktc_tokenUnion_u.at_kad.rk_viceid);
386 }
387 }
388
389out:
390 xdr_free((xdrproc_t) xdr_ktc_tokenUnion, &uToken);
391 return code;
392}
393
394struct ktc_setTokenData *
395token_buildTokenJar(char * cellname) {
396 struct ktc_setTokenData *jar;
397
398 jar = calloc(1, sizeof(struct ktc_setTokenData));
399 if (jar == NULL)
400 return NULL;
401
402 jar->cell = strdup(cellname);
403
404 return jar;
405}
406
407/*!
408 * Add a token to an existing set of tokens. This will always add the token,
409 * regardless of whether an entry for the security class already exists
410 */
411int
412token_addToken(struct ktc_setTokenData *jar, struct ktc_tokenUnion *token) {
413 int code;
414 char *data;
415 size_t len;
416
417 code = encodeTokenUnion(token, &data, &len);
418 if (code)
419 goto out;
420
421 addOpaque(jar, data, len);
422
423out:
424 return code;
425}
426
427/*!
428 * Replace at token in an existing set of tokens. This replaces the first
429 * token stored of a matching type. If no matching tokens are found, then
430 * the new token is added at the end of the list
431 */
432int
433token_replaceToken(struct ktc_setTokenData *jar,
434 struct ktc_tokenUnion *token) {
435 int entry;
436 char *data;
437 size_t len;
438 int code;
439
440 entry = findTokenEntry(jar, token->at_type);
441 if (entry == -1)
442 return token_addToken(jar, token);
443
444 code = encodeTokenUnion(token, &data, &len);
445 if (code)
446 goto out;
447
448 free(jar->tokens.tokens_val[entry].token_opaque_val);
449 jar->tokens.tokens_val[entry].token_opaque_val = data;
450 jar->tokens.tokens_val[entry].token_opaque_len = len;
451
452out:
453 return code;
454}
455
456/*!
457 * Work out if a pair of token sets are equivalent. Equivalence
458 * is defined as both sets containing the same number of tokens,
459 * and every token in the first set having an equivalent token
460 * in the second set. Cell name and flags value are not compared.
461 *
462 * @param[in] tokensA
463 * First set of tokens
464 * @param[in] tokensB
465 * Second set of tokens
466 *
467 * @returns
468 * True if token sets are equivalent, false otherwise
469 */
470int
471token_SetsEquivalent(struct ktc_setTokenData *tokenSetA,
472 struct ktc_setTokenData *tokenSetB) {
473 int i, j;
474 int decodedOK, found;
475 struct ktc_tokenUnion tokenA, tokenB;
476
477 if (tokenSetA->tokens.tokens_len != tokenSetB->tokens.tokens_len)
478 return 0;
479
480 for (i=0; i<tokenSetA->tokens.tokens_len; i++) {
481 found = 0;
482
483 decodedOK = decodeToken(&tokenSetA->tokens.tokens_val[i], &tokenA);
484
485 for (j=0; j<tokenSetB->tokens.tokens_len && !found; j++) {
486 if (rawTokenEqual(&tokenSetA->tokens.tokens_val[i],
487 &tokenSetB->tokens.tokens_val[j])) {
488 found = 1;
489 break;
490 }
491
492 if (decodedOK &&
493 tokenType(&tokenSetB->tokens.tokens_val[j]) == tokenA.at_type
494 && decodeToken(&tokenSetB->tokens.tokens_val[j], &tokenB)) {
495
496 if (tokenEqual(&tokenA, &tokenB)) {
497 found = 1;
498 break;
499 }
500 token_freeTokenContents(&tokenB);
501 }
502 }
503 if (decodedOK)
504 token_freeTokenContents(&tokenA);
505
506 if (!found)
507 return 0;
508 }
509 /* If we made it this far without exiting, we must have found equivalents
510 * for all of our tokens */
511 return 1;
512}
513
514void
515token_setPag(struct ktc_setTokenData *jar, int setpag) {
516 if (setpag)
517 jar->flags |= AFSTOKEN_EX_SETPAG;
518 else
519 jar->flags &= ~AFSTOKEN_EX_SETPAG;
520}
521
522void
523token_freeTokenContents(struct ktc_tokenUnion *atoken)
524{
525 xdr_free((xdrproc_t)xdr_ktc_tokenUnion, atoken);
526}
527
528void
529token_freeToken(struct ktc_tokenUnion **atoken)
530{
531 if (*atoken) {
532 token_freeTokenContents(*atoken);
533 free(*atoken);
534 *atoken = NULL;
535 }
536}
537
538void
539token_FreeSet(struct ktc_setTokenData **jar) {
540 if (*jar) {
541 xdr_free((xdrproc_t)xdr_ktc_setTokenData, *jar);
542 memset(*jar, 0, sizeof(struct ktc_setTokenData));
543 *jar = NULL;
544 }
545}