/* * COPYRIGHT: See COPYING in the top level directory * WINE COPYRIGHT: * Copyright 1999, 2000 Juergen Schmied * Copyright 2003 CodeWeavers Inc. (Ulrich Czekalla) * Copyright 2006 Robert Reif * * PROJECT: ReactOS system libraries * FILE: dll/win32/advapi32/sec/misc.c * PURPOSE: Miscellaneous security functions (some ported from Wine) */ #include WINE_DEFAULT_DEBUG_CHANNEL(advapi); /* Interface to ntmarta.dll ***************************************************/ NTMARTA NtMartaStatic = { 0 }; static PNTMARTA NtMarta = NULL; #define FindNtMartaProc(Name) \ NtMartaStatic.Name = (PVOID)GetProcAddress(NtMartaStatic.hDllInstance, \ "Acc" # Name ); \ if (NtMartaStatic.Name == NULL) \ { \ return GetLastError(); \ } static DWORD LoadAndInitializeNtMarta(VOID) { /* this code may be executed simultaneously by multiple threads in case they're trying to initialize the interface at the same time, but that's no problem because the pointers returned by GetProcAddress will be the same. However, only one of the threads will change the NtMarta pointer to the NtMartaStatic structure, the others threads will detect that there were other threads initializing the structure faster and will release the reference to the DLL */ NtMartaStatic.hDllInstance = LoadLibraryW(L"ntmarta.dll"); if (NtMartaStatic.hDllInstance == NULL) { return GetLastError(); } #if 0 FindNtMartaProc(LookupAccountTrustee); FindNtMartaProc(LookupAccountName); FindNtMartaProc(LookupAccountSid); FindNtMartaProc(SetEntriesInAList); FindNtMartaProc(ConvertAccessToSecurityDescriptor); FindNtMartaProc(ConvertSDToAccess); FindNtMartaProc(ConvertAclToAccess); FindNtMartaProc(GetAccessForTrustee); FindNtMartaProc(GetExplicitEntries); #endif FindNtMartaProc(RewriteGetNamedRights); FindNtMartaProc(RewriteSetNamedRights); FindNtMartaProc(RewriteGetHandleRights); FindNtMartaProc(RewriteSetHandleRights); FindNtMartaProc(RewriteSetEntriesInAcl); FindNtMartaProc(RewriteGetExplicitEntriesFromAcl); FindNtMartaProc(TreeResetNamedSecurityInfo); FindNtMartaProc(GetInheritanceSource); FindNtMartaProc(FreeIndexArray); return ERROR_SUCCESS; } DWORD CheckNtMartaPresent(VOID) { DWORD ErrorCode; if (InterlockedCompareExchangePointer((PVOID)&NtMarta, NULL, NULL) == NULL) { /* we're the first one trying to use ntmarta, initialize it and change the pointer after initialization */ ErrorCode = LoadAndInitializeNtMarta(); if (ErrorCode == ERROR_SUCCESS) { /* try change the NtMarta pointer */ if (InterlockedCompareExchangePointer((PVOID)&NtMarta, &NtMartaStatic, NULL) != NULL) { /* another thread initialized ntmarta in the meanwhile, release the reference of the dll loaded. */ FreeLibrary(NtMartaStatic.hDllInstance); } } #if DBG else { ERR("Failed to init ntmarta.dll! Error: 0x%x\n", ErrorCode); } #endif } else { /* ntmarta was already initialized */ ErrorCode = ERROR_SUCCESS; } return ErrorCode; } VOID UnloadNtMarta(VOID) { if (InterlockedExchangePointer((PVOID)&NtMarta, NULL) != NULL) { FreeLibrary(NtMartaStatic.hDllInstance); } } /******************************************************************************/ /* * @implemented */ BOOL WINAPI ImpersonateAnonymousToken(IN HANDLE ThreadHandle) { NTSTATUS Status; Status = NtImpersonateAnonymousToken(ThreadHandle); if (!NT_SUCCESS(Status)) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } return TRUE; } /* * @implemented */ BOOL WINAPI ImpersonateLoggedOnUser(HANDLE hToken) { SECURITY_QUALITY_OF_SERVICE Qos; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE NewToken; TOKEN_TYPE Type; ULONG ReturnLength; BOOL Duplicated; NTSTATUS Status; /* Get the token type */ Status = NtQueryInformationToken(hToken, TokenType, &Type, sizeof(TOKEN_TYPE), &ReturnLength); if (!NT_SUCCESS(Status)) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } if (Type == TokenPrimary) { /* Create a duplicate impersonation token */ Qos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); Qos.ImpersonationLevel = SecurityImpersonation; Qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; Qos.EffectiveOnly = FALSE; ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES); ObjectAttributes.RootDirectory = NULL; ObjectAttributes.ObjectName = NULL; ObjectAttributes.Attributes = 0; ObjectAttributes.SecurityDescriptor = NULL; ObjectAttributes.SecurityQualityOfService = &Qos; Status = NtDuplicateToken(hToken, TOKEN_IMPERSONATE | TOKEN_QUERY, &ObjectAttributes, FALSE, TokenImpersonation, &NewToken); if (!NT_SUCCESS(Status)) { ERR("NtDuplicateToken failed: Status %08x\n", Status); SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } Duplicated = TRUE; } else { /* User the original impersonation token */ NewToken = hToken; Duplicated = FALSE; } /* Impersonate the the current thread */ Status = NtSetInformationThread(NtCurrentThread(), ThreadImpersonationToken, &NewToken, sizeof(HANDLE)); if (Duplicated != FALSE) { NtClose(NewToken); } if (!NT_SUCCESS(Status)) { ERR("NtSetInformationThread failed: Status %08x\n", Status); SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } return TRUE; } /****************************************************************************** * GetUserNameA [ADVAPI32.@] * * Get the current user name. * * PARAMS * lpszName [O] Destination for the user name. * lpSize [I/O] Size of lpszName. * * * @implemented */ BOOL WINAPI GetUserNameA(LPSTR lpszName, LPDWORD lpSize) { UNICODE_STRING NameW; ANSI_STRING NameA; BOOL Ret; /* apparently Win doesn't check whether lpSize is valid at all! */ NameW.MaximumLength = (*lpSize) * sizeof(WCHAR); NameW.Buffer = LocalAlloc(LMEM_FIXED, NameW.MaximumLength); if(NameW.Buffer == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } NameA.Length = 0; NameA.MaximumLength = ((*lpSize) < 0xFFFF ? (USHORT)(*lpSize) : 0xFFFF); NameA.Buffer = lpszName; Ret = GetUserNameW(NameW.Buffer, lpSize); if(Ret) { NameW.Length = (*lpSize - 1) * sizeof(WCHAR); RtlUnicodeStringToAnsiString(&NameA, &NameW, FALSE); *lpSize = NameA.Length + 1; } LocalFree(NameW.Buffer); return Ret; } /****************************************************************************** * GetUserNameW [ADVAPI32.@] * * See GetUserNameA. * * @implemented */ BOOL WINAPI GetUserNameW(LPWSTR lpszName, LPDWORD lpSize) { HANDLE hToken = INVALID_HANDLE_VALUE; DWORD tu_len = 0; char* tu_buf = NULL; TOKEN_USER* token_user = NULL; DWORD an_len = 0; SID_NAME_USE snu = SidTypeUser; WCHAR* domain_name = NULL; DWORD dn_len = 0; if (!OpenThreadToken (GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken)) { DWORD dwLastError = GetLastError(); if (dwLastError != ERROR_NO_TOKEN && dwLastError != ERROR_NO_IMPERSONATION_TOKEN) { /* don't call SetLastError(), as OpenThreadToken() ought to have set one */ return FALSE; } if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { /* don't call SetLastError(), as OpenProcessToken() ought to have set one */ return FALSE; } } tu_buf = LocalAlloc(LMEM_FIXED, 36); if (!tu_buf) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); CloseHandle(hToken); return FALSE; } if (!GetTokenInformation(hToken, TokenUser, tu_buf, 36, &tu_len) || tu_len > 36) { LocalFree(tu_buf); tu_buf = LocalAlloc(LMEM_FIXED, tu_len); if (!tu_buf) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); CloseHandle(hToken); return FALSE; } if (!GetTokenInformation(hToken, TokenUser, tu_buf, tu_len, &tu_len)) { /* don't call SetLastError(), as GetTokenInformation() ought to have set one */ LocalFree(tu_buf); CloseHandle(hToken); return FALSE; } } CloseHandle(hToken); token_user = (TOKEN_USER*)tu_buf; an_len = *lpSize; dn_len = 32; domain_name = LocalAlloc(LMEM_FIXED, dn_len * sizeof(WCHAR)); if (!domain_name) { LocalFree(tu_buf); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } if (!LookupAccountSidW(NULL, token_user->User.Sid, lpszName, &an_len, domain_name, &dn_len, &snu) || dn_len > 32) { if (dn_len > 32) { LocalFree(domain_name); domain_name = LocalAlloc(LMEM_FIXED, dn_len * sizeof(WCHAR)); if (!domain_name) { LocalFree(tu_buf); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } } an_len = *lpSize; if (!LookupAccountSidW(NULL, token_user->User.Sid, lpszName, &an_len, domain_name, &dn_len, &snu)) { /* don't call SetLastError(), as LookupAccountSid() ought to have set one */ LocalFree(domain_name); LocalFree(tu_buf); *lpSize = an_len; return FALSE; } } LocalFree(domain_name); LocalFree(tu_buf); *lpSize = an_len + 1; return TRUE; } /****************************************************************************** * LookupAccountSidA [ADVAPI32.@] * * @implemented */ BOOL WINAPI LookupAccountSidA(LPCSTR lpSystemName, PSID lpSid, LPSTR lpName, LPDWORD cchName, LPSTR lpReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse) { UNICODE_STRING NameW, ReferencedDomainNameW, SystemNameW; LPWSTR NameBuffer = NULL; LPWSTR ReferencedDomainNameBuffer = NULL; DWORD dwName, dwReferencedDomainName; BOOL Ret; /* * save the buffer sizes the caller passed to us, as they may get modified and * we require the original values when converting back to ansi */ dwName = *cchName; dwReferencedDomainName = *cchReferencedDomainName; /* allocate buffers for the unicode strings to receive */ if (dwName > 0) { NameBuffer = LocalAlloc(LMEM_FIXED, dwName * sizeof(WCHAR)); if (NameBuffer == NULL) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; } } else NameBuffer = NULL; if (dwReferencedDomainName > 0) { ReferencedDomainNameBuffer = LocalAlloc(LMEM_FIXED, dwReferencedDomainName * sizeof(WCHAR)); if (ReferencedDomainNameBuffer == NULL) { if (dwName > 0) { LocalFree(NameBuffer); } SetLastError(ERROR_OUTOFMEMORY); return FALSE; } } else ReferencedDomainNameBuffer = NULL; /* convert the system name to unicode - if present */ if (lpSystemName != NULL) { ANSI_STRING SystemNameA; RtlInitAnsiString(&SystemNameA, lpSystemName); RtlAnsiStringToUnicodeString(&SystemNameW, &SystemNameA, TRUE); } else SystemNameW.Buffer = NULL; /* it's time to call the unicode version */ Ret = LookupAccountSidW(SystemNameW.Buffer, lpSid, NameBuffer, cchName, ReferencedDomainNameBuffer, cchReferencedDomainName, peUse); if (Ret) { /* * convert unicode strings back to ansi, don't forget that we can't convert * more than 0xFFFF (USHORT) characters! Also don't forget to explicitly * terminate the converted string, the Rtl functions don't do that! */ if (lpName != NULL) { ANSI_STRING NameA; NameA.Length = 0; NameA.MaximumLength = ((dwName <= 0xFFFF) ? (USHORT)dwName : 0xFFFF); NameA.Buffer = lpName; RtlInitUnicodeString(&NameW, NameBuffer); RtlUnicodeStringToAnsiString(&NameA, &NameW, FALSE); NameA.Buffer[NameA.Length] = '\0'; } if (lpReferencedDomainName != NULL) { ANSI_STRING ReferencedDomainNameA; ReferencedDomainNameA.Length = 0; ReferencedDomainNameA.MaximumLength = ((dwReferencedDomainName <= 0xFFFF) ? (USHORT)dwReferencedDomainName : 0xFFFF); ReferencedDomainNameA.Buffer = lpReferencedDomainName; RtlInitUnicodeString(&ReferencedDomainNameW, ReferencedDomainNameBuffer); RtlUnicodeStringToAnsiString(&ReferencedDomainNameA, &ReferencedDomainNameW, FALSE); ReferencedDomainNameA.Buffer[ReferencedDomainNameA.Length] = '\0'; } } /* free previously allocated buffers */ if (SystemNameW.Buffer != NULL) { RtlFreeUnicodeString(&SystemNameW); } if (NameBuffer != NULL) { LocalFree(NameBuffer); } if (ReferencedDomainNameBuffer != NULL) { LocalFree(ReferencedDomainNameBuffer); } return Ret; } /****************************************************************************** * LookupAccountSidW [ADVAPI32.@] * * @implemented */ BOOL WINAPI LookupAccountSidW(LPCWSTR pSystemName, PSID pSid, LPWSTR pAccountName, LPDWORD pdwAccountName, LPWSTR pDomainName, LPDWORD pdwDomainName, PSID_NAME_USE peUse) { LSA_UNICODE_STRING SystemName; LSA_OBJECT_ATTRIBUTES ObjectAttributes = {0}; LSA_HANDLE PolicyHandle = NULL; NTSTATUS Status; PLSA_REFERENCED_DOMAIN_LIST ReferencedDomain = NULL; PLSA_TRANSLATED_NAME TranslatedName = NULL; BOOL ret; DWORD dwAccountName, dwDomainName; RtlInitUnicodeString(&SystemName, pSystemName); Status = LsaOpenPolicy(&SystemName, &ObjectAttributes, POLICY_LOOKUP_NAMES, &PolicyHandle); if (!NT_SUCCESS(Status)) { SetLastError(LsaNtStatusToWinError(Status)); return FALSE; } Status = LsaLookupSids(PolicyHandle, 1, &pSid, &ReferencedDomain, &TranslatedName); LsaClose(PolicyHandle); if (!NT_SUCCESS(Status) || Status == STATUS_SOME_NOT_MAPPED) { SetLastError(LsaNtStatusToWinError(Status)); ret = FALSE; } else { ret = TRUE; dwAccountName = TranslatedName->Name.Length / sizeof(WCHAR); if (ReferencedDomain && ReferencedDomain->Entries > 0) dwDomainName = ReferencedDomain->Domains[0].Name.Length / sizeof(WCHAR); else dwDomainName = 0; if (*pdwAccountName <= dwAccountName || *pdwDomainName <= dwDomainName) { /* One or two buffers are insufficient, add up a char for NULL termination */ *pdwAccountName = dwAccountName + 1; *pdwDomainName = dwDomainName + 1; ret = FALSE; } else { /* Lengths are sufficient, copy the data */ if (dwAccountName) RtlCopyMemory(pAccountName, TranslatedName->Name.Buffer, dwAccountName * sizeof(WCHAR)); pAccountName[dwAccountName] = L'\0'; if (dwDomainName) RtlCopyMemory(pDomainName, ReferencedDomain->Domains[0].Name.Buffer, dwDomainName * sizeof(WCHAR)); pDomainName[dwDomainName] = L'\0'; *pdwAccountName = dwAccountName; *pdwDomainName = dwDomainName; if (peUse) *peUse = TranslatedName->Use; } if (!ret) SetLastError(ERROR_INSUFFICIENT_BUFFER); } if (ReferencedDomain) LsaFreeMemory(ReferencedDomain); if (TranslatedName) LsaFreeMemory(TranslatedName); return ret; } /****************************************************************************** * LookupAccountNameW [ADVAPI32.@] * * @implemented */ BOOL WINAPI LookupAccountNameW(LPCWSTR lpSystemName, LPCWSTR lpAccountName, PSID Sid, LPDWORD cbSid, LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse) { OBJECT_ATTRIBUTES ObjectAttributes = {0}; UNICODE_STRING SystemName; UNICODE_STRING AccountName; LSA_HANDLE PolicyHandle = NULL; PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains = NULL; PLSA_TRANSLATED_SID TranslatedSid = NULL; PSID pDomainSid; DWORD dwDomainNameLength; DWORD dwSidLength; UCHAR nSubAuthorities; BOOL bResult; NTSTATUS Status; TRACE("%s %s %p %p %p %p %p\n", lpSystemName, lpAccountName, Sid, cbSid, ReferencedDomainName, cchReferencedDomainName, peUse); RtlInitUnicodeString(&SystemName, lpSystemName); Status = LsaOpenPolicy(lpSystemName ? &SystemName : NULL, &ObjectAttributes, POLICY_LOOKUP_NAMES, &PolicyHandle); if (!NT_SUCCESS(Status)) { SetLastError(LsaNtStatusToWinError(Status)); return FALSE; } RtlInitUnicodeString(&AccountName, lpAccountName); Status = LsaLookupNames(PolicyHandle, 1, &AccountName, &ReferencedDomains, &TranslatedSid); LsaClose(PolicyHandle); if (!NT_SUCCESS(Status) || Status == STATUS_SOME_NOT_MAPPED) { SetLastError(LsaNtStatusToWinError(Status)); bResult = FALSE; } else { pDomainSid = ReferencedDomains->Domains[TranslatedSid->DomainIndex].Sid; nSubAuthorities = *GetSidSubAuthorityCount(pDomainSid); dwSidLength = GetSidLengthRequired(nSubAuthorities + 1); dwDomainNameLength = ReferencedDomains->Domains->Name.Length / sizeof(WCHAR); if (*cbSid < dwSidLength || *cchReferencedDomainName < dwDomainNameLength + 1) { *cbSid = dwSidLength; *cchReferencedDomainName = dwDomainNameLength + 1; bResult = FALSE; } else { CopySid(*cbSid, Sid, pDomainSid); *GetSidSubAuthorityCount(Sid) = nSubAuthorities + 1; *GetSidSubAuthority(Sid, (DWORD)nSubAuthorities) = TranslatedSid->RelativeId; RtlCopyMemory(ReferencedDomainName, ReferencedDomains->Domains->Name.Buffer, dwDomainNameLength * sizeof(WCHAR)); ReferencedDomainName[dwDomainNameLength] = L'\0'; *cchReferencedDomainName = dwDomainNameLength; *peUse = TranslatedSid->Use; bResult = TRUE; } if (bResult == FALSE) SetLastError(ERROR_INSUFFICIENT_BUFFER); } if (ReferencedDomains != NULL) LsaFreeMemory(ReferencedDomains); if (TranslatedSid != NULL) LsaFreeMemory(TranslatedSid); return bResult; } /********************************************************************** * LookupPrivilegeValueA EXPORTED * * @implemented */ BOOL WINAPI LookupPrivilegeValueA(LPCSTR lpSystemName, LPCSTR lpName, PLUID lpLuid) { UNICODE_STRING SystemName; UNICODE_STRING Name; BOOL Result; /* Remote system? */ if (lpSystemName != NULL) { RtlCreateUnicodeStringFromAsciiz(&SystemName, (LPSTR)lpSystemName); } else SystemName.Buffer = NULL; /* Check the privilege name is not NULL */ if (lpName == NULL) { SetLastError(ERROR_NO_SUCH_PRIVILEGE); return FALSE; } RtlCreateUnicodeStringFromAsciiz(&Name, (LPSTR)lpName); Result = LookupPrivilegeValueW(SystemName.Buffer, Name.Buffer, lpLuid); RtlFreeUnicodeString(&Name); /* Remote system? */ if (SystemName.Buffer != NULL) { RtlFreeUnicodeString(&SystemName); } return Result; } /********************************************************************** * LookupPrivilegeValueW * * @implemented */ BOOL WINAPI LookupPrivilegeValueW(LPCWSTR lpSystemName, LPCWSTR lpPrivilegeName, PLUID lpLuid) { OBJECT_ATTRIBUTES ObjectAttributes = {0}; UNICODE_STRING SystemName; UNICODE_STRING PrivilegeName; LSA_HANDLE PolicyHandle = NULL; NTSTATUS Status; TRACE("%S,%S,%p\n", lpSystemName, lpPrivilegeName, lpLuid); RtlInitUnicodeString(&SystemName, lpSystemName); Status = LsaOpenPolicy(lpSystemName ? &SystemName : NULL, &ObjectAttributes, POLICY_LOOKUP_NAMES, &PolicyHandle); if (!NT_SUCCESS(Status)) { SetLastError(LsaNtStatusToWinError(Status)); return FALSE; } RtlInitUnicodeString(&PrivilegeName, lpPrivilegeName); Status = LsaLookupPrivilegeValue(PolicyHandle, &PrivilegeName, lpLuid); LsaClose(PolicyHandle); if (!NT_SUCCESS(Status)) { SetLastError(LsaNtStatusToWinError(Status)); return FALSE; } return TRUE; } /********************************************************************** * LookupPrivilegeNameW EXPORTED * * @implemented */ BOOL WINAPI LookupPrivilegeNameW(LPCWSTR lpSystemName, PLUID lpLuid, LPWSTR lpName, LPDWORD cchName) { OBJECT_ATTRIBUTES ObjectAttributes = {0}; UNICODE_STRING SystemName; PUNICODE_STRING PrivilegeName = NULL; LSA_HANDLE PolicyHandle = NULL; NTSTATUS Status; TRACE("%S,%p,%p,%p\n", lpSystemName, lpLuid, lpName, cchName); RtlInitUnicodeString(&SystemName, lpSystemName); Status = LsaOpenPolicy(lpSystemName ? &SystemName : NULL, &ObjectAttributes, POLICY_LOOKUP_NAMES, &PolicyHandle); if (!NT_SUCCESS(Status)) { SetLastError(LsaNtStatusToWinError(Status)); return FALSE; } Status = LsaLookupPrivilegeName(PolicyHandle, lpLuid, &PrivilegeName); if (NT_SUCCESS(Status)) { if (PrivilegeName->Length + sizeof(WCHAR) > *cchName * sizeof(WCHAR)) { Status = STATUS_BUFFER_TOO_SMALL; *cchName = (PrivilegeName->Length + sizeof(WCHAR)) / sizeof(WCHAR); } else { RtlMoveMemory(lpName, PrivilegeName->Buffer, PrivilegeName->Length); lpName[PrivilegeName->Length / sizeof(WCHAR)] = 0; *cchName = PrivilegeName->Length / sizeof(WCHAR); } LsaFreeMemory(PrivilegeName->Buffer); LsaFreeMemory(PrivilegeName); } LsaClose(PolicyHandle); if (!NT_SUCCESS(Status)) { SetLastError(LsaNtStatusToWinError(Status)); return FALSE; } return TRUE; } /********************************************************************** * LookupPrivilegeDisplayNameW EXPORTED * * @unimplemented */ BOOL WINAPI LookupPrivilegeDisplayNameW(LPCWSTR lpSystemName, LPCWSTR lpName, LPWSTR lpDisplayName, LPDWORD cchDisplayName, LPDWORD lpLanguageId) { OBJECT_ATTRIBUTES ObjectAttributes = {0}; UNICODE_STRING SystemName, Name; PUNICODE_STRING DisplayName; LSA_HANDLE PolicyHandle = NULL; USHORT LanguageId; NTSTATUS Status; TRACE("%S,%S,%p,%p,%p\n", lpSystemName, lpName, lpDisplayName, cchDisplayName, lpLanguageId); RtlInitUnicodeString(&SystemName, lpSystemName); RtlInitUnicodeString(&Name, lpName); Status = LsaOpenPolicy(lpSystemName ? &SystemName : NULL, &ObjectAttributes, POLICY_LOOKUP_NAMES, &PolicyHandle); if (!NT_SUCCESS(Status)) { SetLastError(LsaNtStatusToWinError(Status)); return FALSE; } Status = LsaLookupPrivilegeDisplayName(PolicyHandle, &Name, &DisplayName, &LanguageId); if (NT_SUCCESS(Status)) { *lpLanguageId = LanguageId; if (DisplayName->Length + sizeof(WCHAR) > *cchDisplayName * sizeof(WCHAR)) { Status = STATUS_BUFFER_TOO_SMALL; *cchDisplayName = (DisplayName->Length + sizeof(WCHAR)) / sizeof(WCHAR); } else { RtlMoveMemory(lpDisplayName, DisplayName->Buffer, DisplayName->Length); lpDisplayName[DisplayName->Length / sizeof(WCHAR)] = 0; *cchDisplayName = DisplayName->Length / sizeof(WCHAR); } LsaFreeMemory(DisplayName->Buffer); LsaFreeMemory(DisplayName); } LsaClose(PolicyHandle); if (!NT_SUCCESS(Status)) { SetLastError(LsaNtStatusToWinError(Status)); return FALSE; } return TRUE; } static DWORD pGetSecurityInfoCheck(SECURITY_INFORMATION SecurityInfo, PSID *ppsidOwner, PSID *ppsidGroup, PACL *ppDacl, PACL *ppSacl, PSECURITY_DESCRIPTOR* ppSecurityDescriptor) { if ((SecurityInfo & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)) && ppSecurityDescriptor == NULL) { /* if one of the SIDs or ACLs are present, the security descriptor most not be NULL */ return ERROR_INVALID_PARAMETER; } else { /* reset the pointers unless they're ignored */ if ((SecurityInfo & OWNER_SECURITY_INFORMATION) && ppsidOwner != NULL) { *ppsidOwner = NULL; } if ((SecurityInfo & GROUP_SECURITY_INFORMATION) && ppsidGroup != NULL) { *ppsidGroup = NULL; } if ((SecurityInfo & DACL_SECURITY_INFORMATION) && ppDacl != NULL) { *ppDacl = NULL; } if ((SecurityInfo & SACL_SECURITY_INFORMATION) && ppSacl != NULL) { *ppSacl = NULL; } if (SecurityInfo & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)) { *ppSecurityDescriptor = NULL; } return ERROR_SUCCESS; } } static DWORD pSetSecurityInfoCheck(PSECURITY_DESCRIPTOR pSecurityDescriptor, SECURITY_INFORMATION SecurityInfo, PSID psidOwner, PSID psidGroup, PACL pDacl, PACL pSacl) { /* initialize a security descriptor on the stack */ if (!InitializeSecurityDescriptor(pSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION)) { return GetLastError(); } if (SecurityInfo & OWNER_SECURITY_INFORMATION) { if (RtlValidSid(psidOwner)) { if (!SetSecurityDescriptorOwner(pSecurityDescriptor, psidOwner, FALSE)) { return GetLastError(); } } else { return ERROR_INVALID_PARAMETER; } } if (SecurityInfo & GROUP_SECURITY_INFORMATION) { if (RtlValidSid(psidGroup)) { if (!SetSecurityDescriptorGroup(pSecurityDescriptor, psidGroup, FALSE)) { return GetLastError(); } } else { return ERROR_INVALID_PARAMETER; } } if (SecurityInfo & DACL_SECURITY_INFORMATION) { if (pDacl != NULL) { if (SetSecurityDescriptorDacl(pSecurityDescriptor, TRUE, pDacl, FALSE)) { /* check if the DACL needs to be protected from being modified by inheritable ACEs */ if (SecurityInfo & PROTECTED_DACL_SECURITY_INFORMATION) { goto ProtectDacl; } } else { return GetLastError(); } } else { ProtectDacl: /* protect the DACL from being modified by inheritable ACEs */ if (!SetSecurityDescriptorControl(pSecurityDescriptor, SE_DACL_PROTECTED, SE_DACL_PROTECTED)) { return GetLastError(); } } } if (SecurityInfo & SACL_SECURITY_INFORMATION) { if (pSacl != NULL) { if (SetSecurityDescriptorSacl(pSecurityDescriptor, TRUE, pSacl, FALSE)) { /* check if the SACL needs to be protected from being modified by inheritable ACEs */ if (SecurityInfo & PROTECTED_SACL_SECURITY_INFORMATION) { goto ProtectSacl; } } else { return GetLastError(); } } else { ProtectSacl: /* protect the SACL from being modified by inheritable ACEs */ if (!SetSecurityDescriptorControl(pSecurityDescriptor, SE_SACL_PROTECTED, SE_SACL_PROTECTED)) { return GetLastError(); } } } return ERROR_SUCCESS; } /********************************************************************** * GetNamedSecurityInfoW EXPORTED * * @implemented */ DWORD WINAPI GetNamedSecurityInfoW(LPWSTR pObjectName, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID *ppsidOwner, PSID *ppsidGroup, PACL *ppDacl, PACL *ppSacl, PSECURITY_DESCRIPTOR *ppSecurityDescriptor) { DWORD ErrorCode; if (pObjectName != NULL) { ErrorCode = CheckNtMartaPresent(); if (ErrorCode == ERROR_SUCCESS) { ErrorCode = pGetSecurityInfoCheck(SecurityInfo, ppsidOwner, ppsidGroup, ppDacl, ppSacl, ppSecurityDescriptor); if (ErrorCode == ERROR_SUCCESS) { /* call the MARTA provider */ ErrorCode = AccRewriteGetNamedRights(pObjectName, ObjectType, SecurityInfo, ppsidOwner, ppsidGroup, ppDacl, ppSacl, ppSecurityDescriptor); } } } else ErrorCode = ERROR_INVALID_PARAMETER; return ErrorCode; } /********************************************************************** * SetNamedSecurityInfoW EXPORTED * * @implemented */ DWORD WINAPI SetNamedSecurityInfoW(LPWSTR pObjectName, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID psidOwner, PSID psidGroup, PACL pDacl, PACL pSacl) { DWORD ErrorCode; if (pObjectName != NULL) { ErrorCode = CheckNtMartaPresent(); if (ErrorCode == ERROR_SUCCESS) { SECURITY_DESCRIPTOR SecurityDescriptor; ErrorCode = pSetSecurityInfoCheck(&SecurityDescriptor, SecurityInfo, psidOwner, psidGroup, pDacl, pSacl); if (ErrorCode == ERROR_SUCCESS) { /* call the MARTA provider */ ErrorCode = AccRewriteSetNamedRights(pObjectName, ObjectType, SecurityInfo, &SecurityDescriptor); } } } else ErrorCode = ERROR_INVALID_PARAMETER; return ErrorCode; } /********************************************************************** * GetSecurityInfo EXPORTED * * @implemented */ DWORD WINAPI GetSecurityInfo(HANDLE handle, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID *ppsidOwner, PSID *ppsidGroup, PACL *ppDacl, PACL *ppSacl, PSECURITY_DESCRIPTOR *ppSecurityDescriptor) { DWORD ErrorCode; if (handle != NULL) { ErrorCode = CheckNtMartaPresent(); if (ErrorCode == ERROR_SUCCESS) { ErrorCode = pGetSecurityInfoCheck(SecurityInfo, ppsidOwner, ppsidGroup, ppDacl, ppSacl, ppSecurityDescriptor); if (ErrorCode == ERROR_SUCCESS) { /* call the MARTA provider */ ErrorCode = AccRewriteGetHandleRights(handle, ObjectType, SecurityInfo, ppsidOwner, ppsidGroup, ppDacl, ppSacl, ppSecurityDescriptor); } } } else ErrorCode = ERROR_INVALID_HANDLE; return ErrorCode; } /********************************************************************** * SetSecurityInfo EXPORTED * * @implemented */ DWORD WINAPI SetSecurityInfo(HANDLE handle, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID psidOwner, PSID psidGroup, PACL pDacl, PACL pSacl) { DWORD ErrorCode; if (handle != NULL) { ErrorCode = CheckNtMartaPresent(); if (ErrorCode == ERROR_SUCCESS) { SECURITY_DESCRIPTOR SecurityDescriptor; ErrorCode = pSetSecurityInfoCheck(&SecurityDescriptor, SecurityInfo, psidOwner, psidGroup, pDacl, pSacl); if (ErrorCode == ERROR_SUCCESS) { /* call the MARTA provider */ ErrorCode = AccRewriteSetHandleRights(handle, ObjectType, SecurityInfo, &SecurityDescriptor); } } } else ErrorCode = ERROR_INVALID_HANDLE; return ErrorCode; } /* * @implemented */ BOOL WINAPI CreatePrivateObjectSecurity(PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CreatorDescriptor, PSECURITY_DESCRIPTOR *NewDescriptor, BOOL IsDirectoryObject, HANDLE Token, PGENERIC_MAPPING GenericMapping) { NTSTATUS Status; Status = RtlNewSecurityObject(ParentDescriptor, CreatorDescriptor, NewDescriptor, IsDirectoryObject, Token, GenericMapping); if (!NT_SUCCESS(Status)) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } return TRUE; } /* * @unimplemented */ BOOL WINAPI CreatePrivateObjectSecurityEx(PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CreatorDescriptor, PSECURITY_DESCRIPTOR* NewDescriptor, GUID* ObjectType, BOOL IsContainerObject, ULONG AutoInheritFlags, HANDLE Token, PGENERIC_MAPPING GenericMapping) { FIXME("%s() not implemented!\n", __FUNCTION__); return FALSE; } /* * @unimplemented */ BOOL WINAPI CreatePrivateObjectSecurityWithMultipleInheritance(PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CreatorDescriptor, PSECURITY_DESCRIPTOR* NewDescriptor, GUID** ObjectTypes, ULONG GuidCount, BOOL IsContainerObject, ULONG AutoInheritFlags, HANDLE Token, PGENERIC_MAPPING GenericMapping) { FIXME("%s() semi-stub\n", __FUNCTION__); return CreatePrivateObjectSecurity(ParentDescriptor, CreatorDescriptor, NewDescriptor, IsContainerObject, Token, GenericMapping); } /* * @implemented */ BOOL WINAPI DestroyPrivateObjectSecurity(PSECURITY_DESCRIPTOR *ObjectDescriptor) { NTSTATUS Status; Status = RtlDeleteSecurityObject(ObjectDescriptor); if (!NT_SUCCESS(Status)) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } return TRUE; } /* * @implemented */ BOOL WINAPI GetPrivateObjectSecurity(IN PSECURITY_DESCRIPTOR ObjectDescriptor, IN SECURITY_INFORMATION SecurityInformation, OUT PSECURITY_DESCRIPTOR ResultantDescriptor OPTIONAL, IN DWORD DescriptorLength, OUT PDWORD ReturnLength) { NTSTATUS Status; /* Call RTL */ Status = RtlQuerySecurityObject(ObjectDescriptor, SecurityInformation, ResultantDescriptor, DescriptorLength, ReturnLength); if (!NT_SUCCESS(Status)) { /* Fail */ SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } /* Success */ return TRUE; } /* * @implemented */ BOOL WINAPI SetPrivateObjectSecurity(SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ModificationDescriptor, PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor, PGENERIC_MAPPING GenericMapping, HANDLE Token) { NTSTATUS Status; Status = RtlSetSecurityObject(SecurityInformation, ModificationDescriptor, ObjectsSecurityDescriptor, GenericMapping, Token); if (!NT_SUCCESS(Status)) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } return TRUE; } /* * @implemented */ DWORD WINAPI TreeResetNamedSecurityInfoW(LPWSTR pObjectName, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID pOwner, PSID pGroup, PACL pDacl, PACL pSacl, BOOL KeepExplicit, FN_PROGRESSW fnProgress, PROG_INVOKE_SETTING ProgressInvokeSetting, PVOID Args) { DWORD ErrorCode; if (pObjectName != NULL) { ErrorCode = CheckNtMartaPresent(); if (ErrorCode == ERROR_SUCCESS) { switch (ObjectType) { case SE_FILE_OBJECT: case SE_REGISTRY_KEY: { /* check the SecurityInfo flags for sanity (both, the protected and unprotected dacl/sacl flag must not be passed together) */ if (((SecurityInfo & DACL_SECURITY_INFORMATION) && (SecurityInfo & (PROTECTED_DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION)) == (PROTECTED_DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION)) || ((SecurityInfo & SACL_SECURITY_INFORMATION) && (SecurityInfo & (PROTECTED_SACL_SECURITY_INFORMATION | UNPROTECTED_SACL_SECURITY_INFORMATION)) == (PROTECTED_SACL_SECURITY_INFORMATION | UNPROTECTED_SACL_SECURITY_INFORMATION))) { ErrorCode = ERROR_INVALID_PARAMETER; break; } /* call the MARTA provider */ ErrorCode = AccTreeResetNamedSecurityInfo(pObjectName, ObjectType, SecurityInfo, pOwner, pGroup, pDacl, pSacl, KeepExplicit, fnProgress, ProgressInvokeSetting, Args); break; } default: /* object type not supported */ ErrorCode = ERROR_INVALID_PARAMETER; break; } } } else ErrorCode = ERROR_INVALID_PARAMETER; return ErrorCode; } #ifdef HAS_FN_PROGRESSW typedef struct _INTERNAL_FNPROGRESSW_DATA { FN_PROGRESSA fnProgress; PVOID Args; } INTERNAL_FNPROGRESSW_DATA, *PINTERNAL_FNPROGRESSW_DATA; static VOID WINAPI InternalfnProgressW(LPWSTR pObjectName, DWORD Status, PPROG_INVOKE_SETTING pInvokeSetting, PVOID Args, BOOL SecuritySet) { PINTERNAL_FNPROGRESSW_DATA pifnProgressData = (PINTERNAL_FNPROGRESSW_DATA)Args; INT ObjectNameSize; LPSTR pObjectNameA; ObjectNameSize = WideCharToMultiByte(CP_ACP, 0, pObjectName, -1, NULL, 0, NULL, NULL); if (ObjectNameSize > 0) { pObjectNameA = RtlAllocateHeap(RtlGetProcessHeap(), 0, ObjectNameSize); if (pObjectNameA != NULL) { pObjectNameA[0] = '\0'; WideCharToMultiByte(CP_ACP, 0, pObjectName, -1, pObjectNameA, ObjectNameSize, NULL, NULL); pifnProgressData->fnProgress((LPWSTR)pObjectNameA, /* FIXME: wrong cast!! */ Status, pInvokeSetting, pifnProgressData->Args, SecuritySet); RtlFreeHeap(RtlGetProcessHeap(), 0, pObjectNameA); } } } #endif /* * @implemented */ DWORD WINAPI TreeResetNamedSecurityInfoA(LPSTR pObjectName, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID pOwner, PSID pGroup, PACL pDacl, PACL pSacl, BOOL KeepExplicit, FN_PROGRESSA fnProgress, PROG_INVOKE_SETTING ProgressInvokeSetting, PVOID Args) { #ifndef HAS_FN_PROGRESSW /* That's all this function does, at least up to w2k3... Even MS was too lazy to implement it... */ return ERROR_CALL_NOT_IMPLEMENTED; #else INTERNAL_FNPROGRESSW_DATA ifnProgressData; UNICODE_STRING ObjectName; DWORD Ret; if (!RtlCreateUnicodeStringFromAsciiz(&ObjectName, pObjectName)) { return ERROR_NOT_ENOUGH_MEMORY; } ifnProgressData.fnProgress = fnProgress; ifnProgressData.Args = Args; Ret = TreeResetNamedSecurityInfoW(ObjectName.Buffer, ObjectType, SecurityInfo, pOwner, pGroup, pDacl, pSacl, KeepExplicit, (fnProgress != NULL ? InternalfnProgressW : NULL), ProgressInvokeSetting, &ifnProgressData); RtlFreeUnicodeString(&ObjectName); return Ret; #endif } /* EOF */