From 1919bf9c7a8c0995e4a4bc0483732084b3b5f241 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 31 Jul 2012 18:15:12 -0400 Subject: Move client lib files in their own directory Make space for the actual mechglue plugin interface. The mechglue interface will use the client library to communicate with the gss-proxy but will reimplement all GSSAPI SPI as wrappers in order to properly handle fallbacks to local mechanism and other input/output transformations. --- proxy/src/client/gpm_accept_sec_context.c | 183 +++++++ proxy/src/client/gpm_acquire_cred.c | 289 +++++++++++ proxy/src/client/gpm_common.c | 520 +++++++++++++++++++ proxy/src/client/gpm_display_status.c | 124 +++++ proxy/src/client/gpm_import_and_canon_name.c | 342 +++++++++++++ proxy/src/client/gpm_indicate_mechs.c | 734 +++++++++++++++++++++++++++ proxy/src/client/gpm_init_sec_context.c | 176 +++++++ proxy/src/client/gpm_release_handle.c | 131 +++++ proxy/src/client/gssapi_gpm.h | 162 ++++++ 9 files changed, 2661 insertions(+) create mode 100644 proxy/src/client/gpm_accept_sec_context.c create mode 100644 proxy/src/client/gpm_acquire_cred.c create mode 100644 proxy/src/client/gpm_common.c create mode 100644 proxy/src/client/gpm_display_status.c create mode 100644 proxy/src/client/gpm_import_and_canon_name.c create mode 100644 proxy/src/client/gpm_indicate_mechs.c create mode 100644 proxy/src/client/gpm_init_sec_context.c create mode 100644 proxy/src/client/gpm_release_handle.c create mode 100644 proxy/src/client/gssapi_gpm.h (limited to 'proxy/src/client') diff --git a/proxy/src/client/gpm_accept_sec_context.c b/proxy/src/client/gpm_accept_sec_context.c new file mode 100644 index 0000000..d5eeb8a --- /dev/null +++ b/proxy/src/client/gpm_accept_sec_context.c @@ -0,0 +1,183 @@ +/* + GSS-PROXY + + Copyright (C) 2011 Red Hat, Inc. + Copyright (C) 2011 Simo Sorce + + 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 "gssapi_gpm.h" +#include "src/gp_conv.h" + +OM_uint32 gpm_accept_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_cred_id_t acceptor_cred_handle, + gss_buffer_t input_token_buffer, + gss_channel_bindings_t input_chan_bindings, + gss_name_t *src_name, + gss_OID *mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec, + gss_cred_id_t *delegated_cred_handle) +{ + union gp_rpc_arg uarg; + union gp_rpc_res ures; + gssx_arg_accept_sec_context *arg = &uarg.accept_sec_context; + gssx_res_accept_sec_context *res = &ures.accept_sec_context; + gssx_ctx *ctx = NULL; + gssx_name *name = NULL; + gss_OID_desc *mech = NULL; + gss_buffer_t outbuf = NULL; + uint32_t ret_maj; + int ret; + + memset(&uarg, 0, sizeof(union gp_rpc_arg)); + memset(&ures, 0, sizeof(union gp_rpc_res)); + + /* prepare proxy request */ + if (*context_handle) { + arg->context_handle = (gssx_ctx *)*context_handle; + } + + if (acceptor_cred_handle) { + arg->cred_handle = (gssx_cred *)acceptor_cred_handle; + } + + ret = gp_conv_buffer_to_gssx(input_token_buffer, &arg->input_token); + if (ret) { + goto done; + } + + if (input_chan_bindings) { + ret = gp_conv_cb_to_gssx_alloc(input_chan_bindings, &arg->input_cb); + if (ret) { + goto done; + } + } + + /* execute proxy request */ + ret = gpm_make_call(GSSX_ACCEPT_SEC_CONTEXT, &uarg, &ures); + if (ret) { + goto done; + } + + /* return values */ + if (mech_type) { + if (res->status.mech.octet_string_len) { + ret = gp_conv_gssx_to_oid_alloc(&res->status.mech, &mech); + if (ret) { + goto done; + } + } + } + + if (res->status.major_status) { + gpm_save_status(&res->status); + ret_maj = res->status.major_status; + *minor_status = res->status.minor_status; + ret = 0; + goto done; + } + + if (res->context_handle) { + ctx = res->context_handle; + /* we are stealing the delegated creds on success, so we do not want + * it to be freed by xdr_free */ + res->context_handle = NULL; + } + + if (src_name) { + ret = gp_copy_gssx_name_alloc(&ctx->src_name, &name); + if (ret) { + goto done; + } + } + + ret = gp_conv_gssx_to_buffer_alloc(res->output_token, &outbuf); + if (ret) { + goto done; + } + + /* replace old ctx handle if any */ + if (*context_handle) { + xdr_free((xdrproc_t)xdr_gssx_ctx, (char *)*context_handle); + free(*context_handle); + } + *context_handle = (gss_ctx_id_t)ctx; + if (mech_type) { + *mech_type = mech; + } + if (src_name) { + *src_name = (gss_name_t)name; + } + if (outbuf) { + *output_token = *outbuf; + free(outbuf); + } + if (ret_flags) { + *ret_flags = ctx->ctx_flags; + } + if (time_rec) { + *time_rec = ctx->lifetime; + } + + if (res->delegated_cred_handle) { + if (delegated_cred_handle) { + *delegated_cred_handle = (gss_cred_id_t)res->delegated_cred_handle; + } + /* we are stealing the delegated creds on success, so we do not want + * it to be freed by xdr_free */ + res->delegated_cred_handle = NULL; + } + + *minor_status = 0; + ret_maj = GSS_S_COMPLETE; + +done: + /* we are putting our copy of these structures in here, + * and do not want it to be freed by xdr_free */ + arg->context_handle = NULL; + arg->cred_handle = NULL; + gpm_free_xdrs(GSSX_ACCEPT_SEC_CONTEXT, &uarg, &ures); + if (ret) { + if (ctx) { + xdr_free((xdrproc_t)xdr_gssx_ctx, (char *)ctx); + free(ctx); + } + if (name) { + xdr_free((xdrproc_t)xdr_gssx_name, (char *)name); + free(name); + } + if (mech) { + free(mech->elements); + free(mech); + } + if (outbuf) { + free(outbuf->value); + free(outbuf); + } + *minor_status = ret; + return GSS_S_FAILURE; + } + + return ret_maj; +} + diff --git a/proxy/src/client/gpm_acquire_cred.c b/proxy/src/client/gpm_acquire_cred.c new file mode 100644 index 0000000..8e9b010 --- /dev/null +++ b/proxy/src/client/gpm_acquire_cred.c @@ -0,0 +1,289 @@ +/* + GSS-PROXY + + Copyright (C) 2011 Red Hat, Inc. + Copyright (C) 2011 Simo Sorce + + 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 "gssapi_gpm.h" + +static int gpmint_cred_to_actual_mechs(gssx_cred *c, gss_OID_set *a) +{ + gssx_cred_element *e; + gss_OID_set m = GSS_C_NO_OID_SET; + int i; + + + if (c->elements.elements_len) { + + m = malloc(sizeof(gss_OID_set_desc)); + if (!m) { + return ENOMEM; + } + m->elements = calloc(c->elements.elements_len, + sizeof(gss_OID_desc)); + if (!m->elements) { + free(m); + return ENOMEM; + } + + for (i = 0; i < c->elements.elements_len; i++) { + e = &c->elements.elements_val[i]; + + m->elements[i].elements = gp_memdup(e->mech.octet_string_val, + e->mech.octet_string_len); + if (!m->elements[i].elements) { + while (i > 0) { + i--; + free(m->elements[i].elements); + } + free(m->elements); + free(m); + return ENOMEM; + } + m->elements[i].length = e->mech.octet_string_len; + } + } + + *a = m; + return 0; +} + +OM_uint32 gpm_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) +{ + union gp_rpc_arg uarg; + union gp_rpc_res ures; + gssx_arg_acquire_cred *arg = &uarg.acquire_cred; + gssx_res_acquire_cred *res = &ures.acquire_cred; + uint32_t ret_min; + uint32_t ret_maj; + int ret = 0; + + memset(&uarg, 0, sizeof(union gp_rpc_arg)); + memset(&ures, 0, sizeof(union gp_rpc_res)); + + if (output_cred_handle == NULL) { + ret_maj = GSS_S_FAILURE; + ret_min = EINVAL; + goto done; + } + + /* ignore call_ctx for now */ + + if (desired_name) { + arg->desired_name = calloc(1, sizeof(gssx_name)); + if (!arg->desired_name) { + ret_maj = GSS_S_FAILURE; + ret_min = ENOMEM; + goto done; + } + ret_maj = gp_conv_name_to_gssx(&ret_min, + desired_name, arg->desired_name); + if (ret_maj) { + goto done; + } + } + if (desired_mechs) { + ret = gp_conv_oid_set_to_gssx(desired_mechs, &arg->desired_mechs); + if (ret) { + ret_maj = GSS_S_FAILURE; + ret_min = ret; + goto done; + } + } + arg->time_req = time_req; + arg->cred_usage = gp_conv_cred_usage_to_gssx(cred_usage); + + /* execute proxy request */ + ret = gpm_make_call(GSSX_ACQUIRE_CRED, &uarg, &ures); + if (ret) { + ret_maj = GSS_S_FAILURE; + ret_min = ret; + goto done; + } + + if (res->status.major_status) { + gpm_save_status(&res->status); + ret_min = res->status.minor_status; + ret_maj = res->status.major_status; + goto done; + } + + if (actual_mechs) { + ret = gpmint_cred_to_actual_mechs(res->output_cred_handle, + actual_mechs); + if (ret) { + ret_maj = GSS_S_FAILURE; + ret_min = ret; + goto done; + } + } + + if (time_rec) { + gssx_cred_element *e; + uint32_t t = 0; + + if (res->output_cred_handle->elements.elements_len) { + e = &res->output_cred_handle->elements.elements_val[0]; + if (e->initiator_time_rec < e->acceptor_time_rec) { + t = e->initiator_time_rec; + } else { + t = e->acceptor_time_rec; + } + } + + *time_rec = t; + } + + /* we steal the cred handler here */ + *output_cred_handle = (gss_cred_id_t)res->output_cred_handle; + res->output_cred_handle = NULL; + ret_maj = GSS_S_COMPLETE; + ret_min = 0; + +done: + gpm_free_xdrs(GSSX_ACQUIRE_CRED, &uarg, &ures); + *minor_status = ret_min; + return ret_maj; +} + +OM_uint32 gpm_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) +{ + union gp_rpc_arg uarg; + union gp_rpc_res ures; + gssx_arg_acquire_cred *arg = &uarg.acquire_cred; + gssx_res_acquire_cred *res = &ures.acquire_cred; + gss_OID_set_desc mechs; + uint32_t ret_min; + uint32_t ret_maj; + int ret = 0; + + memset(&uarg, 0, sizeof(union gp_rpc_arg)); + memset(&ures, 0, sizeof(union gp_rpc_res)); + + /* ignore call_ctx for now */ + + if (input_cred_handle) { + arg->input_cred_handle = (gssx_cred *)input_cred_handle; + } + if (output_cred_handle != NULL) { + arg->add_cred_to_input_handle = true; + } + if (desired_name != GSS_C_NO_NAME) { + arg->desired_name = calloc(1, sizeof(gssx_name)); + if (!arg->desired_name) { + ret = ENOMEM; + goto done; + } + ret_maj = gp_conv_name_to_gssx(&ret_min, + desired_name, arg->desired_name); + if (ret_maj) { + goto done; + } + } + if (desired_mech != GSS_C_NO_OID) { + mechs.count = 1; + mechs.elements = desired_mech; + ret = gp_conv_oid_set_to_gssx(&mechs, &arg->desired_mechs); + if (ret) { + ret_maj = GSS_S_FAILURE; + ret_min = ret; + goto done; + } + } + arg->cred_usage = gp_conv_cred_usage_to_gssx(cred_usage); + arg->initiator_time_req = initiator_time_req; + arg->acceptor_time_req = acceptor_time_req; + + /* execute proxy request */ + ret = gpm_make_call(GSSX_ACQUIRE_CRED, &uarg, &ures); + if (ret) { + ret_maj = GSS_S_FAILURE; + ret_min = ret; + goto done; + } + + if (res->status.major_status) { + gpm_save_status(&res->status); + ret_min = res->status.minor_status; + ret_maj = res->status.major_status; + goto done; + } + + if (actual_mechs) { + ret = gpmint_cred_to_actual_mechs(res->output_cred_handle, + actual_mechs); + if (ret) { + ret_maj = GSS_S_FAILURE; + ret_min = ret; + goto done; + } + } + + if (res->output_cred_handle->elements.elements_len) { + gssx_cred_element *e; + e = &res->output_cred_handle->elements.elements_val[0]; + if (initiator_time_rec) { + *initiator_time_rec = e->initiator_time_rec; + } + if (acceptor_time_rec) { + *acceptor_time_rec = e->initiator_time_rec; + } + } else { + if (initiator_time_rec) { + *initiator_time_rec = 0; + } + if (acceptor_time_rec) { + *acceptor_time_rec = 0; + } + } + + if (output_cred_handle) { + /* we steal the cred handler here */ + *output_cred_handle = (gss_cred_id_t)res->output_cred_handle; + res->output_cred_handle = NULL; + } + + ret_maj = GSS_S_COMPLETE; + ret_min = 0; + +done: + gpm_free_xdrs(GSSX_ACQUIRE_CRED, &uarg, &ures); + *minor_status = ret_min; + return ret_maj; +} diff --git a/proxy/src/client/gpm_common.c b/proxy/src/client/gpm_common.c new file mode 100644 index 0000000..16ea7d6 --- /dev/null +++ b/proxy/src/client/gpm_common.c @@ -0,0 +1,520 @@ +/* + GSS-PROXY + + Copyright (C) 2011 Red Hat, Inc. + Copyright (C) 2011 Simo Sorce + + 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 "gssapi_gpm.h" +#include +#include +#include +#include +#include + +#define FRAGMENT_BIT (1 << 31) + +struct gpm_ctx { + pthread_mutex_t lock; + int fd; + int next_xid; +}; + +/* a single global struct is not particularly efficient, + * but will do for now */ +struct gpm_ctx gpm_global_ctx; + +pthread_once_t gpm_init_once_control = PTHREAD_ONCE_INIT; + +static void gpm_init_once(void) +{ + pthread_mutexattr_t attr; + unsigned int seedp; + + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + + pthread_mutex_init(&gpm_global_ctx.lock, &attr); + + gpm_global_ctx.fd = -1; + + seedp = time(NULL) + getpid() + pthread_self(); + gpm_global_ctx.next_xid = rand_r(&seedp); + + pthread_mutexattr_destroy(&attr); +} + +#define GP_SOCKET_NAME "gssproxy.socket" + +static int get_pipe_name(struct gpm_ctx *gpmctx, char *name) +{ + int ret; + + /* TODO: get socket name from config file */ + + ret = snprintf(name, PATH_MAX, "%s/%s", PIPE_PATH, GP_SOCKET_NAME); + if (ret < 0 || ret >= PATH_MAX) { + return ENAMETOOLONG; + } + + return 0; +} + +static int gpm_open_socket(struct gpm_ctx *gpmctx) +{ + struct sockaddr_un addr = {0}; + char name[PATH_MAX]; + int ret; + int fd = -1; + + ret = get_pipe_name(gpmctx, name); + if (ret) { + return ret; + } + + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, name, sizeof(addr.sun_path)-1); + addr.sun_path[sizeof(addr.sun_path)-1] = '\0'; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + ret = errno; + goto done; + } + + ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); + +done: + if (ret) { + if (fd != -1) { + close(fd); + fd = -1; + } + } + gpmctx->fd = fd; + return ret; +} + +static void gpm_close_socket(struct gpm_ctx *gpmctx) +{ + int ret; + + do { + ret = close(gpmctx->fd); + /* in theory we should retry to close() on EINTR, + * but on same system the fd will be invalid after + * close() has been called, so closing again may + * cause a race with another thread that just happend + * to open an unrelated file descriptor. + * So until POSIX finally amends language around close() + * and at least the Linux kernel changes its behavior, + * it is better to risk a leak than closing an unrelated + * file descriptor */ + ret = 0; + } while (ret == EINTR); + + gpmctx->fd = -1; +} + +static int gpm_grab_sock(struct gpm_ctx *gpmctx) +{ + int ret; + + ret = pthread_mutex_lock(&gpmctx->lock); + if (ret) { + return ret; + } + + if (gpmctx->fd == -1) { + ret = gpm_open_socket(gpmctx); + } + + return ret; +} + +static int gpm_release_sock(struct gpm_ctx *gpmctx) +{ + return pthread_mutex_unlock(&gpmctx->lock); +} + +static int gpm_send_buffer(struct gpm_ctx *gpmctx, + char *buffer, uint32_t length) +{ + uint32_t size; + size_t wn; + size_t pos; + bool retry; + int ret; + + if (length > MAX_RPC_SIZE) { + return EINVAL; + } + + gpm_grab_sock(gpmctx); + + size = length | FRAGMENT_BIT; + size = htonl(size); + + retry = false; + do { + ret = 0; + do { + wn = write(gpmctx->fd, &size, sizeof(uint32_t)); + if (wn == -1) { + ret = errno; + } + } while (ret == EINTR); + if (wn != 4) { + /* reopen and retry once */ + if (retry == false) { + gpm_close_socket(gpmctx); + ret = gpm_open_socket(gpmctx); + if (ret == 0) { + retry = true; + continue; + } + } else { + ret = EIO; + } + goto done; + } + retry = false; + } while (retry); + + pos = 0; + while (length > pos) { + wn = write(gpmctx->fd, buffer + pos, length - pos); + if (wn == -1) { + if (errno == EINTR) { + continue; + } + ret = errno; + goto done; + } + pos += wn; + } + + ret = 0; + +done: + if (ret) { + /* on errors we can only close the fd and return */ + gpm_close_socket(gpmctx); + } + gpm_release_sock(gpmctx); + return ret; +} + +static int gpm_recv_buffer(struct gpm_ctx *gpmctx, + char *buffer, uint32_t *length) +{ + uint32_t size; + size_t rn; + size_t pos; + bool retry; + int ret; + + gpm_grab_sock(gpmctx); + + retry = false; + do { + ret = 0; + do { + rn = read(gpmctx->fd, &size, sizeof(uint32_t)); + if (rn == -1) { + ret = errno; + } + } while (ret == EINTR); + if (rn != 4) { + /* reopen and retry once */ + if (retry == false) { + gpm_close_socket(gpmctx); + ret = gpm_open_socket(gpmctx); + if (ret == 0) { + retry = true; + continue; + } + } else { + ret = EIO; + } + goto done; + } + retry = false; + } while (retry); + + *length = ntohl(size); + *length &= ~FRAGMENT_BIT; + + if (*length > MAX_RPC_SIZE) { + ret = EMSGSIZE; + goto done; + } + + pos = 0; + while (*length > pos) { + rn = read(gpmctx->fd, buffer + pos, *length - pos); + if (rn == -1) { + if (errno == EINTR) { + continue; + } + ret = errno; + goto done; + } + if (rn == 0) { + ret = EIO; + goto done; + } + pos += rn; + } + + ret = 0; + +done: + if (ret) { + /* on errors we can only close the fd and return */ + gpm_close_socket(gpmctx); + } + gpm_release_sock(gpmctx); + return ret; +} + +static int gpm_next_xid(struct gpm_ctx *gpmctx, uint32_t *xid) +{ + int ret; + + ret = gpm_grab_sock(gpmctx); + if (ret) { + goto done; + } + + if (gpmctx->next_xid < 0) { + *xid = 0; + gpmctx->next_xid = 1; + } else { + *xid = gpmctx->next_xid++; + } + +done: + gpm_release_sock(gpmctx); + return ret; +} + +static struct gpm_ctx *gpm_get_ctx(void) +{ + int ret; + + pthread_once(&gpm_init_once_control, gpm_init_once); + + ret = gpm_grab_sock(&gpm_global_ctx); + if (ret) { + return NULL; + } + + return &gpm_global_ctx; +} + +static void gpm_release_ctx(struct gpm_ctx *gpmctx) +{ + gpm_release_sock(gpmctx); +} + +OM_uint32 gpm_release_buffer(OM_uint32 *minor_status, + gss_buffer_t buffer) +{ + if (buffer != GSS_C_NO_BUFFER) { + if (buffer->value) { + free(buffer->value); + } + buffer->length = 0; + buffer->value = NULL; + } + return GSS_S_COMPLETE; +} + +struct gpm_rpc_fn_set { + xdrproc_t arg_fn; + xdrproc_t res_fn; +} gpm_xdr_set[] = { + { /* NULLPROC */ + (xdrproc_t)xdr_void, + (xdrproc_t)xdr_void, + }, + { /* GSSX_INDICATE_MECHS */ + (xdrproc_t)xdr_gssx_arg_indicate_mechs, + (xdrproc_t)xdr_gssx_res_indicate_mechs, + }, + { /* GSSX_GET_CALL_CONTEXT */ + (xdrproc_t)xdr_gssx_arg_get_call_context, + (xdrproc_t)xdr_gssx_res_get_call_context, + }, + { /* GSSX_IMPORT_AND_CANON_NAME */ + (xdrproc_t)xdr_gssx_arg_import_and_canon_name, + (xdrproc_t)xdr_gssx_res_import_and_canon_name, + }, + { /* GSSX_EXPORT_CRED */ + (xdrproc_t)xdr_gssx_arg_export_cred, + (xdrproc_t)xdr_gssx_res_export_cred, + }, + { /* GSSX_IMPORT_CRED */ + (xdrproc_t)xdr_gssx_arg_import_cred, + (xdrproc_t)xdr_gssx_res_import_cred, + }, + { /* GSSX_ACQUIRE_CRED */ + (xdrproc_t)xdr_gssx_arg_acquire_cred, + (xdrproc_t)xdr_gssx_res_acquire_cred, + }, + { /* GSSX_STORE_CRED */ + (xdrproc_t)xdr_gssx_arg_store_cred, + (xdrproc_t)xdr_gssx_res_store_cred, + }, + { /* GSSX_INIT_SEC_CONTEXT */ + (xdrproc_t)xdr_gssx_arg_init_sec_context, + (xdrproc_t)xdr_gssx_res_init_sec_context, + }, + { /* GSSX_ACCEPT_SEC_CONTEXT */ + (xdrproc_t)xdr_gssx_arg_accept_sec_context, + (xdrproc_t)xdr_gssx_res_accept_sec_context, + }, + { /* GSSX_RELEASE_HANDLE */ + (xdrproc_t)xdr_gssx_arg_release_handle, + (xdrproc_t)xdr_gssx_res_release_handle, + }, + { /* GSSX_GET_MIC */ + (xdrproc_t)xdr_gssx_arg_get_mic, + (xdrproc_t)xdr_gssx_res_get_mic, + }, + { /* GSSX_VERIFY */ + (xdrproc_t)xdr_gssx_arg_verify_mic, + (xdrproc_t)xdr_gssx_res_verify_mic, + }, + { /* GSSX_WRAP */ + (xdrproc_t)xdr_gssx_arg_wrap, + (xdrproc_t)xdr_gssx_res_wrap, + }, + { /* GSSX_UNWRAP */ + (xdrproc_t)xdr_gssx_arg_unwrap, + (xdrproc_t)xdr_gssx_res_unwrap, + }, + { /* GSSX_WRAP_SIZE_LIMIT */ + (xdrproc_t)xdr_gssx_arg_wrap_size_limit, + (xdrproc_t)xdr_gssx_res_wrap_size_limit, + } +}; + +int gpm_make_call(int proc, union gp_rpc_arg *arg, union gp_rpc_res *res) +{ + struct gpm_ctx *gpmctx; + gp_rpc_msg msg; + XDR xdr_call_ctx; + XDR xdr_reply_ctx; + char buffer[MAX_RPC_SIZE]; + uint32_t length; + uint32_t xid; + bool xdrok; + int ret; + + xdrmem_create(&xdr_call_ctx, buffer, MAX_RPC_SIZE, XDR_ENCODE); + xdrmem_create(&xdr_reply_ctx, buffer, MAX_RPC_SIZE, XDR_DECODE); + + memset(&msg, 0, sizeof(gp_rpc_msg)); + msg.header.type = GP_RPC_CALL; + msg.header.gp_rpc_msg_union_u.chdr.rpcvers = 2; + msg.header.gp_rpc_msg_union_u.chdr.prog = GSSPROXY; + msg.header.gp_rpc_msg_union_u.chdr.vers = GSSPROXYVERS; + msg.header.gp_rpc_msg_union_u.chdr.proc = proc; + msg.header.gp_rpc_msg_union_u.chdr.cred.flavor = GP_RPC_AUTH_NONE; + msg.header.gp_rpc_msg_union_u.chdr.cred.body.body_len = 0; + msg.header.gp_rpc_msg_union_u.chdr.cred.body.body_val = NULL; + msg.header.gp_rpc_msg_union_u.chdr.verf.flavor = GP_RPC_AUTH_NONE; + msg.header.gp_rpc_msg_union_u.chdr.verf.body.body_len = 0; + msg.header.gp_rpc_msg_union_u.chdr.verf.body.body_val = NULL; + + gpmctx = gpm_get_ctx(); + if (!gpmctx) { + return EINVAL; + } + + ret = gpm_next_xid(gpmctx, &xid); + if (ret) { + goto done; + } + msg.xid = xid; + + /* encode header */ + xdrok = xdr_gp_rpc_msg(&xdr_call_ctx, &msg); + if (!xdrok) { + ret = EINVAL; + goto done; + } + + /* encode data */ + xdrok = gpm_xdr_set[proc].arg_fn(&xdr_call_ctx, (char *)arg); + if (!xdrok) { + ret = EINVAL; + goto done; + } + + /* send to proxy */ + ret = gpm_send_buffer(gpmctx, buffer, xdr_getpos(&xdr_call_ctx)); + if (ret) { + goto done; + } + + /* receive answer */ + ret = gpm_recv_buffer(gpmctx, buffer, &length); + if (ret) { + goto done; + } + + /* decode header */ + xdrok = xdr_gp_rpc_msg(&xdr_reply_ctx, &msg); + if (!xdrok) { + ret = EINVAL; + goto done; + } + + if (msg.xid != xid || + msg.header.type != GP_RPC_REPLY || + msg.header.gp_rpc_msg_union_u.rhdr.status != GP_RPC_MSG_ACCEPTED || + msg.header.gp_rpc_msg_union_u.rhdr.gp_rpc_reply_header_u.accepted.reply_data.status != GP_RPC_SUCCESS) { + ret = EINVAL; + goto done; + } + + /* decode answer */ + xdrok = gpm_xdr_set[proc].res_fn(&xdr_reply_ctx, (char *)res); + if (!xdrok) { + ret = EINVAL; + } + +done: + xdr_free((xdrproc_t)xdr_gp_rpc_msg, (char *)&msg); + xdr_destroy(&xdr_call_ctx); + xdr_destroy(&xdr_reply_ctx); + gpm_release_ctx(gpmctx); + return ret; +} + +void gpm_free_xdrs(int proc, union gp_rpc_arg *arg, union gp_rpc_res *res) +{ + xdr_free(gpm_xdr_set[proc].arg_fn, (char *)arg); + xdr_free(gpm_xdr_set[proc].res_fn, (char *)res); +} diff --git a/proxy/src/client/gpm_display_status.c b/proxy/src/client/gpm_display_status.c new file mode 100644 index 0000000..cc5e3cc --- /dev/null +++ b/proxy/src/client/gpm_display_status.c @@ -0,0 +1,124 @@ +/* + GSS-PROXY + + Copyright (C) 2011 Red Hat, Inc. + Copyright (C) 2011 Simo Sorce + + 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 "gssapi_gpm.h" + +__thread gssx_status *tls_last_status = NULL; + +/* Thread local storage for return status. + * FIXME: it's not the most portable construct, so may need fixing in future */ +void gpm_save_status(gssx_status *status) +{ + int ret; + + if (tls_last_status) { + xdr_free((xdrproc_t)xdr_gssx_status, (char *)tls_last_status); + free(tls_last_status); + } + + ret = gp_copy_gssx_status_alloc(status, &tls_last_status); + if (ret) { + /* make sure tls_last_status is zeored on error */ + tls_last_status = NULL; + } +} + +/* This funciton is used to record internal mech errors that are + * generated by the proxy client code */ +void gpm_save_internal_status(uint32_t err, char *err_str) +{ + gssx_status status; + + memset(&status, 0, sizeof(gssx_status)); + +#define STD_MAJ_ERROR_STR "Internal gssproxy error" + status.major_status = GSS_S_FAILURE; + status.major_status_string.utf8string_val = STD_MAJ_ERROR_STR; + status.major_status_string.utf8string_len = sizeof(STD_MAJ_ERROR_STR); + status.minor_status = err; + status.minor_status_string.utf8string_val = err_str; + status.minor_status_string.utf8string_len = strlen(err_str) + 1; + gpm_save_status(&status); +} + +OM_uint32 gpm_display_status(OM_uint32 *minor_status, + OM_uint32 status_value, + int status_type, + const gss_OID mech_type, + OM_uint32 *message_context, + gss_buffer_t status_string) +{ + utf8string tmp; + int ret; + + switch(status_type) { + case GSS_C_GSS_CODE: + if (tls_last_status && + tls_last_status->major_status == status_value && + tls_last_status->major_status_string.utf8string_len) { + ret = gp_copy_utf8string(&tls_last_status->major_status_string, + &tmp); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + status_string->value = tmp.utf8string_val; + status_string->length = tmp.utf8string_len; + *minor_status = 0; + return GSS_S_COMPLETE; + } else { + /* if we do not have it, make it clear */ + return GSS_S_UNAVAILABLE; + } + case GSS_C_MECH_CODE: + if (tls_last_status && + tls_last_status->minor_status == status_value && + tls_last_status->minor_status_string.utf8string_len) { + + if (*message_context) { + /* we do not support multiple messages for now */ + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + ret = gp_copy_utf8string(&tls_last_status->minor_status_string, + &tmp); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + status_string->value = tmp.utf8string_val; + status_string->length = tmp.utf8string_len; + } else { + /* if we do not have it, make it clear */ + return GSS_S_UNAVAILABLE; + } + *minor_status = 0; + return GSS_S_COMPLETE; + default: + *minor_status = EINVAL; + return GSS_S_BAD_STATUS; + } +} diff --git a/proxy/src/client/gpm_import_and_canon_name.c b/proxy/src/client/gpm_import_and_canon_name.c new file mode 100644 index 0000000..5301d60 --- /dev/null +++ b/proxy/src/client/gpm_import_and_canon_name.c @@ -0,0 +1,342 @@ +/* + GSS-PROXY + + Copyright (C) 2011 Red Hat, Inc. + Copyright (C) 2011 Simo Sorce + + 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 "gssapi_gpm.h" + +OM_uint32 gpm_display_name(OM_uint32 *minor_status, + gss_name_t input_name, + gss_buffer_t output_name_buffer, + gss_OID *output_name_type) +{ + gss_buffer_desc input_name_buffer = GSS_C_EMPTY_BUFFER; + gssx_name *output_name = NULL; + gss_name_t tmp; + gssx_name *name; + uint32_t ret_maj; + uint32_t ret_min; + uint32_t discard; + int ret; + + if (!minor_status) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + *minor_status = 0; + + if (!input_name) { + return GSS_S_CALL_INACCESSIBLE_READ; + } + if (!output_name_buffer) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + name = (gssx_name *)input_name; + + if (name->display_name.octet_string_len == 0) { + if (name->exported_name.octet_string_len == 0) { + return GSS_S_BAD_NAME; + } + + gp_conv_gssx_to_buffer(&name->exported_name, &input_name_buffer); + tmp = (gss_name_t)output_name; + + ret_maj = gpm_import_name(&ret_min, &input_name_buffer, + GSS_C_NT_EXPORT_NAME, &tmp); + if (ret_maj) { + goto done; + } + + /* steal display_name and name_type */ + name->display_name = output_name->display_name; + output_name->display_name.octet_string_len = 0; + output_name->display_name.octet_string_val = NULL; + name->name_type = output_name->name_type; + output_name->name_type.octet_string_len = 0; + output_name->name_type.octet_string_val = NULL; + } + + ret = gp_copy_gssx_to_buffer(&name->display_name, output_name_buffer); + if (ret) { + ret_min = ret; + ret_maj = GSS_S_FAILURE; + goto done; + } + + if (output_name_type) { + ret = gp_conv_gssx_to_oid_alloc(&name->name_type, output_name_type); + if (ret) { + gss_release_buffer(&discard, output_name_buffer); + ret_min = ret; + ret_maj = GSS_S_FAILURE; + goto done; + } + } + + ret_min = 0; + ret_maj = GSS_S_COMPLETE; + +done: + if (output_name) { + xdr_free((xdrproc_t)xdr_gssx_name, (char *)output_name); + free(output_name); + } + *minor_status = ret_min; + return ret_maj; +} + +OM_uint32 gpm_import_name(OM_uint32 *minor_status, + gss_buffer_t input_name_buffer, + gss_OID input_name_type, + gss_name_t *output_name) +{ + gssx_name *name; + int ret; + + if (!minor_status) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + *minor_status = 0; + + if (!input_name_buffer || !input_name_type) { + return GSS_S_CALL_INACCESSIBLE_READ; + } + if (!output_name) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + /* ignore call_ctx for now */ + + name = calloc(1, sizeof(gssx_name)); + if (!name) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + ret = gp_conv_buffer_to_gssx(input_name_buffer, &name->display_name); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + ret = gp_conv_oid_to_gssx(input_name_type, &name->name_type); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + *output_name = (gss_name_t)name; + return GSS_S_COMPLETE; +} + +OM_uint32 gpm_export_name(OM_uint32 *minor_status, + const gss_name_t input_name, + gss_buffer_t exported_name) +{ + gssx_name *name; + int ret; + + if (!minor_status) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + *minor_status = 0; + + if (!input_name) { + return GSS_S_CALL_INACCESSIBLE_READ; + } + + name = (gssx_name *)input_name; + + if (name->exported_name.octet_string_len == 0) { + return GSS_S_NAME_NOT_MN; + } + + ret = gp_copy_gssx_to_buffer(&name->exported_name, exported_name); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + return GSS_S_COMPLETE; +} + +OM_uint32 gpm_duplicate_name(OM_uint32 *minor_status, + const gss_name_t input_name, + gss_name_t *dest_name) +{ + gssx_name *name; + gssx_name *namecopy; + int ret; + + name = (gssx_name *)input_name; + + ret = gp_copy_gssx_name_alloc(name, &namecopy); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + *dest_name = (gss_name_t)namecopy; + return GSS_S_COMPLETE; +} + +OM_uint32 gpm_canonicalize_name(OM_uint32 *minor_status, + const gss_name_t input_name, + const gss_OID mech_type, + gss_name_t *output_name) +{ + union gp_rpc_arg uarg; + union gp_rpc_res ures; + gssx_arg_import_and_canon_name *arg = &uarg.import_and_canon_name; + gssx_res_import_and_canon_name *res = &ures.import_and_canon_name; + uint32_t ret_maj; + uint32_t ret_min; + gssx_name *name; + int ret; + + if (!minor_status) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + *minor_status = 0; + + if (!input_name || !mech_type) { + return GSS_S_CALL_INACCESSIBLE_READ; + } + if (!output_name) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + name = (gssx_name *)input_name; + + memset(arg, 0, sizeof(gssx_arg_import_and_canon_name)); + memset(res, 0, sizeof(gssx_res_import_and_canon_name)); + + /* ignore call_ctx for now */ + + ret = gp_copy_gssx_name(name, &arg->input_name); + if (ret) { + goto done; + } + ret = gp_conv_oid_to_gssx(mech_type, &arg->mech); + if (ret) { + goto done; + } + + /* execute proxy request */ + ret = gpm_make_call(GSSX_IMPORT_AND_CANON_NAME, &uarg, &ures); + if (ret) { + goto done; + } + + ret_min = res->status.minor_status; + ret_maj = res->status.major_status; + if (res->status.major_status) { + gpm_save_status(&res->status); + ret = 0; + goto done; + } + + /* steal output_name */ + *output_name = (gss_name_t)res->output_name; + res->output_name = NULL; + +done: + if (ret) { + ret_min = ret; + ret_maj = GSS_S_FAILURE; + } + gpm_free_xdrs(GSSX_IMPORT_AND_CANON_NAME, &uarg, &ures); + *minor_status = ret_min; + return ret_maj; +} + +OM_uint32 gpm_inquire_name(OM_uint32 *minor_status, + gss_name_t name, + int *name_is_MN, + gss_OID *MN_mech, + gss_buffer_set_t *attrs) +{ + gss_buffer_set_t xattrs = GSS_C_NO_BUFFER_SET; + gssx_name *xname; + uint32_t i; + int ret; + + *minor_status = 0; + xname = (gssx_name *)name; + + if (xname->exported_name.octet_string_len != 0) { + if (name_is_MN != NULL) { + *name_is_MN = 1; + } + } + + if (MN_mech != NULL) { + ret = gp_conv_gssx_to_oid_alloc(&xname->name_type, MN_mech); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + } + + if (xname->name_attributes.name_attributes_len != 0) { + xattrs = calloc(1, sizeof(gss_buffer_set_desc)); + if (!xattrs) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + xattrs->count = xname->name_attributes.name_attributes_len; + xattrs->elements = calloc(xattrs->count, sizeof(gss_buffer_desc)); + if (!xattrs->elements) { + free(xattrs); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + for (i = 0; i < xattrs->count; i++) { + ret = gp_copy_gssx_to_buffer( + &xname->name_attributes.name_attributes_val[i].attr, + &xattrs->elements[i]); + if (ret) { + for (--i; i >= 0; i--) { + free(xattrs->elements[i].value); + } + free(xattrs->elements); + free(xattrs); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + } + } + *attrs = xattrs; + + return GSS_S_COMPLETE; +} + +OM_uint32 gpm_release_name(OM_uint32 *minor_status, + gss_name_t *input_name) +{ + *minor_status = 0; + + if (*input_name != GSS_C_NO_NAME) { + xdr_free((xdrproc_t)xdr_gssx_name, (char *)(*input_name)); + free(*input_name); + *input_name = GSS_C_NO_NAME; + } + return GSS_S_COMPLETE; +} diff --git a/proxy/src/client/gpm_indicate_mechs.c b/proxy/src/client/gpm_indicate_mechs.c new file mode 100644 index 0000000..693e588 --- /dev/null +++ b/proxy/src/client/gpm_indicate_mechs.c @@ -0,0 +1,734 @@ +/* + GSS-PROXY + + Copyright (C) 2011 Red Hat, Inc. + Copyright (C) 2011 Simo Sorce + + 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 "gssapi_gpm.h" +#include + +struct gpm_mech_info { + gss_OID mech; + gss_OID_set name_types; + gss_OID_set mech_attrs; + gss_OID_set known_mech_attrs; + gss_OID_set cred_options; + gss_OID_set sec_ctx_options; + gss_buffer_t saslname_sasl_mech_name; + gss_buffer_t saslname_mech_name; + gss_buffer_t saslname_mech_desc; +}; + +struct gpm_mech_attr { + gss_OID attr; + gss_buffer_t name; + gss_buffer_t short_desc; + gss_buffer_t long_desc; +}; + +struct gpm_mechs { + bool initialized; + + gss_OID_set mech_set; + + size_t info_len; + struct gpm_mech_info *info; + + size_t desc_len; + struct gpm_mech_attr *desc; +}; + +pthread_mutex_t global_mechs_lock = PTHREAD_MUTEX_INITIALIZER; +pthread_once_t indicate_mechs_once = PTHREAD_ONCE_INIT; +struct gpm_mechs global_mechs = { + .initialized = false, + .mech_set = GSS_C_NO_OID_SET, + .info_len = 0, + .info = NULL, + .desc_len = 0, + .desc = NULL, +}; + +static uint32_t gpm_copy_gss_OID_set(uint32_t *minor_status, + gss_OID_set oldset, gss_OID_set *newset) +{ + gss_OID_set n; + uint32_t ret_maj; + uint32_t ret_min; + int i; + + ret_maj = gss_create_empty_oid_set(&ret_min, &n); + if (ret_maj) { + *minor_status = ret_min; + return ret_maj; + } + + for (i = 0; i < oldset->count; i++) { + ret_maj = gss_add_oid_set_member(&ret_min, &oldset->elements[i], &n); + if (ret_maj) { + *minor_status = ret_min; + gss_release_oid_set(&ret_min, &n); + return ret_maj; + } + } + + *newset = n; + *minor_status = 0; + return GSS_S_COMPLETE; +} + +static uint32_t gpm_copy_gss_buffer(uint32_t *minor_status, + gss_buffer_t oldbuf, + gss_buffer_t newbuf) +{ + if (!oldbuf || oldbuf->length == 0) { + newbuf->value = NULL; + newbuf->length = 0; + *minor_status = 0; + return GSS_S_COMPLETE; + } + + newbuf->value = malloc(oldbuf->length); + if (!newbuf->value) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(newbuf->value, oldbuf->value, oldbuf->length); + newbuf->length = oldbuf->length; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +static bool gpm_equal_oids(gss_const_OID a, gss_const_OID b) +{ + int ret; + + if (a->length == b->length) { + ret = memcmp(a->elements, b->elements, a->length); + if (ret == 0) { + return true; + } + } + + return false; +} + +static void gpmint_indicate_mechs(void) +{ + union gp_rpc_arg uarg; + union gp_rpc_res ures; + gssx_arg_indicate_mechs *arg = &uarg.indicate_mechs; + gssx_res_indicate_mechs *res = &ures.indicate_mechs; + struct gpm_mech_info *gi; + struct gpm_mech_attr *ga; + gssx_mech_info *mi; + gssx_mech_attr *ma; + uint32_t discard; + uint32_t ret_min; + uint32_t ret_maj = 0; + int ret = 0; + int i; + + memset(arg, 0, sizeof(gssx_arg_indicate_mechs)); + memset(res, 0, sizeof(gssx_res_indicate_mechs)); + + /* ignore call_ctx for now */ + + /* execute proxy request */ + ret = gpm_make_call(GSSX_INDICATE_MECHS, &uarg, &ures); + if (ret) { + goto done; + } + + if (res->status.major_status) { + gpm_save_status(&res->status); + ret_min = res->status.minor_status; + ret_maj = res->status.major_status; + ret = 0; + goto done; + } + + ret_maj = gss_create_empty_oid_set(&ret_min, &global_mechs.mech_set); + if (ret_maj) { + goto done; + } + + global_mechs.info = calloc(res->mechs.mechs_len, + sizeof(struct gpm_mech_info)); + if (!global_mechs.info) { + ret_maj = GSS_S_FAILURE; + ret_min = ENOMEM; + goto done; + } + + for (i = 0; i < res->mechs.mechs_len; i++) { + mi = &res->mechs.mechs_val[i]; + gi = &global_mechs.info[i]; + + ret = gp_conv_gssx_to_oid_alloc(&mi->mech, + &gi->mech); + if (ret) { + goto done; + } + ret_maj = gss_add_oid_set_member(&ret_min, gi->mech, + &global_mechs.mech_set); + if (ret_maj) { + goto done; + } + + ret = gp_conv_gssx_to_oid_set(&mi->name_types, + &gi->name_types); + if (ret) { + goto done; + } + ret = gp_conv_gssx_to_oid_set(&mi->mech_attrs, + &gi->mech_attrs); + if (ret) { + goto done; + } + ret = gp_conv_gssx_to_oid_set(&mi->known_mech_attrs, + &gi->known_mech_attrs); + if (ret) { + goto done; + } + ret = gp_conv_gssx_to_oid_set(&mi->cred_options, + &gi->cred_options); + if (ret) { + goto done; + } + ret = gp_conv_gssx_to_oid_set(&mi->sec_ctx_options, + &gi->sec_ctx_options); + if (ret) { + goto done; + } + ret = gp_conv_gssx_to_buffer_alloc(&mi->saslname_sasl_mech_name, + &gi->saslname_sasl_mech_name); + if (ret) { + goto done; + } + ret = gp_conv_gssx_to_buffer_alloc(&mi->saslname_mech_name, + &gi->saslname_mech_name); + if (ret) { + goto done; + } + ret = gp_conv_gssx_to_buffer_alloc(&mi->saslname_mech_desc, + &gi->saslname_mech_desc); + if (ret) { + goto done; + } + } + global_mechs.info_len = res->mechs.mechs_len; + + global_mechs.desc = calloc(res->mech_attr_descs.mech_attr_descs_len, + sizeof(struct gpm_mech_attr)); + if (!global_mechs.desc) { + goto done; + } + + for (i = 0; i < res->mech_attr_descs.mech_attr_descs_len; i++) { + ma = &res->mech_attr_descs.mech_attr_descs_val[i]; + ga = &global_mechs.desc[i]; + + ret = gp_conv_gssx_to_oid_alloc(&ma->attr, &ga->attr); + if (ret) { + goto done; + } + ret = gp_conv_gssx_to_buffer_alloc(&ma->name, &ga->name); + if (ret) { + goto done; + } + ret = gp_conv_gssx_to_buffer_alloc(&ma->short_desc, &ga->short_desc); + if (ret) { + goto done; + } + ret = gp_conv_gssx_to_buffer_alloc(&ma->long_desc, &ga->long_desc); + if (ret) { + goto done; + } + } + global_mechs.desc_len = res->mech_attr_descs.mech_attr_descs_len; + + global_mechs.initialized = true; + +done: + if (ret || ret_maj) { + for (i = 0; i < global_mechs.desc_len; i++) { + ga = &global_mechs.desc[i]; + gss_release_oid(&discard, &ga->attr); + gss_release_buffer(&discard, ga->name); + gss_release_buffer(&discard, ga->short_desc); + gss_release_buffer(&discard, ga->long_desc); + } + free(global_mechs.desc); + global_mechs.desc = NULL; + for (i = 0; i < global_mechs.info_len; i++) { + gi = &global_mechs.info[i]; + gss_release_oid(&discard, &gi->mech); + gss_release_oid_set(&discard, &gi->name_types); + gss_release_oid_set(&discard, &gi->mech_attrs); + gss_release_oid_set(&discard, &gi->known_mech_attrs); + gss_release_oid_set(&discard, &gi->cred_options); + gss_release_oid_set(&discard, &gi->sec_ctx_options); + gss_release_buffer(&discard, gi->saslname_sasl_mech_name); + gss_release_buffer(&discard, gi->saslname_mech_name); + gss_release_buffer(&discard, gi->saslname_mech_desc); + } + free(global_mechs.info); + global_mechs.info = NULL; + gss_release_oid_set(&discard, &global_mechs.mech_set); + } + gpm_free_xdrs(GSSX_INDICATE_MECHS, &uarg, &ures); +} + +static int gpmint_init_global_mechs(void) +{ + pthread_once(&indicate_mechs_once, gpmint_indicate_mechs); + + if (!global_mechs.initialized) { + /* this is quite a corner case. It means the pthread_once() call + * failed for some reason. In this case we need to use a mutex */ + + pthread_mutex_lock(&global_mechs_lock); + /* need to recheck once we acquired the lock, to avoid redoing + * if we were stuck after another thread that already did it */ + if (!global_mechs.initialized) { + gpmint_indicate_mechs(); + } + pthread_mutex_unlock(&global_mechs_lock); + + if (!global_mechs.initialized) { + /* if still it is not initialized, give up */ + return EIO; + } + } + + return 0; +} + +OM_uint32 gpm_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set) +{ + uint32_t ret_min; + uint32_t ret_maj; + int ret; + + if (!minor_status) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + if (!mech_set) { + *minor_status = 0; + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + ret= gpmint_init_global_mechs(); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret_maj = gpm_copy_gss_OID_set(&ret_min, + global_mechs.mech_set, + mech_set); + *minor_status = ret_min; + return ret_maj; +} + +OM_uint32 gpm_inquire_names_for_mech(OM_uint32 *minor_status, + gss_OID mech_type, + gss_OID_set *mech_names) +{ + uint32_t ret_min; + uint32_t ret_maj; + int i; + + if (!minor_status) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + if (!mech_names) { + *minor_status = 0; + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + ret_min = gpmint_init_global_mechs(); + if (ret_min) { + *minor_status = ret_min; + return GSS_S_FAILURE; + } + + for (i = 0; i < global_mechs.info_len; i++) { + if (!gpm_equal_oids(global_mechs.info[i].mech, mech_type)) { + continue; + } + ret_maj = gpm_copy_gss_OID_set(&ret_min, + global_mechs.info[i].name_types, + mech_names); + *minor_status = ret_min; + return ret_maj; + } + + *minor_status = 0; + return GSS_S_BAD_MECH; +} + +OM_uint32 gpm_inquire_mechs_for_name(OM_uint32 *minor_status, + const gss_name_t input_name, + gss_OID_set *mech_types) +{ + uint32_t ret_min; + uint32_t ret_maj; + uint32_t discard; + gssx_name *name; + gss_OID name_type = GSS_C_NO_OID; + int present; + int i; + + if (!minor_status) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + if (!input_name || !mech_types) { + *minor_status = 0; + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + ret_min = gpmint_init_global_mechs(); + if (ret_min) { + *minor_status = ret_min; + return GSS_S_FAILURE; + } + + name = (gssx_name *)input_name; + ret_min = gp_conv_gssx_to_oid_alloc(&name->name_type, &name_type); + if (ret_min) { + ret_maj = GSS_S_FAILURE; + goto done; + } + + ret_maj = gss_create_empty_oid_set(&ret_min, mech_types); + if (ret_maj) { + goto done; + } + + for (i = 0; i < global_mechs.info_len; i++) { + ret_maj = gss_test_oid_set_member(&ret_min, name_type, + global_mechs.info[i].name_types, + &present); + if (ret_maj) { + /* skip on error */ + continue; + } + if (present) { + ret_maj = gss_add_oid_set_member(&ret_min, + global_mechs.info[i].mech, + mech_types); + } + if (ret_maj) { + goto done; + } + } + +done: + gss_release_oid(&discard, &name_type); + if (ret_maj) { + gss_release_oid_set(&discard, mech_types); + *minor_status = ret_min; + return ret_maj; + } + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 gpm_inquire_attrs_for_mech(OM_uint32 *minor_status, + gss_OID mech, + gss_OID_set *mech_attrs, + gss_OID_set *known_mech_attrs) +{ + uint32_t ret_min; + uint32_t ret_maj; + uint32_t discard; + int i; + + if (!minor_status) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + if (!mech_attrs || !known_mech_attrs) { + *minor_status = 0; + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + ret_min = gpmint_init_global_mechs(); + if (ret_min) { + *minor_status = ret_min; + return GSS_S_FAILURE; + } + + for (i = 0; i < global_mechs.info_len; i++) { + if (!gpm_equal_oids(global_mechs.info[i].mech, mech)) { + continue; + } + ret_maj = gpm_copy_gss_OID_set(&ret_min, + global_mechs.info[i].mech_attrs, + mech_attrs); + if (ret_maj) { + *minor_status = ret_min; + return ret_maj; + } + ret_maj = gpm_copy_gss_OID_set(&ret_min, + global_mechs.info[i].known_mech_attrs, + known_mech_attrs); + if (ret_maj) { + gss_release_oid_set(&discard, known_mech_attrs); + } + *minor_status = ret_min; + return ret_maj; + } + + *minor_status = 0; + return GSS_S_BAD_MECH; +} + +OM_uint32 gpm_inquire_saslname_for_mech(OM_uint32 *minor_status, + const gss_OID desired_mech, + gss_buffer_t sasl_mech_name, + gss_buffer_t mech_name, + gss_buffer_t mech_description) +{ + uint32_t ret_min; + uint32_t ret_maj; + uint32_t discard; + int i; + + if (!minor_status) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + if (!sasl_mech_name || !mech_name || !mech_description) { + *minor_status = 0; + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + ret_min = gpmint_init_global_mechs(); + if (ret_min) { + *minor_status = ret_min; + return GSS_S_FAILURE; + } + + for (i = 0; i < global_mechs.info_len; i++) { + if (!gpm_equal_oids(global_mechs.info[i].mech, desired_mech)) { + continue; + } + ret_maj = gpm_copy_gss_buffer(&ret_min, + global_mechs.info[i].saslname_sasl_mech_name, + sasl_mech_name); + if (ret_maj) { + *minor_status = ret_min; + return ret_maj; + } + ret_maj = gpm_copy_gss_buffer(&ret_min, + global_mechs.info[i].saslname_mech_name, + mech_name); + if (ret_maj) { + gss_release_buffer(&discard, sasl_mech_name); + *minor_status = ret_min; + return ret_maj; + } + ret_maj = gpm_copy_gss_buffer(&ret_min, + global_mechs.info[i].saslname_mech_desc, + mech_description); + if (ret_maj) { + gss_release_buffer(&discard, sasl_mech_name); + gss_release_buffer(&discard, mech_name); + } + *minor_status = ret_min; + return ret_maj; + } + + *minor_status = 0; + return GSS_S_BAD_MECH; +} + +OM_uint32 gpm_display_mech_attr(OM_uint32 *minor_status, + gss_const_OID mech_attr, + gss_buffer_t name, + gss_buffer_t short_desc, + gss_buffer_t long_desc) +{ + uint32_t ret_min; + uint32_t ret_maj; + uint32_t discard; + int i; + + if (!minor_status) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + if (!name || !short_desc || !long_desc) { + *minor_status = 0; + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + ret_min = gpmint_init_global_mechs(); + if (ret_min) { + *minor_status = ret_min; + return GSS_S_FAILURE; + } + + for (i = 0; i < global_mechs.desc_len; i++) { + if (!gpm_equal_oids(global_mechs.desc[i].attr, mech_attr)) { + continue; + } + ret_maj = gpm_copy_gss_buffer(&ret_min, + global_mechs.desc[i].name, + name); + if (ret_maj) { + *minor_status = ret_min; + return ret_maj; + } + ret_maj = gpm_copy_gss_buffer(&ret_min, + global_mechs.desc[i].short_desc, + short_desc); + if (ret_maj) { + gss_release_buffer(&discard, name); + *minor_status = ret_min; + return ret_maj; + } + ret_maj = gpm_copy_gss_buffer(&ret_min, + global_mechs.desc[i].long_desc, + long_desc); + if (ret_maj) { + gss_release_buffer(&discard, name); + gss_release_buffer(&discard, short_desc); + } + *minor_status = ret_min; + return ret_maj; + } + + *minor_status = 0; + return GSS_S_BAD_MECH; +} + +OM_uint32 gpm_indicate_mechs_by_attrs(OM_uint32 *minor_status, + gss_const_OID_set desired_mech_attrs, + gss_const_OID_set except_mech_attrs, + gss_const_OID_set critical_mech_attrs, + gss_OID_set *mechs) +{ + uint32_t ret_min; + uint32_t ret_maj; + uint32_t discard; + int present; + int i, j; + + if (!minor_status) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + if (!mechs) { + *minor_status = 0; + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + ret_min = gpmint_init_global_mechs(); + if (ret_min) { + *minor_status = ret_min; + return GSS_S_FAILURE; + } + + ret_maj = gss_create_empty_oid_set(&ret_min, mechs); + if (ret_maj) { + *minor_status = ret_min; + return ret_maj; + } + + for (i = 0; i < global_mechs.info_len; i++) { + if (desired_mech_attrs != GSS_C_NO_OID_SET) { + for (j = 0; j < desired_mech_attrs->count; j++) { + ret_maj = gss_test_oid_set_member(&ret_min, + &desired_mech_attrs->elements[j], + global_mechs.info[i].mech_attrs, + &present); + if (ret_maj) { + /* skip in case of errors */ + break; + } + if (!present) { + break; + } + } + /* if not desired skip */ + if (j != desired_mech_attrs->count) { + continue; + } + } + if (except_mech_attrs != GSS_C_NO_OID_SET) { + for (j = 0; j < except_mech_attrs->count; j++) { + ret_maj = gss_test_oid_set_member(&ret_min, + &except_mech_attrs->elements[j], + global_mechs.info[i].mech_attrs, + &present); + if (ret_maj) { + /* continue in case of errors */ + continue; + } + if (present) { + break; + } + } + /* if excepted skip */ + if (j == desired_mech_attrs->count) { + continue; + } + } + if (critical_mech_attrs != GSS_C_NO_OID_SET) { + for (j = 0; j < critical_mech_attrs->count; j++) { + ret_maj = gss_test_oid_set_member(&ret_min, + &critical_mech_attrs->elements[j], + global_mechs.info[i].known_mech_attrs, + &present); + if (ret_maj) { + /* skip in case of errors */ + break; + } + if (!present) { + break; + } + } + /* if not known skip */ + if (j != desired_mech_attrs->count) { + continue; + } + } + + /* passes all tests, add to list */ + ret_maj = gss_add_oid_set_member(&ret_min, + global_mechs.info[i].mech, mechs); + if (ret_maj) { + goto done; + } + } + +done: + if (ret_maj) { + gss_release_oid_set(&discard, mechs); + *minor_status = ret_min; + return ret_maj; + } + *minor_status = 0; + return GSS_S_COMPLETE; +} + diff --git a/proxy/src/client/gpm_init_sec_context.c b/proxy/src/client/gpm_init_sec_context.c new file mode 100644 index 0000000..0769363 --- /dev/null +++ b/proxy/src/client/gpm_init_sec_context.c @@ -0,0 +1,176 @@ +/* + GSS-PROXY + + Copyright (C) 2011 Red Hat, Inc. + Copyright (C) 2011 Simo Sorce + + 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 "gssapi_gpm.h" +#include "src/gp_conv.h" + +OM_uint32 gpm_init_sec_context(OM_uint32 *minor_status, + gss_cred_id_t claimant_cred_handle, + gss_ctx_id_t *context_handle, + gss_name_t target_name, + gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + gss_channel_bindings_t input_cb, + gss_buffer_t input_token, + gss_OID *actual_mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec) +{ + union gp_rpc_arg uarg; + union gp_rpc_res ures; + gssx_arg_init_sec_context *arg = &uarg.init_sec_context; + gssx_res_init_sec_context *res = &ures.init_sec_context; + gssx_ctx *ctx = NULL; + gss_OID_desc *mech = NULL; + gss_buffer_t outbuf = NULL; + uint32_t ret_maj = GSS_S_COMPLETE; + uint32_t ret_min = 0; + int ret; + + memset(&uarg, 0, sizeof(union gp_rpc_arg)); + memset(&ures, 0, sizeof(union gp_rpc_res)); + + /* prepare proxy request */ + if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) { + arg->cred_handle = (gssx_cred *)claimant_cred_handle; + } + + if (*context_handle) { + arg->context_handle = (gssx_ctx *)*context_handle; + } + + if (target_name != GSS_C_NO_NAME) { + arg->target_name = (gssx_name *)target_name; + } + + ret = gp_conv_oid_to_gssx(mech_type, &arg->mech_type); + if (ret) { + goto done; + } + + if (input_cb) { + ret = gp_conv_cb_to_gssx_alloc(input_cb, &arg->input_cb); + if (ret) { + goto done; + } + } + + if (input_token != GSS_C_NO_BUFFER) { + ret = gp_conv_buffer_to_gssx_alloc(input_token, &arg->input_token); + if (ret) { + goto done; + } + } + + /* execute proxy request */ + ret = gpm_make_call(GSSX_INIT_SEC_CONTEXT, &uarg, &ures); + if (ret) { + gpm_save_internal_status(ret, strerror(ret)); + goto done; + } + + /* return values */ + if (actual_mech_type) { + if (res->status.mech.octet_string_len) { + ret = gp_conv_gssx_to_oid_alloc(&res->status.mech, &mech); + if (ret) { + goto done; + } + } + } + + if (res->status.major_status) { + gpm_save_status(&res->status); + ret_maj = res->status.major_status; + ret_min = res->status.minor_status; + goto done; + } + + if (res->context_handle) { + ctx = res->context_handle; + /* we are stealing the delegated creds on success, so we do not want + * it to be freed by xdr_free */ + res->context_handle = NULL; + } + + ret = gp_conv_gssx_to_buffer_alloc(res->output_token, &outbuf); + if (ret) { + gpm_save_internal_status(ret, strerror(ret)); + goto done; + } + +done: + if (ret != 0) { + ret_min = ret; + ret_maj = GSS_S_FAILURE; + } + + /* we are putting our copy of these structures in here, + * and do not want it to be freed by xdr_free */ + arg->context_handle = NULL; + arg->cred_handle = NULL; + arg->target_name = NULL; + gpm_free_xdrs(GSSX_INIT_SEC_CONTEXT, &uarg, &ures); + + if (ret_maj == GSS_S_COMPLETE || ret_maj == GSS_S_CONTINUE_NEEDED) { + /* replace old ctx handle if any */ + if (*context_handle) { + xdr_free((xdrproc_t)xdr_gssx_ctx, (char *)*context_handle); + free(*context_handle); + } + *context_handle = (gss_ctx_id_t)ctx; + if (actual_mech_type) { + *actual_mech_type = mech; + } + if (outbuf) { + *output_token = *outbuf; + free(outbuf); + } + if (ret_flags) { + *ret_flags = ctx->ctx_flags; + } + if (time_rec) { + *time_rec = ctx->lifetime; + } + } else { + if (ctx) { + xdr_free((xdrproc_t)xdr_gssx_ctx, (char *)ctx); + free(ctx); + } + if (mech) { + free(mech->elements); + free(mech); + } + if (outbuf) { + free(outbuf->value); + free(outbuf); + } + } + + *minor_status = ret_min; + return ret_maj; +} diff --git a/proxy/src/client/gpm_release_handle.c b/proxy/src/client/gpm_release_handle.c new file mode 100644 index 0000000..010c148 --- /dev/null +++ b/proxy/src/client/gpm_release_handle.c @@ -0,0 +1,131 @@ +/* + GSS-PROXY + + Copyright (C) 2011 Red Hat, Inc. + Copyright (C) 2011 Simo Sorce + + 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 "gssapi_gpm.h" + +OM_uint32 gpm_release_cred(OM_uint32 *minor_status, + gss_cred_id_t *cred_handle) +{ + union gp_rpc_arg uarg; + union gp_rpc_res ures; + gssx_arg_release_handle *arg = &uarg.release_handle; + gssx_res_release_handle *res = &ures.release_handle; + gssx_cred *r; + int ret; + + if (cred_handle == NULL || *cred_handle == GSS_C_NO_CREDENTIAL) { + return 0; + } + + r = (gssx_cred *)(*cred_handle); + + if (!r->needs_release) { + ret = GSS_S_COMPLETE; + goto done; + } + + memset(&uarg, 0, sizeof(union gp_rpc_arg)); + memset(&ures, 0, sizeof(union gp_rpc_res)); + + /* ignore call_ctx for now */ + + arg->cred_handle.handle_type = GSSX_C_HANDLE_CRED; + arg->cred_handle.gssx_handle_u.cred_info = *r; + + /* execute proxy request */ + ret = gpm_make_call(GSSX_RELEASE_HANDLE, &uarg, &ures); + if (ret) { + *minor_status = ret; + ret = GSS_S_FAILURE; + goto rel_done; + } + + if (res->status.major_status) { + gpm_save_status(&res->status); + *minor_status = res->status.minor_status; + ret = res->status.major_status; + } + +rel_done: + /* we passed in our copy by value, so clean out to avoid double frees */ + memset(&arg->cred_handle.gssx_handle_u.cred_info, 0, sizeof(gssx_cred)); + gpm_free_xdrs(GSSX_RELEASE_HANDLE, &uarg, &ures); +done: + xdr_free((xdrproc_t)xdr_gssx_cred, (char *)r); + return ret; +} + +OM_uint32 gpm_delete_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t output_token) +{ + union gp_rpc_arg uarg; + union gp_rpc_res ures; + gssx_arg_release_handle *arg = &uarg.release_handle; + gssx_res_release_handle *res = &ures.release_handle; + gssx_ctx *r; + int ret; + + if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT) { + return 0; + } + + r = (gssx_ctx *)(*context_handle); + + if (!r->needs_release) { + ret = GSS_S_COMPLETE; + goto done; + } + + memset(&uarg, 0, sizeof(union gp_rpc_arg)); + memset(&ures, 0, sizeof(union gp_rpc_res)); + + /* ignore call_ctx for now */ + + arg->cred_handle.handle_type = GSSX_C_HANDLE_SEC_CTX; + arg->cred_handle.gssx_handle_u.sec_ctx_info = *r; + + /* execute proxy request */ + ret = gpm_make_call(GSSX_RELEASE_HANDLE, &uarg, &ures); + if (ret) { + *minor_status = ret; + ret = GSS_S_FAILURE; + goto rel_done; + } + + if (res->status.major_status) { + gpm_save_status(&res->status); + *minor_status = res->status.minor_status; + ret = res->status.major_status; + } + +rel_done: + /* we passed in our copy by value, so clean out to avoid double frees */ + memset(&arg->cred_handle.gssx_handle_u.sec_ctx_info, 0, sizeof(gssx_cred)); + gpm_free_xdrs(GSSX_RELEASE_HANDLE, &uarg, &ures); +done: + xdr_free((xdrproc_t)xdr_gssx_ctx, (char *)r); + return ret; +} diff --git a/proxy/src/client/gssapi_gpm.h b/proxy/src/client/gssapi_gpm.h new file mode 100644 index 0000000..f4faf3f --- /dev/null +++ b/proxy/src/client/gssapi_gpm.h @@ -0,0 +1,162 @@ +/* + GSS-PROXY + + Copyright (C) 2011 Red Hat, Inc. + Copyright (C) 2011 Simo Sorce + + 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. +*/ + +#ifndef _GSSAPI_GPM_H_ +#define _GSSAPI_GPM_H_ + +#include "config.h" +#include +#include +#include +#include +#include +#include "rpcgen/gp_rpc.h" +#include "rpcgen/gss_proxy.h" +#include "src/gp_common.h" +#include "src/gp_conv.h" + +int gpm_make_call(int proc, union gp_rpc_arg *arg, union gp_rpc_res *res); +void gpm_free_xdrs(int proc, union gp_rpc_arg *arg, union gp_rpc_res *res); + +OM_uint32 gpm_release_name(OM_uint32 *minor_status, + gss_name_t *input_name); +OM_uint32 gpm_release_buffer(OM_uint32 *minor_status, + gss_buffer_t buffer); + +void gpm_save_status(gssx_status *status); +void gpm_save_internal_status(uint32_t err, char *err_str); + +OM_uint32 gpm_display_status(OM_uint32 *minor_status, + OM_uint32 status_value, + int status_type, + const gss_OID mech_type, + OM_uint32 *message_context, + gss_buffer_t status_string); + +OM_uint32 gpm_accept_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_cred_id_t acceptor_cred_handle, + gss_buffer_t input_token_buffer, + gss_channel_bindings_t input_chan_bindings, + gss_name_t *src_name, + gss_OID *mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec, + gss_cred_id_t *delegated_cred_handle); + +OM_uint32 gpm_release_cred(OM_uint32 *minor_status, + gss_cred_id_t *cred_handle); + +OM_uint32 gpm_delete_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t output_token); + +OM_uint32 gpm_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 gpm_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 gpm_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set); +OM_uint32 gpm_inquire_names_for_mech(OM_uint32 *minor_status, + gss_OID mech_type, + gss_OID_set *mech_names); +OM_uint32 gpm_inquire_mechs_for_name(OM_uint32 *minor_status, + const gss_name_t input_name, + gss_OID_set *mech_types); +OM_uint32 gpm_inquire_attrs_for_mech(OM_uint32 *minor_status, + gss_OID mech, + gss_OID_set *mech_attrs, + gss_OID_set *known_mech_attrs); +OM_uint32 gpm_inquire_saslname_for_mech(OM_uint32 *minor_status, + const gss_OID desired_mech, + gss_buffer_t sasl_mech_name, + gss_buffer_t mech_name, + gss_buffer_t mech_description); +OM_uint32 gpm_display_mech_attr(OM_uint32 *minor_status, + gss_const_OID mech_attr, + gss_buffer_t name, + gss_buffer_t short_desc, + gss_buffer_t long_desc); +OM_uint32 gpm_indicate_mechs_by_attrs(OM_uint32 *minor_status, + gss_const_OID_set desired_mech_attrs, + gss_const_OID_set except_mech_attrs, + gss_const_OID_set critical_mech_attrs, + gss_OID_set *mechs); + +OM_uint32 gpm_display_name(OM_uint32 *minor_status, + gss_name_t input_name, + gss_buffer_t output_name_buffer, + gss_OID *output_name_type); +OM_uint32 gpm_import_name(OM_uint32 *minor_status, + gss_buffer_t input_name_buffer, + gss_OID input_name_type, + gss_name_t *output_name); +OM_uint32 gpm_export_name(OM_uint32 *minor_status, + const gss_name_t input_name, + gss_buffer_t exported_name); +OM_uint32 gpm_duplicate_name(OM_uint32 *minor_status, + const gss_name_t input_name, + gss_name_t *dest_name); +OM_uint32 gpm_canonicalize_name(OM_uint32 *minor_status, + const gss_name_t input_name, + const gss_OID mech_type, + gss_name_t *output_name); +OM_uint32 gpm_inquire_name(OM_uint32 *minor_status, + gss_name_t name, + int *name_is_NM, + gss_OID *NM_mech, + gss_buffer_set_t *attrs); + +OM_uint32 gpm_init_sec_context(OM_uint32 *minor_status, + gss_cred_id_t claimant_cred_handle, + gss_ctx_id_t *context_handle, + gss_name_t target_name, + gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + gss_channel_bindings_t input_cb, + gss_buffer_t input_token, + gss_OID *actual_mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec); +#endif /* _GSSAPI_GPM_H_ */ -- cgit