windows-nt/Source/XPSP1/NT/shell/ext/ratings/mslocusr/msluuser.cpp
2020-09-26 16:20:57 +08:00

553 lines
14 KiB
C++

#include "mslocusr.h"
#include "msluglob.h"
#include <buffer.h>
#include <regentry.h>
#include "profiles.h"
extern "C" {
#include "netmpr.h"
};
#include <ole2.h>
CLUUser::CLUUser(CLUDatabase *pDB)
: m_cRef(1),
m_hkeyDB(NULL),
m_hkeyUser(NULL),
m_fUserExists(FALSE),
m_fAppearsSupervisor(FALSE),
m_fLoadedProfile(FALSE),
m_nlsUsername(),
m_nlsDir(MAX_PATH),
m_nlsPassword(),
m_fAuthenticated(FALSE),
m_pDB(pDB)
{
/* We have a reference to the database so we can get back to its idea
* of the current user. We handle circular refcount problems specifically
* in CLUDatabase::Release; the database only has one reference to an
* IUser, so if his refcount gets down to 1, he releases his cached
* current-user object.
*/
m_pDB->AddRef();
RefThisDLL(TRUE);
}
CLUUser::~CLUUser(void)
{
if (m_hkeyDB != NULL)
RegCloseKey(m_hkeyDB);
if (m_hkeyUser != NULL)
RegCloseKey(m_hkeyUser);
if (m_pDB != NULL)
m_pDB->Release();
RefThisDLL(FALSE);
}
HRESULT CLUUser::Init(LPCSTR pszUsername)
{
m_nlsUsername = pszUsername;
UINT err = m_nlsUsername.QueryError();
if (err != ERROR_SUCCESS)
return HRESULT_FROM_WIN32(err);
err = m_nlsDir.QueryError();
if (err != ERROR_SUCCESS)
return HRESULT_FROM_WIN32(err);
err = (UINT)RegOpenKey(HKEY_LOCAL_MACHINE, ::szProfileList, &m_hkeyDB);
if (err != ERROR_SUCCESS)
return HRESULT_FROM_WIN32(err);
if (!::strcmpf(pszUsername, ::szDefaultUserName)) {
m_fUserExists = TRUE;
m_fAppearsSupervisor = FALSE;
}
else {
err = (UINT)RegOpenKey(m_hkeyDB, pszUsername, &m_hkeyUser);
if (err != ERROR_SUCCESS) {
m_hkeyUser = NULL;
m_fUserExists = FALSE;
}
else {
DWORD cb = sizeof(m_fAppearsSupervisor);
if (RegQueryValueEx(m_hkeyUser, ::szSupervisor, NULL, NULL,
(LPBYTE)&m_fAppearsSupervisor, &cb) != ERROR_SUCCESS) {
m_fAppearsSupervisor = FALSE;
}
DWORD cbDir = m_nlsDir.QueryAllocSize();
LPBYTE pbDir = (LPBYTE)m_nlsDir.Party();
err = RegQueryValueEx(m_hkeyUser, ::szProfileImagePath, NULL, NULL,
pbDir, &cbDir);
if (err != ERROR_SUCCESS)
*pbDir = '\0';
m_nlsDir.DonePartying();
m_fUserExists = (err == ERROR_SUCCESS);
}
}
return NOERROR;
}
STDMETHODIMP CLUUser::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
if (!IsEqualIID(riid, IID_IUnknown) &&
!IsEqualIID(riid, IID_IUser)) {
*ppvObj = NULL;
return ResultFromScode(E_NOINTERFACE);
}
*ppvObj = this;
AddRef();
return NOERROR;
}
STDMETHODIMP_(ULONG) CLUUser::AddRef(void)
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CLUUser::Release(void)
{
ULONG cRef;
cRef = --m_cRef;
if (0L == m_cRef) {
delete this;
}
return cRef;
}
STDMETHODIMP CLUUser::GetName(LPSTR pbBuffer, LPDWORD pcbBuffer)
{
if (m_nlsUsername.QueryError())
return ResultFromScode(E_OUTOFMEMORY);
UINT err = NPSCopyNLS(&m_nlsUsername, pbBuffer, pcbBuffer);
return HRESULT_FROM_WIN32(err);
}
STDMETHODIMP CLUUser::GetProfileDirectory(LPSTR pbBuffer, LPDWORD pcbBuffer)
{
if (m_nlsDir.QueryError())
return ResultFromScode(E_OUTOFMEMORY);
if (!m_nlsDir.strlen())
return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
UINT err = NPSCopyNLS(&m_nlsDir, pbBuffer, pcbBuffer);
return HRESULT_FROM_WIN32(err);
}
BOOL CLUUser::IsSystemCurrentUser(void)
{
NLS_STR nlsSystemUsername(MAX_PATH);
if (nlsSystemUsername.QueryError() == ERROR_SUCCESS) {
if (SUCCEEDED(GetSystemCurrentUser(&nlsSystemUsername)) &&
!m_nlsUsername.stricmp(nlsSystemUsername)) {
return TRUE;
}
}
return FALSE;
}
HRESULT CLUUser::GetSupervisorPassword(BUFFER *pbufOut)
{
LPSTR pBuffer = (LPSTR)pbufOut->QueryPtr();
if (!m_fAuthenticated) {
if (IsSystemCurrentUser()) {
WORD cbBuffer = (WORD)pbufOut->QuerySize();
APIERR err = WNetGetCachedPassword((LPSTR)::szSupervisorPWLKey,
(WORD)::strlenf(::szSupervisorPWLKey),
pBuffer,
&cbBuffer,
PCE_MISC);
if (err == ERROR_SUCCESS)
return S_OK;
if (err == WN_CANCEL)
return S_FALSE;
return HRESULT_FROM_WIN32(err);
}
return HRESULT_FROM_WIN32(ERROR_NOT_AUTHENTICATED);
}
HPWL hPWL;
HRESULT hres = GetPasswordCache(m_nlsPassword.QueryPch(), &hPWL);
if (FAILED(hres))
return hres;
APIERR err = FindCacheResource(hPWL, ::szSupervisorPWLKey,
(WORD)::strlenf(::szSupervisorPWLKey),
pBuffer,
(WORD)pbufOut->QuerySize(),
PCE_MISC);
::ClosePasswordCache(hPWL, TRUE);
if (err == IERR_CacheEntryNotFound)
return S_FALSE;
else if (err != NOERROR)
return HRESULT_FROM_WIN32(err);
CACHE_ENTRY_INFO *pcei = (CACHE_ENTRY_INFO *)pBuffer;
::memmovef(pBuffer, pBuffer + pcei->dchPassword, pcei->cbPassword);
return NOERROR;
}
STDMETHODIMP CLUUser::IsSupervisor(void)
{
/* If the supervisor password is blank, then everybody's a supervisor */
if (::VerifySupervisorPassword(::szNULL) == S_OK)
return S_OK;
/* If temporary supervisor privilege has been granted to this user object,
* honor it.
*/
if (m_fTempSupervisor)
return S_OK;
BUFFER bufPCE(MAX_ENTRY_SIZE+2);
if (bufPCE.QueryPtr() == NULL)
return E_OUTOFMEMORY;
HRESULT hres = GetSupervisorPassword(&bufPCE);
if (hres != S_OK)
return hres;
return ::VerifySupervisorPassword((LPCSTR)bufPCE.QueryPtr());
}
APIERR MakeSupervisor(HPWL hPWL, LPCSTR pszSupervisorPassword)
{
#ifdef MSLOCUSR_USE_SUPERVISOR_PASSWORD
return ::AddCacheResource(hPWL,
::szSupervisorPWLKey,
::strlenf(::szSupervisorPWLKey),
pszSupervisorPassword,
::strlenf(pszSupervisorPassword)+1,
PCE_MISC, 0);
#else
return ERROR_SUCCESS;
#endif
}
STDMETHODIMP CLUUser::SetSupervisorPrivilege(BOOL fMakeSupervisor, LPCSTR pszSupervisorPassword)
{
if (m_pDB == NULL)
return E_UNEXPECTED;
#ifndef MSLOCUSR_USE_SUPERVISOR_PASSWORD
/* Don't write stuff to the user's password cache if we're not doing any
* supervisor password stuff.
*/
m_fAppearsSupervisor = fMakeSupervisor;
return S_OK;
#else
BUFFER bufPCE(MAX_ENTRY_SIZE+2);
if (bufPCE.QueryPtr() == NULL)
return E_OUTOFMEMORY;
HRESULT hres = S_OK;
/* If supervisor password is provided by the caller, use that, otherwise
* inspect the current user's password cache.
*/
if (pszSupervisorPassword == NULL) {
IUser *pCurrentUser;
if (FAILED(m_pDB->GetCurrentUser(&pCurrentUser)))
return E_ACCESSDENIED;
hres = ((CLUUser *)pCurrentUser)->GetSupervisorPassword(&bufPCE);
pCurrentUser->Release();
pszSupervisorPassword = (LPCSTR)bufPCE.QueryPtr();
}
if (SUCCEEDED(hres)) {
hres = ::VerifySupervisorPassword(pszSupervisorPassword);
if (hres == S_OK) { /* not SUCCEEDED because S_FALSE means wrong PW */
HPWL hpwlThisUser;
hres = GetPasswordCache(m_nlsPassword.QueryPch(), &hpwlThisUser);
if (SUCCEEDED(hres)) {
APIERR err;
if (fMakeSupervisor)
{
err = ::MakeSupervisor(hpwlThisUser, pszSupervisorPassword);
}
else {
err = ::DeleteCacheResource(hpwlThisUser,
::szSupervisorPWLKey,
::strlenf(::szSupervisorPWLKey),
PCE_MISC);
}
::ClosePasswordCache(hpwlThisUser, TRUE);
hres = HRESULT_FROM_WIN32(err);
}
else if (!m_fAuthenticated && IsSystemCurrentUser()) {
APIERR err;
if (fMakeSupervisor) {
err = ::WNetCachePassword(
(LPSTR)::szSupervisorPWLKey,
::strlenf(::szSupervisorPWLKey),
(LPSTR)pszSupervisorPassword,
::strlenf(pszSupervisorPassword)+1,
PCE_MISC, 0);
}
else {
err = ::WNetRemoveCachedPassword(
(LPSTR)::szSupervisorPWLKey,
::strlenf(::szSupervisorPWLKey),
PCE_MISC);
}
hres = HRESULT_FROM_WIN32(err);
}
if (SUCCEEDED(hres)) {
m_fAppearsSupervisor = fMakeSupervisor;
if (m_hkeyUser != NULL)
RegSetValueEx(m_hkeyUser, ::szSupervisor, NULL,
REG_DWORD, (LPBYTE)&m_fAppearsSupervisor,
sizeof(m_fAppearsSupervisor));
}
}
}
return hres;
#endif
}
STDMETHODIMP CLUUser::MakeTempSupervisor(BOOL fMakeSupervisor, LPCSTR pszSupervisorPassword)
{
if (!fMakeSupervisor)
m_fTempSupervisor = FALSE;
else {
HRESULT hres = ::VerifySupervisorPassword(pszSupervisorPassword);
if (hres == S_FALSE)
hres = E_ACCESSDENIED;
if (FAILED(hres))
return hres;
m_fTempSupervisor = TRUE;
}
return S_OK;
}
STDMETHODIMP CLUUser::AppearsSupervisor(void)
{
if (m_fTempSupervisor)
return S_OK;
return m_fAppearsSupervisor ? S_OK : S_FALSE;
}
STDMETHODIMP CLUUser::Authenticate(LPCSTR pszPassword)
{
HPWL hPWL = NULL;
HRESULT hres = GetPasswordCache(pszPassword, &hPWL);
if (FAILED(hres))
return hres;
::ClosePasswordCache(hPWL, TRUE);
return NOERROR;
}
STDMETHODIMP CLUUser::ChangePassword(LPCSTR pszOldPassword, LPCSTR pszNewPassword)
{
// if current user is supervisor, allow null pszOldPassword
NLS_STR nlsNewPassword(pszNewPassword);
if (nlsNewPassword.QueryError())
return HRESULT_FROM_WIN32(nlsNewPassword.QueryError());
nlsNewPassword.strupr();
nlsNewPassword.ToOEM();
HPWL hPWL;
HRESULT hres = GetPasswordCache(pszOldPassword, &hPWL);
if (FAILED(hres))
return hres;
hres = HRESULT_FROM_WIN32(::SetCachePassword(hPWL, nlsNewPassword.QueryPch()));
if (SUCCEEDED(hres)) {
m_nlsPassword = pszNewPassword; /* FEATURE - obfuscate me */
m_fAuthenticated = TRUE;
}
::ClosePasswordCache(hPWL, TRUE);
return hres;
}
HRESULT GetUserPasswordCache(LPCSTR pszUsername, LPCSTR pszPassword, LPHANDLE phOut, BOOL fCreate)
{
NLS_STR nlsUsername(pszUsername);
if (nlsUsername.QueryError())
return HRESULT_FROM_WIN32(nlsUsername.QueryError());
nlsUsername.strupr();
nlsUsername.ToOEM();
NLS_STR nlsPassword(pszPassword);
if (nlsPassword.QueryError())
return HRESULT_FROM_WIN32(nlsPassword.QueryError());
nlsPassword.ToOEM();
*phOut = NULL;
UINT err = ::OpenPasswordCache(phOut, nlsUsername.QueryPch(), nlsPassword.QueryPch(), TRUE);
if (fCreate &&
(err == IERR_UsernameNotFound || err == ERROR_FILE_NOT_FOUND ||
err == ERROR_PATH_NOT_FOUND)) {
err = ::CreatePasswordCache(phOut, nlsUsername.QueryPch(), nlsPassword.QueryPch());
}
if (err == IERR_IncorrectUsername) {
nlsPassword.ToAnsi(); /* must convert to OEM to uppercase properly */
nlsPassword.strupr();
nlsPassword.ToOEM();
err = ::OpenPasswordCache(phOut, nlsUsername.QueryPch(), nlsPassword.QueryPch(), TRUE);
}
if (err)
return HRESULT_FROM_WIN32(err);
return S_OK;
}
STDMETHODIMP CLUUser::GetPasswordCache(LPCSTR pszPassword, LPHANDLE phOut)
{
HRESULT hres = ::GetUserPasswordCache(m_nlsUsername.QueryPch(), pszPassword,
phOut, TRUE);
if (FAILED(hres))
return hres;
m_nlsPassword = pszPassword; /* FEATURE - obfuscate me */
m_fAuthenticated = TRUE;
return NOERROR;
}
STDMETHODIMP CLUUser::LoadProfile(HKEY *phkeyUser)
{
if (IsSystemCurrentUser() ||
!::strcmpf(m_nlsUsername.QueryPch(), ::szDefaultUserName)) {
/* If he's the current or default user, his profile should be loaded
* under HKEY_USERS. If it is, we can return that key. Otherwise,
* we'll need to load it.
*/
if (RegOpenKeyEx(HKEY_USERS, m_nlsUsername.QueryPch(), 0,
KEY_READ | KEY_WRITE, phkeyUser) == ERROR_SUCCESS) {
m_fLoadedProfile = FALSE;
return S_OK;
}
}
else {
if (IsCurrentUserSupervisor(m_pDB) != S_OK)
return E_ACCESSDENIED;
}
RegEntry reRoot(::szProfileList, HKEY_LOCAL_MACHINE);
if (reRoot.GetError() != ERROR_SUCCESS)
return HRESULT_FROM_WIN32(reRoot.GetError());
reRoot.MoveToSubKey(m_nlsUsername.QueryPch());
if (reRoot.GetError() != ERROR_SUCCESS)
return HRESULT_FROM_WIN32(reRoot.GetError());
NLS_STR nlsProfilePath(MAX_PATH);
if (nlsProfilePath.QueryError() != ERROR_SUCCESS)
return E_OUTOFMEMORY;
reRoot.GetValue(::szProfileImagePath, &nlsProfilePath);
if (reRoot.GetError() != ERROR_SUCCESS)
return HRESULT_FROM_WIN32(reRoot.GetError());
AddBackslash(nlsProfilePath);
nlsProfilePath.strcat(::szStdNormalProfile);
if (!FileExists(nlsProfilePath.QueryPch()))
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
LONG err = ::MyRegLoadKey(HKEY_USERS, m_nlsUsername.QueryPch(), nlsProfilePath.QueryPch());
if (err == ERROR_SUCCESS) {
HKEY hkeyNewProfile;
err = ::RegOpenKey(HKEY_USERS, m_nlsUsername.QueryPch(), phkeyUser);
if (err != ERROR_SUCCESS) {
::RegUnLoadKey(HKEY_USERS, m_nlsUsername.QueryPch());
}
else {
m_fLoadedProfile = TRUE;
}
}
return HRESULT_FROM_WIN32(err);
}
STDMETHODIMP CLUUser::UnloadProfile(HKEY hkeyUser)
{
RegFlushKey(hkeyUser);
RegCloseKey(hkeyUser);
if (m_fLoadedProfile) {
RegUnLoadKey(HKEY_USERS, m_nlsUsername.QueryPch());
m_fLoadedProfile = FALSE;
}
return S_OK;
}
STDMETHODIMP CLUUser::GetComponentSettings(REFCLSID clsidComponent,
LPCSTR pszName, IUnknown **ppOut,
DWORD fdwAccess)
{
return ResultFromScode(E_NOTIMPL);
}
STDMETHODIMP CLUUser::EnumerateComponentSettings(IEnumUnknown **ppOut,
DWORD fdwAccess)
{
return ResultFromScode(E_NOTIMPL);
}