673 lines
18 KiB
C++
673 lines
18 KiB
C++
// This file is the metadata version of the key storage object for the w3 server.
|
||
// it knows nothing about the LSA storage and only interacts with the metabase. Likewise,
|
||
// it does not convert old keyset.exe keys into a newer format. Any old LSA keys should have
|
||
// automatically converted to the new metabase format by the setup utility.
|
||
|
||
// file created 4/1/1997 by BoydM
|
||
|
||
#include "stdafx.h"
|
||
#include "KeyObjs.h"
|
||
|
||
#include "iiscnfgp.h"
|
||
#include "wrapmb.h"
|
||
|
||
#include "cmnkey.h"
|
||
#include "mdkey.h"
|
||
#include "mdserv.h"
|
||
|
||
#include "crackcrt.h"
|
||
|
||
#include "resource.h"
|
||
|
||
#include "ListRow.h"
|
||
#include "bindsdlg.h"
|
||
|
||
IMPLEMENT_DYNCREATE(CMDKey, CKey);
|
||
#define MAX_LEN (METADATA_MAX_NAME_LEN * sizeof(WCHAR))
|
||
|
||
#define DEFAULT_PORT 443
|
||
|
||
extern HINSTANCE g_hInstance;
|
||
|
||
//--------------------------------------------------------
|
||
CMDKey::CMDKey() :
|
||
m_fUpdateKeys( FALSE ),
|
||
m_fUpdateFriendlyName( FALSE ),
|
||
m_fUpdateIdent( FALSE ),
|
||
m_fUpdateBindings( FALSE ),
|
||
m_pService( NULL )
|
||
{}
|
||
|
||
//--------------------------------------------------------
|
||
CMDKey::CMDKey(CMDKeyService* pService) :
|
||
m_fUpdateKeys( FALSE ),
|
||
m_fUpdateFriendlyName( FALSE ),
|
||
m_fUpdateIdent( FALSE ),
|
||
m_fUpdateBindings( FALSE ),
|
||
m_pService( pService )
|
||
{}
|
||
|
||
//--------------------------------------------------------
|
||
CMDKey::~CMDKey()
|
||
{}
|
||
|
||
//-------------------------------------------------------------
|
||
void CMDKey::SetName( CString &szNewName )
|
||
{
|
||
CCmnKey::SetName( szNewName );
|
||
m_fUpdateFriendlyName = TRUE;
|
||
}
|
||
|
||
//-------------------------------------------------------------
|
||
// update the key's caption
|
||
void CMDKey::UpdateCaption( void )
|
||
{
|
||
// specify the resources to use
|
||
HINSTANCE hOldRes = AfxGetResourceHandle();
|
||
AfxSetResourceHandle( g_hInstance );
|
||
|
||
CString sz;
|
||
// the caption is based on the name of the key
|
||
CString szCaption = m_szName;
|
||
|
||
// now we tack on info about the server it is attached to
|
||
szCaption += _T(" <");
|
||
switch( m_rgbszBindings.GetSize() )
|
||
{
|
||
case 0: // there are no bindings, do nothing
|
||
sz.Empty();
|
||
break;
|
||
case 1: // if there is only one binding, use it in the brackets
|
||
sz = m_rgbszBindings[0];
|
||
// actually, we need to see if it is the non-localized default string
|
||
if ( sz == MDNAME_DEFAULT )
|
||
sz.LoadString( IDS_DEFAULT ); // load the localized default string
|
||
break;
|
||
default: // there are multiple bindings, say so
|
||
sz.LoadString( IDS_MULTIPLE_BINDINGS );
|
||
break;
|
||
};
|
||
// close the brackets
|
||
szCaption += sz;
|
||
szCaption += _T(">");
|
||
|
||
// and setup the caption
|
||
m_szItemName = szCaption;
|
||
FSetCaption(szCaption);
|
||
|
||
// update the icon too
|
||
UpdateIcon();
|
||
|
||
// restore the resources
|
||
AfxSetResourceHandle( hOldRes );
|
||
}
|
||
|
||
//-------------------------------------------------------------
|
||
// make a copy of the key
|
||
//-------------------------------------------------------------
|
||
CKey* CMDKey::PClone( void )
|
||
{
|
||
CMDKey* pClone = NULL;
|
||
|
||
// TRY to make a new key object
|
||
try
|
||
{
|
||
pClone = new CMDKey(m_pService);
|
||
|
||
// copy over all the data
|
||
pClone->CopyDataFrom( this );
|
||
}
|
||
catch( CException e )
|
||
{
|
||
// if the object had been made, delete it
|
||
if ( pClone )
|
||
delete pClone;
|
||
return NULL;
|
||
}
|
||
|
||
return (CKey*)pClone;
|
||
}
|
||
|
||
//-------------------------------------------------------------
|
||
// copy the members from a key into this key
|
||
//-------------------------------------------------------------
|
||
void CMDKey::CopyDataFrom( CKey* pKey )
|
||
{
|
||
// copy over the base data
|
||
CKey::CopyDataFrom( pKey );
|
||
|
||
// if the key we are copying from is a MD key, copy over
|
||
// the w3MD specific information as well
|
||
if ( pKey->IsKindOf(RUNTIME_CLASS(CMDKey)) )
|
||
{
|
||
CMDKey* pMDKey = (CMDKey*)pKey;
|
||
m_szName = pMDKey->m_szName;
|
||
}
|
||
else
|
||
{
|
||
m_szName = pKey->m_szItemName;
|
||
}
|
||
}
|
||
|
||
|
||
//-------------------------------------------------------------
|
||
void CMDKey::OnProperties()
|
||
{
|
||
// specify the resources to use
|
||
HINSTANCE hOldRes = AfxGetResourceHandle();
|
||
AfxSetResourceHandle( g_hInstance );
|
||
|
||
|
||
// if this key does not have a signed certificate, do not allow the user
|
||
// to make any bindings to it
|
||
if ( !m_pCertificate )
|
||
{
|
||
AfxMessageBox( IDS_DONT_BIND_UNSIGNED );
|
||
// restore the resources
|
||
AfxSetResourceHandle( hOldRes );
|
||
return;
|
||
}
|
||
|
||
// the properties of the w3 key invove its ip address relationship
|
||
CBindingsDlg dlg( m_pService->m_pszwMachineName );
|
||
|
||
// give it this key
|
||
dlg.m_pKey = this;
|
||
|
||
// set the instance members of the dialog
|
||
// run the dialog
|
||
if ( dlg.DoModal() == IDOK )
|
||
{
|
||
// cause the name to rebuild
|
||
UpdateCaption();
|
||
|
||
// set it dirty
|
||
SetDirty( TRUE );
|
||
}
|
||
|
||
// restore the resources
|
||
AfxSetResourceHandle( hOldRes );
|
||
}
|
||
|
||
//--------------------------------------------------------
|
||
// add a binding to the binding list
|
||
void CMDKey::AddBinding( LPCSTR psz )
|
||
{
|
||
CString szBinding = psz;
|
||
|
||
// filter out disabled or incomplete key bindings
|
||
if ( (szBinding.Find(MDNAME_INCOMPLETE) >= 0) ||
|
||
(szBinding.Find(MDNAME_DISABLED) >= 0) )
|
||
{
|
||
return;
|
||
}
|
||
|
||
// add the binding to the list
|
||
m_rgbszBindings.Add( psz );
|
||
|
||
// update the caption if we need to
|
||
switch( m_rgbszBindings.GetSize() )
|
||
{
|
||
case 1: // the display changes on these
|
||
case 2:
|
||
UpdateCaption();
|
||
};
|
||
}
|
||
|
||
//--------------------------------------------------------
|
||
// is a given binding already associated with the key
|
||
void CMDKey::RemoveBinding( CString szBinding )
|
||
{
|
||
DWORD nItems, iItem;
|
||
|
||
// scan the binding list
|
||
nItems = m_rgbszBindings.GetSize();
|
||
for ( iItem = 0; iItem < nItems; iItem++ )
|
||
{
|
||
// look for the binding
|
||
if ( szBinding == m_rgbszBindings[iItem] )
|
||
{
|
||
// found it!
|
||
m_rgbszBindings.RemoveAt( iItem );
|
||
m_fUpdateBindings = TRUE;
|
||
|
||
// update the caption if we need to
|
||
switch( m_rgbszBindings.GetSize() )
|
||
{
|
||
case 0: // the display changes on these
|
||
case 1:
|
||
UpdateCaption();
|
||
};
|
||
}
|
||
}
|
||
}
|
||
|
||
//--------------------------------------------------------
|
||
// is a given binding already associated with the key
|
||
BOOL CMDKey::FContainsBinding( CString szBinding )
|
||
{
|
||
DWORD nItems, iItem;
|
||
|
||
// scan the binding list
|
||
nItems = m_rgbszBindings.GetSize();
|
||
for ( iItem = 0; iItem < nItems; iItem++ )
|
||
{
|
||
// look for the binding
|
||
if ( szBinding == m_rgbszBindings[iItem] )
|
||
{
|
||
// found it!
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
// we did not find the binding
|
||
return FALSE;
|
||
}
|
||
|
||
//--------------------------------------------------------
|
||
BOOL CMDKey::FGetIdentString( CString &szIdent )
|
||
{
|
||
// make sure the cert is there
|
||
if ( !m_pCertificate || !m_cbCertificate )
|
||
return FALSE;
|
||
return FGetIdentString( m_pCertificate, m_cbCertificate, szIdent );
|
||
}
|
||
|
||
//--------------------------------------------------------
|
||
BOOL CMDKey::FGetIdentString( PVOID pCert, DWORD cbCert, CString &szIdent )
|
||
{
|
||
// declare the cracker object
|
||
CCrackedCert cracker;
|
||
// crack the cert
|
||
if ( cracker.CrackCert( (PUCHAR)pCert, cbCert ) )
|
||
{
|
||
DWORD* pdw = cracker.PGetSerialNumber();
|
||
szIdent.Format( "%d:%d:%d:%d", pdw[0], pdw[1], pdw[2], pdw[3] );
|
||
// success
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
//--------------------------------------------------------
|
||
// does a given key name exist already in the metabase?
|
||
BOOL CMDKey::FGetIdentString( CWrapMetaBase* pWrap, PCHAR pszObj, CString &szIdent )
|
||
{
|
||
BOOL fAnswer = FALSE;
|
||
DWORD cbData;
|
||
PVOID pData;
|
||
CString sz;
|
||
|
||
// if this is an incomplete key, fail
|
||
if ( _tcsncmp(MDNAME_INCOMPLETE, pszObj, _tcslen(MDNAME_INCOMPLETE)) == 0 )
|
||
return FALSE;
|
||
|
||
// try and ready the cached ident directly.
|
||
BOOL f = pWrap->GetString( pszObj, MD_SSL_IDENT, IIS_MD_UT_SERVER,
|
||
sz.GetBuffer(MAX_LEN), MAX_LEN);
|
||
sz.ReleaseBuffer();
|
||
if ( f )
|
||
{
|
||
// good. It was cached.
|
||
szIdent = sz;
|
||
m_szIdent = szIdent;
|
||
return TRUE;
|
||
}
|
||
|
||
// drat. We haven't cached the ident for this key before. we need to get it. This
|
||
// means loading the certificate - and cracking it to get the serial number. If there
|
||
// is no certificate (an incomplete key) we return false.
|
||
pData = pWrap->GetData( pszObj, MD_SSL_PUBLIC_KEY, IIS_MD_UT_SERVER,
|
||
BINARY_METADATA, &cbData, 0 );
|
||
// we got the certificate and can now crack it
|
||
if ( pData )
|
||
{
|
||
m_fUpdateIdent = FGetIdentString( (PUCHAR)pData, cbData, szIdent );
|
||
fAnswer = m_fUpdateIdent;
|
||
// cache the ident in memory. It will get written out on Commit
|
||
m_szIdent = szIdent;
|
||
/*
|
||
// declare the cracker object
|
||
CCrackedCert cracker;
|
||
// crack the cert
|
||
if ( cracker.CrackCert( (PUCHAR)pData, cbData ) )
|
||
{
|
||
DWORD* pdw = cracker.PGetSerialNumber();
|
||
szIdent.Format( "%d:%d:%d:%d", pdw[0], pdw[1], pdw[2], pdw[3] );
|
||
// cache the ident in memory. It will get written out on Commit
|
||
m_szIdent = szIdent;
|
||
m_fUpdateIdent = TRUE;
|
||
// success
|
||
fAnswer = TRUE;
|
||
}
|
||
*/
|
||
// free the buffer
|
||
pWrap->FreeWrapData( pData );
|
||
}
|
||
else
|
||
{
|
||
// we did not get the certificate - return FALSE
|
||
// fAnswer is already set to false
|
||
}
|
||
|
||
// return the answer;
|
||
return fAnswer;
|
||
}
|
||
|
||
//--------------------------------------------------------
|
||
BOOL CMDKey::FWriteKey( CWrapMetaBase* pWrap, DWORD iKey, CStringArray* prgbszTracker )
|
||
{
|
||
BOOL f;
|
||
DWORD nBindings = m_rgbszBindings.GetSize();
|
||
CString szBinding;
|
||
BOOL fUpdateAll = FALSE;
|
||
|
||
// if there are no assigned bindings, the key still gets stored with a object
|
||
// name in the format of "disabled{iKey}". and if it is incomplete, then store
|
||
// it with the name "incomplete{iKey}" Because the iKey can change and we don't
|
||
// want any conflicts, re-write them
|
||
if ( nBindings == 0 )
|
||
{
|
||
// build the binding name as appropriate
|
||
if ( m_pCertificate )
|
||
szBinding.Format( "%s%d", MDNAME_DISABLED, iKey );
|
||
else
|
||
szBinding.Format( "%s%d", MDNAME_INCOMPLETE, iKey );
|
||
|
||
// set the update flag
|
||
m_fUpdateBindings = TRUE;
|
||
}
|
||
|
||
// NOTE: pWrap has already been opened to /LM/W3Svc/SSLKeys
|
||
// if the key is not dirty, its easy
|
||
if ( !m_fUpdateKeys && !m_fUpdateFriendlyName && !m_fUpdateIdent && !m_fUpdateBindings && !FGetDirty() )
|
||
{
|
||
// add names of its bindings so it doesn't get deleted
|
||
DWORD iBinding;
|
||
for ( iBinding = 0; iBinding < nBindings; iBinding++ )
|
||
prgbszTracker->Add( m_rgbszBindings[iBinding] );
|
||
return TRUE;
|
||
}
|
||
|
||
// handle no bindings as a special case first
|
||
if ( nBindings == 0 )
|
||
{
|
||
// tell the server about it
|
||
prgbszTracker->Add((LPCSTR)szBinding);
|
||
// ok. Create the key in the metabase.
|
||
f = pWrap->AddObject( szBinding );
|
||
// and save the data
|
||
f = FWriteData( pWrap, szBinding, TRUE );
|
||
// clear the dirty flag and exit
|
||
SetDirty( FALSE );
|
||
return TRUE;
|
||
}
|
||
|
||
// there are bindings to be saved... loop though them and update each
|
||
DWORD iBinding;
|
||
for ( iBinding = 0; iBinding < nBindings; iBinding++ )
|
||
{
|
||
// get the binding name
|
||
szBinding = m_rgbszBindings[iBinding];
|
||
|
||
|
||
// test code
|
||
if ( szBinding.IsEmpty() )
|
||
AfxMessageBox( "Empty Binding Alert!" );
|
||
|
||
|
||
// now that we know where to save it, add the name to list of saved
|
||
// objects being kept track of by the server object - (This is so that
|
||
// the server knows what's been added)
|
||
prgbszTracker->Add((LPCSTR)szBinding);
|
||
|
||
// ok. Create the key in the metabase. Really, we may only need to do this
|
||
// if m_fUpdateBindings is set - if the object is new - update all the data
|
||
fUpdateAll = pWrap->AddObject( szBinding ) || m_fUpdateBindings;
|
||
|
||
// write out the data
|
||
FWriteData( pWrap, szBinding, fUpdateAll );
|
||
}
|
||
|
||
// clear the flags
|
||
m_fUpdateKeys = FALSE;
|
||
m_fUpdateFriendlyName = FALSE;
|
||
m_fUpdateIdent = FALSE;
|
||
m_fUpdateBindings = FALSE;
|
||
|
||
// clear the dirty flag
|
||
SetDirty( FALSE );
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
//--------------------------------------------------------
|
||
// write out the data portion to a particular binding
|
||
BOOL CMDKey::FWriteData( CWrapMetaBase* pWrap, CString szBinding, BOOL fWriteAll )
|
||
{
|
||
BOOL f;
|
||
// write all the parts of the key - start with the certificate
|
||
|
||
// start with the secure parts
|
||
if ( m_fUpdateKeys || fWriteAll )
|
||
{
|
||
if ( m_pCertificate )
|
||
f = pWrap->SetData( szBinding, MD_SSL_PUBLIC_KEY, IIS_MD_UT_SERVER, BINARY_METADATA,
|
||
m_pCertificate, m_cbCertificate,
|
||
METADATA_SECURE );
|
||
|
||
// write out the private key
|
||
if ( m_pPrivateKey )
|
||
f = pWrap->SetData( szBinding, MD_SSL_PRIVATE_KEY, IIS_MD_UT_SERVER, BINARY_METADATA,
|
||
m_pPrivateKey, m_cbPrivateKey,
|
||
METADATA_SECURE );
|
||
|
||
// write out the password - treat is ast secure binary data
|
||
if ( !m_szPassword.IsEmpty() )
|
||
f = pWrap->SetData( szBinding, MD_SSL_KEY_PASSWORD, IIS_MD_UT_SERVER, BINARY_METADATA,
|
||
(PVOID)(LPCSTR)m_szPassword, m_szPassword.GetLength()+1,
|
||
METADATA_SECURE );
|
||
|
||
// write out the request
|
||
if ( m_pCertificateRequest )
|
||
f = pWrap->SetData( szBinding, MD_SSL_KEY_REQUEST, IIS_MD_UT_SERVER, BINARY_METADATA,
|
||
m_pCertificateRequest, m_cbCertificateRequest,
|
||
METADATA_SECURE );
|
||
}
|
||
|
||
// write out the cached serial number
|
||
if ( m_fUpdateIdent || m_fUpdateKeys || fWriteAll )
|
||
if ( !m_szIdent.IsEmpty() )
|
||
{
|
||
f = pWrap->SetString( szBinding, MD_SSL_IDENT, IIS_MD_UT_SERVER,
|
||
m_szIdent, METADATA_SECURE );
|
||
}
|
||
|
||
// write out the friendly name of the key
|
||
if ( m_fUpdateFriendlyName || fWriteAll )
|
||
f = pWrap->SetString( szBinding, MD_SSL_FRIENDLY_NAME, IIS_MD_UT_SERVER,
|
||
m_szName, 0 );
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
//--------------------------------------------------------
|
||
BOOL CMDKey::FLoadKey( CWrapMetaBase* pWrap, PCHAR pszObj )
|
||
{
|
||
DWORD cbData;
|
||
PVOID pData;
|
||
|
||
// start with the public key
|
||
pData = pWrap->GetData( pszObj, MD_SSL_PUBLIC_KEY, IIS_MD_UT_SERVER,
|
||
BINARY_METADATA, &cbData, 0 );
|
||
if ( pData )
|
||
{
|
||
// set the data into place
|
||
m_pCertificate = (PVOID)GlobalAlloc( GPTR, cbData );
|
||
// if we got the pointer, copy the rest of the data into place
|
||
if( m_pCertificate)
|
||
{
|
||
m_cbCertificate = cbData;
|
||
CopyMemory( m_pCertificate, pData, cbData );
|
||
}
|
||
// free the buffer
|
||
pWrap->FreeWrapData( pData );
|
||
}
|
||
|
||
// now the private key
|
||
pData = pWrap->GetData( pszObj, MD_SSL_PRIVATE_KEY, IIS_MD_UT_SERVER,
|
||
BINARY_METADATA, &cbData, 0 );
|
||
if ( pData )
|
||
{
|
||
// set the data into place
|
||
m_pPrivateKey = (PVOID)GlobalAlloc( GPTR, cbData );
|
||
// if we got the pointer, copy the rest of the data into place
|
||
if( m_pPrivateKey)
|
||
{
|
||
m_cbPrivateKey = cbData;
|
||
CopyMemory( m_pPrivateKey, pData, cbData );
|
||
}
|
||
// free the buffer
|
||
pWrap->FreeWrapData( pData );
|
||
}
|
||
|
||
// now the password key
|
||
pData = pWrap->GetData( pszObj, MD_SSL_KEY_PASSWORD, IIS_MD_UT_SERVER,
|
||
BINARY_METADATA, &cbData, 0 );
|
||
if ( pData )
|
||
{
|
||
// set the data into place - relatively easy in this case
|
||
m_szPassword = (LPCSTR)pData;
|
||
// free the buffer
|
||
pWrap->FreeWrapData( pData );
|
||
}
|
||
|
||
// now the request
|
||
pData = pWrap->GetData( pszObj, MD_SSL_KEY_REQUEST, IIS_MD_UT_SERVER,
|
||
BINARY_METADATA, &cbData, 0 );
|
||
if ( pData )
|
||
{
|
||
// set the data into place
|
||
m_pCertificateRequest = (PVOID)GlobalAlloc( GPTR, cbData );
|
||
// if we got the pointer, copy the rest of the data into place
|
||
if( m_pCertificateRequest)
|
||
{
|
||
m_cbCertificateRequest = cbData;
|
||
CopyMemory( m_pCertificateRequest, pData, cbData );
|
||
}
|
||
// free the buffer
|
||
pWrap->FreeWrapData( pData );
|
||
}
|
||
|
||
// finally, retrieve the friendly name
|
||
BOOL f = pWrap->GetString( pszObj, MD_SSL_FRIENDLY_NAME, IIS_MD_UT_SERVER,
|
||
m_szName.GetBuffer(MAX_LEN), MAX_LEN, 0);
|
||
m_szName.ReleaseBuffer();
|
||
if ( !f )
|
||
m_szName.Empty();
|
||
|
||
// make this item's metabase name the first name in the list
|
||
AddBinding( pszObj );
|
||
|
||
// Success
|
||
return TRUE;
|
||
}
|
||
|
||
//-------------------------------------------------------------
|
||
// install a cert
|
||
BOOL CMDKey::FInstallCertificate( PVOID pCert, DWORD cbCert, CString &szPass )
|
||
{
|
||
// first, we should test that the certificate and password are valid
|
||
// for this particular key
|
||
// cache the old certificate in case the new one fails
|
||
DWORD old_cbCertificate = m_cbCertificate;
|
||
PVOID old_pCertificate = m_pCertificate;
|
||
|
||
// set the new one into place
|
||
m_cbCertificate = cbCert;
|
||
m_pCertificate = pCert;
|
||
|
||
// verify the password - verify password puts up any error dialogs
|
||
if ( !FVerifyValidPassword(szPass) )
|
||
{
|
||
// resore the old values
|
||
m_cbCertificate = old_cbCertificate;
|
||
m_pCertificate = old_pCertificate;
|
||
|
||
// dispose of the new stuff
|
||
GlobalFree( pCert );
|
||
|
||
// return false
|
||
return FALSE;
|
||
}
|
||
|
||
// now we need to see if this key has already been installed
|
||
// get the identification string
|
||
CString szIdentThis;
|
||
if ( !FGetIdentString( pCert, cbCert, szIdentThis ) )
|
||
return FALSE;
|
||
|
||
// scan the existing keys, looking for one with the same ident string
|
||
// if one is found, tell the user that it already exists and fail
|
||
CString szIdentTest;
|
||
CMDKey* pTestKey = m_pService->GetFirstMDKey();
|
||
while ( pTestKey )
|
||
{
|
||
// if we are testing against this key, continue
|
||
if ( pTestKey == this )
|
||
goto GETNEXTKEY;
|
||
|
||
// get the test ident string
|
||
if ( !pTestKey->FGetIdentString( pTestKey->m_pCertificate,
|
||
pTestKey->m_cbCertificate, szIdentTest ) )
|
||
goto GETNEXTKEY;
|
||
|
||
// test the ident strings
|
||
if ( szIdentThis == szIdentTest )
|
||
{
|
||
// the key already exists
|
||
AfxMessageBox( IDS_DUPLICATE_CERT );
|
||
return FALSE;
|
||
}
|
||
|
||
GETNEXTKEY:
|
||
// get the next key for the loop
|
||
pTestKey = m_pService->GetNextMDKey(pTestKey);
|
||
}
|
||
|
||
// run the default action
|
||
BOOL fDefault = CKey::FInstallCertificate(pCert, cbCert, szPass);
|
||
|
||
// set the update keys flag
|
||
m_fUpdateKeys = TRUE;
|
||
|
||
|
||
// if everything worked so far then check to see if there is a key
|
||
// on this service with the default binding. If there isn't, then
|
||
// set this key to have the default binding.
|
||
if ( fDefault )
|
||
{
|
||
// load the default binding string
|
||
CString szBinding;
|
||
szBinding = MDNAME_DEFAULT;
|
||
// if no key has the default binding, then make it so
|
||
if ( !m_pService->FIsBindingInUse(szBinding) )
|
||
{
|
||
m_rgbszBindings.Add( MDNAME_DEFAULT );
|
||
}
|
||
}
|
||
|
||
|
||
// if it worked, force the icon to change
|
||
if ( fDefault )
|
||
UpdateIcon();
|
||
|
||
// return the default answer
|
||
return fDefault;
|
||
}
|
||
|
||
|
||
|
||
|
||
|