From a7cfde521d2a0ff452aa1af685a293fb074a0bf8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ale=C5=A1=20K=C5=99enek?= Date: Fri, 9 Jul 2004 10:16:25 +0000 Subject: [PATCH] initial import --- org.glite.security.proxyrenewal/Makefile | 101 ++ org.glite.security.proxyrenewal/build.xml | 104 ++ .../interface/renewal.h | 144 +++ .../project/configure.properties.xml | 44 + .../project/properties.xml | 12 + .../project/taskdefs.xml | 4 + org.glite.security.proxyrenewal/src/api.c | 436 +++++++ org.glite.security.proxyrenewal/src/client.c | 117 ++ org.glite.security.proxyrenewal/src/commands.c | 1258 ++++++++++++++++++++ org.glite.security.proxyrenewal/src/common.c | 239 ++++ org.glite.security.proxyrenewal/src/renew.c | 1146 ++++++++++++++++++ org.glite.security.proxyrenewal/src/renewal_locl.h | 133 +++ org.glite.security.proxyrenewal/src/renewd.c | 666 +++++++++++ org.glite.security.proxyrenewal/src/renewd_locl.h | 83 ++ 14 files changed, 4487 insertions(+) create mode 100644 org.glite.security.proxyrenewal/Makefile create mode 100755 org.glite.security.proxyrenewal/build.xml create mode 100644 org.glite.security.proxyrenewal/interface/renewal.h create mode 100644 org.glite.security.proxyrenewal/project/configure.properties.xml create mode 100755 org.glite.security.proxyrenewal/project/properties.xml create mode 100755 org.glite.security.proxyrenewal/project/taskdefs.xml create mode 100644 org.glite.security.proxyrenewal/src/api.c create mode 100644 org.glite.security.proxyrenewal/src/client.c create mode 100644 org.glite.security.proxyrenewal/src/commands.c create mode 100644 org.glite.security.proxyrenewal/src/common.c create mode 100644 org.glite.security.proxyrenewal/src/renew.c create mode 100644 org.glite.security.proxyrenewal/src/renewal_locl.h create mode 100644 org.glite.security.proxyrenewal/src/renewd.c create mode 100644 org.glite.security.proxyrenewal/src/renewd_locl.h diff --git a/org.glite.security.proxyrenewal/Makefile b/org.glite.security.proxyrenewal/Makefile new file mode 100644 index 0000000..6a386fe --- /dev/null +++ b/org.glite.security.proxyrenewal/Makefile @@ -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 index 0000000..caef0ba --- /dev/null +++ b/org.glite.security.proxyrenewal/build.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.glite.security.proxyrenewal/interface/renewal.h b/org.glite.security.proxyrenewal/interface/renewal.h new file mode 100644 index 0000000..c70b881 --- /dev/null +++ b/org.glite.security.proxyrenewal/interface/renewal.h @@ -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 index 0000000..53d3297 --- /dev/null +++ b/org.glite.security.proxyrenewal/project/configure.properties.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + +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} + + + diff --git a/org.glite.security.proxyrenewal/project/properties.xml b/org.glite.security.proxyrenewal/project/properties.xml new file mode 100755 index 0000000..aef3360 --- /dev/null +++ b/org.glite.security.proxyrenewal/project/properties.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/org.glite.security.proxyrenewal/project/taskdefs.xml b/org.glite.security.proxyrenewal/project/taskdefs.xml new file mode 100755 index 0000000..13e894e --- /dev/null +++ b/org.glite.security.proxyrenewal/project/taskdefs.xml @@ -0,0 +1,4 @@ + + + + diff --git a/org.glite.security.proxyrenewal/src/api.c b/org.glite.security.proxyrenewal/src/api.c new file mode 100644 index 0000000..e241f20 --- /dev/null +++ b/org.glite.security.proxyrenewal/src/api.c @@ -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 index 0000000..eb2d36b --- /dev/null +++ b/org.glite.security.proxyrenewal/src/client.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include "renewal.h" + +static const char rcsid[] = "$Header$"; + +static struct option const long_options[] = { + { "help", no_argument, 0, 'h' }, + { "version", no_argument, 0, 'v' }, + { "server", required_argument, 0, 's' }, + { "port", required_argument, 0, 'p' }, + { "file", required_argument, 0, 'f' }, + { "jobid", required_argument, 0, 'j' }, + { NULL, 0, NULL, 0} +}; + +static char short_options[] = "hvs:p:f:j:"; + +static void +usage(exit_code) +{ + fprintf(stdout, "Usage: edg-wl-renew [option] operation\n" + "\t-s myproxy_server [-p port] -f filename -j jobid start |\n" + "\t-j jobid [-f filename] stop |\n" + "\t-j jobid get\n" + "-h, --help display this help and exit\n" + "-v, --version output version information and exit\n" + "-s, --server address of myproxy server\n" + "-p, --port port of myproxy server\n" + "-f, --file filename with proxy\n" + "-j, --jobid datagrid jobid\n"); + exit(exit_code); +} + +int +main(int argc, char *argv[]) +{ + char *server = NULL; + int port = 0; + char *proxyfile = NULL; + char *jobid_str = NULL; + 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 index 0000000..ba566d0 --- /dev/null +++ b/org.glite.security.proxyrenewal/src/commands.c @@ -0,0 +1,1258 @@ +#include "renewal_locl.h" +#include "renewd_locl.h" + +#ifndef NOVOMS +#include +#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=" */ + 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 index 0000000..87fff76 --- /dev/null +++ b/org.glite.security.proxyrenewal/src/common.c @@ -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 index 0000000..a51fcc7 --- /dev/null +++ b/org.glite.security.proxyrenewal/src/renew.c @@ -0,0 +1,1146 @@ +#include "renewal_locl.h" +#include "renewd_locl.h" + +#ifndef NOVOMS +#include +#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 index 0000000..45317e3 --- /dev/null +++ b/org.glite.security.proxyrenewal/src/renewal_locl.h @@ -0,0 +1,133 @@ +#ifndef RENEWAL_LOCL_H +#define RENEWAL_LOCL_H + +#ident "$Header$" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "renewal.h" + +#define JDL_MYPROXY "Myproxy_server=" + +typedef enum { + EDG_WLPR_COMMAND_NONE = 0, + EDG_WLPR_COMMAND_REG = 1, + EDG_WLPR_COMMAND_UNREG, + EDG_WLPR_COMMAND_GET, + EDG_WLPR_COMMAND_LIST, + EDG_WLPR_COMMAND_STATUS, + EDG_WLPR_COMMAND_UPDATE_DB, +} edg_wlpr_Command; + +/* prefix neni nutny */ +#define EDG_WLPR_PROTO_VERSION "Version=" +#define EDG_WLPR_PROTO_COMMAND "Command=" +#define EDG_WLPR_PROTO_MYPROXY_SERVER "Myproxy_server=" +#define EDG_WLPR_PROTO_PROXY "Proxy_name=" +#define EDG_WLPR_PROTO_UNIQUE_PROXY "Unique=" /* XXX */ +#define EDG_WLPR_PROTO_JOBID "Jobid=" +#define EDG_WLPR_PROTO_ENTRY "Entry=" + +#define EDG_WLPR_PROTO_RESPONSE "Response=" /* XXX result ?? */ +#define EDG_WLPR_PROTO_START_TIME "Start_time=" +#define EDG_WLPR_PROTO_END_TIME "End_time=" +#define EDG_WLPR_PROTO_RENEWAL_TIME "Renewal_time=" /* XXX Next renewal ?? */ + +#define EDG_WLPR_MYPROXY_PORT 7512 + +#define EDG_WLPR_REPOSITORY_ROOT "/var/spool/edg-wl-renewd" + +#define EDG_WLPR_BUF_SIZE 4096 + +#define EDG_WLPR_VERSION "EDG Proxy Renewal 1.0" + +#define MAX_PROXIES 4 /* max. number of jobids sharing one proxy */ + +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 index 0000000..94c39d1 --- /dev/null +++ b/org.glite.security.proxyrenewal/src/renewd.c @@ -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 index 0000000..fb16bc6 --- /dev/null +++ b/org.glite.security.proxyrenewal/src/renewd_locl.h @@ -0,0 +1,83 @@ +#ifndef RENEWALD_LOCL_H +#define RENEWALD_LOCL_H + +#ident "$Header$" + +#include +#include + +#include "glite/wms/thirdparty/globus_ssl_utils/sslutils.h" +#include "renewal.h" + +#ifdef HAVE_DMALLOC_H +#include +#endif + +/* XXX */ +#if 0 +#define EDG_WLPR_ERROR_PARSE_NOT_FOUND EDG_WLPR_ERROR_PROTO_PARSE_ERROR +#define EDG_WLPR_ERROR_NOTFOUND EDG_WLPR_PROXY_NOT_REGISTERED +#endif + +typedef struct { + unsigned int len; + char **val; +} prd_list; + +typedef struct { + int suffix; + prd_list jobids; + int unique; + int voms_exts; + char *myproxy_server; + time_t end_time; + time_t next_renewal; +} proxy_record; + +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 */ -- 1.8.2.3