summaryrefslogtreecommitdiffstats
path: root/proxy
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2015-11-09 17:10:56 -0500
committerRobbie Harwood <rharwood@redhat.com>2015-12-01 17:45:56 -0500
commit84fcb276d2253f34e5d50a87e42e34c1fd918a55 (patch)
treeb30a1b41811ff66c4471da2a0dd4bd1697e9f22b /proxy
parent7e71db8edc9694ed75110ddd9efa373250cc0545 (diff)
downloadgss-proxy-84fcb276d2253f34e5d50a87e42e34c1fd918a55.tar.gz
gss-proxy-84fcb276d2253f34e5d50a87e42e34c1fd918a55.tar.xz
gss-proxy-84fcb276d2253f34e5d50a87e42e34c1fd918a55.zip
Add helpers to store and retrieve encrypted creds
This will allow to (ab)use the krb5 ccache to store encrypted credentials in the user's ccache for later reuse. Signed-off-by: Simo Sorce <simo@redhat.com> Reviewed-by: Robbie Harwoood <rharwood@redhat.com>
Diffstat (limited to 'proxy')
-rw-r--r--proxy/src/gp_creds.c100
-rw-r--r--proxy/src/mechglue/gpp_creds.c139
-rw-r--r--proxy/src/mechglue/gpp_init_sec_context.c15
-rw-r--r--proxy/src/mechglue/gss_plugin.h1
4 files changed, 246 insertions, 9 deletions
diff --git a/proxy/src/gp_creds.c b/proxy/src/gp_creds.c
index c28c10a..e00f735 100644
--- a/proxy/src/gp_creds.c
+++ b/proxy/src/gp_creds.c
@@ -414,6 +414,91 @@ done:
return ret;
}
+uint32_t gp_check_cred(uint32_t *min,
+ gss_cred_id_t in_cred,
+ gssx_name *desired_name,
+ gss_cred_usage_t cred_usage)
+{
+ uint32_t ret_maj = 0;
+ uint32_t ret_min = 0;
+ uint32_t discard;
+ uint32_t i;
+ gss_name_t req_name = GSS_C_NO_NAME;
+ gss_name_t check_name = GSS_C_NO_NAME;
+ gss_OID_set mechanisms = GSS_C_NO_OID_SET;
+ gss_cred_usage_t usage;
+ uint32_t lifetime;
+ int present = 0;
+
+ ret_maj = gss_inquire_cred(&ret_min, in_cred,
+ desired_name?&check_name:NULL,
+ &lifetime, &usage, &mechanisms);
+ if (ret_maj) {
+ goto done;
+ }
+
+ for (i = 0; i < mechanisms->count; i++) {
+ present = gss_oid_equal(&mechanisms->elements[i], gss_mech_krb5);
+ if (present) break;
+ }
+ if (!present) {
+ ret_maj = GSS_S_CRED_UNAVAIL;
+ goto done;
+ }
+
+ if (desired_name) {
+ int equal;
+ ret_maj = gp_conv_gssx_to_name(&ret_min, desired_name, &req_name);
+ if (ret_maj) {
+ goto done;
+ }
+ ret_maj = gss_compare_name(&ret_min, req_name, check_name, &equal);
+ if (ret_maj) {
+ goto done;
+ }
+ if (!equal) {
+ ret_maj = GSS_S_CRED_UNAVAIL;
+ goto done;
+ }
+ }
+
+ switch (cred_usage) {
+ case GSS_C_ACCEPT:
+ if (usage == GSS_C_INITIATE) {
+ ret_maj = GSS_S_NO_CRED;
+ goto done;
+ }
+ break;
+ case GSS_C_INITIATE:
+ if (usage == GSS_C_ACCEPT) {
+ ret_maj = GSS_S_NO_CRED;
+ goto done;
+ }
+ break;
+ case GSS_C_BOTH:
+ if (usage != GSS_C_BOTH) {
+ ret_maj = GSS_S_NO_CRED;
+ goto done;
+ }
+ break;
+ }
+
+ if (lifetime == 0) {
+ ret_maj = GSS_S_CREDENTIALS_EXPIRED;
+ } else {
+ ret_maj = GSS_S_COMPLETE;
+ }
+
+done:
+ gss_release_oid_set(&discard, &mechanisms);
+ gss_release_name(&discard, &check_name);
+ gss_release_name(&discard, &req_name);
+
+ *min = ret_min;
+ return ret_maj;
+}
+
+
uint32_t gp_add_krb5_creds(uint32_t *min,
struct gp_call_ctx *gpcall,
enum gp_aqcuire_cred_type acquire_type,
@@ -453,11 +538,20 @@ uint32_t gp_add_krb5_creds(uint32_t *min,
}
if (in_cred != GSS_C_NO_CREDENTIAL && acquire_type != ACQ_IMPNAME) {
- /* we can't yet handle adding to an existing credential due to
- * the way gss_krb5_import_cred works. This limitation should
+ /* NOTE: we can't yet handle adding to an existing credential due
+ * to the way gss_krb5_import_cred works. This limitation should
* be removed by adding a gssapi extension that superceedes this
* function completely */
- return GSS_S_CRED_UNAVAIL;
+
+ /* just check if it is a valid krb5 cred */
+ ret_maj = gp_check_cred(&ret_min, in_cred, desired_name, cred_usage);
+ if (ret_maj == GSS_S_COMPLETE) {
+ return GSS_S_COMPLETE;
+ } else if (ret_maj != GSS_S_CREDENTIALS_EXPIRED &&
+ ret_maj != GSS_S_NO_CRED) {
+ *min = ret_min;
+ return GSS_S_CRED_UNAVAIL;
+ }
}
if (acquire_type == ACQ_NORMAL) {
diff --git a/proxy/src/mechglue/gpp_creds.c b/proxy/src/mechglue/gpp_creds.c
index dcfc896..ff1dfda 100644
--- a/proxy/src/mechglue/gpp_creds.c
+++ b/proxy/src/mechglue/gpp_creds.c
@@ -1,8 +1,125 @@
-/* Copyright (C) 2012 the GSS-PROXY contributors, see COPYING for license */
+/* Copyright (C) 2015 the GSS-PROXY contributors, see COPYING for license */
#include "gss_plugin.h"
#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, gssx_cred *creds)
+{
+ krb5_context ctx = NULL;
+ krb5_ccache ccache = NULL;
+ krb5_creds cred;
+ krb5_error_code ret;
+ XDR xdrctx;
+ bool xdrok;
+
+ *min = 0;
+
+ if (creds == NULL) return GSS_S_CALL_INACCESSIBLE_READ;
+
+ memset(&cred, 0, sizeof(cred));
+
+ ret = krb5_init_context(&ctx);
+ if (ret) return ret;
+
+ ret = krb5_cc_default(ctx, &ccache);
+ if (ret) goto done;
+
+ ret = krb5_parse_name(ctx,
+ creds->desired_name.display_name.octet_string_val,
+ &cred.client);
+ if (ret) goto done;
+
+ ret = krb5_parse_name(ctx, GPKRB_SRV_NAME, &cred.server);
+ if (ret) goto done;
+
+ cred.ticket.data = malloc(GPKRB_MAX_CRED_SIZE);
+ xdrmem_create(&xdrctx, cred.ticket.data, GPKRB_MAX_CRED_SIZE, XDR_ENCODE);
+ xdrok = xdr_gssx_cred(&xdrctx, creds);
+ if (!xdrok) {
+ ret = ENOSPC;
+ goto done;
+ }
+ cred.ticket.length = xdr_getpos(&xdrctx);
+
+ ret = krb5_cc_store_cred(ctx, ccache, &cred);
+
+ if (ret == KRB5_FCC_NOFILE) {
+ /* If a ccache does not exit, try to create one */
+ ret = krb5_cc_initialize(ctx, ccache, cred.client);
+ if (ret) goto done;
+
+ /* and try again to store the cred */
+ ret = krb5_cc_store_cred(ctx, ccache, &cred);
+ }
+
+done:
+ if (ctx) {
+ krb5_free_cred_contents(ctx, &cred);
+ if (ccache) krb5_cc_close(ctx, ccache);
+ krb5_free_context(ctx);
+ }
+ *min = ret;
+ return ret ? GSS_S_FAILURE : GSS_S_COMPLETE;
+}
+
+static uint32_t retrieve_remote_creds(uint32_t *min, gssx_name *name,
+ gssx_cred *creds)
+{
+ krb5_context ctx = NULL;
+ krb5_ccache ccache = NULL;
+ krb5_creds cred;
+ krb5_creds icred;
+ krb5_error_code ret;
+ XDR xdrctx;
+ bool xdrok;
+
+ memset(&cred, 0, sizeof(krb5_creds));
+ memset(&icred, 0, sizeof(krb5_creds));
+
+ ret = krb5_init_context(&ctx);
+ if (ret) goto done;
+
+ ret = krb5_cc_default(ctx, &ccache);
+ if (ret) goto done;
+
+ if (name) {
+ ret = krb5_parse_name(ctx,
+ name->display_name.octet_string_val,
+ &icred.client);
+ } else {
+ ret = krb5_cc_get_principal(ctx, ccache, &icred.client);
+ }
+ if (ret) goto done;
+
+ ret = krb5_parse_name(ctx, GPKRB_SRV_NAME, &icred.server);
+ if (ret) goto done;
+
+ ret = krb5_cc_retrieve_cred(ctx, ccache, 0, &icred, &cred);
+ if (ret) goto done;
+
+ xdrmem_create(&xdrctx, cred.ticket.data, cred.ticket.length, XDR_DECODE);
+ xdrok = xdr_gssx_cred(&xdrctx, creds);
+
+ if (xdrok) {
+ ret = 0;
+ } else {
+ ret = EIO;
+ }
+
+done:
+ if (ctx) {
+ krb5_free_cred_contents(ctx, &cred);
+ krb5_free_cred_contents(ctx, &icred);
+ if (ccache) krb5_cc_close(ctx, ccache);
+ krb5_free_context(ctx);
+ }
+ *min = ret;
+ return ret ? GSS_S_FAILURE : GSS_S_COMPLETE;
+}
+
static OM_uint32 get_local_def_creds(OM_uint32 *minor_status,
struct gpp_name_handle *name,
gss_cred_usage_t cred_usage,
@@ -66,11 +183,21 @@ OM_uint32 gppint_get_def_creds(OM_uint32 *minor_status,
/* Then try with remote */
if (behavior == GPP_REMOTE_ONLY || behavior == GPP_REMOTE_FIRST) {
+ gssx_cred remote = {0};
+ gssx_cred *premote = NULL;
- maj = gpm_acquire_cred(&min, NULL,
+ /* We intentionally ignore failures as finding creds is optional */
+ maj = retrieve_remote_creds(&min, name ? name->remote : NULL, &remote);
+ if (maj == GSS_S_COMPLETE) {
+ premote = &remote;
+ }
+
+ maj = gpm_acquire_cred(&min, premote,
NULL, 0, NULL, cred_usage, false,
&cred->remote, NULL, NULL);
+ xdr_free((xdrproc_t)xdr_gssx_cred, (char *)&remote);
+
if (maj == GSS_S_COMPLETE || behavior == GPP_REMOTE_ONLY) {
goto done;
}
@@ -379,16 +506,16 @@ OM_uint32 gssi_store_cred(OM_uint32 *minor_status,
}
cred = (struct gpp_cred_handle *)input_cred_handle;
- /* NOTE: For now we can do this only for local credentials */
- if (!cred->local) {
- return GSS_S_UNAVAILABLE;
+ if (cred->remote) {
+ maj = gpp_store_remote_creds(&min, cred->remote);
+ goto done;
}
maj = gss_store_cred(&min, cred->local, input_usage,
gpp_special_mech(desired_mech),
overwrite_cred, default_cred,
elements_stored, cred_usage_stored);
-
+done:
*minor_status = gpp_map_error(min);
return maj;
}
diff --git a/proxy/src/mechglue/gpp_init_sec_context.c b/proxy/src/mechglue/gpp_init_sec_context.c
index 6cfe0e1..2327b58 100644
--- a/proxy/src/mechglue/gpp_init_sec_context.c
+++ b/proxy/src/mechglue/gpp_init_sec_context.c
@@ -151,6 +151,21 @@ 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,
+ GSS_C_NO_NAME,
+ GSS_C_INITIATE,
+ &r_creds);
+ if (maj == GSS_S_COMPLETE) {
+ /* steal result */
+ cred_handle->remote = r_creds->remote;
+ free(r_creds);
+ }
+ }
+
maj = gpm_init_sec_context(&min,
cred_handle->remote,
&ctx_handle->remote,
diff --git a/proxy/src/mechglue/gss_plugin.h b/proxy/src/mechglue/gss_plugin.h
index 6df4c6a..d7ab0b4 100644
--- a/proxy/src/mechglue/gss_plugin.h
+++ b/proxy/src/mechglue/gss_plugin.h
@@ -69,6 +69,7 @@ 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);
+
OM_uint32 gssi_internal_release_oid(OM_uint32 *minor_status, gss_OID *oid);
OM_uint32 gssi_acquire_cred(OM_uint32 *minor_status,