/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * FILE: lib/advapi32/token/token.c * PURPOSE: Token functions * PROGRAMMER: Ariadne ( ariadne@xs4all.nl) * UPDATE HISTORY: * Created 01/11/98 */ #include #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(advapi); /* * @implemented */ BOOL WINAPI AdjustTokenGroups(HANDLE TokenHandle, BOOL ResetToDefault, PTOKEN_GROUPS NewState, DWORD BufferLength, PTOKEN_GROUPS PreviousState, PDWORD ReturnLength) { NTSTATUS Status; Status = NtAdjustGroupsToken(TokenHandle, ResetToDefault, NewState, BufferLength, PreviousState, (PULONG)ReturnLength); if (!NT_SUCCESS(Status)) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } return TRUE; } /* * @implemented */ BOOL WINAPI AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength) { NTSTATUS Status; Status = NtAdjustPrivilegesToken(TokenHandle, DisableAllPrivileges, NewState, BufferLength, PreviousState, (PULONG)ReturnLength); if (STATUS_NOT_ALL_ASSIGNED == Status) { SetLastError(ERROR_NOT_ALL_ASSIGNED); return TRUE; } if (!NT_SUCCESS(Status)) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } /* AdjustTokenPrivileges is documented to do this */ SetLastError(ERROR_SUCCESS); return TRUE; } /* * @implemented */ BOOL WINAPI GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, LPVOID TokenInformation, DWORD TokenInformationLength, PDWORD ReturnLength) { NTSTATUS Status; Status = NtQueryInformationToken(TokenHandle, TokenInformationClass, TokenInformation, TokenInformationLength, (PULONG)ReturnLength); if (!NT_SUCCESS(Status)) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } return TRUE; } /* * @implemented */ BOOL WINAPI SetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, LPVOID TokenInformation, DWORD TokenInformationLength) { NTSTATUS Status; Status = NtSetInformationToken(TokenHandle, TokenInformationClass, TokenInformation, TokenInformationLength); if (!NT_SUCCESS(Status)) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } return TRUE; } /* * @implemented */ BOOL WINAPI AccessCheck(IN PSECURITY_DESCRIPTOR pSecurityDescriptor, IN HANDLE ClientToken, IN DWORD DesiredAccess, IN PGENERIC_MAPPING GenericMapping, OUT PPRIVILEGE_SET PrivilegeSet OPTIONAL, IN OUT LPDWORD PrivilegeSetLength, OUT LPDWORD GrantedAccess, OUT LPBOOL AccessStatus) { NTSTATUS Status; NTSTATUS NtAccessStatus; /* Do the access check */ Status = NtAccessCheck(pSecurityDescriptor, ClientToken, DesiredAccess, GenericMapping, PrivilegeSet, (PULONG)PrivilegeSetLength, (PACCESS_MASK)GrantedAccess, &NtAccessStatus); /* See if the access check operation succeeded */ if (!NT_SUCCESS(Status)) { /* Check failed */ SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } /* Now check the access status */ if (!NT_SUCCESS(NtAccessStatus)) { /* Access denied */ SetLastError(RtlNtStatusToDosError(NtAccessStatus)); *AccessStatus = FALSE; } else { /* Access granted */ *AccessStatus = TRUE; } /* Check succeeded */ return TRUE; } /* * @unimplemented */ BOOL WINAPI AccessCheckByType( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID PrincipalSelfSid, HANDLE ClientToken, DWORD DesiredAccess, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, LPDWORD PrivilegeSetLength, LPDWORD GrantedAccess, LPBOOL AccessStatus) { FIXME("stub\n"); *AccessStatus = TRUE; return !*AccessStatus; } /* * @implemented */ BOOL WINAPI OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle) { NTSTATUS Status; Status = NtOpenProcessToken(ProcessHandle, DesiredAccess, TokenHandle); if (!NT_SUCCESS(Status)) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } return TRUE; } /* * @implemented */ BOOL WINAPI OpenThreadToken(HANDLE ThreadHandle, DWORD DesiredAccess, BOOL OpenAsSelf, PHANDLE TokenHandle) { NTSTATUS Status; Status = NtOpenThreadToken(ThreadHandle, DesiredAccess, OpenAsSelf, TokenHandle); if (!NT_SUCCESS(Status)) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } return TRUE; } /* * @implemented */ BOOL WINAPI SetThreadToken(IN PHANDLE ThreadHandle OPTIONAL, IN HANDLE TokenHandle) { NTSTATUS Status; HANDLE hThread; hThread = (ThreadHandle != NULL) ? *ThreadHandle : NtCurrentThread(); Status = NtSetInformationThread(hThread, ThreadImpersonationToken, &TokenHandle, sizeof(HANDLE)); if (!NT_SUCCESS(Status)) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } return TRUE; } /* * @implemented */ BOOL WINAPI DuplicateTokenEx(IN HANDLE ExistingTokenHandle, IN DWORD dwDesiredAccess, IN LPSECURITY_ATTRIBUTES lpTokenAttributes OPTIONAL, IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, IN TOKEN_TYPE TokenType, OUT PHANDLE DuplicateTokenHandle) { OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS Status; SECURITY_QUALITY_OF_SERVICE Sqos; Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); Sqos.ImpersonationLevel = ImpersonationLevel; Sqos.ContextTrackingMode = 0; Sqos.EffectiveOnly = FALSE; if (lpTokenAttributes != NULL) { InitializeObjectAttributes(&ObjectAttributes, NULL, lpTokenAttributes->bInheritHandle ? OBJ_INHERIT : 0, NULL, lpTokenAttributes->lpSecurityDescriptor); } else { InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); } ObjectAttributes.SecurityQualityOfService = &Sqos; Status = NtDuplicateToken(ExistingTokenHandle, dwDesiredAccess, &ObjectAttributes, FALSE, TokenType, DuplicateTokenHandle); if (!NT_SUCCESS(Status)) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } return TRUE; } /* * @implemented */ BOOL WINAPI DuplicateToken(IN HANDLE ExistingTokenHandle, IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, OUT PHANDLE DuplicateTokenHandle) { return DuplicateTokenEx(ExistingTokenHandle, TOKEN_IMPERSONATE | TOKEN_QUERY, NULL, ImpersonationLevel, TokenImpersonation, DuplicateTokenHandle); } /* * @implemented */ BOOL WINAPI CheckTokenMembership(IN HANDLE ExistingTokenHandle, IN PSID SidToCheck, OUT PBOOL IsMember) { PISECURITY_DESCRIPTOR SecurityDescriptor = NULL; ACCESS_MASK GrantedAccess; struct { PRIVILEGE_SET PrivilegeSet; LUID_AND_ATTRIBUTES Privileges[4]; } PrivBuffer; ULONG PrivBufferSize = sizeof(PrivBuffer); GENERIC_MAPPING GenericMapping = { STANDARD_RIGHTS_READ, STANDARD_RIGHTS_WRITE, STANDARD_RIGHTS_EXECUTE, STANDARD_RIGHTS_ALL }; PACL Dacl; ULONG SidLen; HANDLE hToken = NULL; NTSTATUS Status, AccessStatus; /* doesn't return gracefully if IsMember is NULL! */ *IsMember = FALSE; SidLen = RtlLengthSid(SidToCheck); if (ExistingTokenHandle == NULL) { Status = NtOpenThreadToken(NtCurrentThread(), TOKEN_QUERY, FALSE, &hToken); if (Status == STATUS_NO_TOKEN) { /* we're not impersonating, open the primary token */ Status = NtOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY | TOKEN_DUPLICATE, &hToken); if (NT_SUCCESS(Status)) { HANDLE hNewToken = FALSE; BOOL DupRet; /* duplicate the primary token to create an impersonation token */ DupRet = DuplicateTokenEx(hToken, TOKEN_QUERY | TOKEN_IMPERSONATE, NULL, SecurityImpersonation, TokenImpersonation, &hNewToken); NtClose(hToken); if (!DupRet) { WARN("Failed to duplicate the primary token!\n"); return FALSE; } hToken = hNewToken; } } if (!NT_SUCCESS(Status)) { goto Cleanup; } } else { hToken = ExistingTokenHandle; } /* create a security descriptor */ SecurityDescriptor = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(SECURITY_DESCRIPTOR) + sizeof(ACL) + SidLen + sizeof(ACCESS_ALLOWED_ACE)); if (SecurityDescriptor == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } Status = RtlCreateSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* set the owner and group */ Status = RtlSetOwnerSecurityDescriptor(SecurityDescriptor, SidToCheck, FALSE); if (!NT_SUCCESS(Status)) { goto Cleanup; } Status = RtlSetGroupSecurityDescriptor(SecurityDescriptor, SidToCheck, FALSE); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* create the DACL */ Dacl = (PACL)(SecurityDescriptor + 1); Status = RtlCreateAcl(Dacl, sizeof(ACL) + SidLen + sizeof(ACCESS_ALLOWED_ACE), ACL_REVISION); if (!NT_SUCCESS(Status)) { goto Cleanup; } Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, 0x1, SidToCheck); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* assign the DACL to the security descriptor */ Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, TRUE, Dacl, FALSE); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* it's time to perform the access check. Just use _some_ desired access right (same as for the ACE) and see if we're getting it granted. This indicates our SID is a member of the token. We however can't use a generic access right as those aren't mapped and return an error (STATUS_GENERIC_NOT_MAPPED). */ Status = NtAccessCheck(SecurityDescriptor, hToken, 0x1, &GenericMapping, &PrivBuffer.PrivilegeSet, &PrivBufferSize, &GrantedAccess, &AccessStatus); if (NT_SUCCESS(Status) && NT_SUCCESS(AccessStatus) && (GrantedAccess == 0x1)) { *IsMember = TRUE; } Cleanup: if (hToken != NULL && hToken != ExistingTokenHandle) { NtClose(hToken); } if (SecurityDescriptor != NULL) { RtlFreeHeap(RtlGetProcessHeap(), 0, SecurityDescriptor); } if (!NT_SUCCESS(Status)) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } return TRUE; } /* * @implemented */ BOOL WINAPI IsTokenRestricted(HANDLE TokenHandle) { ULONG RetLength; PTOKEN_GROUPS lpGroups; NTSTATUS Status; BOOL Ret = FALSE; /* determine the required buffer size and allocate enough memory to read the list of restricted SIDs */ Status = NtQueryInformationToken(TokenHandle, TokenRestrictedSids, NULL, 0, &RetLength); if (Status != STATUS_BUFFER_TOO_SMALL) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } AllocAndReadRestrictedSids: lpGroups = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), 0, RetLength); if (lpGroups == NULL) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; } /* actually read the list of the restricted SIDs */ Status = NtQueryInformationToken(TokenHandle, TokenRestrictedSids, lpGroups, RetLength, &RetLength); if (NT_SUCCESS(Status)) { Ret = (lpGroups->GroupCount != 0); } else if (Status == STATUS_BUFFER_TOO_SMALL) { /* looks like the token was modified in the meanwhile, let's just try again */ HeapFree(GetProcessHeap(), 0, lpGroups); goto AllocAndReadRestrictedSids; } else { SetLastError(RtlNtStatusToDosError(Status)); } /* free allocated memory */ HeapFree(GetProcessHeap(), 0, lpGroups); return Ret; } BOOL WINAPI CreateRestrictedToken(HANDLE TokenHandle, DWORD Flags, DWORD DisableSidCount, PSID_AND_ATTRIBUTES pSidAndAttributes, DWORD DeletePrivilegeCount, PLUID_AND_ATTRIBUTES pLUIDAndAttributes, DWORD RestrictedSidCount, PSID_AND_ATTRIBUTES pSIDAndAttributes, PHANDLE NewTokenHandle) { UNIMPLEMENTED; return FALSE; } /* * @unimplemented */ PSID WINAPI GetSiteSidFromToken(IN HANDLE TokenHandle) { PTOKEN_GROUPS RestrictedSids; ULONG RetLen; UINT i; NTSTATUS Status; PSID PSiteSid = NULL; SID_IDENTIFIER_AUTHORITY InternetSiteAuthority = {SECURITY_INTERNETSITE_AUTHORITY}; Status = NtQueryInformationToken(TokenHandle, TokenRestrictedSids, NULL, 0, &RetLen); if (Status != STATUS_BUFFER_TOO_SMALL) { SetLastError(RtlNtStatusToDosError(Status)); return NULL; } RestrictedSids = (PTOKEN_GROUPS)RtlAllocateHeap(RtlGetProcessHeap(), 0, RetLen); if (RestrictedSids == NULL) { SetLastError(ERROR_OUTOFMEMORY); return NULL; } Status = NtQueryInformationToken(TokenHandle, TokenRestrictedSids, RestrictedSids, RetLen, &RetLen); if (NT_SUCCESS(Status)) { for (i = 0; i < RestrictedSids->GroupCount; i++) { SID* RSSid = RestrictedSids->Groups[i].Sid; if (RtlCompareMemory(&(RSSid->IdentifierAuthority), &InternetSiteAuthority, sizeof(SID_IDENTIFIER_AUTHORITY)) == sizeof(SID_IDENTIFIER_AUTHORITY)) { PSiteSid = RtlAllocateHeap(RtlGetProcessHeap(), 0, RtlLengthSid((RestrictedSids-> Groups[i]).Sid)); if (PSiteSid == NULL) { SetLastError(ERROR_OUTOFMEMORY); } else { RtlCopySid(RtlLengthSid(RestrictedSids->Groups[i].Sid), PSiteSid, RestrictedSids->Groups[i].Sid); } break; } } } else { SetLastError(RtlNtStatusToDosError(Status)); } RtlFreeHeap(RtlGetProcessHeap(), 0, RestrictedSids); return PSiteSid; } BOOL WINAPI CreateProcessWithTokenW(IN HANDLE hToken, IN DWORD dwLogonFlags, IN LPCWSTR lpApplicationName OPTIONAL, IN OUT LPWSTR lpCommandLine OPTIONAL, IN DWORD dwCreationFlags, IN LPVOID lpEnvironment OPTIONAL, IN LPCWSTR lpCurrentDirectory OPTIONAL, IN LPSTARTUPINFOW lpStartupInfo, OUT LPPROCESS_INFORMATION lpProcessInfo) { UNIMPLEMENTED; return FALSE; }