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)
downloadgss-proxy-1919bf9c7a8c0995e4a4bc0483732084b3b5f241.tar.gz
gss-proxy-1919bf9c7a8c0995e4a4bc0483732084b3b5f241.tar.xz
gss-proxy-1919bf9c7a8c0995e4a4bc0483732084b3b5f241.zip
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_ */