2709 lines
86 KiB
C++
2709 lines
86 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 1996.
|
|
//
|
|
// File: MARTABAS.CXX
|
|
//
|
|
// Contents: Implementation of the base MARTA funcitons
|
|
//
|
|
// History: 22-Jul-96 MacM Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
#include <aclpch.hxx>
|
|
#pragma hdrstop
|
|
#include <ntprov.hxx>
|
|
#include <strings.h>
|
|
#include <ntdsguid.h>
|
|
|
|
|
|
CSList gWrkrList(NtProvFreeWorkerItem); // List of active worker threads
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvGetCapabilities
|
|
//
|
|
// Synopsis: Gets the provider capabilities
|
|
//
|
|
// Arguments: [IN fClass] -- Class of capabilities to request
|
|
// [OUT pulCaps] -- Provider capabilities
|
|
//
|
|
// Returns: VOID
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
WINAPI
|
|
AccProvGetCapabilities(IN ULONG fClass,
|
|
OUT PULONG pulCaps)
|
|
{
|
|
acDebugOut((DEB_TRACE_API,"in.out AccProvGetCapabilities\n"));
|
|
|
|
if(fClass == ACTRL_CLASS_GENERAL)
|
|
{
|
|
*pulCaps = ACTRL_CAP_KNOWS_SIDS | ACTRL_CAP_SUPPORTS_HANDLES;
|
|
}
|
|
else
|
|
{
|
|
*pulCaps = ACTRL_CAP_NONE;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvIsObjectAccessible
|
|
//
|
|
// Synopsis: Determines if the given path is accessible or not
|
|
//
|
|
// Arguments: [IN pwszObjectPath] -- Path to the object in question
|
|
// [IN ObjectType] -- Type of the object
|
|
//
|
|
// Returns: ERROR_SUCCESS -- The path is recognized
|
|
// ERROR_PATH_NOT_FOUND -- The path was not recognized
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvIsObjectAccessible(IN LPCWSTR pwszObjectPath,
|
|
IN SE_OBJECT_TYPE ObjectType)
|
|
{
|
|
acDebugOut((DEB_TRACE_API,"in AccProvIsObjectAccessible\n"));
|
|
DWORD dwErr = ERROR_PATH_NOT_FOUND;
|
|
PWSTR DsServerlessPath, OldServerPath = NULL;
|
|
|
|
static NTMARTA_ACCESS_CACHE rgAccessCache[MAX_ACCESS_ENTRIES];
|
|
static ULONG cCacheEntries = 0;
|
|
static ULONG iCacheOldest = 0;
|
|
|
|
|
|
//
|
|
// First, check our cache. Maybe we can get out cheap. Note that
|
|
// we expect our result to be failure when we start.
|
|
//
|
|
ULONG dwObjLen = wcslen(pwszObjectPath);
|
|
if(dwObjLen < MAX_PATH)
|
|
{
|
|
RtlAcquireResourceShared(&gCacheLock, TRUE);
|
|
for(ULONG iIndex = 0;
|
|
iIndex < cCacheEntries && dwErr == ERROR_PATH_NOT_FOUND;
|
|
iIndex++)
|
|
{
|
|
//
|
|
// We'll have to do this base on object type...
|
|
//
|
|
switch(ObjectType)
|
|
{
|
|
case SE_SERVICE:
|
|
case SE_PRINTER:
|
|
case SE_REGISTRY_KEY:
|
|
//
|
|
// See if it's a UNC name, in which case we'll compare
|
|
// the only the server\\share name.
|
|
//
|
|
if(dwObjLen > 1 && pwszObjectPath[1] == L'\\')
|
|
{
|
|
//
|
|
// It's a UNC name
|
|
//
|
|
if(_wcsnicmp(pwszObjectPath,
|
|
rgAccessCache[iIndex].wszPath,
|
|
rgAccessCache[iIndex].cLen) == 0 &&
|
|
(*(pwszObjectPath + rgAccessCache[iIndex].cLen)
|
|
== L'\0' ||
|
|
*(pwszObjectPath + rgAccessCache[iIndex].cLen)
|
|
== L'\\'))
|
|
{
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(_wcsicmp(pwszObjectPath,
|
|
rgAccessCache[iIndex].wszPath) == 0)
|
|
{
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SE_DS_OBJECT:
|
|
case SE_DS_OBJECT_ALL:
|
|
//
|
|
// These have to match exact. Handle the case where we were given a
|
|
// server name prefixed DS path
|
|
//
|
|
if(IS_UNC_PATH(pwszObjectPath, dwObjLen ) )
|
|
{
|
|
DsServerlessPath = wcschr(pwszObjectPath+2, L'\\');
|
|
|
|
if(DsServerlessPath != NULL)
|
|
{
|
|
DsServerlessPath++;
|
|
OldServerPath = ( PWSTR )pwszObjectPath;
|
|
pwszObjectPath = DsServerlessPath;
|
|
dwObjLen = wcslen(DsServerlessPath);
|
|
}
|
|
}
|
|
|
|
if(dwObjLen == rgAccessCache[iIndex].cLen &&
|
|
_wcsicmp(pwszObjectPath,
|
|
rgAccessCache[iIndex].wszPath) == 0)
|
|
{
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case SE_FILE_OBJECT:
|
|
case SE_KERNEL_OBJECT:
|
|
case SE_LMSHARE:
|
|
case SE_WMIGUID_OBJECT:
|
|
|
|
if(dwObjLen == rgAccessCache[iIndex].cLen &&
|
|
_wcsicmp(pwszObjectPath,
|
|
rgAccessCache[iIndex].wszPath) == 0)
|
|
{
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Make sure our types match...
|
|
//
|
|
if(dwErr == ERROR_SUCCESS && ObjectType != rgAccessCache[iIndex].ObjectType)
|
|
{
|
|
dwErr = ERROR_PATH_NOT_FOUND;
|
|
}
|
|
#ifdef DBG
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
acDebugOut((DEB_TRACE_CACHE, "Object %ws [%lu] found in cache!\n",
|
|
rgAccessCache[iIndex].wszPath,
|
|
rgAccessCache[iIndex].ObjectType));
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
RtlReleaseResource(&gCacheLock);
|
|
}
|
|
|
|
//
|
|
// If we got a match, return
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// Well, that didn't work, so we'll have to go check. Note that there
|
|
// is not a lock here, so there is a window whereby an entry could be added
|
|
// for the path that we are currently checking. If that happens, it only
|
|
// means that the same entry will be in the cache more than once. This
|
|
// is harmless.
|
|
//
|
|
HANDLE hHandle;
|
|
|
|
switch (ObjectType)
|
|
{
|
|
case SE_FILE_OBJECT:
|
|
dwErr = IsFilePathLocalOrLM((PWSTR)pwszObjectPath);
|
|
break;
|
|
|
|
case SE_SERVICE:
|
|
dwErr = OpenServiceObject((PWSTR)pwszObjectPath,
|
|
SERVICE_USER_DEFINED_CONTROL,
|
|
(SC_HANDLE *)&hHandle);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
CloseServiceHandle((SC_HANDLE)hHandle);
|
|
}
|
|
else
|
|
{
|
|
if(dwErr == ERROR_SERVICE_DOES_NOT_EXIST ||
|
|
dwErr == ERROR_INVALID_NAME)
|
|
{
|
|
dwErr = ERROR_PATH_NOT_FOUND;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SE_PRINTER:
|
|
dwErr = OpenPrinterObject((PWSTR)pwszObjectPath,
|
|
PRINTER_ACCESS_USE,
|
|
&hHandle);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
ClosePrinter(hHandle);
|
|
}
|
|
else
|
|
{
|
|
if(dwErr == ERROR_INVALID_PRINTER_NAME)
|
|
{
|
|
dwErr = ERROR_PATH_NOT_FOUND;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SE_REGISTRY_KEY:
|
|
dwErr = OpenRegistryObject((PWSTR)pwszObjectPath,
|
|
KEY_EXECUTE,
|
|
&hHandle);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey((HKEY)hHandle);
|
|
}
|
|
else
|
|
{
|
|
if(dwErr == ERROR_INVALID_PARAMETER ||
|
|
dwErr == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
dwErr = ERROR_PATH_NOT_FOUND;
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_LMSHARE:
|
|
//
|
|
// Note that this doesn't have to be a local share, just a lan man
|
|
// share
|
|
//
|
|
dwErr = PingLmShare(pwszObjectPath);
|
|
|
|
break;
|
|
|
|
case SE_KERNEL_OBJECT: // FALL THROUGH
|
|
case SE_WMIGUID_OBJECT:
|
|
|
|
//
|
|
// Can't have kernel objects outside of NT, so just return success
|
|
//
|
|
dwErr = ERROR_SUCCESS;
|
|
break;
|
|
|
|
case SE_DS_OBJECT: // FALL THROUGH
|
|
case SE_DS_OBJECT_ALL:
|
|
dwErr = PingDSObj(OldServerPath ? OldServerPath : pwszObjectPath);
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// Unknown object type. Pass it on.
|
|
//
|
|
dwErr = ERROR_PATH_NOT_FOUND;
|
|
break;
|
|
}
|
|
|
|
|
|
if(dwErr == ERROR_ACCESS_DENIED)
|
|
{
|
|
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Add it to the cache, if we succeeded
|
|
//
|
|
if(dwErr == ERROR_SUCCESS &&
|
|
(ObjectType != SE_KERNEL_OBJECT || ObjectType != SE_WMIGUID_OBJECT))
|
|
{
|
|
//
|
|
// Lock the cache
|
|
//
|
|
RtlAcquireResourceExclusive(&gCacheLock, TRUE);
|
|
|
|
//
|
|
// For some items, we'll want to save the root of the path, since it
|
|
// is not possible to have linked services, registry keys, etc, while
|
|
// for files and shares, it can cause problems. If an entry is too
|
|
// long to be cached, we'll ignore it.
|
|
//
|
|
|
|
if(dwObjLen <= MAX_PATH)
|
|
{
|
|
//
|
|
// Save off the object type and path name. For those that
|
|
// need it, we'll go through and shorten them as requried.
|
|
//
|
|
rgAccessCache[iCacheOldest].ObjectType = ObjectType;
|
|
wcscpy(rgAccessCache[iCacheOldest].wszPath,
|
|
pwszObjectPath);
|
|
rgAccessCache[iCacheOldest].cLen = dwObjLen;
|
|
|
|
PWSTR pwszLop = rgAccessCache[iCacheOldest].wszPath;
|
|
switch (ObjectType)
|
|
{
|
|
case SE_SERVICE:
|
|
case SE_PRINTER:
|
|
case SE_REGISTRY_KEY:
|
|
//
|
|
// See if it's a UNC name, in which case we'll lop
|
|
// it off
|
|
//
|
|
if(IS_UNC_PATH(pwszObjectPath, dwObjLen))
|
|
{
|
|
//
|
|
// It's a UNC name, so lop it off
|
|
//
|
|
pwszLop = wcschr(pwszLop + 2,
|
|
L'\\');
|
|
if(pwszLop != NULL)
|
|
{
|
|
pwszLop = wcschr(pwszLop + 1, '\\');
|
|
|
|
if(pwszLop != NULL)
|
|
{
|
|
*pwszLop = L'\0';
|
|
rgAccessCache[iCacheOldest].cLen = (DWORD)(pwszLop -
|
|
rgAccessCache[iCacheOldest].wszPath);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SE_DS_OBJECT:
|
|
case SE_DS_OBJECT_ALL:
|
|
//
|
|
// Save off the domain name part
|
|
//
|
|
|
|
//
|
|
// Note that we'll get the object in RDN format, so
|
|
// it's a simple matter to lop it off if necessary
|
|
pwszLop = wcschr(pwszLop, L'\\');
|
|
if(pwszLop != NULL)
|
|
{
|
|
*pwszLop = L'\0';
|
|
rgAccessCache[iCacheOldest].cLen = (DWORD)(pwszLop -
|
|
rgAccessCache[iCacheOldest].wszPath);
|
|
}
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Update our indexes and counts
|
|
//
|
|
if(cCacheEntries < MAX_ACCESS_ENTRIES)
|
|
{
|
|
cCacheEntries++;
|
|
}
|
|
|
|
iCacheOldest++;
|
|
if(iCacheOldest == MAX_ACCESS_ENTRIES)
|
|
{
|
|
iCacheOldest = 0;
|
|
}
|
|
}
|
|
|
|
RtlReleaseResource(&gCacheLock);
|
|
}
|
|
|
|
if ( dwErr == ERROR_INVALID_NAME ) {
|
|
|
|
acDebugOut(( DEB_ERROR, "%ws returned ERROR_INVALID_NAME\n", pwszObjectPath ));
|
|
ASSERT( FALSE );
|
|
|
|
}
|
|
acDebugOut((DEB_TRACE_API,"out AccProvIsObjectAccessible: %lu\n", dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvHandleIsObjectAccessible
|
|
//
|
|
// Synopsis: Determines if the given object is accessible or not given
|
|
// a handle to it
|
|
//
|
|
// Arguments: [IN hObject] -- Object handle
|
|
// [IN ObjectType] -- Type of the object
|
|
//
|
|
// Returns: ERROR_SUCCESS -- The path is recognized
|
|
// ERROR_PATH_NOT_FOUND -- The path was not recognized
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvHandleIsObjectAccessible(IN HANDLE hObject,
|
|
IN SE_OBJECT_TYPE ObjectType)
|
|
{
|
|
acDebugOut((DEB_TRACE_API,"in AccProvHandleIsObjectAccessible\n"));
|
|
|
|
DWORD dwErr = ERROR_PATH_NOT_FOUND;
|
|
|
|
//
|
|
// Because a handle can get reused, we can't cache them like we did
|
|
// above...
|
|
//
|
|
|
|
switch (ObjectType)
|
|
{
|
|
case SE_FILE_OBJECT:
|
|
{
|
|
DWORD dwHigh;
|
|
DWORD dwSize = GetFileSize(hObject,
|
|
&dwHigh);
|
|
if(dwSize == 0xFFFFFFFF)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SE_SERVICE:
|
|
{
|
|
SERVICE_STATUS SvcStatus;
|
|
|
|
if(QueryServiceStatus((SC_HANDLE)hObject,
|
|
&SvcStatus) == FALSE)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SE_PRINTER:
|
|
{
|
|
dwErr = LoadDLLFuncTable();
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
ULONG cNeeded;
|
|
if(DLLFuncs.PGetPrinter(hObject,
|
|
1,
|
|
NULL,
|
|
0,
|
|
&cNeeded) == FALSE)
|
|
{
|
|
dwErr = GetLastError();
|
|
if(dwErr == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SE_REGISTRY_KEY:
|
|
dwErr = RegQueryInfoKey((HKEY)hObject,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
break;
|
|
|
|
case SE_KERNEL_OBJECT: // FALL THROUGH
|
|
case SE_WINDOW_OBJECT: // FALL THROUGH
|
|
case SE_WMIGUID_OBJECT:
|
|
//
|
|
// Can't have kernel/windows objects outside of NT, so just return
|
|
// success
|
|
//
|
|
dwErr = ERROR_SUCCESS;
|
|
break;
|
|
|
|
case SE_LMSHARE: // FALL THROUGH
|
|
case SE_DS_OBJECT: // FALL THROUGH
|
|
case SE_DS_OBJECT_ALL:
|
|
//
|
|
// Can't have handles to DS objects
|
|
//
|
|
dwErr = ERROR_PATH_NOT_FOUND;
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
//
|
|
// Unknown object type. Pass it on.
|
|
//
|
|
dwErr = ERROR_PATH_NOT_FOUND;
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Make sure the reason we failed isn't because of permissions
|
|
//
|
|
if(dwErr == ERROR_ACCESS_DENIED)
|
|
{
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
|
|
acDebugOut((DEB_TRACE_API,"out AccProvIsObjectAccessible: %lu\n", dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvCancelOperation
|
|
//
|
|
// Synopsis: Cancels an ongoing operation.
|
|
//
|
|
// Arguments: [IN pOverlapped] -- Operation to cancel
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
// ERROR_INVALID_PARAMETER -- A bad overlapped structure was
|
|
// given
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvCancelOperation(IN PACTRL_OVERLAPPED pOverlapped)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Ok, first, grab a read lock, so nobody inserts on us, and find the
|
|
// right node
|
|
//
|
|
PNTMARTA_WRKR_INFO pWrkrNode = NULL;
|
|
|
|
{
|
|
// RtlAcquireResourceShared(&gWrkrLock, TRUE);
|
|
RtlAcquireResourceExclusive(&gWrkrLock, TRUE);
|
|
|
|
pWrkrNode = (PNTMARTA_WRKR_INFO)gWrkrList.Find((PVOID)pOverlapped,
|
|
NtProvFindWorkerItem);
|
|
RtlReleaseResource(&gWrkrLock);
|
|
}
|
|
|
|
if(pWrkrNode == NULL)
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// All right. We'll set our stop flag, and wait for it to return..
|
|
// It doesn't matter what we set the flag to, since all we need to do
|
|
// is set it non-0
|
|
//
|
|
pWrkrNode->fState++;
|
|
|
|
//
|
|
// Now, wait for the call to finish
|
|
//
|
|
WaitForSingleObject(pWrkrNode->hWorker,
|
|
INFINITE);
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvGetOperationResults
|
|
//
|
|
// Synopsis: Gets the results of an operation
|
|
//
|
|
// Arguments: [IN pOverlapped] -- Operation to cancel
|
|
// [OUT dwResults] -- Where the results are returned
|
|
// [OUT pcProcessed] -- Number of items processed
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
// ERROR_INVALID_PARAMETER -- A bad overlapped structure was
|
|
// given
|
|
// ERROR_IO_PENDING -- Operation hasn't completed yet
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvGetOperationResults(IN PACTRL_OVERLAPPED pOverlapped,
|
|
OUT PDWORD dwResults,
|
|
OUT PDWORD pcProcessed)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
PNTMARTA_WRKR_INFO pWrkrNode = NULL;
|
|
|
|
//
|
|
// Ok, first, grab a write lock. This will prevent anyone from
|
|
// reading and or writing to the list, until we get done updating
|
|
// our overlapped structure.
|
|
//
|
|
RtlAcquireResourceExclusive(&gWrkrLock, TRUE);
|
|
|
|
pWrkrNode = (PNTMARTA_WRKR_INFO)gWrkrList.Find((PVOID)pOverlapped,
|
|
NtProvFindWorkerItem);
|
|
|
|
RtlReleaseResource(&gWrkrLock);
|
|
|
|
if(pWrkrNode == NULL)
|
|
{
|
|
//
|
|
// Now, the reason we may have not found the node is that somebody
|
|
// has removed it. If so, check our overlapped structure, since
|
|
// that will have been updated by the last call
|
|
//
|
|
if(pOverlapped->hEvent != NULL)
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
*dwResults = pOverlapped->Reserved2;
|
|
if(pcProcessed != NULL)
|
|
{
|
|
*pcProcessed = pOverlapped->Reserved1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// See if the thread has stopped processing or not
|
|
//
|
|
if(WaitForSingleObject(pWrkrNode->hWorker, 0) == WAIT_TIMEOUT)
|
|
{
|
|
if(pcProcessed != NULL)
|
|
{
|
|
*pcProcessed = pWrkrNode->cProcessed;
|
|
}
|
|
dwErr = ERROR_IO_PENDING;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Get the results of the thread exit first.
|
|
//
|
|
if(GetExitCodeThread(pWrkrNode->hWorker,
|
|
dwResults) == FALSE)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
dwErr = ERROR_SUCCESS;
|
|
CloseHandle(pWrkrNode->hWorker);
|
|
pWrkrNode->hWorker = NULL;
|
|
|
|
//
|
|
// Save off the results. They go in Reserved2 parameter
|
|
//
|
|
pOverlapped->Reserved2 = *dwResults;
|
|
pOverlapped->Reserved1 = pWrkrNode->cProcessed;
|
|
|
|
//
|
|
// Remove the node from our list, and do our updates. We
|
|
// need to do all of this before releasing our resource,
|
|
// to prevent some race conditions
|
|
//
|
|
RtlAcquireResourceExclusive(&gWrkrLock, TRUE);
|
|
|
|
gWrkrList.Remove((PVOID)pWrkrNode);
|
|
|
|
RtlReleaseResource(&gWrkrLock);
|
|
|
|
//
|
|
// Deallocate our memory
|
|
//
|
|
AccFree(pWrkrNode);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvSetAccessRights
|
|
//
|
|
// Synopsis: Sets the access rights on the given object. It replaces any
|
|
// existing rights.
|
|
//
|
|
// Arguments: [IN pwszObjectPath] -- Path to the object in question
|
|
// [IN ObjectType] -- Type of the object
|
|
// [IN pAccessList] -- Optional. The list of access
|
|
// rights to set.
|
|
// [IN pAuditList] -- Optional. The list of access
|
|
// rights to set.
|
|
// [IN pOwner] -- Optional. Owner to set
|
|
// [IN pGroup] -- Optional. Group to set
|
|
// [IN pOverlapped] -- Overlapped structure to use for
|
|
// asynchronous control
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
// ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvSetAccessRights(IN LPCWSTR pwszObjectPath,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN SECURITY_INFORMATION SecurityInfo,
|
|
IN OPTIONAL PACTRL_ACCESS pAccessList,
|
|
IN OPTIONAL PACTRL_AUDIT pAuditList,
|
|
IN OPTIONAL PTRUSTEE pOwner,
|
|
IN OPTIONAL PTRUSTEE pGroup,
|
|
IN PACTRL_OVERLAPPED pOverlapped)
|
|
{
|
|
DWORD dwErr;
|
|
|
|
CAccessList *pAccList = new CAccessList;
|
|
if(pAccList == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
dwErr = pAccList->SetObjectType(ObjectType);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
if(FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
|
|
{
|
|
dwErr = pAccList->AddAccessLists(DACL_SECURITY_INFORMATION,
|
|
pAccessList,
|
|
FALSE);
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS &&
|
|
FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
|
|
{
|
|
dwErr = pAccList->AddAccessLists(SACL_SECURITY_INFORMATION,
|
|
pAuditList,
|
|
FALSE);
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Add the owner and group
|
|
//
|
|
dwErr = pAccList->AddOwnerGroup(SecurityInfo,
|
|
pOwner,
|
|
pGroup);
|
|
}
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Finally, if all that worked, we'll do the rest
|
|
//
|
|
dwErr = NtProvDoSet(pwszObjectPath,
|
|
ObjectType,
|
|
pAccList,
|
|
pOverlapped,
|
|
NTMARTA_DELETE_ALIST);
|
|
}
|
|
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
delete(pAccList);
|
|
}
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvHandleSetAccessRights
|
|
//
|
|
// Synopsis: Sets the access rights on the given object. It replaces any
|
|
// existing rights.
|
|
//
|
|
// Arguments: [IN hObject] -- Handle to the object
|
|
// [IN ObjectType] -- Type of the object
|
|
// [IN pAccessList] -- Optional. The list of access
|
|
// rights to set.
|
|
// [IN pAuditList] -- Optional. The list of access
|
|
// rights to set.
|
|
// [IN pOwner] -- Optional. Owner to set
|
|
// [IN pGroup] -- Optional. Group to set
|
|
// [IN pOverlapped] -- Overlapped structure to use for
|
|
// asynchronous control
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
// ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvHandleSetAccessRights(IN HANDLE hObject,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN SECURITY_INFORMATION SecurityInfo,
|
|
IN PACTRL_ACCESS pAccessList OPTIONAL,
|
|
IN PACTRL_AUDIT pAuditList OPTIONAL,
|
|
IN PTRUSTEE pOwner OPTIONAL,
|
|
IN PTRUSTEE pGroup OPTIONAL,
|
|
IN PACTRL_OVERLAPPED pOverlapped)
|
|
{
|
|
DWORD dwErr;
|
|
|
|
CAccessList *pAccList = new CAccessList;
|
|
if(pAccList == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
dwErr = pAccList->SetObjectType(ObjectType);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
if(FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
|
|
{
|
|
dwErr = pAccList->AddAccessLists(DACL_SECURITY_INFORMATION,
|
|
pAccessList,
|
|
FALSE);
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS &&
|
|
FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
|
|
{
|
|
dwErr = pAccList->AddAccessLists(SACL_SECURITY_INFORMATION,
|
|
pAuditList,
|
|
FALSE);
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Add the owner and group
|
|
//
|
|
dwErr = pAccList->AddOwnerGroup(SecurityInfo,
|
|
pOwner,
|
|
pGroup);
|
|
}
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Finally, if all that worked, we'll do the rest
|
|
//
|
|
dwErr = NtProvDoHandleSet(hObject,
|
|
ObjectType,
|
|
pAccList,
|
|
pOverlapped,
|
|
NTMARTA_DELETE_ALIST);
|
|
}
|
|
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
delete pAccList;
|
|
}
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvGrantAccessRights
|
|
//
|
|
// Synopsis: Grants the access rights on the given object. It merges the
|
|
// supplied rights with any existing rights.
|
|
//
|
|
// Arguments: [IN pwszObjectPath] -- Path to the object in question
|
|
// [IN ObjectType] -- Type of the object
|
|
// [IN pAccessList] -- Optional. The list of access
|
|
// rights to set.
|
|
// [IN pAuditList] -- Optional. The list of access
|
|
// rights to set.
|
|
//
|
|
// Returns: ERROR_SUCCESS -- The path is recognized
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvGrantAccessRights(IN LPCWSTR pwszObjectPath,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN OPTIONAL PACTRL_ACCESS pAccessList,
|
|
IN OPTIONAL PACTRL_AUDIT pAuditList,
|
|
IN PACTRL_OVERLAPPED pOverlapped)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
//
|
|
// First, read the relevant information. This will involve getting the
|
|
// access and audit lists for each property specified in the access and
|
|
// audit list.
|
|
//
|
|
PACTRL_RIGHTS_INFO pRightsList = NULL;
|
|
ULONG cItems;
|
|
dwErr = NtProvSetRightsList(pAccessList,
|
|
pAuditList,
|
|
&cItems,
|
|
&pRightsList);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// First, read all of the rights
|
|
//
|
|
CAccessList *pAccList = NULL;
|
|
|
|
//
|
|
// NtProvGetAccessListForObject modifies its first
|
|
// parameter, so we can't pass in a CONST string.
|
|
//
|
|
|
|
PWSTR pwszTmpObjectPath = (PWSTR)AccAlloc( (wcslen(pwszObjectPath) + 1) * sizeof( WCHAR ) );
|
|
|
|
if (pwszTmpObjectPath)
|
|
{
|
|
wcscpy( pwszTmpObjectPath, pwszObjectPath );
|
|
pwszTmpObjectPath[wcslen(pwszObjectPath)] = UNICODE_NULL;
|
|
|
|
dwErr = NtProvGetAccessListForObject( pwszTmpObjectPath,
|
|
ObjectType,
|
|
pRightsList,
|
|
cItems,
|
|
&pAccList);
|
|
|
|
//
|
|
// Now, process the input lists
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// First, the access list
|
|
//
|
|
if(pAccessList != NULL)
|
|
{
|
|
dwErr = pAccList->AddAccessLists(DACL_SECURITY_INFORMATION,
|
|
pAccessList,
|
|
TRUE);
|
|
|
|
}
|
|
|
|
//
|
|
// Then, the audit list
|
|
//
|
|
if(dwErr == ERROR_SUCCESS && pAuditList != NULL)
|
|
{
|
|
dwErr = pAccList->AddAccessLists(SACL_SECURITY_INFORMATION,
|
|
pAuditList,
|
|
TRUE);
|
|
}
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Finally, if all that worked, we'll do the rest
|
|
//
|
|
dwErr = NtProvDoSet(pwszObjectPath,
|
|
ObjectType,
|
|
pAccList,
|
|
pOverlapped,
|
|
NTMARTA_DELETE_ALIST);
|
|
}
|
|
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
delete pAccList;
|
|
}
|
|
|
|
AccFree( pwszTmpObjectPath );
|
|
}
|
|
else
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
AccFree(pRightsList);
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvHandleGrantAccessRights
|
|
//
|
|
// Synopsis: Grants the access rights on the given object. It merges the
|
|
// supplied rights with any existing rights.
|
|
//
|
|
// Arguments: [IN hObject] -- Handle to the open object
|
|
// [IN ObjectType] -- Type of the object
|
|
// [IN pAccessList] -- Optional. The list of access
|
|
// rights to set.
|
|
// [IN pAuditList] -- Optional. The list of access
|
|
// rights to set.
|
|
//
|
|
// Returns: ERROR_SUCCESS -- The path is recognized
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvHandleGrantAccessRights(IN HANDLE hObject,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN OPTIONAL PACTRL_ACCESS pAccessList,
|
|
IN OPTIONAL PACTRL_AUDIT pAuditList,
|
|
IN PACTRL_OVERLAPPED pOverlapped)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
//
|
|
// First, read the relevant information. This will involve getting the
|
|
// access and audit lists for each property specified in the access and
|
|
// audit list.
|
|
//
|
|
PACTRL_RIGHTS_INFO pRightsList = NULL;
|
|
ULONG cItems;
|
|
dwErr = NtProvSetRightsList(pAccessList,
|
|
pAuditList,
|
|
&cItems,
|
|
&pRightsList);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// First, read all of the rights
|
|
//
|
|
CAccessList *pAccList = NULL;
|
|
dwErr = NtProvGetAccessListForHandle(hObject,
|
|
ObjectType,
|
|
pRightsList,
|
|
cItems,
|
|
&pAccList);
|
|
//
|
|
// Don't need the rights list, so we might as well release it
|
|
//
|
|
AccFree(pRightsList);
|
|
|
|
//
|
|
// Now, process the input lists
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// First, the access list
|
|
//
|
|
if(pAccessList != NULL)
|
|
{
|
|
dwErr = pAccList->AddAccessLists(DACL_SECURITY_INFORMATION,
|
|
pAccessList,
|
|
TRUE);
|
|
|
|
}
|
|
|
|
//
|
|
// Then, the audit list
|
|
//
|
|
if(dwErr == ERROR_SUCCESS && pAuditList != NULL)
|
|
{
|
|
dwErr = pAccList->AddAccessLists(SACL_SECURITY_INFORMATION,
|
|
pAuditList,
|
|
TRUE);
|
|
}
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Finally, if all that worked, we'll do the rest
|
|
//
|
|
dwErr = NtProvDoHandleSet(hObject,
|
|
ObjectType,
|
|
pAccList,
|
|
pOverlapped,
|
|
NTMARTA_DELETE_ALIST);
|
|
}
|
|
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
delete pAccList;
|
|
}
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvRevokeAccessRights
|
|
//
|
|
// Synopsis: Revokes the access rights on the given object. It goes
|
|
// through and removes any explicit entries for the given
|
|
// trustees
|
|
//
|
|
// Arguments: [IN pwszObjectPath] -- Path to the object in question
|
|
// [IN ObjectType] -- Type of the object
|
|
// [IN pwszProperty] -- Optional. The name of the
|
|
// property on the object to revoke
|
|
// for
|
|
// [IN cTrustees] -- Number of trustees in list
|
|
// [IN prgTrustees] -- List of trustees to revoke
|
|
//
|
|
// Returns: ERROR_SUCCESS -- The operation succeeded
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvRevokeAccessRights(IN LPCWSTR pwszObjectPath,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN OPTIONAL LPCWSTR pwszProperty,
|
|
IN ULONG cTrustees,
|
|
IN PTRUSTEE prgTrustees,
|
|
IN PACTRL_OVERLAPPED pOverlapped)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
CAccessList *pAccList = NULL;
|
|
//
|
|
// First, read the relevant information
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
ACTRL_RIGHTS_INFO RI;
|
|
RI.pwszProperty = (PWSTR)pwszProperty;
|
|
RI.SeInfo = DACL_SECURITY_INFORMATION;
|
|
|
|
PWSTR pwszTmpObjectPath = (PWSTR)AccAlloc( (wcslen(pwszObjectPath) + 1) * sizeof( WCHAR ) );
|
|
|
|
if (pwszTmpObjectPath)
|
|
{
|
|
wcscpy( pwszTmpObjectPath, pwszObjectPath );
|
|
pwszTmpObjectPath[wcslen(pwszObjectPath)] = UNICODE_NULL;
|
|
|
|
dwErr = NtProvGetAccessListForObject(pwszTmpObjectPath,
|
|
ObjectType,
|
|
&RI,
|
|
1,
|
|
&pAccList);
|
|
|
|
AccFree( pwszTmpObjectPath );
|
|
}
|
|
else
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
|
|
for(DWORD iIndex = 0;
|
|
iIndex < cTrustees && dwErr == ERROR_SUCCESS;
|
|
iIndex++)
|
|
{
|
|
dwErr = pAccList->RemoveTrusteeFromAccess(DACL_SECURITY_INFORMATION,
|
|
&(prgTrustees[iIndex]),
|
|
(PWSTR)pwszProperty);
|
|
}
|
|
|
|
//
|
|
// Then, do the set
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = NtProvDoSet(pwszObjectPath,
|
|
ObjectType,
|
|
pAccList,
|
|
pOverlapped,
|
|
NTMARTA_DELETE_ALIST);
|
|
}
|
|
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
delete pAccList;
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvHandleRevokeAccessRights
|
|
//
|
|
// Synopsis: Revokes the access rights on the given object. It goes
|
|
// through and removes any explicit entries for the given
|
|
// trustees
|
|
//
|
|
// Arguments: [IN hObject] -- Handle to the open object
|
|
// [IN ObjectType] -- Type of the object
|
|
// [IN pwszProperty] -- Optional. The name of the
|
|
// property on the object to revoke
|
|
// for
|
|
// [IN cTrustees] -- Number of trustees in list
|
|
// [IN prgTrustees] -- List of trustees to revoke
|
|
//
|
|
// Returns: ERROR_SUCCESS -- The operation succeeded
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvHandleRevokeAccessRights(IN HANDLE hObject,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN OPTIONAL LPCWSTR pwszProperty,
|
|
IN ULONG cTrustees,
|
|
IN PTRUSTEE prgTrustees,
|
|
IN PACTRL_OVERLAPPED pOverlapped)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
CAccessList *pAccList = NULL;
|
|
|
|
//
|
|
// First, read the relevant information
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
ACTRL_RIGHTS_INFO RI;
|
|
RI.pwszProperty = (PWSTR)pwszProperty;
|
|
RI.SeInfo = DACL_SECURITY_INFORMATION;
|
|
dwErr = NtProvGetAccessListForHandle(hObject,
|
|
ObjectType,
|
|
&RI,
|
|
1,
|
|
&pAccList);
|
|
}
|
|
|
|
for(DWORD iIndex = 0;
|
|
iIndex < cTrustees && dwErr == ERROR_SUCCESS;
|
|
iIndex++)
|
|
{
|
|
dwErr = pAccList->RemoveTrusteeFromAccess(DACL_SECURITY_INFORMATION,
|
|
&(prgTrustees[iIndex]),
|
|
(PWSTR)pwszProperty);
|
|
}
|
|
|
|
//
|
|
// Then, do the set
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = NtProvDoHandleSet(hObject,
|
|
ObjectType,
|
|
pAccList,
|
|
pOverlapped,
|
|
NTMARTA_DELETE_ALIST);
|
|
}
|
|
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
delete pAccList;
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvRevokeAuditRights
|
|
//
|
|
// Synopsis: Revokes the audit rights on the given object. It goes
|
|
// through and removes any explicit entries for the given
|
|
// trustees
|
|
//
|
|
// Arguments: [IN pwszObjectPath] -- Path to the object in question
|
|
// [IN ObjectType] -- Type of the object
|
|
// [IN pwszProperty] -- Optional. The name of the
|
|
// property on the object to revoke
|
|
// for
|
|
// [IN cTrustees] -- Number of trustees in list
|
|
// [IN prgTrustees] -- List of trustees to revoke
|
|
//
|
|
// Returns: ERROR_SUCCESS -- The operation succeeded
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvRevokeAuditRights(IN LPCWSTR pwszObjectPath,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN OPTIONAL LPCWSTR pwszProperty,
|
|
IN ULONG cTrustees,
|
|
IN PTRUSTEE prgTrustees,
|
|
IN PACTRL_OVERLAPPED pOverlapped)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
CAccessList *pAccList = NULL;
|
|
//
|
|
// First, read the relevant information
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
ACTRL_RIGHTS_INFO RI;
|
|
RI.pwszProperty = (PWSTR)pwszProperty;
|
|
RI.SeInfo = SACL_SECURITY_INFORMATION;
|
|
|
|
PWSTR pwszTmpObjectPath = (PWSTR)AccAlloc( (wcslen(pwszObjectPath) + 1) * sizeof( WCHAR ) );
|
|
|
|
if (pwszTmpObjectPath)
|
|
{
|
|
wcscpy( pwszTmpObjectPath, pwszObjectPath );
|
|
pwszTmpObjectPath[wcslen(pwszObjectPath)] = UNICODE_NULL;
|
|
|
|
dwErr = NtProvGetAccessListForObject(pwszTmpObjectPath,
|
|
ObjectType,
|
|
&RI,
|
|
1,
|
|
&pAccList);
|
|
AccFree( pwszTmpObjectPath );
|
|
}
|
|
else
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
|
|
for(DWORD iIndex = 0;
|
|
iIndex < cTrustees && dwErr == ERROR_SUCCESS;
|
|
iIndex++)
|
|
{
|
|
dwErr = pAccList->RemoveTrusteeFromAccess(SACL_SECURITY_INFORMATION,
|
|
&(prgTrustees[iIndex]),
|
|
(PWSTR)pwszProperty);
|
|
}
|
|
|
|
//
|
|
// Then, do the set
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = NtProvDoSet(pwszObjectPath,
|
|
ObjectType,
|
|
pAccList,
|
|
pOverlapped,
|
|
NTMARTA_DELETE_ALIST);
|
|
}
|
|
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
delete pAccList;
|
|
}
|
|
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvHandleRevokeAuditRights
|
|
//
|
|
// Synopsis: Revokes the audit rights on the given object. It goes
|
|
// through and removes any explicit entries for the given
|
|
// trustees
|
|
//
|
|
// Arguments: [IN hObject] -- Handle to the open object
|
|
// [IN ObjectType] -- Type of the object
|
|
// [IN pwszProperty] -- Optional. The name of the
|
|
// property on the object to revoke
|
|
// for
|
|
// [IN cTrustees] -- Number of trustees in list
|
|
// [IN prgTrustees] -- List of trustees to revoke
|
|
//
|
|
// Returns: ERROR_SUCCESS -- The operation succeeded
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvHandleRevokeAuditRights(IN HANDLE hObject,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN OPTIONAL LPCWSTR pwszProperty,
|
|
IN ULONG cTrustees,
|
|
IN PTRUSTEE prgTrustees,
|
|
IN PACTRL_OVERLAPPED pOverlapped)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
CAccessList *pAccList = NULL;
|
|
//
|
|
// First, read the relevant information
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
ACTRL_RIGHTS_INFO RI;
|
|
RI.pwszProperty = (PWSTR)pwszProperty;
|
|
RI.SeInfo = SACL_SECURITY_INFORMATION;
|
|
dwErr = NtProvGetAccessListForHandle(hObject,
|
|
ObjectType,
|
|
&RI,
|
|
1,
|
|
&pAccList);
|
|
}
|
|
|
|
for(DWORD iIndex = 0;
|
|
iIndex < cTrustees && dwErr == ERROR_SUCCESS;
|
|
iIndex++)
|
|
{
|
|
dwErr = pAccList->RemoveTrusteeFromAccess(SACL_SECURITY_INFORMATION,
|
|
&(prgTrustees[iIndex]),
|
|
(PWSTR)pwszProperty);
|
|
}
|
|
|
|
//
|
|
// Then, do the set
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = NtProvDoHandleSet(hObject,
|
|
ObjectType,
|
|
pAccList,
|
|
pOverlapped,
|
|
NTMARTA_DELETE_ALIST);
|
|
}
|
|
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
delete pAccList;
|
|
}
|
|
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvGetAllRights
|
|
//
|
|
// Synopsis: Gets the all the requested rights from the object. This
|
|
// includes the access rights, audit rights, and owner and group
|
|
// if supported.
|
|
//
|
|
// Arguments: [IN pwszObjectPath] -- Path to the object in question
|
|
// [IN ObjectType] -- Type of the object
|
|
// [IN pwszProperty] -- Optional. The name of the
|
|
// property on the object to revoke
|
|
// for
|
|
// [OUT ppAccessList] -- Optional. Where to return the
|
|
// access list
|
|
// [OUT ppAuditList] -- Optional. Where to return the
|
|
// audit list.
|
|
// [OUT ppOwner] -- Number of trustees in list
|
|
// [OUT ppGroup] -- List of trustees to revoke
|
|
//
|
|
// Returns: ERROR_SUCCESS -- The operation succeeded
|
|
// ERROR_INVALID_PARAMETER -- An non-NULL property name was
|
|
// given on an object that doesn't
|
|
// support properties.
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvGetAllRights(IN LPCWSTR pwszObjectPath,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN LPCWSTR pwszProperty,
|
|
OUT OPTIONAL PACTRL_ACCESS *ppAccessList,
|
|
OUT OPTIONAL PACTRL_AUDIT *ppAuditList,
|
|
OUT OPTIONAL PTRUSTEE *ppOwner,
|
|
OUT OPTIONAL PTRUSTEE *ppGroup)
|
|
{
|
|
acDebugOut((DEB_TRACE_API,"in AccProvGetAllRights\n"));
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Do the simple parameter checks first...
|
|
//
|
|
if(pwszProperty != NULL &&
|
|
!(ObjectType == SE_DS_OBJECT_ALL || ObjectType == SE_DS_OBJECT))
|
|
{
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
SECURITY_INFORMATION SeInfo = 0;
|
|
|
|
//
|
|
// Determine what we need to read
|
|
//
|
|
if(ppAccessList != NULL)
|
|
{
|
|
SeInfo |= DACL_SECURITY_INFORMATION;
|
|
*ppAccessList = NULL;
|
|
}
|
|
|
|
if(ppAuditList != NULL)
|
|
{
|
|
SeInfo |= SACL_SECURITY_INFORMATION;
|
|
*ppAuditList = NULL;
|
|
}
|
|
|
|
if(ppOwner != NULL)
|
|
{
|
|
SeInfo |= OWNER_SECURITY_INFORMATION;
|
|
*ppOwner = NULL;
|
|
}
|
|
|
|
if(ppGroup != NULL)
|
|
{
|
|
SeInfo |= GROUP_SECURITY_INFORMATION;
|
|
*ppGroup = NULL;
|
|
}
|
|
|
|
//
|
|
// If nothing was requested, do nothing...
|
|
//
|
|
if(SeInfo == 0)
|
|
{
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// Now, go ahead and do the read...
|
|
//
|
|
CAccessList *pAccList;
|
|
|
|
ACTRL_RIGHTS_INFO RI;
|
|
RI.pwszProperty = (PWSTR)pwszProperty;
|
|
RI.SeInfo = SeInfo;
|
|
|
|
//
|
|
// NtProvGetAccessListForObject modifies its first
|
|
// parameter, so we can't pass in a CONST string.
|
|
//
|
|
|
|
PWSTR pwszTmpObjectPath = (PWSTR)AccAlloc( (wcslen(pwszObjectPath) + 1) * sizeof( WCHAR ) );
|
|
|
|
if (pwszTmpObjectPath)
|
|
{
|
|
wcscpy( pwszTmpObjectPath, pwszObjectPath );
|
|
pwszTmpObjectPath[wcslen(pwszObjectPath)] = UNICODE_NULL;
|
|
|
|
dwErr = NtProvGetAccessListForObject(pwszTmpObjectPath,
|
|
ObjectType,
|
|
&RI,
|
|
1,
|
|
&pAccList);
|
|
|
|
|
|
//
|
|
// Now, get the data in the form we need
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Now, convert the stuff that we need to...
|
|
//
|
|
dwErr = pAccList->MarshalAccessLists(SeInfo,
|
|
ppAccessList,
|
|
ppAuditList);
|
|
|
|
if(dwErr == ERROR_SUCCESS && ppOwner != NULL)
|
|
{
|
|
dwErr = pAccList->GetSDSidAsTrustee(OWNER_SECURITY_INFORMATION,
|
|
ppOwner);
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS && ppGroup != NULL)
|
|
{
|
|
dwErr = pAccList->GetSDSidAsTrustee(GROUP_SECURITY_INFORMATION,
|
|
ppGroup);
|
|
}
|
|
|
|
//
|
|
// Ok, if anything failed, we'll do the cleanup
|
|
//
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
if((SeInfo & DACL_SECURITY_INFORMATION) != 0)
|
|
{
|
|
AccFree(*ppAccessList);
|
|
}
|
|
|
|
if((SeInfo & SACL_SECURITY_INFORMATION) != 0)
|
|
{
|
|
AccFree(*ppAuditList);
|
|
}
|
|
|
|
if((SeInfo & OWNER_SECURITY_INFORMATION) != 0)
|
|
{
|
|
AccFree(*ppOwner);
|
|
}
|
|
|
|
if((SeInfo & GROUP_SECURITY_INFORMATION) != 0)
|
|
{
|
|
AccFree(*ppGroup);
|
|
}
|
|
}
|
|
|
|
delete pAccList;
|
|
}
|
|
|
|
AccFree( pwszTmpObjectPath );
|
|
}
|
|
else
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// The destruction of the CAclList class will clean up all of the
|
|
// memory we obtained
|
|
//
|
|
acDebugOut((DEB_TRACE_API,"out AccProvGetAllRights: %lu\n", dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvHandleGetAllRights
|
|
//
|
|
// Synopsis: Gets the all the requested rights from the object. This
|
|
// includes the access rights, audit rights, and owner and group
|
|
// if supported.
|
|
//
|
|
// Arguments: [IN hObject] -- Handle to the open object
|
|
// [IN ObjectType] -- Type of the object
|
|
// [IN pwszProperty] -- Optional. The name of the
|
|
// property on the object to revoke
|
|
// for
|
|
// [OUT ppAccessList] -- Optional. Where to return the
|
|
// access list
|
|
// [OUT ppAuditList] -- Optional. Where to return the
|
|
// audit list.
|
|
// [OUT ppOwner] -- Number of trustees in list
|
|
// [OUT ppGroup] -- List of trustees to revoke
|
|
//
|
|
// Returns: ERROR_SUCCESS -- The operation succeeded
|
|
// ERROR_INVALID_PARAMETER -- An non-NULL property name was
|
|
// given on an object that doesn't
|
|
// support properties.
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvHandleGetAllRights(IN HANDLE hObject,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN LPCWSTR pwszProperty,
|
|
OUT OPTIONAL PACTRL_ACCESS *ppAccessList,
|
|
OUT OPTIONAL PACTRL_AUDIT *ppAuditList,
|
|
OUT OPTIONAL PTRUSTEE *ppOwner,
|
|
OUT OPTIONAL PTRUSTEE *ppGroup)
|
|
{
|
|
acDebugOut((DEB_TRACE_API,"in AccProvHandleGetAllRights\n"));
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Do the simple parameter checks first...
|
|
//
|
|
if(pwszProperty != NULL &&
|
|
(ObjectType != SE_DS_OBJECT_ALL || ObjectType != SE_DS_OBJECT))
|
|
{
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
SECURITY_INFORMATION SeInfo = 0;
|
|
|
|
//
|
|
// Determine what we need to read
|
|
//
|
|
if(ppAccessList != NULL)
|
|
{
|
|
SeInfo |= DACL_SECURITY_INFORMATION;
|
|
*ppAccessList = NULL;
|
|
}
|
|
|
|
if(ppAuditList != NULL)
|
|
{
|
|
SeInfo |= SACL_SECURITY_INFORMATION;
|
|
*ppAuditList = NULL;
|
|
}
|
|
|
|
if(ppOwner != NULL)
|
|
{
|
|
SeInfo |= OWNER_SECURITY_INFORMATION;
|
|
*ppOwner = NULL;
|
|
}
|
|
|
|
if(ppGroup != NULL)
|
|
{
|
|
SeInfo |= GROUP_SECURITY_INFORMATION;
|
|
*ppGroup = NULL;
|
|
}
|
|
|
|
//
|
|
// If nothing was requested, do nothing...
|
|
//
|
|
if(SeInfo == 0)
|
|
{
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// Now, go ahead and do the read...
|
|
//
|
|
CAccessList *pAccList;
|
|
|
|
ACTRL_RIGHTS_INFO RI;
|
|
RI.pwszProperty = (PWSTR)pwszProperty;
|
|
RI.SeInfo = SeInfo;
|
|
dwErr = NtProvGetAccessListForHandle(hObject,
|
|
ObjectType,
|
|
&RI,
|
|
1,
|
|
&pAccList);
|
|
|
|
|
|
//
|
|
// Now, get the data in the form we need
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Now, convert the stuff that we need to...
|
|
//
|
|
dwErr = pAccList->MarshalAccessLists(SeInfo,
|
|
ppAccessList,
|
|
ppAuditList);
|
|
|
|
if(dwErr == ERROR_SUCCESS && ppOwner != NULL)
|
|
{
|
|
dwErr = pAccList->GetSDSidAsTrustee(OWNER_SECURITY_INFORMATION,
|
|
ppOwner);
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS && ppGroup != NULL)
|
|
{
|
|
dwErr = pAccList->GetSDSidAsTrustee(GROUP_SECURITY_INFORMATION,
|
|
ppGroup);
|
|
}
|
|
|
|
//
|
|
// Ok, if anything failed, we'll do the cleanup
|
|
//
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
if((SeInfo & DACL_SECURITY_INFORMATION) != 0)
|
|
{
|
|
AccFree(*ppAccessList);
|
|
}
|
|
|
|
if((SeInfo & SACL_SECURITY_INFORMATION) != 0)
|
|
{
|
|
AccFree(*ppAuditList);
|
|
}
|
|
|
|
if((SeInfo & OWNER_SECURITY_INFORMATION) != 0)
|
|
{
|
|
AccFree(*ppOwner);
|
|
}
|
|
|
|
if((SeInfo & GROUP_SECURITY_INFORMATION) != 0)
|
|
{
|
|
AccFree(*ppGroup);
|
|
}
|
|
}
|
|
|
|
delete pAccList;
|
|
}
|
|
|
|
//
|
|
// The destruction of the CAclList class will clean up all of the
|
|
// memory we obtained
|
|
//
|
|
acDebugOut((DEB_TRACE_API,"out AccProvHandleGetAllRights: %lu\n", dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
AccProvpDoTrusteeAccessCalculations(IN CAccessList *pAccList,
|
|
IN PTRUSTEE pTrustee,
|
|
IN OUT PTRUSTEE_ACCESS pTrusteeAccess)
|
|
{
|
|
DWORD dwErr;
|
|
|
|
ULONG DeniedMask;
|
|
ULONG AllowedMask;
|
|
dwErr = pAccList->GetExplicitAccess(pTrustee,
|
|
(PWSTR)pTrusteeAccess->lpProperty,
|
|
&DeniedMask,
|
|
&AllowedMask);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Process the entries
|
|
//
|
|
|
|
//
|
|
// It depends on what it is we're looking for...
|
|
//
|
|
pTrusteeAccess->fReturnedAccess = 0;
|
|
if(pTrusteeAccess->fAccessFlags == TRUSTEE_ACCESS_EXPLICIT)
|
|
{
|
|
//
|
|
// Ok, we'll look for these explicit rights
|
|
//
|
|
|
|
//
|
|
// First, see if any of our denieds match...
|
|
//
|
|
if (pTrusteeAccess->Access == TRUSTEE_ACCESS_ALL)
|
|
{
|
|
pTrusteeAccess->fReturnedAccess = AllowedMask & ~DeniedMask;
|
|
}
|
|
else
|
|
{
|
|
if((pTrusteeAccess->Access & DeniedMask) == 0)
|
|
{
|
|
//
|
|
// Now, see if we're allowed
|
|
//
|
|
if((pTrusteeAccess->Access & AllowedMask) ==
|
|
pTrusteeAccess->Access)
|
|
{
|
|
pTrusteeAccess->fReturnedAccess =
|
|
TRUSTEE_ACCESS_ALLOWED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(FLAG_ON(pTrusteeAccess->fAccessFlags, TRUSTEE_ACCESS_READ) ||
|
|
FLAG_ON(pTrusteeAccess->fAccessFlags, TRUSTEE_ACCESS_WRITE))
|
|
{
|
|
//
|
|
// We're only looking for read/write access
|
|
//
|
|
ACCESS_RIGHTS Access[2];
|
|
ULONG fValue[2], i = 0;
|
|
|
|
if(FLAG_ON(pTrusteeAccess->fAccessFlags, TRUSTEE_ACCESS_READ))
|
|
{
|
|
Access[i] = ACTRL_READ_CONTROL;
|
|
fValue[i] = TRUSTEE_ACCESS_READ;
|
|
i++;
|
|
}
|
|
|
|
if(FLAG_ON(pTrusteeAccess->fAccessFlags, TRUSTEE_ACCESS_WRITE))
|
|
{
|
|
Access[i] = ACTRL_CHANGE_ACCESS | ACTRL_CHANGE_OWNER;
|
|
fValue[i] = TRUSTEE_ACCESS_WRITE;
|
|
i++;
|
|
}
|
|
|
|
for(ULONG iIndex = 0; iIndex < i; iIndex++)
|
|
{
|
|
if((Access[iIndex] & DeniedMask) == 0)
|
|
{
|
|
//
|
|
// Now, see if we're allowed
|
|
//
|
|
if((Access[iIndex] & AllowedMask) == Access[iIndex])
|
|
{
|
|
pTrusteeAccess->fReturnedAccess |= fValue[iIndex];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// If we asked for read/write access, make sure we have them both
|
|
//
|
|
if(dwErr == ERROR_SUCCESS && pTrusteeAccess->fAccessFlags == TRUSTEE_ACCESS_READ_WRITE)
|
|
{
|
|
if( pTrusteeAccess->fReturnedAccess != TRUSTEE_ACCESS_READ_WRITE )
|
|
{
|
|
pTrusteeAccess->fReturnedAccess = 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvGetTrusteesAccess
|
|
//
|
|
// Synopsis: Determines whether the given trustee has the specified
|
|
// rights to the object
|
|
//
|
|
// Arguments: [IN pwszObjectPath] -- Path to the object in question
|
|
// [IN ObjectType] -- Type of the object
|
|
// [IN OUT pTrusteeAccess] -- Type of access to check for
|
|
// and where the access is returned
|
|
//
|
|
// Returns: ERROR_SUCCESS -- The operation succeeded
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvGetTrusteesAccess(IN LPCWSTR pwszObjectPath,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN PTRUSTEE pTrustee,
|
|
IN OUT PTRUSTEE_ACCESS pTrusteeAccess)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Ok, first, we'll load all the objects entries that we need
|
|
//
|
|
CAccessList *pAccList;
|
|
ACTRL_RIGHTS_INFO RI;
|
|
RI.pwszProperty = (PWSTR)pTrusteeAccess->lpProperty;
|
|
RI.SeInfo = DACL_SECURITY_INFORMATION;
|
|
|
|
PWSTR pwszTmpObjectPath = (PWSTR)AccAlloc( (wcslen(pwszObjectPath) + 1) * sizeof( WCHAR ) );
|
|
|
|
if (pwszTmpObjectPath)
|
|
{
|
|
wcscpy( pwszTmpObjectPath, pwszObjectPath );
|
|
pwszTmpObjectPath[wcslen(pwszObjectPath)] = UNICODE_NULL;
|
|
|
|
dwErr = NtProvGetAccessListForObject(pwszTmpObjectPath,
|
|
ObjectType,
|
|
&RI,
|
|
1,
|
|
&pAccList);
|
|
AccFree( pwszTmpObjectPath );
|
|
}
|
|
else
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = AccProvpDoTrusteeAccessCalculations(pAccList,
|
|
pTrustee,
|
|
pTrusteeAccess);
|
|
delete pAccList;
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvHandleGetTrusteesAccess
|
|
//
|
|
// Synopsis: Determines whether the given trustee has the specified
|
|
// rights to the object
|
|
//
|
|
// Arguments: [IN hObject] -- Handle to the open object
|
|
// [IN ObjectType] -- Type of the object
|
|
// [IN OUT pTrusteeAccess] -- Type of access to check for
|
|
// and where the access is returned
|
|
//
|
|
// Returns: ERROR_SUCCESS -- The operation succeeded
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvHandleGetTrusteesAccess(IN HANDLE hObject,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN PTRUSTEE pTrustee,
|
|
IN OUT PTRUSTEE_ACCESS pTrusteeAccess)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Ok, first, we'll load all the objects entries that we need
|
|
//
|
|
CAccessList *pAccList;
|
|
ACTRL_RIGHTS_INFO RI;
|
|
RI.pwszProperty = (PWSTR)pTrusteeAccess->lpProperty;
|
|
RI.SeInfo = DACL_SECURITY_INFORMATION;
|
|
|
|
dwErr = NtProvGetAccessListForHandle(hObject,
|
|
ObjectType,
|
|
&RI,
|
|
1,
|
|
&pAccList);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = AccProvpDoTrusteeAccessCalculations(pAccList,
|
|
pTrustee,
|
|
pTrusteeAccess);
|
|
|
|
delete pAccList;
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
AccProvpDoAccessAuditedCalculations(IN CAccessList *pAccList,
|
|
IN LPCWSTR pwszProperty,
|
|
IN PTRUSTEE pTrustee,
|
|
IN ACCESS_RIGHTS ulAuditRights,
|
|
OUT PBOOL pfAuditedSuccess,
|
|
OUT PBOOL pfAuditedFailure)
|
|
{
|
|
ULONG SuccessMask;
|
|
ULONG FailureMask;
|
|
DWORD dwErr = pAccList->GetExplicitAudits(pTrustee,
|
|
(PWSTR)pwszProperty,
|
|
&SuccessMask,
|
|
&FailureMask);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
|
|
//
|
|
// Process the entries
|
|
//
|
|
*pfAuditedSuccess = FALSE;
|
|
*pfAuditedFailure = FALSE;
|
|
if((ulAuditRights & SuccessMask) == ulAuditRights)
|
|
{
|
|
*pfAuditedSuccess = TRUE;
|
|
}
|
|
|
|
if((ulAuditRights & FailureMask) == ulAuditRights)
|
|
{
|
|
*pfAuditedFailure = TRUE;
|
|
}
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvIsAccessAudited
|
|
//
|
|
// Synopsis: Determines whether the given trustee will envoke an audit
|
|
// entry by accessing the object
|
|
//
|
|
// Arguments: [IN pwszObjectPath] -- Path to the object in question
|
|
// [IN ObjectType] -- Type of the object
|
|
// [IN pwszProperty] -- Optional. The name of the
|
|
// property on the object to revoke
|
|
// for
|
|
// [IN pTrustee] -- Trustee for which to check access
|
|
// [IN AuditRights] -- Type of audit we care about
|
|
// [OUT pfAccessAllowed] -- Where the results are returned.
|
|
//
|
|
// Returns: ERROR_SUCCESS -- The operation succeeded
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvIsAccessAudited(IN LPCWSTR pwszObjectPath,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN LPCWSTR pwszProperty,
|
|
IN PTRUSTEE pTrustee,
|
|
IN ACCESS_RIGHTS AuditRights,
|
|
OUT PBOOL pfAuditedSuccess,
|
|
OUT PBOOL pfAuditedFailure)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Ok, first, we'll load all the objects entries that we need
|
|
//
|
|
CAccessList *pAccList;
|
|
|
|
ACTRL_RIGHTS_INFO RI;
|
|
RI.pwszProperty = (PWSTR)pwszProperty;
|
|
RI.SeInfo = SACL_SECURITY_INFORMATION;
|
|
|
|
PWSTR pwszTmpObjectPath = (PWSTR)AccAlloc( (wcslen(pwszObjectPath) + 1) * sizeof( WCHAR ) );
|
|
|
|
if (pwszTmpObjectPath)
|
|
{
|
|
wcscpy( pwszTmpObjectPath, pwszObjectPath );
|
|
pwszTmpObjectPath[wcslen(pwszObjectPath)] = UNICODE_NULL;
|
|
|
|
dwErr = NtProvGetAccessListForObject(pwszTmpObjectPath,
|
|
ObjectType,
|
|
&RI,
|
|
1,
|
|
&pAccList);
|
|
AccFree( pwszTmpObjectPath );
|
|
}
|
|
else
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = AccProvpDoAccessAuditedCalculations(pAccList,
|
|
pwszProperty,
|
|
pTrustee,
|
|
AuditRights,
|
|
pfAuditedSuccess,
|
|
pfAuditedFailure);
|
|
delete pAccList;
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvHandleIsAccessAudited
|
|
//
|
|
// Synopsis: Determines whether the given trustee will envoke an audit
|
|
// entry by accessing the object
|
|
//
|
|
// Arguments: [IN hObject] -- Handle to the open object
|
|
// [IN ObjectType] -- Type of the object
|
|
// [IN pwszProperty] -- Optional. The name of the
|
|
// property on the object to revoke
|
|
// for
|
|
// [IN pTrustee] -- Trustee for which to check access
|
|
// [IN ulAuditRights] -- Type of audit we care about
|
|
// [OUT pfAccessAllowed] -- Where the results are returned.
|
|
//
|
|
// Returns: ERROR_SUCCESS -- The operation succeeded
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvHandleIsAccessAudited(IN HANDLE hObject,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN LPCWSTR pwszProperty,
|
|
IN PTRUSTEE pTrustee,
|
|
IN ACCESS_RIGHTS AuditRights,
|
|
OUT PBOOL pfAuditedSuccess,
|
|
OUT PBOOL pfAuditedFailure)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Ok, first, we'll load all the objects entries that we need
|
|
//
|
|
CAccessList *pAccList;
|
|
|
|
ACTRL_RIGHTS_INFO RI;
|
|
RI.pwszProperty = (PWSTR)pwszProperty;
|
|
RI.SeInfo = SACL_SECURITY_INFORMATION;
|
|
dwErr = NtProvGetAccessListForHandle(hObject,
|
|
ObjectType,
|
|
&RI,
|
|
1,
|
|
&pAccList);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = AccProvpDoAccessAuditedCalculations(pAccList,
|
|
pwszProperty,
|
|
pTrustee,
|
|
AuditRights,
|
|
pfAuditedSuccess,
|
|
pfAuditedFailure);
|
|
delete pAccList;
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvpGetAccessInfoPerObjectType
|
|
//
|
|
// Synopsis: Returns the list of available access permissions for the
|
|
// specified object type
|
|
//
|
|
// Arguments: [IN ObjectType] -- Type of the object
|
|
// [IN DsObjType] -- If this is a DS object, the type
|
|
// of the object
|
|
// [IN pwszDsPath] -- Full path to the object
|
|
//
|
|
// [IN lpProperty] -- Optional. If present, the name of
|
|
// the property to get the access
|
|
// rights for.
|
|
// [IN fIsDir] -- If TRUE, the path is a directory
|
|
// [OUT pcEntries] -- Where the count of items is returned
|
|
// [OUT ppAccessInfo] -- Where the list of items is returned
|
|
// [OUT pcControlRights] -- Count of control rights are
|
|
// is returned here
|
|
// [OUT ppControlRights] -- Where the list of control rights
|
|
// is returned
|
|
// [OUT pfAccessFlags] -- Where the provider flags are
|
|
// returned.
|
|
//
|
|
// Returns: ERROR_SUCCESS -- The operation succeeded
|
|
// ERROR_INVALID_PARAMETER -- The operation failed
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvpGetAccessInfoPerObjectType(IN SE_OBJECT_TYPE ObjectType,
|
|
IN BOOL fIsDir,
|
|
IN PWSTR pwszDsPath,
|
|
IN PWSTR lpProperty,
|
|
OUT PULONG pcEntries,
|
|
OUT PACTRL_ACCESS_INFO *ppAccessInfoList,
|
|
OUT PULONG pcControlRights,
|
|
OUT PACTRL_CONTROL_INFOW *ppControlRights,
|
|
OUT PULONG pfAccessFlags)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
BOOL ControlRightsValid = FALSE;
|
|
ULONG cStart = 0;
|
|
ULONG cItems = 0;
|
|
|
|
#define LENGTH_OF_STR_GUID 37
|
|
#define LENGTH_OF_LONGEST_STRING 20
|
|
|
|
//
|
|
// DS control rights
|
|
//
|
|
*pfAccessFlags = ACTRL_ACCESS_NO_OPTIONS;
|
|
|
|
*ppControlRights = NULL;
|
|
*pcControlRights = 0;
|
|
|
|
*ppAccessInfoList = 0;
|
|
*pcEntries = 0;
|
|
|
|
//
|
|
// Do the right thing based on the object type
|
|
//
|
|
switch (ObjectType)
|
|
{
|
|
case SE_LMSHARE: // FALL THROUGH
|
|
case SE_FILE_OBJECT:
|
|
if(fIsDir == TRUE)
|
|
{
|
|
cStart = ACCPROV_DIR_ACCESS;
|
|
cItems = ACCPROV_NUM_DIR;
|
|
}
|
|
else
|
|
{
|
|
cStart = ACCPROV_FILE_ACCESS;
|
|
cItems = ACCPROV_NUM_FILE;
|
|
}
|
|
break;
|
|
|
|
case SE_SERVICE:
|
|
cStart = ACCPROV_SERVICE_ACCESS;
|
|
cItems = ACCPROV_NUM_SERVICE;
|
|
break;
|
|
|
|
case SE_PRINTER:
|
|
cStart = ACCPROV_PRINT_ACCESS;
|
|
cItems = ACCPROV_NUM_PRINT;
|
|
break;
|
|
|
|
case SE_REGISTRY_KEY:
|
|
cStart = ACCPROV_REGISTRY_ACCESS;
|
|
cItems = ACCPROV_NUM_REGISTRY;
|
|
break;
|
|
|
|
case SE_KERNEL_OBJECT: // FALL THROUGH
|
|
case SE_WMIGUID_OBJECT:
|
|
cStart = ACCPROV_KERNEL_ACCESS;
|
|
cItems = ACCPROV_NUM_KERNEL;
|
|
break;
|
|
|
|
case SE_DS_OBJECT: // FALL THROUGH
|
|
case SE_DS_OBJECT_ALL:
|
|
cStart = ACCPROV_DS_ACCESS;
|
|
cItems = ACCPROV_NUM_DS;
|
|
ControlRightsValid = TRUE;
|
|
break;
|
|
|
|
case SE_WINDOW_OBJECT:
|
|
cStart = ACCPROV_WIN_ACCESS;
|
|
cItems = ACCPROV_NUM_WIN;
|
|
break;
|
|
|
|
default:
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS && ControlRightsValid == FALSE && lpProperty != NULL)
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Ok, we go through and size all of the strings that we need to add
|
|
//
|
|
ULONG cSize = 0;
|
|
WCHAR wszBuff[ACCPROV_LONGEST_STRING + 1];
|
|
for(ULONG iIndex = 0; iIndex < cItems; iIndex++)
|
|
{
|
|
LoadString(ghDll, cStart + iIndex, wszBuff, ACCPROV_LONGEST_STRING);
|
|
|
|
cSize += SIZE_PWSTR(wszBuff);
|
|
}
|
|
|
|
|
|
//
|
|
// Always return the standard rights, as well...
|
|
//
|
|
for(iIndex = 0; iIndex < ACCPROV_NUM_STD; iIndex++)
|
|
{
|
|
LoadString(ghDll,
|
|
ACCPROV_STD_ACCESS + iIndex,
|
|
wszBuff,
|
|
ACCPROV_LONGEST_STRING);
|
|
cSize += SIZE_PWSTR(wszBuff);
|
|
}
|
|
|
|
//
|
|
// Make sure to return the proper count
|
|
//
|
|
*pcEntries = cItems + ACCPROV_NUM_STD;
|
|
|
|
//
|
|
// Ok, now we can allocate, and do the same thing again
|
|
//
|
|
*ppAccessInfoList = (PACTRL_ACCESS_INFO)AccAlloc(
|
|
(cItems + ACCPROV_NUM_STD) * sizeof(ACTRL_ACCESS_INFO) +
|
|
cSize);
|
|
if(*ppAccessInfoList == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
if(*ppAccessInfoList == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
PWSTR pwszStart = (PWSTR)((PBYTE)(*ppAccessInfoList) +
|
|
(cItems + ACCPROV_NUM_STD) * sizeof(ACTRL_ACCESS_INFO));
|
|
//
|
|
// Start with the standard items
|
|
//
|
|
ULONG iLst = 0;
|
|
for(iIndex = 0; iIndex < ACCPROV_NUM_STD; iIndex++)
|
|
{
|
|
LoadString(ghDll,
|
|
ACCPROV_STD_ACCESS + iIndex,
|
|
wszBuff,
|
|
ACCPROV_LONGEST_STRING);
|
|
cSize = SIZE_PWSTR(wszBuff);
|
|
|
|
memcpy(pwszStart,
|
|
wszBuff,
|
|
cSize);
|
|
|
|
//
|
|
// Handle STD_RIGTHS_ALL as a special case...
|
|
//
|
|
if(iIndex == ACCPROV_NUM_STD - 1)
|
|
{
|
|
(*ppAccessInfoList)[iLst].fAccessPermission = ACTRL_STD_RIGHTS_ALL;
|
|
}
|
|
else
|
|
{
|
|
(*ppAccessInfoList)[iLst].fAccessPermission =
|
|
ACTRL_SYSTEM_ACCESS << iIndex;
|
|
}
|
|
(*ppAccessInfoList)[iLst].lpAccessPermissionName = pwszStart;
|
|
pwszStart = (PWSTR)Add2Ptr(pwszStart,cSize);
|
|
iLst++;
|
|
}
|
|
|
|
|
|
for(ULONG iIndex = 0; iIndex < cItems; iIndex++)
|
|
{
|
|
LoadString(ghDll,
|
|
cStart + iIndex, wszBuff, ACCPROV_LONGEST_STRING);
|
|
|
|
cSize = SIZE_PWSTR(wszBuff);
|
|
|
|
memcpy(pwszStart,
|
|
wszBuff,
|
|
cSize);
|
|
(*ppAccessInfoList)[iLst].fAccessPermission =
|
|
ACTRL_PERM_1 << iIndex;
|
|
(*ppAccessInfoList)[iLst].lpAccessPermissionName = pwszStart;
|
|
pwszStart = (PWSTR)Add2Ptr(pwszStart,cSize);
|
|
iLst++;
|
|
}
|
|
|
|
//
|
|
// Now, add extra control rights
|
|
//
|
|
|
|
if(ObjectType == SE_DS_OBJECT || ObjectType == SE_DS_OBJECT_ALL )
|
|
{
|
|
dwErr = AccctrlLookupRightsByName( NULL,
|
|
pwszDsPath,
|
|
lpProperty,
|
|
pcControlRights,
|
|
ppControlRights);
|
|
|
|
//
|
|
// If we can't find the entry we want, return 0 items...
|
|
//
|
|
if(dwErr == ERROR_NOT_FOUND)
|
|
{
|
|
*pcControlRights = 0;
|
|
*ppControlRights = NULL;
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
*pcEntries = cItems + ACCPROV_NUM_STD;
|
|
|
|
}
|
|
else
|
|
{
|
|
if(*ppAccessInfoList != NULL)
|
|
{
|
|
AccFree(*ppAccessInfoList);
|
|
*pcEntries = 0;
|
|
}
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvGetAccessInfoPerObjectType
|
|
//
|
|
// Synopsis: Returns the list of available access permissions for the
|
|
// specified object type
|
|
//
|
|
// Arguments: [IN lpObject] -- Full path to the object
|
|
// [IN ObjectType] -- Type of the object
|
|
// [IN lpProperty] -- Optional. If present, the name of
|
|
// the property to get the access
|
|
// rights for.
|
|
// [OUT pcEntries] -- Where the count of items is returned
|
|
// [OUT ppAccessInfo] -- Where the list of items is returned
|
|
// [OUT pfAccessFlags] -- Where the provider flags are
|
|
// returned.
|
|
//
|
|
// Returns: ERROR_SUCCESS -- The operation succeeded
|
|
// ERROR_INVALID_PARAMETER -- The operation failed
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvGetAccessInfoPerObjectType(IN LPCWSTR lpObject,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN LPCWSTR lpProperty,
|
|
OUT PULONG pcEntries,
|
|
OUT PACTRL_ACCESS_INFO *ppAccessInfoList,
|
|
OUT PULONG pcControlRights,
|
|
OUT PACTRL_CONTROL_INFOW *ppControlRights,
|
|
OUT PULONG pfAccessFlags)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
BOOL fIsDir = FALSE;
|
|
|
|
if(ObjectType == SE_LMSHARE || ObjectType == SE_FILE_OBJECT)
|
|
{
|
|
//
|
|
// Check to see whether this is a file or a directory...
|
|
//
|
|
ULONG ulAttribs = GetFileAttributes((PWSTR)lpObject);
|
|
if(FLAG_ON(ulAttribs, FILE_ATTRIBUTE_DIRECTORY))
|
|
{
|
|
fIsDir = TRUE;
|
|
}
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = AccProvpGetAccessInfoPerObjectType(ObjectType,
|
|
fIsDir,
|
|
(LPWSTR)lpObject,
|
|
(LPWSTR)lpProperty,
|
|
pcEntries,
|
|
ppAccessInfoList,
|
|
pcControlRights,
|
|
ppControlRights,
|
|
pfAccessFlags);
|
|
}
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccProvHandleGetAccessInfoPerObjectType
|
|
//
|
|
// Synopsis: Returns the list of available access permissions for the
|
|
// specified object type
|
|
//
|
|
// Arguments: [IN hObject] -- Handle to the open object
|
|
// [IN ObjectType] -- Type of the object
|
|
// [IN lpProperty] -- Optional. If present, the name of
|
|
// the property to get the access
|
|
// rights for.
|
|
// [OUT pcEntries] -- Where the count of items is returned
|
|
// [OUT ppAccessInfo] -- Where the list of items is returned
|
|
// [OUT pfAccessFlags] -- Where the provider flags are
|
|
// returned.
|
|
//
|
|
// Returns: ERROR_SUCCESS -- The operation succeeded
|
|
// ERROR_INVALID_PARAMETER -- The operation failed
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AccProvHandleGetAccessInfoPerObjectType(IN HANDLE hObject,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN LPCWSTR lpProperty,
|
|
OUT PULONG pcEntries,
|
|
OUT PACTRL_ACCESS_INFO *ppAccessInfoList,
|
|
OUT PULONG pcControlRights,
|
|
OUT PACTRL_CONTROL_INFOW *ppControlRights,
|
|
OUT PULONG pfAccessFlags)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
BOOL fIsDir = FALSE;
|
|
|
|
if(ObjectType == SE_LMSHARE || ObjectType == SE_FILE_OBJECT)
|
|
{
|
|
BY_HANDLE_FILE_INFORMATION BHFI;
|
|
//
|
|
// Check to see whether this is a file or a directory...
|
|
//
|
|
if(GetFileInformationByHandle(hObject,
|
|
&BHFI) == FALSE)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
if(FLAG_ON(BHFI.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))
|
|
fIsDir = TRUE;
|
|
}
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = AccProvpGetAccessInfoPerObjectType(ObjectType,
|
|
fIsDir,
|
|
NULL,
|
|
(LPWSTR)lpProperty,
|
|
pcEntries,
|
|
ppAccessInfoList,
|
|
pcControlRights,
|
|
ppControlRights,
|
|
pfAccessFlags);
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|