1c2c66affSColin Finck /* 2c2c66affSColin Finck * COPYRIGHT: See COPYING in the top level directory 3c2c66affSColin Finck * PROJECT: ReactOS system libraries 4c2c66affSColin Finck * FILE: lib/rtl/priv.c 5c2c66affSColin Finck * PURPOSE: Security related functions and Security Objects 6c2c66affSColin Finck * PROGRAMMER: Eric Kohl 7c2c66affSColin Finck * Pierre Schweitzer (pierre@reactos.org) 8c2c66affSColin Finck */ 9c2c66affSColin Finck 10c2c66affSColin Finck /* INCLUDES *****************************************************************/ 11c2c66affSColin Finck 12c2c66affSColin Finck #include <rtl.h> 13c2c66affSColin Finck 14c2c66affSColin Finck #define NDEBUG 15c2c66affSColin Finck #include <debug.h> 16c2c66affSColin Finck 17c2c66affSColin Finck /* FUNCTIONS ***************************************************************/ 18c2c66affSColin Finck 19c2c66affSColin Finck /* 20c2c66affSColin Finck * @implemented 21c2c66affSColin Finck */ 22c2c66affSColin Finck NTSTATUS 23c2c66affSColin Finck NTAPI 24c2c66affSColin Finck RtlpOpenThreadToken(IN ACCESS_MASK DesiredAccess, 25c2c66affSColin Finck OUT PHANDLE TokenHandle) 26c2c66affSColin Finck { 27c2c66affSColin Finck NTSTATUS Status; 28c2c66affSColin Finck 29c2c66affSColin Finck Status = ZwOpenThreadToken(NtCurrentThread(), DesiredAccess, 30c2c66affSColin Finck TRUE, TokenHandle); 31c2c66affSColin Finck if (!NT_SUCCESS(Status)) 32c2c66affSColin Finck { 33c2c66affSColin Finck Status = ZwOpenThreadToken(NtCurrentThread(), DesiredAccess, 34c2c66affSColin Finck FALSE, TokenHandle); 35c2c66affSColin Finck } 36c2c66affSColin Finck 37c2c66affSColin Finck return Status; 38c2c66affSColin Finck } 39c2c66affSColin Finck 40c2c66affSColin Finck /* 41c2c66affSColin Finck * @implemented 42c2c66affSColin Finck */ 43c2c66affSColin Finck NTSTATUS 44c2c66affSColin Finck NTAPI 45c2c66affSColin Finck RtlImpersonateSelf(IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel) 46c2c66affSColin Finck { 47c2c66affSColin Finck HANDLE ProcessToken; 48c2c66affSColin Finck HANDLE ImpersonationToken; 49c2c66affSColin Finck NTSTATUS Status; 50c2c66affSColin Finck OBJECT_ATTRIBUTES ObjAttr; 51c2c66affSColin Finck SECURITY_QUALITY_OF_SERVICE Sqos; 52c2c66affSColin Finck 53c2c66affSColin Finck PAGED_CODE_RTL(); 54c2c66affSColin Finck 55c2c66affSColin Finck Status = ZwOpenProcessToken(NtCurrentProcess(), 56c2c66affSColin Finck TOKEN_DUPLICATE, 57c2c66affSColin Finck &ProcessToken); 58c2c66affSColin Finck if (!NT_SUCCESS(Status)) 59c2c66affSColin Finck { 60c2c66affSColin Finck DPRINT1("NtOpenProcessToken() failed (Status %lx)\n", Status); 61c2c66affSColin Finck return Status; 62c2c66affSColin Finck } 63c2c66affSColin Finck 64c2c66affSColin Finck Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); 65c2c66affSColin Finck Sqos.ImpersonationLevel = ImpersonationLevel; 66c2c66affSColin Finck Sqos.ContextTrackingMode = 0; 67c2c66affSColin Finck Sqos.EffectiveOnly = FALSE; 68c2c66affSColin Finck 69c2c66affSColin Finck InitializeObjectAttributes(&ObjAttr, 70c2c66affSColin Finck NULL, 71c2c66affSColin Finck 0, 72c2c66affSColin Finck NULL, 73c2c66affSColin Finck NULL); 74c2c66affSColin Finck 75c2c66affSColin Finck ObjAttr.SecurityQualityOfService = &Sqos; 76c2c66affSColin Finck 77c2c66affSColin Finck Status = ZwDuplicateToken(ProcessToken, 78c2c66affSColin Finck TOKEN_IMPERSONATE, 79c2c66affSColin Finck &ObjAttr, 80c2c66affSColin Finck Sqos.EffectiveOnly, /* why both here _and_ in Sqos? */ 81c2c66affSColin Finck TokenImpersonation, 82c2c66affSColin Finck &ImpersonationToken); 83c2c66affSColin Finck if (!NT_SUCCESS(Status)) 84c2c66affSColin Finck { 85c2c66affSColin Finck DPRINT1("NtDuplicateToken() failed (Status %lx)\n", Status); 86c2c66affSColin Finck NtClose(ProcessToken); 87c2c66affSColin Finck return Status; 88c2c66affSColin Finck } 89c2c66affSColin Finck 90c2c66affSColin Finck Status = ZwSetInformationThread(NtCurrentThread(), 91c2c66affSColin Finck ThreadImpersonationToken, 92c2c66affSColin Finck &ImpersonationToken, 93c2c66affSColin Finck sizeof(HANDLE)); 94c2c66affSColin Finck if (!NT_SUCCESS(Status)) 95c2c66affSColin Finck { 96c2c66affSColin Finck DPRINT1("NtSetInformationThread() failed (Status %lx)\n", Status); 97c2c66affSColin Finck } 98c2c66affSColin Finck 99c2c66affSColin Finck ZwClose(ImpersonationToken); 100c2c66affSColin Finck ZwClose(ProcessToken); 101c2c66affSColin Finck 102c2c66affSColin Finck return Status; 103c2c66affSColin Finck } 104c2c66affSColin Finck 105c2c66affSColin Finck /* 106c2c66affSColin Finck * @implemented 107c2c66affSColin Finck */ 108c2c66affSColin Finck NTSTATUS 109c2c66affSColin Finck NTAPI 110c2c66affSColin Finck RtlAcquirePrivilege(IN PULONG Privilege, 111c2c66affSColin Finck IN ULONG NumPriv, 112c2c66affSColin Finck IN ULONG Flags, 113c2c66affSColin Finck OUT PVOID *ReturnedState) 114c2c66affSColin Finck { 115c2c66affSColin Finck PRTL_ACQUIRE_STATE State; 116c2c66affSColin Finck NTSTATUS Status, IntStatus; 117c2c66affSColin Finck ULONG ReturnLength, i, OldSize; 118c2c66affSColin Finck SECURITY_QUALITY_OF_SERVICE Sqos; 119c2c66affSColin Finck OBJECT_ATTRIBUTES ObjectAttributes; 120c2c66affSColin Finck HANDLE ImpersonationToken = 0, ProcessToken; 121c2c66affSColin Finck 122c2c66affSColin Finck DPRINT("RtlAcquirePrivilege(%p, %u, %u, %p)\n", Privilege, NumPriv, Flags, ReturnedState); 123c2c66affSColin Finck 124c2c66affSColin Finck /* Validate flags */ 125c2c66affSColin Finck if (Flags & ~(RTL_ACQUIRE_PRIVILEGE_PROCESS | RTL_ACQUIRE_PRIVILEGE_IMPERSONATE)) 126c2c66affSColin Finck { 127c2c66affSColin Finck return STATUS_INVALID_PARAMETER; 128c2c66affSColin Finck } 129c2c66affSColin Finck 130c2c66affSColin Finck /* If user wants to acquire privileges for the process, we have to impersonate him */ 131c2c66affSColin Finck if (Flags & RTL_ACQUIRE_PRIVILEGE_PROCESS) 132c2c66affSColin Finck { 133c2c66affSColin Finck Flags |= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE; 134c2c66affSColin Finck } 135c2c66affSColin Finck 136c2c66affSColin Finck /* Allocate enough memory to hold: old privileges (fixed buffer size, might not be enough) 137c2c66affSColin Finck * new privileges (big enough, after old privileges memory area) 138c2c66affSColin Finck */ 139c2c66affSColin Finck State = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(RTL_ACQUIRE_STATE) + sizeof(TOKEN_PRIVILEGES) + 140c2c66affSColin Finck (NumPriv - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES)); 141c2c66affSColin Finck if (!State) 142c2c66affSColin Finck { 143c2c66affSColin Finck return STATUS_NO_MEMORY; 144c2c66affSColin Finck } 145c2c66affSColin Finck 146c2c66affSColin Finck /* Only zero a bit of the memory (will be faster that way) */ 147c2c66affSColin Finck State->Token = 0; 148c2c66affSColin Finck State->OldImpersonationToken = 0; 149c2c66affSColin Finck State->Flags = 0; 150c2c66affSColin Finck State->OldPrivileges = NULL; 151c2c66affSColin Finck 152c2c66affSColin Finck /* Check whether we have already an active impersonation */ 153c2c66affSColin Finck if (NtCurrentTeb()->IsImpersonating) 154c2c66affSColin Finck { 155c2c66affSColin Finck /* Check whether we want to impersonate */ 156c2c66affSColin Finck if (Flags & RTL_ACQUIRE_PRIVILEGE_IMPERSONATE) 157c2c66affSColin Finck { 158c2c66affSColin Finck /* That's all fine, just get the token. 159c2c66affSColin Finck * We need access for: adjust (obvious...) but also 160c2c66affSColin Finck * query, to be able to query old privileges 161c2c66affSColin Finck */ 162c2c66affSColin Finck Status = RtlpOpenThreadToken(TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &State->Token); 163c2c66affSColin Finck if (!NT_SUCCESS(Status)) 164c2c66affSColin Finck { 165c2c66affSColin Finck RtlFreeHeap(RtlGetProcessHeap(), 0, State); 166c2c66affSColin Finck return Status; 167c2c66affSColin Finck } 168c2c66affSColin Finck } 169c2c66affSColin Finck else 170c2c66affSColin Finck { 171c2c66affSColin Finck /* Otherwise, we have to temporary disable active impersonation. 172c2c66affSColin Finck * Get previous impersonation token to save it 173c2c66affSColin Finck */ 174c2c66affSColin Finck Status = RtlpOpenThreadToken(TOKEN_IMPERSONATE, &State->OldImpersonationToken); 175c2c66affSColin Finck if (!NT_SUCCESS(Status)) 176c2c66affSColin Finck { 177c2c66affSColin Finck RtlFreeHeap(RtlGetProcessHeap(), 0, State); 178c2c66affSColin Finck return Status; 179c2c66affSColin Finck } 180c2c66affSColin Finck 181c2c66affSColin Finck /* Remember the fact we had an active impersonation */ 182c2c66affSColin Finck State->Flags |= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE; 183c2c66affSColin Finck 184c2c66affSColin Finck /* Revert impersonation (ie, give 0 as handle) */ 185c2c66affSColin Finck Status = ZwSetInformationThread(NtCurrentThread(), 186c2c66affSColin Finck ThreadImpersonationToken, 187c2c66affSColin Finck &ImpersonationToken, 188c2c66affSColin Finck sizeof(HANDLE)); 189c2c66affSColin Finck } 190c2c66affSColin Finck } 191c2c66affSColin Finck 192c2c66affSColin Finck /* If we have no token yet (which is likely) */ 193c2c66affSColin Finck if (!State->Token) 194c2c66affSColin Finck { 195c2c66affSColin Finck /* If we are asked to use process, then do */ 196c2c66affSColin Finck if (Flags & RTL_ACQUIRE_PRIVILEGE_PROCESS) 197c2c66affSColin Finck { 198c2c66affSColin Finck Status = ZwOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 199c2c66affSColin Finck &State->Token); 200c2c66affSColin Finck if (!NT_SUCCESS(Status)) 201c2c66affSColin Finck { 202c2c66affSColin Finck goto Cleanup; 203c2c66affSColin Finck } 204c2c66affSColin Finck } 205c2c66affSColin Finck else 206c2c66affSColin Finck { 207c2c66affSColin Finck /* Otherwise, we have to impersonate. 208c2c66affSColin Finck * Open token for duplication 209c2c66affSColin Finck */ 210c2c66affSColin Finck Status = ZwOpenProcessToken(NtCurrentProcess(), TOKEN_DUPLICATE, &ProcessToken); 211c2c66affSColin Finck 212c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 213c2c66affSColin Finck NULL, 214c2c66affSColin Finck 0, 215c2c66affSColin Finck NULL, 216c2c66affSColin Finck NULL); 217c2c66affSColin Finck 218c2c66affSColin Finck ObjectAttributes.SecurityQualityOfService = &Sqos; 219c2c66affSColin Finck Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); 220c2c66affSColin Finck Sqos.ImpersonationLevel = SecurityDelegation; 221c2c66affSColin Finck Sqos.ContextTrackingMode = 1; 222c2c66affSColin Finck Sqos.EffectiveOnly = FALSE; 223c2c66affSColin Finck 224c2c66affSColin Finck /* Duplicate */ 225c2c66affSColin Finck Status = ZwDuplicateToken(ProcessToken, 226c2c66affSColin Finck TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_IMPERSONATE, 227c2c66affSColin Finck &ObjectAttributes, 228c2c66affSColin Finck FALSE, 229c2c66affSColin Finck TokenImpersonation, 230c2c66affSColin Finck &ImpersonationToken); 231c2c66affSColin Finck if (!NT_SUCCESS(Status)) 232c2c66affSColin Finck { 233c2c66affSColin Finck ZwClose(ProcessToken); 234c2c66affSColin Finck goto Cleanup; 235c2c66affSColin Finck } 236c2c66affSColin Finck 237c2c66affSColin Finck /* Assign our duplicated token to current thread */ 238c2c66affSColin Finck Status = ZwSetInformationThread(NtCurrentThread(), 239c2c66affSColin Finck ThreadImpersonationToken, 240c2c66affSColin Finck &ImpersonationToken, 241c2c66affSColin Finck sizeof(HANDLE)); 242c2c66affSColin Finck if (!NT_SUCCESS(Status)) 243c2c66affSColin Finck { 244c2c66affSColin Finck ZwClose(ImpersonationToken); 245c2c66affSColin Finck ZwClose(ProcessToken); 246c2c66affSColin Finck goto Cleanup; 247c2c66affSColin Finck } 248c2c66affSColin Finck 249c2c66affSColin Finck /* Save said token and the fact we have impersonated */ 250c2c66affSColin Finck State->Token = ImpersonationToken; 251c2c66affSColin Finck State->Flags |= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE; 252c2c66affSColin Finck 253c2c66affSColin Finck ZwClose(ProcessToken); 254c2c66affSColin Finck } 255c2c66affSColin Finck } 256c2c66affSColin Finck 257c2c66affSColin Finck /* Properly set the privileges pointers: 258c2c66affSColin Finck * OldPrivileges points to the static memory in struct (= OldPrivBuffer) 259c2c66affSColin Finck * NewPrivileges points to the dynamic memory after OldPrivBuffer 260c2c66affSColin Finck * There's NO overflow risks (OldPrivileges is always used with its size) 261c2c66affSColin Finck */ 262c2c66affSColin Finck State->OldPrivileges = (PTOKEN_PRIVILEGES)State->OldPrivBuffer; 263c2c66affSColin Finck State->NewPrivileges = (PTOKEN_PRIVILEGES)(State->OldPrivBuffer + (sizeof(State->OldPrivBuffer) / sizeof(State->OldPrivBuffer[0]))); 264c2c66affSColin Finck 265c2c66affSColin Finck /* Assign all the privileges to be acquired */ 266c2c66affSColin Finck State->NewPrivileges->PrivilegeCount = NumPriv; 267c2c66affSColin Finck for (i = 0; i < NumPriv; ++i) 268c2c66affSColin Finck { 269c2c66affSColin Finck State->NewPrivileges->Privileges[i].Luid.LowPart = Privilege[i]; 270c2c66affSColin Finck State->NewPrivileges->Privileges[i].Luid.HighPart = 0; 271c2c66affSColin Finck State->NewPrivileges->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED; 272c2c66affSColin Finck } 273c2c66affSColin Finck 274c2c66affSColin Finck /* Start privileges adjustements */ 275c2c66affSColin Finck OldSize = sizeof(State->OldPrivBuffer); 276c2c66affSColin Finck do 277c2c66affSColin Finck { 278c2c66affSColin Finck ReturnLength = sizeof(State->OldPrivBuffer); 279c2c66affSColin Finck Status = ZwAdjustPrivilegesToken(State->Token, FALSE, State->NewPrivileges, 280c2c66affSColin Finck OldSize, State->OldPrivileges, &ReturnLength); 281c2c66affSColin Finck /* This is returned when OldPrivileges buffer is too small */ 282c2c66affSColin Finck if (Status == STATUS_BUFFER_TOO_SMALL) 283c2c66affSColin Finck { 284c2c66affSColin Finck /* Try to allocate a new one, big enough to hold data */ 285c2c66affSColin Finck State->OldPrivileges = RtlAllocateHeap(RtlGetProcessHeap(), 0, ReturnLength); 286c2c66affSColin Finck if (State->OldPrivileges) 287c2c66affSColin Finck { 288c2c66affSColin Finck DPRINT("Allocated old privileges: %p\n", State->OldPrivileges); 289c2c66affSColin Finck OldSize = ReturnLength; 290c2c66affSColin Finck continue; 291c2c66affSColin Finck } 292c2c66affSColin Finck else 293c2c66affSColin Finck { 294c2c66affSColin Finck /* If we failed, properly set status: we failed because of the lack of memory */ 295c2c66affSColin Finck Status = STATUS_NO_MEMORY; 296c2c66affSColin Finck } 297c2c66affSColin Finck } 298c2c66affSColin Finck 299c2c66affSColin Finck /* If we failed to assign at least one privilege */ 300c2c66affSColin Finck if (Status == STATUS_NOT_ALL_ASSIGNED) 301c2c66affSColin Finck { 302c2c66affSColin Finck /* If there was actually only one privilege to acquire, use more accurate status */ 303c2c66affSColin Finck if (NumPriv == 1) 304c2c66affSColin Finck { 305c2c66affSColin Finck Status = STATUS_PRIVILEGE_NOT_HELD; 306c2c66affSColin Finck } 307c2c66affSColin Finck } 308c2c66affSColin Finck 309c2c66affSColin Finck /* Fail if needed, otherwise return our state to caller */ 310c2c66affSColin Finck if (!NT_SUCCESS(Status)) 311c2c66affSColin Finck { 312c2c66affSColin Finck goto Cleanup; 313c2c66affSColin Finck } 314c2c66affSColin Finck else 315c2c66affSColin Finck { 316c2c66affSColin Finck *ReturnedState = State; 317c2c66affSColin Finck break; 318c2c66affSColin Finck } 319c2c66affSColin Finck } while (TRUE); 320c2c66affSColin Finck 321c2c66affSColin Finck DPRINT("RtlAcquirePrivilege succeed!\n"); 322c2c66affSColin Finck 323c2c66affSColin Finck return Status; 324c2c66affSColin Finck 325c2c66affSColin Finck Cleanup: 326c2c66affSColin Finck /* If we allocated our own buffer for old privileges, release it */ 327c2c66affSColin Finck if (State->OldPrivileges && (PVOID)State->OldPrivBuffer != (PVOID)State->OldPrivileges) 328c2c66affSColin Finck { 329c2c66affSColin Finck RtlFreeHeap(RtlGetProcessHeap(), 0, State->OldPrivileges); 330c2c66affSColin Finck } 331c2c66affSColin Finck 332c2c66affSColin Finck /* Do we have to restore previously active impersonation? */ 333c2c66affSColin Finck if (State->Flags & RTL_ACQUIRE_PRIVILEGE_IMPERSONATE) 334c2c66affSColin Finck { 335c2c66affSColin Finck IntStatus = ZwSetInformationThread(NtCurrentThread(), ThreadImpersonationToken, 336c2c66affSColin Finck &State->OldImpersonationToken, sizeof(HANDLE)); 337c2c66affSColin Finck /* If this ever happens, we're in a really bad situation... */ 338c2c66affSColin Finck if (!NT_SUCCESS(IntStatus)) 339c2c66affSColin Finck { 340c2c66affSColin Finck RtlRaiseStatus(IntStatus); 341c2c66affSColin Finck } 342c2c66affSColin Finck } 343c2c66affSColin Finck 344c2c66affSColin Finck /* Release token */ 345c2c66affSColin Finck if (State->Token) 346c2c66affSColin Finck { 347c2c66affSColin Finck ZwClose(State->Token); 348c2c66affSColin Finck } 349c2c66affSColin Finck 350c2c66affSColin Finck /* And free our state buffer */ 351c2c66affSColin Finck RtlFreeHeap(RtlGetProcessHeap(), 0, State); 352c2c66affSColin Finck 353c2c66affSColin Finck DPRINT("RtlAcquirePrivilege() failed with status: %lx\n", Status); 354c2c66affSColin Finck 355c2c66affSColin Finck return Status; 356c2c66affSColin Finck } 357c2c66affSColin Finck 358c2c66affSColin Finck /* 359c2c66affSColin Finck * @implemented 360c2c66affSColin Finck */ 361c2c66affSColin Finck VOID 362c2c66affSColin Finck NTAPI 363c2c66affSColin Finck RtlReleasePrivilege(IN PVOID ReturnedState) 364c2c66affSColin Finck { 365c2c66affSColin Finck NTSTATUS Status; 366c2c66affSColin Finck PRTL_ACQUIRE_STATE State = (PRTL_ACQUIRE_STATE)ReturnedState; 367c2c66affSColin Finck 368c2c66affSColin Finck DPRINT("RtlReleasePrivilege(%p)\n", ReturnedState); 369c2c66affSColin Finck 370c2c66affSColin Finck /* If we had an active impersonation before we acquired privileges 371c2c66affSColin Finck * Or if we have impersonated, quit it 372c2c66affSColin Finck */ 373c2c66affSColin Finck if (State->Flags & RTL_ACQUIRE_PRIVILEGE_IMPERSONATE) 374c2c66affSColin Finck { 375c2c66affSColin Finck /* Restore it for the current thread */ 376c2c66affSColin Finck Status = ZwSetInformationThread(NtCurrentThread(), ThreadImpersonationToken, 377c2c66affSColin Finck &State->OldImpersonationToken, sizeof(HANDLE)); 378c2c66affSColin Finck if (!NT_SUCCESS(Status)) 379c2c66affSColin Finck { 380c2c66affSColin Finck RtlRaiseStatus(Status); 381c2c66affSColin Finck } 382c2c66affSColin Finck 383c2c66affSColin Finck /* And close the token if needed */ 384c2c66affSColin Finck if (State->OldImpersonationToken) 385c2c66affSColin Finck ZwClose(State->OldImpersonationToken); 386c2c66affSColin Finck } 387c2c66affSColin Finck else 388c2c66affSColin Finck { 389c2c66affSColin Finck /* Otherwise, restore old state */ 390*46394ab8SJérôme Gardou Status = ZwAdjustPrivilegesToken(State->Token, FALSE, 391c2c66affSColin Finck State->OldPrivileges, 0, NULL, NULL); 392*46394ab8SJérôme Gardou if (!NT_SUCCESS(Status)) 393*46394ab8SJérôme Gardou { 394*46394ab8SJérôme Gardou RtlRaiseStatus(Status); 395*46394ab8SJérôme Gardou } 396c2c66affSColin Finck } 397c2c66affSColin Finck 398c2c66affSColin Finck /* If we used a different buffer for old privileges, just free it */ 399c2c66affSColin Finck if ((PVOID)State->OldPrivBuffer != (PVOID)State->OldPrivileges) 400c2c66affSColin Finck { 401c2c66affSColin Finck DPRINT("Releasing old privileges: %p\n", State->OldPrivileges); 402c2c66affSColin Finck RtlFreeHeap(RtlGetProcessHeap(), 0, State->OldPrivileges); 403c2c66affSColin Finck } 404c2c66affSColin Finck 405c2c66affSColin Finck /* Release token and free state */ 406c2c66affSColin Finck ZwClose(State->Token); 407c2c66affSColin Finck RtlFreeHeap(RtlGetProcessHeap(), 0, State); 408c2c66affSColin Finck } 409c2c66affSColin Finck 410c2c66affSColin Finck /* 411c2c66affSColin Finck * @implemented 412c2c66affSColin Finck */ 413c2c66affSColin Finck NTSTATUS 414c2c66affSColin Finck NTAPI 415c2c66affSColin Finck RtlAdjustPrivilege(IN ULONG Privilege, 416c2c66affSColin Finck IN BOOLEAN Enable, 417c2c66affSColin Finck IN BOOLEAN CurrentThread, 418c2c66affSColin Finck OUT PBOOLEAN Enabled) 419c2c66affSColin Finck { 420c2c66affSColin Finck TOKEN_PRIVILEGES NewState; 421c2c66affSColin Finck TOKEN_PRIVILEGES OldState; 422c2c66affSColin Finck ULONG ReturnLength; 423c2c66affSColin Finck HANDLE TokenHandle; 424c2c66affSColin Finck NTSTATUS Status; 425c2c66affSColin Finck 426c2c66affSColin Finck PAGED_CODE_RTL(); 427c2c66affSColin Finck 428c2c66affSColin Finck DPRINT("RtlAdjustPrivilege() called\n"); 429c2c66affSColin Finck 430c2c66affSColin Finck if (CurrentThread) 431c2c66affSColin Finck { 432c2c66affSColin Finck Status = ZwOpenThreadToken(NtCurrentThread(), 433c2c66affSColin Finck TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 434c2c66affSColin Finck FALSE, 435c2c66affSColin Finck &TokenHandle); 436c2c66affSColin Finck } 437c2c66affSColin Finck else 438c2c66affSColin Finck { 439c2c66affSColin Finck Status = ZwOpenProcessToken(NtCurrentProcess(), 440c2c66affSColin Finck TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 441c2c66affSColin Finck &TokenHandle); 442c2c66affSColin Finck } 443c2c66affSColin Finck 444c2c66affSColin Finck if (!NT_SUCCESS (Status)) 445c2c66affSColin Finck { 446c2c66affSColin Finck DPRINT1("Retrieving token handle failed (Status %lx)\n", Status); 447c2c66affSColin Finck return Status; 448c2c66affSColin Finck } 449c2c66affSColin Finck 450c2c66affSColin Finck OldState.PrivilegeCount = 1; 451c2c66affSColin Finck 452c2c66affSColin Finck NewState.PrivilegeCount = 1; 453c2c66affSColin Finck NewState.Privileges[0].Luid.LowPart = Privilege; 454c2c66affSColin Finck NewState.Privileges[0].Luid.HighPart = 0; 455c2c66affSColin Finck NewState.Privileges[0].Attributes = (Enable) ? SE_PRIVILEGE_ENABLED : 0; 456c2c66affSColin Finck 457c2c66affSColin Finck Status = ZwAdjustPrivilegesToken(TokenHandle, 458c2c66affSColin Finck FALSE, 459c2c66affSColin Finck &NewState, 460c2c66affSColin Finck sizeof(TOKEN_PRIVILEGES), 461c2c66affSColin Finck &OldState, 462c2c66affSColin Finck &ReturnLength); 463c2c66affSColin Finck ZwClose (TokenHandle); 464c2c66affSColin Finck if (Status == STATUS_NOT_ALL_ASSIGNED) 465c2c66affSColin Finck { 466c2c66affSColin Finck DPRINT1("Failed to assign all privileges\n"); 467c2c66affSColin Finck return STATUS_PRIVILEGE_NOT_HELD; 468c2c66affSColin Finck } 469c2c66affSColin Finck 470c2c66affSColin Finck if (!NT_SUCCESS(Status)) 471c2c66affSColin Finck { 472c2c66affSColin Finck DPRINT1("NtAdjustPrivilegesToken() failed (Status %lx)\n", Status); 473c2c66affSColin Finck return Status; 474c2c66affSColin Finck } 475c2c66affSColin Finck 476c2c66affSColin Finck if (OldState.PrivilegeCount == 0) 477c2c66affSColin Finck { 478c2c66affSColin Finck *Enabled = Enable; 479c2c66affSColin Finck } 480c2c66affSColin Finck else 481c2c66affSColin Finck { 482c2c66affSColin Finck *Enabled = (OldState.Privileges[0].Attributes & SE_PRIVILEGE_ENABLED); 483c2c66affSColin Finck } 484c2c66affSColin Finck 485c2c66affSColin Finck DPRINT("RtlAdjustPrivilege() done\n"); 486c2c66affSColin Finck 487c2c66affSColin Finck return STATUS_SUCCESS; 488c2c66affSColin Finck } 489