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