summaryrefslogtreecommitdiffstats
path: root/proxy/src/client
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2012-07-31 18:15:12 -0400
committerSimo Sorce <simo@redhat.com>2012-08-31 16:26:38 -0400
commit1919bf9c7a8c0995e4a4bc0483732084b3b5f241 (patch)
tree9e0f0ce6b073ef01874d4af682d8d191c382c2d0 /proxy/src/client
parent798883aad353add2f9830e6e2c993ac804411639 (diff)
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.
Diffstat (limited to 'proxy/src/client')
-rw-r--r--proxy/src/client/gpm_accept_sec_context.c183
-rw-r--r--proxy/src/client/gpm_acquire_cred.c289
-rw-r--r--proxy/src/client/gpm_common.c520
-rw-r--r--proxy/src/client/gpm_display_status.c124
-rw-r--r--proxy/src/client/gpm_import_and_canon_name.c342
-rw-r--r--proxy/src/client/gpm_indicate_mechs.c734
-rw-r--r--proxy/src/client/gpm_init_sec_context.c176
-rw-r--r--proxy/src/client/gpm_release_handle.c131
-rw-r--r--proxy/src/client/gssapi_gpm.h162
9 files changed, 2661 insertions, 0 deletions
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 <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 "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 <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 "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 <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 "gssapi_gpm.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <pthread.h>
+
+#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 <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 "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 <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 "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 <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 "gssapi_gpm.h"
+#include <pthread.h>
+
+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 <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 "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 <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 "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 <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.
+*/
+
+#ifndef _GSSAPI_GPM_H_
+#define _GSSAPI_GPM_H_
+
+#include "config.h"
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_ext.h>
+#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_ */