diff options
author | Simo Sorce <simo@redhat.com> | 2017-01-04 18:01:30 -0500 |
---|---|---|
committer | Simo Sorce <simo@redhat.com> | 2017-01-13 15:50:06 -0500 |
commit | e1a6805083903a23e9b3287b051f035a3f9f1f01 (patch) | |
tree | 937f985b328d3c1916d70d5c871f213a61445d28 | |
parent | d1d97ef1520eaedc27af679fe7906c038ae7f0e4 (diff) | |
download | gss-proxy-e1a6805083903a23e9b3287b051f035a3f9f1f01.tar.gz gss-proxy-e1a6805083903a23e9b3287b051f035a3f9f1f01.tar.xz gss-proxy-e1a6805083903a23e9b3287b051f035a3f9f1f01.zip |
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 <simo@redhat.com>
-rw-r--r-- | proxy/man/gssproxy.conf.5.xml | 12 | ||||
-rw-r--r-- | proxy/src/gp_config.c | 8 | ||||
-rw-r--r-- | proxy/src/gp_creds.c | 105 | ||||
-rw-r--r-- | proxy/src/gp_proxy.h | 1 | ||||
-rw-r--r-- | proxy/src/gp_rpc_creds.h | 4 | ||||
-rw-r--r-- | proxy/src/gp_rpc_init_sec_context.c | 6 |
6 files changed, 136 insertions, 0 deletions
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 @@ -114,6 +114,18 @@ </varlistentry> <varlistentry> + <term>allow_constrained_delegation (boolean)</term> + <listitem> + <para>Allow clients to request a ticket to another service using an + evidence ticket.</para> + <para>This option controls whether s4u2proxy requests are allowed for + the requesting client. The KDC still needs to allow the operation + for it to succeed.</para> + <para>Default: false</para> + </listitem> + </varlistentry> + + <varlistentry> <term>cred_usage (string)</term> <listitem> <para>Allow to restrict the kind of operations permitted for this service.</para> 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 <stdio.h> #include <sys/socket.h> +#include <sys/types.h> #include <errno.h> #include <string.h> #include <pwd.h> @@ -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, |