XrdSecProtocolgsi.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                 X r d S e c P r o t o c o l g s i . c c                    */
00004 /*                                                                            */
00005 /* (c) 2005 G. Ganis / CERN                                                   */
00006 /*                                                                            */
00007 /******************************************************************************/
00008 
00009 #include <unistd.h>
00010 #include <ctype.h>
00011 #include <errno.h>
00012 #include <stdlib.h>
00013 #include <strings.h>
00014 #include <stdio.h>
00015 #include <sys/param.h>
00016 #include <pwd.h>
00017 #include <sys/types.h>
00018 #include <sys/stat.h>
00019 #include <fcntl.h>
00020 #include <dirent.h>
00021 
00022 #include "XrdNet/XrdNetDNS.hh"
00023 #include "XrdSys/XrdSysHeaders.hh"
00024 #include <XrdSys/XrdSysLogger.hh>
00025 #include <XrdSys/XrdSysError.hh>
00026 #include "XrdSys/XrdSysPlugin.hh"
00027 #include "XrdSys/XrdSysPriv.hh"
00028 #include <XrdOuc/XrdOucStream.hh>
00029 
00030 #include <XrdSut/XrdSutCache.hh>
00031 
00032 #include <XrdCrypto/XrdCryptoMsgDigest.hh>
00033 #include <XrdCrypto/XrdCryptosslAux.hh>
00034 #include <XrdCrypto/XrdCryptosslgsiAux.hh>
00035 
00036 #include <XrdSecgsi/XrdSecProtocolgsi.hh>
00037 #include <XrdSecgsi/XrdSecgsiTrace.hh>
00038 
00039 /******************************************************************************/
00040 /*                           S t a t i c   D a t a                            */
00041 /******************************************************************************/
00042   
00043 static String Prefix   = "xrd";
00044 static String ProtoID  = XrdSecPROTOIDENT;
00045 static const kXR_int32 Version = XrdSecgsiVERSION;
00046 
00047 static const char *gsiClientSteps[] = {
00048    "kXGC_none",
00049    "kXGC_certreq",
00050    "kXGC_cert",
00051    "kXGC_reserved"
00052 };
00053 
00054 static const char *gsiServerSteps[] = {
00055    "kXGS_none",
00056    "kXGS_init",
00057    "kXGS_cert",
00058    "kXGS_reserved"
00059 };
00060 
00061 static const char *gGSErrStr[] = {
00062    "ErrParseBuffer",               // 10000
00063    "ErrDecodeBuffer",              // 10001
00064    "ErrLoadCrypto",                // 10002
00065    "ErrBadProtocol",               // 10003
00066    "ErrCreateBucket",              // 10004
00067    "ErrDuplicateBucket",           // 10005
00068    "ErrCreateBuffer",              // 10006
00069    "ErrSerialBuffer",              // 10007
00070    "ErrGenCipher",                 // 10008
00071    "ErrExportPuK",                 // 10009
00072    "ErrEncRndmTag",                // 10010
00073    "ErrBadRndmTag",                // 10011
00074    "ErrNoRndmTag",                 // 10012
00075    "ErrNoCipher",                  // 10013
00076    "ErrNoCreds",                   // 10014
00077    "ErrBadOpt",                    // 10015
00078    "ErrMarshal",                   // 10016
00079    "ErrUnmarshal",                 // 10017
00080    "ErrSaveCreds",                 // 10018
00081    "ErrNoBuffer",                  // 10019
00082    "ErrRefCipher",                 // 10020
00083    "ErrNoPublic",                  // 10021
00084    "ErrAddBucket",                 // 10022
00085    "ErrFinCipher",                 // 10023
00086    "ErrInit",                      // 10024
00087    "ErrBadCreds",                  // 10025
00088    "ErrError"                      // 10026  
00089 };
00090 
00091 // One day in secs
00092 static const int kOneDay = 86400; 
00093 static const char *gUsrPxyDef = "/tmp/x509up_u";
00094 
00095 /******************************************************************************/
00096 /*                     S t a t i c   C l a s s   D a t a                      */
00097 /******************************************************************************/
00098 
00099 XrdSysMutex XrdSecProtocolgsi::gsiContext;
00100 String XrdSecProtocolgsi::CAdir    = "/etc/grid-security/certificates/";
00101 String XrdSecProtocolgsi::CRLdir   = "/etc/grid-security/certificates/";
00102 String XrdSecProtocolgsi::DefCRLext= ".r0";
00103 String XrdSecProtocolgsi::GMAPFile = "/etc/grid-security/grid-mapfile";
00104 String XrdSecProtocolgsi::SrvCert  = "/etc/grid-security/xrd/xrdcert.pem";
00105 String XrdSecProtocolgsi::SrvKey   = "/etc/grid-security/xrd/xrdkey.pem";
00106 String XrdSecProtocolgsi::UsrProxy;
00107 String XrdSecProtocolgsi::UsrCert  = "/.globus/usercert.pem";
00108 String XrdSecProtocolgsi::UsrKey   = "/.globus/userkey.pem";;
00109 String XrdSecProtocolgsi::PxyValid = "12:00";
00110 int    XrdSecProtocolgsi::DepLength= 0;
00111 int    XrdSecProtocolgsi::DefBits  = 512;
00112 int    XrdSecProtocolgsi::CACheck  = 1;
00113 int    XrdSecProtocolgsi::CRLCheck = 1;
00114 int    XrdSecProtocolgsi::GMAPOpt  = 1;
00115 String XrdSecProtocolgsi::DefCrypto= "ssl";
00116 String XrdSecProtocolgsi::DefCipher= "aes-128-cbc:bf-cbc:des-ede3-cbc";
00117 String XrdSecProtocolgsi::DefMD    = "sha1:md5";
00118 String XrdSecProtocolgsi::DefError = "invalid credentials ";
00119 int    XrdSecProtocolgsi::PxyReqOpts = 0;
00120 int    XrdSecProtocolgsi::AuthzPxy = 0;
00121 XrdSysPlugin   *XrdSecProtocolgsi::GMAPPlugin = 0;
00122 XrdSecgsiGMAP_t XrdSecProtocolgsi::GMAPFun = 0;
00123 XrdSysPlugin   *XrdSecProtocolgsi::AuthzPlugin = 0;
00124 XrdSecgsiAuthz_t XrdSecProtocolgsi::AuthzFun = 0;
00125 int    XrdSecProtocolgsi::GMAPCacheTimeOut = -1;
00126 String XrdSecProtocolgsi::SrvAllowedNames;
00127 //
00128 // Crypto related info
00129 int  XrdSecProtocolgsi::ncrypt    = 0;                 // Number of factories
00130 XrdCryptoFactory *XrdSecProtocolgsi::cryptF[XrdCryptoMax] = {0};   // their hooks 
00131 int  XrdSecProtocolgsi::cryptID[XrdCryptoMax] = {0};   // their IDs 
00132 String XrdSecProtocolgsi::cryptName[XrdCryptoMax] = {0}; // their names 
00133 XrdCryptoCipher *XrdSecProtocolgsi::refcip[XrdCryptoMax] = {0};    // ref for session ciphers 
00134 //
00135 // Caches
00136 XrdSutCache XrdSecProtocolgsi::cacheCA;   // CA info
00137 XrdSutCache XrdSecProtocolgsi::cacheCert; // Server certificates info
00138 XrdSutCache XrdSecProtocolgsi::cachePxy;  // Client proxies
00139 XrdSutCache XrdSecProtocolgsi::cacheGMAP; // Grid map entries
00140 XrdSutCache XrdSecProtocolgsi::cacheGMAPFun; // Entries mapped by GMAPFun
00141 //
00142 // Running options / settings
00143 int  XrdSecProtocolgsi::Debug       = 0; // [CS] Debug level
00144 bool XrdSecProtocolgsi::Server      = 1; // [CS] If server mode 
00145 int  XrdSecProtocolgsi::TimeSkew    = 300; // [CS] Allowed skew in secs for time stamps 
00146 //
00147 // Debug an tracing
00148 XrdSysError    XrdSecProtocolgsi::eDest(0, "secgsi_");
00149 XrdSysLogger   XrdSecProtocolgsi::Logger;
00150 XrdOucTrace   *XrdSecProtocolgsi::GSITrace = 0;
00151 
00152 XrdOucTrace *gsiTrace = 0;
00153 
00154 /******************************************************************************/
00155 /*                    S t a t i c   F u n c t i o n s                         */
00156 /******************************************************************************/
00157 //_____________________________________________________________________________
00158 static const char *ClientStepStr(int kclt)
00159 {
00160    // Return string with client step  
00161    static const char *ukn = "Unknown";
00162 
00163    kclt = (kclt < 0) ? 0 : kclt;
00164    kclt = (kclt > kXGC_reserved) ? 0 : kclt;
00165    kclt = (kclt >= kXGC_certreq) ? (kclt - kXGC_certreq + 1) : kclt;
00166 
00167    if (kclt < 0 || kclt > (kXGC_reserved - kXGC_certreq + 1))
00168       return ukn;  
00169    else
00170       return gsiClientSteps[kclt];
00171 }
00172 
00173 //_____________________________________________________________________________
00174 static const char *ServerStepStr(int ksrv)
00175 {
00176    // Return string with server step  
00177    static const char *ukn = "Unknown";
00178 
00179    ksrv = (ksrv < 0) ? 0 : ksrv;
00180    ksrv = (ksrv > kXGS_reserved) ? 0 : ksrv;
00181    ksrv = (ksrv >= kXGS_init) ? (ksrv - kXGS_init + 1) : ksrv;
00182 
00183    if (ksrv < 0 || ksrv > (kXGS_reserved - kXGS_init + 1))
00184       return ukn;  
00185    else
00186       return gsiServerSteps[ksrv];
00187 }
00188 
00189 
00190 /******************************************************************************/
00191 /*       D u m p  o f   H a n d s h a k e   v a r i a b l e s                 */
00192 /******************************************************************************/
00193 
00194 //_____________________________________________________________________________
00195 void gsiHSVars::Dump(XrdSecProtocolgsi *p)
00196 {
00197    // Dump content
00198    EPNAME("HSVars::Dump");
00199 
00200    PRINT("----------------------------------------------------------------");
00201    PRINT("protocol instance:   "<<p);
00202    PRINT("this:                "<<this);
00203    PRINT(" ");
00204    PRINT("Time stamp:          "<<TimeStamp);
00205    PRINT("Crypto mod:          "<<CryptoMod);
00206    PRINT("Remote version:      "<<RemVers);
00207    PRINT("Ref cipher:          "<<Rcip);
00208    PRINT("Bucket for exp cert: "<<Cbck);
00209    PRINT("Handshake ID:        "<<ID);
00210    PRINT("Cache reference:     "<<Cref);
00211    PRINT("Relevant file entry: "<<Pent);
00212    PRINT("Chain pointer:       "<<Chain);
00213    PRINT("CRL pointer:         "<<Crl);
00214    PRINT("Proxy chain:         "<<PxyChain);
00215    PRINT("Rndm tag checked:    "<<RtagOK);
00216    PRINT("Last step:           "<<LastStep);
00217    PRINT("Options:             "<<Options);
00218    PRINT("----------------------------------------------------------------");
00219 }
00220 
00221 /******************************************************************************/
00222 /*       P r o t o c o l   I n i t i a l i z a t i o n   M e t h o d s        */
00223 /******************************************************************************/
00224 
00225 
00226 //_____________________________________________________________________________
00227 XrdSecProtocolgsi::XrdSecProtocolgsi(int opts, const char *hname,
00228                                      const struct sockaddr *ipadd,
00229                                      const char *parms) : XrdSecProtocol("gsi")
00230 {
00231    // Default constructor
00232    EPNAME("XrdSecProtocolgsi");
00233 
00234    if (QTRACE(Authen)) { PRINT("constructing: "<<this); }
00235 
00236    // Create instance of the handshake vars
00237    if ((hs = new gsiHSVars())) {
00238       // Update time stamp
00239       hs->TimeStamp = time(0);
00240       // Local handshake variables
00241       hs->Tty = (isatty(0) == 0 || isatty(1) == 0) ? 0 : 1;
00242    } else {
00243       DEBUG("could not create handshake vars object");
00244    }
00245 
00246    // Set host name
00247    if (ipadd) {
00248       Entity.host = XrdNetDNS::getHostName((sockaddr&)*ipadd);
00249       // Set host addr
00250       memcpy(&hostaddr, ipadd, sizeof(hostaddr));
00251    } else {
00252       PRINT("WARNING: IP addr undefined: cannot determine host name: failure may follow");
00253    }
00254 
00255    // Init session variables
00256    sessionCF = 0;
00257    sessionKey = 0;
00258    bucketKey = 0;
00259    sessionMD = 0;
00260    sessionKsig = 0;
00261    sessionKver = 0;
00262    sessionKver = 0;
00263    proxyChain = 0;
00264 
00265    //
00266    // Notify, if required
00267    DEBUG("constructing: host: "<<hname);
00268    DEBUG("p: "<<XrdSecPROTOIDENT<<", plen: "<<XrdSecPROTOIDLEN);
00269    //
00270    // basic settings
00271    options  = opts;
00272    srvMode = 0;
00273 
00274    //
00275    // Mode specific initializations
00276    if (Server) {
00277       srvMode = 1;
00278       DEBUG("mode: server");
00279    } else {
00280       DEBUG("mode: client");
00281       //
00282       // Decode received buffer
00283       if (parms) {
00284          XrdOucString p("&P=gsi,");
00285          p += parms;
00286          hs->Parms = new XrdSutBuffer(p.c_str(), p.length());
00287       }
00288    }
00289 
00290    // We are done
00291    String vers = Version;
00292    vers.insert('.',vers.length()-2);
00293    vers.insert('.',vers.length()-5);
00294    DEBUG("object created: v"<<vers.c_str());
00295 }
00296 
00297 //_____________________________________________________________________________
00298 char *XrdSecProtocolgsi::Init(gsiOptions opt, XrdOucErrInfo *erp)
00299 {
00300    // Static method to the configure the static part of the protocol
00301    // Called once by XrdSecProtocolgsiInit
00302    EPNAME("Init");
00303    char *Parms = 0;
00304 
00305    //
00306    // Time stamp of initialization
00307    int timestamp = (int)time(0);
00308    //
00309    // Debug an tracing
00310    Debug = (opt.debug > -1) ? opt.debug : Debug;
00311    // Initiate error logging and tracing
00312    eDest.logger(&Logger);
00313    GSITrace    = new XrdOucTrace(&eDest);
00314    // Set debug mask ... also for auxilliary libs
00315    int trace = 0;
00316    if (Debug >= 3) {
00317       trace = cryptoTRACE_Dump;
00318       GSITrace->What |= TRACE_Authen;
00319       GSITrace->What |= TRACE_Debug;
00320    } else if (Debug >= 1) {
00321       trace = cryptoTRACE_Debug;
00322       GSITrace->What = TRACE_Debug;
00323    }
00324    gsiTrace = GSITrace;
00325    // ... also for auxilliary libs
00326    XrdSutSetTrace(trace);
00327    XrdCryptoSetTrace(trace);
00328 
00329    //
00330    // Operation mode
00331    Server = (opt.mode == 's');
00332 
00333    //
00334    // CA verification level
00335    //
00336    //    0   do not verify
00337    //    1   verify if self-signed; warn if not
00338    //    2   verify in all cases; fail if not possible
00339    //
00340    if (opt.ca >= 0 && opt.ca <= 2)
00341       CACheck = opt.ca;
00342    DEBUG("option CACheck: "<<CACheck);
00343 
00344    //
00345    // Check existence of CA directory
00346    struct stat st;
00347    if (opt.certdir) {
00348       DEBUG("testing CA dir(s): "<<opt.certdir);
00349       String CAtmp;
00350       String tmp = opt.certdir;
00351       String dp;
00352       int from = 0;
00353       while ((from = tmp.tokenize(dp, from, ',')) != -1) {
00354          if (dp.length() > 0) {
00355             if (XrdSutExpand(dp) == 0) {
00356                if (stat(dp.c_str(),&st) == -1) {
00357                   if (errno == ENOENT) {
00358                      ErrF(erp,kGSErrError,"CA directory non existing:",dp.c_str());
00359                      PRINT(erp->getErrText());
00360                   } else {
00361                      ErrF(erp,kGSErrError,"cannot stat CA directory:",dp.c_str());
00362                      PRINT(erp->getErrText());
00363                   }
00364                } else {
00365                   if (!(dp.endswith('/'))) dp += '/';
00366                   if (!(CAtmp.endswith(','))) CAtmp += ',';
00367                   CAtmp += dp;
00368                }
00369             } else {
00370                PRINT("Warning: could not expand: "<<dp);
00371             }
00372          }
00373       }
00374       if (CAtmp.length() > 0)
00375          CAdir = CAtmp;
00376    }
00377    DEBUG("using CA dir(s): "<<CAdir);
00378 
00379    //
00380    // CRL check level
00381    //
00382    //    0   do not care
00383    //    1   use if available
00384    //    2   require
00385    //    3   require not expired
00386    //
00387    if (opt.crl >= 0 && opt.crl <= 3)
00388       CRLCheck = opt.crl;
00389    DEBUG("option CRLCheck: "<<CRLCheck);
00390 
00391    //
00392    // Check existence of CRL directory
00393    if (opt.crldir) {
00394 
00395       DEBUG("testing CRL dir(s): "<<opt.crldir);
00396       String CRLtmp;
00397       String tmp = opt.crldir;
00398       String dp;
00399       int from = 0;
00400       while ((from = tmp.tokenize(dp, from, ',')) != -1) {
00401          if (dp.length() > 0) {
00402             if (XrdSutExpand(dp) == 0) {
00403                if (stat(dp.c_str(),&st) == -1) {
00404                   if (errno == ENOENT) {
00405                      ErrF(erp,kGSErrError,"CRL directory non existing:",dp.c_str());
00406                      PRINT(erp->getErrText());
00407                   } else {
00408                      ErrF(erp,kGSErrError,"cannot stat CRL directory:",dp.c_str());
00409                      PRINT(erp->getErrText());
00410                   }
00411                } else {
00412                   if (!(dp.endswith('/'))) dp += '/';
00413                   if (!(CRLtmp.endswith(','))) CRLtmp += ',';
00414                   CRLtmp += dp;
00415                }
00416             } else {
00417                PRINT("Warning: could not expand: "<<dp);
00418             }
00419          }
00420       }
00421       if (CRLtmp.length() > 0)
00422          CRLdir = CRLtmp;
00423 
00424    } else {
00425       // Use CAdir
00426       CRLdir = CAdir;
00427    }
00428    if (CRLCheck > 0)
00429       DEBUG("using CRL dir(s): "<<CRLdir);
00430 
00431    //
00432    // Default extension for CRL files
00433    if (opt.crlext)
00434       DefCRLext = opt.crlext;
00435 
00436    //
00437    // Server specific options
00438    if (Server) {
00439       //
00440       // List of supported / wanted crypto modules
00441       if (opt.clist)
00442          DefCrypto = opt.clist;
00443       //
00444       // List of crypto modules
00445       String cryptlist(DefCrypto,0,-1,64);
00446       // 
00447       // Load crypto modules
00448       XrdSutPFEntry ent;
00449       XrdCryptoFactory *cf = 0;
00450       if (cryptlist.length()) {
00451          String ncpt = "";
00452          int from = 0;
00453          while ((from = cryptlist.tokenize(ncpt, from, '|')) != -1) {
00454             if (ncpt.length() > 0 && ncpt[0] != '-') {
00455                // Try loading 
00456                if ((cf = XrdCryptoFactory::GetCryptoFactory(ncpt.c_str()))) {
00457                   // Add it to the list
00458                   cryptF[ncrypt] = cf;
00459                   cryptID[ncrypt] = cf->ID();
00460                   cryptName[ncrypt].insert(cf->Name(),0,strlen(cf->Name())+1);
00461                   cf->SetTrace(trace);
00462                   // Ref cipher
00463                   if (!(refcip[ncrypt] = cf->Cipher(0,0,0))) {
00464                      PRINT("ref cipher for module "<<ncpt<<
00465                            " cannot be instantiated : disable");
00466                      from -= ncpt.length();
00467                      cryptlist.erase(ncpt);
00468                   } else {
00469                      ncrypt++;
00470                      if (ncrypt >= XrdCryptoMax) {
00471                         PRINT("max number of crypto modules ("
00472                               << XrdCryptoMax <<") reached ");
00473                         break;
00474                      }
00475                   }
00476                } else {
00477                   PRINT("cannot instantiate crypto factory "<<ncpt<<
00478                            ": disable");
00479                   from -= ncpt.length();
00480                   cryptlist.erase(ncpt);
00481                }
00482             }
00483          }
00484       }
00485       //
00486       // We need at least one valid crypto module
00487       if (ncrypt <= 0) {
00488          ErrF(erp,kGSErrInit,"could not find any valid crypto module");
00489          PRINT(erp->getErrText());
00490          return Parms;
00491       }
00492       //
00493       // Load CA info into cache
00494       if (LoadCADir(timestamp) != 0) {
00495          ErrF(erp,kGSErrError,"problems loading CA info into cache");
00496          PRINT(erp->getErrText());
00497          return Parms;
00498       }
00499       if (QTRACE(Authen)) { cacheCA.Dump(); }
00500 
00501       //
00502       // List of supported / wanted ciphers
00503       if (opt.cipher)
00504          DefCipher = opt.cipher;
00505       // make sure we support all of them
00506       String cip = "";
00507       int from = 0;
00508       while ((from = DefCipher.tokenize(cip, from, ':')) != -1) {
00509          if (cip.length() > 0) {
00510             int i = 0;
00511             for (; i < ncrypt; i++) {
00512                if (!(cryptF[i]->SupportedCipher(cip.c_str()))) {
00513                   // Not supported: drop from the list
00514                   DEBUG("cipher type not supported ("<<cip<<") - disabling");
00515                   from -= cip.length();
00516                   DefCipher.erase(cip);
00517                }
00518             }
00519          }
00520       }
00521 
00522       //
00523       // List of supported / wanted Message Digest
00524       if (opt.md)
00525          DefMD = opt.md;
00526       // make sure we support all of them
00527       String md = "";
00528       from = 0;
00529       while ((from = DefMD.tokenize(md, from, ':')) != -1) {
00530          if (md.length() > 0) {
00531             int i = 0;
00532             for (; i < ncrypt; i++) {
00533                if (!(cryptF[i]->SupportedMsgDigest(md.c_str()))) {
00534                   // Not supported: drop from the list
00535                   PRINT("MD type not supported ("<<md<<") - disabling");
00536                   from -= md.length();
00537                   DefMD.erase(md);
00538                }
00539             }
00540          }
00541       }
00542 
00543       //
00544       // Load server certificate and key
00545       if (opt.cert) {
00546          String TmpCert = opt.cert;
00547          if (XrdSutExpand(TmpCert) == 0) {
00548             SrvCert = TmpCert;
00549          } else {
00550             PRINT("Could not expand: "<<opt.cert<<": use default");
00551          }
00552       }
00553       if (opt.key) {
00554          String TmpKey = opt.key;
00555          if (XrdSutExpand(TmpKey) == 0) {
00556             SrvKey = TmpKey;
00557          } else {
00558             PRINT("Could not expand: "<<opt.key<<": use default");
00559          }
00560       }
00561       //
00562       // Check if we can read the certificate key
00563       if (access(SrvKey.c_str(), R_OK)) {
00564          PRINT("WARNING: process has no permission to read the certificate key file: "<<SrvKey);
00565       }
00566       //
00567       // Get the IDs of the file: we need them to acquire the right privileges when opening
00568       // the certificate
00569       bool getpriv = 0;
00570       uid_t gsi_uid = geteuid();
00571       gid_t gsi_gid = getegid();
00572       if (!stat(SrvKey.c_str(), &st)) {
00573          if (st.st_uid != gsi_uid || st.st_gid != gsi_gid) {
00574             getpriv = 1;
00575             gsi_uid = st.st_uid;
00576             gsi_gid = st.st_gid;
00577          }
00578       }
00579       //
00580       // Init cache for certificates (we allow for more instances of
00581       // the same certificate, one for each different crypto module
00582       // available; this may evetually not be strictly needed.)
00583       if (cacheCert.Init(10) != 0) {
00584          ErrF(erp,kGSErrError,"problems init cache for certificates");
00585          PRINT(erp->getErrText());
00586          return Parms;
00587       }
00588       int i = 0;
00589       String certcalist = "";   // list of CA for server certificates
00590       for (; i<ncrypt; i++) {
00591          // Check normal certificates
00592          XrdCryptoX509 *xsrv = 0;
00593          {  XrdSysPrivGuard pGuard(gsi_uid, gsi_gid);
00594             if (pGuard.Valid())
00595                xsrv = cryptF[i]->X509(SrvCert.c_str(), SrvKey.c_str());
00596          }
00597          if (xsrv) {
00598             // Must be of EEC type
00599             if (xsrv->type != XrdCryptoX509::kEEC) {
00600                PRINT("problems loading srv cert: not EEC but: "<<xsrv->Type());
00601                continue;
00602             }
00603             // Must be valid
00604             if (!(xsrv->IsValid())) {
00605                PRINT("problems loading srv cert: invalid");
00606                continue;
00607             }
00608             // PKI must have been successfully initialized
00609             if (!xsrv->PKI() || xsrv->PKI()->status != XrdCryptoRSA::kComplete) {
00610                PRINT("problems loading srv cert: invalid PKI");
00611                continue;
00612             }
00613             // Must be exportable
00614             XrdSutBucket *xbck = xsrv->Export();
00615             if (!xbck) {
00616                PRINT("problems loading srv cert: cannot export into bucket");
00617                continue;
00618             }
00619             // Ok: save it into the cache
00620             String tag = cryptF[i]->Name();
00621             XrdSutPFEntry *cent = cacheCert.Add(tag.c_str());
00622             if (cent) {
00623                cent->status = kPFE_ok;
00624                cent->cnt = 0;
00625                cent->mtime = xsrv->NotAfter(); // expiration time
00626                // Save pointer to certificate
00627                cent->buf1.buf = (char *)xsrv;
00628                cent->buf1.len = 0;  // just a flag
00629                // Save pointer to key
00630                cent->buf2.buf = (char *)(xsrv->PKI());
00631                cent->buf2.len = 0;  // just a flag
00632                // Save pointer to bucket
00633                cent->buf3.buf = (char *)(xbck);
00634                cent->buf3.len = 0;  // just a flag
00635                // Save CA hash in list to communicate to clients
00636                if (certcalist.find(xsrv->IssuerHash()) == STR_NPOS) {
00637                   if (certcalist.length() > 0)
00638                      certcalist += "|";
00639                   certcalist += xsrv->IssuerHash();
00640                }
00641             }
00642          }
00643       }
00644       // Rehash cache
00645       cacheCert.Rehash(1);
00646       //
00647       // We must have got at least one valid certificate
00648       if (cacheCert.Empty()) {
00649          ErrF(erp,kGSErrError,"no valid server certificate found");
00650          PRINT(erp->getErrText());
00651          return Parms;
00652       }
00653       if (QTRACE(Authen)) { cacheCert.Dump(); }
00654 
00655       DEBUG("CA list: "<<certcalist);
00656 
00657       //
00658       // GRID map check option
00659       //
00660       //    0   do not use (DN will be used as identifier)
00661       //    1   use if available
00662       //    2   require
00663       const char *cogmap[] = { "do-not-use", "use-if-available", "require" };
00664       if (opt.ogmap >= 0 && opt.ogmap <= 2)
00665          GMAPOpt = opt.ogmap;
00666       DEBUG("grid map file option: "<<cogmap[GMAPOpt]);
00667 
00668       //
00669       // Check existence of GRID map file
00670       if (opt.gridmap) {
00671          String GMAPTmp = opt.gridmap;
00672          if (XrdSutExpand(GMAPTmp) == 0) {
00673             GMAPFile = GMAPTmp;
00674          } else {
00675             PRINT("Could not expand: "<<opt.gridmap<<": use default");
00676          }
00677       }
00678       bool hasgmap = 0;
00679       if (GMAPOpt > 0) {
00680          if (access(GMAPFile.c_str(),R_OK) != 0) {
00681             if (GMAPOpt > 1) {
00682                if (errno == ENOENT) {
00683                   ErrF(erp,kGSErrError,"Grid map file non existing:",GMAPFile.c_str());
00684                   PRINT(erp->getErrText());
00685                } else {
00686                   ErrF(erp,kGSErrError,"'access' error on grid map file:",GMAPFile.c_str());
00687                   PRINT(erp->getErrText());
00688                }
00689                return Parms;
00690             } else {
00691                DEBUG("Grid map file: "<<GMAPFile<<" cannot be 'access'ed: do not use");
00692             }
00693          } else {
00694             DEBUG("using grid map file: "<<GMAPFile);
00695             //
00696             // Init cache for gridmap entries
00697             if (LoadGMAP(timestamp) != 0) {
00698                ErrF(erp,kGSErrError,"problems initializing cache for gridmap entries");
00699                PRINT(erp->getErrText());
00700                return Parms;
00701             }
00702             if (QTRACE(Authen)) { cacheGMAP.Dump(); }
00703             hasgmap = 1;
00704          }
00705       }
00706       //
00707       // Load function be used to map DN to usernames, if specified
00708       bool hasauthzfun = 0;
00709       if (opt.authzfun && GMAPOpt > 0) {
00710          if (!(AuthzFun = LoadAuthzFun((const char *) opt.authzfun,
00711                                        (const char *) opt.authzfunparms))) {
00712             PRINT("Could not load plug-in: "<<opt.authzfun<<": ignore");
00713          } else {
00714             hasauthzfun = 1;
00715          }
00716       }
00717       bool hasgmapfun = 0;
00718       if (opt.gmapfun && GMAPOpt > 0) {
00719          if (!hasauthzfun) {
00720             if (!(GMAPFun = LoadGMAPFun((const char *) opt.gmapfun,
00721                                        (const char *) opt.gmapfunparms))) {
00722                PRINT("Could not load plug-in: "<<opt.gmapfun<<": ignore");
00723             } else {
00724                // Init or reset the cache
00725                if (cacheGMAPFun.Empty()) {
00726                   if (cacheGMAPFun.Init(100) != 0) {
00727                      PRINT("Error initializing GMAPFun cache");
00728                      return Parms;
00729                   }
00730                } else {
00731                   if (cacheGMAPFun.Reset() != 0) {
00732                      PRINT("Error resetting GMAPFun cache");
00733                      return Parms;
00734                   }
00735                }
00736                hasgmapfun = 1;
00737             }
00738          } else {
00739             PRINT("WARNING: ignoring 'gmapfun' directive since an authz plugin (specified"
00740                   " via 'authzfun') has already been successfully loaded");
00741          }
00742       }
00743       //
00744       // Disable GMAP if neither a grid mapfile nor a GMAP function are available
00745       if (!hasgmap && !hasgmapfun && !hasauthzfun) {
00746          if (GMAPOpt > 1) {
00747             ErrF(erp,kGSErrError,"Grid mapping required, but neither a grid mapfile"
00748                                  " nor a mapping function are available");
00749             PRINT(erp->getErrText());
00750             return Parms;
00751          }
00752          GMAPOpt = 0;
00753       }
00754       //
00755       // Expiration of GRIDMAP related cache entries
00756       if (GMAPOpt > 0 && !hasauthzfun && opt.gmapto > 0) {
00757          GMAPCacheTimeOut = opt.gmapto;
00758          DEBUG("grid-map cache entries expire after "<<GMAPCacheTimeOut<<" secs");
00759       }
00760 
00761       //
00762       // Request for delegated proxies
00763       if (opt.dlgpxy == 1 || opt.dlgpxy == 3)
00764          PxyReqOpts |= kOptsSrvReq;
00765       if (opt.dlgpxy == 2 || opt.dlgpxy == 3)
00766          PxyReqOpts |= kOptsPxFile;
00767       // Some notification
00768       DEBUG("Delegated proxies options: "<<PxyReqOpts);
00769 
00770       //
00771       // Request for proxy export for authorization
00772       if (opt.authzpxy == 1)
00773          AuthzPxy = 1;
00774       // Some notification
00775       DEBUG("Export proxy for authorization (in XrdSecEntity.endorsement): "<<AuthzPxy);
00776 
00777       //
00778       // Template for the created proxy files
00779       if ((PxyReqOpts & kOptsPxFile)) {
00780          String TmpProxy = gUsrPxyDef;
00781          if (opt.exppxy) TmpProxy = opt.exppxy;
00782          if (XrdSutExpand(TmpProxy) == 0) {
00783             UsrProxy = TmpProxy;
00784          } else {
00785             UsrProxy = gUsrPxyDef;
00786             UsrProxy += "u<uid>";
00787          }
00788          DEBUG("Template for exported proxy files: "<<UsrProxy);
00789       }
00790 
00791       //
00792       // Parms in the form:
00793       //     &P=gsi,v:<version>,c:<cryptomod>,ca:<list_of_srv_cert_ca>
00794       Parms = new char[cryptlist.length()+3+12+certcalist.length()+5];
00795       if (Parms) {
00796          sprintf(Parms,"v:%d,c:%s,ca:%s",
00797                        Version,cryptlist.c_str(),certcalist.c_str());
00798       } else {
00799          ErrF(erp,kGSErrInit,"no system resources for 'Parms'");
00800          PRINT(erp->getErrText());
00801       }
00802 
00803       // Some notification
00804       DEBUG("available crypto modules: "<<cryptlist);
00805       DEBUG("issuer CAs of server certs (hashes): "<<certcalist);
00806    }
00807 
00808    //
00809    // Client specific options
00810    if (!Server) {
00811       //
00812       // Init cache for CA certificate info. Clients will fill it
00813       // upon need
00814       if (cacheCA.Init(100) != 0) {
00815          ErrF(erp,kGSErrError,"problems init cache for CA info");
00816          PRINT(erp->getErrText());
00817          return Parms;
00818       }
00819       //
00820       // Init cache for proxies (in the future we may allow
00821       // users to use more certificates, depending on the context)
00822       if (cachePxy.Init(2) != 0) {
00823          ErrF(erp,kGSErrError,"problems init cache for proxies");
00824          PRINT(erp->getErrText());
00825          return Parms;
00826       }
00827       // use default dir $(HOME)/.<prefix>
00828       struct passwd *pw = getpwuid(getuid());
00829       if (!pw) {
00830          DEBUG("WARNING: cannot get user information (uid:"<<getuid()<<")");
00831       }
00832       //
00833       // Define user proxy file
00834       UsrProxy = gUsrPxyDef;
00835       if (opt.proxy) {
00836          String TmpProxy = opt.proxy;
00837          if (XrdSutExpand(TmpProxy) == 0) {
00838             UsrProxy = TmpProxy;
00839          } else {
00840             PRINT("Could not expand: "<<opt.proxy<<": use default");
00841          }
00842       } else {
00843          if (pw)
00844             UsrProxy += (int)(pw->pw_uid);
00845       }
00846       // Define user certificate file
00847       if (opt.cert) {
00848          String TmpCert = opt.cert;
00849          if (XrdSutExpand(TmpCert) == 0) {
00850             UsrCert = TmpCert;
00851          } else {
00852             PRINT("Could not expand: "<<opt.cert<<": use default");
00853          }
00854       } else {
00855          if (pw)
00856             UsrCert.insert(XrdSutHome(),0);
00857       }
00858       // Define user private key file
00859       if (opt.key) {
00860          String TmpKey = opt.key;
00861          if (XrdSutExpand(TmpKey) == 0) {
00862             UsrKey = TmpKey;
00863          } else {
00864             PRINT("Could not expand: "<<opt.key<<": use default");
00865          }
00866       } else {
00867          if (pw)
00868             UsrKey.insert(XrdSutHome(),0);
00869       }
00870       // Define proxy validity at renewal
00871       if (opt.valid)
00872          PxyValid = opt.valid;
00873       // Set depth of signature path
00874       if (opt.deplen != DepLength)
00875          DepLength = opt.deplen;
00876       // Set number of bits for proxy key
00877       if (opt.bits > DefBits)
00878          DefBits = opt.bits;
00879       //
00880       // Delegate proxy options
00881       if (opt.dlgpxy == 1)
00882          PxyReqOpts |= kOptsDlgPxy;
00883       if (opt.dlgpxy == 2)
00884          PxyReqOpts |= kOptsFwdPxy;
00885       if (opt.sigpxy > 0 || opt.dlgpxy == 1)
00886          PxyReqOpts |= kOptsSigReq;
00887       //
00888       // Define valid CNs for the server certificates; default is null, which means that
00889       // the server CN must be in the form "*/<hostname>"
00890       if (opt.srvnames)
00891          SrvAllowedNames = opt.srvnames;
00892       //
00893       // Notify
00894       DEBUG("using certificate file:         "<<UsrCert);
00895       DEBUG("using private key file:         "<<UsrKey);
00896       DEBUG("proxy: file:                    "<<UsrProxy);
00897       DEBUG("proxy: validity:                "<<PxyValid);
00898       DEBUG("proxy: depth of signature path: "<<DepLength);
00899       DEBUG("proxy: bits in key:             "<<DefBits);
00900       DEBUG("server cert: allowed names:     "<<SrvAllowedNames);
00901 
00902       // We are done
00903       Parms = (char *)"";
00904    }
00905 
00906    // We are done
00907    return Parms;
00908 }
00909 
00910 /******************************************************************************/
00911 /*                                D e l e t e                                 */
00912 /******************************************************************************/
00913 void XrdSecProtocolgsi::Delete()
00914 {
00915    // Deletes the protocol
00916    SafeFree(Entity.name);
00917    SafeFree(Entity.host);
00918    SafeFree(Entity.vorg);
00919    SafeFree(Entity.role);
00920    SafeFree(Entity.grps);
00921    SafeFree(Entity.endorsements);
00922    // Cleanup the handshake variables, if still there
00923    SafeDelete(hs);
00924    // Cleanup any other instance specific to this protocol
00925    SafeDelete(sessionKey);    // Session Key (result of the handshake)
00926    SafeDelete(bucketKey);     // Bucket with the key in export form
00927    SafeDelete(sessionMD);     // Message Digest instance
00928    SafeDelete(sessionKsig);   // RSA key to sign
00929    SafeDelete(sessionKver);   // RSA key to verify
00930    SafeDelete(proxyChain);    // Chain with delegated proxies
00931 
00932    delete this;
00933 }
00934 
00935 
00936 /******************************************************************************/
00937 /*       E n c r y p t i o n  R e l a t e d   M e t h o d s                   */
00938 /******************************************************************************/
00939 
00940 //_____________________________________________________________________________
00941 int XrdSecProtocolgsi::Encrypt(const char *inbuf,  // Data to be encrypted
00942                                int inlen,          // Length of data in inbuff
00943                                XrdSecBuffer **outbuf)  // Returns encrypted data
00944 {
00945    // Encrypt data in inbuff and place it in outbuff.
00946    //
00947    // Returns: < 0 Failed, the return value is -errno of the reason. Typically,
00948    //              -EINVAL    - one or more arguments are invalid.
00949    //              -ENOTSUP   - encryption not supported by the protocol
00950    //              -EOVERFLOW - outbuff is too small to hold result
00951    //              -ENOENT    - Context not initialized
00952    //          = 0 Success, outbuff contains a pointer to the encrypted data.
00953    //
00954    EPNAME("Encrypt");
00955 
00956    // We must have a key
00957    if (!sessionKey)
00958       return -ENOENT;
00959 
00960    // And something to encrypt
00961    if (!inbuf || inlen <= 0 || !outbuf)
00962       return -EINVAL;
00963 
00964    // Get output buffer
00965    char *buf = (char *)malloc(sessionKey->EncOutLength(inlen));
00966    if (!buf)
00967       return -ENOMEM;
00968 
00969    // Encrypt
00970    int len = sessionKey->Encrypt(inbuf, inlen, buf);
00971    if (len <= 0) {
00972       SafeFree(buf);
00973       return -EINVAL;
00974    }
00975 
00976    // Create and fill output buffer
00977    *outbuf = new XrdSecBuffer(buf, len);
00978 
00979    // We are done
00980    DEBUG("encrypted buffer has "<<len<<" bytes");
00981    return 0;
00982 }
00983 
00984 //_____________________________________________________________________________
00985 int XrdSecProtocolgsi::Decrypt(const char *inbuf,  // Data to be decrypted
00986                                int inlen,          // Length of data in inbuff
00987                                XrdSecBuffer **outbuf)  // Returns decrypted data
00988 {
00989    // Decrypt data in inbuff and place it in outbuff.
00990    //
00991    // Returns: < 0 Failed,the return value is -errno (see Encrypt).
00992    //          = 0 Success, outbuff contains a pointer to the encrypted data.
00993    EPNAME("Decrypt");
00994 
00995    // We must have a key
00996    if (!sessionKey)
00997       return -ENOENT;
00998 
00999    // And something to decrypt
01000    if (!inbuf || inlen <= 0 || !outbuf)
01001       return -EINVAL;
01002 
01003    // Get output buffer
01004    char *buf = (char *)malloc(sessionKey->DecOutLength(inlen));
01005    if (!buf)
01006       return -ENOMEM;
01007 
01008    // Decrypt
01009    int len = sessionKey->Decrypt(inbuf, inlen, buf);
01010    if (len <= 0) {
01011       SafeFree(buf);
01012       return -EINVAL;
01013    }
01014 
01015    // Create and fill output buffer
01016    *outbuf = new XrdSecBuffer(buf, len);
01017 
01018    // We are done
01019    DEBUG("decrypted buffer has "<<len<<" bytes");
01020    return 0;
01021 }
01022 
01023 //_____________________________________________________________________________
01024 int XrdSecProtocolgsi::Sign(const char  *inbuf,   // Data to be signed
01025                             int inlen,    // Length of data to be signed
01026                             XrdSecBuffer **outbuf)   // Buffer for the signature
01027 {
01028    // Sign data in inbuff and place the signature in outbuf.
01029    //
01030    // Returns: < 0 Failed, returned value is -errno (see Encrypt).
01031    //          = 0 Success, the return value is the length of the signature
01032    //              placed in outbuf.
01033    //
01034    EPNAME("Sign");
01035 
01036    // We must have a PKI and a digest
01037    if (!sessionKsig || !sessionMD)
01038       return -ENOENT;
01039 
01040    // And something to sign
01041    if (!inbuf || inlen <= 0 || !outbuf)
01042       return -EINVAL;
01043 
01044    // Reset digest
01045    sessionMD->Reset(0);
01046 
01047    // Calculate digest
01048    sessionMD->Update(inbuf, inlen);
01049    sessionMD->Final();
01050 
01051    // Output length
01052    int lmax = sessionKsig->GetOutlen(sessionMD->Length());
01053    char *buf = (char *)malloc(lmax);
01054    if (!buf)
01055       return -ENOMEM;
01056 
01057    // Sign
01058    int len = sessionKsig->EncryptPrivate(sessionMD->Buffer(),
01059                                          sessionMD->Length(),
01060                                          buf, lmax);
01061    if (len <= 0) {
01062       SafeFree(buf);
01063       return -EINVAL;
01064    }
01065 
01066    // Create and fill output buffer
01067    *outbuf = new XrdSecBuffer(buf, len);
01068 
01069    // We are done
01070    DEBUG("signature has "<<len<<" bytes");
01071    return 0;
01072 }
01073 
01074 //_____________________________________________________________________________
01075 int XrdSecProtocolgsi::Verify(const char  *inbuf,   // Data to be verified
01076                               int  inlen,           // Length of data in inbuf
01077                               const char  *sigbuf,  // Buffer with signature
01078                               int  siglen)          // Length of signature
01079 {
01080    // Verify a signature
01081    //
01082    // Returns: < 0 Failed, returned value is -errno (see Encrypt).
01083    //          = 0 Signature matches the value in inbuff.
01084    //          > 0 Failed to verify, signature does not match inbuff data.
01085    //
01086    EPNAME("Verify");
01087 
01088    // We must have a PKI and a digest
01089    if (!sessionKver || !sessionMD)
01090       return -ENOENT;
01091 
01092    // And something to verify
01093    if (!inbuf || inlen <= 0 || !sigbuf || siglen <= 0)
01094       return -EINVAL;
01095 
01096    // Reset digest
01097    sessionMD->Reset(0);
01098 
01099    // Calculate digest
01100    sessionMD->Update(inbuf, inlen);
01101    sessionMD->Final();
01102 
01103    // Output length
01104    int lmax = sessionKver->GetOutlen(siglen);
01105    char *buf = new char[lmax];
01106    if (!buf)
01107       return -ENOMEM;
01108 
01109    // Decrypt signature
01110    int len = sessionKver->DecryptPublic(sigbuf, siglen, buf, lmax);
01111    if (len <= 0) {
01112       delete[] buf;
01113       return -EINVAL;
01114    }
01115 
01116    // Verify signature
01117    bool bad = 1;
01118    if (len == sessionMD->Length()) {
01119       if (!strncmp(buf, sessionMD->Buffer(), len)) {
01120          // Signature matches
01121          bad = 0;
01122          DEBUG("signature successfully verified");
01123       }
01124    }
01125 
01126    // Cleanup
01127    if (buf) delete[] buf;
01128 
01129    // We are done
01130    return ((bad) ? 1 : 0);
01131 }
01132 
01133 //_____________________________________________________________________________
01134 int XrdSecProtocolgsi::getKey(char *kbuf, int klen)
01135 {
01136    // Get the current encryption key
01137    //
01138    // Returns: < 0 Failed, returned value if -errno (see Encrypt)
01139    //         >= 0 The size of the encyption key. The supplied buffer of length
01140    //              size hold the key. If the buffer address is 0, only the 
01141    //              size of the key is returned.
01142    //
01143    EPNAME("getKey");
01144 
01145    // Check if we have to serialize the key
01146    if (!bucketKey) {
01147 
01148       // We must have a key for that
01149       if (!sessionKey)
01150          // Invalid call
01151          return -ENOENT;
01152       // Create bucket
01153       bucketKey = sessionKey->AsBucket();
01154    }
01155 
01156    // Prepare output now, if we have any
01157    if (bucketKey) {
01158       // If are asked only the size, we are done
01159       if (kbuf == 0)
01160          return bucketKey->size;
01161 
01162       // Check the size of the buffer
01163       if (klen < bucketKey->size)
01164          // Too small
01165          return -EOVERFLOW;
01166 
01167       // Copy the buffer
01168       memcpy(kbuf, bucketKey->buffer, bucketKey->size);
01169 
01170       // We are done
01171       DEBUG("session key exported");
01172       return bucketKey->size;
01173    }
01174 
01175    // Key exists but we could export it in bucket format
01176    return -ENOMEM;
01177 }
01178 
01179 //_____________________________________________________________________________
01180 int XrdSecProtocolgsi::setKey(char *kbuf, int klen)
01181 {
01182    // Set the current encryption key
01183    //
01184    // Returns: < 0 Failed, returned value if -errno (see Encrypt)
01185    //            0 The new key has been set.
01186    //
01187    EPNAME("setKey");
01188 
01189    // Make sur that we can initialize the new key
01190    if (!kbuf || klen <= 0) 
01191       // Invalid inputs
01192       return -EINVAL;
01193 
01194    if (!sessionCF) 
01195       // Invalid context
01196       return -ENOENT;
01197 
01198    // Put the buffer key into a bucket
01199    XrdSutBucket *bck = new XrdSutBucket();
01200    if (!bck)
01201       // Cannot get buffer: out-of-resources?
01202       return -ENOMEM;
01203    // Set key buffer
01204    bck->SetBuf(kbuf, klen);
01205 
01206    // Init a new cipher from the bucket
01207    XrdCryptoCipher *newKey = sessionCF->Cipher(bck);
01208    if (!newKey) {
01209       SafeDelete(bck);
01210       return -ENOMEM;
01211    }
01212 
01213    // Delete current key
01214    SafeDelete(sessionKey);
01215 
01216    // Set the new key
01217    sessionKey = newKey;
01218 
01219    // Cleanup
01220    SafeDelete(bck);
01221 
01222    // Ok 
01223    DEBUG("session key update");
01224    return 0;
01225 }
01226 
01227 /******************************************************************************/
01228 /*             C l i e n t   O r i e n t e d   F u n c t i o n s              */
01229 /******************************************************************************/
01230 /******************************************************************************/
01231 /*                        g e t C r e d e n t i a l s                         */
01232 /******************************************************************************/
01233 
01234 XrdSecCredentials *XrdSecProtocolgsi::getCredentials(XrdSecParameters *parm,
01235                                                      XrdOucErrInfo    *ei)
01236 {
01237    // Query client for the password; remote username and host
01238    // are specified in 'parm'. File '.rootnetrc' is checked. 
01239    EPNAME("getCredentials");
01240 
01241    // If we are a server the only reason to be here is to get the forwarded
01242    // or saved client credentials
01243    if (srvMode) {
01244       XrdSecCredentials *creds = 0;
01245       if (proxyChain) {
01246          // Export the proxy chain into a bucket
01247          XrdCryptoX509ExportChain_t ExportChain = sessionCF->X509ExportChain();
01248          if (ExportChain) {
01249             XrdSutBucket *bck = (*ExportChain)(proxyChain, 1);
01250             if (bck) {
01251                // We need to duplicate it because XrdSecCredentials uses
01252                // {malloc, free} instead of {new, delete}
01253                char *nbuf = (char *) malloc(bck->size);
01254                if (nbuf) {
01255                   memcpy(nbuf, bck->buffer, bck->size);
01256                   // Import the buffer in a XrdSecCredentials object
01257                   creds = new XrdSecCredentials(nbuf, bck->size);
01258                }
01259                delete bck;
01260             }
01261          }
01262       }
01263       return creds;
01264    }
01265 
01266    // Handshake vars container must be initialized at this point
01267    if (!hs)
01268       return ErrC(ei,0,0,0,kGSErrError,
01269                   "handshake var container missing","getCredentials");
01270    //
01271    // Nothing to do if buffer is empty
01272    if ((!parm && !hs->Parms) || (parm && (!(parm->buffer) || parm->size <= 0))) {
01273       if (hs->Iter == 0) 
01274          return ErrC(ei,0,0,0,kGSErrNoBuffer,"missing parameters","getCredentials");
01275       else
01276          return (XrdSecCredentials *)0;
01277    }
01278 
01279    // Count interations
01280    (hs->Iter)++;
01281 
01282    // Update time stamp
01283    hs->TimeStamp = time(0);
01284 
01285    // Local vars
01286    int step = 0;
01287    int nextstep = 0;
01288    const char *stepstr = 0;
01289    char *bpub = 0;
01290    int lpub = 0;
01291    String CryptList = "";
01292    String Host = "";
01293    String RemID = "";
01294    String Emsg;
01295    String specID = "";
01296    String issuerHash = "";
01297    // Buffer / Bucket related
01298    XrdSutBuffer *bpar   = 0;  // Global buffer
01299    XrdSutBuffer *bmai   = 0;  // Main buffer
01300 
01301    //
01302    // Decode received buffer
01303    bpar = hs->Parms;
01304    if (!bpar && !(bpar = new XrdSutBuffer((const char *)parm->buffer,parm->size)))
01305       return ErrC(ei,0,0,0,kGSErrDecodeBuffer,"global",stepstr);
01306    // Ownership has been transferred
01307    hs->Parms = 0;
01308    //
01309    // Check protocol ID name
01310    if (strcmp(bpar->GetProtocol(),XrdSecPROTOIDENT))
01311       return ErrC(ei,bpar,bmai,0,kGSErrBadProtocol,stepstr);
01312    //
01313    // The step indicates what we are supposed to do
01314    if (!(step = bpar->GetStep())) {
01315       // The first, fake, step
01316       step = kXGS_init;
01317       bpar->SetStep(step);
01318    }
01319    stepstr = ServerStepStr(step);
01320    // Dump, if requested
01321    if (QTRACE(Authen)) {
01322       XrdOucString msg("IN: ");
01323       msg += stepstr;
01324       bpar->Dump(msg.c_str());
01325    }
01326    //
01327    // Parse input buffer
01328    if (ParseClientInput(bpar, &bmai, Emsg) == -1) {
01329       DEBUG(Emsg<<" CF: "<<sessionCF);
01330       return ErrC(ei,bpar,bmai,0,kGSErrParseBuffer,Emsg.c_str(),stepstr);
01331    }
01332    // Dump, if requested
01333    if (QTRACE(Authen)) {
01334       if (bmai)
01335          bmai->Dump("IN: main");
01336     }
01337    //
01338    // Version
01339    DEBUG("version run by server: "<< hs->RemVers);
01340    //
01341    // Check random challenge
01342    if (!CheckRtag(bmai, Emsg))
01343       return ErrC(ei,bpar,bmai,0,kGSErrBadRndmTag,Emsg.c_str(),stepstr);
01344    //
01345    // Login name if any
01346    String user(Entity.name);
01347    if (user.length() <= 0) user = getenv("XrdSecUSER");
01348    //
01349    // Now action depens on the step
01350    nextstep = kXGC_none;
01351 
01352    XrdCryptoX509 *c = 0;
01353 
01354    switch (step) {
01355 
01356    case kXGS_init:
01357       //
01358       // Add bucket with cryptomod to the global list
01359       // (This must be always visible from now on)
01360       if (bpar->AddBucket(hs->CryptoMod,kXRS_cryptomod) != 0)
01361          return ErrC(ei,bpar,bmai,0,
01362               kGSErrCreateBucket,XrdSutBuckStr(kXRS_cryptomod),stepstr);
01363       //
01364       // Add bucket with our version to the main list
01365       if (bpar->MarshalBucket(kXRS_version,(kXR_int32)(Version)) != 0)
01366          return ErrC(ei,bpar,bmai,0, kGSErrCreateBucket,
01367                 XrdSutBuckStr(kXRS_version),"global",stepstr);
01368       //
01369       // Add our issuer hash
01370       c = hs->PxyChain->Begin();
01371       if (c->type == XrdCryptoX509::kCA)
01372         issuerHash = c->SubjectHash();
01373       else
01374         issuerHash = c->IssuerHash();
01375       while ((c = hs->PxyChain->Next()) != 0) {
01376         if (c->type != XrdCryptoX509::kCA)
01377           break;
01378         issuerHash = c->SubjectHash();
01379       }
01380       DEBUG("Client issuer hash: " << issuerHash);
01381       if (bpar->AddBucket(issuerHash,kXRS_issuer_hash) != 0)
01382             return ErrC(ei,bpar,bmai,0, kGSErrCreateBucket,
01383                         XrdSutBuckStr(kXRS_issuer_hash),stepstr);
01384       //
01385       // Add bucket with our delegate proxy options
01386       if (hs->RemVers >= 10100) {
01387          if (bpar->MarshalBucket(kXRS_clnt_opts,(kXR_int32)(hs->Options)) != 0)
01388          return ErrC(ei,bpar,bmai,0, kGSErrCreateBucket,
01389                 XrdSutBuckStr(kXRS_clnt_opts),"global",stepstr);
01390       }
01391 
01392       //
01393       nextstep = kXGC_certreq;
01394       break;
01395 
01396    case kXGS_cert:
01397       //
01398       // We must have a session cipher at this point
01399       if (!(sessionKey))
01400          return ErrC(ei,bpar,bmai,0,
01401               kGSErrNoCipher,"session cipher",stepstr);
01402 
01403       //
01404       // Extract buffer with public info for the cipher agreement
01405       if (!(bpub = sessionKey->Public(lpub))) 
01406          return ErrC(ei,bpar,bmai,0,
01407                      kGSErrNoPublic,"session",stepstr);
01408       //
01409       // Add it to the global list
01410       if (bpar->UpdateBucket(bpub,lpub,kXRS_puk) != 0)
01411          return ErrC(ei,bpar,bmai,0, kGSErrAddBucket,
01412                      XrdSutBuckStr(kXRS_puk),"global",stepstr);
01413       //
01414       // Add the proxy certificate
01415       bmai->AddBucket(hs->Cbck);
01416       //
01417       // Add login name if any, needed while chosing where to export the proxies
01418       if (user.length() > 0) {
01419          if (bmai->AddBucket(user, kXRS_user) != 0)
01420             return ErrC(ei,bpar,bmai,0, kGSErrCreateBucket,
01421                         XrdSutBuckStr(kXRS_user),stepstr);
01422       }
01423       //
01424       nextstep = kXGC_cert;
01425       break;
01426 
01427    case kXGS_pxyreq:
01428       //
01429       // If something went wrong, send explanation
01430       if (Emsg.length() > 0) {
01431          if (bmai->AddBucket(Emsg,kXRS_message) != 0)
01432             return ErrC(ei,bpar,bmai,0, kGSErrCreateBucket,
01433                         XrdSutBuckStr(kXRS_message),stepstr);
01434       }
01435       //
01436       // Add login name if any, needed while chosing where to export the proxies
01437       if (user.length() > 0) {
01438          if (bmai->AddBucket(user, kXRS_user) != 0)
01439             return ErrC(ei,bpar,bmai,0, kGSErrCreateBucket,
01440                         XrdSutBuckStr(kXRS_user),stepstr);
01441       }
01442       //
01443       // The relevant buckets should already be in the buffers
01444       nextstep = kXGC_sigpxy;
01445       break;
01446 
01447    default:
01448       return ErrC(ei,bpar,bmai,0, kGSErrBadOpt,stepstr);
01449    }
01450 
01451    //
01452    // Serialize and encrypt
01453    if (AddSerialized('c', nextstep, hs->ID,
01454                      bpar, bmai, kXRS_main, sessionKey) != 0) {
01455       // Remove to avoid destruction
01456       bmai->Remove(hs->Cbck);
01457       return ErrC(ei,bpar,bmai,0,
01458                   kGSErrSerialBuffer,"main",stepstr);
01459    }
01460    //
01461    // Serialize the global buffer
01462    char *bser = 0;
01463    int nser = bpar->Serialized(&bser,'f');
01464 
01465    if (QTRACE(Authen)) {
01466       XrdOucString msg("OUT: ");
01467       msg += ClientStepStr(bpar->GetStep());
01468       bpar->Dump(msg.c_str());
01469       msg.replace(ClientStepStr(bpar->GetStep()), "main");
01470       bmai->Dump(msg.c_str());
01471    }
01472    //
01473    // Remove to avoid destruction
01474    bmai->Remove(hs->Cbck);
01475    //
01476    // We may release the buffers now
01477    REL2(bpar,bmai);
01478    //
01479    // Return serialized buffer
01480    if (nser > 0) {
01481       DEBUG("returned " << nser <<" bytes of credentials");
01482       return new XrdSecCredentials(bser, nser);
01483    } else {
01484       DEBUG("problems with final serialization");
01485       return (XrdSecCredentials *)0;
01486    }
01487 }
01488 
01489 /******************************************************************************/
01490 /*               S e r v e r   O r i e n t e d   M e t h o d s                */
01491 /******************************************************************************/
01492 /******************************************************************************/
01493 /*                          A u t h e n t i c a t e                           */
01494 /******************************************************************************/
01495 
01496 int XrdSecProtocolgsi::Authenticate(XrdSecCredentials *cred,
01497                                     XrdSecParameters **parms,
01498                                     XrdOucErrInfo     *ei)
01499 {
01500    //
01501    // Check if we have any credentials or if no credentials really needed.
01502    // In either case, use host name as client name
01503    EPNAME("Authenticate");
01504 
01505    //
01506    // If cred buffer is two small or empty assume host protocol
01507    if (cred->size <= (int)XrdSecPROTOIDLEN || !cred->buffer) {
01508       strncpy(Entity.prot, "host", sizeof(Entity.prot));
01509       return 0;
01510    }
01511 
01512    // Handshake vars conatiner must be initialized at this point
01513    if (!hs)
01514       return ErrS(Entity.tident,ei,0,0,0,kGSErrError,
01515                   "handshake var container missing",
01516                   "protocol initialization problems");
01517 
01518    // Update time stamp
01519    hs->TimeStamp = time(0);
01520 
01521    //
01522    // ID of this handshaking
01523    if (hs->ID.length() <= 0)
01524       hs->ID = Entity.tident;
01525    DEBUG("handshaking ID: " << hs->ID);
01526 
01527    // Local vars 
01528    int kS_rc = kgST_more;
01529    int step = 0;
01530    int nextstep = 0;
01531    char *bpub = 0;
01532    int lpub = 0;
01533    const char *stepstr = 0;
01534    String Message;
01535    String CryptList;
01536    String Host;
01537    String SrvPuKExp;
01538    String Salt;
01539    String RndmTag;
01540    String ClntMsg(256);
01541    // Buffer related
01542    XrdSutBuffer    *bpar = 0;  // Global buffer
01543    XrdSutBuffer    *bmai = 0;  // Main buffer
01544 
01545    //
01546    // Decode received buffer
01547    if (!(bpar = new XrdSutBuffer((const char *)cred->buffer,cred->size)))
01548       return ErrS(hs->ID,ei,0,0,0,kGSErrDecodeBuffer,"global",stepstr);
01549    //
01550    // Check protocol ID name
01551    if (strcmp(bpar->GetProtocol(),XrdSecPROTOIDENT))
01552       return ErrS(hs->ID,ei,bpar,bmai,0,kGSErrBadProtocol,stepstr);
01553    //
01554    // The step indicates what we are supposed to do
01555    step = bpar->GetStep();
01556    stepstr = ClientStepStr(step);
01557    // Dump, if requested
01558    if (QTRACE(Authen)) {
01559       XrdOucString msg("IN: ");
01560       msg += stepstr;
01561       bpar->Dump(msg.c_str());
01562    }
01563    //
01564    // Parse input buffer
01565    if (ParseServerInput(bpar, &bmai, ClntMsg) == -1) {
01566       DEBUG(ClntMsg);
01567       return ErrS(hs->ID,ei,bpar,bmai,0,kGSErrParseBuffer,ClntMsg.c_str(),stepstr);
01568    }
01569    //
01570    // Version
01571    DEBUG("version run by client: "<< hs->RemVers);
01572    DEBUG("options req by client: "<< hs->Options);
01573    //
01574    // Dump, if requested
01575    if (QTRACE(Authen)) {
01576       if (bmai)
01577          bmai->Dump("IN: main");
01578    }
01579    //
01580    // Check random challenge
01581    if (!CheckRtag(bmai, ClntMsg))
01582       return ErrS(hs->ID,ei,bpar,bmai,0,kGSErrBadRndmTag,stepstr,ClntMsg.c_str());
01583    //
01584    // Now action depens on the step
01585    switch (step) {
01586 
01587    case kXGC_certreq:
01588       //
01589       // Client required us to send our certificate and cipher public part:
01590       // add first this last one.
01591       // Extract buffer with public info for the cipher agreement
01592       if (!(bpub = hs->Rcip->Public(lpub))) 
01593          return ErrS(hs->ID,ei,bpar,bmai,0, kGSErrNoPublic,
01594                                          "session",stepstr);
01595       //
01596       // Add it to the global list
01597       if (bpar->AddBucket(bpub,lpub,kXRS_puk) != 0)
01598          return ErrS(hs->ID,ei,bpar,bmai,0, kGSErrAddBucket,
01599                                             "main",stepstr);
01600       //
01601       // Add bucket with list of supported ciphers
01602       if (bpar->AddBucket(DefCipher,kXRS_cipher_alg) != 0)
01603          return ErrS(hs->ID,ei,bpar,bmai,0,
01604               kGSErrAddBucket,XrdSutBuckStr(kXRS_cipher_alg),stepstr);
01605       //
01606       // Add bucket with list of supported MDs
01607       if (bpar->AddBucket(DefMD,kXRS_md_alg) != 0)
01608          return ErrS(hs->ID,ei,bpar,bmai,0,
01609               kGSErrAddBucket,XrdSutBuckStr(kXRS_md_alg),stepstr);
01610       //
01611       // Add the server certificate
01612       bpar->AddBucket(hs->Cbck);
01613 
01614       // We are done for the moment
01615       nextstep = kXGS_cert;
01616       break;
01617 
01618    case kXGC_cert:
01619       //
01620       // Client sent its own credentials: their are checked in
01621       // ParseServerInput, so if we are here they are OK
01622       kS_rc = kgST_ok;
01623       nextstep = kXGS_none;
01624 
01625       if (GMAPOpt > 0) {
01626          // Get name from gridmap
01627          String name;
01628          QueryGMAP(hs->Chain, hs->TimeStamp, name);
01629          DEBUG("username(s) associated with this DN: "<<name);
01630          if (name.length() <= 0) {
01631             // Grid map lookup failure
01632             if (GMAPOpt == 2) {
01633                // It was required, so we fail
01634                kS_rc = kgST_error;
01635                PRINT("ERROR: grid map required, but lookup failed - failure");
01636                break;
01637             } else {
01638                DEBUG("WARNING: grid map lookup failed - use DN as name");
01639             }
01640          } else {
01641             //
01642             // Extract user login name, if any
01643             XrdSutBucket *bck = 0;
01644             String user;
01645             if ((bck = bmai->GetBucket(kXRS_user))) {
01646                bck->ToString(user);
01647                bmai->Deactivate(kXRS_user);
01648             }
01649             DEBUG("target user: "<<user);
01650             if (user.length() > 0) {
01651                // Check if the wanted username is authorized
01652                String u;
01653                int from = 0;
01654                bool ok = 0;
01655                while ((from = name.tokenize(u, from, ',')) != -1) {
01656                   if (user == u) { ok = 1; break; }
01657                }
01658                if (ok) {
01659                   name = u;
01660                   DEBUG("grid map: requested user is authorized: name is '"<<name<<"'");
01661                } else {
01662                   // The requested username is not in the list; we warn and default to the first
01663                   // found (to be Globus compliant)
01664                   if (name.find(',') != STR_NPOS) name.erase(name.find(','));
01665                   PRINT("WARNING: grid map lookup ok, but the requested user is not"
01666                         " authorized ("<<user<<"). Instead, mapped as " << name << ".");
01667                }
01668             } else {
01669                // No username requested: we default to the first found (to be Globus compliant)
01670                if (name.find(',') != STR_NPOS) name.erase(name.find(','));
01671                DEBUG("grid map lookup successful: name is '"<<name<<"'");
01672             }
01673             Entity.name = strdup(name.c_str());
01674          }
01675       }
01676       // If not set, use DN
01677       if (!Entity.name || (strlen(Entity.name) <= 0)) {
01678          // No grid map: set the hash of the client DN as name
01679          if (hs->Chain->EEChash()) {
01680             Entity.name = strdup(hs->Chain->EEChash());
01681          } else {
01682             DEBUG("WARNING: DN missing: corruption? ");
01683          }
01684       }
01685 
01686       // Export proxy for authorization, if required
01687       if (AuthzPxy == 1) {
01688          // In string form
01689          XrdSutBucket *b = XrdCryptosslX509ExportChain(hs->Chain, true);
01690          XrdOucString s;
01691          b->ToString(s);
01692          Entity.endorsements = strdup(s.c_str());
01693          delete b;
01694       }
01695 
01696       if (hs->RemVers >= 10100) {
01697          if (hs->PxyChain) {
01698             // The client is going to send over info for delegation
01699             kS_rc = kgST_more;
01700             nextstep = kXGS_pxyreq;
01701          }
01702       }
01703 
01704       break;
01705 
01706    case kXGC_sigpxy:
01707       //
01708       // Nothing to do after this
01709       kS_rc = kgST_ok;
01710       nextstep = kXGS_none;
01711       //
01712       // If something went wrong, print explanation
01713       if (ClntMsg.length() > 0) {
01714          PRINT(ClntMsg);
01715       }
01716       break;
01717 
01718    default:
01719       return ErrS(hs->ID,ei,bpar,bmai,0, kGSErrBadOpt, stepstr);
01720    }
01721 
01722    if (kS_rc == kgST_more) {
01723       //
01724       // Add message to client
01725       if (ClntMsg.length() > 0)
01726          if (bmai->AddBucket(ClntMsg,kXRS_message) != 0) {
01727             DEBUG("problems adding bucket with message for client");
01728          }
01729       //
01730       // Serialize, encrypt and add to the global list
01731       if (AddSerialized('s', nextstep, hs->ID,
01732                         bpar, bmai, kXRS_main, sessionKey) != 0) {
01733          // Remove to avoid destruction
01734          bpar->Remove(hs->Cbck);
01735          return ErrS(hs->ID,ei,bpar,bmai,0, kGSErrSerialBuffer,
01736                      "main / session cipher",stepstr);
01737       }
01738       //
01739       // Serialize the global buffer
01740       char *bser = 0;
01741       int nser = bpar->Serialized(&bser,'f');
01742       //
01743       // Dump, if requested
01744       if (QTRACE(Authen)) {
01745          XrdOucString msg("OUT: ");
01746          msg += ServerStepStr(bpar->GetStep());
01747          bpar->Dump(msg.c_str());
01748          msg.replace(ServerStepStr(bpar->GetStep()), "main");
01749          bmai->Dump(msg.c_str());
01750       }
01751       //
01752       // Create buffer for client
01753       *parms = new XrdSecParameters(bser,nser);
01754       //
01755       // Remove to avoid destruction
01756       bpar->Remove(hs->Cbck);
01757 
01758    } else {
01759       //
01760       // Remove to avoid destruction
01761       bpar->Remove(hs->Cbck);
01762       //
01763       // Cleanup handshake vars
01764       SafeDelete(hs);
01765    }
01766    //
01767    // We may release the buffers now
01768    REL2(bpar,bmai);
01769    //
01770    // All done
01771    return kS_rc;
01772 }
01773 
01774 /******************************************************************************/
01775 /*              X r d S e c P r o t o c o l p w d I n i t                     */
01776 /******************************************************************************/
01777 
01778 extern "C"
01779 {
01780 char *XrdSecProtocolgsiInit(const char mode,
01781                             const char *parms, XrdOucErrInfo *erp)
01782 {
01783    // One-time protocol initialization, filling the static flags and options
01784    // of the protocol.
01785    // For clients (mode == 'c') we use values in envs.
01786    // For servers (mode == 's') the command line options are passed through
01787    // parms.
01788    gsiOptions opts;
01789    char *rc = (char *)"";
01790    char *cenv = 0;
01791 
01792    //
01793    // Clients first
01794    if (mode == 'c') {
01795       //
01796       // Decode envs:
01797       //             "XrdSecDEBUG"           debug flag ("0","1","2","3")
01798       //             "XrdSecGSICADIR"        full path to an alternative path
01799       //                                     containing the CA info
01800       //                                     [/etc/grid-security/certificates]
01801       //             "XrdSecGSICRLDIR"       full path to an alternative path
01802       //                                     containing the CRL info
01803       //                                     [/etc/grid-security/certificates]
01804       //             "XrdSecGSICRLEXT"       default extension of CRL files [.r0]
01805       //             "XrdSecGSIUSERCERT"     full path to an alternative file
01806       //                                     containing the user certificate
01807       //                                     [$HOME/.globus/usercert.pem]
01808       //             "XrdSecGSIUSERKEY"      full path to an alternative file
01809       //                                     containing the user key
01810       //                                     [$HOME/.globus/userkey.pem]
01811       //             "XrdSecGSIUSERPROXY"    full path to an alternative file
01812       //                                     containing the user proxy
01813       //                                     [/tmp/x509up_u<uid>]
01814       //             "XrdSecGSIPROXYVALID"   validity of proxies in the 
01815       //                                     grid-proxy-init format
01816       //                                     ["12:00", i.e. 12 hours]
01817       //             "XrdSecGSIPROXYDEPLEN"  depth of signature path for proxies;
01818       //                                     use -1 for unlimited [0]
01819       //             "XrdSecGSIPROXYKEYBITS" bits in PKI for proxies [512]
01820       //             "XrdSecGSICACHECK"      CA check level [1]:
01821       //                                      0 do not verify;
01822       //                                      1 verify if self-signed, warn if not;
01823       //                                      2 verify in all cases, fail if not possible
01824       //             "XrdSecGSICRLCHECK"     CRL check level [2]:
01825       //                                      0 don't care;
01826       //                                      1 use if available;
01827       //                                      2 require,
01828       //                                      3 require non-expired CRL
01829       //             "XrdSecGSIDELEGPROXY"   Forwarding of credentials option:
01830       //                                     0 none; 1 sign request created
01831       //                                     by server; 2 forward local proxy
01832       //                                     (include private key) [0]
01833       //             "XrdSecGSISIGNPROXY"    permission to sign requests
01834       //                                     0 no, 1 yes [1]
01835       //             "XrdSecGSISRVNAMES"     Server names allowed: if the server CN
01836       //                                     does not match any of these, or it is
01837       //                                     explicitely denied by these, or it is
01838       //                                     not in the form "*/<hostname>", the
01839       //                                     handshake fails.
01840 
01841       //
01842       opts.mode = mode;
01843       // debug
01844       cenv = getenv("XrdSecDEBUG");
01845       if (cenv)
01846          if (cenv[0] >= 49 && cenv[0] <= 51) opts.debug = atoi(cenv);
01847 
01848       // directory with CA certificates
01849       cenv = (getenv("XrdSecGSICADIR") ? getenv("XrdSecGSICADIR")
01850                                        : getenv("X509_CERT_DIR"));
01851       if (cenv)
01852          opts.certdir = strdup(cenv);
01853 
01854       // directory with CRL info
01855       cenv = (getenv("XrdSecGSICRLDIR") ? getenv("XrdSecGSICRLDIR")
01856                                         : getenv("X509_CERT_DIR"));
01857       if (cenv)
01858          opts.crldir = strdup(cenv);
01859 
01860       // Default extension CRL files
01861       cenv = getenv("XrdSecGSICRLEXT");
01862       if (cenv)
01863          opts.crlext = strdup(cenv);
01864 
01865       // file with user cert
01866       cenv = (getenv("XrdSecGSIUSERCERT") ? getenv("XrdSecGSIUSERCERT")
01867                                           : getenv("X509_USER_CERT"));
01868       if (cenv)
01869          opts.cert = strdup(cenv);
01870 
01871       // file with user key
01872       cenv = (getenv("XrdSecGSIUSERKEY") ? getenv("XrdSecGSIUSERKEY")
01873                                          : getenv("X509_USER_KEY"));
01874       if (cenv)
01875          opts.key = strdup(cenv);
01876 
01877       // file with user proxy
01878       cenv = (getenv("XrdSecGSIUSERPROXY") ? getenv("XrdSecGSIUSERPROXY")
01879                                            : getenv("X509_USER_PROXY"));
01880       if (cenv)
01881          opts.proxy = strdup(cenv);
01882 
01883       // file with user proxy
01884       cenv = getenv("XrdSecGSIPROXYVALID");
01885       if (cenv)
01886          opts.valid = strdup(cenv);
01887 
01888       // Depth of signature path for proxies
01889       cenv = getenv("XrdSecGSIPROXYDEPLEN");
01890       if (cenv)
01891          opts.deplen = atoi(cenv);
01892 
01893       // Key Bit length 
01894       cenv = getenv("XrdSecGSIPROXYKEYBITS");
01895       if (cenv)
01896          opts.bits = atoi(cenv);
01897 
01898       // CA verification level 
01899       cenv = getenv("XrdSecGSICACHECK");
01900       if (cenv)
01901          opts.ca = atoi(cenv);
01902 
01903       // CRL check level 
01904       cenv = getenv("XrdSecGSICRLCHECK");
01905       if (cenv)
01906          opts.crl = atoi(cenv);
01907 
01908       // Delegate proxy
01909       cenv = getenv("XrdSecGSIDELEGPROXY");
01910       if (cenv)
01911          opts.dlgpxy = atoi(cenv);
01912 
01913       // Sign delegate proxy requests
01914       cenv = getenv("XrdSecGSISIGNPROXY");
01915       if (cenv)
01916          opts.sigpxy = atoi(cenv);
01917 
01918       // Allowed server name formats
01919       cenv = getenv("XrdSecGSISRVNAMES");
01920       if (cenv)
01921          opts.srvnames = strdup(cenv);
01922 
01923       //
01924       // Setup the object with the chosen options
01925       rc = XrdSecProtocolgsi::Init(opts,erp);
01926 
01927       // Some cleanup
01928       SafeFree(opts.certdir);
01929       SafeFree(opts.crldir);
01930       SafeFree(opts.crlext);
01931       SafeFree(opts.cert);
01932       SafeFree(opts.key);
01933       SafeFree(opts.proxy);
01934       SafeFree(opts.valid);
01935       SafeFree(opts.srvnames);
01936 
01937       // We are done
01938       return rc;
01939    }
01940 
01941    // Take into account xrootd debug flag
01942    cenv = getenv("XRDDEBUG");
01943    if (cenv && !strcmp(cenv,"1")) opts.debug = 1;
01944 
01945    //
01946    // Server initialization
01947    if (parms) {
01948       //
01949       // Duplicate the parms
01950       char parmbuff[1024];
01951       strlcpy(parmbuff, parms, sizeof(parmbuff));
01952       //
01953       // The tokenizer
01954       XrdOucTokenizer inParms(parmbuff);
01955       //
01956       // Decode parms:
01957       // for servers:
01958       //              [-d:<debug_level>]
01959       //              [-c:[-]ssl[:[-]<CryptoModuleName]]
01960       //              [-certdir:<dir_with_CA_info>]
01961       //              [-crldir:<dir_with_CRL_info>]
01962       //              [-crlext:<default_extension_CRL_files>]
01963       //              [-cert:<path_to_server_certificate>]
01964       //              [-key:<path_to_server_key>]
01965       //              [-cipher:<list_of_supported_ciphers>]
01966       //              [-md:<list_of_supported_digests>]
01967       //              [-ca:<crl_verification_level>]
01968       //              [-crl:<crl_check_level>]
01969       //              [-gridmap:<grid_map_file>]
01970       //              [-gmapfun:<grid_map_function>]
01971       //              [-gmapfunparms:<grid_map_function_init_parameters>]
01972       //              [-authzfun:<authz_function>]
01973       //              [-authzfunparms:<authz_function_init_parameters>]
01974       //              [-gmapto:<grid_map_cache_entry_validity_in_secs>]
01975       //              [-gmapopt:<grid_map_check_option>]
01976       //              [-dlgpxy:<proxy_req_option>]
01977       //              [-exppxy:<filetemplate>]
01978       //              [-authzpxy]
01979       //
01980       int debug = -1;
01981       String clist = "";
01982       String certdir = "";
01983       String crldir = "";
01984       String crlext = "";
01985       String cert = "";
01986       String key = "";
01987       String cipher = "";
01988       String md = "";
01989       String gridmap = "";
01990       String gmapfun = "";
01991       String gmapfunparms = "";
01992       String authzfun = "";
01993       String authzfunparms = "";
01994       String exppxy = "";
01995       int ca = 1;
01996       int crl = 1;
01997       int ogmap = 1;
01998       int gmapto = -1;
01999       int dlgpxy = 0;
02000       int authzpxy = 0;
02001       char *op = 0;
02002       while (inParms.GetLine()) { 
02003          while ((op = inParms.GetToken())) {
02004             if (!strncmp(op, "-d:",3)) {
02005                debug = atoi(op+3);
02006             } else if (!strncmp(op, "-c:",3)) {
02007                clist = (const char *)(op+3);
02008             } else if (!strncmp(op, "-certdir:",9)) {
02009                certdir = (const char *)(op+9);
02010             } else if (!strncmp(op, "-crldir:",8)) {
02011                crldir = (const char *)(op+8);
02012             } else if (!strncmp(op, "-crlext:",8)) {
02013                crlext = (const char *)(op+8);
02014             } else if (!strncmp(op, "-cert:",6)) {
02015                cert = (const char *)(op+6);
02016             } else if (!strncmp(op, "-key:",5)) {
02017                key = (const char *)(op+5);
02018             } else if (!strncmp(op, "-cipher:",8)) {
02019                cipher = (const char *)(op+8);
02020             } else if (!strncmp(op, "-md:",4)) {
02021                md = (const char *)(op+4);
02022             } else if (!strncmp(op, "-ca:",4)) {
02023                ca = atoi(op+4);
02024             } else if (!strncmp(op, "-crl:",5)) {
02025                crl = atoi(op+5);
02026             } else if (!strncmp(op, "-gmapopt:",9)) {
02027                ogmap = atoi(op+9);
02028             } else if (!strncmp(op, "-gridmap:",9)) {
02029                gridmap = (const char *)(op+9);
02030             } else if (!strncmp(op, "-gmapfun:",9)) {
02031                gmapfun = (const char *)(op+9);
02032             } else if (!strncmp(op, "-gmapfunparms:",14)) {
02033                gmapfunparms = (const char *)(op+14);
02034             } else if (!strncmp(op, "-authzfun:",10)) {
02035                authzfun = (const char *)(op+10);
02036             } else if (!strncmp(op, "-authzfunparms:",15)) {
02037                authzfunparms = (const char *)(op+15);
02038             } else if (!strncmp(op, "-gmapto:",8)) {
02039                gmapto = atoi(op+8);
02040             } else if (!strncmp(op, "-dlgpxy:",8)) {
02041                dlgpxy = atoi(op+8);
02042             } else if (!strncmp(op, "-exppxy:",8)) {
02043                exppxy = (const char *)(op+8);
02044             } else if (!strncmp(op, "-authzpxy",9)) {
02045                authzpxy = 1;
02046             }
02047          }
02048       }
02049 
02050       //
02051       // Build the option object
02052       opts.debug = (debug > -1) ? debug : opts.debug;
02053       opts.mode = 's';
02054       opts.ca = ca;
02055       opts.crl = crl;
02056       opts.ogmap = ogmap;
02057       opts.gmapto = gmapto;
02058       opts.dlgpxy = dlgpxy;
02059       opts.authzpxy = authzpxy;
02060       if (clist.length() > 0)
02061          opts.clist = (char *)clist.c_str();
02062       if (certdir.length() > 0)
02063          opts.certdir = (char *)certdir.c_str();
02064       if (crldir.length() > 0)
02065          opts.crldir = (char *)crldir.c_str();
02066       if (crlext.length() > 0)
02067          opts.crlext = (char *)crlext.c_str();
02068       if (cert.length() > 0)
02069          opts.cert = (char *)cert.c_str();
02070       if (key.length() > 0)
02071          opts.key = (char *)key.c_str();
02072       if (cipher.length() > 0)
02073          opts.cipher = (char *)cipher.c_str();
02074       if (md.length() > 0)
02075          opts.md = (char *)md.c_str();
02076       if (gridmap.length() > 0)
02077          opts.gridmap = (char *)gridmap.c_str();
02078       if (gmapfun.length() > 0)
02079          opts.gmapfun = (char *)gmapfun.c_str();
02080       if (gmapfunparms.length() > 0)
02081          opts.gmapfunparms = (char *)gmapfunparms.c_str();
02082       if (authzfun.length() > 0)
02083          opts.authzfun = (char *)authzfun.c_str();
02084       if (authzfunparms.length() > 0)
02085          opts.authzfunparms = (char *)authzfunparms.c_str();
02086       if (exppxy.length() > 0)
02087          opts.exppxy = (char *)exppxy.c_str();
02088       //
02089       // Setup the plug-in with the chosen options
02090       return XrdSecProtocolgsi::Init(opts,erp);
02091    }
02092    //
02093    // Setup the plug-in with the defaults
02094    return XrdSecProtocolgsi::Init(opts,erp);
02095 }}
02096 
02097 
02098 /******************************************************************************/
02099 /*              X r d S e c P r o t o c o l p w d O b j e c t                 */
02100 /******************************************************************************/
02101 
02102 extern "C"
02103 {
02104 XrdSecProtocol *XrdSecProtocolgsiObject(const char              mode,
02105                                         const char             *hostname,
02106                                         const struct sockaddr  &netaddr,
02107                                         const char             *parms,
02108                                         XrdOucErrInfo    *erp)
02109 {
02110    XrdSecProtocolgsi *prot;
02111    int options = XrdSecNOIPCHK;
02112 
02113    //
02114    // Get a new protocol object
02115    if (!(prot = new XrdSecProtocolgsi(options, hostname, &netaddr, parms))) {
02116       char *msg = (char *)"Secgsi: Insufficient memory for protocol.";
02117       if (erp) 
02118          erp->setErrInfo(ENOMEM, msg);
02119       else 
02120          cerr <<msg <<endl;
02121       return (XrdSecProtocol *)0;
02122    }
02123    //
02124    // We are done
02125    if (!erp)
02126       cerr << "protocol object instantiated" << endl;
02127    return prot;
02128 }}
02129 
02130 
02131 /******************************************************************************/
02132 /*                       P r i v a t e   M e t h o d s                        */
02133 /******************************************************************************/
02134 
02135 //_________________________________________________________________________
02136 int XrdSecProtocolgsi::AddSerialized(char opt, kXR_int32 step, String ID,
02137                                      XrdSutBuffer *bls, XrdSutBuffer *buf,
02138                                      kXR_int32 type,
02139                                      XrdCryptoCipher *cip)
02140 {
02141    // Serialize buf, and add it encrypted to bls as bucket type
02142    // Cipher cip is used if defined; else PuK rsa .
02143    // If both are undefined the buffer is just serialized and added.
02144    EPNAME("AddSerialized");
02145 
02146    if (!bls || !buf || (opt != 0 && opt != 'c' && opt != 's')) {
02147       DEBUG("invalid inputs ("
02148             <<bls<<","<<buf<<","<<opt<<")"
02149             <<" - type: "<<XrdSutBuckStr(type));
02150       return -1;
02151    }
02152 
02153    //
02154    // Add step to indicate the counterpart what we send
02155    if (step > 0) {
02156       bls->SetStep(step);
02157       buf->SetStep(step);
02158       hs->LastStep = step;
02159    }
02160 
02161    //
02162    // If a random tag has been sent and we have a session cipher,
02163    // we sign it
02164    XrdSutBucket *brt = buf->GetBucket(kXRS_rtag);
02165    if (brt && sessionKsig) {
02166       //
02167       // Encrypt random tag with session cipher
02168       if (sessionKsig->EncryptPrivate(*brt) <= 0) {
02169          DEBUG("error encrypting random tag");
02170          return -1;
02171       }
02172       //
02173       // Update type
02174       brt->type = kXRS_signed_rtag;
02175    }
02176    //
02177    // Add an random challenge: if a next exchange is required this will
02178    // allow to prove authenticity of counter part
02179    //
02180    // Generate new random tag and create a bucket
02181    String RndmTag;
02182    XrdSutRndm::GetRndmTag(RndmTag);
02183    //
02184    // Get bucket
02185    brt = 0;
02186    if (!(brt = new XrdSutBucket(RndmTag,kXRS_rtag))) {
02187       DEBUG("error creating random tag bucket");
02188       return -1;
02189    }
02190    buf->AddBucket(brt);
02191    //
02192    // Get cache entry
02193    if (!hs->Cref) {
02194       DEBUG("cache entry not found: protocol error");
02195       return -1;
02196    }
02197    //
02198    // Add random tag to the cache and update timestamp
02199    hs->Cref->buf1.SetBuf(brt->buffer,brt->size);
02200    hs->Cref->mtime = (kXR_int32)hs->TimeStamp;
02201    //
02202    // Now serialize the buffer ...
02203    char *bser = 0;
02204    int nser = buf->Serialized(&bser);
02205    //
02206    // Update bucket with this content
02207    XrdSutBucket *bck = 0;;
02208    if (!(bck = bls->GetBucket(type))) {
02209       // or create new bucket, if not existing
02210       if (!(bck = new XrdSutBucket(bser,nser,type))) {
02211          DEBUG("error creating bucket "
02212                <<" - type: "<<XrdSutBuckStr(type));
02213          return -1;
02214       }
02215       //
02216       // Add the bucket to the list
02217       bls->AddBucket(bck);
02218    } else {
02219       bck->Update(bser,nser);
02220    }
02221    //
02222    // Encrypted the bucket
02223    if (cip) {
02224       if (cip->Encrypt(*bck) == 0) {
02225          DEBUG("error encrypting bucket - cipher "
02226                <<" - type: "<<XrdSutBuckStr(type));
02227          return -1;
02228       }
02229    }
02230    // We are done
02231    return 0;
02232 }
02233 
02234 //_________________________________________________________________________
02235 int XrdSecProtocolgsi::ParseClientInput(XrdSutBuffer *br, XrdSutBuffer **bm,
02236                                         String &cmsg)
02237 {
02238    // Parse received buffer b,
02239    // Result used to fill the handshake local variables
02240    EPNAME("ParseClientInput");
02241 
02242    // Space for pointer to main buffer must be already allocated
02243    if (!br || !bm) {
02244       DEBUG("invalid inputs ("<<br<<","<<bm<<")");
02245       cmsg = "invalid inputs";
02246       return -1;
02247    }
02248 
02249    //
02250    // Get the step
02251    int step = br->GetStep();
02252 
02253    // Do the right action
02254    switch (step) {
02255       case kXGS_init:
02256          // Process message
02257          if (ClientDoInit(br, bm, cmsg) != 0)
02258             return -1;
02259          break;
02260       case kXGS_cert:
02261          // Process message
02262          if (ClientDoCert(br, bm, cmsg) != 0)
02263             return -1;
02264          break;
02265       case kXGS_pxyreq:
02266          // Process message
02267          if (ClientDoPxyreq(br, bm, cmsg) != 0)
02268             return -1;
02269          break;
02270       default:
02271          cmsg = "protocol error: unknown action: "; cmsg += step;
02272          return -1;
02273          break;
02274    }
02275 
02276    // We are done
02277    return 0;
02278 }
02279 
02280 //_________________________________________________________________________
02281 int XrdSecProtocolgsi::ClientDoInit(XrdSutBuffer *br, XrdSutBuffer **bm,
02282                                     String &emsg)
02283 {
02284    // Client side: process a kXGS_init message.
02285    // Return 0 on success, -1 on error. If the case, a message is returned
02286    // in cmsg.
02287    EPNAME("ClientDoInit");
02288 
02289    //
02290    // Create the main buffer as a copy of the buffer received
02291    if (!((*bm) = new XrdSutBuffer(br->GetProtocol(),br->GetOptions()))) {
02292       emsg = "error instantiating main buffer";
02293       return -1;
02294    }
02295    //
02296    // Extract server version from options
02297    String opts = br->GetOptions();
02298    int ii = opts.find("v:");
02299    if (ii >= 0) {
02300       String sver(opts,ii+2);
02301       sver.erase(sver.find(','));
02302       hs->RemVers = atoi(sver.c_str());
02303    } else {
02304       hs->RemVers = Version;
02305       emsg = "server version information not found in options:"
02306              " assume same as local";
02307    }
02308    //
02309    // Create cache
02310    if (!(hs->Cref = new XrdSutPFEntry("c"))) {
02311       emsg = "error creating cache";
02312       return -1;
02313    }
02314    //
02315    // Save server version in cache
02316    hs->Cref->status = hs->RemVers;
02317    //
02318    // Set options
02319    hs->Options = PxyReqOpts;
02320    //
02321    // Extract list of crypto modules 
02322    String clist;
02323    ii = opts.find("c:");
02324    if (ii >= 0) {
02325       clist.assign(opts, ii+2);
02326       clist.erase(clist.find(','));
02327    } else {
02328       DEBUG("Crypto list missing: protocol error? (use defaults)");
02329       clist = DefCrypto;
02330    }
02331    // Parse the list loading the first we can
02332    if (ParseCrypto(clist) != 0) {
02333       emsg = "cannot find / load crypto requested modules :";
02334       emsg += clist;
02335       return -1;
02336    }
02337    //
02338    // Extract server certificate CA hashes
02339    String srvca;
02340    ii = opts.find("ca:");
02341    if (ii >= 0) {
02342       srvca.assign(opts, ii+3);
02343       srvca.erase(srvca.find(','));
02344    }
02345    // Parse the list loading the first we can
02346    if (ParseCAlist(srvca) != 0) {
02347       emsg = "unknown CA: cannot verify server certificate";
02348       hs->Chain = 0;
02349       return -1;
02350    }
02351    //
02352    // Resolve place-holders in cert, key and proxy file paths, if any
02353    if (XrdSutResolve(UsrCert, Entity.host, Entity.vorg, Entity.grps, Entity.name) != 0) {
02354       DEBUG("Problems resolving templates in "<<UsrCert);
02355       return -1;
02356    }
02357    if (XrdSutResolve(UsrKey, Entity.host, Entity.vorg, Entity.grps, Entity.name) != 0) {
02358       DEBUG("Problems resolving templates in "<<UsrKey);
02359       return -1;
02360    }
02361    if (XrdSutResolve(UsrProxy, Entity.host, Entity.vorg, Entity.grps, Entity.name) != 0) {
02362       DEBUG("Problems resolving templates in "<<UsrProxy);
02363       return -1;
02364    }
02365    //
02366    // Load / Attach-to user proxies
02367    ProxyIn_t pi = {UsrCert.c_str(), UsrKey.c_str(), CAdir.c_str(),
02368                    UsrProxy.c_str(), PxyValid.c_str(),
02369                    DepLength, DefBits};
02370    ProxyOut_t po = {hs->PxyChain, sessionKsig, hs->Cbck };
02371    if (QueryProxy(1, &cachePxy, "Proxy:0",
02372                   sessionCF, hs->TimeStamp, &pi, &po) != 0) {
02373       emsg = "error getting user proxies";
02374       hs->Chain = 0;
02375       return -1;
02376    }
02377    // Save the result
02378    hs->PxyChain = po.chain;
02379    hs->Cbck = po.cbck;
02380    if (!(sessionKsig = sessionCF->RSA(*(po.ksig)))) {
02381       emsg = "could not get a copy of the signing key:";
02382       hs->Chain = 0;
02383       return -1;
02384    }
02385    //
02386    // And we are done;
02387    return 0;
02388 }
02389 
02390 //_________________________________________________________________________
02391 int XrdSecProtocolgsi::ClientDoCert(XrdSutBuffer *br, XrdSutBuffer **bm,
02392                                     String &emsg)
02393 {
02394    // Client side: process a kXGS_cert message.
02395    // Return 0 on success, -1 on error. If the case, a message is returned
02396    // in cmsg.
02397    EPNAME("ClientDoCert");
02398    XrdSutBucket *bck = 0;
02399 
02400    //
02401    // make sure the cache is still there
02402    if (!hs->Cref) {
02403       emsg = "cache entry not found";
02404       hs->Chain = 0;
02405       return -1;
02406    }
02407    //
02408    // make sure is not too old
02409    int reftime = hs->TimeStamp - TimeSkew;
02410    if (hs->Cref->mtime < reftime) {
02411       emsg = "cache entry expired";
02412       // Remove: should not be checked a second time
02413       SafeDelete(hs->Cref);
02414       hs->Chain = 0;
02415       return -1;
02416    }
02417    //
02418    // Get from cache version run by server
02419    hs->RemVers = hs->Cref->status;
02420 
02421    //
02422    // Extract list of cipher algorithms supported by the server
02423    String cip = "";
02424    if ((bck = br->GetBucket(kXRS_cipher_alg))) {
02425       String ciplist;
02426       bck->ToString(ciplist);
02427       // Parse the list
02428       int from = 0;
02429       while ((from = ciplist.tokenize(cip, from, ':')) != -1) {
02430          if (cip.length() > 0) 
02431             if (sessionCF->SupportedCipher(cip.c_str()))
02432                break;
02433          cip = "";
02434       }
02435       if (cip.length() > 0)
02436          // COmmunicate to server
02437          br->UpdateBucket(cip, kXRS_cipher_alg);
02438    } else {
02439       DEBUG("WARNING: list of ciphers supported by server missing"
02440             " - using default");
02441    }
02442 
02443    //
02444    // Extract server public part for session cipher
02445    if (!(bck = br->GetBucket(kXRS_puk))) {
02446       emsg = "server public part for session cipher missing";
02447       hs->Chain = 0;
02448       return -1;
02449    }
02450    //
02451    // Initialize session cipher
02452    SafeDelete(sessionKey);
02453    if (!(sessionKey =
02454          sessionCF->Cipher(0,bck->buffer,bck->size,cip.c_str()))) {
02455             DEBUG("could not instantiate session cipher "
02456                   "using cipher public info from server");
02457             emsg = "could not instantiate session cipher ";
02458    }
02459    //
02460    // Extract server certificate
02461    if (!(bck = br->GetBucket(kXRS_x509))) {
02462       emsg = "server certificate missing";
02463       hs->Chain = 0;
02464       return -1;
02465    }
02466 
02467    //
02468    // Finalize chain: get a copy of it (we do not touch the reference)
02469    hs->Chain = new X509Chain(hs->Chain);
02470    if (!(hs->Chain)) {
02471       emsg = "cannot duplicate reference chain";
02472       return -1;
02473    }
02474    // The new chain must be deleted at destruction
02475    hs->Options |= kOptsDelChn;
02476 
02477    // Get hook to parsing function
02478    XrdCryptoX509ParseBucket_t ParseBucket = sessionCF->X509ParseBucket();
02479    if (!ParseBucket) {
02480       emsg = "cannot attach to ParseBucket function!";
02481       return -1;
02482    }
02483    // Parse bucket
02484    int nci = (*ParseBucket)(bck, hs->Chain);
02485    if (nci != 1) {
02486       emsg += nci;
02487       emsg += " vs 1 expected)";
02488       return -1;
02489    }
02490    //
02491    // Verify the chain
02492    x509ChainVerifyOpt_t vopt = { 0, hs->TimeStamp, -1, hs->Crl};
02493    XrdCryptoX509Chain::EX509ChainErr ecode = XrdCryptoX509Chain::kNone;
02494    if (!(hs->Chain->Verify(ecode, &vopt))) {
02495       emsg = "certificate chain verification failed: ";
02496       emsg += hs->Chain->LastError();
02497       return -1;
02498    }
02499    //
02500    // Verify server identity
02501    if (!ServerCertNameOK(hs->Chain->End()->Subject(), emsg)) {
02502       return -1;
02503    }
02504    //
02505    // Extract the server key
02506    sessionKver = sessionCF->RSA(*(hs->Chain->End()->PKI()));
02507    if (!sessionKver || !sessionKver->IsValid()) {
02508       emsg = "server certificate contains an invalid key";
02509       return -1;
02510    }
02511 
02512    // Deactivate what not needed any longer
02513    br->Deactivate(kXRS_puk);
02514    br->Deactivate(kXRS_x509);
02515 
02516    //
02517    // Extract list of MD algorithms supported by the server
02518    String md = "";
02519    if ((bck = br->GetBucket(kXRS_md_alg))) {
02520       String mdlist;
02521       bck->ToString(mdlist);
02522       // Parse the list
02523       int from = 0;
02524       while ((from = mdlist.tokenize(md, from, ':')) != -1) {
02525          if (md.length() > 0) 
02526             if (sessionCF->SupportedMsgDigest(md.c_str()))
02527                break;
02528          md = "";
02529       }
02530    } else {
02531       DEBUG("WARNING: list of digests supported by server missing"
02532             " - using default");
02533       md = "md5";
02534    }
02535    if (!(sessionMD = sessionCF->MsgDigest(md.c_str()))) {
02536       emsg = "could not instantiate digest object";
02537       return -1;
02538    }
02539    // Communicate choice to server
02540    br->UpdateBucket(md, kXRS_md_alg);
02541 
02542    //
02543    // Extract the main buffer (it contains the random challenge
02544    // and will contain our credentials encrypted)
02545    XrdSutBucket *bckm = 0;
02546    if (!(bckm = br->GetBucket(kXRS_main))) {
02547       emsg = "main buffer missing";
02548       return -1;
02549    }
02550 
02551    //
02552    // Deserialize main buffer
02553    if (!((*bm) = new XrdSutBuffer(bckm->buffer,bckm->size))) {
02554       emsg = "error deserializing main buffer";
02555       return -1;
02556    }
02557 
02558    //
02559    // And we are done;
02560    return 0;
02561 }
02562 
02563 //_________________________________________________________________________
02564 int XrdSecProtocolgsi::ClientDoPxyreq(XrdSutBuffer *br, XrdSutBuffer **bm,
02565                                       String &emsg)
02566 {
02567    // Client side: process a kXGS_pxyreq message.
02568    // Return 0 on success, -1 on error. If the case, a message is returned
02569    // in cmsg.
02570    XrdSutBucket *bck = 0;
02571 
02572    //
02573    // Extract the main buffer (it contains the random challenge
02574    // and will contain our credentials encrypted)
02575    XrdSutBucket *bckm = 0;
02576    if (!(bckm = br->GetBucket(kXRS_main))) {
02577       emsg = "main buffer missing";
02578       return -1;
02579    }
02580    //
02581    // Decrypt the main buffer with the session cipher, if available
02582    if (sessionKey) {
02583       if (!(sessionKey->Decrypt(*bckm))) {
02584          emsg = "error   with session cipher";
02585          return -1;
02586       }
02587    }
02588 
02589    //
02590    // Deserialize main buffer
02591    if (!((*bm) = new XrdSutBuffer(bckm->buffer,bckm->size))) {
02592       emsg = "error deserializing main buffer";
02593       return -1;
02594    }
02595 
02596    //
02597    // Check if we are ready to proces this
02598    if ((hs->Options & kOptsFwdPxy)) {
02599       // We have to send the private key of our proxy
02600       XrdCryptoX509 *pxy = 0;
02601       XrdCryptoRSA *kpxy = 0;
02602       if (!(hs->PxyChain) ||
02603           !(pxy = hs->PxyChain->End()) || !(kpxy = pxy->PKI())) {
02604          emsg = "local proxy info missing or corrupted";
02605          return 0;
02606       }
02607       // Send back the signed request as bucket
02608       String pri;
02609       if (kpxy->ExportPrivate(pri) != 0) {
02610          emsg = "problems exporting private key";
02611          return 0;
02612       }
02613       // Add it to the main list
02614       if ((*bm)->AddBucket(pri, kXRS_x509) != 0) {
02615          emsg = "problem adding bucket with private key to main buffer";
02616          return 0;
02617       }
02618    } else {
02619       // Proxy request: check if we are allowed to sign it
02620       if (!(hs->Options & kOptsSigReq)) {
02621          emsg = "Not allowed to sign proxy requests";
02622          return 0;
02623       }
02624       // Get the request
02625       if (!(bck = (*bm)->GetBucket(kXRS_x509_req))) {
02626          emsg = "bucket with proxy request missing";
02627          return 0;
02628       }
02629       XrdCryptoX509Req *req = sessionCF->X509Req(bck);
02630       if (!req) {
02631          emsg = "could not resolve proxy request";
02632          return 0;
02633       }
02634       req->SetVersion(hs->RemVers);
02635       // Get our proxy and its private key
02636       XrdCryptoX509 *pxy = 0;
02637       XrdCryptoRSA *kpxy = 0;
02638       if (!(hs->PxyChain) ||
02639           !(pxy = hs->PxyChain->End()) || !(kpxy = pxy->PKI())) {
02640          emsg = "local proxy info missing or corrupted";
02641          return 0;
02642       }
02643       // Sign the request
02644       XrdCryptoX509 *npxy = 0;
02645       if (XrdSslgsiX509SignProxyReq(pxy, kpxy, req, &npxy) != 0) {
02646          emsg = "problems signing the request";
02647          return 0;
02648       }
02649       // Send back the signed request as bucket
02650       if ((bck = npxy->Export())) {
02651          // Add it to the main list
02652          if ((*bm)->AddBucket(bck) != 0) {
02653             emsg = "problem adding signed request to main buffer";
02654             return 0;
02655          }
02656       }
02657    }
02658 
02659    //
02660    // And we are done;
02661    return 0;
02662 
02663 }
02664 
02665 //_________________________________________________________________________
02666 int XrdSecProtocolgsi::ParseServerInput(XrdSutBuffer *br, XrdSutBuffer **bm,
02667                                         String &cmsg)
02668 {
02669    // Parse received buffer b, extracting and decrypting the main 
02670    // buffer *bm and extracting the session 
02671    // cipher, random tag buckets and user name, if any.
02672    // Results used to fill the local handshake variables
02673    EPNAME("ParseServerInput");
02674 
02675    // Space for pointer to main buffer must be already allocated
02676    if (!br || !bm) {
02677       DEBUG("invalid inputs ("<<br<<","<<bm<<")");
02678       cmsg = "invalid inputs";
02679       return -1;
02680    }
02681 
02682    //
02683    // Get the step
02684    int step = br->GetStep();
02685 
02686    // Do the right action
02687    switch (step) {
02688       case kXGC_certreq:
02689          // Process message
02690          if (ServerDoCertreq(br, bm, cmsg) != 0)
02691             return -1;
02692          break;
02693       case kXGC_cert:
02694          // Process message
02695          if (ServerDoCert(br, bm, cmsg) != 0)
02696             return -1;
02697          break;
02698       case kXGC_sigpxy:
02699          // Process message
02700          if (ServerDoSigpxy(br, bm, cmsg) != 0)
02701             return -1;
02702          break;
02703       default:
02704          cmsg = "protocol error: unknown action: "; cmsg += step;
02705          return -1;
02706          break;
02707    }
02708 
02709    //
02710    // We are done
02711    return 0;
02712 }
02713 
02714 //_________________________________________________________________________
02715 int XrdSecProtocolgsi::ServerDoCertreq(XrdSutBuffer *br, XrdSutBuffer **bm,
02716                                        String &cmsg)
02717 {
02718    // Server side: process a kXGC_certreq message.
02719    // Return 0 on success, -1 on error. If the case, a message is returned
02720    // in cmsg.
02721    XrdSutBucket *bck = 0;
02722    XrdSutBucket *bckm = 0;
02723 
02724    //
02725    // Extract the main buffer 
02726    if (!(bckm = br->GetBucket(kXRS_main))) {
02727       cmsg = "main buffer missing";
02728       return -1;
02729    }
02730    //
02731    // Extract bucket with crypto module
02732    if (!(bck = br->GetBucket(kXRS_cryptomod))) {
02733       cmsg = "crypto module specification missing";
02734       return -1;
02735    }
02736    String cmod;
02737    bck->ToString(cmod);
02738    // Parse the list loading the first we can
02739    if (ParseCrypto(cmod) != 0) {
02740       cmsg = "cannot find / load crypto requested module :";
02741       cmsg += cmod;
02742       return -1;
02743    }
02744    //
02745    // Get version run by client, if there
02746    if (br->UnmarshalBucket(kXRS_version,hs->RemVers) != 0) {
02747       hs->RemVers = Version;
02748       cmsg = "client version information not found in options:"
02749              " assume same as local";
02750    } else {
02751       br->Deactivate(kXRS_version);
02752    }
02753    //
02754    // Extract bucket with client issuer hash
02755    if (!(bck = br->GetBucket(kXRS_issuer_hash))) {
02756       cmsg = "client issuer hash missing";
02757       return -1;
02758    }
02759    String cahash;
02760    bck->ToString(cahash);
02761    //
02762    // Check if we know it
02763    if (ParseCAlist(cahash) != 0) {
02764       cmsg = "unknown CA: cannot verify client credentials";
02765       return -1;
02766    }
02767    // Find our certificate in cache
02768    XrdSutPFEntry *cent = 0;
02769    if (!(cent = cacheCert.Get(sessionCF->Name()))) {
02770       cmsg = "cannot find certificate: corruption?";
02771       return -1;
02772    }
02773    // Check validity and run renewal for proxies or fail
02774    if (cent->mtime < hs->TimeStamp) {
02775       if (cent->status == kPFE_special) {
02776          // Try init proxies
02777          ProxyIn_t pi = {SrvCert.c_str(), SrvKey.c_str(), CAdir.c_str(),
02778                          UsrProxy.c_str(), PxyValid.c_str(), 0, 512};
02779          X509Chain *ch = 0;
02780          XrdCryptoRSA *k = 0;
02781          XrdSutBucket *b = 0;
02782          ProxyOut_t po = {ch, k, b };
02783          if (QueryProxy(0, &cacheCert, sessionCF->Name(),
02784                         sessionCF, hs->TimeStamp, &pi, &po) != 0) {
02785             cmsg = "proxy expired and cannot be renewed";
02786             return -1;
02787          }
02788       } else {
02789          cmsg = "certificate has expired - go and get a new one";
02790          return -1;
02791       }
02792    }
02793 
02794    // Fill some relevant handshake variables
02795    sessionKsig = sessionCF->RSA(*((XrdCryptoRSA *)(cent->buf2.buf)));
02796    hs->Cbck = (XrdSutBucket *)(cent->buf3.buf);
02797 
02798    // Create a handshake cache 
02799    if (!(hs->Cref = new XrdSutPFEntry(hs->ID.c_str()))) {
02800       cmsg = "cannot create cache entry";
02801       return -1;
02802    }
02803    //
02804    // Deserialize main buffer
02805    if (!((*bm) = new XrdSutBuffer(bckm->buffer,bckm->size))) {
02806       cmsg = "error deserializing main buffer";
02807       return -1;
02808    }
02809 
02810    // Deactivate what not need any longer
02811    br->Deactivate(kXRS_issuer_hash);
02812 
02813    //
02814    // Get options, if any
02815    if (br->UnmarshalBucket(kXRS_clnt_opts, hs->Options) == 0)
02816       br->Deactivate(kXRS_clnt_opts);
02817 
02818    //
02819    // Deserialize main buffer
02820    if (!((*bm) = new XrdSutBuffer(bckm->buffer,bckm->size))) {
02821       cmsg = "error deserializing main buffer";
02822       return -1;
02823    }
02824 
02825    // We are done
02826    return 0;
02827 }
02828 
02829 //_________________________________________________________________________
02830 int XrdSecProtocolgsi::ServerDoCert(XrdSutBuffer *br,  XrdSutBuffer **bm,
02831                                     String &cmsg)
02832 {
02833    // Server side: process a kXGC_cert message.
02834    // Return 0 on success, -1 on error. If the case, a message is returned
02835    // in cmsg.
02836    EPNAME("ServerDoCert");
02837 
02838    XrdSutBucket *bck = 0;
02839    XrdSutBucket *bckm = 0;
02840 
02841    //
02842    // Extract the main buffer 
02843    if (!(bckm = br->GetBucket(kXRS_main))) {
02844       cmsg = "main buffer missing";
02845       return -1;
02846    }
02847    //
02848    // Extract cipher algorithm chosen by the client
02849    String cip = "";
02850    if ((bck = br->GetBucket(kXRS_cipher_alg))) {
02851       bck->ToString(cip);
02852       // Parse the list
02853       if (DefCipher.find(cip) == -1) {
02854          cmsg = "unsupported cipher chosen by the client";
02855          hs->Chain = 0;
02856          return -1;
02857       }
02858       // Deactivate the bucket
02859       br->Deactivate(kXRS_cipher_alg);
02860    } else {
02861       DEBUG("WARNING: client choice for cipher missing"
02862             " - using default");
02863    }
02864 
02865    // First get the session cipher
02866    if ((bck = br->GetBucket(kXRS_puk))) {
02867       //
02868       // Cleanup
02869       SafeDelete(sessionKey);
02870       //
02871       // Prepare cipher agreement: make sure we have the reference cipher
02872       if (!hs->Rcip) {
02873          cmsg = "reference cipher missing";
02874          hs->Chain = 0;
02875          return -1;
02876       }
02877       // Prepare cipher agreement: get a copy of the reference cipher
02878       if (!(sessionKey = sessionCF->Cipher(*(hs->Rcip)))) {
02879          cmsg = "cannot get reference cipher";
02880          hs->Chain = 0;
02881          return -1;
02882       }
02883       //
02884       // Instantiate the session cipher 
02885       if (!(sessionKey->Finalize(bck->buffer,bck->size,cip.c_str()))) {
02886          cmsg = "cannot finalize session cipher";
02887          hs->Chain = 0;
02888          return -1;
02889       }
02890       //
02891       // We need it only once
02892       br->Deactivate(kXRS_puk);
02893    }
02894    //
02895    // Decrypt the main buffer with the session cipher, if available
02896    if (sessionKey) {
02897       if (!(sessionKey->Decrypt(*bckm))) {
02898          cmsg = "error decrypting main buffer with session cipher";
02899          hs->Chain = 0;
02900          return -1;
02901       }
02902    }
02903    //
02904    // Deserialize main buffer
02905    if (!((*bm) = new XrdSutBuffer(bckm->buffer,bckm->size))) {
02906       cmsg = "error deserializing main buffer";
02907       hs->Chain = 0;
02908       return -1;
02909    }
02910    //
02911    // Get version run by client, if there
02912    if (hs->RemVers == -1) {
02913       if ((*bm)->UnmarshalBucket(kXRS_version,hs->RemVers) != 0) {
02914          hs->RemVers = Version;
02915          cmsg = "client version information not found in options:"
02916                 " assume same as local";
02917       } else {
02918         (*bm)->Deactivate(kXRS_version);
02919       }
02920    }
02921 
02922    //
02923    // Get cache entry 
02924    if (!hs->Cref) {
02925       cmsg = "session cache has gone";
02926       hs->Chain = 0;
02927       return -1;
02928    }
02929    //
02930    // make sure cache is not too old
02931    int reftime = hs->TimeStamp - TimeSkew;
02932    if (hs->Cref->mtime < reftime) {
02933       cmsg = "cache entry expired";
02934       SafeDelete(hs->Cref);
02935       hs->Chain = 0;
02936       return -1;
02937    }
02938 
02939    //
02940    // Extract the client certificate
02941    if (!(bck = (*bm)->GetBucket(kXRS_x509))) {
02942       cmsg = "client certificate missing";
02943       SafeDelete(hs->Cref);
02944       hs->Chain = 0;
02945       return -1;
02946    }
02947    //
02948    // Finalize chain: get a copy of it (we do not touch the reference)
02949    hs->Chain = new X509Chain(hs->Chain);
02950    if (!(hs->Chain)) {
02951       cmsg = "cannot suplicate reference chain";
02952       return -1;
02953    }
02954    // The new chain must be deleted at destruction
02955    hs->Options |= kOptsDelChn;
02956 
02957    // Get hook to parsing function
02958    XrdCryptoX509ParseBucket_t ParseBucket = sessionCF->X509ParseBucket();
02959    if (!ParseBucket) {
02960       cmsg = "cannot attach to ParseBucket function!";
02961       return -1;
02962    }
02963    // Parse bucket
02964    int nci = (*ParseBucket)(bck, hs->Chain);
02965    if (nci < 2) {
02966       cmsg = "wrong number of certificates in received bucket (";
02967       cmsg += nci;
02968       cmsg += " > 1 expected)";
02969       return -1;
02970    }
02971    //
02972    // Verify the chain
02973    x509ChainVerifyOpt_t vopt = { 0, hs->TimeStamp, -1, hs->Crl};
02974    XrdCryptoX509Chain::EX509ChainErr ecode = XrdCryptoX509Chain::kNone;
02975    if (!(hs->Chain->Verify(ecode, &vopt))) {
02976       cmsg = "certificate chain verification failed: ";
02977       cmsg += hs->Chain->LastError();
02978       return -1;
02979    }
02980 
02981    //
02982    // Check if there will be delegated proxies; these can be through
02983    // normal request+signature, or just forwarded by the client.
02984    // In both cases we need to save the proxy chain. If we need a 
02985    // request, we have to prepare it and send it back to the client.
02986    bool needReq =
02987       ((PxyReqOpts & kOptsSrvReq) && (hs->Options & kOptsSigReq)) ||
02988        (hs->Options & kOptsDlgPxy);
02989    if (needReq || (hs->Options & kOptsFwdPxy)) {
02990       // Create a new proxy chain
02991       hs->PxyChain = new X509Chain();
02992       // Add the current proxy
02993       if ((*ParseBucket)(bck, hs->PxyChain) > 1) {
02994          // Reorder it
02995          hs->PxyChain->Reorder();
02996          if (needReq) {
02997             // Create the request
02998             XrdCryptoX509Req *rPXp = (XrdCryptoX509Req *) &(hs->RemVers);
02999             XrdCryptoRSA *krPXp = 0;
03000             if (XrdSslgsiX509CreateProxyReq(hs->PxyChain->End(), &rPXp, &krPXp) == 0) {
03001                // Save key in the cache
03002                hs->Cref->buf4.buf = (char *)krPXp;
03003                // Prepare export bucket for request
03004                XrdSutBucket *bckr = rPXp->Export();
03005                // Add it to the main list
03006                if ((*bm)->AddBucket(bckr) != 0) {
03007                   SafeDelete(hs->PxyChain);
03008                   DEBUG("WARNING: proxy req: problem adding bucket to main buffer");
03009                }
03010             } else {
03011                SafeDelete(hs->PxyChain);
03012                DEBUG("WARNING: proxy req: problem creating request");
03013             }
03014          }
03015       } else {
03016          SafeDelete(hs->PxyChain);
03017          DEBUG("WARNING: proxy req: wrong number of certificates");
03018       }
03019    }
03020 
03021    //
03022    // Extract the client public key
03023    sessionKver = sessionCF->RSA(*(hs->Chain->End()->PKI()));
03024    if (!sessionKver || !sessionKver->IsValid()) {
03025       cmsg = "server certificate contains an invalid key";
03026       return -1;
03027    }
03028    // Deactivate certificate buffer 
03029    (*bm)->Deactivate(kXRS_x509);
03030 
03031    //
03032    // Extract the MD algorithm chosen by the client
03033    String md = "";
03034    if ((bck = br->GetBucket(kXRS_md_alg))) {
03035       String mdlist;
03036       bck->ToString(md);
03037       // Parse the list
03038       if (DefMD.find(md) == -1) {
03039          cmsg = "unsupported MD chosen by the client";
03040          return -1;
03041       }
03042       // Deactivate
03043       br->Deactivate(kXRS_md_alg);
03044    } else {
03045       DEBUG("WARNING: client choice for digests missing"
03046             " - using default");
03047       md = "md5";
03048    }
03049    if (!(sessionMD = sessionCF->MsgDigest(md.c_str()))) {
03050       cmsg = "could not instantiate digest object";
03051       return -1;
03052    }
03053 
03054    // We are done
03055    return 0;
03056 }
03057 
03058 //_________________________________________________________________________
03059 int XrdSecProtocolgsi::ServerDoSigpxy(XrdSutBuffer *br,  XrdSutBuffer **bm,
03060                                       String &cmsg)
03061 {
03062    // Server side: process a kXGC_sigpxy message.
03063    // Return 0 on success, -1 on error. If the case, a message is returned
03064    // in cmsg.
03065    EPNAME("ServerDoSigpxy");
03066 
03067    XrdSutBucket *bck = 0;
03068    XrdSutBucket *bckm = 0;
03069 
03070    //
03071    // Extract the main buffer 
03072    if (!(bckm = br->GetBucket(kXRS_main))) {
03073       cmsg = "main buffer missing";
03074       return 0;
03075    }
03076    //
03077    // Decrypt the main buffer with the session cipher, if available
03078    if (sessionKey) {
03079       if (!(sessionKey->Decrypt(*bckm))) {
03080          cmsg = "error decrypting main buffer with session cipher";
03081          return 0;
03082       }
03083    }
03084    //
03085    // Deserialize main buffer
03086    if (!((*bm) = new XrdSutBuffer(bckm->buffer,bckm->size))) {
03087       cmsg = "error deserializing main buffer";
03088       return 0;
03089    }
03090 
03091    // Get the bucket
03092    if (!(bck = (*bm)->GetBucket(kXRS_x509))) {
03093       cmsg = "buffer with requested info missing";
03094       // Is there a message from the client?
03095       if (!(bck = (*bm)->GetBucket(kXRS_message))) {
03096          // Yes: decode it and print it
03097          String m;
03098          bck->ToString(m);
03099          DEBUG("msg from client: "<<m);
03100          // Add it to the main message
03101          cmsg += " :"; cmsg += m;
03102       }
03103       return 0;
03104    }
03105 
03106    // Make sure we still have the chain
03107    X509Chain *pxyc = hs->PxyChain;
03108    if (!pxyc) {
03109       cmsg = "the proxy chain is gone";
03110       return 0;
03111    }
03112 
03113    // Action depend on the type of message
03114    if ((hs->Options & kOptsFwdPxy)) {
03115       // The bucket contains a private key to be added to the proxy
03116       // public key
03117       XrdCryptoRSA *kpx = pxyc->End()->PKI();
03118       if (kpx->ImportPrivate(bck->buffer, bck->size) != 0) {
03119          cmsg = "problems importing private key";
03120          return 0;
03121       }
03122    } else {
03123       // The bucket contains our request signed by the client
03124       // The full key is in the cache 
03125       if (!hs->Cref) {
03126          cmsg = "session cache has gone";
03127          return 0;
03128       }
03129       // Get the signed certificate
03130       XrdCryptoX509 *npx = sessionCF->X509(bck);
03131       if (!npx) {
03132          cmsg = "could not resolve signed request";
03133          return 0;
03134       }
03135       // Set full PKI
03136       XrdCryptoRSA *knpx = (XrdCryptoRSA *)(hs->Cref->buf4.buf);
03137       npx->SetPKI((XrdCryptoX509data)(knpx->Opaque()));
03138       // Add the new proxy ecert to the chain
03139       pxyc->PushBack(npx);
03140    }
03141    // Save the chain in the instance
03142    proxyChain = pxyc;
03143    hs->PxyChain = 0;
03144    // Notify
03145    if (QTRACE(Authen)) { proxyChain->Dump(); }
03146 
03147    //
03148    // Extract user login name, if any
03149    String user;
03150    if ((bck = (*bm)->GetBucket(kXRS_user))) {
03151       bck->ToString(user);
03152       (*bm)->Deactivate(kXRS_user);
03153    }
03154    if (user.length() <= 0) user = Entity.name;
03155 
03156    // Dump to file if required
03157    if ((PxyReqOpts & kOptsPxFile)) {
03158       if (user.length() > 0) {
03159          String pxfile = UsrProxy, name;
03160          struct passwd *pw = getpwnam(user.c_str());
03161          if (pw) {
03162             name = pw->pw_name;
03163          } else {
03164             // Get Hash of the subject
03165             XrdCryptoX509 *c = proxyChain->SearchBySubject(proxyChain->EECname());
03166             if (c) {
03167                name = c->SubjectHash();
03168             } else {
03169                cmsg = "proxy chain not dumped to file: could not find subject hash";
03170                return 0;
03171             }
03172          }
03173          if (XrdSutResolve(pxfile, Entity.host,
03174                            Entity.vorg, Entity.grps, name.c_str()) != 0) {
03175             DEBUG("Problems resolving templates in "<<pxfile);
03176             return 0;
03177          }
03178          // Replace <uid> placeholder
03179          if (pw && pxfile.find("<uid>") != STR_NPOS) {
03180             String suid; suid += (int) pw->pw_uid;
03181             pxfile.replace("<uid>", suid.c_str());
03182          }
03183 
03184          // Get the function
03185          XrdCryptoX509ChainToFile_t ctofile = sessionCF->X509ChainToFile();
03186          if ((*ctofile)(proxyChain,pxfile.c_str()) != 0) {
03187             cmsg = "problems dumping proxy chain to file ";
03188             cmsg += pxfile;
03189             return 0;
03190          }
03191       } else {
03192          cmsg = "proxy chain not dumped to file: entity name undefined";
03193          return 0;
03194       }
03195    }
03196 
03197    // We are done
03198    return 0;
03199 }
03200 
03201 //__________________________________________________________________
03202 void XrdSecProtocolgsi::ErrF(XrdOucErrInfo *einfo, kXR_int32 ecode,
03203                              const char *msg1, const char *msg2,
03204                              const char *msg3)
03205 {
03206    // Filling the error structure
03207    EPNAME("ErrF");
03208 
03209    char *msgv[12];
03210    int k, i = 0, sz = strlen("Secgsi");
03211 
03212    //
03213    // Code message, if any
03214    int cm = (ecode >= kGSErrParseBuffer && 
03215              ecode <= kGSErrError) ? (ecode-kGSErrParseBuffer) : -1;
03216    const char *cmsg = (cm > -1) ? gGSErrStr[cm] : 0;
03217 
03218    //
03219    // Build error message array
03220               msgv[i++] = (char *)"Secgsi";     //0
03221    if (cmsg) {msgv[i++] = (char *)": ";         //1
03222               msgv[i++] = (char *)cmsg;         //2
03223               sz += strlen(msgv[i-1]) + 2;
03224              }
03225    if (msg1) {msgv[i++] = (char *)": ";         //3
03226               msgv[i++] = (char *)msg1;         //4
03227               sz += strlen(msgv[i-1]) + 2;
03228              }
03229    if (msg2) {msgv[i++] = (char *)": ";         //5
03230               msgv[i++] = (char *)msg2;         //6
03231               sz += strlen(msgv[i-1]) + 2;
03232              }
03233    if (msg3) {msgv[i++] = (char *)": ";         //7
03234               msgv[i++] = (char *)msg3;         //8
03235               sz += strlen(msgv[i-1]) + 2;
03236              }
03237 
03238    // save it (or print it)
03239    if (einfo) {
03240       einfo->setErrInfo(ecode, (const char **)msgv, i);
03241    }
03242    if (QTRACE(Debug)) {
03243       char *bout = new char[sz+10];
03244       if (bout) {
03245          bout[0] = 0;
03246          for (k = 0; k < i; k++)
03247             sprintf(bout,"%s%s",bout,msgv[k]);
03248          DEBUG(bout);
03249       } else {
03250          for (k = 0; k < i; k++)
03251             DEBUG(msgv[k]);
03252       }
03253    }
03254 }
03255 
03256 //__________________________________________________________________
03257 XrdSecCredentials *XrdSecProtocolgsi::ErrC(XrdOucErrInfo *einfo,
03258                                            XrdSutBuffer *b1,
03259                                            XrdSutBuffer *b2,
03260                                            XrdSutBuffer *b3,
03261                                            kXR_int32 ecode,
03262                                            const char *msg1,
03263                                            const char *msg2,
03264                                            const char *msg3)
03265 {
03266    // Error logging client method
03267 
03268    // Fill the error structure
03269    ErrF(einfo, ecode, msg1, msg2, msg3);
03270 
03271    // Release buffers
03272    REL3(b1,b2,b3);
03273 
03274    // We are done
03275    return (XrdSecCredentials *)0;
03276 }
03277 
03278 //__________________________________________________________________
03279 int XrdSecProtocolgsi::ErrS(String ID, XrdOucErrInfo *einfo,
03280                             XrdSutBuffer *b1, XrdSutBuffer *b2,
03281                             XrdSutBuffer *b3, kXR_int32 ecode,
03282                             const char *msg1, const char *msg2,
03283                             const char *msg3)
03284 {
03285    // Error logging server method
03286 
03287    // Fill the error structure
03288    ErrF(einfo, ecode, msg1, msg2, msg3);
03289 
03290    // Release buffers
03291    REL3(b1,b2,b3);
03292 
03293    // We are done
03294    return kgST_error;
03295 }
03296 
03297 //______________________________________________________________________________
03298 bool XrdSecProtocolgsi::CheckRtag(XrdSutBuffer *bm, String &emsg)
03299 {
03300    // Check random tag signature if it was sent with previous packet
03301    EPNAME("CheckRtag");
03302 
03303    // Make sure we got a buffer
03304    if (!bm) {
03305       emsg = "Buffer not defined";
03306       return 0;
03307    }
03308    //
03309    // If we sent out a random tag check its signature
03310    if (hs->Cref && hs->Cref->buf1.len > 0) {
03311       XrdSutBucket *brt = 0;
03312       if ((brt = bm->GetBucket(kXRS_signed_rtag))) {
03313          // Make sure we got the right key to decrypt
03314          if (!(sessionKver)) {
03315             emsg = "Session cipher undefined";
03316             return 0;
03317          }
03318          // Decrypt it with the counter part public key
03319          if (sessionKver->DecryptPublic(*brt) <= 0) {
03320             emsg = "error decrypting random tag with public key";
03321             return 0;
03322          }
03323       } else {
03324          emsg = "random tag missing - protocol error";
03325          return 0;
03326       } 
03327       //
03328       // Random tag cross-check: content
03329       if (memcmp(brt->buffer,hs->Cref->buf1.buf,hs->Cref->buf1.len)) {
03330          emsg = "random tag content mismatch";
03331          SafeDelete(hs->Cref);
03332          // Remove: should not be checked a second time
03333          return 0;
03334       }
03335       //
03336       // Reset the cache entry but we will not use the info a second time
03337       memset(hs->Cref->buf1.buf,0,hs->Cref->buf1.len);
03338       hs->Cref->buf1.SetBuf();
03339       //
03340       // Flag successful check
03341       hs->RtagOK = 1;
03342       bm->Deactivate(kXRS_signed_rtag);
03343       DEBUG("Random tag successfully checked");
03344    } else {
03345       DEBUG("Nothing to check");
03346    }
03347 
03348    // We are done
03349    return 1;
03350 }
03351 
03352 //______________________________________________________________________________
03353 int XrdSecProtocolgsi::LoadCADir(int timestamp)
03354 {
03355    // Scan cadir for valid CA certificates and load them in memory
03356    // in cache ca.
03357    // Return 0 if ok, -1 if problems
03358    EPNAME("LoadCADir");
03359 
03360    // Init cache
03361    XrdSutCache *ca = &(XrdSecProtocolgsi::cacheCA);
03362    if (!ca || ca->Init(100) != 0) {
03363       DEBUG("problems init cache for CA info");
03364       return -1;
03365    }
03366 
03367    // Some global statics
03368    String cadir;
03369    int from = 0;
03370    while ((from = CAdir.tokenize(cadir, from, ',')) != -1) {
03371       if (cadir.length() <= 0) continue;
03372 
03373       // Open directory
03374       DIR *dd = opendir(cadir.c_str());
03375       if (!dd) {
03376          DEBUG("could not open directory: "<<cadir<<" (errno: "<<errno<<")");
03377          continue;
03378       }
03379 
03380       // Read the content
03381       int i = 0;
03382       XrdCryptoX509ParseFile_t ParseFile = 0;
03383       String enam(cadir.length()+100); 
03384       struct dirent *dent = 0;
03385       while ((dent = readdir(dd))) {
03386          // entry name
03387          enam = cadir + dent->d_name;
03388          DEBUG("analysing entry "<<enam);
03389          // Try to init a chain: for each crypto factory
03390          for (i = 0; i < ncrypt; i++) {
03391             X509Chain *chain = new X509Chain();
03392             // Get the parse function
03393             ParseFile = cryptF[i]->X509ParseFile();
03394             int nci = (*ParseFile)(enam.c_str(), chain);
03395             bool ok = 0;
03396             XrdCryptoX509Crl *crl = 0;
03397             // Check what we got
03398             if (chain && nci == 1) {
03399                // Verify the CA
03400                bool verified = VerifyCA(CACheck, chain, cryptF[i]);
03401                if (verified) {
03402 
03403                   // Get CRL, if required
03404                   if (CRLCheck > 0)
03405                      crl = LoadCRL(chain->Begin(), cryptF[i]);
03406                   // Apply requirements
03407                   if (CRLCheck < 2 || crl) {
03408                      if (CRLCheck < 3 ||
03409                         (CRLCheck == 3 && crl && !(crl->IsExpired(timestamp)))) {
03410                         // Good CA
03411                         ok = 1;
03412                      } else {
03413                         DEBUG("CRL is expired (CRLCheck: "<<CRLCheck<<")");
03414                      }
03415                   } else {
03416                      DEBUG("CRL is missing (CRLCheck: "<<CRLCheck<<")");
03417                   }
03418                }
03419             }
03420             //
03421             if (ok) {
03422                // Save the chain: create the tag first
03423                String tag(chain->Begin()->SubjectHash());
03424                tag += ':';
03425                tag += cryptID[i];
03426                // Add to the cache
03427                XrdSutPFEntry *cent = ca->Add(tag.c_str());
03428                if (cent) {
03429                   cent->buf1.buf = (char *)chain;
03430                   cent->buf1.len = 0;      // Just a flag
03431                   if (crl) {
03432                      cent->buf2.buf = (char *)crl;
03433                      cent->buf2.len = 0;      // Just a flag
03434                   }
03435                   cent->mtime = timestamp;
03436                   cent->status = kPFE_ok;
03437                   cent->cnt = 0;
03438                }
03439             } else {
03440                DEBUG("Entry "<<enam<<" does not contain a valid CA");
03441                if (chain)
03442                   chain->Cleanup();
03443                SafeDelete(chain);
03444                SafeDelete(crl);
03445             }
03446          }
03447       }
03448       // Close dir
03449       closedir(dd);
03450    }
03451 
03452    // Rehash cache
03453    ca->Rehash(1);
03454 
03455    // We are done
03456    return 0;
03457 }
03458 
03459 //______________________________________________________________________________
03460 XrdCryptoX509Crl *XrdSecProtocolgsi::LoadCRL(XrdCryptoX509 *xca,
03461                                              XrdCryptoFactory *CF)
03462 {
03463    // Scan crldir for a valid CRL certificate associated to CA whose
03464    // certificate is xca. If the CRL is found and is valid according
03465    // to the chosen option, return its content in a X509Crl object.
03466    // Return 0 in any other case
03467    EPNAME("LoadCRL");
03468    XrdCryptoX509Crl *crl = 0;
03469 
03470    // make sure we got what we need
03471    if (!xca || !CF) {
03472       DEBUG("Invalid inputs");
03473       return crl;
03474    }
03475 
03476    // Get the signing certificate
03477    bool verify = 1;
03478    XrdCryptoX509 *xcasig = xca;
03479    while (xcasig && strcmp(xcasig->Issuer(), xcasig->Subject())) {
03480       String crldir;
03481       int from = 0;
03482       while ((from = CRLdir.tokenize(crldir, from, ',')) != -1) {
03483          if (crldir.length() <= 0) continue;
03484          String casigfile = crldir + xcasig->IssuerHash();
03485          // Try to get the certificate
03486          if ((xcasig = CF->X509(casigfile.c_str()))) break;
03487       }
03488    }
03489    if (!xcasig) {
03490       verify = 0;
03491       if (CACheck == 2) {
03492          DEBUG("CA certificate to verify the signature could not be loaded - exit");
03493          return crl;
03494       } else if (CACheck == 1) {
03495          DEBUG("CA certificate to verify the signature could not be loaded - verification skipped");
03496       }
03497    }
03498 
03499    // Get the CA hash
03500    String cahash = xca->SubjectHash();
03501    // Drop the extension (".0")
03502    String caroot(cahash, 0, cahash.find(".0")-1);
03503 
03504    // The dir
03505    String crlext = XrdSecProtocolgsi::DefCRLext;
03506 
03507    String crldir;
03508    int from = 0;
03509    while ((from = CRLdir.tokenize(crldir, from, ',')) != -1) {
03510       if (crldir.length() <= 0) continue;
03511       // Add the default CRL extension and the dir
03512       String crlfile = crldir + caroot;
03513       crlfile += crlext;
03514       DEBUG("target file: "<<crlfile);
03515       // Try to init a crl
03516       if ((crl = CF->X509Crl(crlfile.c_str()))) {
03517          if (verify) {
03518             // Verify issuer
03519             if (!(strcmp(crl->Issuer(),xcasig->Subject()))) {
03520                // Verify signature
03521                if (crl->Verify(xcasig)) {
03522                   // Ok, we are done
03523                   return crl;
03524                }
03525             }
03526          } else {
03527             // Ok, we are done
03528             return crl;
03529          }
03530       }
03531       SafeDelete(crl);
03532    }
03533 
03534    // If not required, we are done
03535    if (CRLCheck < 2) {
03536       // Done
03537       return crl;
03538    }
03539 
03540    // If in 'required' mode, we will also try to load the CRL from the
03541    // information found in the CA certificate or in the certificate directory.
03542    // To avoid this overload, the CRL information should be installed offline, e.g. with
03543    // utils/getCRLcert
03544 
03545    // Try to retrieve it from the URI in the CA certificate, if any
03546    if ((crl = CF->X509Crl(xca))) {
03547       if (verify) {
03548          // Verify issuer
03549          if (!(strcmp(crl->Issuer(),xcasig->Subject()))) {
03550             // Verify signature
03551             if (crl->Verify(xcasig)) {
03552                // Ok, we are done
03553                return crl;
03554             }
03555          }
03556       } else {
03557          // Ok, we are done
03558          return crl;
03559       }
03560    }
03561 
03562    // Finally try the ".crl_url" file
03563    from = 0;
03564    while ((from = CRLdir.tokenize(crldir, from, ',')) != -1) {
03565       if (crldir.length() <= 0) continue;
03566       SafeDelete(crl);
03567       String crlurl = crldir + caroot;
03568       crlurl += ".crl_url";
03569       DEBUG("target file: "<<crlurl);
03570       FILE *furl = fopen(crlurl.c_str(), "r");
03571       if (!furl) {
03572          DEBUG("could not open file: "<<crlurl);
03573          continue;
03574       }
03575       char line[2048];
03576       while ((fgets(line, sizeof(line), furl))) {
03577          if (line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = 0;
03578          if ((crl = CF->X509Crl(line, 1))) {
03579             if (verify) {
03580                // Verify issuer
03581                if (!(strcmp(crl->Issuer(),xcasig->Subject()))) {
03582                   // Verify signature
03583                   if (crl->Verify(xcasig)) {
03584                      // Ok, we are done
03585                      return crl;
03586                   }
03587                }
03588             } else {
03589                // Ok, we are done
03590                return crl;
03591             }
03592          }
03593       }
03594    }
03595 
03596    // We need to parse the full dirs: make some cleanup first
03597    from = 0;
03598    while ((from = CRLdir.tokenize(crldir, from, ',')) != -1) {
03599       if (crldir.length() <= 0) continue;
03600       SafeDelete(crl);
03601       // Open directory
03602       DIR *dd = opendir(crldir.c_str());
03603       if (!dd) {
03604          DEBUG("could not open directory: "<<crldir<<" (errno: "<<errno<<")");
03605          continue;
03606       }
03607       // Read the content
03608       struct dirent *dent = 0;
03609       while ((dent = readdir(dd))) {
03610          // Do not analyse the CA certificate
03611          if (!strcmp(cahash.c_str(),dent->d_name)) continue;
03612          // File name contain the root CA hash
03613          if (!strstr(dent->d_name,caroot.c_str())) continue;
03614          // candidate name
03615          String crlfile = crldir + dent->d_name;
03616          DEBUG("analysing entry "<<crlfile);
03617          // Try to init a crl
03618          crl = CF->X509Crl(crlfile.c_str());
03619          if (!crl) continue;
03620          if (verify) {
03621             // Verify issuer
03622             if (strcmp(crl->Issuer(),xca->Subject())) {
03623                SafeDelete(crl);
03624                continue;
03625             }
03626             // Verify signature
03627             if (!(crl->Verify(xca))) {
03628                SafeDelete(crl);
03629                continue;
03630             }
03631          }
03632          // Ok
03633          break;
03634       }
03635       // Close dir
03636       closedir(dd);
03637       // Are we done?
03638       if (crl) break;
03639    }
03640 
03641    // We are done
03642    return crl;
03643 }
03644 //______________________________________________________________________________
03645 String XrdSecProtocolgsi::GetCApath(const char *cahash)
03646 {
03647    // Look in the paths defined by CAdir for the certificate file related to
03648    // 'cahash', in the form <CAdir_entry>/<cahash>.0
03649 
03650    String path;
03651    String ent;
03652    int from = 0;
03653    while ((from = CAdir.tokenize(ent, from, ',')) != -1) {
03654       if (ent.length() > 0) {
03655          path = ent;
03656          if (!path.endswith('/'))
03657             path += "/";
03658          path += cahash;
03659          if (!path.endswith(".0"))
03660             path += ".0";
03661          if (!access(path.c_str(), R_OK))
03662             break;
03663       }
03664       path = "";
03665    }
03666 
03667    // Done
03668    return path;
03669 }
03670 //______________________________________________________________________________
03671 bool XrdSecProtocolgsi::VerifyCA(int opt, X509Chain *cca, XrdCryptoFactory *CF)
03672 {
03673    // Verify the CA in 'cca' according to 'opt':
03674    //   opt = 2    full check
03675    //         1    only if self-signed
03676    //         0    no check
03677    EPNAME("VerifyCA");
03678 
03679    bool verified = 0;
03680    XrdCryptoX509Chain::ECAStatus st = XrdCryptoX509Chain::kUnknown;
03681    cca->SetStatusCA(st);
03682 
03683    // We nust have got a chain
03684    if (!cca) {
03685       DEBUG("Invalid input ");
03686       return 0;
03687    }
03688 
03689    // Get the parse function
03690    XrdCryptoX509ParseFile_t ParseFile = CF->X509ParseFile();
03691    if (!ParseFile) {
03692       DEBUG("Cannot attach to the ParseFile function");
03693       return 0;
03694    }
03695 
03696    // Point to the certificate
03697    XrdCryptoX509 *xc = cca->Begin();
03698    // Is it self-signed ?
03699    bool self = (!strcmp(xc->IssuerHash(), xc->SubjectHash())) ? 1 : 0;
03700    if (!self) {
03701       String inam;
03702       if (opt == 2) {
03703          // We are requested to verify it
03704          bool notdone = 1;
03705          // We need to load the issuer(s) CA(s)
03706          XrdCryptoX509 *xd = xc;
03707          while (notdone) {
03708             inam = GetCApath(xd->IssuerHash());
03709             if (inam.length() <= 0) break;
03710             X509Chain *ch = new X509Chain();
03711             int ncis = (*ParseFile)(inam.c_str(), ch);
03712             if (ncis < 1) break;
03713             XrdCryptoX509 *xi = ch->Begin();
03714             while (xi) {
03715                if (!strcmp(xd->IssuerHash(), xi->SubjectHash()))
03716                   break;
03717                xi = ch->Next();
03718             }
03719             if (xi) {
03720                // Add the certificate to the requested CA chain
03721                ch->Remove(xi);
03722                cca->PutInFront(xi);
03723                SafeDelete(ch);
03724                // We may be over
03725                if (!strcmp(xi->IssuerHash(), xi->SubjectHash())) {
03726                   notdone = 0;
03727                   break;
03728                } else {
03729                   // This becomes the daughter
03730                   xd = xi;
03731                }
03732             } else {
03733                break;
03734             }
03735          }
03736          if (!notdone) {
03737             // Verify the chain
03738             X509Chain::EX509ChainErr e;
03739             verified = cca->Verify(e);
03740          } else {
03741             PRINT("CA certificate not self-signed: cannot verify integrity ("<<xc->SubjectHash()<<")");
03742          }
03743       } else {
03744          // Fill CA information
03745          cca->CheckCA(0);
03746          // Set OK in any case
03747          verified = 1;
03748          // Notify if some sort of check was required
03749          if (opt == 1) {
03750             DEBUG("Warning: CA certificate not self-signed:"
03751                   " integrity not checked, assuming OK ("<<xc->SubjectHash()<<")");
03752          }
03753       }
03754    } else if (CACheck > 0) {
03755       // Check self-signature
03756       verified = cca->CheckCA();
03757    }
03758 
03759    // Set the status in the chain
03760    st = (verified) ? XrdCryptoX509Chain::kValid : st;
03761    cca->SetStatusCA(st);
03762 
03763    // Done
03764    return verified;
03765 }
03766 
03767 //______________________________________________________________________________
03768 int XrdSecProtocolgsi::GetCA(const char *cahash)
03769 {
03770    // Gets entry for CA with hash cahash for crypt factory cryptF[ic].
03771    // If not found in cache, try loading from <CAdir>/<cahash>.0 .
03772    // Return 0 if ok, -1 if not available, -2 if CRL not ok
03773    EPNAME("GetCA");
03774 
03775    // We nust have got a CA hash
03776    if (!cahash) {
03777       DEBUG("Invalid input ");
03778       return -1;
03779    }
03780 
03781    // The tag
03782    String tag(cahash,20);
03783    tag += ':';
03784    tag += sessionCF->ID();
03785    DEBUG("Querying cache for tag: "<<tag);
03786 
03787    // Try first the cache
03788    XrdSutPFEntry *cent = cacheCA.Get(tag.c_str());
03789 
03790    // If found, we are done
03791    if (cent) {
03792       hs->Chain = (X509Chain *)(cent->buf1.buf);
03793       hs->Crl = (XrdCryptoX509Crl *)(cent->buf2.buf);
03794       return 0;
03795    }
03796 
03797    // If not, prepare the file name
03798    String fnam = GetCApath(cahash);
03799    DEBUG("trying to load CA certificate from "<<fnam);
03800 
03801    // Create chain
03802    hs->Chain = new X509Chain();
03803    if (!hs->Chain ) {
03804       DEBUG("could not create new GSI chain");
03805       return -1;
03806    }
03807 
03808    // Get the parse function
03809    XrdCryptoX509ParseFile_t ParseFile = sessionCF->X509ParseFile();
03810    if (ParseFile) {
03811       int nci = (*ParseFile)(fnam.c_str(), hs->Chain);
03812       bool ok = 0, verified = 0;
03813       if (nci == 1) {
03814          // Verify the CA
03815          verified = VerifyCA(CACheck, hs->Chain, sessionCF);
03816 
03817          if (verified) {
03818             // Get CRL, if required
03819             if (CRLCheck > 0)
03820                hs->Crl = LoadCRL(hs->Chain->Begin(), sessionCF);
03821             // Apply requirements
03822             if (CRLCheck < 2 || hs->Crl) {
03823                if (CRLCheck < 3 ||
03824                   (CRLCheck == 3 &&
03825                   hs->Crl && !(hs->Crl->IsExpired(hs->TimeStamp)))) {
03826                   // Good CA
03827                   ok = 1;
03828                } else {
03829                   DEBUG("CRL is expired (CRLCheck: "<<CRLCheck<<")");
03830                }
03831             } else {
03832                DEBUG("CRL is missing (CRLCheck: "<<CRLCheck<<")");
03833             }
03834          }
03835          //
03836          if (ok) {
03837             // Add to the cache
03838             cent = cacheCA.Add(tag.c_str());
03839             if (cent) {
03840                cent->buf1.buf = (char *)(hs->Chain);
03841                cent->buf1.len = 0;      // Just a flag
03842                if (hs->Crl) {
03843                   cent->buf2.buf = (char *)(hs->Crl);
03844                   cent->buf2.len = 0;      // Just a flag
03845                }
03846                cent->mtime = hs->TimeStamp;
03847                cent->status = kPFE_ok;
03848                cent->cnt = 0;
03849             }
03850          } else {
03851             return -2;
03852          }
03853       } else {
03854          DEBUG("certificate not found or invalid (nci: "<<nci<<", CA: "<<
03855                (int)(verified)<<")");
03856          return -1;
03857       }
03858    }
03859 
03860    // Rehash cache
03861    cacheCA.Rehash(1);
03862 
03863    // We are done
03864    return 0;
03865 }
03866 
03867 //______________________________________________________________________________
03868 int XrdSecProtocolgsi::InitProxy(ProxyIn_t *pi, X509Chain *ch, XrdCryptoRSA **kp)
03869 {
03870    // Invoke 'grid-proxy-init' via the shell to create a valid the proxy file
03871    // If the variable GLOBUS_LOCATION is defined it prepares the external shell
03872    // by sourcing $GLOBUS_LOCATION/etc/globus-user-env.sh .
03873    // Return 0 in cse of success, != 0 in any other case .
03874    EPNAME("InitProxy");
03875    int rc = 0;
03876 
03877    // We must be able to get an answer
03878    if (isatty(0) == 0 || isatty(1) == 0) {
03879       DEBUG("Not a tty: cannot prompt for proxies - do nothing ");
03880       return -1;
03881    }
03882 
03883 #ifndef HASGRIDPROXYINIT
03884    //
03885    // Use internal function for proxy initialization
03886    //
03887    // Make sure we got a chain and a key to fill
03888    if (!ch || !kp) {
03889       DEBUG("chain or key container undefined");
03890       return -1;
03891    }
03892    //
03893    // Validity
03894    int valid = (pi->valid) ? XrdSutParseTime(pi->valid, 1) : -1;
03895    //
03896    // Options
03897    XrdProxyOpt_t pxopt = {pi->bits,    // bits in key
03898                           valid,       // duration validity in secs
03899                           pi->deplen}; // signature path depth
03900    //
03901    // Init now
03902    rc = XrdSslgsiX509CreateProxy(pi->cert, pi->key, &pxopt,
03903                                  ch, kp, pi->out);
03904 #else
03905    // command string
03906    String cmd(kMAXBUFLEN);
03907 
03908    // Check if GLOBUS_LOCATION is defined
03909    if (getenv("GLOBUS_LOCATION"))
03910       cmd = "source $GLOBUS_LOCATION/etc/globus-user-env.sh;";
03911 
03912    // Add main command
03913    cmd += " grid-proxy-init";
03914 
03915    // Add user cert
03916    cmd += " -cert ";
03917    cmd += pi->cert;
03918 
03919    // Add user key
03920    cmd += " -key ";
03921    cmd += pi->key;
03922 
03923    // Add CA dir (no support for multi-dirs)
03924    String cdir(pi->certdir);
03925    cdir.erase(cdir.find(','));
03926    cmd += " -certdir ";
03927    cmd += cdir;
03928 
03929    // Add validity
03930    if (pi->valid) {
03931       cmd += " -valid ";
03932       cmd += pi->valid;
03933    }
03934 
03935    // Add number of bits in key
03936    if (pi->bits > 512) {
03937       cmd += " -bits ";
03938       cmd += pi->bits;
03939    }
03940 
03941    // Add depth of signature path
03942    if (pi->deplen > -1) {
03943       cmd += " -path-length ";
03944       cmd += pi->deplen;
03945    }
03946 
03947    // Add output proxy coordinates
03948    if (pi->out) {
03949       cmd += " -out ";
03950       cmd += pi->out;
03951    }
03952    // Notify
03953    DEBUG("executing: " << cmd);
03954 
03955    // Execute
03956    rc = system(cmd.c_str());
03957    DEBUG("return code: "<< rc << " (0x"<<(int *)rc<<")");
03958 #endif
03959 
03960    // We are done
03961    return rc;
03962 }
03963 
03964 //__________________________________________________________________________
03965 int XrdSecProtocolgsi::ParseCAlist(String calist)
03966 {
03967    // Parse received ca list, find the first available CA in the list
03968    // and return a chain initialized with such a CA.
03969    // If nothing found return 0.
03970    EPNAME("ParseCAlist");
03971 
03972    // Check inputs
03973    if (calist.length() <= 0) {
03974       DEBUG("nothing to parse");
03975       return -1;
03976    }
03977    DEBUG("parsing list: "<<calist);
03978  
03979    // Load module and define relevant pointers
03980    hs->Chain = 0;
03981    String cahash = "";
03982    // Parse list
03983    if (calist.length()) {
03984       int from = 0;
03985       while ((from = calist.tokenize(cahash, from, '|')) != -1) {
03986          // Check this hash
03987          if (cahash.length()) {
03988             // Get the CA chain
03989             if (GetCA(cahash.c_str()) == 0)
03990                return 0;
03991          }
03992       }
03993    }
03994 
03995    // We did not find it
03996    return -1;
03997 }
03998 
03999 //__________________________________________________________________________
04000 int XrdSecProtocolgsi::ParseCrypto(String clist)
04001 {
04002    // Parse crypto list clist, extracting the first available module
04003    // and getting a related local cipher and a related reference
04004    // cipher to be used to agree the session cipher; the local lists
04005    // crypto info is updated, if needed
04006    // The results are used to fill the handshake part of the protocol
04007    // instance.
04008    EPNAME("ParseCrypto");
04009 
04010    // Check inputs
04011    if (clist.length() <= 0) {
04012       DEBUG("empty list: nothing to parse");
04013       return -1;
04014    }
04015    DEBUG("parsing list: "<<clist);
04016  
04017    // Load module and define relevant pointers
04018    hs->CryptoMod = "";
04019 
04020    // Parse list
04021    int from = 0;
04022    while ((from = clist.tokenize(hs->CryptoMod, from, '|')) != -1) {
04023       // Check this module
04024       if (hs->CryptoMod.length() > 0) {
04025          DEBUG("found module: "<<hs->CryptoMod);
04026          // Load the crypto factory
04027          if ((sessionCF = 
04028               XrdCryptoFactory::GetCryptoFactory(hs->CryptoMod.c_str()))) {
04029             sessionCF->SetTrace(GSITrace->What);
04030             int fid = sessionCF->ID();
04031             int i = 0;
04032             // Retrieve the index in local table
04033             while (i < ncrypt) {
04034                if (cryptID[i] == fid) break;
04035                i++;
04036             }
04037             if (i >= ncrypt) {
04038                if (ncrypt == XrdCryptoMax) {
04039                   DEBUG("max number of crypto slots reached - do nothing");
04040                   return 0;
04041                } else {
04042                   // Add new entry
04043                   cryptF[i] = sessionCF;
04044                   cryptID[i] = fid;
04045                   ncrypt++;
04046                }
04047             }
04048             // On servers the ref cipher should be defined at this point
04049             hs->Rcip = refcip[i];
04050             // we are done
04051             return 0;
04052          }
04053       }
04054    }
04055 
04056    // Nothing found
04057    return -1;
04058 }
04059 
04060 //__________________________________________________________________________
04061 int XrdSecProtocolgsi::QueryProxy(bool checkcache, XrdSutCache *cache,
04062                                   const char *tag, XrdCryptoFactory *cf,
04063                                   int timestamp, ProxyIn_t *pi, ProxyOut_t *po)
04064 {
04065    // Query users proxies, initializing if needed
04066    EPNAME("QueryProxy");
04067 
04068    bool hasproxy = 0;
04069    // We may already loaded valid proxies
04070    XrdSutPFEntry *cent = 0;
04071    if (checkcache) {
04072       cent = cache->Get(tag);
04073       if (cent && cent->buf1.buf) {
04074          //
04075          po->chain = (X509Chain *)(cent->buf1.buf);
04076          // Check validity of the entry found (it may have expired)
04077          if (po->chain->CheckValidity(1, timestamp) == 0) {
04078             po->ksig = (XrdCryptoRSA *)(cent->buf2.buf);
04079             po->cbck = (XrdSutBucket *)(cent->buf3.buf);
04080             hasproxy = 1;
04081             return 0;
04082          } else {
04083             // Cleanup the chain
04084             po->chain->Cleanup();
04085             // Cleanup cache entry
04086             cent->buf1.buf = 0;
04087             cent->buf1.len = 0;
04088             // The key is deleted by the certificate destructor
04089             // Just reset the buffer
04090             cent->buf2.buf = 0;
04091             cent->buf2.len = 0;
04092             // and the related bucket
04093             if (cent->buf3.buf)
04094                delete (XrdSutBucket *)(cent->buf3.buf);
04095             cent->buf3.buf = 0;
04096             cent->buf3.len = 0;
04097          }
04098       }
04099    }
04100 
04101    //
04102    // We do not have good proxies, try load (user may have initialized
04103    // them in the meanwhile)
04104    // Create a new chain first, if needed
04105    if (!(po->chain))
04106       po->chain = new X509Chain();
04107    if (!(po->chain)) {
04108       DEBUG("cannot create new chain!");
04109       return -1;
04110    }
04111    int ntry = 3;
04112    bool parsefile = 1;
04113    bool exportbucket = 0;
04114    XrdCryptoX509ParseFile_t ParseFile = 0;
04115    XrdCryptoX509ParseBucket_t ParseBucket = 0;
04116    while (!hasproxy && ntry > 0) {
04117 
04118       // Try init as last option
04119       if (ntry == 1) {
04120 
04121          // Cleanup the chain
04122          po->chain->Cleanup();
04123 
04124          if (InitProxy(pi, po->chain, &(po->ksig)) != 0) {
04125             DEBUG("problems initializing proxy via external shell");
04126             ntry--;
04127             continue;
04128          }
04129          // We need to explicitely export the proxy in a bucket
04130          exportbucket = 1;
04131 #ifndef HASGRIDPROXYINIT
04132          // Chain is already loaded if we used the internal function
04133          // to initialize the proxies
04134          parsefile = 0;
04135          timestamp = (int)(time(0));
04136 #endif
04137       }
04138       ntry--;
04139 
04140       //
04141       // A proxy chain may have been passed via XrdSecCREDS: check that first
04142       if (ntry == 2) {
04143 
04144          char *cbuf = getenv("XrdSecCREDS");
04145          if (cbuf) {
04146             // Import into a bucket
04147             po->cbck = new XrdSutBucket(0, 0, kXRS_x509);
04148             // Fill bucket
04149             po->cbck->SetBuf(cbuf, strlen(cbuf));
04150             // Parse the bucket
04151             if (!(ParseBucket = cf->X509ParseBucket())) {
04152                DEBUG("cannot attach to ParseBucket function!");
04153                continue;
04154             }
04155             int nci = (*ParseBucket)(po->cbck, po->chain);
04156             if (nci < 2) {
04157                DEBUG("proxy bucket must have at least two certificates"
04158                      " (found: "<<nci<<")");
04159                continue;
04160             }
04161          } else {
04162             // No env: parse the file
04163             ntry--;
04164          }
04165       }
04166       if (ntry == 1) {
04167          if (parsefile) {
04168             if (!ParseFile) {
04169                if (!(ParseFile = cf->X509ParseFile())) {
04170                   DEBUG("cannot attach to ParseFile function!");
04171                   continue;
04172                }
04173             }
04174             // Parse the proxy file
04175             int nci = (*ParseFile)(pi->out, po->chain);
04176             if (nci < 2) {
04177                DEBUG("proxy files must have at least two certificates"
04178                      " (found: "<<nci<<")");
04179                continue;
04180             }
04181             // Check if any CA was in the file
04182             bool checkselfsigned = (CACheck > 1) ? 1 : 0;
04183             po->chain->CheckCA(checkselfsigned);
04184             exportbucket = 1;
04185          }
04186       }
04187 
04188       // Check validity in time
04189       if (po->chain->CheckValidity(1, timestamp) != 0) {
04190          DEBUG("proxy files contains expired certificates");
04191          continue;
04192       }
04193 
04194       // Reorder chain
04195       if (po->chain->Reorder() != 0) {
04196          DEBUG("proxy files contains inconsistent certificates");
04197          continue;
04198       }
04199 
04200       // Check key
04201       po->ksig = po->chain->End()->PKI();
04202       if (po->ksig->status != XrdCryptoRSA::kComplete) {
04203          DEBUG("proxy files contain invalid key pair");
04204          continue;
04205       }
04206 
04207       XrdCryptoX509ExportChain_t ExportChain = cf->X509ExportChain();
04208       if (!ExportChain) {
04209          DEBUG("cannot attach to ExportChain function!");
04210          continue;
04211       }
04212 
04213       // Create bucket for export
04214       if (exportbucket) {
04215          po->cbck = (*ExportChain)(po->chain, 0);
04216          if (!(po->cbck)) {
04217             DEBUG("could not create bucket for export");
04218             continue;
04219          }
04220       }
04221 
04222       // Get attach an entry in cache
04223       if (!(cent = cache->Add(tag))) {
04224          DEBUG("could not create entry in cache");
04225          continue;
04226       }
04227 
04228       // Save info in cache
04229       cent->mtime = po->chain->End()->NotAfter(); // the expiring time
04230       cent->status = kPFE_special;  // distinguish from normal certs
04231       cent->cnt = 0;
04232       // The chain
04233       cent->buf1.buf = (char *)(po->chain);
04234       cent->buf1.len = 0;      // Just a flag
04235       // The key
04236       cent->buf2.buf = (char *)(po->chain->End()->PKI());
04237       cent->buf2.len = 0;      // Just a flag
04238       // The export bucket
04239       cent->buf3.buf = (char *)(po->cbck);
04240       cent->buf3.len = 0;      // Just a flag
04241 
04242       // Rehash cache
04243       cache->Rehash(1);
04244 
04245       // Set the positive flag
04246       hasproxy = 1;
04247    }
04248 
04249    // We are done
04250    if (!hasproxy) {
04251       // Some cleanup
04252       po->chain->Cleanup();
04253       SafeDelete(po->chain);
04254       SafeDelete(po->cbck);
04255       return -1;
04256    }
04257    return 0;
04258 }
04259 
04260 //__________________________________________________________________________
04261 int XrdSecProtocolgsi::LoadGMAP(int now)
04262 {
04263    // Load cache for gridmap entries with current content of the gridmap file.
04264    // The cache content is loaded only if the file was modified since last
04265    // access.
04266    // Returns 0 if successful, -1 if somethign went wrong
04267    EPNAME("LoadGMAP");
04268 
04269    // Time of last check
04270    static int lastCheck = -1;
04271 
04272    // We need a file to load
04273    if (GMAPFile.length() <= 0)
04274       return 0;
04275 
04276    // Get info about last time of modification
04277    struct stat st;
04278    if (stat(GMAPFile.c_str(), &st) != 0) {
04279       PRINT("error 'stat'-ing file "<<GMAPFile);
04280       return -1;
04281    }
04282 
04283    // Check against current time
04284    if (lastCheck > st.st_mtime)
04285       // Nothing to do
04286       return 0;
04287 
04288    // Init or reset the cache
04289    if (cacheGMAP.Empty()) {
04290       if (cacheGMAP.Init(100) != 0) {
04291          PRINT("error initializing cache");
04292          return -1;
04293       }
04294    } else {
04295       if (cacheGMAP.Reset() != 0) {
04296          PRINT("error resetting cache");
04297          return -1;
04298       }
04299    }
04300 
04301    // Open the file
04302    FILE *fm = fopen(GMAPFile.c_str(),"r");
04303    if (!fm) {
04304       PRINT("error opening file "<<GMAPFile);
04305       return -1;
04306    }
04307 
04308    // Read entries now
04309    char line[2048] = {0};
04310    while (fgets(line,sizeof(line),fm)) {
04311       // Skip comment line
04312       if (line[0] == '#') continue;
04313       // Get rid of \n
04314       if (line[strlen(line)-1] == '\n')
04315          line[strlen(line)-1] = 0;
04316       // Extract DN
04317       char *p0 = (line[0] == '"') ? &line[1] : &line[0];
04318       int l0 = 0;
04319       while (p0[l0] != '"')
04320           l0++;
04321       String udn(p0, l0);
04322       p0 = (p0 + l0 + 1);
04323       while (*p0 == ' ')
04324           p0++;
04325 
04326       // Extract username
04327       String usr(p0);
04328 
04329       // Notify
04330       DEBUG("Found: udn: "<<udn<<", usr: "<<usr);
04331 
04332       // Ok: save it into the cache
04333       XrdSutPFEntry *cent = cacheGMAP.Add(udn.c_str());
04334       if (cent) {
04335          cent->status = kPFE_ok;
04336          cent->cnt = 0;
04337          cent->mtime = now; // creation time
04338          // Add username
04339          SafeFree(cent->buf1.buf);
04340          cent->buf1.buf = strdup(usr.c_str());
04341          cent->buf1.len = usr.length();
04342       }
04343    }
04344    fclose(fm);
04345 
04346    // Rehash cache
04347    cacheGMAP.Rehash(1);
04348 
04349    // Save the time
04350    lastCheck = now;
04351 
04352    // We are done
04353    return 0;
04354 }
04355 
04356 //__________________________________________________________________________
04357 void XrdSecProtocolgsi::QueryGMAP(XrdCryptoX509Chain *chain, int now, String &usrs)
04358 {
04359    // Resolve usernames associated with this proxy. The lookup is typically
04360    // based on the 'dn' (either in the grid mapfile or via the 'GMAPFun' plugin) but
04361    // it can also be based on the full proxy via the AuthzFun plugin.
04362    // For 'grid mapfile' and 'GMAPFun' the result is kept valid for a certain amount
04363    // of time, hashed on the 'dn'.
04364    // On return, an empty string in 'usrs' indicates failure.
04365    // Note that 'usrs' can be a comma-separated list of usernames. 
04366    EPNAME("QueryGMAP");
04367 
04368    // List of user names attached to the entity
04369    usrs = "";
04370 
04371    // The chain must be defined
04372    if (!chain) {
04373       PRINT("input chain undefined!");
04374       return;
04375    }
04376 
04377    // We chaeck the authorization plugin first, if any. This excludes any other check.
04378    if (AuthzFun) {
04379       // We export the full proxy and give it to the external plugin, so
04380       // that it can take the decision using whatever it needs (including, e.g.,
04381       // VOMS information).
04382       // We do not use any cache in this case
04383       XrdSutBucket *bucket = XrdCryptosslX509ExportChain(chain, true);
04384       XrdOucString s;
04385       bucket->ToString(s);
04386       delete bucket;
04387       char *name = (*AuthzFun)(s.c_str(), now);
04388       if (name) {
04389          usrs = name;
04390          delete [] name;
04391       }
04392       // Empty string means failure (not-authorized, ...)
04393       return;
04394    }
04395 
04396    // Now we check the DN-mapping function and eventually the gridmap file.
04397    // The result can be cached for a while. 
04398    XrdSutPFEntry *cent = 0;
04399    const char *dn = chain->EECname();
04400    if (GMAPFun) {
04401       // We may have it in the cache
04402       cent = cacheGMAPFun.Get(dn);
04403       // Check expiration, if required
04404       if (GMAPCacheTimeOut > 0 &&
04405          (cent && (now - cent->mtime) > GMAPCacheTimeOut)) {
04406          // Invalidate the entry
04407          cacheGMAPFun.Remove(dn);
04408          cent = 0;
04409       }
04410       // Run the search via the external function
04411       if (!cent) {
04412          char *name = (*GMAPFun)(dn, now);
04413          if ((cent = cacheGMAPFun.Add(dn))) {
04414             if (name) {
04415                cent->status = kPFE_ok;
04416                // Add username
04417                SafeFree(cent->buf1.buf);
04418                cent->buf1.buf = name;
04419                cent->buf1.len = strlen(name);
04420             } else {
04421                // We cache the resul to avoid repeating the search
04422                cent->status = kPFE_allowed;
04423             }
04424             // Fill up the rest
04425             cent->cnt = 0;
04426             cent->mtime = now; // creation time
04427             // Rehash cache
04428             cacheGMAPFun.Rehash(1);
04429          }
04430       }
04431       // This means that the previous search did not return success
04432       if (cent && (cent->status != kPFE_ok))
04433          cent = 0;
04434    }
04435 
04436    // Save the result, if any
04437    if (cent)
04438       usrs = (const char *)(cent->buf1.buf);
04439 
04440    // Try also the map file, if any
04441    if (LoadGMAP(now) != 0) {
04442       DEBUG("error loading/ refreshing grid map file");
04443       return;
04444    }
04445 
04446    // Lookup for 'dn' in the cache
04447    cent = cacheGMAP.Get(dn);
04448 
04449    // Add / Save the result, if any
04450    if (cent) {
04451       if (usrs.length() > 0) usrs += ",";
04452       usrs += (const char *)(cent->buf1.buf);
04453    }
04454 
04455    // Done
04456    return;
04457 }
04458 
04459 //_____________________________________________________________________________
04460 XrdSecgsiGMAP_t XrdSecProtocolgsi::LoadGMAPFun(const char *plugin,
04461                                                const char *parms)
04462 {
04463    // Load the DN-Username mapping function from the specified plug-in
04464    EPNAME("LoadGMAPFun");
04465 
04466    // Make sure the input config file is defined
04467    if (!plugin || strlen(plugin) <= 0) {
04468       PRINT("plug-in file undefined");
04469       return (XrdSecgsiGMAP_t)0;
04470    }
04471 
04472    // Create the plug-in instance
04473    if (!(GMAPPlugin = new XrdSysPlugin(&XrdSecProtocolgsi::eDest, plugin))) {
04474       PRINT("could not create plugin instance for "<<plugin);
04475       return (XrdSecgsiGMAP_t)0;
04476    }
04477 
04478    // Use global symbols?
04479    bool useglobals = 0;
04480    XrdOucString params, ps(parms), p;
04481    int from = 0;
04482    while ((from = ps.tokenize(p, from, '|')) != -1) {
04483       if (p == "useglobals") {
04484          useglobals = 1;
04485       } else {
04486          if (params.length() > 0) params += " ";
04487          params += p;
04488       }
04489    }
04490    DEBUG("params: '"<< params<<"'; useglobals: "<<useglobals);
04491 
04492    // Get the function
04493    XrdSecgsiGMAP_t ep = 0;
04494    if (useglobals) {
04495       ep = (XrdSecgsiGMAP_t) GMAPPlugin->getPlugin("XrdSecgsiGMAPFun", 0, true);
04496    } else {
04497       ep = (XrdSecgsiGMAP_t) GMAPPlugin->getPlugin("XrdSecgsiGMAPFun");
04498    }
04499    if (!ep) {
04500       PRINT("could not find 'XrdSecgsiGMAPFun()' in "<<plugin);
04501       return (XrdSecgsiGMAP_t)0;
04502    }
04503 
04504    // Init it
04505    if ((*ep)(params.c_str(), 0) == (char *)-1) {
04506       PRINT("could not initialize 'XrdSecgsiGMAPFun()'");
04507       return (XrdSecgsiGMAP_t)0;
04508    }
04509 
04510    // Notify
04511    PRINT("using 'XrdSecgsiGMAPFun()' from "<<plugin);
04512 
04513    // Done
04514    return ep;
04515 }
04516 
04517 //_____________________________________________________________________________
04518 XrdSecgsiAuthz_t XrdSecProtocolgsi::LoadAuthzFun(const char *plugin,
04519                                              const char *parms)
04520 {  
04521    // Load the authorization function from the specified plug-in
04522    EPNAME("LoadAuthzFun");
04523    
04524    // Make sure the input config file is defined
04525    if (!plugin || strlen(plugin) <= 0) {
04526       PRINT("plug-in file undefined");
04527       return (XrdSecgsiAuthz_t)0;
04528    }
04529    
04530    // Create the plug-in instance
04531    if (!(AuthzPlugin = new XrdSysPlugin(&XrdSecProtocolgsi::eDest, plugin))) {
04532       PRINT("could not create plugin instance for "<<plugin);
04533       return (XrdSecgsiAuthz_t)0;
04534    }
04535 
04536    // Use global symbols?
04537    bool useglobals = 0;
04538    XrdOucString params, ps(parms), p;
04539    int from = 0;
04540    while ((from = ps.tokenize(p, from, '|')) != -1) {
04541       if (p == "useglobals") {
04542          useglobals = 1;
04543       } else {
04544          if (params.length() > 0) params += " ";
04545          params += p;
04546       }
04547    }
04548    DEBUG("params: '"<< params<<"'; useglobals: "<<useglobals);
04549 
04550    // Get the function
04551    XrdSecgsiAuthz_t ep = 0;
04552    if (useglobals)
04553       ep = (XrdSecgsiAuthz_t) AuthzPlugin->getPlugin("XrdSecgsiAuthzFun", 0, true);
04554    else
04555       ep = (XrdSecgsiAuthz_t) AuthzPlugin->getPlugin("XrdSecgsiAuthzFun");
04556    if (!ep) {
04557       PRINT("could not find 'XrdSecgsiAuthzFun()' in "<<plugin);
04558       return (XrdSecgsiAuthz_t)0;
04559    }
04560    
04561    // Init it
04562    if ((*ep)(params.c_str(), 0) == (char *)-1) {
04563       PRINT("could not initialize 'XrdSecgsiGMAPFun()'");
04564       return (XrdSecgsiAuthz_t)0;
04565    }
04566    
04567    // Notify
04568    PRINT("using 'XrdSecgsiAuthzFun()' from "<<plugin);
04569    
04570    // Done
04571    return ep;
04572 }
04573 
04574 //_____________________________________________________________________________
04575 bool XrdSecProtocolgsi::ServerCertNameOK(const char *subject, XrdOucString &emsg)
04576 {
04577    // Check that the server certificate subject name is consistent with the
04578    // expectations defined by the static SrvAllowedNames
04579 
04580    // The subject must be defined
04581    if (!subject || strlen(subject) <= 0) return 0;
04582 
04583    bool allowed = 0;
04584    emsg = "";
04585 
04586    // The server subject and its CN
04587    String srvsubj(subject);
04588    String srvcn;
04589    int cnidx = srvsubj.find("CN=");
04590    if (cnidx != STR_NPOS) srvcn.assign(srvsubj, cnidx + 3);
04591 
04592    // Always check if the server CN is in the standard form "[*/]<target host name>[/*]"
04593    if (Entity.host) {
04594       if (srvcn != (const char *) Entity.host) {
04595          int ih = srvcn.find((const char *) Entity.host);
04596          if (ih == 0 || (ih > 0 && srvcn[ih-1] == '/')) {
04597             ih += strlen(Entity.host);
04598             if (ih >= srvcn.length() ||
04599                 srvcn[ih] == '\0' || srvcn[ih] == '/') allowed = 1;
04600          }
04601       } else {
04602          allowed = 1;
04603       }
04604       // Update the error msg, if the case
04605       if (!allowed) {
04606          if (emsg.length() <= 0) {
04607             emsg = "server certificate CN '"; emsg += srvcn;
04608             emsg += "' does not match the expected format(s):";
04609          }
04610          String defcn("[*/]"); defcn += Entity.host; defcn += "[/*]";
04611          emsg += " '"; emsg += defcn; emsg += "' (default)";
04612       }
04613    }
04614 
04615    // Take into account specif requests, if any
04616    if (SrvAllowedNames.length() > 0) {
04617       // The SrvAllowedNames string contains the allowed formats separated by a '|'.
04618       // The specifications can contain the <host> or <fqdn> placeholders which
04619       // are replaced by Entity.host; they can also contain the '*' wildcard, in
04620       // which case XrdOucString::matches is used. A '-' before the specification
04621       // will deny the matching CN's; the last matching wins.
04622       String allowedfmts(SrvAllowedNames);
04623       allowedfmts.replace("<host>", (const char *) Entity.host);
04624       allowedfmts.replace("<fqdn>", (const char *) Entity.host);
04625       int from = 0;
04626       String fmt;
04627       while ((from = allowedfmts.tokenize(fmt, from, '|')) != -1) {
04628          // Check if this should be denied
04629          bool deny = 0;
04630          if (fmt.beginswith("-")) {
04631             deny = 1;
04632             fmt.erasefromstart(1);
04633          }
04634          if (srvcn.matches(fmt.c_str()) > 0) allowed = (deny) ? 0 : 1;
04635       }
04636       // Update the error msg, if the case
04637       if (!allowed) {
04638          if (emsg.length() <= 0) {
04639             emsg = "server certificate CN '"; emsg += srvcn;
04640             emsg += "' does not match the expected format:";
04641          }
04642          emsg += " '"; emsg += SrvAllowedNames; emsg += "' (exceptions)";
04643       }
04644    }
04645    // Reset error msg, if the match was successful
04646    if (allowed)
04647       emsg = "";
04648    else
04649       emsg += "; exceptions are controlled by the env XrdSecGSISRVNAMES";
04650 
04651    // Done
04652    return allowed;
04653 }
04654 

Generated on Tue Jul 5 14:46:59 2011 for ROOT_528-00b_version by  doxygen 1.5.1