Files
Mozilla/mozilla/security/manager/ssl/src/nsCertTree.cpp
relyea%netscape.com 493a0a3758 Bug 225034 Certificate Manager Crashes Mozilla [@ nsCertTree::CmpByCrit]
sr=brendan r=wtc a=dbaron

The issue is the use of the PL_DHash* functions. It's possible that a given call
to PL_DHashOperate which adds a new entry may cause the hash table to expand,
and all the existing entries to be reallocated. PL_DHash does this by allocating
new memory, then copying the entries.

getCacheEntry() returns one of these hash entries. CmpBy() makes two consecutive
calls to getCacheEntry, then uses the returned entries for it's comparisons. If
the second entry call causes a new entry to be added to the table, and causes
the hash table to expand, the pointer to the first entry we retrieved will point
to freed memory.

The fix is to make the usable entry a pointer in the hashtable entry, and return
that pointer. When the hashtable rebuilds it's entries, the pointer will be
copied to the new entry and not be disturbed.


git-svn-id: svn://10.0.0.236/trunk@177782 18797224-902f-48f8-a5cc-f745e15eee43
2005-08-15 21:23:51 +00:00

1095 lines
29 KiB
C++

/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape security libraries.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ian McGreer <mcgreer@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsNSSComponent.h" // for PIPNSS string bundle calls.
#include "nsCertTree.h"
#include "nsITreeColumns.h"
#include "nsIX509Cert.h"
#include "nsIX509CertValidity.h"
#include "nsIX509CertDB.h"
#include "nsXPIDLString.h"
#include "nsReadableUtils.h"
#include "nsNSSCertificate.h"
#include "nsNSSCertHelper.h"
#include "nsINSSCertCache.h"
#include "prlog.h"
#ifdef PR_LOGGING
extern PRLogModuleInfo* gPIPNSSLog;
#endif
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
// treeArrayElStr
//
// structure used to hold map of tree. Each thread (an organization
// field from a cert) has an element in the array. The numChildren field
// stores the number of certs corresponding to that thread.
struct treeArrayElStr {
nsString orgName; /* heading for thread */
PRBool open; /* toggle open state for thread */
PRInt32 certIndex; /* index into cert array for 1st cert */
PRInt32 numChildren; /* number of chidren (certs) for thread */
};
CompareCacheHashEntryPtr::CompareCacheHashEntryPtr()
{
entry = new CompareCacheHashEntry;
}
CompareCacheHashEntryPtr::~CompareCacheHashEntryPtr()
{
if (entry) {
delete entry;
}
}
CompareCacheHashEntry::CompareCacheHashEntry()
:key(nsnull)
{
for (int i = 0; i < max_criterions; ++i) {
mCritInit[i] = PR_FALSE;
}
}
PR_STATIC_CALLBACK(const void *)
CompareCacheGetKey(PLDHashTable *table, PLDHashEntryHdr *hdr)
{
CompareCacheHashEntryPtr *entryPtr = NS_STATIC_CAST(CompareCacheHashEntryPtr*, hdr);
return entryPtr->entry->key;
}
PR_STATIC_CALLBACK(PRBool)
CompareCacheMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
const void *key)
{
const CompareCacheHashEntryPtr *entryPtr = NS_STATIC_CAST(const CompareCacheHashEntryPtr*, hdr);
return entryPtr->entry->key == key;
}
PR_STATIC_CALLBACK(PRBool)
CompareCacheInitEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
const void *key)
{
new (hdr) CompareCacheHashEntryPtr();
CompareCacheHashEntryPtr *entryPtr = NS_STATIC_CAST(CompareCacheHashEntryPtr*, hdr);
if (!entryPtr->entry) {
return PR_FALSE;
}
entryPtr->entry->key = (void*)key;
return PR_TRUE;
}
PR_STATIC_CALLBACK(void)
CompareCacheClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
{
CompareCacheHashEntryPtr *entryPtr = NS_STATIC_CAST(CompareCacheHashEntryPtr*, hdr);
entryPtr->~CompareCacheHashEntryPtr();
}
static PLDHashTableOps gMapOps = {
PL_DHashAllocTable,
PL_DHashFreeTable,
CompareCacheGetKey,
PL_DHashVoidPtrKeyStub,
CompareCacheMatchEntry,
PL_DHashMoveEntryStub,
CompareCacheClearEntry,
PL_DHashFinalizeStub,
CompareCacheInitEntry
};
NS_IMPL_ISUPPORTS2(nsCertTree, nsICertTree, nsITreeView)
nsCertTree::nsCertTree() : mTreeArray(NULL)
{
mCompareCache.ops = nsnull;
mNSSComponent = do_GetService(kNSSComponentCID);
}
void nsCertTree::ClearCompareHash()
{
if (mCompareCache.ops) {
PL_DHashTableFinish(&mCompareCache);
mCompareCache.ops = nsnull;
}
}
nsresult nsCertTree::InitCompareHash()
{
ClearCompareHash();
if (!PL_DHashTableInit(&mCompareCache, &gMapOps, nsnull,
sizeof(CompareCacheHashEntryPtr), 128)) {
mCompareCache.ops = nsnull;
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
nsCertTree::~nsCertTree()
{
ClearCompareHash();
delete [] mTreeArray;
}
void
nsCertTree::FreeCertArray()
{
if (mCertArray) {
PRUint32 count;
nsresult rv = mCertArray->Count(&count);
if (NS_FAILED(rv))
{
NS_ASSERTION(0, "Count failed");
return;
}
PRInt32 i;
for (i = count - 1; i >= 0; i--)
{
mCertArray->RemoveElementAt(i);
}
}
}
CompareCacheHashEntry *
nsCertTree::getCacheEntry(void *cache, void *aCert)
{
PLDHashTable &aCompareCache = *NS_REINTERPRET_CAST(PLDHashTable*, cache);
CompareCacheHashEntryPtr *entryPtr =
NS_STATIC_CAST(CompareCacheHashEntryPtr*,
PL_DHashTableOperate(&aCompareCache, aCert, PL_DHASH_ADD));
return entryPtr ? entryPtr->entry : NULL;
}
void nsCertTree::RemoveCacheEntry(void *key)
{
PL_DHashTableOperate(&mCompareCache, key, PL_DHASH_REMOVE);
}
// CountOrganizations
//
// Count the number of different organizations encountered in the cert
// list.
PRInt32
nsCertTree::CountOrganizations()
{
PRUint32 i, certCount;
nsresult rv = mCertArray->Count(&certCount);
if (NS_FAILED(rv)) return -1;
if (certCount == 0) return 0;
nsCOMPtr<nsISupports> isupport = dont_AddRef(mCertArray->ElementAt(0));
nsCOMPtr<nsIX509Cert> orgCert = do_QueryInterface(isupport);
nsCOMPtr<nsIX509Cert> nextCert = nsnull;
PRInt32 orgCount = 1;
for (i=1; i<certCount; i++) {
isupport = dont_AddRef(mCertArray->ElementAt(i));
nextCert = do_QueryInterface(isupport);
// XXX we assume issuer org is always criterion 1
if (CmpBy(&mCompareCache, orgCert, nextCert, sort_IssuerOrg, sort_None, sort_None) != 0) {
orgCert = nextCert;
orgCount++;
}
}
return orgCount;
}
// GetThreadDescAtIndex
//
// If the row at index is an organization thread, return the collection
// associated with that thread. Otherwise, return null.
treeArrayEl *
nsCertTree::GetThreadDescAtIndex(PRInt32 index)
{
int i, idx=0;
if (index < 0) return nsnull;
for (i=0; i<mNumOrgs; i++) {
if (index == idx) {
return &mTreeArray[i];
}
if (mTreeArray[i].open) {
idx += mTreeArray[i].numChildren;
}
idx++;
if (idx > index) break;
}
return nsnull;
}
// GetCertAtIndex
//
// If the row at index is a cert, return that cert. Otherwise, return null.
nsIX509Cert *
nsCertTree::GetCertAtIndex(PRInt32 index)
{
int i, idx = 0, cIndex = 0, nc;
nsIX509Cert *rawPtr = nsnull;
if (index < 0) return nsnull;
// Loop over the threads
for (i=0; i<mNumOrgs; i++) {
if (index == idx) return nsnull; // index is for thread
idx++; // get past the thread
nc = (mTreeArray[i].open) ? mTreeArray[i].numChildren : 0;
if (index < idx + nc) { // cert is within range of this thread
PRInt32 certIndex = cIndex + index - idx;
nsCOMPtr<nsISupports> isupport =
dont_AddRef(mCertArray->ElementAt(certIndex));
nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(isupport);
rawPtr = cert;
NS_IF_ADDREF(rawPtr);
break;
}
if (mTreeArray[i].open)
idx += mTreeArray[i].numChildren;
cIndex += mTreeArray[i].numChildren;
if (idx > index) break;
}
return rawPtr;
}
nsCertTree::nsCertCompareFunc
nsCertTree::GetCompareFuncFromCertType(PRUint32 aType)
{
switch (aType) {
case nsIX509Cert::USER_CERT:
return CmpUserCert;
case nsIX509Cert::CA_CERT:
return CmpCACert;
case nsIX509Cert::EMAIL_CERT:
return CmpEmailCert;
case nsIX509Cert::SERVER_CERT:
default:
return CmpWebSiteCert;
}
}
PRBool
nsCertTree::GetCertsByTypeFromCertList(CERTCertList *aCertList,
PRUint32 aType,
nsCertCompareFunc aCertCmpFn,
void *aCertCmpFnArg,
nsISupportsArray **_certs)
{
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("GetCertsByTypeFromCertList"));
if (!aCertList)
return PR_FALSE;
nsCOMPtr<nsISupportsArray> certarray;
nsresult rv = NS_NewISupportsArray(getter_AddRefs(certarray));
if (NS_FAILED(rv)) return PR_FALSE;
CERTCertListNode *node;
int count = 0;
for (node = CERT_LIST_HEAD(aCertList);
!CERT_LIST_END(node, aCertList);
node = CERT_LIST_NEXT(node)) {
if (getCertType(node->cert) == aType) {
nsCOMPtr<nsIX509Cert> pipCert = new nsNSSCertificate(node->cert);
if (pipCert) {
int i;
for (i = 0; i < count; ++i) {
nsCOMPtr<nsIX509Cert> cert = do_QueryElementAt(certarray, i);
if ((*aCertCmpFn)(aCertCmpFnArg, pipCert, cert) < 0) {
break;
}
}
certarray->InsertElementAt(pipCert, i);
++count;
}
}
}
*_certs = certarray;
NS_ADDREF(*_certs);
return PR_TRUE;
}
PRBool
nsCertTree::GetCertsByType(PRUint32 aType,
nsCertCompareFunc aCertCmpFn,
void *aCertCmpFnArg,
nsISupportsArray **_certs)
{
nsNSSShutDownPreventionLock locker;
CERTCertList *certList = NULL;
nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
certList = PK11_ListCerts(PK11CertListUnique, cxt);
PRBool rv = GetCertsByTypeFromCertList(certList, aType, aCertCmpFn, aCertCmpFnArg, _certs);
if (certList)
CERT_DestroyCertList(certList);
return rv;
}
PRBool
nsCertTree::GetCertsByTypeFromCache(nsINSSCertCache *aCache,
PRUint32 aType,
nsCertCompareFunc aCertCmpFn,
void *aCertCmpFnArg,
nsISupportsArray **_certs)
{
NS_ENSURE_ARG_POINTER(aCache);
CERTCertList *certList = NS_REINTERPRET_CAST(CERTCertList*, aCache->GetCachedCerts());
if (!certList)
return NS_ERROR_FAILURE;
return GetCertsByTypeFromCertList(certList, aType, aCertCmpFn, aCertCmpFnArg, _certs);
}
// LoadCerts
//
// Load all of the certificates in the DB for this type. Sort them
// by token, organization, then common name.
NS_IMETHODIMP
nsCertTree::LoadCertsFromCache(nsINSSCertCache *aCache, PRUint32 aType)
{
if (mTreeArray) {
FreeCertArray();
delete [] mTreeArray;
mTreeArray = nsnull;
mNumRows = 0;
}
nsresult rv = InitCompareHash();
if (NS_FAILED(rv)) return rv;
rv = GetCertsByTypeFromCache(aCache, aType,
GetCompareFuncFromCertType(aType), &mCompareCache,
getter_AddRefs(mCertArray));
if (NS_FAILED(rv)) return rv;
return UpdateUIContents();
}
NS_IMETHODIMP
nsCertTree::LoadCerts(PRUint32 aType)
{
if (mTreeArray) {
FreeCertArray();
delete [] mTreeArray;
mTreeArray = nsnull;
mNumRows = 0;
}
nsresult rv = InitCompareHash();
if (NS_FAILED(rv)) return rv;
rv = GetCertsByType(aType,
GetCompareFuncFromCertType(aType), &mCompareCache,
getter_AddRefs(mCertArray));
if (NS_FAILED(rv)) return rv;
return UpdateUIContents();
}
nsresult
nsCertTree::UpdateUIContents()
{
PRUint32 count;
nsresult rv = mCertArray->Count(&count);
if (NS_FAILED(rv)) return rv;
mNumOrgs = CountOrganizations();
mTreeArray = new treeArrayEl[mNumOrgs];
if (!mTreeArray)
return NS_ERROR_OUT_OF_MEMORY;
PRUint32 j = 0;
nsCOMPtr<nsISupports> isupport = dont_AddRef(mCertArray->ElementAt(j));
nsCOMPtr<nsIX509Cert> orgCert = do_QueryInterface(isupport);
for (PRInt32 i=0; i<mNumOrgs; i++) {
orgCert->GetIssuerOrganization(mTreeArray[i].orgName);
mTreeArray[i].open = PR_TRUE;
mTreeArray[i].certIndex = j;
mTreeArray[i].numChildren = 1;
if (++j >= count) break;
isupport = dont_AddRef(mCertArray->ElementAt(j));
nsCOMPtr<nsIX509Cert> nextCert = do_QueryInterface(isupport);
while (0 == CmpBy(&mCompareCache, orgCert, nextCert, sort_IssuerOrg, sort_None, sort_None)) {
mTreeArray[i].numChildren++;
if (++j >= count) break;
isupport = dont_AddRef(mCertArray->ElementAt(j));
nextCert = do_QueryInterface(isupport);
}
orgCert = nextCert;
}
if (mTree) {
mTree->BeginUpdateBatch();
mTree->RowCountChanged(0, -mNumRows);
}
mNumRows = count + mNumOrgs;
if (mTree)
mTree->EndUpdateBatch();
return NS_OK;
}
NS_IMETHODIMP
nsCertTree::RemoveCert(PRUint32 index)
{
if (!mCertArray || !mTreeArray || index < 0) {
return NS_ERROR_FAILURE;
}
int i;
PRUint32 idx = 0, cIndex = 0, nc;
// Loop over the threads
for (i=0; i<mNumOrgs; i++) {
if (index == idx)
return NS_OK; // index is for thread
idx++; // get past the thread
nc = (mTreeArray[i].open) ? mTreeArray[i].numChildren : 0;
if (index < idx + nc) { // cert is within range of this thread
PRInt32 certIndex = cIndex + index - idx;
nsCOMPtr<nsISupports> isupport = dont_AddRef(mCertArray->ElementAt(certIndex));
RemoveCacheEntry(isupport);
mCertArray->RemoveElementAt(certIndex);
delete [] mTreeArray;
mTreeArray = nsnull;
return UpdateUIContents();
}
if (mTreeArray[i].open)
idx += mTreeArray[i].numChildren;
cIndex += mTreeArray[i].numChildren;
if (idx > index)
break;
}
return NS_ERROR_FAILURE;
}
//////////////////////////////////////////////////////////////////////////////
//
// Begin nsITreeView methods
//
/////////////////////////////////////////////////////////////////////////////
/* nsIX509Cert getCert(in unsigned long index); */
NS_IMETHODIMP
nsCertTree::GetCert(PRUint32 aIndex, nsIX509Cert **_cert)
{
NS_ENSURE_ARG(_cert);
*_cert = GetCertAtIndex(aIndex);
//nsCOMPtr<nsIX509Cert> cert = GetCertAtIndex(aIndex);
//if (cert) {
//*_cert = cert;
//NS_ADDREF(*_cert);
//}
return NS_OK;
}
/* readonly attribute long rowCount; */
NS_IMETHODIMP
nsCertTree::GetRowCount(PRInt32 *aRowCount)
{
if (!mTreeArray)
return NS_ERROR_NOT_INITIALIZED;
PRUint32 count = 0;
for (PRInt32 i=0; i<mNumOrgs; i++) {
if (mTreeArray[i].open) {
count += mTreeArray[i].numChildren;
}
count++;
}
*aRowCount = count;
return NS_OK;
}
/* attribute nsITreeSelection selection; */
NS_IMETHODIMP
nsCertTree::GetSelection(nsITreeSelection * *aSelection)
{
*aSelection = mSelection;
NS_IF_ADDREF(*aSelection);
return NS_OK;
}
NS_IMETHODIMP
nsCertTree::SetSelection(nsITreeSelection * aSelection)
{
mSelection = aSelection;
return NS_OK;
}
/* void getRowProperties (in long index, in nsISupportsArray properties); */
NS_IMETHODIMP
nsCertTree::GetRowProperties(PRInt32 index, nsISupportsArray *properties)
{
return NS_OK;
}
/* void getCellProperties (in long row, in nsITreeColumn col,
* in nsISupportsArray properties);
*/
NS_IMETHODIMP
nsCertTree::GetCellProperties(PRInt32 row, nsITreeColumn* col,
nsISupportsArray* properties)
{
return NS_OK;
}
/* void getColumnProperties (in nsITreeColumn col,
* in nsISupportsArray properties);
*/
NS_IMETHODIMP
nsCertTree::GetColumnProperties(nsITreeColumn* col,
nsISupportsArray* properties)
{
return NS_OK;
}
/* boolean isContainer (in long index); */
NS_IMETHODIMP
nsCertTree::IsContainer(PRInt32 index, PRBool *_retval)
{
if (!mTreeArray)
return NS_ERROR_NOT_INITIALIZED;
treeArrayEl *el = GetThreadDescAtIndex(index);
if (el) {
*_retval = PR_TRUE;
} else {
*_retval = PR_FALSE;
}
return NS_OK;
}
/* boolean isContainerOpen (in long index); */
NS_IMETHODIMP
nsCertTree::IsContainerOpen(PRInt32 index, PRBool *_retval)
{
if (!mTreeArray)
return NS_ERROR_NOT_INITIALIZED;
treeArrayEl *el = GetThreadDescAtIndex(index);
if (el && el->open) {
*_retval = PR_TRUE;
} else {
*_retval = PR_FALSE;
}
return NS_OK;
}
/* boolean isContainerEmpty (in long index); */
NS_IMETHODIMP
nsCertTree::IsContainerEmpty(PRInt32 index, PRBool *_retval)
{
*_retval = !mTreeArray;
return NS_OK;
}
/* boolean isSeparator (in long index); */
NS_IMETHODIMP
nsCertTree::IsSeparator(PRInt32 index, PRBool *_retval)
{
*_retval = PR_FALSE;
return NS_OK;
}
/* long getParentIndex (in long rowIndex); */
NS_IMETHODIMP
nsCertTree::GetParentIndex(PRInt32 rowIndex, PRInt32 *_retval)
{
if (!mTreeArray)
return NS_ERROR_NOT_INITIALIZED;
int i, idx = 0;
for (i = 0; i < mNumOrgs && idx < rowIndex; i++, idx++) {
if (mTreeArray[i].open) {
if (rowIndex <= idx + mTreeArray[i].numChildren) {
*_retval = idx;
return NS_OK;
}
idx += mTreeArray[i].numChildren;
}
}
*_retval = -1;
return NS_OK;
}
/* boolean hasNextSibling (in long rowIndex, in long afterIndex); */
NS_IMETHODIMP
nsCertTree::HasNextSibling(PRInt32 rowIndex, PRInt32 afterIndex,
PRBool *_retval)
{
if (!mTreeArray)
return NS_ERROR_NOT_INITIALIZED;
int i, idx = 0;
for (i = 0; i < mNumOrgs && idx <= rowIndex; i++, idx++) {
if (mTreeArray[i].open) {
idx += mTreeArray[i].numChildren;
if (afterIndex <= idx) {
*_retval = afterIndex < idx;
return NS_OK;
}
}
}
*_retval = PR_FALSE;
return NS_OK;
}
/* long getLevel (in long index); */
NS_IMETHODIMP
nsCertTree::GetLevel(PRInt32 index, PRInt32 *_retval)
{
if (!mTreeArray)
return NS_ERROR_NOT_INITIALIZED;
treeArrayEl *el = GetThreadDescAtIndex(index);
if (el) {
*_retval = 0;
} else {
*_retval = 1;
}
return NS_OK;
}
/* Astring getImageSrc (in long row, in nsITreeColumn col); */
NS_IMETHODIMP
nsCertTree::GetImageSrc(PRInt32 row, nsITreeColumn* col,
nsAString& _retval)
{
_retval.Truncate();
return NS_OK;
}
/* long getProgressMode (in long row, in nsITreeColumn col); */
NS_IMETHODIMP
nsCertTree::GetProgressMode(PRInt32 row, nsITreeColumn* col, PRInt32* _retval)
{
return NS_OK;
}
/* Astring getCellValue (in long row, in nsITreeColumn col); */
NS_IMETHODIMP
nsCertTree::GetCellValue(PRInt32 row, nsITreeColumn* col,
nsAString& _retval)
{
_retval.Truncate();
return NS_OK;
}
/* Astring getCellText (in long row, in nsITreeColumn col); */
NS_IMETHODIMP
nsCertTree::GetCellText(PRInt32 row, nsITreeColumn* col,
nsAString& _retval)
{
if (!mTreeArray)
return NS_ERROR_NOT_INITIALIZED;
nsresult rv;
_retval.Truncate();
const PRUnichar* colID;
col->GetIdConst(&colID);
treeArrayEl *el = GetThreadDescAtIndex(row);
if (el != nsnull) {
if (NS_LITERAL_STRING("certcol").Equals(colID))
_retval.Assign(el->orgName);
else
_retval.SetCapacity(0);
return NS_OK;
}
nsCOMPtr<nsIX509Cert> cert = dont_AddRef(GetCertAtIndex(row));
if (cert == nsnull) return NS_ERROR_FAILURE;
if (NS_LITERAL_STRING("certcol").Equals(colID)) {
rv = cert->GetCommonName(_retval);
if (NS_FAILED(rv) || _retval.IsEmpty()) {
// kaie: I didn't invent the idea to cut off anything before
// the first colon. :-)
nsAutoString nick;
rv = cert->GetNickname(nick);
nsAString::const_iterator start, end, end2;
nick.BeginReading(start);
nick.EndReading(end);
end2 = end;
if (FindInReadable(NS_LITERAL_STRING(":"), start, end)) {
// found. end points to the first char after the colon,
// that's what we want.
_retval = Substring(end, end2);
}
else {
_retval = nick;
}
}
} else if (NS_LITERAL_STRING("tokencol").Equals(colID)) {
rv = cert->GetTokenName(_retval);
} else if (NS_LITERAL_STRING("emailcol").Equals(colID)) {
rv = cert->GetEmailAddress(_retval);
} else if (NS_LITERAL_STRING("purposecol").Equals(colID) && mNSSComponent) {
PRUint32 verified;
nsAutoString theUsages;
rv = cert->GetUsagesString(PR_TRUE, &verified, theUsages); // ignore OCSP
if (NS_FAILED(rv)) {
verified = nsIX509Cert::NOT_VERIFIED_UNKNOWN;
}
switch (verified) {
case nsIX509Cert::VERIFIED_OK:
_retval = theUsages;
break;
case nsIX509Cert::CERT_REVOKED:
rv = mNSSComponent->GetPIPNSSBundleString("VerifyRevoked", _retval);
break;
case nsIX509Cert::CERT_EXPIRED:
rv = mNSSComponent->GetPIPNSSBundleString("VerifyExpired", _retval);
break;
case nsIX509Cert::CERT_NOT_TRUSTED:
rv = mNSSComponent->GetPIPNSSBundleString("VerifyNotTrusted", _retval);
break;
case nsIX509Cert::ISSUER_NOT_TRUSTED:
rv = mNSSComponent->GetPIPNSSBundleString("VerifyIssuerNotTrusted", _retval);
break;
case nsIX509Cert::ISSUER_UNKNOWN:
rv = mNSSComponent->GetPIPNSSBundleString("VerifyIssuerUnknown", _retval);
break;
case nsIX509Cert::INVALID_CA:
rv = mNSSComponent->GetPIPNSSBundleString("VerifyInvalidCA", _retval);
break;
case nsIX509Cert::NOT_VERIFIED_UNKNOWN:
case nsIX509Cert::USAGE_NOT_ALLOWED:
default:
rv = mNSSComponent->GetPIPNSSBundleString("VerifyUnknown", _retval);
break;
}
} else if (NS_LITERAL_STRING("issuedcol").Equals(colID)) {
nsCOMPtr<nsIX509CertValidity> validity;
rv = cert->GetValidity(getter_AddRefs(validity));
if (NS_SUCCEEDED(rv)) {
validity->GetNotBeforeLocalDay(_retval);
}
} else if (NS_LITERAL_STRING("expiredcol").Equals(colID)) {
nsCOMPtr<nsIX509CertValidity> validity;
rv = cert->GetValidity(getter_AddRefs(validity));
if (NS_SUCCEEDED(rv)) {
validity->GetNotAfterLocalDay(_retval);
}
} else if (NS_LITERAL_STRING("serialnumcol").Equals(colID)) {
rv = cert->GetSerialNumber(_retval);
} else {
return NS_ERROR_FAILURE;
}
return rv;
}
/* void setTree (in nsITreeBoxObject tree); */
NS_IMETHODIMP
nsCertTree::SetTree(nsITreeBoxObject *tree)
{
mTree = tree;
return NS_OK;
}
/* void toggleOpenState (in long index); */
NS_IMETHODIMP
nsCertTree::ToggleOpenState(PRInt32 index)
{
if (!mTreeArray)
return NS_ERROR_NOT_INITIALIZED;
treeArrayEl *el = GetThreadDescAtIndex(index);
if (el) el->open = !el->open;
PRInt32 fac = (el->open) ? 1 : -1;
if (mTree) mTree->RowCountChanged(index, fac * el->numChildren);
mSelection->Select(index);
return NS_OK;
}
/* void cycleHeader (in nsITreeColumn); */
NS_IMETHODIMP
nsCertTree::CycleHeader(nsITreeColumn* col)
{
return NS_OK;
}
/* void selectionChanged (); */
NS_IMETHODIMP
nsCertTree::SelectionChanged()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* void cycleCell (in long row, in nsITreeColumn col); */
NS_IMETHODIMP
nsCertTree::CycleCell(PRInt32 row, nsITreeColumn* col)
{
return NS_OK;
}
/* boolean isEditable (in long row, in nsITreeColumn col); */
NS_IMETHODIMP
nsCertTree::IsEditable(PRInt32 row, nsITreeColumn* col, PRBool *_retval)
{
*_retval = PR_FALSE;
return NS_OK;
}
/* void setCellValue (in long row, in nsITreeColumn col, in AString value); */
NS_IMETHODIMP
nsCertTree::SetCellValue(PRInt32 row, nsITreeColumn* col,
const nsAString& value)
{
return NS_OK;
}
/* void setCellText (in long row, in nsITreeColumn col, in AString value); */
NS_IMETHODIMP
nsCertTree::SetCellText(PRInt32 row, nsITreeColumn* col,
const nsAString& value)
{
return NS_OK;
}
/* void performAction (in wstring action); */
NS_IMETHODIMP
nsCertTree::PerformAction(const PRUnichar *action)
{
return NS_OK;
}
/* void performActionOnRow (in wstring action, in long row); */
NS_IMETHODIMP
nsCertTree::PerformActionOnRow(const PRUnichar *action, PRInt32 row)
{
return NS_OK;
}
/* void performActionOnCell (in wstring action, in long row,
* in wstring colID);
*/
NS_IMETHODIMP
nsCertTree::PerformActionOnCell(const PRUnichar *action, PRInt32 row,
nsITreeColumn* col)
{
return NS_OK;
}
#ifdef DEBUG_CERT_TREE
void
nsCertTree::dumpMap()
{
for (int i=0; i<mNumOrgs; i++) {
nsAutoString org(mTreeArray[i].orgName);
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("ORG[%s]", NS_LossyConvertUCS2toASCII(org).get()));
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("OPEN[%d]", mTreeArray[i].open));
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("INDEX[%d]", mTreeArray[i].certIndex));
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NCHILD[%d]", mTreeArray[i].numChildren));
}
for (int i=0; i<mNumRows; i++) {
treeArrayEl *el = GetThreadDescAtIndex(i);
if (el != nsnull) {
nsAutoString td(el->orgName);
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("thread desc[%d]: %s", i, NS_LossyConvertUCS2toASCII(td).get()));
}
nsCOMPtr<nsIX509Cert> ct = dont_AddRef(GetCertAtIndex(i));
if (ct != nsnull) {
PRUnichar *goo;
ct->GetCommonName(&goo);
nsAutoString doo(goo);
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("cert [%d]: %s", i, NS_LossyConvertUCS2toASCII(doo).get()));
}
}
}
#endif
//
// CanDrop
//
NS_IMETHODIMP nsCertTree::CanDrop(PRInt32 index, PRInt32 orientation, PRBool *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = PR_FALSE;
return NS_OK;
}
//
// Drop
//
NS_IMETHODIMP nsCertTree::Drop(PRInt32 row, PRInt32 orient)
{
return NS_OK;
}
//
// IsSorted
//
// ...
//
NS_IMETHODIMP nsCertTree::IsSorted(PRBool *_retval)
{
*_retval = PR_FALSE;
return NS_OK;
}
#define RETURN_NOTHING
void
nsCertTree::CmpInitCriterion(nsIX509Cert *cert, CompareCacheHashEntry *entry,
sortCriterion crit, PRInt32 level)
{
NS_ENSURE_TRUE( (cert!=0 && entry!=0), RETURN_NOTHING );
entry->mCritInit[level] = PR_TRUE;
nsXPIDLString &str = entry->mCrit[level];
switch (crit) {
case sort_IssuerOrg:
cert->GetIssuerOrganization(str);
break;
case sort_Org:
cert->GetOrganization(str);
break;
case sort_Token:
cert->GetTokenName(str);
break;
case sort_CommonName:
cert->GetCommonName(str);
break;
case sort_IssuedDateDescending:
{
nsresult rv;
nsCOMPtr<nsIX509CertValidity> validity;
PRTime notBefore;
rv = cert->GetValidity(getter_AddRefs(validity));
if (NS_SUCCEEDED(rv)) {
rv = validity->GetNotBefore(&notBefore);
}
if (NS_SUCCEEDED(rv)) {
PRExplodedTime explodedTime;
PR_ExplodeTime(notBefore, PR_GMTParameters, &explodedTime);
char datebuf[20]; // 4 + 2 + 2 + 2 + 2 + 2 + 1 = 15
if (0 != PR_FormatTime(datebuf, sizeof(datebuf), "%Y%m%d%H%M%S", &explodedTime)) {
str = NS_ConvertASCIItoUCS2(nsDependentCString(datebuf));
}
}
}
break;
case sort_Email:
cert->GetEmailAddress(str);
break;
case sort_None:
default:
break;
}
}
PRInt32
nsCertTree::CmpByCrit(nsIX509Cert *a, CompareCacheHashEntry *ace,
nsIX509Cert *b, CompareCacheHashEntry *bce,
sortCriterion crit, PRInt32 level)
{
NS_ENSURE_TRUE( (a!=0 && ace!=0 && b!=0 && bce!=0), 0 );
if (!ace->mCritInit[level]) {
CmpInitCriterion(a, ace, crit, level);
}
if (!bce->mCritInit[level]) {
CmpInitCriterion(b, bce, crit, level);
}
nsXPIDLString &str_a = ace->mCrit[level];
nsXPIDLString &str_b = bce->mCrit[level];
PRInt32 result;
if (str_a && str_b)
result = Compare(str_a, str_b);
else
result = !str_a ? (!str_b ? 0 : -1) : 1;
if (sort_IssuedDateDescending == crit)
result *= -1; // reverse compare order
return result;
}
PRInt32
nsCertTree::CmpBy(void *cache, nsIX509Cert *a, nsIX509Cert *b,
sortCriterion c0, sortCriterion c1, sortCriterion c2)
{
NS_ENSURE_TRUE( (cache!=0 && a!=0 && b!=0), 0 );
if (a == b)
return 0;
CompareCacheHashEntry *ace = getCacheEntry(cache, a);
CompareCacheHashEntry *bce = getCacheEntry(cache, b);
PRInt32 cmp;
cmp = CmpByCrit(a, ace, b, bce, c0, 0);
if (cmp != 0)
return cmp;
if (c1 != sort_None) {
cmp = CmpByCrit(a, ace, b, bce, c1, 1);
if (cmp != 0)
return cmp;
if (c2 != sort_None) {
return CmpByCrit(a, ace, b, bce, c2, 2);
}
}
return cmp;
}
PRInt32
nsCertTree::CmpCACert(void *cache, nsIX509Cert *a, nsIX509Cert *b)
{
// XXX we assume issuer org is always criterion 1
return CmpBy(cache, a, b, sort_IssuerOrg, sort_Org, sort_Token);
}
PRInt32
nsCertTree::CmpWebSiteCert(void *cache, nsIX509Cert *a, nsIX509Cert *b)
{
// XXX we assume issuer org is always criterion 1
return CmpBy(cache, a, b, sort_IssuerOrg, sort_CommonName, sort_None);
}
PRInt32
nsCertTree::CmpUserCert(void *cache, nsIX509Cert *a, nsIX509Cert *b)
{
// XXX we assume issuer org is always criterion 1
return CmpBy(cache, a, b, sort_IssuerOrg, sort_Token, sort_IssuedDateDescending);
}
PRInt32
nsCertTree::CmpEmailCert(void *cache, nsIX509Cert *a, nsIX509Cert *b)
{
// XXX we assume issuer org is always criterion 1
return CmpBy(cache, a, b, sort_IssuerOrg, sort_Email, sort_CommonName);
}