Unix CM: Generalise token storage
[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
30 /* A jar for storing tokens in */
31
32 /*!
33  * Return a token of the specified type from the selected tokenjar.
34  *
35  * @param[in] tokens
36  *      The tokenjar in which to search
37  * @param[in] type
38  *      The type of token to return
39  *
40  * @return
41  *      A tokenUnion structure, from which the desired token can be
42  *      accessed using the appropriate element of the union.
43  */
44 union tokenUnion *
45 afs_FindToken(struct tokenJar *tokens, rx_securityIndex type) {
46     while (tokens != NULL) {
47         if (tokens->type == type) {
48             return &tokens->u;
49         }
50         tokens = tokens->next;
51     }
52     return NULL;
53 }
54
55 /*!
56  * Free a single token
57  *
58  * This will free the given token. No attempt is made to unlink
59  * the token from its container, and it is an error to attempt to
60  * free a token which is still linked.
61  *
62  * This performs a secure free, setting all token information to 0
63  * before returning allocated data blocks to the kernel.
64  *
65  * Intended primarily for internal use.
66  *
67  * @param[in] token
68  *      The token to free
69  */
70
71 void
72 afs_FreeOneToken(struct tokenJar *token) {
73     if (token->next != NULL)
74         osi_Panic("Freeing linked token");
75
76     switch (token->type) {
77       case RX_SECIDX_KAD:
78         if (token->u.rxkad.ticket != NULL) {
79                 memset(token->u.rxkad.ticket, 0, token->u.rxkad.ticketLen);
80                 afs_osi_Free(token->u.rxkad.ticket,
81                              token->u.rxkad.ticketLen);
82         }
83         break;
84       default:
85         break;
86     }
87     memset(token, 0, sizeof(struct tokenJar));
88     afs_osi_Free(token, sizeof(struct tokenJar));
89 }
90
91 /*!
92  * Free a token jar
93  *
94  * Free all of the tokens in a given token jar. This will also set the
95  * pointer to the jar to NULL, to indicate that it has been freed.
96  *
97  * @param[in] tokenPtr
98  *      A pointer to the address of the tokenjar to free.
99  */
100 void
101 afs_FreeTokens(struct tokenJar **tokenPtr) {
102     struct tokenJar *next, *tokens;
103
104     tokens = *tokenPtr;
105     *tokenPtr = NULL;
106     while(tokens != NULL) {
107         next = tokens->next;
108         tokens->next = NULL; /* Unlink from chain */
109         afs_FreeOneToken(tokens);
110         tokens = next;
111     }
112 }
113
114 /*!
115  * Add a token to a token jar
116  *
117  * Add a new token to a token jar. If the jar already exists,
118  * then this token becomes the first in the jar. If it doesn't
119  * exist, then a new jar is created. The contents of the new
120  * token are initialised to 0 upon creation.
121  *
122  * @param[in] tokens
123  *      A pointer to the address of the token jar to populate
124  * @param[in] type
125  *      The type of token to create
126  *
127  * @return
128  *      A pointer to the tokenUnion of the newly created token,
129  *      which may then be used to populate the token.
130  */
131 union tokenUnion *
132 afs_AddToken(struct tokenJar **tokens, rx_securityIndex type) {
133     struct tokenJar *newToken;
134
135     newToken = afs_osi_Alloc(sizeof(struct tokenJar));
136     memset(newToken, 0, sizeof(*newToken));
137
138     newToken->type = type;
139     newToken->next = *tokens;
140     *tokens = newToken;
141
142     return &newToken->u;
143 }
144
145 /*!
146  * Indicate if a single token is expired
147  *
148  * @param[in] token
149  *      The token to check
150  * @param[in] now
151  *      The time to check against for expiry (typically the results of
152  *      calling osi_Time())
153  *
154  * @returns
155  *      True if the token has expired, false otherwise
156  */
157 int
158 afs_IsTokenExpired(struct tokenJar *token, afs_int32 now) {
159     switch (token->type) {
160       case RX_SECIDX_KAD:
161         if (token->u.rxkad.clearToken.EndTimestamp < now - NOTOKTIMEOUT)
162             return 1;
163         break;
164       default:
165         return 0;
166     }
167     return 0; /* not reached, but keep gcc happy */
168 }
169
170 /*!
171  * Indicate if a token is usable by the kernel module
172  *
173  * This determines whether a token is usable. A usable token is one that
174  * has not expired, and which is otherwise suitable for use.
175  *
176  * @param[in] token
177  *      The token to check
178  * @param[in] now
179  *      The time to use for the expiry check
180  *
181  * @returns
182  *      True if the token is usable, false otherwise
183  */
184 int
185 afs_IsTokenUsable(struct tokenJar *token, afs_int32 now) {
186
187     if (afs_IsTokenExpired(token, now))
188         return 0;
189
190     switch (token->type) {
191       case RX_SECIDX_KAD:
192         /* We assume that all non-expired rxkad tokens are usable by us */
193         return 1;
194       default :
195         return 0;
196     }
197 }
198
199 /*!
200  * Discard all expired tokens from a token jar
201  *
202  * This permanently removes all tokens which have expired from the token
203  * jar. Note that tokens which are not usable, but which have not expired,
204  * will not be deleted.
205  *
206  * @param[in] tokenPtr
207  *      A pointer to the address of the token jar to check
208  * @param[in] now
209  *      The time to use for the expiry check
210  */
211
212 void
213 afs_DiscardExpiredTokens(struct tokenJar **tokenPtr, afs_int32 now) {
214     struct tokenJar *next;
215
216     while (*tokenPtr != NULL) {
217         if (afs_IsTokenExpired(*tokenPtr, now)) {
218             next = (*tokenPtr)->next;
219             (*tokenPtr)->next = NULL;
220             afs_FreeOneToken(*tokenPtr);
221             *tokenPtr = next;
222         } else {
223             tokenPtr = &(*tokenPtr)->next;
224         }
225     }
226 }
227
228 /*!
229  * Indicate whether a token jar contains one, or more usable tokens
230  *
231  * @param[in] token
232  *      The token jar to check
233  * @param[in] now
234  *      The cime to use for the expiry check
235  *
236  * @returns
237  *      True if the jar contains usable tokens, otherwise false
238  */
239 int
240 afs_HasUsableTokens(struct tokenJar *token, afs_int32 now) {
241     while (token != NULL) {
242         if (afs_IsTokenUsable(token, now))
243             return 1;
244         token = token->next;
245     }
246     return 0;
247 }
248
249 /*!
250  * Add an rxkad token to the token jar
251  *
252  * @param[in] tokens
253  *      A pointer to the address of the jar to add the token to
254  * @param[in] ticket
255  *      A data block containing the token's opaque ticket
256  * @param[in] ticketLen
257  *      The length of the ticket data block
258  * @param[in] clearToken
259  *      The cleartext token information
260  */
261 void
262 afs_AddRxkadToken(struct tokenJar **tokens, char *ticket, int ticketLen,
263                   struct ClearToken *clearToken) {
264     union tokenUnion *tokenU;
265     struct rxkadToken *rxkad;
266
267     tokenU = afs_AddToken(tokens, RX_SECIDX_KAD);
268     rxkad = &tokenU->rxkad;
269
270     rxkad->ticket = afs_osi_Alloc(ticketLen);
271     rxkad->ticketLen = ticketLen;
272     memcpy(rxkad->ticket, ticket, ticketLen);
273     rxkad->clearToken = *clearToken;
274 }
275