aboutsummaryrefslogtreecommitdiff
path: root/tests/libtest
diff options
context:
space:
mode:
authorIsaac Boukris <iboukris@gmail.com>2017-07-18 21:46:21 +0300
committerMarcel Raad <Marcel.Raad@teamviewer.com>2017-09-15 14:09:08 +0200
commit56d949d31ad182a22bd3bad25b1a902b635d549d (patch)
treee95d973da761d9a87eeff98db678f84d7aed97aa /tests/libtest
parent65872efea74f16552e2e0e516164b01913fd706f (diff)
tests: add initial gssapi test using stub implementation
The stub implementation is pre-loaded using LD_PRELOAD and emulates common gssapi uses (only builds if curl is initially built with gssapi support). The initial tests are currently disabled for debug builds as LD_PRELOAD is not used then. Ref: https://github.com/curl/curl/pull/1687
Diffstat (limited to 'tests/libtest')
-rw-r--r--tests/libtest/Makefile.am15
-rw-r--r--tests/libtest/stub_gssapi.c397
-rw-r--r--tests/libtest/stub_gssapi.h183
3 files changed, 595 insertions, 0 deletions
diff --git a/tests/libtest/Makefile.am b/tests/libtest/Makefile.am
index 9128a453d..a4e85ef0c 100644
--- a/tests/libtest/Makefile.am
+++ b/tests/libtest/Makefile.am
@@ -109,6 +109,21 @@ libhostname_la_SOURCES = sethostname.c sethostname.h
libhostname_la_LIBADD =
libhostname_la_DEPENDENCIES =
+# Build a stub gssapi implementation for testing
+if BUILD_STUB_GSS
+noinst_LTLIBRARIES += libstubgss.la
+
+libstubgss_la_CPPFLAGS = $(AM_CPPFLAGS)
+libstubgss_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version -rpath /nowhere
+libstubgss_la_CFLAGS = $(AM_CFLAGS) -g -Wno-unused-parameter
+
+libstubgss_la_SOURCES = stub_gssapi.c stub_gssapi.h
+
+libstubgss_la_LIBADD =
+libstubgss_la_DEPENDENCIES =
+endif
+
+
lib1521.c: $(top_srcdir)/tests/libtest/mk-lib1521.pl $(top_srcdir)/include/curl/curl.h
@PERL@ $(top_srcdir)/tests/libtest/mk-lib1521.pl < $(top_srcdir)/include/curl/curl.h > lib1521.c
diff --git a/tests/libtest/stub_gssapi.c b/tests/libtest/stub_gssapi.c
new file mode 100644
index 000000000..168becf88
--- /dev/null
+++ b/tests/libtest/stub_gssapi.c
@@ -0,0 +1,397 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* Only provides the bare minimum to link with libcurl */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stub_gssapi.h"
+
+#define MAX_CREDS_LENGTH 250
+#define APPROX_TOKEN_LEN 250
+
+enum min_err_code {
+ GSS_OK = 0,
+ GSS_NO_MEMORY,
+ GSS_INVALID_ARGS,
+ GSS_INVALID_CREDS,
+ GSS_INVALID_CTX,
+ GSS_SERVER_ERR,
+ GSS_NO_MECH,
+ GSS_LAST
+};
+
+const char *min_err_table[] = {
+ "stub-gss: no error",
+ "stub-gss: no memory",
+ "stub-gss: invalid arguments",
+ "stub-gss: invalid credentials",
+ "stub-gss: invalid context",
+ "stub-gss: server returned error",
+ "stub-gss: cannot find a mechanism",
+ NULL
+};
+
+struct gss_ctx_id_t_desc_struct {
+ enum { NONE, KRB5, NTLM1, NTLM3 } sent;
+ int have_krb5;
+ int have_ntlm;
+ OM_uint32 flags;
+ char creds[MAX_CREDS_LENGTH];
+};
+
+OM_uint32 gss_init_sec_context(OM_uint32 *min,
+ gss_const_cred_id_t initiator_cred_handle,
+ gss_ctx_id_t *context_handle,
+ gss_const_name_t target_name,
+ const gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ const gss_channel_bindings_t input_chan_bindings,
+ const gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec)
+{
+ /* The token will be encoded in base64 */
+ int length = APPROX_TOKEN_LEN * 3 / 4;
+ int used = 0;
+ char *token = NULL;
+ const char *creds = NULL;
+ gss_ctx_id_t ctx = NULL;
+
+ if(!min)
+ return GSS_S_FAILURE;
+
+ *min = 0;
+
+ if(!context_handle || !target_name || !output_token) {
+ *min = GSS_INVALID_ARGS;
+ return GSS_S_FAILURE;
+ }
+
+ creds = getenv("CURL_STUB_GSS_CREDS");
+ if(!creds || strlen(creds) >= MAX_CREDS_LENGTH) {
+ *min = GSS_INVALID_CREDS;
+ return GSS_S_FAILURE;
+ }
+
+ ctx = *context_handle;
+ if(ctx && strcmp(ctx->creds, creds)) {
+ *min = GSS_INVALID_CREDS;
+ return GSS_S_FAILURE;
+ }
+
+ output_token->length = 0;
+ output_token->value = NULL;
+
+ if(input_token && input_token->length) {
+ if(!ctx) {
+ *min = GSS_INVALID_CTX;
+ return GSS_S_FAILURE;
+ }
+
+ /* Server response, either D (RA==) or C (Qw==) */
+ if(((char *) input_token->value)[0] == 'D') {
+ /* Done */
+ switch(ctx->sent) {
+ case KRB5:
+ case NTLM3:
+ if(ret_flags)
+ *ret_flags = ctx->flags;
+ if(time_rec)
+ *time_rec = GSS_C_INDEFINITE;
+ return GSS_S_COMPLETE;
+ default:
+ *min = GSS_SERVER_ERR;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ if(((char *) input_token->value)[0] != 'C') {
+ /* We only support Done or Continue */
+ *min = GSS_SERVER_ERR;
+ return GSS_S_FAILURE;
+ }
+
+ /* Continue */
+ switch(ctx->sent) {
+ case KRB5:
+ /* We sent KRB5 and it failed, let's try NTLM */
+ if(ctx->have_ntlm) {
+ ctx->sent = NTLM1;
+ break;
+ }
+ else {
+ *min = GSS_SERVER_ERR;
+ return GSS_S_FAILURE;
+ }
+ case NTLM1:
+ ctx->sent = NTLM3;
+ break;
+ default:
+ *min = GSS_SERVER_ERR;
+ return GSS_S_FAILURE;
+ }
+ }
+ else {
+ if(ctx) {
+ *min = GSS_INVALID_CTX;
+ return GSS_S_FAILURE;
+ }
+
+ ctx = (gss_ctx_id_t) calloc(sizeof(*ctx), 1);
+ if(!ctx) {
+ *min = GSS_NO_MEMORY;
+ return GSS_S_FAILURE;
+ }
+
+ if(strstr(creds, "KRB5"))
+ ctx->have_krb5 = 1;
+
+ if(strstr(creds, "NTLM"))
+ ctx->have_ntlm = 1;
+
+ if(ctx->have_krb5)
+ ctx->sent = KRB5;
+ else if(ctx->have_ntlm)
+ ctx->sent = NTLM1;
+ else {
+ free(ctx);
+ *min = GSS_NO_MECH;
+ return GSS_S_FAILURE;
+ }
+
+ strcpy(ctx->creds, creds);
+ ctx->flags = req_flags;
+ }
+
+ token = malloc(length);
+ if(!token) {
+ free(ctx);
+ *min = GSS_NO_MEMORY;
+ return GSS_S_FAILURE;
+ }
+
+ /* Token format: creds:target:type:padding */
+ used = snprintf(token, length, "%s:%s:%d:", creds,
+ (char *) target_name, ctx->sent);
+
+ if(used >= length) {
+ free(token);
+ free(ctx);
+ *min = GSS_NO_MEMORY;
+ return GSS_S_FAILURE;
+ }
+
+ /* Overwrite null terminator */
+ memset(token + used, 'A', length - used);
+
+ *context_handle = ctx;
+
+ output_token->value = token;
+ output_token->length = length;
+
+ return GSS_S_CONTINUE_NEEDED;
+}
+
+OM_uint32 gss_delete_sec_context(OM_uint32 *min,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t output_token)
+{
+ if(!min)
+ return GSS_S_FAILURE;
+
+ if(!context_handle) {
+ *min = GSS_INVALID_CTX;
+ return GSS_S_FAILURE;
+ }
+
+ free(*context_handle);
+ *context_handle = NULL;
+ *min = 0;
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 gss_release_buffer(OM_uint32 *min,
+ gss_buffer_t buffer)
+{
+ if(min)
+ *min = 0;
+
+ if(buffer && buffer->length) {
+ free(buffer->value);
+ buffer->length = 0;
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 gss_import_name(OM_uint32 *min,
+ const gss_buffer_t input_name_buffer,
+ const gss_OID input_name_type,
+ gss_name_t *output_name)
+{
+ char *name = NULL;
+
+ if(!min)
+ return GSS_S_FAILURE;
+
+ if(!input_name_buffer || !output_name) {
+ *min = GSS_INVALID_ARGS;
+ return GSS_S_FAILURE;
+ }
+
+ name = strndup(input_name_buffer->value, input_name_buffer->length);
+ if(!name) {
+ *min = GSS_NO_MEMORY;
+ return GSS_S_FAILURE;
+ }
+
+ *output_name = (gss_name_t) name;
+ *min = 0;
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 gss_release_name(OM_uint32 *min,
+ gss_name_t *input_name)
+{
+ if(min)
+ *min = 0;
+
+ if(input_name)
+ free(*input_name);
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 gss_display_status(OM_uint32 *min,
+ OM_uint32 status_value,
+ int status_type,
+ const gss_OID mech_type,
+ OM_uint32 *message_context,
+ gss_buffer_t status_string)
+{
+ const char maj_str[] = "Stub GSS error";
+ if(min)
+ *min = 0;
+
+ if(message_context)
+ *message_context = 0;
+
+ if(status_string) {
+ status_string->value = NULL;
+ status_string->length = 0;
+
+ if(status_value >= GSS_LAST)
+ return GSS_S_FAILURE;
+
+ switch(status_type) {
+ case GSS_C_GSS_CODE:
+ status_string->value = strdup(maj_str);
+ break;
+ case GSS_C_MECH_CODE:
+ status_string->value = strdup(min_err_table[status_value]);
+ break;
+ default:
+ return GSS_S_FAILURE;
+ }
+
+ if(status_string->value)
+ status_string->length = strlen(status_string->value);
+ else
+ return GSS_S_FAILURE;
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+/* Stubs returning error */
+
+OM_uint32 gss_display_name(OM_uint32 *min,
+ gss_const_name_t input_name,
+ gss_buffer_t output_name_buffer,
+ gss_OID *output_name_type)
+{
+ return GSS_S_FAILURE;
+}
+
+OM_uint32 gss_inquire_context(OM_uint32 *min,
+ gss_const_ctx_id_t context_handle,
+ gss_name_t *src_name,
+ gss_name_t *targ_name,
+ OM_uint32 *lifetime_rec,
+ gss_OID *mech_type,
+ OM_uint32 *ctx_flags,
+ int *locally_initiated,
+ int *open_context)
+{
+ return GSS_S_FAILURE;
+}
+
+OM_uint32 gss_wrap(OM_uint32 *min,
+ gss_const_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ const gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer)
+{
+ return GSS_S_FAILURE;
+}
+
+OM_uint32 gss_unwrap(OM_uint32 *min,
+ gss_const_ctx_id_t context_handle,
+ const gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer,
+ int *conf_state,
+ gss_qop_t *qop_state)
+{
+ return GSS_S_FAILURE;
+}
+
+OM_uint32 gss_seal(OM_uint32 *min,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ int qop_req,
+ gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer)
+{
+ return GSS_S_FAILURE;
+}
+
+OM_uint32 gss_unseal(OM_uint32 *min,
+ gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer,
+ int *conf_state,
+ int *qop_state)
+{
+ return GSS_S_FAILURE;
+}
+
diff --git a/tests/libtest/stub_gssapi.h b/tests/libtest/stub_gssapi.h
new file mode 100644
index 000000000..9a302f0f5
--- /dev/null
+++ b/tests/libtest/stub_gssapi.h
@@ -0,0 +1,183 @@
+#ifndef HEADER_CURL_GSSAPI_STUBS_H
+#define HEADER_CURL_GSSAPI_STUBS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* Roughly based on Heimdal's gssapi.h */
+
+#include <stdint.h>
+#include <stddef.h>
+
+#define GSS_ERROR(status) (status & 0x80000000)
+
+#define GSS_S_COMPLETE 0
+#define GSS_S_FAILURE (0x80000000)
+#define GSS_S_CONTINUE_NEEDED (1ul)
+
+#define GSS_C_QOP_DEFAULT 0
+#define GSS_C_NO_OID ((gss_OID) 0)
+#define GSS_C_NO_NAME ((gss_name_t) 0)
+#define GSS_C_NO_BUFFER ((gss_buffer_t) 0)
+#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) 0)
+#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0)
+#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0)
+
+#define GSS_C_NULL_OID GSS_C_NO_OID
+
+#define GSS_C_EMPTY_BUFFER {0, NULL}
+
+#define GSS_C_AF_INET 2
+
+#define GSS_C_GSS_CODE 1
+#define GSS_C_MECH_CODE 2
+
+#define GSS_C_DELEG_FLAG 1
+#define GSS_C_MUTUAL_FLAG 2
+#define GSS_C_REPLAY_FLAG 4
+#define GSS_C_CONF_FLAG 16
+#define GSS_C_INTEG_FLAG 32
+
+/*
+ * Expiration time of 2^32-1 seconds means infinite lifetime for a
+ * credential or security context
+ */
+#define GSS_C_INDEFINITE 0xfffffffful
+
+#define GSS_C_NT_HOSTBASED_SERVICE NULL
+
+typedef uint32_t OM_uint32;
+
+typedef OM_uint32 gss_qop_t;
+
+typedef struct gss_buffer_desc_struct {
+ size_t length;
+ void *value;
+} gss_buffer_desc, *gss_buffer_t;
+
+struct gss_cred_id_t_desc_struct;
+typedef struct gss_cred_id_t_desc_struct *gss_cred_id_t;
+typedef const struct gss_cred_id_t_desc_struct *gss_const_cred_id_t;
+
+struct gss_ctx_id_t_desc_struct;
+typedef struct gss_ctx_id_t_desc_struct *gss_ctx_id_t;
+typedef const struct gss_ctx_id_t_desc_struct *gss_const_ctx_id_t;
+
+struct gss_name_t_desc_struct;
+typedef struct gss_name_t_desc_struct *gss_name_t;
+typedef const struct gss_name_t_desc_struct *gss_const_name_t;
+
+typedef struct gss_OID_desc_struct {
+ OM_uint32 length;
+ void *elements;
+} gss_OID_desc, *gss_OID;
+
+typedef struct gss_channel_bindings_struct {
+ OM_uint32 initiator_addrtype;
+ gss_buffer_desc initiator_address;
+ OM_uint32 acceptor_addrtype;
+ gss_buffer_desc acceptor_address;
+ gss_buffer_desc application_data;
+} *gss_channel_bindings_t;
+
+OM_uint32 gss_release_buffer(OM_uint32 * /*minor_status*/,
+ gss_buffer_t /*buffer*/);
+
+OM_uint32 gss_init_sec_context(OM_uint32 * /*minor_status*/,
+ gss_const_cred_id_t /*initiator_cred_handle*/,
+ gss_ctx_id_t * /*context_handle*/,
+ gss_const_name_t /*target_name*/,
+ const gss_OID /*mech_type*/,
+ OM_uint32 /*req_flags*/,
+ OM_uint32 /*time_req*/,
+ const gss_channel_bindings_t /*input_chan_bindings*/,
+ const gss_buffer_t /*input_token*/,
+ gss_OID * /*actual_mech_type*/,
+ gss_buffer_t /*output_token*/,
+ OM_uint32 * /*ret_flags*/,
+ OM_uint32 * /*time_rec*/);
+
+OM_uint32 gss_delete_sec_context(OM_uint32 * /*minor_status*/,
+ gss_ctx_id_t * /*context_handle*/,
+ gss_buffer_t /*output_token*/);
+
+OM_uint32 gss_inquire_context(OM_uint32 * /*minor_status*/,
+ gss_const_ctx_id_t /*context_handle*/,
+ gss_name_t * /*src_name*/,
+ gss_name_t * /*targ_name*/,
+ OM_uint32 * /*lifetime_rec*/,
+ gss_OID * /*mech_type*/,
+ OM_uint32 * /*ctx_flags*/,
+ int * /*locally_initiated*/,
+ int * /*open_context*/);
+
+OM_uint32 gss_wrap(OM_uint32 * /*minor_status*/,
+ gss_const_ctx_id_t /*context_handle*/,
+ int /*conf_req_flag*/,
+ gss_qop_t /*qop_req*/,
+ const gss_buffer_t /*input_message_buffer*/,
+ int * /*conf_state*/,
+ gss_buffer_t /*output_message_buffer*/);
+
+OM_uint32 gss_unwrap(OM_uint32 * /*minor_status*/,
+ gss_const_ctx_id_t /*context_handle*/,
+ const gss_buffer_t /*input_message_buffer*/,
+ gss_buffer_t /*output_message_buffer*/,
+ int * /*conf_state*/,
+ gss_qop_t * /*qop_state*/);
+
+OM_uint32 gss_seal(OM_uint32 * /*minor_status*/,
+ gss_ctx_id_t /*context_handle*/,
+ int /*conf_req_flag*/,
+ int /*qop_req*/,
+ gss_buffer_t /*input_message_buffer*/,
+ int * /*conf_state*/,
+ gss_buffer_t /*output_message_buffer*/);
+
+OM_uint32 gss_unseal(OM_uint32 * /*minor_status*/,
+ gss_ctx_id_t /*context_handle*/,
+ gss_buffer_t /*input_message_buffer*/,
+ gss_buffer_t /*output_message_buffer*/,
+ int * /*conf_state*/,
+ int * /*qop_state*/);
+
+OM_uint32 gss_import_name(OM_uint32 * /*minor_status*/,
+ const gss_buffer_t /*input_name_buffer*/,
+ const gss_OID /*input_name_type*/,
+ gss_name_t * /*output_name*/);
+
+OM_uint32 gss_release_name(OM_uint32 * /*minor_status*/,
+ gss_name_t * /*input_name*/);
+
+OM_uint32 gss_display_name(OM_uint32 * /*minor_status*/,
+ gss_const_name_t /*input_name*/,
+ gss_buffer_t /*output_name_buffer*/,
+ gss_OID * /*output_name_type*/);
+
+OM_uint32 gss_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*/);
+
+#endif /* HEADER_CURL_GSSAPI_STUBS_H */
+