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 freeToken(struct ktc_tokenUnion *token) {
80 xdr_free((xdrproc_t)xdr_ktc_tokenUnion, token);
84 rxkadTokenEqual(struct ktc_tokenUnion *tokenA, struct ktc_tokenUnion *tokenB) {
85 return (tokenA->ktc_tokenUnion_u.at_kad.rk_kvno ==
86 tokenB->ktc_tokenUnion_u.at_kad.rk_kvno
87 && tokenA->ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_len ==
88 tokenB->ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_len
89 && !memcmp(tokenA->ktc_tokenUnion_u.at_kad.rk_key,
90 tokenB->ktc_tokenUnion_u.at_kad.rk_key, 8)
91 && !memcmp(tokenA->ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_val,
92 tokenB->ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_val,
93 tokenA->ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_len));
97 tokenEqual(struct ktc_tokenUnion *tokenA,
98 struct ktc_tokenUnion *tokenB) {
99 switch (tokenA->at_type) {
100 case AFSTOKEN_UNION_KAD:
101 return rxkadTokenEqual(tokenA, tokenB);
107 rawTokenEqual(struct token_opaque *tokenA, struct token_opaque *tokenB) {
108 return (tokenA->token_opaque_len == tokenB->token_opaque_len &&
109 !memcmp(tokenA->token_opaque_val, tokenB->token_opaque_val,
110 tokenA->token_opaque_len));
113 /* Given a token type, return the entry number of the first token of that
116 findTokenEntry(struct ktc_setTokenData *token,
121 for (i = 0; i < token->tokens.tokens_len; i++) {
122 if (tokenType(&token->tokens.tokens_val[i]) == targetType)
128 /* XDR encode a token union structure, and return data and length information
129 * suitable for stuffing into a token_opaque structure
132 encodeTokenUnion(struct ktc_tokenUnion *token,
133 char **dataPtr, size_t *lenPtr) {
142 xdrlen_create(&xdrs);
143 if (!xdr_ktc_tokenUnion(&xdrs, token)) {
148 len = xdr_getpos(&xdrs);
156 xdrmem_create(&xdrs, data, len, XDR_ENCODE);
157 if (!xdr_ktc_tokenUnion(&xdrs, token)) {
176 addOpaque(struct ktc_setTokenData *jar, char *data, size_t len)
180 entry = jar->tokens.tokens_len;
181 jar->tokens.tokens_val = realloc(jar->tokens.tokens_val,
182 entry + 1 * sizeof(token_opaque));
183 jar->tokens.tokens_len++;
184 jar->tokens.tokens_val[entry].token_opaque_val = data;
185 jar->tokens.tokens_val[entry].token_opaque_len = len;
189 * Extract a specific token element from a unified token structure
191 * This routine extracts an afsTokenUnion structure from the tokenData
192 * structure used by the SetTokenEx and GetTokenEx pioctls
195 * A ktc_setTokenData structure containing the token to extract from
196 * @param[in] targetType
197 * The securityClass index of the token to be extracted
199 * The decoded token. On entry, this must point to a block of memory
200 * of sufficient size to contain an afsTokenUnion structure. Upon
201 * completion, this block must be passed to xdr_free(), using the
202 * xdr_afsTokenUnion xdrproc_t.
205 token_findByType(struct ktc_setTokenData *token,
207 struct ktc_tokenUnion *output)
211 memset(output, 0, sizeof *output);
212 entry = findTokenEntry(token, targetType);
216 if (!decodeToken(&token->tokens.tokens_val[entry], output))
219 if (output->at_type != targetType) {
220 xdr_free((xdrproc_t)xdr_ktc_tokenUnion, output);
228 * Given an unified token, populate an rxkad token from it
230 * This routine populates an rxkad token using information contained
231 * in the tokenData structure used by the SetTokenEx and GetTokenEX
235 * The new format token to extract information from.
236 * @param[out] rxkadToken
237 * The old-style rxkad token. This must be a pointer to an existing
238 * data block of sufficient size
240 * The set of token flags
241 * @param[out] aclient
242 * The client owning the token. This must be a pointer to an existing
243 * data block of sufficient size, or NULL.
247 token_extractRxkad(struct ktc_setTokenData *token,
248 struct ktc_token *rxkadToken,
250 struct ktc_principal *aclient)
252 struct ktc_tokenUnion uToken;
255 memset(&uToken, 0, sizeof(uToken));
257 memset(aclient, 0, sizeof(*aclient));
259 code = token_findByType(token, AFSTOKEN_UNION_KAD, &uToken);
263 rxkadToken->kvno = uToken.ktc_tokenUnion_u.at_kad.rk_kvno;
264 memcpy(rxkadToken->sessionKey.data,
265 uToken.ktc_tokenUnion_u.at_kad.rk_key, 8);
266 rxkadToken->startTime = uToken.ktc_tokenUnion_u.at_kad.rk_begintime;
267 rxkadToken->endTime = uToken.ktc_tokenUnion_u.at_kad.rk_endtime;
268 rxkadToken->ticketLen = uToken.ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_len;
270 if (rxkadToken->ticketLen > MAXKTCTICKETLEN) {
275 memcpy(rxkadToken->ticket,
276 uToken.ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_val,
277 rxkadToken->ticketLen);
280 *flags = uToken.ktc_tokenUnion_u.at_kad.rk_primary_flag & ~0x8000;
283 strncpy(aclient->cell, token->cell, MAXKTCREALMLEN-1);
284 aclient->cell[MAXKTCREALMLEN-1] = '\0';
286 if ((rxkadToken->kvno == 999) || /* old style bcrypt ticket */
287 (rxkadToken->startTime && /* new w/ prserver lookup */
288 (((rxkadToken->endTime - rxkadToken->startTime) & 1) == 1))) {
289 sprintf(aclient->name, "AFS ID %d",
290 uToken.ktc_tokenUnion_u.at_kad.rk_viceid);
292 sprintf(aclient->name, "Unix UID %d",
293 uToken.ktc_tokenUnion_u.at_kad.rk_viceid);
298 xdr_free((xdrproc_t) xdr_ktc_tokenUnion, &uToken);
302 struct ktc_setTokenData *
303 token_buildTokenJar(char * cellname) {
304 struct ktc_setTokenData *jar;
306 jar = malloc(sizeof(struct ktc_setTokenData));
310 memset(jar, 0, sizeof(struct ktc_setTokenData));
312 jar->cell = strdup(cellname);
318 * Add a token to an existing set of tokens. This will always add the token,
319 * regardless of whether an entry for the security class already exists
322 token_addToken(struct ktc_setTokenData *jar, struct ktc_tokenUnion *token) {
327 code = encodeTokenUnion(token, &data, &len);
331 addOpaque(jar, data, len);
338 * Replace at token in an existing set of tokens. This replaces the first
339 * token stored of a matching type. If no matching tokens are found, then
340 * the new token is added at the end of the list
343 token_replaceToken(struct ktc_setTokenData *jar,
344 struct ktc_tokenUnion *token) {
350 entry = findTokenEntry(jar, token->at_type);
352 return token_addToken(jar, token);
354 code = encodeTokenUnion(token, &data, &len);
358 free(jar->tokens.tokens_val[entry].token_opaque_val);
359 jar->tokens.tokens_val[entry].token_opaque_val = data;
360 jar->tokens.tokens_val[entry].token_opaque_len = len;
367 * Work out if a pair of token sets are equivalent. Equivalence
368 * is defined as both sets containing the same number of tokens,
369 * and every token in the first set having an equivalent token
370 * in the second set. Cell name and flags value are not compared.
373 * First set of tokens
375 * Second set of tokens
378 * True if token sets are equivalent, false otherwise
381 token_SetsEquivalent(struct ktc_setTokenData *tokenSetA,
382 struct ktc_setTokenData *tokenSetB) {
384 int decodedOK, found;
385 struct ktc_tokenUnion tokenA, tokenB;
387 if (tokenSetA->tokens.tokens_len != tokenSetB->tokens.tokens_len)
390 for (i=0; i<tokenSetA->tokens.tokens_len; i++) {
393 decodedOK = decodeToken(&tokenSetA->tokens.tokens_val[i], &tokenA);
395 for (j=0; j<tokenSetB->tokens.tokens_len && !found; j++) {
396 if (rawTokenEqual(&tokenSetA->tokens.tokens_val[i],
397 &tokenSetB->tokens.tokens_val[j])) {
403 tokenType(&tokenSetB->tokens.tokens_val[j]) == tokenA.at_type
404 && decodeToken(&tokenSetB->tokens.tokens_val[j], &tokenB)) {
406 if (tokenEqual(&tokenA, &tokenB)) {
419 /* If we made it this far without exiting, we must have found equivalents
420 * for all of our tokens */
425 token_setPag(struct ktc_setTokenData *jar, int setpag) {
427 jar->flags |= AFSTOKEN_EX_SETPAG;
429 jar->flags &= ~AFSTOKEN_EX_SETPAG;
433 token_FreeSet(struct ktc_setTokenData **jar) {
435 xdr_free((xdrproc_t)xdr_ktc_setTokenData, *jar);
436 memset(*jar, 0, sizeof(struct ktc_setTokenData));