/** * Determines whether we should handle the current session or not. * * @return bool true if we should handle this session, false if not. */ bool VBoxCredProvProvider::HandleCurrentSession(void) { /* Load global configuration from registry. */ int rc = LoadConfiguration(); if (RT_FAILURE(rc)) VBoxCredProvVerbose(0, "VBoxCredProv: Error loading global configuration, rc=%Rrc\n", rc); bool fHandle = false; if (VbglR3AutoLogonIsRemoteSession()) { if (m_fHandleRemoteSessions) /* Force remote session handling. */ fHandle = true; } else /* No remote session. */ fHandle = true; VBoxCredProvVerbose(3, "VBoxCredProv: Handling current session=%RTbool\n", fHandle); return fHandle; }
/** * Called by LogonUI when it needs this credential's advice. * * At the moment we only grab the credential provider events so that we can * trigger a re-enumeration of the credentials later. */ HRESULT VBoxCredProvCredential::Advise(ICredentialProviderCredentialEvents *pEvents) { VBoxCredProvVerbose(0, "VBoxCredProvCredential::Advise: pEvents=0x%p\n", pEvents); if (m_pEvents) { m_pEvents->Release(); m_pEvents = NULL; } return pEvents->QueryInterface(IID_PPV_ARGS(&m_pEvents)); }
/** * Called by LogonUI when it's finished with handling this credential. * * We only need to release the credential provider events, if any. */ HRESULT VBoxCredProvCredential::UnAdvise(void) { VBoxCredProvVerbose(0, "VBoxCredProvCredential::UnAdvise\n"); if (m_pEvents) { m_pEvents->Release(); m_pEvents = NULL; } return S_OK; }
/** * Uninitializes the callback events so that they're no longer valid. * * @return HRESULT */ HRESULT VBoxCredProvProvider::UnAdvise(void) { VBoxCredProvVerbose(0, "VBoxCredProv::UnAdvise: pEvents=0x%p\n", m_pEvents); if (m_pEvents) { m_pEvents->Release(); m_pEvents = NULL; } return S_OK; }
/** * Called by LogonUI when a user profile (tile) has been selected. * * As we don't want Winlogon to try logging in immediately we set pfAutoLogon * to FALSE (if set). */ HRESULT VBoxCredProvCredential::SetSelected(PBOOL pfAutoLogon) { VBoxCredProvVerbose(0, "VBoxCredProvCredential::SetSelected\n"); /* * Don't do auto logon here because it would retry too often with * every credential field (user name, password, domain, ...) which makes * winlogon wait before new login attempts can be made. */ if (pfAutoLogon) *pfAutoLogon = FALSE; return S_OK; }
VBoxCredProvCredential::~VBoxCredProvCredential(void) { VBoxCredProvVerbose(0, "VBoxCredProvCredential: Destroying\n"); Reset(); for (unsigned i = 0; i < VBOXCREDPROV_NUM_FIELDS; i++) { if (m_apwszFields[i]) { RTUtf16Free(m_apwszFields[i]); m_apwszFields[i] = NULL; } } VBoxCredentialProviderRelease(); }
VBoxCredProvCredential::VBoxCredProvCredential(void) : m_enmUsageScenario(CPUS_INVALID), m_cRefs(1), m_pEvents(NULL), m_fHaveCreds(false) { VBoxCredProvVerbose(0, "VBoxCredProvCredential: Created\n"); VBoxCredentialProviderAcquire(); for (unsigned i = 0; i < VBOXCREDPROV_NUM_FIELDS; i++) { const VBOXCREDPROV_FIELD *pField = &s_VBoxCredProvDefaultFields[i]; m_apwszFields[i] = RTUtf16Dup(pField->desc.pszLabel ? pField->desc.pszLabel : L""); AssertPtr(m_apwszFields[i]); } }
/** * Called by LogonUI when it needs this credential's advice. * * At the moment we only grab the credential provider events so that we can * trigger a re-enumeration of the credentials later. */ HRESULT VBoxCredProvCredential::Advise(ICredentialProviderCredentialEvents *pEvents) { VBoxCredProvVerbose(0, "VBoxCredProvCredential::Advise: pEvents=0x%p\n", pEvents); if (m_pEvents) { m_pEvents->Release(); m_pEvents = NULL; } m_pEvents = pEvents; if (m_pEvents) m_pEvents->AddRef(); return S_OK; }
/** * Sets a credential provider field by first zero'ing out its current content in a (hopefully) secure manner, * then applying either the field's default or a new value. * * @return HRESULT * @param dwFieldID Field ID of the credential provider field to reset. * @param pcwszString String to set for the given field. Specify NULL for setting the provider's default value. * @param fNotifyUI Whether to notify the LogonUI about the reset. */ HRESULT VBoxCredProvCredential::setField(DWORD dwFieldID, const PRTUTF16 pcwszString, bool fNotifyUI) { if (dwFieldID >= VBOXCREDPROV_NUM_FIELDS) return E_INVALIDARG; HRESULT hr = S_OK; PRTUTF16 pwszField = m_apwszFields[dwFieldID]; if (pwszField) { /* First, wipe the existing value thoroughly. */ RTMemWipeThoroughly(pwszField, (RTUtf16Len(pwszField) + 1) * sizeof(RTUTF16), 3 /* Passes */); /* Second, free the string. */ RTUtf16Free(pwszField); } /* Either fill in the default value or the one specified in pcwszString. */ pwszField = RTUtf16Dup(pcwszString ? pcwszString : s_VBoxCredProvDefaultFields[dwFieldID].desc.pszLabel); if (pwszField) { m_apwszFields[dwFieldID] = pwszField; /* Update the pointer. */ if ( m_pEvents && fNotifyUI) /* Let the logon UI know if wanted. */ { hr = m_pEvents->SetFieldString(this, dwFieldID, pwszField); } } else hr = E_OUTOFMEMORY; VBoxCredProvVerbose(0, "VBoxCredProvCredential::setField: Setting field dwFieldID=%ld to '%ls', fNotifyUI=%RTbool, hr=0x%08x\n", dwFieldID, #ifdef DEBUG pwszField, #else /* Don't show any passwords in release mode. */ dwFieldID == VBOXCREDPROV_FIELDID_PASSWORD ? L"XXX" : pwszField, #endif fNotifyUI, hr); return hr; }
/** * Called by LogonUI to retrieve the (interactive) state of a UI field. */ HRESULT VBoxCredProvCredential::GetFieldState(DWORD dwFieldID, CREDENTIAL_PROVIDER_FIELD_STATE *pFieldState, CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE *pFieldstateInteractive) { VBoxCredProvVerbose(0, "VBoxCredProvCredential::GetFieldState: dwFieldID=%ld\n", dwFieldID); HRESULT hr = S_OK; if ( (dwFieldID < VBOXCREDPROV_NUM_FIELDS) && pFieldState && pFieldstateInteractive) { *pFieldState = s_VBoxCredProvFields[dwFieldID].state; *pFieldstateInteractive = s_VBoxCredProvFields[dwFieldID].stateInteractive; } else hr = E_INVALIDARG; return hr; }
VBoxCredProvProvider::~VBoxCredProvProvider(void) { VBoxCredProvVerbose(0, "VBoxCredProv: Destroying\n"); if (m_pCred) { m_pCred->Release(); m_pCred = NULL; } if (m_pPoller) { m_pPoller->Shutdown(); delete m_pPoller; m_pPoller = NULL; } VBoxCredProvReportStatus(VBoxGuestFacilityStatus_Terminated); VBoxCredentialProviderRelease(); }
/** * Initializes the communication with LogonUI through callbacks events which we can later * use to start re-enumeration of credentials. * * @return HRESULT * @param pcpEvents Pointer to event interface. * @param upAdviseContext The current advise context. */ HRESULT VBoxCredProvProvider::Advise(ICredentialProviderEvents *pcpEvents, UINT_PTR upAdviseContext) { VBoxCredProvVerbose(0, "VBoxCredProv::Advise, pcpEvents=0x%p, upAdviseContext=%u\n", pcpEvents, upAdviseContext); if (m_pEvents) { m_pEvents->Release(); m_pEvents = NULL; } m_pEvents = pcpEvents; if (m_pEvents) m_pEvents->AddRef(); /* * Save advice context for later use when binding to * certain ICredentialProviderEvents events. */ m_upAdviseContext = upAdviseContext; return S_OK; }
HRESULT VBoxCredProvFactory::QueryInterface(REFIID interfaceID, void **ppvInterface) { VBoxCredProvVerbose(0, "VBoxCredProvFactory: QueryInterface\n"); HRESULT hr = S_OK; if (ppvInterface) { if ( IID_IClassFactory == interfaceID || IID_IUnknown == interfaceID) { *ppvInterface = static_cast<IUnknown*>(this); reinterpret_cast<IUnknown*>(*ppvInterface)->AddRef(); } else { *ppvInterface = NULL; hr = E_NOINTERFACE; } } else hr = E_INVALIDARG; return hr; }
/** * Retrieves a descriptor of a specified field. * * @return HRESULT * @param dwIndex ID of field to retrieve descriptor for. * @param ppFieldDescriptor Pointer which receives the allocated field * descriptor. */ HRESULT VBoxCredProvProvider::GetFieldDescriptorAt(DWORD dwIndex, CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR **ppFieldDescriptor) { HRESULT hr = S_OK; if ( dwIndex < VBOXCREDPROV_NUM_FIELDS && ppFieldDescriptor) { PCREDENTIAL_PROVIDER_FIELD_DESCRIPTOR pcpFieldDesc = (PCREDENTIAL_PROVIDER_FIELD_DESCRIPTOR)CoTaskMemAlloc(sizeof(CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR)); if (pcpFieldDesc) { const VBOXCREDPROV_FIELD &field = s_VBoxCredProvFields[dwIndex]; RT_BZERO(pcpFieldDesc, sizeof(CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR)); pcpFieldDesc->dwFieldID = field.desc.dwFieldID; pcpFieldDesc->cpft = field.desc.cpft; if (field.desc.pszLabel) hr = SHStrDupW(field.desc.pszLabel, &pcpFieldDesc->pszLabel); } else hr = E_OUTOFMEMORY; if (SUCCEEDED(hr)) *ppFieldDescriptor = pcpFieldDesc; else CoTaskMemFree(pcpFieldDesc); } else hr = E_INVALIDARG; VBoxCredProvVerbose(0, "VBoxCredProv::GetFieldDescriptorAt: dwIndex=%ld, ppDesc=0x%p, hr=0x%08x\n", dwIndex, ppFieldDescriptor, hr); return hr; }
/** * Checks and retrieves credentials provided by the host + does account lookup on eventually * renamed user accounts. * * @return IPRT status code. */ int VBoxCredProvCredential::RetrieveCredentials(void) { int rc = VbglR3CredentialsQueryAvailability(); if (RT_SUCCESS(rc)) { /* * Set status to "terminating" to let the host know this module now * tries to receive and use passed credentials so that credentials from * the host won't be sent twice. */ VBoxCredProvReportStatus(VBoxGuestFacilityStatus_Terminating); rc = VbglR3CredentialsRetrieveUtf16(&m_apwszCredentials[VBOXCREDPROV_FIELDID_USERNAME], &m_apwszCredentials[VBOXCREDPROV_FIELDID_PASSWORD], &m_apwszCredentials[VBOXCREDPROV_FIELDID_DOMAINNAME]); VBoxCredProvVerbose(0, "VBoxCredProvCredential::RetrieveCredentials: Retrieved credentials with rc=%Rrc\n", rc); } if (RT_SUCCESS(rc)) { VBoxCredProvVerbose(0, "VBoxCredProvCredential::RetrieveCredentials: User=%ls, Password=%ls, Domain=%ls\n", m_apwszCredentials[VBOXCREDPROV_FIELDID_USERNAME], #ifdef DEBUG m_apwszCredentials[VBOXCREDPROV_FIELDID_PASSWORD], #else L"XXX" /* Don't show any passwords in release mode. */, #endif m_apwszCredentials[VBOXCREDPROV_FIELDID_DOMAINNAME]); /* * In case we got a "display name" (e.g. "John Doe") * instead of the real user name (e.g. "jdoe") we have * to translate the data first ... */ PWSTR pwszAcount; if (TranslateAccountName(m_apwszCredentials[VBOXCREDPROV_FIELDID_USERNAME], &pwszAcount)) { VBoxCredProvVerbose(0, "VBoxCredProvCredential::RetrieveCredentials: Translated account name %ls -> %ls\n", m_apwszCredentials[VBOXCREDPROV_FIELDID_USERNAME], pwszAcount); if (m_apwszCredentials[VBOXCREDPROV_FIELDID_USERNAME]) { RTMemWipeThoroughly(m_apwszCredentials[VBOXCREDPROV_FIELDID_USERNAME], RTUtf16Len(m_apwszCredentials[VBOXCREDPROV_FIELDID_USERNAME]) + sizeof(RTUTF16), 3 /* Passes */); RTUtf16Free(m_apwszCredentials[VBOXCREDPROV_FIELDID_USERNAME]); } m_apwszCredentials[VBOXCREDPROV_FIELDID_USERNAME] = pwszAcount; } else { /* * Okay, no display name, but maybe it's a * principal name from which we have to extract the domain from? * ([email protected] -> jdoe in domain my-domain.sub.net.com.) */ PWSTR pwszDomain; if (ExtractAccoutData(m_apwszCredentials[VBOXCREDPROV_FIELDID_USERNAME], &pwszAcount, &pwszDomain)) { /* Update user name. */ if (m_apwszCredentials[VBOXCREDPROV_FIELDID_USERNAME]) { RTMemWipeThoroughly(m_apwszCredentials[VBOXCREDPROV_FIELDID_USERNAME], RTUtf16Len(m_apwszCredentials[VBOXCREDPROV_FIELDID_USERNAME]) + sizeof(RTUTF16), 3 /* Passes */); RTUtf16Free(m_apwszCredentials[VBOXCREDPROV_FIELDID_USERNAME]); } m_apwszCredentials[VBOXCREDPROV_FIELDID_USERNAME] = pwszAcount; /* Update domain. */ if (m_apwszCredentials[VBOXCREDPROV_FIELDID_DOMAINNAME]) { RTMemWipeThoroughly(m_apwszCredentials[VBOXCREDPROV_FIELDID_DOMAINNAME], RTUtf16Len(m_apwszCredentials[VBOXCREDPROV_FIELDID_DOMAINNAME]) + sizeof(RTUTF16), 3 /* Passes */); RTUtf16Free(m_apwszCredentials[VBOXCREDPROV_FIELDID_DOMAINNAME]); } m_apwszCredentials[VBOXCREDPROV_FIELDID_DOMAINNAME] = pwszDomain; VBoxCredProvVerbose(0, "VBoxCredProvCredential::RetrieveCredentials: Extracted account data pwszAccount=%ls, pwszDomain=%ls\n", m_apwszCredentials[VBOXCREDPROV_FIELDID_USERNAME], m_apwszCredentials[VBOXCREDPROV_FIELDID_DOMAINNAME]); } } m_fHaveCreds = true; } else { /* If credentials already were retrieved by a former call, don't try to retrieve new ones * and just report back the already retrieved ones. */ if (m_fHaveCreds) { VBoxCredProvVerbose(0, "VBoxCredProvCredential::RetrieveCredentials: Credentials already retrieved\n"); rc = VINF_SUCCESS; } } VBoxCredProvVerbose(0, "VBoxCredProvCredential::RetrieveCredentials: Returned rc=%Rrc\n", rc); return rc; }
/** * Tells this provider the current usage scenario. * * @return HRESULT * @param enmUsageScenario Current usage scenario this provider will be * used in. * @param dwFlags Optional flags for the usage scenario. */ HRESULT VBoxCredProvProvider::SetUsageScenario(CREDENTIAL_PROVIDER_USAGE_SCENARIO enmUsageScenario, DWORD dwFlags) { HRESULT hr = S_OK; DWORD dwErr; VBoxCredProvVerbose(0, "VBoxCredProv::SetUsageScenario: enmUsageScenario=%d, dwFlags=%ld\n", enmUsageScenario, dwFlags); m_enmUsageScenario = enmUsageScenario; switch (m_enmUsageScenario) { case CPUS_LOGON: case CPUS_UNLOCK_WORKSTATION: { VBoxCredProvReportStatus(VBoxGuestFacilityStatus_Active); dwErr = LoadConfiguration(); if (dwErr != ERROR_SUCCESS) VBoxCredProvVerbose(0, "VBoxCredProv: Error while loading configuration, error=%ld\n", dwErr); /* Do not stop running on a misconfigured system. */ /* * If we're told to not handle the current session just bail out and let the * user know. */ if (!HandleCurrentSession()) break; if (!m_pPoller) { try { m_pPoller = new VBoxCredProvPoller(); AssertPtr(m_pPoller); int rc = m_pPoller->Initialize(this); if (RT_FAILURE(rc)) VBoxCredProvVerbose(0, "VBoxCredProv::SetUsageScenario: Error initializing poller thread, rc=%Rrc\n", rc); } catch (std::bad_alloc &ex) { NOREF(ex); hr = E_OUTOFMEMORY; } } if ( SUCCEEDED(hr) && !m_pCred) { try { m_pCred = new VBoxCredProvCredential(); AssertPtr(m_pPoller); hr = m_pCred->Initialize(m_enmUsageScenario); } catch (std::bad_alloc &ex) { NOREF(ex); hr = E_OUTOFMEMORY; } } else { /* All set up already! Nothing to do here right now. */ } /* If we failed, do some cleanup. */ if (FAILED(hr)) { if (m_pCred != NULL) { m_pCred->Release(); m_pCred = NULL; } } break; } case CPUS_CHANGE_PASSWORD: /* Asks us to provide a way to change the password. */ case CPUS_CREDUI: /* Displays an own UI. We don't need that. */ case CPUS_PLAP: /* See Pre-Logon-Access Provider. Not needed (yet). */ hr = E_NOTIMPL; break; default: hr = E_INVALIDARG; break; } VBoxCredProvVerbose(0, "VBoxCredProv::SetUsageScenario returned hr=0x%08x\n", hr); return hr; }
/** * Searches the account name based on a display (real) name (e.g. "John Doe" -> "jdoe"). * Result "ppwszAccoutName" needs to be freed with CoTaskMemFree! */ BOOL VBoxCredProvCredential::TranslateAccountName(PWSTR pwszDisplayName, PWSTR *ppwszAccoutName) { AssertPtrReturn(pwszDisplayName, FALSE); VBoxCredProvVerbose(0, "VBoxCredProvCredential::TranslateAccountName: Getting account name for \"%ls\" ...\n", pwszDisplayName); /** @todo Do we need ADS support (e.g. TranslateNameW) here? */ BOOL fFound = FALSE; /* Did we find the desired user? */ NET_API_STATUS rcStatus; DWORD dwLevel = 2; /* Detailed information about user accounts. */ DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH; DWORD dwEntriesRead = 0; DWORD dwTotalEntries = 0; DWORD dwResumeHandle = 0; LPUSER_INFO_2 pBuf = NULL; LPUSER_INFO_2 pCurBuf = NULL; do { rcStatus = NetUserEnum(NULL, /* Server name, NULL for localhost. */ dwLevel, FILTER_NORMAL_ACCOUNT, (LPBYTE*)&pBuf, dwPrefMaxLen, &dwEntriesRead, &dwTotalEntries, &dwResumeHandle); if ( rcStatus == NERR_Success || rcStatus == ERROR_MORE_DATA) { if ((pCurBuf = pBuf) != NULL) { for (DWORD i = 0; i < dwEntriesRead; i++) { /* * Search for the "display name" - that might be * "John Doe" or something similar the user recognizes easier * and may not the same as the "account" name (e.g. "jdoe"). */ if ( pCurBuf && pCurBuf->usri2_full_name && StrCmpI(pwszDisplayName, pCurBuf->usri2_full_name) == 0) { /* * Copy the real user name (e.g. "jdoe") to our * output buffer. */ LPWSTR pwszTemp; HRESULT hr = SHStrDupW(pCurBuf->usri2_name, &pwszTemp); if (hr == S_OK) { *ppwszAccoutName = pwszTemp; fFound = TRUE; } else VBoxCredProvVerbose(0, "VBoxCredProvCredential::TranslateAccountName: Error copying data, hr=%08x\n", hr); break; } pCurBuf++; } } if (pBuf != NULL) { NetApiBufferFree(pBuf); pBuf = NULL; } } } while (rcStatus == ERROR_MORE_DATA && !fFound); if (pBuf != NULL) { NetApiBufferFree(pBuf); pBuf = NULL; } VBoxCredProvVerbose(0, "VBoxCredProvCredential::TranslateAccountName returned rcStatus=%ld, fFound=%RTbool\n", rcStatus, fFound); return fFound; #if 0 DWORD dwErr = NO_ERROR; ULONG cbLen = 0; if ( TranslateNameW(pwszName, NameUnknown, NameUserPrincipal, NULL, &cbLen) && cbLen > 0) { VBoxCredProvVerbose(0, "VBoxCredProvCredential::GetAccountName: Translated ADS name has %u characters\n", cbLen)); ppwszAccoutName = (PWSTR)RTMemAlloc(cbLen * sizeof(WCHAR)); AssertPtrReturn(pwszName, FALSE); if (TranslateNameW(pwszName, NameUnknown, NameUserPrincipal, ppwszAccoutName, &cbLen)) { VBoxCredProvVerbose(0, "VBoxCredProvCredential::GetAccountName: Real ADS account name of '%ls' is '%ls'\n", pwszName, ppwszAccoutName)); }
VBoxCredProvCredential::~VBoxCredProvCredential(void) { VBoxCredProvVerbose(0, "VBoxCredProvCredential: Destroying\n"); Reset(); VBoxCredentialProviderRelease(); }
/** * Checks and retrieves credentials provided by the host + does account lookup on eventually * renamed user accounts. * * @return IPRT status code. */ int VBoxCredProvCredential::RetrieveCredentials(void) { PRTUTF16 pwszUser = NULL; PRTUTF16 pwszPassword = NULL; PRTUTF16 pwszDomain = NULL; int rc = VbglR3CredentialsQueryAvailability(); if (RT_SUCCESS(rc)) { /* * Set status to "terminating" to let the host know this module now * tries to receive and use passed credentials so that credentials from * the host won't be sent twice. */ VBoxCredProvReportStatus(VBoxGuestFacilityStatus_Terminating); rc = VbglR3CredentialsRetrieveUtf16(&pwszUser, &pwszPassword, &pwszDomain); VBoxCredProvVerbose(0, "VBoxCredProvCredential::RetrieveCredentials: Retrieved credentials with rc=%Rrc\n", rc); } if (RT_SUCCESS(rc)) { VBoxCredProvVerbose(0, "VBoxCredProvCredential::RetrieveCredentials: Received credentials for user '%ls'\n", pwszUser); /* * In case we got a "display name" (e.g. "John Doe") * instead of the real user name (e.g. "jdoe") we have * to translate the data first ... */ PWSTR pwszExtractedName = NULL; if ( TranslateAccountName(pwszUser, &pwszExtractedName) && pwszExtractedName) { VBoxCredProvVerbose(0, "VBoxCredProvCredential::RetrieveCredentials: Translated account name '%ls' -> '%ls'\n", pwszUser, pwszExtractedName); RTMemWipeThoroughly(pwszUser, (RTUtf16Len(pwszUser) + 1) * sizeof(RTUTF16), 3 /* Passes */); RTUtf16Free(pwszUser); pwszUser = RTUtf16Dup(pwszExtractedName); CoTaskMemFree(pwszExtractedName); pwszExtractedName = NULL; } else { /* * Okay, no display name, but maybe it's a * principal name from which we have to extract the domain from? * ([email protected] -> jdoe in domain my-domain.sub.net.com.) */ PWSTR pwszExtractedDomain = NULL; if (ExtractAccoutData(pwszUser, &pwszExtractedName, &pwszExtractedDomain)) { /* Update user name. */ if (pwszExtractedName) { if (pwszUser) { RTMemWipeThoroughly(pwszUser, (RTUtf16Len(pwszUser) + 1) * sizeof(RTUTF16), 3 /* Passes */); RTUtf16Free(pwszUser); } pwszUser = RTUtf16Dup(pwszExtractedName); CoTaskMemFree(pwszExtractedName); pwszExtractedName = NULL; } /* Update domain. */ if (pwszExtractedDomain) { if (pwszDomain) { RTMemWipeThoroughly(pwszDomain, (RTUtf16Len(pwszDomain) + 1) * sizeof(RTUTF16), 3 /* Passes */); RTUtf16Free(pwszDomain); } pwszDomain = RTUtf16Dup(pwszExtractedDomain); CoTaskMemFree(pwszExtractedDomain); pwszExtractedDomain = NULL; } VBoxCredProvVerbose(0, "VBoxCredProvCredential::RetrieveCredentials: Extracted account name '%ls' + domain '%ls'\n", pwszUser ? pwszUser : L"<NULL>", pwszDomain ? pwszDomain : L"<NULL>"); } } m_fHaveCreds = true; } if (m_fHaveCreds) { VBoxCredProvVerbose(0, "VBoxCredProvCredential::RetrieveCredentials: Setting fields\n"); setField(VBOXCREDPROV_FIELDID_USERNAME, pwszUser, true /* fNotifyUI */); setField(VBOXCREDPROV_FIELDID_PASSWORD, pwszPassword, true /* fNotifyUI */); setField(VBOXCREDPROV_FIELDID_DOMAINNAME, pwszDomain, true /* fNotifyUI */); } VBoxCredProvVerbose(0, "VBoxCredProvCredential::RetrieveCredentials: Wiping ...\n"); VbglR3CredentialsDestroyUtf16(pwszUser, pwszPassword, pwszDomain, 3 /* cPasses */); VBoxCredProvVerbose(0, "VBoxCredProvCredential::RetrieveCredentials: Returned rc=%Rrc\n", rc); return rc; }
HRESULT VBoxCredProvCredential::kerberosLogonInit(KERB_INTERACTIVE_LOGON *pLogonIn, CREDENTIAL_PROVIDER_USAGE_SCENARIO enmUsage, PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszDomain) { AssertPtrReturn(pLogonIn, E_INVALIDARG); AssertPtrReturn(pwszUser, E_INVALIDARG); AssertPtrReturn(pwszPassword, E_INVALIDARG); /* pwszDomain is optional. */ HRESULT hr; /* Do we have a domain name set? */ if ( pwszDomain && RTUtf16Len(pwszDomain)) { hr = RTUTF16ToUnicode(&pLogonIn->LogonDomainName, pwszDomain, true /* fCopy */); } else /* No domain (FQDN) given, try local computer name. */ { WCHAR wszComputerName[MAX_COMPUTERNAME_LENGTH + 1]; DWORD cch = ARRAYSIZE(wszComputerName); if (GetComputerNameW(wszComputerName, &cch)) { /* Is a domain name missing? Then use the name of the local computer. */ hr = RTUTF16ToUnicode(&pLogonIn->LogonDomainName, wszComputerName, true /* fCopy */); VBoxCredProvVerbose(0, "VBoxCredProvCredential::kerberosLogonInit: Local computer name=%ls\n", wszComputerName); } else hr = HRESULT_FROM_WIN32(GetLastError()); } /* Fill in the username and password. */ if (SUCCEEDED(hr)) { hr = RTUTF16ToUnicode(&pLogonIn->UserName, pwszUser, true /* fCopy */); if (SUCCEEDED(hr)) { hr = RTUTF16ToUnicode(&pLogonIn->Password, pwszPassword, true /* fCopy */); if (SUCCEEDED(hr)) { /* Set credential type according to current usage scenario. */ switch (enmUsage) { case CPUS_UNLOCK_WORKSTATION: pLogonIn->MessageType = KerbWorkstationUnlockLogon; break; case CPUS_LOGON: pLogonIn->MessageType = KerbInteractiveLogon; break; case CPUS_CREDUI: pLogonIn->MessageType = (KERB_LOGON_SUBMIT_TYPE)0; /* No message type required here. */ break; default: VBoxCredProvVerbose(0, "VBoxCredProvCredential::kerberosLogonInit: Unknown usage scenario=%ld\n", enmUsage); hr = E_FAIL; break; } } } } return hr; }
/** * Retrieves a descriptor of a specified field. * * @return HRESULT * @param dwIndex ID of field to retrieve descriptor for. * @param ppFieldDescriptor Pointer which receives the allocated field * descriptor. */ HRESULT VBoxCredProvProvider::GetFieldDescriptorAt(DWORD dwIndex, CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR **ppFieldDescriptor) { HRESULT hr = S_OK; if ( dwIndex < VBOXCREDPROV_NUM_FIELDS && ppFieldDescriptor) { PCREDENTIAL_PROVIDER_FIELD_DESCRIPTOR pcpFieldDesc = (PCREDENTIAL_PROVIDER_FIELD_DESCRIPTOR)CoTaskMemAlloc(sizeof(CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR)); if (pcpFieldDesc) { const VBOXCREDPROV_FIELD &field = s_VBoxCredProvDefaultFields[dwIndex]; RT_BZERO(pcpFieldDesc, sizeof(CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR)); pcpFieldDesc->dwFieldID = field.desc.dwFieldID; pcpFieldDesc->cpft = field.desc.cpft; PCRTUTF16 pcwszField = NULL; if (dwIndex != VBOXCREDPROV_FIELDID_PASSWORD) /* Don't ever get any password. Never ever, ever. */ { if (m_pCred) /* If we have retrieved credentials, get the actual (current) value. */ pcwszField = m_pCred->getField(dwIndex); else /* Otherwise get the default value. */ pcwszField = field.desc.pszLabel; } hr = SHStrDupW(pcwszField ? pcwszField : L"", &pcpFieldDesc->pszLabel); VBoxCredProvVerbose(0, "VBoxCredProv::GetFieldDescriptorAt: dwIndex=%ld, pszLabel=%ls, hr=0x%08x\n", dwIndex, #ifdef DEBUG /* Don't show any (sensitive data) in release mode. */ pcwszField ? pcwszField : L"", #else L"XXX", #endif hr); pcpFieldDesc->guidFieldType = field.desc.guidFieldType; } else hr = E_OUTOFMEMORY; if (SUCCEEDED(hr)) { *ppFieldDescriptor = pcpFieldDesc; } else if (pcpFieldDesc) { if (pcpFieldDesc->pszLabel) { CoTaskMemFree(pcpFieldDesc->pszLabel); pcpFieldDesc->pszLabel = NULL; } CoTaskMemFree(pcpFieldDesc); } } else hr = E_INVALIDARG; VBoxCredProvVerbose(0, "VBoxCredProv::GetFieldDescriptorAt: dwIndex=%ld, ppDesc=0x%p, hr=0x%08x\n", dwIndex, ppFieldDescriptor, hr); return hr; }
/** * Initializes this credential with the current credential provider * usage scenario. */ HRESULT VBoxCredProvCredential::Initialize(CREDENTIAL_PROVIDER_USAGE_SCENARIO enmUsageScenario) { VBoxCredProvVerbose(0, "VBoxCredProvCredential::Initialize: enmUsageScenario=%ld\n", enmUsageScenario); m_enmUsageScenario = enmUsageScenario; return S_OK; }
VBoxCredProvPoller::~VBoxCredProvPoller(void) { VBoxCredProvVerbose(0, "VBoxCredProvPoller: Destroying ...\n"); Shutdown(); }
HRESULT VBoxCredProvCredential::kerberosLogonSerialize(const KERB_INTERACTIVE_LOGON *pLogonIn, PBYTE *ppPackage, DWORD *pcbPackage) { AssertPtrReturn(pLogonIn, E_INVALIDARG); AssertPtrReturn(ppPackage, E_INVALIDARG); AssertPtrReturn(pcbPackage, E_INVALIDARG); /* * First, allocate enough space for the logon structure itself and separate * string buffers right after it to store the actual user, password and domain * credentials. */ DWORD cbLogon = sizeof(KERB_INTERACTIVE_UNLOCK_LOGON) + pLogonIn->LogonDomainName.Length + pLogonIn->UserName.Length + pLogonIn->Password.Length; #ifdef DEBUG /* Do not reveal any hints to credential data in release mode. */ VBoxCredProvVerbose(1, "VBoxCredProvCredential::AllocateLogonPackage: Allocating %ld bytes (%zu bytes credentials)\n", cbLogon, cbLogon - sizeof(KERB_INTERACTIVE_UNLOCK_LOGON)); #endif KERB_INTERACTIVE_UNLOCK_LOGON *pLogon = (KERB_INTERACTIVE_UNLOCK_LOGON*)CoTaskMemAlloc(cbLogon); if (!pLogon) return E_OUTOFMEMORY; /* Make sure to zero everything first. */ RT_BZERO(pLogon, cbLogon); /* Let our byte buffer point to the end of our allocated structure so that it can * be used to store the credential data sequentially in a binary blob * (without terminating \0). */ PBYTE pbBuffer = (PBYTE)pLogon + sizeof(KERB_INTERACTIVE_UNLOCK_LOGON); /* The buffer of the packed destination string does not contain the actual * string content but a relative offset starting at the given * KERB_INTERACTIVE_UNLOCK_LOGON structure. */ #define KERB_CRED_INIT_PACKED(StringDst, StringSrc, LogonOffset) \ StringDst.Length = StringSrc.Length; \ StringDst.MaximumLength = StringSrc.Length; \ if (StringDst.Length) \ { \ StringDst.Buffer = (PWSTR)pbBuffer; \ memcpy(StringDst.Buffer, StringSrc.Buffer, StringDst.Length); \ StringDst.Buffer = (PWSTR)(pbBuffer - (PBYTE)LogonOffset); \ pbBuffer += StringDst.Length; \ } KERB_INTERACTIVE_LOGON *pLogonOut = &pLogon->Logon; pLogonOut->MessageType = pLogonIn->MessageType; KERB_CRED_INIT_PACKED(pLogonOut->LogonDomainName, pLogonIn->LogonDomainName, pLogon); KERB_CRED_INIT_PACKED(pLogonOut->UserName , pLogonIn->UserName, pLogon); KERB_CRED_INIT_PACKED(pLogonOut->Password , pLogonIn->Password, pLogon); *ppPackage = (PBYTE)pLogon; *pcbPackage = cbLogon; #undef KERB_CRED_INIT_PACKED return S_OK; }