Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

552 lines
14 KiB

  1. #include "mslocusr.h"
  2. #include "msluglob.h"
  3. #include <buffer.h>
  4. #include <regentry.h>
  5. #include "profiles.h"
  6. extern "C" {
  7. #include "netmpr.h"
  8. };
  9. #include <ole2.h>
  10. CLUUser::CLUUser(CLUDatabase *pDB)
  11. : m_cRef(1),
  12. m_hkeyDB(NULL),
  13. m_hkeyUser(NULL),
  14. m_fUserExists(FALSE),
  15. m_fAppearsSupervisor(FALSE),
  16. m_fLoadedProfile(FALSE),
  17. m_nlsUsername(),
  18. m_nlsDir(MAX_PATH),
  19. m_nlsPassword(),
  20. m_fAuthenticated(FALSE),
  21. m_pDB(pDB)
  22. {
  23. /* We have a reference to the database so we can get back to its idea
  24. * of the current user. We handle circular refcount problems specifically
  25. * in CLUDatabase::Release; the database only has one reference to an
  26. * IUser, so if his refcount gets down to 1, he releases his cached
  27. * current-user object.
  28. */
  29. m_pDB->AddRef();
  30. RefThisDLL(TRUE);
  31. }
  32. CLUUser::~CLUUser(void)
  33. {
  34. if (m_hkeyDB != NULL)
  35. RegCloseKey(m_hkeyDB);
  36. if (m_hkeyUser != NULL)
  37. RegCloseKey(m_hkeyUser);
  38. if (m_pDB != NULL)
  39. m_pDB->Release();
  40. RefThisDLL(FALSE);
  41. }
  42. HRESULT CLUUser::Init(LPCSTR pszUsername)
  43. {
  44. m_nlsUsername = pszUsername;
  45. UINT err = m_nlsUsername.QueryError();
  46. if (err != ERROR_SUCCESS)
  47. return HRESULT_FROM_WIN32(err);
  48. err = m_nlsDir.QueryError();
  49. if (err != ERROR_SUCCESS)
  50. return HRESULT_FROM_WIN32(err);
  51. err = (UINT)RegOpenKey(HKEY_LOCAL_MACHINE, ::szProfileList, &m_hkeyDB);
  52. if (err != ERROR_SUCCESS)
  53. return HRESULT_FROM_WIN32(err);
  54. if (!::strcmpf(pszUsername, ::szDefaultUserName)) {
  55. m_fUserExists = TRUE;
  56. m_fAppearsSupervisor = FALSE;
  57. }
  58. else {
  59. err = (UINT)RegOpenKey(m_hkeyDB, pszUsername, &m_hkeyUser);
  60. if (err != ERROR_SUCCESS) {
  61. m_hkeyUser = NULL;
  62. m_fUserExists = FALSE;
  63. }
  64. else {
  65. DWORD cb = sizeof(m_fAppearsSupervisor);
  66. if (RegQueryValueEx(m_hkeyUser, ::szSupervisor, NULL, NULL,
  67. (LPBYTE)&m_fAppearsSupervisor, &cb) != ERROR_SUCCESS) {
  68. m_fAppearsSupervisor = FALSE;
  69. }
  70. DWORD cbDir = m_nlsDir.QueryAllocSize();
  71. LPBYTE pbDir = (LPBYTE)m_nlsDir.Party();
  72. err = RegQueryValueEx(m_hkeyUser, ::szProfileImagePath, NULL, NULL,
  73. pbDir, &cbDir);
  74. if (err != ERROR_SUCCESS)
  75. *pbDir = '\0';
  76. m_nlsDir.DonePartying();
  77. m_fUserExists = (err == ERROR_SUCCESS);
  78. }
  79. }
  80. return NOERROR;
  81. }
  82. STDMETHODIMP CLUUser::QueryInterface(REFIID riid, LPVOID * ppvObj)
  83. {
  84. if (!IsEqualIID(riid, IID_IUnknown) &&
  85. !IsEqualIID(riid, IID_IUser)) {
  86. *ppvObj = NULL;
  87. return ResultFromScode(E_NOINTERFACE);
  88. }
  89. *ppvObj = this;
  90. AddRef();
  91. return NOERROR;
  92. }
  93. STDMETHODIMP_(ULONG) CLUUser::AddRef(void)
  94. {
  95. return ++m_cRef;
  96. }
  97. STDMETHODIMP_(ULONG) CLUUser::Release(void)
  98. {
  99. ULONG cRef;
  100. cRef = --m_cRef;
  101. if (0L == m_cRef) {
  102. delete this;
  103. }
  104. return cRef;
  105. }
  106. STDMETHODIMP CLUUser::GetName(LPSTR pbBuffer, LPDWORD pcbBuffer)
  107. {
  108. if (m_nlsUsername.QueryError())
  109. return ResultFromScode(E_OUTOFMEMORY);
  110. UINT err = NPSCopyNLS(&m_nlsUsername, pbBuffer, pcbBuffer);
  111. return HRESULT_FROM_WIN32(err);
  112. }
  113. STDMETHODIMP CLUUser::GetProfileDirectory(LPSTR pbBuffer, LPDWORD pcbBuffer)
  114. {
  115. if (m_nlsDir.QueryError())
  116. return ResultFromScode(E_OUTOFMEMORY);
  117. if (!m_nlsDir.strlen())
  118. return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
  119. UINT err = NPSCopyNLS(&m_nlsDir, pbBuffer, pcbBuffer);
  120. return HRESULT_FROM_WIN32(err);
  121. }
  122. BOOL CLUUser::IsSystemCurrentUser(void)
  123. {
  124. NLS_STR nlsSystemUsername(MAX_PATH);
  125. if (nlsSystemUsername.QueryError() == ERROR_SUCCESS) {
  126. if (SUCCEEDED(GetSystemCurrentUser(&nlsSystemUsername)) &&
  127. !m_nlsUsername.stricmp(nlsSystemUsername)) {
  128. return TRUE;
  129. }
  130. }
  131. return FALSE;
  132. }
  133. HRESULT CLUUser::GetSupervisorPassword(BUFFER *pbufOut)
  134. {
  135. LPSTR pBuffer = (LPSTR)pbufOut->QueryPtr();
  136. if (!m_fAuthenticated) {
  137. if (IsSystemCurrentUser()) {
  138. WORD cbBuffer = (WORD)pbufOut->QuerySize();
  139. APIERR err = WNetGetCachedPassword((LPSTR)::szSupervisorPWLKey,
  140. (WORD)::strlenf(::szSupervisorPWLKey),
  141. pBuffer,
  142. &cbBuffer,
  143. PCE_MISC);
  144. if (err == ERROR_SUCCESS)
  145. return S_OK;
  146. if (err == WN_CANCEL)
  147. return S_FALSE;
  148. return HRESULT_FROM_WIN32(err);
  149. }
  150. return HRESULT_FROM_WIN32(ERROR_NOT_AUTHENTICATED);
  151. }
  152. HPWL hPWL;
  153. HRESULT hres = GetPasswordCache(m_nlsPassword.QueryPch(), &hPWL);
  154. if (FAILED(hres))
  155. return hres;
  156. APIERR err = FindCacheResource(hPWL, ::szSupervisorPWLKey,
  157. (WORD)::strlenf(::szSupervisorPWLKey),
  158. pBuffer,
  159. (WORD)pbufOut->QuerySize(),
  160. PCE_MISC);
  161. ::ClosePasswordCache(hPWL, TRUE);
  162. if (err == IERR_CacheEntryNotFound)
  163. return S_FALSE;
  164. else if (err != NOERROR)
  165. return HRESULT_FROM_WIN32(err);
  166. CACHE_ENTRY_INFO *pcei = (CACHE_ENTRY_INFO *)pBuffer;
  167. ::memmovef(pBuffer, pBuffer + pcei->dchPassword, pcei->cbPassword);
  168. return NOERROR;
  169. }
  170. STDMETHODIMP CLUUser::IsSupervisor(void)
  171. {
  172. /* If the supervisor password is blank, then everybody's a supervisor */
  173. if (::VerifySupervisorPassword(::szNULL) == S_OK)
  174. return S_OK;
  175. /* If temporary supervisor privilege has been granted to this user object,
  176. * honor it.
  177. */
  178. if (m_fTempSupervisor)
  179. return S_OK;
  180. BUFFER bufPCE(MAX_ENTRY_SIZE+2);
  181. if (bufPCE.QueryPtr() == NULL)
  182. return E_OUTOFMEMORY;
  183. HRESULT hres = GetSupervisorPassword(&bufPCE);
  184. if (hres != S_OK)
  185. return hres;
  186. return ::VerifySupervisorPassword((LPCSTR)bufPCE.QueryPtr());
  187. }
  188. APIERR MakeSupervisor(HPWL hPWL, LPCSTR pszSupervisorPassword)
  189. {
  190. #ifdef MSLOCUSR_USE_SUPERVISOR_PASSWORD
  191. return ::AddCacheResource(hPWL,
  192. ::szSupervisorPWLKey,
  193. ::strlenf(::szSupervisorPWLKey),
  194. pszSupervisorPassword,
  195. ::strlenf(pszSupervisorPassword)+1,
  196. PCE_MISC, 0);
  197. #else
  198. return ERROR_SUCCESS;
  199. #endif
  200. }
  201. STDMETHODIMP CLUUser::SetSupervisorPrivilege(BOOL fMakeSupervisor, LPCSTR pszSupervisorPassword)
  202. {
  203. if (m_pDB == NULL)
  204. return E_UNEXPECTED;
  205. #ifndef MSLOCUSR_USE_SUPERVISOR_PASSWORD
  206. /* Don't write stuff to the user's password cache if we're not doing any
  207. * supervisor password stuff.
  208. */
  209. m_fAppearsSupervisor = fMakeSupervisor;
  210. return S_OK;
  211. #else
  212. BUFFER bufPCE(MAX_ENTRY_SIZE+2);
  213. if (bufPCE.QueryPtr() == NULL)
  214. return E_OUTOFMEMORY;
  215. HRESULT hres = S_OK;
  216. /* If supervisor password is provided by the caller, use that, otherwise
  217. * inspect the current user's password cache.
  218. */
  219. if (pszSupervisorPassword == NULL) {
  220. IUser *pCurrentUser;
  221. if (FAILED(m_pDB->GetCurrentUser(&pCurrentUser)))
  222. return E_ACCESSDENIED;
  223. hres = ((CLUUser *)pCurrentUser)->GetSupervisorPassword(&bufPCE);
  224. pCurrentUser->Release();
  225. pszSupervisorPassword = (LPCSTR)bufPCE.QueryPtr();
  226. }
  227. if (SUCCEEDED(hres)) {
  228. hres = ::VerifySupervisorPassword(pszSupervisorPassword);
  229. if (hres == S_OK) { /* not SUCCEEDED because S_FALSE means wrong PW */
  230. HPWL hpwlThisUser;
  231. hres = GetPasswordCache(m_nlsPassword.QueryPch(), &hpwlThisUser);
  232. if (SUCCEEDED(hres)) {
  233. APIERR err;
  234. if (fMakeSupervisor)
  235. {
  236. err = ::MakeSupervisor(hpwlThisUser, pszSupervisorPassword);
  237. }
  238. else {
  239. err = ::DeleteCacheResource(hpwlThisUser,
  240. ::szSupervisorPWLKey,
  241. ::strlenf(::szSupervisorPWLKey),
  242. PCE_MISC);
  243. }
  244. ::ClosePasswordCache(hpwlThisUser, TRUE);
  245. hres = HRESULT_FROM_WIN32(err);
  246. }
  247. else if (!m_fAuthenticated && IsSystemCurrentUser()) {
  248. APIERR err;
  249. if (fMakeSupervisor) {
  250. err = ::WNetCachePassword(
  251. (LPSTR)::szSupervisorPWLKey,
  252. ::strlenf(::szSupervisorPWLKey),
  253. (LPSTR)pszSupervisorPassword,
  254. ::strlenf(pszSupervisorPassword)+1,
  255. PCE_MISC, 0);
  256. }
  257. else {
  258. err = ::WNetRemoveCachedPassword(
  259. (LPSTR)::szSupervisorPWLKey,
  260. ::strlenf(::szSupervisorPWLKey),
  261. PCE_MISC);
  262. }
  263. hres = HRESULT_FROM_WIN32(err);
  264. }
  265. if (SUCCEEDED(hres)) {
  266. m_fAppearsSupervisor = fMakeSupervisor;
  267. if (m_hkeyUser != NULL)
  268. RegSetValueEx(m_hkeyUser, ::szSupervisor, NULL,
  269. REG_DWORD, (LPBYTE)&m_fAppearsSupervisor,
  270. sizeof(m_fAppearsSupervisor));
  271. }
  272. }
  273. }
  274. return hres;
  275. #endif
  276. }
  277. STDMETHODIMP CLUUser::MakeTempSupervisor(BOOL fMakeSupervisor, LPCSTR pszSupervisorPassword)
  278. {
  279. if (!fMakeSupervisor)
  280. m_fTempSupervisor = FALSE;
  281. else {
  282. HRESULT hres = ::VerifySupervisorPassword(pszSupervisorPassword);
  283. if (hres == S_FALSE)
  284. hres = E_ACCESSDENIED;
  285. if (FAILED(hres))
  286. return hres;
  287. m_fTempSupervisor = TRUE;
  288. }
  289. return S_OK;
  290. }
  291. STDMETHODIMP CLUUser::AppearsSupervisor(void)
  292. {
  293. if (m_fTempSupervisor)
  294. return S_OK;
  295. return m_fAppearsSupervisor ? S_OK : S_FALSE;
  296. }
  297. STDMETHODIMP CLUUser::Authenticate(LPCSTR pszPassword)
  298. {
  299. HPWL hPWL = NULL;
  300. HRESULT hres = GetPasswordCache(pszPassword, &hPWL);
  301. if (FAILED(hres))
  302. return hres;
  303. ::ClosePasswordCache(hPWL, TRUE);
  304. return NOERROR;
  305. }
  306. STDMETHODIMP CLUUser::ChangePassword(LPCSTR pszOldPassword, LPCSTR pszNewPassword)
  307. {
  308. // if current user is supervisor, allow null pszOldPassword
  309. NLS_STR nlsNewPassword(pszNewPassword);
  310. if (nlsNewPassword.QueryError())
  311. return HRESULT_FROM_WIN32(nlsNewPassword.QueryError());
  312. nlsNewPassword.strupr();
  313. nlsNewPassword.ToOEM();
  314. HPWL hPWL;
  315. HRESULT hres = GetPasswordCache(pszOldPassword, &hPWL);
  316. if (FAILED(hres))
  317. return hres;
  318. hres = HRESULT_FROM_WIN32(::SetCachePassword(hPWL, nlsNewPassword.QueryPch()));
  319. if (SUCCEEDED(hres)) {
  320. m_nlsPassword = pszNewPassword; /* FEATURE - obfuscate me */
  321. m_fAuthenticated = TRUE;
  322. }
  323. ::ClosePasswordCache(hPWL, TRUE);
  324. return hres;
  325. }
  326. HRESULT GetUserPasswordCache(LPCSTR pszUsername, LPCSTR pszPassword, LPHANDLE phOut, BOOL fCreate)
  327. {
  328. NLS_STR nlsUsername(pszUsername);
  329. if (nlsUsername.QueryError())
  330. return HRESULT_FROM_WIN32(nlsUsername.QueryError());
  331. nlsUsername.strupr();
  332. nlsUsername.ToOEM();
  333. NLS_STR nlsPassword(pszPassword);
  334. if (nlsPassword.QueryError())
  335. return HRESULT_FROM_WIN32(nlsPassword.QueryError());
  336. nlsPassword.ToOEM();
  337. *phOut = NULL;
  338. UINT err = ::OpenPasswordCache(phOut, nlsUsername.QueryPch(), nlsPassword.QueryPch(), TRUE);
  339. if (fCreate &&
  340. (err == IERR_UsernameNotFound || err == ERROR_FILE_NOT_FOUND ||
  341. err == ERROR_PATH_NOT_FOUND)) {
  342. err = ::CreatePasswordCache(phOut, nlsUsername.QueryPch(), nlsPassword.QueryPch());
  343. }
  344. if (err == IERR_IncorrectUsername) {
  345. nlsPassword.ToAnsi(); /* must convert to OEM to uppercase properly */
  346. nlsPassword.strupr();
  347. nlsPassword.ToOEM();
  348. err = ::OpenPasswordCache(phOut, nlsUsername.QueryPch(), nlsPassword.QueryPch(), TRUE);
  349. }
  350. if (err)
  351. return HRESULT_FROM_WIN32(err);
  352. return S_OK;
  353. }
  354. STDMETHODIMP CLUUser::GetPasswordCache(LPCSTR pszPassword, LPHANDLE phOut)
  355. {
  356. HRESULT hres = ::GetUserPasswordCache(m_nlsUsername.QueryPch(), pszPassword,
  357. phOut, TRUE);
  358. if (FAILED(hres))
  359. return hres;
  360. m_nlsPassword = pszPassword; /* FEATURE - obfuscate me */
  361. m_fAuthenticated = TRUE;
  362. return NOERROR;
  363. }
  364. STDMETHODIMP CLUUser::LoadProfile(HKEY *phkeyUser)
  365. {
  366. if (IsSystemCurrentUser() ||
  367. !::strcmpf(m_nlsUsername.QueryPch(), ::szDefaultUserName)) {
  368. /* If he's the current or default user, his profile should be loaded
  369. * under HKEY_USERS. If it is, we can return that key. Otherwise,
  370. * we'll need to load it.
  371. */
  372. if (RegOpenKeyEx(HKEY_USERS, m_nlsUsername.QueryPch(), 0,
  373. KEY_READ | KEY_WRITE, phkeyUser) == ERROR_SUCCESS) {
  374. m_fLoadedProfile = FALSE;
  375. return S_OK;
  376. }
  377. }
  378. else {
  379. if (IsCurrentUserSupervisor(m_pDB) != S_OK)
  380. return E_ACCESSDENIED;
  381. }
  382. RegEntry reRoot(::szProfileList, HKEY_LOCAL_MACHINE);
  383. if (reRoot.GetError() != ERROR_SUCCESS)
  384. return HRESULT_FROM_WIN32(reRoot.GetError());
  385. reRoot.MoveToSubKey(m_nlsUsername.QueryPch());
  386. if (reRoot.GetError() != ERROR_SUCCESS)
  387. return HRESULT_FROM_WIN32(reRoot.GetError());
  388. NLS_STR nlsProfilePath(MAX_PATH);
  389. if (nlsProfilePath.QueryError() != ERROR_SUCCESS)
  390. return E_OUTOFMEMORY;
  391. reRoot.GetValue(::szProfileImagePath, &nlsProfilePath);
  392. if (reRoot.GetError() != ERROR_SUCCESS)
  393. return HRESULT_FROM_WIN32(reRoot.GetError());
  394. AddBackslash(nlsProfilePath);
  395. nlsProfilePath.strcat(::szStdNormalProfile);
  396. if (!FileExists(nlsProfilePath.QueryPch()))
  397. return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  398. LONG err = ::MyRegLoadKey(HKEY_USERS, m_nlsUsername.QueryPch(), nlsProfilePath.QueryPch());
  399. if (err == ERROR_SUCCESS) {
  400. HKEY hkeyNewProfile;
  401. err = ::RegOpenKey(HKEY_USERS, m_nlsUsername.QueryPch(), phkeyUser);
  402. if (err != ERROR_SUCCESS) {
  403. ::RegUnLoadKey(HKEY_USERS, m_nlsUsername.QueryPch());
  404. }
  405. else {
  406. m_fLoadedProfile = TRUE;
  407. }
  408. }
  409. return HRESULT_FROM_WIN32(err);
  410. }
  411. STDMETHODIMP CLUUser::UnloadProfile(HKEY hkeyUser)
  412. {
  413. RegFlushKey(hkeyUser);
  414. RegCloseKey(hkeyUser);
  415. if (m_fLoadedProfile) {
  416. RegUnLoadKey(HKEY_USERS, m_nlsUsername.QueryPch());
  417. m_fLoadedProfile = FALSE;
  418. }
  419. return S_OK;
  420. }
  421. STDMETHODIMP CLUUser::GetComponentSettings(REFCLSID clsidComponent,
  422. LPCSTR pszName, IUnknown **ppOut,
  423. DWORD fdwAccess)
  424. {
  425. return ResultFromScode(E_NOTIMPL);
  426. }
  427. STDMETHODIMP CLUUser::EnumerateComponentSettings(IEnumUnknown **ppOut,
  428. DWORD fdwAccess)
  429. {
  430. return ResultFromScode(E_NOTIMPL);
  431. }