Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

800 lines
23 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
aclmgmt.cpp
Abstract:
Routines to manage access control lists
Geoffrey Guo (geoffguo) 26-Apr-2002 Created
Revision History:
<alias> <date> <comments>
--*/
#include "clmt.h"
#define STRSAFE_LIB
#include <strsafe.h>
DWORD ChangeOwner (
LPTSTR lpObjectName,
SE_OBJECT_TYPE ObjectType)
{
DWORD dwRet = ERROR_SUCCESS;
PSID psidAdministrators;
SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION;
if(!AllocateAndInitializeSid(&siaNtAuthority, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&psidAdministrators))
{
dwRet = GetLastError();
goto Exit;
}
EnablePrivilege(SE_TAKE_OWNERSHIP_NAME,TRUE);
si |= SI_OWNER_RECURSE;
dwRet = SetNamedSecurityInfo(lpObjectName,
ObjectType,
si,
psidAdministrators,
NULL,
NULL,
NULL);
EnablePrivilege(SE_TAKE_OWNERSHIP_NAME,FALSE);
FreeSid(psidAdministrators);
Exit:
return dwRet;
}
//-----------------------------------------------------------------------//
//
// CopyACL: Copy ACL
//
// OldACL: Pointer to source Access Control List
// NewACL: Pointer to destination Access Control List
//-----------------------------------------------------------------------//
DWORD
CopyACL (
PACL OldACL,
PACL NewACL)
{
ACL_SIZE_INFORMATION aclSizeInfo;
LPVOID ace;
ACE_HEADER *aceHeader;
ULONG i;
GetAclInformation (OldACL, (LPVOID) &aclSizeInfo, (DWORD) sizeof (aclSizeInfo), AclSizeInformation);
//
// Copy all of the ACEs to the new ACL
//
for (i = 0; i < aclSizeInfo.AceCount; i++)
{
//
// Get the ACE and header info
//
if (!GetAce (OldACL, i, &ace))
return GetLastError();
aceHeader = (ACE_HEADER *) ace;
//
// Add the ACE to the new list
//
if (!AddAce (NewACL, ACL_REVISION, 0xffffffff, ace, aceHeader->AceSize))
return GetLastError();
}
return ERROR_SUCCESS;
}
//-----------------------------------------------------------------------//
//
// AddAccessAllowedACEToACL: Add Administrator Allowed ACE to ACL
//
// Acl: Pointer to Access Control List
// PermissionMask: Permission will be set for new ACE
//-----------------------------------------------------------------------//
DWORD
AddAccessAllowedACEToACL (
PACL *Acl,
DWORD PermissionMask)
{
ACL_SIZE_INFORMATION aclSizeInfo;
int aclSize;
DWORD dwRet = ERROR_SUCCESS;
USHORT AceSize;
PSID psidAdministrators;
SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
PACL oldACL, newACL;
ACCESS_ALLOWED_ACE *pAllowedAce;
oldACL = *Acl;
if(!AllocateAndInitializeSid(&siaNtAuthority, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&psidAdministrators))
{
dwRet = GetLastError();
goto Exit;
}
GetAclInformation (oldACL, (LPVOID) &aclSizeInfo, (DWORD) sizeof (ACL_SIZE_INFORMATION), AclSizeInformation);
aclSize = aclSizeInfo.AclBytesInUse +
sizeof (ACL) + sizeof (ACCESS_ALLOWED_ACE) +
GetLengthSid (psidAdministrators) - sizeof (DWORD);
newACL = (PACL) calloc(aclSize, 1);
if (!newACL)
{
dwRet = ERROR_NOT_ENOUGH_MEMORY;
goto Exit1;
}
if (!InitializeAcl (newACL, aclSize, ACL_REVISION))
{
dwRet = GetLastError();
free (newACL);
goto Exit1;
}
dwRet = CopyACL (oldACL, newACL);
if (dwRet != ERROR_SUCCESS)
{
free (newACL);
goto Exit1;
}
AceSize = sizeof(ACE_HEADER) + sizeof(ACCESS_MASK) + (USHORT)GetLengthSid(psidAdministrators);
pAllowedAce = (ACCESS_ALLOWED_ACE *)calloc(AceSize, 1);
if (!(pAllowedAce))
{
dwRet = ERROR_NOT_ENOUGH_MEMORY;
goto Exit1;
}
pAllowedAce->Header.AceFlags = 0;
pAllowedAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
pAllowedAce->Header.AceSize = AceSize;
pAllowedAce->Mask = PermissionMask;
CopySid(GetLengthSid(psidAdministrators), &(pAllowedAce->SidStart), psidAdministrators);
if (!AddAce (newACL, ACL_REVISION, 0, pAllowedAce, AceSize))
{
dwRet = GetLastError();
free (newACL);
goto Exit1;
}
*Acl = newACL;
Exit1:
FreeSid(psidAdministrators);
Exit:
return dwRet;
}
//-----------------------------------------------------------------------//
//
// RestoreACE: Restore denied ACE
//
// pACE: Pointer to source Access Control Entry
// lpOnjectName: Pointer to the object name
//-----------------------------------------------------------------------//
DWORD
RestoreACE (
PACL *ppAcl,
LPTSTR lpObjectName)
{
DWORD dwRet = ERROR_INVALID_PARAMETER;
DWORD dwLen;
PACL newACL;
LPDENIED_ACE_LIST pList;
if (!*ppAcl)
goto Exit;
pList = g_DeniedACEList;
if (pList)
{
do
{
if (lstrcmp(lpObjectName, pList->lpObjectName) == 0)
{
newACL = (PACL) calloc(pList->dwAclSize, 1);
if (!newACL)
{
dwRet = ERROR_NOT_ENOUGH_MEMORY;
goto Exit;
}
if (!InitializeAcl (newACL, pList->dwAclSize, ACL_REVISION))
{
free(newACL);
dwRet = GetLastError();
goto Exit;
}
dwRet = CopyACL (*ppAcl, newACL);
if (dwRet != ERROR_SUCCESS)
{
free(newACL);
dwRet = GetLastError();
goto Exit;
}
if (!AddAce (newACL,
ACL_REVISION,
0,
pList->pace,
((PACE_HEADER)(pList->pace))->AceSize))
{
dwRet = GetLastError();
goto Exit;
}
else
DPF(REGmsg, L"Restore denied ACE to ACL: ObjectName=%s", lpObjectName);
if (pList->previous)
pList->previous->next = pList->next;
else
g_DeniedACEList = pList->next;
if (pList->next)
pList->next->previous = pList->previous;
*ppAcl = newACL;
free (pList->lpObjectName);
free (pList->pace);
free (pList);
break;
}
pList = pList->next;
} while (pList->next);
}
dwRet = ERROR_SUCCESS;
Exit:
return dwRet;
}
//-----------------------------------------------------------------------//
//
// RemoveACEFromACL: Remove Administrator ACE from ACL
//
// Acl: Pointer to Access Control List
//-----------------------------------------------------------------------//
DWORD
RemoveACEFromACL (
PACL Acl)
{
ACL_SIZE_INFORMATION aclSizeInfo;
ULONG i;
LPVOID ace;
ACCESS_ALLOWED_ACE *accessAllowedAce;
ACCESS_DENIED_ACE *accessDeniedAce;
SYSTEM_AUDIT_ACE *systemAuditAce;
PSID psidAdministrators;
DWORD returnValue;
SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
ACE_HEADER *aceHeader;
if(!AllocateAndInitializeSid(&siaNtAuthority, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&psidAdministrators))
return GetLastError();
GetAclInformation (Acl, (LPVOID) &aclSizeInfo, (DWORD) sizeof (ACL_SIZE_INFORMATION), AclSizeInformation);
for (i = 0; i < aclSizeInfo.AceCount; i++)
{
if (!GetAce (Acl, i, &ace))
{
FreeSid(psidAdministrators);
return GetLastError();
}
aceHeader = (ACE_HEADER *) ace;
if (aceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE)
{
accessAllowedAce = (ACCESS_ALLOWED_ACE *) ace;
if (EqualSid (psidAdministrators, (PSID) &accessAllowedAce->SidStart))
{
DeleteAce (Acl, i);
FreeSid(psidAdministrators);
return ERROR_SUCCESS;
}
}
}
FreeSid(psidAdministrators);
return ERROR_NO_MORE_ITEMS;
}
//-----------------------------------------------------------------------//
//
// AddACE2List: Add ACE to the list
//
// pACE: Pointer to source Access Control Entry
// lpOnjectName: Pointer to the object name
//-----------------------------------------------------------------------//
DWORD
AddACE2List (
ACCESS_DENIED_ACE *pACE,
LPTSTR lpObjectName,
DWORD dwAclSize)
{
HRESULT hr;
DWORD dwRet = ERROR_SUCCESS;
DWORD dwLen;
LPDENIED_ACE_LIST pList1;
LPDENIED_ACE_LIST pList2;
if (!pACE)
{
dwRet = ERROR_INVALID_PARAMETER;
goto Exit;
}
pList1 = (LPDENIED_ACE_LIST)calloc (sizeof(DENIED_ACE_LIST), 1);
if (!pList1)
{
dwRet = ERROR_NOT_ENOUGH_MEMORY;
goto Exit;
}
pList1->next = NULL;
pList1->dwAclSize = dwAclSize;
pList1->pace = (ACCESS_DENIED_ACE *)calloc(((PACE_HEADER)pACE)->AceSize, 1);
if (!(pList1->pace))
{
dwRet = ERROR_NOT_ENOUGH_MEMORY;
free (pList1);
goto Exit;
}
memcpy (pList1->pace, pACE, ((PACE_HEADER)pACE)->AceSize);
dwLen = lstrlen(lpObjectName)+1;
pList1->lpObjectName = (LPTSTR)calloc (dwLen, sizeof(TCHAR));
if (!(pList1->lpObjectName))
{
dwRet = ERROR_NOT_ENOUGH_MEMORY;
free (pList1);
free (pList1->pace);
goto Exit;
}
hr = StringCchCopy (pList1->lpObjectName, dwLen, lpObjectName);
if (hr != S_OK)
{
dwRet = HRESULT_CODE(hr);
free (pList1);
free (pList1->pace);
goto Exit;
}
pList2 = g_DeniedACEList;
if (pList2)
{
while (pList2->next)
pList2 = pList2->next;
pList2->next = pList1;
pList1->previous = pList2;
}
else
{
g_DeniedACEList = pList1;
pList1->previous = NULL;
}
Exit:
return dwRet;
}
//-----------------------------------------------------------------------//
//
// RemoveDeniedACEFromACL: Remove Denied ACE from ACL
//
// Acl: Pointer to Access Control List
// lpOnjectName: Pointer to the object name
//-----------------------------------------------------------------------//
DWORD
RemoveDeniedACEFromACL (
PACL Acl,
LPTSTR lpObjectName)
{
ACL_SIZE_INFORMATION aclSizeInfo;
ULONG i;
ACCESS_DENIED_ACE *accessDeniedAce;
LPVOID ace;
DWORD dwRet = ERROR_SUCCESS;
ACE_HEADER *aceHeader;
GetAclInformation (Acl, (LPVOID) &aclSizeInfo, (DWORD) sizeof (ACL_SIZE_INFORMATION), AclSizeInformation);
for (i = 0; i < aclSizeInfo.AceCount; i++)
{
if (!GetAce (Acl, i, &ace))
{
dwRet = GetLastError();
if (dwRet == ERROR_NO_MORE_ITEMS)
dwRet = ERROR_SUCCESS;
}
aceHeader = (ACE_HEADER *) ace;
if (aceHeader->AceType == ACCESS_DENIED_ACE_TYPE)
{
accessDeniedAce = (ACCESS_DENIED_ACE *) ace;
AddACE2List (accessDeniedAce, lpObjectName, aclSizeInfo.AclBytesInUse);
if (!DeleteAce (Acl, i))
dwRet = GetLastError();
else
DPF(REGmsg, L"Remove denied ACE from ACL: ObjectName=%s", lpObjectName);
break;
}
}
return dwRet;
}
//-----------------------------------------------------------------------//
//
// AdjustObjectSecurity: Add full control ACE for local administrator.
//
// lpObjectName: Object Name
// ObjectType: Object Type
// ppOldSidOwner: Current object owner
// bSetOrRestore: True --- Add ACE, FALSE --- Remove ACE
//-----------------------------------------------------------------------//
DWORD AdjustObjectSecurity (
LPTSTR lpObjectName,
SE_OBJECT_TYPE ObjectType,
BOOL bSetOrRestore)
{
DWORD dwErr;
HRESULT hr;
PSID psid = NULL;
PSECURITY_DESCRIPTOR pSD;
PACL pDacl = NULL;
PACL psidDacl = NULL;
SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
dwErr = GetNamedSecurityInfo(lpObjectName,
ObjectType,
secInfo,
NULL,
NULL,
&psidDacl,
NULL,
&pSD);
if (dwErr == ERROR_ACCESS_DENIED)
{
TCHAR szString[MAX_PATH*2];
TCHAR szCaption[MAX_PATH];
LoadString((HINSTANCE)g_hInstDll, IDS_OWNERSHIP, szCaption, MAX_PATH-1);
hr = StringCchPrintf(szString, MAX_PATH*2-1, szCaption, lpObjectName);
LoadString((HINSTANCE)g_hInstDll, IDS_MAIN_TITLE, szCaption, MAX_PATH-1);
if (SUCCEEDED(hr) && MessageBox(GetConsoleWindow(), szString, szCaption, MB_YESNO) == IDYES)
{
if (ChangeOwner(lpObjectName, ObjectType) == ERROR_SUCCESS)
{
DPF(REGmsg, L"Administrator takes over the ownership: ObjectName=%s", lpObjectName);
dwErr = GetNamedSecurityInfo(lpObjectName,
ObjectType,
secInfo,
NULL,
NULL,
&psidDacl,
NULL,
&pSD);
}
}
}
if (dwErr == ERROR_SUCCESS)
{
pDacl = psidDacl;
if (bSetOrRestore)
{
dwErr = AddAccessAllowedACEToACL (&pDacl, GENERIC_ALL | SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL);
if (dwErr == ERROR_SUCCESS)
DPF(REGmsg, L"Add Administrator with full control to ACL: ObjectName=%s", lpObjectName);
else
DPF(REGerr, L"Fails to add Administrator with full control to ACL: ObjectName=%s", lpObjectName);
}
else
{
dwErr = RemoveACEFromACL(pDacl);
if (dwErr == ERROR_SUCCESS)
DPF(REGmsg, L"Remove Administrator with full control from ACL: ObjectName=%s", lpObjectName);
else
DPF(REGerr, L"Fails to remove Administrator with full control from ACL: ObjectName=%s", lpObjectName);
}
if (dwErr == ERROR_SUCCESS)
{
dwErr = SetNamedSecurityInfo(lpObjectName,
ObjectType,
secInfo,
NULL,
NULL,
pDacl,
NULL);
}
if (psidDacl != pDacl && pDacl)
free(pDacl);
LocalFree(pSD);
}
return dwErr;
}
#define ACCESS_STATUS_ALLOWED 0
#define ACCESS_STATUS_DENIED 1
#define ACCESS_STATUS_NOTPRESENT 2
HRESULT GetObjectAccessStatus(
LPTSTR lpObjectName,
SE_OBJECT_TYPE ObjectType,
PSID pOwnerSid,
PDWORD pdwStatus)
{
DWORD dwErr;
HRESULT hr;
PSECURITY_DESCRIPTOR pSD = NULL;
PACL psidDacl = NULL;
SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
ACL_SIZE_INFORMATION aclSizeInfo;
LPVOID ace;
ACE_HEADER *aceHeader;
ULONG i;
ACCESS_MASK dwAllowMask,dwDeniedMask;
if (!lpObjectName || !pOwnerSid || !pdwStatus)
{
hr = E_INVALIDARG;
goto cleanup;
}
dwErr = GetNamedSecurityInfo(lpObjectName,
ObjectType,
secInfo,
NULL,
NULL,
&psidDacl,
NULL,
&pSD);
if (dwErr != ERROR_SUCCESS)
{
hr = HRESULT_FROM_WIN32(dwErr);
goto cleanup;
}
if (!psidDacl)
{
// in FS, this must be FAT/FAT32
hr = S_OK;
*pdwStatus = ACCESS_STATUS_ALLOWED;
goto cleanup;
}
if (!GetAclInformation (psidDacl,
(LPVOID) &aclSizeInfo,
(DWORD) sizeof (ACL_SIZE_INFORMATION),
AclSizeInformation))
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup;
}
*pdwStatus = ACCESS_STATUS_NOTPRESENT;
dwAllowMask = dwDeniedMask = 0;
for (i = 0; i < aclSizeInfo.AceCount; i++)
{
ACCESS_ALLOWED_ACE *accessAllowedAce;
ACCESS_DENIED_ACE *accessDeniedAce;
PSID pAclSid;
if (!GetAce (psidDacl, i, &ace))
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup;
}
aceHeader = (ACE_HEADER *) ace;
switch (aceHeader->AceType)
{
case ACCESS_ALLOWED_ACE_TYPE:
accessAllowedAce = (ACCESS_ALLOWED_ACE *) ace;
pAclSid = (PSID) &accessAllowedAce->SidStart;
if (EqualSid (pOwnerSid, pAclSid))
{
dwAllowMask |= accessAllowedAce->Mask;
}
break;
case ACCESS_DENIED_ACE_TYPE:
accessDeniedAce = (ACCESS_DENIED_ACE *) ace;
pAclSid = (PSID) &accessDeniedAce->SidStart;
if (EqualSid (pOwnerSid, pAclSid))
{
dwDeniedMask |= accessDeniedAce->Mask;
}
break;
default:
continue;
}
}
GENERIC_MAPPING gm;
gm.GenericRead = FILE_GENERIC_READ ;
gm.GenericWrite = FILE_GENERIC_WRITE ;
gm.GenericExecute = FILE_GENERIC_EXECUTE ;
gm.GenericAll = FILE_ALL_ACCESS ;
DWORD dwExpected = GENERIC_ALL|GENERIC_WRITE|GENERIC_READ;
MapGenericMask(&dwExpected,&gm);
if (AreAnyAccessesGranted(dwDeniedMask,dwExpected))
{
*pdwStatus = ACCESS_STATUS_DENIED;
hr = S_OK;
goto cleanup;
}
dwExpected = GENERIC_ALL;
MapGenericMask(&dwExpected,&gm);
if (AreAllAccessesGranted(dwAllowMask,dwExpected))
{
*pdwStatus = ACCESS_STATUS_ALLOWED;
hr = S_OK;
goto cleanup;
}
dwExpected = GENERIC_WRITE|GENERIC_READ;
MapGenericMask(&dwExpected,&gm);
if (AreAllAccessesGranted(dwAllowMask,dwExpected))
{
*pdwStatus = ACCESS_STATUS_ALLOWED;
hr = S_OK;
goto cleanup;
}
*pdwStatus = ACCESS_STATUS_NOTPRESENT;
hr = S_OK;
cleanup:
if (pSD)
{
LocalFree(pSD);
}
return hr;
}
HRESULT IsObjectAccessiablebyLocalSys(
LPTSTR lpObjectName,
SE_OBJECT_TYPE ObjectType,
PBOOL pbCanAccess)
{
HRESULT hr = S_OK;
PSID pUserSid = NULL;
DWORD dwLocal,dwEveryone,dwAdmins;
SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
*pbCanAccess = FALSE;
//Local System
if (!ConvertStringSidToSid(TEXT("S-1-5-18"),&pUserSid))
{
hr = HRESULT_FROM_WIN32(GetLastError());
pUserSid = NULL;
goto cleanup;
}
hr = GetObjectAccessStatus(lpObjectName,ObjectType,pUserSid,&dwLocal);
if (hr != S_OK)
{
goto cleanup;
}
if (dwLocal == ACCESS_STATUS_DENIED)
{
*pbCanAccess = FALSE;
goto cleanup;
}
LocalFree(pUserSid);
pUserSid = NULL;
//Everyone
if (!ConvertStringSidToSid(TEXT("S-1-1-0"),&pUserSid))
{
hr = HRESULT_FROM_WIN32(GetLastError());
pUserSid = NULL;
goto cleanup;
}
hr = GetObjectAccessStatus(lpObjectName,ObjectType,pUserSid,&dwEveryone);
if (hr != S_OK)
{
goto cleanup;
}
if (dwEveryone == ACCESS_STATUS_DENIED)
{
*pbCanAccess = FALSE;
goto cleanup;
}
LocalFree(pUserSid);
pUserSid = NULL;
//Local Admins
if(!AllocateAndInitializeSid(&siaNtAuthority, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pUserSid))
{
hr = HRESULT_FROM_WIN32(GetLastError());
pUserSid = NULL;
goto cleanup;
}
hr = GetObjectAccessStatus(lpObjectName,ObjectType,pUserSid,&dwAdmins);
if (hr != S_OK)
{
goto cleanup;
}
if (dwAdmins == ACCESS_STATUS_DENIED)
{
*pbCanAccess = FALSE;
goto cleanup;
}
LocalFree(pUserSid);
pUserSid = NULL;
if (dwEveryone == ACCESS_STATUS_ALLOWED)
{
*pbCanAccess = TRUE;
}
else if ( (dwAdmins ==ACCESS_STATUS_ALLOWED) && (dwLocal ==ACCESS_STATUS_ALLOWED) )
{
*pbCanAccess = TRUE;
}
else
{
*pbCanAccess = FALSE;
}
hr = S_OK;
cleanup:
if (pUserSid)
{
LocalFree(pUserSid);
}
return hr;
}