diff options
author | Simo Sorce <simo@redhat.com> | 2012-05-31 18:49:23 -0400 |
---|---|---|
committer | Simo Sorce <simo@redhat.com> | 2012-08-28 08:25:52 +0200 |
commit | b61963e396f9aad2d004a0d1810df3123b4fa4ec (patch) | |
tree | 09891a90b63aad962fda30e9c66fbf972166428c | |
parent | cc305c3331c3bcef07eb42e3fb0e7918048128b6 (diff) | |
download | gss-proxy-b61963e396f9aad2d004a0d1810df3123b4fa4ec.tar.gz gss-proxy-b61963e396f9aad2d004a0d1810df3123b4fa4ec.tar.xz gss-proxy-b61963e396f9aad2d004a0d1810df3123b4fa4ec.zip |
Implement cred related mechglue wrappers
-rw-r--r-- | proxy/Makefile.am | 2 | ||||
-rw-r--r-- | proxy/src/mechglue/gpp_acquire_cred.c | 326 | ||||
-rw-r--r-- | proxy/src/mechglue/gpp_creds.c | 262 | ||||
-rw-r--r-- | proxy/src/mechglue/gss_plugin.h | 54 |
4 files changed, 644 insertions, 0 deletions
diff --git a/proxy/Makefile.am b/proxy/Makefile.am index a1148d4..55f1573 100644 --- a/proxy/Makefile.am +++ b/proxy/Makefile.am @@ -98,6 +98,8 @@ GP_RPCCLI_OBJ = \ src/client/gpm_verify_mic.c \ src/client/gpm_common.c GP_MECHGLUE_OBJ = \ + src/mechglue/gpp_acquire_cred.c \ + src/mechglue/gpp_creds.c \ src/mechglue/gss_plugin.c dist_noinst_HEADERS = \ diff --git a/proxy/src/mechglue/gpp_acquire_cred.c b/proxy/src/mechglue/gpp_acquire_cred.c new file mode 100644 index 0000000..126b7ae --- /dev/null +++ b/proxy/src/mechglue/gpp_acquire_cred.c @@ -0,0 +1,326 @@ +/* + GSS-PROXY + + Copyright (C) 2012 Red Hat, Inc. + Copyright (C) 2012 Simo Sorce <simo.sorce@redhat.com> + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + + +#include "gss_plugin.h" + +static OM_uint32 acquire_local(OM_uint32 *minor_status, + struct gpp_name_handle *name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + struct gpp_cred_handle *out_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) +{ + gss_OID_set special_mechs = GSS_C_NO_OID_SET; + OM_uint32 maj, min; + + special_mechs = gpp_special_available_mechs(desired_mechs); + if (special_mechs == GSS_C_NO_OID_SET) { + maj = GSS_S_BAD_MECH; + min = 0; + goto done; + } + + if (name && name->remote && !name->local) { + maj = gpp_name_to_local(&min, name->remote, + GSS_C_NO_OID, &name->local); + if (maj) { + goto done; + } + } + + maj = gss_acquire_cred(&min, + name ? name->local : NULL, + time_req, + special_mechs, + cred_usage, + &out_cred_handle->local, + actual_mechs, + time_rec); + +done: + *minor_status = min; + (void)gss_release_oid_set(&min, &special_mechs); + return maj; +} + +OM_uint32 gssi_acquire_cred(OM_uint32 *minor_status, + const gss_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) +{ + enum gpp_behavior behavior; + struct gpp_name_handle *name; + struct gpp_cred_handle *out_cred_handle = NULL; + OM_uint32 maj, min; + OM_uint32 tmaj, tmin; + + if (!output_cred_handle) { + *minor_status = gpp_map_error(EINVAL); + return GSS_S_FAILURE; + } + + 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(); + + /* See if we should try local first */ + if (behavior == GPP_LOCAL_ONLY || behavior == GPP_LOCAL_FIRST) { + + maj = acquire_local(&min, name, time_req, desired_mechs, cred_usage, + out_cred_handle, actual_mechs, time_rec); + + if (maj != GSS_S_NO_CRED || behavior != GPP_LOCAL_FIRST) { + goto done; + } + + /* not successful, save actual local error if remote fallback fails */ + tmaj = maj; + tmin = min; + } + + /* Then try with remote */ + if (behavior == GPP_REMOTE_ONLY || behavior == GPP_REMOTE_FIRST) { + + if (name && name->local && !name->remote) { + maj = gpp_local_to_name(&min, name->local, &name->remote); + if (maj) { + goto done; + } + } + + maj = gpm_acquire_cred(&min, + name ? name->remote : NULL, + time_req, + desired_mechs, + cred_usage, + &out_cred_handle->remote, + actual_mechs, + time_rec); + if (maj == GSS_S_COMPLETE || behavior == GPP_REMOTE_ONLY) { + goto done; + } + + /* So remote failed, but we can fallback to local, try that */ + maj = acquire_local(&min, name, time_req, desired_mechs, cred_usage, + out_cred_handle, actual_mechs, time_rec); + } + +done: + if (maj != GSS_S_COMPLETE && + maj != GSS_S_CONTINUE_NEEDED && + tmaj != GSS_S_COMPLETE) { + maj = tmaj; + min = tmin; + } + if (maj == GSS_S_COMPLETE) { + *output_cred_handle = (gss_cred_id_t)out_cred_handle; + } else { + free(out_cred_handle); + } + *minor_status = gpp_map_error(min); + return maj; +} + +OM_uint32 gssi_add_cred(OM_uint32 *minor_status, + const gss_cred_id_t input_cred_handle, + const gss_name_t desired_name, + const gss_OID desired_mech, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec) +{ + gss_OID_set desired_mechs = GSS_C_NO_OID_SET; + OM_uint32 time_req, time_rec; + OM_uint32 maj, min; + + if (!output_cred_handle) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + if (desired_mech) { + maj = gss_create_empty_oid_set(&min, &desired_mechs); + if (maj != GSS_S_COMPLETE) { + *minor_status = gpp_map_error(min); + return maj; + } + maj = gss_add_oid_set_member(&min, desired_mech, &desired_mechs); + if (maj != GSS_S_COMPLETE) { + (void)gss_release_oid_set(&min, &desired_mechs); + *minor_status = gpp_map_error(min); + return maj; + } + } + + switch (cred_usage) { + case GSS_C_ACCEPT: + time_req = acceptor_time_req; + break; + case GSS_C_INITIATE: + time_req = initiator_time_req; + break; + case GSS_C_BOTH: + if (acceptor_time_req > initiator_time_req) { + time_req = acceptor_time_req; + } else { + time_req = initiator_time_req; + } + break; + default: + time_req = 0; + } + + maj = gssi_acquire_cred(minor_status, + desired_name, + time_req, + desired_mechs, + cred_usage, + output_cred_handle, + actual_mechs, + &time_rec); + if (maj == GSS_S_COMPLETE) { + if (acceptor_time_rec && + (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)) { + *acceptor_time_rec = time_rec; + } + if (initiator_time_rec && + (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)) { + *initiator_time_rec = time_rec; + } + } + + (void)gss_release_oid_set(&min, &desired_mechs); + return maj; +} + +OM_uint32 gssi_acquire_cred_with_password(OM_uint32 *minor_status, + const gss_name_t desired_name, + const gss_buffer_t password, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) +{ + enum gpp_behavior behavior; + struct gpp_name_handle *name; + struct gpp_cred_handle *out_cred_handle; + gss_OID_set special_mechs; + OM_uint32 maj, min; + + name = (struct gpp_name_handle *)desired_name; + + if (!output_cred_handle) { + *minor_status = gpp_map_error(EINVAL); + return GSS_S_FAILURE; + } + + if (desired_mechs == GSS_C_NO_OID_SET) { + return GSS_S_CALL_INACCESSIBLE_READ; + } + + 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; + } + + switch (behavior) { + case GPP_LOCAL_ONLY: + case GPP_LOCAL_FIRST: + case GPP_REMOTE_FIRST: + + /* re-enter the mechglue, using the special OIDs for skipping + * the use of the interposer */ + special_mechs = gpp_special_available_mechs(desired_mechs); + if (special_mechs == GSS_C_NO_OID_SET) { + return GSS_S_FAILURE; + } + + if (name && name->remote && !name->local) { + maj = gpp_name_to_local(&min, name->remote, + GSS_C_NO_OID, &name->local); + if (maj) { + goto done; + } + } + + maj = gss_acquire_cred_with_password(&min, + name->local, + password, + time_req, + special_mechs, + cred_usage, + &out_cred_handle->local, + actual_mechs, + time_rec); + break; + /* fall through if we got no creds locally and we are in + * automatic mode */ + + case GPP_REMOTE_ONLY: + + /* FIXME: not currently available */ + return GSS_S_UNAVAILABLE; + + break; + + default: + maj = GSS_S_FAILURE; + min = EINVAL; + } + +done: + if (maj == GSS_S_COMPLETE) { + *output_cred_handle = (gss_cred_id_t)out_cred_handle; + } else { + free(out_cred_handle); + } + *minor_status = gpp_map_error(min); + (void)gss_release_oid_set(&min, &special_mechs); + return maj; +} diff --git a/proxy/src/mechglue/gpp_creds.c b/proxy/src/mechglue/gpp_creds.c new file mode 100644 index 0000000..ce706a5 --- /dev/null +++ b/proxy/src/mechglue/gpp_creds.c @@ -0,0 +1,262 @@ +/* + GSS-PROXY + + Copyright (C) 2012 Red Hat, Inc. + Copyright (C) 2012 Simo Sorce <simo.sorce@redhat.com> + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "gss_plugin.h" + +static OM_uint32 get_local_def_creds(OM_uint32 *minor_status, + struct gpp_name_handle *name, + struct gpp_cred_handle *cred_handle) +{ + gss_OID_set interposed_mechs = GSS_C_NO_OID_SET; + gss_OID_set special_mechs = GSS_C_NO_OID_SET; + OM_uint32 maj, min; + + maj = GSS_S_FAILURE; + min = 0; + + interposed_mechs = gss_mech_interposer((gss_OID)&gssproxy_mech_interposer); + if (interposed_mechs == GSS_C_NO_OID_SET) { + goto done; + } + special_mechs = gpp_special_available_mechs(interposed_mechs); + if (special_mechs == GSS_C_NO_OID_SET) { + goto done; + } + + maj = gss_acquire_cred(&min, name ? name->local : NULL, 0, special_mechs, + GSS_C_BOTH, &cred_handle->local, NULL, NULL); +done: + *minor_status = min; + (void)gss_release_oid_set(&min, &special_mechs); + (void)gss_release_oid_set(&min, &interposed_mechs); + return maj; +} + +OM_uint32 gppint_get_def_creds(OM_uint32 *minor_status, + enum gpp_behavior behavior, + struct gpp_name_handle *name, + struct gpp_cred_handle **cred_handle) +{ + struct gpp_cred_handle *cred; + OM_uint32 tmaj, tmin; + OM_uint32 maj, min; + + cred = calloc(1, sizeof(struct gpp_cred_handle)); + if (!cred) { + *minor_status = 0; + return GSS_S_FAILURE; + } + + tmaj = GSS_S_COMPLETE; + tmin = 0; + + /* See if we should try local first */ + if (behavior == GPP_LOCAL_ONLY || behavior == GPP_LOCAL_FIRST) { + + maj = get_local_def_creds(&min, name, cred); + if (maj != GSS_S_NO_CRED || behavior != GPP_LOCAL_FIRST) { + goto done; + } + + /* not successful, save actual local error if remote fallback fails */ + tmaj = maj; + tmin = min; + } + + /* Then try with remote */ + if (behavior == GPP_REMOTE_ONLY || behavior == GPP_REMOTE_FIRST) { + + maj = gpm_acquire_cred(&min, + NULL, 0, NULL, GSS_C_BOTH, + &cred->remote, NULL, NULL); + + if (maj == GSS_S_COMPLETE || behavior == GPP_REMOTE_ONLY) { + goto done; + } + + /* So remote failed, but we can fallback to local, try that */ + maj = get_local_def_creds(&min, name, cred); + } + +done: + if (maj != GSS_S_COMPLETE && tmaj != GSS_S_COMPLETE) { + maj = tmaj; + min = tmin; + } + *minor_status = min; + if (maj != GSS_S_COMPLETE) { + gssi_release_cred(&min, (gss_cred_id_t *)&cred); + } + *cred_handle = cred; + return maj; +} + +OM_uint32 gssi_inquire_cred(OM_uint32 *minor_status, + gss_cred_id_t cred_handle, + gss_name_t *name, + OM_uint32 *lifetime, + gss_cred_usage_t *cred_usage, + gss_OID_set *mechanisms) +{ + struct gpp_cred_handle *cred = NULL; + struct gpp_name_handle *gpname = NULL; + OM_uint32 maj, min; + + if (cred_handle == GSS_C_NO_CREDENTIAL) { + maj = gppint_get_def_creds(&min, gpp_get_behavior(), NULL, &cred); + if (maj != GSS_S_COMPLETE) { + goto done; + } + } else { + cred = (struct gpp_cred_handle *)cred_handle; + } + + if (name) { + gpname = calloc(1, sizeof(struct gpp_name_handle)); + if (!gpname) { + min = ENOMEM; + maj = GSS_S_FAILURE; + goto done; + } + } + + if (cred->local) { + maj = gss_inquire_cred(&min, cred->local, + gpname ? &gpname->local : NULL, + lifetime, cred_usage, mechanisms); + } else if (cred->remote) { + maj = gpm_inquire_cred(&min, cred->remote, + gpname ? &gpname->remote : NULL, + lifetime, cred_usage, mechanisms); + } else { + min = 0; + maj = GSS_S_FAILURE; + } + +done: + *minor_status = gpp_map_error(min); + if (cred_handle == GSS_C_NO_CREDENTIAL) { + gssi_release_cred(&min, (gss_cred_id_t*)&cred); + } + if (name && maj == GSS_S_COMPLETE) { + *name = (gss_name_t)gpname; + } else { + free(gpname); + } + return maj; +} + +OM_uint32 gssi_inquire_cred_by_mech(OM_uint32 *minor_status, + gss_cred_id_t cred_handle, + gss_OID mech_type, + gss_name_t *name, + OM_uint32 *initiator_lifetime, + OM_uint32 *acceptor_lifetime, + gss_cred_usage_t *cred_usage) +{ + struct gpp_cred_handle *cred = NULL; + struct gpp_name_handle *gpname = NULL; + OM_uint32 maj, min; + + if (cred_handle == GSS_C_NO_CREDENTIAL) { + maj = gppint_get_def_creds(&min, gpp_get_behavior(), NULL, &cred); + if (maj != GSS_S_COMPLETE) { + goto done; + } + } else { + cred = (struct gpp_cred_handle *)cred_handle; + } + + if (name) { + gpname = calloc(1, sizeof(struct gpp_name_handle)); + if (!gpname) { + min = ENOMEM; + maj = GSS_S_FAILURE; + goto done; + } + } + + if (cred->local) { + maj = gss_inquire_cred_by_mech(&min, cred->local, + gpp_special_mech(mech_type), + gpname ? &gpname->local : NULL, + initiator_lifetime, acceptor_lifetime, + cred_usage); + } else if (cred->remote) { + maj = gpm_inquire_cred_by_mech(&min, cred->remote, mech_type, + gpname ? &gpname->remote : NULL, + initiator_lifetime, acceptor_lifetime, + cred_usage); + } else { + min = 0; + maj = GSS_S_FAILURE; + } + +done: + *minor_status = gpp_map_error(min); + if (cred_handle == GSS_C_NO_CREDENTIAL) { + gssi_release_cred(&min, (gss_cred_id_t*)&cred); + } + if (name && maj == GSS_S_COMPLETE) { + *name = (gss_name_t)gpname; + } else { + free(gpname); + } + return maj; +} + +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; + + if (*cred_handle == GSS_C_NO_CREDENTIAL) { + *minor_status = 0; + return GSS_S_COMPLETE; + } + + cred = (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); + } + } + + if (cred->remote) { + maj = gpm_release_cred(&min, &cred->remote); + if (maj && rmaj == GSS_S_COMPLETE) { + rmaj = maj; + *minor_status = gpp_map_error(min); + } + } + + *cred_handle = GSS_C_NO_CREDENTIAL; + return rmaj; +} diff --git a/proxy/src/mechglue/gss_plugin.h b/proxy/src/mechglue/gss_plugin.h index 12a62e5..bc135c5 100644 --- a/proxy/src/mechglue/gss_plugin.h +++ b/proxy/src/mechglue/gss_plugin.h @@ -66,4 +66,58 @@ uint32_t gpp_name_to_local(uint32_t *minor, gssx_name *name, uint32_t gpp_local_to_name(uint32_t *minor, gss_name_t local_name, gssx_name **name); +OM_uint32 gssi_acquire_cred(OM_uint32 *minor_status, + const gss_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec); + +OM_uint32 gssi_add_cred(OM_uint32 *minor_status, + const gss_cred_id_t input_cred_handle, + const gss_name_t desired_name, + const gss_OID desired_mech, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec); + +OM_uint32 gssi_acquire_cred_with_password(OM_uint32 *minor_status, + const gss_name_t desired_name, + const gss_buffer_t password, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec); + +OM_uint32 gppint_get_def_creds(OM_uint32 *minor_status, + enum gpp_behavior behavior, + struct gpp_name_handle *name, + struct gpp_cred_handle **cred_handle); + +OM_uint32 gssi_inquire_cred(OM_uint32 *minor_status, + gss_cred_id_t cred_handle, + gss_name_t *name, + OM_uint32 *lifetime, + gss_cred_usage_t *cred_usage, + gss_OID_set *mechanisms); + +OM_uint32 gssi_inquire_cred_by_mech(OM_uint32 *minor_status, + gss_cred_id_t cred_handle, + gss_OID mech_type, + gss_name_t *name, + OM_uint32 *initiator_lifetime, + OM_uint32 *acceptor_lifetime, + gss_cred_usage_t *cred_usage); + +OM_uint32 gssi_release_cred(OM_uint32 *minor_status, + gss_cred_id_t *cred_handle); + #endif /* _GGS_PLUGIN_H_ */ |