2 * Copyright (c) 2010 Your Filesystem Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
25 #include <afsconfig.h>
26 #include <afs/param.h>
37 /* Routines for processing tokens in the new XDR format
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
45 /* Take a peak at the enumerator in a given encoded token, in order to
49 tokenType(struct token_opaque *opaque) {
53 xdrmem_create(&xdrs, opaque->token_opaque_val, opaque->token_opaque_len,
56 if (!xdr_enum(&xdrs, &type))
65 decodeToken(struct token_opaque *opaque, struct ktc_tokenUnion *token) {
69 memset(token, 0, sizeof(struct ktc_tokenUnion));
70 xdrmem_create(&xdrs, opaque->token_opaque_val, opaque->token_opaque_len,
72 code = xdr_ktc_tokenUnion(&xdrs, token);
79 rxkadTokenEqual(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));
92 tokenEqual(struct ktc_tokenUnion *tokenA,
93 struct ktc_tokenUnion *tokenB) {
94 switch (tokenA->at_type) {
95 case AFSTOKEN_UNION_KAD:
96 return rxkadTokenEqual(tokenA, tokenB);
102 rawTokenEqual(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));
108 /* Given a token type, return the entry number of the first token of that
111 findTokenEntry(struct ktc_setTokenData *token,
116 for (i = 0; i < token->tokens.tokens_len; i++) {
117 if (tokenType(&token->tokens.tokens_val[i]) == targetType)
123 /* XDR encode a token union structure, and return data and length information
124 * suitable for stuffing into a token_opaque structure
127 encodeTokenUnion(struct ktc_tokenUnion *token,
128 char **dataPtr, size_t *lenPtr) {
137 xdrlen_create(&xdrs);
138 if (!xdr_ktc_tokenUnion(&xdrs, token)) {
143 len = xdr_getpos(&xdrs);
151 xdrmem_create(&xdrs, data, len, XDR_ENCODE);
152 if (!xdr_ktc_tokenUnion(&xdrs, token)) {
171 addOpaque(struct ktc_setTokenData *jar, char *data, size_t len)
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;
184 * Extract a specific token element from a unified token structure
186 * This routine extracts an afsTokenUnion structure from the tokenData
187 * structure used by the SetTokenEx and GetTokenEx pioctls
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
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.
200 token_findByType(struct ktc_setTokenData *token,
202 struct ktc_tokenUnion *output)
206 memset(output, 0, sizeof *output);
207 entry = findTokenEntry(token, targetType);
211 if (!decodeToken(&token->tokens.tokens_val[entry], output))
214 if (output->at_type != targetType) {
215 xdr_free((xdrproc_t)xdr_ktc_tokenUnion, output);
223 SetRxkadViceId(struct token_rxkad *rxkadToken, afs_int32 viceId)
225 rxkadToken->rk_viceid = viceId;
227 if (((rxkadToken->rk_endtime - rxkadToken->rk_begintime) & 1) == 0) {
228 rxkadToken->rk_begintime++; /* force lifetime to be odd */
231 if (((rxkadToken->rk_endtime - rxkadToken->rk_begintime) & 1) == 1) {
232 rxkadToken->rk_begintime++; /* force lifetime to be even */
238 * Import an rxkad token with a ViceId into a unified token.
241 * The resultant unified token. Free with token_freeToken.
242 * @param[in] oldToken
243 * The rxkad token to import.
245 * The optional rxkad ViceId to use. Specify 0 to explicitly not
248 * @return operation status
252 token_importRxkadViceId(struct ktc_tokenUnion **atoken,
253 struct ktc_token *oldToken,
256 struct ktc_tokenUnion *token;
257 struct token_rxkad *rxkadToken;
259 token = malloc(sizeof(struct ktc_tokenUnion));
263 token->at_type = AFSTOKEN_UNION_KAD;
264 rxkadToken = &token->ktc_tokenUnion_u.at_kad;
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;
273 rxkadToken->rk_ticket.rk_ticket_val = xdr_alloc(oldToken->ticketLen);
274 if (!rxkadToken->rk_ticket.rk_ticket_val) {
278 memcpy(rxkadToken->rk_ticket.rk_ticket_val, oldToken->ticket, oldToken->ticketLen);
280 SetRxkadViceId(rxkadToken, viceId);
288 * Set the optional ViceId for an rxkad token.
291 * The token union to change.
293 * The ViceId to set. Specify 0 to explicitly set no ViceId.
295 * @return operation status
296 * @retval EINVAL The given token union is not an rxkad token
300 token_setRxkadViceId(struct ktc_tokenUnion *token,
303 struct token_rxkad *rxkadToken;
305 if (token->at_type != AFSTOKEN_UNION_KAD) {
309 rxkadToken = &token->ktc_tokenUnion_u.at_kad;
310 SetRxkadViceId(rxkadToken, viceId);
316 * Given an unified token, populate an rxkad token from it
318 * This routine populates an rxkad token using information contained
319 * in the tokenData structure used by the SetTokenEx and GetTokenEX
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
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.
335 token_extractRxkad(struct ktc_setTokenData *token,
336 struct ktc_token *rxkadToken,
338 struct ktc_principal *aclient)
340 struct ktc_tokenUnion uToken;
343 memset(&uToken, 0, sizeof(uToken));
345 memset(aclient, 0, sizeof(*aclient));
347 code = token_findByType(token, AFSTOKEN_UNION_KAD, &uToken);
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;
358 if (rxkadToken->ticketLen > MAXKTCTICKETLEN) {
363 memcpy(rxkadToken->ticket,
364 uToken.ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_val,
365 rxkadToken->ticketLen);
369 if ((token->flags & AFSTOKEN_EX_SETPAG)) {
370 *flags |= AFS_SETTOK_SETPAG;
375 strncpy(aclient->cell, token->cell, MAXKTCREALMLEN-1);
376 aclient->cell[MAXKTCREALMLEN-1] = '\0';
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);
384 sprintf(aclient->name, "Unix UID %d",
385 uToken.ktc_tokenUnion_u.at_kad.rk_viceid);
390 xdr_free((xdrproc_t) xdr_ktc_tokenUnion, &uToken);
394 struct ktc_setTokenData *
395 token_buildTokenJar(char * cellname) {
396 struct ktc_setTokenData *jar;
398 jar = calloc(1, sizeof(struct ktc_setTokenData));
402 jar->cell = strdup(cellname);
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
412 token_addToken(struct ktc_setTokenData *jar, struct ktc_tokenUnion *token) {
417 code = encodeTokenUnion(token, &data, &len);
421 addOpaque(jar, data, len);
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
433 token_replaceToken(struct ktc_setTokenData *jar,
434 struct ktc_tokenUnion *token) {
440 entry = findTokenEntry(jar, token->at_type);
442 return token_addToken(jar, token);
444 code = encodeTokenUnion(token, &data, &len);
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;
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.
463 * First set of tokens
465 * Second set of tokens
468 * True if token sets are equivalent, false otherwise
471 token_SetsEquivalent(struct ktc_setTokenData *tokenSetA,
472 struct ktc_setTokenData *tokenSetB) {
474 int decodedOK, found;
475 struct ktc_tokenUnion tokenA, tokenB;
477 if (tokenSetA->tokens.tokens_len != tokenSetB->tokens.tokens_len)
480 for (i=0; i<tokenSetA->tokens.tokens_len; i++) {
483 decodedOK = decodeToken(&tokenSetA->tokens.tokens_val[i], &tokenA);
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])) {
493 tokenType(&tokenSetB->tokens.tokens_val[j]) == tokenA.at_type
494 && decodeToken(&tokenSetB->tokens.tokens_val[j], &tokenB)) {
496 if (tokenEqual(&tokenA, &tokenB)) {
500 token_freeTokenContents(&tokenB);
504 token_freeTokenContents(&tokenA);
509 /* If we made it this far without exiting, we must have found equivalents
510 * for all of our tokens */
515 token_setPag(struct ktc_setTokenData *jar, int setpag) {
517 jar->flags |= AFSTOKEN_EX_SETPAG;
519 jar->flags &= ~AFSTOKEN_EX_SETPAG;
523 token_freeTokenContents(struct ktc_tokenUnion *atoken)
525 xdr_free((xdrproc_t)xdr_ktc_tokenUnion, atoken);
529 token_freeToken(struct ktc_tokenUnion **atoken)
532 token_freeTokenContents(*atoken);
539 token_FreeSet(struct ktc_setTokenData **jar) {
541 xdr_free((xdrproc_t)xdr_ktc_setTokenData, *jar);
542 memset(*jar, 0, sizeof(struct ktc_setTokenData));