afs: remove bogus comment from afs_IsTokenExpired
[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 }