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 | } |
---|