From 27ad1052f2f8a341ce450cf7e25db7d7049b519c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ji=C5=99=C3=AD=20=C5=A0kr=C3=A1bal?= Date: Wed, 9 Feb 2005 10:28:55 +0000 Subject: [PATCH] - New security module which will provide gss communication layer and a gss gSOAP plugin --- org.glite.security.gsoap-plugin/LICENSE | 69 ++ org.glite.security.gsoap-plugin/Makefile | 201 +++++ org.glite.security.gsoap-plugin/build.xml | 104 +++ org.glite.security.gsoap-plugin/examples/calc.h.S | 13 + .../examples/wscalc_clt_ex.c | 47 + .../examples/wscalc_srv_ex.c | 120 +++ .../interface/glite_gsplugin.h | 32 + org.glite.security.gsoap-plugin/interface/lb_gss.h | 108 +++ .../project/build.properties | 0 .../project/configure.properties.xml | 49 + .../project/properties.xml | 55 ++ .../project/tar_exclude | 10 + .../project/version.properties | 3 + .../src/glite_gsplugin.c | 368 ++++++++ org.glite.security.gsoap-plugin/src/lb_gss.c | 982 +++++++++++++++++++++ org.glite.security.gsoap-plugin/test/test_gss.cpp | 149 ++++ 16 files changed, 2310 insertions(+) create mode 100644 org.glite.security.gsoap-plugin/LICENSE create mode 100644 org.glite.security.gsoap-plugin/Makefile create mode 100755 org.glite.security.gsoap-plugin/build.xml create mode 100644 org.glite.security.gsoap-plugin/examples/calc.h.S create mode 100644 org.glite.security.gsoap-plugin/examples/wscalc_clt_ex.c create mode 100644 org.glite.security.gsoap-plugin/examples/wscalc_srv_ex.c create mode 100644 org.glite.security.gsoap-plugin/interface/glite_gsplugin.h create mode 100644 org.glite.security.gsoap-plugin/interface/lb_gss.h create mode 100644 org.glite.security.gsoap-plugin/project/build.properties create mode 100644 org.glite.security.gsoap-plugin/project/configure.properties.xml create mode 100755 org.glite.security.gsoap-plugin/project/properties.xml create mode 100644 org.glite.security.gsoap-plugin/project/tar_exclude create mode 100644 org.glite.security.gsoap-plugin/project/version.properties create mode 100644 org.glite.security.gsoap-plugin/src/glite_gsplugin.c create mode 100644 org.glite.security.gsoap-plugin/src/lb_gss.c create mode 100644 org.glite.security.gsoap-plugin/test/test_gss.cpp diff --git a/org.glite.security.gsoap-plugin/LICENSE b/org.glite.security.gsoap-plugin/LICENSE new file mode 100644 index 0000000..259a91f --- /dev/null +++ b/org.glite.security.gsoap-plugin/LICENSE @@ -0,0 +1,69 @@ +LICENSE file for EGEE Middleware +================================ + +Copyright (c) 2004 on behalf of the EU EGEE Project: +The European Organization for Nuclear Research (CERN), +Istituto Nazionale di Fisica Nucleare (INFN), Italy +Datamat Spa, Italy +Centre National de la Recherche Scientifique (CNRS), France +CS Systeme d'Information (CSSI), France +Royal Institute of Technology, Center for Parallel Computers (KTH-PDC), Sweden +Universiteit van Amsterdam (UvA), Netherlands +University of Helsinki (UH.HIP), Finlan +University of Bergen (UiB), Norway +Council for the Central Laboratory of the Research Councils (CCLRC), United Kingdom + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. The end-user documentation included with the redistribution, if +any, must include the following acknowledgment: "This product includes +software developed by The EU EGEE Project (http://cern.ch/eu-egee/)." +Alternatively, this acknowledgment may appear in the software itself, if +and wherever such third-party acknowledgments normally appear. + +4. The names EGEE and the EU EGEE Project must not be +used to endorse or promote products derived from this software without +prior written permission. For written permission, please contact +. + +5. You are under no obligation whatsoever to provide anyone with any +bug fixes, patches, or upgrades to the features, functionality or +performance of the Software ("Enhancements") that you may develop over +time; however, if you choose to provide your Enhancements to The EU +EGEE Project, or if you choose to otherwise publish or distribute your +Enhancements, in source code form without contemporaneously requiring +end users of The EU EGEE Proejct to enter into a separate written license +agreement for such Enhancements, then you hereby grant The EU EGEE Project +a non-exclusive, royalty-free perpetual license to install, use, copy, +modify, prepare derivative works, incorporate into the EGEE Middleware +or any other computer software, distribute, and sublicense your +Enhancements or derivative works thereof, in binary and source code +form (if any), whether developed by The EU EGEE Project or third parties. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL PROJECT OR ITS CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +This software consists of voluntary contributions made by many +individuals on behalf of the EU EGEE Prject. For more information on The +EU EGEE Project, please see http://cern.ch/eu-egee/. For more information on +EGEE Middleware, please see http://egee-jra1.web.cern.ch/egee-jra1/ + + diff --git a/org.glite.security.gsoap-plugin/Makefile b/org.glite.security.gsoap-plugin/Makefile new file mode 100644 index 0000000..99bedba --- /dev/null +++ b/org.glite.security.gsoap-plugin/Makefile @@ -0,0 +1,201 @@ +# defaults +top_srcdir=. +builddir=build +top_builddir=${top_srcdir}/${builddir} +stagedir=. +distdir=. +globalprefix=glite +lbprefix=lb +package=glite-security-gsoap-plugin +version=1.0.0 +PREFIX=/opt/glite + +glite_location=/opt/glite +globus_prefix=/opt/globus +nothrflavour=gcc32 +thrflavour=gcc32pthr +gsoap_prefix=/opt/gsoap + +-include Makefile.inc +-include ../Makefile.inc + +GSPLUGIN_DEBUG:= yes + +version_info=-version-info `echo ${version} | cut -d. -f1,2 | tr . :` + +VPATH=${top_srcdir}/src:${top_srcdir}/test:${top_srcdir}/examples + +TEST_LIBS:=-L${cppunit}/lib -lcppunit +TEST_INC:=-I${cppunit}/include + +ifeq ($(GSPLUGIN_DEBUG),yes) + DEBUG:=-g -O0 -Wall -DGSPLUGIN_DEBUG +else + DEBUG:=-g -O0 -Wall +endif + +CFLAGS:= ${DEBUG} \ + -DVERSION=\"${version}\" \ + -I${top_srcdir}/src -I${top_srcdir}/interface -I. \ + -I${stagedir}/include \ + -I${gsoap_prefix}/include \ + -I${globus_prefix}/include/${nothrflavour} \ + -I${globus_prefix}/include/${nothrflavour}/openssl \ + ${COVERAGE_FLAGS} -D_GNU_SOURCE -DDATAGRID_EXTENSION + +LDFLAGS:=${COVERAGE_FLAGS} + +COMPILE:=libtool --mode=compile ${CC} ${CFLAGS} +LINK:=libtool --mode=link ${CC} ${LDFLAGS} +LINKXX:=libtool --mode=link ${CXX} ${LDFLAGS} +INSTALL:=libtool --mode=install install +LINKXX:=libtool --mode=link ${CXX} -rpath ${stagedir}/lib ${LDFLAGS} + +GLOBUS_INC:= -I${globus_prefix}/include/${nothrflavour} +GLOBUS_LIBS:= -L${globus_prefix}/lib \ + -lglobus_common_${nothrflavour} \ + -lglobus_gssapi_gsi_${nothrflavour} \ + +GSOAP_LIBS:= -L${gsoap_prefix}/lib -lgsoap + +EX_LIBS:= ${GLOBUS_LIBS} -L${ares_prefix}/lib -lares + +GSS_OBJS:=lb_gss.o +GSS_LOBJS:=${GSS_OBJS:.o=.lo} +GSS_THROBJS:=${GSS_OBJS:.o=.thr.o} +GSS_THRLOBJS:=${GSS_OBJS:.o=.thr.lo} + +GSS_STATICLIB:=libglite_security_gss_${nothrflavour}.a +GSS_THRSTATICLIB:=libglite_security_gss_${thrflavour}.a +GSS_LTLIB:=libglite_security_gss_${nothrflavour}.la +GSS_THRLTLIB:=libglite_security_gss_${thrflavour}.la + +OBJS:=${GSS_OBJS} glite_gsplugin.o +LOBJS:=${GSS_OBJS:.o=.lo} +THROBJS:=${GSS_OBJS:.o=.thr.o} +THRLOBJS:=${GSS_OBJS:.o=.thr.lo} + +STATICLIB:=libglite_security_gsoap_plugin_${nothrflavour}.a +THRSTATICLIB:=libglite_security_gsoap_plugin_${thrflavour}.a +LTLIB:=libglite_security_gsoap_plugin_${nothrflavour}.la +THRLTLIB:=libglite_security_gsoap_plugin_${thrflavour}.la + +HDRS:=lb_gss.h + +${GSS_STATICLIB}: ${GSS_OBJS} + ar crv $@ ${GSS_OBJS} + ranlib $@ + +${GSS_THRSTATICLIB}: ${GSS_THROBJS} + ar crv $@ ${GSS_THROBJS} + ranlib $@ + +${GSS_LTLIB}: ${GSS_OBJS} + ${LINK} ${version_info} -o $@ ${GSS_LOBJS} + +${GSS_THRLTLIB}: ${GSS_THROBJS} + ${LINK} ${version_info} -o $@ ${GSS_THRLOBJS} + +${STATICLIB}: ${OBJS} + ar crv $@ ${OBJS} + ranlib $@ + +${THRSTATICLIB}: ${THROBJS} + ar crv $@ ${THROBJS} + ranlib $@ + +${LTLIB}: ${OBJS} + ${LINK} ${version_info} -o $@ ${LOBJS} + +${THRLTLIB}: ${THROBJS} + ${LINK} ${version_info} -o $@ ${THRLOBJS} + +default: all + +all compile: ${GSS_STATICLIB} ${GSS_LTLIB} ${GSS_THRSTATICLIB} ${GSS_THRLTLIB} ${STATICLIB} ${LTLIB} ${THRSTATICLIB} ${THRLTLIB} examples + +check: compile check.gss + +check.gss: test_gss + # ./test_gss + echo test_gss not run automatically util we have got some credentials + +test_gss: test_gss.o + ${LINKXX} -o $@ test_gss.o ${GSS_LTLIB} ${TEST_LIBS} ${GLOBUS_LIBS} ${EX_LIBS} + +test_coverage: + -mkdir coverage + cd coverage && $(MAKE) -f ../Makefile top_srcdir=../../ COVERAGE_FLAGS="-fprofile-arcs -ftest-coverage" check + cd coverage && for i in ${OBJS}; do gcov -o .libs/ $$i ; done + + +examples: soap_gen wscalc_clt_ex wscalc_srv_ex + +GSOAP_FPREFIX:= GSOAP_ + +ifeq ($(GSPLUGIN_DEBUG),yes) + WSCALC_CLT_OBJS = wscalc_clt_ex.o ${GSOAP_FPREFIX}C.o ${GSOAP_FPREFIX}Client.o \ + stdsoap2.o + WSCALC_SRV_OBJS = wscalc_srv_ex.o ${GSOAP_FPREFIX}C.o ${GSOAP_FPREFIX}Server.o \ + stdsoap2.o +else + WSCALC_CLT_OBJS = wscalc_clt_ex.o ${GSOAP_FPREFIX}C.o ${GSOAP_FPREFIX}Client.o + WSCALC_SRV_OBJS = wscalc_srv_ex.o ${GSOAP_FPREFIX}C.o ${GSOAP_FPREFIX}Server.o +endif + + +wscalc_clt_ex: ${WSCALC_CLT_OBJS} ${STATICLIB} + ${LINK} -o $@ ${STATICLIB} ${GSOAP_LIBS} ${EX_LIBS} ${WSCALC_CLT_OBJS} + +wscalc_srv_ex: ${WSCALC_SRV_OBJS} ${STATICLIB} + ${LINK} -o $@ ${STATICLIB} ${GSOAP_LIBS} ${EX_LIBS} ${WSCALC_SRV_OBJS} + +${GSOAP_FPREFIX}H.h ${GSOAP_FPREFIX}C.c ${GSOAP_FPREFIX}Server.c ${GSOAP_FPREFIX}Client.c ${GSOAP_FPREFIX}ServerLib.c ${GSOAP_FPREFIX}ClientLib.c soap_gen: calc.h.S + ${gsoap_prefix}/bin/soapcpp2 -c -p ${GSOAP_FPREFIX} ${top_srcdir}/examples/calc.h.S + +wscalc_clt_ex.o: wscalc_clt_ex.c + ${CC} -c ${CFLAGS} ${GLOBUS_INC} -o $@ $< + +stdsoap2.o: ${gsoap_prefix}/devel/stdsoap2.c + ${CC} -c ${CFLAGS} -o $@ $< + +doc: + +stage: compile + $(MAKE) install PREFIX=${stagedir} DOSTAGE=yes + +dist: distsrc distbin + +distsrc: + mkdir -p ${top_srcdir}/${package}-${version} + cd ${top_srcdir} && GLOBIGNORE="${package}-${version}" && cp -Rf * ${package}-${version} + cd ${top_srcdir} && tar -czf ${distdir}/${package}-${version}_src.tar.gz --exclude-from=project/tar_exclude ${package}-${version} + rm -rf ${top_srcdir}/${package}-${version} + +distbin: + $(MAKE) install PREFIX=`pwd`/tmpbuilddir${stagedir} + save_dir=`pwd`; cd tmpbuilddir${stagedir} && tar -czf $$save_dir/${top_srcdir}/${distdir}/${package}-${version}_bin.tar.gz *; cd $$save_dir + rm -rf tmpbuilddir + +install: + -mkdir -p ${PREFIX}/lib + -mkdir -p ${PREFIX}/share/doc/${package}-${version} + -mkdir -p ${PREFIX}/include/glite/security/${package} +# ${INSTALL} -m 644 ${LTLIB} ${THRLTLIB} ${PREFIX}/lib +# ${INSTALL} -m 644 ${GSS_LTLIB} ${GSS_THRLTLIB} ${PREFIX}/lib +# ${INSTALL} -m 644 ${top_srcdir}/LICENSE ${PREFIX}/share/doc/${package}-${version} +# cd ${top_srcdir}/interface && ${INSTALL} -m 644 lb_gss.h glite_gsplugin.h ${PREFIX}/include/glite/security/${package} +# if [ x${DOSTAGE} = xyes ]; then \ +# install -m 644 ${GSS_STATICLIB} ${GSS_THRSTATICLIB} ${STATICLIB} ${THRSTATICLIB} ${PREFIX}/lib; \ +# fi + +clean: + +%.o: %.c + ${COMPILE} ${GLOBUS_INC} -o $@ -c $< + +%.thr.o: %.c + ${COMPILE} ${GLOBUS_THR_INC} -o $@ -c $< + +test_gss.o: %.o: %.cpp + ${CXX} -c ${CFLAGS} ${GLOBUSINC} ${TEST_INC} $< diff --git a/org.glite.security.gsoap-plugin/build.xml b/org.glite.security.gsoap-plugin/build.xml new file mode 100755 index 0000000..485aa55 --- /dev/null +++ b/org.glite.security.gsoap-plugin/build.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.glite.security.gsoap-plugin/examples/calc.h.S b/org.glite.security.gsoap-plugin/examples/calc.h.S new file mode 100644 index 0000000..385e872 --- /dev/null +++ b/org.glite.security.gsoap-plugin/examples/calc.h.S @@ -0,0 +1,13 @@ +//gsoap egeesec schema namespace: urn:calc +// +//gsoap egeesec service name: calc +//gsoap egeesec service port: http://localhost:9999/ +//gsoap egeesec service namespace: urn:calc:wscalc + +//gsoap egeesec service method-style: add rpc +//gsoap egeesec service method-action: add "" +int wscalc__add(double a, double b, double *result); + +//gsoap egeesec service method-style: sub rpc +//gsoap egeesec service method-action: sub "" +int wscalc__sub(double a, double b, double *result); diff --git a/org.glite.security.gsoap-plugin/examples/wscalc_clt_ex.c b/org.glite.security.gsoap-plugin/examples/wscalc_clt_ex.c new file mode 100644 index 0000000..b96827d --- /dev/null +++ b/org.glite.security.gsoap-plugin/examples/wscalc_clt_ex.c @@ -0,0 +1,47 @@ +#include + +#include "GSOAP_H.h" +#include "wscalc.nsmap" + +static const char *server = "http://localhost:9999/"; + +int +main(int argc, char **argv) +{ + struct soap soap; + double a, b, result; + int ret; + + + if (argc < 4) { + fprintf(stderr, "Usage: [add|sub] num num\n"); + exit(1); + } + + soap_init(&soap); + soap_register_plugin(&soap, glite_gsplugin); + + a = strtod(argv[2], NULL); + b = strtod(argv[3], NULL); + switch ( *argv[1] ) { + case 'a': + ret = soap_call_wscalc__add(&soap, server, "", a, b, &result); + break; + case 's': + ret = soap_call_wscalc__sub(&soap, server, "", a, b, &result); + break; + default: + fprintf(stderr, "Unknown command\n"); + exit(2); + } + + if ( ret ) { + fprintf(stderr, "NECO JE V ****\n\n"); + fprintf(stderr, "plugin err: %s", glite_gsplugin_errdesc(&soap)); + soap_print_fault(&soap, stderr); + } + else printf("result = %g\n", result); + + + return 0; +} diff --git a/org.glite.security.gsoap-plugin/examples/wscalc_srv_ex.c b/org.glite.security.gsoap-plugin/examples/wscalc_srv_ex.c new file mode 100644 index 0000000..764605c --- /dev/null +++ b/org.glite.security.gsoap-plugin/examples/wscalc_srv_ex.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include + +#include "GSOAP_H.h" +#include "wscalc.nsmap" + + +static struct option long_options[] = { + { "cert", required_argument, NULL, 'c' }, + { "key", required_argument, NULL, 'k' }, + { "CAdir", required_argument, NULL, 'd' }, + { NULL, 0, NULL, 0 } +}; + +void +usage(const char *me) +{ + fprintf(stderr, + "usage: %s [option]\n" + "\t-c, --cred\t certificate file\n" + "\t-k, --key\t private key file\n" + "\t-d, --CAdir\t trusted certificates directory\n", me); +} + + +int +main(int argc, char **argv) +{ + struct soap soap; + edg_wll_GssStatus gss_code; + gss_cred_id_t cred = GSS_C_NO_CREDENTIAL; + char *name, *msg; + char *cert, *key, *cadir; + int m, s; /* master and slave sockets */ + int opt; + + + cert = key = cadir = NULL; + name = strrchr(argv[0],'/'); + if ( name ) name++; else name = argv[0]; + + while ((opt = getopt_long(argc, argv, "c:k:d:", long_options, NULL)) != EOF) { + switch (opt) { + case 'c': cert = optarg; break; + case 'k': key = optarg; break; + case 'd': cadir = optarg; break; + case '?': + default : usage(name); exit(1); + } + } + + if ( cert || key ) { + char *subject = NULL; + + if ( edg_wll_gss_acquire_cred_gsi(cert, key, + &cred, &subject, &gss_code) ) { + edg_wll_gss_get_error(&gss_code, "Failed to read credential", &msg); + fprintf(stderr, "%s\n", msg); + free(msg); + exit(1); + } + if (subject) { + printf("server running with certificate: %s\n", subject); + free(subject); + } + } + + soap_init(&soap); + + if ( soap_register_plugin(&soap, glite_gsplugin) ) { + fprintf(stderr, "Can't register plugin\n"); + exit(1); + } + + if ( (m = soap_bind(&soap, NULL, 9999, 100)) < 0 ) { + soap_print_fault(&soap, stderr); + exit(1); + } + + while ( 1 ) { + printf("accepting connection\n"); + s = soap_accept(&soap); + if ( s < 0 ) { + fprintf(stderr, "soap_accept() failed!!!\n"); + soap_print_fault(&soap, stderr); + fprintf(stderr, "plugin err: %s", glite_gsplugin_errdesc(&soap)); + break; + } + + printf("serving connection\n"); + if ( soap_serve(&soap) ) { + soap_print_fault(&soap, stderr); + fprintf(stderr, "plugin err: %s", glite_gsplugin_errdesc(&soap)); + } + + /* clean up class instances + */ + soap_destroy(&soap); + /* clean up everything and close socket + */ + soap_end(&soap); + } + soap_done(&soap); // close master socket + + return 0; +} + +int wscalc__add(struct soap *soap, double a, double b, double *result) +{ + *result = a + b; + return SOAP_OK; +} + +int wscalc__sub(struct soap *soap, double a, double b, double *result) +{ + *result = a - b; + return SOAP_OK; +} diff --git a/org.glite.security.gsoap-plugin/interface/glite_gsplugin.h b/org.glite.security.gsoap-plugin/interface/glite_gsplugin.h new file mode 100644 index 0000000..4184c38 --- /dev/null +++ b/org.glite.security.gsoap-plugin/interface/glite_gsplugin.h @@ -0,0 +1,32 @@ +#ifndef __GLITE_GSOAP_PLUGIN_H__ +#define __GLITE_GSOAP_PLUGIN_H__ + +#include + +#include "lb_gss.h" + +#define PLUGIN_ID "GLITE_GSOAP_PLUGIN" + +struct _glite_gsplugin_ctx { + struct timeval timeout; /**< timeout for all netcalls + * if tv_sec ==0 and tv_usec == 0 then + * no timeout is used - every call will + * be considered as a nonblocking */ + + char *error_msg; + + char *key_filename; + char *cert_filename; + + edg_wll_GssConnection *connection; + gss_cred_id_t cred; +}; + +typedef struct _glite_gsplugin_ctx *glite_gsplugin_Context; + +extern int glite_gsplugin_init_context(glite_gsplugin_Context *); + +extern int glite_gsplugin(struct soap *, struct soap_plugin *, void *); +extern char *glite_gsplugin_errdesc(struct soap *); + +#endif diff --git a/org.glite.security.gsoap-plugin/interface/lb_gss.h b/org.glite.security.gsoap-plugin/interface/lb_gss.h new file mode 100644 index 0000000..c0c8a71 --- /dev/null +++ b/org.glite.security.gsoap-plugin/interface/lb_gss.h @@ -0,0 +1,108 @@ +#ifndef __EDG_WORKLOAD_LOGGING_COMMON_LB_GSS_H__ +#define __EDG_WORKLOAD_LOGGING_COMMON_LB_GSS_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + EDG_WLL_GSS_OK = 0, /* no GSS errors */ + EDG_WLL_GSS_ERROR_GSS = -1, /* GSS specific error, call edg_wll_get_gss_error() for details */ + EDG_WLL_GSS_ERROR_TIMEOUT = -2, /* Timeout */ + EDG_WLL_GSS_ERROR_EOF = -3, /* EOF occured */ + EDG_WLL_GSS_ERROR_ERRNO = -4, /* System error. See errno */ + EDG_WLL_GSS_ERROR_HERRNO = -5 /* Resolver error. See h_errno */ +}; + +typedef struct _edg_wll_GssConnection { + gss_ctx_id_t context; + int sock; + char buffer[BUFSIZ]; + size_t bufsize; +} edg_wll_GssConnection; + +typedef struct _edg_wll_GssStatus { + OM_uint32 major_status; + OM_uint32 minor_status; +} edg_wll_GssStatus; + + +int +edg_wll_gss_acquire_cred_gsi(char *cert_file, + char *key_file, + gss_cred_id_t *cred, + char **name, + edg_wll_GssStatus* gss_code); + +int +edg_wll_gss_connect(gss_cred_id_t cred, + char const *hostname, + int port, + struct timeval *timeout, + edg_wll_GssConnection *connection, + edg_wll_GssStatus* gss_code); + +int +edg_wll_gss_accept(gss_cred_id_t cred, + int sock, + struct timeval *timeout, + edg_wll_GssConnection *connection, + edg_wll_GssStatus* gss_code); + +int +edg_wll_gss_read(edg_wll_GssConnection *connection, + void *buf, + size_t bufsize, + struct timeval *timeout, + edg_wll_GssStatus* gss_code); + +int +edg_wll_gss_write(edg_wll_GssConnection *connection, + const void *buf, + size_t bufsize, + struct timeval *timeout, + edg_wll_GssStatus* gss_code); + +int +edg_wll_gss_read_full(edg_wll_GssConnection *connection, + void *buf, + size_t bufsize, + struct timeval *timeout, + size_t *total, + edg_wll_GssStatus* gss_code); + +int +edg_wll_gss_write_full(edg_wll_GssConnection *connection, + const void *buf, + size_t bufsize, + struct timeval *timeout, + size_t *total, + edg_wll_GssStatus* gss_code); + +int +edg_wll_gss_watch_creds(const char * proxy_file, + time_t * proxy_mtime); + +int +edg_wll_gss_get_error(edg_wll_GssStatus* gss_code, + const char *prefix, + char **errmsg); + +int +edg_wll_gss_close(edg_wll_GssConnection *connection, + struct timeval *timeout); + +int +edg_wll_gss_reject(int sock); + +int +edg_wll_gss_oid_equal(const gss_OID a, + const gss_OID b); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/org.glite.security.gsoap-plugin/project/build.properties b/org.glite.security.gsoap-plugin/project/build.properties new file mode 100644 index 0000000..e69de29 diff --git a/org.glite.security.gsoap-plugin/project/configure.properties.xml b/org.glite.security.gsoap-plugin/project/configure.properties.xml new file mode 100644 index 0000000..d5999cc --- /dev/null +++ b/org.glite.security.gsoap-plugin/project/configure.properties.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + +top_srcdir=.. +builddir=build +stagedir=${stage.abs.dir} +distdir=${dist.dir} +globalprefix=${global.prefix} +lbprefix=${subsystem.prefix} +package=${module.package.name} +PREFIX=${install.dir} +version=${module.version} +glite_location=${with.glite.location} +globus_prefix=${with.globus.prefix} +thrflavour=${with.globus.thr.flavor} +nothrflavour=${with.globus.nothr.flavor} +cppunit=${with.cppunit.prefix} +gsoap_prefix=${with.gsoap.prefix} + + + diff --git a/org.glite.security.gsoap-plugin/project/properties.xml b/org.glite.security.gsoap-plugin/project/properties.xml new file mode 100755 index 0000000..f63ddbd --- /dev/null +++ b/org.glite.security.gsoap-plugin/project/properties.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.glite.security.gsoap-plugin/project/tar_exclude b/org.glite.security.gsoap-plugin/project/tar_exclude new file mode 100644 index 0000000..b3133e4 --- /dev/null +++ b/org.glite.security.gsoap-plugin/project/tar_exclude @@ -0,0 +1,10 @@ +tar_exclude +CVS +build.xml +build +build.properties +properties.xml +configure-options.xml +.cvsignore +.project +.cdtproject diff --git a/org.glite.security.gsoap-plugin/project/version.properties b/org.glite.security.gsoap-plugin/project/version.properties new file mode 100644 index 0000000..e22bcd3 --- /dev/null +++ b/org.glite.security.gsoap-plugin/project/version.properties @@ -0,0 +1,3 @@ +module.version=1.0.0 +module.build=0 +module.age=0 diff --git a/org.glite.security.gsoap-plugin/src/glite_gsplugin.c b/org.glite.security.gsoap-plugin/src/glite_gsplugin.c new file mode 100644 index 0000000..431584b --- /dev/null +++ b/org.glite.security.gsoap-plugin/src/glite_gsplugin.c @@ -0,0 +1,368 @@ +#include +#include +#include +#include + +#include "glite_gsplugin.h" + +#ifdef GSPLUGIN_DEBUG +# define pdprintf(s) printf s +#else +# define pdprintf(s) +#endif + +typedef struct _int_plugin_data_t { + glite_gsplugin_Context ctx; /**< data used for connection etc. */ + int def; /**< is the context created by plugin? */ +} int_plugin_data_t; + +static const char plugin_id[] = PLUGIN_ID; + +static void glite_gsplugin_delete(struct soap *, struct soap_plugin *); +static int glite_gsplugin_copy(struct soap *, struct soap_plugin *, struct soap_plugin *); + +static size_t glite_gsplugin_recv(struct soap *, char *, size_t); +static int glite_gsplugin_send(struct soap *, const char *, size_t); +static int glite_gsplugin_connect(struct soap *, const char *, const char *, int); +static int glite_gsplugin_close(struct soap *); +static int glite_gsplugin_accept(struct soap *, int, struct sockaddr *, int *); + + +int +glite_gsplugin_init_context(glite_gsplugin_Context *ctx) +{ + glite_gsplugin_Context out = (glite_gsplugin_Context) malloc(sizeof(*out)); + if (!out) return ENOMEM; + + memset(out, 0, sizeof(*out)); + out->cred = GSS_C_NO_CREDENTIAL; + + /* XXX: some troubles with lb_gss and blocking calls! + */ + out->timeout.tv_sec = 10000; + *ctx = out; + + return 0; +} + +int +glite_gsplugin_free_context(glite_gsplugin_Context ctx) +{ + OM_uint32 ms; + + if ( ctx->cred != GSS_C_NO_CREDENTIAL ) gss_release_cred(&ms, &ctx->cred); + if ( ctx->connection ) { + if ( ctx->connection->context != GSS_C_NO_CONTEXT ) + edg_wll_gss_close(ctx->connection, NULL); + free(ctx->connection); + } + free(ctx->error_msg); + free(ctx->key_filename); + free(ctx->cert_filename); + free(ctx); + + return 0; +} + +int +glite_gsplugin(struct soap *soap, struct soap_plugin *p, void *arg) +{ + int_plugin_data_t *pdata = malloc(sizeof(int_plugin_data_t)); + + pdprintf(("GSLITE_GSPLUGIN: initializing gSOAP plugin\n")); + if ( !pdata ) return ENOMEM; + if ( arg ) { + pdprintf(("GSLITE_GSPLUGIN: Context is given\n")); + pdata->ctx = arg; + pdata->def = 0; + } + else { + edg_wll_GssStatus gss_code; + char *subject = NULL; + + pdprintf(("GSLITE_GSPLUGIN: Creating default context\n")); + if ( glite_gsplugin_init_context((glite_gsplugin_Context*)&(pdata->ctx)) ) { + free(pdata); + return ENOMEM; + } + if ( edg_wll_gss_acquire_cred_gsi(NULL, NULL, &pdata->ctx->cred, &subject, &gss_code) ) { + /* XXX: Let user know, that cred. load failed. Somehow... + */ + glite_gsplugin_free_context(pdata->ctx); + return EINVAL; + } + pdprintf(("GSLITE_GSPLUGIN: server running with certificate: %s\n", subject)); + free(subject); + } + + p->id = plugin_id; + p->data = pdata; + p->fdelete = glite_gsplugin_delete; + p->fcopy = glite_gsplugin_copy; + + soap->fconnect = glite_gsplugin_connect; + soap->fclose = glite_gsplugin_close; + soap->faccept = glite_gsplugin_accept; + soap->fsend = glite_gsplugin_send; + soap->frecv = glite_gsplugin_recv; + + + return SOAP_OK; +} + + +char *glite_gsplugin_errdesc(struct soap *soap) +{ + glite_gsplugin_Context ctx; + + ctx = ((int_plugin_data_t *)soap_lookup_plugin(soap, plugin_id))->ctx; + if ( ctx ) return ctx->error_msg; + + return NULL; +} + + + +static int +glite_gsplugin_copy(struct soap *soap, struct soap_plugin *dst, struct soap_plugin *src) +{ + pdprintf(("GSLITE_GSPLUGIN: glite_gsplugin_copy()\n")); + /* Should be the copy code here? + */ + return SOAP_OK; +} + +static void +glite_gsplugin_delete(struct soap *soap, struct soap_plugin *p) +{ + int_plugin_data_t *d = (int_plugin_data_t *)soap_lookup_plugin(soap, plugin_id); + + pdprintf(("GSLITE_GSPLUGIN: glite_gsplugin_delete()\n")); + if ( d->def ) { + OM_uint32 ms; + + glite_gsplugin_close(soap); + if (d->ctx->cred != GSS_C_NO_CREDENTIAL) gss_release_cred(&ms, &d->ctx->cred); + free(d->ctx->error_msg); + } + free(d); +} + + +static int +glite_gsplugin_connect( + struct soap *soap, + const char *endpoint, + const char *host, + int port) +{ + glite_gsplugin_Context ctx; + edg_wll_GssStatus gss_stat; + int ret; + + + pdprintf(("GSLITE_GSPLUGIN: glite_gsplugin_connect()\n")); + ctx = ((int_plugin_data_t *)soap_lookup_plugin(soap, plugin_id))->ctx; + + if ( ctx->cred == GSS_C_NO_CREDENTIAL ) { + pdprintf(("GSLITE_GSPLUGIN: loading credentials\n")); + ret = edg_wll_gss_acquire_cred_gsi(ctx->cert_filename, ctx->key_filename, + &ctx->cred, NULL, &gss_stat); + if ( ret ) { + edg_wll_gss_get_error(&gss_stat, "failed to load GSI credentials", + &ctx->error_msg); + goto err; + } + } + + if ( !(ctx->connection = malloc(sizeof(*ctx->connection))) ) return errno; + ret = edg_wll_gss_connect(ctx->cred, + host, port, + (ctx->timeout.tv_usec || ctx->timeout.tv_sec)? &ctx->timeout: NULL, + ctx->connection, &gss_stat); + if ( ret ) { + edg_wll_gss_get_error(&gss_stat, "edg_wll_gss_connect()", &ctx->error_msg); + goto err; + } + + /* XXX: co s tim??? + * + soap->socket = 2; + */ + + return SOAP_OK; + +err: + pdprintf(("GSLITE_GSPLUGIN: glite_gsplugin_connect() error!\n")); + switch ( ret ) { + case EDG_WLL_GSS_ERROR_HERRNO: + case EDG_WLL_GSS_ERROR_ERRNO: return errno; + case EDG_WLL_GSS_ERROR_EOF: return ECONNREFUSED; + case EDG_WLL_GSS_ERROR_TIMEOUT: return ETIMEDOUT; + } + + return ret; +} + +/** It is called in soap_closesocket() + * + * return like errno value + */ +static int +glite_gsplugin_close(struct soap *soap) +{ + glite_gsplugin_Context ctx; + int ret = SOAP_OK; + + + pdprintf(("GSLITE_GSPLUGIN: glite_gsplugin_close()\n")); + ctx = ((int_plugin_data_t *)soap_lookup_plugin(soap, plugin_id))->ctx; + if ( ctx->connection ) { + if ( ctx->connection->context != GSS_C_NO_CONTEXT) { + pdprintf(("GSLITE_GSPLUGIN: closing gss connection\n")); + ret = edg_wll_gss_close(ctx->connection, + (ctx->timeout.tv_usec || ctx->timeout.tv_sec)? &ctx->timeout: NULL); + } + free(ctx->connection); + ctx->connection = NULL; + } + + return ret; +} + + +static int +glite_gsplugin_accept(struct soap *soap, int s, struct sockaddr *a, int *n) +{ + glite_gsplugin_Context ctx; + edg_wll_GssStatus gss_code; + int conn; + + + pdprintf(("GSLITE_GSPLUGIN: glite_gsplugin_accept()\n")); + ctx = ((int_plugin_data_t *)soap_lookup_plugin(soap, plugin_id))->ctx; + if ( (conn = accept(s, (struct sockaddr *)&a, n)) < 0 ) return conn; + if ( !ctx->connection + && !(ctx->connection = malloc(sizeof(*ctx->connection))) ) return -1; + if ( edg_wll_gss_accept(ctx->cred, conn, &ctx->timeout, ctx->connection, &gss_code)) { + pdprintf(("GSLITE_GSPLUGIN: Client authentication failed, closing.\n")); + edg_wll_gss_get_error(&gss_code, "Client authentication failed", &ctx->error_msg); + return -1; + } + + return conn; +} + +static size_t +glite_gsplugin_recv(struct soap *soap, char *buf, size_t bufsz) +{ + glite_gsplugin_Context ctx; + edg_wll_GssStatus gss_code; + int len; + + + ctx = ((int_plugin_data_t *)soap_lookup_plugin(soap, plugin_id))->ctx; + if ( ctx->error_msg ) { free(ctx->error_msg); ctx->error_msg = NULL; } + + if ( ctx->connection->context == GSS_C_NO_CONTEXT ) { + soap->errnum = ENOTCONN; + /* XXX glite_gsplugin_send() returns SOAP_EOF on errors */ + return 0; + } + + len = edg_wll_gss_read(ctx->connection, buf, bufsz, + (ctx->timeout.tv_usec || ctx->timeout.tv_sec)? &ctx->timeout: NULL, + &gss_code); + + switch ( len ) { + case EDG_WLL_GSS_OK: + break; + + case EDG_WLL_GSS_ERROR_GSS: + edg_wll_gss_get_error(&gss_code, "receving WS request", + &ctx->error_msg); + soap->errnum = ENOTCONN; + return 0; + + case EDG_WLL_GSS_ERROR_ERRNO: + ctx->error_msg = strdup("edg_wll_gss_read()"); + soap->errnum = errno; + return 0; + + case EDG_WLL_GSS_ERROR_TIMEOUT: + soap->errnum = ETIMEDOUT; + return 0; + + case EDG_WLL_GSS_ERROR_EOF: + soap->errnum = ENOTCONN; + return 0; + + /* default: fallthrough */ + } + + pdprintf(("\nWS received:\n%s\n\n", buf)); + return len; +} + +static int +glite_gsplugin_send(struct soap *soap, const char *buf, size_t bufsz) +{ + glite_gsplugin_Context ctx; + edg_wll_GssStatus gss_code; + struct sigaction sa, osa; + size_t total = 0; + int ret; + + + pdprintf(("GSLITE_GSPLUGIN: glite_gsplugin_send():\n%s\n\n", buf)); + ctx = ((int_plugin_data_t *)soap_lookup_plugin(soap, plugin_id))->ctx; + /* XXX: check whether ctx is initialized + * i.e. ctx->connection != NULL + */ + if ( ctx->error_msg ) { free(ctx->error_msg); ctx->error_msg = NULL; } + if ( ctx->connection->context == GSS_C_NO_CONTEXT ) { + soap->errnum = ENOTCONN; + return SOAP_EOF; + } + + memset(&sa, 0, sizeof(sa)); + assert(sa.sa_handler == NULL); + sa.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &sa, &osa); + + ret = edg_wll_gss_write_full(ctx->connection, + (void*)buf, bufsz, &ctx->timeout, &total, &gss_code); + + sigaction(SIGPIPE, &osa, NULL); + + switch ( ret ) { + case EDG_WLL_GSS_OK: + pdprintf(("\nWS sent:\n%s\n\n", buf)); + break; + + case EDG_WLL_GSS_ERROR_TIMEOUT: + ctx->error_msg = strdup("glite_gsplugin_send()"); + soap->errnum = ETIMEDOUT; + return SOAP_EOF; + + case EDG_WLL_GSS_ERROR_ERRNO: + if ( errno == EPIPE ) { + ctx->error_msg = strdup("glite_gsplugin_send()"); + soap->errnum = ENOTCONN; + } + else { + ctx->error_msg = strdup("glite_gsplugin_send()"); + soap->errnum = errno; + } + return SOAP_EOF; + + case EDG_WLL_GSS_ERROR_GSS: + case EDG_WLL_GSS_ERROR_EOF: + default: + ctx->error_msg = strdup("glite_gsplugin_send()"); + soap->errnum = ENOTCONN; + return SOAP_EOF; + } + + return SOAP_OK; +} diff --git a/org.glite.security.gsoap-plugin/src/lb_gss.c b/org.glite.security.gsoap-plugin/src/lb_gss.c new file mode 100644 index 0000000..a9908a3 --- /dev/null +++ b/org.glite.security.gsoap-plugin/src/lb_gss.c @@ -0,0 +1,982 @@ +/* /cvs/jra1mw/org.glite.lb.common/src/lb_gss.c,v 1.3 2004/10/21 10:20:12 dkouril*/ +#ident "$Header$" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lb_gss.h" + +#define tv_sub(a,b) {\ + (a).tv_usec -= (b).tv_usec;\ + (a).tv_sec -= (b).tv_sec;\ + if ((a).tv_usec < 0) {\ + (a).tv_sec--;\ + (a).tv_usec += 1000000;\ + }\ +} + +struct asyn_result { + struct hostent *ent; + int err; +}; + +static int decrement_timeout(struct timeval *timeout, struct timeval before, struct timeval after) +{ + (*timeout).tv_sec = (*timeout).tv_sec - (after.tv_sec - before.tv_sec); + (*timeout).tv_usec = (*timeout).tv_usec - (after.tv_usec - before.tv_usec); + while ( (*timeout).tv_usec < 0) { + (*timeout).tv_sec--; + (*timeout).tv_usec += 1000000; + } + if ( ((*timeout).tv_sec < 0) || (((*timeout).tv_sec == 0) && ((*timeout).tv_usec == 0)) ) return(1); + else return(0); +} + +/* ares callback handler for ares_gethostbyname() */ +static void callback_handler(void *arg, int status, struct hostent *h) { + struct asyn_result *arp = (struct asyn_result *) arg; + + switch (status) { + case ARES_SUCCESS: + if (h && h->h_addr_list[0]) { + arp->ent->h_addr_list = + (char **) malloc(2 * sizeof(char *)); + if (arp->ent->h_addr_list == NULL) { + arp->err = NETDB_INTERNAL; + break; + } + arp->ent->h_addr_list[0] = + malloc(sizeof(struct in_addr)); + if (arp->ent->h_addr_list[0] == NULL) { + free(arp->ent->h_addr_list); + arp->err = NETDB_INTERNAL; + break; + } + memcpy(arp->ent->h_addr_list[0], h->h_addr_list[0], + sizeof(struct in_addr)); + arp->ent->h_addr_list[1] = NULL; + arp->err = NETDB_SUCCESS; + } else { + arp->err = NO_DATA; + } + break; + case ARES_EBADNAME: + case ARES_ENOTFOUND: + arp->err = HOST_NOT_FOUND; + break; + case ARES_ENOTIMP: + arp->err = NO_RECOVERY; + break; + case ARES_ENOMEM: + case ARES_EDESTRUCTION: + default: + arp->err = NETDB_INTERNAL; + break; + } +} + +static void free_hostent(struct hostent *h){ + int i; + + if (h) { + if (h->h_name) free(h->h_name); + if (h->h_aliases) { + for (i=0; h->h_aliases[i]; i++) free(h->h_aliases[i]); + free(h->h_aliases); + } + if (h->h_addr_list) { + for (i=0; h->h_addr_list[i]; i++) free(h->h_addr_list[i]); + free(h->h_addr_list); + } + free(h); + } +} + +static int asyn_gethostbyname(char **addrOut, char const *name, struct timeval *timeout) { + struct asyn_result ar; + ares_channel channel; + int nfds; + fd_set readers, writers; + struct timeval tv, *tvp; + struct timeval start_time,check_time; + +/* start timer */ + gettimeofday(&start_time,0); + +/* ares init */ + if ( ares_init(&channel) != ARES_SUCCESS ) return(NETDB_INTERNAL); + ar.ent = (struct hostent *) calloc (sizeof(*ar.ent),1); + +/* query DNS server asynchronously */ + ares_gethostbyname(channel, name, AF_INET, callback_handler, + (void *) &ar); + +/* wait for result */ + while (1) { + FD_ZERO(&readers); + FD_ZERO(&writers); + nfds = ares_fds(channel, &readers, &writers); + if (nfds == 0) + break; + + gettimeofday(&check_time,0); + if (decrement_timeout(timeout, start_time, check_time)) { + ares_destroy(channel); + free_hostent(ar.ent); + return(TRY_AGAIN); + } + start_time = check_time; + + tvp = ares_timeout(channel, timeout, &tv); + + switch ( select(nfds, &readers, &writers, NULL, tvp) ) { + case -1: if (errno != EINTR) { + ares_destroy(channel); + free_hostent(ar.ent); + return NETDB_INTERNAL; + } else + continue; + case 0: + FD_ZERO(&readers); + FD_ZERO(&writers); + /* fallthrough */ + default: ares_process(channel, &readers, &writers); + } + } + + ares_destroy(channel); + + if (ar.err == NETDB_SUCCESS) { + *addrOut = malloc(sizeof(struct in_addr)); + memcpy(*addrOut,ar.ent->h_addr_list[0], sizeof(struct in_addr)); + free_hostent(ar.ent); + } + return(ar.err); +} + +static int +do_connect(int *s, char const *hostname, int port, struct timeval *timeout) +{ + int sock; + struct timeval before,after,to; + struct sockaddr_in a; + int sock_err; + socklen_t err_len; + char *addr; + int h_errno; + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) return EDG_WLL_GSS_ERROR_ERRNO; + + if (timeout) { + int flags = fcntl(sock, F_GETFL, 0); + if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) + return EDG_WLL_GSS_ERROR_ERRNO; + gettimeofday(&before,NULL); + } + + if (timeout) { + switch (h_errno = asyn_gethostbyname(&addr, hostname, timeout)) { + case NETDB_SUCCESS: + memset(&a,0,sizeof a); + a.sin_family = AF_INET; + memcpy(&a.sin_addr.s_addr,addr,sizeof a.sin_addr.s_addr); + a.sin_port = htons(port); + free(addr); + break; + case TRY_AGAIN: + close(sock); + return EDG_WLL_GSS_ERROR_TIMEOUT; + case NETDB_INTERNAL: + /* fall through */ + default: + close(sock); + /* h_errno may be thread safe with Linux pthread libs, + * but such an assumption is not portable + */ + errno = h_errno; + return EDG_WLL_GSS_ERROR_HERRNO; + } + } else { + struct hostent *hp; + + hp = gethostbyname(hostname); + if (hp == NULL) { + close(sock); + errno = h_errno; + return EDG_WLL_GSS_ERROR_HERRNO; + } + + memset(&a,0,sizeof a); + a.sin_family = AF_INET; + memcpy(&a.sin_addr.s_addr, hp->h_addr_list[0], sizeof(a.sin_addr.s_addr)); + a.sin_port = htons(port); + } + + if (connect(sock,(struct sockaddr *) &a,sizeof a) < 0) { + if (timeout && errno == EINPROGRESS) { + fd_set fds; + FD_ZERO(&fds); + FD_SET(sock,&fds); + memcpy(&to,timeout,sizeof to); + gettimeofday(&before,NULL); + switch (select(sock+1,NULL,&fds,NULL,&to)) { + case -1: close(sock); + return EDG_WLL_GSS_ERROR_ERRNO; + case 0: close(sock); + return EDG_WLL_GSS_ERROR_TIMEOUT; + } + gettimeofday(&after,NULL); + tv_sub(after,before); + tv_sub(*timeout,after); + + err_len = sizeof sock_err; + if (getsockopt(sock,SOL_SOCKET,SO_ERROR,&sock_err,&err_len)) { + close(sock); + return EDG_WLL_GSS_ERROR_ERRNO; + } + if (sock_err) { + close(sock); + errno = sock_err; + return EDG_WLL_GSS_ERROR_ERRNO; + } + } + else { + close(sock); + return EDG_WLL_GSS_ERROR_ERRNO; + } + } + + *s = sock; + return 0; +} + +static int +send_token(int sock, void *token, size_t token_length, struct timeval *to) +{ + size_t num_written = 0; + ssize_t count; + fd_set fds; + struct timeval timeout,before,after; + int ret; + + if (to) { + memcpy(&timeout,to,sizeof(timeout)); + gettimeofday(&before,NULL); + } + + + ret = 0; + while(num_written < token_length) { + FD_ZERO(&fds); + FD_SET(sock,&fds); + switch (select(sock+1, NULL, &fds, NULL, to ? &timeout : NULL)) { + case 0: ret = EDG_WLL_GSS_ERROR_TIMEOUT; + goto end; + break; + case -1: ret = EDG_WLL_GSS_ERROR_ERRNO; + goto end; + break; + } + + count = write(sock, ((char *)token) + num_written, + token_length - num_written); + if(count < 0) { + if(errno == EINTR) + continue; + else { + ret = EDG_WLL_GSS_ERROR_ERRNO; + goto end; + } + } + num_written += count; + } + +end: + if (to) { + gettimeofday(&after,NULL); + tv_sub(after,before); + tv_sub(*to,after); + if (to->tv_sec < 0) { + to->tv_sec = 0; + to->tv_usec = 0; + } + } + + return ret; +} + +static int +recv_token(int sock, void **token, size_t *token_length, struct timeval *to) +{ + ssize_t count; + char buf[4098]; + char *t = NULL; + char *tmp; + size_t tl = 0; + fd_set fds; + struct timeval timeout,before,after; + int ret; + + if (to) { + memcpy(&timeout,to,sizeof(timeout)); + gettimeofday(&before,NULL); + } + + ret = 0; + do { + FD_ZERO(&fds); + FD_SET(sock,&fds); + switch (select(sock+1, &fds, NULL, NULL, to ? &timeout : NULL)) { + case 0: + ret = EDG_WLL_GSS_ERROR_TIMEOUT; + goto end; + break; + case -1: + ret = EDG_WLL_GSS_ERROR_ERRNO; + goto end; + break; + } + + count = read(sock, buf, sizeof(buf)); + if (count < 0) { + if (errno == EINTR) + continue; + else { + ret = EDG_WLL_GSS_ERROR_ERRNO; + goto end; + } + } + if (count == 0 && tl == 0 && errno == 0) + return EDG_WLL_GSS_ERROR_EOF; + tmp=realloc(t, tl + count); + if (tmp == NULL) { + errno = ENOMEM; + return EDG_WLL_GSS_ERROR_ERRNO; + } + t = tmp; + memcpy(t + tl, buf, count); + tl += count; + } while (count == sizeof(buf)); + +end: + if (to) { + gettimeofday(&after,NULL); + tv_sub(after,before); + tv_sub(*to,after); + if (to->tv_sec < 0) { + to->tv_sec = 0; + to->tv_usec = 0; + } + } + + if (ret == 0) { + *token = t; + *token_length = tl; + } else + free(t); + + return ret; +} + +static int +create_proxy(char *cert_file, char *key_file, char **proxy_file) +{ + char buf[4096]; + int in, out; + char *name = NULL; + int ret, len; + + *proxy_file = NULL; + + asprintf(&name, "%s/%d.lb.XXXXXX", P_tmpdir, getpid()); + + out = mkstemp(name); + if (out < 0) + return EDG_WLL_GSS_ERROR_ERRNO; + + in = open(cert_file, O_RDONLY); + if (in < 0) { + ret = EDG_WLL_GSS_ERROR_ERRNO; + goto end; + } + while ((ret = read(in, buf, sizeof(buf))) > 0) { + len = write(out, buf, ret); + if (len != ret) { + ret = -1; + break; + } + } + close(in); + if (ret < 0) { + ret = EDG_WLL_GSS_ERROR_ERRNO; + goto end; + } + + in = open(key_file, O_RDONLY); + if (in < 0) { + ret = EDG_WLL_GSS_ERROR_ERRNO; + goto end; + } + while ((ret = read(in, buf, sizeof(buf))) > 0) { + len = write(out, buf, ret); + if (len != ret) { + ret = -1; + break; + } + } + close(in); + if (ret < 0) { + ret = EDG_WLL_GSS_ERROR_ERRNO; + goto end; + } + + ret = 0; + *proxy_file = name; + +end: + close(out); + if (ret) { + unlink(name); + free(name); + } + + return ret; +} + +static int +destroy_proxy(char *proxy_file) +{ + /* XXX we should erase the contents safely (i.e. overwrite with 0's) */ + unlink(proxy_file); + return 0; +} + +int +edg_wll_gss_acquire_cred_gsi(char *cert_file, char *key_file, gss_cred_id_t *cred, + char **name, edg_wll_GssStatus* gss_code) +{ + OM_uint32 major_status = 0, minor_status, minor_status2; + gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL; + gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER; + gss_name_t gss_name = GSS_C_NO_NAME; + OM_uint32 lifetime; + char *proxy_file = NULL; + int ret; + + if ((cert_file == NULL && key_file != NULL) || + (cert_file != NULL && key_file == NULL)) + return EINVAL; + + if (cert_file == NULL) { + major_status = gss_acquire_cred(&minor_status, GSS_C_NO_NAME, 0, + GSS_C_NO_OID_SET, GSS_C_BOTH, + &gss_cred, NULL, NULL); + if (GSS_ERROR(major_status)) { + ret = EDG_WLL_GSS_ERROR_GSS; + goto end; + } + } else { + proxy_file = cert_file; + if (strcmp(cert_file, key_file) != 0 && + (ret = create_proxy(cert_file, key_file, &proxy_file))) { + proxy_file = NULL; + goto end; + } + + asprintf((char**)&buffer.value, "X509_USER_PROXY=%s", proxy_file); + if (buffer.value == NULL) { + errno = ENOMEM; + ret = EDG_WLL_GSS_ERROR_ERRNO; + goto end; + } + buffer.length = strlen(proxy_file); + + major_status = gss_import_cred(&minor_status, &gss_cred, GSS_C_NO_OID, 1, + &buffer, 0, NULL); + free(buffer.value); + if (GSS_ERROR(major_status)) { + ret = EDG_WLL_GSS_ERROR_GSS; + goto end; + } + } + + /* gss_import_cred() doesn't check validity of credential loaded, so let's + * verify it now */ + major_status = gss_inquire_cred(&minor_status, gss_cred, &gss_name, + &lifetime, NULL, NULL); + if (GSS_ERROR(major_status)) { + ret = EDG_WLL_GSS_ERROR_GSS; + goto end; + } + + /* Must cast to time_t since OM_uint32 is unsinged and hence we couldn't + * detect negative values. */ + if ((time_t) lifetime <= 0) { + major_status = GSS_S_CREDENTIALS_EXPIRED; + minor_status = 0; /* XXX */ + ret = EDG_WLL_GSS_ERROR_GSS; + goto end; + } + + if (name) { + major_status = gss_display_name(&minor_status, gss_name, &buffer, NULL); + if (GSS_ERROR(major_status)) { + ret = EDG_WLL_GSS_ERROR_GSS; + goto end; + } + *name = buffer.value; + memset(&buffer, 0, sizeof(buffer)); + } + + *cred = gss_cred; + gss_cred = GSS_C_NO_CREDENTIAL; + ret = 0; + +end: + if (cert_file && key_file && proxy_file && strcmp(cert_file, key_file) != 0) { + destroy_proxy(proxy_file); + free(proxy_file); + } + + if (gss_name != GSS_C_NO_NAME) + gss_release_name(&minor_status2, &gss_name); + + if (gss_cred != GSS_C_NO_CREDENTIAL) + gss_release_cred(&minor_status2, &gss_cred); + + if (GSS_ERROR(major_status)) { + if (gss_code) { + gss_code->major_status = major_status; + gss_code->minor_status = minor_status; + } + ret = EDG_WLL_GSS_ERROR_GSS; + } + + return ret; +} + +int +edg_wll_gss_connect(gss_cred_id_t cred, char const *hostname, int port, + struct timeval *timeout, edg_wll_GssConnection *connection, + edg_wll_GssStatus* gss_code) +{ + int sock, ret; + OM_uint32 maj_stat, min_stat, min_stat2, req_flags; + int context_established = 0; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + gss_name_t server = GSS_C_NO_NAME; + gss_ctx_id_t context = GSS_C_NO_CONTEXT; + char *servername = NULL; + + maj_stat = min_stat = min_stat2 = req_flags = 0; + + /* GSI specific */ + req_flags = GSS_C_GLOBUS_SSL_COMPATIBLE; + + ret = do_connect(&sock, hostname, port, timeout); + if (ret) + return ret; + + /* XXX find appropriate fqdn */ + asprintf (&servername, "host@%s", hostname); + if (servername == NULL) { + errno = ENOMEM; + ret = EDG_WLL_GSS_ERROR_ERRNO; + goto end; + } + input_token.value = servername; + input_token.length = strlen(servername) + 1; + + maj_stat = gss_import_name(&min_stat, &input_token, + GSS_C_NT_HOSTBASED_SERVICE, &server); + if (GSS_ERROR(maj_stat)) { + ret = EDG_WLL_GSS_ERROR_GSS; + goto end; + } + + free(servername); + memset(&input_token, 0, sizeof(input_token)); + + /* XXX if cred == GSS_C_NO_CREDENTIAL set the ANONYMOUS flag */ + + /* XXX prepsat na do {} while (maj_stat == CONT) a osetrit chyby*/ + while (!context_established) { + /* XXX verify ret_flags match what was requested */ + maj_stat = gss_init_sec_context(&min_stat, cred, &context, + GSS_C_NO_NAME, GSS_C_NO_OID, + req_flags | GSS_C_MUTUAL_FLAG, + 0, GSS_C_NO_CHANNEL_BINDINGS, + &input_token, NULL, &output_token, + NULL, NULL); + if (input_token.length > 0) { + free(input_token.value); + input_token.length = 0; + } + + if (output_token.length != 0) { + ret = send_token(sock, output_token.value, output_token.length, timeout); + gss_release_buffer(&min_stat2, &output_token); + if (ret) + goto end; + } + + if (GSS_ERROR(maj_stat)) { + if (context != GSS_C_NO_CONTEXT) { + /* XXX send closing token to the friend */ + gss_delete_sec_context(&min_stat2, &context, GSS_C_NO_BUFFER); + context = GSS_C_NO_CONTEXT; + } + ret = EDG_WLL_GSS_ERROR_GSS; + goto end; + } + + if(maj_stat & GSS_S_CONTINUE_NEEDED) { + ret = recv_token(sock, &input_token.value, &input_token.length, timeout); + if (ret) + goto end; + } else + context_established = 1; + } + + /* XXX check ret_flags matches to what was requested */ + + memset(connection, 0, sizeof(*connection)); + connection->sock = sock; + connection->context = context; + servername = NULL; + ret = 0; + +end: + if (ret == EDG_WLL_GSS_ERROR_GSS && gss_code) { + gss_code->major_status = maj_stat; + gss_code->minor_status = min_stat; + } + if (server != GSS_C_NO_NAME) + gss_release_name(&min_stat2, &server); + if (servername == NULL) + free(servername); + if (ret) + close(sock); + + return ret; +} + +int +edg_wll_gss_accept(gss_cred_id_t cred, int sock, struct timeval *timeout, + edg_wll_GssConnection *connection, edg_wll_GssStatus* gss_code) +{ + OM_uint32 maj_stat, min_stat, min_stat2; + OM_uint32 ret_flags = 0; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + gss_name_t client_name = GSS_C_NO_NAME; + gss_ctx_id_t context = GSS_C_NO_CONTEXT; + int ret; + + maj_stat = min_stat = min_stat2 = 0; + + /* GSI specific */ + ret_flags = GSS_C_GLOBUS_SSL_COMPATIBLE; + + do { + ret = recv_token(sock, &input_token.value, &input_token.length, timeout); + if (ret) + goto end; + + maj_stat = gss_accept_sec_context(&min_stat, &context, + cred, &input_token, + GSS_C_NO_CHANNEL_BINDINGS, + &client_name, NULL, &output_token, + &ret_flags, NULL, NULL); + if (input_token.length > 0) { + free(input_token.value); + input_token.length = 0; + } + + if (output_token.length) { + ret = send_token(sock, output_token.value, output_token.length, timeout); + gss_release_buffer(&min_stat2, &output_token); + if (ret) + goto end; + } + } while(maj_stat & GSS_S_CONTINUE_NEEDED); + + if (GSS_ERROR(maj_stat)) { + if (context != GSS_C_NO_CONTEXT) { + /* XXX send closing token to the friend */ + gss_delete_sec_context(&min_stat2, &context, GSS_C_NO_BUFFER); + context = GSS_C_NO_CONTEXT; + } + ret = EDG_WLL_GSS_ERROR_GSS; + goto end; + } + + maj_stat = gss_display_name(&min_stat, client_name, &output_token, NULL); + if (GSS_ERROR(maj_stat)) { + /* XXX close context ??? */ + ret = EDG_WLL_GSS_ERROR_GSS; + goto end; + } + + memset(connection, 0, sizeof(*connection)); + connection->sock = sock; + connection->context = context; + memset(&output_token, 0, sizeof(output_token.value)); + ret = 0; + +end: + if (ret == EDG_WLL_GSS_ERROR_GSS && gss_code) { + gss_code->major_status = maj_stat; + gss_code->minor_status = min_stat; + } + if (client_name != GSS_C_NO_NAME) + gss_release_name(&min_stat2, &client_name); + + return ret; +} + +int +edg_wll_gss_write(edg_wll_GssConnection *connection, const void *buf, size_t bufsize, + struct timeval *timeout, edg_wll_GssStatus* gss_code) +{ + OM_uint32 maj_stat, min_stat; + gss_buffer_desc input_token; + gss_buffer_desc output_token; + int ret; + + input_token.value = (void*)buf; + input_token.length = bufsize; + + maj_stat = gss_wrap (&min_stat, connection->context, 0, GSS_C_QOP_DEFAULT, + &input_token, NULL, &output_token); + if (GSS_ERROR(maj_stat)) { + if (gss_code) { + gss_code->minor_status = min_stat; + gss_code->major_status = maj_stat; + } + + return EDG_WLL_GSS_ERROR_GSS; + } + + ret = send_token(connection->sock, output_token.value, output_token.length, + timeout); + gss_release_buffer(&min_stat, &output_token); + + return ret; +} + + +int +edg_wll_gss_read(edg_wll_GssConnection *connection, void *buf, size_t bufsize, + struct timeval *timeout, edg_wll_GssStatus* gss_code) +{ + OM_uint32 maj_stat, min_stat; + gss_buffer_desc input_token; + gss_buffer_desc output_token; + int ret, i; + + if (connection->bufsize > 0) { + size_t len; + + len = (connection->bufsize < bufsize) ? connection->bufsize : bufsize; + memcpy(buf, connection->buffer, len); + connection->bufsize -= len; + if (connection->bufsize > 0) { + for (i = 0; i < sizeof(connection->buffer) - len; i++) + connection->buffer[i] = connection->buffer[i+len]; + } + + return len; + } + + do { + ret = recv_token(connection->sock, &input_token.value, &input_token.length, + timeout); + if (ret) + /* XXX cleanup */ + return ret; + + maj_stat = gss_unwrap(&min_stat, connection->context, &input_token, + &output_token, NULL, NULL); + if (GSS_ERROR(maj_stat)) { + /* XXX cleanup */ + return EDG_WLL_GSS_ERROR_GSS; + } + } while (maj_stat == 0 && output_token.length == 0 && output_token.value == NULL); + + if (output_token.length > bufsize) { + if (output_token.length - bufsize > sizeof(connection->buffer)) + return EINVAL; + connection->bufsize = output_token.length - bufsize; + memcpy(connection->buffer, output_token.value + bufsize, connection->bufsize); + output_token.length = bufsize; + } + memcpy(buf, output_token.value, output_token.length); + + return output_token.length; +} + +int +edg_wll_gss_read_full(edg_wll_GssConnection *connection, void *buf, + size_t bufsize, struct timeval *timeout, size_t *total, + edg_wll_GssStatus* gss_code) +{ + int len,i; + *total = 0; + + if (connection->bufsize > 0) { + size_t len; + + + len = (connection->bufsize < bufsize) ? connection->bufsize : bufsize; + memcpy(buf, connection->buffer, len); + connection->bufsize -= len; + if (connection->bufsize > 0) { + for (i = 0; i < sizeof(connection->buffer) - len; i++) + connection->buffer[i] = connection->buffer[i+len]; + } + *total = len; + } + + while (*total < bufsize) { + len = edg_wll_gss_read(connection, buf+*total, bufsize-*total, + timeout, gss_code); + if (len < 0) return len; + *total += len; + } + + return 0; +} + +int +edg_wll_gss_write_full(edg_wll_GssConnection *connection, const void *buf, + size_t bufsize, struct timeval *timeout, size_t *total, + edg_wll_GssStatus* gss_code) +{ + return edg_wll_gss_write(connection, buf, bufsize, timeout, gss_code); +} + +/* XXX: I'm afraid the contents of stuct stat is somewhat OS dependent */ +int +edg_wll_gss_watch_creds(const char *proxy_file, time_t *proxy_mtime) +{ + struct stat pstat; + int reload = 0; + + if (!proxy_file) return 0; + if (stat(proxy_file,&pstat)) return -1; + + if (!*proxy_mtime) *proxy_mtime = pstat.st_mtime; + + if (*proxy_mtime != pstat.st_mtime) { + *proxy_mtime = pstat.st_mtime; + reload = 1; + } + + return reload; +} + +int +edg_wll_gss_close(edg_wll_GssConnection *con, struct timeval *timeout) +{ + OM_uint32 min_stat; + + /* XXX if timeout is NULL use value of 120 secs */ + + if (con->context != GSS_C_NO_CONTEXT) { + gss_delete_sec_context(&min_stat, &con->context, GSS_C_NO_BUFFER); + /* XXX send the buffer (if any) to the peer. GSSAPI specs doesn't + * recommend sending it, though */ + + /* XXX can socket be open even if context == GSS_C_NO_CONTEXT) ? */ + /* XXX ensure that edg_wll_GssConnection is created with sock set to -1 */ + if (con->sock >= 0) + close(con->sock); + } + memset(con, 0, sizeof(*con)); + con->context = GSS_C_NO_CONTEXT; + con->sock = -1; + return 0; +} + +int +edg_wll_gss_get_error(edg_wll_GssStatus *gss_err, const char *prefix, char **msg) +{ + OM_uint32 maj_stat, min_stat; + OM_uint32 msg_ctx = 0; + gss_buffer_desc maj_status_string = GSS_C_EMPTY_BUFFER; + gss_buffer_desc min_status_string = GSS_C_EMPTY_BUFFER; + char *str = NULL; + char *line, *tmp; + + str = strdup(prefix); + do { + maj_stat = gss_display_status(&min_stat, gss_err->major_status, + GSS_C_GSS_CODE, GSS_C_NO_OID, + &msg_ctx, &maj_status_string); + if (GSS_ERROR(maj_stat)) + break; + + maj_stat = gss_display_status(&min_stat, gss_err->minor_status, + GSS_C_MECH_CODE, GSS_C_NULL_OID, + &msg_ctx, &min_status_string); + if (GSS_ERROR(maj_stat)) { + gss_release_buffer(&min_stat, &maj_status_string); + break; + } + + asprintf(&line, ": %s (%s)", (char *)maj_status_string.value, + (char *)min_status_string.value); + gss_release_buffer(&min_stat, &maj_status_string); + gss_release_buffer(&min_stat, &min_status_string); + + tmp = realloc(str, strlen(str) + strlen(line) + 1); + if (tmp == NULL) { + /* abort() ? */ + free(line); + free(str); + str = "WARNING: Not enough memory to produce error message"; + break; + } + str = tmp; + strcat(str, line); + free(line); + } while (!GSS_ERROR(maj_stat) && msg_ctx != 0); + + *msg = str; + return 0; +} + +int +edg_wll_gss_oid_equal(const gss_OID a, const gss_OID b) +{ + if (a == b) + return 1; + else { + if (a == GSS_C_NO_OID || b == GSS_C_NO_OID || a->length != b->length) + return 0; + else + return (memcmp(a->elements, b->elements, a->length) == 0); + } +} + +int +edg_wll_gss_reject(int sock) +{ + /* XXX is it possible to cut & paste edg_wll_ssl_reject() ? */ + return 0; +} diff --git a/org.glite.security.gsoap-plugin/test/test_gss.cpp b/org.glite.security.gsoap-plugin/test/test_gss.cpp new file mode 100644 index 0000000..d6df484 --- /dev/null +++ b/org.glite.security.gsoap-plugin/test/test_gss.cpp @@ -0,0 +1,149 @@ +#include +#include +#include + + +#include +#include +#include +#include + + +#include "lb_gss.h" + +class GSSTest: public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(GSSTest); + CPPUNIT_TEST(echo); + CPPUNIT_TEST(errorTest); + CPPUNIT_TEST_SUITE_END(); + +public: + void echo(); + void errorTest(); + + void setUp(); + +private: + gss_cred_id_t my_cred; + char * my_subject; + int sock, port; + struct timeval timeout; + + void replier(); + +}; + + +void GSSTest::replier() { + edg_wll_GssConnection conn; + edg_wll_GssStatus stat; + struct sockaddr_in a; + socklen_t alen = sizeof(a); + int s, len; + char buf[100]; + + + if ( (s = accept(sock, (struct sockaddr *) &a, &alen)) < 0 ) exit(1); + + if ( edg_wll_gss_accept(my_cred, s, &timeout, &conn, &stat) ) exit(1); + + while ( (len = edg_wll_gss_read(&conn, buf, sizeof(buf), &timeout, &stat)) >= 0 ) { + if ( edg_wll_gss_write(&conn, buf, len, &timeout, &stat) ) exit(1); + } + + exit(0); +} + + +void GSSTest::setUp(void) { + pid_t pid; + edg_wll_GssStatus stat; + struct sockaddr_in a; + socklen_t alen = sizeof(a); + char * cred_file = NULL; + char * key_file = NULL; + + timeout.tv_sec = 10; + timeout.tv_usec = 0; + + key_file = cred_file = getenv("X509_USER_PROXY"); + CPPUNIT_ASSERT_MESSAGE("credential file", cred_file); + + if (edg_wll_gss_acquire_cred_gsi(cred_file, key_file, &my_cred, &my_subject, &stat)) + CPPUNIT_ASSERT_MESSAGE("gss_acquire_cred", 0); + + sock = socket(PF_INET,SOCK_STREAM,0); + CPPUNIT_ASSERT_MESSAGE("socket()", sock >= 0); + + a.sin_family = AF_INET; + a.sin_port = 0; + a.sin_addr.s_addr = INADDR_ANY; + + if (bind(sock,(struct sockaddr *) &a,sizeof(a))) { + CPPUNIT_ASSERT_MESSAGE("bind()", 0); + } + + if (listen(sock,1)) { + CPPUNIT_ASSERT_MESSAGE("listen()", 0); + } + + getsockname(sock,(struct sockaddr *) &a,&alen); + port = ntohs(a.sin_port); + + if ( !(pid = fork()) ) replier(); + else close(sock); +} + + + +void GSSTest::echo() +{ + edg_wll_GssConnection conn; + edg_wll_GssStatus stat; + size_t total; + int err; + char buf[] = "f843fejwfanczn nc4*&686%$$&^(*)*#$@WSH"; + char buf2[100]; + + + err = edg_wll_gss_connect(my_cred, "localhost", port, &timeout, &conn, &stat); + CPPUNIT_ASSERT_MESSAGE("edg_wll_gss_connect()", !err); + + err = edg_wll_gss_write(&conn, buf, strlen(buf)+1, &timeout, &stat); + CPPUNIT_ASSERT_MESSAGE("edg_wll_gss_write()", !err); + + err = edg_wll_gss_read_full(&conn, buf2, strlen(buf)+1, &timeout, &total, &stat); + CPPUNIT_ASSERT_MESSAGE("edg_wll_gss_read_full()", !err); + + CPPUNIT_ASSERT(strlen(buf)+1 == total && !strcmp(buf,buf2) ); + + edg_wll_gss_close(&conn, &timeout); + +} + + +void GSSTest::errorTest() +{ + edg_wll_GssConnection conn; + edg_wll_GssStatus stat; + int err; + char * msg = NULL; + + + err = edg_wll_gss_connect(my_cred, "xxx.porno.net", port, &timeout, &conn, &stat); + if (err) edg_wll_gss_get_error(&stat, "gss_connect()", &msg); + CPPUNIT_ASSERT_MESSAGE("edg_wll_gss_get_error()", msg); +} + + +CPPUNIT_TEST_SUITE_REGISTRATION( GSSTest ); + +int main (int ac,const char *av[]) +{ + CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest(); + CppUnit::TextUi::TestRunner runner; + + runner.addTest(suite); + return runner.run() ? 0 : 1; +} -- 1.8.2.3