| 1 | /* |
|---|
| 2 | * GSS token handling routines. |
|---|
| 3 | * |
|---|
| 4 | * Higher-level wrappers around the low-level token handling routines that |
|---|
| 5 | * apply integrity and privacy protection to the token data before sending. |
|---|
| 6 | * token_send_priv and token_recv_priv are similar to token_send and |
|---|
| 7 | * token_recv except that they also take a GSS-API context and a GSS-API major |
|---|
| 8 | * and minor status to report errors. |
|---|
| 9 | * |
|---|
| 10 | * Originally written by Anton Ushakov |
|---|
| 11 | * Extensive modifications by Russ Allbery <rra@stanford.edu> |
|---|
| 12 | * Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
|---|
| 13 | * Board of Trustees, Leland Stanford Jr. University |
|---|
| 14 | * |
|---|
| 15 | * See README for licensing terms. |
|---|
| 16 | */ |
|---|
| 17 | |
|---|
| 18 | #include <config.h> |
|---|
| 19 | #include <portable/system.h> |
|---|
| 20 | #include <portable/gssapi.h> |
|---|
| 21 | |
|---|
| 22 | #include <util/util.h> |
|---|
| 23 | |
|---|
| 24 | /* |
|---|
| 25 | * If we're running the test suite, call testing versions of the token |
|---|
| 26 | * functions. |
|---|
| 27 | */ |
|---|
| 28 | #if TESTING |
|---|
| 29 | # define token_send fake_token_send |
|---|
| 30 | # define token_recv fake_token_recv |
|---|
| 31 | enum token_status token_send(int, int, gss_buffer_t); |
|---|
| 32 | enum token_status token_recv(int, int *, gss_buffer_t, size_t); |
|---|
| 33 | #endif |
|---|
| 34 | |
|---|
| 35 | |
|---|
| 36 | /* |
|---|
| 37 | * Wraps, encrypts, and sends a data payload token. Takes the file descriptor |
|---|
| 38 | * to send to, the GSS-API context, the flags to send with the token, the |
|---|
| 39 | * token, and the status variables. Returns TOKEN_OK on success and |
|---|
| 40 | * TOKEN_FAIL_SYSTEM or TOKEN_FAIL_GSSAPI on failure. If the latter is |
|---|
| 41 | * returned, the major and minor status variables will be set to something |
|---|
| 42 | * useful. |
|---|
| 43 | * |
|---|
| 44 | * As a hack to support remctl v1, look to see if the flags includes |
|---|
| 45 | * TOKEN_SEND_MIC and don't include TOKEN_PROTOCOL. If so, expect the remote |
|---|
| 46 | * side to reply with a MIC, which we then verify. |
|---|
| 47 | */ |
|---|
| 48 | enum token_status |
|---|
| 49 | token_send_priv(int fd, gss_ctx_id_t ctx, int flags, gss_buffer_t tok, |
|---|
| 50 | OM_uint32 *major, OM_uint32 *minor) |
|---|
| 51 | { |
|---|
| 52 | gss_buffer_desc out, mic; |
|---|
| 53 | int state, micflags; |
|---|
| 54 | enum token_status status; |
|---|
| 55 | |
|---|
| 56 | if (tok->length > TOKEN_MAX_DATA) |
|---|
| 57 | return TOKEN_FAIL_LARGE; |
|---|
| 58 | *major = gss_wrap(minor, ctx, 1, GSS_C_QOP_DEFAULT, tok, &state, &out); |
|---|
| 59 | if (*major != GSS_S_COMPLETE) |
|---|
| 60 | return TOKEN_FAIL_GSSAPI; |
|---|
| 61 | status = token_send(fd, flags, &out); |
|---|
| 62 | gss_release_buffer(minor, &out); |
|---|
| 63 | if (status != TOKEN_OK) |
|---|
| 64 | return status; |
|---|
| 65 | if ((flags & TOKEN_SEND_MIC) && !(flags & TOKEN_PROTOCOL)) { |
|---|
| 66 | status = token_recv(fd, &micflags, &mic, 10 * 1024); |
|---|
| 67 | if (status != TOKEN_OK) |
|---|
| 68 | return status; |
|---|
| 69 | if (micflags != TOKEN_MIC) { |
|---|
| 70 | gss_release_buffer(minor, &mic); |
|---|
| 71 | return TOKEN_FAIL_INVALID; |
|---|
| 72 | } |
|---|
| 73 | *major = gss_verify_mic(minor, ctx, tok, &mic, NULL); |
|---|
| 74 | if (*major != GSS_S_COMPLETE) { |
|---|
| 75 | gss_release_buffer(minor, &mic); |
|---|
| 76 | return TOKEN_FAIL_GSSAPI; |
|---|
| 77 | } |
|---|
| 78 | gss_release_buffer(minor, &mic); |
|---|
| 79 | } |
|---|
| 80 | return TOKEN_OK; |
|---|
| 81 | } |
|---|
| 82 | |
|---|
| 83 | |
|---|
| 84 | /* |
|---|
| 85 | * Receives and unwraps a data payload token. Takes the file descriptor, |
|---|
| 86 | * GSS-API context, a pointer into which to storge the flags, a buffer for the |
|---|
| 87 | * message, and a place to put GSS-API major and minor status. Returns |
|---|
| 88 | * TOKEN_OK on success or one of the TOKEN_FAIL_* statuses on failure. On |
|---|
| 89 | * success, tok will contain newly allocated memory and should be freed when |
|---|
| 90 | * no longer needed using gss_release_buffer. On failure, any allocated |
|---|
| 91 | * memory will be freed. |
|---|
| 92 | * |
|---|
| 93 | * As a hack to support remctl v1, look to see if the flags includes |
|---|
| 94 | * TOKEN_SEND_MIC and do not include TOKEN_PROTOCOL. If so, calculate a MIC |
|---|
| 95 | * and send it back. |
|---|
| 96 | */ |
|---|
| 97 | enum token_status |
|---|
| 98 | token_recv_priv(int fd, gss_ctx_id_t ctx, int *flags, gss_buffer_t tok, |
|---|
| 99 | size_t max, OM_uint32 *major, OM_uint32 *minor) |
|---|
| 100 | { |
|---|
| 101 | gss_buffer_desc in, mic; |
|---|
| 102 | int state; |
|---|
| 103 | enum token_status status; |
|---|
| 104 | |
|---|
| 105 | status = token_recv(fd, flags, &in, max); |
|---|
| 106 | if (status != TOKEN_OK) |
|---|
| 107 | return status; |
|---|
| 108 | *major = gss_unwrap(minor, ctx, &in, tok, &state, NULL); |
|---|
| 109 | free(in.value); |
|---|
| 110 | if (*major != GSS_S_COMPLETE) |
|---|
| 111 | return TOKEN_FAIL_GSSAPI; |
|---|
| 112 | if ((*flags & TOKEN_SEND_MIC) && !(*flags & TOKEN_PROTOCOL)) { |
|---|
| 113 | *major = gss_get_mic(minor, ctx, GSS_C_QOP_DEFAULT, tok, &mic); |
|---|
| 114 | if (*major != GSS_S_COMPLETE) { |
|---|
| 115 | gss_release_buffer(minor, tok); |
|---|
| 116 | return TOKEN_FAIL_GSSAPI; |
|---|
| 117 | } |
|---|
| 118 | status = token_send(fd, TOKEN_MIC, &mic); |
|---|
| 119 | if (status != TOKEN_OK) { |
|---|
| 120 | gss_release_buffer(minor, tok); |
|---|
| 121 | gss_release_buffer(minor, &mic); |
|---|
| 122 | return status; |
|---|
| 123 | } |
|---|
| 124 | gss_release_buffer(minor, &mic); |
|---|
| 125 | *flags = (*flags) & ~TOKEN_SEND_MIC; |
|---|
| 126 | } |
|---|
| 127 | return TOKEN_OK; |
|---|
| 128 | } |
|---|