• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
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.se/docs/copyright.html.
13  *
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.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * SPDX-License-Identifier: curl
22  *
23  ***************************************************************************/
24 
25 /* Only provides the bare minimum to link with libcurl */
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include "stub_gssapi.h"
32 
33 /* !checksrc! disable SNPRINTF all */
34 
35 #define MAX_CREDS_LENGTH 250
36 #define APPROX_TOKEN_LEN 250
37 
38 enum min_err_code {
39     GSS_OK = 0,
40     GSS_NO_MEMORY,
41     GSS_INVALID_ARGS,
42     GSS_INVALID_CREDS,
43     GSS_INVALID_CTX,
44     GSS_SERVER_ERR,
45     GSS_NO_MECH,
46     GSS_LAST
47 };
48 
49 static const char *min_err_table[] = {
50   "stub-gss: no error",
51   "stub-gss: no memory",
52   "stub-gss: invalid arguments",
53   "stub-gss: invalid credentials",
54   "stub-gss: invalid context",
55   "stub-gss: server returned error",
56   "stub-gss: cannot find a mechanism",
57   NULL
58 };
59 
60 struct gss_ctx_id_t_desc_struct {
61   enum { NONE, KRB5, NTLM1, NTLM3 } sent;
62   int have_krb5;
63   int have_ntlm;
64   OM_uint32 flags;
65   char creds[MAX_CREDS_LENGTH];
66 };
67 
gss_init_sec_context(OM_uint32 * min,gss_const_cred_id_t initiator_cred_handle,gss_ctx_id_t * context_handle,gss_const_name_t target_name,const gss_OID mech_type,OM_uint32 req_flags,OM_uint32 time_req,const gss_channel_bindings_t input_chan_bindings,const gss_buffer_t input_token,gss_OID * actual_mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec)68 OM_uint32 gss_init_sec_context(OM_uint32 *min,
69             gss_const_cred_id_t initiator_cred_handle,
70             gss_ctx_id_t *context_handle,
71             gss_const_name_t target_name,
72             const gss_OID mech_type,
73             OM_uint32 req_flags,
74             OM_uint32 time_req,
75             const gss_channel_bindings_t input_chan_bindings,
76             const gss_buffer_t input_token,
77             gss_OID *actual_mech_type,
78             gss_buffer_t output_token,
79             OM_uint32 *ret_flags,
80             OM_uint32 *time_rec)
81 {
82   /* The token will be encoded in base64 */
83   int length = APPROX_TOKEN_LEN * 3 / 4;
84   int used = 0;
85   char *token = NULL;
86   const char *creds = NULL;
87   gss_ctx_id_t ctx = NULL;
88 
89   (void)initiator_cred_handle;
90   (void)mech_type;
91   (void)time_req;
92   (void)input_chan_bindings;
93   (void)actual_mech_type;
94 
95   if(!min)
96     return GSS_S_FAILURE;
97 
98   *min = 0;
99 
100   if(!context_handle || !target_name || !output_token) {
101     *min = GSS_INVALID_ARGS;
102     return GSS_S_FAILURE;
103   }
104 
105   creds = getenv("CURL_STUB_GSS_CREDS");
106   if(!creds || strlen(creds) >= MAX_CREDS_LENGTH) {
107     *min = GSS_INVALID_CREDS;
108     return GSS_S_FAILURE;
109   }
110 
111   ctx = *context_handle;
112   if(ctx && strcmp(ctx->creds, creds)) {
113     *min = GSS_INVALID_CREDS;
114     return GSS_S_FAILURE;
115   }
116 
117   output_token->length = 0;
118   output_token->value = NULL;
119 
120   if(input_token && input_token->length) {
121     if(!ctx) {
122       *min = GSS_INVALID_CTX;
123       return GSS_S_FAILURE;
124     }
125 
126     /* Server response, either D (RA==) or C (Qw==) */
127     if(((char *) input_token->value)[0] == 'D') {
128       /* Done */
129       switch(ctx->sent) {
130       case KRB5:
131       case NTLM3:
132         if(ret_flags)
133           *ret_flags = ctx->flags;
134         if(time_rec)
135           *time_rec = GSS_C_INDEFINITE;
136         return GSS_S_COMPLETE;
137       default:
138         *min = GSS_SERVER_ERR;
139         return GSS_S_FAILURE;
140       }
141     }
142 
143     if(((char *) input_token->value)[0] != 'C') {
144       /* We only support Done or Continue */
145       *min = GSS_SERVER_ERR;
146       return GSS_S_FAILURE;
147     }
148 
149     /* Continue */
150     switch(ctx->sent) {
151     case KRB5:
152       /* We sent KRB5 and it failed, let's try NTLM */
153       if(ctx->have_ntlm) {
154         ctx->sent = NTLM1;
155         break;
156       }
157       else {
158         *min = GSS_SERVER_ERR;
159         return GSS_S_FAILURE;
160       }
161     case NTLM1:
162       ctx->sent = NTLM3;
163       break;
164     default:
165       *min = GSS_SERVER_ERR;
166       return GSS_S_FAILURE;
167     }
168   }
169   else {
170     if(ctx) {
171       *min = GSS_INVALID_CTX;
172       return GSS_S_FAILURE;
173     }
174 
175     ctx = (gss_ctx_id_t) calloc(sizeof(*ctx), 1);
176     if(!ctx) {
177       *min = GSS_NO_MEMORY;
178       return GSS_S_FAILURE;
179     }
180 
181     if(strstr(creds, "KRB5"))
182       ctx->have_krb5 = 1;
183 
184     if(strstr(creds, "NTLM"))
185       ctx->have_ntlm = 1;
186 
187     if(ctx->have_krb5)
188       ctx->sent = KRB5;
189     else if(ctx->have_ntlm)
190       ctx->sent = NTLM1;
191     else {
192       free(ctx);
193       *min = GSS_NO_MECH;
194       return GSS_S_FAILURE;
195     }
196 
197     strcpy(ctx->creds, creds);
198     ctx->flags = req_flags;
199   }
200 
201   token = malloc(length);
202   if(!token) {
203     free(ctx);
204     *min = GSS_NO_MEMORY;
205     return GSS_S_FAILURE;
206   }
207 
208   /* Token format: creds:target:type:padding */
209   /* Note: this is using the *real* snprintf() and not the curl provided
210      one */
211   used = snprintf(token, length, "%s:%s:%d:", creds,
212                   (char *) target_name, ctx->sent);
213 
214   if(used >= length) {
215     free(token);
216     free(ctx);
217     *min = GSS_NO_MEMORY;
218     return GSS_S_FAILURE;
219   }
220 
221   /* Overwrite null terminator */
222   memset(token + used, 'A', length - used);
223 
224   *context_handle = ctx;
225 
226   output_token->value = token;
227   output_token->length = length;
228 
229   return GSS_S_CONTINUE_NEEDED;
230 }
231 
gss_delete_sec_context(OM_uint32 * min,gss_ctx_id_t * context_handle,gss_buffer_t output_token)232 OM_uint32 gss_delete_sec_context(OM_uint32 *min,
233                                  gss_ctx_id_t *context_handle,
234                                  gss_buffer_t output_token)
235 {
236   (void)output_token;
237 
238   if(!min)
239     return GSS_S_FAILURE;
240 
241   if(!context_handle) {
242     *min = GSS_INVALID_CTX;
243     return GSS_S_FAILURE;
244   }
245 
246   free(*context_handle);
247   *context_handle = NULL;
248   *min = 0;
249 
250   return GSS_S_COMPLETE;
251 }
252 
gss_release_buffer(OM_uint32 * min,gss_buffer_t buffer)253 OM_uint32 gss_release_buffer(OM_uint32 *min,
254                              gss_buffer_t buffer)
255 {
256   if(min)
257     *min = 0;
258 
259   if(buffer && buffer->length) {
260     free(buffer->value);
261     buffer->length = 0;
262   }
263 
264   return GSS_S_COMPLETE;
265 }
266 
gss_import_name(OM_uint32 * min,const gss_buffer_t input_name_buffer,const gss_OID input_name_type,gss_name_t * output_name)267 OM_uint32 gss_import_name(OM_uint32 *min,
268                           const gss_buffer_t input_name_buffer,
269                           const gss_OID input_name_type,
270                           gss_name_t *output_name)
271 {
272   char *name = NULL;
273   (void)input_name_type;
274 
275   if(!min)
276     return GSS_S_FAILURE;
277 
278   if(!input_name_buffer || !output_name) {
279     *min = GSS_INVALID_ARGS;
280     return GSS_S_FAILURE;
281   }
282 
283   name = strndup(input_name_buffer->value, input_name_buffer->length);
284   if(!name) {
285     *min = GSS_NO_MEMORY;
286     return GSS_S_FAILURE;
287   }
288 
289   *output_name = (gss_name_t) name;
290   *min = 0;
291 
292   return GSS_S_COMPLETE;
293 }
294 
gss_release_name(OM_uint32 * min,gss_name_t * input_name)295 OM_uint32 gss_release_name(OM_uint32 *min,
296                            gss_name_t *input_name)
297 {
298   if(min)
299     *min = 0;
300 
301   if(input_name)
302     free(*input_name);
303 
304   return GSS_S_COMPLETE;
305 }
306 
gss_display_status(OM_uint32 * min,OM_uint32 status_value,int status_type,const gss_OID mech_type,OM_uint32 * message_context,gss_buffer_t status_string)307 OM_uint32 gss_display_status(OM_uint32 *min,
308                              OM_uint32 status_value,
309                              int status_type,
310                              const gss_OID mech_type,
311                              OM_uint32 *message_context,
312                              gss_buffer_t status_string)
313 {
314   const char maj_str[] = "Stub GSS error";
315   (void)mech_type;
316   if(min)
317     *min = 0;
318 
319   if(message_context)
320     *message_context = 0;
321 
322   if(status_string) {
323     status_string->value = NULL;
324     status_string->length = 0;
325 
326     if(status_value >= GSS_LAST)
327       return GSS_S_FAILURE;
328 
329     switch(status_type) {
330       case GSS_C_GSS_CODE:
331         status_string->value = strdup(maj_str);
332         break;
333       case GSS_C_MECH_CODE:
334         status_string->value = strdup(min_err_table[status_value]);
335         break;
336       default:
337         return GSS_S_FAILURE;
338     }
339 
340     if(status_string->value)
341       status_string->length = strlen(status_string->value);
342     else
343       return GSS_S_FAILURE;
344   }
345 
346   return GSS_S_COMPLETE;
347 }
348 
349 /* Stubs returning error */
350 
gss_display_name(OM_uint32 * min,gss_const_name_t input_name,gss_buffer_t output_name_buffer,gss_OID * output_name_type)351 OM_uint32 gss_display_name(OM_uint32 *min,
352                            gss_const_name_t input_name,
353                            gss_buffer_t output_name_buffer,
354                            gss_OID *output_name_type)
355 {
356   (void)min;
357   (void)input_name;
358   (void)output_name_buffer;
359   (void)output_name_type;
360   return GSS_S_FAILURE;
361 }
362 
gss_inquire_context(OM_uint32 * min,gss_const_ctx_id_t context_handle,gss_name_t * src_name,gss_name_t * targ_name,OM_uint32 * lifetime_rec,gss_OID * mech_type,OM_uint32 * ctx_flags,int * locally_initiated,int * open_context)363 OM_uint32 gss_inquire_context(OM_uint32 *min,
364                               gss_const_ctx_id_t context_handle,
365                               gss_name_t *src_name,
366                               gss_name_t *targ_name,
367                               OM_uint32 *lifetime_rec,
368                               gss_OID *mech_type,
369                               OM_uint32 *ctx_flags,
370                               int *locally_initiated,
371                               int *open_context)
372 {
373   (void)min;
374   (void)context_handle;
375   (void)src_name;
376   (void)targ_name;
377   (void)lifetime_rec;
378   (void)mech_type;
379   (void)ctx_flags;
380   (void)locally_initiated;
381   (void)open_context;
382   return GSS_S_FAILURE;
383 }
384 
gss_wrap(OM_uint32 * min,gss_const_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,const gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer)385 OM_uint32 gss_wrap(OM_uint32 *min,
386                    gss_const_ctx_id_t context_handle,
387                    int conf_req_flag,
388                    gss_qop_t qop_req,
389                    const gss_buffer_t input_message_buffer,
390                    int *conf_state,
391                    gss_buffer_t output_message_buffer)
392 {
393   (void)min;
394   (void)context_handle;
395   (void)conf_req_flag;
396   (void)qop_req;
397   (void)input_message_buffer;
398   (void)conf_state;
399   (void)output_message_buffer;
400   return GSS_S_FAILURE;
401 }
402 
gss_unwrap(OM_uint32 * min,gss_const_ctx_id_t context_handle,const gss_buffer_t input_message_buffer,gss_buffer_t output_message_buffer,int * conf_state,gss_qop_t * qop_state)403 OM_uint32 gss_unwrap(OM_uint32 *min,
404                      gss_const_ctx_id_t context_handle,
405                      const gss_buffer_t input_message_buffer,
406                      gss_buffer_t output_message_buffer,
407                      int *conf_state,
408                      gss_qop_t *qop_state)
409 {
410   (void)min;
411   (void)context_handle;
412   (void)input_message_buffer;
413   (void)output_message_buffer;
414   (void)conf_state;
415   (void)qop_state;
416   return GSS_S_FAILURE;
417 }
418 
gss_seal(OM_uint32 * min,gss_ctx_id_t context_handle,int conf_req_flag,int qop_req,gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer)419 OM_uint32 gss_seal(OM_uint32 *min,
420                    gss_ctx_id_t context_handle,
421                    int conf_req_flag,
422                    int qop_req,
423                    gss_buffer_t input_message_buffer,
424                    int *conf_state,
425                    gss_buffer_t output_message_buffer)
426 {
427   (void)min;
428   (void)context_handle;
429   (void)conf_req_flag;
430   (void)qop_req;
431   (void)input_message_buffer;
432   (void)conf_state;
433   (void)output_message_buffer;
434   return GSS_S_FAILURE;
435 }
436 
gss_unseal(OM_uint32 * min,gss_ctx_id_t context_handle,gss_buffer_t input_message_buffer,gss_buffer_t output_message_buffer,int * conf_state,int * qop_state)437 OM_uint32 gss_unseal(OM_uint32 *min,
438                      gss_ctx_id_t context_handle,
439                      gss_buffer_t input_message_buffer,
440                      gss_buffer_t output_message_buffer,
441                      int *conf_state,
442                      int *qop_state)
443 {
444   (void)min;
445   (void)context_handle;
446   (void)input_message_buffer;
447   (void)output_message_buffer;
448   (void)conf_state;
449   (void)qop_state;
450   return GSS_S_FAILURE;
451 }
452