#163 Add support for setting the NO Ci Flags credentials option
Closed 7 years ago by rharwood. Opened 7 years ago by simo.
simo/gssproxy setcredopt  into  master

file modified
+18
@@ -389,6 +389,7 @@ 

  }

  

  #define KRB5_SET_ALLOWED_ENCTYPE "krb5_set_allowed_enctype_values"

+ #define KRB5_SET_NO_CI_FLAGS "krb5_set_no_ci_flags"

  

  static void gp_set_cred_options(gssx_cred *cred, gss_cred_id_t gss_cred)

  {
@@ -396,6 +397,7 @@ 

      struct gssx_option *op;

      uint32_t num_ktypes = 0;

      krb5_enctype *ktypes;

+     bool no_ci_flags = false;

      uint32_t maj, min;

      int i, j;

  
@@ -411,6 +413,12 @@ 

                  num_ktypes = op->value.octet_string_len / sizeof(krb5_enctype);

                  ktypes = (krb5_enctype *)op->value.octet_string_val;

                  break;

+             } else if ((op->option.octet_string_len ==

+                         sizeof(KRB5_SET_NO_CI_FLAGS)) &&

+                 (strncmp(KRB5_SET_NO_CI_FLAGS,

+                          op->option.octet_string_val,

+                          op->option.octet_string_len) == 0)) {

+                 no_ci_flags = true;

              }

          }

      }
@@ -422,6 +430,16 @@ 

              GPDEBUG("Failed to set allowable enctypes\n");

          }

      }

+ 

+     if (no_ci_flags) {

+         gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;

+         maj = gss_set_cred_option(&min, &gss_cred,

+                                   discard_const(GSS_KRB5_CRED_NO_CI_FLAGS_X),

+                                   &empty_buffer);

+         if (maj != GSS_S_COMPLETE) {

+             GPDEBUG("Failed to set NO CI Flags\n");

+         }

+     }

  }

  

  uint32_t gp_import_gssx_cred(uint32_t *min, struct gp_call_ctx *gpcall,

file modified
+8 -6
@@ -160,13 +160,15 @@ 

      memcpy(opt.option.octet_string_val, option, option_len);

      opt.option.octet_string_len = option_len;

  

-     opt.value.octet_string_val = malloc(value_len);

-     if (!opt.value.octet_string_val) {

-         ret = ENOMEM;

-         goto done;

+     if (value_len != 0) {

+         opt.value.octet_string_val = malloc(value_len);

+         if (!opt.value.octet_string_val) {

+             ret = ENOMEM;

+             goto done;

+         }

+         memcpy(opt.value.octet_string_val, value, value_len);

+         opt.value.octet_string_len = value_len;

      }

-     memcpy(opt.value.octet_string_val, value, value_len);

-     opt.value.octet_string_len = value_len;

  

      out = realloc(*options_val, (*options_len + 1) * sizeof(gssx_option));

      if (!out) {

file modified
+39 -25
@@ -561,12 +561,9 @@ 

      struct gpp_allowable_enctypes *ae;

      struct gssx_cred_element *ce = NULL;

      gss_OID_desc mech;

-     gssx_option *to;

-     gssx_buffer *tb;

-     int i;

  

      /* Find the first element that matches one of the krb related OIDs */

-     for (i = 0; i < cred->elements.elements_len; i++) {

+     for (unsigned i = 0; i < cred->elements.elements_len; i++) {

Are we allowing this now?

          gp_conv_gssx_to_oid(&cred->elements.elements_val[i].mech, &mech);

          if (gpp_is_krb5_oid(&mech)) {

              ce = &cred->elements.elements_val[i];
@@ -579,36 +576,51 @@ 

          return GSS_S_FAILURE;

      }

  

-     to = realloc(ce->options.options_val,

-                  sizeof(gssx_option) * (ce->options.options_len + 1));

-     if (!to) {

-         *min = ENOMEM;

+     ae = (struct gpp_allowable_enctypes *)value->value;

+     *min = gp_add_option(&ce->options.options_val,

+                          &ce->options.options_len,

+                          KRB5_SET_ALLOWED_ENCTYPE,

+                          sizeof(KRB5_SET_ALLOWED_ENCTYPE),

+                          ae->ktypes,

+                          sizeof(krb5_enctype) * ae->num_ktypes);

+     if (*min != 0) {

          return GSS_S_FAILURE;

      }

-     ce->options.options_val = to;

-     i = ce->options.options_len;

  

-     tb = &ce->options.options_val[i].option;

-     tb->octet_string_len = sizeof(KRB5_SET_ALLOWED_ENCTYPE);

-     tb->octet_string_val = strdup(KRB5_SET_ALLOWED_ENCTYPE);

-     if (!tb->octet_string_val) {

-         *min = ENOMEM;

-         return GSS_S_FAILURE;

+     return GSS_S_COMPLETE;

+ }

+ 

+ #define KRB5_SET_NO_CI_FLAGS "krb5_set_no_ci_flags"

+ 

+ static uint32_t gpp_set_no_ci_flags(uint32_t *min, gssx_cred *cred,

+                                     const gss_buffer_t value)

+ {

+     struct gssx_cred_element *ce = NULL;

+     gss_OID_desc mech;

+ 

+     /* Find the first element that matches one of the krb related OIDs */

+     for (unsigned i = 0; i < cred->elements.elements_len; i++) {

+         gp_conv_gssx_to_oid(&cred->elements.elements_val[i].mech, &mech);

+         if (gpp_is_krb5_oid(&mech)) {

+             ce = &cred->elements.elements_val[i];

+             break;

+         }

      }

  

-     ae = (struct gpp_allowable_enctypes *)value->value;

-     tb = &ce->options.options_val[i].value;

-     tb->octet_string_len = sizeof(krb5_enctype) * ae->num_ktypes;

-     tb->octet_string_val = malloc(tb->octet_string_len);

-     if (!tb->octet_string_val) {

-         *min = ENOMEM;

+     if (!ce) {

+         *min = EINVAL;

          return GSS_S_FAILURE;

      }

-     memcpy(tb->octet_string_val, ae->ktypes, tb->octet_string_len);

  

-     ce->options.options_len++;

+     *min = gp_add_option(&ce->options.options_val,

+                          &ce->options.options_len,

+                          KRB5_SET_NO_CI_FLAGS,

+                          sizeof(KRB5_SET_NO_CI_FLAGS),

+                          NULL, 0);

+     if (*min != 0) {

+         return GSS_S_FAILURE;

+     }

  

-     *min = 0;

      return GSS_S_COMPLETE;

  }

  
@@ -620,6 +632,8 @@ 

  

      if (gss_oid_equal(&gpp_allowed_enctypes_oid, desired_object)) {

          maj = gpp_set_opt_allowable_entypes(min, cred, value);

+     } else if (gss_oid_equal(GSS_KRB5_CRED_NO_CI_FLAGS_X, desired_object)) {

+         maj = gpp_set_no_ci_flags(min, cred, value);

      }

  

      return maj;

file modified
+10 -1
@@ -34,12 +34,21 @@ 

  t_init_LDADD = \

      $(GSSAPI_LIBS)

  

+ t_setcredopt_SOURCES = \

+     t_utils.c \

+     t_setcredopt.c

+ 

+ t_setcredopt_LDADD = \

+     $(GSSAPI_LIBS)

+ 

  check_PROGRAMS = \

      t_acquire \

      t_cred_store \

      t_impersonate \

      t_accept \

-     t_init

+     t_init \

+     t_setcredopt \

+     $(NULL)

  

  noinst_PROGRAMS = $(check_PROGRAMS)

  

file modified
+1
@@ -77,6 +77,7 @@ 

              testnum += 1

      except Exception:

          traceback.print_exc()

+         errored = True

      finally:

          for name in processes:

              print("Killing %s" % name)

@@ -0,0 +1,167 @@ 

+ /* Copyright (C) 2017 the GSS-PROXY contributors, see COPYING for license */

+ 

+ #include "t_utils.h"

+ #include <unistd.h>

+ #include <stdbool.h>

+ 

+ int main(int argc, const char *argv[])

+ {

+     gss_cred_id_t cred_handle = GSS_C_NO_CREDENTIAL;

+     gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;

+     gss_ctx_id_t init_ctx = GSS_C_NO_CONTEXT;

+     gss_ctx_id_t accept_ctx = GSS_C_NO_CONTEXT;

+     gss_buffer_desc in_token = GSS_C_EMPTY_BUFFER;

+     gss_buffer_desc out_token = GSS_C_EMPTY_BUFFER;

+     gss_name_t user_name;

+     gss_name_t target_name;

+     gss_OID_set_desc oid_set = { 1, discard_const(gss_mech_krb5) };

+     uint32_t ret_maj;

+     uint32_t ret_min;

+     uint32_t flags = GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG;

+     uint32_t ret_flags = 0;

+     int ret = -1;

+     gss_key_value_element_desc ccelement = { "ccache", NULL };

+     gss_key_value_set_desc cred_store = { 1, &ccelement };

+     krb5_enctype enc = ENCTYPE_AES256_CTS_HMAC_SHA1_96;

+ 

+     if (argc < 3) return -1;

+ 

+     ret = t_string_to_name(argv[1], &user_name, GSS_C_NT_USER_NAME);

+     if (ret) {

+         DEBUG("Failed to import user name from argv[1]\n");

+         ret = -1;

+         goto done;

+     }

+ 

+     ret = t_string_to_name(argv[2], &target_name,

+                            GSS_C_NT_HOSTBASED_SERVICE);

+     if (ret) {

+         DEBUG("Failed to import server name from argv[2]\n");

+         ret = -1;

+         goto done;

+     }

+ 

+     ccelement.value = argv[3];

+ 

+     ret_maj = gss_acquire_cred_from(&ret_min,

+                                     user_name,

+                                     GSS_C_INDEFINITE,

+                                     &oid_set,

+                                     GSS_C_INITIATE,

+                                     &cred_store,

+                                     &cred_handle,

+                                     NULL, NULL);

+     if (ret_maj != GSS_S_COMPLETE) {

+         DEBUG("gss_acquire_cred_from() [%s,%s] failed\n", argv[1], argv[3]);

+         t_log_failure(GSS_C_NO_OID, ret_maj, ret_min);

+         ret = -1;

+         goto done;

+     }

+ 

+     ret_maj = gss_set_cred_option(&ret_min, &cred_handle,

+                                   (gss_OID)GSS_KRB5_CRED_NO_CI_FLAGS_X,

+                                   &empty_buffer);

+     if (ret_maj != GSS_S_COMPLETE) {

+         DEBUG("gss_set_cred_option(GSS_KRB5_CRED_NO_CI_FLAGS_X) failed\n");

+         t_log_failure(GSS_C_NO_OID, ret_maj, ret_min);

+         ret = -1;

+         goto done;

+     }

+ 

+     ret_maj = gss_krb5_set_allowable_enctypes(&ret_min, cred_handle, 1, &enc);

+     if (ret_maj != GSS_S_COMPLETE) {

+         DEBUG("gss_krb5_set_allowable_enctypes() failed\n");

+         t_log_failure(GSS_C_NO_OID, ret_maj, ret_min);

+         ret = -1;

+         goto done;

+     }

+ 

+     ret_maj = gss_init_sec_context(&ret_min,

+                                    cred_handle,

+                                    &init_ctx,

+                                    target_name,

+                                    GSS_C_NO_OID,

+                                    flags,

+                                    0,

+                                    GSS_C_NO_CHANNEL_BINDINGS,

+                                    &in_token,

+                                    NULL,

+                                    &out_token,

+                                    NULL,

+                                    NULL);

+     if (ret_maj != GSS_S_CONTINUE_NEEDED) {

+         DEBUG("gss_init_sec_context() failed\n");

+         t_log_failure(GSS_C_NO_OID, ret_maj, ret_min);

+         ret = -1;

+         goto done;

+     }

+ 

+     /* We get stuff from stdin and spit it out on stderr */

+     if (!out_token.length) {

+         DEBUG("No output token ?");

+         ret = -1;

+         goto done;

+     }

+ 

+     /* in/out token inverted here intentionally */

+     ret_maj = gss_accept_sec_context(&ret_min,

+                                      &accept_ctx,

+                                      GSS_C_NO_CREDENTIAL,

+                                      &out_token,

+                                      GSS_C_NO_CHANNEL_BINDINGS,

+                                      NULL,

+                                      NULL,

+                                      &in_token,

+                                      &ret_flags,

+                                      NULL,

+                                      NULL);

+     if (ret_maj) {

+         DEBUG("Error accepting context\n");

+         t_log_failure(GSS_C_NO_OID, ret_maj, ret_min);

+         ret = -1;

+         goto done;

+     }

+ 

+     /* now test that flags are as expected */

+     if (ret_flags & (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG)) {

+         DEBUG("Set NO CI Flags but ret_flags matches (%x)!\n", ret_flags);

+         ret = -1;

+         goto done;

+     }

+ 

+     if (!in_token.length) {

+         DEBUG("No output token ?");

+         ret = -1;

+         goto done;

+     }

+ 

+     gss_release_buffer(&ret_min, &out_token);

+ 

+     ret_maj = gss_init_sec_context(&ret_min,

+                                    cred_handle,

+                                    &init_ctx,

+                                    target_name,

+                                    GSS_C_NO_OID,

+                                    flags,

+                                    0,

+                                    GSS_C_NO_CHANNEL_BINDINGS,

+                                    &in_token,

+                                    NULL,

+                                    &out_token,

+                                    NULL,

+                                    NULL);

+     if (ret_maj) {

+         DEBUG("Error initializing context\n");

+         t_log_failure(GSS_C_NO_OID, ret_maj, ret_min);

+         ret = -1;

+         goto done;

+     }

+ 

+     ret = 0;

+ 

+ done:

+     gss_release_buffer(&ret_min, &in_token);

+     gss_release_buffer(&ret_min, &out_token);

+     gss_release_cred(&ret_min, &cred_handle);

+     return ret;

+ }

@@ -0,0 +1,42 @@ 

+ #!/usr/bin/python3

+ # Copyright (C) 2017 - GSS-Proxy contributors; see COPYING for the license

+ 

+ from testlib import *

+ 

+ def run(testdir, env, conf):

+     print("Testing setting credential options...", file=sys.stderr)

+     path_prefix = os.path.join(testdir, 't' + conf['prefix'] + '_')

+     init_ccache = path_prefix + 'sco_init.ccache'

+ 

+     logfile = conf['logfile']

+     testenv = env.copy()

+     testenv.update({'KRB5CCNAME': init_ccache})

+ 

+     usr_keytab = os.path.join(testdir, USR_KTNAME)

+     ksetup = subprocess.Popen(["kinit", "-kt", usr_keytab, USR_NAME],

+                               stdout=logfile, stderr=logfile,

+                               env=testenv, preexec_fn=os.setsid)

+     ksetup.wait()

+     if ksetup.returncode != 0:

+         raise ValueError("Kinit %s failed" % USR_NAME)

+ 

+ 

+     cmd = ["./tests/t_setcredopt", USR_NAME, HOST_GSS, init_ccache]

+ 

+     testenv.update({'KRB5CCNAME': path_prefix + 'sco.ccache',

+                     'KRB5_KTNAME': os.path.join(testdir, PROXY_KTNAME),

+                     'KRB5_TRACE': path_prefix + 'sco.trace',

+                     'GSSPROXY_BEHAVIOR': 'REMOTE_FIRST'})

+ 

+     print("[COMMAND]\n%s\n[ENVIRONMENT]\n%s\n" % (cmd, testenv), file=logfile)

+     logfile.flush()

+ 

+     p1 = subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=logfile,

+                           env=testenv, preexec_fn=os.setsid)

+     try:

+         p1.wait(10)

+     except subprocess.TimeoutExpired:

+         # p1.returncode is set to None here

+         pass

+     print_return(p1.returncode, "Set cred options", False)

+     return p1.returncode

no initial comment

Please rebase this onto master.

rebased

7 years ago
Testing setting credential options...
Traceback (most recent call last):
  File "./tests/runtests.py", line 73, in <module>
    r = t.run(testdir, gssapienv, basicconf)
  File "/home/bos/rharwood/gssproxy.git/proxy/tests/t_setcredopt.py", line 38, in run
    return run_cmd(testdir, env, conf, socket, cmd, False)
NameError: name 'socket' is not defined

3 new commits added

  • Insure tests failure on traceback
  • Add test to check setting cred options
  • Add support for the NO_CI_FLAG credentials option
7 years ago

We should allow for more than one round trip here probably

Some comments inline. Most of this I'd fixup at merge time, but I don't know what we want to do about the for loops, and I don't feel comfortable touching copyright information.

So here is the thing, if it is on the same line there is no risk of adding errors,
if it is on two lines with brackets also no problem, you add content in brackets, but the form

if (x)
    foo();

I find it dangerous, because you can add a line after and forget to add {}, which is why I am ok returning inline if it is this short rather then going next line.

For this test it is ok, we force krb5 which requires only one roundtrip

Fixed up what I think needs fixin'
C99 or even C11 is just fine by me.

3 new commits added

  • Insure tests failure on traceback
  • Add test to check setting cred options
  • Add support for the NO_CI_FLAG credentials option
7 years ago

Thanks, pushed to master as e406ad5

Pull-Request has been closed by rharwood

7 years ago