Add new SetTokenEx pioctl
[openafs.git] / src / auth / token.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 <sys/errno.h>
26
27 #include <afsconfig.h>
28 #include <afs/param.h>
29 #include <afs/auth.h>
30 #include <rx/rxkad.h>
31 #include "ktc.h"
32 #include "token.h"
33
34
35 /* Routines for processing tokens in the new XDR format
36  *
37  * The code here is inspired by work done by Jeffrey Hutzelman et al
38  * at the AFSSIG.se hackathon and further refined by Matt
39  * Benjamin and Marcus Watts as part of rxk5. However, unless
40  * otherwise noted, the implementation is new
41  */
42
43 /* Given a token type, return the entry number of the first token of that
44  * type */
45 static int
46 findTokenEntry(struct ktc_setTokenData *token,
47                int targetType)
48 {
49     XDR xdrs;
50     int i, type;
51
52     for (i = 0; i < token->tokens.tokens_len; i++) {
53         xdrmem_create(&xdrs,
54                       token->tokens.tokens_val[i].token_opaque_val,
55                       token->tokens.tokens_val[i].token_opaque_len,
56                       XDR_DECODE);
57         /* Take a peak at the discriminator. */
58         if (!xdr_enum(&xdrs, &type)) {
59             type = -1;
60         }
61         xdr_destroy(&xdrs);
62
63         if (type == targetType)
64             return i;
65     }
66     return -1;
67 }
68
69 /* XDR encode a token union structure, and return data and length information
70  * suitable for stuffing into a token_opaque structure
71  */
72 static int
73 encodeTokenUnion(struct ktc_tokenUnion *token,
74                  char **dataPtr, size_t *lenPtr) {
75     char *data = NULL;
76     size_t len;
77     XDR xdrs;
78     int code = 0;
79
80     *dataPtr = NULL;
81     *lenPtr = 0;
82
83     xdrlen_create(&xdrs);
84     if (!xdr_ktc_tokenUnion(&xdrs, token)) {
85         code = EINVAL;
86         goto out;
87     }
88
89     len = xdr_getpos(&xdrs);
90     data = malloc(len);
91     if (data == NULL) {
92         code = ENOMEM;
93         goto out;
94     }
95     xdr_destroy(&xdrs);
96
97     xdrmem_create(&xdrs, data, len, XDR_ENCODE);
98     if (!xdr_ktc_tokenUnion(&xdrs, token)) {
99         code = EINVAL;
100         goto out;
101     }
102
103     *dataPtr = data;
104     *lenPtr = len;
105
106 out:
107     xdr_destroy(&xdrs);
108     if (code) {
109         if (data)
110             free(data);
111     }
112
113     return code;
114 }
115
116 static void
117 addOpaque(struct ktc_setTokenData *jar, char *data, size_t len)
118 {
119     int entry;
120
121     entry = jar->tokens.tokens_len;
122     jar->tokens.tokens_val = realloc(jar->tokens.tokens_val,
123                                      entry + 1 * sizeof(token_opaque));
124     jar->tokens.tokens_len++;
125     jar->tokens.tokens_val[entry].token_opaque_val = data;
126     jar->tokens.tokens_val[entry].token_opaque_len = len;
127 }
128
129 /*!
130  * Extract a specific token element from a unified token structure
131  *
132  * This routine extracts an afsTokenUnion structure from the tokenData
133  * structure used by the SetTokenEx and GetTokenEx pioctls
134  *
135  * @param[in] token
136  *      A ktc_setTokenData structure containing the token to extract from
137  * @param[in] targetType
138  *      The securityClass index of the token to be extracted
139  * @param[out] output
140  *      The decoded token. On entry, this must point to a block of memory
141  *      of sufficient size to contain an afsTokenUnion structure. Upon
142  *      completion, this block must be passed to xdr_free(), using the
143  *      xdr_afsTokenUnion xdrproc_t.
144  */
145 int
146 token_findByType(struct ktc_setTokenData *token,
147                  int targetType,
148                  struct ktc_tokenUnion *output)
149 {
150     XDR xdrs;
151     int entry;
152     int code = EINVAL;
153
154     memset(output, 0, sizeof *output);
155     entry = findTokenEntry(token, targetType);
156     if (entry == -1)
157         goto out;
158
159     xdrmem_create(&xdrs,
160                   token->tokens.tokens_val[entry].token_opaque_val,
161                   token->tokens.tokens_val[entry].token_opaque_len,
162                   XDR_DECODE);
163
164     if (!xdr_ktc_tokenUnion(&xdrs, output)) {
165         xdr_destroy(&xdrs);
166         goto out;
167     }
168
169     xdr_destroy(&xdrs);
170     if (output->at_type != targetType) {
171         xdr_free((xdrproc_t)xdr_ktc_tokenUnion, output);
172         goto out;
173     }
174
175     code = 0;
176
177 out:
178     return code;
179 }
180
181 /*!
182  * Given an unified token, populate an rxkad token from it
183  *
184  * This routine populates an rxkad token using information contained
185  * in the tokenData structure used by the SetTokenEx and GetTokenEX
186  * pioctls.
187  *
188  * @param[in] token
189  *      The new format token to extract information from.
190  * @param[out] rxkadToken
191  *      The old-style rxkad token. This must be a pointer to an existing
192  *      data block of sufficient size
193  * @param[out] flags
194  *      The set of token flags
195  * @param[out] aclient
196  *      The client owning the token. This must be a pointer to an existing
197  *      data block of sufficient size, or NULL.
198  */
199
200 int
201 token_extractRxkad(struct ktc_setTokenData *token,
202                    struct ktc_token *rxkadToken,
203                    int *flags,
204                    struct ktc_principal *aclient)
205 {
206     struct ktc_tokenUnion uToken;
207     int code;
208
209     memset(&uToken, 0, sizeof(uToken));
210     if (aclient)
211         memset(aclient, 0, sizeof(*aclient));
212
213     code = token_findByType(token, AFSTOKEN_UNION_KAD, &uToken);
214     if (code)
215         return code;
216
217     rxkadToken->kvno = uToken.ktc_tokenUnion_u.at_kad.rk_kvno;
218     memcpy(rxkadToken->sessionKey.data,
219            uToken.ktc_tokenUnion_u.at_kad.rk_key, 8);
220     rxkadToken->startTime = uToken.ktc_tokenUnion_u.at_kad.rk_begintime;
221     rxkadToken->endTime   = uToken.ktc_tokenUnion_u.at_kad.rk_endtime;
222     rxkadToken->ticketLen = uToken.ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_len;
223
224     if (rxkadToken->ticketLen > MAXKTCTICKETLEN) {
225         code = E2BIG;
226         goto out;
227     }
228
229     memcpy(rxkadToken->ticket,
230            uToken.ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_val,
231            rxkadToken->ticketLen);
232
233     if (flags)
234         *flags = uToken.ktc_tokenUnion_u.at_kad.rk_primary_flag & ~0x8000;
235
236     if (aclient) {
237         strncpy(aclient->cell, token->cell, MAXKTCREALMLEN-1);
238         aclient->cell[MAXKTCREALMLEN-1] = '\0';
239
240         if ((rxkadToken->kvno == 999) ||        /* old style bcrypt ticket */
241             (rxkadToken->startTime &&   /* new w/ prserver lookup */
242              (((rxkadToken->endTime - rxkadToken->startTime) & 1) == 1))) {
243             sprintf(aclient->name, "AFS ID %d",
244                     uToken.ktc_tokenUnion_u.at_kad.rk_viceid);
245         } else {
246             sprintf(aclient->name, "Unix UID %d",
247                     uToken.ktc_tokenUnion_u.at_kad.rk_viceid);
248         }
249     }
250
251 out:
252     xdr_free((xdrproc_t) xdr_ktc_tokenUnion, &uToken);
253     return code;
254 }
255
256 struct ktc_setTokenData *
257 token_buildTokenJar(char * cellname) {
258     struct ktc_setTokenData *jar;
259
260     jar = malloc(sizeof(struct ktc_setTokenData));
261     if (jar == NULL)
262         return NULL;
263
264     memset(jar, 0, sizeof(struct ktc_setTokenData));
265
266     jar->cell = strdup(cellname);
267
268     return jar;
269 }
270
271 /*!
272  * Add a token to an existing set of tokens. This will always add the token,
273  * regardless of whether an entry for the security class already exists
274  */
275 int
276 token_addToken(struct ktc_setTokenData *jar, struct ktc_tokenUnion *token) {
277     int code;
278     char *data;
279     size_t len;
280
281     code = encodeTokenUnion(token, &data, &len);
282     if (code)
283         goto out;
284
285     addOpaque(jar, data, len);
286
287 out:
288     return code;
289 }
290
291 /*!
292  * Replace at token in an existing set of tokens. This replaces the first
293  * token stored of a matching type. If no matching tokens are found, then
294  * the new token is added at the end of the list
295  */
296 int
297 token_replaceToken(struct ktc_setTokenData *jar,
298                    struct ktc_tokenUnion *token) {
299     int entry;
300     char *data;
301     size_t len;
302     int code;
303
304     entry = findTokenEntry(jar, token->at_type);
305     if (entry == -1)
306         return token_addToken(jar, token);
307
308     code = encodeTokenUnion(token, &data, &len);
309     if (code)
310         goto out;
311
312     free(jar->tokens.tokens_val[entry].token_opaque_val);
313     jar->tokens.tokens_val[entry].token_opaque_val = data;
314     jar->tokens.tokens_val[entry].token_opaque_len = len;
315
316 out:
317     return code;
318 }
319
320 void
321 token_setPag(struct ktc_setTokenData *jar, int setpag) {
322     if (setpag)
323         jar->flags |= AFSTOKEN_EX_SETPAG;
324     else
325         jar->flags &= ~AFSTOKEN_EX_SETPAG;
326 }