diff options
Diffstat (limited to 'net/sunrpc/auth_gss/gss_krb5_wrap.c')
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_wrap.c | 61 |
1 files changed, 45 insertions, 16 deletions
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index 38f388c39dce..107c4528654f 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c | |||
@@ -381,21 +381,53 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf) | |||
381 | } | 381 | } |
382 | 382 | ||
383 | /* | 383 | /* |
384 | * We cannot currently handle tokens with rotated data. We need a | 384 | * We can shift data by up to LOCAL_BUF_LEN bytes in a pass. If we need |
385 | * generalized routine to rotate the data in place. It is anticipated | 385 | * to do more than that, we shift repeatedly. Kevin Coffman reports |
386 | * that we won't encounter rotated data in the general case. | 386 | * seeing 28 bytes as the value used by Microsoft clients and servers |
387 | * with AES, so this constant is chosen to allow handling 28 in one pass | ||
388 | * without using too much stack space. | ||
389 | * | ||
390 | * If that proves to a problem perhaps we could use a more clever | ||
391 | * algorithm. | ||
387 | */ | 392 | */ |
388 | static u32 | 393 | #define LOCAL_BUF_LEN 32u |
389 | rotate_left(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf, u16 rrc) | 394 | |
395 | static void rotate_buf_a_little(struct xdr_buf *buf, unsigned int shift) | ||
390 | { | 396 | { |
391 | unsigned int realrrc = rrc % (buf->len - offset - GSS_KRB5_TOK_HDR_LEN); | 397 | char head[LOCAL_BUF_LEN]; |
398 | char tmp[LOCAL_BUF_LEN]; | ||
399 | unsigned int this_len, i; | ||
400 | |||
401 | BUG_ON(shift > LOCAL_BUF_LEN); | ||
392 | 402 | ||
393 | if (realrrc == 0) | 403 | read_bytes_from_xdr_buf(buf, 0, head, shift); |
394 | return 0; | 404 | for (i = 0; i + shift < buf->len; i += LOCAL_BUF_LEN) { |
405 | this_len = min(LOCAL_BUF_LEN, buf->len - (i + shift)); | ||
406 | read_bytes_from_xdr_buf(buf, i+shift, tmp, this_len); | ||
407 | write_bytes_to_xdr_buf(buf, i, tmp, this_len); | ||
408 | } | ||
409 | write_bytes_to_xdr_buf(buf, buf->len - shift, head, shift); | ||
410 | } | ||
395 | 411 | ||
396 | dprintk("%s: cannot process token with rotated data: " | 412 | static void _rotate_left(struct xdr_buf *buf, unsigned int shift) |
397 | "rrc %u, realrrc %u\n", __func__, rrc, realrrc); | 413 | { |
398 | return 1; | 414 | int shifted = 0; |
415 | int this_shift; | ||
416 | |||
417 | shift %= buf->len; | ||
418 | while (shifted < shift) { | ||
419 | this_shift = min(shift - shifted, LOCAL_BUF_LEN); | ||
420 | rotate_buf_a_little(buf, this_shift); | ||
421 | shifted += this_shift; | ||
422 | } | ||
423 | } | ||
424 | |||
425 | static void rotate_left(u32 base, struct xdr_buf *buf, unsigned int shift) | ||
426 | { | ||
427 | struct xdr_buf subbuf; | ||
428 | |||
429 | xdr_buf_subsegment(buf, &subbuf, base, buf->len - base); | ||
430 | _rotate_left(&subbuf, shift); | ||
399 | } | 431 | } |
400 | 432 | ||
401 | static u32 | 433 | static u32 |
@@ -495,11 +527,8 @@ gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf) | |||
495 | 527 | ||
496 | seqnum = be64_to_cpup((__be64 *)(ptr + 8)); | 528 | seqnum = be64_to_cpup((__be64 *)(ptr + 8)); |
497 | 529 | ||
498 | if (rrc != 0) { | 530 | if (rrc != 0) |
499 | err = rotate_left(kctx, offset, buf, rrc); | 531 | rotate_left(offset + 16, buf, rrc); |
500 | if (err) | ||
501 | return GSS_S_FAILURE; | ||
502 | } | ||
503 | 532 | ||
504 | err = (*kctx->gk5e->decrypt_v2)(kctx, offset, buf, | 533 | err = (*kctx->gk5e->decrypt_v2)(kctx, offset, buf, |
505 | &headskip, &tailskip); | 534 | &headskip, &tailskip); |