reactos/dll/win32/ntmarta/ntmarta.c
Amine Khaldi 527f2f9057 [SHELL/EXPERIMENTS]
* Create a branch for some evul shell experiments.

svn path=/branches/shell-experiments/; revision=61927
2014-02-02 19:37:27 +00:00

1685 lines
49 KiB
C

/*
* ReactOS MARTA provider
* Copyright (C) 2005 - 2006 ReactOS Team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* PROJECT: ReactOS MARTA provider
* FILE: lib/ntmarta/ntmarta.c
* PURPOSE: ReactOS MARTA provider
* PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
*
* UPDATE HISTORY:
* 07/26/2005 Created
*/
#include "ntmarta.h"
#define NDEBUG
#include <debug.h>
HINSTANCE hDllInstance;
static ACCESS_MODE
AccpGetAceAccessMode(IN PACE_HEADER AceHeader)
{
ACCESS_MODE Mode = NOT_USED_ACCESS;
switch (AceHeader->AceType)
{
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
Mode = GRANT_ACCESS;
break;
case ACCESS_DENIED_ACE_TYPE:
case ACCESS_DENIED_CALLBACK_ACE_TYPE:
case ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
case ACCESS_DENIED_OBJECT_ACE_TYPE:
Mode = DENY_ACCESS;
break;
case SYSTEM_AUDIT_ACE_TYPE:
case SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
case SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
if (AceHeader->AceFlags & FAILED_ACCESS_ACE_FLAG)
Mode = SET_AUDIT_FAILURE;
else if (AceHeader->AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG)
Mode = SET_AUDIT_SUCCESS;
break;
}
return Mode;
}
static UINT
AccpGetAceStructureSize(IN PACE_HEADER AceHeader)
{
UINT Size = 0;
switch (AceHeader->AceType)
{
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_DENIED_ACE_TYPE:
Size = FIELD_OFFSET(ACCESS_ALLOWED_ACE,
SidStart);
break;
case ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
case ACCESS_DENIED_CALLBACK_ACE_TYPE:
Size = FIELD_OFFSET(ACCESS_ALLOWED_CALLBACK_ACE,
SidStart);
break;
case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
case ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
{
PACCESS_ALLOWED_CALLBACK_OBJECT_ACE Ace = (PACCESS_ALLOWED_CALLBACK_OBJECT_ACE)AceHeader;
Size = FIELD_OFFSET(ACCESS_ALLOWED_CALLBACK_OBJECT_ACE,
ObjectType);
if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
Size += sizeof(Ace->ObjectType);
if (Ace->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
Size += sizeof(Ace->InheritedObjectType);
break;
}
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
case ACCESS_DENIED_OBJECT_ACE_TYPE:
{
PACCESS_ALLOWED_OBJECT_ACE Ace = (PACCESS_ALLOWED_OBJECT_ACE)AceHeader;
Size = FIELD_OFFSET(ACCESS_ALLOWED_OBJECT_ACE,
ObjectType);
if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
Size += sizeof(Ace->ObjectType);
if (Ace->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
Size += sizeof(Ace->InheritedObjectType);
break;
}
case SYSTEM_AUDIT_ACE_TYPE:
Size = FIELD_OFFSET(SYSTEM_AUDIT_ACE,
SidStart);
break;
case SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
Size = FIELD_OFFSET(SYSTEM_AUDIT_CALLBACK_ACE,
SidStart);
break;
case SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
{
PSYSTEM_AUDIT_CALLBACK_OBJECT_ACE Ace = (PSYSTEM_AUDIT_CALLBACK_OBJECT_ACE)AceHeader;
Size = FIELD_OFFSET(SYSTEM_AUDIT_CALLBACK_OBJECT_ACE,
ObjectType);
if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
Size += sizeof(Ace->ObjectType);
if (Ace->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
Size += sizeof(Ace->InheritedObjectType);
break;
}
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
{
PSYSTEM_AUDIT_OBJECT_ACE Ace = (PSYSTEM_AUDIT_OBJECT_ACE)AceHeader;
Size = FIELD_OFFSET(SYSTEM_AUDIT_OBJECT_ACE,
ObjectType);
if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
Size += sizeof(Ace->ObjectType);
if (Ace->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
Size += sizeof(Ace->InheritedObjectType);
break;
}
case SYSTEM_MANDATORY_LABEL_ACE_TYPE:
Size = FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE,
SidStart);
break;
}
return Size;
}
static PSID
AccpGetAceSid(IN PACE_HEADER AceHeader)
{
return (PSID)((ULONG_PTR)AceHeader + AccpGetAceStructureSize(AceHeader));
}
static ACCESS_MASK
AccpGetAceAccessMask(IN PACE_HEADER AceHeader)
{
return *((PACCESS_MASK)(AceHeader + 1));
}
static BOOL
AccpIsObjectAce(IN PACE_HEADER AceHeader)
{
BOOL Ret;
switch (AceHeader->AceType)
{
case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
case ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
case ACCESS_DENIED_OBJECT_ACE_TYPE:
case SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
Ret = TRUE;
break;
default:
Ret = FALSE;
break;
}
return Ret;
}
static DWORD
AccpGetTrusteeObjects(IN PTRUSTEE_W Trustee,
OUT GUID *pObjectTypeGuid OPTIONAL,
OUT GUID *pInheritedObjectTypeGuid OPTIONAL)
{
DWORD Ret;
switch (Trustee->TrusteeForm)
{
case TRUSTEE_IS_OBJECTS_AND_NAME:
{
POBJECTS_AND_NAME_W pOan = (POBJECTS_AND_NAME_W)Trustee->ptstrName;
/* pOan->ObjectsPresent should always be 0 here because a previous
call to AccpGetTrusteeSid should have rejected these trustees
already. */
ASSERT(pOan->ObjectsPresent == 0);
Ret = pOan->ObjectsPresent;
break;
}
case TRUSTEE_IS_OBJECTS_AND_SID:
{
POBJECTS_AND_SID pOas = (POBJECTS_AND_SID)Trustee->ptstrName;
if (pObjectTypeGuid != NULL && pOas->ObjectsPresent & ACE_OBJECT_TYPE_PRESENT)
*pObjectTypeGuid = pOas->ObjectTypeGuid;
if (pInheritedObjectTypeGuid != NULL && pOas->ObjectsPresent & ACE_INHERITED_OBJECT_TYPE_PRESENT)
*pObjectTypeGuid = pOas->InheritedObjectTypeGuid;
Ret = pOas->ObjectsPresent;
break;
}
default:
/* Any other trustee forms have no objects attached... */
Ret = 0;
break;
}
return Ret;
}
static DWORD
AccpCalcNeededAceSize(IN PSID Sid,
IN DWORD ObjectsPresent)
{
DWORD Ret;
Ret = sizeof(ACE) + GetLengthSid(Sid);
/* This routine calculates the generic size of the ACE needed.
If no objects are present it is assumed that only a standard
ACE is to be created. */
if (ObjectsPresent & ACE_OBJECT_TYPE_PRESENT)
Ret += sizeof(GUID);
if (ObjectsPresent & ACE_INHERITED_OBJECT_TYPE_PRESENT)
Ret += sizeof(GUID);
if (ObjectsPresent != 0)
Ret += sizeof(DWORD); /* Include the Flags member to make it an object ACE */
return Ret;
}
static GUID*
AccpGetObjectAceObjectType(IN PACE_HEADER AceHeader)
{
GUID *ObjectType = NULL;
switch (AceHeader->AceType)
{
case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
case ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
{
PACCESS_ALLOWED_CALLBACK_OBJECT_ACE Ace = (PACCESS_ALLOWED_CALLBACK_OBJECT_ACE)AceHeader;
if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
ObjectType = &Ace->ObjectType;
break;
}
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
case ACCESS_DENIED_OBJECT_ACE_TYPE:
{
PACCESS_ALLOWED_OBJECT_ACE Ace = (PACCESS_ALLOWED_OBJECT_ACE)AceHeader;
if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
ObjectType = &Ace->ObjectType;
break;
}
case SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
{
PSYSTEM_AUDIT_CALLBACK_OBJECT_ACE Ace = (PSYSTEM_AUDIT_CALLBACK_OBJECT_ACE)AceHeader;
if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
ObjectType = &Ace->ObjectType;
break;
}
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
{
PSYSTEM_AUDIT_OBJECT_ACE Ace = (PSYSTEM_AUDIT_OBJECT_ACE)AceHeader;
if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
ObjectType = &Ace->ObjectType;
break;
}
}
return ObjectType;
}
static GUID*
AccpGetObjectAceInheritedObjectType(IN PACE_HEADER AceHeader)
{
GUID *ObjectType = NULL;
switch (AceHeader->AceType)
{
case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
case ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
{
PACCESS_ALLOWED_CALLBACK_OBJECT_ACE Ace = (PACCESS_ALLOWED_CALLBACK_OBJECT_ACE)AceHeader;
if (Ace->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
{
if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
ObjectType = &Ace->InheritedObjectType;
else
ObjectType = &Ace->ObjectType;
}
break;
}
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
case ACCESS_DENIED_OBJECT_ACE_TYPE:
{
PACCESS_ALLOWED_OBJECT_ACE Ace = (PACCESS_ALLOWED_OBJECT_ACE)AceHeader;
if (Ace->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
{
if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
ObjectType = &Ace->InheritedObjectType;
else
ObjectType = &Ace->ObjectType;
}
break;
}
case SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
{
PSYSTEM_AUDIT_CALLBACK_OBJECT_ACE Ace = (PSYSTEM_AUDIT_CALLBACK_OBJECT_ACE)AceHeader;
if (Ace->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
{
if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
ObjectType = &Ace->InheritedObjectType;
else
ObjectType = &Ace->ObjectType;
}
break;
}
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
{
PSYSTEM_AUDIT_OBJECT_ACE Ace = (PSYSTEM_AUDIT_OBJECT_ACE)AceHeader;
if (Ace->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
{
if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
ObjectType = &Ace->InheritedObjectType;
else
ObjectType = &Ace->ObjectType;
}
break;
}
}
return ObjectType;
}
static DWORD
AccpOpenLSAPolicyHandle(IN LPWSTR SystemName,
IN ACCESS_MASK DesiredAccess,
OUT PLSA_HANDLE pPolicyHandle)
{
LSA_OBJECT_ATTRIBUTES LsaObjectAttributes = {0};
LSA_UNICODE_STRING LsaSystemName, *psn;
NTSTATUS Status;
if (SystemName != NULL && SystemName[0] != L'\0')
{
LsaSystemName.Buffer = SystemName;
LsaSystemName.Length = wcslen(SystemName) * sizeof(WCHAR);
LsaSystemName.MaximumLength = LsaSystemName.Length + sizeof(WCHAR);
psn = &LsaSystemName;
}
else
{
psn = NULL;
}
Status = LsaOpenPolicy(psn,
&LsaObjectAttributes,
DesiredAccess,
pPolicyHandle);
if (!NT_SUCCESS(Status))
return LsaNtStatusToWinError(Status);
return ERROR_SUCCESS;
}
static LPWSTR
AccpGetTrusteeName(IN PTRUSTEE_W Trustee)
{
switch (Trustee->TrusteeForm)
{
case TRUSTEE_IS_NAME:
return Trustee->ptstrName;
case TRUSTEE_IS_OBJECTS_AND_NAME:
return ((POBJECTS_AND_NAME_W)Trustee->ptstrName)->ptstrName;
default:
return NULL;
}
}
static DWORD
AccpLookupSidByName(IN LSA_HANDLE PolicyHandle,
IN LPWSTR Name,
OUT PSID *pSid)
{
NTSTATUS Status;
LSA_UNICODE_STRING LsaNames[1];
PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains = NULL;
PLSA_TRANSLATED_SID2 TranslatedSid = NULL;
DWORD SidLen;
DWORD Ret = ERROR_SUCCESS;
LsaNames[0].Buffer = Name;
LsaNames[0].Length = wcslen(Name) * sizeof(WCHAR);
LsaNames[0].MaximumLength = LsaNames[0].Length + sizeof(WCHAR);
Status = LsaLookupNames2(PolicyHandle,
0,
sizeof(LsaNames) / sizeof(LsaNames[0]),
LsaNames,
&ReferencedDomains,
&TranslatedSid);
if (!NT_SUCCESS(Status))
return LsaNtStatusToWinError(Status);
if (TranslatedSid->Use == SidTypeUnknown || TranslatedSid->Use == SidTypeInvalid)
{
Ret = LsaNtStatusToWinError(STATUS_NONE_MAPPED); /* FIXME- what error code? */
goto Cleanup;
}
SidLen = GetLengthSid(TranslatedSid->Sid);
ASSERT(SidLen != 0);
*pSid = LocalAlloc(LMEM_FIXED, (SIZE_T)SidLen);
if (*pSid != NULL)
{
if (!CopySid(SidLen,
*pSid,
TranslatedSid->Sid))
{
Ret = GetLastError();
LocalFree((HLOCAL)*pSid);
*pSid = NULL;
}
}
else
Ret = ERROR_NOT_ENOUGH_MEMORY;
Cleanup:
LsaFreeMemory(ReferencedDomains);
LsaFreeMemory(TranslatedSid);
return Ret;
}
static DWORD
AccpGetTrusteeSid(IN PTRUSTEE_W Trustee,
IN OUT PLSA_HANDLE pPolicyHandle,
OUT PSID *ppSid,
OUT BOOL *Allocated)
{
DWORD Ret = ERROR_SUCCESS;
*ppSid = NULL;
*Allocated = FALSE;
if (Trustee->pMultipleTrustee || Trustee->MultipleTrusteeOperation != NO_MULTIPLE_TRUSTEE)
{
/* This is currently not supported */
return ERROR_INVALID_PARAMETER;
}
switch (Trustee->TrusteeForm)
{
case TRUSTEE_IS_OBJECTS_AND_NAME:
if (((POBJECTS_AND_NAME_W)Trustee->ptstrName)->ObjectsPresent != 0)
{
/* This is not supported as there is no way to interpret the
strings provided, and we need GUIDs for the ACEs... */
Ret = ERROR_INVALID_PARAMETER;
break;
}
/* fall through */
case TRUSTEE_IS_NAME:
if (*pPolicyHandle == NULL)
{
Ret = AccpOpenLSAPolicyHandle(NULL, /* FIXME - always local? */
POLICY_LOOKUP_NAMES,
pPolicyHandle);
if (Ret != ERROR_SUCCESS)
return Ret;
ASSERT(*pPolicyHandle != NULL);
}
Ret = AccpLookupSidByName(*pPolicyHandle,
AccpGetTrusteeName(Trustee),
ppSid);
if (Ret == ERROR_SUCCESS)
{
ASSERT(*ppSid != NULL);
*Allocated = TRUE;
}
break;
case TRUSTEE_IS_OBJECTS_AND_SID:
*ppSid = ((POBJECTS_AND_SID)Trustee->ptstrName)->pSid;
break;
case TRUSTEE_IS_SID:
*ppSid = (PSID)Trustee->ptstrName;
break;
default:
Ret = ERROR_INVALID_PARAMETER;
break;
}
return Ret;
}
/**********************************************************************
* AccRewriteGetHandleRights EXPORTED
*
* @unimplemented
*/
DWORD WINAPI
AccRewriteGetHandleRights(HANDLE handle,
SE_OBJECT_TYPE ObjectType,
SECURITY_INFORMATION SecurityInfo,
PSID* ppsidOwner,
PSID* ppsidGroup,
PACL* ppDacl,
PACL* ppSacl,
PSECURITY_DESCRIPTOR* ppSecurityDescriptor)
{
PSECURITY_DESCRIPTOR pSD = NULL;
ULONG SDSize = 0;
NTSTATUS Status;
DWORD LastErr;
DWORD Ret;
/* save the last error code */
LastErr = GetLastError();
do
{
Ret = ERROR_SUCCESS;
/* allocate a buffer large enough to hold the
security descriptor we need to return */
SDSize += 0x100;
if (pSD == NULL)
{
pSD = LocalAlloc(LMEM_FIXED,
(SIZE_T)SDSize);
}
else
{
PSECURITY_DESCRIPTOR newSD;
newSD = LocalReAlloc((HLOCAL)pSD,
(SIZE_T)SDSize,
LMEM_MOVEABLE);
if (newSD != NULL)
pSD = newSD;
}
if (pSD == NULL)
{
Ret = GetLastError();
break;
}
/* perform the actual query depending on the object type */
switch (ObjectType)
{
case SE_REGISTRY_KEY:
{
Ret = (DWORD)RegGetKeySecurity((HKEY)handle,
SecurityInfo,
pSD,
&SDSize);
break;
}
case SE_FILE_OBJECT:
/* FIXME - handle console handles? */
case SE_KERNEL_OBJECT:
{
Status = NtQuerySecurityObject(handle,
SecurityInfo,
pSD,
SDSize,
&SDSize);
if (!NT_SUCCESS(Status))
{
Ret = RtlNtStatusToDosError(Status);
}
break;
}
case SE_SERVICE:
{
if (!QueryServiceObjectSecurity((SC_HANDLE)handle,
SecurityInfo,
pSD,
SDSize,
&SDSize))
{
Ret = GetLastError();
}
break;
}
case SE_WINDOW_OBJECT:
{
if (!GetUserObjectSecurity(handle,
&SecurityInfo,
pSD,
SDSize,
&SDSize))
{
Ret = GetLastError();
}
break;
}
default:
{
UNIMPLEMENTED;
Ret = ERROR_CALL_NOT_IMPLEMENTED;
break;
}
}
} while (Ret == ERROR_INSUFFICIENT_BUFFER);
if (Ret == ERROR_SUCCESS)
{
BOOL Present, Defaulted;
if (SecurityInfo & OWNER_SECURITY_INFORMATION && ppsidOwner != NULL)
{
*ppsidOwner = NULL;
if (!GetSecurityDescriptorOwner(pSD,
ppsidOwner,
&Defaulted))
{
Ret = GetLastError();
goto Cleanup;
}
}
if (SecurityInfo & GROUP_SECURITY_INFORMATION && ppsidGroup != NULL)
{
*ppsidOwner = NULL;
if (!GetSecurityDescriptorGroup(pSD,
ppsidGroup,
&Defaulted))
{
Ret = GetLastError();
goto Cleanup;
}
}
if (SecurityInfo & DACL_SECURITY_INFORMATION && ppDacl != NULL)
{
*ppDacl = NULL;
if (!GetSecurityDescriptorDacl(pSD,
&Present,
ppDacl,
&Defaulted))
{
Ret = GetLastError();
goto Cleanup;
}
}
if (SecurityInfo & SACL_SECURITY_INFORMATION && ppSacl != NULL)
{
*ppSacl = NULL;
if (!GetSecurityDescriptorSacl(pSD,
&Present,
ppSacl,
&Defaulted))
{
Ret = GetLastError();
goto Cleanup;
}
}
*ppSecurityDescriptor = pSD;
}
else
{
Cleanup:
if (pSD != NULL)
{
LocalFree((HLOCAL)pSD);
}
}
/* restore the last error code */
SetLastError(LastErr);
return Ret;
}
/**********************************************************************
* AccRewriteSetHandleRights EXPORTED
*
* @unimplemented
*/
DWORD WINAPI
AccRewriteSetHandleRights(HANDLE handle,
SE_OBJECT_TYPE ObjectType,
SECURITY_INFORMATION SecurityInfo,
PSECURITY_DESCRIPTOR pSecurityDescriptor)
{
NTSTATUS Status;
DWORD LastErr;
DWORD Ret = ERROR_SUCCESS;
/* save the last error code */
LastErr = GetLastError();
/* set the security according to the object type */
switch (ObjectType)
{
case SE_REGISTRY_KEY:
{
Ret = (DWORD)RegSetKeySecurity((HKEY)handle,
SecurityInfo,
pSecurityDescriptor);
break;
}
case SE_FILE_OBJECT:
/* FIXME - handle console handles? */
case SE_KERNEL_OBJECT:
{
Status = NtSetSecurityObject(handle,
SecurityInfo,
pSecurityDescriptor);
if (!NT_SUCCESS(Status))
{
Ret = RtlNtStatusToDosError(Status);
}
break;
}
case SE_SERVICE:
{
if (!SetServiceObjectSecurity((SC_HANDLE)handle,
SecurityInfo,
pSecurityDescriptor))
{
Ret = GetLastError();
}
break;
}
case SE_WINDOW_OBJECT:
{
if (!SetUserObjectSecurity(handle,
&SecurityInfo,
pSecurityDescriptor))
{
Ret = GetLastError();
}
break;
}
default:
{
UNIMPLEMENTED;
Ret = ERROR_CALL_NOT_IMPLEMENTED;
break;
}
}
/* restore the last error code */
SetLastError(LastErr);
return Ret;
}
static DWORD
AccpOpenNamedObject(LPWSTR pObjectName,
SE_OBJECT_TYPE ObjectType,
SECURITY_INFORMATION SecurityInfo,
PHANDLE Handle,
PHANDLE Handle2,
BOOL Write)
{
LPWSTR lpPath;
NTSTATUS Status;
ACCESS_MASK DesiredAccess = (ACCESS_MASK)0;
DWORD Ret = ERROR_SUCCESS;
/* determine the required access rights */
switch (ObjectType)
{
case SE_REGISTRY_KEY:
case SE_FILE_OBJECT:
case SE_KERNEL_OBJECT:
case SE_SERVICE:
case SE_WINDOW_OBJECT:
if (Write)
{
SetSecurityAccessMask(SecurityInfo,
(PDWORD)&DesiredAccess);
}
else
{
QuerySecurityAccessMask(SecurityInfo,
(PDWORD)&DesiredAccess);
}
break;
default:
break;
}
/* make a copy of the path if we're modifying the string */
switch (ObjectType)
{
case SE_REGISTRY_KEY:
case SE_SERVICE:
lpPath = (LPWSTR)LocalAlloc(LMEM_FIXED,
(wcslen(pObjectName) + 1) * sizeof(WCHAR));
if (lpPath == NULL)
{
Ret = GetLastError();
goto Cleanup;
}
wcscpy(lpPath,
pObjectName);
break;
default:
lpPath = pObjectName;
break;
}
/* open a handle to the path depending on the object type */
switch (ObjectType)
{
case SE_FILE_OBJECT:
{
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING FileName;
if (!RtlDosPathNameToNtPathName_U(pObjectName,
&FileName,
NULL,
NULL))
{
Ret = ERROR_INVALID_NAME;
goto Cleanup;
}
InitializeObjectAttributes(&ObjectAttributes,
&FileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenFile(Handle,
DesiredAccess | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_SYNCHRONOUS_IO_NONALERT);
RtlFreeHeap(RtlGetProcessHeap(),
0,
FileName.Buffer);
if (!NT_SUCCESS(Status))
{
Ret = RtlNtStatusToDosError(Status);
}
break;
}
case SE_REGISTRY_KEY:
{
static const struct
{
HKEY hRootKey;
LPCWSTR szRootKey;
} AccRegRootKeys[] =
{
{HKEY_CLASSES_ROOT, L"CLASSES_ROOT"},
{HKEY_CURRENT_USER, L"CURRENT_USER"},
{HKEY_LOCAL_MACHINE, L"MACHINE"},
{HKEY_USERS, L"USERS"},
{HKEY_CURRENT_CONFIG, L"CONFIG"},
};
LPWSTR lpMachineName, lpRootKeyName, lpKeyName;
HKEY hRootKey = NULL;
UINT i;
/* parse the registry path */
if (lpPath[0] == L'\\' && lpPath[1] == L'\\')
{
lpMachineName = lpPath;
lpRootKeyName = wcschr(lpPath + 2,
L'\\');
if (lpRootKeyName == NULL)
goto ParseRegErr;
else
*(lpRootKeyName++) = L'\0';
}
else
{
lpMachineName = NULL;
lpRootKeyName = lpPath;
}
lpKeyName = wcschr(lpRootKeyName,
L'\\');
if (lpKeyName != NULL)
{
*(lpKeyName++) = L'\0';
}
for (i = 0;
i != sizeof(AccRegRootKeys) / sizeof(AccRegRootKeys[0]);
i++)
{
if (!wcsicmp(lpRootKeyName,
AccRegRootKeys[i].szRootKey))
{
hRootKey = AccRegRootKeys[i].hRootKey;
break;
}
}
if (hRootKey == NULL)
{
ParseRegErr:
/* FIXME - right error code? */
Ret = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
/* open the registry key */
if (lpMachineName != NULL)
{
Ret = RegConnectRegistry(lpMachineName,
hRootKey,
(PHKEY)Handle2);
if (Ret != ERROR_SUCCESS)
goto Cleanup;
hRootKey = (HKEY)(*Handle2);
}
Ret = RegOpenKeyEx(hRootKey,
lpKeyName,
0,
(REGSAM)DesiredAccess,
(PHKEY)Handle);
if (Ret != ERROR_SUCCESS)
{
if (*Handle2 != NULL)
{
RegCloseKey((HKEY)(*Handle2));
}
goto Cleanup;
}
break;
}
case SE_SERVICE:
{
LPWSTR lpServiceName, lpMachineName;
/* parse the service path */
if (lpPath[0] == L'\\' && lpPath[1] == L'\\')
{
DesiredAccess |= SC_MANAGER_CONNECT;
lpMachineName = lpPath;
lpServiceName = wcschr(lpPath + 2,
L'\\');
if (lpServiceName == NULL)
{
/* FIXME - right error code? */
Ret = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
else
*(lpServiceName++) = L'\0';
}
else
{
lpMachineName = NULL;
lpServiceName = lpPath;
}
/* open the service */
*Handle2 = (HANDLE)OpenSCManager(lpMachineName,
NULL,
(DWORD)DesiredAccess);
if (*Handle2 == NULL)
{
goto FailOpenService;
}
DesiredAccess &= ~SC_MANAGER_CONNECT;
*Handle = (HANDLE)OpenService((SC_HANDLE)(*Handle2),
lpServiceName,
(DWORD)DesiredAccess);
if (*Handle == NULL)
{
if (*Handle2 != NULL)
{
CloseServiceHandle((SC_HANDLE)(*Handle2));
}
FailOpenService:
Ret = GetLastError();
goto Cleanup;
}
break;
}
default:
{
UNIMPLEMENTED;
Ret = ERROR_CALL_NOT_IMPLEMENTED;
break;
}
}
Cleanup:
if (lpPath != NULL && lpPath != pObjectName)
{
LocalFree((HLOCAL)lpPath);
}
return Ret;
}
static VOID
AccpCloseObjectHandle(SE_OBJECT_TYPE ObjectType,
HANDLE Handle,
HANDLE Handle2)
{
ASSERT(Handle != NULL);
/* close allocated handlees depending on the object type */
switch (ObjectType)
{
case SE_REGISTRY_KEY:
RegCloseKey((HKEY)Handle);
if (Handle2 != NULL)
RegCloseKey((HKEY)Handle2);
break;
case SE_FILE_OBJECT:
NtClose(Handle);
break;
case SE_KERNEL_OBJECT:
case SE_WINDOW_OBJECT:
CloseHandle(Handle);
break;
case SE_SERVICE:
CloseServiceHandle((SC_HANDLE)Handle);
ASSERT(Handle2 != NULL);
CloseServiceHandle((SC_HANDLE)Handle2);
break;
default:
break;
}
}
/**********************************************************************
* AccRewriteGetNamedRights EXPORTED
*
* @unimplemented
*/
DWORD WINAPI
AccRewriteGetNamedRights(LPWSTR pObjectName,
SE_OBJECT_TYPE ObjectType,
SECURITY_INFORMATION SecurityInfo,
PSID* ppsidOwner,
PSID* ppsidGroup,
PACL* ppDacl,
PACL* ppSacl,
PSECURITY_DESCRIPTOR* ppSecurityDescriptor)
{
HANDLE Handle = NULL;
HANDLE Handle2 = NULL;
DWORD LastErr;
DWORD Ret;
/* save the last error code */
LastErr = GetLastError();
/* create the handle */
Ret = AccpOpenNamedObject(pObjectName,
ObjectType,
SecurityInfo,
&Handle,
&Handle2,
FALSE);
if (Ret == ERROR_SUCCESS)
{
ASSERT(Handle != NULL);
/* perform the operation */
Ret = AccRewriteGetHandleRights(Handle,
ObjectType,
SecurityInfo,
ppsidOwner,
ppsidGroup,
ppDacl,
ppSacl,
ppSecurityDescriptor);
/* close opened handles */
AccpCloseObjectHandle(ObjectType,
Handle,
Handle2);
}
/* restore the last error code */
SetLastError(LastErr);
return Ret;
}
/**********************************************************************
* AccRewriteSetNamedRights EXPORTED
*
* @unimplemented
*/
DWORD WINAPI
AccRewriteSetNamedRights(LPWSTR pObjectName,
SE_OBJECT_TYPE ObjectType,
SECURITY_INFORMATION SecurityInfo,
PSECURITY_DESCRIPTOR pSecurityDescriptor)
{
HANDLE Handle = NULL;
HANDLE Handle2 = NULL;
DWORD LastErr;
DWORD Ret;
/* save the last error code */
LastErr = GetLastError();
/* create the handle */
Ret = AccpOpenNamedObject(pObjectName,
ObjectType,
SecurityInfo,
&Handle,
&Handle2,
TRUE);
if (Ret == ERROR_SUCCESS)
{
ASSERT(Handle != NULL);
/* perform the operation */
Ret = AccRewriteSetHandleRights(Handle,
ObjectType,
SecurityInfo,
pSecurityDescriptor);
/* close opened handles */
AccpCloseObjectHandle(ObjectType,
Handle,
Handle2);
}
/* restore the last error code */
SetLastError(LastErr);
return Ret;
}
/**********************************************************************
* AccRewriteSetEntriesInAcl EXPORTED
*
* @implemented
*/
DWORD WINAPI
AccRewriteSetEntriesInAcl(ULONG cCountOfExplicitEntries,
PEXPLICIT_ACCESS_W pListOfExplicitEntries,
PACL OldAcl,
PACL* NewAcl)
{
PACL pNew = NULL;
ACL_SIZE_INFORMATION SizeInformation;
PACE_HEADER pAce;
BOOLEAN KeepAceBuf[8];
BOOLEAN *pKeepAce = NULL;
GUID ObjectTypeGuid, InheritedObjectTypeGuid;
DWORD ObjectsPresent;
BOOL needToClean;
PSID pSid1, pSid2;
ULONG i, j;
LSA_HANDLE PolicyHandle = NULL;
BOOL bRet;
DWORD LastErr;
DWORD Ret = ERROR_SUCCESS;
/* save the last error code */
LastErr = GetLastError();
*NewAcl = NULL;
/* Get information about previous ACL */
if (OldAcl)
{
if (!GetAclInformation(OldAcl, &SizeInformation, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation))
{
Ret = GetLastError();
goto Cleanup;
}
if (SizeInformation.AceCount > sizeof(KeepAceBuf) / sizeof(KeepAceBuf[0]))
{
pKeepAce = (BOOLEAN *)LocalAlloc(LMEM_FIXED, SizeInformation.AceCount * sizeof(*pKeepAce));
if (!pKeepAce)
{
Ret = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
}
else
pKeepAce = KeepAceBuf;
memset(pKeepAce, TRUE, SizeInformation.AceCount * sizeof(*pKeepAce));
}
else
{
ZeroMemory(&SizeInformation, sizeof(ACL_SIZE_INFORMATION));
SizeInformation.AclBytesInUse = sizeof(ACL);
}
/* Get size required for new entries */
for (i = 0; i < cCountOfExplicitEntries; i++)
{
Ret = AccpGetTrusteeSid(&pListOfExplicitEntries[i].Trustee,
&PolicyHandle,
&pSid1,
&needToClean);
if (Ret != ERROR_SUCCESS)
goto Cleanup;
ObjectsPresent = AccpGetTrusteeObjects(&pListOfExplicitEntries[i].Trustee,
NULL,
NULL);
switch (pListOfExplicitEntries[i].grfAccessMode)
{
case REVOKE_ACCESS:
case SET_ACCESS:
/* Discard all accesses for the trustee... */
for (j = 0; j < SizeInformation.AceCount; j++)
{
if (!pKeepAce[j])
continue;
if (!GetAce(OldAcl, j, (PVOID*)&pAce))
{
Ret = GetLastError();
goto Cleanup;
}
pSid2 = AccpGetAceSid(pAce);
if (RtlEqualSid(pSid1, pSid2))
{
pKeepAce[j] = FALSE;
SizeInformation.AclBytesInUse -= pAce->AceSize;
}
}
if (pListOfExplicitEntries[i].grfAccessMode == REVOKE_ACCESS)
break;
/* ...and replace by the current access */
case GRANT_ACCESS:
case DENY_ACCESS:
/* Add to ACL */
SizeInformation.AclBytesInUse += AccpCalcNeededAceSize(pSid1, ObjectsPresent);
break;
case SET_AUDIT_SUCCESS:
case SET_AUDIT_FAILURE:
/* FIXME */
DPRINT1("Case not implemented!\n");
break;
default:
DPRINT1("Unknown access mode 0x%x. Ignoring it\n", pListOfExplicitEntries[i].grfAccessMode);
break;
}
if (needToClean)
LocalFree((HLOCAL)pSid1);
}
/* Succeed, if no ACL needs to be allocated */
if (SizeInformation.AclBytesInUse == 0)
goto Cleanup;
/* OK, now create the new ACL */
DPRINT("Allocating %u bytes for the new ACL\n", SizeInformation.AclBytesInUse);
pNew = (PACL)LocalAlloc(LMEM_FIXED, SizeInformation.AclBytesInUse);
if (!pNew)
{
Ret = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
if (!InitializeAcl(pNew, SizeInformation.AclBytesInUse, ACL_REVISION))
{
Ret = GetLastError();
goto Cleanup;
}
/* Fill it */
/* 1a) New audit entries (SET_AUDIT_SUCCESS, SET_AUDIT_FAILURE) */
/* FIXME */
/* 1b) Existing audit entries */
/* FIXME */
/* 2a) New denied entries (DENY_ACCESS) */
for (i = 0; i < cCountOfExplicitEntries; i++)
{
if (pListOfExplicitEntries[i].grfAccessMode == DENY_ACCESS)
{
/* FIXME: take care of pListOfExplicitEntries[i].grfInheritance */
Ret = AccpGetTrusteeSid(&pListOfExplicitEntries[i].Trustee,
&PolicyHandle,
&pSid1,
&needToClean);
if (Ret != ERROR_SUCCESS)
goto Cleanup;
ObjectsPresent = AccpGetTrusteeObjects(&pListOfExplicitEntries[i].Trustee,
&ObjectTypeGuid,
&InheritedObjectTypeGuid);
if (ObjectsPresent == 0)
{
/* FIXME: Call AddAccessDeniedAceEx instead! */
bRet = AddAccessDeniedAce(pNew, ACL_REVISION, pListOfExplicitEntries[i].grfAccessPermissions, pSid1);
}
else
{
/* FIXME: Call AddAccessDeniedObjectAce */
DPRINT1("Object ACEs not yet supported!\n");
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
bRet = FALSE;
}
if (needToClean) LocalFree((HLOCAL)pSid1);
if (!bRet)
{
Ret = GetLastError();
goto Cleanup;
}
}
}
/* 2b) Existing denied entries */
/* FIXME */
/* 3a) New allow entries (GRANT_ACCESS, SET_ACCESS) */
for (i = 0; i < cCountOfExplicitEntries; i++)
{
if (pListOfExplicitEntries[i].grfAccessMode == SET_ACCESS ||
pListOfExplicitEntries[i].grfAccessMode == GRANT_ACCESS)
{
/* FIXME: take care of pListOfExplicitEntries[i].grfInheritance */
Ret = AccpGetTrusteeSid(&pListOfExplicitEntries[i].Trustee,
&PolicyHandle,
&pSid1,
&needToClean);
if (Ret != ERROR_SUCCESS)
goto Cleanup;
ObjectsPresent = AccpGetTrusteeObjects(&pListOfExplicitEntries[i].Trustee,
&ObjectTypeGuid,
&InheritedObjectTypeGuid);
if (ObjectsPresent == 0)
{
/* FIXME: Call AddAccessAllowedAceEx instead! */
bRet = AddAccessAllowedAce(pNew, ACL_REVISION, pListOfExplicitEntries[i].grfAccessPermissions, pSid1);
}
else
{
/* FIXME: Call AddAccessAllowedObjectAce */
DPRINT1("Object ACEs not yet supported!\n");
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
bRet = FALSE;
}
if (needToClean) LocalFree((HLOCAL)pSid1);
if (!bRet)
{
Ret = GetLastError();
goto Cleanup;
}
}
}
/* 3b) Existing allow entries */
/* FIXME */
*NewAcl = pNew;
Cleanup:
if (pKeepAce && pKeepAce != KeepAceBuf)
LocalFree((HLOCAL)pKeepAce);
if (pNew && Ret != ERROR_SUCCESS)
LocalFree((HLOCAL)pNew);
if (PolicyHandle)
LsaClose(PolicyHandle);
/* restore the last error code */
SetLastError(LastErr);
return Ret;
}
/**********************************************************************
* AccGetInheritanceSource EXPORTED
*
* @unimplemented
*/
DWORD WINAPI
AccGetInheritanceSource(LPWSTR pObjectName,
SE_OBJECT_TYPE ObjectType,
SECURITY_INFORMATION SecurityInfo,
BOOL Container,
GUID** pObjectClassGuids,
DWORD GuidCount,
PACL pAcl,
PFN_OBJECT_MGR_FUNCTS pfnArray,
PGENERIC_MAPPING pGenericMapping,
PINHERITED_FROMW pInheritArray)
{
UNIMPLEMENTED;
return ERROR_CALL_NOT_IMPLEMENTED;
}
/**********************************************************************
* AccFreeIndexArray EXPORTED
*
* @implemented
*/
DWORD WINAPI
AccFreeIndexArray(PINHERITED_FROMW pInheritArray,
USHORT AceCnt,
PFN_OBJECT_MGR_FUNCTS pfnArray OPTIONAL)
{
PINHERITED_FROMW pLast;
UNREFERENCED_PARAMETER(pfnArray);
pLast = pInheritArray + AceCnt;
while (pInheritArray != pLast)
{
if (pInheritArray->AncestorName != NULL)
{
LocalFree((HLOCAL)pInheritArray->AncestorName);
pInheritArray->AncestorName = NULL;
}
pInheritArray++;
}
return ERROR_SUCCESS;
}
/**********************************************************************
* AccRewriteGetExplicitEntriesFromAcl EXPORTED
*
* @implemented
*/
DWORD WINAPI
AccRewriteGetExplicitEntriesFromAcl(PACL pacl,
PULONG pcCountOfExplicitEntries,
PEXPLICIT_ACCESS_W* pListOfExplicitEntries)
{
PACE_HEADER AceHeader;
PSID Sid, SidTarget;
ULONG ObjectAceCount = 0;
POBJECTS_AND_SID ObjSid;
SIZE_T Size;
PEXPLICIT_ACCESS_W peaw;
DWORD LastErr, SidLen;
DWORD AceIndex = 0;
DWORD ErrorCode = ERROR_SUCCESS;
/* save the last error code */
LastErr = GetLastError();
if (pacl != NULL)
{
if (pacl->AceCount != 0)
{
Size = (SIZE_T)pacl->AceCount * sizeof(EXPLICIT_ACCESS_W);
/* calculate the space needed */
while (GetAce(pacl,
AceIndex,
(LPVOID*)&AceHeader))
{
Sid = AccpGetAceSid(AceHeader);
Size += GetLengthSid(Sid);
if (AccpIsObjectAce(AceHeader))
ObjectAceCount++;
AceIndex++;
}
Size += ObjectAceCount * sizeof(OBJECTS_AND_SID);
ASSERT(pacl->AceCount == AceIndex);
/* allocate the array */
peaw = (PEXPLICIT_ACCESS_W)LocalAlloc(LMEM_FIXED,
Size);
if (peaw != NULL)
{
AceIndex = 0;
ObjSid = (POBJECTS_AND_SID)(peaw + pacl->AceCount);
SidTarget = (PSID)(ObjSid + ObjectAceCount);
/* initialize the array */
while (GetAce(pacl,
AceIndex,
(LPVOID*)&AceHeader))
{
Sid = AccpGetAceSid(AceHeader);
SidLen = GetLengthSid(Sid);
peaw[AceIndex].grfAccessPermissions = AccpGetAceAccessMask(AceHeader);
peaw[AceIndex].grfAccessMode = AccpGetAceAccessMode(AceHeader);
peaw[AceIndex].grfInheritance = AceHeader->AceFlags & VALID_INHERIT_FLAGS;
if (CopySid(SidLen,
SidTarget,
Sid))
{
if (AccpIsObjectAce(AceHeader))
{
BuildTrusteeWithObjectsAndSid(&peaw[AceIndex].Trustee,
ObjSid++,
AccpGetObjectAceObjectType(AceHeader),
AccpGetObjectAceInheritedObjectType(AceHeader),
SidTarget);
}
else
{
BuildTrusteeWithSid(&peaw[AceIndex].Trustee,
SidTarget);
}
SidTarget = (PSID)((ULONG_PTR)SidTarget + SidLen);
}
else
{
/* copying the SID failed, treat it as an fatal error... */
ErrorCode = GetLastError();
/* free allocated resources */
LocalFree(peaw);
peaw = NULL;
AceIndex = 0;
break;
}
AceIndex++;
}
*pcCountOfExplicitEntries = AceIndex;
*pListOfExplicitEntries = peaw;
}
else
ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
goto EmptyACL;
}
}
else
{
EmptyACL:
*pcCountOfExplicitEntries = 0;
*pListOfExplicitEntries = NULL;
}
/* restore the last error code */
SetLastError(LastErr);
return ErrorCode;
}
/**********************************************************************
* AccTreeResetNamedSecurityInfo EXPORTED
*
* @unimplemented
*/
DWORD WINAPI
AccTreeResetNamedSecurityInfo(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)
{
UNIMPLEMENTED;
return ERROR_CALL_NOT_IMPLEMENTED;
}
BOOL WINAPI
DllMain(IN HINSTANCE hinstDLL,
IN DWORD dwReason,
IN LPVOID lpvReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
hDllInstance = hinstDLL;
DisableThreadLibraryCalls(hinstDLL);
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}