1 /* Copyright (C) 2008 CERN
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version 2
6 * of the License, or (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
16 * USA.
17 */
18
19 /* Author: Ian Baker */
20
21 #include <config.h>
22
23 #ifdef HAVE_GSSAPI
24 #include <arpa/inet.h>
25 #endif
26
27 #include <limits.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "auth.h"
33 #include "distcc.h"
34 #include "exitcode.h"
35 #include "netutil.h"
36 #include "rpc.h"
37 #include "trace.h"
38
39 /*
40 * Provide a textual representation of a GSS-API or mechanism-specific
41 * status code and write this to the log file.
42 *
43 * @param status_code. Status code to convert.
44 *
45 * @param status_type. The type of the status code, either GSS_C_GSS_CODE
46 * for a GSS-API status code or GSS_C_MECH_CODE
47 * for a mechanism-specific status code.
48 */
dcc_gssapi_status_to_log(OM_uint32 status_code,int status_type)49 void dcc_gssapi_status_to_log(OM_uint32 status_code, int status_type) {
50 gss_buffer_desc status_string = GSS_C_EMPTY_BUFFER;
51 OM_uint32 major_status, minor_status;
52 OM_uint32 message_ctx = 0;
53
54 do {
55 major_status = gss_display_status(&minor_status,
56 status_code,
57 status_type,
58 GSS_C_NULL_OID,
59 &message_ctx,
60 &status_string);
61
62 rs_log_info("%s: %s", (status_type == GSS_C_GSS_CODE) ? "GSSAPI" : "Mech" ,
63 (char *) status_string.value);
64 gss_release_buffer(&minor_status, &status_string);
65
66 } while (message_ctx != 0);
67
68 (void) major_status;
69 (void) minor_status;
70 }
71
72 /*
73 * Perform a cleanup on specified GSS-API internal data formats.
74 *
75 * @param input_tok. The input token to release.
76 *
77 * @param output_tok. The output token to release.
78 *
79 * @param name. The name to release.
80 */
dcc_gssapi_cleanup(gss_buffer_desc * input_tok,gss_buffer_desc * output_tok,gss_name_t * name)81 void dcc_gssapi_cleanup(gss_buffer_desc *input_tok,
82 gss_buffer_desc *output_tok,
83 gss_name_t *name) {
84 OM_uint32 major_status, minor_status;
85
86 if (input_tok != NULL) {
87 if ((major_status = gss_release_buffer(&minor_status,
88 input_tok)) != GSS_S_COMPLETE) {
89 rs_log_error("Failed to release buffer.");
90 }
91 }
92
93 if (output_tok != NULL) {
94 if ((major_status = gss_release_buffer(&minor_status,
95 output_tok)) != GSS_S_COMPLETE) {
96 rs_log_error("Failed to release buffer.");
97 }
98 }
99
100 if (name != NULL) {
101 if ((major_status = gss_release_name(&minor_status,
102 name)) != GSS_S_COMPLETE) {
103 rs_log_error("Failed to release name.");
104 }
105 }
106
107 (void) major_status;
108 (void) minor_status;
109 }
110
111 /*
112 * Perform a comparison of two sets of flags representing security
113 * services. At the moment we only check for mutual authentication,
114 * replay and out of sequence detection, but this function could be
115 * extended to include others.
116 *
117 * @param req_flags. The first set of flags to be compared and
118 * represents what is required by the client
119 * or server.
120 *
121 * @param ret_flags. The second set of flags to be compared and
122 * what is provided/returned by the peer.
123 *
124 * Returns 0 on success, otherwise error.
125 */
dcc_gssapi_compare_flags(OM_uint32 req_flags,OM_uint32 ret_flags)126 int dcc_gssapi_compare_flags(OM_uint32 req_flags, OM_uint32 ret_flags) {
127 if (req_flags & GSS_C_MUTUAL_FLAG) {
128 if (ret_flags & GSS_C_MUTUAL_FLAG) {
129 rs_log_info("Mutual authentication requested and granted.");
130 } else {
131 rs_log_crit("Requested security services don't match those returned.");
132 return EXIT_GSSAPI_FAILED;
133 }
134 }
135
136 if (req_flags & GSS_C_REPLAY_FLAG) {
137 if (ret_flags & GSS_C_REPLAY_FLAG) {
138 rs_log_info("Replay detection requested and granted.");
139 } else {
140 rs_log_crit("Requested security services don't match those returned.");
141 return EXIT_GSSAPI_FAILED;
142 }
143 }
144
145 if (req_flags & GSS_C_SEQUENCE_FLAG) {
146 if (ret_flags & GSS_C_SEQUENCE_FLAG) {
147 rs_log_info("Out of sequence detection requested and granted.");
148 } else {
149 rs_log_crit("Requested security services don't match those returned.");
150 return EXIT_GSSAPI_FAILED;
151 }
152 }
153
154 return 0;
155 }
156
157 /*
158 * Delete a specified secure context from the current process.
159 * The output buffer token is not used as we do not notify the
160 * peer.
161 *
162 * @param ctx_handle. The secure context to delete.
163 */
dcc_gssapi_delete_ctx(gss_ctx_id_t * ctx_handle)164 void dcc_gssapi_delete_ctx(gss_ctx_id_t *ctx_handle) {
165 OM_uint32 major_status, minor_status;
166
167 if (ctx_handle != NULL) {
168 if (*ctx_handle != GSS_C_NO_CONTEXT) {
169 if ((major_status = gss_delete_sec_context(&minor_status,
170 ctx_handle,
171 GSS_C_NO_BUFFER)) != GSS_S_COMPLETE) {
172 rs_log_error("Failed to delete context.");
173 }
174 }
175 }
176 }
177
178 /*
179 * Send the specified token. First we transmit the token length,
180 * then the token itself.
181 *
182 * @param token. The token to be sent.
183 *
184 * Returns 0 on success, otherwise error.
185 */
send_token(int sd,gss_buffer_t token)186 int send_token(int sd, gss_buffer_t token) {
187 int ret;
188
189 if ((ret = dcc_x_token_int(sd, "TLEN", token->length)) != 0) {
190 return ret;
191 }
192
193 if ((ret = dcc_writex(sd, token->value, token->length)) != 0) {
194 return ret;
195 }
196
197 return 0;
198 }
199
200 /*
201 * Receive a token. First we receive the token length,
202 * then the token itself.
203 *
204 * @param token. The token to be received.
205 *
206 * Returns 0 on success, otherwise error.
207 */
recv_token(int sd,gss_buffer_t token)208 int recv_token(int sd, gss_buffer_t token) {
209 int ret;
210 unsigned length;
211
212 if ((ret = dcc_r_token_int(sd, "TLEN", &length)) != 0) {
213 return ret;
214 }
215
216 if (length > INT_MAX || length == 0) {
217 rs_log_error("Malformed token length.");
218 return EXIT_IO_ERROR;
219 }
220
221 token->length = length;
222 token->value = malloc(length);
223
224 if (token->value == NULL && length != 0) {
225 rs_log_error("malloc failed : %lu bytes: out of memory.",
226 (unsigned long) length);
227 return EXIT_OUT_OF_MEMORY;
228 }
229
230 if ((ret = dcc_readx(sd, token->value, token->length)) != 0) {
231 return ret;
232 }
233
234 return 0;
235 }
236