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.

253 lines
8.5 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: Impersonation.cpp
  3. //
  4. // Copyright (c) 1999-2000, Microsoft Corporation
  5. //
  6. // Classes that handle state preservation, changing and restoration.
  7. //
  8. // History: 1999-08-18 vtan created
  9. // 1999-11-16 vtan separate file
  10. // 2000-02-01 vtan moved from Neptune to Whistler
  11. // --------------------------------------------------------------------------
  12. #include "StandardHeader.h"
  13. #include "Impersonation.h"
  14. #include "Access.h"
  15. #include "SingleThreadedExecution.h"
  16. #include "TokenInformation.h"
  17. // --------------------------------------------------------------------------
  18. // CImpersonation::s_pMutex
  19. // CImpersonation::s_iReferenceCount
  20. //
  21. // Purpose: Static member variables that control access to the global
  22. // reference count which controls calling
  23. // kernel32!OpenProfileUserMapping which is a global entity in
  24. // kernel32.dll.
  25. // --------------------------------------------------------------------------
  26. CMutex* CImpersonation::s_pMutex = NULL;
  27. int CImpersonation::s_iReferenceCount = -1;
  28. // --------------------------------------------------------------------------
  29. // CImpersonation::CImpersonation
  30. //
  31. // Arguments: hToken = User token to impersonate.
  32. //
  33. // Returns: <none>
  34. //
  35. // Purpose: Causes the current thread to impersonate the given user for
  36. // scope of the object. See advapi32!ImpersonateLoggedOnUser for
  37. // more information on the token requirements. If the thread is
  38. // already impersonating a debug warning is issued and the
  39. // request is ignored.
  40. //
  41. // History: 1999-08-23 vtan created
  42. // --------------------------------------------------------------------------
  43. CImpersonation::CImpersonation (HANDLE hToken) :
  44. _status(STATUS_UNSUCCESSFUL),
  45. _fAlreadyImpersonating(false)
  46. {
  47. HANDLE hImpersonationToken;
  48. ASSERTMSG(s_iReferenceCount >= 0, "Negative reference count in CImpersonation::CImpersonation");
  49. _fAlreadyImpersonating = (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hImpersonationToken) != FALSE);
  50. if (_fAlreadyImpersonating)
  51. {
  52. TBOOL(CloseHandle(hImpersonationToken));
  53. WARNINGMSG("Thread is already impersonating a user in CImpersonation::CImpersonation");
  54. }
  55. else
  56. {
  57. _status = ImpersonateUser(GetCurrentThread(), hToken);
  58. {
  59. CSingleThreadedMutexExecution execution(*s_pMutex);
  60. // Acquire the s_pMutex mutex before using the reference count.
  61. // Control the reference count so that we only call
  62. // kernel32!OpenProfileUserMapping for a single impersonation
  63. // session. Calling kernel32!CloseProfileUserMapping will
  64. // destroy kernel32.dll's global HKEY to the current user.
  65. if (s_iReferenceCount++ == 0)
  66. {
  67. TBOOL(OpenProfileUserMapping());
  68. }
  69. }
  70. }
  71. }
  72. // --------------------------------------------------------------------------
  73. // CImpersonation::~CImpersonation
  74. //
  75. // Arguments: <none>
  76. //
  77. // Returns: <none>
  78. //
  79. // Purpose: Reverts to the self token for the thread on the object going
  80. // out of scope.
  81. //
  82. // History: 1999-08-23 vtan created
  83. // --------------------------------------------------------------------------
  84. CImpersonation::~CImpersonation (void)
  85. {
  86. if (!_fAlreadyImpersonating)
  87. {
  88. {
  89. CSingleThreadedMutexExecution execution(*s_pMutex);
  90. // When the reference count hits zero - close the mapping.
  91. if (--s_iReferenceCount == 0)
  92. {
  93. TBOOL(CloseProfileUserMapping());
  94. }
  95. }
  96. TBOOL(RevertToSelf());
  97. }
  98. }
  99. // --------------------------------------------------------------------------
  100. // CImpersonation::IsImpersonating
  101. //
  102. // Arguments: <none>
  103. //
  104. // Returns: bool
  105. //
  106. // Purpose: Returns whether the constructor successfully completed
  107. // impersonating the user.
  108. //
  109. // History: 2001-01-18 vtan created
  110. // --------------------------------------------------------------------------
  111. bool CImpersonation::IsImpersonating (void) const
  112. {
  113. return(NT_SUCCESS(_status));
  114. }
  115. // --------------------------------------------------------------------------
  116. // CImpersonation::ImpersonateUser
  117. //
  118. // Arguments: hThread = HANDLE to the thread that will impersonate.
  119. // hToken = Token of user to impersonate.
  120. //
  121. // Returns: NTSTATUS
  122. //
  123. // Purpose: Duplicate the given token as an impersonation token. ACL the
  124. // new token and set it into the thread token.
  125. //
  126. // History: 1999-11-09 vtan created
  127. // --------------------------------------------------------------------------
  128. NTSTATUS CImpersonation::ImpersonateUser (HANDLE hThread, HANDLE hToken)
  129. {
  130. NTSTATUS status;
  131. HANDLE hImpersonationToken;
  132. OBJECT_ATTRIBUTES objectAttributes;
  133. SECURITY_QUALITY_OF_SERVICE securityQualityOfService;
  134. InitializeObjectAttributes(&objectAttributes,
  135. NULL,
  136. OBJ_INHERIT,
  137. NULL,
  138. NULL);
  139. securityQualityOfService.Length = sizeof(securityQualityOfService);
  140. securityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  141. securityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  142. securityQualityOfService.EffectiveOnly = FALSE;
  143. objectAttributes.SecurityQualityOfService = &securityQualityOfService;
  144. status = NtDuplicateToken(hToken,
  145. TOKEN_IMPERSONATE | TOKEN_QUERY | READ_CONTROL | WRITE_DAC,
  146. &objectAttributes,
  147. FALSE,
  148. TokenImpersonation,
  149. &hImpersonationToken);
  150. if (NT_SUCCESS(status))
  151. {
  152. PSID pLogonSID;
  153. CTokenInformation tokenInformation(hImpersonationToken);
  154. pLogonSID = tokenInformation.GetLogonSID();
  155. if (pLogonSID != NULL)
  156. {
  157. CSecuredObject tokenSecurity(hImpersonationToken, SE_KERNEL_OBJECT);
  158. TSTATUS(tokenSecurity.Allow(pLogonSID,
  159. TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | READ_CONTROL,
  160. 0));
  161. }
  162. status = NtSetInformationThread(hThread,
  163. ThreadImpersonationToken,
  164. &hImpersonationToken,
  165. sizeof(hImpersonationToken));
  166. TSTATUS(NtClose(hImpersonationToken));
  167. }
  168. return(status);
  169. }
  170. // --------------------------------------------------------------------------
  171. // CImpersonation::StaticInitialize
  172. //
  173. // Arguments: <none>
  174. //
  175. // Returns: NTSTATUS
  176. //
  177. // Purpose: Initializes the mutex object and the reference count. The
  178. // reference count is initialized to -1 by the compiler to help
  179. // detect cases where this function is not called!
  180. //
  181. // History: 1999-10-13 vtan created
  182. // 2000-12-06 vtan ignore create mutex failure
  183. // --------------------------------------------------------------------------
  184. NTSTATUS CImpersonation::StaticInitialize (void)
  185. {
  186. s_pMutex = new CMutex;
  187. if (s_pMutex != NULL)
  188. {
  189. (NTSTATUS)s_pMutex->Initialize(TEXT("Global\\winlogon: Logon UserProfileMapping Mutex"));
  190. }
  191. s_iReferenceCount = 0;
  192. return(STATUS_SUCCESS);
  193. }
  194. // --------------------------------------------------------------------------
  195. // CImpersonation::StaticTerminate
  196. //
  197. // Arguments: <none>
  198. //
  199. // Returns: NTSTATUS
  200. //
  201. // Purpose: Releases the mutex object.
  202. //
  203. // History: 1999-10-13 vtan created
  204. // --------------------------------------------------------------------------
  205. NTSTATUS CImpersonation::StaticTerminate (void)
  206. {
  207. NTSTATUS status;
  208. ASSERTMSG(s_iReferenceCount == 0, "Non zero reference count in CImpersonation::StaticTerminate");
  209. if (s_pMutex != NULL)
  210. {
  211. status = s_pMutex->Terminate();
  212. delete s_pMutex;
  213. s_pMutex = NULL;
  214. }
  215. else
  216. {
  217. status = STATUS_SUCCESS;
  218. }
  219. return(status);
  220. }