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.

468 lines
10 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. #ifdef UNICODE
  4. BOOL
  5. MyCheckTokenMembership (
  6. IN HANDLE TokenHandle OPTIONAL,
  7. IN PSID SidToCheck,
  8. OUT PBOOL IsMember
  9. )
  10. /*++
  11. Routine Description:
  12. This function checks to see whether the specified sid is enabled in
  13. the specified token.
  14. It was copied from advapi32\security.c
  15. Arguments:
  16. TokenHandle - If present, this token is checked for the sid. If not
  17. present then the current effective token will be used. This must
  18. be an impersonation token.
  19. SidToCheck - The sid to check for presence in the token
  20. IsMember - If the sid is enabled in the token, contains TRUE otherwise
  21. false.
  22. Return Value:
  23. TRUE - The API completed successfully. It does not indicate that the
  24. sid is a member of the token.
  25. FALSE - The API failed. A more detailed status code can be retrieved
  26. via GetLastError()
  27. --*/
  28. {
  29. HANDLE ProcessToken = NULL;
  30. HANDLE EffectiveToken = NULL;
  31. NTSTATUS Status = STATUS_SUCCESS;
  32. PISECURITY_DESCRIPTOR SecDesc = NULL;
  33. ULONG SecurityDescriptorSize;
  34. GENERIC_MAPPING GenericMapping = {
  35. STANDARD_RIGHTS_READ,
  36. STANDARD_RIGHTS_EXECUTE,
  37. STANDARD_RIGHTS_WRITE,
  38. STANDARD_RIGHTS_ALL };
  39. //
  40. // The size of the privilege set needs to contain the set itself plus
  41. // any privileges that may be used. The privileges that are used
  42. // are SeTakeOwnership and SeSecurity, plus one for good measure
  43. //
  44. BYTE PrivilegeSetBuffer[sizeof(PRIVILEGE_SET) + 3*sizeof(LUID_AND_ATTRIBUTES)];
  45. PPRIVILEGE_SET PrivilegeSet = (PPRIVILEGE_SET) PrivilegeSetBuffer;
  46. ULONG PrivilegeSetLength = sizeof(PrivilegeSetBuffer);
  47. ACCESS_MASK AccessGranted = 0;
  48. NTSTATUS AccessStatus = 0;
  49. PACL Dacl = NULL;
  50. #define MEMBER_ACCESS 1
  51. *IsMember = FALSE;
  52. //
  53. // Get a handle to the token
  54. //
  55. if (ARGUMENT_PRESENT(TokenHandle))
  56. {
  57. EffectiveToken = TokenHandle;
  58. }
  59. else
  60. {
  61. Status = NtOpenThreadToken(
  62. NtCurrentThread(),
  63. TOKEN_QUERY,
  64. FALSE, // don't open as self
  65. &EffectiveToken
  66. );
  67. //
  68. // if there is no thread token, try the process token
  69. //
  70. if (Status == STATUS_NO_TOKEN)
  71. {
  72. Status = NtOpenProcessToken(
  73. NtCurrentProcess(),
  74. TOKEN_QUERY | TOKEN_DUPLICATE,
  75. &ProcessToken
  76. );
  77. //
  78. // If we have a process token, we need to convert it to an
  79. // impersonation token
  80. //
  81. if (NT_SUCCESS(Status))
  82. {
  83. BOOL Result;
  84. Result = DuplicateToken(
  85. ProcessToken,
  86. SecurityImpersonation,
  87. &EffectiveToken
  88. );
  89. CloseHandle(ProcessToken);
  90. if (!Result)
  91. {
  92. return(FALSE);
  93. }
  94. }
  95. }
  96. if (!NT_SUCCESS(Status))
  97. {
  98. goto Cleanup;
  99. }
  100. }
  101. //
  102. // Construct a security descriptor to pass to access check
  103. //
  104. //
  105. // The size is equal to the size of an SD + twice the length of the SID
  106. // (for owner and group) + size of the DACL = sizeof ACL + size of the
  107. // ACE, which is an ACE + length of
  108. // ths SID.
  109. //
  110. SecurityDescriptorSize = sizeof(SECURITY_DESCRIPTOR) +
  111. sizeof(ACCESS_ALLOWED_ACE) +
  112. sizeof(ACL) +
  113. 3 * RtlLengthSid(SidToCheck);
  114. SecDesc = (PISECURITY_DESCRIPTOR) LocalAlloc(LMEM_ZEROINIT, SecurityDescriptorSize );
  115. if (SecDesc == NULL)
  116. {
  117. Status = STATUS_INSUFFICIENT_RESOURCES;
  118. goto Cleanup;
  119. }
  120. Dacl = (PACL) (SecDesc + 1);
  121. RtlCreateSecurityDescriptor(
  122. SecDesc,
  123. SECURITY_DESCRIPTOR_REVISION
  124. );
  125. //
  126. // Fill in fields of security descriptor
  127. //
  128. RtlSetOwnerSecurityDescriptor(
  129. SecDesc,
  130. SidToCheck,
  131. FALSE
  132. );
  133. RtlSetGroupSecurityDescriptor(
  134. SecDesc,
  135. SidToCheck,
  136. FALSE
  137. );
  138. Status = RtlCreateAcl(
  139. Dacl,
  140. SecurityDescriptorSize - sizeof(SECURITY_DESCRIPTOR),
  141. ACL_REVISION
  142. );
  143. if (!NT_SUCCESS(Status))
  144. {
  145. goto Cleanup;
  146. }
  147. Status = RtlAddAccessAllowedAce(
  148. Dacl,
  149. ACL_REVISION,
  150. MEMBER_ACCESS,
  151. SidToCheck
  152. );
  153. if (!NT_SUCCESS(Status))
  154. {
  155. goto Cleanup;
  156. }
  157. //
  158. // Set the DACL on the security descriptor
  159. //
  160. Status = RtlSetDaclSecurityDescriptor(
  161. SecDesc,
  162. TRUE, // DACL present
  163. Dacl,
  164. FALSE // not defaulted
  165. );
  166. if (!NT_SUCCESS(Status))
  167. {
  168. goto Cleanup;
  169. }
  170. Status = NtAccessCheck(
  171. SecDesc,
  172. EffectiveToken,
  173. MEMBER_ACCESS,
  174. &GenericMapping,
  175. PrivilegeSet,
  176. &PrivilegeSetLength,
  177. &AccessGranted,
  178. &AccessStatus
  179. );
  180. if (!NT_SUCCESS(Status))
  181. {
  182. goto Cleanup;
  183. }
  184. //
  185. // if the access check failed, then the sid is not a member of the
  186. // token
  187. //
  188. if ((AccessStatus == STATUS_SUCCESS) && (AccessGranted == MEMBER_ACCESS))
  189. {
  190. *IsMember = TRUE;
  191. }
  192. Cleanup:
  193. if (!ARGUMENT_PRESENT(TokenHandle) && (EffectiveToken != NULL))
  194. {
  195. (VOID) NtClose(EffectiveToken);
  196. }
  197. if (SecDesc != NULL)
  198. {
  199. LocalFree(SecDesc);
  200. }
  201. if (!NT_SUCCESS(Status))
  202. {
  203. SetLastError (RtlNtStatusToDosError (Status));
  204. return(FALSE);
  205. }
  206. else
  207. {
  208. return(TRUE);
  209. }
  210. }
  211. #endif
  212. BOOL
  213. IsUserAdmin(
  214. VOID
  215. )
  216. /*++
  217. Routine Description:
  218. This routine returns TRUE if the caller's process is a
  219. member of the Administrators local group.
  220. Caller is NOT expected to be impersonating anyone and IS
  221. expected to be able to open their own process and process
  222. token.
  223. Arguments:
  224. None.
  225. Return Value:
  226. TRUE - Caller has Administrators local group.
  227. FALSE - Caller does not have Administrators local group.
  228. --*/
  229. {
  230. #ifdef UNICODE
  231. BOOL b;
  232. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  233. PSID AdministratorsGroup;
  234. //
  235. // On non-NT platforms the user is administrator.
  236. //
  237. if(!ISNT()) {
  238. return(TRUE);
  239. }
  240. b = AllocateAndInitializeSid (
  241. &NtAuthority,
  242. 2,
  243. SECURITY_BUILTIN_DOMAIN_RID,
  244. DOMAIN_ALIAS_RID_ADMINS,
  245. 0, 0, 0, 0, 0, 0,
  246. &AdministratorsGroup
  247. );
  248. if (b) {
  249. //
  250. // See if the user has the administrators group.
  251. //
  252. if (!MyCheckTokenMembership (NULL, AdministratorsGroup, &b)) {
  253. b = FALSE;
  254. }
  255. FreeSid(AdministratorsGroup);
  256. }
  257. return(b);
  258. #else
  259. return TRUE;
  260. #endif
  261. }
  262. BOOL
  263. DoesUserHavePrivilege(
  264. PCTSTR PrivilegeName
  265. )
  266. /*++
  267. Routine Description:
  268. This routine returns TRUE if the caller's process has
  269. the specified privilege. The privilege does not have
  270. to be currently enabled. This routine is used to indicate
  271. whether the caller has the potential to enable the privilege.
  272. Caller is NOT expected to be impersonating anyone and IS
  273. expected to be able to open their own process and process
  274. token.
  275. Arguments:
  276. Privilege - the name form of privilege ID (such as
  277. SE_SECURITY_NAME).
  278. Return Value:
  279. TRUE - Caller has the specified privilege.
  280. FALSE - Caller does not have the specified privilege.
  281. --*/
  282. {
  283. HANDLE Token;
  284. ULONG BytesRequired;
  285. PTOKEN_PRIVILEGES Privileges;
  286. BOOL b;
  287. DWORD i;
  288. LUID Luid;
  289. //
  290. // On non-NT platforms the user has all privileges
  291. //
  292. if(!ISNT()) {
  293. return(TRUE);
  294. }
  295. //
  296. // Open the process token.
  297. //
  298. if(!OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&Token)) {
  299. return(FALSE);
  300. }
  301. b = FALSE;
  302. Privileges = NULL;
  303. //
  304. // Get privilege information.
  305. //
  306. if(!GetTokenInformation(Token,TokenPrivileges,NULL,0,&BytesRequired)
  307. && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  308. && (Privileges = (PTOKEN_PRIVILEGES)LocalAlloc(LPTR,BytesRequired))
  309. && GetTokenInformation(Token,TokenPrivileges,Privileges,BytesRequired,&BytesRequired)
  310. && LookupPrivilegeValue(NULL,PrivilegeName,&Luid)) {
  311. //
  312. // See if we have the requested privilege
  313. //
  314. for(i=0; i<Privileges->PrivilegeCount; i++) {
  315. if(!memcmp(&Luid,&Privileges->Privileges[i].Luid,sizeof(LUID))) {
  316. b = TRUE;
  317. break;
  318. }
  319. }
  320. }
  321. //
  322. // Clean up and return.
  323. //
  324. if(Privileges) {
  325. LocalFree((HLOCAL)Privileges);
  326. }
  327. CloseHandle(Token);
  328. return(b);
  329. }
  330. BOOL
  331. EnablePrivilege(
  332. IN PTSTR PrivilegeName,
  333. IN BOOL Enable
  334. )
  335. {
  336. HANDLE Token;
  337. BOOL b;
  338. TOKEN_PRIVILEGES NewPrivileges;
  339. LUID Luid;
  340. //
  341. // On non-NT platforms the user already has all privileges
  342. //
  343. if(!ISNT()) {
  344. return(TRUE);
  345. }
  346. if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&Token)) {
  347. return(FALSE);
  348. }
  349. if(!LookupPrivilegeValue(NULL,PrivilegeName,&Luid)) {
  350. CloseHandle(Token);
  351. return(FALSE);
  352. }
  353. NewPrivileges.PrivilegeCount = 1;
  354. NewPrivileges.Privileges[0].Luid = Luid;
  355. NewPrivileges.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
  356. b = AdjustTokenPrivileges(
  357. Token,
  358. FALSE,
  359. &NewPrivileges,
  360. 0,
  361. NULL,
  362. NULL
  363. );
  364. CloseHandle(Token);
  365. return(b);
  366. }