initial import
authorAleš Křenek <ljocha@ics.muni.cz>
Fri, 9 Jul 2004 10:16:25 +0000 (10:16 +0000)
committerAleš Křenek <ljocha@ics.muni.cz>
Fri, 9 Jul 2004 10:16:25 +0000 (10:16 +0000)
14 files changed:
org.glite.security.proxyrenewal/Makefile [new file with mode: 0644]
org.glite.security.proxyrenewal/build.xml [new file with mode: 0755]
org.glite.security.proxyrenewal/interface/renewal.h [new file with mode: 0644]
org.glite.security.proxyrenewal/project/configure.properties.xml [new file with mode: 0644]
org.glite.security.proxyrenewal/project/properties.xml [new file with mode: 0755]
org.glite.security.proxyrenewal/project/taskdefs.xml [new file with mode: 0755]
org.glite.security.proxyrenewal/src/api.c [new file with mode: 0644]
org.glite.security.proxyrenewal/src/client.c [new file with mode: 0644]
org.glite.security.proxyrenewal/src/commands.c [new file with mode: 0644]
org.glite.security.proxyrenewal/src/common.c [new file with mode: 0644]
org.glite.security.proxyrenewal/src/renew.c [new file with mode: 0644]
org.glite.security.proxyrenewal/src/renewal_locl.h [new file with mode: 0644]
org.glite.security.proxyrenewal/src/renewd.c [new file with mode: 0644]
org.glite.security.proxyrenewal/src/renewd_locl.h [new file with mode: 0644]

diff --git a/org.glite.security.proxyrenewal/Makefile b/org.glite.security.proxyrenewal/Makefile
new file mode 100644 (file)
index 0000000..6a386fe
--- /dev/null
@@ -0,0 +1,101 @@
+# 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=/opt/glite
+globus_prefix=/opt/globus
+nothrflavour=gcc32
+thrflavour=gcc32pthr
+myproxy_prefix=/software/myproxy-0.4
+
+-include Makefile.inc
+
+VPATH:=${top_srcdir}/src
+
+GLOBUSINC:= -I${globus_prefix}/include/${nothrflavour} \
+       -I${globus_prefix}/include/${nothrflavour}/openssl
+
+GLOBUSTHRINC:= -I${globus_prefix}/include/${thrflavour} \
+       -I${globus_prefix}/include/${thrflavour}/openssl
+
+
+DEBUG:=-g -O0
+
+# XXX: until VOMS is ready in SCM
+CFLAGS:= -DNOVOMS \
+       ${DEBUG} \
+       -DVOMS_INSTALL_PATH=\"${voms_prefix}\"\
+       -I${myproxy_prefix}/include \
+       -I${top_srcdir}/src -I${top_srcdir}/interface \
+       -I${stagedir}/include
+
+GLOBUS_LIBS:=-L${globus_prefix}/lib \
+       -lglobus_common_${nothrflavour} \
+       -lssl_${nothrflavour}
+
+SSL_UTILS_LIB:=-L${stagedir}/lib -lglobus_ssl_utils
+MYPROXY_LIB:=-L${myproxy_prefix}/lib -lmyproxy
+
+JOBIDLIB:=-L${stagedir}/lib -lglite_wms_cjobid
+
+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
+LIBOBJ:=api.o common.o
+CLIENTOBJ:=client.o
+
+THRLIBOBJ:=${LIBOBJ:.o=.thr.o}
+LIBLOBJ:=${LIBOBJ:.o=.lo}
+THRLIBLOBJ:=${LIBOBJ:.o=.thr.lo}
+
+LIB:=libglite_security_proxyrenewal_${nothrflavour}.la
+THRLIB:=libglite_security_proxyrenewal_${thrflavour}.la
+
+DAEMON:=glite-proxy-renewd
+CLIENT:=glite-proxy-renew
+
+default: all
+compile all: ${LIB} ${THRLIB} ${DAEMON} ${CLIENT}
+
+${LIB}: ${LIBOBJ}
+       ${LINK} -o $@ ${LIBLOBJ} -rpath ${glite_location}/lib ${JOBIDLIB} ${SSL_UTILS_LIB}
+
+
+${THRLIB}: ${THRLIBOBJ}
+       ${LINK} -o $@ ${THRLIBLOBJ} -rpath ${glite_location}/lib ${SSL_UTILS_LIB}
+
+${DAEMON}: ${DAEMONOBJ}
+       ${LINK} -o $@ ${DAEMONOBJ} ${JOBIDLIB} ${SSL_UTILS_LIB} ${MYPROXY_LIB} -lglobus_gss_assist_${nothrflavour} ${GLOBUS_LIBS} 
+
+${CLIENT}: ${CLIENTOBJ} ${LIB}
+       ${LINK} -o $@ ${CLIENTOBJ} ${LIB} ${GLOBUS_LIBS}
+
+${THRLIBOBJ}: %.thr.o: %.c
+       ${COMPILE} ${GLOBUSTHRINC} -o $@ -c $<
+
+%.o: %.c
+       ${COMPILE} ${GLOBUSINC} -c $<
+
+install:
+       -mkdir -p ${PREFIX}/bin ${PREFIX}/lib ${PREFIX}/include/glite/security
+       ${INSTALL} -m 644 ${LIB} ${THRLIB} ${PREFIX}/lib
+       ${INSTALL} -m 755 ${DAEMON} ${CLIENT} ${PREFIX}/bin
+       cd ${top_srcdir}/interface && ${INSTALL} -m 644 renewal.h ${PREFIX}/include/glite/security
+
+
+stage: compile
+       $(MAKE) install PREFIX=${stagedir}
+
+
+check:
+       echo No unit tests
diff --git a/org.glite.security.proxyrenewal/build.xml b/org.glite.security.proxyrenewal/build.xml
new file mode 100755 (executable)
index 0000000..caef0ba
--- /dev/null
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+       Copyright (c) 2004 on behalf of the EU EGEE Project: 
+       The European Organization for Nuclear Research (CERN), 
+       Istituto Nazionale di Fisica Nucleare (INFN), Italy
+       Datamat Spa, Italy
+       Centre National de la Recherche Scientifique (CNRS), France
+       CS Systeme d'Information (CSSI), France
+       Royal Institute of Technology, Center for Parallel Computers (KTH-PDC), Sweden
+       Universiteit van Amsterdam (UvA), Netherlands
+       University of Helsinki (UH.HIP), Finland
+       University of Bergen (UiB), Norway
+       Council for the Central Laboratory of the Research Councils (CCLRC), United Kingdom
+
+       Build file for the GLite LB Client module
+       
+       Authors: Ales Krenek <ljocha@ics.muni.cz>
+       Version info: $Id$
+       Release: $Name$
+
+       Revision history:
+       $Log$
+       Revision 1.2  2004/07/07 09:24:57  akrenek
+       thr/nonthr flavours used correctly
+       
+       Revision 1.3  2004/07/06 17:45:30  flammer
+       Update of classpath definitions, targets & configure file.
+       
+       Revision 1.2  2004/06/23 00:29:33  dimeglio
+       Added standard comments and handling of support files
+       
+-->
+
+<project name="proxyrenewal" default="compile">
+       
+       <!-- =========================================
+            Import properties (order is important)
+            ========================================= -->
+
+       <!-- import baseline & user properties -->
+       <import file="../org.glite/project/baseline.properties.xml" />
+
+       <!-- import component build properties,
+                       component properties &
+                       component common properties -->
+       <import file="./project/properties.xml"/>
+       
+       <!-- import subsystem build properties,
+                       subsystem properties &
+                       subsystem common properties -->
+       <import file="${subsystem.properties.file}"/>
+
+       <!-- import global build properties &
+                       global properties -->
+       <import file="${global.properties.file}" />
+               
+       <!-- =========================================
+                Load dependency property files (order is important)
+            ========================================= -->
+       <property file="${user.dependencies.file}"/>
+       <property file="${component.dependencies.file}" />
+       <property file="${subsystem.dependencies.file}" />
+       <property file="${global.dependencies.file}"/>
+       
+       <!-- =========================================
+                Load configure options (order is important)
+            ========================================= -->
+       <import file="${global.configure.options.file}"/>
+       <import file="${component.configure.options.file}"/>
+
+       <!-- =========================================
+                Import task definitions (order is important)
+            ========================================= -->
+       <import file="${subsystem.taskdefs.file}" />
+       <import file="${global.taskdefs.file}" />
+                       
+       <!-- =========================================
+                Load common targets
+            ========================================= -->
+       <import file="${global.targets-simple_make.file}" />
+
+       <!-- =========================================
+                Load version file 
+            ========================================= -->
+       <property file="${module.version.file}"/>
+               
+       <!-- ==============================================
+                Local private targets
+            ============================================== -->
+       
+       <target name="localinit"
+               description="Module specific initialization tasks">
+               <antcall target="lbmakefiles" />
+       </target>
+               
+       <target name="localcompile"
+               description="Module specific compile tasks">
+       </target>
+       
+       <target name="localclean"
+               description="Module specific cleaning tasks">
+       </target>
+       
+</project>             
diff --git a/org.glite.security.proxyrenewal/interface/renewal.h b/org.glite.security.proxyrenewal/interface/renewal.h
new file mode 100644 (file)
index 0000000..c70b881
--- /dev/null
@@ -0,0 +1,144 @@
+/**
+ * \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$"
+
+#include "glite/wms/jobid/cjobid.h"
+
+#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_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.
+ */
+int
+edg_wlpr_RegisterProxyExt(
+      const char * filename,
+      const char * server,
+      unsigned int port,
+      edg_wlc_JobId 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().
+ */
+int
+edg_wlpr_UnregisterProxy(
+      edg_wlc_JobId 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().
+ */
+int
+edg_wlpr_GetProxy(edg_wlc_JobId jobid, char **repository_filename);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RENEWAL_H */
diff --git a/org.glite.security.proxyrenewal/project/configure.properties.xml b/org.glite.security.proxyrenewal/project/configure.properties.xml
new file mode 100644 (file)
index 0000000..53d3297
--- /dev/null
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+       Copyright (c) 2004 on behalf of the EU EGEE Project: 
+       The European Organization for Nuclear Research (CERN), 
+       Istituto Nazionale di Fisica Nucleare (INFN), Italy
+       Datamat Spa, Italy
+       Centre National de la Recherche Scientifique (CNRS), France
+       CS Systeme d'Information (CSSI), France
+       Royal Institute of Technology, Center for Parallel Computers (KTH-PDC), Sweden
+       Universiteit van Amsterdam (UvA), Netherlands
+       University of Helsinki (UH.HIP), Finland
+       University of Bergen (UiB), Norway
+       Council for the Central Laboratory of the Research Councils (CCLRC), United Kingdom
+
+       Configuration options for the GLite LB Client module
+       
+       Authors: Ales Krenek <ljocha@ics.muni.cz>
+-->
+
+       <!-- ======================================================
+         Define extra properties here ...
+         ====================================================== -->
+        
+       <project name="LB Client configuration options">                                                                        
+               <target name="lbmakefiles">
+                       <exec executable="ln" failonerror="true">
+                               <arg line="-fs ${component.dir}/Makefile ${module.build.dir}/Makefile"/>
+                       </exec>
+                       <echo file="${module.build.dir}/Makefile.inc">
+top_srcdir=..
+builddir=build
+stagedir=${stage.abs.dir}
+distdir=${dist.dir}
+globalprefix=${global.prefix}
+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}
+                       </echo>
+           </target>
+       </project>
diff --git a/org.glite.security.proxyrenewal/project/properties.xml b/org.glite.security.proxyrenewal/project/properties.xml
new file mode 100755 (executable)
index 0000000..aef3360
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project name="Proxy renewal">
+
+       <property file="build.properties" />    
+       <property name="subsystem.name" value="${security.subsystem.name}"/>
+       <property name="subsystem.prefix" value="${security.subsystem.prefix}"/>
+       <property name="component.prefix" value="proxyrenewal" />
+
+       <import file="${component.general.properties.file}" />
+
+</project>
diff --git a/org.glite.security.proxyrenewal/project/taskdefs.xml b/org.glite.security.proxyrenewal/project/taskdefs.xml
new file mode 100755 (executable)
index 0000000..13e894e
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project name="tasks and types definitions">
+</project>
diff --git a/org.glite.security.proxyrenewal/src/api.c b/org.glite.security.proxyrenewal/src/api.c
new file mode 100644 (file)
index 0000000..e241f20
--- /dev/null
@@ -0,0 +1,436 @@
+#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, int *sock);
+
+static int
+send_request(int sock, 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, int *sock)
+{
+   struct sockaddr_un my_addr;
+   int s;
+   int ret;
+
+   assert(sock != NULL);
+   memset(&my_addr, 0, sizeof(my_addr));
+
+   s = socket(AF_UNIX, SOCK_STREAM, 0);
+   if (s == -1) {
+      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) {
+      close(s);
+      return errno;
+   }
+
+   *sock = s;
+   return 0;
+}
+
+static int
+send_request(int sock, 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, buf, strlen(buf) + 1);
+   free(buf);
+   if (ret)
+      return ret;
+
+   ret = edg_wlpr_Read(sock, &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;
+
+   snprintf(sockname, sizeof(sockname), "%s%d",
+           DGPR_REG_SOCKET_NAME_ROOT, getuid());
+   ret = do_connect(sockname, &sock);
+   if (ret)
+      return ret;
+
+   ret = send_request(sock, request, response);
+
+   close(sock);
+   return ret;
+}
+
+int
+edg_wlpr_RegisterProxyExt(const char *filename, const char * server,
+                         unsigned int port,
+                          edg_wlc_JobId 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));
+
+   request.command = EDG_WLPR_COMMAND_REG;
+   request.myproxy_server = server;
+   request.proxy_filename = filename;
+   request.jobid = edg_wlc_JobIdUnparse(jobid);
+   if (request.jobid == NULL)
+      return EINVAL; /* XXX */
+
+   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;
+}
+
+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));
+}
+
+int
+edg_wlpr_UnregisterProxy(edg_wlc_JobId 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));
+
+   request.command = EDG_WLPR_COMMAND_UNREG;
+   request.proxy_filename = repository_filename;
+   request.jobid = edg_wlc_JobIdUnparse(jobid);
+   if (request.jobid == NULL)
+      return EINVAL;
+
+   ret = edg_wlpr_RequestSend(&request, &response);
+   free(request.jobid);
+   
+   if (ret == 0)
+      ret = response.response_code;
+   edg_wlpr_CleanResponse(&response);
+
+   return ret;
+}
+
+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",
+};
+
+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
+edg_wlpr_GetProxy(edg_wlc_JobId jobid, char **repository_filename)
+{
+   edg_wlpr_Request request;
+   edg_wlpr_Response response;
+   int ret;
+
+   memset(&request, 0, sizeof(request));
+   memset(&response, 0, sizeof(response));
+
+   request.command = EDG_WLPR_COMMAND_GET;
+   request.jobid = edg_wlc_JobIdUnparse(jobid);
+   if (request.jobid == NULL)
+      return EINVAL;
+
+   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;
+}
diff --git a/org.glite.security.proxyrenewal/src/client.c b/org.glite.security.proxyrenewal/src/client.c
new file mode 100644 (file)
index 0000000..eb2d36b
--- /dev/null
@@ -0,0 +1,117 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#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 <fqdn>        address of myproxy server\n"
+          "-p, --port <num>           port of myproxy server\n"
+          "-f, --file <file>          filename with proxy\n"
+          "-j, --jobid <str>          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;
+   edg_wlc_JobId jobid = 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 (jobid_str && edg_wlc_JobIdParse(jobid_str, &jobid)) {
+      fprintf(stderr, "Cannot parse jobid\n");
+      exit(1);
+   }
+
+   if (strcmp(argv[optind], "start") == 0) {
+      if (proxyfile == NULL || server == NULL || jobid == NULL)
+        usage(1);
+      ret = edg_wlpr_RegisterProxyExt(proxyfile, server, port, jobid, 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 == NULL)
+        usage(1);
+      ret = edg_wlpr_UnregisterProxy(jobid, 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 == NULL)
+        usage(1);
+      ret = edg_wlpr_GetProxy(jobid, &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.security.proxyrenewal/src/commands.c b/org.glite.security.proxyrenewal/src/commands.c
new file mode 100644 (file)
index 0000000..ba566d0
--- /dev/null
@@ -0,0 +1,1258 @@
+#include "renewal_locl.h"
+#include "renewd_locl.h"
+
+#ifndef NOVOMS
+#include <voms_apic.h>
+#endif
+
+#ident "$Header$"
+
+#define SEPARATORS ",\n"
+#define RENEWAL_START_FRACTION 0.75 /* XXX */
+#define RENEWAL_CLOCK_SKEW (5 * 60)
+#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(const char *s, unsigned char *digest);
+
+static int
+get_record_ext(FILE *fd, proxy_record *record, int *last_used_suffix);
+
+static int
+get_record(FILE *fd, proxy_record *record);
+
+static int
+store_record(char *basename, proxy_record *record);
+
+static int
+copy_file_content(FILE *in, FILE *out);
+
+static int
+copy_file(char *src, char *dst);
+
+static int
+get_base_filename(char *proxy_file, char **basefilename);
+
+int
+decode_record(char *line, proxy_record *record);
+
+int
+encode_record(proxy_record *record, char **line);
+
+static int
+open_metafile(char *proxy_file, FILE **fd);
+
+void
+free_record(proxy_record *record);
+
+static int
+realloc_prd_list(prd_list *list);
+
+/* make public: */
+static int
+edg_wlpr_GetTokenInt(const char *msg, const size_t msg_len,
+                     const char *key, const char *separators,
+                     int req_index, int *value);
+
+static void
+record_to_response(int status_code, proxy_record *record,
+                   edg_wlpr_Response *response);
+
+static int
+filename_to_response(char *filename, edg_wlpr_Response *response);
+
+
+
+
+static char *
+strmd5(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(char *proxy_file, char **basefilename)
+{
+   FILE *cert_file = NULL;
+   X509 *cert = NULL;
+   X509_NAME *s = NULL;
+   char *subject = NULL;
+   char file[FILENAME_MAX];
+   int ret;
+
+   assert(basefilename != NULL);
+
+   cert_file = fopen(proxy_file, "r");
+   if (cert_file == NULL) {
+      edg_wlpr_Log(LOG_ERR, "Cannot open file %s (%s)", 
+                   proxy_file, strerror(errno));
+      return errno;
+   }
+
+   cert = PEM_read_X509(cert_file, NULL, NULL, NULL);
+   if (cert == NULL) {
+      edg_wlpr_Log(LOG_ERR, "Cannot read certificate from %s", proxy_file);
+      ret = EDG_WLPR_ERROR_SSL; /* XXX */
+      goto end;
+   }
+
+   s = X509_NAME_dup(X509_get_subject_name(cert));
+   proxy_get_base_name(s);
+   subject = X509_NAME_oneline(s, NULL, 0);
+   X509_NAME_free(s);
+   X509_free(cert);
+   if (subject == NULL) {
+      edg_wlpr_Log(LOG_ERR, "Cannot read subject name from %s", proxy_file);
+      ret = EDG_WLPR_ERROR_SSL; /* XXX */
+      goto end;
+   }
+
+   snprintf(file, sizeof(file), "%s/%s", repository, strmd5(subject, NULL));
+   *basefilename = strdup(file); /* XXX test ENOMEM */
+   ret = 0;
+   
+end:
+   if (subject)
+      free(subject);
+   fclose(cert_file);
+   return ret;
+}
+
+static int
+copy_file_content(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))) {
+        edg_wlpr_Log(LOG_ERR, "Reading failed: %s", strerror(errno));
+        return ret;
+      }
+      num = fwrite(buf, sizeof(*buf), num, out);
+      if ((ret = ferror(in))) {
+        edg_wlpr_Log(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(time_t current_time, time_t start_time, time_t end_time)
+{
+   time_t length, lifetime;
+   time_t delta;
+   int condor_tested = 0;
+
+   lifetime = end_time - start_time;
+   delta = 0;
+   while (1) {
+      if (end_time - current_time <= RENEWAL_MIN_LIFETIME)
+        /* if the proxy is too short, renew it as soon as possible */
+        return RENEWAL_CLOCK_SKEW;
+
+      /* renewal starts at 3/4 of lifetime */
+      length = end_time - (start_time + delta);
+      delta += length * RENEWAL_START_FRACTION;
+
+      if (!condor_tested && delta > lifetime - condor_limit) {
+        /* Condor requires the proxies to be renewed a specified time interval
+            before the proxies have expired (see the 
+           GRIDMANAGER_MINIMUM_PROXY_TIME variable). We must ensure that
+           renewal takes place before Condor does this check */
+        if (current_time > end_time - condor_limit) {
+           edg_wlpr_Log(LOG_ERR, "Proxy lifetime exceeded value of the Condor limit!"); 
+        }
+        else
+           delta = lifetime - condor_limit - RENEWAL_CLOCK_SKEW;
+        condor_tested = 1;
+      }
+
+      if (abs(current_time - (start_time + delta)) < RENEWAL_CLOCK_SKEW)
+        continue;
+      
+      return (start_time + delta) - current_time;
+   };
+
+   /* not reachable */
+   return 0;
+}
+
+int
+get_times(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) {
+      edg_wlpr_Log(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) {
+      edg_wlpr_Log(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);
+   end_time = ASN1_UTCTIME_mktime(X509_get_notAfter(cert));
+   start_time = ASN1_UTCTIME_mktime(X509_get_notBefore(cert));
+   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) {
+      edg_wlpr_Log(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;
+        }
+        edg_wlpr_Log(LOG_ERR, "Cannot read additional certificates from %s",
+                     proxy_file);
+        ret = -1; /* XXX SSL_ERROR */
+        goto end;
+      }
+      tmp_end = ASN1_UTCTIME_mktime(X509_get_notAfter(cert));
+      if (tmp_end + RENEWAL_CLOCK_SKEW < current_time) {
+        edg_wlpr_Log(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(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(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) {
+      edg_wlpr_Log(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) {
+      edg_wlpr_Log(LOG_ERR, "Cannot create temporary file (%s)",
+                  strerror(errno));
+      ret = errno;
+      goto end;
+   }
+
+
+   tmp_to = fdopen(tmp_fd, "w");
+   if (tmp_to == NULL) {
+      edg_wlpr_Log(LOG_ERR, "Cannot associate stream with temporary file (%s)",
+                  strerror(errno));
+      unlink(tmpfile);
+      ret = errno;
+      goto end;
+   }
+
+   ret = copy_file_content(from, tmp_to);
+   fclose(tmp_to);
+   if (ret) {
+      goto end;
+   }
+
+   ret = rename(tmpfile, dst);
+   if (ret) {
+      edg_wlpr_Log(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(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(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(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(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(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(line, len, "suffix=", SEPARATORS, 0,
+                             &record->suffix);
+   if (ret)
+      return ret;
+
+#if 0
+   ret = edg_wlpr_GetTokenInt(line, len, "counter=", SEPARATORS, 0, 
+                             &record->counter);
+   if (ret)
+      goto end;
+#endif
+
+   ret = edg_wlpr_GetTokenInt(line, len, "unique=", SEPARATORS, 0,
+                             &record->unique);
+   if (ret)
+      goto end;
+
+   ret = edg_wlpr_GetTokenInt(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(line, len, "next_renewal=", SEPARATORS, 0,
+                             (int *)&record->next_renewal);
+   if (ret)
+      goto end;
+
+   ret = edg_wlpr_GetTokenInt(line, len, "end_time=", SEPARATORS, 0,
+                             (int *)&record->end_time);
+   if (ret)
+      goto end;
+
+   ret = get_jobids(line, len, record);
+   if (ret)
+      goto end;
+
+end:
+   if (ret)
+      free_record(record);
+
+   return ret;
+}
+
+int
+encode_record(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=<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(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;
+
+   assert(record != NULL);
+   memset(&tmp_record, 0, sizeof(tmp_record));
+
+   current_time = time(NULL);
+   while (fgets(line, sizeof(line), fd) != NULL) {
+      free_record(&tmp_record);
+      p = strchr(line, '\n');
+      if (p)
+        *p = '\0';
+      ret = decode_record(line, &tmp_record);
+      if (ret)
+        return ret; /* XXX 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 */
+        char *server = record->myproxy_server;
+
+        memset(record, sizeof(*record), 0);
+        record->suffix = tmp_record.suffix;
+        if (record->myproxy_server)
+           free(record->myproxy_server);
+        record->myproxy_server = server;
+        free_record(&tmp_record);
+        return 0;
+      }
+
+      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 &&
+         tmp_record.end_time - current_time < condor_limit) {
+        /* skip expired proxy (and that 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) {
+      edg_wlpr_Log(LOG_DEBUG, "Requested suffix %d not found in meta file",
+                  record->suffix);
+   }
+
+   free_record(&tmp_record);
+
+   return EDG_WLPR_ERROR_PROTO_PARSE_NOT_FOUND;
+}
+
+static int
+get_record(FILE *fd, proxy_record *record)
+{
+   return get_record_ext(fd, record, NULL);
+}
+
+static int
+store_record(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];
+
+   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) {
+      free_record(&tmp_record);
+      p = strchr(line, '\n');
+      if (p)
+        *p = '\0';
+      ret = decode_record(line, &tmp_record);
+      if (ret)
+        goto end;
+      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(&tmp_record.jobids);
+           tmp_record.jobids.val[tmp_record.jobids.len - 1] = 
+              strdup(record->jobids.val[i]);
+        }
+        stored = 1;
+      }
+      ret = encode_record(&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(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(&tmp_record);
+   if (fd)
+      fclose(fd);
+   close(temp);
+   return ret;
+}
+
+static int
+open_metafile(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) {
+      edg_wlpr_Log(LOG_ERR, "Opening meta file %s failed (%s)",
+                  meta_filename, strerror(errno));
+      return errno;
+   }
+   rewind(meta_fd);
+   *fd = meta_fd;
+   edg_wlpr_Log(LOG_DEBUG, "Using meta file %s", meta_filename);
+   return 0;
+}
+
+static int
+filename_to_response(char *filename, edg_wlpr_Response *response)
+{
+   response->filenames = malloc(2 * sizeof(*response->filenames));
+   if (response->filenames == NULL) {
+      edg_wlpr_Log(LOG_DEBUG, "Not enough memory");
+      return errno;
+   }
+   response->filenames[0] = strdup(filename);
+   if (response->filenames[0] == NULL) {
+      edg_wlpr_Log(LOG_DEBUG, "Not enough memory");
+      free(response->filenames);
+      return errno;
+   }
+   response->filenames[1] = NULL;
+   return 0;
+}
+
+static void
+record_to_response(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(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) {
+      edg_wlpr_Log(LOG_ERR, "Cannot open meta file %s (%s)",
+                  datafile, strerror(errno));
+      return errno;
+   }
+
+   while (fgets(line, sizeof(line), meta_fd) != NULL) {
+      free_record(&record);
+      p = strchr(line, '\n');
+      if (p)
+        *p = '\0';
+      ret = decode_record(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(&record);
+           fclose(meta_fd);
+           return 0;
+        }
+      }
+   }
+   free_record(&record);
+   fclose(meta_fd);
+   return EDG_WLPR_ERROR_PROTO_PARSE_NOT_FOUND;
+}
+      
+int
+find_proxyname(char *jobid, char **filename)
+{
+   DIR *dir = NULL;
+   struct dirent *file;
+   int ret;
+   
+   chdir(repository);
+
+   dir = opendir(repository);
+   if (dir == NULL) {
+      edg_wlpr_Log(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(file->d_name, jobid, filename);
+      if (ret == 0) {
+        closedir(dir);
+        return 0;
+      }
+   }
+   closedir(dir);
+   edg_wlpr_Log(LOG_ERR, "Requested proxy is not registered");
+   return EDG_WLPR_PROXY_NOT_REGISTERED;
+}
+
+#ifdef NOVOMS
+int
+find_voms_cert(char *file, int *present)
+{
+       *present = 0;
+       return 0;
+}
+
+#else
+int
+find_voms_cert(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) {
+      edg_wlpr_Log(LOG_ERR, "check_voms_cert(): Cannot initialize VOMS context (VOMS_Init() failed, probably voms dir was not specified)");
+      return EDG_WLPR_ERROR_VOMS;
+   }
+
+   ret = load_proxy(file, &cert, &privkey, &chain);
+   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(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));
+   edg_wlpr_Log(LOG_DEBUG, "Registration request for %s", request->proxy_filename);
+
+   if (request->proxy_filename == NULL || request->jobid == NULL) {
+      edg_wlpr_Log(LOG_ERR, "Registration request doesn't contain registration information");
+      return; /*  EINVAL; */
+   }
+   umask(0177);
+
+   ret = get_base_filename(request->proxy_filename, &basename);
+   if (ret)
+      goto end;
+
+   ret = open_metafile(basename, &meta_fd);
+   if (ret)
+      goto end;
+
+   if (voms_enabled)
+     ret = find_voms_cert(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(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(request->proxy_filename, filename);
+      if (ret)
+        goto end;
+      ret = get_times(filename, &record);
+      if (ret)
+        goto end;
+      record.suffix = suffix;
+      ret = realloc_prd_list(&record.jobids);
+      if (ret)
+        goto end;
+      record.jobids.val[record.jobids.len - 1] = strdup(request->jobid);
+      record.unique = request->unique;
+      edg_wlpr_Log(LOG_DEBUG, "Created a new proxy file in repository (%s)",
+                  filename);
+   } else {
+      ret = realloc_prd_list(&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);
+      edg_wlpr_Log(LOG_DEBUG, "Inremented counter on %s", filename);
+   }
+
+   ret = store_record(basename, &record);
+
+end:
+   if (meta_fd) {
+      fclose(meta_fd);
+   }
+
+   if (basename)
+      free(basename);
+
+   if (ret == 0)
+      ret = filename_to_response(filename, response);
+   record_to_response(ret, &record, response);
+   free_record(&record);
+}
+
+void
+unregister_proxy(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));
+   edg_wlpr_Log(LOG_DEBUG, "Unregistration request for %s", request->jobid);
+
+   if (request->jobid == NULL) {
+      edg_wlpr_Log(LOG_ERR, "Unregistration request doesn't contain needed information");
+      ret = EINVAL;
+      goto end;
+   }
+
+   if (request->proxy_filename == NULL) {
+      ret = find_proxyname(request->jobid, &request->proxy_filename);
+      if (ret)
+        goto end;
+   }
+
+   ret = get_base_filename(request->proxy_filename, &basename);
+   if (ret) {
+      goto end;
+   }
+
+   if (strncmp(request->proxy_filename, basename, strlen(basename) != 0)) {
+      edg_wlpr_Log(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) {
+      edg_wlpr_Log(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) {
+      edg_wlpr_Log(LOG_DEBUG, "Requested proxy %s is not from repository",
+                 request->proxy_filename);
+      ret = EDG_WLPR_PROXY_NOT_REGISTERED;
+      goto end;
+   }
+
+   ret = open_metafile(basename, &meta_fd);
+   if (ret) {
+      /* fill in error response */
+      return;
+   }
+
+   ret = get_record(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) {
+      edg_wlpr_Log(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) {
+      edg_wlpr_Log(LOG_DEBUG, "Cannot stat file %s: (%s)",
+                  request->proxy_filename, strerror(errno));
+      ret = errno;
+      goto end;
+   }
+
+   ret = store_record(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(request->proxy_filename, response);
+   record_to_response(ret, &record, response);
+   free_record(&record);
+}
+
+void
+get_proxy(edg_wlpr_Request *request, edg_wlpr_Response *response)
+{
+   char *filename = NULL;
+   int ret;
+
+   memset(response, 0, sizeof(*response));
+
+   edg_wlpr_Log(LOG_DEBUG, "GET request for %s", request->jobid);
+   
+   if (request->jobid == NULL) {
+      edg_wlpr_Log(LOG_ERR, "GET request doesn't contain jobid specification");
+      ret = EINVAL;
+      goto end;
+   }
+
+   ret = find_proxyname(request->jobid, &filename);
+
+end:
+   if (ret == 0)
+      ret = filename_to_response(filename, response);
+   if (filename)
+      free(filename);
+   response->response_code = ret;
+}
+
+void
+update_db(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));
+
+   edg_wlpr_Log(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) {
+      edg_wlpr_Log(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) {
+      edg_wlpr_Log(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(&record);
+      p = strchr(line, '\n');
+      if (p)
+        *p = '\0';
+      ret = decode_record(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(&record);
+              record.suffix = suffix;
+              record.myproxy_server = server;
+              edg_wlpr_Log(LOG_WARNING, "Removed expired proxy (suffix %d)",
+                           suffix);
+           } else
+              get_times(cur_proxy, &record);
+        } else {
+           ret = get_times(proxy, &record);
+           (ret == 0) ? rename(proxy, cur_proxy) : unlink(proxy);
+        }
+      }
+      
+      ret = encode_record(&record, &new_line);
+      if (ret)
+        goto end;
+
+      dprintf(tmp_fd, "%s\n", new_line);
+      free(new_line);
+      new_line = NULL;
+   }
+   free_record(&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(&record);
+
+   return;
+}
diff --git a/org.glite.security.proxyrenewal/src/common.c b/org.glite.security.proxyrenewal/src/common.c
new file mode 100644 (file)
index 0000000..87fff76
--- /dev/null
@@ -0,0 +1,239 @@
+#include "renewal_locl.h"
+
+#ident "$Header$"
+
+/* nread() and nwrite() never return partial data */
+static size_t
+nread(int sock, char *buf, size_t buf_len)
+{
+   size_t count;
+   size_t remain = buf_len;
+   char *cbuf = buf;
+
+   while (remain > 0) {
+      count = read(sock, cbuf, remain);
+      if (count < 0) {
+        if (errno == EINTR)
+           continue;
+        else
+           return count;
+      } else
+        if (count == 0) {
+           return count;
+        }
+      cbuf += count;
+      remain -= count;
+   }
+   return buf_len;
+}
+
+static size_t
+nwrite(int sock, const char *buf, size_t buf_len)
+{
+   const char *cbuf = buf;
+   size_t count;
+   size_t remain = buf_len;
+
+   while (remain > 0) {
+      count = write(sock, cbuf, remain);
+      if (count < 0) {
+        if (errno == EINTR)
+           continue;
+        else
+           return count;
+      }
+      cbuf += count;
+      remain -= count;
+   }
+   return buf_len;
+}
+
+int
+edg_wlpr_Read(int sock, char **buf, size_t *buf_len)
+{
+   int ret;
+   unsigned char length[4];
+
+   ret = nread(sock, length, 4);
+   if (ret == -1) {
+      *buf_len = 0;
+      return errno;
+   }
+   if (ret < 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, *buf, *buf_len);
+   if (ret != *buf_len) {
+      free(*buf);
+      *buf_len = 0;
+      return errno;
+   }
+
+   return 0;
+}
+
+int
+edg_wlpr_Write(int sock, char *buf, size_t buf_len)
+{
+   unsigned char length[4];
+
+   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 (nwrite(sock, length, 4) != 4 ||
+       nwrite(sock, buf, buf_len) != buf_len)
+       return errno;
+   
+   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;
+}
diff --git a/org.glite.security.proxyrenewal/src/renew.c b/org.glite.security.proxyrenewal/src/renew.c
new file mode 100644 (file)
index 0000000..a51fcc7
--- /dev/null
@@ -0,0 +1,1146 @@
+#include "renewal_locl.h"
+#include "renewd_locl.h"
+
+#ifndef NOVOMS
+#include <voms_apic.h>
+#endif
+
+#ident "$Header$"
+
+extern char *repository;
+extern char *cadir;
+extern char *vomsdir;
+extern int voms_enabled;
+extern char *vomsconf;
+extern struct vomses_records vomses;
+
+static int received_signal = -1;
+
+static void
+check_renewal(char *datafile, int force_renew);
+
+static int
+renew_proxy(proxy_record *record, char *basename, char **new_proxy);
+
+static void
+register_signal(int signal);
+
+
+#define DGPR_RETRIEVE_DEFAULT_HOURS 10
+#define RENEWAL_CLOCK_SKEW 5 * 60
+
+static const char *
+get_ssl_err()
+{
+   return "SSL failed";
+}
+
+int
+load_proxy(const char *filename, X509 **cert, EVP_PKEY **privkey,
+           STACK_OF(X509) **chain)
+{
+   X509 *my_cert = NULL;
+   EVP_PKEY *my_key = NULL;
+   STACK_OF(X509) *my_chain = NULL;
+   FILE *fd = NULL;
+   int ret;
+
+   fd = fopen(filename, "r");
+   if (fd == NULL) {
+      edg_wlpr_Log(LOG_ERR,
+           "Cannot read VOMS certificate (fopen() failed on %s: %s)",
+           filename, strerror(errno));
+      return errno;
+   }
+
+   my_cert = PEM_read_X509(fd, NULL, NULL, NULL);
+   if (my_cert == NULL) {
+      edg_wlpr_Log(LOG_ERR,
+           "Cannot read VOMS certificate (PEM_read_X509() failed: %s)",
+           get_ssl_err());
+      ret = EDG_WLPR_ERROR_SSL;
+      goto end;
+   }
+
+   my_key = PEM_read_PrivateKey(fd, NULL, NULL, NULL);
+   if (my_key == NULL) {
+      edg_wlpr_Log(LOG_ERR,
+           "Cannot read VOMS certificate (PEM_read_PrivateKey() failed: %s)",
+           get_ssl_err());
+      ret = EDG_WLPR_ERROR_SSL;
+      goto end;
+   }
+
+   my_chain = sk_X509_new_null();
+   if (my_chain == NULL) {
+      edg_wlpr_Log(LOG_ERR,
+                  "Cannot read VOMS certificate (sk_X509_new_null() failed: %s)",
+                  get_ssl_err());
+      ret = EDG_WLPR_ERROR_SSL;
+      goto end;
+   }
+
+   while (1) {
+      X509 *c;
+
+      c = PEM_read_X509(fd, NULL, NULL, NULL);
+      if (c == NULL) {
+        if (ERR_GET_REASON(ERR_peek_error()) == PEM_R_NO_START_LINE) {
+           /* End of file reached. no error */
+           ERR_clear_error();
+           break;
+        }
+        edg_wlpr_Log(LOG_ERR,
+                     "Cannot read VOMS certificate (PEM_read_X509() failed: %s)",
+                     get_ssl_err());
+        ret = EDG_WLPR_ERROR_SSL;
+        goto end;
+      }
+      sk_X509_push(my_chain, c);
+   }
+
+   *cert = my_cert;
+   *privkey = my_key;
+   *chain = my_chain;
+   my_cert = NULL; my_key = NULL; my_chain = NULL;
+   ret = 0;
+
+end:
+   fclose(fd);
+
+   if (my_cert)
+      X509_free(my_cert);
+   if (my_key)
+      EVP_PKEY_free(my_key);
+   if (my_chain)
+      sk_X509_pop_free(my_chain, X509_free);
+
+   return ret;
+}
+
+static int
+save_proxy(const char *filename, X509 *new_cert, EVP_PKEY *new_privkey, 
+           STACK_OF(X509) *chain)
+{
+   FILE *fd = NULL;
+   int ret, i;
+   int retval = EDG_WLPR_ERROR_SSL;
+
+   fd = fopen(filename, "w");
+   if (fd == NULL) {
+      edg_wlpr_Log(LOG_ERR,
+                  "Cannot store proxy (fopen() failed on %s: %s)",
+                  filename, strerror(errno));
+      return errno;
+   }
+
+   ret = PEM_write_X509(fd, new_cert);
+   if (ret == 0) {
+      edg_wlpr_Log(LOG_ERR,
+                  "Cannot store proxy (PEM_write_X509() failed: %s)",
+                  get_ssl_err());
+      goto end;
+   }
+
+   ret = PEM_write_PrivateKey(fd, new_privkey, NULL, NULL, 0, NULL, NULL);
+   if (ret == 0) {
+      edg_wlpr_Log(LOG_ERR,
+                  "Cannot store proxy (PEM_write_PrivateKey() failed: %s)",
+                  get_ssl_err());
+      goto end;
+   }
+
+   for (i = 0; i < sk_X509_num(chain); i++) {
+      X509 *cert = sk_X509_value(chain, i);
+      ret = PEM_write_X509(fd, cert);
+      if (ret == 0) {
+        edg_wlpr_Log(LOG_ERR,
+                     "Cannot store proxy (PEM_write_X509() failed: %s)",
+                     get_ssl_err());
+        goto end;
+      }
+   }
+      
+   retval = 0;
+
+end:
+   fclose(fd);
+
+   return retval;
+}
+
+static int
+gen_keypair(EVP_PKEY **keypair, int requested_bits)
+{
+   RSA *rsa = NULL;
+   EVP_PKEY *key;
+
+   *keypair = NULL;
+   rsa = RSA_generate_key(requested_bits,
+                         RSA_F4 /* public exponent */,
+                         NULL, NULL);
+   if (rsa == NULL) {
+      edg_wlpr_Log(LOG_ERR,
+                  "Cannot generate new proxy (RSA_generate_key() failed: %s)",
+                  get_ssl_err());
+      return EDG_WLPR_ERROR_SSL;
+   }
+
+   key = EVP_PKEY_new();
+   if (key == NULL) {
+      edg_wlpr_Log(LOG_ERR,
+                  "Cannot generate new proxy (EVP_PKEY_new() failed: %s)",
+                  get_ssl_err());
+      RSA_free(rsa);
+      return EDG_WLPR_ERROR_SSL;
+   }
+
+   if (EVP_PKEY_assign_RSA(key, rsa) == 0) {
+      edg_wlpr_Log(LOG_ERR,
+                  "Cannot generate new proxy (EVP_PKEY_assign_RSA() failed: %s)",
+                  get_ssl_err());
+      RSA_free(rsa);
+      EVP_PKEY_free(key);
+      return EDG_WLPR_ERROR_SSL;
+   }
+
+   *keypair = key;
+
+   return 0;
+}
+
+static int
+gen_subject_name(X509 *old_cert, X509 *new_cert)
+{
+   X509_NAME *name = NULL;
+   X509_NAME_ENTRY *name_entry = NULL;
+   int ret = EDG_WLPR_ERROR_SSL;
+
+   name = X509_NAME_dup(X509_get_subject_name(old_cert));
+   if (name == NULL) {
+      edg_wlpr_Log(LOG_ERR,
+                  "Cannot generate new proxy (X509_NAME_dup() failed: %s",
+                  get_ssl_err());
+      goto end;
+   }
+
+   name_entry = X509_NAME_ENTRY_create_by_NID(NULL /* make new entry */,
+                                             NID_commonName,
+                                             V_ASN1_APP_CHOOSE,
+                                             "proxy", -1);
+   if (name_entry == NULL) {
+      edg_wlpr_Log(LOG_ERR,
+                  "Cannot generate new proxy (X509_NAME_ENTRY_create_by_NID() failed: %s)",
+                  get_ssl_err());
+      goto end;
+   }
+
+   if (X509_NAME_add_entry(name, name_entry, X509_NAME_entry_count(name), 0) == 0) {
+      edg_wlpr_Log(LOG_ERR,
+                  "Cannot generate new proxy (X509_NAME_add_entry() failed: %s)",
+                  get_ssl_err());
+      goto end;
+   }
+
+
+   if (X509_set_subject_name(new_cert, name) == 0) {
+      edg_wlpr_Log(LOG_ERR,
+                  "Cannot generate new proxy (X509_set_subject_name() failed: %s)",
+                  get_ssl_err());
+      goto end;
+   }
+
+   ret = 0;
+
+end:
+   if (name)
+      X509_NAME_free(name);
+   if (name_entry != NULL)
+      X509_NAME_ENTRY_free(name_entry);
+
+   return ret;
+}
+
+static int
+create_proxy(X509 *old_cert, EVP_PKEY *old_privkey, X509_EXTENSION *extension, 
+            X509 **new_cert, EVP_PKEY **new_privkey)
+{
+   /* Inspired by code from Myproxy */
+   EVP_PKEY *key_pair = NULL;
+   X509 *cert = NULL;
+   int ret;
+   int retval = EDG_WLPR_ERROR_SSL;
+
+   ret = gen_keypair(&key_pair, 512);
+   if (ret)
+      return ret;
+
+   cert = X509_new();
+   if (cert == NULL) {
+      edg_wlpr_Log(LOG_ERR, "Cannot generate new proxy (X509_new() failed: Not enough memory)");
+      goto end;
+   }
+
+   ret = gen_subject_name(old_cert, cert);
+   if (ret) {
+      retval = ret;
+      goto end;
+   }
+
+   if (X509_set_issuer_name(cert, X509_get_subject_name(old_cert)) == 0) {
+      edg_wlpr_Log(LOG_ERR,
+                  "Cannot generate new proxy (X509_set_issuer_name() failed: %s)",
+                  get_ssl_err());
+      goto end;
+   }
+
+   if (X509_set_serialNumber(cert, X509_get_serialNumber(old_cert)) == 0) {
+      edg_wlpr_Log(LOG_ERR,
+                  "Cannot generate new proxy (X509_set_serialNumber() failed: %s)",
+                  get_ssl_err());
+      goto end;
+   }
+
+   X509_gmtime_adj(X509_get_notBefore(cert), -(60 * 5));
+   X509_set_notAfter(cert, X509_get_notAfter(old_cert));
+
+   if (X509_set_pubkey(cert, key_pair) == 0) {
+      edg_wlpr_Log(LOG_ERR, 
+                  "Cannot generate new proxy (X509_set_pubkey() failed: %s)",
+                  get_ssl_err());
+      goto end;
+   }
+
+   /* set v3 */
+   if (X509_set_version(cert, 2L) == 0) {
+      edg_wlpr_Log(LOG_ERR,
+                  "Cannot generate new proxy (X509_set_version() failed: %s)",
+                  get_ssl_err());
+      goto end;
+   }
+
+   if (cert->cert_info->extensions != NULL)
+      sk_X509_EXTENSION_pop_free(cert->cert_info->extensions,
+                                X509_EXTENSION_free);
+   cert->cert_info->extensions = sk_X509_EXTENSION_new_null();
+   sk_X509_EXTENSION_push(cert->cert_info->extensions, extension);
+
+   if (X509_sign(cert, old_privkey, EVP_md5()) == 0) {
+      edg_wlpr_Log(LOG_ERR,
+                  "Cannot generate new proxy (X509_sign() failed: %s)",
+                  get_ssl_err());
+      goto end;
+   }
+
+   *new_privkey = key_pair;
+   *new_cert = cert;
+   key_pair = NULL;
+   cert = NULL;
+
+   retval = 0;
+
+end:
+   if (key_pair)
+      EVP_PKEY_free(key_pair);
+   if (cert)
+      X509_free(cert);
+
+   return retval;
+}
+
+static int
+create_voms_extension(char *buf, size_t buf_len, X509_EXTENSION **extensions)
+{
+   ASN1_OBJECT *voms_obj = NULL;
+   ASN1_OCTET_STRING *voms_oct = NULL;
+
+   *extensions = NULL;
+
+   voms_oct = ASN1_OCTET_STRING_new();
+   if (voms_oct == NULL) {
+      edg_wlpr_Log(LOG_ERR,
+                  "Cannot generate new proxy (ASN1_OCTET_STRING_new() failed: %s)",
+                  get_ssl_err());
+      return EDG_WLPR_ERROR_SSL;
+   }
+
+   voms_oct->data = buf;
+   voms_oct->length = buf_len;
+
+   voms_obj = OBJ_nid2obj(OBJ_txt2nid("VOMS"));
+   if (voms_obj == NULL) {
+      edg_wlpr_Log(LOG_ERR, "Cannot generate new proxy (OBJ_nid2obj() failed");
+      goto end;
+   }
+
+   *extensions = X509_EXTENSION_create_by_OBJ(NULL, voms_obj, 0, voms_oct);
+   if (*extensions == NULL) {
+      edg_wlpr_Log(LOG_ERR, "Cannot generate new proxy (X509_EXTENSION_create_by_OBJ() failed");
+      goto end;
+   }
+
+   return 0;
+
+end:
+   if (voms_oct)
+      ASN1_OCTET_STRING_free(voms_oct);
+   if (voms_obj)
+      ASN1_OBJECT_free(voms_obj);
+   return EDG_WLPR_ERROR_SSL;
+}
+
+#ifndef NOVOMS
+static int
+export_std_data(struct data *voms_data, char **buf)
+{
+   asprintf(buf, "GROUP: %s\n"
+                "ROLE:%s\n" /* the space is missing intentionaly */
+                "CAP: %s\n",
+                (voms_data->group) ? voms_data->group : "NULL",
+                (voms_data->role) ? voms_data->role : "NULL",
+                (voms_data->cap) ? voms_data->cap : "NULL");
+   return 0;
+}
+
+static int
+export_user_data(struct voms *voms_cert, char **buf, size_t *len)
+{
+   struct data **voms_data;
+   char *str = NULL;
+   char *ptr;
+
+   *buf = NULL;
+
+   switch (voms_cert->type) {
+      case TYPE_NODATA:
+        *buf = strdup("NO DATA");
+        break;
+      case TYPE_CUSTOM:
+        *buf = strdup(voms_cert->custom);
+        break;
+      case TYPE_STD:
+        for (voms_data = voms_cert->std; voms_data && *voms_data; voms_data++) {
+           export_std_data(*voms_data, &str);
+           if (*buf == NULL)
+              ptr = calloc(strlen(str) + 1, 1);
+           else
+              ptr = realloc(*buf, strlen(*buf) + strlen(str) + 1);
+           if (ptr == NULL) {
+              return ENOMEM;
+           }
+           *buf = ptr;
+           strcat(*buf, str);
+           free(str);
+        }
+           
+        break;
+      default:
+        return -1;
+   }
+   
+   *len = strlen(*buf);
+   return 0;
+}
+
+#endif
+
+static int
+encode_voms_buf(const char *label, char *data, size_t data_len,
+                char **buf, size_t *buf_len)
+{
+   char *tmp;
+
+   tmp = realloc(*buf, *buf_len + strlen(label) + data_len + 1);
+   if (tmp == NULL)
+      return ENOMEM;
+
+   memcpy(tmp + *buf_len, label, strlen(label));
+
+   memcpy(tmp + *buf_len + strlen(label), data, data_len);
+   tmp[*buf_len + strlen(label) + data_len] = '\n';
+   *buf = tmp;
+   *buf_len = *buf_len + strlen(label) + data_len + 1;
+
+   return 0;
+}
+
+static int
+encode_voms_int(const char *label, int value, char **buf, size_t *buf_len)
+{
+   char tmp[16];
+
+   snprintf(tmp, sizeof(tmp), "%d", value);
+   return encode_voms_buf(label, tmp, strlen(tmp), buf, buf_len);
+}
+
+static int
+encode_voms_str(const char *label, char *value, char **buf, size_t *buf_len)
+{
+   return encode_voms_buf(label, value, strlen(value), buf, buf_len);
+}
+
+#if 0
+static int
+VOMS_Export(struct vomsdata *voms_info, char **buf, size_t *len)
+{
+   struct voms *vc;
+   char *enc_voms = NULL;
+   size_t enc_voms_len = 0;
+   char *data_buf;
+   size_t data_len;
+   int ret;
+
+   if (voms_info == NULL || voms_info->data == NULL || *voms_info->data == NULL)
+      return EINVAL;
+   vc = *voms_info->data;
+
+   ret = export_user_data(vc, &data_buf, &data_len);
+   if (ret)
+      return ret;
+
+   encode_voms_int("SIGLEN:",   vc->siglen, &enc_voms, &enc_voms_len);
+   encode_voms_buf("SIGNATURE:",vc->signature, vc->siglen,
+                  &enc_voms, &enc_voms_len);
+   enc_voms_len--; /* Signature is not followed by '\n' */
+   encode_voms_str("USER:",     vc->user, &enc_voms, &enc_voms_len);
+   encode_voms_str("UCA:",      vc->userca, &enc_voms, &enc_voms_len);
+   encode_voms_str("SERVER:",   vc->server, &enc_voms, &enc_voms_len);
+   encode_voms_str("SCA:",      vc->serverca, &enc_voms, &enc_voms_len);
+   encode_voms_str("VO:",       vc->voname, &enc_voms, &enc_voms_len);
+   encode_voms_str("URI:",      vc->uri, &enc_voms, &enc_voms_len);
+   encode_voms_str("TIME1:",    vc->date1, &enc_voms, &enc_voms_len);
+   encode_voms_str("TIME2:",    vc->date2, &enc_voms, &enc_voms_len);
+   encode_voms_int("DATALEN:",  data_len, &enc_voms, &enc_voms_len);
+   encode_voms_buf("",          data_buf, data_len, &enc_voms, &enc_voms_len);
+   enc_voms_len--; /* the data already contains endind '\n' */
+
+   free(data_buf);
+   if (enc_voms == NULL) {
+      edg_wlpr_Log(LOG_ERR, "Cannot renew VOMS certificate (Not enough memory)");
+      return ENOMEM;
+   }
+   *buf = enc_voms;
+   *len = enc_voms_len;
+   return 0;
+}
+
+static int
+voms_cert_renew(char *hostname, int port, char *voms_subject,
+               char *proxy,
+                struct voms **cur_voms_cert, struct vomsdata *voms_info)
+{
+   int ret = 0;
+   char *command = "A";
+   int err = 0;
+   char *old_env_proxy = getenv("X509_USER_PROXY");
+
+   setenv("X509_USER_PROXY", proxy, 1);
+
+   /* hack (suggested by Vincenzo Ciaschini) to work around problem with
+    * unitialized VOMS struct */
+   ret = VOMS_Ordering("zzz:zzz", voms_info, &err);
+   if (ret == 0) {
+      edg_wlpr_Log(LOG_ERR, "Cannot renew VOMS certificate (VOMS_Ordering() failed");
+      ret = EDG_WLPR_ERROR_VOMS;
+      goto end;
+   }
+
+   /* XXX only attributes which are in current certificate should be requested*/
+   ret = VOMS_Contact(hostname, port, (*cur_voms_cert)->server, command,
+                     voms_info, &err);
+   if (ret == 0) {
+#if 0
+      if (err == 1) { /* XXX cannot connect voms server */ 
+        ret = 0;
+        goto end;
+      }
+#endif
+      edg_wlpr_Log(LOG_ERR, "Cannot renew VOMS certificate (VOMS_Contact() failed: %d)", err);
+      ret = EDG_WLPR_ERROR_VOMS;
+   } else
+      ret = 0;
+
+end:
+   (old_env_proxy) ? setenv("X509_USER_PROXY", old_env_proxy, 1) :
+                    unsetenv("X509_USER_PROXY");
+
+   return ret;
+}
+
+static int
+renew_voms_cert(struct voms **cur_voms_cert, char *proxy, char **buf, size_t *buf_len)
+{
+   struct vomsdata *voms_info = NULL;
+   char *hostname = NULL;
+   char *p;
+   int port, ret;
+
+   hostname = strdup((*cur_voms_cert)->uri);
+   p = strchr(hostname, ':');
+   if (p)
+      *p = '\0';
+   port = (p) ? atoi(p+1) : 15000;
+
+   voms_info = VOMS_Init(vomsdir, cadir);
+   if (voms_info == NULL) {
+      edg_wlpr_Log(LOG_ERR, "Cannot renew VOMS certificate (VOMS_Init() failed)");
+      ret = EDG_WLPR_ERROR_VOMS;
+      goto end;
+   }
+
+   ret = voms_cert_renew(hostname, port, (*cur_voms_cert)->server, proxy, cur_voms_cert,
+                        voms_info);
+   if (ret)
+      goto end;
+  
+   ret = VOMS_Export(voms_info, buf, buf_len);
+   if (ret) {
+      edg_wlpr_Log(LOG_ERR, "Cannot renew VOMS certificate (VOMS_Export() failed)");
+      ret = EDG_WLPR_ERROR_VOMS;
+      goto end;
+   }
+
+   ret = 0;
+
+end:
+   if (hostname)
+      free(hostname);
+#if 0
+   if (voms_info)
+      VOMS_Destroy(voms_info);
+#endif
+
+   return ret;
+}
+#endif
+
+#ifndef NOVOMS
+static vomses_record *
+find_vomses_record(char *hostname, int port)
+{
+   int i;
+
+   for (i = 0; i < vomses.len; i++) {
+      if (strcmp(vomses.val[i]->hostname, hostname) == 0 &&
+         vomses.val[i]->port == port)
+        return vomses.val[i];
+   }
+
+   return NULL;
+}
+
+static int
+set_vo_params(struct voms **voms_cert, char **arg)
+{
+   vomses_record *r;
+   char *tmp;
+   int port;
+   char *hostname;
+   char *p;
+
+   hostname = strdup((*voms_cert)->uri);
+   p = strchr(hostname, ':');
+   if (p)
+      *p = '\0';
+   port = (p) ? atoi(p+1) : 15000;
+
+   r = find_vomses_record(hostname, port);
+   if (r == NULL)
+      return EINVAL;
+
+   if (*arg == NULL) {
+      asprintf(arg, " -voms %s", r->nick);
+   } else {
+      tmp = realloc(*arg, 
+                   strlen(*arg) + strlen(" -voms ") + strlen(r->nick) + 1);
+      if (tmp == NULL)
+        return ENOMEM;
+      *arg = tmp;
+      *arg = strcat(*arg, " -voms ");
+      *arg = strcat(*arg, r->nick);
+   }
+   return 0;
+}
+#endif
+
+static int
+exec_voms_proxy_init(char *arg, char *old_proxy, char *new_proxy)
+{
+   char command[256];
+   int ret;
+   char *old_env_proxy = getenv("X509_USER_PROXY");
+
+   setenv("X509_USER_PROXY", old_proxy, 1);
+
+   snprintf(command, sizeof(command), 
+        "edg-voms-proxy-init -out %s -key %s -cert %s -confile %s -q %s",
+        new_proxy, old_proxy, old_proxy, vomsconf, arg);
+   ret = system(command);
+
+   (old_env_proxy) ? setenv("X509_USER_PROXY", old_env_proxy, 1) :
+                     unsetenv("X509_USER_PROXY");
+
+   return ret;
+}
+
+#if 0
+static int
+renew_voms_certs(const char *old_proxy, const char *new_proxy)
+{
+   struct vomsdata *voms_info = NULL;
+   struct voms **voms_cert = NULL;
+   STACK_OF(X509) *chain = NULL;
+   EVP_PKEY *privkey = NULL;
+   X509 *cert = NULL;
+   int ret, err;
+   char *buf = NULL;
+   size_t buf_len = 0;
+   X509_EXTENSION *extension = NULL;
+   X509 *new_cert = NULL;
+   EVP_PKEY *new_privkey = NULL;
+
+   voms_info = VOMS_Init(vomsdir, cadir);
+   if (voms_info == NULL) {
+      edg_wlpr_Log(LOG_ERR, "Cannot initialize VOMS context (VOMS_Init() failed)");
+      return EDG_WLPR_ERROR_VOMS;
+   }
+
+   ret = load_proxy(old_proxy, &cert, &privkey, &chain);
+   if (ret)
+      goto end;
+
+   ret = VOMS_Retrieve(cert, chain, RECURSE_CHAIN, voms_info, &err);
+   if (ret == 0) {
+      if (err == VERR_NOEXT) {
+        /* no VOMS cred, no problem; continue */
+        ret = 0;
+      } else {
+         edg_wlpr_Log(LOG_ERR, "Cannot get VOMS certificate(s) from proxy");
+         ret = EDG_WLPR_ERROR_VOMS;
+      }
+      goto end;
+   }
+
+   for (voms_cert = voms_info->data; voms_cert && *voms_cert; voms_cert++) {
+      char *tmp, *ptr;
+      size_t tmp_len;
+
+      ret = renew_voms_cert(voms_cert, old_proxy, &tmp, &tmp_len);
+      if (ret)
+        continue;
+      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 = create_voms_extension(buf, buf_len, &extension);
+   if (ret)
+      goto end;
+
+   X509_free(cert);
+   EVP_PKEY_free(privkey);
+   sk_X509_pop_free(chain, X509_free);
+
+   ret = load_proxy(new_proxy, &cert, &privkey, &chain);
+   if (ret)
+      goto end;
+
+   ret = create_proxy(cert, privkey, extension, &new_cert, &new_privkey);
+   if (ret)
+      goto end;
+
+   sk_X509_insert(chain, cert, 0);
+        
+   ret = save_proxy(new_proxy, new_cert, new_privkey, chain);
+   if (ret)
+      goto end;
+
+   ret = 0;
+
+end:
+   VOMS_Destroy(voms_info);
+
+   return ret;
+}
+#else /* 0 */
+
+#ifdef NOVOMS
+static int
+renew_voms_certs(const char *old_proxy, char *myproxy_proxy, const char *new_proxy)
+{
+       return 0;
+}
+
+#else
+static int
+renew_voms_certs(const char *old_proxy, char *myproxy_proxy, const char *new_proxy)
+{
+   struct vomsdata *voms_info = NULL;
+   struct voms **voms_cert = NULL;
+   STACK_OF(X509) *chain = NULL;
+   EVP_PKEY *privkey = NULL;
+   X509 *cert = NULL;
+   int ret, err;
+   char *arg = NULL;
+
+   voms_info = VOMS_Init(vomsdir, cadir);
+   if (voms_info == NULL) {
+      edg_wlpr_Log(LOG_ERR, "Cannot initialize VOMS context (VOMS_Init() failed)");
+      return EDG_WLPR_ERROR_VOMS;
+   }
+
+   ret = load_proxy(old_proxy, &cert, &privkey, &chain);
+   if (ret)
+      goto end;
+
+   ret = VOMS_Retrieve(cert, chain, RECURSE_CHAIN, voms_info, &err);
+   if (ret == 0) {
+      if (err == VERR_NOEXT) {
+        /* no VOMS cred, no problem; continue */
+        ret = 0;
+      } else {
+         edg_wlpr_Log(LOG_ERR, "Cannot get VOMS certificate(s) from proxy");
+         ret = EDG_WLPR_ERROR_VOMS;
+      }
+      goto end;
+   }
+
+   for (voms_cert = voms_info->data; voms_cert && *voms_cert; voms_cert++) {
+      ret = set_vo_params(voms_cert, &arg);
+      if (ret)
+        goto end;
+   }
+   ret = exec_voms_proxy_init(arg, myproxy_proxy, new_proxy);
+
+end:
+   VOMS_Destroy(voms_info);
+   return ret;
+}
+#endif /* NOVOMS */
+
+#endif /* 0 */
+
+static void
+register_signal(int signal)
+{
+      received_signal = signal;
+}
+
+static int
+renew_proxy(proxy_record *record, char *basename, char **new_proxy)
+{
+   char tmp_proxy[FILENAME_MAX];
+   int tmp_fd;
+   char repository_file[FILENAME_MAX];
+   FILE *fd = NULL;
+   int ret = -1;
+   char *p;
+   X509 *cert = NULL;
+   X509_NAME *subject = NULL;
+   char *server = NULL;
+   myproxy_socket_attrs_t *socket_attrs;
+   myproxy_request_t      *client_request;
+   myproxy_response_t     *server_response;
+   char *renewed_proxy;
+
+   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));
+
+   edg_wlpr_Log(LOG_DEBUG, "Trying to renew proxy in %s.%d",
+               basename, record->suffix);
+
+   snprintf(tmp_proxy, sizeof(tmp_proxy), "%s.%d.renew.XXXXXX", 
+           basename, record->suffix);
+   tmp_fd = mkstemp(tmp_proxy);
+   if (tmp_fd == -1) {
+      edg_wlpr_Log(LOG_ERR, "Cannot create temporary file (%s)",
+                   strerror(errno));
+      return errno;
+   }
+
+   myproxy_set_delegation_defaults(socket_attrs, client_request);
+
+   snprintf(repository_file, sizeof(repository_file),"%s.%d",
+           basename, record->suffix);
+   fd = fopen(repository_file, "r");
+   if (fd == NULL) {
+      edg_wlpr_Log(LOG_ERR, "Cannot open proxy %s for renewal (%s)",
+                  repository_file, strerror(errno));
+      ret = errno;
+      goto end; /* XXX */
+   }
+
+   cert = PEM_read_X509(fd, NULL, NULL, NULL);
+   fclose(fd);
+   if (cert == NULL) {
+      edg_wlpr_Log(LOG_ERR, "SSL routines failed to read proxy %s for renewal",
+                  repository_file);
+      ret = EDG_WLPR_ERROR_SSL;
+      goto end;
+   }
+
+   subject = X509_NAME_dup(X509_get_subject_name(cert));
+   proxy_get_base_name(subject);
+   client_request->username = X509_NAME_oneline(subject, NULL, 0);
+   X509_NAME_free(subject);
+   X509_free(cert);
+   if (client_request->username == NULL) {
+      edg_wlpr_Log(LOG_ERR, "Cannot read subject name from %s", repository_file);
+      ret = EINVAL;
+      goto end;
+   }
+
+   /* XXX support VERY_SHORT_LIFETIME ? */
+   client_request->proxy_lifetime = 60 * 60 * DGPR_RETRIEVE_DEFAULT_HOURS;
+
+   server = (record->myproxy_server) ? record->myproxy_server :
+                                       socket_attrs->pshost;
+   if (server == NULL) {
+      edg_wlpr_Log(LOG_ERR, "No myproxy server specified");
+      ret = EINVAL;
+      goto end;
+   }
+   socket_attrs->pshost = strdup(server);
+
+   p = strchr(socket_attrs->pshost, ':');
+   if (p) {
+      *p++ = '\0';
+      ret = edg_wlpr_DecodeInt(p, &socket_attrs->psport);
+      if (ret)
+        goto end;
+   } else
+      socket_attrs->psport = MYPROXY_SERVER_PORT;
+
+   ret = myproxy_get_delegation(socket_attrs, client_request, repository_file,
+                               server_response, tmp_proxy);
+   if (ret == 1) {
+      ret = EDG_WLPR_ERROR_MYPROXY;
+      edg_wlpr_Log(LOG_ERR, "Cannot get renewed proxy from Myproxy server");
+      goto end;
+   }
+
+   renewed_proxy = tmp_proxy;
+
+   if (voms_enabled) {
+      char tmp_voms_proxy[FILENAME_MAX];
+      int tmp_voms_fd;
+      
+      snprintf(tmp_voms_proxy, sizeof(tmp_voms_proxy), "%s.%d.renew.XXXXXX",
+              basename, record->suffix);
+      tmp_voms_fd = mkstemp(tmp_voms_proxy);
+      if (tmp_voms_fd == -1) {
+        edg_wlpr_Log(LOG_ERR, "Cannot create temporary file (%s)",
+                     strerror(errno));
+        ret = errno;
+        goto end;
+      }
+
+      ret = renew_voms_certs(repository_file, tmp_proxy, tmp_voms_proxy);
+      if (ret)
+        goto end;
+
+      renewed_proxy = tmp_voms_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;
+}
+
+static void
+check_renewal(char *datafile, int force_renew)
+{
+   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);
+
+   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) {
+      edg_wlpr_Log(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) {
+      edg_wlpr_Log(LOG_ERR, "Cannot open meta file %s (%s)",
+                  datafile, strerror(errno));
+      return;
+   }
+
+   current_time = time(NULL);
+   edg_wlpr_Log(LOG_DEBUG, "Reading metafile %s", datafile);
+
+   while (fgets(line, sizeof(line), meta_fd) != NULL) {
+      free_record(&record);
+      p = strchr(line, '\n');
+      if (p)
+        *p = '\0';
+      ret = decode_record(line, &record);
+      if (ret)
+        continue; /* XXX exit? */
+      if (record.jobids.len == 0) /* no jobid registered for this proxy */
+        continue;
+      if (record.end_time - current_time < RENEWAL_CLOCK_SKEW ||
+         abs(record.next_renewal - current_time) < RENEWAL_CLOCK_SKEW ||
+         record.next_renewal < current_time ||
+         record.end_time < current_time ||
+         force_renew) {
+        ret = EDG_WLPR_PROXY_EXPIRED;
+        if (record.end_time >= current_time)
+           /* only try renewal if the proxy hasn't already expired */
+           ret = renew_proxy(&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(&record);
+           return;
+        }
+        request.entries = tmp;
+        request.entries[num] = entry;
+        request.entries[num+1] = NULL;
+        num++;
+      }
+   }
+   free_record(&record);
+
+   if (num > 0) {
+      ret = edg_wlpr_RequestSend(&request, &response);
+      if (ret != 0)
+        edg_wlpr_Log(LOG_ERR,
+                     "Failed to send update request to master (%d)", ret);
+      else if (response.response_code != 0)
+        edg_wlpr_Log(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);
+
+   return;
+}
+
+int renewal(int force_renew)
+{
+   DIR *dir = NULL;
+   struct dirent *file;
+   FILE *fd;
+
+   edg_wlpr_Log(LOG_DEBUG, "Starting renewal process");
+
+   if (chdir(repository)) {
+      edg_wlpr_Log(LOG_ERR, "Cannot access repository directory %s (%s)",
+                  repository, strerror(errno));
+      return errno;
+   }
+
+   dir = opendir(repository);
+   if (dir == NULL) {
+      edg_wlpr_Log(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) {
+        edg_wlpr_Log(LOG_ERR, "Cannot open meta file %s (%s)",
+                     file->d_name, strerror(errno));
+        continue;
+      }
+      check_renewal(file->d_name, force_renew);
+      fclose(fd);
+   }
+   closedir(dir);
+   edg_wlpr_Log(LOG_DEBUG, "Finishing renewal process");
+   return 0;
+}
+
+void
+watchdog_start(void)
+{
+   struct sigaction sa;
+   int force_renewal;
+   
+   memset(&sa,0,sizeof(sa));
+   sa.sa_handler = register_signal;
+   sigaction(SIGUSR1, &sa, NULL);
+
+   /* load_vomses(); */
+
+   while (1) {
+       received_signal = -1;
+       sleep(60 * 5);
+       force_renewal = (received_signal == SIGUSR1) ? 1 : 0;
+       /* XXX uninstall signal handler ? */
+       renewal(force_renewal);
+   }
+}
diff --git a/org.glite.security.proxyrenewal/src/renewal_locl.h b/org.glite.security.proxyrenewal/src/renewal_locl.h
new file mode 100644 (file)
index 0000000..45317e3
--- /dev/null
@@ -0,0 +1,133 @@
+#ifndef RENEWAL_LOCL_H
+#define RENEWAL_LOCL_H
+
+#ident "$Header$"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <syslog.h>
+#include <linux/limits.h>
+#include <signal.h>
+#include <assert.h>
+#include <getopt.h>
+#include <dirent.h>
+#include <sys/un.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <openssl/md5.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+
+#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 */
+
+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, char **buf, size_t *buf_len);
+
+int
+edg_wlpr_Write(int sock, 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);
+
+#endif /* RENEWAL_LOCL_H */
diff --git a/org.glite.security.proxyrenewal/src/renewd.c b/org.glite.security.proxyrenewal/src/renewd.c
new file mode 100644 (file)
index 0000000..94c39d1
--- /dev/null
@@ -0,0 +1,666 @@
+#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 *vomsconf = "/opt/edg/etc/vomses";
+#ifndef NOVOMS
+struct vomses_records vomses;
+#endif
+
+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' },
+   { NULL, 0, NULL, 0 }
+};
+
+typedef struct {
+   edg_wlpr_Command code;
+   void (*handler) (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(char *progname);
+
+static int
+do_listen(char *socket_name, int *sock);
+
+static int
+encode_response(edg_wlpr_Response *response, char **msg);
+
+static command_table *
+find_command(edg_wlpr_Command code);
+
+static int
+proto(int sock);
+
+static int
+doit(int sock);
+
+static int
+decode_request(const char *msg, const size_t msg_len, edg_wlpr_Request *request);
+
+static command_table *
+find_command(edg_wlpr_Command code)
+{
+   command_table *c;
+
+   for (c = commands; c->code; c++) {
+      if (c->code == code)
+          return c;
+   }
+   return NULL;
+}
+
+static int
+proto(int sock)
+{
+   char  *buf = NULL;
+   size_t  buf_len;
+   int  ret;
+   edg_wlpr_Response  response;
+   edg_wlpr_Request  request;
+   command_table  *command;
+
+   memset(&request, 0, sizeof(request));
+   memset(&response, 0, sizeof(response));
+
+   ret = edg_wlpr_Read(sock, &buf, &buf_len);
+   if (ret) {
+      edg_wlpr_Log(LOG_ERR, "Error reading from client: %s",
+                   edg_wlpr_GetErrorString(ret));
+      return ret;
+   }
+
+   ret = decode_request(buf, buf_len, &request);
+   free(buf);
+   if (ret)
+      goto end;
+
+   /* XXX check request (protocol version, ...) */
+
+   command = find_command(request.command);
+   if (command == NULL) {
+      ret = EDG_WLPR_ERROR_UNKNOWN_COMMAND;
+      edg_wlpr_Log(LOG_ERR, "Received unknown command (%d)", request.command);
+      goto end;
+   }
+
+   edg_wlpr_Log(LOG_INFO, "Received command code %d for proxy %s",
+                request.command,
+                request.proxy_filename ? request.proxy_filename : "(unspecified)");
+
+   command->handler(&request, &response);
+
+   ret = encode_response(&response, &buf);
+   if (ret)
+      goto end;
+
+   ret = edg_wlpr_Write(sock, buf, strlen(buf) + 1);
+   free(buf);
+   if (ret) {
+      edg_wlpr_Log(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(int sock)
+{
+   int newsock;
+   struct sockaddr_un client_addr;
+   int client_addr_len = sizeof(client_addr);
+#if 0
+   next_renewal = LONG_MAX;
+   size_of_proxies = PROXIES_ALLOC_SIZE;
+   proxies = malloc((size_of_proxies) * sizeof(struct guarded_proxy *));
+   if (proxies == NULL) {
+       return ENOMEM;
+   }
+   proxies[0] = NULL;
+#endif
+
+#if 0
+   sigemptyset(&sset);
+   sigaddset(&sset,SIGTERM);
+   sigaddset(&sset,SIGINT);
+   sigaddset(&sset, SIGKILL);
+   sigaddset(&sset, SIGUSR1);
+   sigaddset(&sset, SIGALRM);
+   sigprocmask(SIG_BLOCK,&sset,NULL);
+#endif
+
+   while (1) {
+#if 0
+      sigprocmask(SIG_UNBLOCK,&sset,NULL);
+      newsock = accept(sock, (struct sockaddr *) &client_addr, &client_addr_len);
+      sigprocmask(SIG_BLOCK,&sset,NULL);
+
+      if (newsock == -1) {
+         if (errno == EINTR) /* ERESTARTSYS */
+             proxy_renewal(received_signal);
+         else
+            log();
+         continue;
+      }
+#else
+      newsock = accept(sock, (struct sockaddr *) &client_addr, &client_addr_len);
+      if (newsock == -1) {
+         edg_wlpr_Log(LOG_ERR, "accept() failed");
+         continue;
+      }
+      edg_wlpr_Log(LOG_DEBUG, "Got connection");
+
+#endif
+
+      proto(newsock);
+
+      edg_wlpr_Log(LOG_DEBUG, "Connection closed");
+      close(newsock);
+   }
+}
+
+static int
+decode_request(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) {
+      edg_wlpr_Log(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) {
+      edg_wlpr_Log(LOG_ERR, "Protocol error reading command specification: %s",
+                   edg_wlpr_GetErrorString(ret));
+      goto err;
+   }
+
+   ret = edg_wlpr_DecodeInt(value, (int *)(&request->command));
+   if (ret) {
+      edg_wlpr_Log(LOG_ERR, "Received non-numeric command specification (%s)",
+                   value);
+      free(value);
+      goto err;
+   }
+   free(value);
+
+   if (find_command(request->command) == NULL) {
+      edg_wlpr_Log(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) {
+      edg_wlpr_Log(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) {
+      edg_wlpr_Log(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) {
+      edg_wlpr_Log(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(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(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(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) {
+      edg_wlpr_Log(LOG_ERR, "socket(): %s", strerror(errno));
+      return errno;
+   }
+
+   ret = bind(s, (struct sockaddr *)&my_addr, sizeof(my_addr));
+   if (ret == -1) {
+      edg_wlpr_Log(LOG_ERR, "bind(): %s", strerror(errno));
+      close(s);
+      return errno;
+   }
+
+   ret = listen(s, 5); /* XXX enough ? */
+   if (ret == -1) {
+      edg_wlpr_Log(LOG_ERR, "listen(): %s", strerror(errno));
+      close(s);
+      return errno;
+   }
+
+   *sock = s;
+   return 0;
+}
+
+void
+edg_wlpr_Log(int dbg_level, const char *format, ...)
+{
+   va_list ap;
+   char    log_mess[1024];
+
+   /* cannot handle the %m format argument specific for syslog() */
+   va_start(ap, format);
+   vsnprintf(log_mess, sizeof(log_mess), format, ap);
+   va_end(ap);
+   
+   if (debug)
+      printf("[%d] %s\n", getpid(), log_mess);
+   else
+      if (dbg_level < LOG_DEBUG) /* XXX make configurable */
+         syslog(dbg_level, "%s", log_mess);
+}
+
+int
+start_watchdog(pid_t *pid)
+{
+   pid_t p;
+
+   switch ((p = fork())) {
+      case -1:
+        edg_wlpr_Log(LOG_ERR, "fork() failed: %s",
+                     strerror(errno));
+        return errno;
+      case 0:
+        watchdog_start();
+        exit(0); 
+        break;
+      default:
+        *pid = p;
+        return 0;
+   }
+   /* not reachable */
+   exit(0);
+}
+
+#ifdef NOVOMS
+static int
+load_vomses()
+{
+       return ENOSYS;
+}
+
+#else
+static int
+load_vomses()
+{
+   FILE *fd = NULL;
+   char line[1024];
+   char *nick, *hostname;
+   int port;
+   vomses_record *rec;
+   vomses_record **tmp;
+   char *p;
+   
+   fd = fopen(vomsconf, "r");
+   if (fd == NULL) {
+      edg_wlpr_Log(LOG_ERR, "Cannot open vomses configuration file (%s)",
+                  strerror(errno));
+      return errno;
+   }
+   while (fgets(line, sizeof(line), fd) != NULL) {
+      p = line;
+      if (*p != '"') {
+        edg_wlpr_Log(LOG_ERR, "Parsing error when reading vomses configuration file");
+        return EINVAL;
+      }
+      nick = strdup(strtok(p+1, "\""));
+
+      p = strtok(NULL, "\"");
+      hostname = strdup(strtok(NULL, "\""));
+
+      p = strtok(NULL, "\"");
+      port = atoi(strdup(strtok(NULL, "\"")));
+
+      if (nick == NULL || hostname == NULL) {
+        edg_wlpr_Log(LOG_ERR, "Parsing error when reading vomses configuration file");
+        return EINVAL;
+      }
+
+      rec = calloc(1, sizeof(*rec));
+      if (rec == NULL) {
+        edg_wlpr_Log(LOG_ERR, "Not enough memory");
+        return ENOMEM;
+      }
+      rec->nick = nick;
+      rec->hostname = hostname;
+      rec->port = port;
+
+      tmp = realloc(vomses.val, vomses.len + 1);
+      if (tmp == NULL) {
+        edg_wlpr_Log(LOG_ERR, "Not enough memory");
+        return ENOMEM;
+      }
+      vomses.val = tmp;
+      vomses.len++;
+
+      vomses.val[vomses.len-1] = rec;
+   }
+   fclose(fd);
+   return 0;
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+   int   sock;
+   char  *progname;
+   int   opt;
+   int   fd;
+   char  sockname[PATH_MAX];
+   int   ret;
+   pid_t pid;
+
+   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:", opts, NULL)) != EOF)
+      switch (opt) {
+        case 'h': usage(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 '?': usage(progname); return 1;
+      }
+
+   if (optind < argc) {
+      usage(progname);
+      exit(1);
+   }
+
+   if (chdir(repository)) {
+      edg_wlpr_Log(LOG_ERR, "Cannot access repository directory %s (%s)",
+                  repository, strerror(errno));
+      exit(1);
+   }
+
+   if (!debug)
+      for (fd = 3; fd < OPEN_MAX; fd++) close(fd);
+
+   if (!debug) {
+      /* chdir ? */
+      if (daemon(1,0) == -1) {
+        perror("deamon()");
+        exit(1);
+      }
+      openlog(progname, LOG_PID, LOG_DAEMON);
+   }
+
+   if (voms_enabled) {
+      char *path;
+      char *new_path;
+      ret = load_vomses();
+      if (ret)
+        return 1;
+      setenv("GLOBUS_VERSION", "22", 0);
+      if (VOMS_INSTALL_PATH != NULL && *VOMS_INSTALL_PATH != '\0') {
+        path = getenv("PATH");
+        asprintf(&new_path, "%s:%s/bin", path, VOMS_INSTALL_PATH);
+         setenv("PATH", new_path, 1);
+      }
+   }
+   
+   ret = start_watchdog(&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(sockname, &sock);
+   if (ret)
+      return 1;
+   edg_wlpr_Log(LOG_DEBUG, "Listening at %s", sockname);
+
+#if 0
+   /* XXX ??? */
+   install_handlers();
+#endif
+   
+
+#if 0
+   /* XXX this overrides setings done by install_handlers()? */
+   signal(SIGTERM, cleanup);
+   signal(SIGINT, cleanup);
+   signal(SIGKILL, cleanup);
+   signal(SIGPIPE, SIG_IGN);
+
+   atexit(cleanup);
+#endif
+
+   ret = doit(sock);
+
+   close(sock);
+   return ret;
+}
diff --git a/org.glite.security.proxyrenewal/src/renewd_locl.h b/org.glite.security.proxyrenewal/src/renewd_locl.h
new file mode 100644 (file)
index 0000000..fb16bc6
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef RENEWALD_LOCL_H
+#define RENEWALD_LOCL_H
+
+#ident "$Header$"
+
+#include <myproxy.h>
+#include <myproxy_delegation.h>
+
+#include "glite/wms/thirdparty/globus_ssl_utils/sslutils.h"
+#include "renewal.h"
+
+#ifdef HAVE_DMALLOC_H
+#include <dmalloc.h>
+#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;
+
+typedef struct vomses_record {
+   char *nick;
+   char *hostname;
+   int port;
+} vomses_record;
+
+typedef struct vomses_records {
+   unsigned int len;
+   struct vomses_record **val;
+} vomses_records;
+
+/* commands */
+void
+register_proxy(edg_wlpr_Request *request, edg_wlpr_Response *response);
+
+void
+unregister_proxy(edg_wlpr_Request *request, edg_wlpr_Response *response);
+
+void
+get_proxy(edg_wlpr_Request *request, edg_wlpr_Response *response);
+
+void
+update_db(edg_wlpr_Request *request, edg_wlpr_Response *response);
+
+int
+get_times(char *proxy_file, proxy_record *record);
+
+void
+watchdog_start(void);
+
+void
+edg_wlpr_Log(int dbg_level, const char *format, ...);
+
+int
+decode_record(char *line, proxy_record *record);
+
+int
+encode_record(proxy_record *record, char **line);
+
+void
+free_record(proxy_record *record);
+
+int
+load_proxy(const char *filename, X509 **cert, EVP_PKEY **privkey,
+           STACK_OF(X509) **chain);
+
+#endif /* RENEWALD_LOCL_H */