diff --git a/src/XrdCrypto/XrdCryptosslCipher.cc b/src/XrdCrypto/XrdCryptosslCipher.cc index a0f5de82f8b..cb282c7eaeb 100644 --- a/src/XrdCrypto/XrdCryptosslCipher.cc +++ b/src/XrdCrypto/XrdCryptosslCipher.cc @@ -902,6 +902,7 @@ bool XrdCryptosslCipher::Finalize(bool padded, EVP_PKEY_derive_set_peer(pkctx, peer); EVP_PKEY_derive(pkctx, (unsigned char *)ktmp, <mp); EVP_PKEY_CTX_free(pkctx); + EVP_PKEY_free(peer); if (ltmp > 0) { #if OPENSSL_VERSION_NUMBER < 0x10101000L if (padded) { diff --git a/src/XrdCrypto/XrdCryptosslRSA.cc b/src/XrdCrypto/XrdCryptosslRSA.cc index 13a48ccb933..54818139ac3 100644 --- a/src/XrdCrypto/XrdCryptosslRSA.cc +++ b/src/XrdCrypto/XrdCryptosslRSA.cc @@ -322,6 +322,8 @@ int XrdCryptosslRSA::ImportPrivate(const char *pri, int lpri) if (!fEVP) return -1; + + int rc = -1; prilen = -1; // Bio for exporting the pub key @@ -337,9 +339,10 @@ int XrdCryptosslRSA::ImportPrivate(const char *pri, int lpri) if (PEM_read_bio_PrivateKey(bpri, &fEVP, 0, 0)) { // Update status status = kComplete; - return 0; + rc = 0; } - return -1; + BIO_free(bpri); + return rc; } //_____________________________________________________________________________ diff --git a/src/XrdCrypto/XrdCryptosslgsiAux.cc b/src/XrdCrypto/XrdCryptosslgsiAux.cc index cef86cb1f0f..a88dbd900b8 100644 --- a/src/XrdCrypto/XrdCryptosslgsiAux.cc +++ b/src/XrdCrypto/XrdCryptosslgsiAux.cc @@ -42,6 +42,7 @@ #include #include #include +#include #include "XrdSut/XrdSutRndm.hh" #include "XrdCrypto/XrdCryptogsiX509Chain.hh" @@ -51,6 +52,26 @@ #include "XrdCrypto/XrdCryptosslX509.hh" #include "XrdCrypto/XrdCryptosslX509Req.hh" +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// +// // +// type aliases to ease use of smart pointers with common ssl structures // +// // +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// +static void stackOfX509ExtensionDelete(STACK_OF(X509_EXTENSION) *ske) { +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + sk_X509_EXTENSION_pop_free(ske, X509_EXTENSION_free); +#else /* OPENSSL */ + sk_pop_free(ske, X509_EXTENSION_free); +#endif /* OPENSSL */ +} +using EVP_PKEY_ptr = std::unique_ptr; +using X509_ptr = std::unique_ptr; +using X509_NAME_ptr = std::unique_ptr; +using X509_REQ_ptr = std::unique_ptr; +using X509_EXTENSION_ptr = std::unique_ptr; +using PROXY_CERT_INFO_EXTENSION_ptr = std::unique_ptr; +using STACK_OF_X509_EXTENSION_ptr = std::unique_ptr; + //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// // // // Extensions OID relevant for proxies // @@ -656,9 +677,20 @@ int XrdCryptosslX509CreateProxyReq(XrdCryptoX509 *xcpi, PRINT("EEC certificate has expired"); return -kErrPX_ExpiredEEC; } + + // These will be assigned dynamically allocated ssl structures later. + // They use type aliases for unique_ptr, to ease use of a smart pointer. + // + EVP_PKEY_ptr ekro(nullptr, &EVP_PKEY_free); + X509_EXTENSION_ptr ext(nullptr, &X509_EXTENSION_free); + X509_NAME_ptr psubj(nullptr, &X509_NAME_free); + X509_REQ_ptr xro(nullptr, &X509_REQ_free); + PROXY_CERT_INFO_EXTENSION_ptr pci(nullptr, &PROXY_CERT_INFO_EXTENSION_free); + STACK_OF_X509_EXTENSION_ptr esk(nullptr, &stackOfX509ExtensionDelete); + // // Create a new request - X509_REQ *xro = X509_REQ_new(); + xro.reset(X509_REQ_new()); if (!xro) { PRINT("cannot to create cert request"); return -kErrPX_NoResources; @@ -666,7 +698,10 @@ int XrdCryptosslX509CreateProxyReq(XrdCryptoX509 *xcpi, // // Use same num of bits as the signing certificate, but // less than 512 - int bits = EVP_PKEY_bits(X509_get_pubkey(xpi)); + ekro.reset(X509_get_pubkey(xpi)); + int bits = EVP_PKEY_bits(ekro.get()); + ekro = nullptr; + bits = (bits < 512) ? 512 : bits; // // Create the new PKI for the proxy (exponent 65537) @@ -676,7 +711,6 @@ int XrdCryptosslX509CreateProxyReq(XrdCryptoX509 *xcpi, return -kErrPX_GenerateKey; } BN_set_word(e, 0x10001); - EVP_PKEY *ekro = 0; EVP_PKEY_CTX *pkctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, 0); EVP_PKEY_keygen_init(pkctx); EVP_PKEY_CTX_set_rsa_keygen_bits(pkctx, bits); @@ -686,7 +720,11 @@ int XrdCryptosslX509CreateProxyReq(XrdCryptoX509 *xcpi, #else EVP_PKEY_CTX_set_rsa_keygen_pubexp(pkctx, e); #endif - EVP_PKEY_keygen(pkctx, &ekro); + { + EVP_PKEY *tmppk = nullptr; + EVP_PKEY_keygen(pkctx, &tmppk); + ekro.reset(tmppk); + } EVP_PKEY_CTX_free(pkctx); // // Set the key into the request @@ -694,7 +732,7 @@ int XrdCryptosslX509CreateProxyReq(XrdCryptoX509 *xcpi, PRINT("proxy key could not be generated - return"); return -kErrPX_GenerateKey; } - X509_REQ_set_pubkey(xro, ekro); + X509_REQ_set_pubkey(xro.get(), ekro.get()); // // Generate a serial number. Specification says that this *should* // unique, so we just draw an unsigned random integer @@ -704,16 +742,16 @@ int XrdCryptosslX509CreateProxyReq(XrdCryptoX509 *xcpi, // with is a random unsigned int used also as serial // number. // Duplicate user subject name - X509_NAME *psubj = X509_NAME_dup(X509_get_subject_name(xpi)); + psubj.reset(X509_NAME_dup(X509_get_subject_name(xpi))); if (xcro && *xcro && *((int *)(*xcro)) <= 10100) { // Delete existing proxy CN addition; for backward compatibility #if OPENSSL_VERSION_NUMBER >= 0x10000000L - int ne = X509_NAME_entry_count(psubj); + int ne = X509_NAME_entry_count(psubj.get()); #else /* OPENSSL */ int ne = psubj->entries->num; #endif /* OPENSSL */ if (ne >= 0) { - X509_NAME_ENTRY *cne = X509_NAME_delete_entry(psubj, ne-1); + X509_NAME_ENTRY *cne = X509_NAME_delete_entry(psubj.get(), ne-1); if (cne) { X509_NAME_ENTRY_free(cne); } else { @@ -725,21 +763,21 @@ int XrdCryptosslX509CreateProxyReq(XrdCryptoX509 *xcpi, // Create an entry with the common name unsigned char sn[20] = {0}; sprintf((char *)sn, "%d", serial); - if (!X509_NAME_add_entry_by_txt(psubj, (char *)"CN", MBSTRING_ASC, + if (!X509_NAME_add_entry_by_txt(psubj.get(), (char *)"CN", MBSTRING_ASC, sn, -1, -1, 0)) { PRINT("could not add CN - (serial: "<proxyPolicy->policyLanguage = OBJ_txt2obj("1.3.6.1.5.5.7.21.1", 1); // // Create a stack - STACK_OF(X509_EXTENSION) *esk = sk_X509_EXTENSION_new_null(); + esk.reset(sk_X509_EXTENSION_new_null()); if (!esk) { PRINT("could not create stack for extensions"); return -kErrPX_NoResources; @@ -780,11 +818,13 @@ int XrdCryptosslX509CreateProxyReq(XrdCryptoX509 *xcpi, inpci->pcPathLengthConstraint) indepthlen = ASN1_INTEGER_get(inpci->pcPathLengthConstraint); DEBUG("IN depth length: "<length = i2d_PROXY_CERT_INFO_EXTENSION(pci, 0); - if (!(X509_EXTENSION_get_data(ext)->data = (unsigned char *)malloc(X509_EXTENSION_get_data(ext)->length+1))) { + X509_EXTENSION_get_data(ext.get())->length = i2d_PROXY_CERT_INFO_EXTENSION(pci.get(), 0); + if (!(X509_EXTENSION_get_data(ext.get())->data = (unsigned char *)malloc(X509_EXTENSION_get_data(ext.get())->length+1))) { PRINT("could not allocate data field for extension"); return -kErrPX_NoResources; } - unsigned char *pp = X509_EXTENSION_get_data(ext)->data; - if ((i2d_PROXY_CERT_INFO_EXTENSION(pci, &pp)) <= 0) { + unsigned char *pp = X509_EXTENSION_get_data(ext.get())->data; + if ((i2d_PROXY_CERT_INFO_EXTENSION(pci.get(), &pp)) <= 0) { PRINT("problem converting data for extension"); return -kErrPX_Error; } + pci = nullptr; + // Set extension name. ASN1_OBJECT *obj = OBJ_txt2obj(gsiProxyCertInfo_OID, 1); - if (!obj || X509_EXTENSION_set_object(ext, obj) != 1) { + if (!obj || X509_EXTENSION_set_object(ext.get(), obj) != 1) { PRINT("could not set extension name"); + ASN1_OBJECT_free(obj); return -kErrPX_SetAttribute; } + ASN1_OBJECT_free(obj); + obj = 0; + // flag as critical - if (X509_EXTENSION_set_critical(ext, 1) != 1) { + if (X509_EXTENSION_set_critical(ext.get(), 1) != 1) { PRINT("could not set extension critical flag"); return -kErrPX_SetAttribute; } - if (sk_X509_EXTENSION_push(esk, ext) == 0) { + if (sk_X509_EXTENSION_push(esk.get(), ext.get()) == 0) { PRINT("could not push the extension in the stack"); return -kErrPX_Error; } + // ext resource now owned by esk + ext.release(); + // Add extensions - if (!(X509_REQ_add_extensions(xro, esk))) { + if (!(X509_REQ_add_extensions(xro.get(), esk.get()))) { PRINT("problem adding extension"); return -kErrPX_SetAttribute; } // // Sign the request - if (!(X509_REQ_sign(xro, ekro, EVP_sha256()))) { + if (!(X509_REQ_sign(xro.get(), ekro.get(), EVP_sha256()))) { PRINT("problems signing the request"); return -kErrPX_Signing; } // Prepare output - *xcro = new XrdCryptosslX509Req(xro); - *kcro = new XrdCryptosslRSA(ekro); + *xcro = new XrdCryptosslX509Req(xro.get()); + *kcro = new XrdCryptosslRSA(ekro.get()); - // Cleanup -#if OPENSSL_VERSION_NUMBER >= 0x10000000L - sk_X509_EXTENSION_pop_free(esk, X509_EXTENSION_free); -#else /* OPENSSL */ - sk_free(esk); -#endif /* OPENSSL */ + // xro, ekro resoruce now owned by *xcro and *kcro + xro.release(); + ekro.release(); // We are done return 0; @@ -900,9 +946,19 @@ int XrdCryptosslX509SignProxyReq(XrdCryptoX509 *xcpi, XrdCryptoRSA *kcpi, PRINT("inconsistent key loaded"); return -kErrPX_BadEECkey; } + + // These will be assigned dynamically allocated ssl structures later. + // They use type aliases for unique_ptr, to ease use of a smart pointer. + // + EVP_PKEY_ptr ekpi(nullptr, &EVP_PKEY_free); + X509_ptr xpo(nullptr, &X509_free); + X509_EXTENSION_ptr ext(nullptr, &X509_EXTENSION_free); + PROXY_CERT_INFO_EXTENSION_ptr pci(nullptr, &PROXY_CERT_INFO_EXTENSION_free); + STACK_OF_X509_EXTENSION_ptr xrisk(nullptr, &stackOfX509ExtensionDelete); + // Point to the cerificate #if OPENSSL_VERSION_NUMBER >= 0x30000000L - EVP_PKEY *ekpi = EVP_PKEY_dup((EVP_PKEY *)(kcpi->Opaque())); + ekpi.reset(EVP_PKEY_dup((EVP_PKEY *)(kcpi->Opaque()))); if (!ekpi) { PRINT("could not create a EVP_PKEY * instance - return"); return -kErrPX_NoResources; @@ -911,12 +967,12 @@ int XrdCryptosslX509SignProxyReq(XrdCryptoX509 *xcpi, XrdCryptoRSA *kcpi, RSA *kpi = EVP_PKEY_get0_RSA((EVP_PKEY *)(kcpi->Opaque())); // // Set the key into the request - EVP_PKEY *ekpi = EVP_PKEY_new(); + ekpi.reset(EVP_PKEY_new()); if (!ekpi) { PRINT("could not create a EVP_PKEY * instance - return"); return -kErrPX_NoResources; } - EVP_PKEY_set1_RSA(ekpi, kpi); + EVP_PKEY_set1_RSA(ekpi.get(), kpi); #endif // Get request in raw form @@ -960,50 +1016,50 @@ int XrdCryptosslX509SignProxyReq(XrdCryptoX509 *xcpi, XrdCryptoRSA *kcpi, unsigned int serial = (unsigned int)(strtol(sserial.c_str(), 0, 10)); // // Create new proxy cert - X509 *xpo = X509_new(); + xpo.reset(X509_new()); if (!xpo) { PRINT("could not create certificate object for proxies"); return -kErrPX_NoResources; } // Set version number - if (X509_set_version(xpo, 2L) != 1) { + if (X509_set_version(xpo.get(), 2L) != 1) { PRINT("could not set version"); return -kErrPX_SetAttribute; } // Set serial number - if (ASN1_INTEGER_set(X509_get_serialNumber(xpo), serial) != 1) { + if (ASN1_INTEGER_set(X509_get_serialNumber(xpo.get()), serial) != 1) { PRINT("could not set serial number"); return -kErrPX_SetAttribute; } // Set subject name - if (X509_set_subject_name(xpo, X509_REQ_get_subject_name(xri)) != 1) { + if (X509_set_subject_name(xpo.get(), X509_REQ_get_subject_name(xri)) != 1) { PRINT("could not set subject name"); return -kErrPX_SetAttribute; } // Set issuer name - if (X509_set_issuer_name(xpo, X509_get_subject_name(xpi)) != 1) { + if (X509_set_issuer_name(xpo.get(), X509_get_subject_name(xpi)) != 1) { PRINT("could not set issuer name"); return -kErrPX_SetAttribute; } // Set public key - if (X509_set_pubkey(xpo, X509_REQ_get_pubkey(xri)) != 1) { + if (X509_set_pubkey(xpo.get(), X509_REQ_get_pubkey(xri)) != 1) { PRINT("could not set public key"); return -kErrPX_SetAttribute; } // Set proxy validity: notBefore now - if (!X509_gmtime_adj(X509_get_notBefore(xpo), 0)) { + if (!X509_gmtime_adj(X509_get_notBefore(xpo.get()), 0)) { PRINT("could not set notBefore"); return -kErrPX_SetAttribute; } // Set proxy validity: notAfter timeleft from now - if (!X509_gmtime_adj(X509_get_notAfter(xpo), timeleft)) { + if (!X509_gmtime_adj(X509_get_notAfter(xpo.get()), timeleft)) { PRINT("could not set notAfter"); return -kErrPX_SetAttribute; } @@ -1033,6 +1089,7 @@ int XrdCryptosslX509SignProxyReq(XrdCryptoX509 *xcpi, XrdCryptoRSA *kcpi, inpci->pcPathLengthConstraint) indepthlen = ASN1_INTEGER_get(inpci->pcPathLengthConstraint); DEBUG("IN depth length: "<= 0x10000000L - int nriext = sk_X509_EXTENSION_num(xrisk); + int nriext = sk_X509_EXTENSION_num(xrisk.get()); #else /* OPENSSL */ - int nriext = sk_num(xrisk); + int nriext = sk_num(xrisk.get()); #endif /* OPENSSL */ if (nriext == 0 || !haskeyusage) { PRINT("wrong extensions in request: "<< nriext<<", "<pcPathLengthConstraint) reqdepthlen = ASN1_INTEGER_get(reqpci->pcPathLengthConstraint); + PROXY_CERT_INFO_EXTENSION_free(reqpci); } DEBUG("REQ depth length: "<length = i2d_PROXY_CERT_INFO_EXTENSION(pci, 0); - if (!(X509_EXTENSION_get_data(ext)->data = (unsigned char *)malloc(X509_EXTENSION_get_data(ext)->length+1))) { + X509_EXTENSION_get_data(ext.get())->length = i2d_PROXY_CERT_INFO_EXTENSION(pci.get(), 0); + if (!(X509_EXTENSION_get_data(ext.get())->data = (unsigned char *)malloc(X509_EXTENSION_get_data(ext.get())->length+1))) { PRINT("could not allocate data field for extension"); return -kErrPX_NoResources; } - unsigned char *pp = X509_EXTENSION_get_data(ext)->data; - if ((i2d_PROXY_CERT_INFO_EXTENSION(pci, &pp)) <= 0) { + unsigned char *pp = X509_EXTENSION_get_data(ext.get())->data; + if ((i2d_PROXY_CERT_INFO_EXTENSION(pci.get(), &pp)) <= 0) { PRINT("problem converting data for extension"); return -kErrPX_Error; } - PROXY_CERT_INFO_EXTENSION_free( pci ); + pci = nullptr; // Set extension name. ASN1_OBJECT *obj = OBJ_txt2obj(gsiProxyCertInfo_OID, 1); - if (!obj || X509_EXTENSION_set_object(ext, obj) != 1) { + if (!obj || X509_EXTENSION_set_object(ext.get(), obj) != 1) { PRINT("could not set extension name"); + ASN1_OBJECT_free( obj ); return -kErrPX_SetAttribute; } ASN1_OBJECT_free( obj ); + obj = 0; // flag as critical - if (X509_EXTENSION_set_critical(ext, 1) != 1) { + if (X509_EXTENSION_set_critical(ext.get(), 1) != 1) { PRINT("could not set extension critical flag"); return -kErrPX_SetAttribute; } - // Add the extension - if (X509_add_ext(xpo, ext, -1) == 0) { + // Add the extension (adds a copy of the extension) + if (X509_add_ext(xpo.get(), ext.get(), -1) == 0) { PRINT("could not add extension"); return -kErrPX_SetAttribute; } // // Sign the certificate - if (!(X509_sign(xpo, ekpi, EVP_sha256()))) { + if (!(X509_sign(xpo.get(), ekpi.get(), EVP_sha256()))) { PRINT("problems signing the certificate"); return -kErrPX_Signing; } - EVP_PKEY_free( ekpi ); // decrement reference counter - X509_EXTENSION_free( ext ); + ekpi = nullptr; + ext = nullptr; // Prepare outputs - *xcpo = new XrdCryptosslX509(xpo); + *xcpo = new XrdCryptosslX509(xpo.get()); - // Cleanup -#if OPENSSL_VERSION_NUMBER >= 0x10000000L - sk_X509_EXTENSION_free(xrisk); -#else /* OPENSSL */ - sk_free(xrisk); -#endif /* OPENSSL */ + // xpo resource is now owned by the *xcpo + xpo.release(); // We are done return 0; diff --git a/src/XrdSecgsi/XrdSecProtocolgsi.cc b/src/XrdSecgsi/XrdSecProtocolgsi.cc index 52d80a660b2..fe182057fb9 100644 --- a/src/XrdSecgsi/XrdSecProtocolgsi.cc +++ b/src/XrdSecgsi/XrdSecProtocolgsi.cc @@ -1080,7 +1080,7 @@ void XrdSecProtocolgsi::Delete() SafeDelete(sessionMD); // Message Digest instance SafeDelete(sessionKsig); // RSA key to sign SafeDelete(sessionKver); // RSA key to verify - if (proxyChain) proxyChain->Cleanup(1); + if (proxyChain) proxyChain->Cleanup(); SafeDelete(proxyChain); // Chain with delegated proxies SafeFree(expectedHost); @@ -3902,6 +3902,9 @@ int XrdSecProtocolgsi::ServerDoCert(XrdSutBuffer *br, XrdSutBuffer **bm, if (needReq || (hs->Options & kOptsFwdPxy)) { // Create a new proxy chain hs->PxyChain = new X509Chain(); + // The new chain must be deleted if still in the handshake info + // when the info is destroyed + hs->Options |= kOptsDelPxy; // Add the current proxy if ((*ParseBucket)(bck, hs->PxyChain) > 1) { // Reorder it @@ -3912,21 +3915,34 @@ int XrdSecProtocolgsi::ServerDoCert(XrdSutBuffer *br, XrdSutBuffer **bm, XrdCryptoRSA *krPXp = 0; if ((*X509CreateProxyReq)(hs->PxyChain->End(), &rPXp, &krPXp) == 0) { // Save key in the cache - hs->Cref->buf4.buf = (char *)krPXp; + hs->Cref->buf4.len = krPXp->GetPrilen() + 1; + hs->Cref->buf4.buf = new char[hs->Cref->buf4.len]; + if (krPXp->ExportPrivate(hs->Cref->buf4.buf, hs->Cref->buf4.len) != 0) { + delete krPXp; + delete rPXp; + if (hs->PxyChain) hs->PxyChain->Cleanup(); + SafeDelete(hs->PxyChain); + cmsg = "cannot export private key of the proxy request!"; + return -1; + } // Prepare export bucket for request XrdSutBucket *bckr = rPXp->Export(); // Add it to the main list if ((*bm)->AddBucket(bckr) != 0) { + if (hs->PxyChain) hs->PxyChain->Cleanup(); SafeDelete(hs->PxyChain); NOTIFY("WARNING: proxy req: problem adding bucket to main buffer"); } + delete krPXp; delete rPXp; } else { + if (hs->PxyChain) hs->PxyChain->Cleanup(); SafeDelete(hs->PxyChain); NOTIFY("WARNING: proxy req: problem creating request"); } } } else { + if (hs->PxyChain) hs->PxyChain->Cleanup(); SafeDelete(hs->PxyChain); NOTIFY("WARNING: proxy req: wrong number of certificates"); } @@ -4037,8 +4053,12 @@ int XrdSecProtocolgsi::ServerDoSigpxy(XrdSutBuffer *br, XrdSutBuffer **bm, return 0; } // Set full PKI - XrdCryptoRSA *knpx = (XrdCryptoRSA *)(hs->Cref->buf4.buf); - npx->SetPKI((XrdCryptoX509data)(knpx->Opaque())); + XrdCryptoRSA *const knpx = npx->PKI(); + if (!knpx || knpx->ImportPrivate(hs->Cref->buf4.buf, hs->Cref->buf4.len) != 0) { + delete npx; + cmsg = "could not import private key into signed request"; + return 0; + } // Add the new proxy ecert to the chain pxyc->PushBack(npx); } diff --git a/src/XrdSecgsi/XrdSecProtocolgsi.hh b/src/XrdSecgsi/XrdSecProtocolgsi.hh index 5c5ccfa0cd6..2c79f5aebe8 100644 --- a/src/XrdSecgsi/XrdSecProtocolgsi.hh +++ b/src/XrdSecgsi/XrdSecProtocolgsi.hh @@ -112,7 +112,8 @@ enum kgsiHandshakeOpts { kOptsPxFile = 16, // 0x0010: Save delegated proxies in file kOptsDelChn = 32, // 0x0020: Delete chain kOptsPxCred = 64, // 0x0040: Save delegated proxies as credentials - kOptsCreatePxy = 128 // 0x0080: Request a client proxy + kOptsCreatePxy = 128, // 0x0080: Request a client proxy + kOptsDelPxy = 256 // 0x0100: Delete the proxy PxyChain }; // Error codes @@ -540,9 +541,14 @@ public: XrdSecProtocolgsi::stackCRL->Del(Crl); Crl = 0; } - // The proxy chain is owned by the proxy cache; invalid proxies are - // detected (and eventually removed) by QueryProxy - PxyChain = 0; + if (Options & kOptsDelPxy) { + if (PxyChain) PxyChain->Cleanup(); + SafeDelete(PxyChain); + } else { + // The proxy chain is owned by the proxy cache; invalid proxies + // are detected (and eventually removed) by QueryProxy + PxyChain = 0; + } SafeDelete(Parms); } void Dump(XrdSecProtocolgsi *p = 0); };