|
|
#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); }
|