Leaked source code of windows server 2003
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.

757 lines
17 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Abstract:
  4. @doc
  5. @module security.cxx | Implementation of IsAdministrator
  6. @end
  7. Author:
  8. Adi Oltean [aoltean] 07/09/1999
  9. TBD:
  10. Add comments.
  11. Revision History:
  12. Name Date Comments
  13. aoltean 07/09/1999 Created
  14. aoltean 08/26/1999 Adding RegisterProvider
  15. aoltean 08/26/1999 Adding UnregisterProvider
  16. aoltean 08/27/1999 Adding IsAdministrator,
  17. Adding unique provider name test.
  18. aoltean 08/30/1999 Calling OnUnregister on un-registering
  19. Improving IsProviderNameAlreadyUsed.
  20. aoltean 09/09/1999 dss -> vss
  21. aoltean 09/21/1999 Adding a new header for the "ptr" class.
  22. aoltean 09/27/1999 Adding new headers
  23. aoltean 10/15/1999 Moving declaration in security.hxx
  24. aoltean 01/18/2000 Moved into a separate directory
  25. brianb 04/04/2000 Add IsBackupOperator
  26. brianb 04/27/2000 Change IsBackupOperator to check SE_BACKUP_NAME privilege
  27. brianb 05/03/2000 Added GetClientTokenOwner method
  28. brianb 05/10/2000 fix problem with uninitialized variable
  29. brianb 05/12/2000 handle in proc case for impersonation failures
  30. --*/
  31. /////////////////////////////////////////////////////////////////////////////
  32. // Includes
  33. #include "stdafx.hxx"
  34. #include "vs_inc.hxx"
  35. #include "vs_sec.hxx"
  36. #include "vssmsg.h"
  37. ////////////////////////////////////////////////////////////////////////
  38. // Standard foo for file name aliasing. This code block must be after
  39. // all includes of VSS header files.
  40. //
  41. #ifdef VSS_FILE_ALIAS
  42. #undef VSS_FILE_ALIAS
  43. #endif
  44. #define VSS_FILE_ALIAS "SECSECRC"
  45. //
  46. ////////////////////////////////////////////////////////////////////////
  47. BOOL DoImpersonate
  48. (
  49. BOOL bImpersonate,
  50. HANDLE *phToken
  51. )
  52. {
  53. CVssFunctionTracer ft(VSSDBG_GEN, L"DoImpersonate");
  54. if (bImpersonate)
  55. {
  56. // Impersonate the client to get its identity access token.
  57. // The client should not have RPC_C_IMP_LEVEL_ANONYMOUS otherwise an error will be returned
  58. ft.hr = ::CoImpersonateClient();
  59. if (ft.hr == RPC_E_CALL_COMPLETE)
  60. {
  61. // this means that the call came from the same thread
  62. // do not do impersonation. Just use the process
  63. // token
  64. bImpersonate = false;
  65. ft.hr = S_OK;
  66. }
  67. else
  68. {
  69. BOOL bRes;
  70. ft.CheckForError(VSSDBG_GEN, L"CoImpersonateClient");
  71. // Get the Access Token of the client calling process in order to establish the client identity
  72. CVssAutoWin32Handle hThread = ::GetCurrentThread(); // CloseHandle have no effect here
  73. bRes = ::OpenThreadToken
  74. (
  75. hThread, // IN HANDLE ThreadHandle,
  76. TOKEN_QUERY, // IN DWORD DesiredAccess,
  77. TRUE, // IN BOOL OpenAsSelf (TRUE means not the client calling thread's access token)
  78. phToken // OUT PHANDLE TokenHandle
  79. );
  80. DWORD dwErr = GetLastError();
  81. // Revert the thread's access token - finish the impersonation
  82. ft.hr = ::CoRevertToSelf();
  83. ft.CheckForError(VSSDBG_GEN, L"CoRevertToSelf");
  84. if (!bRes)
  85. ft.TranslateError
  86. (
  87. VSSDBG_GEN,
  88. HRESULT_FROM_WIN32(dwErr),
  89. L"OpenThreadToken"
  90. );
  91. }
  92. }
  93. // note that the previous if statement may change the value
  94. // of bImpersonate. This is why we can't just put this in an
  95. // else clause
  96. if (!bImpersonate)
  97. {
  98. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY,phToken))
  99. ft.TranslateError
  100. (
  101. VSSDBG_GEN,
  102. HRESULT_FROM_WIN32(GetLastError()),
  103. L"OpenProcessToken"
  104. );
  105. }
  106. return bImpersonate;
  107. }
  108. bool IsInGroup(DWORD dwGroup, bool bImpersonate)
  109. /*++
  110. Routine Description:
  111. Return TRUE if the current thread/process is running under the context of an administrator
  112. Arguments:
  113. none
  114. Remarks:
  115. The current impersonation thread is asked for the access token.
  116. After that we check if the specified group is between token groups.
  117. Return Value:
  118. true, if the caller thread is running under the context of the specified group
  119. false, otherwise
  120. Thrown exceptions:
  121. E_UNEXPECTED // Runtime error
  122. E_OUTOFMEMORY // Memory allocation error
  123. --*/
  124. {
  125. CVssFunctionTracer ft( VSSDBG_GEN, L"IsInGroup" );
  126. BOOL bIsInGroup = FALSE;
  127. PSID psidGroup = NULL;
  128. BOOL bRes;
  129. // Reset the error code
  130. ft.hr = S_OK;
  131. // Build the SID for the Administrators group
  132. SID_IDENTIFIER_AUTHORITY SidAuth = SECURITY_NT_AUTHORITY;
  133. bRes = AllocateAndInitializeSid
  134. (
  135. &SidAuth, // IN PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
  136. 2, // IN BYTE nSubAuthorityCount,
  137. SECURITY_BUILTIN_DOMAIN_RID, // IN DWORD nSubAuthority0,
  138. dwGroup, // IN DWORD nSubAuthority1,
  139. 0, // IN DWORD nSubAuthority2,
  140. 0, // IN DWORD nSubAuthority3,
  141. 0, // IN DWORD nSubAuthority4,
  142. 0, // IN DWORD nSubAuthority5,
  143. 0, // IN DWORD nSubAuthority6,
  144. 0, // IN DWORD nSubAuthority7,
  145. &psidGroup // OUT PSID *pSid
  146. );
  147. if (!bRes)
  148. ft.TranslateError
  149. (
  150. VSSDBG_GEN,
  151. HRESULT_FROM_WIN32(GetLastError()),
  152. L"AllocateAndInitializeSid"
  153. );
  154. try
  155. {
  156. if (!bImpersonate)
  157. bRes = CheckTokenMembership(NULL, psidGroup, &bIsInGroup);
  158. else
  159. {
  160. CVssAutoWin32Handle hToken;
  161. // impersonate client (or get process token)
  162. if (DoImpersonate(true, hToken.ResetAndGetAddress()))
  163. // check token membership
  164. bRes = CheckTokenMembership(hToken, psidGroup, &bIsInGroup);
  165. else
  166. // called from same thread
  167. bRes = CheckTokenMembership(NULL, psidGroup, &bIsInGroup);
  168. }
  169. if (!bRes)
  170. ft.TranslateError
  171. (
  172. VSSDBG_GEN,
  173. HRESULT_FROM_WIN32(GetLastError()),
  174. L"CheckTokenMembership"
  175. );
  176. }
  177. VSS_STANDARD_CATCH(ft)
  178. HRESULT hr = ft.hr;
  179. // Catch possible AVs
  180. try
  181. {
  182. // Free the previously allocated SID
  183. if (psidGroup)
  184. ::FreeSid( psidGroup );
  185. }
  186. VSS_STANDARD_CATCH(ft)
  187. // Pass down the exception, if any
  188. if (FAILED(hr))
  189. throw(hr);
  190. return bIsInGroup ? true : false;
  191. }
  192. bool HasPrivilege(LPWSTR wszPriv, bool bImpersonate)
  193. /*++
  194. Routine Description:
  195. Return TRUE if the current thread/process has a specific privilege
  196. Arguments:
  197. none
  198. Remarks:
  199. The current impersonation thread is asked for the access token.
  200. After that we check if the specified group is between token groups.
  201. Return Value:
  202. true, if the caller thread is running under the context of the specified group
  203. false, otherwise
  204. Thrown exceptions:
  205. E_UNEXPECTED // Runtime error
  206. E_OUTOFMEMORY // Memory allocation error
  207. --*/
  208. {
  209. CVssFunctionTracer ft( VSSDBG_GEN, L"HasPrivilege" );
  210. BOOL bHasPrivilege = false;
  211. CVssAutoWin32Handle hToken;
  212. LUID TokenValue;
  213. if (!LookupPrivilegeValue (NULL, wszPriv, &TokenValue))
  214. ft.TranslateError
  215. (
  216. VSSDBG_GEN,
  217. HRESULT_FROM_WIN32(GetLastError()),
  218. L"LookupPrivilegeValue"
  219. );
  220. DoImpersonate(bImpersonate, hToken.ResetAndGetAddress());
  221. BYTE rgb[sizeof(LUID_AND_ATTRIBUTES) + sizeof(PRIVILEGE_SET)];
  222. PRIVILEGE_SET *pSet = (PRIVILEGE_SET *) rgb;
  223. pSet->PrivilegeCount = 1;
  224. pSet->Control = PRIVILEGE_SET_ALL_NECESSARY;
  225. pSet->Privilege[0].Luid = TokenValue;
  226. pSet->Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
  227. if (!PrivilegeCheck(hToken, pSet, &bHasPrivilege))
  228. ft.TranslateError
  229. (
  230. VSSDBG_GEN,
  231. HRESULT_FROM_WIN32(GetLastError()),
  232. L"PrivilegeCheck"
  233. );
  234. return bHasPrivilege ? true : false;
  235. }
  236. TOKEN_OWNER *GetClientTokenOwner(BOOL bImpersonate)
  237. /*++
  238. Routine Description:
  239. Return TOKEN_OWNER of client process
  240. Arguments:
  241. none
  242. Remarks:
  243. The current impersonation thread is asked for the access token.
  244. After that we return the client sid of that token
  245. Return Value:
  246. SID of client thread
  247. Thrown exceptions:
  248. E_UNEXPECTED // Runtime error
  249. E_OUTOFMEMORY // Memory allocation error
  250. --*/
  251. {
  252. CVssFunctionTracer ft( VSSDBG_GEN, L"GetClientTokenOwner" );
  253. BOOL bRes;
  254. CVssAutoWin32Handle hToken;
  255. DoImpersonate(bImpersonate, hToken.ResetAndGetAddress());
  256. DWORD cbSid;
  257. bRes = ::GetTokenInformation
  258. (
  259. hToken, // IN HANDLE TokenHandle,
  260. TokenOwner, // IN TOKEN_INFORMATION_CLASS TokenInformationClass,
  261. NULL, // OUT LPVOID TokenInformation,
  262. 0, // IN DWORD TokenInformationLength,
  263. &cbSid // OUT PDWORD ReturnLength
  264. );
  265. BS_ASSERT( bRes == FALSE );
  266. DWORD dwError = GetLastError();
  267. if ( dwError != ERROR_INSUFFICIENT_BUFFER )
  268. {
  269. ft.LogError(VSS_ERROR_EXPECTED_INSUFFICENT_BUFFER, VSSDBG_GEN << (HRESULT) dwError);
  270. ft.Throw
  271. (
  272. VSSDBG_GEN,
  273. E_UNEXPECTED,
  274. L"ERROR_INSUFFICIENT_BUFFER expected error . [0x%08lx]",
  275. dwError
  276. );
  277. }
  278. // Allocate the buffer needed to get the Token Groups information
  279. TOKEN_OWNER *pToken = (TOKEN_OWNER*) new BYTE[cbSid];
  280. if (pToken == NULL)
  281. ft.Throw(VSSDBG_GEN, E_OUTOFMEMORY, L"Memory allocation error.");
  282. // Get the all Group SIDs in the token
  283. DWORD cbTokenObtained;
  284. bRes = ::GetTokenInformation
  285. (
  286. hToken, // IN HANDLE TokenHandle,
  287. TokenOwner, // IN TOKEN_INFORMATION_CLASS TokenInformationClass,
  288. pToken, // OUT LPVOID TokenInformation,
  289. cbSid, // IN DWORD TokenInformationLength,
  290. &cbTokenObtained // OUT PDWORD ReturnLength
  291. );
  292. if ( !bRes )
  293. ft.TranslateError
  294. (
  295. VSSDBG_GEN,
  296. HRESULT_FROM_WIN32(GetLastError()),
  297. L"GetTokenInformation"
  298. );
  299. if (cbTokenObtained != cbSid)
  300. {
  301. ft.LogError(VSS_ERROR_GET_TOKEN_INFORMATION_BUFFER_SIZE_MISMATCH, VSSDBG_GEN << (INT) cbTokenObtained << (INT) cbSid);
  302. ft.Throw
  303. (
  304. VSSDBG_GEN,
  305. E_UNEXPECTED,
  306. L"Unexpected error. Final buffer size = %lu, original size was %lu",
  307. cbTokenObtained,
  308. cbSid
  309. );
  310. }
  311. return pToken;
  312. }
  313. bool IsAdministrator()
  314. /*++
  315. Routine Description:
  316. Return TRUE if the current thread/process is running under the context of an administrator
  317. Arguments:
  318. none
  319. Remarks:
  320. The current impersonation thread is asked for the access token.
  321. After that we check if the Administrators group is between token groups.
  322. Return Value:
  323. true, if the caller thread is running under the context of an administrator
  324. false, otherwise
  325. Thrown exceptions:
  326. E_UNEXPECTED // Runtime error
  327. E_OUTOFMEMORY // Memory allocation error
  328. --*/
  329. {
  330. return IsInGroup(DOMAIN_ALIAS_RID_ADMINS, true);
  331. }
  332. bool IsProcessAdministrator()
  333. /*++
  334. Routine Description:
  335. Return TRUE if the current process is running under the context of an administrator
  336. Arguments:
  337. none
  338. Remarks:
  339. The current process is asked for the access token.
  340. After that we check if the Administrators group is between token groups.
  341. Return Value:
  342. true, if the process is running under the context of an administrator
  343. false, otherwise
  344. Thrown exceptions:
  345. E_UNEXPECTED // Runtime error
  346. E_OUTOFMEMORY // Memory allocation error
  347. --*/
  348. {
  349. return IsInGroup(DOMAIN_ALIAS_RID_ADMINS, false);
  350. }
  351. bool IsBackupOperator()
  352. /*++
  353. Routine Description:
  354. Return TRUE if the current thread/process is running under the context of a backup operator
  355. Arguments:
  356. none
  357. Remarks:
  358. The current impersonation thread is asked for the access token.
  359. After that we check if the Administrators group is in the groups token
  360. or the backup privilege is enabled
  361. Return Value:
  362. true, if the caller thread is running under the context of an administrator
  363. false, otherwise
  364. Thrown exceptions:
  365. E_UNEXPECTED // Runtime error
  366. E_OUTOFMEMORY // Memory allocation error
  367. --*/
  368. {
  369. return HasPrivilege(SE_BACKUP_NAME, true) || IsAdministrator();
  370. }
  371. bool IsRestoreOperator()
  372. /*++
  373. Routine Description:
  374. Return TRUE if the current thread/process is running under the context of a restore operator
  375. Arguments:
  376. none
  377. Remarks:
  378. The current impersonation thread is asked for the access token.
  379. After that we check if the Administrators group is in the token groups or
  380. if the restore privilege is enabled.
  381. Return Value:
  382. true, if the caller thread is running under the context of an administrator
  383. false, otherwise
  384. Thrown exceptions:
  385. E_UNEXPECTED // Runtime error
  386. E_OUTOFMEMORY // Memory allocation error
  387. --*/
  388. {
  389. return HasPrivilege(SE_RESTORE_NAME, true) || IsAdministrator();
  390. }
  391. bool IsProcessBackupOperator()
  392. /*++
  393. Routine Description:
  394. Return TRUE if the current process is running under the context of a backup operator
  395. Arguments:
  396. none
  397. Remarks:
  398. Return Value:
  399. true, if the process is running under the context of an administrator or
  400. has SE_BACKUP_NAME privilege enabled
  401. false, otherwise
  402. Thrown exceptions:
  403. E_UNEXPECTED // Runtime error
  404. E_OUTOFMEMORY // Memory allocation error
  405. --*/
  406. {
  407. return HasPrivilege(SE_BACKUP_NAME, false) || IsProcessAdministrator();
  408. }
  409. bool IsProcessRestoreOperator()
  410. /*++
  411. Routine Description:
  412. Return TRUE if the current process is running under the context of a restore operator
  413. Arguments:
  414. none
  415. Remarks:
  416. Return Value:
  417. true, if the process is running under the context of an administrator
  418. or has the SE_RESTORE_NAME privilege; false otherwise
  419. Thrown exceptions:
  420. E_UNEXPECTED // Runtime error
  421. E_OUTOFMEMORY // Memory allocation error
  422. --*/
  423. {
  424. return HasPrivilege(SE_RESTORE_NAME, false) || IsProcessAdministrator();
  425. }
  426. // turn on a particular security privilege
  427. HRESULT TurnOnSecurityPrivilege(LPCWSTR wszPriv)
  428. /*++
  429. Routine Description:
  430. sets the specified privilege on the process token
  431. Arguments:
  432. none
  433. Remarks:
  434. Return Value:
  435. status code for operation
  436. Thrown exceptions:
  437. none
  438. --*/
  439. {
  440. HANDLE hProcessToken = INVALID_HANDLE_VALUE;
  441. BOOL bProcessTokenValid = FALSE;
  442. CVssFunctionTracer ft(VSSDBG_GEN, L"TurnOnSecurityPrivilege");
  443. try
  444. {
  445. LUID TokenValue = {0, 0};
  446. bProcessTokenValid = OpenProcessToken
  447. (
  448. GetCurrentProcess(),
  449. TOKEN_ADJUST_PRIVILEGES,
  450. &hProcessToken
  451. );
  452. if (!bProcessTokenValid)
  453. ft.TranslateError
  454. (
  455. VSSDBG_GEN,
  456. HRESULT_FROM_WIN32(GetLastError()),
  457. L"OpenProcessToken"
  458. );
  459. if (!LookupPrivilegeValue (NULL, wszPriv, &TokenValue))
  460. ft.TranslateError
  461. (
  462. VSSDBG_GEN,
  463. HRESULT_FROM_WIN32(GetLastError()),
  464. L"LookupPrivilegeValue"
  465. );
  466. TOKEN_PRIVILEGES NewTokenPrivileges;
  467. NewTokenPrivileges.PrivilegeCount = 1;
  468. NewTokenPrivileges.Privileges[0].Luid = TokenValue;
  469. NewTokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  470. // AdjustTokenPrivileges succeeds even the token isn't set
  471. SetLastError(ERROR_SUCCESS);
  472. AdjustTokenPrivileges
  473. (
  474. hProcessToken,
  475. FALSE,
  476. &NewTokenPrivileges,
  477. sizeof (NewTokenPrivileges),
  478. NULL,
  479. NULL
  480. );
  481. DWORD dwErr = GetLastError();
  482. if (dwErr != ERROR_SUCCESS)
  483. ft.TranslateError
  484. (
  485. VSSDBG_GEN,
  486. HRESULT_FROM_WIN32(GetLastError()),
  487. L"AdjustTokenPrivileges"
  488. );
  489. }
  490. VSS_STANDARD_CATCH(ft)
  491. if (bProcessTokenValid)
  492. CloseHandle (hProcessToken);
  493. return ft.hr;
  494. }
  495. // turn on backup security privilege
  496. HRESULT TurnOnSecurityPrivilegeBackup()
  497. {
  498. return TurnOnSecurityPrivilege(SE_BACKUP_NAME);
  499. }
  500. // turn on restore security privilege
  501. HRESULT TurnOnSecurityPrivilegeRestore()
  502. {
  503. return TurnOnSecurityPrivilege(SE_RESTORE_NAME);
  504. }
  505. // determine if the process is a local service
  506. bool IsProcessLocalService()
  507. {
  508. CVssFunctionTracer ft(VSSDBG_GEN, L"IsProcessLocalService");
  509. BYTE rgbSid[256];
  510. DWORD cbSid = sizeof(rgbSid);
  511. TOKEN_OWNER *pOwner = GetClientTokenOwner(FALSE);
  512. if (!CreateWellKnownSid(WinLocalServiceSid, NULL, (SID *) rgbSid, &cbSid))
  513. {
  514. ft.hr = HRESULT_FROM_WIN32(GetLastError());
  515. ft.CheckForError(VSSDBG_GEN, L"CreateWellKnownSid");
  516. }
  517. return EqualSid(pOwner->Owner, (SID *) rgbSid) ? true : false;
  518. }
  519. // determine if the process is a local service
  520. bool IsProcessNetworkService()
  521. {
  522. CVssFunctionTracer ft(VSSDBG_GEN, L"IsProcessNetworkService");
  523. BYTE rgbSid[256];
  524. TOKEN_OWNER *pOwner = GetClientTokenOwner(FALSE);
  525. DWORD cbSid = sizeof(rgbSid);
  526. if (!CreateWellKnownSid(WinNetworkServiceSid, NULL, (SID *) rgbSid, &cbSid))
  527. {
  528. ft.hr = HRESULT_FROM_WIN32(GetLastError());
  529. ft.CheckForError(VSSDBG_GEN, L"CreateWellKnownSid");
  530. }
  531. return EqualSid(pOwner->Owner, (SID *) rgbSid) ? true : false;
  532. }