//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1997 - 1999 // // File: wizpage.cpp // // Contents: Wizard page construction and presentation functions to be used // by the OCM driver code. // // History: 04/16/97 JerryK Fixed/Changed/Unmangled // 0/8/97 XTan major structure change // //---------------------------------------------------------------------------- #include "pch.cpp" #pragma hdrstop // ** System Includes ** #include #include #include // ** Application Includes ** #include "cryptui.h" #include "csdisp.h" #include "csprop.h" #include "cspenum.h" #include "usecert.h" #include "wizpage.h" #include "cscsp.h" #include "clibres.h" #include "certmsg.h" #include "websetup.h" #include "dssetup.h" #include "setupids.h" #include "tfc.h" //defines #define __dwFILE__ __dwFILE_OCMSETUP_WIZPAGE_CPP__ #define dwWIZDISABLE -2 #define dwWIZBACK -1 #define dwWIZACTIVE 0 #define dwWIZNEXT 1 #define C_CSPHASNOKEYMINMAX -1 #define MAX_KEYLENGTHEDIT 128 #define MAX_KEYLENGTHDIGIT 5 #define wszOLDCASTOREPREFIX L"CA_" #define _ReturnIfWizError(hr) \ { \ if (S_OK != (hr)) \ { \ CSILOG((hr), IDS_LOG_WIZ_PAGE_ERROR, NULL, NULL, NULL); \ _PrintError(hr, "CertSrv Wizard error"); \ return TRUE; \ } \ } #define _GetCompDataOrReturnIfError(pComp, hDlg) \ (PER_COMPONENT_DATA*)GetWindowLongPtr((hDlg), DWLP_USER); \ if (NULL == (pComp) || S_OK != (pComp)->hrContinue) \ { \ return TRUE; \ } #define _GetCompDataOrReturn(pComp, hDlg) \ (PER_COMPONENT_DATA*)GetWindowLongPtr((hDlg), DWLP_USER); \ if (NULL == (pComp)) \ { \ return TRUE; \ } #define _DisableWizDisplayIfError(pComp, hDlg) \ if (S_OK != (pComp)->hrContinue) \ { \ CSILOG((pComp)->hrContinue, IDS_LOG_DISABLE_WIZ_PAGE, NULL, NULL, NULL); \ SetWindowLongPtr((hDlg), DWLP_MSGRESULT, -1); \ } //-------------------------------------------------------------------- struct FAKEPROGRESSINFO { HANDLE hStopEvent; CRITICAL_SECTION csTimeSync; BOOL fCSInit; DWORD dwSecsRemaining; HWND hwndProgBar; }; struct KEYGENPROGRESSINFO { HWND hDlg; // wizard page window PER_COMPONENT_DATA * pComp; // setup data }; KEYGENPROGRESSINFO g_KeyGenInfo = { NULL, //hDlg NULL, //pComp }; BOOL g_fAllowUnicodeStrEncoding = FALSE; // ** Prototypes/Forward Declarations ** LRESULT CALLBACK IdInfoNameEditFilterHook(HWND, UINT, WPARAM, LPARAM); __inline VOID SetEditFocusAndSelect( IN HWND hwnd, IN DWORD indexStart, IN DWORD indexEnd) { SetFocus(hwnd); SendMessage(hwnd, EM_SETSEL, indexStart, indexEnd); } // fix for 160324 - NT4->Whistler upgrade: // cannot reinstall CA w/ same cert as instructions tell us to do // // Upgrade NT4->Whistler is not supported but old CA key and cert can be reused // But NT4 used to install CA certs in a separate store (CA_MACHINENAME) so we // need to move the cert to root store so it can be validated. HRESULT CopyNT4CACertToRootStore(CASERVERSETUPINFO *pServer) { HRESULT hr; WCHAR wszOldCAStore[MAX_PATH]; HCERTSTORE hOldStore = NULL; HCERTSTORE hRootStore = NULL; CERT_RDN_ATTR rdnAttr = { szOID_COMMON_NAME, CERT_RDN_ANY_TYPE,}; CERT_RDN rdn = { 1, &rdnAttr }; DWORD cCA = 0; CERT_CONTEXT const *pCACert; CERT_CONTEXT const *pCACertKeep = NULL; // needn't free DWORD dwFlags; ENUM_CATYPES CATypeDummy; CERT_CONTEXT const **ppCACertKeep = NULL; CRYPT_KEY_PROV_INFO keyProvInfo; DWORD IndexCA; DWORD *pIndex = NULL; DWORD i = 0; ZeroMemory(&keyProvInfo, sizeof(keyProvInfo)); // form old ca store name // !!! NT4 uses different sanitize, how do we build it correctly? wcscpy(wszOldCAStore, wszOLDCASTOREPREFIX); wcscat(wszOldCAStore, pServer->pwszSanitizedName); // open old CA store hOldStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W, X509_ASN_ENCODING, NULL, // hProv CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_LOCAL_MACHINE, wszOldCAStore); if (NULL == hOldStore) { hr = myHLastError(); _JumpError(hr, error, "CertOpenStore"); } // find CA cert, old ca common name always same as ca name rdnAttr.Value.pbData = (BYTE *) pServer->pwszCACommonName; rdnAttr.Value.cbData = 0; pCACert = NULL; do { pCACert = CertFindCertificateInStore( hOldStore, X509_ASN_ENCODING, CERT_UNICODE_IS_RDN_ATTRS_FLAG | CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG, CERT_FIND_SUBJECT_ATTR, &rdn, pCACert); if (NULL != pCACert) { // find one if (NULL == ppCACertKeep) { ppCACertKeep = (CERT_CONTEXT const **)LocalAlloc(LMEM_FIXED, (cCA + 1) * sizeof(CERT_CONTEXT const *)); _JumpIfOutOfMemory(hr, error, ppCACertKeep); } else { CERT_CONTEXT const ** ppTemp; ppTemp = (CERT_CONTEXT const **)LocalReAlloc( ppCACertKeep, (cCA + 1) * sizeof(CERT_CONTEXT const *), LMEM_MOVEABLE); _JumpIfOutOfMemory(hr, error, ppTemp); ppCACertKeep = ppTemp; } // keep current ppCACertKeep[cCA] = CertDuplicateCertificateContext(pCACert); if (NULL == ppCACertKeep[cCA]) { hr = myHLastError(); _JumpError(hr, error, "CertDuplicateCertificate"); } ++cCA; } } while (NULL != pCACert); if (1 > cCA) { // no ca cert hr = E_INVALIDARG; _JumpError(hr, error, "no ca cert"); } // assume 1st one pCACertKeep = ppCACertKeep[0]; if (1 < cCA) { DWORD cCA2 = cCA; BOOL fMatch; // have multi ca certs with the same cn // because sp4 doesn't reg ca serial # so need to decide which one // once the correct one is found, reg its serial # // build an index pIndex = (DWORD*)LocalAlloc(LMEM_FIXED, cCA * sizeof(DWORD)); _JumpIfOutOfMemory(hr, error, pIndex); i = 0; for (pIndex[i] = i; i < cCA; ++i); // try to compare with public key // in case ca cert doesn't have kpi which is the case for v10 // so try base rsa hr = csiFillKeyProvInfo( pServer->pwszSanitizedName, pServer->pCSPInfo->pwszProvName, pServer->pCSPInfo->dwProvType, TRUE, // always machine keyset &keyProvInfo); if (S_OK == hr) { cCA2 = 0; for (i = 0; i < cCA; ++i) { hr = myVerifyPublicKey( ppCACertKeep[i], FALSE, &keyProvInfo, NULL, &fMatch); if (S_OK != hr) { continue; } if (fMatch) { // found one match with current public key from container pIndex[cCA2] = i; ++cCA2; } } } // compare all ca certs and pick one has most recent NotAfter pCACertKeep = ppCACertKeep[pIndex[0]]; for (i = 1; i < cCA2; ++i) { if (0 < CompareFileTime( &ppCACertKeep[pIndex[i]]->pCertInfo->NotAfter, &pCACertKeep->pCertInfo->NotAfter)) { // update pCACertKeep = ppCACertKeep[pIndex[i]]; } } } // if get here, must find ca cert CSASSERT(NULL != pCACertKeep); // add cert to root store hRootStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W, X509_ASN_ENCODING, NULL, // hProv CERT_SYSTEM_STORE_LOCAL_MACHINE, wszROOT_CERTSTORE); if (NULL == hRootStore) { hr = myHLastError(); _JumpError(hr, error, "CertOpenStore"); } if(!CertAddCertificateContextToStore( hRootStore, pCACertKeep, CERT_STORE_ADD_NEW, NULL)) { hr = myHLastError(); _JumpError(hr, error, "CertAddCertificateContextToStore"); } error: csiFreeKeyProvInfo(&keyProvInfo); for (i = 0; i < cCA; ++i) { CertFreeCertificateContext(ppCACertKeep[i]); } if (NULL != hOldStore) { CertCloseStore(hOldStore, CERT_CLOSE_STORE_CHECK_FLAG); } if (NULL != hRootStore) { CertCloseStore(hRootStore, CERT_CLOSE_STORE_CHECK_FLAG); } return hr; } //-------------------------------------------------------------------- // Clear the key container name to indicate that we must generate a new key. void ClearKeyContainerName(CASERVERSETUPINFO *pServer) { if (NULL!=pServer->pwszKeyContainerName) { // Delete the key container if this is a new one if (pServer->fDeletableNewKey) { // Delete the key container. Ignore any errors. HCRYPTPROV hProv=NULL; myCertSrvCryptAcquireContext( &hProv, pServer->pwszKeyContainerName, pServer->pCSPInfo->pwszProvName, pServer->pCSPInfo->dwProvType, CRYPT_DELETEKEYSET, pServer->pCSPInfo->fMachineKeyset); if (NULL!=hProv) { CryptReleaseContext(hProv, 0); } pServer->fDeletableNewKey=FALSE; } // Clear the key container name, to indicate that we must generate a new key. LocalFree(pServer->pwszKeyContainerName); LocalFree(pServer->pwszDesanitizedKeyContainerName); pServer->pwszKeyContainerName=NULL; pServer->pwszDesanitizedKeyContainerName=NULL; // if we were using an existing cert, we are not anymore ClearExistingCertToUse(pServer); } else { // if there was no key, there couldn't be a existing cert. CSASSERT(NULL==pServer->pccExistingCert); // key container name is already clear } } //-------------------------------------------------------------------- // Set both the real key container name and the display key container name HRESULT SetKeyContainerName( CASERVERSETUPINFO *pServer, const WCHAR * pwszKeyContainerName) { HRESULT hr; // get rid of any previous names ClearKeyContainerName(pServer); // set the real key container name pServer->pwszKeyContainerName = (WCHAR *) LocalAlloc( LMEM_FIXED, sizeof(WCHAR) * (wcslen(pwszKeyContainerName) + 1)); _JumpIfOutOfMemory(hr, error, pServer->pwszKeyContainerName); wcscpy(pServer->pwszKeyContainerName, pwszKeyContainerName); // set the display key container name hr = myRevertSanitizeName( pServer->pwszKeyContainerName, &pServer->pwszDesanitizedKeyContainerName); _JumpIfError(hr, error, "myRevertSanitizeName"); // Must validate the key again when the selected key changes pServer->fValidatedHashAndKey = FALSE; CSILOG( hr, IDS_ILOG_KEYCONTAINERNAME, pServer->pwszKeyContainerName, pServer->pwszDesanitizedKeyContainerName, NULL); error: return hr; } HRESULT UpdateDomainAndUserName( IN HWND hwnd, IN OUT PER_COMPONENT_DATA *pComp); BOOL CertConfirmCancel( HWND hwnd, PER_COMPONENT_DATA *pComp) { HRESULT hr; CSASSERT(NULL != pComp); if (!(*pComp->HelperRoutines.ConfirmCancelRoutine)(hwnd)) { SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE); return TRUE; } hr = CancelCertsrvInstallation(hwnd, pComp); _PrintIfError(hr, "CancelCertsrvInstallation"); return FALSE; } HRESULT StartWizardPageEditControls( IN HWND hDlg, IN OUT PAGESTRINGS *pPageStrings) { HRESULT hr; for ( ; NULL != pPageStrings->ppwszString; pPageStrings++) { SendMessage( GetDlgItem(hDlg, pPageStrings->idControl), WM_SETTEXT, 0, (LPARAM) *pPageStrings->ppwszString); } hr = S_OK; //error: return hr; } HRESULT FinishWizardPageEditControls( IN HWND hDlg, IN OUT PAGESTRINGS *pPageStrings) { HRESULT hr; for ( ; NULL != pPageStrings->ppwszString; pPageStrings++) { WCHAR *pwszString = NULL; hr = myUIGetWindowText( GetDlgItem(hDlg, pPageStrings->idControl), &pwszString); _JumpIfError(hr, error, "myUIGetWindowText"); if (NULL != *pPageStrings->ppwszString) { // free old one LocalFree(*pPageStrings->ppwszString); *pPageStrings->ppwszString = NULL; } *pPageStrings->ppwszString = pwszString; CSILOG(S_OK, pPageStrings->idLog, pwszString, NULL, NULL); } hr = S_OK; error: return hr; } //+------------------------------------------------------------------------ // Function: WizPageSetTextLimits // // Synopsis: Sets text input limits for the text controls of a dlg page. //------------------------------------------------------------------------- HRESULT WizPageSetTextLimits( HWND hDlg, IN OUT PAGESTRINGS *pPageStrings) { HRESULT hr; for ( ; NULL != pPageStrings->ppwszString; pPageStrings++) { SendDlgItemMessage( hDlg, pPageStrings->idControl, EM_SETLIMITTEXT, (WPARAM) pPageStrings->cchMax, (LPARAM) 0); } hr = S_OK; //error: return hr; } // check optional or mac length in edit field // if any invalid, focus on the edit field, select all HRESULT ValidateTextField( HINSTANCE hInstance, BOOL fUnattended, HWND hDlg, LPTSTR pszTestString, DWORD nUBValue, int nMsgBoxNullStringErrID, int nMsgBoxLenStringErrID, int nControlID) { HRESULT hr = E_INVALIDARG; HWND hwndCtrl = NULL; BOOL fIsEmpty; fIsEmpty = (NULL == pszTestString) || (L'\0' == pszTestString[0]); if (fIsEmpty) { if (0 != nMsgBoxNullStringErrID) // non optional { // edit field can't be empty CertWarningMessageBox( hInstance, fUnattended, hDlg, nMsgBoxNullStringErrID, 0, NULL); if (!fUnattended) { hwndCtrl = GetDlgItem(hDlg, nControlID); // Get offending ctrl } goto error; } goto done; } // the following may not be necessary because edit field set to max limit if (wcslen(pszTestString) > nUBValue) // Make sure it's not too long { CertWarningMessageBox( hInstance, fUnattended, hDlg, nMsgBoxLenStringErrID, 0, NULL); if (!fUnattended) { hwndCtrl = GetDlgItem(hDlg, nControlID); } goto error; } done: hr = S_OK; error: if (!fUnattended && NULL != hwndCtrl) { SetEditFocusAndSelect(hwndCtrl, 0, -1); } return hr; } HRESULT WizardPageValidation( IN HINSTANCE hInstance, IN BOOL fUnattended, IN HWND hDlg, IN PAGESTRINGS *pPageStrings) { HRESULT hr; for ( ; NULL != pPageStrings->ppwszString; pPageStrings++) { hr = ValidateTextField( hInstance, fUnattended, hDlg, *pPageStrings->ppwszString, pPageStrings->cchMax, pPageStrings->idMsgBoxNullString, pPageStrings->idMsgBoxLenString, pPageStrings->idControl); _JumpIfError(hr, error, "invalid edit field"); } hr = S_OK; error: return hr; } #define KEYGEN_GENERATE_KEY 60 // estimated seconds to gen key #define KEYGEN_PROTECT_KEY 60 // estimated seconds to acl key #define KEYGEN_TEST_HASH 2 // estimated seconds to acl key //-------------------------------------------------------------------- // Fake progress by incrementing a progress bar every second DWORD WINAPI KeyGenFakeProgressThread( LPVOID lpParameter) { FAKEPROGRESSINFO * pFakeProgressInfo=(FAKEPROGRESSINFO *)lpParameter; // Wait for the stop signal for 1 second. while (WAIT_TIMEOUT==WaitForSingleObject(pFakeProgressInfo->hStopEvent, 1000)) { // See if we can send another tick to the progress bar if(pFakeProgressInfo->fCSInit) { EnterCriticalSection(&pFakeProgressInfo->csTimeSync); if (pFakeProgressInfo->dwSecsRemaining>0) { // move one step (one second) SendMessage(pFakeProgressInfo->hwndProgBar, PBM_DELTAPOS, 1, 0); pFakeProgressInfo->dwSecsRemaining--; } LeaveCriticalSection(&pFakeProgressInfo->csTimeSync); } } // We were signaled, so stop. return 0; // return value ignored } //-------------------------------------------------------------------- // Generate a new key and test the hash algorithm DWORD WINAPI GenerateKeyThread( LPVOID lpParameter) { HRESULT hr = S_OK; WCHAR * pwszMsg; FAKEPROGRESSINFO fpi; KEYGENPROGRESSINFO * pKeyGenInfo=(KEYGENPROGRESSINFO *)lpParameter; PER_COMPONENT_DATA * pComp=pKeyGenInfo->pComp; CASERVERSETUPINFO * pServer=pComp->CA.pServer; HWND hwndProgBar=GetDlgItem(pKeyGenInfo->hDlg, IDC_KEYGEN_PROGRESS); HWND hwndText=GetDlgItem(pKeyGenInfo->hDlg, IDC_KEYGEN_PROGRESS_TEXT); int iErrMsg=0; // error msg id const WCHAR * pwszErrMsgData = L""; // variables that must be cleaned up fpi.hStopEvent=NULL; HANDLE hFakeProgressThread=NULL; HCRYPTPROV hProv=NULL; fpi.fCSInit = FALSE; __try { InitializeCriticalSection(&fpi.csTimeSync); fpi.fCSInit = TRUE; } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { } _JumpIfError(hr, error, "InitializeCriticalSection"); // STEP 0: // initialize the fake-progress thread // set up the structure for the fake-progress thread fpi.hStopEvent=CreateEvent( NULL, // security FALSE, // manual reset? FALSE, // signaled? NULL); // name if (NULL==fpi.hStopEvent) { hr = myHLastError(); _JumpError(hr, error, "CreateEvent"); } fpi.hwndProgBar=hwndProgBar; fpi.dwSecsRemaining=0; // Initially, the thread has no work to do. // start the fake-progress thread DWORD dwThreadID; // ignored hFakeProgressThread=CreateThread( NULL, // security 0, // stack KeyGenFakeProgressThread, (void *)&fpi, 0, // flags &dwThreadID); if (NULL==hFakeProgressThread) { hr = myHLastError(); _JumpError(hr, error, "CreateThread"); } if (NULL==pServer->pwszKeyContainerName) { // STEP 1: // Generate a key // set the status hr = myLoadRCString(pComp->hInstance, IDS_KEYGEN_GENERATING, &pwszMsg); _JumpIfError(hr, error, "myLoadRCString"); SetWindowText(hwndText, pwszMsg); LocalFree(pwszMsg); SendMessage(hwndProgBar, PBM_SETPOS, (WPARAM)0, 0); if(fpi.fCSInit) { EnterCriticalSection(&fpi.csTimeSync); fpi.dwSecsRemaining = KEYGEN_GENERATE_KEY; LeaveCriticalSection(&fpi.csTimeSync); } // generate key hr = csiGenerateKeysOnly( pServer->pwszSanitizedName, pServer->pCSPInfo->pwszProvName, pServer->pCSPInfo->dwProvType, pServer->pCSPInfo->fMachineKeyset, pServer->dwKeyLength, pComp->fUnattended, &hProv, &iErrMsg); if (S_OK != hr) { pwszErrMsgData=pServer->pwszSanitizedName; pServer->fKeyGenFailed = TRUE; _JumpError(hr, error, "csiGenerateKeysOnly"); } pServer->fKeyGenFailed = FALSE; // now set this as the existing key SetKeyContainerName(pServer, pServer->pwszSanitizedName); pServer->fDeletableNewKey=TRUE; // STEP 2: // Set the ACLs // set the status hr = myLoadRCString(pComp->hInstance, IDS_KEYGEN_PROTECTING, &pwszMsg); _JumpIfError(hr, error, "myLoadRCString"); SetWindowText(hwndText, pwszMsg); LocalFree(pwszMsg); if(fpi.fCSInit) { EnterCriticalSection(&fpi.csTimeSync); SendMessage(hwndProgBar, PBM_SETPOS, (WPARAM)KEYGEN_GENERATE_KEY, 0); fpi.dwSecsRemaining=KEYGEN_PROTECT_KEY; LeaveCriticalSection(&fpi.csTimeSync); } // set the ACLs hr = csiSetKeyContainerSecurity(hProv); if (S_OK!=hr) { iErrMsg=IDS_ERR_KEYSECURITY; pwszErrMsgData=pServer->pwszKeyContainerName; _JumpError(hr, error, "csiSetKeyContainerSecurity"); } } // <- end if (NULL==pServer->pwszKeyContainerName) if (FALSE==pServer->fValidatedHashAndKey) { // STEP 3: // Test the hash algorithm and key set // set the status hr = myLoadRCString(pComp->hInstance, IDS_KEYGEN_TESTINGHASHANDKEY, &pwszMsg); _JumpIfError(hr, error, "myLoadRCString"); SetWindowText(hwndText, pwszMsg); LocalFree(pwszMsg); if(fpi.fCSInit) { EnterCriticalSection(&fpi.csTimeSync); SendMessage(hwndProgBar, PBM_SETPOS, (WPARAM)KEYGEN_GENERATE_KEY+KEYGEN_PROTECT_KEY, 0); fpi.dwSecsRemaining=KEYGEN_TEST_HASH; LeaveCriticalSection(&fpi.csTimeSync); } // test the hash and keyset hr = myValidateHashForSigning( pServer->pwszKeyContainerName, pServer->pCSPInfo->pwszProvName, pServer->pCSPInfo->dwProvType, pServer->pCSPInfo->fMachineKeyset, NULL, pServer->pHashInfo->idAlg); if (S_OK!=hr) { if (NTE_BAD_KEY_STATE==hr || //all the errors with KEY in them NTE_NO_KEY==hr || NTE_BAD_PUBLIC_KEY==hr || NTE_BAD_KEYSET==hr || NTE_KEYSET_NOT_DEF==hr || NTE_KEYSET_ENTRY_BAD==hr || NTE_BAD_KEYSET_PARAM==hr) { // Bad keyset (eg, not AT_SIGNATURE) - force user to pick another iErrMsg=IDS_KEY_INVALID; pwszErrMsgData=pServer->pwszKeyContainerName; } else { // Bad hash algorithm - force user to pick another iErrMsg=IDS_ERR_INVALIDHASH; pwszErrMsgData=pServer->pHashInfo->pwszName; } _JumpError(hr, error, "myValidateHashForSigning"); } // mark this hash as validated pServer->fValidatedHashAndKey=TRUE; } // STEP 3: // Go to the next page // set the status, so the user sees the bar go all the way. if(fpi.fCSInit) { EnterCriticalSection(&fpi.csTimeSync); SendMessage(hwndProgBar, PBM_SETPOS, (WPARAM)KEYGEN_GENERATE_KEY+KEYGEN_PROTECT_KEY+KEYGEN_TEST_HASH, 0); fpi.dwSecsRemaining=0; LeaveCriticalSection(&fpi.csTimeSync); } error: // clean up after the false-progress thread if (NULL!=hFakeProgressThread) { CSASSERT(NULL!=fpi.hStopEvent); // tell the progress thread to stop if (FALSE==SetEvent(fpi.hStopEvent)) { _PrintError(myHLastError(), "SetEvent"); } else { // wait for it to stop WaitForSingleObject(hFakeProgressThread, INFINITE); } CloseHandle(hFakeProgressThread); } if(fpi.fCSInit) { DeleteCriticalSection(&fpi.csTimeSync); } if (NULL!=fpi.hStopEvent) { CloseHandle(fpi.hStopEvent); } if (NULL!=hProv) { CryptReleaseContext(hProv, 0); } // show an error message if we need to if (0!=iErrMsg) { CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, pKeyGenInfo->hDlg, iErrMsg, hr, pwszErrMsgData); } pServer->LastWiz=ENUM_WIZ_KEYGEN; if (S_OK==hr) { // go to next page PropSheet_PressButton(GetParent(pKeyGenInfo->hDlg), PSBTN_NEXT); } else { // go back PropSheet_PressButton(GetParent(pKeyGenInfo->hDlg), PSBTN_BACK); } return 0; // return value ignored } //-------------------------------------------------------------------- // Start the KeyGen wizard page HRESULT HandleKeyGenWizActive( HWND hDlg, PER_COMPONENT_DATA *pComp, KEYGENPROGRESSINFO *pKeyGenInfo) { HRESULT hr = S_OK; // Suppress this wizard page if // we are going backwards, or // we've already seen an error, or // we are not installing the server, // or the key exists and the hash has been checked. if (ENUM_WIZ_STORE == pComp->CA.pServer->LastWiz || !(IS_SERVER_INSTALL & pComp->dwInstallStatus) || (NULL != pComp->CA.pServer->pwszKeyContainerName && pComp->CA.pServer->fValidatedHashAndKey)) { // skip/disable page CSILOGDWORD(IDS_KEYGEN_TITLE, dwWIZDISABLE); SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1); } else { // set progress bar parameters: range, step, and position // set them now so the user will never see a full bar if this is the second visit. HWND hwndProgBar=GetDlgItem(hDlg, IDC_KEYGEN_PROGRESS); SendMessage(hwndProgBar, PBM_SETRANGE, 0, MAKELPARAM(0, KEYGEN_GENERATE_KEY+KEYGEN_PROTECT_KEY+KEYGEN_TEST_HASH)); SendMessage(hwndProgBar, PBM_SETSTEP, (WPARAM)1, 0); SendMessage(hwndProgBar, PBM_SETPOS, (WPARAM)0, 0); // init info for keygen thread pKeyGenInfo->hDlg=hDlg; pKeyGenInfo->pComp=pComp; // start the key gen thread DWORD dwThreadID; // ignored HANDLE hKeyGenThread=CreateThread( NULL, // security 0, // stack GenerateKeyThread, (void *)pKeyGenInfo, 0, // flags &dwThreadID); if (NULL==hKeyGenThread) { hr = myHLastError(); _JumpError(hr, error, "CreateThread"); } CloseHandle(hKeyGenThread); } error: return hr; } //+------------------------------------------------------------------------ // Function: WizKeyGenPageDlgProc(. . . .) // // Synopsis: Dialog procedure for keygen wiz-page //------------------------------------------------------------------------- INT_PTR WizKeyGenPageDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { HWND hwndCtrl; PER_COMPONENT_DATA *pComp = NULL; switch(iMsg) { case WM_INITDIALOG: // point to component data SetWindowLongPtr(hDlg, DWLP_USER, (ULONG_PTR)((PROPSHEETPAGE*)lParam)->lParam); pComp = (PER_COMPONENT_DATA*)(ULONG_PTR)((PROPSHEETPAGE*)lParam)->lParam; _ReturnIfWizError(pComp->hrContinue); break; case WM_COMMAND: break; case WM_NOTIFY: switch (((NMHDR FAR *) lParam)->code) { case PSN_KILLACTIVE: break; case PSN_RESET: break; case PSN_QUERYCANCEL: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); return CertConfirmCancel(hDlg, pComp); break; case PSN_SETACTIVE: CSILOGDWORD(IDS_KEYGEN_TITLE, dwWIZACTIVE); PropSheet_SetWizButtons(GetParent(hDlg), 0); pComp = _GetCompDataOrReturn(pComp, hDlg); _DisableWizDisplayIfError(pComp, hDlg); _ReturnIfWizError(pComp->hrContinue); pComp->hrContinue=HandleKeyGenWizActive(hDlg, pComp, &g_KeyGenInfo); _ReturnIfWizError(pComp->hrContinue); break; case PSN_WIZBACK: CSILOGDWORD(IDS_KEYGEN_TITLE, dwWIZBACK); break; case PSN_WIZNEXT: CSILOGDWORD(IDS_KEYGEN_TITLE, dwWIZNEXT); break; default: return FALSE; } break; default: return FALSE; } return TRUE; } HRESULT ValidateESERestrictions( IN WCHAR const *pwszDirectory) { HRESULT hr; HANDLE hFile = INVALID_HANDLE_VALUE; HANDLE hFileA = INVALID_HANDLE_VALUE; WCHAR *pwszPath = NULL; char *pszPath = NULL; WCHAR *pwsz; char *psz; DWORD cwcbs; DWORD cchbs; hr = myBuildPathAndExt(pwszDirectory, L"certocm.tmp", NULL, &pwszPath); _JumpIfError(hr, error, "myBuildPathAndExt"); if (!ConvertWszToSz(&pszPath, pwszPath, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ConvertWszToSz") } pwsz = pwszPath; cwcbs = 0; while (TRUE) { pwsz = wcschr(pwsz, L'\\'); if (NULL == pwsz) { break; } pwsz++; cwcbs++; } psz = pszPath; cchbs = 0; while (TRUE) { psz = strchr(psz, '\\'); if (NULL == psz) { break; } psz++; cchbs++; } if (cchbs != cwcbs) { hr = E_INVALIDARG; _JumpError(hr, error, "backslash count") } hFile = CreateFile( pwszPath, GENERIC_WRITE, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, // security OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); // template if (INVALID_HANDLE_VALUE == hFile) { hr = myHLastError(); _JumpErrorStr(hr, error, "CreateFile", pwszPath); } hFileA = CreateFileA( pszPath, GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, // security OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); // template if (INVALID_HANDLE_VALUE == hFileA) { hr = myHLastError(); _JumpErrorStr(hr, error, pszPath, L"CreateFileA"); } CSASSERT(S_OK == hr); error: if (INVALID_HANDLE_VALUE != hFileA) { CloseHandle(hFileA); // close before below delete } if (NULL != pszPath) { LocalFree(pszPath); } if (NULL != pwszPath) { if (INVALID_HANDLE_VALUE != hFile) { CloseHandle(hFile); // close before delete DeleteFile(pwszPath); } LocalFree(pwszPath); } return(hr); } //+------------------------------------------------------------------------- // Function: check if a database edit field //-------------------------------------------------------------------------- BOOL ValidateAndCreateDirField( HINSTANCE hInstance, BOOL fUnattended, HWND hDlg, WCHAR *pwszDirectory, BOOL fDefaultDir, int iMsgNotFullPath, BOOL *pfExist, BOOL *pfIsUNC) { BOOL fRet = FALSE; DWORD dwPathFlag = 0; HRESULT hr; *pfExist = TRUE; // check edit field if (!myIsFullPath(pwszDirectory, &dwPathFlag)) { CertWarningMessageBox( hInstance, fUnattended, hDlg, iMsgNotFullPath, 0, pwszDirectory); goto error; } // set the UNC check *pfIsUNC = (dwPathFlag == UNC_PATH); if (MAX_PATH - 1 < wcslen(pwszDirectory)) { WCHAR wszMsg[256 + MAX_PATH]; WCHAR *pwszFormat = NULL; hr = myLoadRCString(hInstance, IDS_STORELOC_PATHTOOLONG, &pwszFormat); _JumpIfError(hr, error, "myLoadRCString"); swprintf(wszMsg, pwszFormat, pwszDirectory, MAX_PATH-1); CertWarningMessageBox( hInstance, fUnattended, hDlg, 0, 0, wszMsg); LocalFree(pwszFormat); goto error; } if (DE_DIREXISTS != DirExists(pwszDirectory)) { if (*pfIsUNC) { CertWarningMessageBox( hInstance, fUnattended, hDlg, IDS_STORELOC_UNCMUSTEXIST, 0, pwszDirectory); goto error; } else { if (!fDefaultDir) { // confirm and create outside *pfExist = FALSE; goto done; } // try to create default dir hr = myCreateNestedDirectories(pwszDirectory); _JumpIfError(hr, error, "myCreateNestedDirectories"); } } done: fRet = TRUE; error: return fRet; } //+--------------------------------------------------------------------------- // Description: set MS Base CSP as default csp otherwise 1st one //---------------------------------------------------------------------------- HRESULT DetermineDefaultCSP(CASERVERSETUPINFO *pServer) { HRESULT hr; CSP_INFO *pCSPInfo = NULL; // select 1st if no MSBase pServer->pCSPInfo = pServer->pCSPInfoList; if (NULL == pServer->pDefaultCSPInfo) { goto done; } // check all csps pCSPInfo = pServer->pCSPInfoList; while (NULL != pCSPInfo) { if (NULL != pCSPInfo->pwszProvName) { if (0 == wcscmp(pCSPInfo->pwszProvName, pServer->pDefaultCSPInfo->pwszProvName) && pCSPInfo->dwProvType == pServer->pDefaultCSPInfo->dwProvType) { // change to default pServer->pCSPInfo = pCSPInfo; break; } } pCSPInfo = pCSPInfo->next; } done: hr = S_OK; //error: return hr; } //+--------------------------------------------------------------------------- // Description: set SHA as default hash alg. otherwise 1st one //---------------------------------------------------------------------------- HRESULT DetermineDefaultHash(CASERVERSETUPINFO *pServer) { CSP_HASH *pHashInfo = NULL; HRESULT hr; if ((NULL == pServer) || (NULL == pServer->pCSPInfo)) return E_POINTER; // select 1st if no default match pServer->pHashInfo = pServer->pCSPInfo->pHashList; // search list pHashInfo = pServer->pCSPInfo->pHashList; while (NULL != pHashInfo) { if (pHashInfo->idAlg == pServer->pDefaultHashInfo->idAlg) { //change to default pServer->pHashInfo = pHashInfo; break; } pHashInfo = pHashInfo->next; } // Must validate the hash again when the selected hash changes pServer->fValidatedHashAndKey = FALSE; hr = S_OK; //error: return hr; } HRESULT UpdateCADescription( HWND hDlg, PER_COMPONENT_DATA *pComp) { int ids; WCHAR *pwszDesc = NULL; HRESULT hr; switch (pComp->CA.pServer->CAType) { case ENUM_STANDALONE_ROOTCA: ids = IDS_CATYPE_DES_STANDALONE_ROOTCA; break; case ENUM_STANDALONE_SUBCA: ids = IDS_CATYPE_DES_STANDALONE_SUBCA; break; case ENUM_ENTERPRISE_ROOTCA: ids = IDS_CATYPE_DES_ENTERPRISE_ROOTCA; break; case ENUM_ENTERPRISE_SUBCA: ids = IDS_CATYPE_DES_ENTERPRISE_SUBCA; break; } // load description from resource hr = myLoadRCString(pComp->hInstance, ids, &pwszDesc); _JumpIfError(hr, error, "myLoadRCString"); // change text SetWindowText(GetDlgItem(hDlg, IDC_CATYPE_CA_DESCRIPTION), pwszDesc); hr = S_OK; error: if (NULL != pwszDesc) { LocalFree(pwszDesc); } return hr; } HRESULT InitCATypeWizControls( HWND hDlg, PER_COMPONENT_DATA *pComp) { HRESULT hr; int idc; CASERVERSETUPINFO *pServer = pComp->CA.pServer; EnableWindow(GetDlgItem(hDlg, IDC_CATYPE_ENT_ROOT_CA), pServer->fUseDS); EnableWindow(GetDlgItem(hDlg, IDC_CATYPE_ENT_SUB_CA), pServer->fUseDS); ShowWindow(GetDlgItem(hDlg, IDC_CATYPE_DESCRIPTION_ENTERPRISE), !pServer->fUseDS); EnableWindow(GetDlgItem(hDlg, IDC_CATYPE_STAND_ROOT_CA), TRUE); EnableWindow(GetDlgItem(hDlg, IDC_CATYPE_STAND_SUB_CA), TRUE); if (pServer->fUseDS) { if (ENUM_ENTERPRISE_SUBCA == pServer->CAType) { idc = IDC_CATYPE_ENT_SUB_CA; } else { idc = IDC_CATYPE_ENT_ROOT_CA; } } else { idc = IDC_CATYPE_STAND_ROOT_CA; } SendMessage(GetDlgItem(hDlg, idc), BM_CLICK, (WPARAM)0, (LPARAM)0); hr= UpdateCADescription(hDlg, pComp); _JumpIfError(hr, error, "UpdateCADescription"); hr = S_OK; error: return hr; } BOOL IsRadioControlChecked(HWND hwnd) { BOOL checked = FALSE; if (BST_CHECKED == SendMessage(hwnd, BM_GETCHECK, (WPARAM)0, (LPARAM)0)) { checked = TRUE; } return checked; } HRESULT HandleAdvanceChange(HWND hDlg, CASERVERSETUPINFO *pServer) { HRESULT hr; if (!pServer->fAdvance) { // if not advance, clear all advance flags pServer->fPreserveDB = FALSE; ClearExistingCertToUse(pServer); } hr = S_OK; //error: return hr; } HRESULT HandleCATypeChange( IN HWND hDlg, IN PER_COMPONENT_DATA *pComp, IN ENUM_CATYPES eNewType) { HRESULT hr; BOOL bCertOK; CASERVERSETUPINFO * pServer=pComp->CA.pServer; pServer->CAType = eNewType; pServer->dwKeyLength = IsRootCA(pServer->CAType)? CA_DEFAULT_KEY_LENGTH_ROOT: CA_DEFAULT_KEY_LENGTH_SUB; hr=UpdateCADescription(hDlg, pComp); _JumpIfError(hr, error, "UpdateCADescription"); // make sure that if we are using an existing cert, we didn't make it invalid. if (NULL!=pServer->pccExistingCert) { hr=IsCertSelfSignedForCAType(pServer, pServer->pccExistingCert, &bCertOK); _JumpIfError(hr, error, "UpdateCADescription"); if (FALSE==bCertOK) { // can't use this cert with this CA type. ClearExistingCertToUse(pServer); } } hr = S_OK; error: return hr; } HRESULT HandleCATypeWizActive( HWND hDlg, PER_COMPONENT_DATA *pComp) { HRESULT hr; // first of all, get install status hr = UpdateSubComponentInstallStatus(wszCERTSRVSECTION, wszSERVERSECTION, pComp); _JumpIfError(hr, error, "UpdateSubComponentInstallStatus"); hr = UpdateSubComponentInstallStatus(wszCERTSRVSECTION, wszCLIENTSECTION, pComp); _JumpIfError(hr, error, "UpdateSubComponentInstallStatus"); // Suppress this wizard page if // we've already seen an error, or // we are not installing the server. if (!(IS_SERVER_INSTALL & pComp->dwInstallStatus) ) { // disable page CSILOGDWORD(IDS_CATYPE_TITLE, dwWIZDISABLE); SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1); goto done; } done: hr = S_OK; error: return hr; } //+------------------------------------------------------------------------ // Function: WizCATypePageDlgProc(. . . .) // // Synopsis: Dialog procedure for CA Type wiz-page //------------------------------------------------------------------------- INT_PTR WizCATypePageDlgProc( HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { PER_COMPONENT_DATA *pComp = NULL; switch (iMsg) { case WM_INITDIALOG: // point to component data SetWindowLongPtr(hDlg, DWLP_USER, (ULONG_PTR)((PROPSHEETPAGE*)lParam)->lParam); pComp = (PER_COMPONENT_DATA*)(ULONG_PTR)((PROPSHEETPAGE*)lParam)->lParam; _ReturnIfWizError(pComp->hrContinue); pComp->hrContinue = InitCATypeWizControls(hDlg, pComp); _ReturnIfWizError(pComp->hrContinue); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_CATYPE_STAND_ROOT_CA: if (IsRadioControlChecked((HWND)lParam)) { pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleCATypeChange(hDlg, pComp, ENUM_STANDALONE_ROOTCA); _ReturnIfWizError(pComp->hrContinue); } break; case IDC_CATYPE_STAND_SUB_CA: if (IsRadioControlChecked((HWND)lParam)) { pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleCATypeChange(hDlg, pComp, ENUM_STANDALONE_SUBCA); _ReturnIfWizError(pComp->hrContinue); } break; case IDC_CATYPE_ENT_ROOT_CA: if (IsRadioControlChecked((HWND)lParam)) { pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleCATypeChange(hDlg, pComp, ENUM_ENTERPRISE_ROOTCA); _ReturnIfWizError(pComp->hrContinue); } break; case IDC_CATYPE_ENT_SUB_CA: if (IsRadioControlChecked((HWND)lParam)) { pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleCATypeChange(hDlg, pComp, ENUM_ENTERPRISE_SUBCA); _ReturnIfWizError(pComp->hrContinue); } break; case IDC_CATYPE_CHECK_ADVANCE: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->CA.pServer->fAdvance = !pComp->CA.pServer->fAdvance; pComp->hrContinue = HandleAdvanceChange(hDlg, pComp->CA.pServer); _ReturnIfWizError(pComp->hrContinue); break; } break; case WM_NOTIFY: switch (((NMHDR FAR *) lParam)->code) { case PSN_KILLACTIVE: break; case PSN_RESET: break; case PSN_QUERYCANCEL: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); return CertConfirmCancel(hDlg, pComp); break; case PSN_SETACTIVE: CSILOGDWORD(IDS_CATYPE_TITLE, dwWIZACTIVE); PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_NEXT); pComp = _GetCompDataOrReturn(pComp, hDlg); _DisableWizDisplayIfError(pComp, hDlg); _ReturnIfWizError(pComp->hrContinue); pComp->hrContinue = HandleCATypeWizActive(hDlg, pComp); _ReturnIfWizError(pComp->hrContinue); break; case PSN_WIZBACK: CSILOGDWORD(IDS_CATYPE_TITLE, dwWIZBACK); pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->CA.pServer->LastWiz = ENUM_WIZ_CATYPE; break; case PSN_WIZNEXT: CSILOGDWORD(IDS_CATYPE_TITLE, dwWIZNEXT); pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->CA.pServer->LastWiz = ENUM_WIZ_CATYPE; CSILOGDWORD(IDS_LOG_CATYPE, pComp->CA.pServer->CAType); pComp->hrContinue = InitNameFields(pComp->CA.pServer); _ReturnIfWizError(pComp->hrContinue); break; default: return FALSE; } break; default: return FALSE; } return TRUE; } //+--------------------------------------------------------------------------- // Description: display existing keys from list //---------------------------------------------------------------------------- HRESULT ShowExistingKey( IN HWND hDlg, KEY_LIST *pKeyList) { HRESULT hr; KEY_LIST *pKey = pKeyList; HWND hKeyList = GetDlgItem(hDlg, IDC_ADVANCE_KEYLIST); LRESULT nItem; LRESULT lr; WCHAR *pwszDeSanitize = NULL; while (NULL != pKey) { if (NULL != pKey->pwszName) { if (NULL != pwszDeSanitize) { LocalFree(pwszDeSanitize); pwszDeSanitize = NULL; } hr = myRevertSanitizeName(pKey->pwszName, &pwszDeSanitize); _JumpIfError(hr, error, "myRevertSanitizeName"); nItem = (INT)SendMessage( hKeyList, LB_ADDSTRING, (WPARAM) 0, (LPARAM) pwszDeSanitize); if (LB_ERR == nItem) { hr = myHLastError(); _JumpError(hr, error, "SendMessage"); } lr = (INT)SendMessage( hKeyList, LB_SETITEMDATA, (WPARAM) nItem, (LPARAM) pKey->pwszName); if (LB_ERR == lr) { hr = myHLastError(); _JumpError(hr, error, "SendMessage"); } } pKey = pKey->next; } if (NULL != pKeyList) { // choose the 1st one as default lr = (INT)SendMessage(hKeyList, LB_SETCURSEL, (WPARAM) 0, (LPARAM) 0); if (LB_ERR == lr) { hr = myHLastError(); _JumpError(hr, error, "SendMessage"); } } hr = S_OK; error: if (NULL != pwszDeSanitize) { LocalFree(pwszDeSanitize); } return hr; } //+--------------------------------------------------------------------------- // Description: hilight an item by matched data //---------------------------------------------------------------------------- HRESULT HilightItemInList(HWND hDlg, int id, VOID const *pData, BOOL fString) { HWND hListCtrl = GetDlgItem(hDlg, id); LRESULT iItem; LRESULT count; VOID *pItemData; HRESULT hr = NTE_NOT_FOUND; // find item if (fString) { iItem = (INT)SendMessage( hListCtrl, LB_FINDSTRING, (WPARAM) 0, (LPARAM) pData); if (LB_ERR == iItem) { _JumpError(hr, error, "SendMessage"); } hr = S_OK; } else { count = (INT)SendMessage(hListCtrl, LB_GETCOUNT, (WPARAM)0, (LPARAM)0); for (iItem = 0; iItem < count; ++iItem) { pItemData = (VOID*)SendMessage(hListCtrl, LB_GETITEMDATA, (WPARAM)iItem, (LPARAM)0); if (pItemData == pData) { hr = S_OK; break; } } } if (S_OK != hr) { _JumpError(hr, error, "not found"); } // hilight it SendMessage(hListCtrl, LB_SETCURSEL, (WPARAM)iItem, (LPARAM)0); hr = S_OK; error: return hr; } HRESULT ShowAllCSP( HWND hDlg, CSP_INFO *pCSPInfo) { HWND hCSPList = GetDlgItem(hDlg, IDC_ADVANCE_CSPLIST); LRESULT nItem; // list all of csps while (pCSPInfo) { if (pCSPInfo->pwszProvName) { nItem = (INT)SendMessage(hCSPList, LB_ADDSTRING, (WPARAM)0, (LPARAM)pCSPInfo->pwszProvName); SendMessage(hCSPList, LB_SETITEMDATA, (WPARAM)nItem, (LPARAM)pCSPInfo); } pCSPInfo = pCSPInfo->next; } return S_OK; } HRESULT ShowAllHash( HWND hDlg, CSP_HASH *pHashInfo) { HWND hHashList = GetDlgItem(hDlg, IDC_ADVANCE_HASHLIST); LRESULT nItem; // remove hash of previous csp from list while (SendMessage(hHashList, LB_GETCOUNT, (WPARAM)0, (LPARAM)0)) { SendMessage(hHashList, LB_DELETESTRING, (WPARAM)0, (LPARAM)0); } // list all hash while (NULL != pHashInfo) { if (NULL != pHashInfo->pwszName) { nItem = (INT)SendMessage(hHashList, LB_ADDSTRING, (WPARAM)0, (LPARAM)pHashInfo->pwszName); SendMessage(hHashList, LB_SETITEMDATA, (WPARAM)nItem, (LPARAM)pHashInfo); } pHashInfo = pHashInfo->next; } return S_OK; } //-------------------------------------------------------------------- HRESULT UpdateUseCertCheckbox( HWND hDlg, CASERVERSETUPINFO *pServer) { HRESULT hr; BOOL bUsingExistingCert; if (NULL==pServer->pccExistingCert) { bUsingExistingCert=FALSE; } else { bUsingExistingCert=TRUE; } // check "use cert" control SendMessage(GetDlgItem(hDlg, IDC_ADVANCE_USECERTCHECK), BM_SETCHECK, (WPARAM)(bUsingExistingCert?BST_CHECKED:BST_UNCHECKED), (LPARAM)0); // enable the "View Cert" button if necessary EnableWindow(GetDlgItem(hDlg, IDC_ADVANCE_VIEWCERT), bUsingExistingCert); // we will match the hash alg used by the cert, if possible hr=HilightItemInList(hDlg, IDC_ADVANCE_HASHLIST, pServer->pHashInfo, FALSE); _JumpIfError(hr, error, "HilightItemInList"); hr=S_OK; error: return hr; } HRESULT FindCertificateByKeyWithWaitCursor( IN CASERVERSETUPINFO *pServer, OUT CERT_CONTEXT const **ppccCert) { HRESULT hr; HCURSOR hPrevCur = SetCursor(LoadCursor(NULL, IDC_WAIT)); hr = FindCertificateByKey(pServer, ppccCert); SetCursor(hPrevCur); _JumpIfError(hr, error, "FindCertificateByKey"); error: return(hr); } //-------------------------------------------------------------------- // handle the "Use existing Cert" checkbox HRESULT HandleUseCertCheckboxChange( HWND hDlg, CASERVERSETUPINFO *pServer) { HRESULT hr; CERT_CONTEXT const * pccCert; if(pServer->pwszFullCADN) { LocalFree(pServer->pwszFullCADN); pServer->pwszFullCADN = NULL; } // is the checkbox checked or unchecked? if (BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_ADVANCE_USECERTCHECK)) { // checkbox was just checked, so we previously were not using an existing cert CSASSERT(NULL==pServer->pccExistingCert); // Find the existing cert for this key hr = FindCertificateByKeyWithWaitCursor(pServer, &pccCert); _JumpIfError(hr, error, "FindCertificateByKeyWithWaitCursor"); // use it hr=SetExistingCertToUse(pServer, pccCert); _JumpIfError(hr, error, "SetExistingCertToUse"); } else { // checkbox was just unchecked, so we previously were using an existing cert. CSASSERT(NULL!=pServer->pccExistingCert); // stop using the cert ClearExistingCertToUse(pServer); } hr = UpdateUseCertCheckbox(hDlg, pServer); _JumpIfError(hr, error, "UpdateUseCertCheckbox"); error: return hr; } //---------------------------------------------------------------------------- // Hilight the current key - don't use HilightItemInList because we // must use string-compare on the data portion, and HilightItemInList does not // support this. HRESULT HilightKeyInList(HWND hDlg, CASERVERSETUPINFO * pServer) { HWND hListCtrl=GetDlgItem(hDlg, IDC_ADVANCE_KEYLIST); LRESULT nIndex; LRESULT nTotNames; WCHAR * pwszKeyContainerName; HRESULT hr = NTE_NOT_FOUND; nTotNames=(INT)SendMessage(hListCtrl, LB_GETCOUNT, (WPARAM)0, (LPARAM)0); for (nIndex=0; nIndexpwszKeyContainerName)) { SendMessage(hListCtrl, LB_SETCURSEL, (WPARAM)nIndex, (LPARAM)0); hr = S_OK; break; } } if (S_OK != hr) { // can lead to dead wiz pages CSILOG( hr, IDS_LOG_KEY_NOT_FOUND_IN_LIST, pServer->pwszKeyContainerName, NULL, NULL); _PrintErrorStr(hr, "not found", pServer->pwszKeyContainerName); } hr = S_OK; //error: return hr; } //-------------------------------------------------------------------- HRESULT UpdateKeySelection( HWND hDlg, CASERVERSETUPINFO *pServer) { HRESULT hr; BOOL bAvailableExistingCert = FALSE; CERT_CONTEXT const * pccCert; // if we have an existing key, make sure it is the one hilighted // in the list and check for coresponding certs. if (NULL!=pServer->pwszKeyContainerName) { // hilight key hr = HilightKeyInList(hDlg, pServer); _JumpIfError(hr, error, "HilightKeyInList"); if (NULL!=pServer->pccExistingCert) { // we are using an existing cert, so it better exist! bAvailableExistingCert = TRUE; } else { // see if there is an existing cert for this key hr = FindCertificateByKeyWithWaitCursor(pServer, &pccCert); if (S_OK==hr) { CertFreeCertificateContext(pccCert); bAvailableExistingCert = TRUE; } else { // only other return is 'not found' CSASSERT(CRYPT_E_NOT_FOUND==hr); } } } else { // no key selected, can't have an existing cert } // enable/disable reuse cert... EnableWindow(GetDlgItem(hDlg, IDC_ADVANCE_USECERTCHECK), bAvailableExistingCert); hr = UpdateUseCertCheckbox(hDlg, pServer); _JumpIfError(hr, error, "UpdateUseCertCheckbox"); error: return hr; } //-------------------------------------------------------------------- HRESULT UpdateUseKeyCheckbox( HWND hDlg, CASERVERSETUPINFO *pServer) { HRESULT hr; BOOL bReuseKey; if (NULL==pServer->pwszKeyContainerName) { // we are creating a new key bReuseKey=FALSE; } else { // we are using an existing key bReuseKey=TRUE; } // check/uncheck the checkbox depending upon whether we are reusing a key SendDlgItemMessage(hDlg, IDC_ADVANCE_USEKEYCHECK, BM_SETCHECK, (WPARAM)(bReuseKey?BST_CHECKED:BST_UNCHECKED), (LPARAM)0); // enable the key list if we are reusing a key EnableWindow(GetDlgItem(hDlg, IDC_ADVANCE_KEYLIST), bReuseKey); // disable the key length box if we are reusing a key EnableWindow(GetDlgItem(hDlg, IDC_ADVANCE_KEY_LENGTH), !bReuseKey); hr = UpdateKeySelection(hDlg, pServer); _JumpIfError(hr, error, "UpdateKeySelection"); error: return hr; } //+--------------------------------------------------------------------------- // Description: update hash alg. list if csp selection changes //---------------------------------------------------------------------------- HRESULT UpdateHashList( HWND hDlg, CASERVERSETUPINFO *pServer) { HRESULT hr; // load new hash list hr = ShowAllHash(hDlg, pServer->pCSPInfo->pHashList); _JumpIfError(hr, error, "ShowAllHash"); hr = HilightItemInList(hDlg, IDC_ADVANCE_HASHLIST, pServer->pHashInfo, FALSE); _JumpIfError(hr, error, "HilightItemInList"); hr = S_OK; error: return hr; } //+--------------------------------------------------------------------------- // Description: update key list if csp selection changes //---------------------------------------------------------------------------- HRESULT UpdateKeyList( HWND hDlg, CASERVERSETUPINFO *pServer) { HRESULT hr; HWND hKeyList; CSP_HASH *pHashInfo = NULL; int nItem; HCURSOR hPrevCur; // remove keys of previous csp from list hKeyList = GetDlgItem(hDlg, IDC_ADVANCE_KEYLIST); while (SendMessage(hKeyList, LB_GETCOUNT, (WPARAM) 0, (LPARAM) 0)) { SendMessage(hKeyList, LB_DELETESTRING, (WPARAM) 0, (LPARAM) 0); } // update key list with new CSP if (NULL != pServer->pKeyList) { csiFreeKeyList(pServer->pKeyList); } hPrevCur = SetCursor(LoadCursor(NULL, IDC_WAIT)); hr = csiGetKeyList( pServer->pCSPInfo->dwProvType, pServer->pCSPInfo->pwszProvName, pServer->pCSPInfo->fMachineKeyset, FALSE, // fSilent &pServer->pKeyList); SetCursor(hPrevCur); if (S_OK != hr) { _PrintError(hr, "csiGetKeyList"); // don't fail setup if only no key update //goto done; } // show keys if (NULL != pServer->pKeyList) { hr = ShowExistingKey(hDlg, pServer->pKeyList); _JumpIfError(hr, error, "ShowExistingKey"); } if (NULL == pServer->pKeyList) { // no existing key for the csp, so disable "use existing key" checkbox EnableWindow(GetDlgItem(hDlg, IDC_ADVANCE_USEKEYCHECK), FALSE); CSASSERT(NULL==pServer->pwszKeyContainerName); } else { EnableWindow(GetDlgItem(hDlg, IDC_ADVANCE_USEKEYCHECK), TRUE); } hr = UpdateUseKeyCheckbox(hDlg, pServer); _JumpIfError(hr, error, "UpdateUseKeyCheckbox"); //done: hr = S_OK; error: return(hr); } DWORD g_adwKeyLengths[] = { 512, 1024, 2048, 4096, }; DWORD g_adwKeyLengthsSmall[] = { 128, 256, 512, 1024, }; HRESULT AddPredefinedKeyLength ( HWND hwnd, DWORD dwKeyLength) { HRESULT hr; WCHAR wszKeyLength[MAX_KEYLENGTHDIGIT + 1]; WCHAR const *pwszKeyLength; LRESULT nIndex; CSASSERT(0 != dwKeyLength); wsprintf(wszKeyLength, L"%u", dwKeyLength); pwszKeyLength = wszKeyLength; nIndex = (INT)SendMessage(hwnd, CB_ADDSTRING, (WPARAM)0, (LPARAM)pwszKeyLength); if (CB_ERR == nIndex) { hr = E_INVALIDARG; _JumpError(hr, error, "SendMessage(CB_ADDSTRING)"); } SendMessage(hwnd, CB_SETITEMDATA, (WPARAM)nIndex, (LPARAM)dwKeyLength); hr = S_OK; error: return hr; } HRESULT ShowAllKeyLength( HWND hDlg, CASERVERSETUPINFO *pServer) { HRESULT hr; HWND hwndCtrl = GetDlgItem(hDlg, IDC_ADVANCE_KEY_LENGTH); WCHAR wszKeyLength[MAX_KEYLENGTHDIGIT + 1]; DWORD *pdw; DWORD *pdwEnd; // remove existing key length list while (SendMessage(hwndCtrl, CB_GETCOUNT, (WPARAM) 0, (LPARAM) 0)) { SendMessage(hwndCtrl, CB_DELETESTRING, (WPARAM) 0, (LPARAM) 0); } CSASSERT(0 != pServer->dwKeyLength); if(pServer->dwKeyLength > pServer->dwKeyLenMax) { pServer->dwKeyLength=pServer->dwKeyLenMax; } wsprintf(wszKeyLength, L"%u", pServer->dwKeyLength); SetWindowText(hwndCtrl, wszKeyLength); pdw = g_adwKeyLengths; pdwEnd = &g_adwKeyLengths[ARRAYSIZE(g_adwKeyLengths)]; if (C_CSPHASNOKEYMINMAX != pServer->dwKeyLenMin && C_CSPHASNOKEYMINMAX != pServer->dwKeyLenMax && g_adwKeyLengthsSmall[ARRAYSIZE(g_adwKeyLengthsSmall) - 1] >= pServer->dwKeyLenMax) { pdw = g_adwKeyLengthsSmall; pdwEnd = &g_adwKeyLengthsSmall[ARRAYSIZE(g_adwKeyLengthsSmall)]; } // show new key length list for ( ; pdw < pdwEnd; pdw++) { if (0 == *pdw || ((C_CSPHASNOKEYMINMAX != pServer->dwKeyLenMin && *pdw >= pServer->dwKeyLenMin) && (C_CSPHASNOKEYMINMAX != pServer->dwKeyLenMax && *pdw <= pServer->dwKeyLenMax)) ) { hr = AddPredefinedKeyLength(hwndCtrl, *pdw); _JumpIfError(hr, error, "AddPredefinedKeyLength"); } } hr = S_OK; error: return hr; } HRESULT UpdateKeyLengthMinMax( HWND hDlg, CASERVERSETUPINFO *pServer) { HRESULT hr; HCRYPTPROV hProv = NULL; CSP_INFO *pCSPInfo = pServer->pCSPInfo; PROV_ENUMALGS_EX paramData; DWORD cbData; DWORD dwFlags; // default that csp doesn't support PP_ENUMALGS_EX pServer->dwKeyLenMin = C_CSPHASNOKEYMINMAX; pServer->dwKeyLenMax = C_CSPHASNOKEYMINMAX; // determine the min and max key length for selected csp if (!myCertSrvCryptAcquireContext( &hProv, NULL, pCSPInfo->pwszProvName, pCSPInfo->dwProvType, CRYPT_VERIFYCONTEXT, FALSE)) { hr = myHLastError(); if (NULL != hProv) { hProv = NULL; _PrintError(hr, "CSP returns a non-null handle"); } _JumpErrorStr(hr, error, "myCertSrvCryptAcquireContext", pCSPInfo->pwszProvName); } dwFlags = CRYPT_FIRST; while (TRUE) { cbData = sizeof(paramData); if (!CryptGetProvParam( hProv, PP_ENUMALGS_EX, (BYTE *) ¶mData, &cbData, dwFlags)) { hr = myHLastError(); if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr) { // out of for loop break; } _JumpError(hr, error, "CryptGetProvParam"); } if (ALG_CLASS_SIGNATURE == GET_ALG_CLASS(paramData.aiAlgid)) { pServer->dwKeyLenMin = paramData.dwMinLen; pServer->dwKeyLenMax = paramData.dwMaxLen; break; } dwFlags = 0; } error: hr = ShowAllKeyLength(hDlg, pServer); _PrintIfError(hr, "ShowAllKeyLength"); if (NULL != hProv) { CryptReleaseContext(hProv, 0); } return(S_OK); } HRESULT InitializeKeyLengthControl(HWND hDlg) { HWND hwndCtrl = GetDlgItem(hDlg, IDC_ADVANCE_KEY_LENGTH); // set digit length SendMessage( hwndCtrl, CB_LIMITTEXT, (WPARAM) MAX_KEYLENGTHDIGIT, (LPARAM) 0); return S_OK; } //-------------------------------------------------------------------- HRESULT HandleKeySelectionChange( HWND hDlg, CASERVERSETUPINFO *pServer, BOOL fUpdate) { HRESULT hr; HWND hKeyList = GetDlgItem(hDlg, IDC_ADVANCE_KEYLIST); WCHAR * pwszKeyContainerName; CERT_CONTEXT const * pccCert; LRESULT nItem = (INT)SendMessage( hKeyList, LB_GETCURSEL, (WPARAM) 0, (LPARAM) 0); CSASSERT(LB_ERR!=nItem); pwszKeyContainerName = (WCHAR *) SendMessage( hKeyList, LB_GETITEMDATA, (WPARAM) nItem, (LPARAM) 0); CSASSERT(NULL!=pwszKeyContainerName); // Only change is this is a different selection if (NULL==pServer->pwszKeyContainerName || 0!=wcscmp(pwszKeyContainerName, pServer->pwszKeyContainerName)) { // Set the container name to match what the user picked. BOOL fKeyListChange=pServer->fDeletableNewKey; hr = SetKeyContainerName(pServer, pwszKeyContainerName); _JumpIfError(hr, error, "SetKeyContainerName"); // see if there is an existing cert for this key hr = FindCertificateByKeyWithWaitCursor(pServer, &pccCert); if (S_OK==hr) { // Yes there is. By default, use it. hr=SetExistingCertToUse(pServer, pccCert); _JumpIfError(hr, error, "SetExistingCertToUse"); } else { // only other return is 'not found' CSASSERT(CRYPT_E_NOT_FOUND==hr); } // check to see if our caller wants us to update. // our caller may want to do the update himself. if (fUpdate) { // perform the minimum necessary update if (fKeyListChange) { hr = UpdateKeyList(hDlg, pServer); _JumpIfError(hr, error, "UpdateKeyList"); } else { hr = UpdateKeySelection(hDlg, pServer); _JumpIfError(hr, error, "UpdateKeySelection"); } } } hr=S_OK; error: return hr; } //-------------------------------------------------------------------- // handle the "Use existing Key" checkbox HRESULT HandleUseKeyCheckboxChange( HWND hDlg, CASERVERSETUPINFO *pServer) { HRESULT hr; static bool fNT4CertCopiedAlready = false; if(pServer->pwszFullCADN) { LocalFree(pServer->pwszFullCADN); pServer->pwszFullCADN = NULL; } if(pServer->pwszCACommonName) { LocalFree(pServer->pwszCACommonName); pServer->pwszCACommonName = NULL; } if(pServer->pwszDNSuffix) { LocalFree(pServer->pwszDNSuffix); pServer->pwszDNSuffix = NULL; } // is the checkbox checked or unchecked? if (BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_ADVANCE_USEKEYCHECK)) { // checkbox was just checked, so we previously did not have a chosen key. CSASSERT(NULL==pServer->pwszKeyContainerName); hr = HandleKeySelectionChange(hDlg, pServer, FALSE); // don't update, because we need to update too. _JumpIfError(hr, error, "HandleKeySelectionChange"); hr = UpdateUseKeyCheckbox(hDlg, pServer); _JumpIfError(hr, error, "UpdateUseKeyCheckbox"); } else { // checkbox was just unchecked, so we previously had a chosen key.. CSASSERT(NULL!=pServer->pwszKeyContainerName); BOOL fKeyListChange=pServer->fDeletableNewKey; ClearKeyContainerName(pServer); // perform the minimum necessary update if (fKeyListChange) { hr = UpdateKeyList(hDlg, pServer); _JumpIfError(hr, error, "UpdateKeyList"); } else { hr = UpdateUseKeyCheckbox(hDlg, pServer); _JumpIfError(hr, error, "UpdateUseKeyCheckbox"); } hr = InitNameFields(pServer); _JumpIfError(hr, error, "InitNameFields"); } error: return hr; } //-------------------------------------------------------------------- HRESULT UpdateCSPSelection( HWND hDlg, CASERVERSETUPINFO *pServer) { HRESULT hr; bool fInteractiveOff; if (NULL == pServer->pCSPInfo) { hr = E_POINTER; _JumpError(hr, error, "NULL pCSPInfo"); } // hilight current CSP hr = HilightItemInList(hDlg, IDC_ADVANCE_CSPLIST, pServer->pCSPInfo->pwszProvName, TRUE); _JumpIfError(hr, error, "HilightItemInList"); hr = UpdateHashList(hDlg, pServer); _JumpIfError(hr, error, "UpdateHashList"); hr = UpdateKeyLengthMinMax(hDlg, pServer); _JumpIfError(hr, error, "UpdateKeyLengthMinMax"); hr = UpdateKeyList(hDlg, pServer); _JumpIfError(hr, error, "UpdateKeyList"); // Update "interact with desktop" flag. For default CSP // we turn it off, otherwise turn it on. CSASSERT(pServer->pCSPInfo && pServer->pDefaultCSPInfo&& pServer->pCSPInfo->pwszProvName && pServer->pDefaultCSPInfo->pwszProvName); fInteractiveOff = (0 == wcscmp(pServer->pCSPInfo->pwszProvName, pServer->pDefaultCSPInfo->pwszProvName) && (pServer->pCSPInfo->dwProvType == pServer->pDefaultCSPInfo->dwProvType)); SendMessage( GetDlgItem(hDlg, IDC_ADVANCE_INTERACTIVECHECK), BM_SETCHECK, (WPARAM)(fInteractiveOff?BST_UNCHECKED:BST_CHECKED), (LPARAM)0); hr = S_OK; error: return hr; } //-------------------------------------------------------------------- HRESULT HandleCSPSelectionChange( HWND hDlg, CASERVERSETUPINFO *pServer) { HRESULT hr = S_OK; HWND hCSPList; LRESULT nItem; CSP_INFO * pCSPInfo; // get current csp hCSPList = GetDlgItem(hDlg, IDC_ADVANCE_CSPLIST); nItem = (INT)SendMessage(hCSPList, LB_GETCURSEL, (WPARAM)0, (LPARAM)0); pCSPInfo = (CSP_INFO *)SendMessage(hCSPList, LB_GETITEMDATA, (WPARAM)nItem, (LPARAM)0); // only change if this is a different selection if (pCSPInfo->dwProvType!=pServer->pCSPInfo->dwProvType || 0!=wcscmp(pCSPInfo->pwszProvName, pServer->pCSPInfo->pwszProvName)) { // Must create a new key if the CSP changes ClearKeyContainerName(pServer); pServer->pCSPInfo=pCSPInfo; hr = DetermineDefaultHash(pServer); _JumpIfError(hr, error, "DetermineDefaultHash"); hr = UpdateCSPSelection(hDlg, pServer); _JumpIfError(hr, error, "UpdateCSPSelection"); } error: return hr; } // Update cascade: // // UpdateCSPSelection // |-UpdateHashList // |-UpdateKeyLengthMinMax // \-UpdateKeyList // \-UpdateUseKeyCheckbox // \-UpdateKeySelection // \-UpdateUseCertCheckbox HRESULT InitAdvanceWizPageControls( HWND hDlg, CASERVERSETUPINFO *pServer) { HRESULT hr; EnableWindow(GetDlgItem(hDlg, IDC_ADVANCE_INTERACTIVECHECK), TRUE); hr = S_OK; //error: return hr; } HRESULT HandleHashSelectionChange( HWND hDlg, CASERVERSETUPINFO *pServer) { HRESULT hr; HWND hHashList = GetDlgItem(hDlg, IDC_ADVANCE_HASHLIST); LRESULT nItem = (INT)SendMessage( hHashList, LB_GETCURSEL, (WPARAM) 0, (LPARAM) 0); pServer->pHashInfo = (CSP_HASH*)SendMessage( hHashList, LB_GETITEMDATA, (WPARAM) nItem, (LPARAM) 0); // Must validate the hash again when the selected hash changes pServer->fValidatedHashAndKey = FALSE; hr = S_OK; //error: return hr; } HRESULT HandleKeyLengthSelectionChange( HWND hDlg, CASERVERSETUPINFO *pServer) { HRESULT hr; HWND hwndCtrl = GetDlgItem(hDlg, IDC_ADVANCE_KEY_LENGTH); LRESULT nItem = (INT)SendMessage(hwndCtrl, CB_GETCURSEL, (WPARAM)0, (LPARAM)0); pServer->dwKeyLength = (DWORD)SendMessage(hwndCtrl, CB_GETITEMDATA, (WPARAM)nItem, (LPARAM)0); // If key length chenges, we must not have created a key yet. CSASSERT(NULL==pServer->pwszKeyContainerName); hr = S_OK; //error: return hr; } // remove any non-numeric chars except default string HRESULT HandleKeyLengthEditChange( HWND hwndComboBox) { HRESULT hr; WCHAR wszKeyLength[MAX_KEYLENGTHEDIT]; int index = 0; // index for new # int posi = 0; // current position wszKeyLength[0] = L'\0'; // PREFIX says initialize GetWindowText(hwndComboBox, wszKeyLength, ARRAYSIZE(wszKeyLength)); // remove non-numeric chars while (L'\0' != wszKeyLength[posi]) { if (iswdigit(wszKeyLength[posi])) { // take digit wszKeyLength[index] = wszKeyLength[posi]; ++index; } ++posi; } if (index != posi) { // null terminator wszKeyLength[index] = L'\0'; // update SetWindowText(hwndComboBox, wszKeyLength); // point to end SendMessage(hwndComboBox, CB_SETEDITSEL, (WPARAM)0, MAKELPARAM((index), (index)) ); } hr = S_OK; //error: return hr; } HRESULT HandleImportPFXButton( HWND hDlg, PER_COMPONENT_DATA *pComp) { HRESULT hr; CASERVERSETUPINFO *pServer = pComp->CA.pServer; hr = ImportPFXAndUpdateCSPInfo(hDlg, pComp); _PrintIfError(hr, "ImportPFXAndUpdateCSPInfo"); // ignore error and force update anyway. hr = UpdateCSPSelection(hDlg, pServer); _JumpIfError(hr, error, "UpdateCSPSelection"); hr = S_OK; error: return hr; } HRESULT HandleAdvanceWizNext( HWND hDlg, PER_COMPONENT_DATA *pComp) { HRESULT hr; WCHAR wszKeyLength[MAX_KEYLENGTHEDIT]; CASERVERSETUPINFO *pServer = pComp->CA.pServer; HWND hwndCtrl = GetDlgItem(hDlg, IDC_ADVANCE_KEY_LENGTH); BOOL fDontNext = FALSE; WCHAR wszKeyRange[2*MAX_KEYLENGTHDIGIT + 4]; //"(xxxx,xxxx)" format WCHAR *pwszKeyRange = NULL; //don't free just a pointer int dwKeyLength; int idMsg; BOOL fValidDigitString; if (NULL == pServer->pwszKeyContainerName) { GetWindowText(hwndCtrl, wszKeyLength, ARRAYSIZE(wszKeyLength)); dwKeyLength = myWtoI(wszKeyLength, &fValidDigitString); if (0 > dwKeyLength) { idMsg = IDS_ADVANCE_NEGATIVEKEYLENGTH; fDontNext = TRUE; } else if (!fValidDigitString) { idMsg = IDS_ADVANCE_INVALIDKEYLENGTH; fDontNext = TRUE; } else if ( (C_CSPHASNOKEYMINMAX != pServer->dwKeyLenMin && (DWORD)dwKeyLength < pServer->dwKeyLenMin) || (C_CSPHASNOKEYMINMAX != pServer->dwKeyLenMax && (DWORD)dwKeyLength > pServer->dwKeyLenMax) ) { swprintf(wszKeyRange, L"(%ld, %ld)", pServer->dwKeyLenMin, pServer->dwKeyLenMax); pwszKeyRange = wszKeyRange; idMsg = IDS_ADVANCE_KEYLENGTHOUTOFRANGE; fDontNext = TRUE; } if (fDontNext) { CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, idMsg, 0, pwszKeyRange); SetEditFocusAndSelect(hwndCtrl, 0, -1); goto done; } // take the length pServer->dwKeyLength = dwKeyLength; } else { // use existing key if (NULL==pServer->pccExistingCert) { // If reusing a key but not a cert, make the common name match the key name if (NULL != pServer->pwszCACommonName) { // free old LocalFree(pServer->pwszCACommonName); pServer->pwszCACommonName = NULL; } pServer->pwszCACommonName = (WCHAR*) LocalAlloc(LPTR, (wcslen(pServer->pwszDesanitizedKeyContainerName) + 1) * sizeof(WCHAR)); _JumpIfOutOfMemory(hr, error, pServer->pwszCACommonName); wcscpy(pServer->pwszCACommonName, pServer->pwszDesanitizedKeyContainerName); hr = InitNameFields(pServer); _JumpIfError(hr, error, "InitNameFields"); } else { // If reusing a cert, make all the ID fields match the cert // use idinfo from signing cert hr = DetermineExistingCAIdInfo(pServer, NULL); if (S_OK != hr) { CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_ERR_ANALYSIS_CA, hr, NULL); _PrintError(hr, "DetermineExistingCAIdInfo"); fDontNext = TRUE; goto done; } } } // get "interactive service" check box state pServer->fInteractiveService = (BST_CHECKED == SendMessage(GetDlgItem(hDlg, IDC_ADVANCE_INTERACTIVECHECK), BM_GETCHECK, (WPARAM)0, (LPARAM)0))? TRUE:FALSE; // update hash oid if (NULL != pServer->pszAlgId) { // free old LocalFree(pServer->pszAlgId); } hr = myGetSigningOID( NULL, // hProv pServer->pCSPInfo->pwszProvName, pServer->pCSPInfo->dwProvType, pServer->pHashInfo->idAlg, &(pServer->pszAlgId)); if (S_OK != hr) { CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_ERR_UNSUPPORTEDHASH, hr, NULL); fDontNext = TRUE; goto done; } done: if (fDontNext) { SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE); // forbid } else { pServer->LastWiz = ENUM_WIZ_ADVANCE; } hr = S_OK; error: return hr; } HRESULT HandleAdvanceWizActive( HWND hDlg, PER_COMPONENT_DATA *pComp) { HRESULT hr; CASERVERSETUPINFO *pServer = pComp->CA.pServer; // Suppress this wizard page if // we've already seen an error, or // the advanced option was not selected, or // we are not installing the server. if (!pServer->fAdvance || !(IS_SERVER_INSTALL & pComp->dwInstallStatus) ) { // disable page CSILOGDWORD(IDS_ADVANCE_TITLE, dwWIZDISABLE); SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1); goto done; } if (NULL == pServer->pCSPInfoList) { // construct CSP info list HCURSOR hPrevCur = SetCursor(LoadCursor(NULL, IDC_WAIT)); hr = GetCSPInfoList(&pServer->pCSPInfoList); SetCursor(hPrevCur); _JumpIfError(hr, error, "GetCSPInfoList"); // show all csps hr = ShowAllCSP(hDlg, pServer->pCSPInfoList); _JumpIfError(hr, error, "ShowAllCSP"); // determine default csp hr = DetermineDefaultCSP(pServer); _JumpIfError(hr, error, "DetermineDefaultCSP"); hr = DetermineDefaultHash(pServer); _JumpIfError(hr, error, "DetermineDefaultHash"); hr = InitializeKeyLengthControl(hDlg); _JumpIfError(hr, error, "InitializeKeyLengthControl"); } hr = UpdateCSPSelection(hDlg, pServer); _JumpIfError(hr, error, "UpdateCSPSelection"); done: hr = S_OK; error: return hr; } HRESULT HandleViewCertButton( HWND hDlg, PER_COMPONENT_DATA *pComp) { HRESULT hr; CRYPTUI_VIEWCERTIFICATE_STRUCTW viewCert; CASERVERSETUPINFO *pServer = pComp->CA.pServer; CSASSERT(NULL!=pServer->pwszKeyContainerName && NULL!=pServer->pccExistingCert); ZeroMemory(&viewCert, sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW)); viewCert.hwndParent = hDlg; viewCert.dwSize = sizeof(viewCert); viewCert.pCertContext = CertDuplicateCertificateContext(pServer->pccExistingCert); if (NULL == viewCert.pCertContext) { hr = myHLastError(); _JumpError(hr, error, "CertDuplicateCertificateContext"); } // viewCert.rghStores = &pServer->hMyStore; // viewCert.cStores = 1; viewCert.dwFlags = CRYPTUI_DONT_OPEN_STORES; if (!CryptUIDlgViewCertificateW(&viewCert, NULL)) { hr = myHLastError(); _PrintError(hr, "CryptUIDlgViewCertificate"); } hr = S_OK; error: if (NULL != viewCert.pCertContext) { CertFreeCertificateContext(viewCert.pCertContext); } return hr; } //+------------------------------------------------------------------------ // // Function: WizAdvancedPageDlgProc(. . . .) // // Synopsis: Dialog procedure for advanced configuration OCM wizard. // // Arguments: [hDlg] // [iMsg] // [wParam] // [lParam] ... the usual. // // Returns: BOOL dlg proc result. // //------------------------------------------------------------------------- INT_PTR WizAdvancedPageDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { PER_COMPONENT_DATA *pComp = NULL; switch (iMsg) { case WM_INITDIALOG: // point to component data SetWindowLongPtr(hDlg, DWLP_USER, (LONG)((PROPSHEETPAGE*)lParam)->lParam); pComp = (PER_COMPONENT_DATA*)((PROPSHEETPAGE*)lParam)->lParam; _ReturnIfWizError(pComp->hrContinue); pComp->hrContinue = InitAdvanceWizPageControls(hDlg, pComp->CA.pServer); _ReturnIfWizError(pComp->hrContinue); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_ADVANCE_CSPLIST: switch (HIWORD(wParam)) { case LBN_SELCHANGE: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleCSPSelectionChange(hDlg, pComp->CA.pServer); _ReturnIfWizError(pComp->hrContinue); break; default: break; } break; case IDC_ADVANCE_HASHLIST: switch (HIWORD(wParam)) { case LBN_SELCHANGE: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleHashSelectionChange(hDlg, pComp->CA.pServer); _ReturnIfWizError(pComp->hrContinue); break; } break; case IDC_ADVANCE_KEYLIST: switch (HIWORD(wParam)) { case LBN_SELCHANGE: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleKeySelectionChange(hDlg, pComp->CA.pServer, TRUE); _ReturnIfWizError(pComp->hrContinue); break; } break; case IDC_ADVANCE_USEKEYCHECK: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleUseKeyCheckboxChange(hDlg, pComp->CA.pServer); _ReturnIfWizError(pComp->hrContinue); break; case IDC_ADVANCE_USECERTCHECK: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleUseCertCheckboxChange(hDlg, pComp->CA.pServer); _ReturnIfWizError(pComp->hrContinue); break; case IDC_ADVANCE_KEY_LENGTH: switch (HIWORD(wParam)) { case CBN_SELCHANGE: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleKeyLengthSelectionChange(hDlg, pComp->CA.pServer); _ReturnIfWizError(pComp->hrContinue); break; case CBN_EDITCHANGE: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleKeyLengthEditChange( (HWND)lParam); _ReturnIfWizError(pComp->hrContinue); break; } break; case IDC_ADVANCE_IMPORT: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleImportPFXButton(hDlg, pComp); _ReturnIfWizError(pComp->hrContinue); break; case IDC_ADVANCE_VIEWCERT: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleViewCertButton(hDlg, pComp); _ReturnIfWizError(pComp->hrContinue); break; default: return FALSE; } break; case WM_NOTIFY: switch (((NMHDR FAR*) lParam)->code) { case PSN_KILLACTIVE: break; case PSN_RESET: break; case PSN_QUERYCANCEL: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); return CertConfirmCancel(hDlg, pComp); break; case PSN_SETACTIVE: CSILOGDWORD(IDS_ADVANCE_TITLE, dwWIZACTIVE); PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_NEXT); pComp = _GetCompDataOrReturn(pComp, hDlg); _DisableWizDisplayIfError(pComp, hDlg); _ReturnIfWizError(pComp->hrContinue); pComp->hrContinue = HandleAdvanceWizActive(hDlg, pComp); _ReturnIfWizError(pComp->hrContinue); break; case PSN_WIZBACK: CSILOGDWORD(IDS_ADVANCE_TITLE, dwWIZBACK); break; case PSN_WIZNEXT: DWORD fReuseCert; pComp = _GetCompDataOrReturnIfError(pComp, hDlg); fReuseCert = NULL != pComp->CA.pServer->pccExistingCert; CSILOG( S_OK, IDS_LOG_KEYNAME, pComp->CA.pServer->pwszKeyContainerName, pComp->CA.pServer->pwszDesanitizedKeyContainerName, &fReuseCert); CSILOGDWORD(IDS_ADVANCE_TITLE, dwWIZNEXT); pComp->hrContinue = HandleAdvanceWizNext(hDlg, pComp); _ReturnIfWizError(pComp->hrContinue); break; default: return FALSE; } break; default: return FALSE; } return TRUE; } HRESULT EnableSharedFolderControls(HWND hDlg, BOOL fUseSharedFolder) { EnableWindow(GetDlgItem(hDlg, IDC_STORE_EDIT_SHAREDFOLDER), fUseSharedFolder); EnableWindow(GetDlgItem(hDlg, IDC_STORE_SHAREDBROWSE), fUseSharedFolder); if (fUseSharedFolder) { SetEditFocusAndSelect(GetDlgItem(hDlg, IDC_STORE_EDIT_SHAREDFOLDER), 0, -1); } return S_OK; } HRESULT StorePageValidation( HWND hDlg, PER_COMPONENT_DATA *pComp, BOOL *pfDontNext) { HRESULT hr; UINT uiFocus = 0; WCHAR *pwszDefaultDBDir = NULL; WCHAR *pwszDefaultSF = NULL; LPWSTR pwszPrompt = NULL; LPWSTR pwszComputerName = NULL; BOOL fExistSF = TRUE; BOOL fExistDB = TRUE; BOOL fExistLog = TRUE; BOOL fDefaultDir; BOOL fIsUNC, fIsSharedFolderUNC; WCHAR wszNotExistingDir[3 * MAX_PATH]; BOOL fUseSharedFolder; CASERVERSETUPINFO *pServer = pComp->CA.pServer; *pfDontNext = FALSE; // get shared folder check state if (pComp->fUnattended) { CSASSERT(NULL != pServer->pwszSharedFolder); fUseSharedFolder = TRUE; // unattended always use shared folder } else { fUseSharedFolder = (BST_CHECKED == SendMessage( GetDlgItem(hDlg, IDC_STORE_USE_SHAREDFOLDER), BM_GETCHECK, 0, 0)); } if (NULL != pServer->pwszSharedFolder) { fDefaultDir = TRUE; hr = GetDefaultSharedFolder(&pwszDefaultSF); _JumpIfError(hr, error, "GetDefaultSharedFolder"); // make sure case insensitive if (0 != lstrcmpiW(pwszDefaultSF, pServer->pwszSharedFolder)) { fDefaultDir = FALSE; } if (!ValidateAndCreateDirField( pComp->hInstance, pComp->fUnattended, hDlg, pServer->pwszSharedFolder, fDefaultDir, IDS_WRN_STORELOC_SHAREDFOLDER_FULLPATH, &fExistSF, &fIsSharedFolderUNC)) { uiFocus = IDC_STORE_EDIT_SHAREDFOLDER; *pfDontNext = TRUE; goto done; } } else if (fUseSharedFolder) { // the case to enforce shared folder but edit field is empty CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_WRN_STORELOC_SHAREDFOLDER_FULLPATH, 0, L""); uiFocus = IDC_STORE_EDIT_SHAREDFOLDER; *pfDontNext = TRUE; goto done; } fDefaultDir = TRUE; hr = GetDefaultDBDirectory(pComp, &pwszDefaultDBDir); _JumpIfError(hr, error, "GetDefaultDBDirectory"); // make sure case insensitive if (0 != lstrcmpiW(pwszDefaultDBDir, pServer->pwszDBDirectory)) { fDefaultDir = FALSE; } if (!ValidateAndCreateDirField( pComp->hInstance, pComp->fUnattended, hDlg, pServer->pwszDBDirectory, fDefaultDir, IDS_WRN_STORELOC_DB_FULLPATH, &fExistDB, &fIsUNC)) { uiFocus = IDC_STORE_EDIT_DB; *pfDontNext = TRUE; goto done; } fDefaultDir = TRUE; // remember default log dir is the same as db if (0 != lstrcmpiW(pwszDefaultDBDir, pServer->pwszLogDirectory)) { fDefaultDir = FALSE; } if (!ValidateAndCreateDirField( pComp->hInstance, pComp->fUnattended, hDlg, pServer->pwszLogDirectory, fDefaultDir, IDS_WRN_STORELOC_LOG_FULLPATH, &fExistLog, &fIsUNC)) { uiFocus = IDC_STORE_EDIT_LOG; *pfDontNext = TRUE; goto done; } wszNotExistingDir[0] = '\0'; // empty string if (!fExistSF) { wcscat(wszNotExistingDir, pServer->pwszSharedFolder); } if (!fExistDB) { if ('\0' != wszNotExistingDir[0]) { wcscat(wszNotExistingDir, L"\n"); } wcscat(wszNotExistingDir, pServer->pwszDBDirectory); } if (!fExistLog) { if ('\0' != wszNotExistingDir[0]) { wcscat(wszNotExistingDir, L"\n"); } wcscat(wszNotExistingDir, pServer->pwszLogDirectory); } if ('\0' != wszNotExistingDir[0]) { // skip confirm in unattended mode if (!pComp->fUnattended) { // confirm all here if (IDYES != CertMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_ASK_CREATE_DIRECTORY, 0, MB_YESNO | MB_ICONWARNING | CMB_NOERRFROMSYS, wszNotExistingDir) ) { if (!fExistSF) { uiFocus = IDC_STORE_EDIT_SHAREDFOLDER; } else if (!fExistDB) { uiFocus = IDC_STORE_EDIT_DB; } else if (!fExistLog) { uiFocus = IDC_STORE_EDIT_LOG; } *pfDontNext = TRUE; goto done; } } if (!fExistSF) { hr = myCreateNestedDirectories(pServer->pwszSharedFolder); if (S_OK != hr) { CertWarningMessageBox(pComp->hInstance, pComp->fUnattended, hDlg, IDS_ERR_CREATE_DIR, hr, pServer->pwszSharedFolder); uiFocus = IDC_STORE_EDIT_SHAREDFOLDER; *pfDontNext = TRUE; goto done; } } if (!fExistDB) { hr = myCreateNestedDirectories(pServer->pwszDBDirectory); if (S_OK != hr) { CertWarningMessageBox(pComp->hInstance, pComp->fUnattended, hDlg, IDS_ERR_CREATE_DIR, hr, pServer->pwszDBDirectory); uiFocus = IDC_STORE_EDIT_DB; *pfDontNext = TRUE; goto done; } } if (!fExistLog) { hr = myCreateNestedDirectories(pServer->pwszLogDirectory); if (S_OK != hr) { CertWarningMessageBox(pComp->hInstance, pComp->fUnattended, hDlg, IDS_ERR_CREATE_DIR, hr, pServer->pwszLogDirectory); uiFocus = IDC_STORE_EDIT_LOG; *pfDontNext = TRUE; goto done; } } } hr = ValidateESERestrictions(pServer->pwszDBDirectory); if (S_OK != hr) { CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_WRN_DBSPECIALCHARACTERS, hr, pServer->pwszDBDirectory); uiFocus = IDC_STORE_EDIT_DB; *pfDontNext = TRUE; goto done; } hr = ValidateESERestrictions(pServer->pwszLogDirectory); if (S_OK != hr) { CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_WRN_DBSPECIALCHARACTERS, hr, pServer->pwszLogDirectory); uiFocus = IDC_STORE_EDIT_LOG; *pfDontNext = TRUE; goto done; } CSASSERT(!*pfDontNext); // directory creation done; now analyze for UNC, sharepath if (NULL != pServer->pwszSharedFolder) { // if not UNC, prompt to change to UNC if (!fIsSharedFolderUNC) { #define UNCPATH_TEMPLATE L"\\\\%ws\\" wszCERTCONFIGSHARENAME hr = myAddShare( wszCERTCONFIGSHARENAME, myLoadResourceString(IDS_CERTCONFIG_FOLDERDESCR), pServer->pwszSharedFolder, TRUE, // overwrite NULL); _JumpIfError(hr, done, "myAddShare"); // get the local machine name WCHAR wszUNCPath[MAX_PATH + ARRAYSIZE(UNCPATH_TEMPLATE)]; // "machine" + UNCPATH_TEMPLATE hr = myGetMachineDnsName(&pwszComputerName); _JumpIfError(hr, done, "myGetMachineDnsName"); // create UNC path swprintf(wszUNCPath, UNCPATH_TEMPLATE, pwszComputerName); // only convert to UNC if this thing is shared LocalFree(pServer->pwszSharedFolder); pServer->pwszSharedFolder = (LPWSTR)LocalAlloc(LMEM_FIXED, WSZ_BYTECOUNT(wszUNCPath)); _JumpIfOutOfMemory(hr, error, pServer->pwszSharedFolder); wcscpy(pServer->pwszSharedFolder, wszUNCPath); } // else, user typed in an already-shared UNC path } done: hr = S_OK; error: if (NULL != pwszDefaultDBDir) LocalFree(pwszDefaultDBDir); if (NULL != pwszDefaultSF) LocalFree(pwszDefaultSF); if (NULL != pwszPrompt) LocalFree(pwszPrompt); if (NULL != pwszComputerName) LocalFree(pwszComputerName); if (!pComp->fUnattended && uiFocus != 0 && *pfDontNext) { SetEditFocusAndSelect(GetDlgItem(hDlg, uiFocus), 0, -1); } return hr; } HRESULT StoreDBShareValidation( IN HWND hDlg, IN PER_COMPONENT_DATA *pComp, IN WCHAR const *pwszDir, IN BOOL fDB, //db dir vs. log dir OUT BOOL *pfDontNext) { HRESULT hr; WCHAR *pwszDefaultLogDir = NULL; BOOL fDefaultLogPath; WCHAR *pwszFileInUse = NULL; BOOL fFilesExist; static BOOL s_fOverwriteDB = FALSE; static BOOL s_fOverwriteLog = FALSE; BOOL *pfOverwrite = fDB ? &s_fOverwriteDB : &s_fOverwriteLog; // init *pfDontNext = FALSE; // get default log path which is the same as db hr = GetDefaultDBDirectory(pComp, &pwszDefaultLogDir); _JumpIfError(hr, error, "GetDefaultDBDirectory"); fDefaultLogPath = (0 == lstrcmpi(pwszDir, pwszDefaultLogDir)); hr = myDoDBFilesExistInDir(pwszDir, &fFilesExist, &pwszFileInUse); _JumpIfError(hr, error, "myDoDBFilesExistInDir"); if (NULL != pwszFileInUse) { CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_WRN_DBFILEINUSE, 0, pwszFileInUse); *pfDontNext = TRUE; goto done; } if (!pComp->CA.pServer->fPreserveDB && fFilesExist && !*pfOverwrite && !fDefaultLogPath) { // log file exists in non-default dir if (IDYES != CertMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_WRN_STORELOC_EXISTINGDB, 0, MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING | CMB_NOERRFROMSYS, pwszDir)) { *pfDontNext = TRUE; goto done; } // warn only once *pfOverwrite = TRUE; } done: if (*pfDontNext) { // set focus SetEditFocusAndSelect(GetDlgItem(hDlg, IDC_STORE_EDIT_LOG), 0, -1); } hr = S_OK; error: if (NULL != pwszFileInUse) { LocalFree(pwszFileInUse); } if (NULL != pwszDefaultLogDir) { LocalFree(pwszDefaultLogDir); } return hr; } HRESULT FinishDirectoryBrowse( HWND hDlg, int idEdit) { HRESULT hr = S_FALSE; WCHAR dirInitName[MAX_PATH]; WCHAR dirName[MAX_PATH]; GetWindowText(GetDlgItem(hDlg, idEdit), dirInitName, MAX_PATH); if (BrowseForDirectory( GetParent(hDlg), dirInitName, dirName, MAX_PATH, NULL, TRUE)) { SetDlgItemText(hDlg, idEdit, dirName); hr = S_OK; } return hr; } HRESULT HookStorePageStrings( HWND hDlg, PAGESTRINGS *pPageString, CASERVERSETUPINFO *pServer) { HRESULT hr; for ( ; 0 != pPageString->idControl; pPageString++) { switch (pPageString->idControl) { case IDC_STORE_EDIT_SHAREDFOLDER: pPageString->ppwszString = &(pServer->pwszSharedFolder); break; case IDC_STORE_EDIT_DB: pPageString->ppwszString = &(pServer->pwszDBDirectory); break; case IDC_STORE_EDIT_LOG: pPageString->ppwszString = &(pServer->pwszLogDirectory); break; default: hr = E_INVALIDARG; _JumpError(hr, error, "Internal error"); break; } } hr = S_OK; error: return hr; } HRESULT InitStoreWizControls( HWND hDlg, PAGESTRINGS *pPageString, CASERVERSETUPINFO *pServer) { HRESULT hr; // now make page strings complete hr = HookStorePageStrings(hDlg, pPageString, pServer); _JumpIfError(hr, error, "HookStorePageStrings"); SendDlgItemMessage(hDlg, IDC_STORE_USE_SHAREDFOLDER, BM_SETCHECK, (WPARAM)((NULL != pServer->pwszSharedFolder) ? BST_CHECKED : BST_UNCHECKED), (LPARAM)0); if (!pServer->fUseDS && (NULL != pServer->pwszSharedFolder)) { // no DS, disable shared folder check to force it EnableWindow(GetDlgItem(hDlg, IDC_STORE_USE_SHAREDFOLDER), FALSE); } hr = StartWizardPageEditControls(hDlg, pPageString); _JumpIfError(hr, error, "StartWizardPageEditControls"); hr = S_OK; error: return hr; } HRESULT HandlePreservingDB( HWND hDlg, PER_COMPONENT_DATA *pComp) { HRESULT hr; CASERVERSETUPINFO *pServer = pComp->CA.pServer; HWND hwndSF = GetDlgItem(hDlg, IDC_STORE_EDIT_SHAREDFOLDER); HWND hwndDB = GetDlgItem(hDlg, IDC_STORE_EDIT_DB); HWND hwndLog = GetDlgItem(hDlg, IDC_STORE_EDIT_LOG); BOOL fEnable = TRUE; BOOL fEnableSharedFolder = TRUE; WCHAR *pwszExistingSharedFolder = NULL; WCHAR *pwszExistingDBDirectory = NULL; WCHAR *pwszExistingLogDirectory = NULL; if (pServer->fPreserveDB) { if (!pServer->fUNCPathNotFound) { // get shared folder path hr = myGetCertRegStrValue(NULL, NULL, NULL, wszREGDIRECTORY, &pwszExistingSharedFolder); if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) { // optional value hr = S_OK; pwszExistingSharedFolder = NULL; } _JumpIfError(hr, error, "myGetCertRegStrValue"); fEnableSharedFolder = FALSE; } else { pwszExistingSharedFolder = pServer->pwszSharedFolder; } // get existing db path hr = myGetCertRegStrValue(NULL, NULL, NULL, wszREGDBDIRECTORY, &pwszExistingDBDirectory); _JumpIfError(hr, error, "myGetCertRegStrValue"); hr = myGetCertRegStrValue(NULL, NULL, NULL, wszREGDBLOGDIRECTORY, &pwszExistingLogDirectory); _JumpIfError(hr, error, "myGetCertRegStrValue"); // fill edit fields SetWindowText(hwndSF, pwszExistingSharedFolder); SetWindowText(hwndDB, pwszExistingDBDirectory); SetWindowText(hwndLog, pwszExistingLogDirectory); // disable them fEnable = FALSE; } EnableWindow(hwndSF, fEnableSharedFolder); EnableWindow(hwndDB, fEnable); EnableWindow(hwndLog, fEnable); hr = S_OK; error: if (NULL != pwszExistingSharedFolder && pwszExistingSharedFolder != pServer->pwszSharedFolder) { LocalFree(pwszExistingSharedFolder); } if (NULL != pwszExistingDBDirectory) { LocalFree(pwszExistingDBDirectory); } if (NULL != pwszExistingLogDirectory) { LocalFree(pwszExistingLogDirectory); } return hr; } HRESULT HandleStoreWizActive( HWND hDlg, PER_COMPONENT_DATA *pComp, PAGESTRINGS *pPageString) { HRESULT hr; HWND hwndDB; BOOL fEnableKeepDB = FALSE; CASERVERSETUPINFO *pServer = pComp->CA.pServer; // Suppress this wizard page if // we've already seen an error, or // we are not installing the server. if (!(IS_SERVER_INSTALL & pComp->dwInstallStatus) ) { // disable page CSILOGDWORD(IDS_STORE_TITLE, dwWIZDISABLE); SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1); goto done; } CSASSERT(NULL != pServer->pwszKeyContainerName); hwndDB = GetDlgItem(hDlg, IDC_STORE_KEEPDB); if (NULL != pServer->pccExistingCert) { // determine existing db status hr = myDoDBFilesExist( pServer->pwszSanitizedName, &fEnableKeepDB, NULL); _JumpIfError(hr, error, "myDoDBFilesExist"); } else { // can't use db pServer->fPreserveDB = FALSE; SendMessage(hwndDB, BM_SETCHECK, (WPARAM)BST_UNCHECKED, (LPARAM)0); HandlePreservingDB(hDlg, pComp); } // enable/disable the control EnableSharedFolderControls(hDlg, NULL != pServer->pwszSharedFolder); EnableWindow(hwndDB, fEnableKeepDB); done: hr = S_OK; error: return hr; } HRESULT HandleStoreWizNextOrBack( HWND hDlg, PAGESTRINGS *pPageString, PER_COMPONENT_DATA *pComp, int iWizBN) { HRESULT hr; HWND hwndCtrl = NULL; WCHAR *pwszFile = NULL; WCHAR const *pwszCertName; CASERVERSETUPINFO *pServer = pComp->CA.pServer; BOOL fDontNext = FALSE; BOOL fGoBack = FALSE; BOOL fUseSharedFolder; HCURSOR hPrevCur; hr = FinishWizardPageEditControls(hDlg, pPageString); _JumpIfError(hr, error, "FinishWizardPageEditControls"); if (PSN_WIZBACK == iWizBN) { goto done; } // make sure at least one way to publish ca CSASSERT(NULL != pServer->pwszSharedFolder || pComp->CA.pServer->fUseDS); // get shared folder check state fUseSharedFolder = (BST_CHECKED == SendMessage( GetDlgItem(hDlg, IDC_STORE_USE_SHAREDFOLDER), BM_GETCHECK, 0, 0)); if (!fUseSharedFolder && NULL != pServer->pwszSharedFolder) { //don't collect shared folder from edit control LocalFree(pServer->pwszSharedFolder); pServer->pwszSharedFolder = NULL; } hPrevCur = SetCursor(LoadCursor(NULL, IDC_WAIT)); hr = StorePageValidation(hDlg, pComp, &fDontNext); SetCursor(hPrevCur); _JumpIfError(hr, error, "StorePageValidation"); if (fDontNext) { goto done; } // validate existing db sharing here hr = StoreDBShareValidation( hDlg, pComp, pComp->CA.pServer->pwszDBDirectory, TRUE, //db dir &fDontNext); _JumpIfError(hr, error, "StoreDBShareValidation"); if (fDontNext) { goto done; } if (0 != lstrcmpi( pComp->CA.pServer->pwszDBDirectory, pComp->CA.pServer->pwszLogDirectory)) { hr = StoreDBShareValidation( hDlg, pComp, pComp->CA.pServer->pwszLogDirectory, FALSE, //log dir &fDontNext); _JumpIfError(hr, error, "StoreDBShareValidation"); if (fDontNext) { goto done; } } hr = myBuildPathAndExt( pComp->CA.pServer->pwszDBDirectory, pServer->pwszSanitizedName, wszDBFILENAMEEXT, &pwszFile); _JumpIfError(hr, error, "myBuildPathAndExt"); // make sure path fits if (MAX_PATH <= wcslen(pwszFile)) { // pop up warning CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_PATH_TOO_LONG_CANAME, S_OK, pwszFile); // make it go back fGoBack = TRUE; fDontNext = TRUE; goto done; } LocalFree(pwszFile); pwszFile = NULL; hr = myBuildPathAndExt( pComp->CA.pServer->pwszLogDirectory, TEXT(szDBBASENAMEPARM) L"00000", wszLOGFILENAMEEXT, &pwszFile); _JumpIfError(hr, error, "myBuildPathAndExt"); // make sure path fits if (MAX_PATH <= wcslen(pwszFile)) { // pop up warning CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_PATH_TOO_LONG_DIRECTORY, S_OK, pwszFile); SetEditFocusAndSelect(GetDlgItem(hDlg, IDC_STORE_EDIT_LOG), 0, -1); fDontNext = TRUE; goto done; } LocalFree(pwszFile); pwszFile = NULL; hr = csiBuildCACertFileName( pComp->hInstance, hDlg, pComp->fUnattended, pServer->pwszSharedFolder, pServer->pwszSanitizedName, L".crt", 0, // CANAMEIDTOICERT(pServer->dwCertNameId), &pwszFile); _JumpIfError(hr, error, "csiBuildCACertFileName"); // make sure path fit if (MAX_PATH <= wcslen(pwszFile) + cwcSUFFIXMAX) { // pop up warning CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_PATH_TOO_LONG_CANAME, S_OK, pwszFile); // make it go back fGoBack = TRUE; fDontNext = TRUE; goto done; } if (NULL != pServer->pwszCACertFile) { // free old one LocalFree(pServer->pwszCACertFile); } pServer->pwszCACertFile = pwszFile; pwszFile = NULL; if (IsRootCA(pServer->CAType)) { hPrevCur = SetCursor(LoadCursor(NULL, IDC_WAIT)); hr = StartAndStopService(pComp->hInstance, pComp->fUnattended, hDlg, wszW3SVCNAME, TRUE, TRUE, // confirmation IDS_STOP_W3SVC, &g_fW3SvcRunning); SetCursor(hPrevCur); if (S_OK != hr) { if (E_ABORT == hr) { fDontNext = TRUE; goto done; } _JumpError(hr, error, "StartAndStopService"); } } done: if (fDontNext) { SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE); // forbid if (fGoBack) { PropSheet_PressButton(GetParent(hDlg), PSBTN_BACK); pServer->LastWiz = ENUM_WIZ_STORE; } } else { // continue to next pServer->LastWiz = ENUM_WIZ_STORE; } hr = S_OK; error: if (NULL != pwszFile) { LocalFree(pwszFile); } return hr; } HRESULT HandleUseSharedFolder( IN HWND hDlg, IN OUT PER_COMPONENT_DATA *pComp) { HRESULT hr; // get shared folder check state BOOL fUseSharedFolder = (BST_CHECKED == SendMessage( GetDlgItem(hDlg, IDC_STORE_USE_SHAREDFOLDER), BM_GETCHECK, 0, 0)); if (!fUseSharedFolder && !pComp->CA.pServer->fUseDS) { // must check at least one, force unchange fUseSharedFolder = TRUE; SendDlgItemMessage(hDlg, IDC_STORE_USE_SHAREDFOLDER, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0); } hr = EnableSharedFolderControls(hDlg, fUseSharedFolder); // _JumpIfError(hr, error, "EnableSharedFolderControls"); _PrintIfError(hr, "EnableSharedFolderControls"); // hr = S_OK; //error: return hr; } //+------------------------------------------------------------------------ // Function: WizStorePageDlgProc(. . . .) // // Synopsis: Dialog procedure for storage location //------------------------------------------------------------------------- INT_PTR WizStorePageDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { PER_COMPONENT_DATA *pComp = NULL; // keep scope of following array inside static PAGESTRINGS saStoreString[] = { { IDC_STORE_EDIT_SHAREDFOLDER, IDS_LOG_SHAREDFOLDER, 0, 0, MAX_PATH, NULL, }, { IDC_STORE_EDIT_DB, IDS_LOG_DBDIR, 0, 0, MAX_PATH, NULL, }, { IDC_STORE_EDIT_LOG, IDS_LOG_DBLOGDIR, 0, 0, MAX_PATH, NULL, }, // you need to add code in HookStoreStrings if adding more... { 0, 0, 0, 0, 0, NULL, } }; switch(iMsg) { case WM_INITDIALOG: // point to component data SetWindowLongPtr(hDlg, DWLP_USER, (LONG)((PROPSHEETPAGE*)lParam)->lParam); pComp = (PER_COMPONENT_DATA*)((PROPSHEETPAGE*)lParam)->lParam; _ReturnIfWizError(pComp->hrContinue); pComp->hrContinue = InitStoreWizControls(hDlg, saStoreString, pComp->CA.pServer); _ReturnIfWizError(pComp->hrContinue); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_STORE_USE_SHAREDFOLDER: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleUseSharedFolder(hDlg, pComp); _ReturnIfWizError(pComp->hrContinue); break; case IDC_STORE_KEEPDB: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->CA.pServer->fPreserveDB = !pComp->CA.pServer->fPreserveDB; pComp->hrContinue = HandlePreservingDB(hDlg, pComp); _ReturnIfWizError(pComp->hrContinue); break; case IDC_STORE_SHAREDBROWSE: FinishDirectoryBrowse(hDlg, IDC_STORE_EDIT_SHAREDFOLDER); break; case IDC_STORE_DBBROWSE: FinishDirectoryBrowse(hDlg, IDC_STORE_EDIT_DB); break; case IDC_STORE_LOGBROWSE: FinishDirectoryBrowse(hDlg, IDC_STORE_EDIT_LOG); break; } break; case WM_NOTIFY: switch (((NMHDR FAR *) lParam)->code) { case PSN_KILLACTIVE: break; case PSN_RESET: break; case PSN_QUERYCANCEL: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); return CertConfirmCancel(hDlg, pComp); break; case PSN_SETACTIVE: CSILOGDWORD(IDS_STORE_TITLE, dwWIZACTIVE); PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_NEXT); pComp = _GetCompDataOrReturn(pComp, hDlg); _DisableWizDisplayIfError(pComp, hDlg); _ReturnIfWizError(pComp->hrContinue); pComp->hrContinue = HandleStoreWizActive(hDlg, pComp, saStoreString); _ReturnIfWizError(pComp->hrContinue); break; case PSN_WIZBACK: CSILOGDWORD(IDS_STORE_TITLE, dwWIZBACK); pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleStoreWizNextOrBack(hDlg, saStoreString, pComp, PSN_WIZBACK); _ReturnIfWizError(pComp->hrContinue); break; case PSN_WIZNEXT: CSILOGDWORD(IDS_STORE_TITLE, dwWIZNEXT); pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleStoreWizNextOrBack(hDlg, saStoreString, pComp, PSN_WIZNEXT); _ReturnIfWizError(pComp->hrContinue); break; default: return FALSE; } break; default: return FALSE; } return TRUE; } HRESULT EnableCARequestControls( HWND hDlg, PER_COMPONENT_DATA *pComp) { HRESULT hr; CASERVERSETUPINFO *pServer = pComp->CA.pServer; // Online req EnableWindow(GetDlgItem(hDlg, IDC_CAREQUEST_CANAME), !pServer->fSaveRequestAsFile); EnableWindow(GetDlgItem(hDlg, IDC_CAREQUEST_COMPUTERNAME), !pServer->fSaveRequestAsFile); EnableWindow(GetDlgItem(hDlg, IDC_CAREQUEST_CA_BROWSE), !pServer->fSaveRequestAsFile && pServer->fCAsExist); EnableWindow(GetDlgItem(hDlg, IDC_CAREQUEST_CNLABEL), !pServer->fSaveRequestAsFile); EnableWindow(GetDlgItem(hDlg, IDC_CAREQUEST_PCALABEL), !pServer->fSaveRequestAsFile); // File req EnableWindow(GetDlgItem(hDlg, IDC_CAREQUEST_FILE), pServer->fSaveRequestAsFile); EnableWindow(GetDlgItem(hDlg, IDC_CAREQUEST_FILE_BROWSE), pServer->fSaveRequestAsFile); EnableWindow(GetDlgItem(hDlg, IDC_CAREQUEST_FILELABEL), pServer->fSaveRequestAsFile); if (pServer->fSaveRequestAsFile) { SetFocus(GetDlgItem(hDlg, IDC_CAREQUEST_FILE)); } else { SetFocus(GetDlgItem(hDlg, IDC_CAREQUEST_CANAME)); } hr = S_OK; //error: return hr; } HRESULT BuildRequestFileName( IN WCHAR const *pwszCACertFile, OUT WCHAR **ppwszRequestFile) { #define wszREQEXT L".req" HRESULT hr; WCHAR const *pwszStart; WCHAR const *pwszEnd; WCHAR *pwszRequestFile = NULL; CSASSERT(NULL != pwszCACertFile); // derive request file name pwszStart = pwszCACertFile; pwszEnd = wcsrchr(pwszStart, L'.'); if (pwszEnd == NULL) { // set to end of entire string -- no '.' found pwszEnd = &pwszStart[wcslen(pwszStart)]; } pwszRequestFile = (WCHAR*)LocalAlloc(LMEM_FIXED, (SAFE_SUBTRACT_POINTERS(pwszEnd, pwszStart) + wcslen(wszREQEXT) + 1) * sizeof(WCHAR)); _JumpIfOutOfMemory(hr, error, pwszRequestFile); CopyMemory(pwszRequestFile, pwszStart, SAFE_SUBTRACT_POINTERS(pwszEnd, pwszStart) * sizeof(WCHAR)); wcscpy(pwszRequestFile + SAFE_SUBTRACT_POINTERS(pwszEnd, pwszStart), wszREQEXT); // return *ppwszRequestFile = pwszRequestFile; pwszRequestFile = NULL; hr = S_OK; error: if (NULL != pwszRequestFile) { LocalFree(pwszRequestFile); } return hr; } HRESULT StartCARequestPage( HWND hDlg, PAGESTRINGS *pPageString, CASERVERSETUPINFO *pServer) { HRESULT hr; if (NULL == pServer->pwszRequestFile) { hr = BuildRequestFileName( pServer->pwszCACertFile, &pServer->pwszRequestFile); _JumpIfError(hr, error, "BuildRequestFileName"); } hr = StartWizardPageEditControls(hDlg, pPageString); _JumpIfError(hr, error, "StartWizardPageEditControls"); hr = S_OK; error: return hr; } HRESULT GetRequestFileName( HWND hDlg, PER_COMPONENT_DATA *pComp) { HRESULT hr; WCHAR *pwszFileIn = NULL; WCHAR *pwszFileOut = NULL; HWND hCtrl = GetDlgItem(hDlg, IDC_CAREQUEST_FILE); hr = myUIGetWindowText(hCtrl, &pwszFileIn); _JumpIfError(hr, error, "myUIGetWindowText"); hr = myGetSaveFileName( hDlg, pComp->hInstance, IDS_REQUEST_SAVE_TITLE, IDS_REQUEST_FILE_FILTER, IDS_REQUEST_FILE_DEFEXT, OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT, pwszFileIn, &pwszFileOut); _JumpIfError(hr, error, "myGetSaveFileName"); if (NULL != pwszFileOut) { SetWindowText(hCtrl, pwszFileOut); } hr = S_OK; error: if (NULL != pwszFileOut) { LocalFree(pwszFileOut); } if (NULL != pwszFileIn) { LocalFree(pwszFileIn); } return hr; } HRESULT HookCARequestPageStrings( HWND hDlg, PAGESTRINGS *pPageString, CASERVERSETUPINFO *pServer) { HRESULT hr; for ( ; 0 != pPageString->idControl; pPageString++) { switch (pPageString->idControl) { case IDC_CAREQUEST_CANAME: pPageString->ppwszString = &(pServer->pwszParentCAName); break; case IDC_CAREQUEST_COMPUTERNAME: pPageString->ppwszString = &(pServer->pwszParentCAMachine); break; case IDC_CAREQUEST_FILE: pPageString->ppwszString = &(pServer->pwszRequestFile); break; default: hr = E_INVALIDARG; _JumpError(hr, error, "Internal error"); break; } } hr = S_OK; error: return hr; } CERTSRVUICASELECTION g_CARequestUICASelection = {NULL, NULL, NULL, NULL, NULL, ENUM_UNKNOWN_CA, false}; HRESULT InitCARequestWizControls( HWND hDlg, PAGESTRINGS *pSubmitPageString, PAGESTRINGS *pFilePageString, PER_COMPONENT_DATA *pComp) { HRESULT hr; CASERVERSETUPINFO *pServer = pComp->CA.pServer; HWND hwndCtrl; // now make page strings complete hr = HookCARequestPageStrings(hDlg, pSubmitPageString, pServer); _JumpIfError(hr, error, "HookCARequestPageStrings"); hr = HookCARequestPageStrings(hDlg, pFilePageString, pServer); _JumpIfError(hr, error, "HookCARequestPageStrings"); if (!(SETUPOP_STANDALONE & pComp->Flags)) { // nt base setup // disable online submit EnableWindow(GetDlgItem(hDlg, IDC_CAREQUEST_SUBMITTOCA), FALSE); SendMessage(GetDlgItem(hDlg, IDC_CAREQUEST_SUBMITTOCA), BM_SETCHECK, (WPARAM) BST_UNCHECKED, (LPARAM) 0); // only save as file pServer->fSaveRequestAsFile = TRUE; SendMessage(GetDlgItem(hDlg, IDC_CAREQUEST_SAVETOFILE), BM_SETCHECK, (WPARAM) BST_CHECKED, (LPARAM) 0); } else { // set online submit as default pServer->fSaveRequestAsFile = FALSE; SendMessage(GetDlgItem(hDlg, IDC_CAREQUEST_SUBMITTOCA), BM_CLICK, (WPARAM) 0, (LPARAM) 0); hr = myInitUICASelectionControls( &g_CARequestUICASelection, pComp->hInstance, hDlg, GetDlgItem(hDlg, IDC_CAREQUEST_CA_BROWSE), GetDlgItem(hDlg, IDC_CAREQUEST_COMPUTERNAME), GetDlgItem(hDlg, IDC_CAREQUEST_CANAME), csiIsAnyDSCAAvailable(), &pServer->fCAsExist); _JumpIfError(hr, error, "myInitUICASelectionControls"); } hr = S_OK; error: return hr; } HRESULT HandleCARequestWizActive( HWND hDlg, PAGESTRINGS *pPageString, PER_COMPONENT_DATA *pComp) { HRESULT hr; DWORD dwCACount; CRYPTUI_CA_CONTEXT const *pCAContext = NULL; CASERVERSETUPINFO *pServer = pComp->CA.pServer; BOOL fMatchAll = IsEverythingMatched(pServer); // Suppress this wizard page if // we've already seen an error, or // we are not installing the server, or // we are not installing a subordinate, or // the advanced page already selected a matching key and cert if (!(IS_SERVER_INSTALL & pComp->dwInstallStatus) || IsRootCA(pServer->CAType) || fMatchAll) { // disable page CSILOGDWORD(IDS_CAREQUEST_TITLE, dwWIZDISABLE); SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1); goto done; } EnableCARequestControls(hDlg, pComp); hr = StartCARequestPage(hDlg, pPageString, pServer); _JumpIfError(hr, error, "StartCARequestPage"); done: hr = S_OK; error: if (NULL != pCAContext) { CryptUIDlgFreeCAContext(pCAContext); } return hr; } HRESULT ConvertEditControlFullFilePath( HWND hEdtCtrl) { HRESULT hr; WCHAR *pwszPath = NULL; WCHAR wszFullPath[MAX_PATH]; WCHAR *pwszNotUsed; DWORD dwSize = 0; hr = myUIGetWindowText(hEdtCtrl, &pwszPath); _JumpIfError(hr, error, "myUIGetWindowText"); if (NULL == pwszPath) { // empty path, done goto done; } dwSize = GetFullPathName(pwszPath, ARRAYSIZE(wszFullPath), wszFullPath, &pwszNotUsed); CSASSERT(ARRAYSIZE(wszFullPath) > dwSize); if (0 == dwSize) { hr = myHLastError(); _JumpError(hr, error, "GetFullPathName"); } // get full path, set it back to edit control SetWindowText(hEdtCtrl, wszFullPath); done: hr = S_OK; error: if (NULL != pwszPath) { LocalFree(pwszPath); } return hr; } HRESULT HandleCARequestWizNextOrBack( HWND hDlg, PAGESTRINGS *pPageString, PER_COMPONENT_DATA *pComp, int iWizBN) { HRESULT hr; CASERVERSETUPINFO *pServer = pComp->CA.pServer; BOOL fDontNext = FALSE; BOOL fValid; if (pServer->fSaveRequestAsFile) { // convert request file to full path hr = ConvertEditControlFullFilePath( GetDlgItem(hDlg, IDC_CAREQUEST_FILE)); _JumpIfError(hr, error, "ConvertEditControlFullFilePath"); CSASSERT(pServer->pwszSanitizedName); CSASSERT(pServer->pwszKeyContainerName); hr = mySetCertRegStrValue( pServer->pwszSanitizedName, NULL, NULL, wszREGREQUESTKEYCONTAINER, pServer->pwszKeyContainerName); _JumpIfErrorStr(hr, error, "mySetCertRegStrValue", wszREGREQUESTKEYCONTAINER); } hr = FinishWizardPageEditControls(hDlg, pPageString); _JumpIfError(hr, error, "FinishWizardPageEditControls"); if (PSN_WIZBACK == iWizBN) { goto done; } if (!pServer->fSaveRequestAsFile && NULL==pServer->pccExistingCert) { // online case hr = myUICASelectionValidation(&g_CARequestUICASelection, &fValid); _JumpIfError(hr, error, "myUICASelectionValidation"); if (!fValid) { fDontNext = TRUE; goto done; } } hr = WizardPageValidation(pComp->hInstance, pComp->fUnattended, hDlg, pPageString); if (S_OK != hr) { fDontNext = TRUE; goto done; } if (pServer->fSaveRequestAsFile) { // validate dir path existance of the request file WCHAR *pwszLastSlash = wcsrchr(pServer->pwszRequestFile, L'\\'); CSASSERT(NULL != pwszLastSlash); if (NULL != pwszLastSlash) { // make request file path into a dir path pwszLastSlash[0] = L'\0'; if (DE_DIREXISTS != DirExists(pServer->pwszRequestFile) || L'\0' == pwszLastSlash[1]) { // bring request file path back pwszLastSlash[0] = L'\\'; CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_CAREQUEST_REQUESTFILEPATH_MUSTEXIST, 0, pServer->pwszRequestFile); SetEditFocusAndSelect(GetDlgItem(hDlg, IDC_CAREQUEST_FILE), 0, -1); fDontNext = TRUE; goto done; } // bring request file path back pwszLastSlash[0] = L'\\'; } // Fail if a directory with the same name already exists if(DE_DIREXISTS == DirExists(pServer->pwszRequestFile)) { CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_CAREQUEST_REQUESTFILEPATH_DIREXISTS, 0, pServer->pwszRequestFile); SetEditFocusAndSelect(GetDlgItem(hDlg, IDC_CAREQUEST_FILE), 0, -1); fDontNext = TRUE; goto done; } } hr = StartAndStopService(pComp->hInstance, pComp->fUnattended, hDlg, wszW3SVCNAME, TRUE, TRUE, IDS_STOP_W3SVC, &g_fW3SvcRunning); if (S_OK != hr) { if (E_ABORT == hr) { fDontNext = TRUE; goto done; } _JumpError(hr, error, "StartAndStopService"); } done: if (fDontNext) { SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE); // forbid } else { pServer->LastWiz = ENUM_WIZ_REQUEST; } hr = S_OK; error: return hr; } //+------------------------------------------------------------------------ // Function: WizCARequestPageDlgProc(. . . .) // // Synopsis: Dialog procedure for CA Request wiz-page //------------------------------------------------------------------------- INT_PTR WizCARequestPageDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { PAGESTRINGS *pPageString; PER_COMPONENT_DATA *pComp = NULL; static BOOL s_fComputerChange = FALSE; // keep the following in local scope static PAGESTRINGS saCARequestSubmit[] = { { IDC_CAREQUEST_COMPUTERNAME, IDS_LOG_COMPUTER, IDS_COMPUTERNULLSTRERR, IDS_COMPUTERLENSTRERR, MAX_PATH, NULL, }, { IDC_CAREQUEST_CANAME, IDS_LOG_CANAME, IDS_CANULLSTRERR, IDS_CALENSTRERR, cchCOMMONNAMEMAX, NULL, }, // add more code in HookCARequestPageStrings if you add { 0, 0, 0, 0, 0, NULL } }; static PAGESTRINGS saCARequestFile[] = { { IDC_CAREQUEST_FILE, IDS_LOG_REQUESTFILE, IDS_REQUESTFILENULLSTRERR, IDS_REQUESTFILELENSTRERR, MAX_PATH, NULL, }, // add more code in HookCARequestPageStrings if you add { 0, 0, 0, 0, 0, NULL, } }; switch(iMsg) { case WM_INITDIALOG: // point to component data SetWindowLongPtr(hDlg, DWLP_USER, (ULONG_PTR)((PROPSHEETPAGE*)lParam)->lParam); pComp = (PER_COMPONENT_DATA*)(ULONG_PTR)((PROPSHEETPAGE*)lParam)->lParam; _ReturnIfWizError(pComp->hrContinue); pComp->hrContinue = InitCARequestWizControls(hDlg, saCARequestSubmit, saCARequestFile, pComp); _ReturnIfWizError(pComp->hrContinue); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_CAREQUEST_SAVETOFILE: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->CA.pServer->fSaveRequestAsFile = TRUE; pComp->hrContinue = EnableCARequestControls(hDlg, pComp); _ReturnIfWizError(pComp->hrContinue); break; case IDC_CAREQUEST_SUBMITTOCA: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->CA.pServer->fSaveRequestAsFile = FALSE; pComp->hrContinue = EnableCARequestControls(hDlg, pComp); _ReturnIfWizError(pComp->hrContinue); break; case IDC_CAREQUEST_CA_BROWSE: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = myUICAHandleCABrowseButton( &g_CARequestUICASelection, csiIsAnyDSCAAvailable(), IDS_CA_PICKER_TITLE, IDS_CA_PICKER_PROMPT, NULL); _ReturnIfWizError(pComp->hrContinue); break; case IDC_CAREQUEST_FILE_BROWSE: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = GetRequestFileName(hDlg, pComp); _ReturnIfWizError(pComp->hrContinue); break; case IDC_CAREQUEST_CANAME: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = myUICAHandleCAListDropdown( (int)HIWORD(wParam), // notification &g_CARequestUICASelection, &s_fComputerChange); _ReturnIfWizError(pComp->hrContinue); break; case IDC_CAREQUEST_COMPUTERNAME: switch ((int)HIWORD(wParam)) { case EN_CHANGE: // edit changed s_fComputerChange = TRUE; break; } break; } break; case WM_NOTIFY: switch (((NMHDR FAR *) lParam)->code) { case PSN_KILLACTIVE: break; case PSN_RESET: break; case PSN_QUERYCANCEL: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); return CertConfirmCancel(hDlg, pComp); break; case PSN_SETACTIVE: CSILOGDWORD(IDS_CAREQUEST_TITLE, dwWIZACTIVE); pComp = _GetCompDataOrReturn(pComp, hDlg); PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_NEXT); _DisableWizDisplayIfError(pComp, hDlg); _ReturnIfWizError(pComp->hrContinue); pComp->hrContinue = HandleCARequestWizActive(hDlg, saCARequestFile, pComp); _ReturnIfWizError(pComp->hrContinue); break; case PSN_WIZBACK: CSILOGDWORD(IDS_CAREQUEST_TITLE, dwWIZBACK); pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pPageString = saCARequestSubmit; if (pComp->CA.pServer->fSaveRequestAsFile) { pPageString = saCARequestFile; } pComp->hrContinue = HandleCARequestWizNextOrBack(hDlg, pPageString, pComp, PSN_WIZBACK); _ReturnIfWizError(pComp->hrContinue); break; case PSN_WIZNEXT: CSILOGDWORD(IDS_CAREQUEST_TITLE, dwWIZNEXT); pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pPageString = saCARequestSubmit; if (pComp->CA.pServer->fSaveRequestAsFile) { pPageString = saCARequestFile; } pComp->hrContinue = HandleCARequestWizNextOrBack(hDlg, pPageString, pComp, PSN_WIZNEXT); _ReturnIfWizError(pComp->hrContinue); break; default: return FALSE; } break; default: return FALSE; } return TRUE; } HRESULT HookClientPageStrings( HWND hDlg, PAGESTRINGS *pPageString, CAWEBCLIENTSETUPINFO *pClient) { HRESULT hr; for ( ; 0 != pPageString->idControl; pPageString++) { switch (pPageString->idControl) { case IDC_CLIENT_COMPUTERNAME: pPageString->ppwszString = &(pClient->pwszWebCAMachine); break; default: hr = E_INVALIDARG; _JumpError(hr, error, "Internal error"); break; } } hr = S_OK; error: return hr; } CERTSRVUICASELECTION g_WebClientUICASelection = {NULL, NULL, NULL, NULL, NULL, ENUM_UNKNOWN_CA, true}; HRESULT InitClientWizControls( HWND hDlg, PAGESTRINGS *pPageString, PER_COMPONENT_DATA *pComp) { HRESULT hr; BOOL fCAsExist; CAWEBCLIENTSETUPINFO *pClient = pComp->CA.pClient; hr = HookClientPageStrings(hDlg, pPageString, pClient); _JumpIfError(hr, error, "HookClientPageStrings"); hr = WizPageSetTextLimits(hDlg, pPageString); _JumpIfError(hr, error, "WizPageSetTextLimits"); pClient->fUseDS = FALSE; if (IsDSAvailable()) { pClient->fUseDS = csiIsAnyDSCAAvailable(); } hr = myInitUICASelectionControls( &g_WebClientUICASelection, pComp->hInstance, hDlg, GetDlgItem(hDlg, IDC_CLIENT_BROWSECNFG), GetDlgItem(hDlg, IDC_CLIENT_COMPUTERNAME), GetDlgItem(hDlg, IDC_CLIENT_CANAME), pClient->fUseDS, &fCAsExist); _JumpIfError(hr, error, "myInitUICASelectionControls"); hr = S_OK; error: return hr; } HRESULT GetCAConfigInfo( HWND hDlg, PER_COMPONENT_DATA *pComp) { HRESULT hr = S_OK; CAWEBCLIENTSETUPINFO *pClient = pComp->CA.pClient; // free old shared folder always if (NULL != pClient->pwszSharedFolder) { // free old LocalFree(pClient->pwszSharedFolder); pClient->pwszSharedFolder = NULL; } hr = myUICAHandleCABrowseButton( &g_WebClientUICASelection, pClient->fUseDS, IDS_CONFIG_PICKER_TITLE, IDS_CONFIG_PICKER_PROMPT, &pClient->pwszSharedFolder); _JumpIfError(hr, error, "myUICAHandleCABrowseButton"); error: return hr; } HRESULT HandleClientWizNextOrBack( HWND hDlg, PAGESTRINGS *pPageString, PER_COMPONENT_DATA *pComp, int iWizBN) { HWND hwndCtrl; HRESULT hr; CAWEBCLIENTSETUPINFO *pClient = pComp->CA.pClient; BOOL fDontNext = FALSE; WCHAR *pwszCAName = NULL; WCHAR *pwszSanitizedCAName; int nItem; int len; BOOL fValid; BOOL fCoInit = FALSE; // CAINFO *pCAInfo = NULL; HCURSOR hPrevCur; hr = FinishWizardPageEditControls(hDlg, pPageString); _JumpIfError(hr, error, "FinishWizardPageEditControls"); if (PSN_WIZBACK == iWizBN) { goto done; } hr = myUICASelectionValidation(&g_WebClientUICASelection, &fValid); _JumpIfError(hr, error, "myUICASelectionValidation"); if (!fValid) { fDontNext = TRUE; goto done; } // at this point, g_WebClientUICASelection.CAType is guaranteed to be filled in hr = WizardPageValidation(pComp->hInstance, pComp->fUnattended, hDlg, pPageString); if (S_OK != hr) { fDontNext = TRUE; goto done; } hr = myUIGetWindowText(GetDlgItem(hDlg, IDC_CLIENT_CANAME), &pwszCAName); _JumpIfError(hr, error, "myUIGetWindowText"); CSASSERT(NULL != pwszCAName); if (NULL != pClient->pwszWebCAName) { // free old one LocalFree(pClient->pwszWebCAName); } pClient->pwszWebCAName = pwszCAName; pwszCAName = NULL; hr = mySanitizeName(pClient->pwszWebCAName, &pwszSanitizedCAName); _JumpIfError(hr, error, "mySanitizeName"); if (NULL != pClient->pwszSanitizedWebCAName) { // free old one LocalFree(pClient->pwszSanitizedWebCAName); } pClient->pwszSanitizedWebCAName = pwszSanitizedCAName; // pClient->WebCAType = pCAInfo->CAType; pClient->WebCAType = g_WebClientUICASelection.CAType; hr = StartAndStopService(pComp->hInstance, pComp->fUnattended, hDlg, wszW3SVCNAME, TRUE, TRUE, IDS_STOP_W3SVC, &g_fW3SvcRunning); if (S_OK != hr) { if (E_ABORT == hr) { fDontNext = TRUE; goto done; } _JumpError(hr, error, "StartAndStopService"); } done: hr = S_OK; error: if (fCoInit) { CoUninitialize(); } if (fDontNext) { SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE); // forbid } if (NULL != pwszCAName) { LocalFree(pwszCAName); } // if (NULL != pCAInfo) { // LocalFree(pCAInfo); } return hr; } HRESULT HandleClientWizActive( HWND hDlg, PER_COMPONENT_DATA *pComp, PAGESTRINGS *pPageString) { HRESULT hr; // Suppress this wizard page if // we've already seen an error, or // the server is or will be installed, or // the client isn't or won't be installed, or // ther will be no change in client and server install states. if ((IS_SERVER_ENABLED & pComp->dwInstallStatus) || !(IS_CLIENT_ENABLED & pComp->dwInstallStatus) || !((IS_CLIENT_CHANGE | IS_SERVER_CHANGE) & pComp->dwInstallStatus)) { // disable page CSILOGDWORD(IDS_CLIENT_TITLE, dwWIZDISABLE); SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1); goto done; } // load id info hr = StartWizardPageEditControls(hDlg, pPageString); _JumpIfError(hr, error, "StartWizardPageEditControls"); done: hr = S_OK; error: return hr; } //+------------------------------------------------------------------------ // Function: WizClientPageDlgProc(. . . .) // // Synopsis: Dialog procedure for CA Client wiz-page //------------------------------------------------------------------------- INT_PTR WizClientPageDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { PER_COMPONENT_DATA *pComp = NULL; static BOOL s_fComputerChange = FALSE; static PAGESTRINGS saClientPageString[] = { { IDC_CLIENT_COMPUTERNAME, IDS_LOG_COMPUTER, IDS_CLIENT_NOCOMPUTER, IDS_COMPUTERLENSTRERR, MAX_PATH, NULL, }, // you need to add code in HookClientPageStrings if adding more... { 0, 0, 0, 0, 0, NULL } }; switch(iMsg) { case WM_INITDIALOG: // point to component data SetWindowLongPtr(hDlg, DWLP_USER, (LONG)((PROPSHEETPAGE*)lParam)->lParam); pComp = (PER_COMPONENT_DATA*)((PROPSHEETPAGE*)lParam)->lParam; _ReturnIfWizError(pComp->hrContinue); pComp->hrContinue = InitClientWizControls(hDlg, saClientPageString, pComp); _ReturnIfWizError(pComp->hrContinue); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_CLIENT_BROWSECNFG: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = GetCAConfigInfo(hDlg, pComp); _ReturnIfWizError(pComp->hrContinue); break; case IDC_CLIENT_CANAME: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = myUICAHandleCAListDropdown( (int)HIWORD(wParam), &g_WebClientUICASelection, &s_fComputerChange); _ReturnIfWizError(pComp->hrContinue); break; case IDC_CLIENT_COMPUTERNAME: switch ((int)HIWORD(wParam)) { case EN_CHANGE: // edit change s_fComputerChange = TRUE; break; } break; } break; case WM_NOTIFY: switch (((NMHDR FAR *) lParam)->code) { case PSN_KILLACTIVE: break; case PSN_RESET: break; case PSN_QUERYCANCEL: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); return CertConfirmCancel(hDlg, pComp); break; case PSN_SETACTIVE: CSILOGDWORD(IDS_CLIENT_TITLE, dwWIZACTIVE); PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_NEXT); pComp = _GetCompDataOrReturn(pComp, hDlg); _DisableWizDisplayIfError(pComp, hDlg); _ReturnIfWizError(pComp->hrContinue); pComp->hrContinue = HandleClientWizActive(hDlg, pComp, saClientPageString); _ReturnIfWizError(pComp->hrContinue); break; case PSN_WIZBACK: CSILOGDWORD(IDS_CLIENT_TITLE, dwWIZBACK); pComp = _GetCompDataOrReturnIfError(pComp, hDlg); // enable back SetWindowLongPtr(hDlg, DWLP_MSGRESULT, 0); pComp->hrContinue = HandleClientWizNextOrBack(hDlg, saClientPageString, pComp, PSN_WIZBACK); _ReturnIfWizError(pComp->hrContinue); break; case PSN_WIZNEXT: CSILOGDWORD(IDS_CLIENT_TITLE, dwWIZNEXT); pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleClientWizNextOrBack(hDlg, saClientPageString, pComp, PSN_WIZNEXT); _ReturnIfWizError(pComp->hrContinue); break; default: return FALSE; } break; default: return FALSE; } return TRUE; } static CFont s_cBigBoldFont; static BOOL s_fBigBoldFont; BOOL ocmWiz97SetupFonts(HWND hwnd) { BOOL bReturn = FALSE; // // Create the fonts we need based on the dialog font // NONCLIENTMETRICS ncm = {0}; ncm.cbSize = sizeof (ncm); SystemParametersInfo (SPI_GETNONCLIENTMETRICS, 0, &ncm, 0); LOGFONT BigBoldLogFont = ncm.lfMessageFont; // // Create Big Bold Font and Bold Font // BigBoldLogFont.lfWeight = FW_BOLD; WCHAR largeFontSizeString[24]; INT largeFontSize; // // Load size and name from resources, since these may change // from locale to locale based on the size of the system font, etc. // if ( !::LoadString (g_hInstance, IDS_LARGEFONTNAME, BigBoldLogFont.lfFaceName, LF_FACESIZE) ) { CSASSERT (0); lstrcpy (BigBoldLogFont.lfFaceName, L"MS Shell Dlg"); } if ( ::LoadStringW (g_hInstance, IDS_LARGEFONTSIZE, largeFontSizeString, ARRAYSIZE(largeFontSizeString)) ) { largeFontSize = wcstoul (largeFontSizeString, NULL, 10); } else { CSASSERT (0); largeFontSize = 12; } HDC hdc = GetDC(hwnd); if (hdc) { BigBoldLogFont.lfHeight = 0 - (GetDeviceCaps(hdc, LOGPIXELSY) * largeFontSize / 72); BOOL bBigBold = s_cBigBoldFont.CreateFontIndirect (&BigBoldLogFont); ReleaseDC(hwnd, hdc); if ( bBigBold ) bReturn = TRUE; } return bReturn; } HFONT ocmWiz97GetBigBoldFont(HWND hwnd) { if (FALSE == s_fBigBoldFont) { if (!ocmWiz97SetupFonts(hwnd)) return NULL; s_fBigBoldFont = TRUE; } return s_cBigBoldFont; } //+------------------------------------------------------------------------ // Function: WizWelcomePageDlgProc(. . . .) // // Synopsis: Dialog procedure welcome wiz-page //------------------------------------------------------------------------- INT_PTR WizWelcomePageDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { PER_COMPONENT_DATA *pComp = NULL; HFONT hf; switch(iMsg) { case WM_INITDIALOG: // point to component data SetWindowLongPtr(hDlg, DWLP_USER, (LONG)((PROPSHEETPAGE*)lParam)->lParam); pComp = (PER_COMPONENT_DATA*)((PROPSHEETPAGE*)lParam)->lParam; // set wizard 97 fonts hf = ocmWiz97GetBigBoldFont(hDlg); if (NULL != hf) SendMessage(GetDlgItem(hDlg, IDC_TEXT_BIGBOLD), WM_SETFONT, (WPARAM)hf, MAKELPARAM(TRUE, 0)); _ReturnIfWizError(pComp->hrContinue); break; case WM_NOTIFY: switch (((NMHDR FAR *) lParam)->code) { case PSN_SETACTIVE: // disable back button PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT); pComp = _GetCompDataOrReturn(pComp, hDlg); _DisableWizDisplayIfError(pComp, hDlg); _ReturnIfWizError(pComp->hrContinue); break; default: return FALSE; } break; default: return FALSE; } return TRUE; } //+------------------------------------------------------------------------ // Function: WizFinalPageDlgProc(. . . .) // // Synopsis: Dialog procedure final wiz-page //------------------------------------------------------------------------- INT_PTR WizFinalPageDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { PER_COMPONENT_DATA *pComp = NULL; HFONT hf; switch(iMsg) { case WM_INITDIALOG: // point to component data SetWindowLongPtr(hDlg, DWLP_USER, (LONG)((PROPSHEETPAGE*)lParam)->lParam); pComp = (PER_COMPONENT_DATA*)((PROPSHEETPAGE*)lParam)->lParam; hf = ocmWiz97GetBigBoldFont(hDlg); if (NULL != hf) SendMessage(GetDlgItem(hDlg,IDC_TEXT_BIGBOLD), WM_SETFONT, (WPARAM)hf, MAKELPARAM(TRUE, 0)); _ReturnIfWizError(pComp->hrContinue); break; case WM_NOTIFY: switch (((NMHDR FAR *) lParam)->code) { case PSN_SETACTIVE: // enable finish button PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_FINISH); pComp = _GetCompDataOrReturn(pComp, hDlg); // always display final wiz page if (S_OK != pComp->hrContinue) { WCHAR *pwszFail = NULL; HRESULT hr2 = myLoadRCString( pComp->hInstance, IDS_FINAL_ERROR_TEXT, &pwszFail); if (S_OK == hr2) { SetWindowText(GetDlgItem(hDlg, IDC_FINAL_STATUS), pwszFail); LocalFree(pwszFail); } else { // well, use hard code string SetWindowText(GetDlgItem(hDlg, IDC_FINAL_STATUS), L"Certificate Services Installation failed"); _PrintError(hr2, "myLoadRCString"); } } _ReturnIfWizError(pComp->hrContinue); break; default: return FALSE; } break; default: return FALSE; } return TRUE; } // Map table for dialog template resource IDs and dialog proc pointers WIZPAGERESENTRY aWizPageResources[] = { IDD_WIZCATYPEPAGE, WizCATypePageDlgProc, IDS_CATYPE_TITLE, IDS_CATYPE_SUBTITLE, IDD_WIZADVANCEDPAGE, WizAdvancedPageDlgProc, IDS_ADVANCE_TITLE, IDS_ADVANCE_SUBTITLE, IDD_WIZIDINFOPAGE, WizIdInfoPageDlgProc, IDS_IDINFO_TITLE, IDS_IDINFO_SUBTITLE, IDD_WIZKEYGENPAGE, WizKeyGenPageDlgProc, IDS_KEYGEN_TITLE, IDS_KEYGEN_SUBTITLE, IDD_WIZSTOREPAGE, WizStorePageDlgProc, IDS_STORE_TITLE, IDS_STORE_SUBTITLE, IDD_WIZCAREQUESTPAGE, WizCARequestPageDlgProc, IDS_CAREQUEST_TITLE, IDS_CAREQUEST_SUBTITLE, IDD_WIZCLIENTPAGE, WizClientPageDlgProc, IDS_CLIENT_TITLE, IDS_CLIENT_SUBTITLE, }; #define NUM_SERVERWIZPAGES sizeof(aWizPageResources)/sizeof(WIZPAGERESENTRY) HRESULT CreateCertsrvWizPage( IN PER_COMPONENT_DATA *pComp, IN int idTitle, IN int idSubTitle, IN int idDlgResource, IN DLGPROC fnDlgProc, IN BOOL fWelcomeFinal, OUT HPROPSHEETPAGE *phPage) { HRESULT hr; PROPSHEETPAGE Page; WCHAR *pwszTitle = NULL; WCHAR *pwszSubTitle = NULL; // init ZeroMemory(&Page, sizeof(PROPSHEETPAGE)); // construct page info // Set titles Page.dwFlags = PSP_DEFAULT; if (fWelcomeFinal) Page.dwFlags |= PSP_HIDEHEADER; if (-1 != idTitle) { hr = myLoadRCString(pComp->hInstance, idTitle, &pwszTitle); _JumpIfError(hr, error, "Internal Error"); Page.pszHeaderTitle = pwszTitle; Page.dwFlags |= PSP_USEHEADERTITLE; } if (-1 != idSubTitle) { hr = myLoadRCString(pComp->hInstance, idSubTitle, &pwszSubTitle); _JumpIfError(hr, error, "Internal Error"); Page.pszHeaderSubTitle = pwszSubTitle; Page.dwFlags |= PSP_USEHEADERSUBTITLE; } // Set the basic property sheet data Page.dwSize = sizeof(PROPSHEETPAGE); // + sizeof(MYWIZPAGE); // Set up module and resource dependent data Page.hInstance = pComp->hInstance; Page.pszTemplate = MAKEINTRESOURCE(idDlgResource); Page.pfnDlgProc = fnDlgProc; Page.pfnCallback = NULL; Page.pcRefParent = NULL; Page.pszIcon = NULL; Page.pszTitle = NULL; Page.lParam = (LPARAM)pComp; // pass this to wizpage handlers // Create the page *phPage = CreatePropertySheetPage(&Page); _JumpIfOutOfMemory(hr, error, *phPage); hr = S_OK; error: if (NULL != pwszTitle) { LocalFree(pwszTitle); } if (NULL != pwszSubTitle) { LocalFree(pwszSubTitle); } return hr; } //+------------------------------------------------------------------------ // // Function: DoPageRequest(. . . .) // // Synopsis: Handler for the OC_REQUEST_PAGES notification. // // Effects: Ponies up the pages for the OCM driven wizard to display. // // Arguments: [ComponentId] ID String for the component. // [WhichOnes] Type specifier for requested pages. // [SetupPages] Structure to receive page handles. // // Returns: DWORD count of pages returned or -1 (MAXDWORD) in case of // failure; in this case SetLastError() will provide extended // error information. // // History: 04/16/97 JerryK Unmangled // 08/97 XTan major structure change // //------------------------------------------------------------------------- DWORD DoPageRequest( IN PER_COMPONENT_DATA *pComp, IN WIZPAGERESENTRY *pWizPageResources, IN DWORD dwWizPageNum, IN WizardPagesType WhichOnes, IN OUT PSETUP_REQUEST_PAGES SetupPages) { DWORD dwPageNum = MAXDWORD; HRESULT hr; DWORD i; if (pComp->fUnattended) { // don't create wiz page if unattended return 0; } // handle welcome page if (pComp->fPostBase && WizPagesWelcome == WhichOnes) { if (1 > SetupPages->MaxPages) { // ask ocm allocate enough pages return 1; // only welcome, 1 page } hr = CreateCertsrvWizPage( pComp, IDS_WELCOME_TITLE, // title, -1, // no sub-title IDD_WIZWELCOMEPAGE, WizWelcomePageDlgProc, TRUE, &SetupPages->Pages[0]); _JumpIfError(hr, error, "CreateCertsrvWizPage"); return 1; // create 1 page } // handle final page if (pComp->fPostBase && WizPagesFinal == WhichOnes) { if (1 > SetupPages->MaxPages) { // ask ocm allocate enough pages return 1; // only final, 1 page } hr = CreateCertsrvWizPage( pComp, IDS_FINAL_TITLE, // title, -1, // no sub-title IDD_WIZFINALPAGE, WizFinalPageDlgProc, TRUE, &SetupPages->Pages[0]); _JumpIfError(hr, error, "CreateCertsrvWizPage"); return 1; // create 1 page } // from now on, we should only handle post net wiz pages if (WizPagesPostnet != WhichOnes) { // ignore all others except postnet pages return 0; } if (dwWizPageNum > SetupPages->MaxPages) { // OCM didn't allocate enough for pages, return # and ask more return dwWizPageNum; } // Create the property sheet pages for the wizard for (i = 0; i < dwWizPageNum; i++) { hr = CreateCertsrvWizPage( pComp, pWizPageResources[i].idTitle, // title, pWizPageResources[i].idSubTitle, // sub-title pWizPageResources[i].idResource, pWizPageResources[i].fnDlgProc, FALSE, &SetupPages->Pages[i]); _JumpIfError(hr, error, "CreateCertsrvWizPage"); } dwPageNum = dwWizPageNum; error: return dwPageNum; } DWORD myDoPageRequest( IN PER_COMPONENT_DATA *pComp, IN WizardPagesType WhichOnes, IN OUT PSETUP_REQUEST_PAGES SetupPages) { pComp->CA.pServer->LastWiz = ENUM_WIZ_UNKNOWN; return DoPageRequest(pComp, aWizPageResources, NUM_SERVERWIZPAGES, WhichOnes, SetupPages); } //+------------------------------------------------------------------------- // // Function: DirExists() // // Synopsis: Determines whether or not a directory already exists. // // Arguments: [pszTestFileName] -- Name of directory to test for. // // Returns: FALSE -- Directory doesn't exist // DE_DIREXISTS -- Directory exists // DE_NAMEINUSE -- Name in use by non-directory entity // // History: 10/23/96 JerryK Created // //-------------------------------------------------------------------------- int DirExists(LPTSTR pszTestFileName) { DWORD dwFileAttrs; int nRetVal; // Get file attributes dwFileAttrs = GetFileAttributes(pszTestFileName); if (0xFFFFFFFF == dwFileAttrs) // Error code from GetFileAttributes { nRetVal = FALSE; // Couldn't open file } else if (dwFileAttrs & FILE_ATTRIBUTE_DIRECTORY) { nRetVal = DE_DIREXISTS; // Directory already exists } else { nRetVal = DE_NAMEINUSE; // Name in use by non-directory entity } return nRetVal; } BOOL IsEverythingMatched(CASERVERSETUPINFO *pServer) { return pServer->fAdvance && (NULL!=pServer->pwszKeyContainerName) && NULL!=pServer->pccExistingCert; } //==================================================================== // // CA info code // // //==================================================================== WNDPROC g_pfnValidityWndProcs; WNDPROC g_pfnIdInfoWndProcs; HRESULT GetValidityEditCount( HWND hDlg, DWORD *pdwPeriodCount) { HRESULT hr; WCHAR *pwszPeriodCount = NULL; BOOL fValidDigitString; // init to 0 *pdwPeriodCount = 0; hr = myUIGetWindowText(GetDlgItem(hDlg, IDC_IDINFO_EDIT_VALIDITYCOUNT), &pwszPeriodCount); _JumpIfError(hr, error, "myUIGetWindowText"); if (NULL != pwszPeriodCount) { *pdwPeriodCount = myWtoI(pwszPeriodCount, &fValidDigitString); } hr = S_OK; error: if (NULL != pwszPeriodCount) { LocalFree(pwszPeriodCount); } return hr; } HRESULT UpdateExpirationDate( HWND hDlg, CASERVERSETUPINFO *pServer) { HRESULT hr; WCHAR *pwszExpiration = NULL; hr = GetValidityEditCount(hDlg, &pServer->dwValidityPeriodCount); _JumpIfError(hr, error, "GetValidityEditCount"); if (0 < pServer->dwValidityPeriodCount) { if(!pServer->pccExistingCert) { GetSystemTimeAsFileTime(&pServer->NotBefore); pServer->NotAfter = pServer->NotBefore; myMakeExprDateTime( &pServer->NotAfter, pServer->dwValidityPeriodCount, pServer->enumValidityPeriod); } hr = myGMTFileTimeToWszLocalTime( &pServer->NotAfter, FALSE, &pwszExpiration); _JumpIfError(hr, error, "myGMTFileTimeToWszLocalTime"); if (!SetWindowText(GetDlgItem(hDlg, IDC_IDINFO_EXPIRATION), pwszExpiration)) { hr = myHLastError(); _JumpError(hr, error, "SetWindowText"); } } hr = S_OK; error: if (NULL != pwszExpiration) { LocalFree(pwszExpiration); } return hr; } HRESULT AddValidityString( IN HINSTANCE hInstance, const HWND hList, const int ids, ENUM_PERIOD enumValidityPeriod) { HRESULT hr; WCHAR *pwsz = NULL; LRESULT nIndex; hr = myLoadRCString(hInstance, ids, &pwsz); _JumpIfError(hr, error, "myLoadRCString"); // add string nIndex = (INT)SendMessage(hList, CB_ADDSTRING, (WPARAM)0, (LPARAM)pwsz); if (CB_ERR == nIndex) { hr = E_INVALIDARG; _JumpError(hr, error, "SendMessage(CB_ADDSTRING)"); } // set data nIndex = (INT)SendMessage(hList, CB_SETITEMDATA, (WPARAM)nIndex, (LPARAM)enumValidityPeriod); if (CB_ERR == nIndex) { hr = E_INVALIDARG; _JumpError(hr, error, "SendMessage(CB_ADDSTRING)"); } hr = S_OK; error: if (NULL != pwsz) { LocalFree(pwsz); } return hr; } HRESULT SelectValidityString( PER_COMPONENT_DATA *pComp, HWND hList, ENUM_PERIOD enumValidityPeriod) { HRESULT hr; WCHAR *pwsz = NULL; LRESULT nIndex; LRESULT lr; int id; switch (enumValidityPeriod) { case ENUM_PERIOD_YEARS: id = IDS_VALIDITY_YEAR; break; case ENUM_PERIOD_MONTHS: id = IDS_VALIDITY_MONTH; break; case ENUM_PERIOD_WEEKS: id = IDS_VALIDITY_WEEK; break; case ENUM_PERIOD_DAYS: id = IDS_VALIDITY_DAY; break; default: hr = E_INVALIDARG; _JumpError(hr, error, "Invalid validity period enum"); break; } hr = myLoadRCString(pComp->hInstance, id, &pwsz); _JumpIfError(hr, error, "myLoadRCString"); nIndex = (INT)SendMessage(hList, CB_FINDSTRING, (WPARAM)0, (LPARAM)pwsz); if (CB_ERR == nIndex) { hr = E_INVALIDARG; _JumpError(hr, error, "SendMessage(CB_FINDSTRING)"); } lr = (INT)SendMessage(hList, CB_SETCURSEL, (WPARAM)nIndex, (LPARAM)0); if (CB_ERR == lr) { hr = E_INVALIDARG; _JumpError(hr, error, "SendMessage(CB_FINDSTRING)"); } lr = (INT)SendMessage(hList, CB_GETITEMDATA, (WPARAM)nIndex, (LPARAM)0); if (CB_ERR == lr) { hr = E_INVALIDARG; _JumpError(hr, error, "SendMessage(CB_FINDSTRING)"); } pComp->CA.pServer->enumValidityPeriod = (ENUM_PERIOD)lr; hr = S_OK; error: if (pwsz) LocalFree(pwsz); return hr; } HRESULT DetermineKeyExistence( CSP_INFO *pCSPInfo, WCHAR *pwszKeyName) { HRESULT hr; HCRYPTPROV hProv = NULL; if (!myCertSrvCryptAcquireContext( &hProv, pwszKeyName, pCSPInfo->pwszProvName, pCSPInfo->dwProvType, CRYPT_SILENT, TRUE)) { hr = myHLastError(); goto error; } hr = S_OK; error: if (NULL != hProv) { CryptReleaseContext(hProv, 0); } return hr; } LRESULT CALLBACK ValidityEditFilterHook( HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { int ret; BOOL fUpdate = FALSE; LRESULT lr; CASERVERSETUPINFO *pServer = (CASERVERSETUPINFO*)GetWindowLongPtr(hwnd, GWLP_USERDATA); switch(iMsg) { case WM_CHAR: fUpdate = TRUE; if (!iswdigit((TCHAR) wParam)) { if (VK_BACK != (int)wParam) { // ignore the key MessageBeep(0xFFFFFFFF); return 0; } } break; case WM_KEYDOWN: if (VK_DELETE == (int)wParam) { // validity is changed fUpdate = TRUE; } break; } lr = CallWindowProc( g_pfnValidityWndProcs, hwnd, iMsg, wParam, lParam); if (fUpdate) { UpdateExpirationDate(GetParent(hwnd), pServer); } return lr; } HRESULT MakeNullStringEmpty(LPWSTR *ppwszStr) { if(!*ppwszStr) return myDupString(L"", ppwszStr); return S_OK; } HRESULT HideAndShowMachineDNControls( HWND hDlg, CASERVERSETUPINFO *pServer) { HRESULT hr; LPCWSTR pcwszDNSuffix; hr = MakeNullStringEmpty(&pServer->pwszFullCADN); _JumpIfError(hr, error, "MakeNullStringEmpty"); hr = MakeNullStringEmpty(&pServer->pwszCACommonName); _JumpIfError(hr, error, "MakeNullStringEmpty"); hr = MakeNullStringEmpty(&pServer->pwszDNSuffix); _JumpIfError(hr, error, "MakeNullStringEmpty"); SetDlgItemText(hDlg, IDC_IDINFO_NAMEEDIT, pServer->pwszCACommonName); SetDlgItemText(hDlg, IDC_IDINFO_DNSUFFIXEDIT, pServer->pwszDNSuffix); SetDlgItemText(hDlg, IDC_IDINFO_NAMEPREVIEW, pServer->pwszFullCADN); // name preview is never editable // EnableWindow(GetDlgItem(hDlg, IDC_IDINFO_NAMEPREVIEW), FALSE); SendDlgItemMessage(hDlg, IDC_IDINFO_NAMEPREVIEW, EM_SETREADONLY, TRUE, 0); // if we're in reuse cert mode, we can't edit the DNs if (NULL != pServer->pccExistingCert) { // EnableWindow(GetDlgItem(hDlg, IDC_IDINFO_NAMEEDIT), FALSE); // EnableWindow(GetDlgItem(hDlg, IDC_IDINFO_DNSUFFIXEDIT), FALSE); SendDlgItemMessage(hDlg, IDC_IDINFO_NAMEEDIT, EM_SETREADONLY, TRUE, 0); SendDlgItemMessage(hDlg, IDC_IDINFO_DNSUFFIXEDIT, EM_SETREADONLY, TRUE, 0); } else { // set the defaults again // and re-enable everything else // EnableWindow(GetDlgItem(hDlg, IDC_IDINFO_NAMEEDIT), TRUE); // EnableWindow(GetDlgItem(hDlg, IDC_IDINFO_DNSUFFIXEDIT), TRUE); SendDlgItemMessage(hDlg, IDC_IDINFO_NAMEEDIT, EM_SETREADONLY, FALSE, 0); SendDlgItemMessage(hDlg, IDC_IDINFO_DNSUFFIXEDIT, EM_SETREADONLY, FALSE, 0); // SendDlgItemMessage(hDlg, IDC_IDINFO_NAMEPREVIEW, EM_SETREADONLY, FALSE, 0); } hr = S_OK; error: return hr; } HRESULT InitNameFields(CASERVERSETUPINFO *pServer) { HRESULT hr; CAutoLPWSTR pwsz; const WCHAR *pwszFirstDCComponent = L""; if(pServer->pccExistingCert) { } else { if(!pServer->pwszCACommonName) { // avoid null name hr = myDupString(L"", &pServer->pwszCACommonName); _JumpIfError(hr, error, "myDupString"); } hr = myGetComputerObjectName(NameFullyQualifiedDN, &pwsz); _PrintIfError(hr, "myGetComputerObjectName"); if (S_OK == hr && pwsz != NULL) { pwszFirstDCComponent = wcsstr(pwsz, L"DC="); } if(pServer->pwszDNSuffix) { LocalFree(pServer->pwszDNSuffix); pServer->pwszDNSuffix = NULL; } if(!pwszFirstDCComponent) { pwszFirstDCComponent = L""; } hr = myDupString(pwszFirstDCComponent, &pServer->pwszDNSuffix); _JumpIfError(hr, error, "myDupString"); if(pServer->pwszFullCADN) { LocalFree(pServer->pwszFullCADN); pServer->pwszFullCADN = NULL; } hr = BuildFullDN( pServer->pwszCACommonName, pwszFirstDCComponent, &pServer->pwszFullCADN); _JumpIfError(hr, error, "BuildFullDN"); } error: return hr; } // Builds full DN "CN=CAName,DistinguishedName" where CAName and DistinguishedName // could be empty or NULL; HRESULT BuildFullDN( OPTIONAL LPCWSTR pcwszCAName, OPTIONAL LPCWSTR pcwszDNSuffix, LPWSTR* ppwszFullDN) { HRESULT hr = S_OK; DWORD cBytes = 4; // 4 chars for leading "CN=" plus null terminator CSASSERT(ppwszFullDN); if(!EmptyString(pcwszCAName)) cBytes += wcslen(pcwszCAName); if(!EmptyString(pcwszDNSuffix)) cBytes += wcslen(pcwszDNSuffix)+1; // comma cBytes *= sizeof(WCHAR); *ppwszFullDN = (LPWSTR) LocalAlloc(LMEM_FIXED, cBytes); _JumpIfAllocFailed(*ppwszFullDN, error); wcscpy(*ppwszFullDN, L"CN="); if(!EmptyString(pcwszCAName)) { wcscat(*ppwszFullDN, pcwszCAName); } if(!EmptyString(pcwszDNSuffix)) { wcscat(*ppwszFullDN, L","); wcscat(*ppwszFullDN, pcwszDNSuffix); } error: return hr; } HRESULT EnableValidityControls(HWND hDlg, BOOL fEnabled) { EnableWindow(GetDlgItem(hDlg, IDC_IDINFO_COMBO_VALIDITYSTRING), fEnabled); EnableWindow(GetDlgItem(hDlg, IDC_IDINFO_EDIT_VALIDITYCOUNT), fEnabled); return S_OK; } HRESULT HideAndShowValidityControls( HWND hDlg, ENUM_CATYPES CAType) { // default to root ca int showValidity = SW_SHOW; int showHelp = SW_HIDE; BOOL fEnableLabel = TRUE; if (IsSubordinateCA(CAType)) { showValidity = SW_HIDE; showHelp = SW_SHOW; fEnableLabel = FALSE; } ShowWindow(GetDlgItem(hDlg, IDC_IDINFO_DETERMINEDBYPCA), showHelp); ShowWindow(GetDlgItem(hDlg, IDC_IDINFO_EDIT_VALIDITYCOUNT), showValidity); ShowWindow(GetDlgItem(hDlg, IDC_IDINFO_COMBO_VALIDITYSTRING), showValidity); ShowWindow(GetDlgItem(hDlg, IDC_IDINFO_EXPIRATION_LABEL), showValidity); ShowWindow(GetDlgItem(hDlg, IDC_IDINFO_EXPIRATION), showValidity); EnableWindow(GetDlgItem(hDlg, IDC_IDINFO_VPLABEL), fEnableLabel); return S_OK; } HRESULT InitValidityControls( HWND hDlg, PER_COMPONENT_DATA *pComp) { HRESULT hr; HWND hwndCtrl = GetDlgItem(hDlg, IDC_IDINFO_COMBO_VALIDITYSTRING); ENUM_PERIOD enumValidityPeriod = ENUM_PERIOD_YEARS; WCHAR *pwsz = NULL; CASERVERSETUPINFO *pServer = pComp->CA.pServer; // load validity help text hr = myLoadRCString(pComp->hInstance, IDS_IDINFO_DETERMINEDBYPCA, &pwsz); _JumpIfError(hr, error, "LoadString"); if (!SetWindowText(GetDlgItem(hDlg, IDC_IDINFO_DETERMINEDBYPCA), pwsz)) { hr = myHLastError(); _JumpError(hr, error, "SetWindowText"); } // load validity period strings hr = AddValidityString(pComp->hInstance, hwndCtrl, IDS_VALIDITY_YEAR, ENUM_PERIOD_YEARS); _JumpIfError(hr, error, "AddValidityString"); hr = AddValidityString(pComp->hInstance, hwndCtrl, IDS_VALIDITY_MONTH, ENUM_PERIOD_MONTHS); _JumpIfError(hr, error, "AddValidityString"); hr = AddValidityString(pComp->hInstance, hwndCtrl, IDS_VALIDITY_WEEK, ENUM_PERIOD_WEEKS); _JumpIfError(hr, error, "AddValidityString"); hr = AddValidityString(pComp->hInstance, hwndCtrl, IDS_VALIDITY_DAY, ENUM_PERIOD_DAYS); _JumpIfError(hr, error, "AddValidityString"); hr = S_OK; error: if (NULL != pwsz) { LocalFree(pwsz); } return hr; } HRESULT EnableMatchedCertIdInfoEditFields(HWND hDlg, BOOL fEnable) { HRESULT hr; EnableValidityControls(hDlg, fEnable); hr = S_OK; //error: return hr; } HRESULT WizIdInfoPageSetHooks(HWND hDlg, PER_COMPONENT_DATA *pComp) { HRESULT hr; CSASSERT (NULL != pComp); // CA Name filter proc g_pfnIdInfoWndProcs = (WNDPROC) SetWindowLongPtr( GetDlgItem(hDlg, IDC_IDINFO_NAMEEDIT), GWLP_WNDPROC, (LPARAM)IdInfoNameEditFilterHook); if (0 == g_pfnIdInfoWndProcs) { hr = myHLastError(); _JumpError(hr, error, "SetWindowLongPtr"); } SetLastError(0); if (0 == SetWindowLongPtr( GetDlgItem(hDlg, IDC_IDINFO_NAMEEDIT), GWLP_USERDATA, (LPARAM)pComp->CA.pServer)) { hr = myHLastError(); // might return S_OK _JumpIfError(hr, error, "SetWindowLongPtr USERDATA"); } hr = S_OK; error: return hr; } HRESULT HandleValidityStringChange( HWND hDlg, CASERVERSETUPINFO *pServer) { HRESULT hr; LRESULT nItem; LRESULT lr; HWND hwndCtrl = GetDlgItem(hDlg, IDC_IDINFO_COMBO_VALIDITYSTRING); if (NULL == hwndCtrl) { hr = E_INVALIDARG; _JumpError(hr, error, "Internal Error"); } nItem = (INT)SendMessage(hwndCtrl, CB_GETCURSEL, (WPARAM)0, (LPARAM)0); if (CB_ERR == nItem) { hr = E_INVALIDARG; _JumpError(hr, error, "Internal Error"); } lr = (INT)SendMessage(hwndCtrl, CB_GETITEMDATA, (WPARAM)nItem, (LPARAM)0); if (CB_ERR == nItem) { hr = E_INVALIDARG; _JumpError(hr, error, "Internal Error"); } pServer->enumValidityPeriod = (ENUM_PERIOD)lr; hr = UpdateExpirationDate(hDlg, pServer); _JumpIfError(hr, error, "UpdateExpirationDate"); hr = S_OK; error: return hr; } HRESULT HookIdInfoPageStrings( HWND hDlg, PAGESTRINGS *pPageString, CASERVERSETUPINFO *pServer) { HRESULT hr; for ( ; 0 != pPageString->idControl; pPageString++) { switch (pPageString->idControl) { case IDC_IDINFO_NAMEEDIT: pPageString->ppwszString = &(pServer->pwszCACommonName); break; case IDC_IDINFO_EDIT_VALIDITYCOUNT: pPageString->ppwszString = &(pServer->pwszValidityPeriodCount); break; default: hr = E_INVALIDARG; _JumpError(hr, error, "Internal error"); break; } } hr = S_OK; error: return hr; } HRESULT InitIdInfoWizControls( HWND hDlg, PAGESTRINGS *pIdPageString, PER_COMPONENT_DATA *pComp) { HRESULT hr; HWND hwndCtrl; CASERVERSETUPINFO *pServer = pComp->CA.pServer; // now make page strings complete hr = HookIdInfoPageStrings(hDlg, pIdPageString, pServer); _JumpIfError(hr, error, "HookIdInfoPageStrings"); hr = WizPageSetTextLimits(hDlg, pIdPageString); _JumpIfError(hr, error, "WizPageSetTextLimits"); hr = WizIdInfoPageSetHooks(hDlg, pComp); _JumpIfError(hr, error, "WizIdInfoPageSetHooks"); hr = InitValidityControls(hDlg, pComp); _JumpIfError(hr, error, "InitValidityControls"); if (!IsSubordinateCA(pServer->CAType)) { hwndCtrl = GetDlgItem(hDlg, IDC_IDINFO_EDIT_VALIDITYCOUNT); g_pfnValidityWndProcs = (WNDPROC)SetWindowLongPtr(hwndCtrl, GWLP_WNDPROC, (LPARAM)ValidityEditFilterHook); if (NULL == g_pfnValidityWndProcs) { hr = myHLastError(); _JumpError(hr, error, "SetWindowLongPtr"); } // pass data SetWindowLongPtr(hwndCtrl, GWLP_USERDATA, (ULONG_PTR)pServer); } hr = S_OK; error: return hr; } HRESULT UpdateValidityMaxDigits( BOOL fMatchAll, PAGESTRINGS *pIdPageString) { HRESULT hr; for (; 0 != pIdPageString; pIdPageString++) { if (IDC_IDINFO_EDIT_VALIDITYCOUNT == pIdPageString->idControl) { pIdPageString->cchMax = fMatchAll? UB_VALIDITY_ANY : UB_VALIDITY; break; } } hr = S_OK; //error: return hr; } HRESULT HandleIdInfoWizActive( HWND hDlg, PER_COMPONENT_DATA *pComp, PAGESTRINGS *pIdPageString) { HRESULT hr; WCHAR wszValidity[20]; CASERVERSETUPINFO *pServer = pComp->CA.pServer; ENUM_PERIOD enumValidityPeriod = pServer->enumValidityPeriod; BOOL fMatchAll; // Suppress this wizard page if // we've already seen an error, or // we are not installing the server. if (!(IS_SERVER_INSTALL & pComp->dwInstallStatus) ) { // disable page CSILOGDWORD(IDS_IDINFO_TITLE, dwWIZDISABLE); SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1); goto done; } if (ENUM_WIZ_STORE == pServer->LastWiz) { // if back from ca request, reset g_fAllowUnicodeStrEncoding = FALSE; } if (pServer->fAdvance && ENUM_WIZ_KEYGEN == pServer->LastWiz && (pServer->fKeyGenFailed || pServer->fValidatedHashAndKey) ) { // key gen failed and go back PropSheet_PressButton(GetParent(hDlg), PSBTN_BACK); } if (!pServer->fAdvance && ENUM_WIZ_CATYPE == pServer->LastWiz) { hr = LoadDefaultAdvanceAttributes(pServer); _JumpIfError(hr, error, "LoadDefaultAdvanceAttributes"); } hr = HideAndShowValidityControls(hDlg, pServer->CAType); _JumpIfError(hr, error, "HideAndShowValidityControls"); hr = HideAndShowMachineDNControls(hDlg, pServer); _JumpIfError(hr, error, "HideAndShowMachineDNControls"); // load id info hr = StartWizardPageEditControls(hDlg, pIdPageString); _JumpIfError(hr, error, "StartWizardPageEditControls"); hr = EnableMatchedCertIdInfoEditFields(hDlg, TRUE); _JumpIfError(hr, error, "EnableMatchedCertIdInfoEditFields"); // default wsprintf(wszValidity, L"%u", pServer->dwValidityPeriodCount); fMatchAll = IsEverythingMatched(pServer); if (fMatchAll) { enumValidityPeriod = ENUM_PERIOD_DAYS; wsprintf(wszValidity, L"%u", pServer->lExistingValidity); hr = EnableMatchedCertIdInfoEditFields(hDlg, FALSE); _JumpIfError(hr, error, "EnableMatchedCertIdInfoEditFields"); } // update validity period string hr = SelectValidityString( pComp, GetDlgItem(hDlg, IDC_IDINFO_COMBO_VALIDITYSTRING), enumValidityPeriod); _JumpIfError(hr, error, "SelectValidityString"); // update validity SetWindowText(GetDlgItem(hDlg, IDC_IDINFO_EDIT_VALIDITYCOUNT), wszValidity); hr = UpdateExpirationDate(hDlg, pServer); _JumpIfError(hr, error, "UpdateExpirationDate"); // update validity digits max for validation hr = UpdateValidityMaxDigits(fMatchAll, pIdPageString); _JumpIfError(hr, error, "UpdateValidityMaxDigits"); EnableValidityControls(hDlg, !IsSubordinateCA(pServer->CAType) && !fMatchAll); done: hr = S_OK; error: return hr; } // check server RDN info, warning any invalid or // or confirm from users once if any unicode string encoding BOOL IsAnyInvalidRDN( OPTIONAL HWND hDlg, PER_COMPONENT_DATA *pComp) { HRESULT hr = S_OK; BOOL fInvalidRDN = TRUE; BYTE *pbEncodedName = NULL; DWORD cbEncodedName; CERT_NAME_INFO *pbDecodedNameInfo = NULL; DWORD cbDecodedNameInfo; CERT_NAME_INFO *pNameInfo = NULL; DWORD *pIndexRDN = NULL; DWORD *pIndexAttr = NULL; DWORD dwUnicodeCount; WCHAR *pwszAllStrings = NULL; CASERVERSETUPINFO *pServer = pComp->CA.pServer; DWORD indexRDN; DWORD indexAttr; DWORD indexValue; int idControl; LPCWSTR pszErrorPtr = NULL; // don't bother calling with CERT_NAME_STR_REVERSE_FLAG, we're just throwing this encoding away hr = myCertStrToName( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pServer->pwszDNSuffix, CERT_X500_NAME_STR | CERT_NAME_STR_COMMA_FLAG, NULL, &pbEncodedName, &cbEncodedName, &pszErrorPtr); if(S_OK != hr) { CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_WRN_IDINFO_INVALIDDN, 0, NULL); int nStartIndex = 0; int nEndIndex = wcslen(pServer->pwszDNSuffix); if(pszErrorPtr) { nStartIndex = SAFE_SUBTRACT_POINTERS(pszErrorPtr,pServer->pwszDNSuffix); const WCHAR *pwszNextComma = wcsstr(pszErrorPtr, L","); if(pwszNextComma) { nEndIndex = SAFE_SUBTRACT_POINTERS(pwszNextComma,pServer->pwszDNSuffix+1); } } SetEditFocusAndSelect( GetDlgItem(hDlg, IDC_IDINFO_DNSUFFIXEDIT), nStartIndex, nEndIndex); } _JumpIfError(hr, error, "myCertStrToName"); // call CryptDecodeObject to get pbDecodedNameInfo // if hit here, check if any unicode string encoding if (!g_fAllowUnicodeStrEncoding && !pComp->fUnattended) { // decode to nameinfo if (!myDecodeName( X509_ASN_ENCODING, X509_UNICODE_NAME, pbEncodedName, cbEncodedName, CERTLIB_USE_LOCALALLOC, &pbDecodedNameInfo, &cbDecodedNameInfo)) { hr = myHLastError(); _JumpError(hr, error, "myDecodeName"); } // calculate attributes total in RDN dwUnicodeCount = 0; for (indexRDN = 0; indexRDN < pbDecodedNameInfo->cRDN; ++indexRDN) { dwUnicodeCount += pbDecodedNameInfo->rgRDN[indexRDN].cRDNAttr; } // allocate & init index // sure allocate max for possible all unicode strings pIndexRDN = (DWORD*)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, dwUnicodeCount * sizeof(DWORD)); _JumpIfOutOfMemory(hr, error, pIndexRDN); pIndexAttr = (DWORD*)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, dwUnicodeCount * sizeof(DWORD)); _JumpIfOutOfMemory(hr, error, pIndexAttr); dwUnicodeCount = 0; // reset count for (indexRDN = 0; indexRDN < pbDecodedNameInfo->cRDN; ++indexRDN) { DWORD cRDNAttr = pbDecodedNameInfo->rgRDN[indexRDN].cRDNAttr; CERT_RDN_ATTR *rgRDNAttr = pbDecodedNameInfo->rgRDN[indexRDN].rgRDNAttr; // for each RDN for (indexAttr = 0; indexAttr < cRDNAttr; indexAttr++) { // for each attr, check unicode string switch (rgRDNAttr[indexAttr].dwValueType) { case CERT_RDN_UTF8_STRING: case CERT_RDN_UNICODE_STRING: // there is a unicode or UTF8 string, save index pIndexRDN[dwUnicodeCount] = indexRDN; pIndexAttr[dwUnicodeCount] = indexAttr; // set count ++dwUnicodeCount; break; } } } if (0 == dwUnicodeCount) { // no unicode string encoding goto done; } // calculate size of all unicode strings for display DWORD dwLen = 0; for (indexAttr = 0; indexAttr < dwUnicodeCount; ++indexAttr) { dwLen += (wcslen((WCHAR*)pbDecodedNameInfo->rgRDN[pIndexRDN[indexAttr]].rgRDNAttr[pIndexAttr[indexAttr]].Value.pbData) + 3 ) * sizeof(WCHAR); } pwszAllStrings = (WCHAR*)LocalAlloc(LMEM_FIXED, dwLen); _JumpIfOutOfMemory(hr, error, pwszAllStrings); // form all strings for display for (indexAttr = 0; indexAttr < dwUnicodeCount; ++indexAttr) { if (0 == indexAttr) { wcscpy(pwszAllStrings, (WCHAR*) pbDecodedNameInfo->rgRDN[pIndexRDN[indexAttr]].rgRDNAttr[pIndexAttr[indexAttr]].Value.pbData); } else { wcscat(pwszAllStrings, (WCHAR*) pbDecodedNameInfo->rgRDN[pIndexRDN[indexAttr]].rgRDNAttr[pIndexAttr[indexAttr]].Value.pbData); } if (dwUnicodeCount - 1 > indexAttr) { // add comma + new line wcscat(pwszAllStrings, L",\n"); } } // ok, ready to put out a warning if (IDYES == CertMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_WRN_UNICODESTRINGENCODING, 0, MB_YESNO | MB_ICONWARNING | CMB_NOERRFROMSYS, NULL)) //pwszAllStrings)) { // warning only once g_fAllowUnicodeStrEncoding = TRUE; goto done; } goto error; } done: fInvalidRDN = FALSE; error: if (NULL != pIndexRDN) { LocalFree(pIndexRDN); } if (NULL != pIndexAttr) { LocalFree(pIndexAttr); } if (NULL != pwszAllStrings) { LocalFree(pwszAllStrings); } if (NULL != pbEncodedName) { LocalFree(pbEncodedName); } if (NULL != pbDecodedNameInfo) { LocalFree(pbDecodedNameInfo); } if (NULL != pNameInfo) { csiFreeCertNameInfo(pNameInfo); } return fInvalidRDN; } /*HRESULT ExtractCommonName(LPCWSTR pcwszDN, LPWSTR* ppwszCN) { HRESULT hr = S_OK; WCHAR* pszComma; LPWSTR pwszDNUpperCase = NULL; const WCHAR* pszCN = pcwszDN; if(0!=_wcsnicmp(pcwszDN, L"CN=", wcslen(L"CN="))) { hr = E_INVALIDARG; _JumpError(hr, error, "distinguished name doesn't start with the common name"); } pszCN += wcslen(L"CN="); while(iswspace(*pszCN)) pszCN++; pszComma = wcsstr(pszCN, L","); DWORD iChars; if (pszComma == NULL) { // ONLY CN= string, no additional names iChars = wcslen(pszCN); } else { iChars = SAFE_SUBTRACT_POINTERS(pszComma, pszCN); } if(0==iChars) { hr = E_INVALIDARG; _JumpError(hr, error, "invalid syntax, common name should follow CN="); } *ppwszCN = (LPWSTR)LocalAlloc(LMEM_FIXED, (iChars+1)*sizeof(WCHAR)); _JumpIfAllocFailed(*ppwszCN, error); CopyMemory(*ppwszCN, pszCN, iChars*sizeof(WCHAR)); (*ppwszCN)[iChars] = L'\0'; error: LOCAL_FREE(pwszDNUpperCase); return hr; }*/ HRESULT HandleIdInfoWizNextOrBack( HWND hDlg, PER_COMPONENT_DATA *pComp, PAGESTRINGS *pIdPageString, int iWizBN) { HRESULT hr; WCHAR *pwszSanitizedName = NULL; CASERVERSETUPINFO *pServer = pComp->CA.pServer; BOOL fDontNext = FALSE; WCHAR wszCountryCode[cchCOUNTRYNAMEMAX+1]; HWND hwnd; DWORD size; DWORD i; BOOL fValidDigitString; WCHAR * pwszFullPath = NULL; WCHAR * pwszDir = NULL; DWORD cDirLen; hr = FinishWizardPageEditControls(hDlg, pIdPageString); _JumpIfError(hr, error, "FinishWizardPageEditControls"); if (PSN_WIZBACK == iWizBN) { goto done; } hr = WizardPageValidation(pComp->hInstance, pComp->fUnattended, hDlg, pIdPageString); if (S_OK != hr) { _PrintError(hr, "WizardPageValidation"); fDontNext = TRUE; goto done; } // snag the full DN specified if (NULL != pServer->pwszCACommonName) { LocalFree(pServer->pwszCACommonName); pServer->pwszCACommonName = NULL; } if (NULL != pServer->pwszFullCADN) { LocalFree(pServer->pwszFullCADN); pServer->pwszFullCADN = NULL; } if (NULL != pServer->pwszDNSuffix) { LocalFree(pServer->pwszDNSuffix); pServer->pwszDNSuffix = NULL; } myUIGetWindowText(GetDlgItem(hDlg, IDC_IDINFO_NAMEEDIT), &pServer->pwszCACommonName); myUIGetWindowText(GetDlgItem(hDlg, IDC_IDINFO_NAMEPREVIEW), &pServer->pwszFullCADN); myUIGetWindowText(GetDlgItem(hDlg, IDC_IDINFO_DNSUFFIXEDIT), &pServer->pwszDNSuffix); // if generate a new cert if (NULL == pServer->pccExistingCert && IsAnyInvalidRDN(hDlg, pComp)) { fDontNext = TRUE; goto done; } // if we are not using an existing cert, verify the chosen validity // period of the new cert. if (NULL==pServer->pccExistingCert) { // convert validity count string to a number pServer->dwValidityPeriodCount = myWtoI( pServer->pwszValidityPeriodCount, &fValidDigitString); if (!fValidDigitString || !IsValidPeriod(pServer)) { // validity out of range, put out a warning dlg CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_IDINFO_INVALID_VALIDITY, 0, NULL); SetEditFocusAndSelect(GetDlgItem(hDlg, IDC_IDINFO_EDIT_VALIDITYCOUNT), 0, -1); _PrintError(E_INVALIDARG, "invalid validity"); fDontNext = TRUE; goto done; } } // get sanitized name hr = mySanitizeName(pServer->pwszCACommonName, &pwszSanitizedName); _JumpIfError(hr, error, "mySanitizeName"); CSILOG( hr, IDS_ILOG_SANITIZEDNAME, pwszSanitizedName, NULL, NULL); if (MAX_PATH <= wcslen(pwszSanitizedName) + cwcSUFFIXMAX) { CertMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_WRN_KEYNAMETOOLONG, S_OK, MB_ICONWARNING | CMB_NOERRFROMSYS, pwszSanitizedName); SetEditFocusAndSelect(GetDlgItem(hDlg, IDC_IDINFO_NAMEEDIT), 0, -1); fDontNext = TRUE; goto done; } // if we are making a new key, see if a key by that name already exists. // if it does, see if the user wants to overwrite it. if (NULL == pServer->pwszKeyContainerName) { if (S_OK == DetermineKeyExistence(pServer->pCSPInfo, pwszSanitizedName)) { // warn user if key exist if (IDYES != CertMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_WRN_OVERWRITEEXISTINGKEY, S_OK, MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2 | CMB_NOERRFROMSYS, pServer->pwszCACommonName)) { SetEditFocusAndSelect(GetDlgItem(hDlg, IDC_IDINFO_NAMEEDIT), 0, -1); fDontNext = TRUE; goto done; } } } if (NULL != pServer->pwszSanitizedName) { // free old LocalFree(pServer->pwszSanitizedName); } pServer->pwszSanitizedName = pwszSanitizedName; pwszSanitizedName = NULL; if (pServer->fUseDS) { if (IsCAExistInDS(pServer->pwszSanitizedName)) { int ret = CertMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_IDINFO_CAEXISTINDS, 0, MB_YESNO | MB_ICONWARNING | CMB_NOERRFROMSYS, NULL); if (IDYES != ret) { // not overwrite SetEditFocusAndSelect(GetDlgItem(hDlg, IDC_IDINFO_NAMEEDIT), 0, -1); fDontNext = TRUE; goto done; } else { hr = RemoveCAInDS(pServer->pwszSanitizedName); if(hr != S_OK) { _PrintError(hr, "RemoveCAInDS"); SetEditFocusAndSelect(GetDlgItem(hDlg, IDC_IDINFO_NAMEEDIT), 0, -1); fDontNext = TRUE; goto done; } } } } hr = UpdateDomainAndUserName(hDlg, pComp); _JumpIfError(hr, error, "UpdateDomainAndUserName"); if(pServer->fUseDS) { pServer->dwRevocationFlags = REVEXT_DEFAULT_DS; } else { pServer->dwRevocationFlags = REVEXT_DEFAULT_NODS; } // validate cert file path lenght cDirLen = wcslen(pComp->pwszSystem32)+ wcslen(wszCERTENROLLSHAREPATH) + 1; pwszDir = (WCHAR *) LocalAlloc(LMEM_FIXED, cDirLen * sizeof(WCHAR)); if (NULL == pwszDir) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } wcscpy(pwszDir, pComp->pwszSystem32); // has trailing "\\" wcscat(pwszDir, wszCERTENROLLSHAREPATH); hr = csiBuildFileName( pwszDir, pServer->pwszSanitizedName, L".crt", 0, &pwszFullPath, pComp->hInstance, pComp->fUnattended, hDlg); _JumpIfError(hr, error, "csiBuildFileName"); if (MAX_PATH <= wcslen(pwszFullPath) + cwcSUFFIXMAX) { // pop up warning CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_PATH_TOO_LONG_CANAME, S_OK, pwszFullPath); fDontNext = TRUE; goto done; } done: if (fDontNext) { SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE); // forbid } else { pServer->LastWiz = ENUM_WIZ_IDINFO; } hr = S_OK; error: if (NULL != pwszSanitizedName) { LocalFree(pwszSanitizedName); } if(NULL != pwszFullPath) { LocalFree(pwszFullPath); } if(NULL != pwszDir) { LocalFree(pwszDir); } return hr; } PAGESTRINGS g_aIdPageString[] = { { IDC_IDINFO_NAMEEDIT, IDS_LOG_CANAME, IDS_IDINFO_NAMENULLSTRERR, IDS_IDINFO_NAMELENSTRERR, cchCOMMONNAMEMAX, NULL, }, { IDC_IDINFO_EDIT_VALIDITYCOUNT, IDS_LOG_VALIDITY, IDS_IDINFO_VALIDITYNULLSTRERR, IDS_IDINFO_VALIDITYLENSTRERR, UB_VALIDITY, NULL, }, // you need to add code in HookIdInfoPageStrings if adding more... { 0, 0, 0, 0, 0, NULL, } }; LRESULT CALLBACK IdInfoNameEditFilterHook( HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { WCHAR rgchUpper[] = {'\0', '\0'}; switch(iMsg) { case WM_CHAR: if ((WCHAR)wParam == L',') { MessageBeep(0xFFFFFFFF); return 0; break; } break; default: break; } return CallWindowProc(g_pfnIdInfoWndProcs, hwnd, iMsg, wParam, lParam); return 0; } //------------------------------------------------------------------------- // WizIdInfoPageDlgProc //------------------------------------------------------------------------- INT_PTR WizIdInfoPageDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { PER_COMPONENT_DATA *pComp = NULL; switch(iMsg) { case WM_INITDIALOG: // point to component data SetWindowLongPtr(hDlg, DWLP_USER, (ULONG_PTR)((PROPSHEETPAGE*)lParam)->lParam); pComp = (PER_COMPONENT_DATA*)(ULONG_PTR)((PROPSHEETPAGE*)lParam)->lParam; _ReturnIfWizError(pComp->hrContinue); pComp->hrContinue = InitIdInfoWizControls(hDlg, g_aIdPageString, pComp); _ReturnIfWizError(pComp->hrContinue); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_IDINFO_NAMEEDIT: case IDC_IDINFO_DNSUFFIXEDIT: if (HIWORD(wParam) == EN_CHANGE) { CAutoLPWSTR pwszCAName, pwszDNSuffix, pwszFullDN; CASERVERSETUPINFO* pServer; pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pServer = pComp->CA.pServer; // if using existing certs ignore the notification // to avoid building the full DN if(pServer->pccExistingCert) { break; } pComp->hrContinue = myUIGetWindowText( GetDlgItem(hDlg, IDC_IDINFO_NAMEEDIT), &pwszCAName); _ReturnIfWizError(pComp->hrContinue); pComp->hrContinue = myUIGetWindowText( GetDlgItem(hDlg, IDC_IDINFO_DNSUFFIXEDIT), &pwszDNSuffix); _ReturnIfWizError(pComp->hrContinue); pComp->hrContinue = BuildFullDN( pwszCAName, pwszDNSuffix, &pwszFullDN); _ReturnIfWizError(pComp->hrContinue); SetDlgItemText( hDlg, IDC_IDINFO_NAMEPREVIEW, pwszFullDN); } break; case IDC_IDINFO_EDIT_VALIDITYCOUNT: break; case IDC_IDINFO_COMBO_VALIDITYSTRING: switch (HIWORD(wParam)) { case CBN_SELCHANGE: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleValidityStringChange( hDlg, pComp->CA.pServer); _ReturnIfWizError(pComp->hrContinue); break; } break; } break; case WM_NOTIFY: switch (((NMHDR FAR *) lParam)->code) { case PSN_KILLACTIVE: break; case PSN_RESET: break; case PSN_QUERYCANCEL: pComp = _GetCompDataOrReturnIfError(pComp, hDlg); return CertConfirmCancel(hDlg, pComp); break; case PSN_SETACTIVE: CSILOGDWORD(IDS_IDINFO_TITLE, dwWIZACTIVE); PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_NEXT); pComp = _GetCompDataOrReturn(pComp, hDlg); _DisableWizDisplayIfError(pComp, hDlg); _ReturnIfWizError(pComp->hrContinue); pComp->hrContinue = HandleIdInfoWizActive(hDlg, pComp, g_aIdPageString); _ReturnIfWizError(pComp->hrContinue); break; case PSN_WIZBACK: CSILOGDWORD(IDS_IDINFO_TITLE, dwWIZBACK); pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleIdInfoWizNextOrBack( hDlg, pComp, g_aIdPageString, PSN_WIZBACK); _ReturnIfWizError(pComp->hrContinue); break; case PSN_WIZNEXT: CSILOGDWORD(IDS_IDINFO_TITLE, dwWIZNEXT); pComp = _GetCompDataOrReturnIfError(pComp, hDlg); pComp->hrContinue = HandleIdInfoWizNextOrBack( hDlg, pComp, g_aIdPageString, PSN_WIZNEXT); _ReturnIfWizError(pComp->hrContinue); break; default: return FALSE; } break; default: return FALSE; } return TRUE; }