From e1a6805083903a23e9b3287b051f035a3f9f1f01 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 4 Jan 2017 18:01:30 -0500 Subject: Control access to constrained delegation A client must be tusted or must be explicitly allowed to perform impersonation or constrained delegation to be able to use evidence tickets for s4u2proxy operations. Signed-off-by: Simo Sorce --- proxy/man/gssproxy.conf.5.xml | 12 +++++ proxy/src/gp_config.c | 8 +++ proxy/src/gp_creds.c | 105 ++++++++++++++++++++++++++++++++++++ proxy/src/gp_proxy.h | 1 + proxy/src/gp_rpc_creds.h | 4 ++ proxy/src/gp_rpc_init_sec_context.c | 6 +++ 6 files changed, 136 insertions(+) diff --git a/proxy/man/gssproxy.conf.5.xml b/proxy/man/gssproxy.conf.5.xml index 6d44e8a..7c724d6 100644 --- a/proxy/man/gssproxy.conf.5.xml +++ b/proxy/man/gssproxy.conf.5.xml @@ -113,6 +113,18 @@ + + allow_constrained_delegation (boolean) + + Allow clients to request a ticket to another service using an + evidence ticket. + This option controls whether s4u2proxy requests are allowed for + the requesting client. The KDC still needs to allow the operation + for it to succeed. + Default: false + + + cred_usage (string) diff --git a/proxy/src/gp_config.c b/proxy/src/gp_config.c index 1493fab..3eff961 100644 --- a/proxy/src/gp_config.c +++ b/proxy/src/gp_config.c @@ -379,6 +379,14 @@ static int load_services(struct gp_config *cfg, struct gp_ini_context *ctx) } } + ret = gp_config_get_string(ctx, secname, + "allow_constrained_delegation", &value); + if (ret == 0) { + if (gp_boolean_is_true(value)) { + cfg->svcs[n]->allow_const_deleg = 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 8fafa66..7236ee1 100644 --- a/proxy/src/gp_creds.c +++ b/proxy/src/gp_creds.c @@ -3,6 +3,7 @@ #include "config.h" #include #include +#include #include #include #include @@ -681,3 +682,107 @@ void gp_filter_flags(struct gp_call_ctx *gpcall, uint32_t *flags) *flags |= gpcall->service->enforce_flags; *flags &= ~gpcall->service->filter_flags; } + +uint32_t gp_cred_allowed(uint32_t *min, + struct gp_call_ctx *gpcall, + gss_cred_id_t cred) +{ + uint32_t ret_maj = 0; + uint32_t ret_min = 0; + char *memcache = NULL; + krb5_context context = NULL; + krb5_ccache ccache = NULL; + krb5_data config; + int err; + + if (cred == GSS_C_NO_CREDENTIAL) { + return GSS_S_CRED_UNAVAIL; + } + + if (gpcall->service->trusted || + gpcall->service->impersonate || + gpcall->service->allow_const_deleg) { + + GPDEBUGN(2, "Credentials allowed by configuration\n"); + *min = 0; + return GSS_S_COMPLETE; + } + + /* FIXME: krb5 specific code, should get an oid registerd to query the + * cred with gss_inquire_cred_by_oid() or similar instead */ + + 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; + } + + /* if we find an impersonator entry we bail as that is not authorized, + * if it were then gpcall->service->allow_const_deleg would have caused + * the ealier check to return GSS_S_COMPLETE already */ + err = krb5_cc_get_config(context, ccache, NULL, "proxy_impersonator", + &config); + if (!err) { + krb5_free_data_contents(context, &config); + ret_min = 0; + ret_maj = GSS_S_UNAUTHORIZED; + } else if (err != KRB5_CC_NOTFOUND) { + ret_min = err; + ret_maj = GSS_S_FAILURE; + } else { + ret_min = 0; + ret_maj = GSS_S_COMPLETE; + } + +done: + switch (ret_maj) { + case GSS_S_UNAUTHORIZED: + GPDEBUGN(2, "Unauthorized impersonator credentials detected\n"); + break; + case GSS_S_COMPLETE: + GPDEBUGN(2, "No impersonator credentials detected\n"); + break; + default: + GPDEBUG("Failure while checking credentials\n"); + break; + } + 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; +} diff --git a/proxy/src/gp_proxy.h b/proxy/src/gp_proxy.h index 4216b72..ad6806a 100644 --- a/proxy/src/gp_proxy.h +++ b/proxy/src/gp_proxy.h @@ -31,6 +31,7 @@ struct gp_service { uid_t euid; bool any_uid; bool allow_proto_trans; + bool allow_const_deleg; bool trusted; bool kernel_nfsd; bool impersonate; diff --git a/proxy/src/gp_rpc_creds.h b/proxy/src/gp_rpc_creds.h index ead6afc..93df7e1 100644 --- a/proxy/src/gp_rpc_creds.h +++ b/proxy/src/gp_rpc_creds.h @@ -32,6 +32,10 @@ uint32_t gp_add_krb5_creds(uint32_t *min, uint32_t *initiator_time_rec, uint32_t *acceptor_time_rec); +uint32_t gp_cred_allowed(uint32_t *min, + struct gp_call_ctx *gpcall, + gss_cred_id_t cred); + void gp_filter_flags(struct gp_call_ctx *gpcall, uint32_t *flags); #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 d607b07..f3dc11d 100644 --- a/proxy/src/gp_rpc_init_sec_context.c +++ b/proxy/src/gp_rpc_init_sec_context.c @@ -55,6 +55,7 @@ int gp_init_sec_context(struct gp_call_ctx *gpcall, goto done; } } + ret_maj = gp_conv_gssx_to_name(&ret_min, isca->target_name, &target_name); if (ret_maj) { goto done; @@ -98,6 +99,11 @@ int gp_init_sec_context(struct gp_call_ctx *gpcall, } } + ret_maj = gp_cred_allowed(&ret_min, gpcall, ich); + if (ret_maj) { + goto done; + } + gp_filter_flags(gpcall, &req_flags); ret_maj = gss_init_sec_context(&ret_min, -- cgit