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