From 8269394af20a6ed1fe929a80457bae8aee27c023 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Zden=C4=9Bk=20=C5=A0ustr?= Date: Mon, 4 Oct 2010 09:53:36 +0000 Subject: [PATCH] Moving files to proper locations --- org.glite.px.proxyrenewal/LICENSE | 69 ++ org.glite.px.proxyrenewal/Makefile | 167 +++ org.glite.px.proxyrenewal/build.xml | 134 +++ org.glite.px.proxyrenewal/config/startup | 80 ++ org.glite.px.proxyrenewal/examples/renew_core.c | 63 + org.glite.px.proxyrenewal/interface/renewal.h | 175 +++ org.glite.px.proxyrenewal/interface/renewal_core.h | 62 + org.glite.px.proxyrenewal/project/build.number | 1 + org.glite.px.proxyrenewal/project/build.properties | 0 .../project/configure.properties.xml | 66 + org.glite.px.proxyrenewal/project/properties.xml | 68 ++ org.glite.px.proxyrenewal/project/tar_exclude | 10 + org.glite.px.proxyrenewal/project/taskdefs.xml | 4 + .../project/version.properties | 2 + org.glite.px.proxyrenewal/src/api.c | 550 +++++++++ org.glite.px.proxyrenewal/src/client.c | 111 ++ org.glite.px.proxyrenewal/src/commands.c | 1256 ++++++++++++++++++++ org.glite.px.proxyrenewal/src/common.c | 322 +++++ org.glite.px.proxyrenewal/src/renew.c | 256 ++++ org.glite.px.proxyrenewal/src/renewal_core.c | 283 +++++ org.glite.px.proxyrenewal/src/renewal_locl.h | 148 +++ org.glite.px.proxyrenewal/src/renewd.c | 606 ++++++++++ org.glite.px.proxyrenewal/src/renewd_locl.h | 82 ++ org.glite.px.proxyrenewal/src/voms.c | 356 ++++++ 24 files changed, 4871 insertions(+) create mode 100644 org.glite.px.proxyrenewal/LICENSE create mode 100644 org.glite.px.proxyrenewal/Makefile create mode 100755 org.glite.px.proxyrenewal/build.xml create mode 100755 org.glite.px.proxyrenewal/config/startup create mode 100644 org.glite.px.proxyrenewal/examples/renew_core.c create mode 100644 org.glite.px.proxyrenewal/interface/renewal.h create mode 100644 org.glite.px.proxyrenewal/interface/renewal_core.h create mode 100644 org.glite.px.proxyrenewal/project/build.number create mode 100644 org.glite.px.proxyrenewal/project/build.properties create mode 100644 org.glite.px.proxyrenewal/project/configure.properties.xml create mode 100755 org.glite.px.proxyrenewal/project/properties.xml create mode 100644 org.glite.px.proxyrenewal/project/tar_exclude create mode 100755 org.glite.px.proxyrenewal/project/taskdefs.xml create mode 100644 org.glite.px.proxyrenewal/project/version.properties create mode 100644 org.glite.px.proxyrenewal/src/api.c create mode 100644 org.glite.px.proxyrenewal/src/client.c create mode 100644 org.glite.px.proxyrenewal/src/commands.c create mode 100644 org.glite.px.proxyrenewal/src/common.c create mode 100644 org.glite.px.proxyrenewal/src/renew.c create mode 100644 org.glite.px.proxyrenewal/src/renewal_core.c create mode 100644 org.glite.px.proxyrenewal/src/renewal_locl.h create mode 100644 org.glite.px.proxyrenewal/src/renewd.c create mode 100644 org.glite.px.proxyrenewal/src/renewd_locl.h create mode 100644 org.glite.px.proxyrenewal/src/voms.c diff --git a/org.glite.px.proxyrenewal/LICENSE b/org.glite.px.proxyrenewal/LICENSE new file mode 100644 index 0000000..01b973b --- /dev/null +++ b/org.glite.px.proxyrenewal/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.px.proxyrenewal/Makefile b/org.glite.px.proxyrenewal/Makefile new file mode 100644 index 0000000..24252c7 --- /dev/null +++ b/org.glite.px.proxyrenewal/Makefile @@ -0,0 +1,167 @@ +# +# 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 +# +# Top Makefile file for the GLite Security Proxyrenewal module +# +# Authors: Ales Krenek +# Version info: $Id$ +# Release: $Name$ +# +# Revision history: +# $Log +# + +# defaults +top_srcdir=. +builddir=build +top_builddir=${top_srcdir}/${builddir} +stagedir=. +distdir=. +globalprefix=glite +lbprefix=lb +package=glite-security-proxyrenewal +version=0.0.0 +PREFIX=/opt/glite + +glite_location=$PREFIX +globus_prefix=/opt/globus +nothrflavour=gcc32 +thrflavour=gcc32pthr +myproxy_prefix=$globus_prefix + +-include Makefile.inc + +VPATH:=${top_srcdir}/src:${top_srcdir}/examples + +GLOBUSINC:= -I${globus_prefix}/include/${nothrflavour} \ + -I${globus_prefix}/include/${nothrflavour}/openssl + +GLOBUSTHRINC:= -I${globus_prefix}/include/${thrflavour} \ + -I${globus_prefix}/include/${thrflavour}/openssl + +MYPROXYINC:= -I${myproxy_prefix}/include/${nothrflavour} +MYPROXYTHRINC:= -I${myproxy_prefix}/include/${thrflavour} + +DEBUG:=-g -O0 + +CFLAGS:= ${DEBUG} \ + ${MYPROXYINC} \ + -I${top_srcdir}/src -I${top_srcdir}/interface \ + -I${glite_location}/include + +GLOBUS_LIBS:=-L${globus_prefix}/lib \ + -lglobus_common_${nothrflavour} \ + -lssl_${nothrflavour} + +MYPROXY_LIB_NOTHR :=-L${myproxy_prefix}/lib -lmyproxy_${nothrflavour} +MYPROXY_LIB_THR:=-L${myproxy_prefix}/lib -lmyproxy_${thrflavour} + +offset=1 +version_info:=-version-info ${shell \ + perl -e '$$,=":"; @F=split "\\.","${version}"; print $$F[0]+$$F[1]+${offset},$$F[2],$$F[1]' } + +COMPILE:=libtool --mode=compile ${CC} ${CFLAGS} +LINK:=libtool --mode=link ${CC} ${LDFLAGS} +INSTALL:=libtool --mode=install install + +DAEMONOBJ:=renewd.o renew.o common.o commands.o api.o voms.o +LIBOBJ:=api.o common.o +LIB_CORE_OBJS := renewal_core.o voms.o +CLIENTOBJ:=client.o + +THRLIBOBJ:=${LIBOBJ:.o=.thr.o} +LIBLOBJ:=${LIBOBJ:.o=.lo} +THRLIBLOBJ:=${LIBOBJ:.o=.thr.lo} + +LIB_CORE_NOTHR_OBJS := ${LIB_CORE_OBJS} +LIB_CORE_NOTHR_LOBJS := ${LIB_CORE_OBJS:.o=.lo} +LIB_CORE_THR_OBJS := ${LIB_CORE_OBJS:.o=.thr.o} +LIB_CORE_THR_LOBJS := ${LIB_CORE_OBJS:.o=.thr.lo} + +LIB:=libglite_security_proxyrenewal_${nothrflavour}.la +THRLIB:=libglite_security_proxyrenewal_${thrflavour}.la +LIB_CORE_NOTHR := libglite_security_proxyrenewal_core_${nothrflavour}.la +LIB_CORE_THR := libglite_security_proxyrenewal_core_${thrflavour}.la + +VOMS_LIB_NOTHR := -L${glite_location}/lib -lvomsc_${nothrflavour} +VOMS_LIB_THR := -L${glite_location}/lib -lvomsc_${thrflavour} + +DAEMON:=glite-proxy-renewd +CLIENT:=glite-proxy-renew +EXAMPLES := renew_core + +default: all +compile all: ${LIB} ${THRLIB} ${LIB_CORE_NOTHR} ${DAEMON} ${CLIENT} + +${LIB}: ${LIBOBJ} + ${LINK} ${version_info} -o $@ ${LIBLOBJ} -rpath ${glite_location}/lib + +${THRLIB}: ${THRLIBOBJ} + ${LINK} ${version_info} -o $@ ${THRLIBLOBJ} -rpath ${glite_location}/lib + +${LIB_CORE_NOTHR}: ${LIB_CORE_NOTHR_OBJS} + ${LINK} ${version_info} -o $@ ${LIB_CORE_NOTHR_LOBJS} -rpath ${glite_location}/lib ${MYPROXY_LIB_NOTHR} ${VOMS_LIB_NOTHR} + +${LIB_CORE_THR}: ${LIB_CORE_THR_OBJS} + ${LINK} ${version_info} -o $@ ${LIB_CORE_THR_LOBJS} -rpath ${glite_location}/lib ${MYPROXY_LIB_THR} ${VOMS_LIB_THR} + +${DAEMON}: ${DAEMONOBJ} ${LIB_CORE_NOTHR} + ${LINK} -o $@ ${DAEMONOBJ} ${LIB_CORE_NOTHR} + +${CLIENT}: ${CLIENTOBJ} ${LIB} + ${LINK} -o $@ ${CLIENTOBJ} ${LIB} ${GLOBUS_LIBS} + +${THRLIBOBJ} ${LIB_CORE_THR_OBJS}: %.thr.o: %.c + ${COMPILE} ${GLOBUSTHRINC} -o $@ -c $< + +%.o: %.c + ${COMPILE} ${GLOBUSINC} -c $< + +${EXAMPLES}: %: %.o + ${LINK} -o $@ $< ${LIB_CORE_NOTHR} + +stage: compile + $(MAKE) install PREFIX=${stagedir} + +check: + echo No unit tests + +examples: ${EXAMPLES} + +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 + cd tmpbuilddir && tar -czf ../${top_srcdir}/${distdir}/${package}-${version}_bin.tar.gz * + rm -rf tmpbuilddir + +install: + -mkdir -p ${PREFIX}/bin ${PREFIX}/lib ${PREFIX}/include/glite/security/proxyrenewal ${PREFIX}/share/doc/${package}-${version} ${PREFIX}/etc/init.d + ${INSTALL} -m 644 ${LIB} ${THRLIB} ${LIB_CORE_NOTHR} ${PREFIX}/lib + ${INSTALL} -m 755 ${DAEMON} ${CLIENT} ${PREFIX}/bin + ${INSTALL} -m 644 ${top_srcdir}/LICENSE ${PREFIX}/share/doc/${package}-${version} + cd ${top_srcdir}/interface && ${INSTALL} -m 644 renewal.h renewal_core.h ${PREFIX}/include/glite/security/proxyrenewal + + ${INSTALL} -m 755 ${top_srcdir}/config/startup ${PREFIX}/etc/init.d/glite-proxy-renewald + + +clean: + $(RM) $(LIB) ${THRLIB} ${LIB_CORE_NOTHR} ${LIB_CORE_THR} $(DAEMON) $(CLIENT) $(EXAMPLES) *.o *.lo core + +.PHONY: default all compile examples check stage dist distsrc distbin install clean diff --git a/org.glite.px.proxyrenewal/build.xml b/org.glite.px.proxyrenewal/build.xml new file mode 100755 index 0000000..ac94daf --- /dev/null +++ b/org.glite.px.proxyrenewal/build.xml @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.glite.px.proxyrenewal/config/startup b/org.glite.px.proxyrenewal/config/startup new file mode 100755 index 0000000..26ba757 --- /dev/null +++ b/org.glite.px.proxyrenewal/config/startup @@ -0,0 +1,80 @@ +#!/bin/sh + +GLITE_LOCATION=${GLITE_LOCATION:-/opt/glite} +GLITE_LOCATION_VAR=${GLITE_LOCATION_VAR:-/opt/glite/var} + +[ -f /etc/glite.conf ] && . /etc/glite.conf +[ -f $GLITE_LOCATION/etc/glite-wms.conf ] && . $GLITE_LOCATION/etc/glite-wms.conf +[ -f $HOME/.glite.conf ] && . $HOME/.glite.conf + +PROXY_REPOSITORY="$GLITE_LOCATION_VAR/spool/glite-renewd" + +unset creds + +start() +{ + if test -z "$GLITE_USER" ;then + echo 'Error: GLITE_USER is not set' + echo FAILED + return 1 + fi + + [ -n "$GLITE_HOST_CERT" -a -n "$GLITE_HOST_KEY" ] && + creds="-t $GLITE_HOST_CERT -k $GLITE_HOST_KEY" + + if test -z "$creds"; then + if su - $GLITE_USER -c "test -r /etc/grid-security/hostkey.pem -a -r /etc/grid-security/hostcert.pem"; then + echo "$0: WARNING: /etc/grid-security/hostkey.pem readable by $GLITE_USER" + creds="-t /etc/grid-security/hostcert.pem -k /etc/grid-security/hostkey.pem" + fi + fi + + [ -z "$creds" ] && + echo $0: WARNING: No credentials specified. Using default lookup which is dangerous. >&2 + + # workaround for VOMS_FindByVO that seems to always require user's own VOMS config file (bug #7511) + user_voms_config=$HOME/.glite/vomses + if [ ! -f "$user_voms_config" ]; then + rm -f /tmp/renewal_vomses + su - $GLITE_USER -c "touch /tmp/renewal_vomses && chmod 644 /tmp/renewal_vomses" + user_voms_config=/tmp/renewal_vomses + fi + + echo -n Starting ProxyRenewal Daemon: glite-proxy-renewd ... + + if [ ! -d "$PROXY_REPOSITORY" ]; then + mkdir -p $PROXY_REPOSITORY || exit 1 + chown $GLITE_USER $PROXY_REPOSITORY + chmod 0700 $PROXY_REPOSITORY + fi + + su - $GLITE_USER -c "VOMS_USERCONF=$user_voms_config \ + $GLITE_LOCATION/bin/glite-proxy-renewd \ + -r $PROXY_REPOSITORY $creds -A" && echo " done" +} + +stop() +{ + echo -n "Stopping ProxyRenewal Daemon: glite-proxy-renewd ..." + killall glite-proxy-renewd + echo " done" +} + +status() +{ + if netstat -an --unix | grep "^unix .* LISTEN.* /tmp/dgpr_renew_" >/dev/null 2>&1 ;then + echo glite-proxy-renewd running + else + echo glite-proxy-renewd not running + return 1 + fi +} + +case x$1 in + xstart) start;; + xstop) stop;; + xrestart) stop; start;; + xstatus) status;; + x*) echo usage: $0 start,stop,restart,status >&2 + exit 1;; +esac diff --git a/org.glite.px.proxyrenewal/examples/renew_core.c b/org.glite.px.proxyrenewal/examples/renew_core.c new file mode 100644 index 0000000..69518ea --- /dev/null +++ b/org.glite.px.proxyrenewal/examples/renew_core.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include + +static struct option const long_options[] = { + { "server", required_argument, 0, 's' }, + { "proxy", required_argument, 0, 'p' }, + { "help", no_argument, 0, 'h' }, + { NULL, 0, NULL, 0} +}; + +static char short_options[] = "s:p:h"; + +int +main(int argc, char *argv[]) +{ + char *server = NULL; + char *proxy = NULL; + char *new_proxy = NULL; + extern int optind; + char arg; + glite_renewal_core_context ctx = NULL; + int ret; + + while ((arg = getopt_long(argc, argv, short_options, long_options, NULL)) != EOF) { + switch(arg) { + case 's': + server = optarg; break; + case 'p': + proxy = optarg; break; + case 'h': + fprintf(stdout, "Usage: %s --server --proxy \n", argv[0]); + exit(1); + } + } + + if (server == NULL || proxy == NULL) { + fprintf(stderr, "both server and proxy parameters must be given\n"); + exit(1); + } + + ret = glite_renewal_core_init_ctx(&ctx); + if (ret) { + fprintf(stderr, "glite_renewal_core_init_ctx() failed\n"); + exit(1); + } + + ctx->log_dst = GLITE_RENEWAL_LOG_NONE; + + ret = glite_renewal_core_renew(ctx, server, 0, proxy, &new_proxy); + if (ret) { + fprintf(stderr, "%s: glite_renewal_core_renew() failed: %s", + argv[0], ctx->err_message); + exit(1); + } + + ret = glite_renewal_core_destroy_ctx(ctx); + + printf("%s\n", new_proxy); + + return 0; +} diff --git a/org.glite.px.proxyrenewal/interface/renewal.h b/org.glite.px.proxyrenewal/interface/renewal.h new file mode 100644 index 0000000..e07a89f --- /dev/null +++ b/org.glite.px.proxyrenewal/interface/renewal.h @@ -0,0 +1,175 @@ +/** + * \file proxyrenewal/renewal.h + * \author Daniel Kouril + * \author Miroslav Ruda + * \brief API for proxy renewal. + * \version 2.0 + * + * General rules: + * - functions return 0 on success, nonzero on error, errror details can + * be found via edg_wlpr_GetErrorText() + */ + +#ifndef RENEWAL_H +#define RENEWAL_H + +#ident "$Header$" + +#ifdef RENEWAL_HAVE_JOBID +#include "glite/wmsutils/jobid/cjobid.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define EDG_WLPR_FLAG_UNIQUE 1 +#define EDG_WLPR_FLAG_UPDATE 2 + +typedef enum _edg_wlpr_ErrorCode { +/** + * Base for proxy renewal specific code. + * Start sufficently high not to collide with standard errno. */ + /* XXX see common/exception_codes.h */ + EDG_WLPR_ERROR_BASE = 1900, + EDG_WLPR_ERROR_UNEXPECTED_EOF, + EDG_WLPR_ERROR_GENERIC, + EDG_WLPR_ERROR_PROTO_PARSE_ERROR, + EDG_WLPR_ERROR_PROTO_PARSE_NOT_FOUND, + EDG_WLPR_ERROR_UNKNOWN_COMMAND, + EDG_WLPR_ERROR_SSL, + EDG_WLPR_ERROR_MYPROXY, + EDG_WLPR_PROXY_NOT_REGISTERED, + EDG_WLPR_PROXY_EXPIRED, + EDG_WLPR_ERROR_VOMS, + EDG_WLPR_ERROR_TIMEOUT, + EDG_WLPR_ERROR_ERRNO, +} edg_wlpr_ErrorCode; + +/** + * Return a human readable string containg description of the errorcode + * \retval char* pointer to a error description + */ +const char * +edg_wlpr_GetErrorText(int err_code); + +/** + * This function contacts the renewal daemon and registers the specified proxy + * for periodic renewal. + * \param filename IN: specification of the proxy to register. + * \param jdl IN: JDL of the job owing the proxy. The JDL is looked for a + * myproxy server contact. + * \param flags IN: one of EDG_WLPR_FLAG_UNIQUE or EDG_WLPR_FLAG_UPDATE, or + * their bitwise OR. + * \param repository_filename OUT: filename of registered proxy in repository. + * \retval 0 success + * \retval nonzero on error. Human readable form of the error can be get via + * edg_wlpr_GetErrorText(). + */ +int +edg_wlpr_RegisterProxy( + const char * filename, + const char *jdl, + int flags, + char ** repository_filename +); + +/** + * The same function as edg_wlpr_RegisterProxy() but information about the + * myproxy server and jobid are passed as parameters instead of in JDL. + */ +#ifdef RENEWAL_HAVE_JOBID +int +edg_wlpr_RegisterProxyExt( + const char * filename, + const char * server, + unsigned int port, + edg_wlc_JobId jobid, + int flags, + char ** repository_filename +); +#endif + +int +glite_renewal_RegisterProxy( + const char * filename, + const char * server, + unsigned int port, + const char *jobid, + int flags, + char ** repository_filename +); + +/** + * Unregister proxy from the renewal daemon. + * \param jobid IN: specification of job whose proxy shall be unregistered + * \param filename IN: (optional) specification of the proxy to unregister. + * \retval 0 success + * \retval nonzero on error. Human readable form of the error can be get via + * edg_wlpr_GetErrorText(). + */ +#ifdef RENEWAL_HAVE_JOBID +int +edg_wlpr_UnregisterProxy( + edg_wlc_JobId jobid, + const char * repository_filename +); +#endif + +int +glite_renewal_UnregisterProxy( + const char * jobid, + const char * repository_filename +); + +/** + * Get a list of registered proxies maintained by the renewal daemon. + * \param count OUT: number of proxies + * \param list OUT: a list of filenames separated by '\n' + * specifying the registered proxies. + * \warning The caller is responsible for freeing the data. + * \retval 0 success + * \retval nonzero on error. Human readable form of the error can be get via + * edg_wlpr_GetErrorText(). + */ +int +edg_wlpr_GetList(int *count, char **list); + +/** + * Get a status message about a proxy. + * The function contacts the renewal daemon and retrieve information it + * maintains about the proxy. + * \param filename IN: specification of the proxy to query + * \param info OUT: status message. + * \warning The caller is responsible for freeing the data. + * \retval 0 success + * \retval nonzero on error. Human readable form of the error can be get via + * edg_wlpr_GetErrorText(). + */ +int +edg_wlpr_GetStatus(const char *repository_filename, char **info); + +/** + * For given jobid return registered proxy filename from repository + * \param jobid IN: specification of jobid + * \param repository_filename OUT: proxy regitered for given jobid + * \warning The caller is responsible for freeing the data. + * \retval 0 success + * \retval nonzero on error. Human readable form of the error can be get via + * edg_wlpr_GetErrorText(). + */ +#ifdef RENEWAL_HAVE_JOBID +int +edg_wlpr_GetProxy(edg_wlc_JobId jobid, char **repository_filename); +#endif + +int +glite_renewal_GetProxy( + const char * jobid, + char **repository_filename); + +#ifdef __cplusplus +} +#endif + +#endif /* RENEWAL_H */ diff --git a/org.glite.px.proxyrenewal/interface/renewal_core.h b/org.glite.px.proxyrenewal/interface/renewal_core.h new file mode 100644 index 0000000..8348963 --- /dev/null +++ b/org.glite.px.proxyrenewal/interface/renewal_core.h @@ -0,0 +1,62 @@ +#ifndef RENEWAL_CORE_H +#define RENEWAL_CORE_H + +#ident "$Id$" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + GLITE_RENEWAL_LOG_NONE, + GLITE_RENEWAL_LOG_STDOUT, + GLITE_RENEWAL_LOG_SYSLOG, +} glite_renewal_log_dst; + +typedef struct glite_renewal_core_context_data { + int log_level; + glite_renewal_log_dst log_dst; + char *err_message; + char *voms_conf; +} glite_renewal_core_context_data; + +typedef struct glite_renewal_core_context_data *glite_renewal_core_context; + +/** + * This cal initializes the context and sets default values + */ +int +glite_renewal_core_init_ctx(glite_renewal_core_context *context); + +/** + * This call frees the context and all memory used by the context + */ +int +glite_renewal_core_destroy_ctx(glite_renewal_core_context context); + +/** + * This call tries to renew the proxy certificate using the MyProxy + * repository. If VOMS attributes are present in the proxy they are renewed + * as well. + * \param context IN: context with authentication information + * \param myproxy_server IN: hostname of the myproxy repository + * \param myproxy_port IN: TCP port of the myproxy repository, if 0 the + * default value will be used + * \param current_proxy IN: filename with the proxy to renew + * \param new_proxy OUT: filename with the renewed proxy, the caller is + * responsible for removing the file when it's not needed. + */ +int +glite_renewal_core_renew(glite_renewal_core_context context, + const char *myproxy_server, + unsigned int myproxy_port, + const char *current_proxy, + char **new_proxy); + +#ifdef __cplusplus +} +#endif + +#endif /* RENEWAL_CORE_H */ diff --git a/org.glite.px.proxyrenewal/project/build.number b/org.glite.px.proxyrenewal/project/build.number new file mode 100644 index 0000000..1936771 --- /dev/null +++ b/org.glite.px.proxyrenewal/project/build.number @@ -0,0 +1 @@ +module.build=137 diff --git a/org.glite.px.proxyrenewal/project/build.properties b/org.glite.px.proxyrenewal/project/build.properties new file mode 100644 index 0000000..e69de29 diff --git a/org.glite.px.proxyrenewal/project/configure.properties.xml b/org.glite.px.proxyrenewal/project/configure.properties.xml new file mode 100644 index 0000000..e7dcdbd --- /dev/null +++ b/org.glite.px.proxyrenewal/project/configure.properties.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + +top_srcdir=.. +builddir=build +stagedir=${stage.abs.dir} +distdir=${dist.dir} +globalprefix=${global.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} +myproxy_prefix=${with.myproxy.prefix} + + + diff --git a/org.glite.px.proxyrenewal/project/properties.xml b/org.glite.px.proxyrenewal/project/properties.xml new file mode 100755 index 0000000..c2e72fb --- /dev/null +++ b/org.glite.px.proxyrenewal/project/properties.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.glite.px.proxyrenewal/project/tar_exclude b/org.glite.px.proxyrenewal/project/tar_exclude new file mode 100644 index 0000000..e1fcd1a --- /dev/null +++ b/org.glite.px.proxyrenewal/project/tar_exclude @@ -0,0 +1,10 @@ +tar_exclude +CVS +build.xml +build +build.properties +properties.xml +configure.properties.xml +.cvsignore +.project +.cdtproject diff --git a/org.glite.px.proxyrenewal/project/taskdefs.xml b/org.glite.px.proxyrenewal/project/taskdefs.xml new file mode 100755 index 0000000..13e894e --- /dev/null +++ b/org.glite.px.proxyrenewal/project/taskdefs.xml @@ -0,0 +1,4 @@ + + + + diff --git a/org.glite.px.proxyrenewal/project/version.properties b/org.glite.px.proxyrenewal/project/version.properties new file mode 100644 index 0000000..1441742 --- /dev/null +++ b/org.glite.px.proxyrenewal/project/version.properties @@ -0,0 +1,2 @@ +module.version=1.3.0 +module.age=1 diff --git a/org.glite.px.proxyrenewal/src/api.c b/org.glite.px.proxyrenewal/src/api.c new file mode 100644 index 0000000..a72d692 --- /dev/null +++ b/org.glite.px.proxyrenewal/src/api.c @@ -0,0 +1,550 @@ +#include "renewal.h" +#include "renewal_locl.h" + +#ident "$Header$" + +#define SEPARATORS "\n" + +/* prototypes of static routines */ +static int +encode_request(edg_wlpr_Request *request, char **msg); + +static int +decode_response(const char *msg, const size_t msg_len, edg_wlpr_Response *response); + +static int +do_connect(char *socket_name, struct timeval *timeout, int *sock); + +static int +send_request(int sock, struct timeval *timeout, edg_wlpr_Request *request, edg_wlpr_Response *response); + +static int +encode_request(edg_wlpr_Request *request, char **msg) +{ + char *buf; + size_t buf_len; + int ret; + + buf_len = EDG_WLPR_BUF_SIZE; + buf = malloc(buf_len); + if (buf == NULL) + return ENOMEM; + buf[0] = '\0'; + + ret = edg_wlpr_StoreToken(&buf, &buf_len, EDG_WLPR_PROTO_VERSION, + EDG_WLPR_VERSION, SEPARATORS); + if (ret) + goto err; + + ret = edg_wlpr_StoreToken(&buf, &buf_len, EDG_WLPR_PROTO_COMMAND, + edg_wlpr_EncodeInt(request->command), + SEPARATORS); + if (ret) + goto err; + + if (request->myproxy_server) { + char host[1024]; + +#if 0 + snprintf(host, sizeof(host), "%s:%d", request->myproxy_server, + (request->myproxy_port) ? request->myproxy_port : EDG_WLPR_MYPROXY_PORT); /* XXX let server decide ? */ +#else + snprintf(host, sizeof(host), "%s", request->myproxy_server); +#endif + ret = edg_wlpr_StoreToken(&buf, &buf_len, EDG_WLPR_PROTO_MYPROXY_SERVER, + host, SEPARATORS); + if (ret) + goto err; + } + + if (request->proxy_filename) { + ret = edg_wlpr_StoreToken(&buf, &buf_len, EDG_WLPR_PROTO_PROXY, + request->proxy_filename, SEPARATORS); + if (ret) + goto err; + } + + if (request->jobid) { + ret = edg_wlpr_StoreToken(&buf, &buf_len, EDG_WLPR_PROTO_JOBID, + request->jobid, SEPARATORS); + if (ret) + goto err; + } + + if (request->entries) { + char **p = request->entries; + while (*p) { + ret = edg_wlpr_StoreToken(&buf, &buf_len, EDG_WLPR_PROTO_ENTRY, + *p, SEPARATORS); + if (ret) + goto err; + p++; + } + } + + buf[strlen(buf)] = '\0'; + *msg = buf; + return 0; + +err: + free(buf); + *msg = NULL; + return ret; +} + +static int +decode_response(const char *msg, const size_t msg_len, edg_wlpr_Response *response) +{ + int ret; + char *value = NULL; + /* char *p; */ + int i; + int current_size = 0; + + /* XXX add an ending zero '\0' */ + + assert(msg != NULL); + assert(response != NULL); + + memset(response, 0, sizeof(*response)); + + ret = edg_wlpr_GetToken(msg, msg_len, EDG_WLPR_PROTO_VERSION, SEPARATORS, + 0, &response->version); + if (ret) + goto err; + + ret = edg_wlpr_GetToken(msg, msg_len, EDG_WLPR_PROTO_RESPONSE, SEPARATORS, + 0, &value); + if (ret) + goto err; + + ret = edg_wlpr_DecodeInt(value, (int *)(&response->response_code)); + free(value); + if (ret) + goto err; + + ret = edg_wlpr_GetToken(msg, msg_len, EDG_WLPR_PROTO_MYPROXY_SERVER, + SEPARATORS, 0, &response->myproxy_server); + if (ret && ret != EDG_WLPR_ERROR_PROTO_PARSE_NOT_FOUND) + goto err; + +#if 0 + response->myproxy_port = EDG_WLPR_MYPROXY_PORT; /* ??? */ + if (response->myproxy_server && (p = strchr(response->myproxy_server, ':'))) { + int port; + *p = '\0'; + port = atol(p+1); /* XXX */ + response->myproxy_port = port; + } +#endif + + ret = edg_wlpr_GetToken(msg, msg_len, EDG_WLPR_PROTO_START_TIME, SEPARATORS, + 0, &value); + if (ret && ret != EDG_WLPR_ERROR_PROTO_PARSE_NOT_FOUND) + goto err; + if (ret == 0) { + ret = edg_wlpr_DecodeInt(value, (int *)(&response->start_time)); + free(value); + if (ret) + goto err; + } + + ret = edg_wlpr_GetToken(msg, msg_len, EDG_WLPR_PROTO_END_TIME, SEPARATORS, + 0, &value); + if (ret && ret != EDG_WLPR_ERROR_PROTO_PARSE_NOT_FOUND) + goto err; + if (ret == 0) { + ret = edg_wlpr_DecodeInt(value, (int *)(&response->end_time)); + free(value); + if (ret) + goto err; + } + + ret = edg_wlpr_GetToken(msg, msg_len, EDG_WLPR_PROTO_RENEWAL_TIME, + SEPARATORS, 0, &value); + if (ret && ret != EDG_WLPR_ERROR_PROTO_PARSE_NOT_FOUND) + goto err; + if (ret == 0) { + ret = edg_wlpr_DecodeInt(value, (int *)(&response->next_renewal_time)); + free(value); + if (ret) + goto err; + } + + /* XXX Counter */ + + i = 0; + while ((ret = edg_wlpr_GetToken(msg, msg_len, EDG_WLPR_PROTO_PROXY, + SEPARATORS, i, &value)) == 0) { + if (i >= current_size) { + char **tmp; + + tmp = realloc(response->filenames, + (current_size + 16 + 1) * sizeof(*tmp)); + if (tmp == NULL) { + ret = ENOMEM; + goto err; + } + response->filenames = tmp; + current_size += 16; + } + response->filenames[i] = value; + i++; + } + if (ret != EDG_WLPR_ERROR_PROTO_PARSE_NOT_FOUND) + goto err; + if (response->filenames) + response->filenames[i] = NULL; + + return 0; + +err: + edg_wlpr_CleanResponse(response); + + return ret; +} + +static int +do_connect(char *socket_name, struct timeval *timeout, int *sock) +{ + struct sockaddr_un my_addr; + int s; + int ret; + struct timeval before,after; + int sock_err; + socklen_t err_len; + + assert(sock != NULL); + memset(&my_addr, 0, sizeof(my_addr)); + + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s == -1) { + return errno; + } + + if (timeout) { + int flags = fcntl(s, F_GETFL, 0); + if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) + return errno; + } + + my_addr.sun_family = AF_UNIX; + strncpy(my_addr.sun_path, socket_name, sizeof(my_addr.sun_path)); + + ret = connect(s, (struct sockaddr *) &my_addr, sizeof(my_addr)); + if (ret == -1) { + if (errno == EINPROGRESS) { + struct pollfd pollfds[1]; + + pollfds[0].fd = s; + pollfds[0].events = POLLOUT; + + gettimeofday(&before,NULL); + switch (poll(pollfds, 1, timeout->tv_sec*1000+timeout->tv_usec/1000)) { + case -1: close(s); + return errno; + case 0: close(s); + return EDG_WLPR_ERROR_TIMEOUT; + } + gettimeofday(&after,NULL); + if (edg_wlpr_DecrementTimeout(timeout, before, after)) { + close (s); + return EDG_WLPR_ERROR_TIMEOUT; + } + + err_len = sizeof sock_err; + if (getsockopt(s,SOL_SOCKET,SO_ERROR,&sock_err,&err_len)) { + close(s); + return errno; + } + if (sock_err) { + close(s); + errno = sock_err; + return errno; + } + } else { + close(s); + return errno; + } + } + + *sock = s; + return 0; +} + +static int +send_request(int sock, struct timeval *timeout, edg_wlpr_Request *request, edg_wlpr_Response *response) +{ + int ret; + char *buf = NULL; + size_t buf_len; + + /* timeouts ?? */ + + ret = encode_request(request, &buf); + if (ret) + return ret; + + ret = edg_wlpr_Write(sock, timeout, buf, strlen(buf) + 1); + free(buf); + if (ret) + return ret; + + ret = edg_wlpr_Read(sock, timeout, &buf, &buf_len); + if (ret) + return ret; + + ret = decode_response(buf, buf_len, response); + free(buf); + if (ret) + return ret; + + return 0; +} + +int +edg_wlpr_RequestSend(edg_wlpr_Request *request, edg_wlpr_Response *response) +{ + char sockname[1024]; + int ret; + int sock; + struct timeval timeout; + const char *s = NULL; + double d; + + s = getenv("GLITE_PR_TIMEOUT"); + d = s ? atof(s) : GLITE_PR_TIMEOUT_DEFAULT; + timeout.tv_sec = (long) d; + timeout.tv_usec = (long) ((d-timeout.tv_sec) * 1e6); + + snprintf(sockname, sizeof(sockname), "%s%d", + DGPR_REG_SOCKET_NAME_ROOT, getuid()); + ret = do_connect(sockname, &timeout, &sock); + if (ret) + return ret; + + ret = send_request(sock, &timeout, request, response); + + close(sock); + return ret; +} + +int +glite_renewal_RegisterProxy(const char *filename, const char * server, + unsigned int port, + const char *jobid, int flags, + char **repository_filename) +{ + edg_wlpr_Request request; + edg_wlpr_Response response; + int ret; + + memset(&request, 0, sizeof(request)); + memset(&response, 0, sizeof(response)); + + if (jobid == NULL) + return EINVAL; + + request.command = EDG_WLPR_COMMAND_REG; + request.myproxy_server = server; + request.proxy_filename = filename; + request.jobid = strdup(jobid); + if (request.jobid == NULL) + return ENOMEM; + + ret = edg_wlpr_RequestSend(&request, &response); + free(request.jobid); + if (ret == 0 && response.response_code == 0 && repository_filename && + response.filenames && response.filenames[0] ) + *repository_filename = strdup(response.filenames[0]); + + if (ret == 0) + ret = response.response_code; + + edg_wlpr_CleanResponse(&response); + + return ret; +} + +#ifdef RENEWAL_HAVE_JOBID +int +edg_wlpr_RegisterProxyExt(const char *filename, const char * server, + unsigned int port, + edg_wlc_JobId jobid, int flags, + char **repository_filename) +{ + char *ji; + int ret; + + ji = edg_wlc_JobIdUnparse(jobid); + if (ji == NULL) + return EINVAL; + + ret = glite_renewal_RegisterProxy(filename, server, port, ji, flags, + repository_filename); + free(ji); + return ret; +} +#endif /* RENEWAL_HAVE_JOBID */ + +#if 0 +int +edg_wlpr_RegisterProxy(const char *filename, const char *jdl, + int flags, char **repository_filename) +{ + char server[1024]; + size_t server_len; + unsigned int port = 0; + char *p, *q; + + memset(server, 0, sizeof(server)); + + /* parse JDL and find information about myproxy server */ + p = strstr(jdl, JDL_MYPROXY); + if (p == NULL) + return 0; /* XXX */ + q = strchr(p, '\n'); /* XXX */ + if (q) + server_len = q - p; + else + server_len = jdl + strlen(jdl) - p; + if (server_len >= sizeof(server)) + return EINVAL; /* XXX */ + strncmp(server, p, sizeof(server)); + + return (edg_wlpr_RegisterProxyExt(filename, server, port, NULL, flags, + repository_filename)); +} +#endif + +int +glite_renewal_UnregisterProxy(const char *jobid, const char *repository_filename) +{ + edg_wlpr_Request request; + edg_wlpr_Response response; + int ret; + + memset(&request, 0, sizeof(request)); + memset(&response, 0, sizeof(response)); + + if (jobid == NULL) + return EINVAL; + + request.command = EDG_WLPR_COMMAND_UNREG; + request.proxy_filename = repository_filename; + request.jobid = strdup(jobid); + if (request.jobid == NULL) + return ENOMEM; + + ret = edg_wlpr_RequestSend(&request, &response); + free(request.jobid); + + if (ret == 0) + ret = response.response_code; + edg_wlpr_CleanResponse(&response); + + return ret; +} + +#ifdef RENEWAL_HAVE_JOBID +int +edg_wlpr_UnregisterProxy(edg_wlc_JobId jobid, const char *repository_filename) +{ + char *ji; + int ret; + + ji = edg_wlc_JobIdUnparse(jobid); + if (ji == NULL) + return EINVAL; + ret = glite_renewal_UnregisterProxy(ji, repository_filename); + free(ji); + return ret; +} +#endif /* RENEWAL_HAVE_JOBID */ + +int +edg_wlpr_GetList(int *count, char **list) +{ + return ENOSYS; /* XXX */ +} + +int +edg_wlpr_GetStatus(const char *filename, char **info) +{ + return ENOSYS; /* XXX */ +} + +static const char* const errTexts[] = { + "Unexpected EOF from peer", + "Generic error", + "Protocol parse error", + "Compulsory element not found in message", + "Unknown protocol command", + "SSL error", + "Error from Myproxy server", + "Proxy not registered", + "Proxy expired", + "VOMS error", + "Operation timed out", + "System error" +}; + +const char * +edg_wlpr_GetErrorText(int code) +{ + return code ? + (code <= EDG_WLPR_ERROR_BASE ? + strerror(code) : + errTexts[code - EDG_WLPR_ERROR_BASE - 1] + ) : + NULL; +} + +int +glite_renewal_GetProxy(const char *jobid, char **repository_filename) +{ + edg_wlpr_Request request; + edg_wlpr_Response response; + int ret; + + memset(&request, 0, sizeof(request)); + memset(&response, 0, sizeof(response)); + + if (jobid == NULL) + return EINVAL; + + request.command = EDG_WLPR_COMMAND_GET; + request.jobid = strdup(jobid); + if (request.jobid == NULL) + return ENOMEM; + + ret = edg_wlpr_RequestSend(&request, &response); + free(request.jobid); + + if (ret == 0 && response.response_code == 0 && repository_filename && + response.filenames && response.filenames[0] ) + *repository_filename = strdup(response.filenames[0]); + + if (ret == 0) + ret = response.response_code; + edg_wlpr_CleanResponse(&response); + + return ret; +} + +#ifdef RENEWAL_HAVE_JOBID +int +edg_wlpr_GetProxy(edg_wlc_JobId jobid, char **repository_filename) +{ + char *ji; + int ret; + + ji = edg_wlc_JobIdUnparse(jobid); + if (ji == NULL) + return EINVAL; + + ret = glite_renewal_GetProxy(ji, repository_filename); + free(ji); + return ret; +} +#endif /* RENEWAL_HAVE_JOBID */ diff --git a/org.glite.px.proxyrenewal/src/client.c b/org.glite.px.proxyrenewal/src/client.c new file mode 100644 index 0000000..87efd78 --- /dev/null +++ b/org.glite.px.proxyrenewal/src/client.c @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include "renewal.h" + +static const char rcsid[] = "$Header$"; + +static struct option const long_options[] = { + { "help", no_argument, 0, 'h' }, + { "version", no_argument, 0, 'v' }, + { "server", required_argument, 0, 's' }, + { "port", required_argument, 0, 'p' }, + { "file", required_argument, 0, 'f' }, + { "jobid", required_argument, 0, 'j' }, + { NULL, 0, NULL, 0} +}; + +static char short_options[] = "hvs:p:f:j:"; + +static void +usage(exit_code) +{ + fprintf(stdout, "Usage: edg-wl-renew [option] operation\n" + "\t-s myproxy_server [-p port] -f filename -j jobid start |\n" + "\t-j jobid [-f filename] stop |\n" + "\t-j jobid get\n" + "-h, --help display this help and exit\n" + "-v, --version output version information and exit\n" + "-s, --server address of myproxy server\n" + "-p, --port port of myproxy server\n" + "-f, --file filename with proxy\n" + "-j, --jobid datagrid jobid\n"); + exit(exit_code); +} + +int +main(int argc, char *argv[]) +{ + char *server = NULL; + int port = 0; + char *proxyfile = NULL; + char *jobid_str = NULL; + char *repository_filename = NULL; + int ret; + int arg; + extern int optind; + + while ((arg = getopt_long(argc, argv, + short_options, long_options, (int *) 0)) != EOF) + switch(arg) { + case 'h': + usage(0); break; + case 'v': + fprintf(stdout, "%s:\t%s\n", argv[0], rcsid); exit(0); + case 's': + server = strdup(optarg); break; + case 'p': + port = atoi(optarg); break; + case 'f': + proxyfile = strdup(optarg); break; + case 'j': + jobid_str = strdup(optarg); break; + default: + usage(1); break; + } + + if (optind >= argc) + usage(1); + + if (strcmp(argv[optind], "start") == 0) { + if (proxyfile == NULL || server == NULL || jobid_str == NULL) + usage(1); + ret = glite_renewal_RegisterProxy(proxyfile, server, port, jobid_str, 0, + &repository_filename); + if (ret) { + fprintf(stderr, "Registering proxy failed: %s\n", + edg_wlpr_GetErrorText(ret)); + exit(1); + } + printf("%s\n", repository_filename); + free(repository_filename); + exit(0); + } + else if (strcmp(argv[optind], "stop") == 0) { + if (jobid_str == NULL) + usage(1); + ret = glite_renewal_UnregisterProxy(jobid_str, proxyfile); + if (ret) { + fprintf(stderr, "Unregistering proxy failed: %s\n", + edg_wlpr_GetErrorText(ret)); + exit(1); + } + } + else if (strcmp(argv[optind], "get") == 0) { + if (jobid_str == NULL) + usage(1); + ret = glite_renewal_GetProxy(jobid_str, &proxyfile); + if (ret) { + fprintf(stderr, "GET request failed: %s\n", + edg_wlpr_GetErrorText(ret)); + exit(1); + } + printf("%s\n", proxyfile); + free(proxyfile); + } + else + usage(1); + + return 0; +} diff --git a/org.glite.px.proxyrenewal/src/commands.c b/org.glite.px.proxyrenewal/src/commands.c new file mode 100644 index 0000000..abc4809 --- /dev/null +++ b/org.glite.px.proxyrenewal/src/commands.c @@ -0,0 +1,1256 @@ +#include "renewal_locl.h" +#include "renewd_locl.h" + +#include "glite/security/voms/voms_apic.h" + +#ident "$Header$" + +#define SEPARATORS ",\n" +#define RENEWAL_START_FRACTION 0.75 /* XXX */ +#define RENEWAL_MIN_LIFETIME (15 * 60) + +extern char *repository; +extern time_t condor_limit; +extern char *cadir; +extern char *vomsdir; +extern int voms_enabled; + +static char * +strmd5(glite_renewal_core_context ctx, const char *s, unsigned char *digest); + +static int +get_record_ext(glite_renewal_core_context ctx, FILE *fd, proxy_record *record, int *last_used_suffix); + +static int +get_record(glite_renewal_core_context ctx, FILE *fd, proxy_record *record); + +static int +store_record(glite_renewal_core_context ctx, char *basename, proxy_record *record); + +static int +copy_file_content(glite_renewal_core_context ctx, FILE *in, FILE *out); + +static int +copy_file(glite_renewal_core_context ctx, char *src, char *dst); + +static int +get_base_filename(glite_renewal_core_context ctx, char *proxy_file, char **basefilename); + +int +decode_record(glite_renewal_core_context ctx, char *line, proxy_record *record); + +int +encode_record(glite_renewal_core_context ctx, proxy_record *record, char **line); + +static int +open_metafile(glite_renewal_core_context ctx, char *proxy_file, FILE **fd); + +void +free_record(glite_renewal_core_context ctx, proxy_record *record); + +static int +realloc_prd_list(glite_renewal_core_context ctx, prd_list *list); + +/* make public: */ +static int +edg_wlpr_GetTokenInt(glite_renewal_core_context ctx, const char *msg, const size_t msg_len, + const char *key, const char *separators, + int req_index, int *value); + +static void +record_to_response(glite_renewal_core_context ctx, int status_code, proxy_record *record, + edg_wlpr_Response *response); + +static int +filename_to_response(glite_renewal_core_context ctx, char *filename, edg_wlpr_Response *response); + + + + +static char * +strmd5(glite_renewal_core_context ctx, const char *s, unsigned char *digest) +{ + MD5_CTX md5; + unsigned char d[16]; + int i; + static char mbuf[33]; + + MD5_Init(&md5); + MD5_Update(&md5,s,strlen(s)); + MD5_Final(d,&md5); + + if (digest) + memcpy(digest,d,sizeof(d)); + for (i=0; i<16; i++) { + int dd = d[i] & 0x0f; + mbuf[2*i+1] = dd<10 ? dd+'0' : dd-10+'a'; + dd = d[i] >> 4; + mbuf[2*i] = dd<10 ? dd+'0' : dd-10+'a'; + } + mbuf[32] = 0; + return mbuf; +} + +static int +get_base_filename(glite_renewal_core_context ctx, char *proxy_file, char **basefilename) +{ + char *subject = NULL; + char file[FILENAME_MAX]; + int ret; + + assert(basefilename != NULL); + + ret = glite_renewal_get_proxy_base_name(ctx, proxy_file, &subject); + if (ret) + goto end; + + snprintf(file, sizeof(file), "%s/%s", repository, strmd5(ctx, subject, NULL)); + *basefilename = strdup(file); /* XXX test ENOMEM */ + ret = 0; + +end: + if (subject) + free(subject); + return ret; +} + +static int +copy_file_content(glite_renewal_core_context ctx, FILE *in, FILE *out) +{ + char buf[1024]; + size_t num; + int ret; + + while (1) { + num = fread(buf, sizeof(*buf), sizeof(buf), in); + if ((ret = ferror(in))) { + glite_renewal_log(ctx, LOG_ERR, "Reading failed: %s", strerror(errno)); + return ret; + } + num = fwrite(buf, sizeof(*buf), num, out); + if ((ret = ferror(in))) { + glite_renewal_log(ctx, LOG_ERR, "Writing failed: %s", strerror(errno)); + return ret; + } + if (feof(in)) + return 0; + } +} + +/* return the time interval, after which the renewal should be started */ +static time_t +get_delta(glite_renewal_core_context ctx, time_t current_time, time_t start_time, time_t end_time) +{ + time_t remaining_life; + time_t life_to_lose; + time_t limit; + time_t delta; + + if (RENEWAL_MIN_LIFETIME > condor_limit) { + limit = RENEWAL_MIN_LIFETIME; + } else { + limit = condor_limit; + } + + limit += RENEWAL_CLOCK_SKEW; + + if (current_time + limit >= end_time) { + /* if the proxy is too short, renew it as soon as possible */ + + if (current_time + condor_limit > end_time ) { + glite_renewal_log(ctx, LOG_ERR, "Remaining proxy lifetime fell below the value of the Condor limit!"); + } + + return 0; + } + + remaining_life = end_time - current_time; + + /* renewal should gain the jobs an extra lifetime of + RENEWAL_START_FRACTION (default 3/4) of the new proxy's + lifetime. If the time remaining on the current proxy is already + small then the jobs may gain an extra lifetime of more than that. + + In any case, a renewal will be scheduled to happen before the + lifetime limit. + + 'life_to_lose' is the lifetime that will be lost, ie the time that + will still remain on the current proxy when it is renewed + */ + + life_to_lose = (1.0-RENEWAL_START_FRACTION)*60*60*DGPR_RETRIEVE_DEFAULT_HOURS; + + if (life_to_lose < limit) { + life_to_lose = limit; + } + + delta = life_to_lose - limit; + + while( remaining_life < (limit + delta) ) { + delta *= (1.0-RENEWAL_START_FRACTION); + } + + life_to_lose = limit + delta; + + return (remaining_life - life_to_lose); +} + +int +get_times(glite_renewal_core_context ctx, char *proxy_file, proxy_record *record) +{ + FILE *fd; + X509 *cert = NULL; + ASN1_UTCTIME *asn1_time = NULL; + int ret; + time_t current_time, start_time, end_time; + + assert(record != NULL); + assert(proxy_file != NULL); + + fd = fopen(proxy_file, "r"); + if (fd == NULL) { + glite_renewal_log(ctx, LOG_ERR, "Opening proxy file %s failed: %s", + proxy_file, strerror(errno)); + return errno; + } + + cert = PEM_read_X509(fd, NULL, NULL, NULL); + if (cert == NULL) { + glite_renewal_log(ctx, LOG_ERR, "Cannot read X.509 certificate from %s", + proxy_file); + ret = -1; /* XXX SSL_ERROR */ + goto end; + } + + asn1_time = ASN1_UTCTIME_new(); + X509_gmtime_adj(asn1_time,0); + globus_gsi_cert_utils_make_time(X509_get_notAfter(cert), &end_time); + globus_gsi_cert_utils_make_time(X509_get_notBefore(cert), &start_time); + current_time = time(NULL); + ASN1_UTCTIME_free(asn1_time); + /* if (end_time - RENEWAL_CLOCK_SKEW < current_time) { Too short proxy } */ + if (end_time + RENEWAL_CLOCK_SKEW < current_time) { + glite_renewal_log(ctx, LOG_ERR, "Expired proxy in %s", proxy_file); + ret = EDG_WLPR_PROXY_EXPIRED; + goto end; + } + + /* Myproxy seems not to do check on expiration and return expired proxies + if credentials in repository are expired */ + X509_free(cert); + cert = NULL; + while (1) { + time_t tmp_end; + /* see http://www.openssl.org/docs/crypto/pem.html section BUGS */ + cert = PEM_read_X509(fd, NULL, NULL, NULL); + if (cert == NULL) { + if (ERR_GET_REASON(ERR_peek_error()) == PEM_R_NO_START_LINE) { + /* End of file reached. no error */ + ERR_clear_error(); + break; + } + glite_renewal_log(ctx, LOG_ERR, "Cannot read additional certificates from %s", + proxy_file); + ret = -1; /* XXX SSL_ERROR */ + goto end; + } + globus_gsi_cert_utils_make_time(X509_get_notAfter(cert), &tmp_end); + if (tmp_end + RENEWAL_CLOCK_SKEW < current_time) { + glite_renewal_log(ctx, LOG_ERR, "Expired proxy in %s", proxy_file); + ret = EDG_WLPR_PROXY_EXPIRED; + goto end; + } + X509_free(cert); + cert = NULL; + } + + record->next_renewal = current_time + get_delta(ctx, current_time, start_time, + end_time); + record->end_time = end_time; + ret = 0; + +end: + fclose(fd); + if (cert) + X509_free(cert); + + return ret; +} + +static int +copy_file(glite_renewal_core_context ctx, char *src, char *dst) +{ + FILE *from = NULL; + FILE *tmp_to = NULL; + int tmp_fd; + char tmpfile[FILENAME_MAX]; + int ret; + + if (strcmp(src, dst) == 0) + return 0; + + from = fopen(src, "r"); + if (from == NULL) { + glite_renewal_log(ctx, LOG_ERR, "Cannot open file %s for reading (%s)", + src, strerror(errno)); + return errno; + } + + snprintf(tmpfile, sizeof(tmpfile), "%s.XXXXXX", dst); + tmp_fd = mkstemp(tmpfile); + if (tmp_fd == -1) { + glite_renewal_log(ctx, LOG_ERR, "Cannot create temporary file (%s)", + strerror(errno)); + ret = errno; + goto end; + } + + + tmp_to = fdopen(tmp_fd, "w"); + if (tmp_to == NULL) { + glite_renewal_log(ctx, LOG_ERR, "Cannot associate stream with temporary file (%s)", + strerror(errno)); + unlink(tmpfile); + ret = errno; + goto end; + } + + ret = copy_file_content(ctx, from, tmp_to); + fclose(tmp_to); + if (ret) { + goto end; + } + + ret = rename(tmpfile, dst); + if (ret) { + glite_renewal_log(ctx, LOG_ERR, "Cannot replace repository file %s with temporary file (%s)", + strerror(errno)); + unlink(tmpfile); + ret = errno; + goto end; + } + tmp_to = NULL; + +end: + fclose(from); + close(tmp_fd); + unlink(tmpfile); + + return ret; +} + +void +free_record(glite_renewal_core_context ctx, proxy_record *record) +{ + int i; + + if (record == NULL) + return; + if (record->myproxy_server) + free(record->myproxy_server); + if (record->jobids.val) { + for (i = 0; i < record->jobids.len; i++) + free(record->jobids.val[i]); + free(record->jobids.val); + } + memset(record, 0, sizeof(*record)); +} + +static int +realloc_prd_list(glite_renewal_core_context ctx, prd_list *list) +{ + char **tmp; + + tmp = realloc(list->val, (list->len + 1) * sizeof(*list->val)); + if (tmp == NULL) + return ENOMEM; + list->val = tmp; + list->len++; + return 0; +} + +static int +get_jobids(glite_renewal_core_context ctx, const char *msg, const size_t msg_len, proxy_record *record) +{ + int index = 0; + int ret; + char *value; + char **tmp; + + memset(&record->jobids, 0, sizeof(record->jobids)); + while ((ret = edg_wlpr_GetToken(msg, msg_len, "jobid=", SEPARATORS, + index, &value)) == 0) { + tmp = realloc(record->jobids.val, (record->jobids.len + 1) * sizeof(*tmp)); + if (tmp == NULL) { + ret = ENOMEM; + break; + } + record->jobids.val = tmp; + record->jobids.val[index] = value; + record->jobids.len++; + index++; + } + if (ret != EDG_WLPR_ERROR_PROTO_PARSE_NOT_FOUND) { + if (record->jobids.len) + free(record->jobids.val); + record->jobids.len = 0; + record->jobids.val = NULL; + return ret; + } + + return 0; +} + +static int +edg_wlpr_GetTokenInt(glite_renewal_core_context ctx, const char *msg, const size_t msg_len, + const char *key, const char *separators, + int req_index, int *value) +{ + int ret; + char *str_value = NULL; + + ret = edg_wlpr_GetToken(msg, msg_len, key, separators, req_index, &str_value); + if (ret) + return ret; + + ret = edg_wlpr_DecodeInt(str_value, value); + free(str_value); + return ret; +} + +int +decode_record(glite_renewal_core_context ctx, char *line, proxy_record *record) +{ + /* line must be ended with '\0' */ + int ret; + size_t len; + + assert(line != NULL); + assert(record != NULL); + + memset(record, 0, sizeof(*record)); + + len = strlen(line) + 1; + + ret = edg_wlpr_GetTokenInt(ctx, line, len, "suffix=", SEPARATORS, 0, + &record->suffix); + if (ret) + return ret; + +#if 0 + ret = edg_wlpr_GetTokenInt(ctx, line, len, "counter=", SEPARATORS, 0, + &record->counter); + if (ret) + goto end; +#endif + + ret = edg_wlpr_GetTokenInt(ctx, line, len, "unique=", SEPARATORS, 0, + &record->unique); + if (ret) + goto end; + + ret = edg_wlpr_GetTokenInt(ctx, line, len, "voms_exts=", SEPARATORS, 0, + &record->voms_exts); + + ret = edg_wlpr_GetToken(line, len, "server=", SEPARATORS, 0, + &record->myproxy_server); + if (ret) + goto end; + + ret = edg_wlpr_GetTokenInt(ctx, line, len, "next_renewal=", SEPARATORS, 0, + (int *)&record->next_renewal); + if (ret) + goto end; + + ret = edg_wlpr_GetTokenInt(ctx, line, len, "end_time=", SEPARATORS, 0, + (int *)&record->end_time); + if (ret) + goto end; + + ret = get_jobids(ctx, line, len, record); + if (ret) + goto end; + +end: + if (ret) + free_record(ctx, record); + + return ret; +} + +int +encode_record(glite_renewal_core_context ctx, proxy_record *record, char **line) +{ + char tmp_line[1024]; + size_t jobids_len = 0; + int i; + + snprintf(tmp_line, sizeof(tmp_line), "suffix=%d, unique=%d, voms_exts=%d, server=%s, next_renewal=%ld, end_time=%ld", + record->suffix, record->unique, record->voms_exts, + (record->myproxy_server) ? record->myproxy_server : "", + record->next_renewal, record->end_time); + for (i = 0; i < record->jobids.len; i++) + /* alloc space for string ", jobid=" */ + jobids_len += 2 + strlen("jobid=") + strlen(record->jobids.val[i]); + + *line = calloc(1, strlen(tmp_line) + jobids_len + 1); + if (*line == NULL) + return ENOMEM; + + strcat(*line, tmp_line); + memset(tmp_line, 0, sizeof(tmp_line)); + + for (i = 0; i < record->jobids.len; i++) { + snprintf(tmp_line, sizeof(tmp_line), ", jobid=%s", record->jobids.val[i]); + strcat(*line, tmp_line); + } + + return 0; +} + +/* Get proxy record from the index file. If no suffix is defined return a free + record with the smallest index */ +static int +get_record_ext(glite_renewal_core_context ctx, FILE *fd, proxy_record *record, int *last_used_suffix) +{ + char line[1024]; + int last_suffix = -1; + int ret; + char *p; + proxy_record tmp_record; + time_t current_time; + int line_num = 0; + + assert(record != NULL); + memset(&tmp_record, 0, sizeof(tmp_record)); + + current_time = time(NULL); + while (fgets(line, sizeof(line), fd) != NULL) { + line_num++; + free_record(ctx, &tmp_record); + p = strchr(line, '\n'); + if (p) + *p = '\0'; + ret = decode_record(ctx, line, &tmp_record); + if (ret) { + glite_renewal_log(ctx, LOG_ERR, "Skipping invalid entry at line %d", line_num); + continue; + } + if (record->suffix >= 0) { + if (record->suffix == tmp_record.suffix) { + record->suffix = tmp_record.suffix; + record->jobids.len = tmp_record.jobids.len; + record->jobids.val = tmp_record.jobids.val; + record->unique = tmp_record.unique; + record->voms_exts = tmp_record.voms_exts; + if (record->myproxy_server) + free(record->myproxy_server); + record->myproxy_server = tmp_record.myproxy_server; + record->end_time = tmp_record.end_time; + record->next_renewal = tmp_record.next_renewal; + return 0; + } else + continue; + } + if (tmp_record.suffix > last_suffix) + last_suffix = tmp_record.suffix; + + /* if no particular suffix was specified get the first free record + available */ + if (tmp_record.jobids.len >= MAX_PROXIES || tmp_record.unique || + tmp_record.voms_exts) + continue; + + if (tmp_record.jobids.len == 0) { + /* no jobs registered for this record, so use it initialized with the + * parameters (currently myproxy location) provided by user */ + record->suffix = tmp_record.suffix; + record->next_renewal = record->end_time = 0; + free_record(ctx, &tmp_record); + return 0; + } + + /* Proxies with VOMS attributes require a separate record, which is not + * shared with another proxies. The same applies it the unique flag was + * set by the caller */ + if (record->voms_exts || record->unique) + continue; + + if (tmp_record.jobids.len > 0 && record->myproxy_server && + strcmp(record->myproxy_server, tmp_record.myproxy_server) != 0) + continue; + + if (tmp_record.jobids.len > 0 && + current_time + condor_limit + RENEWAL_CLOCK_SKEW > tmp_record.end_time) { + + /* skip expired proxy (or ones that are going to expire soon), + leaving it untouched (it will be removed after next run of the + renewal process) */ + + continue; + } + + record->suffix = tmp_record.suffix; + record->jobids.len = tmp_record.jobids.len; + record->jobids.val = tmp_record.jobids.val; + record->unique = tmp_record.unique; + record->voms_exts = tmp_record.voms_exts; + if (record->myproxy_server) + free(record->myproxy_server); + record->myproxy_server = tmp_record.myproxy_server; + record->end_time = tmp_record.end_time; + record->next_renewal = tmp_record.next_renewal; + return 0; + } + + if (last_used_suffix) + *last_used_suffix = last_suffix; + + if (record->suffix >= 0) { + glite_renewal_log(ctx, LOG_DEBUG, "Requested suffix %d not found in meta file", + record->suffix); + } + + free_record(ctx, &tmp_record); + + return EDG_WLPR_ERROR_PROTO_PARSE_NOT_FOUND; +} + +static int +get_record(glite_renewal_core_context ctx, FILE *fd, proxy_record *record) +{ + return get_record_ext(ctx, fd, record, NULL); +} + +static int +store_record(glite_renewal_core_context ctx, char *basename, proxy_record *record) +{ + int stored = 0; + FILE *fd = NULL; + int temp; + char line[1024]; + char *new_line = NULL; + int ret, i; + char *p; + proxy_record tmp_record; + char tmp_file[FILENAME_MAX]; + char meta_file[FILENAME_MAX]; + int line_num = 0; + + assert (record != NULL); + + memset(&tmp_record, 0, sizeof(tmp_record)); + + snprintf(meta_file, sizeof(meta_file), "%s.data", basename); + snprintf(tmp_file, sizeof(tmp_file), "%s.XXXXXX", meta_file); + + temp = mkstemp(tmp_file); + if (temp < 0) + return errno; + + fd = fopen(meta_file, "r"); + if (fd == NULL) { + ret = errno; + goto end; + } + while (fgets(line, sizeof(line), fd) != NULL) { + line_num++; + free_record(ctx, &tmp_record); + p = strchr(line, '\n'); + if (p) + *p = '\0'; + ret = decode_record(ctx, line, &tmp_record); + if (ret) { + glite_renewal_log(ctx, LOG_ERR, "Removing invalid entry at line %d in %s", line_num, basename); + continue; + } + if (record->suffix == tmp_record.suffix && + record->unique == tmp_record.unique) { + tmp_record.next_renewal = record->next_renewal; + tmp_record.end_time = record->end_time; + tmp_record.voms_exts = record->voms_exts; + if (tmp_record.myproxy_server != NULL) + free(tmp_record.myproxy_server); + tmp_record.myproxy_server = strdup(record->myproxy_server); + if (tmp_record.jobids.val) { + for (i = 0; i < tmp_record.jobids.len; i++) + free(tmp_record.jobids.val[i]); + free(tmp_record.jobids.val); + } + tmp_record.jobids.len = 0; + tmp_record.jobids.val = NULL; + for (i = 0; i < record->jobids.len; i++) { + realloc_prd_list(ctx, &tmp_record.jobids); + tmp_record.jobids.val[tmp_record.jobids.len - 1] = + strdup(record->jobids.val[i]); + } + stored = 1; + } + ret = encode_record(ctx, &tmp_record, &new_line); + if (ret) + goto end; + dprintf(temp, "%s\n", new_line); + free(new_line); + new_line = NULL; + } + if (! stored) { + ret = encode_record(ctx, record, &new_line); + if (ret) + goto end; + ret = dprintf(temp, "%s\n", new_line); + free(new_line); + new_line = NULL; + } + fclose(fd); fd = NULL; + close(temp); + + ret = rename(tmp_file, meta_file); + if (ret) + ret = errno; + +end: + free_record(ctx, &tmp_record); + if (fd) + fclose(fd); + close(temp); + return ret; +} + +static int +open_metafile(glite_renewal_core_context ctx, char *basename, FILE **fd) +{ + FILE *meta_fd; + char meta_filename[FILENAME_MAX]; + + snprintf(meta_filename, sizeof(meta_filename), "%s.data", basename); + meta_fd = fopen(meta_filename, "a+"); + if (meta_fd == NULL) { + glite_renewal_log(ctx, LOG_ERR, "Opening meta file %s failed (%s)", + meta_filename, strerror(errno)); + return errno; + } + rewind(meta_fd); + *fd = meta_fd; + glite_renewal_log(ctx, LOG_DEBUG, "Using meta file %s", meta_filename); + return 0; +} + +static int +filename_to_response(glite_renewal_core_context ctx, char *filename, edg_wlpr_Response *response) +{ + response->filenames = malloc(2 * sizeof(*response->filenames)); + if (response->filenames == NULL) { + glite_renewal_log(ctx, LOG_DEBUG, "Not enough memory"); + return errno; + } + response->filenames[0] = strdup(filename); + if (response->filenames[0] == NULL) { + glite_renewal_log(ctx, LOG_DEBUG, "Not enough memory"); + free(response->filenames); + return errno; + } + response->filenames[1] = NULL; + return 0; +} + +static void +record_to_response(glite_renewal_core_context ctx, int status_code, proxy_record *record, + edg_wlpr_Response *response) +{ + /* XXX Neni struktrura proxy_record zbytecna? Mohla by se pouzivat primo + edg_wlpr_Response? */ + response->response_code = status_code; /* XXX chyba parsovatelna pres API */ + if (status_code) + return; + + if (response->myproxy_server) { + response->myproxy_server = strdup(record->myproxy_server); + if (response->myproxy_server == NULL) { + response->response_code = ENOMEM; /* XXX */ + return; + } + } + response->end_time = record->end_time; + response->next_renewal_time = record->next_renewal; + /* XXX use jobid response->counter = record->counter; */ +} + +int +check_proxyname(glite_renewal_core_context ctx, char *datafile, char *jobid, char **filename) +{ + proxy_record record; + FILE *meta_fd = NULL; + char line[1024]; + char proxy[FILENAME_MAX]; + char *p; + int ret, i; + + memset(&record, 0, sizeof(record)); + + meta_fd = fopen(datafile, "r"); + if (meta_fd == NULL) { + glite_renewal_log(ctx, LOG_ERR, "Cannot open meta file %s (%s)", + datafile, strerror(errno)); + return errno; + } + + while (fgets(line, sizeof(line), meta_fd) != NULL) { + free_record(ctx, &record); + p = strchr(line, '\n'); + if (p) + *p = '\0'; + ret = decode_record(ctx, line, &record); + if (ret) + continue; /* XXX exit? */ + for (i = 0; i < record.jobids.len; i++) { + if (strcmp(jobid, record.jobids.val[i]) == 0) { + snprintf(proxy, sizeof(proxy), "%s/%s", repository, datafile); + p = strrchr(proxy, '.'); + sprintf(p, ".%d", record.suffix); + *filename = strdup(proxy); + free_record(ctx, &record); + fclose(meta_fd); + return 0; + } + } + } + free_record(ctx, &record); + fclose(meta_fd); + return EDG_WLPR_ERROR_PROTO_PARSE_NOT_FOUND; +} + +int +find_proxyname(glite_renewal_core_context ctx, char *jobid, char **filename) +{ + DIR *dir = NULL; + struct dirent *file; + int ret; + + chdir(repository); + + dir = opendir(repository); + if (dir == NULL) { + glite_renewal_log(ctx, LOG_ERR, "Cannot open repository directory %s (%s)", + repository, strerror(errno)); + return errno; + } + + while ((file = readdir(dir))) { + /* read files of format `md5sum`.data, where md5sum() is of fixed length + 32 chars */ + if (file->d_name == NULL || strlen(file->d_name) != 37 || + strcmp(file->d_name + 32, ".data") != 0) + continue; + ret = check_proxyname(ctx, file->d_name, jobid, filename); + if (ret == 0) { + closedir(dir); + return 0; + } + } + closedir(dir); + glite_renewal_log(ctx, LOG_ERR, "Requested proxy is not registered"); + return EDG_WLPR_PROXY_NOT_REGISTERED; +} + +#ifdef NOVOMS +int +find_voms_cert(glite_renewal_core_context ctx, char *file, int *present) +{ + *present = 0; + return 0; +} + +#else +int +find_voms_cert(glite_renewal_core_context ctx, char *file, int *present) +{ + struct vomsdata *voms_info = NULL; + STACK_OF(X509) *chain = NULL; + EVP_PKEY *privkey = NULL; + X509 *cert = NULL; + int ret, err; + + *present = 0; + + voms_info = VOMS_Init(vomsdir, cadir); + if (voms_info == NULL) { + glite_renewal_log(ctx, LOG_ERR, "check_voms_cert(): Cannot initialize VOMS context (VOMS_Init() failed, probably voms dir was not specified)"); + return EDG_WLPR_ERROR_VOMS; + } + + ret = glite_renewal_load_proxy(ctx, file, &cert, &privkey, &chain, NULL); + if (ret) { + VOMS_Destroy(voms_info); + return ret; + } + + ret = VOMS_Retrieve(cert, chain, RECURSE_CHAIN, voms_info, &err); + if (ret == 1) { + *present = 1; + } + + VOMS_Destroy(voms_info); + X509_free(cert); + EVP_PKEY_free(privkey); + sk_X509_pop_free(chain, X509_free); + return 0; +} +#endif + +void +register_proxy(glite_renewal_core_context ctx, edg_wlpr_Request *request, edg_wlpr_Response *response) +{ + proxy_record record; + int ret; + FILE *meta_fd = NULL; + int last_suffix; + char *basename = NULL; + char filename[FILENAME_MAX]; + + assert(request != NULL); + assert(response != NULL); + + memset(&record, 0, sizeof(record)); + memset(response, 0, sizeof(*response)); + glite_renewal_log(ctx, LOG_DEBUG, "Registration request for %s", request->proxy_filename); + + if (request->proxy_filename == NULL || request->jobid == NULL) { + glite_renewal_log(ctx, LOG_ERR, "Registration request doesn't contain registration information"); + return; /* EINVAL; */ + } + umask(0177); + + ret = get_base_filename(ctx, request->proxy_filename, &basename); + if (ret) + goto end; + + ret = open_metafile(ctx, basename, &meta_fd); + if (ret) + goto end; + + if (voms_enabled) + ret = find_voms_cert(ctx, request->proxy_filename, &record.voms_exts); + /* ignore VOMS related error */ + + /* Find first free record */ + record.suffix = -1; + record.myproxy_server = strdup(request->myproxy_server); + ret = get_record_ext(ctx, meta_fd, &record, &last_suffix); + fclose(meta_fd); meta_fd = NULL; + if (ret && ret != EDG_WLPR_ERROR_PROTO_PARSE_NOT_FOUND) + goto end; + + if (ret == EDG_WLPR_ERROR_PROTO_PARSE_NOT_FOUND || record.jobids.len == 0 || request->unique || record.voms_exts) { + /* create a new proxy file in the repository */ + int suffix; + + suffix = (record.jobids.len == 0 && record.suffix >= 0) ? + record.suffix : last_suffix + 1; + snprintf(filename, sizeof(filename), "%s.%d", basename, suffix); + ret = copy_file(ctx, request->proxy_filename, filename); + if (ret) + goto end; + ret = get_times(ctx, filename, &record); + if (ret) + goto end; + record.suffix = suffix; + ret = realloc_prd_list(ctx, &record.jobids); + if (ret) + goto end; + record.jobids.val[record.jobids.len - 1] = strdup(request->jobid); + record.unique = request->unique; + glite_renewal_log(ctx, LOG_DEBUG, "Created a new proxy file in repository (%s)", + filename); + } else { + ret = realloc_prd_list(ctx, &record.jobids); + if (ret) + goto end; + record.jobids.val[record.jobids.len - 1] = strdup(request->jobid); + snprintf(filename, sizeof(filename), "%s.%d", basename, record.suffix); + glite_renewal_log(ctx, LOG_DEBUG, "Inremented counter on %s", filename); + } + + ret = store_record(ctx, basename, &record); + +end: + if (meta_fd) { + fclose(meta_fd); + } + + if (basename) + free(basename); + + if (ret == 0) + ret = filename_to_response(ctx, filename, response); + record_to_response(ctx, ret, &record, response); + free_record(ctx, &record); +} + +void +unregister_proxy(glite_renewal_core_context ctx, edg_wlpr_Request *request, edg_wlpr_Response *response) +{ + proxy_record record; + int ret, i, index; + FILE *meta_fd = NULL; + char *basename = NULL; + char *p; + struct stat stat_buf; + + memset(&record, 0, sizeof(record)); + glite_renewal_log(ctx, LOG_DEBUG, "Unregistration request for %s", request->jobid); + + if (request->jobid == NULL) { + glite_renewal_log(ctx, LOG_ERR, "Unregistration request doesn't contain needed information"); + ret = EINVAL; + goto end; + } + + if (request->proxy_filename == NULL) { + ret = find_proxyname(ctx, request->jobid, &request->proxy_filename); + if (ret) + goto end; + } + + ret = get_base_filename(ctx, request->proxy_filename, &basename); + if (ret) { + goto end; + } + + if (strncmp(request->proxy_filename, basename, strlen(basename) != 0)) { + glite_renewal_log(ctx, LOG_DEBUG, "Requested proxy %s is not from repository", + request->proxy_filename); + ret = EDG_WLPR_PROXY_NOT_REGISTERED; + goto end; + } + + p = strrchr(request->proxy_filename, '.'); + if (p == NULL) { + glite_renewal_log(ctx, LOG_DEBUG, "Requested proxy %s is not from repository", + request->proxy_filename); + ret = EDG_WLPR_PROXY_NOT_REGISTERED; + goto end; + } + + ret = edg_wlpr_DecodeInt(p+1, &record.suffix); + if (ret) { + glite_renewal_log(ctx, LOG_DEBUG, "Requested proxy %s is not from repository", + request->proxy_filename); + ret = EDG_WLPR_PROXY_NOT_REGISTERED; + goto end; + } + + ret = open_metafile(ctx, basename, &meta_fd); + if (ret) { + /* fill in error response */ + return; + } + + ret = get_record(ctx, meta_fd, &record); + if (ret) + goto end; + + ret = EDG_WLPR_PROXY_NOT_REGISTERED; + for (i = 0; i < record.jobids.len; i++) + if (strcmp(request->jobid, record.jobids.val[i]) == 0) { + ret = 0; + break; + } + if (ret) { + glite_renewal_log(ctx, LOG_DEBUG, "Requested proxy %s is not registered", + request->proxy_filename); + goto end; + } + + /* remove jobid from the list */ + index = i; + free(record.jobids.val[i]); + record.jobids.len--; + for (i = index; i < record.jobids.len; i++) + record.jobids.val[i] = record.jobids.val[i+1]; + + if (record.jobids.len == 0) { + record.unique = 0; + record.voms_exts = 0; + record.end_time = 0; + record.next_renewal = 0; + } + + ret = stat(request->proxy_filename, &stat_buf); + if (ret) { + glite_renewal_log(ctx, LOG_DEBUG, "Cannot stat file %s: (%s)", + request->proxy_filename, strerror(errno)); + ret = errno; + goto end; + } + + ret = store_record(ctx, basename, &record); + if (ret) + goto end; + + if (record.jobids.len == 0) + unlink(request->proxy_filename); + +end: + if (meta_fd) { + fclose(meta_fd); + } + if (basename) + free(basename); + + if (ret == 0) + ret = filename_to_response(ctx, request->proxy_filename, response); + record_to_response(ctx, ret, &record, response); + free_record(ctx, &record); +} + +void +get_proxy(glite_renewal_core_context ctx, edg_wlpr_Request *request, edg_wlpr_Response *response) +{ + char *filename = NULL; + int ret; + + memset(response, 0, sizeof(*response)); + + glite_renewal_log(ctx, LOG_DEBUG, "GET request for %s", request->jobid); + + if (request->jobid == NULL) { + glite_renewal_log(ctx, LOG_ERR, "GET request doesn't contain jobid specification"); + ret = EINVAL; + goto end; + } + + ret = find_proxyname(ctx, request->jobid, &filename); + +end: + if (ret == 0) + ret = filename_to_response(ctx, filename, response); + if (filename) + free(filename); + response->response_code = ret; +} + +void +update_db(glite_renewal_core_context ctx, edg_wlpr_Request *request, edg_wlpr_Response *response) +{ + FILE *fd = NULL; + int tmp_fd = -1; + int suffix = -1; + char tmp_file[FILENAME_MAX]; + char cur_proxy[FILENAME_MAX]; + char datafile[FILENAME_MAX]; + char line[1024]; + char *new_line = NULL; + char *basename, *proxy = NULL; + char **entry; + proxy_record record; + int ret; + char *p; + time_t current_time; + + memset(&record, 0, sizeof(record)); + + glite_renewal_log(ctx, LOG_DEBUG, "UPDATE_DB request for %s", request->proxy_filename); + + chdir(repository); + basename = request->proxy_filename; + + snprintf(datafile, sizeof(datafile), "%s.data", basename); + fd = fopen(datafile, "r"); + if (fd == NULL) { + glite_renewal_log(ctx, LOG_ERR, "Cannot open meta file %s (%s)", + datafile, strerror(errno)); + ret = errno; + return; + } + + snprintf(tmp_file, sizeof(tmp_file), "%s.XXXXXX", datafile); + tmp_fd = mkstemp(tmp_file); + if (tmp_fd < 0) { + glite_renewal_log(ctx, LOG_ERR, "Cannot create temporary file (%s)", + strerror(errno)); + ret = errno; + goto end; + } + + entry = request->entries; + if (entry) { + p = strchr(*entry, ':'); + *p = '\0'; + suffix = atoi(*entry); + proxy = p+1; + } + + current_time = time(NULL); + + while (fgets(line, sizeof(line), fd) != NULL) { + free_record(ctx, &record); + p = strchr(line, '\n'); + if (p) + *p = '\0'; + ret = decode_record(ctx, line, &record); + if (ret) + goto end; + + if (record.suffix > suffix && entry && *entry) { + do { + entry++; + if (entry == NULL || *entry == NULL) { + suffix = -1; + break; + } + + p = strchr(*entry, ':'); + suffix = atoi(*entry); + proxy = p+1; + } while (record.suffix > suffix); + } + + if (record.suffix == suffix) { + snprintf(cur_proxy, sizeof(cur_proxy), "%s.%d", basename, suffix); + if (proxy == NULL || *proxy == '\0') { + /* if proxy isn't specified use file registered currently and + * reschedule renewal */ + if (record.end_time < current_time) { + char *server; + /* remove file with expired proxy and clean the record in db */ + unlink(cur_proxy); + server = strdup(record.myproxy_server); + free_record(ctx, &record); + record.suffix = suffix; + record.myproxy_server = server; + glite_renewal_log(ctx, LOG_WARNING, "Removed expired proxy %s", cur_proxy); + } else + get_times(ctx, cur_proxy, &record); + } else { + ret = get_times(ctx, proxy, &record); + (ret == 0) ? rename(proxy, cur_proxy) : unlink(proxy); + } + } + + ret = encode_record(ctx, &record, &new_line); + if (ret) + goto end; + + dprintf(tmp_fd, "%s\n", new_line); + free(new_line); + new_line = NULL; + } + free_record(ctx, &record); + + close(tmp_fd); + fclose(fd); + + rename(tmp_file, datafile); + + return; + +end: + if (fd) + fclose(fd); + unlink(tmp_file); + if (tmp_fd > 0) + close(tmp_fd); + free_record(ctx, &record); + + return; +} diff --git a/org.glite.px.proxyrenewal/src/common.c b/org.glite.px.proxyrenewal/src/common.c new file mode 100644 index 0000000..206bc2f --- /dev/null +++ b/org.glite.px.proxyrenewal/src/common.c @@ -0,0 +1,322 @@ +#include "renewal_locl.h" + +#ident "$Header$" + +/* nread() and nwrite() never return partial data */ +static int +nread(int sock, struct timeval *to, char *buf, size_t buf_len, size_t *read_len) +{ + int count; + size_t remain = buf_len; + char *cbuf = buf; + struct pollfd pollfds[1]; + struct timeval before,after; + int ret; + + if (to) { + gettimeofday(&before,NULL); + } + + while (remain > 0) { + pollfds[0].fd = sock; + pollfds[0].events = POLLIN; + switch (poll(pollfds, 1, to ? (to->tv_sec*1000+to->tv_usec/1000) : INFTIM)) { + case 0: + ret = EDG_WLPR_ERROR_TIMEOUT; + goto end; + case -1: + ret = EDG_WLPR_ERROR_ERRNO; + goto end; + } + + count = read(sock, cbuf, remain); + if (count < 0) { + if (errno == EINTR) + continue; + else { + ret = EDG_WLPR_ERROR_ERRNO; + goto end; + } + } else + if (count == 0) { + *read_len = 0; + return 0; + } + cbuf += count; + remain -= count; + } + *read_len = buf_len; + ret = 0; + +end: + if (to) { + gettimeofday(&after,NULL); + edg_wlpr_DecrementTimeout(to, before, after); + if (to->tv_sec < 0) { + to->tv_sec = 0; + to->tv_usec = 0; + } + } + + return ret; +} + +static int +nwrite(int sock, struct timeval *to, const char *buf, size_t buf_len) +{ + const char *cbuf = buf; + int count; + size_t remain = buf_len; + struct pollfd pollfds[1]; + struct timeval before,after; + int ret; + + if (to) { + gettimeofday(&before,NULL); + } + + while (remain > 0) { + pollfds[0].fd = sock; + pollfds[0].events = POLLOUT; + switch (poll(pollfds, 1, to ? (to->tv_sec*1000+to->tv_usec/1000) : INFTIM)) { + case 0: ret = EDG_WLPR_ERROR_TIMEOUT; + goto end; + case -1: ret = EDG_WLPR_ERROR_ERRNO; + goto end; + } + + count = write(sock, cbuf, remain); + if (count < 0) { + if (errno == EINTR) + continue; + else { + ret = EDG_WLPR_ERROR_ERRNO; + goto end; + } + } + cbuf += count; + remain -= count; + } + ret = 0; + +end: + if (to) { + gettimeofday(&after,NULL); + edg_wlpr_DecrementTimeout(to, before, after); + if (to->tv_sec < 0) { + to->tv_sec = 0; + to->tv_usec = 0; + } + } + + return ret; +} + +int +edg_wlpr_Read(int sock, struct timeval *timeout, char **buf, size_t *buf_len) +{ + int ret; + unsigned char length[4]; + size_t len; + + ret = nread(sock, timeout, length, 4, &len); + if (ret) { + *buf_len = 0; + return ret; + } + if (len != 4) { + *buf_len = 0; + return EDG_WLPR_ERROR_UNEXPECTED_EOF; /* XXX vraci i kdyz peer spadne a zavre trubku */ + } + *buf_len = (length[0] << 24) | + (length[1] << 16) | + (length[2] << 8 ) | + (length[3] << 0); + + *buf = malloc(*buf_len); + if (*buf == NULL) + return ENOMEM; + + ret = nread(sock, timeout, *buf, *buf_len, &len); + if (ret) + return ret; + + if (len != *buf_len) { + free(*buf); + *buf_len = 0; + return EDG_WLPR_ERROR_UNEXPECTED_EOF; /* XXX */ + } + + return 0; +} + +int +edg_wlpr_Write(int sock, struct timeval *timeout, char *buf, size_t buf_len) +{ + unsigned char length[4]; + int ret; + + length[0] = (buf_len >> 24) & 0xFF; + length[1] = (buf_len >> 16) & 0xFF; + length[2] = (buf_len >> 8) & 0xFF; + length[3] = (buf_len >> 0) & 0xFF; + + if ((ret = nwrite(sock, timeout, length, 4)) != 0 || + (ret = nwrite(sock, timeout, buf, buf_len)) != 0) + return ret; + + return 0; +} + +int +edg_wlpr_GetToken(const char *msg, const size_t msg_len, + const char *key, const char *separators, + int req_index, char **value) +{ + char *p; + size_t len; + int index; + + assert(separators != NULL); + + /* Add ending zero ? */ + + index = 0; + p = (char *)msg; + while (p && (p = strstr(p, key))) { + if (index == req_index) + break; + index++; + p += strlen(key); + } + if (p == NULL) + return EDG_WLPR_ERROR_PROTO_PARSE_NOT_FOUND; + + p = strchr(p, '='); + if (p == NULL) + return EDG_WLPR_ERROR_PROTO_PARSE_ERROR; + + len = strcspn(p+1, separators); + if (len == 0) + return EDG_WLPR_ERROR_PROTO_PARSE_ERROR; + + *value = malloc(len + 1); + if (*value == NULL) + return ENOMEM; + + memcpy(*value, p+1, len); + (*value)[len] = '\0'; + + return 0; +} + +int +edg_wlpr_StoreToken(char **buf, size_t *buf_len, char *command, + char *value, const char *separator) +{ + char line[2048]; + char *tmp; + + assert(buf != NULL); + assert(separator != NULL); + + if (strlen(command) + 1 + strlen(value) + 2 > sizeof(line)) + return ERANGE; /* XXX */ + + snprintf(line, sizeof(line), "%s%s%s", command, value, separator); + + while (strlen(*buf) + strlen(line) + 1 > *buf_len) { + tmp = realloc(*buf, *buf_len + EDG_WLPR_BUF_SIZE); + if (tmp == NULL) + return ENOMEM; + *buf = tmp; + *buf_len += EDG_WLPR_BUF_SIZE; + } + strcat(*buf, line); + + return 0; +} + +void +edg_wlpr_CleanRequest(edg_wlpr_Request *request) +{ + assert(request != NULL); + if (request->version) + free(request->version); + if (request->proxy_filename) + free(request->proxy_filename); + if (request->myproxy_server) + free(request->myproxy_server); + if (request->jobid) + free(request->jobid); + if (request->entries) { + char **p = request->entries; + char **next; + while (*p) { + next = p+1; + free(*p); + p = next; + } + free(request->entries); + } + + memset(request, 0, sizeof(request)); +} + +void +edg_wlpr_CleanResponse(edg_wlpr_Response *response) +{ + assert(response != NULL); + if (response->version) + free(response->version); + if (response->myproxy_server) + free(response->myproxy_server); + if (response->filenames) { + char **p = response->filenames; + char **next; + + while (*p) { + next = p+1; + free(*p); + p = next; + } + free(response->filenames); + } + memset(response, 0, sizeof(*response)); +} + +const char * +edg_wlpr_GetErrorString(int code) +{ + return (code == 0) ? "OK" : "Error"; +} + +char * +edg_wlpr_EncodeInt(int num) /* long? time */ +{ + static char ret[64]; + + snprintf(ret, sizeof(ret), "%d", num); + return ret; +} + +int +edg_wlpr_DecodeInt(char *str, int *num) +{ + *num = atol(str); /* XXX */ + return 0; +} + +int +edg_wlpr_DecrementTimeout(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); +} diff --git a/org.glite.px.proxyrenewal/src/renew.c b/org.glite.px.proxyrenewal/src/renew.c new file mode 100644 index 0000000..29105d2 --- /dev/null +++ b/org.glite.px.proxyrenewal/src/renew.c @@ -0,0 +1,256 @@ +#include "renewal_locl.h" +#include "renewd_locl.h" + +#include "glite/security/voms/voms_apic.h" + +#ident "$Header$" + +#define RENEWAL_COUNTS_MAX 1000 /* the slave daemon exits after that many attemtps */ + +extern char *repository; +extern char *cadir; +extern char *vomsdir; +extern int voms_enabled; +static int received_signal = -1, die = 0; + +static void +check_renewal(glite_renewal_core_context ctx, char *datafile, int force_renew, int *num_renewed); + +static int +renew_proxy(glite_renewal_core_context ctx, proxy_record *record, char *basename, char **new_proxy); + +static void +register_signal(int signal); + +static void +register_signal(int signal) +{ + received_signal = signal; + switch ((received_signal = signal)) { + case SIGINT: + case SIGTERM: + case SIGQUIT: + die = signal; + break; + default: + break; + } +} + +static int +renew_proxy(glite_renewal_core_context ctx, proxy_record *record, char *basename, char **new_proxy) +{ + char repository_file[FILENAME_MAX]; + int ret = -1; + char *p = NULL; + char *server = NULL; + unsigned int port = 0; + + snprintf(repository_file, sizeof(repository_file),"%s.%d", + basename, record->suffix); + + if (record->myproxy_server) + server = strdup(record->myproxy_server); + + if (server && (p = strchr(server, ':'))) { + *p++ = '\0'; + ret = edg_wlpr_DecodeInt(p, &port); + } + + ret = glite_renewal_core_renew(ctx, server, port, repository_file, new_proxy); + if (ret) + goto end; + + ret = 0; + +end: + if (server) + free(server); + + return ret; +} + +static void +check_renewal(glite_renewal_core_context ctx, char *datafile, int force_renew, int *num_renewed) +{ + char line[1024]; + proxy_record record; + char *p; + int ret, i; + time_t current_time; + FILE *meta_fd = NULL; + char basename[FILENAME_MAX]; + edg_wlpr_Request request; + edg_wlpr_Response response; + char *new_proxy = NULL; + char *entry = NULL; + char **tmp; + int num = 0; + + assert(datafile != NULL); + + *num_renewed = 0; + + memset(&record, 0, sizeof(record)); + memset(basename, 0, sizeof(basename)); + memset(&request, 0, sizeof(request)); + memset(&response, 0, sizeof(response)); + + strncpy(basename, datafile, sizeof(basename) - 1); + p = basename + strlen(basename) - strlen(".data"); + if (strcmp(p, ".data") != 0) { + glite_renewal_log(ctx, LOG_ERR, "Meta filename doesn't end with '.data'"); + return; + } + *p = '\0'; + + request.command = EDG_WLPR_COMMAND_UPDATE_DB; + request.proxy_filename = strdup(basename); + + meta_fd = fopen(datafile, "r"); + if (meta_fd == NULL) { + glite_renewal_log(ctx, LOG_ERR, "Cannot open meta file %s (%s)", + datafile, strerror(errno)); + return; + } + + current_time = time(NULL); + glite_renewal_log(ctx, LOG_DEBUG, "Reading metafile %s", datafile); + + while (fgets(line, sizeof(line), meta_fd) != NULL) { + free_record(ctx, &record); + p = strchr(line, '\n'); + if (p) + *p = '\0'; + ret = decode_record(ctx, line, &record); + if (ret) + continue; /* XXX exit? */ + if (record.jobids.len == 0) /* no jobid registered for this proxy */ + continue; + if (current_time + RENEWAL_CLOCK_SKEW >= record.end_time || + record.next_renewal <= current_time || + force_renew) { + ret = EDG_WLPR_PROXY_EXPIRED; + if ( record.end_time + RENEWAL_CLOCK_SKEW >= current_time) { + /* only try renewal if the proxy hasn't already expired */ + ret = renew_proxy(ctx, &record, basename, &new_proxy); + } + + /* if the proxy wasn't renewed have the daemon planned another renewal */ + asprintf(&entry, "%d:%s", record.suffix, (ret == 0) ? new_proxy : ""); + if (new_proxy) { + free(new_proxy); new_proxy = NULL; + } + + tmp = realloc(request.entries, (num + 2) * sizeof(*tmp)); + if (tmp == NULL) { + free_record(ctx, &record); + return; + } + request.entries = tmp; + request.entries[num] = entry; + request.entries[num+1] = NULL; + num++; + } + } + free_record(ctx, &record); + + if (num > 0) { + ret = edg_wlpr_RequestSend(&request, &response); + if (ret != 0) + glite_renewal_log(ctx, LOG_ERR, + "Failed to send update request to master (%d)", ret); + else if (response.response_code != 0) + glite_renewal_log(ctx, LOG_ERR, + "Master failed to update database (%d)", response.response_code); + + /* delete all tmp proxy files which may survive */ + for (i = 0; i < num; i++) { + p = strchr(request.entries[i], ':'); + if (p+1) + unlink(p+1); + } + } + fclose(meta_fd); + + edg_wlpr_CleanResponse(&response); + edg_wlpr_CleanRequest(&request); + + *num_renewed = num; + + return; +} + +int renewal(glite_renewal_core_context ctx, int force_renew, int *num_renewed) +{ + DIR *dir = NULL; + struct dirent *file; + FILE *fd; + int num = 0; + + glite_renewal_log(ctx, LOG_DEBUG, "Starting renewal process"); + + *num_renewed = 0; + + if (chdir(repository)) { + glite_renewal_log(ctx, LOG_ERR, "Cannot access repository directory %s (%s)", + repository, strerror(errno)); + return errno; + } + + dir = opendir(repository); + if (dir == NULL) { + glite_renewal_log(ctx, LOG_ERR, "Cannot open repository directory %s (%s)", + repository, strerror(errno)); + return errno; + } + + while ((file = readdir(dir))) { + /* read files of format `md5sum`.data, where md5sum() is of fixed length + 32 chars */ + if (file->d_name == NULL || strlen(file->d_name) != 37 || + strcmp(file->d_name + 32, ".data") != 0) + continue; + fd = fopen(file->d_name, "r"); + if (fd == NULL) { + glite_renewal_log(ctx, LOG_ERR, "Cannot open meta file %s (%s)", + file->d_name, strerror(errno)); + continue; + } + check_renewal(ctx, file->d_name, force_renew, &num); + *num_renewed += num; + fclose(fd); + } + closedir(dir); + glite_renewal_log(ctx, LOG_DEBUG, "Finishing renewal process"); + return 0; +} + +void +watchdog_start(glite_renewal_core_context ctx) +{ + struct sigaction sa; + int force_renewal; + int count = 0, num; + + memset(&sa,0,sizeof(sa)); + sa.sa_handler = register_signal; + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGINT,&sa,NULL); + sigaction(SIGQUIT,&sa,NULL); + sigaction(SIGTERM,&sa,NULL); + sigaction(SIGPIPE,&sa,NULL); + + while (count < RENEWAL_COUNTS_MAX && !die) { + received_signal = -1; + sleep(60 * 5); + force_renewal = (received_signal == SIGUSR1) ? 1 : 0; + if (die) + break; + /* XXX uninstall signal handler ? */ + renewal(ctx, force_renewal, &num); + count += num; + } + glite_renewal_log(ctx, LOG_DEBUG, "Terminating after %d renewal attempts", count); + exit(0); +} diff --git a/org.glite.px.proxyrenewal/src/renewal_core.c b/org.glite.px.proxyrenewal/src/renewal_core.c new file mode 100644 index 0000000..3bd2d1d --- /dev/null +++ b/org.glite.px.proxyrenewal/src/renewal_core.c @@ -0,0 +1,283 @@ +#include +#include + +#include "renewal_core.h" +#include "renewal_locl.h" +#include "renewd_locl.h" + +static const char rcsid[] = "$Id$"; + +int +glite_renewal_load_proxy(glite_renewal_core_context ctx, const char *cur_file, X509 **cert, EVP_PKEY **priv_key, + STACK_OF(X509) **chain, globus_gsi_cred_handle_t *cur_proxy) +{ + globus_result_t result; + globus_gsi_cred_handle_t proxy = NULL; + int ret; + + result = globus_gsi_cred_handle_init(&proxy, NULL); + if (result) { + fprintf(stderr, "globus_gsi_cred_handle_init() failed\n"); + goto end; + } + + result = globus_gsi_cred_read_proxy(proxy, (char *) cur_file); + if (result) { + fprintf(stderr, "globus_gsi_cred_read_proxy() failed\n"); + goto end; + } + + if (cert) { + result = globus_gsi_cred_get_cert(proxy, cert); + if (result) { + fprintf(stderr, "globus_gsi_cred_get_cert() failed\n"); + goto end; + } + } + + if (priv_key) { + result = globus_gsi_cred_get_key(proxy, priv_key); + if (result) { + fprintf(stderr, "globus_gsi_cred_get_key() failed\n"); + goto end; + } + } + + if (chain) { + result = globus_gsi_cred_get_cert_chain(proxy, chain); + if (result) { + fprintf(stderr, "globus_gsi_cred_get_cert_chain() failed\n"); + goto end; + } + } + + if (cur_proxy) { + *cur_proxy = proxy; + proxy = NULL; + } + + ret = 0; + +end: + if (proxy) + globus_gsi_cred_handle_destroy(proxy); + if (result) + ret = EDG_WLPR_ERROR_GENERIC; + + return ret; +} + +int +glite_renewal_get_proxy_base_name(glite_renewal_core_context ctx, const char *file, char **name) +{ + X509 *cert = NULL; + EVP_PKEY *key = NULL; + STACK_OF(X509) *chain = NULL; + X509_NAME *subject = NULL; + int ret; + globus_result_t result; + + ret = glite_renewal_load_proxy(ctx, file, &cert, &key, &chain, NULL); + if (ret) + return ret; + + subject = X509_NAME_dup(X509_get_subject_name(cert)); + + sk_X509_insert(chain, cert, 0); + cert = NULL; + + result = globus_gsi_cert_utils_get_base_name(subject, chain); + if (result) { + glite_renewal_log(ctx, LOG_ERR, "Cannot get subject name from proxy %s", file); + ret = EDG_WLPR_ERROR_SSL; /* XXX ??? */ + goto end; + } + + *name = X509_NAME_oneline(subject, NULL, 0); + ret = 0; + +end: + if (cert) + X509_free(cert); + if (key) + EVP_PKEY_free(key); + if (chain) + sk_X509_pop_free(chain, X509_free); + if (subject) + X509_NAME_free(subject); + + return ret; +} + +int +glite_renewal_core_renew(glite_renewal_core_context ctx, + const char * myproxy_server, + unsigned int myproxy_port, + const char *current_proxy, + char **new_proxy) +{ + char tmp_proxy[FILENAME_MAX]; + int tmp_fd; + int ret = -1; + char *p; + const char *server = NULL; + myproxy_socket_attrs_t *socket_attrs; + myproxy_request_t *client_request; + myproxy_response_t *server_response; + char *renewed_proxy; + int voms_exts; + + socket_attrs = malloc(sizeof(*socket_attrs)); + memset(socket_attrs, 0, sizeof(*socket_attrs)); + + client_request = malloc(sizeof(*client_request)); + memset(client_request, 0, sizeof(*client_request)); + + server_response = malloc(sizeof(*server_response)); + memset(server_response, 0, sizeof(*server_response)); + + myproxy_set_delegation_defaults(socket_attrs, client_request); + + glite_renewal_log(ctx, LOG_DEBUG, "Trying to renew proxy in %s", current_proxy); + + snprintf(tmp_proxy, sizeof(tmp_proxy), "%s.myproxy.XXXXXX", current_proxy); + tmp_fd = mkstemp(tmp_proxy); + if (tmp_fd == -1) { + glite_renewal_log(ctx, LOG_ERR, "Cannot create temporary file (%s)", + strerror(errno)); + return errno; + } + + ret = glite_renewal_get_proxy_base_name(ctx, current_proxy, &client_request->username); + if (ret) + goto end; + + voms_exts = glite_renewal_check_voms_attrs(ctx, current_proxy); + + client_request->proxy_lifetime = 60 * 60 * DGPR_RETRIEVE_DEFAULT_HOURS; + + server = (myproxy_server) ? myproxy_server : socket_attrs->pshost; + if (server == NULL) { + glite_renewal_log(ctx, LOG_ERR, "No myproxy server specified"); + ret = EINVAL; + goto end; + } + socket_attrs->pshost = strdup(server); + + socket_attrs->psport = (myproxy_port) ? myproxy_port : MYPROXY_SERVER_PORT; + + verror_clear(); + ret = myproxy_get_delegation(socket_attrs, client_request, (char *) current_proxy, + server_response, tmp_proxy); + if (ret == 1) { + ret = EDG_WLPR_ERROR_MYPROXY; + glite_renewal_log(ctx, LOG_ERR, "Error contacting MyProxy server for proxy %s: %s", + current_proxy, verror_get_string()); + verror_clear(); + goto end; + } + + renewed_proxy = tmp_proxy; + + if (voms_exts) { + char tmp_voms_proxy[FILENAME_MAX]; + int tmp_voms_fd; + + snprintf(tmp_voms_proxy, sizeof(tmp_voms_proxy), "%s.voms.XXXXXX", + current_proxy); + tmp_voms_fd = mkstemp(tmp_voms_proxy); + if (tmp_voms_fd == -1) { + glite_renewal_log(ctx, LOG_ERR, "Cannot create temporary file (%s)", + strerror(errno)); + ret = errno; + goto end; + } + + ret = glite_renewal_renew_voms_creds(ctx, current_proxy, renewed_proxy, tmp_voms_proxy); + close(tmp_voms_fd); + if (ret) { + unlink(tmp_voms_proxy); + goto end; + } + + renewed_proxy = tmp_voms_proxy; + unlink(tmp_proxy); + } + + if (new_proxy) + *new_proxy = strdup(renewed_proxy); + + ret = 0; + +end: + if (socket_attrs->socket_fd) + close(socket_attrs->socket_fd); + close(tmp_fd); + if (ret) + unlink(tmp_proxy); + myproxy_free(socket_attrs, client_request, server_response); + + return ret; +} + +int +glite_renewal_core_init_ctx(glite_renewal_core_context *context) +{ + glite_renewal_core_context p = NULL; + + *context = NULL; + + p = calloc(1, sizeof(*p)); + if (p == NULL) + return ENOMEM; + + p->log_level = LOG_ERR; + p->log_dst = GLITE_RENEWAL_LOG_SYSLOG; + + *context = p; + return 0; +} + +int +glite_renewal_core_destroy_ctx(glite_renewal_core_context context) +{ + if (context == NULL) + return 0; + if (context->err_message); + free(context->err_message); + free(context); + return 0; +} + +void +glite_renewal_log(glite_renewal_core_context context, int dbg_level, const char *format, ...) +{ + va_list ap; + + if (context->err_message) { + free(context->err_message); + context->err_message = NULL; + } + + /* cannot handle the %m format argument specific for syslog() */ + va_start(ap, format); + vasprintf(&context->err_message, format, ap); + va_end(ap); + + if (dbg_level > context->log_level) + return; + + switch (context->log_dst) { + case GLITE_RENEWAL_LOG_STDOUT: + printf("%s\n", context->err_message); + break; + case GLITE_RENEWAL_LOG_SYSLOG: + syslog(dbg_level, "%s", context->err_message); + break; + case GLITE_RENEWAL_LOG_NONE: + default: + break; + } + + return; +} diff --git a/org.glite.px.proxyrenewal/src/renewal_locl.h b/org.glite.px.proxyrenewal/src/renewal_locl.h new file mode 100644 index 0000000..256eb26 --- /dev/null +++ b/org.glite.px.proxyrenewal/src/renewal_locl.h @@ -0,0 +1,148 @@ +#ifndef RENEWAL_LOCL_H +#define RENEWAL_LOCL_H + +#ident "$Header$" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef INFTIM +#define INFTIM (-1) +#endif + +#include +#include +#include +#include + +#include "renewal.h" + +#define JDL_MYPROXY "Myproxy_server=" + +typedef enum { + EDG_WLPR_COMMAND_NONE = 0, + EDG_WLPR_COMMAND_REG = 1, + EDG_WLPR_COMMAND_UNREG, + EDG_WLPR_COMMAND_GET, + EDG_WLPR_COMMAND_LIST, + EDG_WLPR_COMMAND_STATUS, + EDG_WLPR_COMMAND_UPDATE_DB, +} edg_wlpr_Command; + +/* prefix neni nutny */ +#define EDG_WLPR_PROTO_VERSION "Version=" +#define EDG_WLPR_PROTO_COMMAND "Command=" +#define EDG_WLPR_PROTO_MYPROXY_SERVER "Myproxy_server=" +#define EDG_WLPR_PROTO_PROXY "Proxy_name=" +#define EDG_WLPR_PROTO_UNIQUE_PROXY "Unique=" /* XXX */ +#define EDG_WLPR_PROTO_JOBID "Jobid=" +#define EDG_WLPR_PROTO_ENTRY "Entry=" + +#define EDG_WLPR_PROTO_RESPONSE "Response=" /* XXX result ?? */ +#define EDG_WLPR_PROTO_START_TIME "Start_time=" +#define EDG_WLPR_PROTO_END_TIME "End_time=" +#define EDG_WLPR_PROTO_RENEWAL_TIME "Renewal_time=" /* XXX Next renewal ?? */ + +#define EDG_WLPR_MYPROXY_PORT 7512 + +#define EDG_WLPR_REPOSITORY_ROOT "/var/spool/edg-wl-renewd" + +#define EDG_WLPR_BUF_SIZE 4096 + +#define EDG_WLPR_VERSION "EDG Proxy Renewal 1.0" + +#define MAX_PROXIES 4 /* max. number of jobids sharing one proxy */ + +#define RENEWAL_CLOCK_SKEW (5 * 60) + +#define DGPR_RETRIEVE_DEFAULT_HOURS 10 + +#define GLITE_PR_TIMEOUT_DEFAULT 120 + +typedef struct { + char *version; + edg_wlpr_Command command; + char *myproxy_server; + char *proxy_filename; + int unique; + char *jobid; + char **entries; /* for updates from the renewal part (renew.c) */ +} edg_wlpr_Request; + +typedef struct { + char *version; + int response_code; + time_t start_time; + time_t end_time; + time_t next_renewal_time; + int counter; + char *myproxy_server; + char **filenames; +} edg_wlpr_Response; + +#define DGPR_REG_SOCKET_NAME_ROOT "/tmp/dgpr_renew_" + +#if 0 +/* Errors: */ +/* XXX enum */ +#define EDG_WLPR_ERROR_EOF 1 +#define EDG_WLPR_ERROR_PARSE_NOT_FOUND 2 +#define EDG_WLPR_ERROR_PARSE_ERROR 3 +#define EDG_WLPR_ERROR_UNKNOWN_COMMAND 4 +#define EDG_WLPR_ERROR_NOTFOUND 5 +#endif + +int +edg_wlpr_GetToken(const char *msg, const size_t msg_len, + const char *key, const char *separators, + int req_index, char **value); + +int +edg_wlpr_StoreToken(char **buf, size_t *buf_len, char *command, + char *value, const char *separator); + +int +edg_wlpr_Read(int sock, struct timeval *timeout, char **buf, size_t *buf_len); + +int +edg_wlpr_Write(int sock, struct timeval *timeout, char *buf, size_t buf_len); + +void +edg_wlpr_CleanRequest(edg_wlpr_Request *request); + +void +edg_wlpr_CleanResponse(edg_wlpr_Response *response); + +const char * +edg_wlpr_GetErrorString(int err); + +char * +edg_wlpr_EncodeInt(int num); /* long? time */ + +int +edg_wlpr_DecodeInt(char *str, int *num); + +int +edg_wlpr_RequestSend(edg_wlpr_Request *request, edg_wlpr_Response *response); + +int +edg_wlpr_DecrementTimeout(struct timeval *timeout, struct timeval before, struct timeval after); + +#endif /* RENEWAL_LOCL_H */ diff --git a/org.glite.px.proxyrenewal/src/renewd.c b/org.glite.px.proxyrenewal/src/renewd.c new file mode 100644 index 0000000..69a2ea0 --- /dev/null +++ b/org.glite.px.proxyrenewal/src/renewd.c @@ -0,0 +1,606 @@ +#include "renewal_locl.h" +#include "renewd_locl.h" + +static const char rcsid[] = "$Header$"; + +#define SEPARATORS "\n" +/* GRIDMANAGER_CHECKPROXY_INTERVAL + GRIDMANAGER_MINIMUM_PROXY_TIME */ +#define CONDOR_MINIMUM_PROXY_TIME (1800) + +int debug = 0; +char *repository = NULL; +time_t condor_limit = CONDOR_MINIMUM_PROXY_TIME; +char *cadir = NULL; +char *vomsdir = NULL; +int voms_enabled = 0; +char *cert = NULL; +char *key = NULL; +char *vomsconf = NULL; + +static volatile int die = 0, child_died = 0; +double default_timeout = 0; + +static struct option opts[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { "debug", no_argument, NULL, 'd' }, + { "repository", required_argument, NULL, 'r' }, + { "condor-limit", required_argument, NULL, 'c' }, + { "CAdir", required_argument, NULL, 'C' }, + { "VOMSdir", required_argument, NULL, 'V' }, + { "enable-voms", no_argument, NULL, 'A' }, + { "voms-config", required_argument, NULL, 'G' }, + { "cert", required_argument, NULL, 't' }, + { "key", required_argument, NULL, 'k' }, + { NULL, 0, NULL, 0 } +}; + +typedef struct { + edg_wlpr_Command code; + void (*handler) (glite_renewal_core_context ctx, edg_wlpr_Request *request, edg_wlpr_Response *response); +} command_table; + +static command_table commands[] = { + { EDG_WLPR_COMMAND_REG, register_proxy, }, + { EDG_WLPR_COMMAND_UNREG, unregister_proxy, }, + { EDG_WLPR_COMMAND_GET, get_proxy, }, +#if 0 + { EDG_WLPR_COMMAND_LIST, list_proxies, }, + { EDG_WLPR_COMMAND_STATUS, status_proxy, }, +#endif + { EDG_WLPR_COMMAND_UPDATE_DB, update_db, }, + { 0, NULL }, +}; + +/* static prototypes */ +static void +usage(glite_renewal_core_context ctx, char *progname); + +static int +do_listen(glite_renewal_core_context ctx, char *socket_name, int *sock); + +static int +encode_response(glite_renewal_core_context ctx, edg_wlpr_Response *response, char **msg); + +static command_table * +find_command(glite_renewal_core_context ctx, edg_wlpr_Command code); + +static int +proto(glite_renewal_core_context ctx, int sock); + +static int +doit(glite_renewal_core_context ctx, int sock); + +static int +decode_request(glite_renewal_core_context ctx, const char *msg, const size_t msg_len, edg_wlpr_Request *request); + +int +start_watchdog(glite_renewal_core_context ctx, pid_t *pid); + +static void +catchsig(int sig) +{ + switch (sig) { + case SIGINT: + case SIGTERM: + case SIGQUIT: + die = sig; + break; + case SIGCHLD: + child_died = 1; + break; + default: + break; + } +} + +static command_table * +find_command(glite_renewal_core_context ctx, edg_wlpr_Command code) +{ + command_table *c; + + for (c = commands; c->code; c++) { + if (c->code == code) + return c; + } + return NULL; +} + +static int +proto(glite_renewal_core_context ctx, int sock) +{ + char *buf = NULL; + size_t buf_len; + int ret; + edg_wlpr_Response response; + edg_wlpr_Request request; + command_table *command; + struct timeval timeout; + + memset(&request, 0, sizeof(request)); + memset(&response, 0, sizeof(response)); + + timeout.tv_sec = (long) default_timeout; + timeout.tv_usec = (long) ((default_timeout - timeout.tv_sec) * 1e6); + + ret = edg_wlpr_Read(sock, &timeout, &buf, &buf_len); + if (ret) { + glite_renewal_log(ctx, LOG_ERR, "Error reading from client: %s", + edg_wlpr_GetErrorString(ret)); + return ret; + } + + ret = decode_request(ctx, buf, buf_len, &request); + free(buf); + if (ret) + goto end; + + /* XXX check request (protocol version, ...) */ + + command = find_command(ctx, request.command); + if (command == NULL) { + ret = EDG_WLPR_ERROR_UNKNOWN_COMMAND; + glite_renewal_log(ctx, LOG_ERR, "Received unknown command (%d)", request.command); + goto end; + } + + glite_renewal_log(ctx, LOG_INFO, "Received command code %d for proxy %s and jobid %s", + request.command, + request.proxy_filename ? request.proxy_filename : "(unspecified)", + request.jobid ? request.jobid : "(unspecified)"); + + command->handler(ctx, &request, &response); + + ret = encode_response(ctx, &response, &buf); + if (ret) + goto end; + + ret = edg_wlpr_Write(sock, &timeout, buf, strlen(buf) + 1); + free(buf); + if (ret) { + glite_renewal_log(ctx, LOG_ERR, "Error sending response to client: %s", + edg_wlpr_GetErrorString(ret)); + goto end; + } + +end: + edg_wlpr_CleanRequest(&request); + edg_wlpr_CleanResponse(&response); + + return ret; +} + +static int +doit(glite_renewal_core_context ctx, int sock) +{ + int newsock; + struct sockaddr_un client_addr; + int client_addr_len = sizeof(client_addr); + int flags; + + while (!die) { + + if (child_died) { + int pid, newpid, ret; + + while ((pid=waitpid(-1,NULL,WNOHANG))>0) + ; + ret = start_watchdog(ctx, &newpid); + if (ret) + return ret; + glite_renewal_log(ctx, LOG_DEBUG, "Renewal slave process re-started"); + child_died = 0; + continue; + } + + newsock = accept(sock, (struct sockaddr *) &client_addr, &client_addr_len); + if (newsock == -1) { + if (errno != EINTR) + glite_renewal_log(ctx, LOG_ERR, "accept() failed"); + continue; + } + glite_renewal_log(ctx, LOG_DEBUG, "Got connection"); + + flags = fcntl(newsock, F_GETFL, 0); + if (fcntl(newsock, F_SETFL, flags | O_NONBLOCK) < 0) { + glite_renewal_log(ctx, LOG_ERR, "Can't set O_NONBLOCK mode (%s), closing.\n", + strerror(errno)); + close(newsock); + continue; + } + + proto(ctx, newsock); + + glite_renewal_log(ctx, LOG_DEBUG, "Connection closed"); + close(newsock); + } + glite_renewal_log(ctx, LOG_DEBUG, "Terminating on signal %d\n",die); + return 0; +} + +static int +decode_request(glite_renewal_core_context ctx, const char *msg, const size_t msg_len, edg_wlpr_Request *request) +{ + char *value = NULL; +#if 0 + char *p; + int port; +#endif + int ret; + int index; + + /* XXX add an ending zero '\0' */ + + assert(msg != NULL); + assert(request != NULL); + + memset(request, 0, sizeof(*request)); + + ret = edg_wlpr_GetToken(msg, msg_len, EDG_WLPR_PROTO_VERSION, SEPARATORS, + 0, &request->version); + if (ret) { + glite_renewal_log(ctx, LOG_ERR, "Protocol error reading protocol specification: %s", + edg_wlpr_GetErrorString(ret)); + return ret; + } + + ret = edg_wlpr_GetToken(msg, msg_len, EDG_WLPR_PROTO_COMMAND, SEPARATORS, + 0, &value); + if (ret) { + glite_renewal_log(ctx, LOG_ERR, "Protocol error reading command specification: %s", + edg_wlpr_GetErrorString(ret)); + goto err; + } + + ret = edg_wlpr_DecodeInt(value, (int *)(&request->command)); + if (ret) { + glite_renewal_log(ctx, LOG_ERR, "Received non-numeric command specification (%s)", + value); + free(value); + goto err; + } + free(value); + + if (find_command(ctx, request->command) == NULL) { + glite_renewal_log(ctx, LOG_ERR, "Received unknown command (%d)", request->command); + ret = EDG_WLPR_ERROR_UNKNOWN_COMMAND; + goto err; + } + + ret = edg_wlpr_GetToken(msg, msg_len, EDG_WLPR_PROTO_MYPROXY_SERVER, + SEPARATORS, 0, &request->myproxy_server); + if (ret && ret != EDG_WLPR_ERROR_PROTO_PARSE_NOT_FOUND) { + glite_renewal_log(ctx, LOG_ERR, "Protocol error reading myproxy server specification: %s", + edg_wlpr_GetErrorString(ret)); + goto err; + } + +#if 0 + request->myproxy_port = EDG_WLPR_MYPROXY_PORT; /* ??? */ + if (request->myproxy_server && (p = strchr(request->myproxy_server, ':'))) { + *p = '\0'; + port = atol(p+1); /* XXX see myproxy for err check */ + request->myproxy_port = port; + } +#endif + + ret = edg_wlpr_GetToken(msg, msg_len, EDG_WLPR_PROTO_PROXY, SEPARATORS, + 0, &request->proxy_filename); + if (ret && ret != EDG_WLPR_ERROR_PROTO_PARSE_NOT_FOUND) { + glite_renewal_log(ctx, LOG_ERR, "Protocol error reading proxy specification: %s", + edg_wlpr_GetErrorString(ret)); + goto err; + } + +#if 0 + ret = edg_wlpr_GetToken(msg, msg_len, EDG_WLPR_PROTO_UNIQUE_PROXY, + SEPARATORS, 0, &value); + if (ret && ret != EDG_WLPR_ERROR_PARSE_NOT_FOUND) + goto err; + if (ret == 0 && strcasecmp(value, "yes") == 0) + request->unique = 1; + free(value); +#endif + + ret = edg_wlpr_GetToken(msg, msg_len, EDG_WLPR_PROTO_JOBID, SEPARATORS, + 0, &request->jobid); + if (ret && ret != EDG_WLPR_ERROR_PROTO_PARSE_NOT_FOUND) { + glite_renewal_log(ctx, LOG_ERR, "Protocol error reading JobId : %s", + edg_wlpr_GetErrorString(ret)); + goto err; + } + + index = 0; + while ((ret = edg_wlpr_GetToken(msg, msg_len, EDG_WLPR_PROTO_ENTRY, + SEPARATORS, index, &value)) == 0) { + char **tmp; + + tmp = realloc(request->entries, (index + 2) * sizeof(*tmp)); + if (tmp == NULL) { + ret = ENOMEM; + goto err; + } + request->entries = tmp; + request->entries[index] = value; + index++; + } + if (ret != EDG_WLPR_ERROR_PROTO_PARSE_NOT_FOUND) + goto err; + if (request->entries) + request->entries[index] = NULL; + + return 0; + +err: + edg_wlpr_CleanRequest(request); + return ret; +} + +static int +encode_response(glite_renewal_core_context ctx, edg_wlpr_Response *response, char **msg) +{ + char *buf; + size_t buf_len; + int ret; + + buf_len = EDG_WLPR_BUF_SIZE; + buf = malloc(buf_len); + if (buf == NULL) + return ENOMEM; + buf[0] = '\0'; + + ret = edg_wlpr_StoreToken(&buf, &buf_len, EDG_WLPR_PROTO_VERSION, + EDG_WLPR_VERSION, SEPARATORS); + if (ret) + goto err; + + ret = edg_wlpr_StoreToken(&buf, &buf_len, EDG_WLPR_PROTO_RESPONSE, + edg_wlpr_EncodeInt(response->response_code), + SEPARATORS); + if (ret) + goto err; + + if (response->myproxy_server) { + char host[1024]; + +#if 0 + snprintf(host, sizeof(host), "%s:%d", response->myproxy_server, + (response->myproxy_port) ? response->myproxy_port : EDG_WLPR_MYPROXY_PORT); +#endif + ret = edg_wlpr_StoreToken(&buf, &buf_len, EDG_WLPR_PROTO_MYPROXY_SERVER, + host, SEPARATORS); + if (ret) + goto err; + } + + if (response->start_time) { + ret = edg_wlpr_StoreToken(&buf, &buf_len, EDG_WLPR_PROTO_START_TIME, + edg_wlpr_EncodeInt(response->start_time), + SEPARATORS); + if (ret) + goto err; + } + + if (response->end_time) { + ret = edg_wlpr_StoreToken(&buf, &buf_len, EDG_WLPR_PROTO_END_TIME, + edg_wlpr_EncodeInt(response->end_time), + SEPARATORS); + if (ret) + goto err; + } + + if (response->next_renewal_time) { + ret = edg_wlpr_StoreToken(&buf, &buf_len, EDG_WLPR_PROTO_RENEWAL_TIME, + edg_wlpr_EncodeInt(response->next_renewal_time), + SEPARATORS); + if (ret) + goto err; + } + + if (response->filenames) { + char **p = response->filenames; + while (*p) { + ret = edg_wlpr_StoreToken(&buf, &buf_len, EDG_WLPR_PROTO_PROXY, *p, + SEPARATORS); + if (ret) + goto err; + p++; + } + } + + buf[strlen(buf)] = '\0'; + *msg = buf; + return 0; + +err: + free(buf); + *msg = NULL; + return ret; +} + + +static void +usage(glite_renewal_core_context ctx, char *progname) +{ + fprintf(stderr,"usage: %s [option]\n" + "\t-h, --help display this help and exit\n" + "\t-v, --version output version information and exit\n" + "\t-d, --debug don't fork, print out debugging information\n" + "\t-r, --repository repository directory\n" + "\t-c, --condor-limit how long before expiration the proxy must be renewed\n" + "\t-C, --CAdir trusted certificates directory\n" + "\t-V, --VOMSdir trusted VOMS servers certificates directory\n" + "\t-A, --enable-voms renew also VOMS certificates in proxies\n" + "\t-G, --voms-config location of the vomses configuration file\n", + progname); +} + +static int +do_listen(glite_renewal_core_context ctx, char *socket_name, int *sock) +{ + struct sockaddr_un my_addr; + int s; + int ret; + + assert(sock != NULL); + + memset(&my_addr, 0, sizeof(my_addr)); + my_addr.sun_family = AF_UNIX; + strncpy(my_addr.sun_path, socket_name, sizeof(my_addr.sun_path)); + unlink(socket_name); + umask(0177); + + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s == -1) { + glite_renewal_log(ctx, LOG_ERR, "socket(): %s", strerror(errno)); + return errno; + } + + ret = bind(s, (struct sockaddr *)&my_addr, sizeof(my_addr)); + if (ret == -1) { + glite_renewal_log(ctx, LOG_ERR, "bind(): %s", strerror(errno)); + close(s); + return errno; + } + + ret = listen(s, 50); + if (ret == -1) { + glite_renewal_log(ctx, LOG_ERR, "listen(): %s", strerror(errno)); + close(s); + return errno; + } + + *sock = s; + return 0; +} + +int +start_watchdog(glite_renewal_core_context ctx, pid_t *pid) +{ + pid_t p; + + switch ((p = fork())) { + case -1: + glite_renewal_log(ctx, LOG_ERR, "fork() failed: %s", + strerror(errno)); + return errno; + case 0: + watchdog_start(ctx); + exit(0); + break; + default: + *pid = p; + return 0; + } + /* not reachable */ + exit(0); +} + +int main(int argc, char *argv[]) +{ + int sock; + char *progname; + int opt; + int fd; + char sockname[PATH_MAX]; + int ret; + pid_t pid; + struct sigaction sa; + const char *s = NULL; + glite_renewal_core_context ctx = NULL; + + progname = strrchr(argv[0],'/'); + if (progname) progname++; + else progname = argv[0]; + + repository = EDG_WLPR_REPOSITORY_ROOT; + debug = 0; + + while ((opt = getopt_long(argc, argv, "hvdr:c:C:V:AG:t:k:", opts, NULL)) != EOF) + switch (opt) { + case 'h': usage(ctx, progname); exit(0); + case 'v': fprintf(stdout, "%s:\t%s\n", progname, rcsid); exit(0); + case 'd': debug = 1; break; + case 'r': repository = optarg; break; + case 'c': condor_limit = atoi(optarg); break; + case 'C': cadir = optarg; break; + case 'V': vomsdir = optarg; break; + case 'A': voms_enabled = 1; break; + case 'G': vomsconf = optarg; break; + case 't': cert = optarg; break; + case 'k': key = optarg; break; + case '?': usage(ctx, progname); return 1; + } + + if (optind < argc) { + usage(ctx, progname); + exit(1); + } + + ret = glite_renewal_core_init_ctx(&ctx); + if (ret) { + fprintf(stderr, "Cannot initialize context\n"); + exit(1); + } + if (debug) { + ctx->log_level = LOG_DEBUG; + ctx->log_dst = GLITE_RENEWAL_LOG_STDOUT; + } + ctx->voms_conf = vomsconf; + + if (chdir(repository)) { + glite_renewal_log(ctx, LOG_ERR, "Cannot access repository directory %s (%s)", + repository, strerror(errno)); + exit(1); + } + + globus_module_activate(GLOBUS_GSI_CERT_UTILS_MODULE); + globus_module_activate(GLOBUS_GSI_PROXY_MODULE); + + if (!debug) { + /* chdir ? */ + if (daemon(1,0) == -1) { + perror("deamon()"); + exit(1); + } + openlog(progname, LOG_PID, LOG_DAEMON); + } + + if (cert) + setenv("X509_USER_CERT", cert, 1); + + if (key) + setenv("X509_USER_KEY", key, 1); + + if (cadir) + setenv("X509_CERT_DIR", cadir, 1); + + s = getenv("GLITE_PR_TIMEOUT"); + default_timeout = s ? atof(s) : GLITE_PR_TIMEOUT_DEFAULT; + + memset(&sa,0,sizeof(sa)); + sa.sa_handler = catchsig; + sigaction(SIGINT,&sa,NULL); + sigaction(SIGQUIT,&sa,NULL); + sigaction(SIGTERM,&sa,NULL); + sigaction(SIGCHLD,&sa,NULL); + sigaction(SIGPIPE,&sa,NULL); + + ret = start_watchdog(ctx, &pid); + if (ret) + return 1; + + umask(0177); + snprintf(sockname, sizeof(sockname), "%s%d", + DGPR_REG_SOCKET_NAME_ROOT, getuid()); + /* XXX check that the socket is not already active */ + ret = do_listen(ctx, sockname, &sock); + if (ret) + return 1; + glite_renewal_log(ctx, LOG_DEBUG, "Listening at %s", sockname); + + ret = doit(ctx, sock); + + close(sock); + return ret; +} diff --git a/org.glite.px.proxyrenewal/src/renewd_locl.h b/org.glite.px.proxyrenewal/src/renewd_locl.h new file mode 100644 index 0000000..489e909 --- /dev/null +++ b/org.glite.px.proxyrenewal/src/renewd_locl.h @@ -0,0 +1,82 @@ +#ifndef RENEWALD_LOCL_H +#define RENEWALD_LOCL_H + +#ident "$Header$" + +#include +#include +#include + +#include "renewal.h" +#include "renewal_core.h" + +#ifdef HAVE_DMALLOC_H +#include +#endif + +/* XXX */ +#if 0 +#define EDG_WLPR_ERROR_PARSE_NOT_FOUND EDG_WLPR_ERROR_PROTO_PARSE_ERROR +#define EDG_WLPR_ERROR_NOTFOUND EDG_WLPR_PROXY_NOT_REGISTERED +#endif + +typedef struct { + unsigned int len; + char **val; +} prd_list; + +typedef struct { + int suffix; + prd_list jobids; + int unique; + int voms_exts; + char *myproxy_server; + time_t end_time; + time_t next_renewal; +} proxy_record; + +/* commands */ +void +register_proxy(glite_renewal_core_context ctx, edg_wlpr_Request *request, edg_wlpr_Response *response); + +void +unregister_proxy(glite_renewal_core_context ctx, edg_wlpr_Request *request, edg_wlpr_Response *response); + +void +get_proxy(glite_renewal_core_context ctx, edg_wlpr_Request *request, edg_wlpr_Response *response); + +void +update_db(glite_renewal_core_context ctx, edg_wlpr_Request *request, edg_wlpr_Response *response); + +int +get_times(glite_renewal_core_context ctx, char *proxy_file, proxy_record *record); + +void +watchdog_start(glite_renewal_core_context ctx); + +void +glite_renewal_log(glite_renewal_core_context ctx, int dbg_level, const char *format, ...); + +int +decode_record(glite_renewal_core_context ctx, char *line, proxy_record *record); + +int +encode_record(glite_renewal_core_context ctx, proxy_record *record, char **line); + +void +free_record(glite_renewal_core_context ctx, proxy_record *record); + +int +glite_renewal_load_proxy(glite_renewal_core_context ctx, const char *filename, X509 **cert, EVP_PKEY **privkey, + STACK_OF(X509) **chain, globus_gsi_cred_handle_t *proxy); + +int +glite_renewal_get_proxy_base_name(glite_renewal_core_context ctx, const char *file, char **subject); + +int +glite_renewal_renew_voms_creds(glite_renewal_core_context ctx, const char *cur_file, const char *renewed_file, const char *new_file); + +int +glite_renewal_check_voms_attrs(glite_renewal_core_context ctx, const char *proxy); + +#endif /* RENEWALD_LOCL_H */ diff --git a/org.glite.px.proxyrenewal/src/voms.c b/org.glite.px.proxyrenewal/src/voms.c new file mode 100644 index 0000000..687d93b --- /dev/null +++ b/org.glite.px.proxyrenewal/src/voms.c @@ -0,0 +1,356 @@ +#include "renewal_locl.h" +#include "renewd_locl.h" + +#include +#include + +#include "glite/security/voms/voms_apic.h" + +#include "glite/security/voms/newformat.h" + +char * Decode(const char *, int, int *); +char **listadd(char **, char *, int); + +static int +generate_proxy(glite_renewal_core_context ctx, globus_gsi_cred_handle_t cur_proxy, + X509_EXTENSION *voms_extension, const char *new_file) +{ + globus_result_t result; + globus_gsi_proxy_handle_t proxy_handle = NULL; + globus_gsi_cred_handle_t proxy = NULL; + EVP_PKEY *cur_proxy_priv_key = NULL; + X509 *new_cert = NULL; + X509 *voms_cert = NULL; + globus_gsi_cert_utils_cert_type_t proxy_type; + + result = globus_gsi_proxy_handle_init(&proxy_handle, NULL); + if (result) { + glite_renewal_log(ctx, LOG_ERR, "globus_gsi_proxy_handle_init() failed\n"); + goto end; + } + + result = globus_gsi_cred_get_key(cur_proxy, &cur_proxy_priv_key); + if (result) { + glite_renewal_log(ctx, LOG_ERR, "globus_gsi_cred_get_key() failed\n"); + goto end; + } + + /* Create and sign a new proxy */ + result = globus_gsi_cred_get_cert_type(cur_proxy, &proxy_type); + if (result) { + glite_renewal_log(ctx, LOG_ERR, "globus_gsi_cred_get_cert_type() failed\n"); + goto end; + } + + result = globus_gsi_proxy_handle_set_type(proxy_handle, proxy_type); + if (result) { + glite_renewal_log(ctx, LOG_ERR, "globus_gsi_proxy_handle_set_type() failed\n"); + goto end; + } + + result = globus_gsi_proxy_create_signed(proxy_handle, cur_proxy, &proxy); + if (result) { + glite_renewal_log(ctx, LOG_ERR, "globus_gsi_proxy_handle_init() failed\n"); + goto end; + } + + /* Get the new proxy */ + result = globus_gsi_cred_get_cert(proxy, &new_cert); + if (result) { + glite_renewal_log(ctx, LOG_ERR, "globus_gsi_cred_get_cert() failed\n"); + goto end; + } + + /* The Globus API doesn't allow to store custom X.509 extensions */ + voms_cert = X509_dup(new_cert); + if (voms_cert->cert_info->extensions == NULL) + voms_cert->cert_info->extensions = sk_X509_EXTENSION_new_null(); + sk_X509_EXTENSION_push(voms_cert->cert_info->extensions, voms_extension); + + /* Openssl ensures that memory containing old signature structures is unallocated */ +#if 0 + X509_sign(voms_cert, cur_proxy_priv_key, proxy_handle->attrs->signing_algorithm); +#else + X509_sign(voms_cert, cur_proxy_priv_key, EVP_md5()); +#endif + + /* And put the cert back, older one is unallocated by the function */ + result = globus_gsi_cred_set_cert(proxy, voms_cert); + if (result) { + glite_renewal_log(ctx, LOG_ERR, "globus_gsi_cred_set_cert() failed\n"); + goto end; + } + + result = globus_gsi_cred_write_proxy(proxy, (char *)new_file); + +end: + + return 0; +} + +static int +my_VOMS_Export(glite_renewal_core_context ctx, void *buf, int buf_len, X509_EXTENSION **extension) +{ + AC *ac = NULL; + unsigned char *p, *pp; + AC **voms_attrs = NULL; + + p = pp = buf; + ac = d2i_AC(NULL, &p, buf_len+1); + if (ac == NULL) { + glite_renewal_log(ctx, LOG_ERR, "d2i_AC() failed\n"); + return 1; + } + + voms_attrs = (AC **)listadd((char **)voms_attrs, (char *)ac, sizeof(AC *)); + + *extension = X509V3_EXT_conf_nid(NULL, NULL, OBJ_txt2nid("acseq"), + (char*)voms_attrs); + return 0; +} + +static int +create_voms_command(glite_renewal_core_context ctx, struct vomsdata *vd, struct voms **voms_cert, char **command) +{ + int voms_error, ret; + struct data **attribs; + +#if 0 + VOMS_ResetOrder(vd, &voms_error); + for (i = 2; i < argc; i++) { + ret = VOMS_Ordering(argv[i], vd, &voms_error); + if (ret == 0) { + glite_renewal_log(ctx, LOG_ERR, "VOMS_Ordering() failed\n"); + return 1; + } + } +#endif + + if (voms_cert == NULL || *voms_cert == NULL || (*voms_cert)->std == NULL) { + glite_renewal_log(ctx, LOG_ERR, "Invalid VOMS certificate\n"); + return 1; + } + + attribs = (*voms_cert)->std; + + if (strcmp (attribs[0]->role, "NULL") == 0 ) + ret = asprintf(command, "G%s", attribs[0]->group); + else + ret = asprintf(command, "B%s:%s", attribs[0]->group, attribs[0]->role); + +end: + + return 0; +} + +static int +renew_voms_cert(glite_renewal_core_context ctx, struct vomsdata *vd, struct voms **voms_cert, + char **buf, size_t *buf_len) +{ + int voms_error = 0, i, ret, voms_version; + struct contactdata **voms_contacts = NULL; + char *command = NULL; + + voms_contacts = VOMS_FindByVO(vd, (*voms_cert)->voname, ctx->voms_conf, NULL, &voms_error); + + if (voms_contacts == NULL) { + glite_renewal_log(ctx, LOG_ERR, "VOMS_FindByVO() failed\n"); + return 1; + } + + ret = create_voms_command(ctx, vd, voms_cert, &command); + + /* XXX the lifetime should be taken from the older proxy */ + ret = VOMS_SetLifetime(60*60*12, vd, &voms_error); + + /* XXX iterate over all servers on the list on errors */ + ret = VOMS_ContactRaw(voms_contacts[0]->host, voms_contacts[0]->port, + voms_contacts[0]->contact, command, + (void**) buf, buf_len, &voms_version, + vd, &voms_error); + if (ret == 0) { + glite_renewal_log(ctx, LOG_ERR, "VOMS_Contact() failed\n"); + return 1; + } + + VOMS_DeleteContacts(voms_contacts); + + if (command) + free(command); + + return 0; +} + +static int +renew_voms_certs(glite_renewal_core_context ctx, const char *cur_file, const char *renewed_file, const char *new_file) +{ + globus_gsi_cred_handle_t cur_proxy = NULL; + globus_gsi_cred_handle_t new_proxy = NULL; + struct vomsdata *vd = NULL; + struct voms **voms_cert = NULL; + int voms_err, ret; + X509 *cert = NULL; + STACK_OF(X509) *chain = NULL; + char *buf = NULL; + size_t buf_len = 0; + X509_EXTENSION *extension = NULL; + char *old_env_proxy = getenv("X509_USER_PROXY"); + char *old_env_cert = getenv("X509_USER_CERT"); + char *old_env_key = getenv("X509_USER_KEY"); + + setenv("X509_USER_PROXY", cur_file, 1); + setenv("X509_USER_CERT", renewed_file, 1); + setenv("X509_USER_KEY", renewed_file, 1); + + ret = glite_renewal_load_proxy(ctx, cur_file, &cert, NULL, &chain, &cur_proxy); + if (ret) + goto end; + + vd = VOMS_Init(NULL, NULL); + if (vd == NULL) { + glite_renewal_log(ctx, LOG_ERR, "VOMS_Init() failed\n"); + return 1; + } + + ret = VOMS_Retrieve(cert, chain, RECURSE_CHAIN, vd, &voms_err); + if (ret == 0) { + if (voms_err == VERR_NOEXT) { + /* no VOMS cred, no problem; continue */ + /* XXX this part shouldn't be reachable, this call is only called + * if the proxy does contain VOMS attributes */ + glite_renewal_log(ctx, LOG_ERR, "No VOMS attributes found in proxy %s\n", cur_file); + ret = 0; + goto end; + } else { + glite_renewal_log(ctx, LOG_ERR, "Cannot get VOMS certificate(s) from proxy"); + ret = 1; + goto end; + } + } + + /* XXX make sure this loop can really work for multiple voms certificates + * embedded in the proxy */ + for (voms_cert = vd->data; voms_cert && *voms_cert; voms_cert++) { + char *tmp, *ptr; + size_t tmp_len; + + ret = renew_voms_cert(ctx, vd, voms_cert, &tmp, &tmp_len); + if (ret) + goto end; + ptr = realloc(buf, buf_len + tmp_len); + if (ptr == NULL) { + ret = ENOMEM; + goto end; + } + buf = ptr; + memcpy(buf + buf_len, tmp, tmp_len); + buf_len += tmp_len; + } + + if (buf == NULL) { + /* no extension renewed, return */ + ret = 0; + goto end; + } + + ret = my_VOMS_Export(ctx, buf, buf_len, &extension); + if (ret) + goto end; + + ret = glite_renewal_load_proxy(ctx, renewed_file, NULL, NULL, NULL, &new_proxy); + if (ret) + goto end; + + ret = generate_proxy(ctx, new_proxy, extension, new_file); + +end: + (old_env_proxy) ? setenv("X509_USER_PROXY", old_env_proxy, 1) : + unsetenv("X509_USER_PROXY"); + (old_env_cert) ? setenv("X509_USER_CERT", old_env_cert, 1) : + unsetenv("X509_USER_CERT"); + (old_env_key) ? setenv("X509_USER_KEY", old_env_key, 1) : + unsetenv("X509_USER_KEY"); + + if (cert) + X509_free(cert); + if (chain) + sk_X509_pop_free(chain, X509_free); + if (vd) + VOMS_Destroy(vd); + if (cur_proxy) + globus_gsi_cred_handle_destroy(cur_proxy); + if (new_proxy) + globus_gsi_cred_handle_destroy(new_proxy); + if (buf) + free(buf); + + return ret; +} + +int +glite_renewal_renew_voms_creds(glite_renewal_core_context ctx, const char *cur_file, const char *renewed_file, const char *new_file) +{ + return renew_voms_certs(ctx, cur_file, renewed_file, new_file); +} + +int +glite_renewal_check_voms_attrs(glite_renewal_core_context ctx, const char *proxy) +{ + int ret, voms_err, present; + X509 *cert = NULL; + STACK_OF(X509) *chain = NULL; + struct vomsdata *vd = NULL; + + ret = glite_renewal_load_proxy(ctx, proxy, &cert, NULL, &chain, NULL); + if (ret) + return 0; + + vd = VOMS_Init(NULL, NULL); + if (vd == NULL) { + present = 0; + goto end; + } + + ret = VOMS_Retrieve(cert, chain, RECURSE_CHAIN, vd, &voms_err); + if (ret == 0) { + present = 0; + goto end; + } + + present = 1; + +end: + if (cert) + X509_free(cert); + if (chain) + sk_X509_pop_free(chain, X509_free); + if (vd) + VOMS_Destroy(vd); + + return present; +} + +#if 0 +int +main(int argc, char *argv[]) +{ + int ret; + const char *current_proxy = "/tmp/x509up_u11930"; + const char *renewed_proxy = "/tmp/proxy"; + + if (argc > 1) + current_proxy = argv[1]; + if (argc > 2) + renewed_proxy = argv[2]; + + if (globus_module_activate(GLOBUS_GSI_PROXY_MODULE) != GLOBUS_SUCCESS || + globus_module_activate(GLOBUS_GSI_CERT_UTILS_MODULE) != GLOBUS_SUCCESS) { + glite_renewal_log(ctx, LOG_ERR, "[%d]: Unable to initialize Globus modules\n", getpid()); + return 1; + } + + ret = renew_voms_certs(current_proxy, renewed_proxy); + + return 0; +} +#endif -- 1.8.2.3