summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2014-08-14 17:48:02 -0400
committerGünther Deschner <gdeschner@redhat.com>2014-09-15 13:09:56 +0200
commit57a9447610eb29c72f606a59d10c211c8d7f41e6 (patch)
treefaf961eb52b6a18dcfa9b5e94b64f81b6d415221
parent38a158446d1f9ce495715aa83265fe35a29f8a2b (diff)
downloadgss-proxy-57a9447610eb29c72f606a59d10c211c8d7f41e6.tar.gz
gss-proxy-57a9447610eb29c72f606a59d10c211c8d7f41e6.tar.xz
gss-proxy-57a9447610eb29c72f606a59d10c211c8d7f41e6.zip
Add a test framework for gss-proxy
This sets up a kdc using socket_wrapper and nss_wrapper from the cwrap project, and uses a dirty hack to force gssapi to load the current proxymech interposer library. It provisions a service and a user key then runs the interpostest binary in this artifical environment. Signed-off-by: Simo Sorce <simo@redhat.com> Reviewed-by: Guenther Deschner <gdeschner@redhat.com>
-rw-r--r--.gitignore2
-rw-r--r--proxy/Makefile.am3
-rw-r--r--proxy/configure.ac2
-rw-r--r--proxy/tests/Makefile.am22
-rwxr-xr-xproxy/tests/runtests.py403
-rw-r--r--proxy/tests/t_accept.c66
-rw-r--r--proxy/tests/t_init.c97
-rw-r--r--proxy/tests/t_utils.c109
-rw-r--r--proxy/tests/t_utils.h25
9 files changed, 727 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index 4716c78..c8be862 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,3 +40,5 @@ cli_srv_comm
gssproxy.spec
interposetest
gssproxy.service
+t_accept
+t_init
diff --git a/proxy/Makefile.am b/proxy/Makefile.am
index c946421..8c160b0 100644
--- a/proxy/Makefile.am
+++ b/proxy/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS =
+SUBDIRS = tests
#SUBDIRS += po
if HAVE_MANPAGES
@@ -264,6 +264,7 @@ clean-local:
CLEANFILES = *.X */*.X */*/*.X
tests: all $(check_PROGRAMS)
+ ./tests/runtests.py
# RPM-related tasks
diff --git a/proxy/configure.ac b/proxy/configure.ac
index a0cc4ef..a709d20 100644
--- a/proxy/configure.ac
+++ b/proxy/configure.ac
@@ -181,7 +181,7 @@ abs_build_dir=`pwd`
AC_DEFINE_UNQUOTED([ABS_BUILD_DIR], ["$abs_build_dir"], [Absolute path to the build directory])
AC_SUBST([abs_builddir], $abs_build_dir)
-AC_CONFIG_FILES([Makefile systemd/gssproxy.service man/Makefile
+AC_CONFIG_FILES([Makefile tests/Makefile systemd/gssproxy.service man/Makefile
contrib/gssproxy.spec examples/mech examples/gssproxy.conf
man/gssproxy-mech.8.xml])
AC_OUTPUT
diff --git a/proxy/tests/Makefile.am b/proxy/tests/Makefile.am
new file mode 100644
index 0000000..058893f
--- /dev/null
+++ b/proxy/tests/Makefile.am
@@ -0,0 +1,22 @@
+
+t_accept_SOURCES = \
+ t_utils.c \
+ t_accept.c
+
+t_accept_LDADD = \
+ $(GSSAPI_LIBS)
+
+t_init_SOURCES = \
+ t_utils.c \
+ t_init.c
+
+t_init_LDADD = \
+ $(GSSAPI_LIBS)
+
+check_PROGRAMS = \
+ t_accept \
+ t_init
+
+noinst_PROGRAMS = $(check_PROGRAMS)
+
+all: $(check_PROGRAMS)
diff --git a/proxy/tests/runtests.py b/proxy/tests/runtests.py
new file mode 100755
index 0000000..4b7aa55
--- /dev/null
+++ b/proxy/tests/runtests.py
@@ -0,0 +1,403 @@
+#!/usr/bin/python
+# copyright (C) 2014 - GSS-Proxy contributors, see COPYING for the license.
+
+import argparse
+import glob
+import os
+import shutil
+import signal
+from string import Template
+import subprocess
+import sys
+import time
+
+
+def parse_args():
+ parser = argparse.ArgumentParser(description='GSS-Proxy Tests Environment')
+ parser.add_argument('--path', default='%s/scratchdir' % os.getcwd(),
+ help="Directory in which tests are run")
+
+ return vars(parser.parse_args())
+
+
+WRAP_HOSTNAME = "kdc.gssproxy.dev"
+
+
+def setup_wrappers(base):
+
+ pkgcfg = subprocess.Popen(['pkg-config', '--exists', 'socket_wrapper'])
+ pkgcfg.wait()
+ if pkgcfg.returncode != 0:
+ raise ValueError('Socket Wrappers not available')
+
+ pkgcfg = subprocess.Popen(['pkg-config', '--exists', 'nss_wrapper'])
+ pkgcfg.wait()
+ if pkgcfg.returncode != 0:
+ raise ValueError('Socket Wrappers not available')
+
+ wrapdir = os.path.join(base, 'wrapdir')
+ if not os.path.exists(wrapdir):
+ os.makedirs(wrapdir)
+
+ hosts_file = os.path.join(testdir, 'hosts')
+ with open(hosts_file, 'w+') as f:
+ f.write('127.0.0.9 %s' % WRAP_HOSTNAME)
+
+ wenv = {'LD_PRELOAD': 'libsocket_wrapper.so libnss_wrapper.so',
+ 'SOCKET_WRAPPER_DIR': wrapdir,
+ 'SOCKET_WRAPPER_DEFAULT_IFACE': '9',
+ 'NSS_WRAPPER_HOSTNAME': WRAP_HOSTNAME,
+ 'NSS_WRAPPER_HOSTS': hosts_file}
+
+ return wenv
+
+
+TESTREALM = "GSSPROXY.DEV"
+KDC_DBNAME = 'db.file'
+KDC_STASH = 'stash.file'
+KDC_PASSWORD = 'gssproxy'
+KRB5_CONF_TEMPLATE = '''
+[libdefaults]
+ default_realm = ${TESTREALM}
+ dns_lookup_realm = false
+ dns_lookup_kdc = false
+ rdns = false
+ ticket_lifetime = 24h
+ forwardable = yes
+ default_ccache_name = FILE://${TESTDIR}/ccaches/krb5_ccache_XXXXXX
+
+[realms]
+ ${TESTREALM} = {
+ kdc =${WRAP_HOSTNAME}
+ }
+
+[domain_realm]
+ .gssproxy.dev = GSSPROXY.DEV
+ gssproxy.dev = GSSPROXY.DEV
+
+[dbmodules]
+ ${TESTREALM} = {
+ database_name = ${KDCDIR}/${KDC_DBNAME}
+ }
+'''
+KDC_CONF_TEMPLATE = '''
+[kdcdefaults]
+ kdc_ports = 88
+ kdc_tcp_ports = 88
+ restrict_anonymous_to_tgt = true
+
+[realms]
+ ${TESTREALM} = {
+ master_key_type = aes256-cts
+ max_life = 7d
+ max_renewable_life = 14d
+ acl_file = ${KDCDIR}/kadm5.acl
+ dict_file = /usr/share/dict/words
+ default_principal_flags = +preauth
+ admin_keytab = ${TESTREALM}/kadm5.keytab
+ key_stash_file = ${KDCDIR}/${KDC_STASH}
+ }
+[logging]
+ kdc = FILE:${KDCLOG}
+'''
+
+
+def setup_kdc(testdir, wrapenv):
+
+ # setup kerberos environment
+ testlog = os.path.join(testdir, 'kerb.log')
+ krb5conf = os.path.join(testdir, 'krb5.conf')
+ kdcconf = os.path.join(testdir, 'kdc.conf')
+ kdcdir = os.path.join(testdir, 'kdc')
+ kdcstash = os.path.join(kdcdir, KDC_STASH)
+ kdcdb = os.path.join(kdcdir, KDC_DBNAME)
+ if os.path.exists(kdcdir):
+ shutil.rmtree(kdcdir)
+ os.makedirs(kdcdir)
+
+ t = Template(KRB5_CONF_TEMPLATE)
+ text = t.substitute({'TESTREALM': TESTREALM,
+ 'TESTDIR': testdir,
+ 'KDCDIR': kdcdir,
+ 'KDC_DBNAME': KDC_DBNAME,
+ 'WRAP_HOSTNAME': WRAP_HOSTNAME})
+ with open(krb5conf, 'w+') as f:
+ f.write(text)
+
+ t = Template(KDC_CONF_TEMPLATE)
+ text = t.substitute({'TESTREALM': TESTREALM,
+ 'KDCDIR': kdcdir,
+ 'KDCLOG': testlog,
+ 'KDC_STASH': KDC_STASH})
+ with open(kdcconf, 'w+') as f:
+ f.write(text)
+
+ kdcenv = {'PATH': '/sbin:/bin:/usr/sbin:/usr/bin',
+ 'KRB5_CONFIG': krb5conf,
+ 'KRB5_KDC_PROFILE': kdcconf}
+ kdcenv.update(wrapenv)
+
+ with (open(testlog, 'a')) as logfile:
+ ksetup = subprocess.Popen(["kdb5_util", "create", "-s",
+ "-r", TESTREALM, "-P", KDC_PASSWORD],
+ stdout=logfile, stderr=logfile,
+ env=kdcenv, preexec_fn=os.setsid)
+ ksetup.wait()
+ if ksetup.returncode != 0:
+ raise ValueError('KDC Setup failed')
+
+ kdcproc = subprocess.Popen(['krb5kdc', '-n'],
+ env=kdcenv, preexec_fn=os.setsid)
+
+ return kdcproc, kdcenv
+
+
+def kadmin_local(cmd, env, logfile):
+ ksetup = subprocess.Popen(["kadmin.local", "-q", cmd],
+ stdout=logfile, stderr=logfile,
+ env=env, preexec_fn=os.setsid)
+ ksetup.wait()
+ if ksetup.returncode != 0:
+ raise ValueError('Kadmin local [%s] failed' % cmd)
+
+
+USR_NAME = "user"
+USR_KTNAME = "user.gssproxy.keytab"
+USR_CCACHE = "krb5ccache_usr"
+SVC_KTNAME = "kdc.gssproxy.keytab"
+KEY_TYPE = "aes256-cts-hmac-sha1-96:normal"
+
+
+def setup_keys(tesdir, env):
+
+ testlog = os.path.join(testdir, 'kerb.log')
+
+ svc_name = "host/%s" % WRAP_HOSTNAME
+ svc_keytab = os.path.join(testdir, SVC_KTNAME)
+ cmd = "addprinc -randkey -e %s %s" % (KEY_TYPE, svc_name)
+ with (open(testlog, 'a')) as logfile:
+ kadmin_local(cmd, env, logfile)
+ cmd = "ktadd -k %s -e %s %s" % (svc_keytab, KEY_TYPE, svc_name)
+ with (open(testlog, 'a')) as logfile:
+ kadmin_local(cmd, env, logfile)
+
+ usr_keytab = os.path.join(testdir, USR_KTNAME)
+ cmd = "addprinc -randkey -e %s %s" % (KEY_TYPE, USR_NAME)
+ with (open(testlog, 'a')) as logfile:
+ kadmin_local(cmd, env, logfile)
+ cmd = "ktadd -k %s -e %s %s" % (usr_keytab, KEY_TYPE, USR_NAME)
+ with (open(testlog, 'a')) as logfile:
+ kadmin_local(cmd, env, logfile)
+
+ keys_env = { "KRB5_KTNAME": svc_keytab}
+ keys_env.update(env)
+
+ return keys_env
+
+
+# This is relative to the path where the test binary is being run
+GSSAPI_SYMLINK_DIR = ".test655"
+MECH_CONF_TEMPLATE = '''
+gssproxy_v1 2.16.840.1.113730.3.8.15.1 ${PROXYMECH} <interposer>
+'''
+
+
+def setup_gssapi_env(testdir, wrapenv):
+
+ libgssapi_dir = os.path.join(testdir, 'libgssapi')
+ libgssapi_mechd_dir = os.path.join(GSSAPI_SYMLINK_DIR, 'mech.d')
+
+ if os.path.exists(libgssapi_dir):
+ shutil.rmtree(libgssapi_dir)
+ os.makedirs(libgssapi_dir)
+
+ if os.path.exists(GSSAPI_SYMLINK_DIR):
+ os.unlink(GSSAPI_SYMLINK_DIR)
+ os.symlink(libgssapi_dir, GSSAPI_SYMLINK_DIR)
+ os.makedirs(libgssapi_mechd_dir)
+
+ # find them all and get the longest name in the hopes
+ # we hit /usr/lib64/libgssapi_krb5.so.2.2 in preference
+ libs = glob.glob("/usr/lib*/libgssapi*.so*")
+ lib = None
+ lib_len = 0
+ for l in libs:
+ if len(l) > lib_len:
+ lib_len = len(l)
+ lib = l
+ if not lib:
+ raise KeyError('Gssapi library not found')
+
+ libgssapi_lib = os.path.join(libgssapi_dir, os.path.basename(lib))
+ libgssapi_conf = os.path.join(libgssapi_mechd_dir, 'gssproxy-mech.conf')
+
+ # horrible, horrible hack to load our own configuration later
+ with open(lib, 'rb') as f:
+ data = f.read()
+ with open(libgssapi_lib, 'wb') as f:
+ f.write(data.replace('/etc/gss/mech.d', libgssapi_mechd_dir))
+
+ shutil.copy('.libs/proxymech.so', libgssapi_dir)
+ proxymech = os.path.join(libgssapi_dir, 'proxymech.so')
+
+ t = Template(MECH_CONF_TEMPLATE)
+ text = t.substitute({'PROXYMECH': proxymech})
+ with open(libgssapi_conf, 'w+') as f:
+ f.write(text)
+
+ # first swallow in wrapenv vars if any
+ gssapi_env = dict()
+ gssapi_env.update(wrapenv)
+
+ # then augment preload if any
+ ld_pre = ''
+ if 'LD_PRELOAD' in wrapenv:
+ ld_pre = wrapenv['LD_PRELOAD'] + ' '
+ ld_pre = ld_pre + os.path.join(GSSAPI_SYMLINK_DIR,
+ os.path.basename(libgssapi_lib))
+ gssapi_env['LD_PRELOAD'] = ld_pre
+
+ return gssapi_env
+
+
+def run_interposetest(testdir, env):
+ testlog = os.path.join(testdir, 'tests.log')
+
+ ienv = {"KRB5CCNAME": os.path.join(testdir, 'interpose_ccache')}
+ ienv.update(env)
+ usr_keytab = os.path.join(testdir, USR_KTNAME)
+ with (open(testlog, 'a')) as logfile:
+ ksetup = subprocess.Popen(["kinit", "-kt", usr_keytab, USR_NAME],
+ stdout=logfile, stderr=logfile,
+ env=ienv, preexec_fn=os.setsid)
+ ksetup.wait()
+ if ksetup.returncode != 0:
+ raise ValueError('Kinit %s failed' % USR_NAME)
+
+ with (open(testlog, 'a')) as logfile:
+ itest = subprocess.Popen(["./interposetest", "-t",
+ "host@%s" % WRAP_HOSTNAME],
+ stdout=logfile, stderr=logfile,
+ env=ienv)
+ itest.wait()
+ if itest.returncode != 0:
+ raise ValueError('Interposetest failed')
+
+
+GSSPROXY_CONF_TEMPLATE = '''
+[gssproxy]
+
+[service/test]
+ mechs = krb5
+ cred_store = keytab:${GSSPROXY_KEYTAB}
+ cred_store = ccache:FILE:${GSSPROXY_CLIENT_CCACHE}
+ cred_store = client_keytab:${GSSPROXY_CLIENT_KEYTAB}
+ trusted = yes
+ euid = ${UIDNUMBER}
+'''
+
+
+def setup_gssproxy(testdir, env):
+ testlog = os.path.join(testdir, 'tests.log')
+
+ gssproxy = os.path.join(testdir, 'gssproxy')
+ if os.path.exists(gssproxy):
+ shutil.rmtree(gssproxy)
+ os.makedirs(gssproxy)
+
+ socket = os.path.join(gssproxy, 'gp.sock')
+ ccache = os.path.join(gssproxy, 'gpccache')
+ ckeytab = os.path.join(testdir, USR_KTNAME)
+
+ conf = os.path.join(gssproxy, 'gp.conf')
+ t = Template(GSSPROXY_CONF_TEMPLATE)
+ text = t.substitute({'GSSPROXY_KEYTAB': env['KRB5_KTNAME'],
+ 'GSSPROXY_CLIENT_CCACHE': ccache,
+ 'GSSPROXY_CLIENT_KEYTAB': ckeytab,
+ 'UIDNUMBER': os.getuid()})
+ with open(conf, 'w+') as f:
+ f.write(text)
+
+ with (open(testlog, 'a')) as logfile:
+ gproc = subprocess.Popen(["./gssproxy", "-i", "-d",
+ "-s", socket, "-c", conf],
+ stdout=logfile, stderr=logfile,
+ env=env, preexec_fn=os.setsid)
+
+ return gproc, socket
+
+
+def run_basic_test(testdir, env):
+
+ print "STARTING BASIC init/Accept tests"
+ testlog = os.path.join(testdir, 'tests.log')
+
+ svc_name = "host@%s" % WRAP_HOSTNAME
+ svc_keytab = os.path.join(testdir, SVC_KTNAME)
+ svcenv = {'KRB5_KTNAME': svc_keytab}
+ svcenv.update(env)
+
+ cli_keytab = os.path.join(testdir, USR_KTNAME)
+ cli_ccache = os.path.join(testdir, 't_basic_ccname')
+ clienv = {'GSS_USE_PROXY': 'yes',
+ 'GSSPROXY_BEHAVIOR': 'REMOTE_FIRST',
+ 'KRB5CCNAME': cli_ccache,
+ 'KRB5_CLIENT_KTNAME': cli_keytab}
+ clienv.update(env)
+
+ pipe0 = os.pipe()
+ pipe1 = os.pipe()
+
+ with (open(testlog, 'a')) as logfile:
+ p1 = subprocess.Popen(["./tests/t_init", svc_name],
+ stdin=pipe0[0], stdout=pipe1[1],
+ stderr=logfile, env=clienv, preexec_fn=os.setsid)
+ p2 = subprocess.Popen(["./tests/t_accept"],
+ stdin=pipe1[0], stdout=pipe0[1],
+ stderr=logfile, env=clienv, preexec_fn=os.setsid)
+ p1.wait()
+ if p1.returncode != 0:
+ print >> sys.stderr, "FAILED: Init test"
+ os.killpg(p2.pid, signal.SIGTERM)
+ else:
+ print >> sys.stderr, "SUCCESS: Init test"
+ p2.wait()
+ if p2.returncode != 0:
+ print >> sys.stderr, "FAILED: Accept test"
+ os.killpg(p1.pid, signal.SIGTERM)
+ else:
+ print >> sys.stderr, "SUCCESS: Accept test"
+
+
+if __name__ == '__main__':
+
+ args = parse_args()
+
+ testdir = args['path']
+ if os.path.exists(testdir):
+ shutil.rmtree(testdir)
+ os.makedirs(testdir)
+
+ processes = dict()
+
+ try:
+ wrapenv = setup_wrappers(testdir)
+
+ kdcproc, kdcenv = setup_kdc(testdir, wrapenv)
+ processes['KDC(%d)' % kdcproc.pid] = kdcproc
+
+ keysenv = setup_keys(testdir, kdcenv)
+
+ gssapienv = setup_gssapi_env(testdir, keysenv)
+
+ run_interposetest(testdir, gssapienv)
+
+ gproc, gpsocket = setup_gssproxy(testdir, keysenv)
+ processes['GSS-Proxy(%d)' % gproc.pid] = gproc
+ gssapienv['GSSPROXY_SOCKET'] = gpsocket
+ run_basic_test(testdir, gssapienv)
+
+ finally:
+ for name in processes:
+ print "Killing %s" % name
+ os.killpg(processes[name].pid, signal.SIGTERM)
diff --git a/proxy/tests/t_accept.c b/proxy/tests/t_accept.c
new file mode 100644
index 0000000..eba0272
--- /dev/null
+++ b/proxy/tests/t_accept.c
@@ -0,0 +1,66 @@
+/* Copyright (C) 2014 the GSS-PROXY contributors, see COPYING for license */
+
+#include "t_utils.h"
+
+int main(int argc, const char *argv[])
+{
+ char buffer[MAX_RPC_SIZE];
+ uint32_t buflen;
+ gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
+ gss_buffer_desc in_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc out_token = GSS_C_EMPTY_BUFFER;
+ gss_name_t src_name;
+ uint32_t ret_maj;
+ uint32_t ret_min;
+ int ret = -1;
+
+ /* We get stuff from stdin and spit it out on stderr */
+ ret = t_recv_buffer(STDIN_FD, buffer, &buflen);
+ if (ret != 0) {
+ DEBUG(argv[0], "Failed to read token from STDIN\n");
+ ret = -1;
+ goto done;
+ }
+
+ in_token.value = buffer;
+ in_token.length = buflen;
+
+ ret_maj = gss_accept_sec_context(&ret_min,
+ &context_handle,
+ GSS_C_NO_CREDENTIAL,
+ &in_token,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &src_name,
+ NULL,
+ &out_token,
+ NULL,
+ NULL,
+ NULL);
+ if (ret_maj) {
+ DEBUG(argv[0], "Error accepting context\n");
+ t_log_failure(GSS_C_NO_OID, ret_maj, ret_min);
+ ret = -1;
+ goto done;
+ }
+
+ if (!out_token.length) {
+ DEBUG(argv[0], "No output token ?");
+ ret = -1;
+ goto done;
+ }
+
+ ret = t_send_buffer(STDOUT_FD, out_token.value, out_token.length);
+ if (ret) {
+ DEBUG(argv[0], "Failed to send data to client!\n");
+ ret = -1;
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ gss_delete_sec_context(&ret_min, &context_handle, NULL);
+ gss_release_buffer(&ret_min, &out_token);
+ gss_release_name(&ret_min, &src_name);
+ return ret;
+}
diff --git a/proxy/tests/t_init.c b/proxy/tests/t_init.c
new file mode 100644
index 0000000..fd8cdf6
--- /dev/null
+++ b/proxy/tests/t_init.c
@@ -0,0 +1,97 @@
+/* Copyright (C) 2014 the GSS-PROXY contributors, see COPYING for license */
+
+#include "t_utils.h"
+
+int main(int argc, const char *argv[])
+{
+ char buffer[MAX_RPC_SIZE];
+ uint32_t buflen;
+ gss_cred_id_t cred_handle = GSS_C_NO_CREDENTIAL;
+ gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
+ gss_buffer_desc in_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc out_token = GSS_C_EMPTY_BUFFER;
+ gss_name_t name;
+ uint32_t ret_maj;
+ uint32_t ret_min;
+ int ret = -1;
+
+ ret = t_string_to_name(argv[1], &name);
+ if (ret) {
+ DEBUG(argv[0], "Failed to import server name from argv[1]\n");
+ ret = -1;
+ goto done;
+ }
+
+ ret_maj = gss_init_sec_context(&ret_min,
+ cred_handle,
+ &context_handle,
+ name,
+ GSS_C_NO_OID,
+ GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
+ 0,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &in_token,
+ NULL,
+ &out_token,
+ NULL,
+ NULL);
+ if (ret_maj != GSS_S_CONTINUE_NEEDED) {
+ DEBUG(argv[0], "gss_init_sec_context() failed\n");
+ t_log_failure(GSS_C_NO_OID, ret_maj, ret_min);
+ ret = -1;
+ goto done;
+ }
+
+ /* We get stuff from stdin and spit it out on stderr */
+ if (!out_token.length) {
+ DEBUG(argv[0], "No output token ?");
+ ret = -1;
+ goto done;
+ }
+
+ ret = t_send_buffer(STDOUT_FD, out_token.value, out_token.length);
+ if (ret) {
+ DEBUG(argv[0], "Failed to send data to server!\n");
+ ret = -1;
+ goto done;
+ }
+
+ ret = t_recv_buffer(STDIN_FD, buffer, &buflen);
+ if (ret != 0) {
+ DEBUG(argv[0], "Failed to read token from STDIN\n");
+ ret = -1;
+ goto done;
+ }
+
+ in_token.value = buffer;
+ in_token.length = buflen;
+
+ ret_maj = gss_init_sec_context(&ret_min,
+ cred_handle,
+ &context_handle,
+ name,
+ GSS_C_NO_OID,
+ GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
+ 0,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &in_token,
+ NULL,
+ &out_token,
+ NULL,
+ NULL);
+ if (ret_maj) {
+ DEBUG(argv[0], "Error initializing context\n");
+ t_log_failure(GSS_C_NO_OID, ret_maj, ret_min);
+ ret = -1;
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ gss_delete_sec_context(&ret_min, &context_handle, NULL);
+ gss_release_cred(&ret_min, &cred_handle);
+ gss_release_buffer(&ret_min, &out_token);
+ gss_release_name(&ret_min, &name);
+ return ret;
+}
diff --git a/proxy/tests/t_utils.c b/proxy/tests/t_utils.c
new file mode 100644
index 0000000..f4446fa
--- /dev/null
+++ b/proxy/tests/t_utils.c
@@ -0,0 +1,109 @@
+/* Copyright (C) 2014 the GSS-PROXY contributors, see COPYING for license */
+
+#include "t_utils.h"
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <errno.h>
+
+int t_send_buffer(int fd, char *buf, uint32_t len)
+{
+ uint32_t size;
+ size_t wn;
+ size_t pos;
+
+ size = htonl(len);
+
+ wn = write(fd, &size, sizeof(uint32_t));
+ if (wn != 4) {
+ return EIO;
+ }
+
+ pos = 0;
+ while (len > pos) {
+ wn = write(fd, buf + pos, len - pos);
+ if (wn == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ return errno;
+ }
+ pos += wn;
+ }
+
+ return 0;
+}
+
+int t_recv_buffer(int fd, char *buf, uint32_t *len)
+{
+ uint32_t size;
+ size_t rn;
+ size_t pos;
+
+ rn = read(fd, &size, sizeof(uint32_t));
+ if (rn != 4) {
+ return EIO;
+ }
+
+ *len = ntohl(size);
+
+ if (*len > MAX_RPC_SIZE) {
+ return EINVAL;
+ }
+
+ pos = 0;
+ while (*len > pos) {
+ rn = read(fd, buf + pos, *len - pos);
+ if (rn == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ return errno;
+ }
+ if (rn == 0) {
+ return EIO;
+ }
+ pos += rn;
+ }
+
+ return 0;
+}
+
+void t_log_failure(gss_OID mech, uint32_t maj, uint32_t min)
+{
+ uint32_t msgctx;
+ uint32_t discard;
+ gss_buffer_desc tmp;
+
+ fprintf(stderr, "Failed with:");
+
+ if (mech != GSS_C_NO_OID) {
+ gss_oid_to_str(&discard, mech, &tmp);
+ fprintf(stderr, " (OID: %s)", (char *)tmp.value);
+ gss_release_buffer(&discard, &tmp);
+ }
+
+ msgctx = 0;
+ gss_display_status(&discard, maj, GSS_C_GSS_CODE, mech, &msgctx, &tmp);
+ fprintf(stderr, " %s,", (char *)tmp.value);
+ gss_release_buffer(&discard, &tmp);
+
+ msgctx = 0;
+ gss_display_status(&discard, min, GSS_C_MECH_CODE, mech, &msgctx, &tmp);
+ fprintf(stderr, " %s\n", (char *)tmp.value);
+ gss_release_buffer(&discard, &tmp);
+}
+
+int t_string_to_name(const char *string, gss_name_t *name)
+{
+ gss_buffer_desc target_buf;
+ uint32_t ret_maj;
+ uint32_t ret_min;
+
+ target_buf.value = strdup(string);
+ target_buf.length = strlen(string) + 1;
+
+ ret_maj = gss_import_name(&ret_min, &target_buf,
+ GSS_C_NT_HOSTBASED_SERVICE, name);
+ free(target_buf.value);
+ return ret_maj;
+}
diff --git a/proxy/tests/t_utils.h b/proxy/tests/t_utils.h
new file mode 100644
index 0000000..74f8ad5
--- /dev/null
+++ b/proxy/tests/t_utils.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2014 the GSS-PROXY contributors, see COPYING for license */
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gssapi/gssapi.h>
+
+#define STDIN_FD 0
+#define STDOUT_FD 1
+#define MAX_RPC_SIZE 1024*1024
+
+#define DEBUG(name, ...) do { \
+ char msg[4096]; \
+ snprintf(msg, 4096, __VA_ARGS__); \
+ fprintf(stderr, "%s[%s:%d]: %s", name, __FUNCTION__, __LINE__, msg); \
+ fflush(stderr); \
+} while(0);
+
+int t_send_buffer(int fd, char *buf, uint32_t len);
+int t_recv_buffer(int fd, char *buf, uint32_t *len);
+
+void t_log_failure(gss_OID mech, uint32_t maj, uint32_t min);
+
+int t_string_to_name(const char *string, gss_name_t *name);