- New security module which will provide gss communication layer and a gss gSOAP
authorJiří Škrábal <nykolas@ics.muni.cz>
Wed, 9 Feb 2005 10:28:55 +0000 (10:28 +0000)
committerJiří Škrábal <nykolas@ics.muni.cz>
Wed, 9 Feb 2005 10:28:55 +0000 (10:28 +0000)
plugin

16 files changed:
org.glite.security.gsoap-plugin/LICENSE [new file with mode: 0644]
org.glite.security.gsoap-plugin/Makefile [new file with mode: 0644]
org.glite.security.gsoap-plugin/build.xml [new file with mode: 0755]
org.glite.security.gsoap-plugin/examples/calc.h.S [new file with mode: 0644]
org.glite.security.gsoap-plugin/examples/wscalc_clt_ex.c [new file with mode: 0644]
org.glite.security.gsoap-plugin/examples/wscalc_srv_ex.c [new file with mode: 0644]
org.glite.security.gsoap-plugin/interface/glite_gsplugin.h [new file with mode: 0644]
org.glite.security.gsoap-plugin/interface/lb_gss.h [new file with mode: 0644]
org.glite.security.gsoap-plugin/project/build.properties [new file with mode: 0644]
org.glite.security.gsoap-plugin/project/configure.properties.xml [new file with mode: 0644]
org.glite.security.gsoap-plugin/project/properties.xml [new file with mode: 0755]
org.glite.security.gsoap-plugin/project/tar_exclude [new file with mode: 0644]
org.glite.security.gsoap-plugin/project/version.properties [new file with mode: 0644]
org.glite.security.gsoap-plugin/src/glite_gsplugin.c [new file with mode: 0644]
org.glite.security.gsoap-plugin/src/lb_gss.c [new file with mode: 0644]
org.glite.security.gsoap-plugin/test/test_gss.cpp [new file with mode: 0644]

diff --git a/org.glite.security.gsoap-plugin/LICENSE b/org.glite.security.gsoap-plugin/LICENSE
new file mode 100644 (file)
index 0000000..259a91f
--- /dev/null
@@ -0,0 +1,69 @@
+LICENSE file for EGEE Middleware\r
+================================\r
+\r
+Copyright (c) 2004 on behalf of the EU EGEE Project: \r
+The European Organization for Nuclear Research (CERN), \r
+Istituto Nazionale di Fisica Nucleare (INFN), Italy\r
+Datamat Spa, Italy\r
+Centre National de la Recherche Scientifique (CNRS), France\r
+CS Systeme d'Information (CSSI), France\r
+Royal Institute of Technology, Center for Parallel Computers (KTH-PDC), Sweden\r
+Universiteit van Amsterdam (UvA), Netherlands\r
+University of Helsinki (UH.HIP), Finlan\r
+University of Bergen (UiB), Norway\r
+Council for the Central Laboratory of the Research Councils (CCLRC), United Kingdom\r
+\r
+Redistribution and use in source and binary forms, with or without\r
+modification, are permitted provided that the following conditions are\r
+met: \r
+\r
+1. Redistributions of source code must retain the above copyright\r
+notice, this list of conditions and the following disclaimer.\r
+\r
+2. Redistributions in binary form must reproduce the above copyright\r
+notice, this list of conditions and the following disclaimer in the\r
+documentation and/or other materials provided with the distribution.\r
+\r
+3. The end-user documentation included with the redistribution, if\r
+any, must include the following acknowledgment: "This product includes\r
+software developed by The EU EGEE Project (http://cern.ch/eu-egee/)."\r
+Alternatively, this acknowledgment may appear in the software itself, if\r
+and wherever such third-party acknowledgments normally appear.\r
+\r
+4. The names EGEE and the EU EGEE Project must not be\r
+used to endorse or promote products derived from this software without\r
+prior written permission. For written permission, please contact\r
+<email address>.\r
+\r
+5. You are under no obligation whatsoever to provide anyone with any\r
+bug fixes, patches, or upgrades to the features, functionality or\r
+performance of the Software ("Enhancements") that you may develop over\r
+time; however, if you choose to provide your Enhancements to The EU\r
+EGEE Project, or if you choose to otherwise publish or distribute your\r
+Enhancements, in source code form without contemporaneously requiring\r
+end users of The EU EGEE Proejct to enter into a separate written license\r
+agreement for such Enhancements, then you hereby grant The EU EGEE Project\r
+a non-exclusive, royalty-free perpetual license to install, use, copy,\r
+modify, prepare derivative works, incorporate into the EGEE Middleware\r
+or any other computer software, distribute, and sublicense your\r
+Enhancements or derivative works thereof, in binary and source code\r
+form (if any), whether developed by The EU EGEE Project or third parties.\r
+\r
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED\r
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
+DISCLAIMED. IN NO EVENT SHALL PROJECT OR ITS CONTRIBUTORS BE LIABLE\r
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\r
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\r
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\r
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\r
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+\r
+This software consists of voluntary contributions made by many\r
+individuals on behalf of the EU EGEE Prject. For more information on The\r
+EU EGEE Project, please see http://cern.ch/eu-egee/. For more information on\r
+EGEE Middleware, please see http://egee-jra1.web.cern.ch/egee-jra1/\r
+\r
+\r
diff --git a/org.glite.security.gsoap-plugin/Makefile b/org.glite.security.gsoap-plugin/Makefile
new file mode 100644 (file)
index 0000000..99bedba
--- /dev/null
@@ -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 (executable)
index 0000000..485aa55
--- /dev/null
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+       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), Finland
+       University of Bergen (UiB), Norway
+       Council for the Central Laboratory of the Research Councils (CCLRC), United Kingdom
+
+       Build file for the GLite gSOAP plugin and gss libraries
+
+       Release: $Name$
+
+       Revision history:
+       
+-->
+
+<project name="gsoap-plugin" default="dist">
+       
+       <!-- =========================================
+                Builds the GLite gSOAP plugin and gss libraries
+            ========================================= -->
+       
+       <!-- =========================================
+            Import properties (order is important)
+            ========================================= -->
+
+       <!-- import baseline & user properties -->
+       <import file="../org.glite/project/baseline.properties.xml" />
+
+       <!-- import component build properties,
+                       component properties &
+                       component common properties -->
+       <import file="./project/properties.xml"/>
+       
+       <!-- import subsystem build properties,
+                       subsystem properties &
+                       subsystem common properties -->
+       <import file="${subsystem.properties.file}"/>
+
+       <!-- import global build properties &
+                       global properties -->
+       <import file="${global.properties.file}" />
+               
+       <!-- =========================================
+                Load dependency property files (order is important)
+            ========================================= -->
+       <property file="${user.dependencies.file}"/>
+       <property file="${component.dependencies.file}" />
+       <property file="${subsystem.dependencies.file}" />
+       <property file="${global.dependencies.file}"/>
+       
+       <!-- =========================================
+                Load configure options (order is important)
+            ========================================= -->
+       <import file="${global.configure.options.file}"/>
+       <import file="${component.configure.options.file}"/>
+
+       <!-- =========================================
+                Import task definitions (order is important)
+            ========================================= -->
+       <import file="${subsystem.taskdefs.file}" />
+       <import file="${global.taskdefs.file}" />
+                       
+       <!-- =========================================
+                Load common targets
+            ========================================= -->
+       <import file="${global.targets-simple_make.file}" />
+
+       <!-- =========================================
+                Load version file 
+            ========================================= -->
+       <property file="${module.version.file}"/>
+               
+       <!-- ==============================================
+                Local private targets
+            ============================================== -->
+       
+       <target name="localinit"
+               description="Module specific initialization tasks">
+               <antcall target="secmakefiles" />
+       </target>
+               
+       <target name="localcompile"
+               description="Module specific compile tasks">
+       </target>
+       
+       <target name="localclean"
+               description="Module specific cleaning tasks">
+       </target>
+       
+       <!-- =========================================
+            RPM settings
+            ========================================= -->
+
+       <property name="build.package.summary" value="gSOAP plugin and gss libraries" />
+       <property name="build.package.description" value=" The gSOAP gss plugin" />
+
+</project>             
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 (file)
index 0000000..385e872
--- /dev/null
@@ -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 (file)
index 0000000..b96827d
--- /dev/null
@@ -0,0 +1,47 @@
+#include <glite_gsplugin.h>
+
+#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 (file)
index 0000000..764605c
--- /dev/null
@@ -0,0 +1,120 @@
+#include <stdio.h>
+#include <getopt.h>
+#include <stdsoap2.h>
+#include <glite_gsplugin.h>
+
+#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 (file)
index 0000000..4184c38
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __GLITE_GSOAP_PLUGIN_H__
+#define __GLITE_GSOAP_PLUGIN_H__
+
+#include <stdsoap2.h>
+
+#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 (file)
index 0000000..c0c8a71
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef __EDG_WORKLOAD_LOGGING_COMMON_LB_GSS_H__
+#define __EDG_WORKLOAD_LOGGING_COMMON_LB_GSS_H__
+
+#include <gssapi.h>
+
+#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 (file)
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 (file)
index 0000000..d5999cc
--- /dev/null
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+       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), Finland
+       University of Bergen (UiB), Norway
+       Council for the Central Laboratory of the Research Councils (CCLRC), United Kingdom
+
+       Configuration options for the GLite gSOAP plugin and gss libraries
+       
+       Revision history:
+       
+       
+-->
+
+       <!-- ======================================================
+         Define extra properties here ...
+         ====================================================== -->
+        
+       <project name="gSOAP plugin configuration options">                                                                        
+               <target name="secmakefiles">
+                       <exec executable="ln" failonerror="true">
+                               <arg line="-fs ${component.dir}/Makefile ${module.build.dir}/Makefile"/>
+                       </exec>
+                       <echo file="${module.build.dir}/Makefile.inc">
+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}
+                       </echo>
+           </target>
+       </project>
diff --git a/org.glite.security.gsoap-plugin/project/properties.xml b/org.glite.security.gsoap-plugin/project/properties.xml
new file mode 100755 (executable)
index 0000000..f63ddbd
--- /dev/null
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+       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), Finland
+       University of Bergen (UiB), Norway
+       Council for the Central Laboratory of the Research Councils (CCLRC), United Kingdom
+
+       Common build properties file for the GLite gSOAP plugin and gss libraries
+       
+       Revision history:
+       
+-->
+
+<project name="GLite gSOAP plugin component common properties">
+
+       <!-- Include build properties to allow overwriting 
+            of properties for subsystem                    -->
+       <property file="build.properties" />    
+
+       <!-- ======================================================
+          Define corresponding subsystem properties
+                ====================================================== -->
+
+       <!-- Subsystem name -->
+       <property name="subsystem.name" value="${security.subsystem.name}"/>
+               
+       <!-- Subsystem prefix -->
+       <property name="subsystem.prefix" value="${security.subsystem.prefix}"/>
+
+       <!-- ======================================================
+          Define component properties
+                ====================================================== -->
+                               
+       <!-- Component name prefix -->
+       <property name="component.prefix" value="gsoap-plugin" />
+                       
+       <!-- ======================================================
+          Define general component properties
+                ====================================================== -->
+       
+       <import file="${component.general.properties.file}" />
+                                               
+       <!-- ======================================================
+                Define extra properties here ...
+                ====================================================== -->
+                
+                                                               
+</project>
diff --git a/org.glite.security.gsoap-plugin/project/tar_exclude b/org.glite.security.gsoap-plugin/project/tar_exclude
new file mode 100644 (file)
index 0000000..b3133e4
--- /dev/null
@@ -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 (file)
index 0000000..e22bcd3
--- /dev/null
@@ -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 (file)
index 0000000..431584b
--- /dev/null
@@ -0,0 +1,368 @@
+#include <stdio.h>
+#include <assert.h>
+#include <signal.h>
+#include <stdsoap2.h>
+
+#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 (file)
index 0000000..a9908a3
--- /dev/null
@@ -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 <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <ares.h>
+#include <errno.h>
+
+#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 (file)
index 0000000..d6df484
--- /dev/null
@@ -0,0 +1,149 @@
+#include <iostream>
+#include <sys/types.h>
+#include <unistd.h>
+
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/CompilerOutputter.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+
+
+#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;
+}