Blob Blame History Raw
From 556ea844a5783f9876ee748e1c686bb268f54e8a Mon Sep 17 00:00:00 2001
From: Simo Sorce <simo@redhat.com>
Date: Fri, 15 Nov 2013 10:33:52 -0500
Subject: [PATCH] Fix continuations in context establishment calls
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Properly support continuations, including returning the rigth error code
and exporting partial contexts.

Fixes multistep authentications in particular for the initialization case
which always uses continuations.

Resolves: https://fedorahosted.org/gss-proxy/ticket/108

Reviewed-by: Günther Deschner <gdeschner@redhat.com>
---
 proxy/src/client/gpm_init_sec_context.c | 21 ++++++++++-----------
 proxy/src/gp_export.c                   | 33 +++++++++++++++++++++++++++++----
 proxy/src/gp_export.h                   |  3 ++-
 proxy/src/gp_rpc_accept_sec_context.c   | 20 +++++++++++++++++---
 proxy/src/gp_rpc_get_mic.c              |  2 +-
 proxy/src/gp_rpc_init_sec_context.c     | 16 +++++++++++++++-
 proxy/src/gp_rpc_unwrap.c               |  2 +-
 proxy/src/gp_rpc_verify_mic.c           |  2 +-
 proxy/src/gp_rpc_wrap.c                 |  2 +-
 9 files changed, 77 insertions(+), 24 deletions(-)

diff --git a/proxy/src/client/gpm_init_sec_context.c b/proxy/src/client/gpm_init_sec_context.c
index b6ce34f..f6dfe53 100644
--- a/proxy/src/client/gpm_init_sec_context.c
+++ b/proxy/src/client/gpm_init_sec_context.c
@@ -104,13 +104,6 @@ OM_uint32 gpm_init_sec_context(OM_uint32 *minor_status,
         }
     }
 
-    if (res->status.major_status) {
-        gpm_save_status(&res->status);
-        ret_maj = res->status.major_status;
-        ret_min = res->status.minor_status;
-        goto done;
-    }
-
     if (res->context_handle) {
         ctx = res->context_handle;
         /* we are stealing the delegated creds on success, so we do not want
@@ -118,12 +111,18 @@ OM_uint32 gpm_init_sec_context(OM_uint32 *minor_status,
         res->context_handle = NULL;
     }
 
-    ret = gp_conv_gssx_to_buffer_alloc(res->output_token, &outbuf);
-    if (ret) {
-        gpm_save_internal_status(ret, strerror(ret));
-        goto done;
+    if (res->output_token) {
+        ret = gp_conv_gssx_to_buffer_alloc(res->output_token, &outbuf);
+        if (ret) {
+            gpm_save_internal_status(ret, strerror(ret));
+            goto done;
+        }
     }
 
+    ret_maj = res->status.major_status;
+    ret_min = res->status.minor_status;
+    gpm_save_status(&res->status);
+
 done:
     if (ret != 0) {
         ret_min = ret;
diff --git a/proxy/src/gp_export.c b/proxy/src/gp_export.c
index 51dd686..3cd5148 100644
--- a/proxy/src/gp_export.c
+++ b/proxy/src/gp_export.c
@@ -390,6 +390,7 @@ done:
 #define LINUX_LUCID_V1      "linux_lucid_v1"
 
 enum exp_ctx_types {
+    EXP_CTX_PARTIAL = -1, /* cannot be specified by client */
     EXP_CTX_DEFAULT = 0,
     EXP_CTX_LINUX_LUCID_V1 = 1,
 };
@@ -418,6 +419,11 @@ int gp_get_exported_context_type(struct gssx_call_ctx *ctx)
     return EXP_CTX_DEFAULT;
 }
 
+int gp_get_continue_needed_type(void)
+{
+    return EXP_CTX_PARTIAL;
+}
+
 #define KRB5_CTX_FLAG_INITIATOR         0x00000001
 #define KRB5_CTX_FLAG_CFX               0x00000002
 #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY   0x00000004
@@ -513,7 +519,7 @@ done:
 }
 
 
-uint32_t gp_export_ctx_id_to_gssx(uint32_t *min, int type,
+uint32_t gp_export_ctx_id_to_gssx(uint32_t *min, int type, gss_OID mech,
                                   gss_ctx_id_t *in, gssx_ctx *out)
 {
     uint32_t ret_maj;
@@ -529,9 +535,6 @@ uint32_t gp_export_ctx_id_to_gssx(uint32_t *min, int type,
     int is_open;
     int ret;
 
-/* TODO: For mechs that need multiple roundtrips to complete */
-    /* out->state; */
-
     /* we do not need the client to release anything until we handle state */
     out->needs_release = false;
 
@@ -539,6 +542,11 @@ uint32_t gp_export_ctx_id_to_gssx(uint32_t *min, int type,
                                   &lifetime_rec, &mech_type, &ctx_flags,
                                   &is_locally_initiated, &is_open);
     if (ret_maj) {
+        if (type == EXP_CTX_PARTIAL) {
+            /* This may happen on partially established context,
+             * so just go on and put in what we can */
+            goto export;
+        }
         goto done;
     }
 
@@ -571,9 +579,26 @@ uint32_t gp_export_ctx_id_to_gssx(uint32_t *min, int type,
         out->open = true;
     }
 
+export:
     /* note: once converted the original context token is not usable anymore,
      * so this must be the last call to use it */
     switch (type) {
+    case EXP_CTX_PARTIAL:
+        /* this happens only when a init_sec_context call returns a partially
+         * initialized context so we return only what we have, not much */
+        ret = gp_conv_oid_to_gssx(mech, &out->mech);
+        if (ret) {
+            ret_maj = GSS_S_FAILURE;
+            ret_min = ret;
+            goto done;
+        }
+
+        out->locally_initiated = true;
+        out->open = false;
+
+        /* out->state; */
+
+        /* fall through */
     case EXP_CTX_DEFAULT:
         ret_maj = gss_export_sec_context(&ret_min, in, &export_buffer);
         if (ret_maj) {
diff --git a/proxy/src/gp_export.h b/proxy/src/gp_export.h
index 58c0040..03e5d18 100644
--- a/proxy/src/gp_export.h
+++ b/proxy/src/gp_export.h
@@ -37,7 +37,8 @@ uint32_t gp_import_gssx_cred(uint32_t *min, struct gp_call_ctx *gpcall,
                              gssx_cred *cred, gss_cred_id_t *out);
 
 int gp_get_exported_context_type(struct gssx_call_ctx *ctx);
-uint32_t gp_export_ctx_id_to_gssx(uint32_t *min, int type,
+int gp_get_continue_needed_type(void);
+uint32_t gp_export_ctx_id_to_gssx(uint32_t *min, int type, gss_OID mech,
                                   gss_ctx_id_t *in, gssx_ctx *out);
 uint32_t gp_import_gssx_to_ctx_id(uint32_t *min, int type,
                                   gssx_ctx *in, gss_ctx_id_t *out);
diff --git a/proxy/src/gp_rpc_accept_sec_context.c b/proxy/src/gp_rpc_accept_sec_context.c
index 40370aa..efbf07a 100644
--- a/proxy/src/gp_rpc_accept_sec_context.c
+++ b/proxy/src/gp_rpc_accept_sec_context.c
@@ -46,6 +46,8 @@ int gp_accept_sec_context(struct gp_call_ctx *gpcall,
     gss_cred_id_t *pdch = NULL;
     int exp_ctx_type;
     int exp_creds_type;
+    uint32_t acpt_maj;
+    uint32_t acpt_min;
     int ret;
 
     asca = &arg->accept_sec_context;
@@ -109,17 +111,25 @@ int gp_accept_sec_context(struct gp_call_ctx *gpcall,
                                      &ret_flags,
                                      NULL,
                                      pdch);
-    if (ret_maj) {
+    if (ret_maj != GSS_S_COMPLETE &&
+        ret_maj != GSS_S_CONTINUE_NEEDED) {
         goto done;
+    } else {
+        acpt_maj = ret_maj;
+        acpt_min = ret_min;
+    }
+    if (acpt_maj == GSS_S_CONTINUE_NEEDED) {
+        exp_ctx_type = gp_get_continue_needed_type();
     }
 
+
     ascr->context_handle = calloc(1, sizeof(gssx_ctx));
     if (!ascr->context_handle) {
         ret_maj = GSS_S_FAILURE;
         ret_min = ENOMEM;
         goto done;
     }
-    ret_maj = gp_export_ctx_id_to_gssx(&ret_min, exp_ctx_type,
+    ret_maj = gp_export_ctx_id_to_gssx(&ret_min, exp_ctx_type, oid,
                                        &ctx, ascr->context_handle);
     if (ret_maj) {
         goto done;
@@ -138,7 +148,7 @@ int gp_accept_sec_context(struct gp_call_ctx *gpcall,
         goto done;
     }
 
-    if ((ret_flags & GSS_C_DELEG_FLAG) && asca->ret_deleg_cred) {
+    if ((ret_flags & GSS_C_DELEG_FLAG) && asca->ret_deleg_cred && dch) {
         ascr->delegated_cred_handle = calloc(1, sizeof(gssx_cred));
         if (!ascr->delegated_cred_handle) {
             ret_maj = GSS_S_FAILURE;
@@ -159,6 +169,10 @@ int gp_accept_sec_context(struct gp_call_ctx *gpcall,
                                               &ascr->options.options_val);
 
 done:
+    if (ret_maj == GSS_S_COMPLETE) {
+        ret_maj = acpt_maj;
+        ret_min = acpt_min;
+    }
     ret = gp_conv_status_to_gssx(&asca->call_ctx,
                                  ret_maj, ret_min, oid,
                                  &ascr->status);
diff --git a/proxy/src/gp_rpc_get_mic.c b/proxy/src/gp_rpc_get_mic.c
index ca60fe4..2db7d3f 100644
--- a/proxy/src/gp_rpc_get_mic.c
+++ b/proxy/src/gp_rpc_get_mic.c
@@ -73,7 +73,7 @@ int gp_get_mic(struct gp_call_ctx *gpcall,
         goto done;
     }
 
-    ret_maj = gp_export_ctx_id_to_gssx(&ret_min, exp_ctx_type,
+    ret_maj = gp_export_ctx_id_to_gssx(&ret_min, exp_ctx_type, GSS_C_NO_OID,
                                        &context_handle,
                                        gmr->context_handle);
     if (ret_maj) {
diff --git a/proxy/src/gp_rpc_init_sec_context.c b/proxy/src/gp_rpc_init_sec_context.c
index 944389c..2781238 100644
--- a/proxy/src/gp_rpc_init_sec_context.c
+++ b/proxy/src/gp_rpc_init_sec_context.c
@@ -45,6 +45,8 @@ int gp_init_sec_context(struct gp_call_ctx *gpcall,
     gss_buffer_desc obuf = GSS_C_EMPTY_BUFFER;
     uint32_t ret_maj;
     uint32_t ret_min;
+    uint32_t init_maj;
+    uint32_t init_min;
     int exp_ctx_type;
     int ret;
 
@@ -121,6 +123,12 @@ int gp_init_sec_context(struct gp_call_ctx *gpcall,
     if (ret_maj != GSS_S_COMPLETE &&
         ret_maj != GSS_S_CONTINUE_NEEDED) {
         goto done;
+    } else {
+        init_maj = ret_maj;
+        init_min = ret_min;
+    }
+    if (init_maj == GSS_S_CONTINUE_NEEDED) {
+        exp_ctx_type = gp_get_continue_needed_type();
     }
 
     iscr->context_handle = calloc(1, sizeof(gssx_ctx));
@@ -129,7 +137,7 @@ int gp_init_sec_context(struct gp_call_ctx *gpcall,
         ret_min = ENOMEM;
         goto done;
     }
-    ret_maj = gp_export_ctx_id_to_gssx(&ret_min, exp_ctx_type,
+    ret_maj = gp_export_ctx_id_to_gssx(&ret_min, exp_ctx_type, mech_type,
                                        &ctx, iscr->context_handle);
     if (ret_maj) {
         goto done;
@@ -150,7 +158,13 @@ int gp_init_sec_context(struct gp_call_ctx *gpcall,
         }
     }
 
+    ret_maj = GSS_S_COMPLETE;
+
 done:
+    if (ret_maj == GSS_S_COMPLETE) {
+        ret_maj = init_maj;
+        ret_min = init_min;
+    }
     ret = gp_conv_status_to_gssx(&isca->call_ctx,
                                  ret_maj, ret_min, mech_type,
                                  &iscr->status);
diff --git a/proxy/src/gp_rpc_unwrap.c b/proxy/src/gp_rpc_unwrap.c
index a20b8ea..faffa82 100644
--- a/proxy/src/gp_rpc_unwrap.c
+++ b/proxy/src/gp_rpc_unwrap.c
@@ -85,7 +85,7 @@ int gp_unwrap(struct gp_call_ctx *gpcall,
         goto done;
     }
 
-    ret_maj = gp_export_ctx_id_to_gssx(&ret_min, exp_ctx_type,
+    ret_maj = gp_export_ctx_id_to_gssx(&ret_min, exp_ctx_type, GSS_C_NO_OID,
                                        &context_handle,
                                        uwr->context_handle);
     if (ret_maj) {
diff --git a/proxy/src/gp_rpc_verify_mic.c b/proxy/src/gp_rpc_verify_mic.c
index 68369a0..a2d3f7e 100644
--- a/proxy/src/gp_rpc_verify_mic.c
+++ b/proxy/src/gp_rpc_verify_mic.c
@@ -76,7 +76,7 @@ int gp_verify_mic(struct gp_call_ctx *gpcall,
         goto done;
     }
 
-    ret_maj = gp_export_ctx_id_to_gssx(&ret_min, exp_ctx_type,
+    ret_maj = gp_export_ctx_id_to_gssx(&ret_min, exp_ctx_type, GSS_C_NO_OID,
                                        &context_handle,
                                        vmr->context_handle);
     if (ret_maj) {
diff --git a/proxy/src/gp_rpc_wrap.c b/proxy/src/gp_rpc_wrap.c
index d17c292..c2da7ba 100644
--- a/proxy/src/gp_rpc_wrap.c
+++ b/proxy/src/gp_rpc_wrap.c
@@ -85,7 +85,7 @@ int gp_wrap(struct gp_call_ctx *gpcall,
         goto done;
     }
 
-    ret_maj = gp_export_ctx_id_to_gssx(&ret_min, exp_ctx_type,
+    ret_maj = gp_export_ctx_id_to_gssx(&ret_min, exp_ctx_type, GSS_C_NO_OID,
                                        &context_handle, wr->context_handle);
     if (ret_maj) {
         goto done;
-- 
1.8.3.1