diff options
-rw-r--r-- | proxy/Makefile.am | 1 | ||||
-rw-r--r-- | proxy/src/mechglue/gpp_context.c | 408 | ||||
-rw-r--r-- | proxy/src/mechglue/gss_plugin.h | 52 |
3 files changed, 461 insertions, 0 deletions
diff --git a/proxy/Makefile.am b/proxy/Makefile.am index c75f0c6..e93cb67 100644 --- a/proxy/Makefile.am +++ b/proxy/Makefile.am @@ -103,6 +103,7 @@ GP_RPCCLI_OBJ = \ GP_MECHGLUE_OBJ = \ src/mechglue/gpp_acquire_cred.c \ src/mechglue/gpp_creds.c \ + src/mechglue/gpp_context.c \ src/mechglue/gss_plugin.c dist_noinst_HEADERS = \ diff --git a/proxy/src/mechglue/gpp_context.c b/proxy/src/mechglue/gpp_context.c new file mode 100644 index 0000000..5276084 --- /dev/null +++ b/proxy/src/mechglue/gpp_context.c @@ -0,0 +1,408 @@ +/* + 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" +#include <endian.h> +#include <time.h> + +OM_uint32 gssi_export_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t interprocess_token) +{ + struct gpp_context_handle *ctx; + gss_buffer_desc output_token; + OM_uint32 maj, min; + + ctx = (struct gpp_context_handle *)context_handle; + if (!ctx) { + return GSS_S_CALL_INACCESSIBLE_READ; + } + + /* for now we have support only for some specific known + * mechanisms for which we can export/import the context */ + if (ctx->remote && !ctx->local) { + maj = gpp_remote_to_local_ctx(&min, &ctx->remote, &ctx->local); + if (maj != GSS_S_COMPLETE) { + *minor_status = gpp_map_error(min); + return maj; + } + } + + maj = gss_export_sec_context(minor_status, &ctx->local, + interprocess_token); + + if (maj == GSS_S_COMPLETE && ctx->remote) { + (void)gpm_delete_sec_context(&min, &ctx->remote, &output_token); + } + + return maj; +} + +OM_uint32 gssi_import_sec_context(OM_uint32 *minor_status, + gss_buffer_t interprocess_token, + gss_ctx_id_t *context_handle) +{ + return GSS_S_UNAVAILABLE; +} + +OM_uint32 gssi_import_sec_context_for_mech(OM_uint32 *minor_status, + gss_OID mech_type, + gss_buffer_t interprocess_token, + gss_ctx_id_t *context_handle) +{ + struct gpp_context_handle *ctx; + gss_buffer_desc wrap_token = {0}; + gss_OID spmech; + OM_uint32 maj, min = 0; + uint32_t len; + + ctx = calloc(1, sizeof(struct gpp_context_handle)); + if (!ctx) { + *minor_status = 0; + return GSS_S_FAILURE; + } + + /* NOTE: it makes no sense to import a context remotely atm, + * so we only handle the local case for now. */ + spmech = gpp_special_mech(mech_type); + if (spmech == GSS_C_NO_OID) { + maj = GSS_S_FAILURE; + goto done; + } + + wrap_token.length = sizeof(uint32_t) + spmech->length + + interprocess_token->length; + wrap_token.value = malloc(wrap_token.length); + if (!wrap_token.value) { + wrap_token.length = 0; + maj = GSS_S_FAILURE; + goto done; + } + + len = htobe32(wrap_token.length); + memcpy(wrap_token.value, &len, sizeof(uint32_t)); + memcpy(wrap_token.value + sizeof(uint32_t), + spmech->elements, spmech->length); + memcpy(wrap_token.value + sizeof(uint32_t) + spmech->length, + interprocess_token->value, interprocess_token->length); + + maj = gss_import_sec_context(&min, &wrap_token, &ctx->local); + +done: + *minor_status = gpp_map_error(min); + if (maj == GSS_S_COMPLETE) { + *context_handle = (gss_ctx_id_t)ctx; + } else { + free(ctx); + } + (void)gss_release_buffer(&min, &wrap_token); + return maj; +} + +OM_uint32 gssi_process_context_token(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_buffer_t token_buffer) +{ + struct gpp_context_handle *ctx; + OM_uint32 maj, min; + + ctx = (struct gpp_context_handle *)context_handle; + if (!ctx) { + return GSS_S_CALL_INACCESSIBLE_READ; + } + + /* for now we have support only for some specific known + * mechanisms for which we can export/import the context */ + if (ctx->remote && !ctx->local) { + maj = gpp_remote_to_local_ctx(&min, &ctx->remote, &ctx->local); + if (maj != GSS_S_COMPLETE) { + *minor_status = gpp_map_error(min); + return maj; + } + } + + return gss_process_context_token(minor_status, ctx->local, token_buffer); +} + +OM_uint32 gssi_context_time(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + OM_uint32 *time_rec) +{ + struct gpp_context_handle *ctx; + OM_uint32 maj, min; + + *minor_status = 0; + + ctx = (struct gpp_context_handle *)context_handle; + if (!ctx) { + return GSS_S_CALL_INACCESSIBLE_READ; + } + + /* for now we have support only for some specific known + * mechanisms for which we can export/import the context */ + if (ctx->remote) { + OM_uint32 lifetime; + long int t; + maj = gpm_inquire_context(&min, ctx->remote, NULL, NULL, + &lifetime, NULL, NULL, NULL, NULL); + if (maj != GSS_S_COMPLETE) { + *minor_status = gpp_map_error(min); + return maj; + } + t = lifetime - time(NULL); + if (t > 0) { + *time_rec = t; + return GSS_S_COMPLETE; + } else { + return GSS_S_CONTEXT_EXPIRED; + } + } else if (ctx->local) { + return gss_context_time(minor_status, ctx->local, time_rec); + } else { + return GSS_S_NO_CONTEXT; + } +} + +OM_uint32 gssi_inquire_context(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_name_t *src_name, + gss_name_t *targ_name, + OM_uint32 *lifetime_rec, + gss_OID *mech_type, + OM_uint32 *ctx_flags, + int *locally_initiated, + int *open) +{ + struct gpp_context_handle *ctx_handle; + struct gpp_name_handle *s_name = NULL; + struct gpp_name_handle *t_name = NULL; + gss_OID mech_oid; + OM_uint32 maj, min; + + if (!context_handle) { + return GSS_S_CALL_INACCESSIBLE_READ; + } + + ctx_handle = (struct gpp_context_handle *)context_handle; + if (!ctx_handle->local && + !ctx_handle->remote) { + return GSS_S_CALL_INACCESSIBLE_READ; + } + + if (src_name) { + s_name = calloc(1, sizeof(struct gpp_name_handle)); + if (!s_name) { + min = ENOMEM; + maj = GSS_S_FAILURE; + goto done; + } + } + if (targ_name) { + t_name = calloc(1, sizeof(struct gpp_name_handle)); + if (!t_name) { + min = ENOMEM; + maj = GSS_S_FAILURE; + goto done; + } + } + + if (ctx_handle->local) { + maj = gss_inquire_context(&min, + ctx_handle->local, + src_name ? &s_name->local : NULL, + src_name ? &t_name->local : NULL, + lifetime_rec, + &mech_oid, + ctx_flags, + locally_initiated, + open); + } else { + maj = gpm_inquire_context(&min, + ctx_handle->remote, + src_name ? &s_name->remote : NULL, + src_name ? &t_name->remote : NULL, + lifetime_rec, + &mech_oid, + ctx_flags, + locally_initiated, + open); + } + + if (maj != GSS_S_COMPLETE) { + goto done; + } + + if (mech_type) { + *mech_type = mech_oid; + } + + if (src_name) { + maj = gpp_copy_oid(&min, mech_oid, &s_name->mech_type); + if (maj != GSS_S_COMPLETE) { + goto done; + } + *src_name = (gss_name_t)s_name; + } + + if (t_name) { + maj = gpp_copy_oid(&min, mech_oid, &t_name->mech_type); + if (maj != GSS_S_COMPLETE) { + goto done; + } + *targ_name = (gss_name_t)t_name; + } + +done: + *minor_status = gpp_map_error(min); + if (maj != GSS_S_COMPLETE) { + (void)gssi_release_name(&min, (gss_name_t *)&s_name); + (void)gssi_release_name(&min, (gss_name_t *)&t_name); + } + return maj; +} + +OM_uint32 gssi_inquire_sec_context_by_oid(OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set) +{ + struct gpp_context_handle *ctx; + OM_uint32 maj, min; + + ctx = (struct gpp_context_handle *)context_handle; + if (!ctx) { + return GSS_S_CALL_INACCESSIBLE_READ; + } + + /* for now we have support only for some specific known + * mechanisms for which we can export/import the context */ + if (ctx->remote && !ctx->local) { + maj = gpp_remote_to_local_ctx(&min, &ctx->remote, &ctx->local); + if (maj != GSS_S_COMPLETE) { + *minor_status = gpp_map_error(min); + return maj; + } + } + + return gss_inquire_sec_context_by_oid(minor_status, ctx->local, + desired_object, data_set); +} + +OM_uint32 gssi_set_sec_context_option(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + const gss_OID desired_object, + const gss_buffer_t value) +{ + struct gpp_context_handle *ctx; + OM_uint32 maj, min; + + if (context_handle) { + ctx = (struct gpp_context_handle *)context_handle; + } else { + ctx = calloc(1, sizeof(struct gpp_context_handle)); + if (!ctx) { + *minor_status = 0; + return GSS_S_FAILURE; + } + } + + /* for now we have support only for some specific known + * mechanisms for which we can export/import the context */ + if (ctx->remote && !ctx->local) { + maj = gpp_remote_to_local_ctx(&min, &ctx->remote, &ctx->local); + if (maj != GSS_S_COMPLETE) { + *minor_status = gpp_map_error(min); + return maj; + } + } + + maj = gss_set_sec_context_option(minor_status, &ctx->local, + desired_object, value); + if (maj == GSS_S_COMPLETE) { + *context_handle = (gss_ctx_id_t)ctx; + } + return maj; +} + +OM_uint32 gssi_delete_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t output_token) +{ + struct gpp_context_handle *ctx; + OM_uint32 maj, min; + OM_uint32 rmaj = GSS_S_COMPLETE; + + ctx = (struct gpp_context_handle *)*context_handle; + + *context_handle = GSS_C_NO_CONTEXT; + + if (ctx->local) { + maj = gss_delete_sec_context(&min, &ctx->local, output_token); + if (maj != GSS_S_COMPLETE) { + rmaj = maj; + *minor_status = gpp_map_error(min); + } + } + + if (ctx->remote) { + maj = gpm_delete_sec_context(&min, &ctx->remote, output_token); + if (maj && rmaj == GSS_S_COMPLETE) { + rmaj = maj; + *minor_status = gpp_map_error(min); + } + } + + return rmaj; +} + +OM_uint32 gssi_pseudo_random(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int prf_key, + const gss_buffer_t prf_in, + ssize_t desired_output_len, + gss_buffer_t prf_out) +{ + struct gpp_context_handle *ctx; + OM_uint32 maj, min; + + ctx = (struct gpp_context_handle *)context_handle; + if (!ctx) { + return GSS_S_CALL_INACCESSIBLE_READ; + } + + /* for now we have support only for some specific known + * mechanisms for which we can export/import the context */ + if (ctx->remote && !ctx->local) { + maj = gpp_remote_to_local_ctx(&min, &ctx->remote, &ctx->local); + if (maj != GSS_S_COMPLETE) { + *minor_status = gpp_map_error(min); + return maj; + } + } + + return gss_pseudo_random(minor_status, + ctx->local, prf_key, prf_in, + desired_output_len, prf_out); +} diff --git a/proxy/src/mechglue/gss_plugin.h b/proxy/src/mechglue/gss_plugin.h index fb548e0..a713ecd 100644 --- a/proxy/src/mechglue/gss_plugin.h +++ b/proxy/src/mechglue/gss_plugin.h @@ -142,4 +142,56 @@ OM_uint32 gssi_store_cred(OM_uint32 *minor_status, OM_uint32 gssi_release_cred(OM_uint32 *minor_status, gss_cred_id_t *cred_handle); +OM_uint32 gssi_export_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t interprocess_token); + +OM_uint32 gssi_import_sec_context(OM_uint32 *minor_status, + gss_buffer_t interprocess_token, + gss_ctx_id_t *context_handle); + +OM_uint32 gssi_import_sec_context_for_mech(OM_uint32 *minor_status, + gss_OID mech_type, + gss_buffer_t interprocess_token, + gss_ctx_id_t *context_handle); + +OM_uint32 gssi_process_context_token(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_buffer_t token_buffer); + +OM_uint32 gssi_context_time(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + OM_uint32 *time_rec); + +OM_uint32 gssi_inquire_context(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_name_t *src_name, + gss_name_t *targ_name, + OM_uint32 *lifetime_rec, + gss_OID *mech_type, + OM_uint32 *ctx_flags, + int *locally_initiated, + int *open); + +OM_uint32 gssi_inquire_sec_context_by_oid(OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set); + +OM_uint32 gssi_set_sec_context_option(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + const gss_OID desired_object, + const gss_buffer_t value); + +OM_uint32 gssi_pseudo_random(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int prf_key, + const gss_buffer_t prf_in, + ssize_t desired_output_len, + gss_buffer_t prf_out); + +OM_uint32 gssi_delete_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t output_token); + #endif /* _GSS_PLUGIN_H_ */ |