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
));