Fix for SHM session cache bug
authorAndrew McNab <andrew.mcnab@manchester.ac.uk>
Thu, 6 Oct 2005 11:59:20 +0000 (11:59 +0000)
committerAndrew McNab <andrew.mcnab@manchester.ac.uk>
Thu, 6 Oct 2005 11:59:20 +0000 (11:59 +0000)
org.gridsite.core/CHANGES
org.gridsite.core/doc/htcp.1
org.gridsite.core/doc/httpd-fileserver.conf
org.gridsite.core/doc/httpd-webserver.conf
org.gridsite.core/interface/gridsite.h
org.gridsite.core/src/grst_x509.c
org.gridsite.core/src/htcp
org.gridsite.core/src/htcp.c
org.gridsite.core/src/mod_gridsite.c

index c3e9507..5f9c111 100644 (file)
@@ -1,3 +1,7 @@
+* Thu Oct 6 2005 Andrew McNab <Andrew.McNab@man.ac.uk>
+- Fix session reuse with Shared-Memory SSL Session
+  Cache bug #8856 in mod_gridsite.
+- Add SiteCast support to file copying in htcp.
 * Tue Oct 4 2005 Andrew McNab <Andrew.McNab@man.ac.uk>
 - Move User, Config, Admin and Install guides from 
   doc directory into GridSite Wiki.
index 62d2e4c..39e20f5 100644 (file)
@@ -70,6 +70,7 @@ SiteCast enabled servers will respond immediately with a NOP reply, and all
 of the responses will be listed, with the round trip time in milliseconds. 
 Any waiting times specified in the --groups option will be ignored. Calling
 the program as htping has the same effect.
+(--groups must be used for this option to work.)
 
 .IP "--find"
 Query specified multicast groups with the HTCP TST code. SiteCast enabled
@@ -78,6 +79,7 @@ to the given SiteCast target URL(s). All of the transfer URLs returned
 will be listed. Waiting times specified in the --groups option will be used
 to space out the multicast queries, but the program listens for responses
 continuously. Calling the program as htfind has the same effect.
+(--groups must be used for this option to work.)
 
 .IP "--groups <IP Groups>"
 IP multicast groups to use for SiteCast queries. IP Groups is a comma
@@ -88,6 +90,9 @@ limits packets to the local network. Multiple groups may be specified,
 separated by commas. If multiple groups are specified, then seconds is the 
 time to wait before making the next multicast - 1 second is the default.
 
+.IP "--timeout <seconds>"
+A request timeout used for multicast ping.
+
 .IP "--anon"
 Do not attempt to use X.509 user certificates or GSI proxies to authenticate
 to the remote HTTPS server. This means you are "anonymous", but the server's
@@ -126,6 +131,23 @@ the GRID_AUTH_ONETIME single-use passcode obtained via HTTPS. The --grid-http
 option will be ignored for directory operations or HTTP URLs. If a redirected
 transfer isn't possible, a normal HTTPS data transfer will be attempted.
 
+.IP "--sitecast"
+Try to use SiteCast to locate remote files which are to be copied (currently
+only for the
+.BR fetching
+of remote files.) If no location is found via SiteCast, then a direct request
+for the given URL is tried. (--groups must be used for this option to work.)
+
+.IP "--domain <SiteCast domain>"
+Try to use SiteCast to locate remote files which are to be copied (currently
+only for the
+.BR fetching
+of remote files) 
+.BR "if the domain component of the URL matches"
+the SiteCast domain given.
+If no location is found via SiteCast, then a direct request
+for the given URL is tried. (--groups must be used for this option to work.)
+
 .SH FILES
 .IP /tmp/x509up_uID
 Default GSI Proxy file for Unix UID equal to ID.
index a14a559..27293e8 100644 (file)
@@ -131,8 +131,8 @@ Listen 777
 Listen 443
 Listen 488
 SSLSessionCacheTimeout  300
-SSLSessionCache         dbm:/var/cache/mod_ssl/scache
-# This version of GridSite is NOT compatible with the SHM SSL cache!!!
+SSLSessionCache         shm:/var/cache/mod_ssl/shm_cache
+
 <VirtualHost *:443 *:488>
  
 SSLEngine               on
index 59b7487..1b163cf 100644 (file)
@@ -160,8 +160,8 @@ ScriptAlias /real-gridsite-admin.cgi /usr/sbin/real-gridsite-admin.cgi
 Listen 443
 Listen 488
 SSLSessionCacheTimeout  300
-SSLSessionCache         dbm:/var/cache/mod_ssl/scache
-# This version of GridSite is NOT compatible with the SHM SSL cache!!!
+SSLSessionCache         shm:/var/cache/mod_ssl/shm_cache
+
 <VirtualHost *:443 *:488>
  
 SSLEngine               on
index 9e6b302..d9473a8 100644 (file)
@@ -284,7 +284,7 @@ int GRSTx509VerifyCallback(int, X509_STORE_CTX *);
 
 int GRSTx509GetVomsCreds(int *, int, size_t, char *, X509 *, STACK_OF(X509) *, char *);
 GRSTgaclCred *GRSTx509CompactToCred(char *);
-int GRSTx509CompactCreds(int *, int, size_t, char *, STACK_OF(X509) *, char *);
+int GRSTx509CompactCreds(int *, int, size_t, char *, STACK_OF(X509) *, char *, X509 *);
 char *GRSTx509CachedProxyFind(char *, char *, char *);
 char *GRSTx509FindProxyFileName(void);
 int GRSTx509MakeProxyCert(char **, FILE *, char *, char *, char *, int);
index ccf6100..00caa61 100644 (file)
@@ -680,7 +680,8 @@ GRSTgaclCred *GRSTx509CompactToCred(char *grst_cred)
  */
  
 int GRSTx509CompactCreds(int *lastcred, int maxcreds, size_t credlen, 
-                         char *creds, STACK_OF(X509) *certstack, char *vomsdir)
+                         char *creds, STACK_OF(X509) *certstack, char *vomsdir, 
+                         X509 *peercert)
 {   
    int   i, j, delegation = 0;
    char  credtemp[credlen+1];
@@ -704,6 +705,19 @@ int GRSTx509CompactCreds(int *lastcred, int maxcreds, size_t credlen,
                                           /* found the 1st non-CA cert */
       }
 
+   if (peercert != NULL)
+     {
+       if (usercert != NULL) /* found a (GSI proxy) cert after user cert */
+         {
+           gsiproxycert = peercert;
+           ++delegation;
+         }
+
+       if ((usercert == NULL) && 
+           (GRSTx509IsCA(peercert) != GRST_RET_OK)) usercert = peercert;
+                                          /* found the 1st non-CA cert */
+     }
+
    if ((usercert == NULL) /* if no usercert ("EEC"), we're not interested */
        ||
        (snprintf(credtemp, credlen+1, "X509USER %010lu %010lu %d %s",
index 8d187de..1b8ab8a 100644 (file)
Binary files a/org.gridsite.core/src/htcp and b/org.gridsite.core/src/htcp differ
index 1219455..763042a 100644 (file)
@@ -84,6 +84,9 @@
 
 #define HTCP_SITECAST_GROUPS 32
 
+#define HTCP_HOST_CONF       "/etc/htcp.conf"
+#define HTCP_USER_CONF       ".htcp.conf"
+
 struct grst_stream_data { char *source;
                           char *destination;
                           int   ishttps;
@@ -286,7 +289,7 @@ int do_copies(char *sources[], char *destination,
          }
  
        if (common_data->verbose > 0)
-            fprintf(stderr, "%s -> %s\n", sources[isrc], thisdestination);
+            fprintf(stderr, "Copy %s -> %s\n", sources[isrc], thisdestination);
 
        if (common_data->method == HTCP_GET)
          {
@@ -721,10 +724,16 @@ int do_finds(char *sources[],
 
   /* parse common_data_ptr->groups */ 
 
+  if (common_data_ptr->groups == NULL)
+    {
+      fprintf(stderr, "No multicast groups given\n");
+      return CURLE_FAILED_INIT;
+    }
+
   p = common_data_ptr->groups;
   igroup = -1;
 
-  for (igroup=-1; igroup+1 < HTCP_SITECAST_GROUPS; ++igroup)
+  for (igroup=-1; igroup+1 < HTCP_SITECAST_GROUPS;)
      {  
        sitecast_groups[igroup+1].port     = GRST_HTCP_PORT;
        sitecast_groups[igroup+1].timewait = 1;
@@ -842,6 +851,152 @@ int do_finds(char *sources[],
    return GRST_RET_OK;
 }
 
+int translate_sitecast_url(char **source_ptr,
+                           struct grst_stream_data *common_data_ptr)
+{
+  int request_length, response_length, i, ret, s, igroup;
+  struct sockaddr_in srv, from;
+  socklen_t fromlen;
+#define MAXBUF 8192  
+  char *request, response[MAXBUF], *p;
+  GRSThtcpMessage msg;
+  struct timeval start_timeval, wait_timeval;
+  struct grst_sitecast_group sitecast_groups[HTCP_SITECAST_GROUPS];
+  fd_set readsckts;
+
+  /* parse common_data_ptr->groups */ 
+
+  if (common_data_ptr->groups == NULL)
+    {
+      fprintf(stderr, "No multicast groups given\n");
+      return CURLE_FAILED_INIT;
+    }
+
+  p = common_data_ptr->groups;
+  igroup = -1;
+  
+  for (igroup=-1; igroup+1 < HTCP_SITECAST_GROUPS;)
+     {  
+       sitecast_groups[igroup+1].port     = GRST_HTCP_PORT;
+       sitecast_groups[igroup+1].timewait = 1;
+       sitecast_groups[igroup+1].ttl      = 1;
+       
+       ret = sscanf(p, "%d.%d.%d.%d:%d:%d:%d", 
+                 &(sitecast_groups[igroup+1].quad1),
+                 &(sitecast_groups[igroup+1].quad2),    
+                 &(sitecast_groups[igroup+1].quad3),
+                 &(sitecast_groups[igroup+1].quad4),    
+                 &(sitecast_groups[igroup+1].port),
+                 &(sitecast_groups[igroup+1].ttl),
+                 &(sitecast_groups[igroup+1].timewait));
+
+       if (ret == 0) break; /* end of list ? */
+         
+       if (ret < 5)
+         {
+           fprintf(stderr, "Failed to parse multicast group "
+                     "parameter %s\n", p);
+           return CURLE_FAILED_INIT;
+         }
+         
+       ++igroup;  
+       
+       if ((p = index(p, ',')) == NULL) break;       
+       ++p;
+     }
+
+  if (igroup == -1)
+    {
+      fprintf(stderr, "Failed to parse multicast group parameter %s\n", p);
+      return CURLE_FAILED_INIT;
+    }
+
+  if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
+    {
+      fprintf(stderr, "Failed to open UDP socket\n");
+      return CURLE_FAILED_INIT;
+    }
+
+  /* loop through multicast groups since we need to take each 
+     ones timewait into account */
+
+  gettimeofday(&start_timeval, NULL);
+
+  for (i=0; i <= igroup; ++i)
+     {
+       if (common_data_ptr->verbose)
+        fprintf(stderr, "Querying multicast group %d.%d.%d.%d:%d:%d:%d\n",
+                sitecast_groups[i].quad1, sitecast_groups[i].quad2,
+                sitecast_groups[i].quad3, sitecast_groups[i].quad4,
+                sitecast_groups[i].port, sitecast_groups[i].ttl,
+                sitecast_groups[i].timewait);
+        
+       bzero(&srv, sizeof(srv));
+       srv.sin_family = AF_INET;
+       srv.sin_port = htons(sitecast_groups[i].port);
+       srv.sin_addr.s_addr = htonl(sitecast_groups[i].quad1*0x1000000
+                                 + sitecast_groups[i].quad2*0x10000
+                                 + sitecast_groups[i].quad3*0x100
+                                 + sitecast_groups[i].quad4);
+
+       /* send off queries, one for each source file */
+
+       GRSThtcpTSTrequestMake(&request, &request_length, 
+                                   (int) (start_timeval.tv_usec),
+                                   "GET", *source_ptr, "");
+
+       sendto(s, request, request_length, 0, 
+                       (struct sockaddr *) &srv, sizeof(srv));
+
+       free(request);
+          
+       /* reusing wait_timeval is a Linux-specific feature of select() */
+       wait_timeval.tv_usec = 0;
+       wait_timeval.tv_sec  = sitecast_groups[i].timewait;
+
+       while ((wait_timeval.tv_sec > 0) || (wait_timeval.tv_usec > 0))
+            {
+              FD_ZERO(&readsckts);
+              FD_SET(s, &readsckts);
+  
+              ret = select(s + 1, &readsckts, NULL, NULL, &wait_timeval);
+
+              if (ret > 0)
+                {
+                  response_length = recvfrom(s, response, MAXBUF,
+                                             0, &from, &fromlen);
+  
+                  if ((GRSThtcpMessageParse(&msg, response, response_length) 
+                                                      == GRST_RET_OK) &&
+                      (msg.opcode == GRSThtcpTSTop) && (msg.rr == 1) && 
+                      (msg.trans_id == (int) start_timeval.tv_usec) &&
+                      (msg.resp_hdrs != NULL) &&
+                      (GRSThtcpCountstrLen(msg.resp_hdrs) > 12))
+                    { 
+                      /* found one */ 
+
+                      if (common_data_ptr->verbose > 0)
+                        fprintf(stderr, "Sitecast %s -> %.*s\n",
+                                *source_ptr, 
+                                GRSThtcpCountstrLen(msg.resp_hdrs) - 12,
+                                &(msg.resp_hdrs->text[10]));
+
+                      free(*source_ptr);
+                      
+                      asprintf(source_ptr, "%.*s",
+                          GRSThtcpCountstrLen(msg.resp_hdrs) - 12, 
+                          &(msg.resp_hdrs->text[10]));
+                          
+                      return GRST_RET_OK;
+                    }
+                }
+            }
+
+     }
+     
+  return GRST_RET_OK;
+}
+
 size_t rawindex_callback(void *ptr, size_t size, size_t nmemb, void *data)
 {
   if ( ((struct grst_index_blob *) data)->used + size * nmemb >=
@@ -1312,15 +1467,7 @@ void printsyntax(char *argv0)
 "(Version: %s)\n", p, p, VERSION);
 }
 
-int main(int argc, char *argv[])
-{
-  char **sources, *destination = NULL, *executable, *p;
-  int    c, i, option_index, anyerror;
-  struct stat statbuf;
-  struct grst_stream_data common_data;
-  struct grst_sitecast_group sitecast_groups[HTCP_SITECAST_GROUPS];
-  struct passwd *userpasswd;
-  struct option long_options[] = {     {"verbose",             0, 0, 'v'},
+struct option long_options[] = {       {"verbose",             0, 0, 'v'},
                                        {"cert",                1, 0, 0},
                                        {"key",                 1, 0, 0},
                                        {"capath",              1, 0, 0},
@@ -1338,8 +1485,93 @@ int main(int argc, char *argv[])
                                        {"sitecast",            0, 0, 0},
                                        {"domain",              1, 0, 0},
                                        {"find",                0, 0, 0},
+                                       {"conf",                1, 0, 0},
                                        {0, 0, 0, 0}  };
 
+int update_common_data(struct grst_stream_data *, int, char *);
+
+void parse_conf(struct grst_stream_data *common_data_ptr, char *conf_file)
+{
+  int   option_index;
+  char  line[1001], *p;
+  FILE *fp;
+  
+  fp = fopen(conf_file, "r");
+  if (fp == NULL)
+    {
+      if (common_data_ptr->verbose)
+        fprintf(stderr, "Failed to open configuration file %s\n", conf_file);
+      return;
+    }
+    
+  if (common_data_ptr->verbose)
+      fprintf(stderr, "Opened configuration file %s\n", conf_file);
+
+  while (fgets(line, sizeof(line), fp) != NULL)
+       {
+         if ((p = index(line, '\n')) != NULL) *p = '\0';
+       
+         for (option_index=0; 
+              long_options[option_index].name != NULL; ++option_index)
+            {
+              if (long_options[option_index].has_arg &&
+                  (strncmp(line, long_options[option_index].name, 
+                          strlen(long_options[option_index].name)) == 0) &&
+                  (line[strlen(long_options[option_index].name)] == '='))
+                {
+                  update_common_data(common_data_ptr, option_index,
+                   strdup(&line[strlen(long_options[option_index].name) + 1]));
+                  break;
+                }              
+
+              if (!long_options[option_index].has_arg &&
+                  (strcmp(line, long_options[option_index].name) == 0))
+                {
+                  update_common_data(common_data_ptr, option_index, "");
+                  break;
+                }              
+            }
+       }  
+    
+  fclose(fp);
+}
+
+int update_common_data(struct grst_stream_data *common_data_ptr,
+                        int option_index, char *optarg)
+{
+  if      (option_index == 1) common_data_ptr->cert       = optarg;
+  else if (option_index == 2) common_data_ptr->key        = optarg; 
+  else if (option_index == 3) common_data_ptr->capath     = optarg;
+  else if (option_index == 4) common_data_ptr->method     = HTCP_DELETE;
+  else if (option_index == 5) common_data_ptr->method     = HTCP_LIST;
+  else if (option_index == 6) common_data_ptr->method     = HTCP_LONGLIST;
+  else if (option_index == 7) common_data_ptr->method     = HTCP_MKDIR;
+  else if (option_index == 8) common_data_ptr->noverify   = 1;
+  else if (option_index == 9) common_data_ptr->anonymous  = 1;
+  else if (option_index ==10) common_data_ptr->gridhttp   = 1;
+  else if (option_index ==11) common_data_ptr->method     = HTCP_MOVE;
+  else if (option_index ==12) common_data_ptr->method     = HTCP_PING;
+  else if (option_index ==13) common_data_ptr->groups     = optarg;
+  else if (option_index ==14) common_data_ptr->timeout    = atoi(optarg);
+  else if (option_index ==15) common_data_ptr->sitecast   = 1;
+  else if (option_index ==16) { common_data_ptr->sitecast = 1;
+                                common_data_ptr->domain   = optarg; }
+  else if (option_index ==17) common_data_ptr->method     = HTCP_FIND;
+  /* option_index == 18 is used by the --conf command line-only option */
+  else return GRST_RET_FAILED;
+  
+  return GRST_RET_OK;
+}
+
+int main(int argc, char *argv[])
+{
+  char **sources, *destination = NULL, *executable, *p, *htcp_conf;
+  int    c, i, option_index, anyerror;
+  struct stat statbuf;
+  struct grst_stream_data common_data;
+  struct grst_sitecast_group sitecast_groups[HTCP_SITECAST_GROUPS];
+  struct passwd *userpasswd;
+
 #if (LIBCURL_VERSION_NUM < 0x070908)
   char *tmp_ca_roots = NULL;
 #endif
@@ -1366,6 +1598,23 @@ int main(int argc, char *argv[])
   common_data.timeout   = 0;
   common_data.sitecast  = 0;
   common_data.domain    = NULL;
+
+  if ((argc > 1) && ((strcmp(argv[1], "--verbose") == 0) || 
+                     (strcmp(argv[1], "-v") == 0))) common_data.verbose = 1;
+    
+  /* examine any configuration files */
+    
+  parse_conf(&common_data, HTCP_HOST_CONF);  
+  
+  userpasswd = getpwuid(geteuid());
+  asprintf(&htcp_conf, "%s/%s", userpasswd->pw_dir, HTCP_USER_CONF);
+  parse_conf(&common_data, htcp_conf);
+  free(htcp_conf);
+
+  htcp_conf = getenv("HTCP_CONF");
+  if (htcp_conf != NULL) parse_conf(&common_data, htcp_conf);
+
+  common_data.verbose = 0;
     
   while (1)
        {
@@ -1376,24 +1625,8 @@ int main(int argc, char *argv[])
          if      (c == -1) break;
          else if (c == 0)
            {
-             if      (option_index == 1) common_data.cert       = optarg;
-             else if (option_index == 2) common_data.key        = optarg; 
-             else if (option_index == 3) common_data.capath     = optarg;
-             else if (option_index == 4) common_data.method     = HTCP_DELETE;
-             else if (option_index == 5) common_data.method     = HTCP_LIST;
-             else if (option_index == 6) common_data.method     = HTCP_LONGLIST;
-             else if (option_index == 7) common_data.method     = HTCP_MKDIR;
-             else if (option_index == 8) common_data.noverify   = 1;
-             else if (option_index == 9) common_data.anonymous  = 1;
-             else if (option_index ==10) common_data.gridhttp   = 1;
-             else if (option_index ==11) common_data.method     = HTCP_MOVE;
-             else if (option_index ==12) common_data.method     = HTCP_PING;
-             else if (option_index ==13) common_data.groups     = optarg;
-             else if (option_index ==14) common_data.timeout    = atoi(optarg);
-             else if (option_index ==15) common_data.sitecast   = 1;
-             else if (option_index ==16) { common_data.sitecast = 1;
-                                           common_data.domain   = optarg; }
-             else if (option_index ==17) common_data.method     = HTCP_FIND;
+             if (option_index == 18) parse_conf(&common_data, optarg);
+             else update_common_data(&common_data, option_index, optarg);
            }
          else if (c == 'v') ++(common_data.verbose);
        }
@@ -1432,8 +1665,6 @@ int main(int argc, char *argv[])
               common_data.cert = getenv("X509_USER_CERT");
               common_data.key  = getenv("X509_USER_KEY");
               
-              userpasswd = getpwuid(geteuid());
-              
               if ((common_data.cert == NULL) &&
                   (userpasswd != NULL) &&
                   (userpasswd->pw_dir != NULL))
@@ -1562,8 +1793,8 @@ int main(int argc, char *argv[])
   for (i=0; i < (argc - optind - 1); ++i) 
      {
        if (strncmp(argv[optind + i], "file:", 5) == 0)
-            sources[i] = &argv[optind + i][5];
-       else sources[i] =  argv[optind + i];
+            sources[i] = strdup(&argv[optind + i][5]);
+       else sources[i] = strdup(argv[optind + i]);
        
        if (sources[i][0] == '\0') 
          {
@@ -1575,9 +1806,24 @@ int main(int argc, char *argv[])
   
   sources[i]  = NULL;  
 
-  if (strncmp(argv[optind + i], "file:", 5) == 0)
-       destination = &argv[optind + i][5];
-  else destination =  argv[optind + i];
+  if (strncmp(argv[optind+i], "file:", 5) == 0)
+    {
+      if ((argv[optind+i][strlen(argv[optind+i]) - 1] != '/') &&
+          (stat(&argv[optind + i][5], &statbuf) == 0) &&
+          S_ISDIR(statbuf.st_mode))
+                         asprintf(&destination, "%s/", &argv[optind + i][5]);
+      else destination = strdup(&argv[optind + i][5]);
+    }
+  else if ((strncmp(argv[optind+i], "http://",  7) != 0) &&
+           (strncmp(argv[optind+i], "https://", 8) != 0)) 
+    {
+      if ((argv[optind+i][strlen(argv[optind+i]) - 1] != '/') &&
+          (stat(argv[optind+i], &statbuf) == 0) &&
+          S_ISDIR(statbuf.st_mode))
+                         asprintf(&destination, "%s/", argv[optind+i]);
+      else destination = strdup(argv[optind+i]);
+    }
+  else destination = strdup(argv[optind+i]);
   
   if (destination[0] == '\0')
     {
@@ -1621,14 +1867,23 @@ int main(int argc, char *argv[])
                    return CURLE_URL_MALFORMAT;
                  }
 
-/* NEED TO CHECK common_data.domain MATCHES IF IT IS SET */
-/*
-               if (common_data.sitecast) 
+               if ((common_data.sitecast) && 
+                   ((common_data.domain == NULL) ||
+
+                    ((strncmp(sources[i], "http://", 7) == 0) &&
+                     (strncmp(&sources[i][7], common_data.domain, 
+                                 strlen(common_data.domain)) == 0) &&
+                     ((sources[i][7+strlen(common_data.domain)] == ':') ||
+                      (sources[i][7+strlen(common_data.domain)] == '/'))) ||
+
+                    ((strncmp(sources[i], "https://", 8) == 0) &&
+                     (strncmp(&sources[i][8], common_data.domain, 
+                                 strlen(common_data.domain)) == 0) &&
+                     ((sources[i][8+strlen(common_data.domain)] == ':') ||
+                      (sources[i][8+strlen(common_data.domain)] == '/')))))
                  {
-                   translate_sitecast_url(&sources[i], 
-                                          sources[i], &common_data);
+                   translate_sitecast_url(&sources[i], &common_data);
                  }
-*/
              }
          }
          
index a64d155..cf5b0d8 100644 (file)
@@ -2103,6 +2103,41 @@ static int mod_gridsite_first_fixups(request_rec *r)
     return DECLINED;
 }  
 
+void GRST_creds_to_conn(conn_rec *conn, 
+                        STACK_OF(X509) *certstack, X509 *peercert)
+{
+   int i, lastcred;
+   const int maxcreds = 99;
+   const size_t credlen = 1024;
+   char creds[maxcreds][credlen+1], envname[14];
+
+   if ((certstack != NULL) && (conn->notes != NULL) &&
+       (apr_table_get(conn->notes, "GRST_creds_to_conn") != NULL)) return;
+
+   /* Put result of GRSTx509CompactCreds() into connection notes */
+
+   apr_table_set(conn->notes, "GRST_creds_to_conn", "yes");
+   ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, conn->base_server,
+                                            "set GRST_creds_to_conn");
+
+   if (GRSTx509CompactCreds(&lastcred, maxcreds, credlen, (char *) creds,
+                          certstack, GRST_VOMS_DIR, peercert) == GRST_RET_OK)
+     {
+       for (i=0; i <= lastcred; ++i)
+          {
+            apr_table_setn(conn->notes,
+                                 apr_psprintf(conn->pool, "GRST_CRED_%d", i),
+                                 apr_pstrdup(conn->pool, creds[i]));
+
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, conn->base_server,
+                                      "store GRST_CRED_%d=%s", i, creds[i]);
+
+          }
+                                   
+       /* free remaining dup'd certs? */
+     }     
+}
+
 static int mod_gridsite_perm_handler(request_rec *r)
 /*
     Do authentication/authorization here rather than in the normal module
@@ -2129,6 +2164,9 @@ static int mod_gridsite_perm_handler(request_rec *r)
     GRSTgaclPerm     perm = GRST_PERM_NONE, destination_perm = GRST_PERM_NONE;
     GRSTgaclAcl     *acl = NULL;
     mod_gridsite_dir_cfg *cfg;
+    SSLConnRec      *sslconn;
+    STACK_OF(X509)  *certstack;
+    X509           *peercert;
 
     cfg = (mod_gridsite_dir_cfg *)
                     ap_get_module_config(r->per_dir_config, &gridsite_module);
@@ -2142,6 +2180,19 @@ static int mod_gridsite_perm_handler(request_rec *r)
     env = r->subprocess_env;
 
     /* do we need/have per-connection (SSL) cred variable(s)? */
+    
+    sslconn = (SSLConnRec *) ap_get_module_config(r->connection->conn_config, 
+                                                  &ssl_module);
+
+    if ((sslconn != NULL) && (sslconn->ssl != NULL) &&
+        (r->connection->notes != NULL) &&
+        (apr_table_get(r->connection->notes, "GRST_creds_to_conn") == NULL))
+      {
+        certstack = SSL_get_peer_cert_chain(sslconn->ssl);
+        peercert  = SSL_get_peer_certificate(sslconn->ssl);
+      
+        GRST_creds_to_conn(r->connection, certstack, peercert);
+      }
 
     if ((user == NULL) && 
         (r->connection->notes != NULL) &&
@@ -2561,6 +2612,7 @@ int GRST_callback_SSLVerify_wrapper(int ok, X509_STORE_CTX *ctx)
    int errdepth        = X509_STORE_CTX_get_error_depth(ctx);
    int returned_ok;
    int first_non_ca;
+   STACK_OF(X509) *certstack;
 
    /*
     * GSI Proxy user-cert-as-CA handling:
@@ -2626,35 +2678,13 @@ int GRST_callback_SSLVerify_wrapper(int ok, X509_STORE_CTX *ctx)
           }
         else 
           {
-            int i, lastcred;
-            STACK_OF(X509) *peer_certs;
-            const int maxcreds = 99;
-            const size_t credlen = 1024;
-            char creds[maxcreds][credlen+1], envname[14];
-
             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Valid certificate"
                                    " chain reported by GRSTx509CheckChain()");
 
-            /*
-             * Always put result of GRSTx509CompactCreds() into environment
-             */
-            if (peer_certs = (STACK_OF(X509) *) X509_STORE_CTX_get_chain(ctx))
-              {    
-                if (GRSTx509CompactCreds(&lastcred, maxcreds, credlen,
-                    (char *) creds, peer_certs, GRST_VOMS_DIR) == GRST_RET_OK)
-                  {
-                    for (i=0; i <= lastcred; ++i)
-                       {
-                         apr_table_setn(conn->notes,
-                                 apr_psprintf(conn->pool, "GRST_CRED_%d", i),
-                                 apr_pstrdup(conn->pool, creds[i]));
-
-                         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                                      "store GRST_CRED_%d=%s", i, creds[i]);
-                       }
-                  }
-            /* free remaining dup'd certs? */
-              }                                   
+            /* Put result of GRSTx509CompactCreds() into connection notes */
+            if ((certstack = 
+                  (STACK_OF(X509) *) X509_STORE_CTX_get_chain(ctx)) != NULL)
+             GRST_creds_to_conn(conn, certstack, NULL);
           }
      }