diff --git a/src/XrdCrypto/XrdCryptosslX509Crl.cc b/src/XrdCrypto/XrdCryptosslX509Crl.cc index 609e14f234c..c0d7223e1d4 100644 --- a/src/XrdCrypto/XrdCryptosslX509Crl.cc +++ b/src/XrdCrypto/XrdCryptosslX509Crl.cc @@ -350,7 +350,6 @@ int XrdCryptosslX509Crl::LoadCache() // Load relevant info into the cache // Return 0 if ok, -1 in case of error EPNAME("LoadCache"); - XrdSutCacheRef pfeRef; // The CRL must exists if (!crl) { @@ -381,12 +380,6 @@ int XrdCryptosslX509Crl::LoadCache() return 0; } - // Init cache - if (cache.Init(nrevoked) != 0) { - DEBUG("problems init cache for CRL info"); - return -1; - } - // Get serial numbers of revoked certificates char *tagser = 0; int i = 0; @@ -404,22 +397,23 @@ int XrdCryptosslX509Crl::LoadCache() TRACE(Dump, "certificate with serial number: "<mtime = XrdCryptosslASN1toUTC(X509_REVOKED_get0_revocationDate(rev)); + // Set status + cent->mtime = kCE_ok; // Release the string for the serial number OPENSSL_free(tagser); + // Unlock the entry + cent->rwmtx.UnLock(); } } - // rehash the cache - pfeRef.UnLock(); // Prevent lock inversion (though it doesn't matter here) - cache.Rehash(1); - return 0; } @@ -550,7 +544,6 @@ bool XrdCryptosslX509Crl::IsRevoked(int serialnumber, int when) // Check if certificate with serialnumber is in the // list of revocated certificates EPNAME("IsRevoked"); - XrdSutCacheRef pfeRef; // Reference time int now = (when > 0) ? when : time(0); @@ -571,13 +564,15 @@ bool XrdCryptosslX509Crl::IsRevoked(int serialnumber, int when) sprintf(tagser,"%x",serialnumber); // Look into the cache - XrdSutPFEntry *cent = cache.Get(pfeRef, (const char *)tagser); - if (cent) { + XrdSutCacheEntry *cent = cache.Get((const char *)tagser); + if (cent && cent->status == kCE_ok) { // Check the revocation time if (now > cent->mtime) { DEBUG("certificate "<rwmtx.UnLock(); return 1; } + cent->rwmtx.UnLock(); } // Certificate not revoked @@ -590,7 +585,6 @@ bool XrdCryptosslX509Crl::IsRevoked(const char *sernum, int when) // Check if certificate with 'sernum' is in the // list of revocated certificates EPNAME("IsRevoked"); - XrdSutCacheRef pfeRef; // Reference time int now = (when > 0) ? when : time(0); @@ -607,13 +601,15 @@ bool XrdCryptosslX509Crl::IsRevoked(const char *sernum, int when) } // Look into the cache - XrdSutPFEntry *cent = cache.Get(pfeRef, (const char *)sernum); - if (cent) { + XrdSutCacheEntry *cent = cache.Get((const char *)sernum); + if (cent && cent->status == kCE_ok) { // Check the revocation time if (now > cent->mtime) { DEBUG("certificate "<rwmtx.UnLock(); return 1; } + cent->rwmtx.UnLock(); } // Certificate not revoked diff --git a/src/XrdCrypto/XrdCryptosslX509Crl.hh b/src/XrdCrypto/XrdCryptosslX509Crl.hh index 0b282437407..6537d9dd2f9 100644 --- a/src/XrdCrypto/XrdCryptosslX509Crl.hh +++ b/src/XrdCrypto/XrdCryptosslX509Crl.hh @@ -45,7 +45,6 @@ // // ---------------------------------------------------------------------------// -class XrdSutCache; class XrdCryptoX509; class XrdCryptosslX509Crl : public XrdCryptoX509Crl { diff --git a/src/XrdSecgsi/XrdSecProtocolgsi.cc b/src/XrdSecgsi/XrdSecProtocolgsi.cc index 6cde2fd8ecb..b88620c5ecf 100644 --- a/src/XrdSecgsi/XrdSecProtocolgsi.cc +++ b/src/XrdSecgsi/XrdSecProtocolgsi.cc @@ -49,7 +49,6 @@ #include "XrdOuc/XrdOucEnv.hh" #include "XrdSut/XrdSutAux.hh" -#include "XrdSut/XrdSutCache.hh" #include "XrdCrypto/XrdCryptoMsgDigest.hh" #include "XrdCrypto/XrdCryptoX509Req.hh" @@ -172,20 +171,15 @@ String XrdSecProtocolgsi::cryptName[XrdCryptoMax] = {0}; // their names XrdCryptoCipher *XrdSecProtocolgsi::refcip[XrdCryptoMax] = {0}; // ref for session ciphers // // Caches -XrdSutCache XrdSecProtocolgsi::cacheCA; // CA info -XrdSutCache XrdSecProtocolgsi::cacheCert; // Server certificates info -XrdSutCache XrdSecProtocolgsi::cachePxy; // Client proxies -XrdSutCache XrdSecProtocolgsi::cacheGMAP; // Grid map entries -XrdSutCache XrdSecProtocolgsi::cacheGMAPFun; // Entries mapped by GMAPFun -XrdSutCache XrdSecProtocolgsi::cacheAuthzFun; // Entities filled by AuthzFun +XrdSutCache XrdSecProtocolgsi::cacheCA; // Server certificates info cache (default size 144) +XrdSutCache XrdSecProtocolgsi::cacheCert(8,13); // Server certificates info cache (Fibonacci-based sizes) +XrdSutCache XrdSecProtocolgsi::cachePxy(8,13); // Client proxies cache (Fibonacci-based sizes) +XrdSutCache XrdSecProtocolgsi::cacheGMAPFun; // Entries mapped by GMAPFun (default size 144) +XrdSutCache XrdSecProtocolgsi::cacheAuthzFun; // Entities filled by AuthzFun (default size 144) // // Services XrdOucGMap *XrdSecProtocolgsi::servGMap = 0; // Grid map service // -// CA and CRL stacks -GSIStack XrdSecProtocolgsi::stackCA; // Stack of CA in use -GSIStack XrdSecProtocolgsi::stackCRL; // Stack of CRL in use -// // GMAP control vars time_t XrdSecProtocolgsi::lastGMAPCheck = -1; // Time of last check XrdSysMutex XrdSecProtocolgsi::mutexGMAP; // Mutex to control GMAP reloads @@ -566,13 +560,6 @@ char *XrdSecProtocolgsi::Init(gsiOptions opt, XrdOucErrInfo *erp) return Parms; } // - // Init CA info cache - if (cacheCA.Init(100) != 0) { - ErrF(erp,kGSErrError,"problems initializing CA info cache"); - PRINT(erp->getErrText()); - return Parms; - } - // // List of supported / wanted ciphers if (opt.cipher) DefCipher = opt.cipher; @@ -637,36 +624,25 @@ char *XrdSecProtocolgsi::Init(gsiOptions opt, XrdOucErrInfo *erp) if (access(SrvKey.c_str(), R_OK)) { PRINT("WARNING: process has no permission to read the certificate key file: "<getErrText()); - return Parms; - } int i = 0; String certcalist = ""; // list of CA for server certificates - XrdSutCacheRef pfeRef; + XrdSutCERef ceref; for (; igetErrText()); return Parms; } - if (QTRACE(Authen)) { cacheCert.Dump(); } DEBUG("CA list: "<getErrText()); - return Parms; - } - } else { - if (cacheGMAPFun.Reset() != 0) { - PRINT("Error resetting GMAPFun cache"); - ErrF(erp, kGSErrError, "Internal cache for the GMAP plug-in failed to reset"); - PRINT(erp->getErrText()); - return Parms; - } - } } } // @@ -777,20 +738,6 @@ char *XrdSecProtocolgsi::Init(gsiOptions opt, XrdOucErrInfo *erp) } else { NOTIFY("authzfun: proxy certificate format: unknown (code: "<getErrText()); - return Parms; - } - } else { - if (cacheAuthzFun.Reset() != 0) { - ErrF(erp, kGSErrError, "Internal cache for authz plug-in failed to reset"); - PRINT(erp->getErrText()); - return Parms; - } - } // Expiration of Authz related cache entries if (opt.authzto > 0) { AuthzCacheTimeOut = opt.authzto; @@ -909,22 +856,6 @@ char *XrdSecProtocolgsi::Init(gsiOptions opt, XrdOucErrInfo *erp) // // Client specific options if (!Server) { - // - // Init cache for CA certificate info. Clients will fill it - // upon need - if (cacheCA.Init(100) != 0) { - ErrF(erp,kGSErrError,"problems init cache for CA info"); - PRINT(erp->getErrText()); - return Parms; - } - // - // Init cache for proxies (in the future we may allow - // users to use more certificates, depending on the context) - if (cachePxy.Init(2) != 0) { - ErrF(erp,kGSErrError,"problems init cache for proxies"); - PRINT(erp->getErrText()); - return Parms; - } // use default dir $(HOME)/. struct passwd *pw = getpwuid(getuid()); if (!pw) { @@ -1610,6 +1541,32 @@ XrdSecCredentials *XrdSecProtocolgsi::getCredentials(XrdSecParameters *parm, /******************************************************************************/ /* S e r v e r O r i e n t e d M e t h o d s */ /******************************************************************************/ + +//_____________________________________________________________________________ +static bool AuthzFunCheck(XrdSutCacheEntry *e, void *a) { + + int st_ref = (*((XrdSutCacheArg_t *)a)).arg1; + time_t ts_ref = (time_t)(*((XrdSutCacheArg_t *)a)).arg2; + long to_ref = (*((XrdSutCacheArg_t *)a)).arg3; + int st_exp = (*((XrdSutCacheArg_t *)a)).arg4; + + if (e) { + // Check expiration, if required + bool expired = 0; + if (to_ref > 0 && (ts_ref - e->mtime) > to_ref) expired = 1; + int notafter = *((int *) e->buf2.buf); + if (to_ref > notafter) expired = 1; + + if (expired || (e->status != st_ref)) { + // Invalidate the entry, if the case + e->status = st_exp; + } else { + return true; + } + } + return false; +} + /******************************************************************************/ /* A u t h e n t i c a t e */ /******************************************************************************/ @@ -1622,7 +1579,6 @@ int XrdSecProtocolgsi::Authenticate(XrdSecCredentials *cred, // Check if we have any credentials or if no credentials really needed. // In either case, use host name as client name EPNAME("Authenticate"); - XrdSutCacheRef pfeRef; // // If cred buffer is two small or empty assume host protocol @@ -1895,56 +1851,51 @@ int XrdSecProtocolgsi::Authenticate(XrdSecCredentials *cred, const char *dn = (const char *)key; time_t now = hs->TimeStamp; // We may have it in the cache - XrdSutPFEntry *cent = cacheAuthzFun.Get(pfeRef, dn); - // Check expiration, if required - if (cent) { - bool expired = 0; - if (AuthzCacheTimeOut > 0 && (now - cent->mtime) > AuthzCacheTimeOut) expired = 1; - int notafter = *((int *) cent->buf2.buf); - if (now > notafter) expired = 1; - // Invalidate the entry, if the case - if (expired) { + XrdSutCERef ceref; + bool rdlock = false; + XrdSutCacheArg_t arg = {kCE_ok, now, AuthzCacheTimeOut, kCE_disabled}; + XrdSutCacheEntry *cent = cacheAuthzFun.Get(dn, rdlock, AuthzFunCheck, (void *) &arg); + if (!cent) { + // Fatal error + kS_rc = kgST_error; + PRINT("ERROR: unable to get cache entry for dn: "<rwmtx)); + if (!rdlock) { + if (cent->buf1.buf) FreeEntity((XrdSecEntity *) cent->buf1.buf); - SafeDelete(cent->buf1.buf); - SafeDelete(cent->buf2.buf); - cent->status = kPFE_disabled; // Prevent use after unlock! - pfeRef.UnLock(); // Discarding cent! - cacheAuthzFun.Remove(dn); - cent = 0; - } + SafeDelete(cent->buf1.buf); + SafeDelete(cent->buf2.buf); } - if (!cent || (cent && (cent->status != kPFE_ok))) { + if (cent->status != kCE_ok) { int authzrc = 0; if ((authzrc = (*AuthzFun)(Entity)) != 0) { // Error kS_rc = kgST_error; PRINT("ERROR: the authorization plug-in reported a failure for this handshake"); SafeDelete(key); + ceref.UnLock(); break; } else { - if ((cent = cacheAuthzFun.Add(pfeRef, dn))) { - cent->status = kPFE_ok; - // Save a copy of the relevant Entity fields - XrdSecEntity *se = new XrdSecEntity(); - int slen = 0; - CopyEntity(&Entity, se, &slen); - FreeEntity((XrdSecEntity *) cent->buf1.buf); - SafeDelete(cent->buf1.buf); - cent->buf1.buf = (char *) se; - cent->buf1.len = slen; - // Proxy expiration time - int notafter = hs->Chain->End() ? hs->Chain->End()->NotAfter() : -1; - cent->buf2.buf = (char *) new int(notafter); - cent->buf2.len = sizeof(int); - // Fill up the rest - cent->cnt = 0; - cent->mtime = now; // creation time - // Rehash cache - pfeRef.UnLock(); // cent can no longer be used - cacheAuthzFun.Rehash(1); - // Notify - DEBUG("Saved Entity to cacheAuthzFun ("<status = kCE_ok; + // Save a copy of the relevant Entity fields + XrdSecEntity *se = new XrdSecEntity(); + int slen = 0; + CopyEntity(&Entity, se, &slen); + FreeEntity((XrdSecEntity *) cent->buf1.buf); + SafeDelete(cent->buf1.buf); + cent->buf1.buf = (char *) se; + cent->buf1.len = slen; + // Proxy expiration time + int notafter = hs->Chain->End() ? hs->Chain->End()->NotAfter() : -1; + cent->buf2.buf = (char *) new int(notafter); + cent->buf2.len = sizeof(int); + // Fill up the rest + cent->cnt = 0; + cent->mtime = now; // creation time + // Notify + DEBUG("Saved Entity to cacheAuthzFun ("<TimeStamp, cadum); + XrdSutCacheEntry *cent = GetSrvCertEnt(ceref, sessionCF, hs->TimeStamp, cadum); if (!cent) { cmsg = "cannot find certificate: corruption?"; return -1; @@ -3374,6 +3327,7 @@ int XrdSecProtocolgsi::ServerDoCertreq(XrdSutBuffer *br, XrdSutBuffer **bm, // Fill some relevant handshake variables sessionKsig = sessionCF->RSA(*((XrdCryptoRSA *)(cent->buf2.buf))); hs->Cbck = new XrdSutBucket(*((XrdSutBucket *)(cent->buf3.buf))); + ceref.UnLock(); // Create a handshake cache if (!(hs->Cref = new XrdSutPFEntry(hs->ID.c_str()))) { @@ -4235,6 +4189,44 @@ bool XrdSecProtocolgsi::VerifyCA(int opt, X509Chain *cca, XrdCryptoFactory *CF) return verified; } +//_____________________________________________________________________________ +static bool GetCACheck(XrdSutCacheEntry *e, void *a) { + + EPNAME("GetCACheck"); + + int crl_check = (*((XrdSutCacheArg_t *)a)).arg1; + int crl_refresh = (*((XrdSutCacheArg_t *)a)).arg2; + time_t ts_ref = (time_t)(*((XrdSutCacheArg_t *)a)).arg3; + + if (!e) return false; + + X509Chain *chain = 0; + // If we had already something, check it, as we may be done + bool goodca = 0; + if ((chain = (X509Chain *)(e->buf1.buf))) { + // Check the validity of the certificates in the chain; if a certificate became invalid, + // we need to reload a valid one for the same CA. + if (chain->CheckValidity() == 0) { + goodca = 1; + } else { + PRINT("CA entry for '"<name<<"' needs refreshing: clean the related entry cache first"); + return false; + } + } + if (goodca) { + XrdCryptoX509Crl *crl = (XrdCryptoX509Crl *)(e->buf2.buf); + bool goodcrl = 1; + if ((crl_check == 2 && !crl) || (crl_check == 3 && crl->IsExpired())) goodcrl = 0; + if (crl_refresh > 0 && ((ts_ref - e->mtime) > crl_refresh)) goodcrl = 0; + if (goodcrl) { + return true; + } else if (crl) { + PRINT("CRL entry for '"<name<<"' needs refreshing: clean the related entry cache first ("<rwmtx)); - X509Chain *chain = 0; - // If found, we are done - if (cent) { - bool goodca = 0; - if ((chain = (X509Chain *)(cent->buf1.buf))) { - // Check the validity of the certificates in the chain; if a certificate became invalid, - // we need to reload a valid one for the same CA. - if (chain->CheckValidity() == 0) { - goodca = 1; - if (hs) hs->Chain = chain; - // Add to the stack for proper cleaning of invalidated CAs - stackCA.Add(chain); - } else { - PRINT("CA entry for '"<buf1.buf = 0; - if (!cacheCA.Remove(tag.c_str())) { - PRINT("problems removing entry from CA cache"); - rc = -1; - } - } - } - if (rc == 0) { - XrdCryptoX509Crl *crl = (XrdCryptoX509Crl *)(cent->buf2.buf); - bool goodcrl = (crl) ? 1 : 0; - if (goodcrl && CRLCheck >= 3 && crl->IsExpired()) goodcrl = 0; - if (goodcrl && CRLRefresh > 0 && ((timestamp - cent->mtime) > CRLRefresh)) goodcrl = 0; - // If the CA is not good, we reload the CRL in any case - if (goodca && goodcrl) { - if (hs) hs->Crl = crl; - // Add to the stack for proper cleaning of invalidated CRLs - stackCRL.Add(crl); - pfeRef.UnLock(); - return 0; - } else if (crl) { - PRINT("CRL entry for '"<buf2.buf = 0; - } - } - chain = 0; - } else { - if (!(cent = cacheCA.Add(pfeRef, tag.c_str()))) { - PRINT("could not create a cache entry for this CA (" << tag <<")"); - rc = -1; - } + // Point to the content + X509Chain *chain = (X509Chain *)(cent->buf1.buf); + XrdCryptoX509Crl *crl = (XrdCryptoX509Crl *)(cent->buf2.buf); + + // If invalid we fail + if (cent->status == kCE_inactive) { + // Cleanup and remove existing invalid entries + if (chain) delete chain; + if (crl) delete crl; + PRINT("unable to get a valid entry from cache for " << tag); + return -1; } - // - // If any failure, return - if (rc != 0) { - pfeRef.UnLock(); - return rc; + // Check if we are done + if (rdlock) { + // Save chain + chain = (X509Chain *)(cent->buf1.buf); + if (hs) hs->Chain = chain; + // Save crl + if (crl && hs) hs->Crl = crl; + // Done + return 0; } + // Cleanup and remove existing invalid entries + if (chain) delete chain; + if (crl) delete crl; + + chain = 0; + crl = 0; + cent->buf1.buf = 0; + cent->buf2.buf = 0; + // If not, prepare the file name String fnam = GetCApath(cahash); DEBUG("trying to load CA certificate from "<buf2.buf = (char *)(crl); cent->buf2.len = 0; // Just a flag - stackCRL.Add(crl); } cent->mtime = timestamp; - cent->status = kPFE_ok; + cent->status = kCE_ok; cent->cnt = 0; // Fill output, if required if (hs) { @@ -4388,18 +4359,19 @@ int XrdSecProtocolgsi::GetCA(const char *cahash, } } else { SafeDelete(crl); + SafeDelete(chain); rc = -2; } } else { + SafeDelete(chain); NOTIFY("certificate not found or invalid (nci: "<buf1.buf); + if (chain->CheckValidity(1, ts_ref) == 0) return true; + } + return false; +} + + //__________________________________________________________________________ int XrdSecProtocolgsi::QueryProxy(bool checkcache, XrdSutCache *cache, const char *tag, XrdCryptoFactory *cf, @@ -4625,45 +4610,45 @@ int XrdSecProtocolgsi::QueryProxy(bool checkcache, XrdSutCache *cache, { // Query users proxies, initializing if needed EPNAME("QueryProxy"); - XrdSutCacheRef pfeRef; + XrdSutCERef ceref; bool hasproxy = 0; // We may already loaded valid proxies - XrdSutPFEntry *cent = 0; - if (checkcache) { - cent = cache->Get(pfeRef, tag); - if (cent && cent->buf1.buf) { - // - po->chain = (X509Chain *)(cent->buf1.buf); - // Check validity of the entry found (it may have expired) - if (po->chain->CheckValidity(1, timestamp) == 0) { - po->ksig = (XrdCryptoRSA *)(cent->buf2.buf); - po->cbck = (XrdSutBucket *)(cent->buf3.buf); - hasproxy = 1; - return 0; - } else { - // Cleanup the chain - po->chain->Cleanup(); - // Cleanup cache entry - cent->buf1.buf = 0; - cent->buf1.len = 0; - // The key is deleted by the certificate destructor - // Just reset the buffer - cent->buf2.buf = 0; - cent->buf2.len = 0; - // and the related bucket - if (cent->buf3.buf) - delete (XrdSutBucket *)(cent->buf3.buf); - cent->buf3.buf = 0; - cent->buf3.len = 0; - } - } + bool rdlock = false; + XrdSutCacheArg_t arg = {timestamp, -1, -1, -1}; + XrdSutCacheEntry *cent = cache->Get(tag, rdlock, QueryProxyCheck, (void *) &arg); + if (!cent) { + PRINT("cannot get cache entry for: "<rwmtx)); - // This is the last use of cent so we should remove the lock prior to - // entry the proxy refresh loop if we have a valid pointer. - // - if (cent) {cent = 0; pfeRef.UnLock();} + if (checkcache && rdlock) { + po->chain = (X509Chain *)(cent->buf1.buf); + po->ksig = (XrdCryptoRSA *)(cent->buf2.buf); + po->cbck = (XrdSutBucket *)(cent->buf3.buf); + // We are done + ceref.UnLock(); + return 0; + } + + // Cleanup the chain + po->chain = (X509Chain *)(cent->buf1.buf); + if (po->chain) po->chain->Cleanup(); + SafeDelete(po->chain); + + // Cleanup cache entry + cent->buf1.buf = 0; + cent->buf1.len = 0; + // The key is deleted by the certificate destructor + // Just reset the buffer + cent->buf2.buf = 0; + cent->buf2.len = 0; + // and the related bucket + if (cent->buf3.buf) + delete (XrdSutBucket *)(cent->buf3.buf); + cent->buf3.buf = 0; + cent->buf3.len = 0; // // We do not have good proxies, try load (user may have initialized @@ -4786,15 +4771,9 @@ int XrdSecProtocolgsi::QueryProxy(bool checkcache, XrdSutCache *cache, } } - // Get attach an entry in cache - if (!(cent = cache->Add(pfeRef, tag))) { - PRINT("could not create entry in cache"); - continue; - } - // Save info in cache cent->mtime = po->chain->End()->NotAfter(); // the expiring time - cent->status = kPFE_special; // distinguish from normal certs + cent->status = kCE_special; // distinguish from normal certs cent->cnt = 0; // The chain cent->buf1.buf = (char *)(po->chain); @@ -4805,15 +4784,12 @@ int XrdSecProtocolgsi::QueryProxy(bool checkcache, XrdSutCache *cache, // The export bucket cent->buf3.buf = (char *)(po->cbck); cent->buf3.len = 0; // Just a flag - pfeRef.UnLock(); - - // Rehash cache - pfeRef.UnLock(); // cent can no longer be used - cache->Rehash(1); // Set the positive flag hasproxy = 1; } + // Always unlock + ceref.UnLock(); // We are done if (!hasproxy) { @@ -4826,6 +4802,26 @@ int XrdSecProtocolgsi::QueryProxy(bool checkcache, XrdSutCache *cache, return 0; } + +//_____________________________________________________________________________ +static bool QueryGMAPCheck(XrdSutCacheEntry *e, void *a) { + int st_ref = (*((XrdSutCacheArg_t *)a)).arg1; + time_t ts_ref = (time_t)(*((XrdSutCacheArg_t *)a)).arg2; + long to_ref = (*((XrdSutCacheArg_t *)a)).arg3; + if (e) { + // Check expiration, if required + if ((e->status != st_ref) || + ((e->status == st_ref) && + (to_ref > 0) && + ((ts_ref - e->mtime) > to_ref))) { + return false; + } else { + return true; + } + } + return false; +} + //__________________________________________________________________________ void XrdSecProtocolgsi::QueryGMAP(XrdCryptoX509Chain *chain, int now, String &usrs) { @@ -4837,7 +4833,6 @@ void XrdSecProtocolgsi::QueryGMAP(XrdCryptoX509Chain *chain, int now, String &us // On return, an empty string in 'usrs' indicates failure. // Note that 'usrs' can be a comma-separated list of usernames. EPNAME("QueryGMAP"); - XrdSutCacheRef pfeRef; // List of user names attached to the entity usrs = ""; @@ -4850,45 +4845,37 @@ void XrdSecProtocolgsi::QueryGMAP(XrdCryptoX509Chain *chain, int now, String &us // Now we check the DN-mapping function and eventually the gridmap file. // The result can be cached for a while. - XrdSutPFEntry *cent = 0; const char *dn = chain->EECname(); - XrdOucString s; if (GMAPFun) { - // We may have it in the cache - cent = cacheGMAPFun.Get(pfeRef, dn); - // Check expiration, if required - if (GMAPCacheTimeOut > 0 && - (cent && (now - cent->mtime) > GMAPCacheTimeOut)) { - // Invalidate the entry - pfeRef.UnLock(); - cacheGMAPFun.Remove(dn); - cent = 0; - } - // Run the search via the external function - if (cent) {usrs=(const char *)(cent->buf1.buf); pfeRef.UnLock(); cent=0;} - else { + XrdSutCERef ceref; + bool rdlock = false; + XrdSutCacheArg_t arg = {kCE_ok, now, GMAPCacheTimeOut, -1}; + XrdSutCacheEntry *cent = cacheGMAPFun.Get(dn, rdlock, QueryGMAPCheck, (void *) &arg); + if (!cent) { + PRINT("unable to get a valid entry from cache for dn: " << dn); + return; + } + ceref.Set(&(cent->rwmtx)); + + // Check if we need to get/update the content + if (!rdlock) { + // Run the search via the external function char *name = (*GMAPFun)(dn, now); - if ((cent = cacheGMAPFun.Add(pfeRef, dn))) { - if (name) { - cent->status = kPFE_ok; - // Add username - SafeDelArray(cent->buf1.buf); - cent->buf1.buf = name; - cent->buf1.len = strlen(name); - usrs = (const char *)name; - } else { - // We cache the resul to avoid repeating the search - cent->status = kPFE_allowed; - } - // Fill up the rest - cent->cnt = 0; - cent->mtime = now; // creation time - // Rehash cache - pfeRef.UnLock(); // cent can no longer be used - cent = 0; - cacheGMAPFun.Rehash(1); + if (name) { + cent->status = kCE_ok; + // Add username + SafeDelArray(cent->buf1.buf); + cent->buf1.buf = name; + cent->buf1.len = strlen(name); } + // Fill up the rest + cent->cnt = 0; + cent->mtime = now; // creation time } + // Retrieve result form cache + usrs = cent->buf1.buf; + // We are done with the cache + ceref.UnLock(); } // Check the map file, if any @@ -5240,9 +5227,22 @@ bool XrdSecProtocolgsi::ServerCertNameOK(const char *subject, XrdOucString &emsg } //_____________________________________________________________________________ -XrdSutPFEntry *XrdSecProtocolgsi::GetSrvCertEnt(XrdSutCacheRef &pfeRef, - XrdCryptoFactory *cf, - time_t timestamp, String &certcalist) +static bool GetSrvCertEntCheck(XrdSutCacheEntry *e, void *a) { + int st_ref = (*((XrdSutCacheArg_t *)a)).arg1; + time_t ts_ref = (time_t)(*((XrdSutCacheArg_t *)a)).arg2; + if (e) { + if (e->status > st_ref) { + if (e->mtime >= ts_ref) + return true; + } + } + return false; +} + +//_____________________________________________________________________________ +XrdSutCacheEntry *XrdSecProtocolgsi::GetSrvCertEnt(XrdSutCERef &ceref, + XrdCryptoFactory *cf, + time_t timestamp, String &certcalist) { // Get cache entry for server certificate. This function checks the cache // and loads or re-loads the certificate form the specified files if required. @@ -5251,20 +5251,24 @@ XrdSutPFEntry *XrdSecProtocolgsi::GetSrvCertEnt(XrdSutCacheRef &pfeRef, if (!cf) { PRINT("Invalid inputs"); - return (XrdSutPFEntry *)0; + return (XrdSutCacheEntry *)0; } - XrdSutPFEntry *cent = cacheCert.Get(pfeRef, cf->Name()); - - // If there is already one valid, we are done. Note that the caller has - // lock ownership of the pointer should it be returned. - // - if (cent && cent->mtime >= timestamp) return cent; + bool rdlock = false; + XrdSutCacheArg_t arg = {kCE_allowed, timestamp, -1, -1}; + XrdSutCacheEntry *cent = cacheCert.Get(cf->Name(), rdlock, GetSrvCertEntCheck, (void *) &arg); + if (!cent) { + PRINT("unable to get a valid entry from cache for " << cf->Name()); + return (XrdSutCacheEntry *)0; + } + ceref.Set(&(cent->rwmtx)); - if (cent) PRINT("entry has expired: trying to renew ..."); + // Are we done ? + if (rdlock) return cent; + if (cent->buf1.buf) PRINT("entry has expired: trying to renew ..."); // Try get one or renew-it - if (cent && cent->status == kPFE_special) { + if (cent->status == kCE_special) { // Try init proxies ProxyIn_t pi = {SrvCert.c_str(), SrvKey.c_str(), CAdir.c_str(), UsrProxy.c_str(), PxyValid.c_str(), 0, 512}; @@ -5272,24 +5276,23 @@ XrdSutPFEntry *XrdSecProtocolgsi::GetSrvCertEnt(XrdSutCacheRef &pfeRef, XrdCryptoRSA *k = 0; XrdSutBucket *b = 0; ProxyOut_t po = {ch, k, b }; + // We lock inside + ceref.UnLock(false); if (QueryProxy(0, &cacheCert, cf->Name(), cf, timestamp, &pi, &po) != 0) { PRINT("proxy expired and cannot be renewed"); - pfeRef.UnLock(); - return (XrdSutPFEntry *)0; + return (XrdSutCacheEntry *)0; } + // When successful we return read-locked (this flow needs checking; but it is not mainstream) + ceref.ReadLock(); + return cent; } - if (cent) { - // Reset the entry - delete (XrdCryptoX509 *) cent->buf1.buf; // Destroys also xsrv->PKI() pointed in cent->buf2.buf - delete (XrdSutBucket *) cent->buf3.buf; - cent->buf1.buf = 0; - cent->buf2.buf = 0; - cent->buf3.buf = 0; - cent->Reset(); - pfeRef.UnLock(); // Note we throw away the pointer just below!/ - } - cent = 0; + // Reset the entry + delete (XrdCryptoX509 *) cent->buf1.buf; // Destroys also xsrv->PKI() pointed in cent->buf2.buf + delete (XrdSutBucket *) cent->buf3.buf; + cent->buf1.buf = 0; + cent->buf2.buf = 0; + cent->buf3.buf = 0; // // Get the IDs of the file: we need them to acquire the right privileges when opening @@ -5311,26 +5314,30 @@ XrdSutPFEntry *XrdSecProtocolgsi::GetSrvCertEnt(XrdSutCacheRef &pfeRef, if (xsrv->type != XrdCryptoX509::kEEC) { PRINT("problems loading srv cert: not EEC but: "<Type()); SafeDelete(xsrv); - return cent; + ceref.UnLock(); + return (XrdSutCacheEntry *)0; } // Must be valid if (!(xsrv->IsValid())) { PRINT("problems loading srv cert: invalid"); SafeDelete(xsrv); - return cent; + ceref.UnLock(); + return (XrdSutCacheEntry *)0; } // PKI must have been successfully initialized if (!xsrv->PKI() || xsrv->PKI()->status != XrdCryptoRSA::kComplete) { PRINT("problems loading srv cert: invalid PKI"); SafeDelete(xsrv); - return cent; + ceref.UnLock(); + return (XrdSutCacheEntry *)0; } // Must be exportable XrdSutBucket *xbck = xsrv->Export(); if (!xbck) { PRINT("problems loading srv cert: cannot export into bucket"); SafeDelete(xsrv); - return cent; + ceref.UnLock(); + return (XrdSutCacheEntry *)0; } // We must have the issuing CA certificate int rcgetca = 0; @@ -5352,47 +5359,48 @@ XrdSutPFEntry *XrdSecProtocolgsi::GetSrvCertEnt(XrdSutCacheRef &pfeRef, } SafeDelete(xsrv); SafeDelete(xbck); - return cent; + ceref.UnLock(); + return (XrdSutCacheEntry *)0; } } + // Ok: save it into the cache - String tag = cf->Name(); - cent = cacheCert.Add(pfeRef, tag.c_str()); - if (cent) { - cent->status = kPFE_ok; - cent->cnt = 0; - cent->mtime = xsrv->NotAfter(); // expiration time - // Save pointer to certificate (destroys also xsrv->PKI()) - if (cent->buf1.buf) delete (XrdCryptoX509 *) cent->buf1.buf; - cent->buf1.buf = (char *)xsrv; - cent->buf1.len = 0; // just a flag - // Save pointer to key - cent->buf2.buf = 0; - cent->buf2.buf = (char *)(xsrv->PKI()); - cent->buf2.len = 0; // just a flag - // Save pointer to bucket - if (cent->buf3.buf) delete (XrdSutBucket *) cent->buf3.buf; - cent->buf3.buf = (char *)(xbck); - cent->buf3.len = 0; // just a flag - // Save CA hash in list to communicate to clients - if (certcalist.find(xsrv->IssuerHash()) == STR_NPOS) { + cent->status = kCE_ok; + cent->cnt = 0; + cent->mtime = xsrv->NotAfter(); // expiration time + // Save pointer to certificate (destroys also xsrv->PKI()) + if (cent->buf1.buf) delete (XrdCryptoX509 *) cent->buf1.buf; + cent->buf1.buf = (char *)xsrv; + cent->buf1.len = 0; // just a flag + // Save pointer to key + cent->buf2.buf = 0; + cent->buf2.buf = (char *)(xsrv->PKI()); + cent->buf2.len = 0; // just a flag + // Save pointer to bucket + if (cent->buf3.buf) delete (XrdSutBucket *) cent->buf3.buf; + cent->buf3.buf = (char *)(xbck); + cent->buf3.len = 0; // just a flag + // Save CA hash in list to communicate to clients + if (certcalist.find(xsrv->IssuerHash()) == STR_NPOS) { + if (certcalist.length() > 0) certcalist += "|"; + certcalist += xsrv->IssuerHash(); + } + // Save also old CA hash in list to communicate to clients, if relevant + if (HashCompatibility && xsrv->IssuerHash(1) && + strcmp(xsrv->IssuerHash(1),xsrv->IssuerHash())) { + if (certcalist.find(xsrv->IssuerHash(1)) == STR_NPOS) { if (certcalist.length() > 0) certcalist += "|"; - certcalist += xsrv->IssuerHash(); + certcalist += xsrv->IssuerHash(1); } - // Save also old CA hash in list to communicate to clients, if relevant - if (HashCompatibility && xsrv->IssuerHash(1) && - strcmp(xsrv->IssuerHash(1),xsrv->IssuerHash())) { - if (certcalist.find(xsrv->IssuerHash(1)) == STR_NPOS) { - if (certcalist.length() > 0) certcalist += "|"; - certcalist += xsrv->IssuerHash(1); - } - } - } else { - // Cleanup - SafeDelete(xsrv); - SafeDelete(xbck); } + } else { + PRINT("failed to load certificate from files ("<< SrvCert <<","< -class GSIStack { -public: - void Add(T *t) { - char k[40]; snprintf(k, 40, "%p", t); - mtx.Lock(); - if (!stack.Find(k)) stack.Add(k, t, 0, Hash_count); // We need an additional count - stack.Add(k, t, 0, Hash_count); - mtx.UnLock(); - } - void Del(T *t) { - char k[40]; snprintf(k, 40, "%p", t); - mtx.Lock(); - if (stack.Find(k)) stack.Del(k, Hash_count); - mtx.UnLock(); - } -private: - XrdSysMutex mtx; - XrdOucHash stack; -}; - /******************************************************************************/ /* X r d S e c P r o t o c o l g s i C l a s s */ /******************************************************************************/ @@ -348,20 +329,15 @@ private: static XrdCryptoCipher *refcip[XrdCryptoMax]; // ref for session ciphers // // Caches - static XrdSutCache cacheCA; // Info about trusted CA's - static XrdSutCache cacheCert; // Cache for available server certs - static XrdSutCache cachePxy; // Cache for client proxies - static XrdSutCache cacheGMAP; // Cache for gridmap entries - static XrdSutCache cacheGMAPFun; // Cache for entries mapped by GMAPFun - static XrdSutCache cacheAuthzFun; // Cache for entities filled by AuthzFun + static XrdSutCache cacheCA; // Info about trusted CA's + static XrdSutCache cacheCert; // Server certificates info cache + static XrdSutCache cachePxy; // Client proxies cache; + static XrdSutCache cacheGMAPFun; // Cache for entries mapped by GMAPFun + static XrdSutCache cacheAuthzFun; // Cache for entities filled by AuthzFun // // Services static XrdOucGMap *servGMap; // Grid mapping service // - // CA and CRL stacks - static GSIStack stackCA; // Stack of CA in use - static GSIStack stackCRL; // Stack of CRL in use - // // GMAP control vars static time_t lastGMAPCheck; // time of last check on GMAP static XrdSysMutex mutexGMAP; // mutex to control GMAP reloads @@ -422,7 +398,7 @@ private: static int VerifyCRL(XrdCryptoX509Crl *crl, XrdCryptoX509 *xca, XrdOucString crldir, XrdCryptoFactory *CF, int hashalg); bool ServerCertNameOK(const char *subject, String &e); - static XrdSutPFEntry *GetSrvCertEnt(XrdSutCacheRef &pfeRef, + static XrdSutCacheEntry *GetSrvCertEnt(XrdSutCERef &gcref, XrdCryptoFactory *cf, time_t timestamp, String &cal); @@ -510,12 +486,7 @@ public: if (Chain) Chain->Cleanup(1); SafeDelete(Chain); } - if (Crl) { - // This decreases the counter and actually deletes the object only - // when no instance is using it - XrdSecProtocolgsi::stackCRL.Del(Crl); - Crl = 0; - } + Crl = 0; // The proxy chain is owned by the proxy cache; invalid proxies are // detected (and eventually removed) by QueryProxy PxyChain = 0; diff --git a/src/XrdSecpwd/XrdSecProtocolpwd.cc b/src/XrdSecpwd/XrdSecProtocolpwd.cc index d9616faa76e..b067abcb864 100644 --- a/src/XrdSecpwd/XrdSecProtocolpwd.cc +++ b/src/XrdSecpwd/XrdSecProtocolpwd.cc @@ -49,7 +49,7 @@ #include "XrdSys/XrdSysPriv.hh" -#include "XrdSut/XrdSutCache.hh" +#include "XrdSut/XrdSutPFCache.hh" #include "XrdSecpwd/XrdSecProtocolpwd.hh" #include "XrdSecpwd/XrdSecpwdPlatform.hh" @@ -178,10 +178,10 @@ String XrdSecProtocolpwd::cryptName[XrdCryptoMax] = {0}; // their names XrdCryptoCipher *XrdSecProtocolpwd::refcip[XrdCryptoMax] = {0}; // ref for session ciphers // // Caches for info files -XrdSutCache XrdSecProtocolpwd::cacheAdmin; // Admin file -XrdSutCache XrdSecProtocolpwd::cacheSrvPuk; // SrvPuk file -XrdSutCache XrdSecProtocolpwd::cacheUser; // User files -XrdSutCache XrdSecProtocolpwd::cacheAlog; // Autologin file +XrdSutPFCache XrdSecProtocolpwd::cacheAdmin; // Admin file +XrdSutPFCache XrdSecProtocolpwd::cacheSrvPuk; // SrvPuk file +XrdSutPFCache XrdSecProtocolpwd::cacheUser; // User files +XrdSutPFCache XrdSecProtocolpwd::cacheAlog; // Autologin file // // Running options / settings int XrdSecProtocolpwd::Debug = 0; // [CS] Debug level @@ -343,7 +343,7 @@ char *XrdSecProtocolpwd::Init(pwdOptions opt, XrdOucErrInfo *erp) // Static method to the configure the static part of the protocol // Called once by XrdSecProtocolpwdInit EPNAME("Init"); - XrdSutCacheRef pfeRef; + XrdSutPFCacheRef pfeRef; char *Parms = 0; // // Debug an tracing @@ -2116,7 +2116,7 @@ int XrdSecProtocolpwd::SaveCreds(XrdSutBucket *creds) // Save credentials in creds in the password file // Returns 0 if ok, -1 otherwise EPNAME("SaveCreds"); - XrdSutCacheRef pfeRef; + XrdSutPFCacheRef pfeRef; // Check inputs if ((hs->User.length() <= 0) || !hs->CF || !creds) { @@ -2317,7 +2317,7 @@ XrdSutBucket *XrdSecProtocolpwd::QueryCreds(XrdSutBuffer *bm, { // Get credential information to be sent to the server EPNAME("QueryCreds"); - XrdSutCacheRef pfeRef; + XrdSutPFCacheRef pfeRef; // Check inputs if (!bm || !hs->CF || hs->Tag.length() <= 0) { @@ -2669,7 +2669,7 @@ int XrdSecProtocolpwd::QueryUser(int &status, String &cmsg) { // Check that info about the defined user is available EPNAME("QueryUser"); - XrdSutCacheRef pfeRef; + XrdSutPFCacheRef pfeRef; DEBUG("Enter: " << hs->User); @@ -3027,7 +3027,7 @@ int XrdSecProtocolpwd::ParseClientInput(XrdSutBuffer *br, XrdSutBuffer **bm, // cipher and server public keys, if there // Result used to fill the handshake local variables EPNAME("ParseClientInput"); - XrdSutCacheRef pfeRef; + XrdSutPFCacheRef pfeRef; // Space for pointer to main buffer must be already allocated if (!br || !bm) { diff --git a/src/XrdSecpwd/XrdSecProtocolpwd.hh b/src/XrdSecpwd/XrdSecProtocolpwd.hh index 4148ec840c5..a085b49873a 100644 --- a/src/XrdSecpwd/XrdSecProtocolpwd.hh +++ b/src/XrdSecpwd/XrdSecProtocolpwd.hh @@ -332,10 +332,10 @@ private: static XrdCryptoCipher *refcip[XrdCryptoMax]; // ref for session ciphers // // Caches for info files - static XrdSutCache cacheAdmin; // Admin file - static XrdSutCache cacheSrvPuk; // SrvPuk file - static XrdSutCache cacheUser; // User files - static XrdSutCache cacheAlog; // Autologin file + static XrdSutPFCache cacheAdmin; // Admin file + static XrdSutPFCache cacheSrvPuk; // SrvPuk file + static XrdSutPFCache cacheUser; // User files + static XrdSutPFCache cacheAlog; // Autologin file // // Running options / settings static int Debug; // [CS] Debug level diff --git a/src/XrdSut/XrdSutCache.hh b/src/XrdSut/XrdSutCache.hh index 4d52eb95688..48643f60f12 100644 --- a/src/XrdSut/XrdSutCache.hh +++ b/src/XrdSut/XrdSutCache.hh @@ -1,10 +1,10 @@ -#ifndef __SUT_CACHE_H__ -#define __SUT_CACHE_H__ +#ifndef __SUT_CACHE_H +#define __SUT_CACHE_H /******************************************************************************/ /* */ -/* X r d S u t C a c h e . h h */ +/* X r d S u t C a c h e . h h */ /* */ -/* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */ +/* (c) 2005 by the Board of Trustees of the Leland Stanford, Jr., University */ /* Produced by Gerri Ganis for CERN */ /* */ /* This file is part of the XRootD software suite. */ @@ -28,95 +28,119 @@ /* specific prior written permission of the institution or contributor. */ /******************************************************************************/ -#include "XProtocol/XPtypes.hh" -#include "XrdSut/XrdSutPFEntry.hh" #include "XrdOuc/XrdOucHash.hh" -#include "XrdOuc/XrdOucString.hh" +#include "XrdSut/XrdSutCacheEntry.hh" #include "XrdSys/XrdSysPthread.hh" /******************************************************************************/ /* */ -/* For caching temporary information during the authentication handshake */ +/* Class defining the basic memory cache */ /* */ /******************************************************************************/ -class XrdSutCacheRef -{ -public: - -inline void Lock(XrdSysMutex *Mutex) - {if (mtx) {if (mtx != Mutex) mtx->UnLock(); - else return; - } - Mutex->Lock(); - mtx = Mutex; - }; - -inline void Set(XrdSysMutex *Mutex) - {if (mtx) {if (mtx != Mutex) mtx->UnLock(); - else return; - } - mtx = Mutex; - }; - -inline void UnLock() {if (mtx) {mtx->UnLock(); mtx = 0;}} - - XrdSutCacheRef() : mtx(0) {} +typedef bool (*XrdSutCacheGet_t)(XrdSutCacheEntry *, void *); +typedef struct { + long arg1; + long arg2; + long arg3; + long arg4; +} XrdSutCacheArg_t; - ~XrdSutCacheRef() {if (mtx) UnLock();} -protected: -XrdSysMutex *mtx; -}; +class XrdSutCache { +public: + XrdSutCache(int psize = 89, int size = 144, int load = 80) : table(psize, size, load) {} + virtual ~XrdSutCache() {} + + XrdSutCacheEntry *Get(const char *tag) { + // Get the entry with 'tag'. + // If found the entry is returned rd-locked. + // If rd-locking fails the status is set to kCE_inactive. + // Returns null if not found. + + XrdSutCacheEntry *cent = 0; + + // Exclusive access to the table + XrdSysMutexHelper raii(mtx); + + // Look for an entry + if (!(cent = table.Find(tag))) { + // none found + return cent; + } + + // We found an existing entry: + // lock until we get the ability to read (another thread may be valudating it) + if (cent->rwmtx.ReadLock()) { + // A problem occured: fail (set the entry invalid) + cent->status = kCE_inactive; + } + return cent; + } + + XrdSutCacheEntry *Get(const char *tag, bool &rdlock, XrdSutCacheGet_t condition = 0, void *arg = 0) { + // Get or create the entry with 'tag'. + // New entries are always returned write-locked. + // The status of existing ones depends on condition: if condition is undefined or if applied + // to the entry with arguments 'arg' returns true, the entry is returned read-locked. + // Otherwise a write-lock is attempted on the entry: if unsuccessful (another thread is modifing + // the entry) the entry is read-locked. + // The status of the lock is returned in rdlock (true if read-locked). + rdlock = false; + XrdSutCacheEntry *cent = 0; + + // Exclusive access to the table + XrdSysMutexHelper raii(mtx); + + // Look for an entry + if (!(cent = table.Find(tag))) { + // If none, create a new one and write-lock for validation + cent = new XrdSutCacheEntry(tag); + if (cent->rwmtx.WriteLock()) { + // A problem occured: delete the entry and fail + delete cent; + return (XrdSutCacheEntry *)0; + } + // Register it in the table + table.Add(tag, cent); + return cent; + } + + // We found an existing entry: + // lock until we get the ability to read (another thread may be valudating it) + if (cent->rwmtx.ReadLock()) { + // A problem occured: fail (set the entry invalid) + cent->status = kCE_inactive; + return cent; + } + + // Check-it by apply the condition, if required + if (condition) { + if ((*condition)(cent, arg)) { + // Good and valid entry + rdlock = true; + } else { + // Invalid entry: unlock and write-lock to be able to validate it + cent->rwmtx.UnLock(); + if (cent->rwmtx.WriteLock()) { + // A problem occured: fail (set the entry invalid) + cent->status = kCE_inactive; + return cent; + } + } + } else { + // Good and valid entry + rdlock = true; + } + // We are done: return read-locked so we can use it until we need it + return cent; + } + + inline int Num() { return table.Num(); } + inline void Reset() { return table.Purge(); } -class XrdSutCache -{ private: - XrdSysRWLock rwlock; // Access synchronizator - int cachesz; // Number of entries allocated - int cachemx; // Largest Index of allocated entries - XrdSutPFEntry **cachent; // Pointers to filled entries - kXR_int32 utime; // time at which was last updated - int lifetime; // lifetime (in secs) of the cache info - XrdOucHash hashtable; // Reflects the file index structure - kXR_int32 htmtime; // time at which hash table was last rebuild - XrdOucString pfile; // file name (if loaded from file) - bool isinit; // true if already initialized - - XrdSutPFEntry *Get(const char *ID, bool *wild); - bool Delete(XrdSutPFEntry *pfEnt); - - static const int maxTries = 100; // Max time to try getting a lock - static const int retryMSW = 300; // Milliseconds to wait to get lock - -public: - XrdSutCache() { cachemx = -1; cachesz = 0; cachent = 0; lifetime = 300; - utime = -1; htmtime = -1; pfile = ""; isinit = 0; } - virtual ~XrdSutCache(); - - // Status - int Entries() const { return (cachemx+1); } - bool Empty() const { return (cachemx == -1); } - - // Initialization methods - int Init(int capacity = 100, bool lock = 1); - int Reset(int newsz = -1, bool lock = 1); - int Load(const char *pfname); // build cache of a pwd file - int Flush(const char *pfname = 0); // flush content to pwd file - int Refresh(); // refresh content from source file - int Rehash(bool force = 0, bool lock = 1); // (re)build hash table - void SetLifetime(int lifet = 300) { lifetime = lifet; } - - // Cache management - XrdSutPFEntry *Get(int i) const { return (i<=cachemx) ? cachent[i] : - (XrdSutPFEntry *)0; } - XrdSutPFEntry *Get(XrdSutCacheRef &urRef, const char *ID, bool *wild = 0); - XrdSutPFEntry *Add(XrdSutCacheRef &urRef, const char *ID, bool force = 0); - bool Remove(const char *ID, int opt = 1); - int Trim(int lifet = 0); - - // For debug purposes - void Dump(const char *msg= 0); + XrdSysRecMutex mtx; // Protect access to table + XrdOucHash table; // table with content }; #endif - diff --git a/src/XrdSut/XrdSutCacheEntry.cc b/src/XrdSut/XrdSutCacheEntry.cc new file mode 100644 index 00000000000..64707c5d781 --- /dev/null +++ b/src/XrdSut/XrdSutCacheEntry.cc @@ -0,0 +1,184 @@ +/******************************************************************************/ +/* */ +/* X r d S u t C a c h e E n t r y . c c */ +/* */ +/* (c) 2012 by the Board of Trustees of the Leland Stanford, Jr., University */ +/* Produced by Gerri Ganis for CERN */ +/* */ +/* This file is part of the XRootD software suite. */ +/* */ +/* XRootD is free software: you can redistribute it and/or modify it under */ +/* the terms of the GNU Lesser General Public License as published by the */ +/* Free Software Foundation, either version 3 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* XRootD is distributed in the hope that it will be useful, but WITHOUT */ +/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */ +/* License for more details. */ +/* */ +/* You should have received a copy of the GNU Lesser General Public License */ +/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */ +/* COPYING (GPL license). If not, see . */ +/* */ +/* The copyright holder's institutional names and contributor's names may not */ +/* be used to endorse or promote products derived from this software without */ +/* specific prior written permission of the institution or contributor. */ +/******************************************************************************/ + +#include +#include +#include + +#include "XrdSutAux.hh" +#include "XrdSutCacheEntry.hh" + +//__________________________________________________________________ +XrdSutCacheEntryBuf::XrdSutCacheEntryBuf(char *b, kXR_int32 l) +{ + // Constructor + + len = 0; + buf = 0; + if (b) { + buf = b; + len = l; + } +} + +//__________________________________________________________________ +XrdSutCacheEntryBuf::XrdSutCacheEntryBuf(const XrdSutCacheEntryBuf &b) +{ + //Copy constructor + + buf = 0; + len = 0; + if (b.buf) { + buf = new char[b.len]; + if (buf) { + memcpy(buf,b.buf,b.len); + len = b.len; + } + } +} + +//__________________________________________________________________ +void XrdSutCacheEntryBuf::SetBuf(const char *b, kXR_int32 l) +{ + // Set the buffer + + len = 0; + if (buf) { + delete[] buf; + buf = 0; + } + if (b && l > 0) { + buf = new char[l]; + if (buf) { + memcpy(buf,b,l); + len = l; + } + } +} + +//____________________________________________________________________ +XrdSutCacheEntry::XrdSutCacheEntry(const char *n, short st, short cn, + kXR_int32 mt) +{ + // Constructor + + name = 0; + status = st; + cnt = cn; + mtime = (mt > 0) ? mt : (kXR_int32)time(0); + if (n) { + name = new char[strlen(n)+1]; + if (name) + strcpy(name,n); + } +} + +//_____________________________________________________________________ +XrdSutCacheEntry::XrdSutCacheEntry(const XrdSutCacheEntry &e) : buf1(e.buf1), + buf2(e.buf2), buf3(e.buf3), buf4(e.buf4) +{ + // Copy constructor + + name = 0; + status = e.status; + cnt = e.cnt; + mtime = e.mtime; + if (e.name) { + name = new char[strlen(e.name)+1]; + if (name) + strcpy(name,e.name); + } +} + +//____________________________________________________________________ +void XrdSutCacheEntry::Reset() +{ + // Resetting entry + + if (name) + delete[] name; + name = 0; + status = 0; + cnt = 0; + mtime = (kXR_int32)time(0); + buf1.SetBuf(); + buf2.SetBuf(); + buf3.SetBuf(); + buf4.SetBuf(); +} + +//_____________________________________________________________________ +void XrdSutCacheEntry::SetName(const char *n) +{ + // Set the name + + if (name) { + delete[] name; + name = 0; + } + if (n) { + name = new char[strlen(n)+1]; + if (name) + strcpy(name,n); + } +} + +//_____________________________________________________________________ +char *XrdSutCacheEntry::AsString() const +{ + // Return a string with serialized information + // For print purposes + // The output string points to a static buffer, so it must + // not be deleted by the caller + static char pbuf[2048]; + + char smt[20] = {0}; + XrdSutTimeString(mtime,smt); + + sprintf(pbuf,"st:%d cn:%d buf:%d,%d,%d,%d modified:%s name:%s", + status,cnt,buf1.len,buf2.len,buf3.len,buf4.len,smt,name); + + return pbuf; +} + +//______________________________________________________________________________ +XrdSutCacheEntry& XrdSutCacheEntry::operator=(const XrdSutCacheEntry &e) +{ + // Assign entry e to local entry. + + SetName(name); + status = e.status; + cnt = e.cnt; // counter + mtime = e.mtime; // time of last modification / creation + buf1.SetBuf(e.buf1.buf); + buf2.SetBuf(e.buf2.buf); + buf3.SetBuf(e.buf3.buf); + buf4.SetBuf(e.buf4.buf); + + return (*this); +} diff --git a/src/XrdSut/XrdSutCacheEntry.hh b/src/XrdSut/XrdSutCacheEntry.hh new file mode 100644 index 00000000000..099ca34ac7e --- /dev/null +++ b/src/XrdSut/XrdSutCacheEntry.hh @@ -0,0 +1,129 @@ +#ifndef __SUT_CACHEENTRY_H +#define __SUT_CACHEENTRY_H +/******************************************************************************/ +/* */ +/* X r d S u t C a c h e E n t r y . h h */ +/* */ +/* (c) 2005 by the Board of Trustees of the Leland Stanford, Jr., University */ +/* Produced by Gerri Ganis for CERN */ +/* */ +/* This file is part of the XRootD software suite. */ +/* */ +/* XRootD is free software: you can redistribute it and/or modify it under */ +/* the terms of the GNU Lesser General Public License as published by the */ +/* Free Software Foundation, either version 3 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* XRootD is distributed in the hope that it will be useful, but WITHOUT */ +/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */ +/* License for more details. */ +/* */ +/* You should have received a copy of the GNU Lesser General Public License */ +/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */ +/* COPYING (GPL license). If not, see . */ +/* */ +/* The copyright holder's institutional names and contributor's names may not */ +/* be used to endorse or promote products derived from this software without */ +/* specific prior written permission of the institution or contributor. */ +/******************************************************************************/ + +#include "XProtocol/XProtocol.hh" +#include "XrdSys/XrdSysPthread.hh" + +/******************************************************************************/ +/* */ +/* Class defining the basic cache entry */ +/* */ +/******************************************************************************/ + +enum kCEntryStatus { + kCE_inactive = -2, // -2 inactive: eliminated at next trim + kCE_disabled, // -1 disabled, cannot be enabled + kCE_allowed, // 0 empty creds, can be enabled + kCE_expired, // 1 enabled, creds to be changed at next used + kCE_ok, // 2 enabled and OK + kCE_special // 3 special (non-creds) entry +}; + +// +// Buffer used internally by XrdGCEntry +// +class XrdSutCacheEntryBuf { +public: + char *buf; + kXR_int32 len; + XrdSutCacheEntryBuf(char *b = 0, kXR_int32 l = 0); + XrdSutCacheEntryBuf(const XrdSutCacheEntryBuf &b); + + virtual ~XrdSutCacheEntryBuf() { if (len > 0 && buf) delete[] buf; } + + void SetBuf(const char *b = 0, kXR_int32 l = 0); +}; + +// +// Generic cache entry: it stores a +// +// name +// status 2 bytes +// cnt 2 bytes +// mtime 4 bytes +// buf1, buf2, buf3, buf4 +// +// The buffers are generic buffers to store bufferized info +// +class XrdSutCacheEntry { +public: + char *name; + short status; + short cnt; // counter + kXR_int32 mtime; // time of last modification / creation + XrdSutCacheEntryBuf buf1; + XrdSutCacheEntryBuf buf2; + XrdSutCacheEntryBuf buf3; + XrdSutCacheEntryBuf buf4; + XrdSysRWLock rwmtx; // Locked when reference is outstanding + XrdSutCacheEntry(const char *n = 0, short st = 0, short cn = 0, + kXR_int32 mt = 0); + XrdSutCacheEntry(const XrdSutCacheEntry &e); + virtual ~XrdSutCacheEntry() { if (name) delete[] name; } + kXR_int32 Length() const { return (buf1.len + buf2.len + 2*sizeof(short) + + buf3.len + buf4.len + 5*sizeof(kXR_int32)); } + void Reset(); + void SetName(const char *n = 0); + char *AsString() const; + + XrdSutCacheEntry &operator=(const XrdSutCacheEntry &pfe); +}; + +class XrdSutCERef +{ +public: + +inline void ReadLock(XrdSysRWLock *lock = 0) + { if (lock) Set(lock); + rwlock->ReadLock(); + }; + +inline void WriteLock(XrdSysRWLock *lock = 0) + { if (lock) Set(lock); + rwlock->WriteLock(); + }; + +inline void Set(XrdSysRWLock *lock) + {if (rwlock) {if (rwlock != lock) rwlock->UnLock(); + else return; + } + rwlock = lock; + }; + +inline void UnLock(bool reset = true) {if (rwlock) {rwlock->UnLock(); if (reset) rwlock = 0; }} + + XrdSutCERef() : rwlock(0) {} + + ~XrdSutCERef() {if (rwlock) UnLock(); rwlock = 0; } +protected: +XrdSysRWLock *rwlock; +}; + +#endif diff --git a/src/XrdSut/XrdSutCache.cc b/src/XrdSut/XrdSutPFCache.cc similarity index 96% rename from src/XrdSut/XrdSutCache.cc rename to src/XrdSut/XrdSutPFCache.cc index 9a108468fd1..3084892ce95 100644 --- a/src/XrdSut/XrdSutCache.cc +++ b/src/XrdSut/XrdSutPFCache.cc @@ -33,7 +33,7 @@ #include #include -#include "XrdSut/XrdSutCache.hh" +#include "XrdSut/XrdSutPFCache.hh" #include "XrdSut/XrdSutPFile.hh" #include "XrdSut/XrdSutTrace.hh" #include "XrdSut/XrdSutAux.hh" @@ -46,7 +46,7 @@ /******************************************************************************/ //__________________________________________________________________ -XrdSutCache::~XrdSutCache() +XrdSutPFCache::~XrdSutPFCache() { // Destructor @@ -70,7 +70,7 @@ XrdSutCache::~XrdSutCache() } //__________________________________________________________________ -int XrdSutCache::Init(int capacity, bool lock) +int XrdSutPFCache::Init(int capacity, bool lock) { // Initialize the cache to hold up to capacity entries. // Later on, capacity is double each time more space is needed. @@ -119,7 +119,7 @@ int XrdSutCache::Init(int capacity, bool lock) } //__________________________________________________________________ -XrdSutPFEntry *XrdSutCache::Get(XrdSutCacheRef &urRef, const char *ID, bool *wild) +XrdSutPFEntry *XrdSutPFCache::Get(XrdSutPFCacheRef &urRef, const char *ID, bool *wild) { // Retrieve an entry with ID, if any // If wild is defined, search also best matching regular expression @@ -170,7 +170,7 @@ XrdSutPFEntry *XrdSutCache::Get(XrdSutCacheRef &urRef, const char *ID, bool *wil } //__________________________________________________________________ -XrdSutPFEntry *XrdSutCache::Get(const char *ID, bool *wild) +XrdSutPFEntry *XrdSutPFCache::Get(const char *ID, bool *wild) { // Look in the hash first @@ -204,7 +204,7 @@ XrdSutPFEntry *XrdSutCache::Get(const char *ID, bool *wild) } //__________________________________________________________________ -XrdSutPFEntry *XrdSutCache::Add(XrdSutCacheRef &urRef, const char *ID, bool force) +XrdSutPFEntry *XrdSutPFCache::Add(XrdSutPFCacheRef &urRef, const char *ID, bool force) { // Add an entry with ID in cache // Cache buffer is re-allocated with double size, if needed @@ -291,7 +291,7 @@ XrdSutPFEntry *XrdSutCache::Add(XrdSutCacheRef &urRef, const char *ID, bool forc } //__________________________________________________________________ -bool XrdSutCache::Remove(const char *ID, int opt) +bool XrdSutPFCache::Remove(const char *ID, int opt) { // If opt==1 remove entry with name matching exactly ID from cache // If opt==0 all entries with names starting with ID are removed @@ -364,7 +364,7 @@ bool XrdSutCache::Remove(const char *ID, int opt) } //__________________________________________________________________ -bool XrdSutCache::Delete(XrdSutPFEntry *pfEnt) +bool XrdSutPFCache::Delete(XrdSutPFEntry *pfEnt) { struct pfQ {pfQ *next; XrdSutPFEntry *pfEnt; @@ -407,7 +407,7 @@ bool XrdSutCache::Delete(XrdSutPFEntry *pfEnt) } //__________________________________________________________________ -int XrdSutCache::Trim(int lifet) +int XrdSutPFCache::Trim(int lifet) { // Remove entries older then lifet seconds. If lifet <=0, compare // to lifetime, which can be set with SetValidity(). @@ -445,7 +445,7 @@ int XrdSutCache::Trim(int lifet) } //__________________________________________________________________ -int XrdSutCache::Reset(int newsz, bool lock) +int XrdSutPFCache::Reset(int newsz, bool lock) { // Remove all existing entries. // If newsz > -1, set new capacity to newsz, reallocating if needed @@ -484,7 +484,7 @@ int XrdSutCache::Reset(int newsz, bool lock) } //________________________________________________________________ -void XrdSutCache::Dump(const char *msg) +void XrdSutPFCache::Dump(const char *msg) { // Dump content of the cache EPNAME("Cache::Dump"); @@ -528,7 +528,7 @@ void XrdSutCache::Dump(const char *msg) } //__________________________________________________________________ -int XrdSutCache::Load(const char *pfn) +int XrdSutPFCache::Load(const char *pfn) { // Initialize the cache from the content of a file of PF entries // Return 0 if ok, -1 otherwise @@ -656,7 +656,7 @@ int XrdSutCache::Load(const char *pfn) //__________________________________________________________________ -int XrdSutCache::Rehash(bool force, bool lock) +int XrdSutPFCache::Rehash(bool force, bool lock) { // Update or create hahs table corresponding to the present content of the // cache @@ -698,7 +698,7 @@ int XrdSutCache::Rehash(bool force, bool lock) } //__________________________________________________________________ -int XrdSutCache::Flush(const char *pfn) +int XrdSutPFCache::Flush(const char *pfn) { // Flush cache content to file pfn. // If pfn == 0 and the cache was initialized from a file, flush @@ -766,7 +766,7 @@ int XrdSutCache::Flush(const char *pfn) } //__________________________________________________________________ -int XrdSutCache::Refresh() +int XrdSutPFCache::Refresh() { // Refresh content of a cache created from file. // Return 0 if ok, -1 otherwise diff --git a/src/XrdSut/XrdSutPFCache.hh b/src/XrdSut/XrdSutPFCache.hh new file mode 100644 index 00000000000..7b5ad1b18bc --- /dev/null +++ b/src/XrdSut/XrdSutPFCache.hh @@ -0,0 +1,122 @@ +#ifndef __SUT_CACHE_H__ +#define __SUT_CACHE_H__ +/******************************************************************************/ +/* */ +/* X r d S u t C a c h e . h h */ +/* */ +/* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */ +/* Produced by Gerri Ganis for CERN */ +/* */ +/* This file is part of the XRootD software suite. */ +/* */ +/* XRootD is free software: you can redistribute it and/or modify it under */ +/* the terms of the GNU Lesser General Public License as published by the */ +/* Free Software Foundation, either version 3 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* XRootD is distributed in the hope that it will be useful, but WITHOUT */ +/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */ +/* License for more details. */ +/* */ +/* You should have received a copy of the GNU Lesser General Public License */ +/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */ +/* COPYING (GPL license). If not, see . */ +/* */ +/* The copyright holder's institutional names and contributor's names may not */ +/* be used to endorse or promote products derived from this software without */ +/* specific prior written permission of the institution or contributor. */ +/******************************************************************************/ + +#include "XProtocol/XPtypes.hh" +#include "XrdSut/XrdSutPFEntry.hh" +#include "XrdOuc/XrdOucHash.hh" +#include "XrdOuc/XrdOucString.hh" +#include "XrdSys/XrdSysPthread.hh" + +/******************************************************************************/ +/* */ +/* For caching temporary information during the authentication handshake */ +/* */ +/******************************************************************************/ + +class XrdSutPFCacheRef +{ +public: + +inline void Lock(XrdSysMutex *Mutex) + {if (mtx) {if (mtx != Mutex) mtx->UnLock(); + else return; + } + Mutex->Lock(); + mtx = Mutex; + }; + +inline void Set(XrdSysMutex *Mutex) + {if (mtx) {if (mtx != Mutex) mtx->UnLock(); + else return; + } + mtx = Mutex; + }; + +inline void UnLock() {if (mtx) {mtx->UnLock(); mtx = 0;}} + + XrdSutPFCacheRef() : mtx(0) {} + + ~XrdSutPFCacheRef() {if (mtx) UnLock();} +protected: +XrdSysMutex *mtx; +}; + +class XrdSutPFCache +{ +private: + XrdSysRWLock rwlock; // Access synchronizator + int cachesz; // Number of entries allocated + int cachemx; // Largest Index of allocated entries + XrdSutPFEntry **cachent; // Pointers to filled entries + kXR_int32 utime; // time at which was last updated + int lifetime; // lifetime (in secs) of the cache info + XrdOucHash hashtable; // Reflects the file index structure + kXR_int32 htmtime; // time at which hash table was last rebuild + XrdOucString pfile; // file name (if loaded from file) + bool isinit; // true if already initialized + + XrdSutPFEntry *Get(const char *ID, bool *wild); + bool Delete(XrdSutPFEntry *pfEnt); + + static const int maxTries = 100; // Max time to try getting a lock + static const int retryMSW = 300; // Milliseconds to wait to get lock + +public: + XrdSutPFCache() { cachemx = -1; cachesz = 0; cachent = 0; lifetime = 300; + utime = -1; htmtime = -1; pfile = ""; isinit = 0; } + virtual ~XrdSutPFCache(); + + // Status + int Entries() const { return (cachemx+1); } + bool Empty() const { return (cachemx == -1); } + + // Initialization methods + int Init(int capacity = 100, bool lock = 1); + int Reset(int newsz = -1, bool lock = 1); + int Load(const char *pfname); // build cache of a pwd file + int Flush(const char *pfname = 0); // flush content to pwd file + int Refresh(); // refresh content from source file + int Rehash(bool force = 0, bool lock = 1); // (re)build hash table + void SetLifetime(int lifet = 300) { lifetime = lifet; } + + // Cache management + XrdSutPFEntry *Get(int i) const { return (i<=cachemx) ? cachent[i] : + (XrdSutPFEntry *)0; } + XrdSutPFEntry *Get(XrdSutPFCacheRef &urRef, const char *ID, bool *wild = 0); + XrdSutPFEntry *Add(XrdSutPFCacheRef &urRef, const char *ID, bool force = 0); + bool Remove(const char *ID, int opt = 1); + int Trim(int lifet = 0); + + // For debug purposes + void Dump(const char *msg= 0); +}; + +#endif + diff --git a/src/XrdSut/XrdSutPFile.hh b/src/XrdSut/XrdSutPFile.hh index be60e48f73e..db32c68de36 100644 --- a/src/XrdSut/XrdSutPFile.hh +++ b/src/XrdSut/XrdSutPFile.hh @@ -120,7 +120,7 @@ public: class XrdSutPFile { - friend class XrdSutCache; // for open/close operation; + friend class XrdSutPFCache; // for open/close operation; private: char *name; diff --git a/src/XrdSys/XrdSysPthread.hh b/src/XrdSys/XrdSysPthread.hh index 22a81d694be..9217fdc3d3a 100644 --- a/src/XrdSys/XrdSysPthread.hh +++ b/src/XrdSys/XrdSysPthread.hh @@ -234,8 +234,8 @@ inline int CondWriteLock() return 1; } -inline void ReadLock() {pthread_rwlock_rdlock(&lock);} -inline void WriteLock() {pthread_rwlock_wrlock(&lock);} +inline int ReadLock() {return pthread_rwlock_rdlock(&lock);} +inline int WriteLock() {return pthread_rwlock_wrlock(&lock);} inline void UnLock() {pthread_rwlock_unlock(&lock);} diff --git a/src/XrdUtils.cmake b/src/XrdUtils.cmake index 6d1f420f0f2..6a5f2199dd1 100644 --- a/src/XrdUtils.cmake +++ b/src/XrdUtils.cmake @@ -137,11 +137,12 @@ add_library( # XrdSut #----------------------------------------------------------------------------- XrdSut/XrdSutAux.cc XrdSut/XrdSutAux.hh - XrdSut/XrdSutCache.cc XrdSut/XrdSutCache.hh + XrdSut/XrdSutPFCache.cc XrdSut/XrdSutPFCache.hh XrdSut/XrdSutBucket.cc XrdSut/XrdSutBucket.hh XrdSut/XrdSutBuckList.cc XrdSut/XrdSutBuckList.hh XrdSut/XrdSutBuffer.cc XrdSut/XrdSutBuffer.hh XrdSut/XrdSutPFile.cc XrdSut/XrdSutPFile.hh + XrdSut/XrdSutCacheEntry.cc XrdSut/XrdSutCacheEntry.hh XrdSut/XrdSutPFEntry.cc XrdSut/XrdSutPFEntry.hh XrdSut/XrdSutRndm.cc XrdSut/XrdSutRndm.hh XrdSut/XrdSutTrace.hh