This is an automated email from the git hooks/post-receive script.
rharwood pushed a commit to branch master
in repository gssproxy.
commit 172bedea74bb8a0d465bfa8150d1eb02761554d7
Author: Simo Sorce <simo(a)redhat.com>
Date: Mon Feb 27 15:15:17 2017 -0500
Add ability to sync creds back on modification
If enabled and if the client requests it, the server will check if new
credentials are available and send back a fresh copy to the client if they
are.
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 <simo(a)redhat.com>
[rharwood(a)redhat.com: Style fixes, typo in comment, commit message tweak]
Reviewed-by: Robbie Harwood <rharwood(a)redhat.com>
---
proxy/man/gssproxy.conf.5.xml | 14 +++
proxy/src/gp_common.h | 5 ++
proxy/src/gp_config.c | 8 ++
proxy/src/gp_creds.c | 173 ++++++++++++++++++++++++++++++++++++
proxy/src/gp_proxy.h | 1 +
proxy/src/gp_rpc_creds.h | 13 +++
proxy/src/gp_rpc_init_sec_context.c | 23 +++++
proxy/src/mechglue/gpp_creds.c | 1 -
8 files changed, 237 insertions(+), 1 deletion(-)
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 @@
</varlistentry>
<varlistentry>
+ <term>allow_client_ccache_sync (boolean)</term>
+ <listitem>
+ <para>Allow clients to request credentials to be sent back
for better
+ caching.</para>
+ <para>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.</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_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..5d84904 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,175 @@ 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 != 0) {
+ 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 != 0) {
+ ret_min = err;
+ ret_maj = GSS_S_FAILURE;
+ goto done;
+ }
+
+ err = krb5_cc_start_seq_get(context, ccache, &cursor);
+ if (err != 0) {
+ ret_min = err;
+ ret_maj = GSS_S_FAILURE;
+ goto done;
+ }
+
+ do {
+ err = krb5_cc_next_cred(context, ccache, &cursor, &creds);
+ if (err != 0 && err != KRB5_CC_END) {
+ ret_min = err;
+ ret_maj = GSS_S_FAILURE;
+ goto done;
+ }
+
+ /* TODO: Should we do a real checksum over all creds->ticket data and
+ * flags in future ? */
+ (*ccsum)++;
+
+ } while (err == 0);
+
+ err = krb5_cc_end_seq_get(context, ccache, &cursor);
+ if (err != 0) {
+ 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 <gssapi/gssapi_krb5.h>
#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,
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.