847 lines
26 KiB
C++
847 lines
26 KiB
C++
// Copyright (c) 1997-1999 Microsoft Corporation
|
|
#include "precomp.h"
|
|
#include "SI.h"
|
|
#include "..\common\util.h"
|
|
#include "..\common\ServiceThread.h"
|
|
#include "..\MMFUtil\MsgDlg.h"
|
|
#include "resource.h"
|
|
#include <winbase.h>
|
|
|
|
//----------------------------------------------------------------------------
|
|
EXTERN_C const GUID IID_ISecurityInformation =
|
|
{ 0x965fc360, 0x16ff, 0x11d0, 0x91, 0xcb, 0x0, 0xaa, 0x0, 0xbb, 0xb7, 0x23 };
|
|
|
|
#define MY_FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED \
|
|
| SYNCHRONIZE \
|
|
| FILE_READ_DATA | FILE_LIST_DIRECTORY \
|
|
| FILE_WRITE_DATA | FILE_ADD_FILE \
|
|
| FILE_APPEND_DATA | FILE_ADD_SUBDIRECTORY \
|
|
| FILE_CREATE_PIPE_INSTANCE \
|
|
| FILE_READ_EA \
|
|
| FILE_WRITE_EA \
|
|
| FILE_EXECUTE | FILE_TRAVERSE \
|
|
| FILE_DELETE_CHILD \
|
|
| FILE_READ_ATTRIBUTES \
|
|
| FILE_WRITE_ATTRIBUTES)
|
|
|
|
#if(FILE_ALL_ACCESS != MY_FILE_ALL_ACCESS)
|
|
#error ACL editor needs to sync with file permissions changes in ntioapi.h (or ntioapi.h is broken)
|
|
#endif
|
|
|
|
#define INHERIT_FULL (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE)
|
|
|
|
//
|
|
// Treat SYNCHRONIZE specially. In particular, always allow SYNCHRONIZE and
|
|
// never Deny SYNCHRONIZE. Do this by removing it from the Generic Mapping,
|
|
// turning it off in all ACEs and SI_ACCESS entries, and then adding it to
|
|
// all Allow ACEs before saving a new ACL.
|
|
//
|
|
#define FILE_GENERIC_READ_ (FILE_GENERIC_READ & ~SYNCHRONIZE)
|
|
#define FILE_GENERIC_WRITE_ (FILE_GENERIC_WRITE & ~(SYNCHRONIZE | READ_CONTROL))
|
|
#define FILE_GENERIC_EXECUTE_ (FILE_GENERIC_EXECUTE & ~SYNCHRONIZE)
|
|
#define FILE_GENERIC_ALL_ (FILE_ALL_ACCESS & ~SYNCHRONIZE)
|
|
|
|
#define FILE_GENERAL_MODIFY (FILE_GENERIC_READ_ | FILE_GENERIC_WRITE_ | FILE_GENERIC_EXECUTE_ | DELETE)
|
|
#define FILE_GENERAL_PUBLISH (FILE_GENERIC_READ_ | FILE_GENERIC_WRITE_ | FILE_GENERIC_EXECUTE_)
|
|
#define FILE_GENERAL_DEPOSIT (FILE_GENERIC_WRITE_ | FILE_GENERIC_EXECUTE_)
|
|
#define FILE_GENERAL_READ_EX (FILE_GENERIC_READ_ | FILE_GENERIC_EXECUTE_)
|
|
|
|
// The following array defines the permission names for NTFS objects.
|
|
SI_ACCESS siNTFSAccesses[] =
|
|
{
|
|
{ &GUID_NULL, FILE_GENERIC_ALL_, MAKEINTRESOURCE(IDS_NTFS_GENERIC_ALL), SI_ACCESS_GENERAL | INHERIT_FULL },
|
|
{ &GUID_NULL, FILE_GENERAL_MODIFY, MAKEINTRESOURCE(IDS_NTFS_GENERAL_MODIFY), SI_ACCESS_GENERAL | INHERIT_FULL },
|
|
{ &GUID_NULL, FILE_GENERAL_READ_EX, MAKEINTRESOURCE(IDS_NTFS_GENERAL_READ), SI_ACCESS_GENERAL | INHERIT_FULL },
|
|
{ &GUID_NULL, FILE_GENERAL_READ_EX, MAKEINTRESOURCE(IDS_NTFS_GENERAL_LIST), SI_ACCESS_CONTAINER | CONTAINER_INHERIT_ACE },
|
|
{ &GUID_NULL, FILE_GENERIC_READ_, MAKEINTRESOURCE(IDS_NTFS_GENERIC_READ), SI_ACCESS_GENERAL | INHERIT_FULL },
|
|
{ &GUID_NULL, FILE_GENERIC_WRITE_, MAKEINTRESOURCE(IDS_NTFS_GENERIC_WRITE), SI_ACCESS_GENERAL | INHERIT_FULL },
|
|
{ &GUID_NULL, FILE_EXECUTE, MAKEINTRESOURCE(IDS_NTFS_FILE_EXECUTE), SI_ACCESS_SPECIFIC },
|
|
{ &GUID_NULL, FILE_READ_DATA, MAKEINTRESOURCE(IDS_NTFS_FILE_READ_DATA), SI_ACCESS_SPECIFIC },
|
|
{ &GUID_NULL, FILE_READ_ATTRIBUTES, MAKEINTRESOURCE(IDS_NTFS_FILE_READ_ATTR), SI_ACCESS_SPECIFIC },
|
|
{ &GUID_NULL, FILE_READ_EA, MAKEINTRESOURCE(IDS_NTFS_FILE_READ_EA), SI_ACCESS_SPECIFIC },
|
|
{ &GUID_NULL, FILE_WRITE_DATA, MAKEINTRESOURCE(IDS_NTFS_FILE_WRITE_DATA), SI_ACCESS_SPECIFIC },
|
|
{ &GUID_NULL, FILE_APPEND_DATA, MAKEINTRESOURCE(IDS_NTFS_FILE_APPEND_DATA), SI_ACCESS_SPECIFIC },
|
|
{ &GUID_NULL, FILE_WRITE_ATTRIBUTES,MAKEINTRESOURCE(IDS_NTFS_FILE_WRITE_ATTR), SI_ACCESS_SPECIFIC },
|
|
{ &GUID_NULL, FILE_WRITE_EA, MAKEINTRESOURCE(IDS_NTFS_FILE_WRITE_EA), SI_ACCESS_SPECIFIC },
|
|
#if(FILE_CREATE_PIPE_INSTANCE != FILE_APPEND_DATA)
|
|
{ &GUID_NULL, FILE_CREATE_PIPE_INSTANCE, MAKEINTRESOURCE(IDS_NTFS_FILE_CREATE_PIPE), SI_ACCESS_SPECIFIC },
|
|
#endif
|
|
{ &GUID_NULL, FILE_DELETE_CHILD, MAKEINTRESOURCE(IDS_NTFS_FILE_DELETE_CHILD),SI_ACCESS_SPECIFIC },
|
|
{ &GUID_NULL, DELETE, MAKEINTRESOURCE(IDS_NTFS_STD_DELETE), SI_ACCESS_SPECIFIC },
|
|
{ &GUID_NULL, READ_CONTROL, MAKEINTRESOURCE(IDS_NTFS_STD_READ_CONTROL), SI_ACCESS_SPECIFIC },
|
|
{ &GUID_NULL, WRITE_DAC, MAKEINTRESOURCE(IDS_NTFS_STD_WRITE_DAC), SI_ACCESS_SPECIFIC },
|
|
{ &GUID_NULL, WRITE_OWNER, MAKEINTRESOURCE(IDS_NTFS_STD_WRITE_OWNER), SI_ACCESS_SPECIFIC },
|
|
// { &GUID_NULL, SYNCHRONIZE, MAKEINTRESOURCE(IDS_NTFS_STD_SYNCHRONIZE), SI_ACCESS_SPECIFIC },
|
|
{ &GUID_NULL, 0, MAKEINTRESOURCE(IDS_NONE), 0 },
|
|
{ &GUID_NULL, FILE_GENERIC_EXECUTE_,MAKEINTRESOURCE(IDS_NTFS_GENERIC_EXECUTE), 0 },
|
|
{ &GUID_NULL, FILE_GENERAL_DEPOSIT, MAKEINTRESOURCE(IDS_NTFS_GENERAL_DEPOSIT), 0 },
|
|
{ &GUID_NULL, FILE_GENERAL_PUBLISH, MAKEINTRESOURCE(IDS_NTFS_GENERAL_PUBLISH), 0 },
|
|
};
|
|
#define iNTFSDefAccess 2 // FILE_GENERAL_READ_EX
|
|
|
|
|
|
// The following array defines the inheritance types for NTFS directories.
|
|
SI_INHERIT_TYPE siNTFSInheritTypes[] =
|
|
{
|
|
&GUID_NULL, 0, MAKEINTRESOURCE(IDS_NTFS_FOLDER),
|
|
&GUID_NULL, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, MAKEINTRESOURCE(IDS_NTFS_FOLDER_SUBITEMS),
|
|
&GUID_NULL, CONTAINER_INHERIT_ACE, MAKEINTRESOURCE(IDS_NTFS_FOLDER_SUBFOLDER),
|
|
&GUID_NULL, OBJECT_INHERIT_ACE, MAKEINTRESOURCE(IDS_NTFS_FOLDER_FILE),
|
|
&GUID_NULL, INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, MAKEINTRESOURCE(IDS_NTFS_SUBITEMS_ONLY),
|
|
&GUID_NULL, INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE, MAKEINTRESOURCE(IDS_NTFS_SUBFOLDER_ONLY),
|
|
&GUID_NULL, INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE, MAKEINTRESOURCE(IDS_NTFS_FILE_ONLY),
|
|
};
|
|
|
|
GENERIC_MAPPING NTFSMap =
|
|
{
|
|
FILE_GENERIC_READ,
|
|
FILE_GENERIC_WRITE,
|
|
FILE_GENERIC_EXECUTE,
|
|
FILE_ALL_ACCESS
|
|
};
|
|
|
|
//---------------------------------------------------------------
|
|
CSecurity::CSecurity() :m_initingDlg(false),
|
|
g_serviceThread(0)
|
|
{
|
|
m_dwprevSize = 0;
|
|
m_prevTokens = NULL;
|
|
m_prevBuffer = NULL;
|
|
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
void CSecurity::Initialize(WbemServiceThread *serviceThread,
|
|
CWbemClassObject &inst,
|
|
bstr_t deviceID,
|
|
LPWSTR idiotName,
|
|
LPWSTR provider,
|
|
LPWSTR mangled)
|
|
{
|
|
m_deviceID = deviceID;
|
|
wcsncpy(m_idiotName, idiotName, 100);
|
|
wcsncpy(m_provider, provider, 100);
|
|
wcsncpy(m_mangled, mangled, 255);
|
|
|
|
g_serviceThread = serviceThread;
|
|
m_inst = inst;
|
|
}
|
|
|
|
//------------------ Accessors to the above arrays---------------
|
|
//---------------------------------------------------------------
|
|
HRESULT CSecurity::MapGeneric(const GUID *pguidObjectType,
|
|
UCHAR *pAceFlags,
|
|
ACCESS_MASK *pMask)
|
|
{
|
|
ATLASSERT(pMask);
|
|
|
|
MapGenericMask(pMask, &NTFSMap);
|
|
*pMask &= ~SYNCHRONIZE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CSecurity::GetInheritTypes(PSI_INHERIT_TYPE *ppInheritTypes,
|
|
ULONG *pcInheritTypes)
|
|
{
|
|
ATLASSERT(ppInheritTypes != NULL);
|
|
ATLASSERT(pcInheritTypes != NULL);
|
|
|
|
*ppInheritTypes = siNTFSInheritTypes;
|
|
*pcInheritTypes = ARRAYSIZE(siNTFSInheritTypes);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
#define ALL_SECURITY_ACCESS (READ_CONTROL | WRITE_DAC | WRITE_OWNER | ACCESS_SYSTEM_SECURITY)
|
|
|
|
DWORD CSecurity::GetAccessMask(CWbemClassObject &inst)
|
|
{
|
|
CWbemClassObject paramCls, dummy;
|
|
|
|
DWORD dwAccessGranted = 0;
|
|
DWORD dwAccessDesired[] = { ALL_SECURITY_ACCESS,
|
|
READ_CONTROL,
|
|
WRITE_DAC,
|
|
WRITE_OWNER,
|
|
ACCESS_SYSTEM_SECURITY};
|
|
|
|
paramCls = m_WbemServices.GetObject("CIM_LogicalFile");
|
|
|
|
if(paramCls)
|
|
{
|
|
CWbemClassObject param;
|
|
CWbemClassObject setting;
|
|
|
|
HRESULT hr = paramCls.GetMethod(L"GetEffectivePermission", param, dummy);
|
|
|
|
if(SUCCEEDED(hr) && (bool)param)
|
|
{
|
|
bstr_t path(L"CIM_LogicalFile=\"");
|
|
path += m_deviceID;
|
|
path += L"\\\\\"";
|
|
|
|
for(int i = 0; i < ARRAYSIZE(dwAccessDesired); i++)
|
|
{
|
|
if((dwAccessDesired[i] & dwAccessGranted) == dwAccessDesired[i])
|
|
continue; // already have this access
|
|
|
|
CWbemClassObject retCls;
|
|
|
|
hr = S_OK;
|
|
hr = param.Put(L"Permissions", (long)dwAccessDesired[i]);
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
hr = m_WbemServices.ExecMethod(path,
|
|
L"GetEffectivePermission",
|
|
param, retCls);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
// extract the real error code.
|
|
bool granted = retCls.GetBool("ReturnValue");
|
|
|
|
if(granted)
|
|
dwAccessGranted |= dwAccessDesired[i];
|
|
}
|
|
}
|
|
|
|
} //endfor
|
|
|
|
} //endif (SUCCEEDED
|
|
}
|
|
|
|
return dwAccessGranted;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
#define ALL_SI (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION|\
|
|
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)
|
|
|
|
|
|
// NOTE: To efficiently get the SD ONLY ONCE, GetObjectInformation calls
|
|
// CacheSecurity() which keeps and SD ptr in m_ppCachedSD. GetSecurity()
|
|
// simply returns this pointer and zero's m_ppCachedSD. Aclui will clean up
|
|
// the actually memory as usual.
|
|
HRESULT CSecurity::GetObjectInformation(PSI_OBJECT_INFO pObjectInfo)
|
|
{
|
|
ATLASSERT(pObjectInfo != NULL &&
|
|
!IsBadWritePtr(pObjectInfo, sizeof(*pObjectInfo)));
|
|
|
|
wchar_t fmt[100];
|
|
_bstr_t temp;
|
|
_bstr_t driveName;
|
|
TCHAR driveLtr[3] = {0};
|
|
TCHAR szTemp[30] = {0};
|
|
HRESULT hr = S_OK;
|
|
|
|
if(m_initingDlg)
|
|
{
|
|
memset(fmt, 0, 100 * sizeof(wchar_t));
|
|
memset(m_idiotName, 0, 100 * sizeof(wchar_t));
|
|
|
|
HRESULT hr2 = E_FAIL;
|
|
IWbemServices *service = 0;
|
|
|
|
if(g_serviceThread)
|
|
{
|
|
m_WbemServices = g_serviceThread->GetPtr();
|
|
m_WbemServices.GetServices(&service);
|
|
SetPriv(service);
|
|
|
|
// NOTE: This also sets m_hAccessToken as a side effect.
|
|
hr2 = CacheSecurity(ALL_SI, (PSECURITY_DESCRIPTOR *)&m_ppCachedSD, false);
|
|
}
|
|
|
|
if(SUCCEEDED(hr2) && (bool)m_inst)
|
|
{
|
|
DWORD granted = 0;
|
|
|
|
pObjectInfo->dwFlags |= SI_EDIT_ALL | // dacl, sacl, owner pages.
|
|
SI_ADVANCED; // more than generic rights.
|
|
|
|
granted = GetAccessMask(m_inst);
|
|
|
|
if (!(granted & WRITE_DAC))
|
|
pObjectInfo->dwFlags |= SI_READONLY;
|
|
|
|
if (!(granted & WRITE_OWNER))
|
|
{
|
|
if (!(granted & READ_CONTROL))
|
|
pObjectInfo->dwFlags &= ~SI_EDIT_OWNER;
|
|
else
|
|
pObjectInfo->dwFlags |= SI_OWNER_READONLY;
|
|
}
|
|
|
|
if (!(granted & ACCESS_SYSTEM_SECURITY))
|
|
pObjectInfo->dwFlags &= ~SI_EDIT_AUDITS;
|
|
|
|
|
|
pObjectInfo->dwFlags |= SI_NO_ACL_PROTECT | // no parent.
|
|
SI_CONTAINER; // it's a container since I
|
|
// only do the root dir.
|
|
|
|
long driveType = m_inst.GetLong(L"DriveType");
|
|
|
|
// if its a network connection (remote)....
|
|
if(driveType == 4)
|
|
{
|
|
// use the leftovers from the mangling routine.
|
|
pObjectInfo->pszServerName = CloneWideString(m_provider);
|
|
}
|
|
else
|
|
{
|
|
bstr_t server;
|
|
server = m_inst.GetString(L"__SERVER");
|
|
pObjectInfo->pszServerName = CloneWideString(server);
|
|
}
|
|
|
|
driveName = m_inst.GetString("Name");
|
|
|
|
// isolate the drive letter for later.
|
|
_tcsncpy(driveLtr, driveName, driveName.length());
|
|
}
|
|
else
|
|
{
|
|
pObjectInfo->pszServerName = NULL;
|
|
}
|
|
|
|
ClearPriv(service);
|
|
|
|
pObjectInfo->hInstance = HINST_THISDLL;
|
|
|
|
if(::LoadString(HINST_THISDLL,
|
|
IDS_IDIOT_CAPTION_FMT,
|
|
fmt, 100) == 0)
|
|
{
|
|
wcscpy(fmt, L"%s (%c:)");
|
|
}
|
|
|
|
|
|
// if its locally mapped...
|
|
if(wcslen(m_mangled) == 0)
|
|
{
|
|
// format sheet caption using volumeName (temp).
|
|
if(temp.length() == 0)
|
|
{
|
|
// if not volume name... just say "Local Disk".
|
|
if(::LoadString(HINST_THISDLL,
|
|
IDS_LOCAL_DISK,
|
|
szTemp, 30) == 0)
|
|
{
|
|
wcscpy(szTemp, L"Local Disk");
|
|
}
|
|
temp = szTemp;
|
|
}
|
|
swprintf(m_idiotName, fmt, (wchar_t *)temp, driveLtr[0]);
|
|
}
|
|
else
|
|
{
|
|
// format sheet caption using m_mangled. (network drives)
|
|
swprintf(m_idiotName, fmt, m_mangled, driveLtr[0]);
|
|
}
|
|
pObjectInfo->pszObjectName = m_idiotName;
|
|
}
|
|
else // just the initial creation.
|
|
{
|
|
// its only looking for the _TITLE bit which we dont set anyway.
|
|
pObjectInfo->dwFlags = 0;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CSecurity::GetAccessRights(const GUID *pguidObjectType,
|
|
DWORD dwFlags,
|
|
PSI_ACCESS *ppAccess,
|
|
ULONG *pcAccesses,
|
|
ULONG *piDefaultAccess)
|
|
{
|
|
ATLASSERT(ppAccess);
|
|
ATLASSERT(pcAccesses);
|
|
ATLASSERT(piDefaultAccess);
|
|
|
|
*ppAccess = siNTFSAccesses;
|
|
*pcAccesses = ARRAYSIZE(siNTFSAccesses);
|
|
*piDefaultAccess = iNTFSDefAccess;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//------------------ Real workers -------------------------------
|
|
//---------------------------------------------------------------
|
|
void CSecurity::SetPriv(IWbemServices *service)
|
|
{
|
|
ImpersonateSelf(SecurityImpersonation);
|
|
|
|
if(OpenThreadToken( GetCurrentThread(),
|
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
|
FALSE, &m_hAccessToken ) )
|
|
{
|
|
m_fClearToken = true;
|
|
|
|
// Now, get the LUID for the privilege from the local system
|
|
ZeroMemory(&m_luid, sizeof(m_luid));
|
|
ZeroMemory(&m_luid, sizeof(m_luid2));
|
|
|
|
LookupPrivilegeValue(NULL, SE_SECURITY_NAME, &m_luid);
|
|
LookupPrivilegeValue(NULL, SE_TAKE_OWNERSHIP_NAME, &m_luid2);
|
|
m_WbemServices.m_cloak = true;
|
|
|
|
EnablePriv(service, true);
|
|
}
|
|
else
|
|
{
|
|
DWORD err = GetLastError();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
#define EOAC_DYNAMIC_CLOAKING 0x40
|
|
|
|
DWORD CSecurity::EnablePriv(IWbemServices *service, bool fEnable )
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
DWORD dwSize = 2 * sizeof(TOKEN_PRIVILEGES);
|
|
BYTE *buffer;
|
|
BYTE *prevbuffer;
|
|
TOKEN_PRIVILEGES *tokenPrivileges;
|
|
|
|
//Itz better to save the previous state and restore it on EnablePriv(...,false);
|
|
|
|
if((fEnable == false) && (m_prevTokens != NULL))
|
|
{
|
|
dwSize = m_dwprevSize;
|
|
buffer = new BYTE[dwSize];
|
|
tokenPrivileges = (TOKEN_PRIVILEGES*)buffer;
|
|
memcpy(tokenPrivileges,m_prevTokens,dwSize);
|
|
}
|
|
else
|
|
{
|
|
buffer = new BYTE[dwSize];
|
|
tokenPrivileges = (TOKEN_PRIVILEGES*)buffer;
|
|
tokenPrivileges->PrivilegeCount = 2;
|
|
tokenPrivileges->Privileges[0].Luid = m_luid;
|
|
tokenPrivileges->Privileges[0].Attributes = (fEnable ? SE_PRIVILEGE_ENABLED : 0);
|
|
tokenPrivileges->Privileges[1].Luid = m_luid2;
|
|
tokenPrivileges->Privileges[1].Attributes = (fEnable ? SE_PRIVILEGE_ENABLED : 0);
|
|
if(m_prevTokens != NULL)
|
|
{
|
|
delete []m_prevBuffer;
|
|
m_prevTokens = NULL;
|
|
}
|
|
m_dwprevSize = 0;
|
|
//Find the size of the PrevState Buffer
|
|
AdjustTokenPrivileges(m_hAccessToken,
|
|
FALSE,
|
|
tokenPrivileges,
|
|
dwSize,
|
|
m_prevTokens, &m_dwprevSize);
|
|
m_prevBuffer = new BYTE[m_dwprevSize];
|
|
m_prevTokens = (TOKEN_PRIVILEGES*)m_prevBuffer;
|
|
}
|
|
|
|
if(AdjustTokenPrivileges(m_hAccessToken,
|
|
FALSE,
|
|
tokenPrivileges,
|
|
dwSize,
|
|
m_prevTokens, &m_dwprevSize))
|
|
{
|
|
long lRes = GetLastError();
|
|
|
|
IClientSecurity* pSec;
|
|
HRESULT hres = service->QueryInterface(IID_IClientSecurity, (void**)&pSec);
|
|
if(FAILED(hres))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
hres = pSec->SetBlanket(service, RPC_C_AUTHN_WINNT,
|
|
RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_DYNAMIC_CLOAKING);
|
|
pSec->Release();
|
|
|
|
}
|
|
else
|
|
{
|
|
dwError = ::GetLastError();
|
|
}
|
|
|
|
delete[] buffer;
|
|
|
|
if(fEnable == false)
|
|
{
|
|
delete []m_prevBuffer;
|
|
m_prevTokens = NULL;
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
void CSecurity::ClearPriv(IWbemServices *service)
|
|
{
|
|
|
|
EnablePriv(service, false);
|
|
m_WbemServices.m_cloak = false;
|
|
|
|
if(m_fClearToken)
|
|
{
|
|
CloseHandle(m_hAccessToken);
|
|
m_hAccessToken = 0;
|
|
m_fClearToken = false;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
#define FirstAce(Acl) ((PVOID)((PUCHAR)(Acl) + sizeof(ACL)))
|
|
#define NextAce(Ace) ((PVOID)((PUCHAR)(Ace) + ((PACE_HEADER)(Ace))->AceSize))
|
|
|
|
void CSecurity::ProtectACLs(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD)
|
|
{
|
|
SECURITY_DESCRIPTOR_CONTROL wSDControl;
|
|
DWORD dwRevision;
|
|
PACL pAcl;
|
|
BOOL bDefaulted;
|
|
BOOL bPresent;
|
|
PACE_HEADER pAce;
|
|
UINT cAces;
|
|
|
|
|
|
if (0 == si || NULL == pSD)
|
|
return; // Nothing to do
|
|
|
|
// Get the ACL protection control bits
|
|
GetSecurityDescriptorControl(pSD, &wSDControl, &dwRevision);
|
|
wSDControl &= SE_DACL_PROTECTED | SE_SACL_PROTECTED;
|
|
|
|
if ((si & DACL_SECURITY_INFORMATION) && !(wSDControl & SE_DACL_PROTECTED))
|
|
{
|
|
wSDControl |= SE_DACL_PROTECTED;
|
|
pAcl = NULL;
|
|
GetSecurityDescriptorDacl(pSD, &bPresent, &pAcl, &bDefaulted);
|
|
|
|
// Theoretically, modifying the DACL in this way can cause it to be
|
|
// no longer canonical. However, the only way this can happen is if
|
|
// there is an inherited Deny ACE and a non-inherited Allow ACE.
|
|
// Since this function is only called for root objects, this means
|
|
// a) the server DACL must have a Deny ACE and b) the DACL on this
|
|
// object must have been modified later. But if the DACL was
|
|
// modified through the UI, then we would have eliminated all of the
|
|
// Inherited ACEs already. Therefore, it must have been modified
|
|
// through some other means. Considering that the DACL originally
|
|
// inherited from the server never has a Deny ACE, this situation
|
|
// should be extrememly rare. If it ever does happen, the ACL
|
|
// Editor will just tell the user that the DACL is non-canonical.
|
|
//
|
|
// Therefore, let's ignore the possibility here.
|
|
|
|
if (NULL != pAcl)
|
|
{
|
|
for (cAces = pAcl->AceCount, pAce = (PACE_HEADER)FirstAce(pAcl);
|
|
cAces > 0;
|
|
--cAces, pAce = (PACE_HEADER)NextAce(pAce))
|
|
{
|
|
pAce->AceFlags &= ~INHERITED_ACE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((si & SACL_SECURITY_INFORMATION) && !(wSDControl & SE_SACL_PROTECTED))
|
|
{
|
|
wSDControl |= SE_SACL_PROTECTED;
|
|
pAcl = NULL;
|
|
GetSecurityDescriptorSacl(pSD, &bPresent, &pAcl, &bDefaulted);
|
|
|
|
if (NULL != pAcl)
|
|
{
|
|
for (cAces = pAcl->AceCount, pAce = (PACE_HEADER)FirstAce(pAcl);
|
|
cAces > 0;
|
|
--cAces, pAce = (PACE_HEADER)NextAce(pAce))
|
|
{
|
|
pAce->AceFlags &= ~INHERITED_ACE;
|
|
}
|
|
}
|
|
}
|
|
|
|
SetSecurityDescriptorControl(pSD, SE_DACL_PROTECTED | SE_SACL_PROTECTED, wSDControl);
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
HRESULT CSecurity::GetSecurity(THIS_ SECURITY_INFORMATION RequestedInformation,
|
|
PSECURITY_DESCRIPTOR *ppSecurityDescriptor,
|
|
BOOL fDefault )
|
|
{
|
|
if(fDefault)
|
|
{
|
|
ATLTRACE(L"Default security descriptor not supported");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// NOTE: After apply, aclui comes right here. When initially starting up, it'll go
|
|
// through GetObjectInformation() first.
|
|
|
|
// so, make sure to get a fresh SD from AFTER to apply.
|
|
if(m_ppCachedSD == 0)
|
|
{
|
|
HRESULT hr2 = CacheSecurity(ALL_SI, (PSECURITY_DESCRIPTOR *)&m_ppCachedSD, false);
|
|
}
|
|
|
|
// if there's an SD available...
|
|
if(m_ppCachedSD && SUCCEEDED(m_cacheHR))
|
|
{
|
|
// give ownership of the ptr.
|
|
*ppSecurityDescriptor = m_ppCachedSD;
|
|
m_ppCachedSD = NULL;
|
|
}
|
|
return m_cacheHR;
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
HRESULT CSecurity::CacheSecurity(THIS_ SECURITY_INFORMATION RequestedInformation,
|
|
PSECURITY_DESCRIPTOR *ppSecurityDescriptor,
|
|
BOOL fDefault )
|
|
{
|
|
ATLASSERT(ppSecurityDescriptor != NULL);
|
|
|
|
*ppSecurityDescriptor = NULL;
|
|
|
|
// does it want something?
|
|
if(RequestedInformation != 0)
|
|
{
|
|
CWbemClassObject dummy, setting, param;
|
|
|
|
// call wbem.GetSecurityDescriptor() method
|
|
m_settingPath = L"Win32_LogicalFileSecuritySetting=\"";
|
|
m_settingPath += m_deviceID;
|
|
m_settingPath += L"\\\\\"";
|
|
|
|
m_cacheHR = m_WbemServices.ExecMethod(m_settingPath,
|
|
L"GetSecurityDescriptor",
|
|
dummy, param);
|
|
|
|
if(SUCCEEDED(m_cacheHR))
|
|
{
|
|
setting = param.GetEmbeddedObject("Descriptor");
|
|
|
|
if(setting)
|
|
{
|
|
// translate SD to CInstance
|
|
m_sec.Wbem2SD(RequestedInformation,
|
|
setting,
|
|
m_WbemServices,
|
|
(SECURITY_DESCRIPTOR **)ppSecurityDescriptor);
|
|
|
|
SECURITY_DESCRIPTOR **test = (SECURITY_DESCRIPTOR **)ppSecurityDescriptor;
|
|
|
|
}
|
|
else
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DisplayUserMessage(NULL, HINST_THISDLL,
|
|
IDS_DISPLAY_NAME, BASED_ON_SRC,
|
|
GetSecurityDescriptor,
|
|
m_cacheHR, MB_ICONWARNING);
|
|
return m_cacheHR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*ppSecurityDescriptor = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
|
|
|
|
if(*ppSecurityDescriptor)
|
|
InitializeSecurityDescriptor(*ppSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
|
|
else
|
|
m_cacheHR = E_OUTOFMEMORY;
|
|
}
|
|
|
|
ProtectACLs(RequestedInformation & (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION),
|
|
*ppSecurityDescriptor);
|
|
|
|
return m_cacheHR;
|
|
}
|
|
|
|
//
|
|
// See comments about SYNCHRONIZE at the top of this file
|
|
//
|
|
void CSecurity::FixSynchronizeAccess(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD)
|
|
{
|
|
if (NULL != pSD && 0 != (si & DACL_SECURITY_INFORMATION))
|
|
{
|
|
BOOL bPresent;
|
|
BOOL bDefault;
|
|
PACL pDacl = NULL;
|
|
|
|
GetSecurityDescriptorDacl(pSD, &bPresent, &pDacl, &bDefault);
|
|
|
|
if (pDacl)
|
|
{
|
|
PACE_HEADER pAce;
|
|
int i;
|
|
|
|
for (i = 0, pAce = (PACE_HEADER)FirstAce(pDacl);
|
|
i < pDacl->AceCount;
|
|
i++, pAce = (PACE_HEADER)NextAce(pAce))
|
|
{
|
|
if (ACCESS_ALLOWED_ACE_TYPE == pAce->AceType)
|
|
((ACCESS_ALLOWED_ACE *)pAce)->Mask |= SYNCHRONIZE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CSecurity::SetSecurity(SECURITY_INFORMATION SecurityInformation,
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
try
|
|
{
|
|
// since taking ownership grants implicit WRITE_DAC access, which may
|
|
// be helpful when a new DACL is propagated downward.
|
|
// if ((SecurityInformation & (OWNER_SECURITY_INFORMATION | SI_OWNER_RECURSE))
|
|
// == (OWNER_SECURITY_INFORMATION | SI_OWNER_RECURSE))
|
|
// {
|
|
// BOOL bNotAllApplied = FALSE;
|
|
|
|
// dont pass the SI_OWNER_RECURSE bit to wbem.
|
|
SecurityInformation &= ~(SI_OWNER_RECURSE);
|
|
|
|
// wbem cant do recursive ownership.
|
|
// hr = TakeOwnership(pSD, &bNotAllApplied);
|
|
|
|
// if (FAILED(hr) || bNotAllApplied)
|
|
// {
|
|
// ATLTRACE(L"Unable to take ownership of all items in tree.");
|
|
// }
|
|
|
|
// }
|
|
|
|
// if something was changed...
|
|
if(SecurityInformation != 0)
|
|
{
|
|
CWbemClassObject dummy, paramCls;
|
|
|
|
paramCls = m_WbemServices.GetObject("Win32_LogicalFileSecuritySetting");
|
|
|
|
if(paramCls)
|
|
{
|
|
CWbemClassObject param;
|
|
CWbemClassObject setting;
|
|
|
|
hr = paramCls.GetMethod(L"SetSecurityDescriptor",
|
|
param, dummy);
|
|
|
|
if(SUCCEEDED(hr) && (bool)param)
|
|
{
|
|
// See comments about SYNCHRONIZE at the top of this file.
|
|
if(SecurityInformation & DACL_SECURITY_INFORMATION)
|
|
FixSynchronizeAccess(SecurityInformation, pSecurityDescriptor);
|
|
|
|
// translate SD to CInstance
|
|
m_sec.SD2Wbem(SecurityInformation,
|
|
(SECURITY_DESCRIPTOR *)pSecurityDescriptor,
|
|
m_WbemServices,
|
|
setting);
|
|
|
|
hr = S_OK;
|
|
hr = param.PutEmbeddedObject(L"Descriptor", setting);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
|
|
IWbemServices *service;
|
|
m_WbemServices.GetServices(&service);
|
|
|
|
// NOTE: m_settingPath was built during GetSecurity.
|
|
|
|
// call wbem.SetSecurityDescriptor() method
|
|
SetPriv(service);
|
|
hr = m_WbemServices.ExecMethod(m_settingPath,
|
|
L"SetSecurityDescriptor",
|
|
param, dummy);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
// extract the real error code.
|
|
DWORD err = (DWORD)dummy.GetLong("ReturnValue");
|
|
|
|
// NOTE: there's a issue about which error values should be
|
|
// returned in 'returnValue'.
|
|
if(err == 0x5)
|
|
{
|
|
// Access Denied at the OS level.
|
|
DisplayUserMessage(NULL, HINST_THISDLL,
|
|
IDS_DISPLAY_NAME, BASED_ON_SRC,
|
|
SetSecurityDescriptor,
|
|
WBEM_E_ACCESS_DENIED, MB_ICONWARNING);
|
|
|
|
}
|
|
}
|
|
|
|
ClearPriv(service);
|
|
service->Release();
|
|
service = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_METHOD;
|
|
}
|
|
}
|
|
}
|
|
catch( ... )
|
|
{
|
|
ATLASSERT(FALSE);
|
|
hr = WBEM_E_UNEXPECTED;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CSecurity::PropertySheetPageCallback(HWND hwnd,
|
|
UINT uMsg,
|
|
SI_PAGE_TYPE uPage)
|
|
{
|
|
if(uMsg == PSPCB_SI_INITDIALOG)
|
|
{
|
|
// make GetObjectInformation() cache the SD cuz we're going to display RSN.
|
|
m_initingDlg = true;
|
|
}
|
|
else if((uMsg == PSPCB_CREATE) || uMsg == 0)
|
|
{
|
|
}
|
|
else if(uMsg == PSPCB_RELEASE)
|
|
{
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------
|
|
LPWSTR CSecurity::CloneWideString(_bstr_t pszSrc )
|
|
{
|
|
LPWSTR pszDst = NULL;
|
|
|
|
pszDst = new WCHAR[(lstrlen(pszSrc) + 1)];
|
|
if (pszDst)
|
|
{
|
|
wcscpy( pszDst, pszSrc );
|
|
}
|
|
|
|
return pszDst;
|
|
}
|
|
|