Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / afs / afs_tokens.c
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 #include "afs/sysincludes.h"
28 #include "afsincludes.h"
29 #include "token.h"
30
31 /* A jar for storing tokens in */
32
33 /*!
34 * Return a token of the specified type from the selected tokenjar.
35 *
36 * @param[in] tokens
37 * The tokenjar in which to search
38 * @param[in] type
39 * The type of token to return
40 *
41 * @return
42 * A tokenUnion structure, from which the desired token can be
43 * accessed using the appropriate element of the union.
44 */
45 union tokenUnion *
46 afs_FindToken(struct tokenJar *tokens, rx_securityIndex type) {
47 while (tokens != NULL) {
48 if (tokens->type == type) {
49 return &tokens->content;
50 }
51 tokens = tokens->next;
52 }
53 return NULL;
54 }
55
56 /*!
57 * Free a single token
58 *
59 * This will free the given token. No attempt is made to unlink
60 * the token from its container, and it is an error to attempt to
61 * free a token which is still linked.
62 *
63 * This performs a secure free, setting all token information to 0
64 * before returning allocated data blocks to the kernel.
65 *
66 * Intended primarily for internal use.
67 *
68 * @param[in] token
69 * The token to free
70 */
71
72 void
73 afs_FreeOneToken(struct tokenJar *token) {
74 if (token->next != NULL)
75 osi_Panic("Freeing linked token");
76
77 switch (token->type) {
78 case RX_SECIDX_KAD:
79 if (token->content.rxkad.ticket != NULL) {
80 memset(token->content.rxkad.ticket, 0, token->content.rxkad.ticketLen);
81 afs_osi_Free(token->content.rxkad.ticket,
82 token->content.rxkad.ticketLen);
83 }
84 break;
85 default:
86 break;
87 }
88 memset(token, 0, sizeof(struct tokenJar));
89 afs_osi_Free(token, sizeof(struct tokenJar));
90 }
91
92 /*!
93 * Free a token jar
94 *
95 * Free all of the tokens in a given token jar. This will also set the
96 * pointer to the jar to NULL, to indicate that it has been freed.
97 *
98 * @param[in] tokenPtr
99 * A pointer to the address of the tokenjar to free.
100 */
101 void
102 afs_FreeTokens(struct tokenJar **tokenPtr) {
103 struct tokenJar *next, *tokens;
104
105 tokens = *tokenPtr;
106 *tokenPtr = NULL;
107 while(tokens != NULL) {
108 next = tokens->next;
109 tokens->next = NULL; /* Unlink from chain */
110 afs_FreeOneToken(tokens);
111 tokens = next;
112 }
113 }
114
115 /*!
116 * Add a token to a token jar
117 *
118 * Add a new token to a token jar. If the jar already exists,
119 * then this token becomes the first in the jar. If it doesn't
120 * exist, then a new jar is created. The contents of the new
121 * token are initialised to 0 upon creation.
122 *
123 * @param[in] tokens
124 * A pointer to the address of the token jar to populate
125 * @param[in] type
126 * The type of token to create
127 *
128 * @return
129 * A pointer to the tokenUnion of the newly created token,
130 * which may then be used to populate the token.
131 */
132 union tokenUnion *
133 afs_AddToken(struct tokenJar **tokens, rx_securityIndex type) {
134 struct tokenJar *newToken;
135
136 newToken = afs_osi_Alloc(sizeof(struct tokenJar));
137 osi_Assert(newToken != NULL);
138 memset(newToken, 0, sizeof(*newToken));
139
140 newToken->type = type;
141 newToken->next = *tokens;
142 *tokens = newToken;
143
144 return &newToken->content;
145 }
146
147 /*!
148 * Indicate if a single token is expired
149 *
150 * @param[in] token
151 * The token to check
152 * @param[in] now
153 * The time to check against for expiry (typically the results of
154 * calling osi_Time())
155 *
156 * @returns
157 * True if the token has expired, false otherwise
158 */
159 int
160 afs_IsTokenExpired(struct tokenJar *token, afs_int32 now) {
161 switch (token->type) {
162 case RX_SECIDX_KAD:
163 if (token->content.rxkad.clearToken.EndTimestamp < now - NOTOKTIMEOUT)
164 return 1;
165 break;
166 default:
167 return 0;
168 }
169 return 0;
170 }
171
172 /*!
173 * Indicate if a token is usable by the kernel module
174 *
175 * This determines whether a token is usable. A usable token is one that
176 * has not expired, and which is otherwise suitable for use.
177 *
178 * @param[in] token
179 * The token to check
180 * @param[in] now
181 * The time to use for the expiry check
182 *
183 * @returns
184 * True if the token is usable, false otherwise
185 */
186 int
187 afs_IsTokenUsable(struct tokenJar *token, afs_int32 now) {
188
189 if (afs_IsTokenExpired(token, now))
190 return 0;
191
192 switch (token->type) {
193 case RX_SECIDX_KAD:
194 /* We assume that all non-expired rxkad tokens are usable by us */
195 return 1;
196 default :
197 return 0;
198 }
199 }
200
201 /*!
202 * Discard all expired tokens from a token jar
203 *
204 * This permanently removes all tokens which have expired from the token
205 * jar. Note that tokens which are not usable, but which have not expired,
206 * will not be deleted.
207 *
208 * @param[in] tokenPtr
209 * A pointer to the address of the token jar to check
210 * @param[in] now
211 * The time to use for the expiry check
212 */
213
214 void
215 afs_DiscardExpiredTokens(struct tokenJar **tokenPtr, afs_int32 now) {
216 struct tokenJar *next;
217
218 while (*tokenPtr != NULL) {
219 if (afs_IsTokenExpired(*tokenPtr, now)) {
220 next = (*tokenPtr)->next;
221 (*tokenPtr)->next = NULL;
222 afs_FreeOneToken(*tokenPtr);
223 *tokenPtr = next;
224 } else {
225 tokenPtr = &(*tokenPtr)->next;
226 }
227 }
228 }
229
230 /*!
231 * Indicate whether a token jar contains one, or more usable tokens
232 *
233 * @param[in] token
234 * The token jar to check
235 * @param[in] now
236 * The cime to use for the expiry check
237 *
238 * @returns
239 * True if the jar contains usable tokens, otherwise false
240 */
241 int
242 afs_HasUsableTokens(struct tokenJar *token, afs_int32 now) {
243 while (token != NULL) {
244 if (afs_IsTokenUsable(token, now))
245 return 1;
246 token = token->next;
247 }
248 return 0;
249 }
250
251 /*!
252 * Indicate whether a token jar contains a valid (non-expired) token
253 *
254 * @param[in] token
255 * The token jar to check
256 * @param[in] now
257 * The time to use for the expiry check
258 *
259 * @returns
260 * True if the jar contains valid tokens, otherwise false
261 *
262 */
263 int
264 afs_HasValidTokens(struct tokenJar *token, afs_int32 now) {
265 while (token != NULL) {
266 if (!afs_IsTokenExpired(token, now))
267 return 1;
268 token = token->next;
269 }
270 return 0;
271 }
272
273 /*!
274 * Count the number of valid tokens in a jar. A valid token is
275 * one which is not expired - note that valid tokens may not be
276 * usable by the kernel.
277 *
278 * @param[in] token
279 * The token jar to check
280 * @param[in] now
281 * The time to use for the expiry check
282 *
283 * @returns
284 * The number of valid tokens in the jar
285 */
286 static int
287 countValidTokens(struct tokenJar *token, time_t now) {
288 int count = 0;
289
290 while (token != NULL) {
291 if (!afs_IsTokenExpired(token, now))
292 count ++;
293 token = token->next;
294 }
295 return count;
296 }
297
298 /*!
299 * Add an rxkad token to the token jar
300 *
301 * @param[in] tokens
302 * A pointer to the address of the jar to add the token to
303 * @param[in] ticket
304 * A data block containing the token's opaque ticket
305 * @param[in] ticketLen
306 * The length of the ticket data block
307 * @param[in] clearToken
308 * The cleartext token information
309 */
310 void
311 afs_AddRxkadToken(struct tokenJar **tokens, char *ticket, int ticketLen,
312 struct ClearToken *clearToken) {
313 union tokenUnion *tokenU;
314 struct rxkadToken *rxkad;
315
316 tokenU = afs_AddToken(tokens, RX_SECIDX_KAD);
317 rxkad = &tokenU->rxkad;
318
319 rxkad->ticket = afs_osi_Alloc(ticketLen);
320 osi_Assert(rxkad->ticket != NULL);
321 rxkad->ticketLen = ticketLen;
322 memcpy(rxkad->ticket, ticket, ticketLen);
323 rxkad->clearToken = *clearToken;
324 }
325
326 static int
327 afs_AddRxkadTokenFromPioctl(struct tokenJar **tokens,
328 struct ktc_tokenUnion *pioctlToken) {
329 struct ClearToken clear;
330
331 clear.AuthHandle = pioctlToken->ktc_tokenUnion_u.at_kad.rk_kvno;
332 clear.ViceId = pioctlToken->ktc_tokenUnion_u.at_kad.rk_viceid;
333 clear.BeginTimestamp = pioctlToken->ktc_tokenUnion_u.at_kad.rk_begintime;
334 clear.EndTimestamp = pioctlToken->ktc_tokenUnion_u.at_kad.rk_endtime;
335 memcpy(clear.HandShakeKey, pioctlToken->ktc_tokenUnion_u.at_kad.rk_key, 8);
336 afs_AddRxkadToken(tokens,
337 pioctlToken->ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_val,
338 pioctlToken->ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_len,
339 &clear);
340
341 /* Security means never having to say you're sorry */
342 memset(clear.HandShakeKey, 0, 8);
343
344 return 0;
345 }
346
347 static int
348 rxkad_extractTokenForPioctl(struct tokenJar *token,
349 struct ktc_tokenUnion *pioctlToken) {
350
351 struct token_rxkad *rxkadPioctl;
352 struct rxkadToken *rxkadInternal;
353
354 rxkadPioctl = &pioctlToken->ktc_tokenUnion_u.at_kad;
355 rxkadInternal = &token->content.rxkad;
356
357 rxkadPioctl->rk_kvno = rxkadInternal->clearToken.AuthHandle;
358 rxkadPioctl->rk_viceid = rxkadInternal->clearToken.ViceId;
359 rxkadPioctl->rk_begintime = rxkadInternal->clearToken.BeginTimestamp;
360 rxkadPioctl->rk_endtime = rxkadInternal->clearToken.EndTimestamp;
361 memcpy(rxkadPioctl->rk_key, rxkadInternal->clearToken.HandShakeKey, 8);
362
363 rxkadPioctl->rk_ticket.rk_ticket_val = xdr_alloc(rxkadInternal->ticketLen);
364 if (rxkadPioctl->rk_ticket.rk_ticket_val == NULL)
365 return ENOMEM;
366 rxkadPioctl->rk_ticket.rk_ticket_len = rxkadInternal->ticketLen;
367 memcpy(rxkadPioctl->rk_ticket.rk_ticket_val,
368 rxkadInternal->ticket, rxkadInternal->ticketLen);
369
370 return 0;
371 }
372
373 /*!
374 * Add a token to a token jar based on the input from a new-style
375 * SetToken pioctl
376 *
377 * @param[in] tokens
378 * Pointer to the address of a token jar
379 * @param[in] pioctlToken
380 * The token structure obtained through the pioctl (note this
381 * is a single, XDR decoded, token)
382 *
383 * @returns
384 * 0 on success, an error code on failure
385 */
386 int
387 afs_AddTokenFromPioctl(struct tokenJar **tokens,
388 struct ktc_tokenUnion *pioctlToken) {
389
390 switch (pioctlToken->at_type) {
391 case RX_SECIDX_KAD:
392 return afs_AddRxkadTokenFromPioctl(tokens, pioctlToken);
393 }
394
395 return EINVAL;
396 }
397
398 static int
399 extractPioctlToken(struct tokenJar *token,
400 struct token_opaque *opaque) {
401 XDR xdrs;
402 struct ktc_tokenUnion *pioctlToken;
403 int code;
404
405 memset(opaque, 0, sizeof(token_opaque));
406
407 pioctlToken = osi_Alloc(sizeof(struct ktc_tokenUnion));
408 if (pioctlToken == NULL)
409 return ENOMEM;
410
411 pioctlToken->at_type = token->type;
412
413 switch (token->type) {
414 case RX_SECIDX_KAD:
415 code = rxkad_extractTokenForPioctl(token, pioctlToken);
416 break;
417 default:
418 code = EINVAL;;
419 }
420
421 if (code)
422 goto out;
423
424 xdrlen_create(&xdrs);
425 if (!xdr_ktc_tokenUnion(&xdrs, pioctlToken)) {
426 code = EINVAL;
427 xdr_destroy(&xdrs);
428 goto out;
429 }
430
431 opaque->token_opaque_len = xdr_getpos(&xdrs);
432 xdr_destroy(&xdrs);
433
434 opaque->token_opaque_val = osi_Alloc(opaque->token_opaque_len);
435 if (opaque->token_opaque_val == NULL) {
436 code = ENOMEM;
437 goto out;
438 }
439
440 xdrmem_create(&xdrs,
441 opaque->token_opaque_val,
442 opaque->token_opaque_len,
443 XDR_ENCODE);
444 if (!xdr_ktc_tokenUnion(&xdrs, pioctlToken)) {
445 code = EINVAL;
446 xdr_destroy(&xdrs);
447 goto out;
448 }
449 xdr_destroy(&xdrs);
450
451 out:
452 xdr_free((xdrproc_t) xdr_ktc_tokenUnion, &pioctlToken);
453 osi_Free(pioctlToken, sizeof(struct ktc_tokenUnion));
454
455 if (code != 0) {
456 if (opaque->token_opaque_val != NULL)
457 osi_Free(opaque->token_opaque_val, opaque->token_opaque_len);
458 opaque->token_opaque_val = NULL;
459 opaque->token_opaque_len = 0;
460 }
461 return code;
462 }
463
464 int
465 afs_ExtractTokensForPioctl(struct tokenJar *token,
466 time_t now,
467 struct ktc_setTokenData *tokenSet)
468 {
469 int numTokens, pos;
470 int code = 0;
471
472 numTokens = countValidTokens(token, now);
473
474 tokenSet->tokens.tokens_len = numTokens;
475 tokenSet->tokens.tokens_val
476 = xdr_alloc(sizeof(struct token_opaque) * numTokens);
477
478 if (tokenSet->tokens.tokens_val == NULL)
479 return ENOMEM;
480
481 pos = 0;
482 while (token != NULL && pos < numTokens) {
483 code = extractPioctlToken(token, &tokenSet->tokens.tokens_val[pos]);
484 if (code)
485 goto out;
486 token = token->next;
487 pos++;
488 }
489
490 out:
491 if (code)
492 xdr_free((xdrproc_t) xdr_ktc_setTokenData, tokenSet);
493
494 return code;
495 }