From 76298c4b11ddafccc963f618b67643cf14f30dc2 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mar 03 2017 22:27:29 +0000 Subject: [PATCH 1/10] Fix potential memleak from gpm_release_cred Signed-off-by: Simo Sorce --- diff --git a/proxy/src/client/gpm_release_handle.c b/proxy/src/client/gpm_release_handle.c index 2da25d2..7a6aaed 100644 --- a/proxy/src/client/gpm_release_handle.c +++ b/proxy/src/client/gpm_release_handle.c @@ -51,6 +51,8 @@ rel_done: gpm_free_xdrs(GSSX_RELEASE_HANDLE, &uarg, &ures); done: xdr_free((xdrproc_t)xdr_gssx_cred, (char *)r); + free(r); + *cred_handle = NULL; return ret; } From 7fc4ad21bcca07a7ea9b15b1ad0e82232bdef11f Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mar 03 2017 22:27:36 +0000 Subject: [PATCH 2/10] Local vs Remote cred check fixes - Do not check for remote cred in LOCAL_ONLY case In the Local Only case we are instructed to specifically not check with the proxy, so obey that. - Still fall back to remote with cred_store If a cred_store is provided it doesn't mean we should never try a remote call, the cred_store may simply indicate what ccache to use to store the remote credentials reerence and not where to fecth the credential from. Related to #51 Signed-off-by: Simo Sorce --- diff --git a/proxy/src/mechglue/gpp_acquire_cred.c b/proxy/src/mechglue/gpp_acquire_cred.c index 277e61a..fb5bda0 100644 --- a/proxy/src/mechglue/gpp_acquire_cred.c +++ b/proxy/src/mechglue/gpp_acquire_cred.c @@ -120,20 +120,22 @@ OM_uint32 gssi_acquire_cred_from(OM_uint32 *minor_status, } } - in_cred_remote = calloc(1, sizeof(gssx_cred)); - if (!in_cred_remote) { - maj = GSS_S_FAILURE; - min = ENOMEM; - goto done; - } - maj = gppint_retrieve_remote_creds(&min, ccache_name, NULL, - in_cred_remote); - if (maj == GSS_S_COMPLETE) { - behavior = GPP_REMOTE_ONLY; - } else { - safefree(in_cred_remote); - if (ccache_name) { - behavior = GPP_LOCAL_ONLY; + if (behavior != GPP_LOCAL_ONLY) { + in_cred_remote = calloc(1, sizeof(gssx_cred)); + if (!in_cred_remote) { + maj = GSS_S_FAILURE; + min = ENOMEM; + goto done; + } + maj = gppint_retrieve_remote_creds(&min, ccache_name, NULL, + in_cred_remote); + if (maj == GSS_S_COMPLETE) { + behavior = GPP_REMOTE_FIRST; + } else { + safefree(in_cred_remote); + if (ccache_name) { + behavior = GPP_LOCAL_FIRST; + } } } From 7143c099a7fd57648edea13da6b031664f9c36e0 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mar 03 2017 22:29:21 +0000 Subject: [PATCH 3/10] Add a helper function to pack options Signed-off-by: Simo Sorce --- diff --git a/proxy/src/client/gpm_acquire_cred.c b/proxy/src/client/gpm_acquire_cred.c index a2ac068..632973d 100644 --- a/proxy/src/client/gpm_acquire_cred.c +++ b/proxy/src/client/gpm_acquire_cred.c @@ -90,29 +90,16 @@ OM_uint32 gpm_acquire_cred(OM_uint32 *minor_status, /* impersonate calls use input cred and a special option */ if (impersonate) { - gssx_option *opt; - arg->options.options_val = calloc(1, sizeof(gssx_option)); - if (!arg->options.options_val) { + ret_min = gp_add_option(&arg->options.options_val, + &arg->options.options_len, + ACQUIRE_TYPE_OPTION, + sizeof(ACQUIRE_TYPE_OPTION), + ACQUIRE_IMPERSONATE_NAME, + sizeof(ACQUIRE_IMPERSONATE_NAME)); + if (ret_min) { ret_maj = GSS_S_FAILURE; - ret_min = ENOMEM; goto done; } - arg->options.options_len = 1; - opt = &arg->options.options_val[0]; - opt->option.octet_string_val = strdup(ACQUIRE_TYPE_OPTION); - if (!opt->option.octet_string_val) { - ret_maj = GSS_S_FAILURE; - ret_min = ENOMEM; - goto done; - } - opt->option.octet_string_len = sizeof(ACQUIRE_TYPE_OPTION); - opt->value.octet_string_val = strdup(ACQUIRE_IMPERSONATE_NAME); - if (!opt->value.octet_string_val) { - ret_maj = GSS_S_FAILURE; - ret_min = ENOMEM; - goto done; - } - opt->value.octet_string_len = sizeof(ACQUIRE_IMPERSONATE_NAME); } /* execute proxy request */ diff --git a/proxy/src/gp_common.h b/proxy/src/gp_common.h index 5b9b9b2..9f23f3e 100644 --- a/proxy/src/gp_common.h +++ b/proxy/src/gp_common.h @@ -117,4 +117,8 @@ do { \ #define ACQUIRE_TYPE_OPTION "acquire_type" #define ACQUIRE_IMPERSONATE_NAME "impersonate_name" +uint32_t gp_add_option(gssx_option **options_val, u_int *options_len, + const void *option, size_t option_len, + const void *value, size_t value_len); + #endif /* _GP_COMMON_H_ */ diff --git a/proxy/src/gp_util.c b/proxy/src/gp_util.c index ff1cfed..a91f392 100644 --- a/proxy/src/gp_util.c +++ b/proxy/src/gp_util.c @@ -143,3 +143,46 @@ ssize_t gp_safe_write(int fd, const void *buf, size_t count) return len; } + +uint32_t gp_add_option(gssx_option **options_val, u_int *options_len, + const void *option, size_t option_len, + const void *value, size_t value_len) +{ + gssx_option opt = { 0 }; + gssx_option *out; + uint32_t ret; + + opt.option.octet_string_val = malloc(option_len); + if (!opt.option.octet_string_val) { + ret = ENOMEM; + goto done; + } + 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; + } + 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) { + ret = ENOMEM; + goto done; + } + + out[*options_len] = opt; + *options_val = out; + (*options_len)++; + + ret = 0; + +done: + if (ret) { + xdr_free((xdrproc_t)xdr_gssx_option, (char *)&opt); + } + return ret; +} From 7f47a43b9aee3ad017bf9109972602a69d089354 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mar 03 2017 22:45:23 +0000 Subject: [PATCH 4/10] Add ability to sync creds back on modification This is the proxy server side, if enabled, and if the client requests it then the server will check if new credentials are available, and if so will send back a fresh copy to the client. Works only if: - allow_client_ccache_sync is True - a custom ccache is not set for the service - the client explicitly requests a sync for the call Signed-off-by: Simo Sorce --- diff --git a/proxy/man/gssproxy.conf.5.xml b/proxy/man/gssproxy.conf.5.xml index 7ddb2fb..ad9d96f 100644 --- a/proxy/man/gssproxy.conf.5.xml +++ b/proxy/man/gssproxy.conf.5.xml @@ -126,6 +126,20 @@ + allow_client_ccache_sync (boolean) + + Allow clients to request credentials to be sent back for better + caching. + This option allows the proxy, in certain circumstances, to send back + an additional option in the response structure of certain calls when + it determines that a new ticket may have been added to the internal + ccache. Clients can then replace their (encrypted) copy with the + updated ccache. + Default: false + + + + cred_usage (string) Allow to restrict the kind of operations permitted for this service. diff --git a/proxy/src/gp_common.h b/proxy/src/gp_common.h index 9f23f3e..36fd843 100644 --- a/proxy/src/gp_common.h +++ b/proxy/src/gp_common.h @@ -116,6 +116,11 @@ do { \ #define ACQUIRE_TYPE_OPTION "acquire_type" #define ACQUIRE_IMPERSONATE_NAME "impersonate_name" +#define CRED_SYNC_OPTION "sync_modified_creds" +#define CRED_SYNC_DEFAULT "default" +#define CRED_SYNC_PAYLOAD "sync_creds" + +#define GPKRB_MAX_CRED_SIZE 1024 * 512 uint32_t gp_add_option(gssx_option **options_val, u_int *options_len, const void *option, size_t option_len, diff --git a/proxy/src/gp_config.c b/proxy/src/gp_config.c index 184f59e..1b833fd 100644 --- a/proxy/src/gp_config.c +++ b/proxy/src/gp_config.c @@ -387,6 +387,14 @@ static int load_services(struct gp_config *cfg, struct gp_ini_context *ctx) } } + ret = gp_config_get_string(ctx, secname, + "allow_client_ccache_sync", &value); + if (ret == 0) { + if (gp_boolean_is_true(value)) { + cfg->svcs[n]->allow_cc_sync = true; + } + } + ret = gp_config_get_string(ctx, secname, "trusted", &value); if (ret == 0) { if (gp_boolean_is_true(value)) { diff --git a/proxy/src/gp_creds.c b/proxy/src/gp_creds.c index db5b4b2..5623bb8 100644 --- a/proxy/src/gp_creds.c +++ b/proxy/src/gp_creds.c @@ -15,6 +15,7 @@ #include "gp_rpc_creds.h" #include "gp_creds.h" #include "gp_conv.h" +#include "gp_export.h" #define GSS_MECH_KRB5_OID_LENGTH 9 #define GSS_MECH_KRB5_OID "\052\206\110\206\367\022\001\002\002" @@ -871,3 +872,164 @@ done: *min = ret_min; return ret_maj; } + +uint32_t gp_count_tickets(uint32_t *min, gss_cred_id_t cred, uint32_t *ccsum) +{ + uint32_t ret_maj = 0; + uint32_t ret_min = 0; + char *memcache = NULL; + krb5_context context = NULL; + krb5_ccache ccache = NULL; + krb5_cc_cursor cursor = NULL; + krb5_creds creds; + int err; + + err = krb5_init_context(&context); + if (err) { + ret_min = err; + ret_maj = GSS_S_FAILURE; + goto done; + } + + /* Create a memory ccache we can iterate with libkrb5 functions */ + gss_key_value_element_desc ccelement = { "ccache", NULL }; + gss_key_value_set_desc cred_store = { 1, &ccelement }; + + err = asprintf(&memcache, "MEMORY:cred_allowed_%p", &memcache); + if (err == -1) { + memcache = NULL; + ret_min = ENOMEM; + ret_maj = GSS_S_FAILURE; + goto done; + } + cred_store.elements[0].value = memcache; + + ret_maj = gss_store_cred_into(&ret_min, cred, GSS_C_INITIATE, + discard_const(gss_mech_krb5), 1, 0, + &cred_store, NULL, NULL); + if (ret_maj != GSS_S_COMPLETE) { + goto done; + } + + err = krb5_cc_resolve(context, memcache, &ccache); + if (err) { + ret_min = err; + ret_maj = GSS_S_FAILURE; + goto done; + } + + err = krb5_cc_start_seq_get(context, ccache, &cursor); + if (err) { + ret_min = err; + ret_maj = GSS_S_FAILURE; + goto done; + } + + do { + err = krb5_cc_next_cred(context, ccache, &cursor, &creds); + if (err && err != KRB5_CC_END) { + ret_min = err; + ret_maj = GSS_S_FAILURE; + goto done; + } + + /* TODO: Should we ch real ecksum over all creds->ticket data and + * flags in future ? */ + (*ccsum)++; + + } while(err == 0); + + err = krb5_cc_end_seq_get(context, ccache, &cursor); + if (err) { + ret_min = err; + ret_maj = GSS_S_FAILURE; + goto done; + } + +done: + if (context) { + /* NOTE: destroy only if we created a MEMORY ccache */ + if (ccache) { + if (memcache) krb5_cc_destroy(context, ccache); + else krb5_cc_close(context, ccache); + } + krb5_free_context(context); + } + free(memcache); + *min = ret_min; + return ret_maj; +} + +/* Check if cred refresh is being requested by the client. + * if so, take a snapshot of the cred so that later we can check if anything + * was added */ + +uint32_t gp_check_sync_creds(struct gp_cred_check_handle *h, + gss_cred_id_t cred) +{ + uint32_t ret_maj = 0; + uint32_t ret_min = 0; + struct gp_service *svc = h->ctx->service; + struct gssx_option *opt = NULL; + uint32_t ccsum = 0; + + if (!svc->allow_cc_sync) return 0; + + gp_options_find(opt, h->options, CRED_SYNC_OPTION, + sizeof(CRED_SYNC_OPTION)); + if (!opt) return 0; + if (!gpopt_string_match(&opt->value, CRED_SYNC_DEFAULT, + sizeof(CRED_SYNC_DEFAULT))) return 0; + + for (size_t i = 0; i < svc->krb5.store.count; i++) { + if (strcmp(svc->krb5.store.elements[i].key, "ccache") == 0) { + /* Saving in local ccache no need to sync up to client */ + return 0; + } + } + + ret_maj = gp_count_tickets(&ret_min, cred, &ccsum); + if (ret_maj) return 0; + + return ccsum; +} + +uint32_t gp_export_sync_creds(uint32_t *min, struct gp_call_ctx *gpcall, + gss_cred_id_t *cred, + gssx_option **options_val, u_int *options_len) +{ + uint32_t ret_maj = 0; + uint32_t ret_min = 0; + gssx_cred creds = { 0 }; + char value[GPKRB_MAX_CRED_SIZE]; + size_t len; + XDR xdrctx; + bool xdrok; + + ret_maj = gp_export_gssx_cred(&ret_min, gpcall, cred, &creds); + if (ret_maj) goto done; + + xdrmem_create(&xdrctx, value, GPKRB_MAX_CRED_SIZE, XDR_ENCODE); + xdrok = xdr_gssx_cred(&xdrctx, &creds); + if (!xdrok) { + ret_min = ENOSPC; + ret_maj = GSS_S_FAILURE; + goto done; + } + len = xdr_getpos(&xdrctx); + + ret_min = gp_add_option(options_val, options_len, CRED_SYNC_PAYLOAD, + sizeof(CRED_SYNC_PAYLOAD), value, len); + if (ret_min) { + ret_maj = GSS_S_FAILURE; + goto done; + } + + ret_min = 0; + ret_maj = GSS_S_COMPLETE; + +done: + xdr_free((xdrproc_t)xdr_gssx_cred, (char *)&creds); + *min = ret_min; + return ret_maj; +} diff --git a/proxy/src/gp_proxy.h b/proxy/src/gp_proxy.h index 869000d..971a7b6 100644 --- a/proxy/src/gp_proxy.h +++ b/proxy/src/gp_proxy.h @@ -32,6 +32,7 @@ struct gp_service { bool any_uid; bool allow_proto_trans; bool allow_const_deleg; + bool allow_cc_sync; bool trusted; bool kernel_nfsd; bool impersonate; diff --git a/proxy/src/gp_rpc_creds.h b/proxy/src/gp_rpc_creds.h index 93df7e1..54fe482 100644 --- a/proxy/src/gp_rpc_creds.h +++ b/proxy/src/gp_rpc_creds.h @@ -38,4 +38,17 @@ uint32_t gp_cred_allowed(uint32_t *min, void gp_filter_flags(struct gp_call_ctx *gpcall, uint32_t *flags); +struct gp_cred_check_handle { + struct gp_call_ctx *ctx; + struct { + u_int options_len; + gssx_option *options_val; + } options; +}; +uint32_t gp_check_sync_creds(struct gp_cred_check_handle *h, + gss_cred_id_t cred); +uint32_t gp_export_sync_creds(uint32_t *min, struct gp_call_ctx *gpcall, + gss_cred_id_t *cred, + gssx_option **options_val, u_int *options_len); + #endif /* _GP_RPC_CREDS_H_ */ diff --git a/proxy/src/gp_rpc_init_sec_context.c b/proxy/src/gp_rpc_init_sec_context.c index f3dc11d..767a3ff 100644 --- a/proxy/src/gp_rpc_init_sec_context.c +++ b/proxy/src/gp_rpc_init_sec_context.c @@ -26,6 +26,13 @@ int gp_init_sec_context(struct gp_call_ctx *gpcall, uint32_t init_maj; uint32_t init_min; int exp_ctx_type; + struct gp_cred_check_handle gcch = { + .ctx = gpcall, + .options.options_len = arg->init_sec_context.options.options_len, + .options.options_val = arg->init_sec_context.options.options_val, + }; + uint32_t gccn_before = 0; + uint32_t gccn_after = 0; int ret; isca = &arg->init_sec_context; @@ -54,6 +61,8 @@ int gp_init_sec_context(struct gp_call_ctx *gpcall, if (ret_maj) { goto done; } + + gccn_before = gp_check_sync_creds(&gcch, ich); } ret_maj = gp_conv_gssx_to_name(&ret_min, isca->target_name, &target_name); @@ -157,6 +166,20 @@ int gp_init_sec_context(struct gp_call_ctx *gpcall, } } + gccn_after = gp_check_sync_creds(&gcch, ich); + + if (gccn_before != gccn_after) { + /* export creds back to client for sync up */ + ret_maj = gp_export_sync_creds(&ret_min, gpcall, &ich, + &iscr->options.options_val, + &iscr->options.options_len); + if (ret_maj) { + /* not fatal, log and continue */ + GPDEBUG("Failed to export sync creds (%d: %d)", + (int)ret_maj, (int)ret_min); + } + } + ret_maj = GSS_S_COMPLETE; done: diff --git a/proxy/src/mechglue/gpp_creds.c b/proxy/src/mechglue/gpp_creds.c index 8fcef36..21ecabd 100644 --- a/proxy/src/mechglue/gpp_creds.c +++ b/proxy/src/mechglue/gpp_creds.c @@ -4,7 +4,6 @@ #include #define GPKRB_SRV_NAME "Encrypted/Credentials/v1@X-GSSPROXY:" -#define GPKRB_MAX_CRED_SIZE 1024 * 512 uint32_t gpp_store_remote_creds(uint32_t *min, gss_const_key_value_set_t cred_store, From 82e4480e9ba2bc0d39f72b4d4b43d8064e79efa0 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mar 03 2017 22:45:25 +0000 Subject: [PATCH 5/10] Do not re-export unchanged creds This avoids a needless re-encryption operation and also insures the client receives back the exact same input; this way the client can detect if credentials have changed. Signed-off-by: Simo Sorce --- diff --git a/proxy/src/gp_rpc_acquire_cred.c b/proxy/src/gp_rpc_acquire_cred.c index 7f40c64..9a55937 100644 --- a/proxy/src/gp_rpc_acquire_cred.c +++ b/proxy/src/gp_rpc_acquire_cred.c @@ -137,10 +137,16 @@ int gp_acquire_cred(struct gp_call_ctx *gpcall, ret_min = ENOMEM; goto done; } - ret_maj = gp_export_gssx_cred(&ret_min, gpcall, - &out_cred, acr->output_cred_handle); - if (ret_maj) { - goto done; + + if (out_cred == in_cred) { + acr->output_cred_handle = aca->input_cred_handle; + aca->input_cred_handle = NULL; + } else { + ret_maj = gp_export_gssx_cred(&ret_min, gpcall, + &out_cred, acr->output_cred_handle); + if (ret_maj) { + goto done; + } } done: From da244cd03b5c61aad1c41d74e3a4fd788096ec3c Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mar 03 2017 22:45:25 +0000 Subject: [PATCH 6/10] Rework gpp_cred_handle management Provide helper functions to create and free gpp_cred_handle, and also record if the credential is a default credntial or there is a custome ccache name associated with it' This is in preparation of following patches. Signed-off-by: Simo Sorce --- diff --git a/proxy/src/mechglue/gpp_accept_sec_context.c b/proxy/src/mechglue/gpp_accept_sec_context.c index 3c3244f..7cf8170 100644 --- a/proxy/src/mechglue/gpp_accept_sec_context.c +++ b/proxy/src/mechglue/gpp_accept_sec_context.c @@ -79,12 +79,8 @@ OM_uint32 gssi_accept_sec_context(OM_uint32 *minor_status, } if (delegated_cred_handle) { - deleg_cred = calloc(1, sizeof(struct gpp_cred_handle)); - if (!deleg_cred) { - maj = GSS_S_FAILURE; - min = ENOMEM; - goto done; - } + maj = gpp_cred_handle_init(&min, false, NULL, &deleg_cred); + if (!maj) goto done; } /* behavior has been set to local only or remote only by context or diff --git a/proxy/src/mechglue/gpp_acquire_cred.c b/proxy/src/mechglue/gpp_acquire_cred.c index fb5bda0..28ded9b 100644 --- a/proxy/src/mechglue/gpp_acquire_cred.c +++ b/proxy/src/mechglue/gpp_acquire_cred.c @@ -102,13 +102,6 @@ OM_uint32 gssi_acquire_cred_from(OM_uint32 *minor_status, tmaj = GSS_S_COMPLETE; tmin = 0; - out_cred_handle = calloc(1, sizeof(struct gpp_cred_handle)); - if (!out_cred_handle) { - maj = GSS_S_FAILURE; - min = ENOMEM; - goto done; - } - name = (struct gpp_name_handle *)desired_name; behavior = gpp_get_behavior(); @@ -120,6 +113,10 @@ OM_uint32 gssi_acquire_cred_from(OM_uint32 *minor_status, } } + maj = gpp_cred_handle_init(&min, !ccache_name, ccache_name, + &out_cred_handle); + if (maj) goto done; + if (behavior != GPP_LOCAL_ONLY) { in_cred_remote = calloc(1, sizeof(gssx_cred)); if (!in_cred_remote) { @@ -196,7 +193,7 @@ done: if (maj == GSS_S_COMPLETE) { *output_cred_handle = (gss_cred_id_t)out_cred_handle; } else { - free(out_cred_handle); + (void)gpp_cred_handle_free(&tmin, out_cred_handle); } *minor_status = gpp_map_error(min); return maj; @@ -329,10 +326,10 @@ OM_uint32 gssi_acquire_cred_with_password(OM_uint32 *minor_status, behavior = gpp_get_behavior(); - out_cred_handle = calloc(1, sizeof(struct gpp_cred_handle)); - if (!out_cred_handle) { - *minor_status = gpp_map_error(ENOMEM); - return GSS_S_FAILURE; + maj = gpp_cred_handle_init(&min, false, NULL, &out_cred_handle); + if (maj) { + *minor_status = gpp_map_error(min); + return maj; } switch (behavior) { @@ -426,12 +423,8 @@ OM_uint32 gssi_acquire_cred_impersonate_name(OM_uint32 *minor_status, tmaj = GSS_S_COMPLETE; tmin = 0; - out_cred_handle = calloc(1, sizeof(struct gpp_cred_handle)); - if (!out_cred_handle) { - maj = GSS_S_FAILURE; - min = ENOMEM; - goto done; - } + maj = gpp_cred_handle_init(&min, false, NULL, &out_cred_handle); + if (maj) goto done; name = (struct gpp_name_handle *)desired_name; behavior = gpp_get_behavior(); diff --git a/proxy/src/mechglue/gpp_creds.c b/proxy/src/mechglue/gpp_creds.c index 21ecabd..d8b17e1 100644 --- a/proxy/src/mechglue/gpp_creds.c +++ b/proxy/src/mechglue/gpp_creds.c @@ -5,7 +5,85 @@ #define GPKRB_SRV_NAME "Encrypted/Credentials/v1@X-GSSPROXY:" -uint32_t gpp_store_remote_creds(uint32_t *min, +uint32_t gpp_cred_handle_init(uint32_t *min, bool defcred, const char *ccache, + struct gpp_cred_handle **out_handle) +{ + struct gpp_cred_handle *h = NULL; + uint32_t maj = 0; + + h = calloc(1, sizeof(struct gpp_cred_handle)); + if (!h) { + *min = ENOMEM; + return GSS_S_FAILURE; + } + + h->default_creds = defcred; + + if (ccache) { + h->store.elements = calloc(1, sizeof(gss_key_value_element_desc)); + if (!h->store.elements) { + *min = ENOMEM; + maj = GSS_S_FAILURE; + goto done; + } + h->store.count = 1; + + h->store.elements[0].key = strdup("ccache"); + if (!h->store.elements[0].key) { + *min = ENOMEM; + maj = GSS_S_FAILURE; + goto done; + } + + h->store.elements[0].value = strdup(ccache); + if (!h->store.elements[0].value) { + *min = ENOMEM; + maj = GSS_S_FAILURE; + goto done; + } + } + +done: + if (maj) { + uint32_t tmp; + (void)gpp_cred_handle_free(&tmp, h); + } else { + *out_handle = h; + } + return maj; +} + +uint32_t gpp_cred_handle_free(uint32_t *min, struct gpp_cred_handle *handle) +{ + uint32_t maj = GSS_S_COMPLETE; + + *min = 0; + + if (!handle) return GSS_S_COMPLETE; + + if (handle->local) { + maj = gss_release_cred(min, &handle->local); + } + + if (handle->remote) { + xdr_free((xdrproc_t)xdr_gssx_cred, (char *)handle->remote); + free(handle->remote); + } + + if (handle->store.count > 0) { + for (size_t i = 0; i < handle->store.count; i++) { + free((void *)handle->store.elements[i].key); + free((void *)handle->store.elements[i].value); + } + free(handle->store.elements); + handle->store.count = 0; + } + + free(handle); + return maj; +} + +uint32_t gpp_store_remote_creds(uint32_t *min, bool default_creds, gss_const_key_value_set_t cred_store, gssx_cred *creds) { @@ -35,6 +113,10 @@ uint32_t gpp_store_remote_creds(uint32_t *min, } } if (!ccache) { + if (!default_creds) { + ret = ENOMEDIUM; + goto done; + } ret = krb5_cc_default(ctx, &ccache); if (ret) goto done; } @@ -140,7 +222,7 @@ done: static OM_uint32 get_local_def_creds(OM_uint32 *minor_status, struct gpp_name_handle *name, gss_cred_usage_t cred_usage, - struct gpp_cred_handle *cred_handle) + gss_cred_id_t *cred_handle) { gss_OID_set interposed_mechs = GSS_C_NO_OID_SET; gss_OID_set special_mechs = GSS_C_NO_OID_SET; @@ -159,7 +241,7 @@ static OM_uint32 get_local_def_creds(OM_uint32 *minor_status, } maj = gss_acquire_cred(&min, name ? name->local : NULL, 0, special_mechs, - cred_usage, &cred_handle->local, NULL, NULL); + cred_usage, cred_handle, NULL, NULL); done: *minor_status = min; (void)gss_release_oid_set(&min, &special_mechs); @@ -179,17 +261,21 @@ OM_uint32 gppint_get_def_creds(OM_uint32 *minor_status, OM_uint32 maj = GSS_S_FAILURE; OM_uint32 min = 0; - cred = calloc(1, sizeof(struct gpp_cred_handle)); - if (!cred) { - min = ENOMEM; - goto done; + if (*cred_handle) { + cred = *cred_handle; + } else { + maj = gpp_cred_handle_init(&min, true, NULL, &cred); + if (maj) { + *minor_status = min; + return maj; + } } /* See if we should try local first */ if (behavior == GPP_LOCAL_ONLY || behavior == GPP_LOCAL_FIRST) { - maj = get_local_def_creds(&min, name, cred_usage, cred); - if (maj != GSS_S_NO_CRED || behavior != GPP_LOCAL_FIRST) { + maj = get_local_def_creds(&min, name, cred_usage, &cred->local); + if (maj == GSS_S_COMPLETE || behavior == GPP_LOCAL_ONLY) { goto done; } @@ -199,7 +285,7 @@ OM_uint32 gppint_get_def_creds(OM_uint32 *minor_status, } /* Then try with remote */ - if (behavior == GPP_REMOTE_ONLY || behavior == GPP_REMOTE_FIRST) { + if (behavior != GPP_LOCAL_ONLY) { gssx_cred remote; gssx_cred *premote = NULL; @@ -219,12 +305,14 @@ OM_uint32 gppint_get_def_creds(OM_uint32 *minor_status, xdr_free((xdrproc_t)xdr_gssx_cred, (char *)&remote); - if (maj == GSS_S_COMPLETE || behavior == GPP_REMOTE_ONLY) { + if (maj == GSS_S_COMPLETE) { goto done; } - /* So remote failed, but we can fallback to local, try that */ - maj = get_local_def_creds(&min, name, cred_usage, cred); + if (behavior == GPP_REMOTE_FIRST) { + /* So remote failed, but we can fallback to local, try that */ + maj = get_local_def_creds(&min, name, cred_usage, &cred->local); + } } done: @@ -234,7 +322,9 @@ done: } *minor_status = min; if (maj != GSS_S_COMPLETE) { - gssi_release_cred(&min, (gss_cred_id_t *)&cred); + if (cred != *cred_handle) { + gssi_release_cred(&min, (gss_cred_id_t *)&cred); + } } *cred_handle = cred; return maj; @@ -543,7 +633,8 @@ OM_uint32 gssi_store_cred_into(OM_uint32 *minor_status, cred = (struct gpp_cred_handle *)input_cred_handle; if (cred->remote) { - maj = gpp_store_remote_creds(&min, cred_store, cred->remote); + maj = gpp_store_remote_creds(&min, default_cred != 0, cred_store, + cred->remote); goto done; } @@ -559,40 +650,29 @@ done: OM_uint32 gssi_release_cred(OM_uint32 *minor_status, gss_cred_id_t *cred_handle) { - struct gpp_cred_handle *cred; - OM_uint32 maj, min; - OM_uint32 rmaj = GSS_S_COMPLETE; + struct gpp_cred_handle *handle; + uint32_t tmaj; + uint32_t tmin; + uint32_t maj; + uint32_t min; GSSI_TRACE(); - if (cred_handle == NULL) { - return GSS_S_NO_CRED | GSS_S_CALL_INACCESSIBLE_READ; - } else if (*cred_handle == GSS_C_NO_CREDENTIAL) { - *minor_status = 0; - return GSS_S_COMPLETE; - } + if (cred_handle == NULL) return GSS_S_CALL_INACCESSIBLE_READ; - cred = (struct gpp_cred_handle *)*cred_handle; + handle = (struct gpp_cred_handle *)*cred_handle; - if (cred->local) { - maj = gss_release_cred(&min, &cred->local); - if (maj != GSS_S_COMPLETE) { - rmaj = maj; - *minor_status = gpp_map_error(min); - } - } + tmaj = gpm_release_cred(&tmin, &handle->remote); - if (cred->remote) { - maj = gpm_release_cred(&min, &cred->remote); - if (maj && rmaj == GSS_S_COMPLETE) { - rmaj = maj; - *minor_status = gpp_map_error(min); - } + maj = gpp_cred_handle_free(&min, handle); + if (tmaj && maj == GSS_S_COMPLETE) { + maj = tmaj; + min = tmin; } - free(cred); *cred_handle = GSS_C_NO_CREDENTIAL; - return rmaj; + *minor_status = min; + return maj; } OM_uint32 gssi_export_cred(OM_uint32 *minor_status, @@ -638,11 +718,8 @@ OM_uint32 gssi_import_cred_by_mech(OM_uint32 *minor_status, GSSI_TRACE(); - cred = calloc(1, sizeof(struct gpp_cred_handle)); - if (!cred) { - *minor_status = 0; - return GSS_S_FAILURE; - } + maj = gpp_cred_handle_init(minor_status, false, NULL, &cred); + if (maj) return maj; /* NOTE: it makes no sense to import a cred remotely atm, * so we only handle the local case for now. */ @@ -679,4 +756,3 @@ done: (void)gss_release_buffer(&min, &wrap_token); return maj; } - diff --git a/proxy/src/mechglue/gpp_init_sec_context.c b/proxy/src/mechglue/gpp_init_sec_context.c index 7b10400..920ac14 100644 --- a/proxy/src/mechglue/gpp_init_sec_context.c +++ b/proxy/src/mechglue/gpp_init_sec_context.c @@ -110,12 +110,8 @@ OM_uint32 gssi_init_sec_context(OM_uint32 *minor_status, goto done; } } else { - cred_handle = calloc(1, sizeof(struct gpp_cred_handle)); - if (!cred_handle) { - maj = GSS_S_FAILURE; - min = ENOMEM; - goto done; - } + maj = gpp_cred_handle_init(&min, true, NULL, &cred_handle); + if (maj) goto done; } name = (struct gpp_name_handle *)target_name; @@ -152,18 +148,9 @@ OM_uint32 gssi_init_sec_context(OM_uint32 *minor_status, } if (!cred_handle->remote) { - struct gpp_cred_handle *r_creds; - - maj = gppint_get_def_creds(&min, - GPP_REMOTE_ONLY, - NULL, - GSS_C_INITIATE, - &r_creds); - if (maj == GSS_S_COMPLETE) { - /* steal result */ - cred_handle->remote = r_creds->remote; - free(r_creds); - } + /* we ignore failures here */ + (void)gppint_get_def_creds(&min, GPP_REMOTE_ONLY, NULL, + GSS_C_INITIATE, &cred_handle); } maj = gpm_init_sec_context(&min, @@ -179,16 +166,17 @@ OM_uint32 gssi_init_sec_context(OM_uint32 *minor_status, output_token, ret_flags, time_rec); - if (maj == GSS_S_COMPLETE || maj == GSS_S_CONTINUE_NEEDED || - behavior == GPP_REMOTE_ONLY) { + if (maj == GSS_S_COMPLETE || maj == GSS_S_CONTINUE_NEEDED) { goto done; } - /* So remote failed, but we can fallback to local, try that */ - maj = init_ctx_local(&min, cred_handle, ctx_handle, name, - mech_type, req_flags, time_req, input_cb, - input_token, actual_mech_type, output_token, - ret_flags, time_rec); + if (behavior == GPP_REMOTE_FIRST) { + /* So remote failed, but we can fallback to local, try that */ + maj = init_ctx_local(&min, cred_handle, ctx_handle, name, + mech_type, req_flags, time_req, input_cb, + input_token, actual_mech_type, output_token, + ret_flags, time_rec); + } } done: diff --git a/proxy/src/mechglue/gss_plugin.h b/proxy/src/mechglue/gss_plugin.h index d32f2bc..7b87519 100644 --- a/proxy/src/mechglue/gss_plugin.h +++ b/proxy/src/mechglue/gss_plugin.h @@ -7,9 +7,12 @@ struct gpp_cred_handle { gssx_cred *remote; + gss_key_value_set_desc store; + bool default_creds; gss_cred_id_t local; }; + struct gpp_context_handle { gssx_ctx *remote; gss_ctx_id_t local; @@ -69,6 +72,12 @@ uint32_t gpp_name_to_local(uint32_t *minor, gssx_name *name, gss_OID mech_type, gss_name_t *mech_name); uint32_t gpp_local_to_name(uint32_t *minor, gss_name_t local_name, gssx_name **name); +uint32_t gpp_cred_handle_init(uint32_t *min, bool defcred, const char *ccache, + struct gpp_cred_handle **out_handle); +uint32_t gpp_cred_handle_free(uint32_t *min, struct gpp_cred_handle *handle); +uint32_t gpp_store_remote_creds(uint32_t *min, bool default_creds, + gss_const_key_value_set_t cred_store, + gssx_cred *creds); OM_uint32 gssi_internal_release_oid(OM_uint32 *minor_status, gss_OID *oid); From 7e004c960807c9952e17cf6d9d05a3ab69943934 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mar 03 2017 22:45:25 +0000 Subject: [PATCH 7/10] Add utility function to compare gssx_creds This is not a full comparison, just enough to detect if creds have changed in an acquire_cred loop to a proxy. Signed-off-by: Simo Sorce --- diff --git a/proxy/src/mechglue/gpp_creds.c b/proxy/src/mechglue/gpp_creds.c index d8b17e1..50689f6 100644 --- a/proxy/src/mechglue/gpp_creds.c +++ b/proxy/src/mechglue/gpp_creds.c @@ -83,6 +83,42 @@ uint32_t gpp_cred_handle_free(uint32_t *min, struct gpp_cred_handle *handle) return maj; } +/* NOTE: currently the only things we check for are the cred name and the + * cred_handle_reference, we do NOT check each cred element except for them to + * match in number */ +bool gpp_creds_are_equal(gssx_cred *a, gssx_cred *b) +{ + gssx_buffer *ta; + gssx_buffer *tb; + + if (!a && !b) return true; + if (!a || !b) return false; + + ta = &a->desired_name.display_name; + tb = &b->desired_name.display_name; + if (ta->octet_string_len != tb->octet_string_len) return false; + if (!ta->octet_string_val && tb->octet_string_val) return false; + if (ta->octet_string_val) { + if (!tb->octet_string_val) return false; + if (memcmp(ta->octet_string_val, tb->octet_string_val, + ta->octet_string_len) != 0) return false; + } + + if (a->elements.elements_len != b->elements.elements_len) return false; + + ta = &a->cred_handle_reference; + tb = &b->cred_handle_reference; + if (ta->octet_string_len != tb->octet_string_len) return false; + if (!ta->octet_string_val && tb->octet_string_val) return false; + if (ta->octet_string_val) { + if (!tb->octet_string_val) return false; + if (memcmp(ta->octet_string_val, tb->octet_string_val, + ta->octet_string_len) != 0) return false; + } + + return true; +} + uint32_t gpp_store_remote_creds(uint32_t *min, bool default_creds, gss_const_key_value_set_t cred_store, gssx_cred *creds) diff --git a/proxy/src/mechglue/gss_plugin.h b/proxy/src/mechglue/gss_plugin.h index 7b87519..333d63c 100644 --- a/proxy/src/mechglue/gss_plugin.h +++ b/proxy/src/mechglue/gss_plugin.h @@ -75,6 +75,7 @@ uint32_t gpp_local_to_name(uint32_t *minor, uint32_t gpp_cred_handle_init(uint32_t *min, bool defcred, const char *ccache, struct gpp_cred_handle **out_handle); uint32_t gpp_cred_handle_free(uint32_t *min, struct gpp_cred_handle *handle); +bool gpp_creds_are_equal(gssx_cred *a, gssx_cred *b); uint32_t gpp_store_remote_creds(uint32_t *min, bool default_creds, gss_const_key_value_set_t cred_store, gssx_cred *creds); From 451f8485d6becb4586b7bcd3ff9b8781856abdae Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mar 03 2017 22:45:25 +0000 Subject: [PATCH 8/10] Always request cred sync on init_sec_context Signed-off-by: Simo Sorce --- diff --git a/proxy/src/client/gpm_init_sec_context.c b/proxy/src/client/gpm_init_sec_context.c index 82c84ee..bea2010 100644 --- a/proxy/src/client/gpm_init_sec_context.c +++ b/proxy/src/client/gpm_init_sec_context.c @@ -3,6 +3,26 @@ #include "gssapi_gpm.h" #include "src/gp_conv.h" +static void return_new_cred_handle(struct gssx_option *val, + gssx_cred **out_cred_handle) +{ + gssx_cred *creds; + XDR xdrctx; + bool xdrok; + + creds = calloc(1, sizeof(*creds)); + if (creds) { + xdrmem_create(&xdrctx, val->value.octet_string_val, + val->value.octet_string_len, XDR_DECODE); + xdrok = xdr_gssx_cred(&xdrctx, creds); + if (xdrok) { + *out_cred_handle = creds; + } else { + free(creds); + } + } +} + OM_uint32 gpm_init_sec_context(OM_uint32 *minor_status, gssx_cred *cred_handle, gssx_ctx **context_handle, @@ -15,7 +35,8 @@ OM_uint32 gpm_init_sec_context(OM_uint32 *minor_status, gss_OID *actual_mech_type, gss_buffer_t output_token, OM_uint32 *ret_flags, - OM_uint32 *time_rec) + OM_uint32 *time_rec, + gssx_cred **out_cred_handle) { union gp_rpc_arg uarg; union gp_rpc_res ures; @@ -40,6 +61,12 @@ OM_uint32 gpm_init_sec_context(OM_uint32 *minor_status, arg->context_handle = *context_handle; } + /* always try request cred sync, ignore errors, not critical */ + (void)gp_add_option(&arg->options.options_val, + &arg->options.options_len, + CRED_SYNC_OPTION, sizeof(CRED_SYNC_OPTION), + CRED_SYNC_DEFAULT, sizeof(CRED_SYNC_DEFAULT)); + arg->target_name = target_name; ret = gp_conv_oid_to_gssx(mech_type, &arg->mech_type); @@ -96,6 +123,16 @@ OM_uint32 gpm_init_sec_context(OM_uint32 *minor_status, } } + /* check if a sync cred was returned to us, don't fail on errors */ + if (out_cred_handle && res->options.options_len > 0) { + struct gssx_option *val = NULL; + gp_options_find(val, res->options, CRED_SYNC_PAYLOAD, + sizeof(CRED_SYNC_PAYLOAD)); + if (val) { + return_new_cred_handle(val, out_cred_handle); + } + } + ret_maj = res->status.major_status; ret_min = res->status.minor_status; gpm_save_status(&res->status); diff --git a/proxy/src/client/gssapi_gpm.h b/proxy/src/client/gssapi_gpm.h index 667b0e0..22beecf 100644 --- a/proxy/src/client/gssapi_gpm.h +++ b/proxy/src/client/gssapi_gpm.h @@ -158,7 +158,8 @@ OM_uint32 gpm_init_sec_context(OM_uint32 *minor_status, gss_OID *actual_mech_type, gss_buffer_t output_token, OM_uint32 *ret_flags, - OM_uint32 *time_rec); + OM_uint32 *time_rec, + gssx_cred **out_cred_handle); OM_uint32 gpm_inquire_context(OM_uint32 *minor_status, gssx_ctx *context_handle, gssx_name **src_name, diff --git a/proxy/src/mechglue/gpp_init_sec_context.c b/proxy/src/mechglue/gpp_init_sec_context.c index 920ac14..ac550ef 100644 --- a/proxy/src/mechglue/gpp_init_sec_context.c +++ b/proxy/src/mechglue/gpp_init_sec_context.c @@ -165,7 +165,8 @@ OM_uint32 gssi_init_sec_context(OM_uint32 *minor_status, actual_mech_type, output_token, ret_flags, - time_rec); + time_rec, + NULL); if (maj == GSS_S_COMPLETE || maj == GSS_S_CONTINUE_NEEDED) { goto done; } diff --git a/proxy/tests/cli_srv_comm.c b/proxy/tests/cli_srv_comm.c index ae0851c..4138743 100644 --- a/proxy/tests/cli_srv_comm.c +++ b/proxy/tests/cli_srv_comm.c @@ -154,6 +154,7 @@ void *client_thread(void *pvt) NULL, &out_token, NULL, + NULL, NULL); if (ret_maj != GSS_S_COMPLETE && ret_maj != GSS_S_CONTINUE_NEEDED) { From 4e27f66f2e0852761f5a91e0a1a722be1518f7d3 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mar 03 2017 22:45:25 +0000 Subject: [PATCH 9/10] If credentials changed try to store them This allows for efficient caching when new tickets are added on the proxy side when using memory ccaches. It also allows to store changes in flags and other ccache ancillary modifications. Fix impersonate tests to cope with the acquire_cred behavior change. Signed-off-by: Simo Sorce --- diff --git a/proxy/src/mechglue/gpp_acquire_cred.c b/proxy/src/mechglue/gpp_acquire_cred.c index 28ded9b..003ef22 100644 --- a/proxy/src/mechglue/gpp_acquire_cred.c +++ b/proxy/src/mechglue/gpp_acquire_cred.c @@ -168,7 +168,18 @@ OM_uint32 gssi_acquire_cred_from(OM_uint32 *minor_status, &out_cred_handle->remote, actual_mechs, time_rec); - if (maj == GSS_S_COMPLETE || behavior == GPP_REMOTE_ONLY) { + if (maj == GSS_S_COMPLETE) { + /* store back creds if they changed */ + if (out_cred_handle->remote && + !gpp_creds_are_equal(in_cred_remote, out_cred_handle->remote)) { + tmaj = gpp_store_remote_creds(&tmin, + out_cred_handle->default_creds, + &out_cred_handle->store, + out_cred_handle->remote); + if (tmaj != GSS_S_COMPLETE) { + maj = tmaj; + } + } goto done; } diff --git a/proxy/src/mechglue/gpp_creds.c b/proxy/src/mechglue/gpp_creds.c index 50689f6..34e6c63 100644 --- a/proxy/src/mechglue/gpp_creds.c +++ b/proxy/src/mechglue/gpp_creds.c @@ -338,6 +338,13 @@ OM_uint32 gppint_get_def_creds(OM_uint32 *minor_status, maj = gpm_acquire_cred(&min, premote, NULL, 0, NULL, cred_usage, false, &cred->remote, NULL, NULL); + if (maj == GSS_S_COMPLETE) { + if (premote && + !gpp_creds_are_equal(premote, cred->remote)) { + maj = gpp_store_remote_creds(&min, cred->default_creds, + &cred->store, cred->remote); + } + } xdr_free((xdrproc_t)xdr_gssx_cred, (char *)&remote); diff --git a/proxy/src/mechglue/gpp_init_sec_context.c b/proxy/src/mechglue/gpp_init_sec_context.c index ac550ef..0d68290 100644 --- a/proxy/src/mechglue/gpp_init_sec_context.c +++ b/proxy/src/mechglue/gpp_init_sec_context.c @@ -139,6 +139,7 @@ OM_uint32 gssi_init_sec_context(OM_uint32 *minor_status, /* Then try with remote */ if (behavior != GPP_LOCAL_ONLY) { + gssx_cred *out_cred = NULL; if (name->local && !name->remote) { maj = gpp_local_to_name(&min, name->local, &name->remote); @@ -166,8 +167,20 @@ OM_uint32 gssi_init_sec_context(OM_uint32 *minor_status, output_token, ret_flags, time_rec, - NULL); + &out_cred); if (maj == GSS_S_COMPLETE || maj == GSS_S_CONTINUE_NEEDED) { + if (out_cred) { + xdr_free((xdrproc_t)xdr_gssx_cred, + (char *)cred_handle->remote); + free(cred_handle->remote); + cred_handle->remote = out_cred; + out_cred = NULL; + /* failuire is not fatal */ + (void)gpp_store_remote_creds(&tmin, + cred_handle->default_creds, + &cred_handle->store, + cred_handle->remote); + } goto done; } diff --git a/proxy/tests/t_impersonate.c b/proxy/tests/t_impersonate.c index 42d59a4..a9974ba 100644 --- a/proxy/tests/t_impersonate.c +++ b/proxy/tests/t_impersonate.c @@ -22,9 +22,10 @@ int main(int argc, const char *argv[]) int ret = -1; bool selfhalf = false; bool proxyhalf = false; - const char *deleg_ccache = NULL; + gss_key_value_element_desc ccelement = { "ccache", NULL }; + gss_key_value_set_desc cred_store = { 1, &ccelement }; - if (argc < 4) return -1; + if (argc < 5) return -1; ret = t_string_to_name(argv[1], &user_name, GSS_C_NT_USER_NAME); if (ret) { @@ -49,29 +50,22 @@ int main(int argc, const char *argv[]) goto done; } - if (argc > 4) { - if (strcmp(argv[4], "s4u2self") == 0) { + ccelement.value = argv[4]; + + if (argc > 5) { + if (strcmp(argv[5], "s4u2self") == 0) { selfhalf = true; - } else if (strcmp(argv[4], "s4u2proxy") == 0) { + } else if (strcmp(argv[5], "s4u2proxy") == 0) { proxyhalf = true; } else { - DEBUG("Invalid argument 4: %s\n", argv[4]); - ret = -1; - goto done; - } - if (argc < 6) { - DEBUG("Option %s requires additional arguments\n", argv[4]); + DEBUG("Invalid argument 5: %s\n", argv[5]); ret = -1; goto done; } - deleg_ccache = argv[5]; - DEBUG("S4U2%s half [ccache %s]\n", selfhalf?"Self":"Proxy", argv[5]); + DEBUG("S4U2%s half\n", selfhalf?"Self":"Proxy", argv[5]); } if (proxyhalf) { - gss_key_value_element_desc ccelement = { "ccache", deleg_ccache }; - gss_key_value_set_desc cred_store = { 1, &ccelement }; - ret_maj = gss_acquire_cred_from(&ret_min, user_name, GSS_C_INDEFINITE, @@ -90,15 +84,17 @@ int main(int argc, const char *argv[]) flags = GSS_C_MUTUAL_FLAG; } else { - ret_maj = gss_acquire_cred(&ret_min, - proxy_name, - GSS_C_INDEFINITE, - &oid_set, - GSS_C_BOTH, - &impersonator_cred_handle, - NULL, NULL); + ret_maj = gss_acquire_cred_from(&ret_min, + proxy_name, + GSS_C_INDEFINITE, + &oid_set, + GSS_C_BOTH, + &cred_store, + &impersonator_cred_handle, + NULL, NULL); if (ret_maj != GSS_S_COMPLETE) { - DEBUG("gss_acquire_cred() failed\n"); + DEBUG("gss_acquire_cred_from() [%s] failed\n", + selfhalf ? "s4u2self" : "impersonate"); t_log_failure(GSS_C_NO_OID, ret_maj, ret_min); ret = -1; goto done; @@ -121,9 +117,6 @@ int main(int argc, const char *argv[]) } if (selfhalf) { - gss_key_value_element_desc ccelement = { "ccache", deleg_ccache }; - gss_key_value_set_desc cred_store = { 1, &ccelement }; - ret_maj = gss_store_cred_into(&ret_min, cred_handle, GSS_C_INITIATE, diff --git a/proxy/tests/t_impersonate.py b/proxy/tests/t_impersonate.py index 499b9a1..3e25962 100755 --- a/proxy/tests/t_impersonate.py +++ b/proxy/tests/t_impersonate.py @@ -75,40 +75,43 @@ def run(testdir, env, conf): # Test all permitted socket = os.path.join(testdir, 'impersonate.socket') - cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS] + cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS, + path_prefix + 'impersonate.cache'] r = run_cmd(testdir, env, conf, "Impersonate", socket, cmd, False) rets.append(r) #Test fail socket = os.path.join(testdir, 'impersonate-proxyonly.socket') - cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS] + cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS, + path_prefix + 'impersonate.cache'] r = run_cmd(testdir, env, conf, "Impersonate fail self", socket, cmd, True) rets.append(r) #Test fail socket = os.path.join(testdir, 'impersonate-selfonly.socket') - cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS] + cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS, + path_prefix + 'impersonate.cache'] r = run_cmd(testdir, env, conf, "Impersonate fail proxy", socket, cmd, True) rets.append(r) #Test s4u2self half succeed socket = os.path.join(testdir, 'impersonate-selfonly.socket') - cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS, 's4u2self', - path_prefix + 'impersonate-proxy.ccache'] + cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS, + path_prefix + 'impersonate.cache', 's4u2self'] r = run_cmd(testdir, env, conf, "s4u2self delegation", socket, cmd, False) rets.append(r) #Test s4u2proxy half fail socket = os.path.join(testdir, 'impersonate-selfonly.socket') - cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS, 's4u2proxy', - path_prefix + 'impersonate-proxy.ccache'] + cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS, + path_prefix + 'impersonate.cache', 's4u2proxy'] r = run_cmd(testdir, env, conf, "s4u2proxy fail", socket, cmd, True) rets.append(r) #Test s4u2proxy half succeed socket = os.path.join(testdir, 'impersonate-proxyonly.socket') - cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS, 's4u2proxy', - path_prefix + 'impersonate-proxy.ccache'] + cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS, + path_prefix + 'impersonate.cache', 's4u2proxy'] r = run_cmd(testdir, env, conf, "s4u2proxy", socket, cmd, False) rets.append(r) From 39a3583b9749042449217cebe4f2c06dfdf78f4b Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mar 03 2017 22:45:25 +0000 Subject: [PATCH 10/10] Change tests to always exercise ccache sycns Do not use a gssproxy side ccache in tests, let them use the new default temporary memcache for operations. Additionally allow the proxy to always sync back ccaches on operations so that the sync path is exercised as well. Signed-off-by: Simo Sorce --- diff --git a/proxy/tests/testlib.py b/proxy/tests/testlib.py index bb210d3..08dfdd6 100755 --- a/proxy/tests/testlib.py +++ b/proxy/tests/testlib.py @@ -535,10 +535,10 @@ GSSPROXY_CONF_TEMPLATE = ''' [service/test] mechs = krb5 cred_store = keytab:${GSSPROXY_KEYTAB} - cred_store = ccache:FILE:${GSSPROXY_CLIENT_CCACHE} cred_store = client_keytab:${GSSPROXY_CLIENT_KEYTAB} trusted = yes euid = ${UIDNUMBER} + allow_client_ccache_sync = yes [service/badkeytab] mechs = krb5 @@ -553,10 +553,10 @@ GSSPROXY_CONF_MINIMAL_TEMPLATE = ''' [service/dontuse] mechs = krb5 cred_store = keytab:${GSSPROXY_KEYTAB} - cred_store = ccache:FILE:${GSSPROXY_CLIENT_CCACHE} cred_store = client_keytab:${GSSPROXY_CLIENT_KEYTAB} trusted = yes euid = nobody + allow_client_ccache_sync = yes ''' GSSPROXY_CONF_SOCKET_TEMPLATE = ''' @@ -566,11 +566,11 @@ GSSPROXY_CONF_SOCKET_TEMPLATE = ''' [service/test] mechs = krb5 cred_store = keytab:${GSSPROXY_KEYTAB} - cred_store = ccache:FILE:${GSSPROXY_CLIENT_CCACHE} cred_store = client_keytab:${GSSPROXY_CLIENT_KEYTAB} trusted = yes euid = ${UIDNUMBER} socket = ${SECOND_SOCKET} + allow_client_ccache_sync = yes ''' GSSPROXY_MULTI_TEMPLATE = ''' @@ -580,10 +580,10 @@ GSSPROXY_MULTI_TEMPLATE = ''' [service/test] mechs = krb5 cred_store = keytab:${GSSPROXY_KEYTAB} - cred_store = client_keytab:${GSSPROXY_CLIENT_KEYTAB} krb5_principal = ${GSSPROXY_CLIENT_PRINCIPAL} trusted = yes euid = ${UIDNUMBER} + allow_client_ccache_sync = yes ''' def update_gssproxy_conf(testdir, env, template):