Reactos

[NTOS:SE] Implement the NtImpersonateAnonymousToken system call

Implement SepImpersonateAnonymousToken private helpers, which is necessary for the complete implementation of NtImpersonateAnonymousToken function and thus finally we're able to impersonate the anonymous logon token.

+168 -6
+167 -5
ntoskrnl/se/token.c
··· 363 363 return STATUS_SUCCESS; 364 364 } 365 365 366 + /** 367 + * @brief 368 + * Private function that impersonates the system's anonymous logon token. 369 + * The major bulk of the impersonation procedure is done here. 370 + * 371 + * @param[in] Thread 372 + * The executive thread object that is to impersonate the client. 373 + * 374 + * @param[in] PreviousMode 375 + * The access processor mode, indicating if the call is executed 376 + * in kernel or user mode. 377 + * 378 + * @return 379 + * Returns STATUS_SUCCESS if the impersonation has succeeded. 380 + * STATUS_UNSUCCESSFUL is returned if the primary token couldn't be 381 + * obtained from the current process to perform additional tasks. 382 + * STATUS_ACCESS_DENIED is returned if the process' primary token is 383 + * restricted, which for this matter we cannot impersonate onto a 384 + * restricted process. Otherwise a failure NTSTATUS code is returned. 385 + */ 386 + static 387 + NTSTATUS 388 + SepImpersonateAnonymousToken( 389 + _In_ PETHREAD Thread, 390 + _In_ KPROCESSOR_MODE PreviousMode) 391 + { 392 + NTSTATUS Status; 393 + PTOKEN TokenToImpersonate, ProcessToken; 394 + ULONG IncludeEveryoneValueData; 395 + PAGED_CODE(); 396 + 397 + /* 398 + * We must check first which kind of token 399 + * shall we assign for the thread to impersonate, 400 + * the one with Everyone Group SID or the other 401 + * without. Invoke the registry helper to 402 + * return the data value for us. 403 + */ 404 + Status = SepRegQueryHelper(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Lsa", 405 + L"EveryoneIncludesAnonymous", 406 + REG_DWORD, 407 + sizeof(IncludeEveryoneValueData), 408 + &IncludeEveryoneValueData); 409 + if (!NT_SUCCESS(Status)) 410 + { 411 + DPRINT1("SepRegQueryHelper(): Failed to query the registry value (Status 0x%lx)\n", Status); 412 + return Status; 413 + } 414 + 415 + if (IncludeEveryoneValueData == 0) 416 + { 417 + DPRINT("SepImpersonateAnonymousToken(): Assigning the token not including the Everyone Group SID...\n"); 418 + TokenToImpersonate = SeAnonymousLogonTokenNoEveryone; 419 + } 420 + else 421 + { 422 + DPRINT("SepImpersonateAnonymousToken(): Assigning the token including the Everyone Group SID...\n"); 423 + TokenToImpersonate = SeAnonymousLogonToken; 424 + } 425 + 426 + /* 427 + * Tell the object manager that we're going to use this token 428 + * object now by incrementing the reference count. 429 + */ 430 + Status = ObReferenceObjectByPointer(TokenToImpersonate, 431 + TOKEN_IMPERSONATE, 432 + SeTokenObjectType, 433 + PreviousMode); 434 + if (!NT_SUCCESS(Status)) 435 + { 436 + DPRINT1("SepImpersonateAnonymousToken(): Couldn't be able to use the token, bail out...\n"); 437 + return Status; 438 + } 439 + 440 + /* 441 + * Reference the primary token of the current process that the anonymous 442 + * logon token impersonation procedure is being performed. We'll be going 443 + * to use the process' token to figure out if the process is actually 444 + * restricted or not. 445 + */ 446 + ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess()); 447 + if (!ProcessToken) 448 + { 449 + DPRINT1("SepImpersonateAnonymousToken(): Couldn't be able to get the process' primary token, bail out...\n"); 450 + ObDereferenceObject(TokenToImpersonate); 451 + return STATUS_UNSUCCESSFUL; 452 + } 453 + 454 + /* Now, is the token from the current process restricted? */ 455 + if (SeTokenIsRestricted(ProcessToken)) 456 + { 457 + DPRINT1("SepImpersonateAnonymousToken(): The process is restricted, can't do anything. Bail out...\n"); 458 + PsDereferencePrimaryToken(ProcessToken); 459 + ObDereferenceObject(TokenToImpersonate); 460 + return STATUS_ACCESS_DENIED; 461 + } 462 + 463 + /* 464 + * Finally it's time to impersonate! But first, fast dereference the 465 + * process' primary token as we no longer need it. 466 + */ 467 + ObFastDereferenceObject(&PsGetCurrentProcess()->Token, ProcessToken); 468 + Status = PsImpersonateClient(Thread, TokenToImpersonate, TRUE, FALSE, SecurityImpersonation); 469 + if (!NT_SUCCESS(Status)) 470 + { 471 + DPRINT1("SepImpersonateAnonymousToken(): Failed to impersonate, bail out...\n"); 472 + ObDereferenceObject(TokenToImpersonate); 473 + return Status; 474 + } 475 + 476 + return Status; 477 + } 478 + 366 479 static 367 480 VOID 368 481 SepUpdateSinglePrivilegeFlagToken( ··· 4304 4417 return STATUS_NOT_IMPLEMENTED; 4305 4418 } 4306 4419 4307 - /* 4308 - * @unimplemented 4420 + /** 4421 + * @brief 4422 + * Allows the calling thread to impersonate the system's anonymous 4423 + * logon token. 4424 + * 4425 + * @param[in] ThreadHandle 4426 + * A handle to the thread to start the procedure of logon token 4427 + * impersonation. The thread must have the THREAD_IMPERSONATE 4428 + * access right. 4429 + * 4430 + * @return 4431 + * Returns STATUS_SUCCESS if the thread has successfully impersonated the 4432 + * anonymous logon token, otherwise a failure NTSTATUS code is returned. 4433 + * 4434 + * @remarks 4435 + * By default the system gives the opportunity to the caller to impersonate 4436 + * the anonymous logon token without including the Everyone Group SID. 4437 + * In cases where the caller wants to impersonate the token including such 4438 + * group, the EveryoneIncludesAnonymous registry value setting has to be set 4439 + * to 1, from HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa registry 4440 + * path. The calling thread must invoke PsRevertToSelf when impersonation 4441 + * is no longer needed or RevertToSelf if the calling execution is done 4442 + * in user mode. 4309 4443 */ 4310 4444 NTSTATUS 4311 4445 NTAPI 4312 - NtImpersonateAnonymousToken(IN HANDLE Thread) 4446 + NtImpersonateAnonymousToken( 4447 + _In_ HANDLE ThreadHandle) 4313 4448 { 4314 - UNIMPLEMENTED; 4315 - return STATUS_NOT_IMPLEMENTED; 4449 + PETHREAD Thread; 4450 + KPROCESSOR_MODE PreviousMode; 4451 + NTSTATUS Status; 4452 + PAGED_CODE(); 4453 + 4454 + PreviousMode = ExGetPreviousMode(); 4455 + 4456 + /* Obtain the thread object from the handle */ 4457 + Status = ObReferenceObjectByHandle(ThreadHandle, 4458 + THREAD_IMPERSONATE, 4459 + PsThreadType, 4460 + PreviousMode, 4461 + (PVOID*)&Thread, 4462 + NULL); 4463 + if (!NT_SUCCESS(Status)) 4464 + { 4465 + DPRINT1("NtImpersonateAnonymousToken(): Failed to reference the object (Status 0x%lx)\n", Status); 4466 + return Status; 4467 + } 4468 + 4469 + /* Call the private routine to impersonate the token */ 4470 + Status = SepImpersonateAnonymousToken(Thread, PreviousMode); 4471 + if (!NT_SUCCESS(Status)) 4472 + { 4473 + DPRINT1("NtImpersonateAnonymousToken(): Failed to impersonate the token (Status 0x%lx)\n", Status); 4474 + } 4475 + 4476 + ObDereferenceObject(Thread); 4477 + return Status; 4316 4478 } 4317 4479 4318 4480 /* EOF */
+1 -1
sdk/include/ndk/sefuncs.h
··· 239 239 NTSTATUS 240 240 NTAPI 241 241 NtImpersonateAnonymousToken( 242 - _In_ HANDLE Thread 242 + _In_ HANDLE ThreadHandle 243 243 ); 244 244 245 245 __kernel_entry