1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 /* Only provides the bare minimum to link with libcurl */
29 #include "stub_gssapi.h"
31 #define MAX_CREDS_LENGTH 250
32 #define APPROX_TOKEN_LEN 250
45 const char *min_err_table[] = {
47 "stub-gss: no memory",
48 "stub-gss: invalid arguments",
49 "stub-gss: invalid credentials",
50 "stub-gss: invalid context",
51 "stub-gss: server returned error",
52 "stub-gss: cannot find a mechanism",
56 struct gss_ctx_id_t_desc_struct {
57 enum { NONE, KRB5, NTLM1, NTLM3 } sent;
61 char creds[MAX_CREDS_LENGTH];
64 OM_uint32 gss_init_sec_context(OM_uint32 *min,
65 gss_const_cred_id_t initiator_cred_handle,
66 gss_ctx_id_t *context_handle,
67 gss_const_name_t target_name,
68 const gss_OID mech_type,
71 const gss_channel_bindings_t input_chan_bindings,
72 const gss_buffer_t input_token,
73 gss_OID *actual_mech_type,
74 gss_buffer_t output_token,
78 /* The token will be encoded in base64 */
79 int length = APPROX_TOKEN_LEN * 3 / 4;
82 const char *creds = NULL;
83 gss_ctx_id_t ctx = NULL;
90 if(!context_handle || !target_name || !output_token) {
91 *min = GSS_INVALID_ARGS;
95 creds = getenv("CURL_STUB_GSS_CREDS");
96 if(!creds || strlen(creds) >= MAX_CREDS_LENGTH) {
97 *min = GSS_INVALID_CREDS;
101 ctx = *context_handle;
102 if(ctx && strcmp(ctx->creds, creds)) {
103 *min = GSS_INVALID_CREDS;
104 return GSS_S_FAILURE;
107 output_token->length = 0;
108 output_token->value = NULL;
110 if(input_token && input_token->length) {
112 *min = GSS_INVALID_CTX;
113 return GSS_S_FAILURE;
116 /* Server response, either D (RA==) or C (Qw==) */
117 if(((char *) input_token->value)[0] == 'D') {
123 *ret_flags = ctx->flags;
125 *time_rec = GSS_C_INDEFINITE;
126 return GSS_S_COMPLETE;
128 *min = GSS_SERVER_ERR;
129 return GSS_S_FAILURE;
133 if(((char *) input_token->value)[0] != 'C') {
134 /* We only support Done or Continue */
135 *min = GSS_SERVER_ERR;
136 return GSS_S_FAILURE;
142 /* We sent KRB5 and it failed, let's try NTLM */
148 *min = GSS_SERVER_ERR;
149 return GSS_S_FAILURE;
155 *min = GSS_SERVER_ERR;
156 return GSS_S_FAILURE;
161 *min = GSS_INVALID_CTX;
162 return GSS_S_FAILURE;
165 ctx = (gss_ctx_id_t) calloc(sizeof(*ctx), 1);
167 *min = GSS_NO_MEMORY;
168 return GSS_S_FAILURE;
171 if(strstr(creds, "KRB5"))
174 if(strstr(creds, "NTLM"))
179 else if(ctx->have_ntlm)
184 return GSS_S_FAILURE;
187 strcpy(ctx->creds, creds);
188 ctx->flags = req_flags;
191 token = malloc(length);
194 *min = GSS_NO_MEMORY;
195 return GSS_S_FAILURE;
198 /* Token format: creds:target:type:padding */
199 used = snprintf(token, length, "%s:%s:%d:", creds,
200 (char *) target_name, ctx->sent);
205 *min = GSS_NO_MEMORY;
206 return GSS_S_FAILURE;
209 /* Overwrite null terminator */
210 memset(token + used, 'A', length - used);
212 *context_handle = ctx;
214 output_token->value = token;
215 output_token->length = length;
217 return GSS_S_CONTINUE_NEEDED;
220 OM_uint32 gss_delete_sec_context(OM_uint32 *min,
221 gss_ctx_id_t *context_handle,
222 gss_buffer_t output_token)
225 return GSS_S_FAILURE;
227 if(!context_handle) {
228 *min = GSS_INVALID_CTX;
229 return GSS_S_FAILURE;
232 free(*context_handle);
233 *context_handle = NULL;
236 return GSS_S_COMPLETE;
239 OM_uint32 gss_release_buffer(OM_uint32 *min,
245 if(buffer && buffer->length) {
250 return GSS_S_COMPLETE;
253 OM_uint32 gss_import_name(OM_uint32 *min,
254 const gss_buffer_t input_name_buffer,
255 const gss_OID input_name_type,
256 gss_name_t *output_name)
261 return GSS_S_FAILURE;
263 if(!input_name_buffer || !output_name) {
264 *min = GSS_INVALID_ARGS;
265 return GSS_S_FAILURE;
268 name = strndup(input_name_buffer->value, input_name_buffer->length);
270 *min = GSS_NO_MEMORY;
271 return GSS_S_FAILURE;
274 *output_name = (gss_name_t) name;
277 return GSS_S_COMPLETE;
280 OM_uint32 gss_release_name(OM_uint32 *min,
281 gss_name_t *input_name)
289 return GSS_S_COMPLETE;
292 OM_uint32 gss_display_status(OM_uint32 *min,
293 OM_uint32 status_value,
295 const gss_OID mech_type,
296 OM_uint32 *message_context,
297 gss_buffer_t status_string)
299 const char maj_str[] = "Stub GSS error";
304 *message_context = 0;
307 status_string->value = NULL;
308 status_string->length = 0;
310 if(status_value >= GSS_LAST)
311 return GSS_S_FAILURE;
313 switch(status_type) {
315 status_string->value = strdup(maj_str);
317 case GSS_C_MECH_CODE:
318 status_string->value = strdup(min_err_table[status_value]);
321 return GSS_S_FAILURE;
324 if(status_string->value)
325 status_string->length = strlen(status_string->value);
327 return GSS_S_FAILURE;
330 return GSS_S_COMPLETE;
333 /* Stubs returning error */
335 OM_uint32 gss_display_name(OM_uint32 *min,
336 gss_const_name_t input_name,
337 gss_buffer_t output_name_buffer,
338 gss_OID *output_name_type)
340 return GSS_S_FAILURE;
343 OM_uint32 gss_inquire_context(OM_uint32 *min,
344 gss_const_ctx_id_t context_handle,
345 gss_name_t *src_name,
346 gss_name_t *targ_name,
347 OM_uint32 *lifetime_rec,
349 OM_uint32 *ctx_flags,
350 int *locally_initiated,
353 return GSS_S_FAILURE;
356 OM_uint32 gss_wrap(OM_uint32 *min,
357 gss_const_ctx_id_t context_handle,
360 const gss_buffer_t input_message_buffer,
362 gss_buffer_t output_message_buffer)
364 return GSS_S_FAILURE;
367 OM_uint32 gss_unwrap(OM_uint32 *min,
368 gss_const_ctx_id_t context_handle,
369 const gss_buffer_t input_message_buffer,
370 gss_buffer_t output_message_buffer,
372 gss_qop_t *qop_state)
374 return GSS_S_FAILURE;
377 OM_uint32 gss_seal(OM_uint32 *min,
378 gss_ctx_id_t context_handle,
381 gss_buffer_t input_message_buffer,
383 gss_buffer_t output_message_buffer)
385 return GSS_S_FAILURE;
388 OM_uint32 gss_unseal(OM_uint32 *min,
389 gss_ctx_id_t context_handle,
390 gss_buffer_t input_message_buffer,
391 gss_buffer_t output_message_buffer,
395 return GSS_S_FAILURE;