UserAcct.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. /////////////////////////////////////////////////////////////////////////////
  2. // UserAcct.cpp : Implementation of the TCUserAccount class.
  3. //
  4. #include "UserAcct.h"
  5. /////////////////////////////////////////////////////////////////////////////
  6. // Construction / Destruction
  7. HRESULT TCUserAccount::Init(LPCWSTR szUserName)
  8. {
  9. // Not supported under Windows9x
  10. if (IsWin9x())
  11. return S_FALSE;
  12. // Delete any previous user name
  13. m_spszUserName = NULL;
  14. // Delete any previous SID
  15. m_spSIDPrincipal = NULL;
  16. // Get the SID and domain name of the specified user
  17. RETURN_FAILED(GetSID(szUserName, &m_spSIDPrincipal, &m_spszDomainName));
  18. // Get a pointer to just the user name (no domain)
  19. LPCWSTR pszWhack = wcschr(szUserName, L'\\');
  20. LPCWSTR pszUserOnly = pszWhack ? pszWhack + 1 : szUserName;
  21. // Save the user name
  22. int cchUserName = wcslen(pszUserOnly) + 1;
  23. m_spszUserName = (LPWSTR)CoTaskMemAlloc(cchUserName * sizeof(WCHAR));
  24. wcscpy(m_spszUserName, pszUserOnly);
  25. // Get the server information of the local machine
  26. TCNetApiPtr<SERVER_INFO_101*> si101;
  27. DWORD dw = NetServerGetInfo(NULL, 101, (LPBYTE*)&si101);
  28. if (NERR_Success != dw)
  29. return HRESULT_FROM_WIN32(dw);
  30. // Declare and initialize an LSA_OBJECT_ATTRIBUTES structure
  31. LSA_OBJECT_ATTRIBUTES oa = {sizeof(oa)};
  32. // Special processing when the local computer is a backup domain controller
  33. TCNetApiPtr<WCHAR*> domainController;
  34. if (si101->sv101_type & SV_TYPE_DOMAIN_BAKCTRL)
  35. {
  36. // Get the server name of the primary domain controller
  37. TCNetApiPtr<USER_MODALS_INFO_2*> umi2;
  38. if (0 == (dw = NetUserModalsGet(NULL, 2, (LPBYTE*)&umi2)))
  39. {
  40. // Get the domain name of the primary domain controller
  41. NetGetDCName(NULL, umi2->usrmod2_domain_name, (LPBYTE*)&domainController);
  42. // Create an LSA_UNICODE_STRING for the name of the PDC
  43. LSA_UNICODE_STRING lsaPDC;
  44. lsaPDC.Length = (USHORT)((wcslen(domainController) * sizeof(WCHAR))-2);
  45. lsaPDC.MaximumLength = (USHORT)(lsaPDC.Length + sizeof(WCHAR));
  46. lsaPDC.Buffer = &domainController[2];
  47. // Open the policy of the primary domain controller
  48. RETURN_FAILED(LsaOpenPolicy(&lsaPDC, &oa,
  49. POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES, &m_hPolicy));
  50. }
  51. }
  52. // Open the policy of the local computer if not a BDC or if anything failed
  53. if (domainController.IsNull())
  54. {
  55. RETURN_FAILED(LsaOpenPolicy(NULL, &oa,
  56. POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES, &m_hPolicy));
  57. }
  58. // Indicate success
  59. return S_OK;
  60. }
  61. /////////////////////////////////////////////////////////////////////////////
  62. // Attributes
  63. // Security ID (SID) Lookup
  64. HRESULT TCUserAccount::GetSID(LPCWSTR szUserName, PSID* ppSID, LPWSTR* ppszDomain)
  65. {
  66. // Not supported under Windows9x
  67. if (IsWin9x())
  68. return S_FALSE;
  69. // Initialize the [out] parameters
  70. if (ppSID)
  71. *ppSID = NULL;
  72. if (ppszDomain)
  73. *ppszDomain = NULL;
  74. // Skip past "\" or ".\", if the specified name begins with that
  75. if (L'\\' == szUserName[0])
  76. szUserName += 1;
  77. else if (L'.' == szUserName[0] && L'\\' == szUserName[1])
  78. szUserName += 2;
  79. // Get the needed size of the buffers
  80. SID_NAME_USE eUse;
  81. DWORD cbSID = 0, cchDomain = 0;
  82. if (!LookupAccountNameW(NULL, szUserName, NULL, &cbSID, NULL, &cchDomain, &eUse))
  83. {
  84. DWORD dwLastError = GetLastError();
  85. if (ERROR_INSUFFICIENT_BUFFER != dwLastError)
  86. return HRESULT_FROM_WIN32(dwLastError);
  87. }
  88. // Allocate domain name buffer on the task allocation, since we return it
  89. DWORD cbDomain = cchDomain * sizeof(WCHAR);
  90. TCCoTaskPtr<WCHAR*> spszDomain = (WCHAR*)CoTaskMemAlloc(cbDomain);
  91. if (spszDomain.IsNull())
  92. return E_OUTOFMEMORY;
  93. // Allocate the SID buffer on the task allocator, since we return it
  94. TCCoTaskPtr<PSID> spSID = (PSID)CoTaskMemAlloc(cbSID);
  95. if (spSID.IsNull())
  96. return E_OUTOFMEMORY;
  97. // Lookup the account name
  98. if (!LookupAccountNameW(NULL, szUserName, spSID, &cbSID, spszDomain,
  99. &cchDomain, &eUse))
  100. return HRESULT_FROM_WIN32(GetLastError());
  101. // Copy the SID to the [out] parameter
  102. if (ppSID)
  103. *ppSID = spSID.Detach();
  104. // Copy the domain string to the [out] parameter
  105. if (ppszDomain)
  106. *ppszDomain = spszDomain.Detach();
  107. // Indicate success
  108. return S_OK;
  109. }
  110. // AppID Helpers
  111. HRESULT TCUserAccount::ResolveAppID(LPWSTR pszAppID, HKEY* phKey, REGSAM samDesired)
  112. {
  113. USES_CONVERSION;
  114. // Is the specified string a GUID string?
  115. GUID appid;
  116. HRESULT hr = CLSIDFromString(pszAppID, &appid);
  117. if (FAILED(hr))
  118. {
  119. // Is the specified string a ProgID?
  120. if (FAILED(hr = CLSIDFromProgID(pszAppID, &appid)))
  121. return hr;
  122. // Convert the ProgID's CLSID to a string
  123. _VERIFYE(StringFromGUID2(appid, pszAppID, 48));
  124. // Recursively call into ourself to resolve the CLSID string into an AppID
  125. return ResolveAppID(pszAppID, phKey, samDesired);
  126. }
  127. // Convert the AppID back to a string
  128. RETURN_FAILED(StringFromGUID2(appid, pszAppID, 48));
  129. // Format a string for the AppID's registry key
  130. TCHAR szKey[_MAX_PATH];
  131. _stprintf(szKey, TEXT("AppID\\%ls"), pszAppID);
  132. // Does the AppID exist in the registry?
  133. LONG lr;
  134. CRegKey key;
  135. if (ERROR_SUCCESS != (lr = key.Open(HKEY_CLASSES_ROOT, szKey, samDesired)))
  136. {
  137. // Format a string for the CLSID's registry key
  138. TCHAR szKey[_MAX_PATH];
  139. _stprintf(szKey, TEXT("CLSID\\%ls"), pszAppID);
  140. // Open the CLSID's registry key
  141. if (ERROR_SUCCESS != (lr = key.Open(HKEY_CLASSES_ROOT, szKey, samDesired)))
  142. return HRESULT_FROM_WIN32(lr);
  143. // Read the CLSID's AppID value
  144. TCHAR szAppID[48];
  145. DWORD cbData = sizeof(szAppID);
  146. if (ERROR_SUCCESS != (lr = RegQueryValueEx(key, TEXT("AppID"), 0, NULL,
  147. (BYTE*)szAppID, &cbData)))
  148. return HRESULT_FROM_WIN32(lr);
  149. // Copy the AppID String to the [in/out] parameter
  150. wcscpy(pszAppID, T2CW(szAppID));
  151. // Recursively call into ourself to resolve and verify the APPID string
  152. return ResolveAppID(pszAppID, phKey, samDesired);
  153. }
  154. // Detach the AppID key from the CRegKey object
  155. if (phKey)
  156. *phKey = key.Detach();
  157. // Indicate success
  158. return S_OK;
  159. }
  160. HRESULT TCUserAccount::HasRight(LPTSTR pszPrivilege) const
  161. {
  162. // Not supported under Windows9x
  163. if (IsWin9x())
  164. return S_FALSE;
  165. // Fail if Init has not been called successfully
  166. if (!m_hPolicy || m_spSIDPrincipal.IsNull())
  167. return E_UNEXPECTED;
  168. // Fail if the specified pointer is NULL
  169. if (!pszPrivilege)
  170. return E_POINTER;
  171. // Get the array of user rights
  172. PLSA_UNICODE_STRING pUserRights = NULL;
  173. ULONG cRights = 0;
  174. RETURN_FAILED(LsaEnumerateAccountRights(m_hPolicy, m_spSIDPrincipal,
  175. &pUserRights, &cRights));
  176. // Get a pointer to a UNICODE version of the specified privilege
  177. USES_CONVERSION;
  178. LPCWSTR pszWidePrivilege = T2CW(pszPrivilege);
  179. // Loop through the array of privileges
  180. for (ULONG i = 0; i < cRights; ++i)
  181. if (0 == _wcsicmp(pUserRights[i].Buffer, pszWidePrivilege))
  182. return S_OK;
  183. // Specified privilege wasnt' found
  184. return S_FALSE;
  185. }
  186. HRESULT TCUserAccount::SetRight(LPTSTR pszPrivilege)
  187. {
  188. // Not supported under Windows9x
  189. if (IsWin9x())
  190. return S_FALSE;
  191. // Fail if Init has not been called successfully
  192. if (!m_hPolicy || m_spSIDPrincipal.IsNull())
  193. return E_UNEXPECTED;
  194. // Fail if the specified pointer is NULL
  195. if (!pszPrivilege)
  196. return E_POINTER;
  197. // Get a pointer to a UNICODE version of the specified privilege
  198. USES_CONVERSION;
  199. LPWSTR pszWidePrivilege = T2W(pszPrivilege);
  200. // Create an LSA_UNICODE_STRING for the specified privilege name
  201. LSA_UNICODE_STRING lsaString;
  202. lsaString.Length = (USHORT)(wcslen(pszWidePrivilege) * sizeof(WCHAR));
  203. lsaString.MaximumLength = (USHORT)(lsaString.Length + sizeof(WCHAR));
  204. lsaString.Buffer = pszWidePrivilege;
  205. // Attempt to add the specified privilege to the current user
  206. RETURN_FAILED(LsaAddAccountRights(m_hPolicy, m_spSIDPrincipal,
  207. &lsaString, 1));
  208. // Indicate success
  209. return S_OK;
  210. }
  211. HRESULT TCUserAccount::RemoveRight(LPTSTR pszPrivilege)
  212. {
  213. // Not supported under Windows9x
  214. if (IsWin9x())
  215. return S_FALSE;
  216. // Fail if Init has not been called successfully
  217. if (!m_hPolicy || m_spSIDPrincipal.IsNull())
  218. return E_UNEXPECTED;
  219. // Fail if the specified pointer is NULL
  220. if (!pszPrivilege)
  221. return E_POINTER;
  222. // Get a pointer to a UNICODE version of the specified privilege
  223. USES_CONVERSION;
  224. LPWSTR pszWidePrivilege = T2W(pszPrivilege);
  225. // Create an LSA_UNICODE_STRING for the specified privilege name
  226. LSA_UNICODE_STRING lsaString;
  227. lsaString.Length = (USHORT)(wcslen(pszWidePrivilege) * sizeof(WCHAR));
  228. lsaString.MaximumLength = (USHORT)(lsaString.Length + sizeof(WCHAR));
  229. lsaString.Buffer = pszWidePrivilege;
  230. // Attempt to remove the specified privilege from the current user
  231. RETURN_FAILED(LsaRemoveAccountRights(m_hPolicy, m_spSIDPrincipal, false,
  232. &lsaString, 1));
  233. // Indicate success
  234. return S_OK;
  235. }
  236. HRESULT TCUserAccount::SetRunAsInteractiveUser(LPCTSTR szAppID)
  237. {
  238. // Not supported under Windows9x
  239. if (IsWin9x())
  240. return S_FALSE;
  241. // Copy the specified AppID string to a non-const wide string
  242. USES_CONVERSION;
  243. UINT cchAppID = max(_tcslen(szAppID), 48) + 1;
  244. LPWSTR pszAppID = (LPWSTR)_alloca(cchAppID * sizeof(WCHAR));
  245. wcscpy(pszAppID, T2CW(szAppID));
  246. // Resolve the specified string to an AppID
  247. HKEY hkey = NULL;
  248. RETURN_FAILED(ResolveAppID(pszAppID, &hkey));
  249. CRegKey key;
  250. key.Attach(hkey);
  251. // Set "Interactive User" as the RunAs user for the AppID
  252. LONG lr = key.SetValue(TEXT("Interactive User"), TEXT("RunAs"));
  253. if (lr)
  254. return HRESULT_FROM_WIN32(lr);
  255. // Indicate success
  256. return S_OK;
  257. }
  258. HRESULT TCUserAccount::SetRunAsUser(LPCTSTR szAppID, LPCTSTR szPassword)
  259. {
  260. // Not supported under Windows9x
  261. if (IsWin9x())
  262. return S_FALSE;
  263. // Fail if Init has not been called successfully
  264. if (!m_hPolicy || m_spSIDPrincipal.IsNull())
  265. return E_UNEXPECTED;
  266. // Concatenate the user name onto the domain name
  267. USES_CONVERSION;
  268. UINT cch = wcslen(m_spszDomainName) + wcslen(m_spszUserName) + 2;
  269. LPTSTR pszUserName = (LPTSTR)_alloca(cch * sizeof(TCHAR));
  270. _tcscpy(pszUserName, W2CT(m_spszDomainName));
  271. _tcscat(pszUserName, TEXT("\\"));
  272. _tcscat(pszUserName, W2CT(m_spszUserName));
  273. // Delegate to the static method
  274. return SetRunAsUser(szAppID, pszUserName, szPassword);
  275. }
  276. HRESULT TCUserAccount::SetRunAsUser(LPCTSTR szAppID, LPCTSTR szUserName, LPCTSTR szPassword)
  277. {
  278. // Not supported under Windows9x
  279. if (IsWin9x())
  280. return S_FALSE;
  281. // Copy the specified AppID string to a non-const wide string
  282. USES_CONVERSION;
  283. UINT cchAppID = max(_tcslen(szAppID), 48) + 1;
  284. LPWSTR pszAppID = (LPWSTR)_alloca(cchAppID * sizeof(WCHAR));
  285. wcscpy(pszAppID, T2CW(szAppID));
  286. // Resolve the specified string to an AppID
  287. HKEY hkey = NULL;
  288. RETURN_FAILED(ResolveAppID(pszAppID, &hkey));
  289. CRegKey key;
  290. key.Attach(hkey);
  291. // Ensure that we have a domain name
  292. LPCTSTR pszUserName = szUserName;
  293. LPCTSTR pszWhack = _tcschr(szUserName, TEXT('\\'));
  294. if (!pszWhack || pszWhack == szUserName ||
  295. (pszWhack == (szUserName + 1) && TEXT('.') == *szUserName))
  296. {
  297. // Get the domain name and user name
  298. TCCoTaskPtr<LPTSTR> spszDomainName;
  299. RETURN_FAILED(GetSID(szUserName, NULL, &spszDomainName));
  300. LPCTSTR pszUserOnly = pszWhack ? pszWhack + 1 : szUserName;
  301. // Concatenate the user name onto the domain name
  302. UINT cch = _tcslen(spszDomainName) + _tcslen(pszUserOnly) + 2;
  303. LPTSTR pszUserNameTemp = (LPTSTR)_alloca(cch * sizeof(TCHAR));
  304. _tcscpy(pszUserNameTemp, spszDomainName);
  305. _tcscat(pszUserNameTemp, TEXT("\\"));
  306. _tcscat(pszUserNameTemp, pszUserOnly);
  307. pszUserName = pszUserNameTemp;
  308. }
  309. // Open the local security policy
  310. TCLsaHandle hPolicy;
  311. LSA_OBJECT_ATTRIBUTES oa = {sizeof(oa)};
  312. RETURN_FAILED(LsaOpenPolicy(NULL, &oa, POLICY_CREATE_SECRET, &hPolicy));
  313. // Format the key string
  314. WCHAR szKey[48] = L"SCM:";
  315. wcscat(szKey, pszAppID);
  316. // Create an LSA_UNICODE_STRING for the key name
  317. LSA_UNICODE_STRING lsaKeyString;
  318. lsaKeyString.Length = (wcslen(szKey) + 1) * sizeof(WCHAR);
  319. lsaKeyString.MaximumLength = lsaKeyString.Length;
  320. lsaKeyString.Buffer = szKey;
  321. // Copy the specified password string to a non-const wide string
  322. UINT cchPassword = _tcslen(szPassword);
  323. LPWSTR pszPassword = (LPWSTR)_alloca((cchPassword + 1) * sizeof(WCHAR));
  324. wcscpy(pszPassword, T2CW(szPassword));
  325. // Create an LSA_UNICODE_STRING for the password string
  326. LSA_UNICODE_STRING lsaPasswordString;
  327. lsaPasswordString.Length = (cchPassword + 1) * sizeof(WCHAR);
  328. lsaPasswordString.MaximumLength = lsaPasswordString.Length;
  329. lsaPasswordString.Buffer = pszPassword;
  330. // Store the specified password
  331. RETURN_FAILED(LsaStorePrivateData(hPolicy, &lsaKeyString,
  332. &lsaPasswordString));
  333. // Set the specified user name as the RunAs user for the AppID
  334. LONG lr = key.SetValue(pszUserName, TEXT("RunAs"));
  335. if (lr)
  336. return HRESULT_FROM_WIN32(lr);
  337. // Indicate success
  338. return S_OK;
  339. }