diff options
author | David Howells <dhowells@redhat.com> | 2009-09-13 21:17:46 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-09-15 05:44:33 -0400 |
commit | 99455153d0670ba110e6a3b855b8369bcbd11120 (patch) | |
tree | 166ba6e3046654f7d1cd5f0debdcae1aa8938080 | |
parent | ed6dd18b5aceb322da9840f01a68d648e91c8a72 (diff) |
RxRPC: Parse security index 5 keys (Kerberos 5)
Parse RxRPC security index 5 type keys (Kerberos 5 tokens).
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/keys/rxrpc-type.h | 52 | ||||
-rw-r--r-- | net/rxrpc/ar-key.c | 577 |
2 files changed, 589 insertions, 40 deletions
diff --git a/include/keys/rxrpc-type.h b/include/keys/rxrpc-type.h index c0d91218fdd3..5eb23571b425 100644 --- a/include/keys/rxrpc-type.h +++ b/include/keys/rxrpc-type.h | |||
@@ -36,6 +36,54 @@ struct rxkad_key { | |||
36 | }; | 36 | }; |
37 | 37 | ||
38 | /* | 38 | /* |
39 | * Kerberos 5 principal | ||
40 | * name/name/name@realm | ||
41 | */ | ||
42 | struct krb5_principal { | ||
43 | u8 n_name_parts; /* N of parts of the name part of the principal */ | ||
44 | char **name_parts; /* parts of the name part of the principal */ | ||
45 | char *realm; /* parts of the realm part of the principal */ | ||
46 | }; | ||
47 | |||
48 | /* | ||
49 | * Kerberos 5 tagged data | ||
50 | */ | ||
51 | struct krb5_tagged_data { | ||
52 | /* for tag value, see /usr/include/krb5/krb5.h | ||
53 | * - KRB5_AUTHDATA_* for auth data | ||
54 | * - | ||
55 | */ | ||
56 | int32_t tag; | ||
57 | uint32_t data_len; | ||
58 | u8 *data; | ||
59 | }; | ||
60 | |||
61 | /* | ||
62 | * RxRPC key for Kerberos V (type-5 security) | ||
63 | */ | ||
64 | struct rxk5_key { | ||
65 | uint64_t authtime; /* time at which auth token generated */ | ||
66 | uint64_t starttime; /* time at which auth token starts */ | ||
67 | uint64_t endtime; /* time at which auth token expired */ | ||
68 | uint64_t renew_till; /* time to which auth token can be renewed */ | ||
69 | int32_t is_skey; /* T if ticket is encrypted in another ticket's | ||
70 | * skey */ | ||
71 | int32_t flags; /* mask of TKT_FLG_* bits (krb5/krb5.h) */ | ||
72 | struct krb5_principal client; /* client principal name */ | ||
73 | struct krb5_principal server; /* server principal name */ | ||
74 | uint16_t ticket_len; /* length of ticket */ | ||
75 | uint16_t ticket2_len; /* length of second ticket */ | ||
76 | u8 n_authdata; /* number of authorisation data elements */ | ||
77 | u8 n_addresses; /* number of addresses */ | ||
78 | struct krb5_tagged_data session; /* session data; tag is enctype */ | ||
79 | struct krb5_tagged_data *addresses; /* addresses */ | ||
80 | u8 *ticket; /* krb5 ticket */ | ||
81 | u8 *ticket2; /* second krb5 ticket, if related to ticket (via | ||
82 | * DUPLICATE-SKEY or ENC-TKT-IN-SKEY) */ | ||
83 | struct krb5_tagged_data *authdata; /* authorisation data */ | ||
84 | }; | ||
85 | |||
86 | /* | ||
39 | * list of tokens attached to an rxrpc key | 87 | * list of tokens attached to an rxrpc key |
40 | */ | 88 | */ |
41 | struct rxrpc_key_token { | 89 | struct rxrpc_key_token { |
@@ -43,6 +91,7 @@ struct rxrpc_key_token { | |||
43 | struct rxrpc_key_token *next; /* the next token in the list */ | 91 | struct rxrpc_key_token *next; /* the next token in the list */ |
44 | union { | 92 | union { |
45 | struct rxkad_key *kad; | 93 | struct rxkad_key *kad; |
94 | struct rxk5_key *k5; | ||
46 | }; | 95 | }; |
47 | }; | 96 | }; |
48 | 97 | ||
@@ -64,8 +113,11 @@ struct rxrpc_key_data_v1 { | |||
64 | * - based on openafs-1.4.10/src/auth/afs_token.xg | 113 | * - based on openafs-1.4.10/src/auth/afs_token.xg |
65 | */ | 114 | */ |
66 | #define AFSTOKEN_LENGTH_MAX 16384 /* max payload size */ | 115 | #define AFSTOKEN_LENGTH_MAX 16384 /* max payload size */ |
116 | #define AFSTOKEN_STRING_MAX 256 /* max small string length */ | ||
117 | #define AFSTOKEN_DATA_MAX 64 /* max small data length */ | ||
67 | #define AFSTOKEN_CELL_MAX 64 /* max cellname length */ | 118 | #define AFSTOKEN_CELL_MAX 64 /* max cellname length */ |
68 | #define AFSTOKEN_MAX 8 /* max tokens per payload */ | 119 | #define AFSTOKEN_MAX 8 /* max tokens per payload */ |
120 | #define AFSTOKEN_BDATALN_MAX 16384 /* max big data length */ | ||
69 | #define AFSTOKEN_RK_TIX_MAX 12000 /* max RxKAD ticket size */ | 121 | #define AFSTOKEN_RK_TIX_MAX 12000 /* max RxKAD ticket size */ |
70 | #define AFSTOKEN_GK_KEY_MAX 64 /* max GSSAPI key size */ | 122 | #define AFSTOKEN_GK_KEY_MAX 64 /* max GSSAPI key size */ |
71 | #define AFSTOKEN_GK_TOKEN_MAX 16384 /* max GSSAPI token size */ | 123 | #define AFSTOKEN_GK_TOKEN_MAX 16384 /* max GSSAPI token size */ |
diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c index bf4d623ee1ce..44836f6c9643 100644 --- a/net/rxrpc/ar-key.c +++ b/net/rxrpc/ar-key.c | |||
@@ -64,7 +64,7 @@ struct key_type key_type_rxrpc_s = { | |||
64 | static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr, | 64 | static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr, |
65 | unsigned toklen) | 65 | unsigned toklen) |
66 | { | 66 | { |
67 | struct rxrpc_key_token *token; | 67 | struct rxrpc_key_token *token, **pptoken; |
68 | size_t plen; | 68 | size_t plen; |
69 | u32 tktlen; | 69 | u32 tktlen; |
70 | int ret; | 70 | int ret; |
@@ -129,13 +129,398 @@ static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr, | |||
129 | key->type_data.x[0]++; | 129 | key->type_data.x[0]++; |
130 | 130 | ||
131 | /* attach the data */ | 131 | /* attach the data */ |
132 | token->next = key->payload.data; | 132 | for (pptoken = (struct rxrpc_key_token **)&key->payload.data; |
133 | key->payload.data = token; | 133 | *pptoken; |
134 | pptoken = &(*pptoken)->next) | ||
135 | continue; | ||
136 | *pptoken = token; | ||
137 | if (token->kad->expiry < key->expiry) | ||
138 | key->expiry = token->kad->expiry; | ||
139 | |||
140 | _leave(" = 0"); | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static void rxrpc_free_krb5_principal(struct krb5_principal *princ) | ||
145 | { | ||
146 | int loop; | ||
147 | |||
148 | if (princ->name_parts) { | ||
149 | for (loop = princ->n_name_parts - 1; loop >= 0; loop--) | ||
150 | kfree(princ->name_parts[loop]); | ||
151 | kfree(princ->name_parts); | ||
152 | } | ||
153 | kfree(princ->realm); | ||
154 | } | ||
155 | |||
156 | static void rxrpc_free_krb5_tagged(struct krb5_tagged_data *td) | ||
157 | { | ||
158 | kfree(td->data); | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * free up an RxK5 token | ||
163 | */ | ||
164 | static void rxrpc_rxk5_free(struct rxk5_key *rxk5) | ||
165 | { | ||
166 | int loop; | ||
167 | |||
168 | rxrpc_free_krb5_principal(&rxk5->client); | ||
169 | rxrpc_free_krb5_principal(&rxk5->server); | ||
170 | rxrpc_free_krb5_tagged(&rxk5->session); | ||
171 | |||
172 | if (rxk5->addresses) { | ||
173 | for (loop = rxk5->n_addresses - 1; loop >= 0; loop--) | ||
174 | rxrpc_free_krb5_tagged(&rxk5->addresses[loop]); | ||
175 | kfree(rxk5->addresses); | ||
176 | } | ||
177 | if (rxk5->authdata) { | ||
178 | for (loop = rxk5->n_authdata - 1; loop >= 0; loop--) | ||
179 | rxrpc_free_krb5_tagged(&rxk5->authdata[loop]); | ||
180 | kfree(rxk5->authdata); | ||
181 | } | ||
182 | |||
183 | kfree(rxk5->ticket); | ||
184 | kfree(rxk5->ticket2); | ||
185 | kfree(rxk5); | ||
186 | } | ||
187 | |||
188 | /* | ||
189 | * extract a krb5 principal | ||
190 | */ | ||
191 | static int rxrpc_krb5_decode_principal(struct krb5_principal *princ, | ||
192 | const __be32 **_xdr, | ||
193 | unsigned *_toklen) | ||
194 | { | ||
195 | const __be32 *xdr = *_xdr; | ||
196 | unsigned toklen = *_toklen, n_parts, loop, tmp; | ||
197 | |||
198 | /* there must be at least one name, and at least #names+1 length | ||
199 | * words */ | ||
200 | if (toklen <= 12) | ||
201 | return -EINVAL; | ||
202 | |||
203 | _enter(",{%x,%x,%x},%u", | ||
204 | ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), toklen); | ||
205 | |||
206 | n_parts = ntohl(*xdr++); | ||
207 | toklen -= 4; | ||
208 | if (n_parts <= 0 || n_parts > AFSTOKEN_K5_COMPONENTS_MAX) | ||
209 | return -EINVAL; | ||
210 | princ->n_name_parts = n_parts; | ||
211 | |||
212 | if (toklen <= (n_parts + 1) * 4) | ||
213 | return -EINVAL; | ||
214 | |||
215 | princ->name_parts = kcalloc(sizeof(char *), n_parts, GFP_KERNEL); | ||
216 | if (!princ->name_parts) | ||
217 | return -ENOMEM; | ||
218 | |||
219 | for (loop = 0; loop < n_parts; loop++) { | ||
220 | if (toklen < 4) | ||
221 | return -EINVAL; | ||
222 | tmp = ntohl(*xdr++); | ||
223 | toklen -= 4; | ||
224 | if (tmp <= 0 || tmp > AFSTOKEN_STRING_MAX) | ||
225 | return -EINVAL; | ||
226 | if (tmp > toklen) | ||
227 | return -EINVAL; | ||
228 | princ->name_parts[loop] = kmalloc(tmp + 1, GFP_KERNEL); | ||
229 | if (!princ->name_parts[loop]) | ||
230 | return -ENOMEM; | ||
231 | memcpy(princ->name_parts[loop], xdr, tmp); | ||
232 | princ->name_parts[loop][tmp] = 0; | ||
233 | tmp = (tmp + 3) & ~3; | ||
234 | toklen -= tmp; | ||
235 | xdr += tmp >> 2; | ||
236 | } | ||
237 | |||
238 | if (toklen < 4) | ||
239 | return -EINVAL; | ||
240 | tmp = ntohl(*xdr++); | ||
241 | toklen -= 4; | ||
242 | if (tmp <= 0 || tmp > AFSTOKEN_K5_REALM_MAX) | ||
243 | return -EINVAL; | ||
244 | if (tmp > toklen) | ||
245 | return -EINVAL; | ||
246 | princ->realm = kmalloc(tmp + 1, GFP_KERNEL); | ||
247 | if (!princ->realm) | ||
248 | return -ENOMEM; | ||
249 | memcpy(princ->realm, xdr, tmp); | ||
250 | princ->realm[tmp] = 0; | ||
251 | tmp = (tmp + 3) & ~3; | ||
252 | toklen -= tmp; | ||
253 | xdr += tmp >> 2; | ||
254 | |||
255 | _debug("%s/...@%s", princ->name_parts[0], princ->realm); | ||
256 | |||
257 | *_xdr = xdr; | ||
258 | *_toklen = toklen; | ||
259 | _leave(" = 0 [toklen=%u]", toklen); | ||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * extract a piece of krb5 tagged data | ||
265 | */ | ||
266 | static int rxrpc_krb5_decode_tagged_data(struct krb5_tagged_data *td, | ||
267 | size_t max_data_size, | ||
268 | const __be32 **_xdr, | ||
269 | unsigned *_toklen) | ||
270 | { | ||
271 | const __be32 *xdr = *_xdr; | ||
272 | unsigned toklen = *_toklen, len; | ||
273 | |||
274 | /* there must be at least one tag and one length word */ | ||
275 | if (toklen <= 8) | ||
276 | return -EINVAL; | ||
277 | |||
278 | _enter(",%zu,{%x,%x},%u", | ||
279 | max_data_size, ntohl(xdr[0]), ntohl(xdr[1]), toklen); | ||
280 | |||
281 | td->tag = ntohl(*xdr++); | ||
282 | len = ntohl(*xdr++); | ||
283 | toklen -= 8; | ||
284 | if (len > max_data_size) | ||
285 | return -EINVAL; | ||
286 | td->data_len = len; | ||
287 | |||
288 | if (len > 0) { | ||
289 | td->data = kmalloc(len, GFP_KERNEL); | ||
290 | if (!td->data) | ||
291 | return -ENOMEM; | ||
292 | memcpy(td->data, xdr, len); | ||
293 | len = (len + 3) & ~3; | ||
294 | toklen -= len; | ||
295 | xdr += len >> 2; | ||
296 | } | ||
297 | |||
298 | _debug("tag %x len %x", td->tag, td->data_len); | ||
299 | |||
300 | *_xdr = xdr; | ||
301 | *_toklen = toklen; | ||
302 | _leave(" = 0 [toklen=%u]", toklen); | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * extract an array of tagged data | ||
308 | */ | ||
309 | static int rxrpc_krb5_decode_tagged_array(struct krb5_tagged_data **_td, | ||
310 | u8 *_n_elem, | ||
311 | u8 max_n_elem, | ||
312 | size_t max_elem_size, | ||
313 | const __be32 **_xdr, | ||
314 | unsigned *_toklen) | ||
315 | { | ||
316 | struct krb5_tagged_data *td; | ||
317 | const __be32 *xdr = *_xdr; | ||
318 | unsigned toklen = *_toklen, n_elem, loop; | ||
319 | int ret; | ||
320 | |||
321 | /* there must be at least one count */ | ||
322 | if (toklen < 4) | ||
323 | return -EINVAL; | ||
324 | |||
325 | _enter(",,%u,%zu,{%x},%u", | ||
326 | max_n_elem, max_elem_size, ntohl(xdr[0]), toklen); | ||
327 | |||
328 | n_elem = ntohl(*xdr++); | ||
329 | toklen -= 4; | ||
330 | if (n_elem < 0 || n_elem > max_n_elem) | ||
331 | return -EINVAL; | ||
332 | *_n_elem = n_elem; | ||
333 | if (n_elem > 0) { | ||
334 | if (toklen <= (n_elem + 1) * 4) | ||
335 | return -EINVAL; | ||
336 | |||
337 | _debug("n_elem %d", n_elem); | ||
338 | |||
339 | td = kcalloc(sizeof(struct krb5_tagged_data), n_elem, | ||
340 | GFP_KERNEL); | ||
341 | if (!td) | ||
342 | return -ENOMEM; | ||
343 | *_td = td; | ||
344 | |||
345 | for (loop = 0; loop < n_elem; loop++) { | ||
346 | ret = rxrpc_krb5_decode_tagged_data(&td[loop], | ||
347 | max_elem_size, | ||
348 | &xdr, &toklen); | ||
349 | if (ret < 0) | ||
350 | return ret; | ||
351 | } | ||
352 | } | ||
353 | |||
354 | *_xdr = xdr; | ||
355 | *_toklen = toklen; | ||
356 | _leave(" = 0 [toklen=%u]", toklen); | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | /* | ||
361 | * extract a krb5 ticket | ||
362 | */ | ||
363 | static int rxrpc_krb5_decode_ticket(u8 **_ticket, uint16_t *_tktlen, | ||
364 | const __be32 **_xdr, unsigned *_toklen) | ||
365 | { | ||
366 | const __be32 *xdr = *_xdr; | ||
367 | unsigned toklen = *_toklen, len; | ||
368 | |||
369 | /* there must be at least one length word */ | ||
370 | if (toklen <= 4) | ||
371 | return -EINVAL; | ||
372 | |||
373 | _enter(",{%x},%u", ntohl(xdr[0]), toklen); | ||
374 | |||
375 | len = ntohl(*xdr++); | ||
376 | toklen -= 4; | ||
377 | if (len > AFSTOKEN_K5_TIX_MAX) | ||
378 | return -EINVAL; | ||
379 | *_tktlen = len; | ||
380 | |||
381 | _debug("ticket len %u", len); | ||
382 | |||
383 | if (len > 0) { | ||
384 | *_ticket = kmalloc(len, GFP_KERNEL); | ||
385 | if (!*_ticket) | ||
386 | return -ENOMEM; | ||
387 | memcpy(*_ticket, xdr, len); | ||
388 | len = (len + 3) & ~3; | ||
389 | toklen -= len; | ||
390 | xdr += len >> 2; | ||
391 | } | ||
392 | |||
393 | *_xdr = xdr; | ||
394 | *_toklen = toklen; | ||
395 | _leave(" = 0 [toklen=%u]", toklen); | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | /* | ||
400 | * parse an RxK5 type XDR format token | ||
401 | * - the caller guarantees we have at least 4 words | ||
402 | */ | ||
403 | static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr, | ||
404 | unsigned toklen) | ||
405 | { | ||
406 | struct rxrpc_key_token *token, **pptoken; | ||
407 | struct rxk5_key *rxk5; | ||
408 | const __be32 *end_xdr = xdr + (toklen >> 2); | ||
409 | int ret; | ||
410 | |||
411 | _enter(",{%x,%x,%x,%x},%u", | ||
412 | ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), | ||
413 | toklen); | ||
414 | |||
415 | /* reserve some payload space for this subkey - the length of the token | ||
416 | * is a reasonable approximation */ | ||
417 | ret = key_payload_reserve(key, key->datalen + toklen); | ||
418 | if (ret < 0) | ||
419 | return ret; | ||
420 | |||
421 | token = kzalloc(sizeof(*token), GFP_KERNEL); | ||
422 | if (!token) | ||
423 | return -ENOMEM; | ||
424 | |||
425 | rxk5 = kzalloc(sizeof(*rxk5), GFP_KERNEL); | ||
426 | if (!rxk5) { | ||
427 | kfree(token); | ||
428 | return -ENOMEM; | ||
429 | } | ||
430 | |||
431 | token->security_index = RXRPC_SECURITY_RXK5; | ||
432 | token->k5 = rxk5; | ||
433 | |||
434 | /* extract the principals */ | ||
435 | ret = rxrpc_krb5_decode_principal(&rxk5->client, &xdr, &toklen); | ||
436 | if (ret < 0) | ||
437 | goto error; | ||
438 | ret = rxrpc_krb5_decode_principal(&rxk5->server, &xdr, &toklen); | ||
439 | if (ret < 0) | ||
440 | goto error; | ||
441 | |||
442 | /* extract the session key and the encoding type (the tag field -> | ||
443 | * ENCTYPE_xxx) */ | ||
444 | ret = rxrpc_krb5_decode_tagged_data(&rxk5->session, AFSTOKEN_DATA_MAX, | ||
445 | &xdr, &toklen); | ||
446 | if (ret < 0) | ||
447 | goto error; | ||
448 | |||
449 | if (toklen < 4 * 8 + 2 * 4) | ||
450 | goto inval; | ||
451 | rxk5->authtime = be64_to_cpup((const __be64 *) xdr); | ||
452 | xdr += 2; | ||
453 | rxk5->starttime = be64_to_cpup((const __be64 *) xdr); | ||
454 | xdr += 2; | ||
455 | rxk5->endtime = be64_to_cpup((const __be64 *) xdr); | ||
456 | xdr += 2; | ||
457 | rxk5->renew_till = be64_to_cpup((const __be64 *) xdr); | ||
458 | xdr += 2; | ||
459 | rxk5->is_skey = ntohl(*xdr++); | ||
460 | rxk5->flags = ntohl(*xdr++); | ||
461 | toklen -= 4 * 8 + 2 * 4; | ||
462 | |||
463 | _debug("times: a=%llx s=%llx e=%llx rt=%llx", | ||
464 | rxk5->authtime, rxk5->starttime, rxk5->endtime, | ||
465 | rxk5->renew_till); | ||
466 | _debug("is_skey=%x flags=%x", rxk5->is_skey, rxk5->flags); | ||
467 | |||
468 | /* extract the permitted client addresses */ | ||
469 | ret = rxrpc_krb5_decode_tagged_array(&rxk5->addresses, | ||
470 | &rxk5->n_addresses, | ||
471 | AFSTOKEN_K5_ADDRESSES_MAX, | ||
472 | AFSTOKEN_DATA_MAX, | ||
473 | &xdr, &toklen); | ||
474 | if (ret < 0) | ||
475 | goto error; | ||
476 | |||
477 | ASSERTCMP((end_xdr - xdr) << 2, ==, toklen); | ||
478 | |||
479 | /* extract the tickets */ | ||
480 | ret = rxrpc_krb5_decode_ticket(&rxk5->ticket, &rxk5->ticket_len, | ||
481 | &xdr, &toklen); | ||
482 | if (ret < 0) | ||
483 | goto error; | ||
484 | ret = rxrpc_krb5_decode_ticket(&rxk5->ticket2, &rxk5->ticket2_len, | ||
485 | &xdr, &toklen); | ||
486 | if (ret < 0) | ||
487 | goto error; | ||
488 | |||
489 | ASSERTCMP((end_xdr - xdr) << 2, ==, toklen); | ||
490 | |||
491 | /* extract the typed auth data */ | ||
492 | ret = rxrpc_krb5_decode_tagged_array(&rxk5->authdata, | ||
493 | &rxk5->n_authdata, | ||
494 | AFSTOKEN_K5_AUTHDATA_MAX, | ||
495 | AFSTOKEN_BDATALN_MAX, | ||
496 | &xdr, &toklen); | ||
497 | if (ret < 0) | ||
498 | goto error; | ||
499 | |||
500 | ASSERTCMP((end_xdr - xdr) << 2, ==, toklen); | ||
501 | |||
502 | if (toklen != 0) | ||
503 | goto inval; | ||
504 | |||
505 | /* attach the payload to the key */ | ||
506 | for (pptoken = (struct rxrpc_key_token **)&key->payload.data; | ||
507 | *pptoken; | ||
508 | pptoken = &(*pptoken)->next) | ||
509 | continue; | ||
510 | *pptoken = token; | ||
134 | if (token->kad->expiry < key->expiry) | 511 | if (token->kad->expiry < key->expiry) |
135 | key->expiry = token->kad->expiry; | 512 | key->expiry = token->kad->expiry; |
136 | 513 | ||
137 | _leave(" = 0"); | 514 | _leave(" = 0"); |
138 | return 0; | 515 | return 0; |
516 | |||
517 | inval: | ||
518 | ret = -EINVAL; | ||
519 | error: | ||
520 | rxrpc_rxk5_free(rxk5); | ||
521 | kfree(token); | ||
522 | _leave(" = %d", ret); | ||
523 | return ret; | ||
139 | } | 524 | } |
140 | 525 | ||
141 | /* | 526 | /* |
@@ -228,6 +613,8 @@ static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datal | |||
228 | sec_ix = ntohl(*xdr++); | 613 | sec_ix = ntohl(*xdr++); |
229 | toklen -= 4; | 614 | toklen -= 4; |
230 | 615 | ||
616 | _debug("TOKEN type=%u [%p-%p]", sec_ix, xdr, token); | ||
617 | |||
231 | switch (sec_ix) { | 618 | switch (sec_ix) { |
232 | case RXRPC_SECURITY_RXKAD: | 619 | case RXRPC_SECURITY_RXKAD: |
233 | ret = rxrpc_instantiate_xdr_rxkad(key, xdr, toklen); | 620 | ret = rxrpc_instantiate_xdr_rxkad(key, xdr, toklen); |
@@ -235,6 +622,12 @@ static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datal | |||
235 | goto error; | 622 | goto error; |
236 | break; | 623 | break; |
237 | 624 | ||
625 | case RXRPC_SECURITY_RXK5: | ||
626 | ret = rxrpc_instantiate_xdr_rxk5(key, xdr, toklen); | ||
627 | if (ret != 0) | ||
628 | goto error; | ||
629 | break; | ||
630 | |||
238 | default: | 631 | default: |
239 | ret = -EPROTONOSUPPORT; | 632 | ret = -EPROTONOSUPPORT; |
240 | goto error; | 633 | goto error; |
@@ -412,6 +805,10 @@ static void rxrpc_destroy(struct key *key) | |||
412 | case RXRPC_SECURITY_RXKAD: | 805 | case RXRPC_SECURITY_RXKAD: |
413 | kfree(token->kad); | 806 | kfree(token->kad); |
414 | break; | 807 | break; |
808 | case RXRPC_SECURITY_RXK5: | ||
809 | if (token->k5) | ||
810 | rxrpc_rxk5_free(token->k5); | ||
811 | break; | ||
415 | default: | 812 | default: |
416 | printk(KERN_ERR "Unknown token type %x on rxrpc key\n", | 813 | printk(KERN_ERR "Unknown token type %x on rxrpc key\n", |
417 | token->security_index); | 814 | token->security_index); |
@@ -602,10 +999,13 @@ EXPORT_SYMBOL(rxrpc_get_null_key); | |||
602 | static long rxrpc_read(const struct key *key, | 999 | static long rxrpc_read(const struct key *key, |
603 | char __user *buffer, size_t buflen) | 1000 | char __user *buffer, size_t buflen) |
604 | { | 1001 | { |
605 | struct rxrpc_key_token *token; | 1002 | const struct rxrpc_key_token *token; |
606 | size_t size, toksize; | 1003 | const struct krb5_principal *princ; |
607 | __be32 __user *xdr; | 1004 | size_t size; |
608 | u32 cnlen, tktlen, ntoks, zero; | 1005 | __be32 __user *xdr, *oldxdr; |
1006 | u32 cnlen, toksize, ntoks, tok, zero; | ||
1007 | u16 toksizes[AFSTOKEN_MAX]; | ||
1008 | int loop; | ||
609 | 1009 | ||
610 | _enter(""); | 1010 | _enter(""); |
611 | 1011 | ||
@@ -614,28 +1014,68 @@ static long rxrpc_read(const struct key *key, | |||
614 | return -EOPNOTSUPP; | 1014 | return -EOPNOTSUPP; |
615 | cnlen = strlen(key->description + 4); | 1015 | cnlen = strlen(key->description + 4); |
616 | 1016 | ||
1017 | #define RND(X) (((X) + 3) & ~3) | ||
1018 | |||
617 | /* AFS keys we return in XDR form, so we need to work out the size of | 1019 | /* AFS keys we return in XDR form, so we need to work out the size of |
618 | * the XDR */ | 1020 | * the XDR */ |
619 | size = 2 * 4; /* flags, cellname len */ | 1021 | size = 2 * 4; /* flags, cellname len */ |
620 | size += (cnlen + 3) & ~3; /* cellname */ | 1022 | size += RND(cnlen); /* cellname */ |
621 | size += 1 * 4; /* token count */ | 1023 | size += 1 * 4; /* token count */ |
622 | 1024 | ||
623 | ntoks = 0; | 1025 | ntoks = 0; |
624 | for (token = key->payload.data; token; token = token->next) { | 1026 | for (token = key->payload.data; token; token = token->next) { |
1027 | toksize = 4; /* sec index */ | ||
1028 | |||
625 | switch (token->security_index) { | 1029 | switch (token->security_index) { |
626 | case RXRPC_SECURITY_RXKAD: | 1030 | case RXRPC_SECURITY_RXKAD: |
627 | size += 2 * 4; /* length, security index (switch ID) */ | 1031 | toksize += 8 * 4; /* viceid, kvno, key*2, begin, |
628 | size += 8 * 4; /* viceid, kvno, key*2, begin, end, | 1032 | * end, primary, tktlen */ |
629 | * primary, tktlen */ | 1033 | toksize += RND(token->kad->ticket_len); |
630 | size += (token->kad->ticket_len + 3) & ~3; /* ticket */ | ||
631 | ntoks++; | ||
632 | break; | 1034 | break; |
633 | 1035 | ||
634 | default: /* can't encode */ | 1036 | case RXRPC_SECURITY_RXK5: |
1037 | princ = &token->k5->client; | ||
1038 | toksize += 4 + princ->n_name_parts * 4; | ||
1039 | for (loop = 0; loop < princ->n_name_parts; loop++) | ||
1040 | toksize += RND(strlen(princ->name_parts[loop])); | ||
1041 | toksize += 4 + RND(strlen(princ->realm)); | ||
1042 | |||
1043 | princ = &token->k5->server; | ||
1044 | toksize += 4 + princ->n_name_parts * 4; | ||
1045 | for (loop = 0; loop < princ->n_name_parts; loop++) | ||
1046 | toksize += RND(strlen(princ->name_parts[loop])); | ||
1047 | toksize += 4 + RND(strlen(princ->realm)); | ||
1048 | |||
1049 | toksize += 8 + RND(token->k5->session.data_len); | ||
1050 | |||
1051 | toksize += 4 * 8 + 2 * 4; | ||
1052 | |||
1053 | toksize += 4 + token->k5->n_addresses * 8; | ||
1054 | for (loop = 0; loop < token->k5->n_addresses; loop++) | ||
1055 | toksize += RND(token->k5->addresses[loop].data_len); | ||
1056 | |||
1057 | toksize += 4 + RND(token->k5->ticket_len); | ||
1058 | toksize += 4 + RND(token->k5->ticket2_len); | ||
1059 | |||
1060 | toksize += 4 + token->k5->n_authdata * 8; | ||
1061 | for (loop = 0; loop < token->k5->n_authdata; loop++) | ||
1062 | toksize += RND(token->k5->authdata[loop].data_len); | ||
635 | break; | 1063 | break; |
1064 | |||
1065 | default: /* we have a ticket we can't encode */ | ||
1066 | BUG(); | ||
1067 | continue; | ||
636 | } | 1068 | } |
1069 | |||
1070 | _debug("token[%u]: toksize=%u", ntoks, toksize); | ||
1071 | ASSERTCMP(toksize, <=, AFSTOKEN_LENGTH_MAX); | ||
1072 | |||
1073 | toksizes[ntoks++] = toksize; | ||
1074 | size += toksize + 4; /* each token has a length word */ | ||
637 | } | 1075 | } |
638 | 1076 | ||
1077 | #undef RND | ||
1078 | |||
639 | if (!buffer || buflen < size) | 1079 | if (!buffer || buflen < size) |
640 | return size; | 1080 | return size; |
641 | 1081 | ||
@@ -647,52 +1087,109 @@ static long rxrpc_read(const struct key *key, | |||
647 | if (put_user(y, xdr++) < 0) \ | 1087 | if (put_user(y, xdr++) < 0) \ |
648 | goto fault; \ | 1088 | goto fault; \ |
649 | } while(0) | 1089 | } while(0) |
1090 | #define ENCODE_DATA(l, s) \ | ||
1091 | do { \ | ||
1092 | u32 _l = (l); \ | ||
1093 | ENCODE(l); \ | ||
1094 | if (copy_to_user(xdr, (s), _l) != 0) \ | ||
1095 | goto fault; \ | ||
1096 | if (_l & 3 && \ | ||
1097 | copy_to_user((u8 *)xdr + _l, &zero, 4 - (_l & 3)) != 0) \ | ||
1098 | goto fault; \ | ||
1099 | xdr += (_l + 3) >> 2; \ | ||
1100 | } while(0) | ||
1101 | #define ENCODE64(x) \ | ||
1102 | do { \ | ||
1103 | __be64 y = cpu_to_be64(x); \ | ||
1104 | if (copy_to_user(xdr, &y, 8) != 0) \ | ||
1105 | goto fault; \ | ||
1106 | xdr += 8 >> 2; \ | ||
1107 | } while(0) | ||
1108 | #define ENCODE_STR(s) \ | ||
1109 | do { \ | ||
1110 | const char *_s = (s); \ | ||
1111 | ENCODE_DATA(strlen(_s), _s); \ | ||
1112 | } while(0) | ||
650 | 1113 | ||
651 | ENCODE(0); /* flags */ | 1114 | ENCODE(0); /* flags */ |
652 | ENCODE(cnlen); /* cellname length */ | 1115 | ENCODE_DATA(cnlen, key->description + 4); /* cellname */ |
653 | if (copy_to_user(xdr, key->description + 4, cnlen) != 0) | 1116 | ENCODE(ntoks); |
654 | goto fault; | ||
655 | if (cnlen & 3 && | ||
656 | copy_to_user((u8 *)xdr + cnlen, &zero, 4 - (cnlen & 3)) != 0) | ||
657 | goto fault; | ||
658 | xdr += (cnlen + 3) >> 2; | ||
659 | ENCODE(ntoks); /* token count */ | ||
660 | 1117 | ||
1118 | tok = 0; | ||
661 | for (token = key->payload.data; token; token = token->next) { | 1119 | for (token = key->payload.data; token; token = token->next) { |
662 | toksize = 1 * 4; /* sec index */ | 1120 | toksize = toksizes[tok++]; |
1121 | ENCODE(toksize); | ||
1122 | oldxdr = xdr; | ||
1123 | ENCODE(token->security_index); | ||
663 | 1124 | ||
664 | switch (token->security_index) { | 1125 | switch (token->security_index) { |
665 | case RXRPC_SECURITY_RXKAD: | 1126 | case RXRPC_SECURITY_RXKAD: |
666 | toksize += 8 * 4; | ||
667 | toksize += (token->kad->ticket_len + 3) & ~3; | ||
668 | ENCODE(toksize); | ||
669 | ENCODE(token->security_index); | ||
670 | ENCODE(token->kad->vice_id); | 1127 | ENCODE(token->kad->vice_id); |
671 | ENCODE(token->kad->kvno); | 1128 | ENCODE(token->kad->kvno); |
672 | if (copy_to_user(xdr, token->kad->session_key, 8) != 0) | 1129 | ENCODE_DATA(8, token->kad->session_key); |
673 | goto fault; | ||
674 | xdr += 8 >> 2; | ||
675 | ENCODE(token->kad->start); | 1130 | ENCODE(token->kad->start); |
676 | ENCODE(token->kad->expiry); | 1131 | ENCODE(token->kad->expiry); |
677 | ENCODE(token->kad->primary_flag); | 1132 | ENCODE(token->kad->primary_flag); |
678 | tktlen = token->kad->ticket_len; | 1133 | ENCODE_DATA(token->kad->ticket_len, token->kad->ticket); |
679 | ENCODE(tktlen); | 1134 | break; |
680 | if (copy_to_user(xdr, token->kad->ticket, tktlen) != 0) | 1135 | |
681 | goto fault; | 1136 | case RXRPC_SECURITY_RXK5: |
682 | if (tktlen & 3 && | 1137 | princ = &token->k5->client; |
683 | copy_to_user((u8 *)xdr + tktlen, &zero, | 1138 | ENCODE(princ->n_name_parts); |
684 | 4 - (tktlen & 3)) != 0) | 1139 | for (loop = 0; loop < princ->n_name_parts; loop++) |
685 | goto fault; | 1140 | ENCODE_STR(princ->name_parts[loop]); |
686 | xdr += (tktlen + 3) >> 2; | 1141 | ENCODE_STR(princ->realm); |
1142 | |||
1143 | princ = &token->k5->server; | ||
1144 | ENCODE(princ->n_name_parts); | ||
1145 | for (loop = 0; loop < princ->n_name_parts; loop++) | ||
1146 | ENCODE_STR(princ->name_parts[loop]); | ||
1147 | ENCODE_STR(princ->realm); | ||
1148 | |||
1149 | ENCODE(token->k5->session.tag); | ||
1150 | ENCODE_DATA(token->k5->session.data_len, | ||
1151 | token->k5->session.data); | ||
1152 | |||
1153 | ENCODE64(token->k5->authtime); | ||
1154 | ENCODE64(token->k5->starttime); | ||
1155 | ENCODE64(token->k5->endtime); | ||
1156 | ENCODE64(token->k5->renew_till); | ||
1157 | ENCODE(token->k5->is_skey); | ||
1158 | ENCODE(token->k5->flags); | ||
1159 | |||
1160 | ENCODE(token->k5->n_addresses); | ||
1161 | for (loop = 0; loop < token->k5->n_addresses; loop++) { | ||
1162 | ENCODE(token->k5->addresses[loop].tag); | ||
1163 | ENCODE_DATA(token->k5->addresses[loop].data_len, | ||
1164 | token->k5->addresses[loop].data); | ||
1165 | } | ||
1166 | |||
1167 | ENCODE_DATA(token->k5->ticket_len, token->k5->ticket); | ||
1168 | ENCODE_DATA(token->k5->ticket2_len, token->k5->ticket2); | ||
1169 | |||
1170 | ENCODE(token->k5->n_authdata); | ||
1171 | for (loop = 0; loop < token->k5->n_authdata; loop++) { | ||
1172 | ENCODE(token->k5->authdata[loop].tag); | ||
1173 | ENCODE_DATA(token->k5->authdata[loop].data_len, | ||
1174 | token->k5->authdata[loop].data); | ||
1175 | } | ||
687 | break; | 1176 | break; |
688 | 1177 | ||
689 | default: | 1178 | default: |
1179 | BUG(); | ||
690 | break; | 1180 | break; |
691 | } | 1181 | } |
1182 | |||
1183 | ASSERTCMP((unsigned long)xdr - (unsigned long)oldxdr, ==, | ||
1184 | toksize); | ||
692 | } | 1185 | } |
693 | 1186 | ||
1187 | #undef ENCODE_STR | ||
1188 | #undef ENCODE_DATA | ||
1189 | #undef ENCODE64 | ||
694 | #undef ENCODE | 1190 | #undef ENCODE |
695 | 1191 | ||
1192 | ASSERTCMP(tok, ==, ntoks); | ||
696 | ASSERTCMP((char __user *) xdr - buffer, ==, size); | 1193 | ASSERTCMP((char __user *) xdr - buffer, ==, size); |
697 | _leave(" = %zu", size); | 1194 | _leave(" = %zu", size); |
698 | return size; | 1195 | return size; |