Back to index

nordugrid-arc-nox  1.1.0~rc6
VOMSUtil.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #include <fstream>
00006 #include <glibmm/fileutils.h>
00007 #include <unistd.h>
00008 
00009 #ifndef HAVE_GETDOMAINNAME
00010 #include <sys/systeminfo.h>
00011 #endif
00012 
00013 #include <arc/ArcRegex.h>
00014 #include <arc/Utils.h>
00015 
00016 #include <arc/credential/VOMSAttribute.h>
00017 #include <arc/credential/VOMSUtil.h>
00018 #include "listfunc.h"
00019 
00020 #ifdef WIN32
00021 #include <arc/win32.h>
00022 int gethostname_mingw (char *, size_t);
00023 int gethostname_mingw (char *name, size_t len) {
00024   DWORD dlen = (len <= (DWORD)~0 ? len : (DWORD)~0);
00025   return (GetComputerNameExA(ComputerNameDnsHostname, name, &dlen) ? 0 : -1);
00026 }
00027 #define gethostname gethostname_mingw
00028 
00029 int getdomainname_mingw (char *, size_t);
00030 int getdomainname_mingw (char *name, size_t len) {
00031   DWORD dlen = (len <= (DWORD)~0 ? len : (DWORD)~0);
00032   return (GetComputerNameExA(ComputerNameDnsDomain, name, &dlen) ? 0 : -1);
00033 }
00034 #define getdomainname getdomainname_mingw
00035 #endif
00036 
00037 #ifndef HAVE_TIMEGM
00038 // TODO: add lock or move it to Utils
00039 static time_t timegm (struct tm *tm) {
00040   bool tz_found = false;
00041   std::string tz = Arc::GetEnv("TZ", tz_found);
00042   Arc::SetEnv("TZ","UTC");
00043   tzset();
00044   tm->tm_isdst = -1;
00045   time_t ret = mktime(tm);
00046   if(tz_found) {
00047     Arc::SetEnv("TZ", tz);
00048   } else {
00049     Arc::UnsetEnv("TZ");
00050   }
00051   tzset();
00052   return ret;
00053 }
00054 #endif
00055 
00056 
00057 using namespace ArcCredential;
00058 
00059 namespace Arc {
00060 
00061   VOMSTrustList::VOMSTrustList(const std::vector<std::string>& encoded_list) {
00062     VOMSTrustChain chain;
00063     for(std::vector<std::string>::const_iterator i = encoded_list.begin();
00064                                 i != encoded_list.end(); ++i) {
00065       if((*i).find("NEXT CHAIN") != std::string::npos) {
00066         if(chain.size() > 0) {
00067           if(chain.size() > 1) { // More than one item in chain means DN list
00068             AddChain(chain);
00069           } else {
00070             // Trying to find special symbols
00071             if((chain[0].find('^') != std::string::npos) ||
00072                (chain[0].find('$') != std::string::npos) ||
00073                (chain[0].find('*') != std::string::npos)) {
00074               AddRegex(chain[0]);
00075             } else {
00076               AddChain(chain);
00077             };
00078           }
00079           chain.clear();
00080         }
00081         continue;
00082       }
00083       chain.push_back(*i);
00084     }
00085     if(chain.size() > 0) {
00086       if(chain.size() > 1) { // More than one item in chain means DN list
00087         AddChain(chain);
00088       } else {
00089         // Trying to find special symbols
00090         if((chain[0].find('^') != std::string::npos) ||
00091            (chain[0].find('$') != std::string::npos) ||
00092            (chain[0].find('*') != std::string::npos)) {
00093           AddRegex(chain[0]);
00094         } else {
00095           AddChain(chain);
00096         };
00097       }
00098       chain.clear();
00099     }
00100   }
00101 
00102   VOMSTrustList::VOMSTrustList(const std::vector<VOMSTrustChain>& chains,
00103     const std::vector<VOMSTrustRegex>& regexs):chains_(chains) {
00104     for(std::vector<VOMSTrustRegex>::const_iterator r = regexs.begin();
00105                     r != regexs.end();++r) {
00106       AddRegex(*r);
00107     }
00108   }
00109 
00110   VOMSTrustList::~VOMSTrustList(void) {
00111     for(std::vector<RegularExpression*>::iterator r = regexs_.begin();
00112                     r != regexs_.end();++r) {
00113       if(*r) delete *r; *r=NULL;
00114     }
00115   }
00116 
00117   VOMSTrustChain& VOMSTrustList::AddChain(void) {
00118     VOMSTrustChain chain;
00119     return *chains_.insert(chains_.end(),chain);
00120   }
00121 
00122   VOMSTrustChain& VOMSTrustList::AddChain(const VOMSTrustChain& chain) {
00123     return *chains_.insert(chains_.end(),chain);
00124   }
00125 
00126   RegularExpression& VOMSTrustList::AddRegex(const VOMSTrustRegex& reg) {
00127     RegularExpression* r = new RegularExpression(reg);
00128     regexs_.insert(regexs_.end(),r);
00129     return *r;
00130   }
00131 
00132 
00133   void InitVOMSAttribute(void) {
00134     #define idpkix                "1.3.6.1.5.5.7"
00135     #define idpkcs9               "1.2.840.113549.1.9"
00136     #define idpe                  idpkix ".1"
00137     #define idce                  "2.5.29"
00138     #define idaca                 idpkix ".10"
00139     #define idat                  "2.5.4"
00140     #define idpeacauditIdentity   idpe ".4"
00141     #define idcetargetInformation idce ".55"
00142     #define idceauthKeyIdentifier idce ".35"
00143     #define idceauthInfoAccess    idpe ".1"
00144     #define idcecRLDistPoints     idce ".31"
00145     #define idcenoRevAvail        idce ".56"
00146     #define idceTargets           idce ".55"
00147     #define idacaauthentInfo      idaca ".1"
00148     #define idacaaccessIdentity   idaca ".2"
00149     #define idacachargIdentity    idaca ".3"
00150     #define idacagroup            idaca ".4"
00151     #define idatclearance         "2.5.1.5.5"
00152     #define voms                  "1.3.6.1.4.1.8005.100.100.1"
00153     #define incfile               "1.3.6.1.4.1.8005.100.100.2"
00154     #define vo                    "1.3.6.1.4.1.8005.100.100.3"
00155     #define idatcap               "1.3.6.1.4.1.8005.100.100.4"
00156 
00157     #define attribs            "1.3.6.1.4.1.8005.100.100.11"
00158     #define acseq                 "1.3.6.1.4.1.8005.100.100.5"
00159     #define order                 "1.3.6.1.4.1.8005.100.100.6"
00160     #define certseq               "1.3.6.1.4.1.8005.100.100.10"
00161     #define email                 idpkcs9 ".1"
00162 
00163     #define OBJC(c,n) OBJ_create(c,n,#c)
00164 
00165     X509V3_EXT_METHOD *vomsattribute_x509v3_ext_meth;
00166     static int done=0;
00167     if (done)
00168       return;
00169 
00170     done=1;
00171 
00172     /* VOMS Attribute related objects*/
00173     //OBJ_create(email, "Email", "Email");
00174     OBJC(idatcap,"idatcap");
00175 
00176     OBJC(attribs,"attributes");
00177     OBJC(idcenoRevAvail, "idcenoRevAvail");
00178     OBJC(idceauthKeyIdentifier, "authKeyId");
00179     OBJC(idceTargets, "idceTargets");
00180     OBJC(acseq, "acseq");
00181     OBJC(order, "order");
00182     OBJC(voms, "voms");
00183     OBJC(incfile, "incfile");
00184     OBJC(vo, "vo");
00185     OBJC(certseq, "certseq");
00186 
00187     vomsattribute_x509v3_ext_meth = VOMSAttribute_auth_x509v3_ext_meth();
00188     if (vomsattribute_x509v3_ext_meth) {
00189       vomsattribute_x509v3_ext_meth->ext_nid = OBJ_txt2nid("authKeyId");
00190       X509V3_EXT_add(vomsattribute_x509v3_ext_meth);
00191     }
00192 
00193     vomsattribute_x509v3_ext_meth = VOMSAttribute_avail_x509v3_ext_meth();
00194     if (vomsattribute_x509v3_ext_meth) {
00195       vomsattribute_x509v3_ext_meth->ext_nid = OBJ_txt2nid("idcenoRevAvail");
00196       X509V3_EXT_add(vomsattribute_x509v3_ext_meth);
00197     }
00198 
00199     vomsattribute_x509v3_ext_meth = VOMSAttribute_targets_x509v3_ext_meth();
00200     if (vomsattribute_x509v3_ext_meth) {
00201       vomsattribute_x509v3_ext_meth->ext_nid = OBJ_txt2nid("idceTargets");
00202       X509V3_EXT_add(vomsattribute_x509v3_ext_meth);
00203     }
00204 
00205     vomsattribute_x509v3_ext_meth = VOMSAttribute_acseq_x509v3_ext_meth();
00206     if (vomsattribute_x509v3_ext_meth) {
00207       vomsattribute_x509v3_ext_meth->ext_nid = OBJ_txt2nid("acseq");
00208       X509V3_EXT_add(vomsattribute_x509v3_ext_meth);
00209     }
00210 
00211     vomsattribute_x509v3_ext_meth = VOMSAttribute_certseq_x509v3_ext_meth();
00212     if (vomsattribute_x509v3_ext_meth) {
00213       vomsattribute_x509v3_ext_meth->ext_nid = OBJ_txt2nid("certseq");
00214       X509V3_EXT_add(vomsattribute_x509v3_ext_meth);
00215     }
00216 
00217     vomsattribute_x509v3_ext_meth = VOMSAttribute_attribs_x509v3_ext_meth();
00218     if (vomsattribute_x509v3_ext_meth) {
00219       vomsattribute_x509v3_ext_meth->ext_nid = OBJ_txt2nid("attributes");
00220       X509V3_EXT_add(vomsattribute_x509v3_ext_meth);
00221     }
00222   }
00223 
00224   int createVOMSAC(X509 *issuer, STACK_OF(X509) *issuerstack, X509 *holder, EVP_PKEY *pkey, BIGNUM *serialnum,
00225              std::vector<std::string> &fqan, std::vector<std::string> &targets, std::vector<std::string>& attrs, 
00226              AC **ac, std::string voname, std::string uri, int lifetime) {
00227     #define ERROR(e) do { err = (e); goto err; } while (0)
00228     AC *a = NULL;
00229     X509_NAME *subname = NULL, *issname = NULL;
00230     GENERAL_NAME *dirn1 = NULL, *dirn2 = NULL;
00231     ASN1_INTEGER  *serial = NULL, *holdserial = NULL, *version = NULL;
00232     ASN1_BIT_STRING *uid = NULL;
00233     AC_ATTR *capabilities = NULL;
00234     AC_IETFATTR *capnames = NULL;
00235     AC_FULL_ATTRIBUTES *ac_full_attrs = NULL;
00236     ASN1_OBJECT *cobj = NULL, *aobj = NULL;
00237     X509_ALGOR *alg1, *alg2;
00238     ASN1_GENERALIZEDTIME *time1 = NULL, *time2 = NULL;
00239     X509_EXTENSION *norevavail = NULL, *targetsext = NULL, *auth = NULL, *certstack = NULL;
00240     AC_ATT_HOLDER *ac_att_holder = NULL;
00241     //char *qual = NULL, *name = NULL, *value = NULL, *tmp1 = NULL, *tmp2 = NULL;
00242     STACK_OF(X509) *stk = NULL;
00243     int err = AC_ERR_UNKNOWN;
00244     time_t curtime;
00245 
00246     InitVOMSAttribute();
00247 
00248     if (!issuer || !holder || !serialnum || fqan.empty() || !ac || !pkey)
00249       return AC_ERR_PARAMETERS;
00250 
00251     a = *ac;
00252     subname = X509_NAME_dup(X509_get_issuer_name(holder)); //old or new version?
00253     issname = X509_NAME_dup(X509_get_subject_name(issuer));
00254 
00255     time(&curtime);
00256     time1 = ASN1_GENERALIZEDTIME_set(NULL, curtime);
00257     time2 = ASN1_GENERALIZEDTIME_set(NULL, curtime+lifetime);
00258 
00259     dirn1  = GENERAL_NAME_new();
00260     dirn2  = GENERAL_NAME_new();
00261     holdserial      = M_ASN1_INTEGER_dup(holder->cert_info->serialNumber);
00262     serial          = BN_to_ASN1_INTEGER(serialnum, NULL);
00263     version         = BN_to_ASN1_INTEGER((BIGNUM *)(BN_value_one()), NULL);
00264     capabilities    = AC_ATTR_new();
00265     cobj            = OBJ_txt2obj("idatcap",0);
00266     aobj            = OBJ_txt2obj("attributes",0);
00267     capnames        = AC_IETFATTR_new();
00268     ac_full_attrs   = AC_FULL_ATTRIBUTES_new();
00269     ac_att_holder   = AC_ATT_HOLDER_new();
00270 
00271     std::string buffer, complete;
00272 
00273     GENERAL_NAME *g = GENERAL_NAME_new();
00274     ASN1_IA5STRING *tmpr = ASN1_IA5STRING_new();
00275 
00276 
00277     if (!subname || !issuer || !dirn1 || !dirn2 || !holdserial || !serial ||
00278       !capabilities || !cobj || !capnames || !time1 || !time2 || !ac_full_attrs || !ac_att_holder)
00279       ERROR(AC_ERR_MEMORY);
00280 
00281     for (std::vector<std::string>::iterator i = targets.begin(); i != targets.end(); i++) {
00282       if (i == targets.begin()) complete = (*i);
00283       else complete.append(",").append(*i);
00284     }
00285 
00286     // prepare AC_IETFATTR
00287     for (std::vector<std::string>::iterator i = fqan.begin(); i != fqan.end(); i++) {
00288       ASN1_OCTET_STRING *tmpc = ASN1_OCTET_STRING_new();
00289       if (!tmpc) {
00290         ASN1_OCTET_STRING_free(tmpc);
00291         ERROR(AC_ERR_MEMORY);
00292       }
00293 
00294       CredentialLogger.msg(DEBUG,"VOMS: create FQAN: %s",*i);
00295 
00296 #ifdef HAVE_OPENSSL_OLDRSA
00297       ASN1_OCTET_STRING_set(tmpc, (unsigned char*)((*i).c_str()), (*i).length());
00298 #else
00299       ASN1_OCTET_STRING_set(tmpc, (const unsigned char*)((*i).c_str()), (*i).length());
00300 #endif
00301 
00302       sk_AC_IETFATTRVAL_push(capnames->values, (AC_IETFATTRVAL *)tmpc);
00303     }
00304  
00305     //GENERAL_NAME *g = GENERAL_NAME_new();
00306     //ASN1_IA5STRING *tmpr = ASN1_IA5STRING_new();
00307     buffer.append(voname);
00308     buffer.append("://");
00309     buffer.append(uri);
00310     if (!tmpr || !g) {
00311       GENERAL_NAME_free(g);
00312       ASN1_IA5STRING_free(tmpr);
00313       ERROR(AC_ERR_MEMORY);
00314     }
00315 
00316     ASN1_STRING_set(tmpr, buffer.c_str(), buffer.size());
00317     g->type  = GEN_URI;
00318     g->d.ia5 = tmpr;
00319     sk_GENERAL_NAME_push(capnames->names, g);
00320  
00321     // stuff the created AC_IETFATTR in ietfattr (values) and define its object
00322     sk_AC_IETFATTR_push(capabilities->ietfattr, capnames);
00323     capabilities->get_type = GET_TYPE_FQAN;
00324     ASN1_OBJECT_free(capabilities->type);
00325     capabilities->type = cobj;
00326 
00327     // prepare AC_FULL_ATTRIBUTES
00328     for (std::vector<std::string>::iterator i = attrs.begin(); i != attrs.end(); i++) {
00329       std::string qual, name, value;
00330 
00331       CredentialLogger.msg(DEBUG,"VOMS: create attribute: %s",*i); 
00332  
00333       AC_ATTRIBUTE *ac_attr = AC_ATTRIBUTE_new();
00334       if (!ac_attr) {
00335         AC_ATTRIBUTE_free(ac_attr);
00336         ERROR(AC_ERR_MEMORY);
00337       }
00338 
00339       //Accoding to the definition of voms, the attributes will be like "qualifier::name=value" or "::name=value"
00340       size_t pos =(*i).find_first_of("::");
00341       if (pos != std::string::npos) {
00342         qual = (*i).substr(0, pos);
00343         pos += 2;
00344       }
00345       else { pos = 2; } 
00346 
00347       size_t pos1 = (*i).find_first_of("=");
00348       if (pos1 == std::string::npos) {
00349         ERROR(AC_ERR_PARAMETERS);
00350       }
00351       else {
00352         name = (*i).substr(pos, pos1 - pos);
00353         value = (*i).substr(pos1 + 1);
00354       }
00355 
00356 #ifdef HAVE_OPENSSL_OLDRSA
00357       if (!qual.empty())
00358         ASN1_OCTET_STRING_set(ac_attr->qualifier, (unsigned char*)(qual.c_str()), qual.length());
00359       else
00360         ASN1_OCTET_STRING_set(ac_attr->qualifier, (unsigned char*)(voname.c_str()), voname.length());
00361 
00362       ASN1_OCTET_STRING_set(ac_attr->name, (unsigned char*)(name.c_str()), name.length());
00363       ASN1_OCTET_STRING_set(ac_attr->value, (unsigned char*)(value.c_str()), value.length());
00364 #else
00365       if (!qual.empty())
00366         ASN1_OCTET_STRING_set(ac_attr->qualifier, (const unsigned char*)(qual.c_str()), qual.length());
00367       else
00368         ASN1_OCTET_STRING_set(ac_attr->qualifier, (const unsigned char*)(voname.c_str()), voname.length());
00369 
00370       ASN1_OCTET_STRING_set(ac_attr->name, (const unsigned char*)(name.c_str()), name.length());
00371       ASN1_OCTET_STRING_set(ac_attr->value, (const unsigned char*)(value.c_str()), value.length());
00372 #endif
00373 
00374       sk_AC_ATTRIBUTE_push(ac_att_holder->attributes, ac_attr);
00375     }
00376 
00377     if (attrs.empty()) 
00378       AC_ATT_HOLDER_free(ac_att_holder);
00379     else {
00380       GENERAL_NAME *g = GENERAL_NAME_new();
00381       ASN1_IA5STRING *tmpr = ASN1_IA5STRING_new();
00382       if (!tmpr || !g) {
00383         GENERAL_NAME_free(g);
00384         ASN1_IA5STRING_free(tmpr);
00385         ERROR(AC_ERR_MEMORY);
00386       }
00387     
00388       std::string buffer(voname);
00389       buffer.append("://");
00390       buffer.append(uri);
00391 
00392       ASN1_STRING_set(tmpr, buffer.c_str(), buffer.length());
00393       g->type  = GEN_URI;
00394       g->d.ia5 = tmpr;
00395       sk_GENERAL_NAME_push(ac_att_holder->grantor, g);
00396 
00397       sk_AC_ATT_HOLDER_push(ac_full_attrs->providers, ac_att_holder);
00398     }  
00399   
00400     // push both AC_ATTR into STACK_OF(AC_ATTR)
00401     sk_AC_ATTR_push(a->acinfo->attrib, capabilities);
00402 
00403     if (ac_full_attrs) {
00404       X509_EXTENSION *ext = NULL;
00405 
00406       ext = X509V3_EXT_conf_nid(NULL, NULL, OBJ_txt2nid("attributes"), (char *)(ac_full_attrs->providers));
00407       AC_FULL_ATTRIBUTES_free(ac_full_attrs);
00408       if (!ext)
00409         ERROR(AC_ERR_NO_EXTENSION);
00410 
00411       sk_X509_EXTENSION_push(a->acinfo->exts, ext);
00412       ac_full_attrs = NULL;
00413     }
00414 
00415     stk = sk_X509_new_null();
00416     
00417     if (issuerstack) {
00418       for (int j =0; j < sk_X509_num(issuerstack); j++)
00419         sk_X509_push(stk, X509_dup(sk_X509_value(issuerstack, j)));
00420     }
00421 
00422    //for (int i=0; i < sk_X509_num(stk); i++) 
00423    //  fprintf(stderr, "stk[%i] = %s\n", i , 
00424    //  X509_NAME_oneline(X509_get_subject_name((X509 *)sk_X509_value(stk, i)), NULL, 0)); 
00425 
00426 #ifdef HAVE_OPENSSL_OLDRSA
00427     sk_X509_push(stk, (X509 *)ASN1_dup((int (*)())i2d_X509,
00428           (char*(*)())d2i_X509, (char *)issuer));
00429 #else
00430     sk_X509_push(stk, (X509 *)ASN1_dup((int (*)(void*, unsigned char**))i2d_X509,
00431           (void*(*)(void**, const unsigned char**, long int))d2i_X509, (char *)issuer));
00432 #endif
00433 
00434    //for(int i=0; i<sk_X509_num(stk); i++)
00435    //  fprintf(stderr, "stk[%i] = %d  %s\n", i , sk_X509_value(stk, i),  
00436    //  X509_NAME_oneline(X509_get_subject_name((X509 *)sk_X509_value(stk, i)), NULL, 0));
00437 
00438     certstack = X509V3_EXT_conf_nid(NULL, NULL, OBJ_txt2nid("certseq"), (char*)stk);
00439     sk_X509_pop_free(stk, X509_free);
00440 
00441     /* Create extensions */
00442     norevavail = X509V3_EXT_conf_nid(NULL, NULL, OBJ_txt2nid("idcenoRevAvail"), (char*)"loc");
00443     if (!norevavail)
00444       ERROR(AC_ERR_NO_EXTENSION);
00445     X509_EXTENSION_set_critical(norevavail, 0); 
00446 
00447     auth = X509V3_EXT_conf_nid(NULL, NULL, OBJ_txt2nid("authKeyId"), (char *)issuer);
00448     if (!auth)
00449       ERROR(AC_ERR_NO_EXTENSION);
00450     X509_EXTENSION_set_critical(auth, 0); 
00451 
00452     if (!complete.empty()) {
00453       targetsext = X509V3_EXT_conf_nid(NULL, NULL, OBJ_txt2nid("idceTargets"), (char*)(complete.c_str()));
00454       if (!targetsext)
00455         ERROR(AC_ERR_NO_EXTENSION);
00456 
00457       X509_EXTENSION_set_critical(targetsext,1);
00458       sk_X509_EXTENSION_push(a->acinfo->exts, targetsext);
00459     }
00460 
00461     sk_X509_EXTENSION_push(a->acinfo->exts, norevavail);
00462     sk_X509_EXTENSION_push(a->acinfo->exts, auth);
00463     if (certstack)
00464       sk_X509_EXTENSION_push(a->acinfo->exts, certstack);
00465 
00466     alg1 = X509_ALGOR_dup(issuer->cert_info->signature);
00467     alg2 = X509_ALGOR_dup(issuer->sig_alg);
00468 
00469     if (issuer->cert_info->issuerUID)
00470       if (!(uid = M_ASN1_BIT_STRING_dup(issuer->cert_info->issuerUID)))
00471         ERROR(AC_ERR_MEMORY);
00472 
00473     ASN1_INTEGER_free(a->acinfo->holder->baseid->serial);
00474     ASN1_INTEGER_free(a->acinfo->serial);
00475     ASN1_INTEGER_free(a->acinfo->version);
00476     ASN1_GENERALIZEDTIME_free(a->acinfo->validity->notBefore);
00477     ASN1_GENERALIZEDTIME_free(a->acinfo->validity->notAfter);
00478     dirn1->d.dirn = subname;
00479     dirn1->type = GEN_DIRNAME;
00480     sk_GENERAL_NAME_push(a->acinfo->holder->baseid->issuer, dirn1);
00481     dirn2->d.dirn = issname;
00482     dirn2->type = GEN_DIRNAME;
00483     sk_GENERAL_NAME_push(a->acinfo->form->names, dirn2);
00484     a->acinfo->holder->baseid->serial = holdserial;
00485     a->acinfo->serial = serial;
00486     a->acinfo->version = version;
00487     a->acinfo->validity->notBefore = time1;
00488     a->acinfo->validity->notAfter  = time2;
00489     a->acinfo->id = uid;
00490     X509_ALGOR_free(a->acinfo->alg);
00491     a->acinfo->alg = alg1;
00492     X509_ALGOR_free(a->sig_alg);
00493     a->sig_alg = alg2;
00494 
00495 #ifdef HAVE_OPENSSL_OLDRSA
00496     ASN1_sign((int (*)())i2d_AC_INFO, a->acinfo->alg, a->sig_alg, a->signature,
00497            (char *)a->acinfo, pkey, EVP_md5());
00498 #else
00499     ASN1_sign((int (*)(void*, unsigned char**))i2d_AC_INFO, a->acinfo->alg, a->sig_alg, a->signature,
00500             (char *)a->acinfo, pkey, EVP_md5());
00501 #endif
00502 
00503     *ac = a;
00504     return 0;
00505 
00506 err:
00507     X509_EXTENSION_free(auth);
00508     X509_EXTENSION_free(norevavail);
00509     X509_EXTENSION_free(targetsext);
00510     X509_EXTENSION_free(certstack);
00511     X509_NAME_free(subname);
00512     X509_NAME_free(issname);
00513     GENERAL_NAME_free(dirn1);
00514     GENERAL_NAME_free(dirn2);
00515     ASN1_INTEGER_free(holdserial);
00516     ASN1_INTEGER_free(serial);
00517     AC_ATTR_free(capabilities);
00518     ASN1_OBJECT_free(cobj);
00519     AC_IETFATTR_free(capnames);
00520     ASN1_UTCTIME_free(time1);
00521     ASN1_UTCTIME_free(time2);
00522     AC_ATT_HOLDER_free(ac_att_holder);
00523     AC_FULL_ATTRIBUTES_free(ac_full_attrs);
00524     return err;
00525   }
00526 
00527   bool createVOMSAC(std::string &codedac, Credential &issuer_cred, Credential &holder_cred, 
00528              std::vector<std::string> &fqan, std::vector<std::string> &targets, 
00529              std::vector<std::string>& attributes, std::string &voname, std::string &uri, int lifetime) {
00530 
00531     EVP_PKEY* issuerkey = NULL;
00532     X509* holder = NULL;
00533     X509* issuer = NULL;
00534     STACK_OF(X509)* issuerchain = NULL;
00535 
00536     issuer = issuer_cred.GetCert();
00537     issuerchain = issuer_cred.GetCertChain();
00538     issuerkey = issuer_cred.GetPrivKey();
00539     holder = holder_cred.GetCert();
00540 
00541     AC* ac = NULL;
00542     ac = AC_new();
00543 
00544     if(createVOMSAC(issuer, issuerchain, holder, issuerkey, (BIGNUM *)(BN_value_one()),
00545              fqan, targets, attributes, &ac, voname, uri, lifetime)){
00546       AC_free(ac); return false;
00547     }
00548 
00549     unsigned int len = i2d_AC(ac, NULL);
00550     unsigned char *tmp = (unsigned char *)OPENSSL_malloc(len);
00551 
00552     if (tmp) {
00553       unsigned char *ttmp = tmp;
00554       i2d_AC(ac, &ttmp);
00555       //codedac = std::string((char *)tmp, len);
00556       codedac.append((const char*)tmp, len);
00557     }
00558     free(tmp);
00559 
00560     AC_free(ac);
00561   
00562     return true;
00563   }
00564 
00565 
00566   bool addVOMSAC(AC** &aclist, std::string &acorder, std::string &codedac) {
00567     AC* received_ac;
00568     AC** actmplist = NULL;
00569     char *p, *pp;
00570     BIGNUM* dataorder = NULL;
00571 
00572     InitVOMSAttribute();
00573 
00574     int l = codedac.size();
00575 
00576     pp = (char *)malloc(codedac.size());
00577     if(!pp) {
00578       CredentialLogger.msg(ERROR,"VOMS: Can not allocate memory for parsing AC");
00579       return false; 
00580     }
00581 
00582     pp = (char *)memcpy(pp, codedac.data(), codedac.size());
00583     p = pp;
00584 
00585     dataorder = BN_new();
00586     if (!dataorder) {
00587       free(pp);
00588       CredentialLogger.msg(ERROR,"VOMS: Can not allocate memory for storing the order of AC");
00589       return false;
00590     }
00591     BN_one(dataorder);
00592 
00593     //Parse the AC, and insert it into an AC list
00594     if((received_ac = d2i_AC(NULL, (SSLCONST unsigned char**)&p, l))) {
00595       actmplist = (AC **)listadd((char **)aclist, (char *)received_ac, sizeof(AC *));
00596       if (actmplist) {
00597         aclist = actmplist; 
00598         (void)BN_lshift1(dataorder, dataorder);
00599         (void)BN_set_bit(dataorder, 0);
00600         char *buffer = BN_bn2hex(dataorder);
00601         acorder = std::string(buffer);
00602         OPENSSL_free(buffer);
00603         free(pp); BN_free(dataorder); return true;
00604       }
00605       else {
00606         listfree((char **)aclist, (freefn)AC_free);  free(pp); BN_free(dataorder); return false;
00607       }
00608     }
00609     else {
00610       CredentialLogger.msg(ERROR,"VOMS: Can not parse AC");
00611       free(pp); BN_free(dataorder); return false;
00612     }
00613   }
00614 
00615   static int cb(int ok, X509_STORE_CTX *ctx) {
00616     if (!ok) {
00617       if (ctx->error == X509_V_ERR_CERT_HAS_EXPIRED) ok=1;
00618       /* since we are just checking the certificates, it is
00619        * ok if they are self signed. But we should still warn
00620        * the user.
00621        */
00622       if (ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ok=1;
00623       /* Continue after extension errors too */
00624       if (ctx->error == X509_V_ERR_INVALID_CA) ok=1;
00625       if (ctx->error == X509_V_ERR_PATH_LENGTH_EXCEEDED) ok=1;
00626       if (ctx->error == X509_V_ERR_CERT_CHAIN_TOO_LONG) ok=1;
00627       if (ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ok=1;
00628     }
00629     return(ok);
00630   }
00631 
00632   static bool check_cert(X509 *cert, const std::string& ca_cert_dir, const std::string& ca_cert_file) {
00633     X509_STORE *ctx = NULL;
00634     X509_STORE_CTX *csc = NULL;
00635     X509_LOOKUP *lookup = NULL;
00636     int i = 0;
00637 
00638     if(ca_cert_dir.empty() && ca_cert_file.empty()) {
00639       CredentialLogger.msg(ERROR,"VOMS: CA directory or CA file must be provided");
00640       return false;
00641     }
00642 
00643     csc = X509_STORE_CTX_new();
00644     ctx = X509_STORE_new();
00645     if (ctx && csc) {
00646       X509_STORE_set_verify_cb_func(ctx,cb);
00647 //#ifdef SIGPIPE
00648 //      signal(SIGPIPE,SIG_IGN);
00649 //#endif
00650       CRYPTO_malloc_init();
00651       if (!(ca_cert_dir.empty()) && (lookup = X509_STORE_add_lookup(ctx,X509_LOOKUP_hash_dir()))) {
00652         X509_LOOKUP_add_dir(lookup, ca_cert_dir.c_str(), X509_FILETYPE_PEM);
00653         ERR_clear_error();
00654         X509_STORE_CTX_init(csc,ctx,cert,NULL);
00655         i = X509_verify_cert(csc);
00656       }
00657       else if (!(ca_cert_file.empty()) && (lookup = X509_STORE_add_lookup(ctx, X509_LOOKUP_file()))) {
00658         X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_PEM);
00659         ERR_clear_error();
00660         X509_STORE_CTX_init(csc,ctx,cert,NULL);
00661         i = X509_verify_cert(csc);
00662       }
00663     }
00664     if (ctx) X509_STORE_free(ctx);
00665     if (csc) X509_STORE_CTX_free(csc);
00666 
00667     return (i != 0);
00668   }
00669 
00670   static bool check_cert(STACK_OF(X509) *stack, const std::string& ca_cert_dir, const std::string& ca_cert_file) {
00671     X509_STORE *ctx = NULL;
00672     X509_STORE_CTX *csc = NULL;
00673     X509_LOOKUP *lookup = NULL;
00674     int index = 0;
00675 
00676     if(ca_cert_dir.empty() && ca_cert_file.empty()) {
00677       CredentialLogger.msg(ERROR,"VOMS: CA direcory or CA file must be provided");
00678       return false;
00679     }
00680 
00681     csc = X509_STORE_CTX_new();
00682     ctx = X509_STORE_new();
00683     if (ctx && csc) {
00684       X509_STORE_set_verify_cb_func(ctx,cb);
00685 //#ifdef SIGPIPE
00686 //      signal(SIGPIPE,SIG_IGN);
00687 //#endif
00688       CRYPTO_malloc_init();
00689 
00690       if (!(ca_cert_dir.empty()) && (lookup = X509_STORE_add_lookup(ctx,X509_LOOKUP_hash_dir()))) {
00691         X509_LOOKUP_add_dir(lookup, ca_cert_dir.c_str(), X509_FILETYPE_PEM);
00692         //Check the AC issuer certificate's chain
00693         for (int i = sk_X509_num(stack)-1; i >=0; i--) {
00694           //Firstly, try to verify the certificate which is issues by CA;
00695           //Then try to verify the next one; the last one is the certificate
00696           //(voms server certificate) which issues AC.
00697           //Normally the voms server certificate is directly issued by a CA,
00698           //in this case, sk_X509_num(stack) should be 1.
00699           //On the other hand, if the voms server certificate is issued by a CA
00700           //which is issued by an parent CA, and so on, then the AC issuer should 
00701           //put those CA certificates (except the root CA certificate which has 
00702           //been configured to be trusted on the AC consumer side) together with 
00703           //the voms server certificate itself in the 'certseq' part of AC.
00704           //
00705           //The CA certificates are checked one by one: the certificate which
00706           //is signed by root CA is checked firstly; the voms server certificate
00707           //is checked lastly.
00708           //
00709           X509_STORE_CTX_init(csc, ctx, sk_X509_value(stack, i), NULL);
00710           index = X509_verify_cert(csc);
00711           if(!index) break;
00712           //If the 'i'th certificate is verified, then add it as trusted certificate,
00713           //then 'i'th certificate will be used as 'trusted certificate' to check
00714           //the 'i-1'th certificate
00715           X509_STORE_add_cert(ctx,sk_X509_value(stack, i));
00716         }
00717 /*
00718         for (int i = 1; i < sk_X509_num(stack); i++)
00719           X509_STORE_add_cert(ctx,sk_X509_value(stack, i)); 
00720         ERR_clear_error();
00721         X509_STORE_CTX_init(csc, ctx, sk_X509_value(stack, 0), NULL);
00722         index = X509_verify_cert(csc);
00723 */
00724       }
00725       else if (!(ca_cert_file.empty()) && (lookup = X509_STORE_add_lookup(ctx, X509_LOOKUP_file()))) {
00726         X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_PEM);
00727         for (int i = sk_X509_num(stack)-1; i >=0; i--) {
00728           X509_STORE_CTX_init(csc, ctx, sk_X509_value(stack, i), NULL);
00729           index = X509_verify_cert(csc);
00730           if(!index) break;
00731           X509_STORE_add_cert(ctx,sk_X509_value(stack, i));
00732         }
00733 /*
00734         for (int i = 1; i < sk_X509_num(stack); i++)
00735           X509_STORE_add_cert(ctx,sk_X509_value(stack, i));
00736         ERR_clear_error();
00737         X509_STORE_CTX_init(csc, ctx, sk_X509_value(stack, 0), NULL);
00738         index = X509_verify_cert(csc);
00739 */
00740       }
00741     }
00742     if (ctx) X509_STORE_free(ctx);
00743     if (csc) X509_STORE_CTX_free(csc);
00744 
00745     return (index != 0);
00746   }
00747   
00748   static bool check_sig_ac(X509* cert, AC* ac){
00749     if (!cert || !ac) return false;
00750 
00751     EVP_PKEY *key = X509_extract_key(cert);
00752     if (!key) return false;
00753 
00754     int res;
00755 #ifdef HAVE_OPENSSL_OLDRSA
00756     res = ASN1_verify((int (*)())i2d_AC_INFO, ac->sig_alg, ac->signature,
00757                         (char *)ac->acinfo, key);
00758 #else
00759     res = ASN1_verify((int (*)(void*, unsigned char**))i2d_AC_INFO, ac->sig_alg, ac->signature,
00760                         (char *)ac->acinfo, key);
00761 #endif
00762 
00763     if (!res) CredentialLogger.msg(ERROR,"VOMS: unable to verify AC signature");
00764   
00765     EVP_PKEY_free(key);
00766     return (res == 1);
00767   }
00768 
00769   static bool regex_match(std::string& label, std::string& value) {
00770     bool match=false;
00771     RegularExpression regex(label);
00772     if(regex.isOk()){
00773       std::list<std::string> unmatched, matched;
00774       if(regex.match(value, unmatched, matched))
00775         match=true;
00776     }
00777     return match;
00778   }
00779 
00780   static bool check_trust(const VOMSTrustChain& chain,STACK_OF(X509)* certstack) {
00781     int n = 0;
00782     X509 *current = NULL;
00783     //A trusted chain is like following:
00784     // /O=Grid/O=NorduGrid/CN=host/arthur.hep.lu.se
00785     // /O=Grid/O=NorduGrid/CN=NorduGrid Certification Authority
00786     // ----NEXT CHAIN----
00787     if(chain.size()-1 > (sk_X509_num(certstack)+1)) return false;
00788 #if 0
00789     for(;n < sk_X509_num(certstack);++n) {
00790       if(n >= chain.size()) return true;
00791       current = sk_X509_value(certstack,n);
00792       if(!current) return false;
00793       if(chain[n] != X509_NAME_oneline(X509_get_subject_name(current),NULL,0)) {
00794         return false;
00795       }
00796     }
00797     if(n < chain.size()) {
00798       if(!current) return false;
00799       if(chain[n] != X509_NAME_oneline(X509_get_issuer_name(current),NULL,0)) {
00800         return false;
00801       }
00802     }
00803 #endif
00804 
00805     for(;n < sk_X509_num(certstack);++n) {
00806       if((n+1) >= chain.size()) return true;
00807       current = sk_X509_value(certstack,n);
00808       if(!current) return false;
00809       if(chain[n] != X509_NAME_oneline(X509_get_subject_name(current),NULL,0)) {
00810         CredentialLogger.msg(ERROR,"VOMS: the DN does in certificate: %s does not match that in trusted DN list: %s",
00811           X509_NAME_oneline(X509_get_subject_name(current),NULL,0), chain[n]);
00812         return false;
00813       }
00814       if(chain[n+1] != X509_NAME_oneline(X509_get_issuer_name(current),NULL,0)) {
00815         CredentialLogger.msg(ERROR,"VOMS: the Issuer identity does in certificate: %s does not match that in trusted DN list: %s",
00816           X509_NAME_oneline(X509_get_issuer_name(current),NULL,0), chain[n+1]);
00817         return false;
00818       }
00819     }
00820 
00821     return true;
00822   }
00823 
00824   static bool check_trust(const RegularExpression& reg,STACK_OF(X509)* certstack) {
00825     if(sk_X509_num(certstack) <= 0) return false;
00826     X509 *current = sk_X509_value(certstack,0);
00827 #if 0
00828     std::string subject(X509_NAME_oneline(X509_get_subject_name(current),NULL,0));
00829     std::list<std::string> unmatched, matched;
00830     return reg.match(subject,unmatched,matched);
00831 #endif
00832     std::string subject(X509_NAME_oneline(X509_get_subject_name(current),NULL,0));
00833     std::string issuer(X509_NAME_oneline(X509_get_issuer_name(current),NULL,0));
00834     std::list<std::string> unmatched, matched;
00835     return (reg.match(subject,unmatched,matched) && reg.match(issuer,unmatched,matched));
00836 
00837   }
00838 
00839   static bool check_signature(AC* ac, std::string& voname, 
00840     std::string& hostname, 
00841     const std::string& ca_cert_dir, const std::string& ca_cert_file, 
00842     const VOMSTrustList& vomscert_trust_dn, 
00843     //const std::vector<std::string>& vomscert_trust_dn, 
00844     X509** issuer_cert, bool verify) {
00845     X509* issuer = NULL;
00846 
00847     int nid = OBJ_txt2nid("certseq");
00848     STACK_OF(X509_EXTENSION) *exts = ac->acinfo->exts;
00849     int pos = X509v3_get_ext_by_NID(exts, nid, -1);
00850     if (pos >= 0) {
00851       //Check if the DN/CA file is installed for a given VO.
00852       X509_EXTENSION* ext = sk_X509_EXTENSION_value(exts, pos);
00853       AC_CERTS* certs = (AC_CERTS *)X509V3_EXT_d2i(ext);
00854       //The relatively new version of VOMS server is supposed to
00855       //create AC which includes the certificate stack:
00856       //the certificate of voms server; the non-CA certificate/s 
00857       //(if there are) that signs the voms server' certificate.
00858       STACK_OF(X509)* certstack = certs->stackcert;
00859 
00860       if(verify) {
00861         bool success = false;
00862 
00863         //Check if the DN of those certificates in the certificate stack
00864         //corresponds to the trusted DN chain in the configuration 
00865         if(certstack) {
00866           for(int n = 0;n < vomscert_trust_dn.SizeChains();++n) {
00867             const VOMSTrustChain& chain = vomscert_trust_dn.GetChain(n);
00868             if(check_trust(chain,certstack)) {
00869               success = true;
00870               break;
00871             }
00872           }
00873           if(!success) for(int n = 0;n < vomscert_trust_dn.SizeRegexs();++n) {
00874             const RegularExpression& reg = vomscert_trust_dn.GetRegex(n);
00875             if(check_trust(reg,certstack)) {
00876               success = true;
00877               break;
00878             }
00879           }
00880         }
00881 
00882         if (!success) {
00883           AC_CERTS_free(certs);
00884           CredentialLogger.msg(ERROR,"VOMS: unable to match certificate chain against VOMS trusted DNs");
00885           return false;
00886         }
00887       };
00888                   
00889       //If the certificate stack does correspond to some of the trusted DN chain, 
00890       //then check if the AC signature is valid by using the voms server 
00891       //certificate (voms server certificate is supposed to be the first on
00892       //in the certificate stack).
00893 #ifdef HAVE_OPENSSL_OLDRSA
00894       X509 *cert = (X509 *)ASN1_dup((int (*)())i2d_X509, 
00895         (char * (*)())d2i_X509, (char *)sk_X509_value(certstack, 0));
00896 #else
00897       X509 *cert = (X509 *)ASN1_dup((int (*)(void*, unsigned char**))i2d_X509, 
00898         (void*(*)(void**, const unsigned char**, long int))d2i_X509, (char *)sk_X509_value(certstack, 0));
00899 #endif
00900 
00901       //for (int i=0; i <sk_X509_num(certstack); i ++)
00902       //fprintf(stderr, "+++ stk[%i] = %d  %s\n", i , sk_X509_value(certstack, i),  X509_NAME_oneline(X509_get_subject_name((X509 *)sk_X509_value(certstack, i)), NULL, 0));
00903 
00904       bool found = false;
00905 
00906       if (check_sig_ac(cert, ac))
00907         found = true;
00908       else
00909         CredentialLogger.msg(ERROR,"VOMS: unable to verify AC signature");
00910    
00911       if(verify) { 
00912         //Check if those certificate in the certificate stack are trusted.
00913         if (found) {
00914           if (!check_cert(certstack, ca_cert_dir, ca_cert_file)) {
00915             X509_free(cert);
00916             cert = NULL;
00917             CredentialLogger.msg(ERROR,"VOMS: unable to verify certificate chain");
00918           }
00919         }
00920         else
00921           CredentialLogger.msg(ERROR,"VOMS: cannot find certificate of AC issuer for VO %s",voname);
00922       }; 
00923  
00924       AC_CERTS_free(certs);
00925      
00926       if(cert != NULL) issuer = cert;
00927     }
00928 
00929 #if 0 
00930     //For those old-stype voms configuration, there is no 
00931     //certificate stack in the AC. So there should be a local
00932     //directory which includes the voms server certificate.
00933     //It is deprecated here.
00934     /*check if able to find the signing certificate 
00935      among those specific for the vo or else in the vomsdir
00936      *directory 
00937      */
00938     if(issuer == NULL){
00939       bool found  = false;
00940       BIO * in = NULL;
00941       X509 * x = NULL;
00942       for(int i = 0; (i < 2 && !found); ++i) {
00943         std::string directory = vomsdir + (i ? "" : "/" + voname);
00944         CredentialLogger.msg(DEBUG,"VOMS: directory for trusted service certificates: %s",directory);
00945         Glib::Dir dir(directory); 
00946         while(true){
00947           std::string filename = dir.read_name(); 
00948           if (!filename.empty()) {
00949             in = BIO_new(BIO_s_file());
00950             if (in) {
00951               std::string temp = directory + "/" + filename;
00952               if (BIO_read_filename(in, temp.c_str()) > 0) {
00953                 x = PEM_read_bio_X509(in, NULL, 0, NULL);
00954                 if (x) {
00955                   if (check_sig_ac(x, ac)) { found = true; break; }
00956                   else { X509_free(x); x = NULL; }
00957                 }
00958               }
00959               BIO_free(in); in = NULL;
00960             }
00961           }
00962           else break;
00963         }
00964       }
00965       if (in) BIO_free(in);
00966       if (found) {
00967         if (!check_cert(x, ca_cert_dir, ca_cert_file)) { X509_free(x); x = NULL; }
00968       }
00969       else {
00970         CredentialLogger.msg(ERROR,"VOMS: Cannot find certificate of AC issuer for VO %s",voname);
00971 
00972       issuer = x;
00973     }
00974 #endif
00975 
00976     if(issuer == NULL) {
00977       CredentialLogger.msg(ERROR,"VOMS: unable to verify AC signature");
00978       return false;
00979     } 
00980 
00981     *issuer_cert = issuer; return true; 
00982   }
00983 
00984 
00985   static bool checkAttributes(STACK_OF(AC_ATTR) *atts, std::vector<std::string>& attributes) {
00986     AC_ATTR *caps;
00987     STACK_OF(AC_IETFATTRVAL) *values;
00988     AC_IETFATTR *capattr;
00989     AC_IETFATTRVAL *capname;
00990     GENERAL_NAME *data;
00991 
00992     /* find AC_ATTR with IETFATTR type */
00993     int  nid = OBJ_txt2nid("idatcap");
00994     int pos = X509at_get_attr_by_NID((STACK_OF(X509_ATTRIBUTE)*)atts, nid, -1);
00995     if (!(pos >=0)) { 
00996       CredentialLogger.msg(ERROR,"VOMS: Can not find AC_ATTR with IETFATTR type");
00997       return false;
00998     }
00999     caps = sk_AC_ATTR_value(atts, pos);
01000   
01001     /* check there's exactly one IETFATTR attribute */
01002     if (sk_AC_IETFATTR_num(caps->ietfattr) != 1) {
01003       CredentialLogger.msg(ERROR,"VOMS: case of multiple IETFATTR attributes not supported");
01004       return false; 
01005     }
01006 
01007     /* retrieve the only AC_IETFFATTR */
01008     capattr = sk_AC_IETFATTR_value(caps->ietfattr, 0);
01009     values = capattr->values;
01010   
01011     /* check it has exactly one policyAuthority */
01012     if (sk_GENERAL_NAME_num(capattr->names) != 1) {
01013       CredentialLogger.msg(ERROR,"VOMS: case of multiple policyAuthority not supported");
01014       return false;
01015     }
01016 
01017     /* store policyAuthority */
01018     data = sk_GENERAL_NAME_value(capattr->names, 0);
01019     if (data->type == GEN_URI) {
01020       std::string voname("/voname=");
01021       voname.append((const char*)(data->d.ia5->data), data->d.ia5->length);
01022       std::string::size_type pos = voname.find("://");
01023       if(pos != std::string::npos) {
01024         voname.replace(pos,3,"/hostname=");
01025       }
01026       attributes.push_back(voname);
01027     }
01028     else {
01029       CredentialLogger.msg(ERROR,"VOMS: the format of policyAuthority is unsupported - expecting URI");
01030       return false;
01031     }
01032 
01033     /* scan the stack of IETFATTRVAL to store attribute */
01034     for (int i=0; i<sk_AC_IETFATTRVAL_num(values); i++) {
01035       capname = sk_AC_IETFATTRVAL_value(values, i);
01036 
01037       if (capname->type != V_ASN1_OCTET_STRING) {
01038         CredentialLogger.msg(ERROR,"VOMS: the format of IETFATTRVAL is not supported - expecting OCTET STRING");
01039         return false;
01040       }
01041 
01042       std::string fqan((const char*)(capname->data), capname->length);
01043       if(fqan[0] == '/') fqan.erase(0,1);
01044       std::size_t group_pos = fqan.find("/",0);
01045       std::size_t role_pos = std::string::npos;
01046       if(group_pos != std::string::npos) {
01047         role_pos = fqan.find("/Role=",group_pos);
01048         if(role_pos == group_pos) {
01049           fqan.insert(group_pos,"/Group=NULL");
01050         } else {
01051           fqan.insert(group_pos+1,"Group=");
01052         }
01053       }
01054       fqan.insert(0,"/VO=");
01055 
01056       // if the attribute is like: /VO=knowarc.eu/Group=NULL/Role=NULL/Capability=NULL
01057       // or /VO=knowarc.eu/Group=NULL/Role=tester/Capability=NULL
01058       // then remove the element with "=NULL" to be:
01059       // /VO=knowarc.eu
01060       // /VO=knowarc.eu/Role=tester
01061 
01062       std::string str = fqan;
01063       std::size_t pos = str.find("/Role=NULL");
01064       if(pos != std::string::npos) str.erase(pos, 10);
01065       pos = str.find("/Group=NULL");
01066       if(pos != std::string::npos) str.erase(pos, 11);
01067       pos = str.find("/Capability=NULL");
01068       if(pos != std::string::npos) str.erase(pos, 16);
01069 
01070       attributes.push_back(str);
01071     }
01072 
01073     return true;
01074   }
01075 
01076 #ifndef HAVE_GETDOMAINNAME
01077   static int getdomainname(char *name, int length) {
01078     char      szBuffer[256];
01079     long      nBufSize = sizeof(szBuffer);
01080     char      *pBuffer = szBuffer;      
01081 
01082     long result_len = sysinfo( SI_SRPC_DOMAIN, pBuffer, nBufSize );          
01083 
01084     if (result_len > length) {
01085       return -1;
01086     }
01087 
01088     memcpy (name, pBuffer, result_len);
01089     if (result_len < length)
01090       name[result_len] = '\0';
01091    
01092     return 0;
01093   }
01094 #endif
01095 
01096   static std::string getfqdn(void) {
01097     std::string name;
01098     char hostname[256];
01099     char domainname[256];
01100 
01101     if ((!gethostname(hostname, 255)) && (!getdomainname(domainname, 255))) {
01102       name.append(hostname); 
01103       if(strcmp(domainname, "(none)")) {
01104         if (*domainname == '.')
01105           name.append(domainname);
01106         else {
01107           name.append(".").append(domainname);
01108         }
01109       }
01110     }
01111     return name;
01112   }
01113 
01114   static bool interpret_attributes(AC_FULL_ATTRIBUTES *full_attr, std::vector<std::string>& attributes) {
01115     std::string name, value, qualifier, grantor, voname, uri;
01116     GENERAL_NAME *gn = NULL;
01117     STACK_OF(AC_ATT_HOLDER) *providers = NULL;
01118     int i;
01119 
01120     providers = full_attr->providers;
01121 
01122     for (i = 0; i < sk_AC_ATT_HOLDER_num(providers); i++) {
01123       AC_ATT_HOLDER *holder = sk_AC_ATT_HOLDER_value(providers, i);
01124       STACK_OF(AC_ATTRIBUTE) *atts = holder->attributes;
01125 
01126       gn = sk_GENERAL_NAME_value(holder->grantor, 0);
01127       grantor.assign((const char*)(gn->d.ia5->data), gn->d.ia5->length);
01128       if(grantor.empty()) {
01129         CredentialLogger.msg(ERROR,"VOMS: the grantor attribute is empty");
01130         return false;
01131       }
01132       std::string::size_type pos = grantor.find("://");
01133       if(pos == std::string::npos) {
01134         voname = grantor; uri="NULL";
01135       } else {
01136         voname = grantor.substr(0,pos);
01137         uri = grantor.substr(pos+3);
01138       }
01139 
01140       for (int j = 0; j < sk_AC_ATTRIBUTE_num(atts); j++) {
01141         std::string attribute;
01142         AC_ATTRIBUTE *at = sk_AC_ATTRIBUTE_value(atts, j);
01143 
01144         name.assign((const char*)(at->name->data), at->name->length);
01145         if(name.empty()) {
01146           CredentialLogger.msg(ERROR,"VOMS: the attribute name is empty");
01147           return false;
01148         }
01149         value.assign((const char*)(at->value->data), at->value->length);
01150         if(value.empty()) {
01151           CredentialLogger.msg(WARNING,"VOMS: the attribute value for %s is empty", name.c_str());
01152           //return false;
01153         }
01154         qualifier.assign((const char*)(at->qualifier->data), at->qualifier->length);
01155         if(qualifier.empty()) {
01156           CredentialLogger.msg(ERROR,"VOMS: the attribute qualifier is empty");
01157           return false;
01158         }
01159         //attribute.append("/grantor=").append(grantor).append("/").append(qualifier).append(":").append(name).append("=").append(value);
01160         std::string seperator;
01161         if(qualifier.substr(0,1) != "/") seperator = "/";
01162         attribute.append("/voname=").append(voname).
01163                   append("/hostname=").append(uri).
01164                   append(seperator).append(qualifier).append(":").append(name).
01165                   append("=").append(value);
01166         attributes.push_back(attribute);
01167       }
01168       grantor.clear();
01169     }
01170     return true;
01171   }
01172  
01173   static bool checkExtensions(STACK_OF(X509_EXTENSION) *exts, X509 *iss, std::vector<std::string>& output) {
01174     int nid1 = OBJ_txt2nid("idcenoRevAvail");
01175     int nid2 = OBJ_txt2nid("authorityKeyIdentifier");
01176     int nid3 = OBJ_txt2nid("idceTargets");
01177     int nid5 = OBJ_txt2nid("attributes");
01178 
01179     int pos1 = X509v3_get_ext_by_NID(exts, nid1, -1);
01180     int pos2 = X509v3_get_ext_by_NID(exts, nid2, -1);
01181     int pos3 = X509v3_get_ext_by_critical(exts, 1, -1);
01182     int pos4 = X509v3_get_ext_by_NID(exts, nid3, -1);
01183     int pos5 = X509v3_get_ext_by_NID(exts, nid5, -1);
01184 
01185     /* noRevAvail, Authkeyid MUST be present */
01186     if ((pos1 < 0) || (pos2 < 0)) {
01187       CredentialLogger.msg(ERROR,"VOMS: both idcenoRevAvail and authorityKeyIdentifier certificate extensions must be present");
01188       return false;
01189     }
01190 
01191     //Check if the target fqan matches idceTargets
01192     while (pos3 >=0) {
01193       X509_EXTENSION *ex;
01194       AC_TARGETS *targets;
01195       AC_TARGET *name;
01196 
01197       ex = sk_X509_EXTENSION_value(exts, pos3);
01198       if (pos3 == pos4) {     //The only critical extension allowed is idceTargets,
01199         std::string fqdn = getfqdn();
01200         int ok = 0;
01201         int i;
01202         ASN1_IA5STRING* fqdns = ASN1_IA5STRING_new();
01203         if (fqdns) {
01204           ASN1_STRING_set(fqdns, fqdn.c_str(), fqdn.size());
01205           targets = (AC_TARGETS *)X509V3_EXT_d2i(ex);
01206           if (targets)
01207             for (i = 0; i < sk_AC_TARGET_num(targets->targets); i++) {
01208               name = sk_AC_TARGET_value(targets->targets, i);
01209               if (name->name && name->name->type == GEN_URI) {
01210                 ok = !ASN1_STRING_cmp(name->name->d.ia5, fqdns);
01211                 if (ok)
01212                   break;
01213               }
01214             }
01215           ASN1_STRING_free(fqdns);
01216         }
01217         if (!ok) {
01218           CredentialLogger.msg(WARNING,"VOMS: FQDN of this host %s does not match any target in AC", fqdn);
01219           // return false;
01220         }
01221       }
01222       else {
01223         CredentialLogger.msg(ERROR,"VOMS: the only supported critical extension of the AC is idceTargets");
01224         return false;
01225       }
01226       pos3 = X509v3_get_ext_by_critical(exts, 1, pos3);
01227     }
01228 
01229     //Parse the attributes
01230     if (pos5 >= 0) {
01231       X509_EXTENSION *ex = NULL;
01232       AC_FULL_ATTRIBUTES *full_attr = NULL;
01233       ex = sk_X509_EXTENSION_value(exts, pos5);
01234       full_attr = (AC_FULL_ATTRIBUTES *)X509V3_EXT_d2i(ex);
01235       if (full_attr) {
01236         if (!interpret_attributes(full_attr, output)) {
01237           CredentialLogger.msg(ERROR,"VOMS: failed to parse attributes from AC"); 
01238           AC_FULL_ATTRIBUTES_free(full_attr); return false; 
01239         }
01240       }
01241       AC_FULL_ATTRIBUTES_free(full_attr);
01242     }
01243 
01244     //Check the authorityKeyIdentifier
01245     if (pos2 >= 0) {
01246       X509_EXTENSION *ex;
01247       bool keyerr = false; 
01248       AUTHORITY_KEYID *key;
01249       ex = sk_X509_EXTENSION_value(exts, pos2);
01250       key = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ex);
01251       if (key) {
01252         if (iss) {
01253           if (key->keyid) {
01254             unsigned char hashed[20];
01255             if (!SHA1(iss->cert_info->key->public_key->data,
01256                       iss->cert_info->key->public_key->length,
01257                       hashed))
01258               keyerr = true;
01259           
01260             if ((memcmp(key->keyid->data, hashed, 20) != 0) && 
01261                 (key->keyid->length == 20))
01262               keyerr = true;
01263           }
01264           else {
01265             if (!(key->issuer && key->serial)) keyerr = true;
01266             if (M_ASN1_INTEGER_cmp((key->serial), (iss->cert_info->serialNumber))) keyerr = true;
01267             if (key->serial->type != GEN_DIRNAME) keyerr = true;
01268             if (X509_NAME_cmp(sk_GENERAL_NAME_value((key->issuer), 0)->d.dirn, (iss->cert_info->subject))) keyerr = true;
01269           }
01270         }
01271         AUTHORITY_KEYID_free(key);
01272       }
01273       else {
01274         keyerr = true;
01275       }
01276 
01277       if(keyerr) {
01278         CredentialLogger.msg(ERROR,"VOMS: authorityKey is wrong");
01279         return false;
01280       }
01281     }
01282 
01283     return true;
01284   }
01285 
01286   static time_t ASN1_GENERALIZEDTIME_get(const ASN1_GENERALIZEDTIME* const s) {
01287     struct tm tm;
01288     int offset;
01289     memset(&tm,'\0',sizeof tm);
01290 
01291 #define g1(n) ((n)-'0')
01292 #define g2(p) (g1((p)[0])*10+g1((p)[1]))
01293 #define g4(p) g1((p)[0])*1000+g1((p)[1])*100+g2(p+2)
01294 
01295     tm.tm_year=g4(s->data)-1900;
01296     tm.tm_mon=g2(s->data+4)-1;
01297     tm.tm_mday=g2(s->data+6);
01298     tm.tm_hour=g2(s->data+8);
01299     tm.tm_min=g2(s->data+10);
01300     tm.tm_sec=g2(s->data+12);
01301     if(s->data[14] == 'Z')
01302       offset=0;
01303     else {
01304       offset=g2(s->data+15)*60+g2(s->data+17);
01305       if(s->data[14] == '-')
01306         offset= -offset;
01307     }
01308 #undef g1
01309 #undef g2
01310 #undef g4
01311 
01312     return timegm(&tm)-offset*60;
01313   }
01314 
01315   static bool check_acinfo(X509* cert, X509* issuer, AC* ac, 
01316     std::vector<std::string>& output, Period& period_left) {
01317     if(!ac || !cert || !(ac->acinfo) || !(ac->acinfo->version) || !(ac->acinfo->holder) 
01318        || (ac->acinfo->holder->digest) || !(ac->acinfo->form) || !(ac->acinfo->form->names) 
01319        || (ac->acinfo->form->is) || (ac->acinfo->form->digest) || !(ac->acinfo->serial) 
01320        || !(ac->acinfo->validity) || !(ac->acinfo->alg) || !(ac->acinfo->validity) 
01321        || !(ac->acinfo->validity->notBefore) || !(ac->acinfo->validity->notAfter) 
01322        || !(ac->acinfo->attrib) || !(ac->sig_alg) || !(ac->signature)) return false;
01323 
01324     //Check the validity time  
01325     ASN1_GENERALIZEDTIME *start;
01326     ASN1_GENERALIZEDTIME *end;
01327     start = ac->acinfo->validity->notBefore;
01328     end = ac->acinfo->validity->notAfter;
01329 
01330     time_t ctime, dtime;
01331     time (&ctime);
01332     ctime += 300;
01333     dtime = ctime-600;
01334 
01335     if ((start->type != V_ASN1_GENERALIZEDTIME) || (end->type != V_ASN1_GENERALIZEDTIME)) {
01336       CredentialLogger.msg(ERROR,"VOMS: unsupported time format format in AC - expecting GENERALIZED TIME");
01337       return false;
01338     }
01339     if ((X509_cmp_current_time(start) >= 0) &&
01340         (X509_cmp_time(start, &ctime) >= 0)) {
01341       CredentialLogger.msg(ERROR,"VOMS: AC is not yet valid");
01342       return false;
01343     }
01344     if ((X509_cmp_current_time(end) <= 0) &&
01345         (X509_cmp_time(end, &dtime) <= 0)) {
01346       CredentialLogger.msg(ERROR,"VOMS: AC has expired");
01347       return false;
01348     }
01349     period_left = Time(ASN1_GENERALIZEDTIME_get(end)) - Time();
01350 
01351     STACK_OF(GENERAL_NAME) *names;
01352     GENERAL_NAME  *name;
01353 
01354     if (ac->acinfo->holder->baseid) {
01355       if(!(ac->acinfo->holder->baseid->serial) ||
01356          !(ac->acinfo->holder->baseid->issuer)) {
01357         CredentialLogger.msg(ERROR,"VOMS: AC is not complete - missing Serial or Issuer information");
01358         return false;
01359       }
01360 
01361       if (ASN1_INTEGER_cmp(ac->acinfo->holder->baseid->serial, cert->cert_info->serialNumber)) {
01362         CredentialLogger.msg(WARNING,"VOMS: the holder serial number %i is not the same as the serial number in AC %i",
01363           ASN1_INTEGER_get(cert->cert_info->serialNumber),
01364           ASN1_INTEGER_get(ac->acinfo->holder->baseid->serial));
01365         // return false;
01366       }
01367        
01368       names = ac->acinfo->holder->baseid->issuer;
01369       if ((sk_GENERAL_NAME_num(names) != 1) || !(name = sk_GENERAL_NAME_value(names,0)) ||
01370         (name->type != GEN_DIRNAME)) {
01371         CredentialLogger.msg(ERROR,"VOMS: the holder issuer information in AC is wrong");
01372         return false;
01373       }
01374       
01375       //If the holder is self-signed, and the holder also self sign the AC
01376       CredentialLogger.msg(DEBUG,"VOMS: DN of holder in AC: %s",X509_NAME_oneline(name->d.dirn,NULL,0));
01377       CredentialLogger.msg(DEBUG,"VOMS: DN of holder: %s",X509_NAME_oneline(cert->cert_info->subject,NULL,0));
01378       CredentialLogger.msg(DEBUG,"VOMS: DN of issuer: %s",X509_NAME_oneline(cert->cert_info->issuer,NULL,0));
01379       if (X509_NAME_cmp(name->d.dirn, cert->cert_info->subject) && 
01380         X509_NAME_cmp(name->d.dirn, cert->cert_info->issuer)) {
01381         CredentialLogger.msg(ERROR,"VOMS: the holder itself can not sign an AC by using a self-sign certificate"); 
01382         return false;
01383       }
01384 
01385       if ((ac->acinfo->holder->baseid->uid && cert->cert_info->issuerUID) ||
01386           (!cert->cert_info->issuerUID && !ac->acinfo->holder->baseid->uid)) {
01387         if (ac->acinfo->holder->baseid->uid) {
01388           if (M_ASN1_BIT_STRING_cmp(ac->acinfo->holder->baseid->uid, cert->cert_info->issuerUID)) {
01389             CredentialLogger.msg(ERROR,"VOMS: the holder issuerUID is not the same as that in AC");
01390             return false;
01391           }
01392         }
01393       }
01394       else {
01395         CredentialLogger.msg(ERROR,"VOMS: the holder issuerUID is not the same as that in AC");
01396         return false;
01397       }
01398     }
01399     else if (ac->acinfo->holder->name) {
01400       names = ac->acinfo->holder->name;
01401       if ((sk_GENERAL_NAME_num(names) == 1) ||      //??? 
01402           ((name = sk_GENERAL_NAME_value(names,0))) ||
01403           (name->type != GEN_DIRNAME)) {
01404         if (X509_NAME_cmp(name->d.dirn, cert->cert_info->issuer)) {
01405           /* CHECK ALT_NAMES */
01406           /* in VOMS ACs, checking into alt names is assumed to always fail. */
01407           CredentialLogger.msg(ERROR,"VOMS: the holder issuer name is not the same as that in AC");
01408           return false;
01409         }
01410       }
01411     }
01412   
01413     names = ac->acinfo->form->names;
01414     if ((sk_GENERAL_NAME_num(names) != 1) || !(name = sk_GENERAL_NAME_value(names,0)) || 
01415        (name->type != GEN_DIRNAME) || X509_NAME_cmp(name->d.dirn, issuer->cert_info->subject)) {
01416       CredentialLogger.msg(ERROR,"VOMS: the issuer name %s is not the same as that in AC - %s",
01417         X509_NAME_oneline(issuer->cert_info->subject,NULL,0),
01418         X509_NAME_oneline(name->d.dirn,NULL,0));
01419       return false;
01420     }
01421 
01422     if (ac->acinfo->serial->length > 20) {
01423       CredentialLogger.msg(ERROR,"VOMS: the serial number of AC INFO is too long - expecting no more than 20 octets");
01424       return false;
01425     }
01426   
01427     bool ret = false;
01428  
01429     //Check AC's extension
01430     ret = checkExtensions(ac->acinfo->exts, issuer, output);
01431     if(!ret)return false;
01432  
01433     //Check AC's attribute    
01434     checkAttributes(ac->acinfo->attrib, output);
01435     if(!ret)return false;
01436 
01437     return true;
01438   }
01439 
01440   static bool verifyVOMSAC(AC* ac,
01441         const std::string& ca_cert_dir, const std::string& ca_cert_file, 
01442         const VOMSTrustList& vomscert_trust_dn,
01443         //const std::vector<std::string>& vomscert_trust_dn,
01444         X509* holder, std::vector<std::string>& attr_output, 
01445         std::string& vo_name, Period& period_left, bool verify) {
01446     //Extract name 
01447     STACK_OF(AC_ATTR) * atts = ac->acinfo->attrib;
01448     int nid = 0;
01449     int pos = 0;
01450     nid = OBJ_txt2nid("idatcap");
01451     pos = X509at_get_attr_by_NID((STACK_OF(X509_ATTRIBUTE)*)atts, nid, -1);
01452     if(!(pos >=0)) {
01453       CredentialLogger.msg(ERROR,"VOMS: unable to extract VO name from AC");
01454       return false;
01455     }
01456 
01457     AC_ATTR * caps = sk_AC_ATTR_value(atts, pos);
01458     if(!caps) {
01459       CredentialLogger.msg(ERROR,"VOMS: unable to extract vo name from AC");
01460       return false;
01461     }
01462 
01463     AC_IETFATTR * capattr = sk_AC_IETFATTR_value(caps->ietfattr, 0);
01464     if(!capattr) {
01465       CredentialLogger.msg(ERROR,"VOMS: unable to extract vo name from AC");
01466       return false;
01467     }
01468 
01469     GENERAL_NAME * name = sk_GENERAL_NAME_value(capattr->names, 0);
01470     if(!name) {
01471       CredentialLogger.msg(ERROR,"VOMS: unable to extract vo name from AC");
01472       return false;
01473     }
01474 
01475     std::string voname((const char *)name->d.ia5->data, 0, name->d.ia5->length);
01476     std::string::size_type cpos = voname.find("://");
01477     std::string hostname;
01478     if (cpos != std::string::npos) {
01479       std::string::size_type cpos2 = voname.find(":", cpos+1);
01480       if (cpos2 != std::string::npos)
01481         hostname = voname.substr(cpos+3, (cpos2 - cpos - 3));
01482       else {
01483         CredentialLogger.msg(ERROR,"VOMS: unable to determine hostname of AC from VO name: %s",voname);
01484         return false;
01485       }
01486       voname = voname.substr(0, cpos);
01487       vo_name = voname;
01488     }
01489     else {
01490       CredentialLogger.msg(ERROR,"VOMS: unable to extract VO name from AC");
01491       return false;
01492     }
01493  
01494     X509* issuer = NULL;
01495 
01496     if(!check_signature(ac, voname, hostname, ca_cert_dir, ca_cert_file, vomscert_trust_dn, &issuer, verify)) {
01497       CredentialLogger.msg(ERROR,"VOMS: cannt verify the signature of the AC");
01498       return false; 
01499     }
01500 
01501     if(check_acinfo(holder, issuer, ac, attr_output, period_left)) return true;
01502     else return false;
01503   }
01504 
01505   bool parseVOMSAC(X509* holder,
01506         const std::string& ca_cert_dir, const std::string& ca_cert_file, 
01507         const VOMSTrustList& vomscert_trust_dn,
01508         std::vector<std::string>& output, bool verify) {
01509 
01510     InitVOMSAttribute();
01511 
01512     //Search the extension
01513     int nid = 0;
01514     int position = 0;
01515     X509_EXTENSION * ext;
01516     AC_SEQ* aclist = NULL;
01517     nid = OBJ_txt2nid("acseq");
01518     position = X509_get_ext_by_NID(holder, nid, -1);
01519     if(position >= 0) {
01520       ext = X509_get_ext(holder, position);
01521       if (ext){
01522         aclist = (AC_SEQ *)X509V3_EXT_d2i(ext);
01523       }
01524     }    
01525     if(aclist == NULL) {
01526       ERR_clear_error();
01527       //while(ERR_get_error() != 0);
01528       //std::cerr<<"No AC in the proxy certificate"<<std::endl; return false;
01529       return true;
01530     }
01531 
01532     bool verified = false;
01533     int num = sk_AC_num(aclist->acs);
01534     for (int i = 0; i < num; i++) {
01535       AC *ac = (AC *)sk_AC_value(aclist->acs, i);
01536       std::string vo_name;
01537       Period period_left;
01538       if (verifyVOMSAC(ac, ca_cert_dir, ca_cert_file, vomscert_trust_dn, 
01539           holder, output, vo_name, period_left, verify)) {
01540         verified = true;
01541         std::cout<<"======AC extenstion information for VO "<<vo_name<<"======"<<std::endl;
01542         for(int i = 0; i < output.size(); i++) {
01543           std::cout<<"Attribute: "<<output[i]<<std::endl;
01544         }
01545         std::cout << IString("Timeleft for AC: %s", period_left.istr())<<std::endl;
01546       }
01547       if (!verified) break;
01548     } 
01549     ERR_clear_error();
01550     //while(ERR_get_error() != 0);
01551 
01552     return verified;
01553   }
01554 
01555   bool parseVOMSAC(Credential& holder_cred,
01556          const std::string& ca_cert_dir, const std::string& ca_cert_file,
01557          const VOMSTrustList& vomscert_trust_dn,
01558          std::vector<std::string>& output, bool verify) {
01559     X509* holder = holder_cred.GetCert();
01560     if(!holder) return false;
01561     bool res = parseVOMSAC(holder, ca_cert_dir, ca_cert_file, vomscert_trust_dn, output, verify);
01562 
01563     //Also parse the voms attributes inside the certificates on 
01564     //the upstream of the holder certificate; in this case,
01565     //multiple level of delegation exists, and user(or intermediate 
01566     //actor such as grid manager) could hold a voms proxy and use this 
01567     //proxy to create a more level of proxy
01568     STACK_OF(X509)* certchain = holder_cred.GetCertChain();
01569     if(certchain != NULL) {
01570       for(int idx = 0;;++idx) {
01571         if(idx >= sk_X509_num(certchain)) break;
01572         X509* cert = sk_X509_value(certchain,sk_X509_num(certchain)-idx-1);
01573         bool res = parseVOMSAC(cert, ca_cert_dir, ca_cert_file, vomscert_trust_dn, output, verify);
01574       };
01575     }
01576 
01577     X509_free(holder);
01578     sk_X509_pop_free(certchain, X509_free);
01579     return res;
01580   }
01581 
01582   static char trans2[128] = { 0,   0,  0,  0,  0,  0,  0,  0,
01583                             0,   0,  0,  0,  0,  0,  0,  0,
01584                             0,   0,  0,  0,  0,  0,  0,  0,
01585                             0,   0,  0,  0,  0,  0,  0,  0,
01586                             0,   0,  0,  0,  0,  0,  0,  0,
01587                             0,   0,  0,  0,  0,  0,  0,  0,
01588                             52, 53, 54, 55, 56, 57, 58, 59,
01589                             60, 61,  0,  0,  0,  0,  0,  0,
01590                             0,  26, 27, 28, 29, 30, 31, 32,
01591                             33, 34, 35, 36, 37, 38, 39, 40,
01592                             41, 42, 43, 44, 45, 46, 47, 48,
01593                             49, 50, 51, 62,  0, 63,  0,  0,
01594                             0,   0,  1,  2,  3,  4,  5,  6,
01595                             7,   8,  9, 10, 11, 12, 13, 14,
01596                             15, 16, 17, 18, 19, 20, 21, 22,
01597                             23, 24, 25,  0,  0,  0,  0,  0};
01598 
01599   static char *base64Decode(const char *data, int size, int *j) {
01600     BIO *b64 = NULL;
01601     BIO *in = NULL;
01602 
01603     char *buffer = (char *)malloc(size);
01604     if (!buffer)
01605       return NULL;
01606 
01607     memset(buffer, 0, size);
01608 
01609     b64 = BIO_new(BIO_f_base64());
01610     in = BIO_new_mem_buf((void*)data, size);
01611     in = BIO_push(b64, in);
01612 
01613     *j = BIO_read(in, buffer, size);
01614 
01615     BIO_free_all(in);
01616     return buffer;
01617   }
01618 
01619   static char *MyDecode(const char *data, int size, int *n) {
01620     int bit = 0;
01621     int i = 0;
01622     char *res;
01623 
01624     if (!data || !size) return NULL;
01625 
01626     if ((res = (char *)calloc(1, (size*3)/4 + 2))) {
01627       *n = 0;
01628 
01629       while (i < size) {
01630         char c  = trans2[(int)data[i]];
01631         char c2 = (((i+1) < size) ? trans2[(int)data[i+1]] : 0);
01632 
01633         switch(bit) {
01634         case 0:
01635           res[*n] = ((c & 0x3f) << 2) | ((c2 & 0x30) >> 4);
01636           if ((i+1) < size)
01637             (*n)++;
01638           bit=4;
01639           i++;
01640           break;
01641         case 4:
01642           res[*n] = ((c & 0x0f) << 4) | ((c2 & 0x3c) >> 2);
01643           if ((i+1) < size)
01644             (*n)++;
01645           bit=2;
01646           i++;
01647           break;
01648         case 2:
01649           res[*n] = ((c & 0x03) << 6) | (c2 & 0x3f);
01650           if ((i+1) < size)
01651             (*n)++;
01652 
01653           i += 2;
01654           bit = 0;
01655           break;
01656         }
01657       }
01658 
01659       return res;
01660     }
01661     return NULL;
01662   }
01663 
01664   char *VOMSDecode(const char *data, int size, int *j) {
01665     int i = 0;
01666 
01667     while (i < size)
01668       if (data[i++] == '\n')
01669         return base64Decode(data, size, j);
01670 
01671     return MyDecode(data, size, j);
01672   }
01673 
01674   const std::string get_property(Arc::Credential& u,const std::string property) {
01675     if (property == "dn"){
01676         return u.GetIdentityName();
01677     }
01678 // If it was not DN, then we have to deal with VOMS
01679     std::vector<std::string> output;
01680     std::string emptystring = "";
01681     VOMSTrustList emptylist;
01682     parseVOMSAC(u,emptystring,emptystring,emptylist,output,false);
01683     if (property == "voms:vo"){
01684         if (output.empty())return ""; // if it's not possible to determine the VO -- such jobs will go into generic share
01685         else { // the  name of the VO is in the first string. Strip hostname from it, leave only voname parameter;
01686                 size_t pos1, pos2;
01687                 pos1 = output[0].find("=",1);
01688                 pos2 = output[0].find("/",1);
01689                 return output[0].substr(pos1+1,pos2-pos1-1);
01690         }
01691     }
01692     else if (property == "voms:role"){
01693        if (output.empty()) return "";
01694         else{
01695                 size_t pos1, pos2;
01696                 unsigned int i,j;
01697                 std::string role = "null";
01698                 std::string vo_name;
01699                 pos1 = output[0].find("=",1);
01700                 pos2 = output[0].find("/",1);
01701                 vo_name = output[0].substr(pos1+1,pos2-pos1-1);
01702                 for (i=1;i<output.size();i++){
01703                         pos1 = output[i].find("/Role=");
01704                         if(pos1 != std::string::npos){
01705                                 pos2 = output[i].find("/",pos1+1);
01706                                 if(pos2 == std::string::npos)
01707                                         role = output[i].substr(pos1+6,output[i].length()-pos1-6);
01708                                 else
01709                                         role = output[i].substr(pos1+6,pos2-pos1-6);
01710                                 break;
01711                         }
01712                 }
01713               vo_name.insert(vo_name.end(),':');
01714                 vo_name.insert(vo_name.length(),role);
01715                 return vo_name;
01716         }
01717     }
01718     else if (property == "voms:group"){
01719         if (output.empty()) return "";
01720         else{
01721                 size_t pos1, pos2;
01722                 unsigned int i,j;
01723                 std::string group = "";
01724                 std::string vo_name;
01725                 pos1 = output[0].find("=",1);
01726                 pos2 = output[0].find("/",1);
01727                 vo_name = output[0].substr(pos1+1,pos2-pos1-1);
01728                 vo_name.insert(vo_name.begin(),'/');
01729                 for (i=1;i<output.size();i++){
01730                         pos1 = output[i].find("/Group=");
01731                         if(pos1 != std::string::npos){
01732                                 pos2 = output[i].find("/",pos1+1);
01733                                 if(pos2 == std::string::npos)
01734                                    group = output[i].substr(pos1+7,output[i].length()-pos1-7);
01735                                 else
01736                                         group = output[i].substr(pos1+7,pos2-pos1-7);
01737                                 break;
01738                         }
01739                 }
01740                 if(group != ""){
01741                         vo_name.insert(vo_name.end(),'/');
01742                         vo_name.insert(vo_name.length(),group);
01743                 }
01744                 return vo_name;
01745         }
01746     }
01747     else return "";
01748   }
01749 
01750 
01751 } // namespace Arc
01752