+* Mon Jul 17 2006 Andrew McNab <Andrew.McNab@man.ac.uk>
+- Add Shibboleth handling from Joseph Dada's branch to
+ mod_gridsite in main GridSite tree.
* Tue Jun 27 2006 Andrew McNab <Andrew.McNab@man.ac.uk>
- Merge delegation services back into core.
- Add OCSP options
MAJOR_VERSION=1
MINOR_VERSION=1.3
-PATCH_VERSION=1.3.1
+PATCH_VERSION=1.3.2
VERSION=$(PATCH_VERSION)
int tag; } ;
typedef struct { int type; /* CA, user, proxy, VOMS, ... */
- int status; /* unchecked, bad sig, bad time */
+ int errors; /* unchecked, bad sig, bad time */
char *ca; /* Cert CA DN, or VOMS issuer CA */
char *dn; /* Cert DN, or VOMS issuer DN */
char *value; /* VOMS FQAN or NULL */
void *raw; /* X509 or VOMS Extension object */
void *next; } GRSTx509Cert;
+#define GRST_CERT_BAD_FORMAT 1
+#define GRST_CERT_BAD_CHAIN 2
+#define GRST_CERT_BAD_SIG 4
+#define GRST_CERT_BAD_TIME 8
+#define GRST_CERT_BAD_OCSP 16
+
+#define GRST_CERT_TYPE_CA 1
+#define GRST_CERT_TYPE_EEC 2
+#define GRST_CERT_TYPE_PROXY 3
+#define GRST_CERT_TYPE_VOMS 4
+
+/* a chain of certs, starting from the first CA */
typedef struct { GRSTx509Cert *firstcert; } GRSTx509Chain;
int GRSTx509CertLoad(GRSTx509Cert *, X509 *);
-int GRSTx509ChainLoad(GRSTx509Chain *, STACK_OF(X509) *, X509 *);
+int GRSTx509ChainLoadCheck(GRSTx509Chain **, STACK_OF(X509) *, X509 *, char *);
int GRSTx509ChainFree(GRSTx509Chain *);
#define GRST_HTTP_PORT 777
-module.version=1.3.1
+module.version=1.3.2
module.age=1
gcc -g -DVERSION=\"$(PATCH_VERSION)\" $(MYCFLAGS) \
-o gsexec gsexec.c
-urlencode: urlencode.c libgridsite.a
+urlencode: urlencode.c libgridsite.so.$(VERSION)
gcc -g -DVERSION=\"$(PATCH_VERSION)\" $(MYCFLAGS) \
-o urlencode urlencode.c -L. \
-I/usr/kerberos/include \
-lgridsite
-htcp: htcp.c libgridsite.a
+htcp: htcp.c libgridsite.so.$(VERSION)
gcc -g -DVERSION=\"$(PATCH_VERSION)\" $(MYCFLAGS) \
-o htcp htcp.c -L. \
-I/usr/kerberos/include \
`curl-config --cflags` `curl-config --libs` \
-lgridsite
-gridsite-copy.cgi: gridsite-copy.c libgridsite.a
+gridsite-copy.cgi: gridsite-copy.c libgridsite.so.$(VERSION)
gcc -g -DVERSION=\"$(PATCH_VERSION)\" $(MYCFLAGS) \
-o gridsite-copy.cgi gridsite-copy.c -L. \
-I/usr/kerberos/include \
`curl-config --cflags` `curl-config --libs` \
-lgridsite
-mod_gridsite.so: mod_gridsite.c mod_ssl-private.h libgridsite.a
+mod_gridsite.so: mod_gridsite.c mod_ssl-private.h libgridsite.so.$(VERSION)
gcc -g $(MYCFLAGS) -shared -Wl,-soname=gridsite_module \
-I/usr/kerberos/include \
-I/usr/include/libxml2 \
-I/usr/kerberos/include \
-DVERSION=\"$(VERSION)\" -lgridsite -lssl -lcrypto -lxml2 -lz -lm
-findproxyfile: findproxyfile.c libgridsite.a
+findproxyfile: findproxyfile.c libgridsite.so.$(VERSION)
gcc -g -DVERSION=\"$(PATCH_VERSION)\" $(MYCFLAGS) $(MYLDFLAGS) \
-o findproxyfile findproxyfile.c -L. \
-I/usr/kerberos/include -lgridsite \
-lssl -lcrypto -lxml2 -lz -lm
-showx509exts: showx509exts.c libgridsite.a
+showx509exts: showx509exts.c libgridsite.so.$(VERSION)
gcc -g -DVERSION=\"$(PATCH_VERSION)\" $(MYCFLAGS) $(MYLDFLAGS) \
-o showx509exts showx509exts.c -L. \
-I/usr/kerberos/include \
DelegationService.wsdl: delegation.h
$(GSOAPDIR)/bin/soapcpp2 -c delegation.h
-gridsite-delegation.cgi: grst-delegation.c delegation.h DelegationService.wsdl
+gridsite-delegation.cgi: grst-delegation.c delegation.h \
+ DelegationService.wsdl libgridsite.so.$(VERSION)
gcc -g $(MYCFLAGS) $(MYLDFLAGS) -o gridsite-delegation.cgi \
grst-delegation.c \
-I/usr/kerberos/include -I. -I$(GSOAPDIR)/include \
-I$(GRIDSITEDIR)/include \
- -DVERSION=\"$(VERSION)\" -L$(GSOAPDIR)/lib \
+ -DVERSION=\"$(VERSION)\" -L. -L$(GSOAPDIR)/lib \
-L$(GRIDSITEDIR)/lib \
soapC.c soapServer.c -lgsoap \
-lgridsite -lcurl -lz -lssl -lcrypto -lxml2 -lm
-htproxyput: htproxyput.c delegation.h DelegationService.wsdl
+htproxyput: htproxyput.c delegation.h DelegationService.wsdl libgridsite.so.$(VERSION)
gcc -g $(MYCFLAGS) $(MYLDFLAGS) -o htproxyput \
htproxyput.c \
-I/usr/kerberos/include -I. \
-g -DVERSION=\"$(VERSION)\" \
-I$(GSOAPDIR)/include \
-I$(GRIDSITEDIR)/include \
- -DWITH_OPENSSL -L$(GSOAPDIR)/lib \
- $(STDSOAP2) -L$(GRIDSITEDIR)/lib \
+ -DWITH_OPENSSL -L. -L$(GSOAPDIR)/lib \
+ $(STDSOAP2) \
soapC.c soapClient.c -lgsoapssl \
-lgridsite -lcurl -lz -lssl -lcrypto -lxml2 -lm
#include "gridsite.h"
-/* Little piece of GRSTerror in GRSTgacl */
-
void (*GRSTerrorLogFunc)(char *, int, int, char *, ...) = NULL;
else return GRST_RET_FAILED;
}
+int GRSTx509ChainFree(GRSTx509Chain *chain)
+{
+ GRSTx509Cert *grst_cert;
+
+ if (chain == NULL) return GRST_RET_OK;
+
+// delete the various stuff in the chain members....
+
+ return GRST_RET_OK;
+}
+
+/// Check certificate chain for GSI proxy acceptability.
+/**
+ * Returns GRST_RET_OK if valid; OpenSSL X509 errors otherwise.
+ *
+ * The GridSite version handles old and new style Globus proxies, and
+ * proxies derived from user certificates issued with "X509v3 Basic
+ * Constraints: CA:FALSE" (eg UK e-Science CA)
+ *
+ * TODO: we do not yet check ProxyCertInfo and ProxyCertPolicy extensions
+ * (although via GRSTx509KnownCriticalExts() we can accept them.)
+ */
+
+int GRSTx509ChainLoadCheck(GRSTx509Chain **chain,
+ STACK_OF(X509) *certstack, X509 *lastcert,
+ char *capath)
+{
+ X509 *cert; /* Points to the current cert in the loop */
+ int depth = 0; /* Depth of cert chain */
+ int chain_errors = 0; /* records previous errors */
+ int first_non_ca;
+ size_t len,len2; /* Lengths of issuer and cert DN */
+ int IsCA; /* Holds whether cert is allowed to sign */
+ int prevIsCA; /* Holds whether previous cert in chain is
+ allowed to sign */
+ int prevIsLimited; /* previous cert was proxy and limited */
+ int i,j; /* Iteration variables */
+ char *cert_DN; /* Pointer to current-certificate-in-chain's
+ DN */
+ char *issuer_DN; /* Pointer to
+ issuer-of-current-cert-in-chain's DN */
+ char *proxy_part_DN; /* Pointer to end part of current-cert-in-chain
+ maybe eg "/CN=proxy" */
+ time_t now;
+ GRSTx509Cert *grst_cert, *new_grst_cert;
+
+ GRSTerrorLog(GRST_LOG_DEBUG, "GRSTx509ChainLoadCheck() starts");
+printf("GRSTx509ChainLoadCheck() starts");
+
+ time(&now);
+
+ first_non_ca = 0; /* set to something predictable if things fail */
+
+ /* Set necessary preliminary values */
+ IsCA = TRUE; /* =prevIsCA - start from a CA */
+ prevIsLimited = 0;
+
+
+ /* Get the client cert chain */
+ if (certstack != NULL)
+ depth = sk_X509_num(certstack); /* How deep is that chain? */
+
+printf("depth=%d\n", depth);
+
+ if ((depth == 0) && (lastcert == NULL))
+ {
+ *chain = NULL;
+ return GRST_RET_FAILED;
+ }
+
+ *chain = malloc(sizeof(GRSTx509Chain));
+ bzero(*chain, sizeof(GRSTx509Chain));
+
+ /* Check the client chain */
+ for (i = depth - 1; i >= (lastcert == NULL) ? 0 : -1; --i)
+ /* loop through client-presented chain starting at CA end */
+ {
+ prevIsCA=IsCA;
+
+ new_grst_cert = malloc(sizeof(GRSTx509Cert));
+ bzero(new_grst_cert, sizeof(GRSTx509Cert));
+ new_grst_cert->errors = chain_errors;
+
+ if (i == depth - 1) (*chain)->firstcert = new_grst_cert;
+ else grst_cert->next = new_grst_cert;
+
+ /* Check for X509 certificate and point to it with 'cert' */
+ if (i < 0) cert = lastcert;
+ else cert = sk_X509_value(certstack, i);
+
+ if (cert != NULL)
+ {
+ /* we check times and record if invalid */
+
+ if (now <
+ GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notBefore(cert)),0))
+ new_grst_cert->errors |= GRST_CERT_BAD_TIME;
+
+ if (now >
+ GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notAfter(cert)),0))
+ new_grst_cert->errors |= GRST_CERT_BAD_TIME;
+
+ /* If any forebear certificate is not allowed to sign we must
+ assume all decendents are proxies and cannot sign either */
+ if (prevIsCA)
+ {
+ /* always treat the first cert (from the CA files) as a CA */
+ if (i == depth - 1) IsCA = TRUE;
+ /* check if this cert is valid CA for signing certs */
+ else IsCA = (GRSTx509IsCA(cert) == GRST_RET_OK);
+
+ if (!IsCA) first_non_ca = i;
+ }
+ else
+ {
+ IsCA = FALSE;
+ /* Force proxy check next iteration. Important because I can
+ sign any CA I create! */
+ }
+
+ cert_DN = X509_NAME_oneline(X509_get_subject_name(cert),NULL,0);
+ issuer_DN = X509_NAME_oneline(X509_get_issuer_name(cert),NULL,0);
+ len = strlen(cert_DN);
+ len2 = strlen(issuer_DN);
+
+ if (!prevIsCA)
+ {
+ /* issuer didn't have CA status, so this is (at best) a proxy:
+ check for bad proxy extension*/
+
+ if (prevIsLimited) /* we reject proxies of limited proxies! */
+ {
+ new_grst_cert->errors |= GRST_CERT_BAD_CHAIN;
+ chain_errors |= GRST_CERT_BAD_CHAIN;
+ }
+
+ /* User not allowed to sign shortened DN */
+ if (len2 > len)
+ {
+ new_grst_cert->errors |= GRST_CERT_BAD_CHAIN;
+ chain_errors |= GRST_CERT_BAD_CHAIN;
+ }
+
+ /* Proxy subject must begin with issuer. */
+ if (strncmp(cert_DN, issuer_DN, len2) != 0)
+ {
+ new_grst_cert->errors |= GRST_CERT_BAD_CHAIN;
+ chain_errors |= GRST_CERT_BAD_CHAIN;
+ }
+
+ /* Set pointer to end of base DN in cert_DN */
+ proxy_part_DN = &cert_DN[len2];
+
+ /* First attempt at support for Old and New style GSI
+ proxies: /CN=anything is ok for now */
+ if (strncmp(proxy_part_DN, "/CN=", 4) != 0)
+ {
+ new_grst_cert->errors |= GRST_CERT_BAD_CHAIN;
+ chain_errors |= GRST_CERT_BAD_CHAIN;
+ }
+
+ if (strncmp(proxy_part_DN, "/CN=limited proxy", 17) == 0)
+ prevIsLimited = 1; /* ready for next cert ... */
+ }
+ }
+ }
+
+
+ return GRST_RET_OK; /* this is also GRST_RET_OK, of course - by choice */
+}
+
/// Check certificate chain for GSI proxy acceptability.
/**
* Returns X509_V_OK/GRST_RET_OK if valid; OpenSSL X509 errors otherwise.
#define HTPROXY_TIME 3
#define HTPROXY_UNIXTIME 4
#define HTPROXY_MAKE 5
+#define HTPROXY_INFO 6
void printsyntax(char *argv0)
{
fprintf(stderr, "%s [options] URL\n"
"(Version: %s)\n", p, VERSION);
}
+
+void htproxy_logfunc(char *file, int line, int level, char *fmt, ...)
+{
+ char *mesg;
+ va_list ap;
+
+ va_start(ap, fmt);
+ vasprintf(&mesg, fmt, ap);
+ va_end(ap);
+
+ fprintf(stderr, "%s(%d) %s\n", file, line, mesg);
+
+ free(mesg);
+}
int main(int argc, char *argv[])
{
*executable, *keytxt, *proxychain, *ptr;
struct ns__putProxyResponse *unused;
struct tm *finish_tm;
- int option_index, c, noverify = 0, i,
+ int option_index, c, noverify = 0, i, ret,
method = HTPROXY_PUT, verbose = 0, fd, minutes;
struct soap soap_get, soap_put;
struct ns__getProxyReqResponse getProxyReqResponse;
STACK_OF(X509) *x509_certstack;
X509 *x509_cert;
BIO *certmem;
+ GRSTx509Chain *grst_chain = NULL;
+ GRSTx509Cert *grst_cert = NULL;
long ptrlen;
struct stat statbuf;
struct passwd *userpasswd;
{"renew", 0, 0, 0},
{"unixtime", 0, 0, 0},
{"make", 0, 0, 0},
+ {"info", 0, 0, 0},
{0, 0, 0, 0} };
if (argc == 1)
else if (option_index == 10) method = HTPROXY_RENEW;
else if (option_index == 11) method = HTPROXY_UNIXTIME;
else if (option_index == 12) method = HTPROXY_MAKE;
+ else if (option_index == 13) method = HTPROXY_INFO;
}
- else if (c == 'v') ++verbose;
+ else if (c == 'v')
+ {
+ GRSTerrorLogFunc = htproxy_logfunc;
+ ++verbose;
+ }
}
executable = rindex(argv[0], '/');
else if (strcmp(executable, "htproxyunixtime") == 0)
method = HTPROXY_UNIXTIME;
else if (strcmp(executable, "htproxymake") == 0) method = HTPROXY_MAKE;
+ else if (strcmp(executable, "htproxyinfo") == 0) method = HTPROXY_INFO;
- if ((method != HTPROXY_MAKE) && (optind + 1 != argc))
+ if ((method != HTPROXY_MAKE) &&
+ (method != HTPROXY_INFO) && (optind + 1 != argc))
{
fprintf(stderr, "Must specify a delegation service URL!\n");
return 1;
expiry too to avoid suprises when we try to use it ... */
if (stat(cert, &statbuf) == 0) key = cert;
- else
+ else if (method != HTPROXY_INFO)
{
cert = getenv("X509_USER_CERT");
key = getenv("X509_USER_KEY");
if (verbose) fprintf(stderr, "key=%s\ncert=%s\ncapath=%s\n",
key, cert, capath);
- if (strcmp(key, cert) != 0) /* we have to concatenate for gSOAP */
+ if ((key != NULL) && (cert != NULL) &&
+ (strcmp(key, cert) != 0)) /* we have to concatenate for gSOAP */
{
keycert = strdup("/tmp/.XXXXXX");
return 0;
}
+ else if (method == HTPROXY_INFO)
+ {
+ if (cert != NULL)
+ {
+ if (verbose) fprintf(stderr, "Getting proxy info from %s\n", cert);
+
+ ifp = fopen(cert, "r");
+ if (ifp == NULL)
+ {
+ fprintf(stderr, "Failed to open proxy file\n");
+ return 2;
+ }
+ }
+ else
+ {
+ if (verbose) fprintf(stderr, "Getting proxy info from stdin\n");
+ ifp = stdin;
+ }
+
+ ptrlen = 4096;
+ ptr = malloc(ptrlen);
+ i = 0;
+
+ while ((c = fgetc(ifp)) != EOF)
+ {
+ ptr[i] = c;
+ ++i;
+
+ if (i >= ptrlen)
+ {
+ ptrlen += 4096;
+ ptr = realloc(ptr, ptrlen);
+ }
+ }
+
+ ptr[i] = '\0';
+ if (cert != NULL) fclose(ifp);
+
+ if ((GRSTx509StringToChain(&x509_certstack, ptr) != GRST_RET_OK) ||
+ (x509_certstack == NULL))
+ {
+ fprintf(stderr, "Failed to parse proxy file for certificate chain\n");
+ free(ptr);
+ return 2;
+ }
+
+// fprintf(stderr, "%s\n", ptr);
+ free(ptr);
+
+ if (verbose) fprintf(stderr, "Parsing certificate chain\n");
+
+ ret = GRSTx509ChainLoadCheck(&grst_chain, x509_certstack, NULL, capath);
+
+ if ((ret != GRST_RET_OK) ||
+ (grst_chain == NULL) || (grst_chain->firstcert == NULL))
+ {
+ fprintf(stderr, "Failed parsing certificate chain\n");
+ return 3;
+ }
+
+ grst_cert = grst_chain->firstcert;
+
+// printf("%lu\n", grst_cert);
+// printf("%lu\n", grst_cert->type);
+// printf("%lu\n", grst_cert->dn);
+// printf("%lu\n", grst_cert->next);
+
+// printf("before for\n");
+ for (i=0;
+ grst_cert != NULL;
+ grst_cert = grst_cert->next)
+ {
+// printf("inside for %i\n", grst_cert == NULL);
+
+ printf("%d %d %s\n", i, grst_cert->type, grst_cert->dn);
+ printf("%lu\n", grst_cert->next);
+
+ grst_cert = grst_cert->next;
+ ++i;
+ }
+
+
+ GRSTx509ChainFree(grst_chain);
+ }
/* weirdness */
}
/*
- Copyright (c) 2003-6, Andrew McNab and Shiv Kaushal,
- University of Manchester. All rights reserved.
+ Copyright (c) 2003-6, Andrew McNab, Shiv Kaushal, Joseph Dada,
+ and Yibiao Li, University of Manchester. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, are permitted provided that the following
{NULL}
};
+/* Blank unset these HTTP headers, to prevent injection attacks.
+ This is run before mod_shib's check_user_id hook, which may
+ legitimately create such headers. */
+
+static int mod_gridsite_check_user_id(request_rec *r)
+{
+ ap_table_unset(r->headers_in, "User-Distinguished-Name");
+ ap_table_unset(r->headers_in, "Nist-LoA");
+ ap_table_unset(r->headers_in, "VOMS-Attribute");
+
+ return DECLINED; /* ie carry on processing request */
+}
+
static int mod_gridsite_first_fixups(request_rec *r)
{
mod_gridsite_dir_cfg *conf;
*gridauthpasscode = NULL, *cookiefile, oneline[1025], *key_i,
*destination = NULL, *destination_uri = NULL, *querytmp,
*destination_prefix = NULL, *destination_translated = NULL;
+ char *vomsAttribute, *loa;
const char *content_type;
time_t now, notbefore, notafter;
apr_table_t *env;
return DECLINED; /* if not turned on, look invisible */
env = r->subprocess_env;
+
+ /* Get the user's attributes from Shibboleth and set up user credential
+ based on the attributes if authentication has been carried out using
+ a Shibboleth Identity Provider.*/
+
+ /* Get DN from a Shibboleth attribute */
+ if (vomsAttribute == NULL)
+ {
+ dn = (char *) apr_table_get(r->headers_in, "User-Distinguished-Name");
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "DN: %s", dn);
+ }
+#if 0
+ /* Get the NIST LoA attribute */
+ loa = (char *) apr_table_get(r->headers_in, "nist-loa");
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "Nist-LoA: %d", loa);
+#endif
+ /* Set up user credential based on the DN and LoA attributes */
+
+ if (dn != NULL)
+ {
+ cred = GRSTgaclCredNew("person");
+ GRSTgaclCredAddValue(cred, "dn", dn);
+ user = GRSTgaclUserNew(cred);
+ cred = GRSTgaclCredNew("level");
+#if 0
+ GRSTgaclCredAddValue(cred, "nist-loa", loa);
+#endif
+ GRSTgaclCredAddValue(cred, "nist-loa", "2"); /* hardcoded for now */
+ GRSTgaclUserAddCred(user, cred);
+ }
+
+ vomsAttribute = (char *) apr_table_get(r->headers_in, "VOMS-Attribute");
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "VOMS-Attribute: %s", vomsAttribute);
+
+ /* Set up user credential based on VOMS Attribute */
+ if (vomsAttribute != NULL)
+ {
+ cred = GRSTgaclCredNew("voms");
+ GRSTgaclCredAddValue(cred, "fqan", vomsAttribute);
+ if (user == NULL) user = GRSTgaclUserNew(cred);
+ else GRSTgaclUserAddCred(user, cred);
+ }
p = (char *) apr_table_get(r->subprocess_env, "HTTPS");
if ((p != NULL) && (strcmp(p, "on") == 0)) ishttps = 1;
ap_hook_post_config(mod_gridsite_server_post_config, NULL, NULL,
APR_HOOK_LAST);
ap_hook_child_init(mod_gridsite_child_init, NULL, NULL, APR_HOOK_MIDDLE);
+
+ ap_hook_check_user_id(mod_gridsite_check_user_id, NULL, NULL,
+ APR_HOOK_REALLY_FIRST);
ap_hook_fixups(mod_gridsite_first_fixups,NULL,NULL,APR_HOOK_FIRST);