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.

438 lines
13 KiB

  1. /*************************************************************************
  2. *
  3. * secutil.c
  4. *
  5. * Security Related utility functions
  6. *
  7. * copyright notice: Copyright 1998, Microsoft.
  8. *
  9. *
  10. *
  11. *************************************************************************/
  12. // Include NT headers
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <ntseapi.h>
  17. #include "windows.h"
  18. #include <winsta.h>
  19. #include <syslib.h>
  20. /*****************************************************************************
  21. *
  22. * TestUserForAdmin
  23. *
  24. * Returns whether the current thread is running under admin
  25. * security.
  26. *
  27. * ENTRY:
  28. *
  29. * EXIT:
  30. * TRUE/FALSE - whether user is specified admin
  31. *
  32. ****************************************************************************/
  33. BOOL
  34. TestUserForAdmin( VOID )
  35. {
  36. BOOL IsMember, IsAnAdmin;
  37. SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY;
  38. PSID AdminSid;
  39. IsAnAdmin = FALSE;
  40. if (NT_SUCCESS(RtlAllocateAndInitializeSid(
  41. &SystemSidAuthority,
  42. 2,
  43. SECURITY_BUILTIN_DOMAIN_RID,
  44. DOMAIN_ALIAS_RID_ADMINS,
  45. 0, 0, 0, 0, 0, 0,
  46. &AdminSid
  47. ) ) )
  48. {
  49. CheckTokenMembership( NULL,
  50. AdminSid,
  51. &IsAnAdmin);
  52. RtlFreeSid(AdminSid);
  53. }
  54. return IsAnAdmin;
  55. }
  56. /*****************************************************************************
  57. *
  58. * TestUserForGroup
  59. *
  60. * Returns whether the current thread is a member of the requested group.
  61. *
  62. * ENTRY:
  63. * pwszGrouName (input)
  64. *
  65. * EXIT:
  66. * STATUS_SUCCESS - no error
  67. *
  68. ****************************************************************************/
  69. /* unused
  70. BOOL
  71. TestUserForGroup( PWCHAR pwszGroupName )
  72. {
  73. HANDLE Token;
  74. ULONG InfoLength;
  75. PTOKEN_GROUPS TokenGroupList;
  76. ULONG GroupIndex;
  77. BOOL GroupMember = FALSE;
  78. PSID pGroupSid = NULL;
  79. DWORD cbGroupSid = 0;
  80. NTSTATUS Status;
  81. PWCHAR pwszDomain = NULL;
  82. DWORD cbDomain = 0;
  83. SID_NAME_USE peUse;
  84. //
  85. // Open current thread/process token
  86. //
  87. Status = NtOpenThreadToken( NtCurrentThread(), TOKEN_QUERY, FALSE, &Token );
  88. if ( !NT_SUCCESS( Status ) ) {
  89. Status = NtOpenProcessToken( NtCurrentProcess(), TOKEN_QUERY, &Token );
  90. if ( !NT_SUCCESS( Status ) ) {
  91. return( FALSE );
  92. }
  93. }
  94. //
  95. // Retrieve the requested sid
  96. //
  97. if ( !LookupAccountNameW( NULL,
  98. pwszGroupName,
  99. pGroupSid,
  100. &cbGroupSid,
  101. pwszDomain,
  102. &cbDomain,
  103. &peUse ) ) {
  104. //
  105. // other eror
  106. //
  107. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) {
  108. NtClose(Token);
  109. return(FALSE);
  110. }
  111. //
  112. // alloc group sid
  113. //
  114. pGroupSid = LocalAlloc(LPTR, cbGroupSid);
  115. if (pGroupSid == NULL) {
  116. NtClose(Token);
  117. return(FALSE);
  118. }
  119. //
  120. // alloc domain name
  121. //
  122. cbDomain *= sizeof(WCHAR);
  123. pwszDomain = LocalAlloc(LPTR, cbDomain);
  124. if (pwszDomain == NULL) {
  125. LocalFree(pGroupSid);
  126. NtClose(Token);
  127. return(FALSE);
  128. }
  129. //
  130. // Retrieve the requested sid
  131. //
  132. if ( !LookupAccountNameW( NULL,
  133. pwszGroupName,
  134. pGroupSid,
  135. &cbGroupSid,
  136. pwszDomain,
  137. &cbDomain,
  138. &peUse ) ) {
  139. LocalFree(pGroupSid);
  140. LocalFree(pwszDomain);
  141. NtClose( Token );
  142. return( FALSE );
  143. }
  144. }
  145. else {
  146. #if DBG
  147. DbgPrint("***ERROR*** this path should never get hit\n");
  148. #endif
  149. NtClose( Token );
  150. return( FALSE );
  151. }
  152. ASSERT(pGroupSid != NULL);
  153. ASSERT(pwszDomain != NULL);
  154. //
  155. // Get a list of groups in the token
  156. //
  157. Status = NtQueryInformationToken(
  158. Token, // Handle
  159. TokenGroups, // TokenInformationClass
  160. NULL, // TokenInformation
  161. 0, // TokenInformationLength
  162. &InfoLength // ReturnLength
  163. );
  164. if ((Status != STATUS_SUCCESS) && (Status != STATUS_BUFFER_TOO_SMALL)) {
  165. LocalFree(pwszDomain);
  166. LocalFree(pGroupSid);
  167. NtClose(Token);
  168. return( FALSE );
  169. }
  170. TokenGroupList = LocalAlloc(LPTR, InfoLength);
  171. if (TokenGroupList == NULL) {
  172. LocalFree(pwszDomain);
  173. LocalFree(pGroupSid);
  174. NtClose(Token);
  175. return(FALSE);
  176. }
  177. Status = NtQueryInformationToken(
  178. Token, // Handle
  179. TokenGroups, // TokenInformationClass
  180. TokenGroupList, // TokenInformation
  181. InfoLength, // TokenInformationLength
  182. &InfoLength // ReturnLength
  183. );
  184. if (!NT_SUCCESS(Status)) {
  185. LocalFree(TokenGroupList);
  186. LocalFree(pwszDomain);
  187. LocalFree(pGroupSid);
  188. NtClose(Token);
  189. return(FALSE);
  190. }
  191. //
  192. // Search group list for membership
  193. //
  194. GroupMember = FALSE;
  195. for (GroupIndex=0; GroupIndex < TokenGroupList->GroupCount; GroupIndex++ ) {
  196. if (RtlEqualSid(TokenGroupList->Groups[GroupIndex].Sid, pGroupSid)) {
  197. GroupMember = TRUE;
  198. break;
  199. }
  200. }
  201. //
  202. // Tidy up
  203. //
  204. LocalFree(TokenGroupList);
  205. LocalFree(pwszDomain);
  206. LocalFree(pGroupSid);
  207. NtClose(Token);
  208. return(GroupMember);
  209. }
  210. */
  211. /***************************************************************************\
  212. * FUNCTION: CtxImpersonateUser
  213. *
  214. * PURPOSE: Impersonates the user by setting the users token
  215. * on the specified thread. If no thread is specified the token
  216. * is set on the current thread.
  217. *
  218. * RETURNS: Handle to be used on call to StopImpersonating() or NULL on failure
  219. * If a non-null thread handle was passed in, the handle returned will
  220. * be the one passed in. (See note)
  221. *
  222. * NOTES: Take care when passing in a thread handle and then calling
  223. * StopImpersonating() with the handle returned by this routine.
  224. * StopImpersonating() will close any thread handle passed to it -
  225. * even yours !
  226. *
  227. * HISTORY:
  228. *
  229. * 04-21-92 Davidc Created.
  230. * 12-18-96 cjc copied from \windows\gina\msgina\wlsec.c
  231. *
  232. \***************************************************************************/
  233. HANDLE
  234. CtxImpersonateUser(
  235. PCTX_USER_DATA UserData,
  236. HANDLE ThreadHandle
  237. )
  238. {
  239. NTSTATUS Status, IgnoreStatus;
  240. HANDLE UserToken = UserData->UserToken;
  241. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  242. OBJECT_ATTRIBUTES ObjectAttributes;
  243. HANDLE ImpersonationToken;
  244. BOOL ThreadHandleOpened = FALSE;
  245. if (ThreadHandle == NULL) {
  246. //
  247. // Get a handle to the current thread.
  248. // Once we have this handle, we can set the user's impersonation
  249. // token into the thread and remove it later even though we ARE
  250. // the user for the removal operation. This is because the handle
  251. // contains the access rights - the access is not re-evaluated
  252. // at token removal time.
  253. //
  254. Status = NtDuplicateObject( NtCurrentProcess(), // Source process
  255. NtCurrentThread(), // Source handle
  256. NtCurrentProcess(), // Target process
  257. &ThreadHandle, // Target handle
  258. THREAD_SET_THREAD_TOKEN,// Access
  259. 0L, // Attributes
  260. DUPLICATE_SAME_ATTRIBUTES
  261. );
  262. if (!NT_SUCCESS(Status)) {
  263. return(NULL);
  264. }
  265. ThreadHandleOpened = TRUE;
  266. }
  267. //
  268. // If the usertoken is NULL, there's nothing to do
  269. //
  270. if (UserToken != NULL) {
  271. //
  272. // UserToken is a primary token - create an impersonation token version
  273. // of it so we can set it on our thread
  274. //
  275. InitializeObjectAttributes(
  276. &ObjectAttributes,
  277. NULL,
  278. 0L,
  279. NULL,
  280. UserData->NewThreadTokenSD);
  281. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  282. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  283. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  284. SecurityQualityOfService.EffectiveOnly = FALSE;
  285. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  286. Status = NtDuplicateToken( UserToken,
  287. TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES |
  288. TOKEN_QUERY,
  289. &ObjectAttributes,
  290. FALSE,
  291. TokenImpersonation,
  292. &ImpersonationToken
  293. );
  294. if (!NT_SUCCESS(Status)) {
  295. if (ThreadHandleOpened) {
  296. IgnoreStatus = NtClose(ThreadHandle);
  297. ASSERT(NT_SUCCESS(IgnoreStatus));
  298. }
  299. return(NULL);
  300. }
  301. //
  302. // Set the impersonation token on this thread so we 'are' the user
  303. //
  304. Status = NtSetInformationThread( ThreadHandle,
  305. ThreadImpersonationToken,
  306. (PVOID)&ImpersonationToken,
  307. sizeof(ImpersonationToken)
  308. );
  309. //
  310. // We're finished with our handle to the impersonation token
  311. //
  312. IgnoreStatus = NtClose(ImpersonationToken);
  313. ASSERT(NT_SUCCESS(IgnoreStatus));
  314. //
  315. // Check we set the token on our thread ok
  316. //
  317. if (!NT_SUCCESS(Status)) {
  318. if (ThreadHandleOpened) {
  319. IgnoreStatus = NtClose(ThreadHandle);
  320. ASSERT(NT_SUCCESS(IgnoreStatus));
  321. }
  322. return(NULL);
  323. }
  324. }
  325. return(ThreadHandle);
  326. }
  327. /***************************************************************************\
  328. * FUNCTION: CtxStopImpersonating
  329. *
  330. * PURPOSE: Stops impersonating the client by removing the token on the
  331. * current thread.
  332. *
  333. * PARAMETERS: ThreadHandle - handle returned by ImpersonateUser() call.
  334. *
  335. * RETURNS: TRUE on success, FALSE on failure
  336. *
  337. * NOTES: If a thread handle was passed in to ImpersonateUser() then the
  338. * handle returned was one and the same. If this is passed to
  339. * StopImpersonating() the handle will be closed. Take care !
  340. *
  341. * HISTORY:
  342. *
  343. * 04-21-92 Davidc Created.
  344. * 12-18-96 cjc copied from \windows\gina\msgina\wlsec.c
  345. *
  346. \***************************************************************************/
  347. BOOL
  348. CtxStopImpersonating(
  349. HANDLE ThreadHandle
  350. )
  351. {
  352. NTSTATUS Status, IgnoreStatus;
  353. HANDLE ImpersonationToken;
  354. if (ThreadHandle == NULL) {
  355. return FALSE;
  356. }
  357. //
  358. // Remove the user's token from our thread so we are 'ourself' again
  359. //
  360. ImpersonationToken = NULL;
  361. Status = NtSetInformationThread( ThreadHandle,
  362. ThreadImpersonationToken,
  363. (PVOID)&ImpersonationToken,
  364. sizeof(ImpersonationToken)
  365. );
  366. //
  367. // We're finished with the thread handle
  368. //
  369. IgnoreStatus = NtClose(ThreadHandle);
  370. ASSERT(NT_SUCCESS(IgnoreStatus));
  371. return(NT_SUCCESS(Status));
  372. }