mirror of https://github.com/tongzx/nt5src
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.
3700 lines
113 KiB
3700 lines
113 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
tree.cpp
|
|
|
|
Abstract:
|
|
|
|
SCE Engine security inheritance and propagation APIs
|
|
|
|
Author:
|
|
|
|
Jin Huang (jinhuang) 23-Jun-1997 created
|
|
|
|
--*/
|
|
#include "serverp.h"
|
|
#include "srvutil.h"
|
|
#include <io.h>
|
|
|
|
BOOL gbQueriedIfSystemContext = FALSE;
|
|
BOOL gbIsSystemContext = FALSE;
|
|
|
|
#ifdef SCE_DBG
|
|
DWORD gDbgNumPushed = 0;
|
|
DWORD gDbgNumPopped = 0;
|
|
#endif
|
|
|
|
#if _WIN32_WINNT==0x0400
|
|
#include "dsrights.h"
|
|
#endif
|
|
|
|
#pragma hdrstop
|
|
#define SCETREE_QUERY_SD 1
|
|
|
|
#define SE_VALID_CONTROL_BITS ( SE_DACL_UNTRUSTED | \
|
|
SE_SERVER_SECURITY | \
|
|
SE_DACL_AUTO_INHERIT_REQ | \
|
|
SE_SACL_AUTO_INHERIT_REQ | \
|
|
SE_DACL_AUTO_INHERITED | \
|
|
SE_SACL_AUTO_INHERITED | \
|
|
SE_DACL_PROTECTED | \
|
|
SE_SACL_PROTECTED )
|
|
|
|
|
|
#define SCEP_IGNORE_SOME_ERRORS(ErrorCode) ErrorCode == ERROR_FILE_NOT_FOUND ||\
|
|
ErrorCode == ERROR_PATH_NOT_FOUND ||\
|
|
ErrorCode == ERROR_ACCESS_DENIED ||\
|
|
ErrorCode == ERROR_SHARING_VIOLATION ||\
|
|
ErrorCode == ERROR_INVALID_OWNER ||\
|
|
ErrorCode == ERROR_INVALID_PRIMARY_GROUP ||\
|
|
ErrorCode == ERROR_INVALID_HANDLE ||\
|
|
ErrorCode == ERROR_INVALID_SECURITY_DESCR ||\
|
|
ErrorCode == ERROR_CANT_ACCESS_FILE
|
|
|
|
|
|
DWORD
|
|
AccRewriteSetNamedRights(
|
|
IN LPWSTR pObjectName,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN SECURITY_INFORMATION SecurityInfo,
|
|
IN OUT PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|
IN BOOL bSkipInheritanceComputation
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepCreateObjectNode(
|
|
IN PWSTR Buffer,
|
|
IN WCHAR Delim,
|
|
IN PSCE_OBJECT_TREE *ParentNode,
|
|
OUT PSCE_OBJECT_CHILD_LIST *NewNode
|
|
);
|
|
|
|
DWORD
|
|
ScepDoesObjectHasChildren(
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN PWSTR ObjectName,
|
|
OUT PBOOL pbHasChildren
|
|
);
|
|
|
|
DWORD
|
|
ScepAddAutoInheritRequest(
|
|
IN OUT PSECURITY_DESCRIPTOR pSD,
|
|
IN OUT SECURITY_INFORMATION *pSeInfo
|
|
);
|
|
|
|
DWORD
|
|
ScepSetSecurityOverwriteExplicit(
|
|
IN PCWSTR ObjectName,
|
|
IN SECURITY_INFORMATION SeInfo,
|
|
IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN HANDLE Token,
|
|
IN PGENERIC_MAPPING GenericMapping
|
|
);
|
|
|
|
DWORD
|
|
ScepConfigureOneSubTreeFile(
|
|
IN PSCE_OBJECT_TREE ThisNode,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN HANDLE Token,
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
IN BOOL BackSlashExist
|
|
);
|
|
|
|
DWORD
|
|
ScepConfigureOneSubTreeKey(
|
|
IN PSCE_OBJECT_TREE ThisNode,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN HANDLE Token,
|
|
IN PGENERIC_MAPPING GenericMapping
|
|
);
|
|
|
|
typedef struct _SCEP_STACK_NODE_ {
|
|
PWSTR Buffer;
|
|
PSECURITY_DESCRIPTOR pObjectSecurity;
|
|
struct _SCEP_STACK_NODE_ *Next;
|
|
} SCEP_STACK_NODE, *PSCEP_STACK_NODE;
|
|
|
|
DWORD
|
|
ScepStackNodePush(
|
|
IN PSCEP_STACK_NODE *ppStackHead,
|
|
IN PWSTR pszObjectName,
|
|
IN PSECURITY_DESCRIPTOR pSecurityDescriptor
|
|
);
|
|
|
|
VOID
|
|
ScepStackNodePop(
|
|
IN OUT PSCEP_STACK_NODE *ppStackHead,
|
|
IN OUT PWSTR *ppszObjectName,
|
|
IN OUT PSECURITY_DESCRIPTOR *ppSecurityDescriptor
|
|
);
|
|
|
|
VOID
|
|
ScepFreeStack(
|
|
IN PSCEP_STACK_NODE *ppStackHead
|
|
);
|
|
|
|
VOID
|
|
ScepDumpStack(
|
|
IN PSCEP_STACK_NODE *ppStackHead
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepBuildObjectTree(
|
|
IN OUT PSCE_OBJECT_TREE *ParentNode,
|
|
IN OUT PSCE_OBJECT_CHILD_LIST *ChildHead,
|
|
IN ULONG Level,
|
|
IN WCHAR Delim,
|
|
IN PCWSTR ObjectFullName,
|
|
IN BOOL IsContainer,
|
|
IN BYTE Status,
|
|
IN PSECURITY_DESCRIPTOR pInfSecurityDescriptor,
|
|
IN SECURITY_INFORMATION InfSeInfo
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine adds the ObjectFullName to the tree. When this routine is
|
|
first called from outside, the root of the tree is passed in as *SiblingHead,
|
|
and the ParentNode is NULL. Then the routine parses the ObjectFullName for
|
|
each level and adds the node if it does not exist. For example:
|
|
|
|
root
|
|
|
|
level 1 c: ---------> d:--->...
|
|
/ /
|
|
level 2 winnt->NTLDR->... "Program Files"->...
|
|
/
|
|
level 3 system32->system->...
|
|
|
|
Arguments:
|
|
|
|
ParentNode - The parent node pointer
|
|
|
|
SiblingHead - The sibling head pointer for this level
|
|
|
|
Level - The level (1,2,3...)
|
|
|
|
Delim - The deliminator to separate each level in the full name component
|
|
Currently '\' is used for file and registry objects, and '/' is used
|
|
for acitve directory objects.
|
|
|
|
ObjectFullName - Full path name of the object (file, registry)
|
|
|
|
Status - The configuration status
|
|
SCE_STATUS_CHECK (with AUTO_INHERIT)
|
|
SCE_STATUS_NO_AUTO_INHERIT
|
|
SCE_STATUS_IGNORE
|
|
SCE_STATUS_OVERWRITE
|
|
|
|
pInfSecurityDescriptor - The security descriptor set in the INF file
|
|
|
|
InfSeInfo - The security information set in the INF file
|
|
|
|
Return value:
|
|
|
|
SCESTATUS_SUCCESS
|
|
SCESTATUS_INVALID_PARAMETER
|
|
SCESTATUS_NOT_ENOUGH_RESOURCE
|
|
|
|
|
|
-- */
|
|
{
|
|
SCESTATUS rc;
|
|
TCHAR *Buffer = NULL;
|
|
PSCE_OBJECT_CHILD_LIST NewNode=NULL;
|
|
PSCE_OBJECT_CHILD_LIST PrevSib=NULL;
|
|
PSCE_OBJECT_TREE ThisNode=NULL;
|
|
INT Result;
|
|
BOOL LastOne=FALSE;
|
|
DWORD dwObjectFullNameLen = 0;
|
|
|
|
//
|
|
// address for ParentNode can be empty( the root )
|
|
// but address for the first node of the level cannot be empty.
|
|
//
|
|
if ( ChildHead == NULL ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// find the object name for the level (from ObjectFullName)
|
|
// e.g., if ObjectFullName is c:\winnt\system32 then
|
|
// level 1 name is c:, level 2 name is winnt, level 3 name is system32
|
|
//
|
|
dwObjectFullNameLen = wcslen(ObjectFullName);
|
|
Buffer = (TCHAR *)LocalAlloc(LMEM_ZEROINIT,
|
|
sizeof(TCHAR) * (dwObjectFullNameLen + 1));
|
|
|
|
if (NULL == Buffer) {
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
goto Done;
|
|
}
|
|
|
|
memset(Buffer, '\0', dwObjectFullNameLen * sizeof(TCHAR));
|
|
|
|
rc = ScepGetNameInLevel(ObjectFullName,
|
|
Level,
|
|
Delim,
|
|
Buffer,
|
|
&LastOne);
|
|
|
|
if ( rc != SCESTATUS_SUCCESS )
|
|
goto Done;
|
|
|
|
if ( *ChildHead == NULL ) {
|
|
//
|
|
// This is the first node in this level
|
|
// Create the node and assign it to the ChildHead
|
|
//
|
|
rc = ScepCreateObjectNode(
|
|
Buffer,
|
|
Delim,
|
|
ParentNode,
|
|
&NewNode
|
|
);
|
|
|
|
if ( rc != SCESTATUS_SUCCESS)
|
|
goto Done;
|
|
|
|
*ChildHead = NewNode;
|
|
|
|
//
|
|
// Establish the link if there is a parent
|
|
//
|
|
if ( ParentNode != NULL )
|
|
if ( *ParentNode != NULL )
|
|
(*ParentNode)->ChildList = NewNode;
|
|
|
|
ThisNode = NewNode->Node;
|
|
|
|
} else {
|
|
//
|
|
// There are existing nodes. Search all siblings
|
|
// All siblings are stored in alphabetic order.
|
|
//
|
|
PSCE_OBJECT_CHILD_LIST pTemp;
|
|
|
|
for ( pTemp = *ChildHead, PrevSib = NULL;
|
|
pTemp != NULL;
|
|
pTemp = pTemp->Next) {
|
|
//
|
|
// Compare the node's object name with the current object name
|
|
//
|
|
Result = _wcsicmp(pTemp->Node->Name, Buffer);
|
|
//
|
|
// if the node's object name is equal to (find it) or greater
|
|
// than (insert the node) the current object name, then stop
|
|
//
|
|
if ( Result >= 0 ) {
|
|
break;
|
|
}
|
|
PrevSib = pTemp;
|
|
}
|
|
|
|
if ( pTemp == NULL ) {
|
|
//
|
|
// Not exist. Append the new node
|
|
//
|
|
rc = ScepCreateObjectNode(
|
|
Buffer,
|
|
Delim,
|
|
ParentNode,
|
|
&NewNode
|
|
);
|
|
|
|
if ( rc != SCESTATUS_SUCCESS)
|
|
goto Done;
|
|
|
|
if ( PrevSib != NULL )
|
|
PrevSib->Next = NewNode;
|
|
else {
|
|
//
|
|
// this is the first one in the level
|
|
//
|
|
(*ChildHead)->Next = NewNode;
|
|
}
|
|
ThisNode = NewNode->Node;
|
|
|
|
} else {
|
|
//
|
|
// either find it (i=0) or need to insert between PrevSib and ThisNode
|
|
//
|
|
if ( Result > 0 ) {
|
|
//
|
|
// insert the node
|
|
//
|
|
rc = ScepCreateObjectNode(
|
|
Buffer,
|
|
Delim,
|
|
ParentNode,
|
|
&NewNode
|
|
);
|
|
|
|
if ( rc != SCESTATUS_SUCCESS)
|
|
goto Done;
|
|
|
|
NewNode->Next = pTemp;
|
|
if ( PrevSib != NULL )
|
|
PrevSib->Next = NewNode;
|
|
else {
|
|
//
|
|
// insert before SiblingHead
|
|
//
|
|
*ChildHead = NewNode;
|
|
if ( ParentNode != NULL )
|
|
if ( *ParentNode != NULL )
|
|
(*ParentNode)->ChildList = NewNode;
|
|
}
|
|
|
|
ThisNode = NewNode->Node;
|
|
|
|
} else {
|
|
ThisNode = pTemp->Node;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( LastOne ) {
|
|
//
|
|
// Assign Inf security information to this node
|
|
//
|
|
ThisNode->pSecurityDescriptor = pInfSecurityDescriptor;
|
|
ThisNode->SeInfo = InfSeInfo;
|
|
ThisNode->Status = Status;
|
|
ThisNode->IsContainer = IsContainer;
|
|
|
|
} else {
|
|
//
|
|
// process next level recursively
|
|
//
|
|
rc = ScepBuildObjectTree(&ThisNode,
|
|
&(ThisNode->ChildList),
|
|
Level+1,
|
|
Delim,
|
|
ObjectFullName,
|
|
IsContainer,
|
|
Status,
|
|
pInfSecurityDescriptor,
|
|
InfSeInfo);
|
|
}
|
|
|
|
Done:
|
|
|
|
if (Buffer) {
|
|
LocalFree(Buffer);
|
|
}
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepCreateObjectNode(
|
|
IN PWSTR Buffer,
|
|
IN WCHAR Delim,
|
|
IN PSCE_OBJECT_TREE *ParentNode,
|
|
OUT PSCE_OBJECT_CHILD_LIST *NewNode
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine allocates memory for a new node in the tree. The ParentNode
|
|
is used to determine the full object name and link the new node (if not NULL)
|
|
|
|
Arguments:
|
|
|
|
Buffer - The component name of a object
|
|
|
|
Delim - The deliminator to separate different levels in the full name.
|
|
|
|
ParentNode - Pointer of the parent node of this new node
|
|
|
|
NewNode - New created node
|
|
|
|
Return value:
|
|
|
|
SCESTATUS
|
|
|
|
-- */
|
|
{
|
|
DWORD Len;
|
|
|
|
if (NewNode == NULL )
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
|
|
//
|
|
// allocate buffer for the node
|
|
//
|
|
*NewNode = (PSCE_OBJECT_CHILD_LIST)ScepAlloc(LPTR, sizeof(SCE_OBJECT_CHILD_LIST));
|
|
if ( *NewNode == NULL )
|
|
return(SCESTATUS_NOT_ENOUGH_RESOURCE);
|
|
|
|
PSCE_OBJECT_TREE Node = (PSCE_OBJECT_TREE)ScepAlloc((UINT)0, sizeof(SCE_OBJECT_TREE));
|
|
|
|
if ( Node == NULL ) {
|
|
ScepFree(*NewNode);
|
|
*NewNode = NULL;
|
|
return(SCESTATUS_NOT_ENOUGH_RESOURCE);
|
|
}
|
|
|
|
//
|
|
// allocate buffer for the object name
|
|
//
|
|
Len = wcslen(Buffer);
|
|
|
|
Node->Name = (PWSTR)ScepAlloc((UINT)0,
|
|
(Len+1) * sizeof(TCHAR));
|
|
if ( Node->Name == NULL ) {
|
|
ScepFree(Node);
|
|
ScepFree(*NewNode);
|
|
*NewNode = NULL;
|
|
return(SCESTATUS_NOT_ENOUGH_RESOURCE);
|
|
}
|
|
|
|
if ( ParentNode != NULL &&
|
|
*ParentNode != NULL ) {
|
|
Len += wcslen((*ParentNode)->ObjectFullName)+1;
|
|
++((*ParentNode)->dwSize_aChildNames);
|
|
// Reserve a space for "\" for the root dir c:\ .
|
|
} else if ( Buffer[1] == L':' ) {
|
|
Len++;
|
|
}
|
|
|
|
Node->ObjectFullName = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (Len+1)*sizeof(TCHAR));
|
|
|
|
if ( Node->ObjectFullName == NULL ) {
|
|
ScepFree(Node->Name );
|
|
ScepFree(Node);
|
|
ScepFree( *NewNode );
|
|
*NewNode = NULL;
|
|
return(SCESTATUS_NOT_ENOUGH_RESOURCE);
|
|
}
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
wcscpy(Node->Name, Buffer);
|
|
Node->ChildList = NULL;
|
|
Node->pSecurityDescriptor = NULL;
|
|
Node->pApplySecurityDescriptor = NULL;
|
|
Node->SeInfo = 0;
|
|
Node->IsContainer = TRUE;
|
|
Node->aChildNames = NULL;
|
|
Node->dwSize_aChildNames = 0;
|
|
|
|
if ( ParentNode != NULL &&
|
|
*ParentNode != NULL ) {
|
|
//
|
|
// link to parent, use parent's status for this one
|
|
//
|
|
Node->Parent = *ParentNode;
|
|
swprintf(Node->ObjectFullName,
|
|
L"%s%c%s",
|
|
(*ParentNode)->ObjectFullName,
|
|
Delim,
|
|
Buffer);
|
|
Node->Status = (*ParentNode)->Status;
|
|
} else {
|
|
//
|
|
// this is the first node.
|
|
//
|
|
Node->Parent = NULL;
|
|
wcscpy(Node->ObjectFullName, Buffer);
|
|
Node->Status = SCE_STATUS_CHECK;
|
|
}
|
|
|
|
(*NewNode)->Node = Node;
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepCalculateSecurityToApply(
|
|
IN PSCE_OBJECT_TREE ThisNode,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN HANDLE Token,
|
|
IN PGENERIC_MAPPING GenericMapping
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine walks through the security tree to determine security
|
|
descriptor for each node. It calls RtlNewSecurityObject, passing a
|
|
parent node's SD and current node's SD specified in the INF file.
|
|
The output SD from that API is the security descriptor to set to the
|
|
current object.
|
|
|
|
Arguments:
|
|
|
|
ThisNode - The current object's node
|
|
|
|
ObjectType - The object's type
|
|
SE_FILE_OBJECT
|
|
SE_REGISTRY_KEY
|
|
|
|
Token - The thread/process token of the calling client
|
|
|
|
GenericMapping - Generic access map table
|
|
|
|
Return value:
|
|
|
|
SCESTATUS_SUCCESS
|
|
SCESTATUS_OTHER_ERROR (see log for detail error)
|
|
|
|
-- */
|
|
{
|
|
SCESTATUS rc=SCESTATUS_SUCCESS;
|
|
PSECURITY_DESCRIPTOR ParentSD=NULL;
|
|
SECURITY_INFORMATION SeInfoGet;
|
|
DWORD Win32rc;
|
|
intptr_t hFile;
|
|
struct _wfinddata_t *pFileInfo=NULL;
|
|
DWORD dwChildIndex = 0;
|
|
|
|
|
|
|
|
if ( ThisNode == NULL )
|
|
return(SCESTATUS_SUCCESS);
|
|
|
|
#ifdef SCE_DBG
|
|
wprintf(L"%s\n", ThisNode->ObjectFullName);
|
|
#endif
|
|
//
|
|
// if IGNORE is set, skip this node too
|
|
//
|
|
if ( ThisNode->Status != SCE_STATUS_CHECK &&
|
|
ThisNode->Status != SCE_STATUS_NO_AUTO_INHERIT &&
|
|
ThisNode->Status != SCE_STATUS_OVERWRITE )
|
|
goto Done;
|
|
|
|
if ( ThisNode->dwSize_aChildNames != 0) {
|
|
ThisNode->aChildNames = (PWSTR *) LocalAlloc( LMEM_ZEROINIT,
|
|
(sizeof(PWSTR) * ThisNode->dwSize_aChildNames));
|
|
|
|
if ( ThisNode->aChildNames == NULL ) {
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
goto Done;
|
|
}
|
|
}
|
|
|
|
|
|
if ( ThisNode->Parent == NULL ) {
|
|
|
|
//
|
|
// this is the first node
|
|
// should always use Rtl routine to compute security descriptor
|
|
// so Creator Owner ace is translated properly.
|
|
//
|
|
|
|
if ( ThisNode->pSecurityDescriptor ) {
|
|
Win32rc = ScepGetNewSecurity(
|
|
ThisNode->ObjectFullName,
|
|
NULL, // parent's SD
|
|
ThisNode->pSecurityDescriptor,
|
|
0, // does not query current object SD
|
|
(BOOLEAN)(ThisNode->IsContainer),
|
|
ThisNode->SeInfo,
|
|
ObjectType,
|
|
Token,
|
|
GenericMapping,
|
|
&(ThisNode->pApplySecurityDescriptor)
|
|
);
|
|
if ( Win32rc != NO_ERROR ) {
|
|
ScepLogOutput3(1, Win32rc, SCEDLL_ERROR_BUILD_SD,
|
|
ThisNode->ObjectFullName );
|
|
rc = ScepDosErrorToSceStatus(Win32rc);
|
|
goto Done;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// no explicit security specified for this node
|
|
//
|
|
ThisNode->pApplySecurityDescriptor = NULL;
|
|
}
|
|
|
|
goto ProcChild;
|
|
}
|
|
|
|
//
|
|
// process children nodes
|
|
//
|
|
if ( ThisNode->pSecurityDescriptor != NULL ||
|
|
ThisNode->Parent->pApplySecurityDescriptor != NULL ) {
|
|
|
|
if ( ObjectType == SE_FILE_OBJECT && NULL == ThisNode->ChildList ) {
|
|
//
|
|
// detect if this is a file (non-container object)
|
|
//
|
|
pFileInfo = (struct _wfinddata_t *)ScepAlloc(0,sizeof(struct _wfinddata_t));
|
|
if ( pFileInfo == NULL ) {
|
|
|
|
//
|
|
// out of memory, treat it as a container for now and
|
|
// will error out later.
|
|
//
|
|
|
|
ThisNode->IsContainer = TRUE;
|
|
|
|
} else {
|
|
|
|
hFile = _wfindfirst(ThisNode->ObjectFullName, pFileInfo);
|
|
ThisNode->IsContainer = FALSE;
|
|
if ( hFile != -1 ) {
|
|
_findclose(hFile);
|
|
if ( pFileInfo->attrib & _A_SUBDIR ) {
|
|
ThisNode->IsContainer = TRUE;
|
|
}
|
|
}
|
|
|
|
ScepFree(pFileInfo);
|
|
pFileInfo = NULL;
|
|
}
|
|
|
|
} else {
|
|
|
|
ThisNode->IsContainer = TRUE;
|
|
}
|
|
|
|
//
|
|
// even if the security descriptor is protected,
|
|
// still need to call ScepNewSecurity to get CREATOR OWNER ace
|
|
// translated correctly.
|
|
//
|
|
|
|
//
|
|
// if this is the first explicit node in this branch,
|
|
// the pApplySecurityDescriptor of the parent must be NULL.
|
|
//
|
|
|
|
if ( ThisNode->Parent->pApplySecurityDescriptor == NULL ) {
|
|
|
|
//
|
|
// yes, this is the first explicit node.
|
|
// get the current system's setting on the parent node
|
|
// have to use Win32 api because it will compute all inherited
|
|
// security information from all parents automatically
|
|
//
|
|
|
|
SeInfoGet = 0;
|
|
if ( ThisNode->SeInfo & DACL_SECURITY_INFORMATION )
|
|
SeInfoGet |= DACL_SECURITY_INFORMATION;
|
|
|
|
if ( ThisNode->SeInfo & SACL_SECURITY_INFORMATION )
|
|
SeInfoGet |= SACL_SECURITY_INFORMATION;
|
|
|
|
Win32rc = GetNamedSecurityInfo(
|
|
ThisNode->Parent->ObjectFullName,
|
|
ObjectType,
|
|
SeInfoGet,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&ParentSD
|
|
);
|
|
/*
|
|
Win32rc = ScepGetNamedSecurityInfo(
|
|
ThisNode->Parent->ObjectFullName,
|
|
ObjectType,
|
|
SeInfoGet,
|
|
&ParentSD
|
|
);
|
|
*/
|
|
if ( Win32rc != NO_ERROR &&
|
|
Win32rc != ERROR_FILE_NOT_FOUND &&
|
|
Win32rc != ERROR_PATH_NOT_FOUND &&
|
|
Win32rc != ERROR_ACCESS_DENIED &&
|
|
Win32rc != ERROR_CANT_ACCESS_FILE &&
|
|
Win32rc != ERROR_SHARING_VIOLATION ) {
|
|
|
|
ScepLogOutput3(1, Win32rc, SCEDLL_ERROR_QUERY_SECURITY,
|
|
ThisNode->Parent->ObjectFullName );
|
|
rc = ScepDosErrorToSceStatus(Win32rc);
|
|
goto Done;
|
|
}
|
|
|
|
} else {
|
|
ParentSD = ThisNode->Parent->pApplySecurityDescriptor;
|
|
//
|
|
// owner/group information are not inheritable
|
|
//
|
|
if ( ThisNode->Parent->SeInfo & DACL_SECURITY_INFORMATION )
|
|
ThisNode->SeInfo |= DACL_SECURITY_INFORMATION;
|
|
if ( ThisNode->Parent->SeInfo & SACL_SECURITY_INFORMATION )
|
|
ThisNode->SeInfo |= SACL_SECURITY_INFORMATION;
|
|
}
|
|
|
|
//
|
|
// compute the new security descriptor with inherited aces from the parentSD
|
|
// if the status is SCE_STATUS_CHECK (auto inherit), need to query the current
|
|
// object's security descriptor if no explicit SD is specified
|
|
// (ThisNode->pSecurityDescriptor is NULL)
|
|
//
|
|
|
|
Win32rc = ScepGetNewSecurity(
|
|
ThisNode->ObjectFullName,
|
|
ParentSD,
|
|
ThisNode->pSecurityDescriptor,
|
|
(BYTE)(( ThisNode->Status == SCE_STATUS_CHECK ) ? SCETREE_QUERY_SD : 0),
|
|
(BOOLEAN)(ThisNode->IsContainer),
|
|
ThisNode->SeInfo,
|
|
ObjectType,
|
|
Token,
|
|
GenericMapping,
|
|
&(ThisNode->pApplySecurityDescriptor)
|
|
);
|
|
|
|
if ( ParentSD &&
|
|
ParentSD != ThisNode->Parent->pApplySecurityDescriptor ) {
|
|
//
|
|
// free the parent security descriptor if it's allocated here
|
|
//
|
|
LocalFree(ParentSD);
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == Win32rc ||
|
|
ERROR_FILE_NOT_FOUND == Win32rc ||
|
|
ERROR_PATH_NOT_FOUND == Win32rc ||
|
|
ERROR_ACCESS_DENIED == Win32rc ||
|
|
ERROR_CANT_ACCESS_FILE == Win32rc ||
|
|
ERROR_SHARING_VIOLATION == Win32rc ) {
|
|
|
|
rc = SCESTATUS_SUCCESS;
|
|
} else {
|
|
ScepLogOutput3(1, Win32rc,
|
|
SCEDLL_ERROR_BUILD_SD,
|
|
ThisNode->ObjectFullName
|
|
);
|
|
rc = ScepDosErrorToSceStatus(Win32rc);
|
|
goto Done;
|
|
}
|
|
|
|
}
|
|
|
|
ProcChild:
|
|
//
|
|
// then process left child
|
|
//
|
|
|
|
for ( PSCE_OBJECT_CHILD_LIST pTemp = ThisNode->ChildList;
|
|
pTemp != NULL; pTemp = pTemp->Next ) {
|
|
|
|
if ( pTemp->Node == NULL ) continue;
|
|
|
|
ThisNode->aChildNames[dwChildIndex] = pTemp->Node->Name;
|
|
|
|
++dwChildIndex;
|
|
|
|
rc = ScepCalculateSecurityToApply(
|
|
pTemp->Node,
|
|
ObjectType,
|
|
Token,
|
|
GenericMapping
|
|
);
|
|
|
|
if ( rc != SCESTATUS_SUCCESS )
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// in case there are lesser child names than initially calcluated
|
|
//
|
|
|
|
if (dwChildIndex < ThisNode->dwSize_aChildNames) {
|
|
|
|
ThisNode->dwSize_aChildNames = dwChildIndex;
|
|
|
|
}
|
|
|
|
Done:
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepGetNewSecurity(
|
|
IN LPTSTR ObjectName,
|
|
IN PSECURITY_DESCRIPTOR pParentSD OPTIONAL,
|
|
IN PSECURITY_DESCRIPTOR pObjectSD OPTIONAL,
|
|
IN BYTE nFlag,
|
|
IN BOOLEAN bIsContainer,
|
|
IN SECURITY_INFORMATION SeInfo,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN HANDLE Token,
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
OUT PSECURITY_DESCRIPTOR *ppNewSD
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
This routine will compute a security descriptor based on parent's security
|
|
descriptor and the explicit security descriptor for the object. If no owner
|
|
information is specified in the object's security descriptor, this routine
|
|
will query the current owner of the object on the system so CREATOR_OWNER
|
|
ace can be translated into the proper ace based on the owner.
|
|
|
|
Arguments:
|
|
|
|
ObjectName - the object's full name
|
|
|
|
pParentSD - optional security descriptor of the parent
|
|
|
|
pObjectSD - optional explicit security descriptor of this object
|
|
|
|
SeInfo - security information contained in the object's SD
|
|
|
|
bIsContainer - if the object is a container
|
|
|
|
pNewSD - the new computed security descriptor address
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS of this operation
|
|
*/
|
|
{
|
|
|
|
BOOL bOwner;
|
|
BOOLEAN tFlag;
|
|
BOOLEAN aclPresent;
|
|
PSID pOwner=NULL;
|
|
PACL pDacl=NULL;
|
|
PACL pSacl=NULL;
|
|
SECURITY_DESCRIPTOR SD;
|
|
PSECURITY_DESCRIPTOR pCurrentSD=NULL;
|
|
DWORD Win32rc;
|
|
NTSTATUS NtStatus;
|
|
SECURITY_DESCRIPTOR_CONTROL Control;
|
|
ULONG Revision;
|
|
|
|
if ( !ppNewSD ) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// In case there is no RPC call causing us to enter here, there
|
|
// is no impersonation happening and the current thread is already
|
|
// running under Local System context in which case there is no
|
|
// need to RevertToSelf() etc. as below.
|
|
// This behavior happens when, for example, the server side itself
|
|
// initiates a configuration
|
|
//
|
|
|
|
if ( !gbQueriedIfSystemContext ) {
|
|
|
|
//
|
|
// if any error happens when checking if running under system context,
|
|
// continue - since there will be impersonation errors later on in
|
|
// this routine
|
|
//
|
|
|
|
NtStatus = ScepIsSystemContext(
|
|
Token,
|
|
&gbIsSystemContext);
|
|
|
|
if (ERROR_SUCCESS == RtlNtStatusToDosError(NtStatus)) {
|
|
|
|
gbQueriedIfSystemContext = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( nFlag == SCETREE_QUERY_SD &&
|
|
!pObjectSD ) {
|
|
//
|
|
// current object's security descriptor is used, for SeInfo | OWNER
|
|
// NOTE: the inherited ace from pCurrentSD are not copied (which is correct).
|
|
//
|
|
|
|
Win32rc = GetNamedSecurityInfo(
|
|
ObjectName,
|
|
ObjectType,
|
|
SeInfo | OWNER_SECURITY_INFORMATION,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&pCurrentSD
|
|
);
|
|
/*
|
|
Win32rc = ScepGetNamedSecurityInfo(
|
|
ObjectName,
|
|
ObjectType,
|
|
SeInfo | OWNER_SECURITY_INFORMATION,
|
|
&pCurrentSD
|
|
);
|
|
*/
|
|
//
|
|
// RtlNewSecurityObjectEx must be called on the process context (system)
|
|
// because it will try to get process information inside the api.
|
|
//
|
|
|
|
if (!gbIsSystemContext) {
|
|
|
|
RpcRevertToSelf();
|
|
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == Win32rc ||
|
|
ERROR_FILE_NOT_FOUND == Win32rc ||
|
|
ERROR_PATH_NOT_FOUND == Win32rc ) {
|
|
|
|
//
|
|
// use the current SD to compute
|
|
//
|
|
NtStatus = RtlNewSecurityObjectEx(
|
|
pParentSD,
|
|
pCurrentSD,
|
|
ppNewSD,
|
|
NULL, // GUID
|
|
bIsContainer,
|
|
SEF_DACL_AUTO_INHERIT |
|
|
SEF_SACL_AUTO_INHERIT |
|
|
SEF_AVOID_OWNER_CHECK |
|
|
SEF_AVOID_PRIVILEGE_CHECK,
|
|
Token,
|
|
GenericMapping
|
|
);
|
|
Win32rc = RtlNtStatusToDosError(NtStatus);
|
|
}
|
|
|
|
if ( pCurrentSD ) {
|
|
ScepFree(pCurrentSD);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// RtlNewSecurityObjectEx must be called on the process context (system)
|
|
// because it will try to get process information inside the api.
|
|
//
|
|
|
|
if (!gbIsSystemContext) {
|
|
|
|
RpcRevertToSelf();
|
|
|
|
}
|
|
|
|
if ( pObjectSD ) {
|
|
//
|
|
// check if there is a owner
|
|
//
|
|
|
|
NtStatus = RtlGetOwnerSecurityDescriptor(
|
|
pObjectSD,
|
|
&pOwner,
|
|
&tFlag);
|
|
if ( NT_SUCCESS(NtStatus) && pOwner && !tFlag ) {
|
|
bOwner = TRUE;
|
|
} else {
|
|
bOwner = FALSE;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// no owner
|
|
//
|
|
bOwner = FALSE;
|
|
}
|
|
|
|
if ( !bOwner ) {
|
|
//
|
|
// query owner information only
|
|
//
|
|
Win32rc = ScepGetNamedSecurityInfo(
|
|
ObjectName,
|
|
ObjectType,
|
|
OWNER_SECURITY_INFORMATION,
|
|
&pCurrentSD
|
|
);
|
|
|
|
if ( ERROR_SUCCESS == Win32rc ) {
|
|
|
|
NtStatus = RtlGetOwnerSecurityDescriptor(
|
|
pCurrentSD,
|
|
&pOwner,
|
|
&tFlag);
|
|
Win32rc = RtlNtStatusToDosError(NtStatus);
|
|
}
|
|
|
|
if ( ERROR_FILE_NOT_FOUND == Win32rc ||
|
|
ERROR_PATH_NOT_FOUND == Win32rc ) {
|
|
Win32rc = ERROR_SUCCESS;
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == Win32rc ) {
|
|
|
|
//
|
|
// build a security descriptor to use
|
|
//
|
|
|
|
if ( SeInfo & DACL_SECURITY_INFORMATION &&
|
|
pObjectSD ) {
|
|
|
|
//
|
|
// Get DACL address
|
|
//
|
|
Win32rc = RtlNtStatusToDosError(
|
|
RtlGetDaclSecurityDescriptor(
|
|
pObjectSD,
|
|
&aclPresent,
|
|
&pDacl,
|
|
&tFlag));
|
|
if (Win32rc == NO_ERROR && !aclPresent ) {
|
|
pDacl = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
if ( ERROR_SUCCESS == Win32rc &&
|
|
(SeInfo & SACL_SECURITY_INFORMATION) &&
|
|
pObjectSD ) {
|
|
|
|
//
|
|
// Get SACL address
|
|
//
|
|
|
|
Win32rc = RtlNtStatusToDosError(
|
|
RtlGetSaclSecurityDescriptor(
|
|
pObjectSD,
|
|
&aclPresent,
|
|
&pSacl,
|
|
&tFlag));
|
|
if ( Win32rc == NO_ERROR && !aclPresent ) {
|
|
pSacl = NULL;
|
|
}
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == Win32rc ) {
|
|
|
|
//
|
|
// build an absolute security descriptor
|
|
//
|
|
NtStatus = RtlCreateSecurityDescriptor( &SD,
|
|
SECURITY_DESCRIPTOR_REVISION );
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
//
|
|
// set control field
|
|
//
|
|
|
|
if ( pObjectSD ) {
|
|
|
|
NtStatus = RtlGetControlSecurityDescriptor (
|
|
pObjectSD,
|
|
&Control,
|
|
&Revision
|
|
);
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
Control &= SE_VALID_CONTROL_BITS;
|
|
NtStatus = RtlSetControlSecurityDescriptor (
|
|
&SD,
|
|
Control,
|
|
Control
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// set owner first
|
|
//
|
|
|
|
if ( pOwner ) {
|
|
NtStatus = RtlSetOwnerSecurityDescriptor (
|
|
&SD,
|
|
pOwner,
|
|
FALSE
|
|
);
|
|
}
|
|
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
//
|
|
// set DACL and SACL pointer to this SD
|
|
//
|
|
if ( SeInfo & DACL_SECURITY_INFORMATION && pDacl ) {
|
|
|
|
NtStatus = RtlSetDaclSecurityDescriptor (
|
|
&SD,
|
|
TRUE,
|
|
pDacl,
|
|
FALSE
|
|
);
|
|
}
|
|
|
|
if ( NT_SUCCESS(NtStatus) &&
|
|
(SeInfo & SACL_SECURITY_INFORMATION) && pSacl ) {
|
|
|
|
NtStatus = RtlSetSaclSecurityDescriptor (
|
|
&SD,
|
|
TRUE,
|
|
pSacl,
|
|
FALSE
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// now compute the new security descriptor
|
|
//
|
|
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
NtStatus = RtlNewSecurityObjectEx(
|
|
pParentSD,
|
|
&SD,
|
|
ppNewSD,
|
|
NULL, // GUID
|
|
bIsContainer,
|
|
SEF_DACL_AUTO_INHERIT |
|
|
SEF_SACL_AUTO_INHERIT |
|
|
SEF_AVOID_OWNER_CHECK |
|
|
SEF_AVOID_PRIVILEGE_CHECK,
|
|
Token,
|
|
GenericMapping
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
Win32rc = RtlNtStatusToDosError(NtStatus);
|
|
}
|
|
}
|
|
|
|
if ( pCurrentSD ) {
|
|
//
|
|
// this owner needs to be freed
|
|
//
|
|
LocalFree(pCurrentSD);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// there is a SD and there is a owner in it, just use it
|
|
//
|
|
NtStatus = RtlNewSecurityObjectEx(
|
|
pParentSD,
|
|
pObjectSD,
|
|
ppNewSD,
|
|
NULL, // GUID
|
|
bIsContainer,
|
|
SEF_DACL_AUTO_INHERIT |
|
|
SEF_SACL_AUTO_INHERIT |
|
|
SEF_AVOID_OWNER_CHECK |
|
|
SEF_AVOID_PRIVILEGE_CHECK,
|
|
Token,
|
|
GenericMapping
|
|
);
|
|
|
|
Win32rc = RtlNtStatusToDosError(NtStatus);
|
|
}
|
|
|
|
}
|
|
|
|
RPC_STATUS RpcStatus = RPC_S_OK;
|
|
|
|
if (!gbIsSystemContext) {
|
|
|
|
RpcStatus = RpcImpersonateClient( NULL );
|
|
|
|
}
|
|
|
|
if ( RpcStatus != RPC_S_OK ) {
|
|
|
|
Win32rc = I_RpcMapWin32Status(RpcStatus);
|
|
}
|
|
|
|
if ( NO_ERROR != Win32rc &&
|
|
*ppNewSD ) {
|
|
//
|
|
// free the buffer if there is an error
|
|
//
|
|
RtlDeleteSecurityObject(ppNewSD);
|
|
*ppNewSD = NULL;
|
|
}
|
|
|
|
return(Win32rc);
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepAddAutoInheritRequest(
|
|
IN OUT PSECURITY_DESCRIPTOR pSD,
|
|
IN OUT SECURITY_INFORMATION *pSeInfo
|
|
)
|
|
{
|
|
|
|
SECURITY_DESCRIPTOR_CONTROL Control;
|
|
SECURITY_DESCRIPTOR_CONTROL ToSet;
|
|
ULONG Revision;
|
|
NTSTATUS NtStatus;
|
|
|
|
DWORD Win32rc=NO_ERROR;
|
|
|
|
if ( !pSeInfo )
|
|
return(ERROR_INVALID_PARAMETER);
|
|
|
|
if ( pSD != NULL &&
|
|
(*pSeInfo & DACL_SECURITY_INFORMATION ||
|
|
*pSeInfo & SACL_SECURITY_INFORMATION) ) {
|
|
|
|
NtStatus = RtlGetControlSecurityDescriptor (
|
|
pSD,
|
|
&Control,
|
|
&Revision
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
|
|
Win32rc = RtlNtStatusToDosError(NtStatus);
|
|
|
|
} else {
|
|
|
|
if ( !(Control & SE_DACL_PRESENT) )
|
|
*pSeInfo &= ~DACL_SECURITY_INFORMATION;
|
|
|
|
if ( !(Control & SE_SACL_PRESENT) )
|
|
*pSeInfo &= ~SACL_SECURITY_INFORMATION;
|
|
|
|
if ( *pSeInfo & (DACL_SECURITY_INFORMATION |
|
|
SACL_SECURITY_INFORMATION) ) {
|
|
|
|
ToSet = 0;
|
|
if ( *pSeInfo & DACL_SECURITY_INFORMATION ) {
|
|
|
|
ToSet |= (SE_DACL_AUTO_INHERIT_REQ |
|
|
SE_DACL_AUTO_INHERITED);
|
|
}
|
|
|
|
if ( *pSeInfo & SACL_SECURITY_INFORMATION) {
|
|
|
|
ToSet |= (SE_SACL_AUTO_INHERIT_REQ |
|
|
SE_SACL_AUTO_INHERITED);
|
|
}
|
|
|
|
if ( ToSet ) {
|
|
((SECURITY_DESCRIPTOR *)pSD)->Control &= ~ToSet;
|
|
((SECURITY_DESCRIPTOR *)pSD)->Control |= ToSet;
|
|
/*
|
|
NtStatus = RtlSetControlSecurityDescriptor (
|
|
pSD,
|
|
ToSet,
|
|
ToSet
|
|
);
|
|
Win32rc = RtlNtStatusToDosError(NtStatus);
|
|
*/
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return(Win32rc);
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
ScepDoesObjectHasChildren(
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN PWSTR ObjectName,
|
|
OUT PBOOL pbHasChildren
|
|
)
|
|
{
|
|
PWSTR Name=NULL;
|
|
DWORD rc=NO_ERROR;
|
|
DWORD Len;
|
|
intptr_t hFile;
|
|
struct _wfinddata_t FileInfo;
|
|
HKEY hKey;
|
|
DWORD cSubKeys=0;
|
|
|
|
|
|
if ( ObjectName == NULL || pbHasChildren == NULL ) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
*pbHasChildren = TRUE; // default
|
|
|
|
if ( ObjectType == SE_FILE_OBJECT ) {
|
|
//
|
|
// detect if this is a container for file system
|
|
//
|
|
Len = wcslen(ObjectName);
|
|
Name = (PWSTR)ScepAlloc(0, (Len+5)*sizeof(WCHAR) );
|
|
|
|
if ( Name != NULL ) {
|
|
|
|
swprintf(Name, L"%s\\*.*", ObjectName);
|
|
Name[Len+3] = L'\0';
|
|
|
|
hFile = _wfindfirst(Name, &FileInfo);
|
|
|
|
if ( hFile == -1 ) {
|
|
*pbHasChildren = FALSE;
|
|
} else {
|
|
_findclose(hFile);
|
|
}
|
|
|
|
ScepFree(Name);
|
|
|
|
} else
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
#ifdef _WIN64
|
|
} else if ( ObjectType == SE_REGISTRY_KEY || ObjectType == SE_REGISTRY_WOW64_32KEY) {
|
|
#else
|
|
} else if ( ObjectType == SE_REGISTRY_KEY) {
|
|
#endif
|
|
|
|
rc = ScepOpenRegistryObject(
|
|
ObjectType,
|
|
(LPWSTR)ObjectName,
|
|
KEY_READ,
|
|
&hKey
|
|
);
|
|
|
|
if ( rc == NO_ERROR ) {
|
|
|
|
cSubKeys = 0;
|
|
|
|
rc = RegQueryInfoKey (
|
|
hKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&cSubKeys,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if ( rc == NO_ERROR && cSubKeys == 0 ) {
|
|
*pbHasChildren = FALSE;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepConfigureObjectTree(
|
|
IN PSCE_OBJECT_TREE ThisNode,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN HANDLE Token,
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
IN DWORD ConfigOptions
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine set security information to each node in the tree and objects of
|
|
the container if SCE_STATUS_OVERWRITE is set.
|
|
|
|
Arguments:
|
|
|
|
ThisNode - one node in the tree
|
|
|
|
ObjectType - type of the object (SE_FILE_OBJECT, SE_REGISTRY_KEY)
|
|
|
|
Token - The current process/thread's token (for computing new security descriptors)
|
|
|
|
GenericMapping - The access mask mappings from generic access rights to object
|
|
specific access rights.
|
|
|
|
Return value:
|
|
|
|
SCESTATUS_SUCCESS
|
|
SCESTATUS_OTHER_ERROR (see the log file for detail error)
|
|
|
|
-- */
|
|
{
|
|
// two error codes to distinguish between config status of "ThisNode" and "ThisNode's children"
|
|
DWORD rcThisNodeOnly = ERROR_SUCCESS;
|
|
DWORD rcThisNodeChildren = ERROR_SUCCESS;
|
|
|
|
if ( ThisNode == NULL )
|
|
return(SCESTATUS_SUCCESS);
|
|
|
|
//
|
|
// if IGNORE is set, skip this node, but post progress on it
|
|
//
|
|
if ( ThisNode->pSecurityDescriptor != NULL ) {
|
|
//
|
|
// notify the progress bar if there is any
|
|
//
|
|
switch(ObjectType) {
|
|
case SE_FILE_OBJECT:
|
|
ScepPostProgress(1, AREA_FILE_SECURITY, ThisNode->ObjectFullName);
|
|
break;
|
|
case SE_REGISTRY_KEY:
|
|
#ifdef _WIN64
|
|
case SE_REGISTRY_WOW64_32KEY:
|
|
#endif
|
|
ScepPostProgress(1, AREA_REGISTRY_SECURITY, ThisNode->ObjectFullName);
|
|
break;
|
|
default:
|
|
ScepPostProgress(1, 0, ThisNode->ObjectFullName);
|
|
break;
|
|
}
|
|
}
|
|
|
|
SCESTATUS rc=SCESTATUS_SUCCESS;
|
|
DWORD Win32Rc=ERROR_SUCCESS;
|
|
|
|
if ( ThisNode->Status != SCE_STATUS_CHECK &&
|
|
ThisNode->Status != SCE_STATUS_NO_AUTO_INHERIT &&
|
|
ThisNode->Status != SCE_STATUS_OVERWRITE )
|
|
goto SkipNode;
|
|
|
|
if ( ThisNode->pSecurityDescriptor != NULL ) {
|
|
|
|
ScepLogOutput3(2, 0, SCEDLL_SCP_CONFIGURE, ThisNode->ObjectFullName);
|
|
}
|
|
|
|
//
|
|
// Process this node first
|
|
// Note: we do not set NULL security descriptor
|
|
//
|
|
|
|
if ( ThisNode->pApplySecurityDescriptor != NULL ) {
|
|
|
|
if ( ThisNode->pSecurityDescriptor == NULL ) {
|
|
ScepLogOutput3(3, 0, SCEDLL_SCP_CONFIGURE, ThisNode->ObjectFullName);
|
|
}
|
|
|
|
BOOL BackSlashExist=FALSE;
|
|
|
|
if ( ThisNode->Status == SCE_STATUS_NO_AUTO_INHERIT ) {
|
|
//
|
|
// no auto inherit to children. Apply to this object only
|
|
// this flag is removed since 2/20/1998
|
|
//
|
|
Win32Rc = ScepSetSecurityObjectOnly(
|
|
ThisNode->ObjectFullName,
|
|
ThisNode->SeInfo,
|
|
ThisNode->pApplySecurityDescriptor,
|
|
ObjectType,
|
|
NULL
|
|
);
|
|
|
|
rcThisNodeOnly = Win32Rc;
|
|
|
|
} else if ( ThisNode->ChildList == NULL &&
|
|
ThisNode->Status != SCE_STATUS_OVERWRITE ) {
|
|
//
|
|
// there is no children
|
|
// apply security to everyone underneeth, using the win32 api.
|
|
//
|
|
Win32Rc = ScepDoesObjectHasChildren(ObjectType,
|
|
ThisNode->ObjectFullName,
|
|
&BackSlashExist // temp use
|
|
);
|
|
if ( Win32Rc == NO_ERROR ) {
|
|
|
|
if ( BackSlashExist ) {
|
|
//
|
|
// this is a container which has children
|
|
//
|
|
|
|
//
|
|
// new marta API without considering parent
|
|
//
|
|
Win32Rc = AccRewriteSetNamedRights(
|
|
ThisNode->ObjectFullName,
|
|
ObjectType,
|
|
ThisNode->SeInfo,
|
|
ThisNode->pApplySecurityDescriptor,
|
|
TRUE // bSkipInheritanceComputation
|
|
);
|
|
/*
|
|
Win32Rc = ScepSetSecurityWin32(
|
|
ThisNode->ObjectFullName,
|
|
ThisNode->SeInfo,
|
|
ThisNode->pApplySecurityDescriptor,
|
|
ObjectType
|
|
);
|
|
*/
|
|
} else {
|
|
//
|
|
// no children
|
|
//
|
|
Win32Rc = ScepSetSecurityObjectOnly(
|
|
ThisNode->ObjectFullName,
|
|
ThisNode->SeInfo,
|
|
ThisNode->pApplySecurityDescriptor,
|
|
ObjectType,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
} else {
|
|
ScepLogOutput3(1, Win32Rc, SCEDLL_SAP_ERROR_ENUMERATE,
|
|
ThisNode->ObjectFullName);
|
|
}
|
|
|
|
rcThisNodeOnly = Win32Rc;
|
|
|
|
} else {
|
|
|
|
//
|
|
// there is child(ren) in the tree, or OVERWRITE flag is set
|
|
//
|
|
|
|
|
|
Win32Rc = ScepDoesObjectHasChildren(ObjectType,
|
|
ThisNode->ObjectFullName,
|
|
&BackSlashExist // temp use
|
|
);
|
|
|
|
rcThisNodeOnly = Win32Rc;
|
|
|
|
if ( Win32Rc != ERROR_SUCCESS ) {
|
|
//
|
|
// for registry keys, the above function could fail if the key does
|
|
// not exist. Log the error in this case
|
|
//
|
|
ScepLogOutput3(1, Win32Rc, SCEDLL_SAP_ERROR_ENUMERATE,
|
|
ThisNode->ObjectFullName);
|
|
|
|
}
|
|
if ( Win32Rc == ERROR_SUCCESS && !BackSlashExist ) {
|
|
//
|
|
// no child exist
|
|
//
|
|
if (ThisNode->Status == SCE_STATUS_OVERWRITE ) {
|
|
|
|
//
|
|
// if OVERWRITE flag set and no children, set now (top-down)
|
|
// if OVERWRITE flag and has children then share logic with 0 mode, set later (bottom-up)
|
|
// maybe we can have all OVERWRITE mode go bottom-up if goto SkipNode is removed here
|
|
//
|
|
|
|
Win32Rc = ScepSetSecurityObjectOnly(
|
|
ThisNode->ObjectFullName,
|
|
ThisNode->SeInfo,
|
|
ThisNode->pApplySecurityDescriptor,
|
|
ObjectType,
|
|
&BackSlashExist
|
|
);
|
|
|
|
rcThisNodeOnly = rcThisNodeOnly == NO_ERROR ? Win32Rc: rcThisNodeOnly;
|
|
|
|
}
|
|
|
|
goto SkipNode;
|
|
}
|
|
|
|
if ( Win32Rc == ERROR_SUCCESS && BackSlashExist ) {
|
|
|
|
//
|
|
// set security for other files/keys under this directory
|
|
//
|
|
//
|
|
// child exist, set child node first
|
|
// set security for other files/keys under this directory
|
|
//
|
|
|
|
switch ( ObjectType ) {
|
|
case SE_FILE_OBJECT:
|
|
|
|
//
|
|
// detect if there is a \ at the end
|
|
//
|
|
BackSlashExist = ScepLastBackSlash(ThisNode->ObjectFullName);
|
|
|
|
Win32Rc = ScepConfigureOneSubTreeFile(ThisNode,
|
|
ObjectType,
|
|
Token,
|
|
GenericMapping,
|
|
BackSlashExist
|
|
);
|
|
break;
|
|
|
|
case SE_REGISTRY_KEY:
|
|
#ifdef _WIN64
|
|
case SE_REGISTRY_WOW64_32KEY:
|
|
#endif
|
|
|
|
//
|
|
// process this key and any sub keys
|
|
//
|
|
|
|
Win32Rc = ScepConfigureOneSubTreeKey(ThisNode,
|
|
ObjectType,
|
|
Token,
|
|
GenericMapping
|
|
);
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// this rc is the status for configuration of children of ThisNode
|
|
//
|
|
rcThisNodeChildren = Win32Rc;
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// ignore some error codes and continue to configure other objects
|
|
//
|
|
if ( SCEP_IGNORE_SOME_ERRORS(Win32Rc) ) {
|
|
|
|
gWarningCode = Win32Rc;
|
|
rc = SCESTATUS_SUCCESS;
|
|
goto SkipNode;
|
|
}
|
|
|
|
if ( Win32Rc != ERROR_SUCCESS ) {
|
|
//
|
|
// if security for this object was specified in the config template/database, log to RSOP status
|
|
//
|
|
|
|
if (ThisNode->pSecurityDescriptor && (ConfigOptions & SCE_RSOP_CALLBACK) ) {
|
|
|
|
ScepRsopLog(ObjectType == SE_FILE_OBJECT ?
|
|
SCE_RSOP_FILE_SECURITY_INFO :
|
|
SCE_RSOP_REGISTRY_SECURITY_INFO,
|
|
rcThisNodeOnly,
|
|
ThisNode->ObjectFullName,0,0);
|
|
|
|
if (rcThisNodeOnly == ERROR_SUCCESS && rcThisNodeChildren != ERROR_SUCCESS) {
|
|
|
|
ScepRsopLog(ObjectType == SE_FILE_OBJECT ?
|
|
(SCE_RSOP_FILE_SECURITY_INFO | SCE_RSOP_FILE_SECURITY_INFO_CHILD) :
|
|
(SCE_RSOP_REGISTRY_SECURITY_INFO | SCE_RSOP_REGISTRY_SECURITY_INFO_CHILD),
|
|
rcThisNodeChildren,
|
|
ThisNode->ObjectFullName,0,0);
|
|
}
|
|
|
|
}
|
|
|
|
return(ScepDosErrorToSceStatus(Win32Rc));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// then process children
|
|
//
|
|
|
|
for ( PSCE_OBJECT_CHILD_LIST pTemp = ThisNode->ChildList;
|
|
pTemp != NULL; pTemp = pTemp->Next ) {
|
|
|
|
if ( pTemp->Node == NULL ) continue;
|
|
|
|
rc = ScepConfigureObjectTree(
|
|
pTemp->Node,
|
|
ObjectType,
|
|
Token,
|
|
GenericMapping,
|
|
ConfigOptions
|
|
);
|
|
Win32Rc = ScepSceStatusToDosError(rc);
|
|
|
|
//
|
|
// ignore some error codes and continue to configure other objects
|
|
//
|
|
if ( SCEP_IGNORE_SOME_ERRORS(Win32Rc) ) {
|
|
|
|
gWarningCode = Win32Rc;
|
|
Win32Rc = ERROR_SUCCESS;
|
|
rc = SCESTATUS_SUCCESS;
|
|
}
|
|
|
|
if ( rc != SCESTATUS_SUCCESS )
|
|
return(rc);
|
|
|
|
}
|
|
|
|
if ( ThisNode->pApplySecurityDescriptor != NULL &&
|
|
ThisNode->Status != SCE_STATUS_NO_AUTO_INHERIT &&
|
|
( ThisNode->ChildList != NULL ||
|
|
ThisNode->Status == SCE_STATUS_OVERWRITE ) ) {
|
|
|
|
//
|
|
// finally config the current node - (post order)
|
|
//
|
|
|
|
Win32Rc = ScepSetSecurityObjectOnly(
|
|
ThisNode->ObjectFullName,
|
|
ThisNode->SeInfo,
|
|
ThisNode->pApplySecurityDescriptor,
|
|
ObjectType,
|
|
NULL
|
|
);
|
|
|
|
rc = ScepDosErrorToSceStatus(Win32Rc);
|
|
|
|
rcThisNodeOnly = rcThisNodeOnly == NO_ERROR ? Win32Rc: rcThisNodeOnly;
|
|
|
|
//
|
|
// ignore the following error codes and continue to configure other objects
|
|
//
|
|
if ( SCEP_IGNORE_SOME_ERRORS(Win32Rc) ) {
|
|
|
|
gWarningCode = Win32Rc;
|
|
Win32Rc = ERROR_SUCCESS;
|
|
rc = SCESTATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
SkipNode:
|
|
|
|
//
|
|
// if security for this object was specified in the config template/database, log to RSOP status
|
|
//
|
|
|
|
if (ThisNode->pSecurityDescriptor && (ConfigOptions & SCE_RSOP_CALLBACK) ) {
|
|
|
|
ScepRsopLog(ObjectType == SE_FILE_OBJECT ?
|
|
SCE_RSOP_FILE_SECURITY_INFO :
|
|
SCE_RSOP_REGISTRY_SECURITY_INFO,
|
|
rcThisNodeOnly,
|
|
ThisNode->ObjectFullName,0,0);
|
|
|
|
if (rcThisNodeOnly == ERROR_SUCCESS && rcThisNodeChildren != ERROR_SUCCESS) {
|
|
|
|
ScepRsopLog(ObjectType == SE_FILE_OBJECT ?
|
|
(SCE_RSOP_FILE_SECURITY_INFO | SCE_RSOP_FILE_SECURITY_INFO_CHILD) :
|
|
(SCE_RSOP_REGISTRY_SECURITY_INFO | SCE_RSOP_REGISTRY_SECURITY_INFO_CHILD),
|
|
rcThisNodeChildren,
|
|
ThisNode->ObjectFullName,0,0);
|
|
}
|
|
|
|
}
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepConfigureOneSubTreeFile(
|
|
IN PSCE_OBJECT_TREE ThisNode,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN HANDLE Token,
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
IN BOOL BackSlashExist
|
|
)
|
|
{
|
|
|
|
if ( NULL == ThisNode ) {
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
DWORD BufSize;
|
|
PWSTR Buffer=NULL;
|
|
|
|
//
|
|
// find all files under this directory/file
|
|
//
|
|
|
|
BufSize = wcslen(ThisNode->ObjectFullName)+4;
|
|
Buffer = (PWSTR)ScepAlloc( 0, (BufSize+1)*sizeof(WCHAR));
|
|
if ( Buffer == NULL ) {
|
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
if ( BackSlashExist ) {
|
|
swprintf(Buffer, L"%s*.*", ThisNode->ObjectFullName);
|
|
} else {
|
|
swprintf(Buffer, L"%s\\*.*", ThisNode->ObjectFullName);
|
|
}
|
|
|
|
intptr_t hFile;
|
|
struct _wfinddata_t *pFileInfo=NULL;
|
|
|
|
//
|
|
// allocate the find buffer
|
|
//
|
|
pFileInfo = (struct _wfinddata_t *)ScepAlloc(0,sizeof(struct _wfinddata_t));
|
|
if ( pFileInfo == NULL ) {
|
|
ScepFree(Buffer);
|
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
hFile = _wfindfirst(Buffer, pFileInfo);
|
|
|
|
ScepFree(Buffer);
|
|
Buffer = NULL;
|
|
|
|
DWORD Win32Rc = ERROR_SUCCESS;
|
|
BOOL bFilePresentInTree;
|
|
|
|
if ( hFile != -1 ) {
|
|
|
|
PSCE_OBJECT_CHILD_LIST pTemp;
|
|
INT i;
|
|
DWORD EnumRc;
|
|
PSECURITY_DESCRIPTOR pChildrenSD=NULL;
|
|
|
|
do {
|
|
if ( pFileInfo->name[0] == L'.' &&
|
|
(pFileInfo->name[1] == L'\0' || (pFileInfo->name[1] == L'.' && pFileInfo->name[2] == L'\0')))
|
|
continue;
|
|
|
|
bFilePresentInTree = ScepBinarySearch(
|
|
ThisNode->aChildNames,
|
|
ThisNode->dwSize_aChildNames,
|
|
pFileInfo->name);
|
|
|
|
if ( ! bFilePresentInTree ) {
|
|
|
|
//
|
|
// The name is not in the list, so set.
|
|
// build the full name first
|
|
//
|
|
|
|
BufSize = wcslen(ThisNode->ObjectFullName)+wcslen(pFileInfo->name)+1;
|
|
Buffer = (PWSTR)ScepAlloc( 0, (BufSize+1)*sizeof(WCHAR));
|
|
if ( Buffer == NULL ) {
|
|
Win32Rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
if ( BackSlashExist ) {
|
|
|
|
swprintf(Buffer, L"%s%s", ThisNode->ObjectFullName, pFileInfo->name);
|
|
} else {
|
|
|
|
swprintf(Buffer, L"%s\\%s", ThisNode->ObjectFullName, pFileInfo->name);
|
|
}
|
|
EnumRc = pFileInfo->attrib; // borrow this variable temperaorily
|
|
|
|
ScepFree(pFileInfo);
|
|
pFileInfo = NULL;
|
|
|
|
|
|
//
|
|
// compute the SDs for each individual object
|
|
//
|
|
Win32Rc = ScepGetNewSecurity(
|
|
Buffer,
|
|
ThisNode->pApplySecurityDescriptor, // parent's SD
|
|
NULL,
|
|
(BYTE)((ThisNode->Status != SCE_STATUS_OVERWRITE ) ? SCETREE_QUERY_SD : 0),
|
|
(BOOLEAN)(EnumRc & _A_SUBDIR),
|
|
ThisNode->SeInfo,
|
|
ObjectType,
|
|
Token,
|
|
GenericMapping,
|
|
&pChildrenSD
|
|
);
|
|
|
|
if (Win32Rc == ERROR_SHARING_VIOLATION ||
|
|
Win32Rc == ERROR_ACCESS_DENIED ||
|
|
Win32Rc == ERROR_CANT_ACCESS_FILE) {
|
|
|
|
ScepLogOutput3(1, Win32Rc, SCEDLL_ERROR_BUILD_SD, Buffer);
|
|
}
|
|
|
|
if ( Win32Rc == NO_ERROR ) {
|
|
|
|
if ( !(EnumRc & _A_SUBDIR) ) {
|
|
|
|
// this is a single file
|
|
//
|
|
|
|
Win32Rc = ScepSetSecurityObjectOnly(
|
|
Buffer,
|
|
(ThisNode->SeInfo & DACL_SECURITY_INFORMATION) |
|
|
(ThisNode->SeInfo & SACL_SECURITY_INFORMATION),
|
|
pChildrenSD,
|
|
ObjectType,
|
|
NULL
|
|
);
|
|
|
|
} else if ( ThisNode->Status == SCE_STATUS_OVERWRITE ) {
|
|
|
|
//
|
|
// enumerate all nodes under this one and "empty" explicit aces by
|
|
// calling NtSetSecurityInfo directly but please note
|
|
// Creator Owner Ace should be reserved
|
|
//
|
|
|
|
Win32Rc = ScepSetSecurityOverwriteExplicit(
|
|
Buffer,
|
|
(ThisNode->SeInfo & DACL_SECURITY_INFORMATION) |
|
|
(ThisNode->SeInfo & SACL_SECURITY_INFORMATION),
|
|
pChildrenSD,
|
|
ObjectType,
|
|
Token,
|
|
GenericMapping
|
|
);
|
|
} else {
|
|
//
|
|
// new marta API without considering parent
|
|
//
|
|
Win32Rc = AccRewriteSetNamedRights(
|
|
Buffer,
|
|
ObjectType,
|
|
ThisNode->SeInfo & (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION),
|
|
pChildrenSD,
|
|
TRUE // bSkipInheritanceComputation
|
|
);
|
|
/*
|
|
Win32Rc = ScepSetSecurityWin32(
|
|
Buffer,
|
|
(ThisNode->SeInfo & DACL_SECURITY_INFORMATION) |
|
|
(ThisNode->SeInfo & SACL_SECURITY_INFORMATION),
|
|
pChildrenSD,
|
|
ObjectType
|
|
);
|
|
*/
|
|
|
|
if ( Win32Rc != ERROR_SUCCESS ) {
|
|
//
|
|
// something is wrong to set inheritance info, log it
|
|
// but still continue to the next one
|
|
//
|
|
gWarningCode = Win32Rc;
|
|
|
|
Win32Rc = NO_ERROR;
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
ScepFree(Buffer);
|
|
Buffer = NULL;
|
|
|
|
//
|
|
// free the SD pointers allocated for this object
|
|
//
|
|
if ( pChildrenSD != NULL )
|
|
RtlDeleteSecurityObject( &pChildrenSD );
|
|
|
|
pChildrenSD = NULL;
|
|
|
|
if (Win32Rc == ERROR_FILE_NOT_FOUND ||
|
|
Win32Rc == ERROR_PATH_NOT_FOUND ||
|
|
Win32Rc == ERROR_SHARING_VIOLATION ||
|
|
Win32Rc == ERROR_ACCESS_DENIED ||
|
|
Win32Rc == ERROR_CANT_ACCESS_FILE ) {
|
|
|
|
gWarningCode = Win32Rc;
|
|
|
|
Win32Rc = NO_ERROR;
|
|
} else if ( Win32Rc != ERROR_SUCCESS )
|
|
break;
|
|
|
|
pFileInfo = (struct _wfinddata_t *)ScepAlloc(0,sizeof(struct _wfinddata_t));
|
|
if ( pFileInfo == NULL ) {
|
|
Win32Rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
}
|
|
} while ( _wfindnext(hFile, pFileInfo) == 0 );
|
|
|
|
_findclose(hFile);
|
|
|
|
//
|
|
// free memory if allocated
|
|
//
|
|
if ( pChildrenSD != NULL &&
|
|
pChildrenSD != ThisNode->pApplySecurityDescriptor ) {
|
|
|
|
RtlDeleteSecurityObject( &pChildrenSD );
|
|
pChildrenSD = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
if ( pFileInfo != NULL ) {
|
|
ScepFree(pFileInfo);
|
|
pFileInfo = NULL;
|
|
}
|
|
|
|
if ( Buffer != NULL ) {
|
|
ScepFree(Buffer);
|
|
Buffer = NULL;
|
|
}
|
|
|
|
return(Win32Rc);
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepConfigureOneSubTreeKey(
|
|
IN PSCE_OBJECT_TREE ThisNode,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN HANDLE Token,
|
|
IN PGENERIC_MAPPING GenericMapping
|
|
)
|
|
{
|
|
|
|
if ( NULL == ThisNode ) {
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
HKEY hKey=NULL;
|
|
DWORD Win32Rc;
|
|
|
|
DWORD SubKeyLen;
|
|
PWSTR Buffer1=NULL;
|
|
|
|
//
|
|
// open the key
|
|
//
|
|
|
|
Win32Rc = ScepOpenRegistryObject(
|
|
ObjectType,
|
|
ThisNode->ObjectFullName,
|
|
KEY_READ,
|
|
&hKey
|
|
);
|
|
|
|
if ( Win32Rc == ERROR_SUCCESS ) {
|
|
|
|
SubKeyLen = 0;
|
|
Win32Rc = RegQueryInfoKey (
|
|
hKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&SubKeyLen,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
} else {
|
|
ScepLogOutput3(1, Win32Rc, SCEDLL_ERROR_OPEN, ThisNode->ObjectFullName );
|
|
}
|
|
|
|
if ( Win32Rc == ERROR_SUCCESS ) {
|
|
|
|
//
|
|
// enumerate all subkeys of the key
|
|
//
|
|
Buffer1 = (PWSTR)ScepAlloc(0, (SubKeyLen+2)*sizeof(WCHAR));
|
|
if ( Buffer1 == NULL ) {
|
|
Win32Rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
|
|
if ( Win32Rc == ERROR_SUCCESS ) {
|
|
|
|
DWORD index;
|
|
DWORD EnumRc;
|
|
DWORD BufSize;
|
|
|
|
PSCE_OBJECT_CHILD_LIST pTemp;
|
|
INT i;
|
|
PWSTR Buffer=NULL;
|
|
PSECURITY_DESCRIPTOR pChildrenSD=NULL;
|
|
BOOL bKeyPresentInTree;
|
|
|
|
index = 0;
|
|
|
|
do {
|
|
|
|
BufSize = SubKeyLen+1;
|
|
memset(Buffer1, L'\0', (SubKeyLen+2)*sizeof(WCHAR));
|
|
|
|
EnumRc = RegEnumKeyEx(hKey,
|
|
index,
|
|
Buffer1,
|
|
&BufSize,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
|
|
if ( EnumRc == ERROR_SUCCESS ) {
|
|
|
|
index++;
|
|
//
|
|
// find if the subkey is already in the tree
|
|
// if it is in the tree, it will be processed later
|
|
//
|
|
|
|
bKeyPresentInTree = ScepBinarySearch(
|
|
ThisNode->aChildNames,
|
|
ThisNode->dwSize_aChildNames,
|
|
Buffer1);
|
|
|
|
if ( ! bKeyPresentInTree ) {
|
|
//
|
|
// The name is not in the list, so set
|
|
// build the fullname first
|
|
//
|
|
BufSize += wcslen(ThisNode->ObjectFullName)+1;
|
|
Buffer = (PWSTR)ScepAlloc( 0, (BufSize+1)*sizeof(WCHAR));
|
|
if ( Buffer == NULL ) {
|
|
Win32Rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
swprintf(Buffer, L"%s\\%s", ThisNode->ObjectFullName, Buffer1);
|
|
|
|
ScepLogOutput3(3, 0, SCEDLL_SCP_CONFIGURE, Buffer);
|
|
|
|
//
|
|
// compute the SDs for each individual object
|
|
//
|
|
Win32Rc = ScepGetNewSecurity(
|
|
Buffer,
|
|
ThisNode->pApplySecurityDescriptor, // parent's SD
|
|
NULL,
|
|
(BYTE)((ThisNode->Status != SCE_STATUS_OVERWRITE ) ? SCETREE_QUERY_SD : 0),
|
|
(BOOLEAN)TRUE,
|
|
ThisNode->SeInfo,
|
|
ObjectType,
|
|
Token,
|
|
GenericMapping,
|
|
&pChildrenSD
|
|
);
|
|
|
|
if (Win32Rc == ERROR_SHARING_VIOLATION ||
|
|
Win32Rc == ERROR_ACCESS_DENIED ||
|
|
Win32Rc == ERROR_CANT_ACCESS_FILE) {
|
|
|
|
ScepLogOutput3(1, Win32Rc, SCEDLL_ERROR_BUILD_SD, Buffer);
|
|
}
|
|
|
|
if ( Win32Rc == ERROR_SUCCESS ) {
|
|
if ( ThisNode->Status == SCE_STATUS_OVERWRITE ) {
|
|
|
|
//
|
|
// enumerate all nodes under this one and "empty" explicit aces by
|
|
// calling NtSetSecurityInfo directly
|
|
//
|
|
|
|
Win32Rc = ScepSetSecurityOverwriteExplicit(
|
|
Buffer,
|
|
(ThisNode->SeInfo & DACL_SECURITY_INFORMATION) |
|
|
(ThisNode->SeInfo & SACL_SECURITY_INFORMATION),
|
|
pChildrenSD,
|
|
ObjectType,
|
|
Token,
|
|
GenericMapping
|
|
);
|
|
} else {
|
|
|
|
//
|
|
// new marta API without considering parent
|
|
//
|
|
Win32Rc = AccRewriteSetNamedRights(
|
|
Buffer,
|
|
ObjectType,
|
|
ThisNode->SeInfo & (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION),
|
|
pChildrenSD,
|
|
TRUE // bSkipInheritanceComputation
|
|
);
|
|
|
|
/*
|
|
Win32Rc = ScepSetSecurityWin32(
|
|
Buffer,
|
|
(ThisNode->SeInfo & DACL_SECURITY_INFORMATION) |
|
|
(ThisNode->SeInfo & SACL_SECURITY_INFORMATION),
|
|
pChildrenSD, // ThisNode->pApplySecurityDescriptor, calculate autoinheritance
|
|
ObjectType
|
|
);
|
|
*/
|
|
|
|
if ( Win32Rc != ERROR_SUCCESS ) {
|
|
//
|
|
// can't set inheritance to children, log it but continue
|
|
//
|
|
gWarningCode = Win32Rc;
|
|
|
|
Win32Rc = NO_ERROR;
|
|
}
|
|
}
|
|
|
|
}
|
|
if ( pChildrenSD != NULL ) {
|
|
RtlDeleteSecurityObject( &pChildrenSD );
|
|
pChildrenSD = NULL;
|
|
}
|
|
|
|
if ( Win32Rc == ERROR_FILE_NOT_FOUND ||
|
|
Win32Rc == ERROR_INVALID_HANDLE ||
|
|
Win32Rc == ERROR_PATH_NOT_FOUND ||
|
|
Win32Rc == ERROR_ACCESS_DENIED ||
|
|
Win32Rc == ERROR_CANT_ACCESS_FILE ||
|
|
Win32Rc == ERROR_SHARING_VIOLATION ) {
|
|
|
|
gWarningCode = Win32Rc;
|
|
Win32Rc = NO_ERROR;
|
|
}
|
|
|
|
if ( Win32Rc != ERROR_SUCCESS )
|
|
ScepLogOutput3(1, Win32Rc, SCEDLL_ERROR_SET_SECURITY, Buffer);
|
|
|
|
ScepFree(Buffer);
|
|
Buffer = NULL;
|
|
|
|
if ( Win32Rc != ERROR_SUCCESS )
|
|
break;
|
|
}
|
|
|
|
} else if ( EnumRc != ERROR_NO_MORE_ITEMS ) {
|
|
break;
|
|
}
|
|
} while ( EnumRc != ERROR_NO_MORE_ITEMS );
|
|
|
|
ScepFree(Buffer1);
|
|
Buffer1 = NULL;
|
|
|
|
if ( EnumRc != ERROR_SUCCESS && EnumRc != ERROR_NO_MORE_ITEMS ) {
|
|
|
|
ScepLogOutput3(1, EnumRc, SCEDLL_SAP_ERROR_ENUMERATE,
|
|
ThisNode->ObjectFullName );
|
|
if ( Win32Rc == ERROR_SUCCESS )
|
|
Win32Rc = EnumRc;
|
|
|
|
}
|
|
|
|
//
|
|
// free memory if allocated
|
|
//
|
|
if ( pChildrenSD != NULL &&
|
|
pChildrenSD != ThisNode->pApplySecurityDescriptor ) {
|
|
|
|
RtlDeleteSecurityObject( &pChildrenSD );
|
|
pChildrenSD = NULL;
|
|
}
|
|
if ( Buffer != NULL ) {
|
|
ScepFree(Buffer);
|
|
Buffer = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
if ( hKey ) {
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
return(Win32Rc);
|
|
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepFreeObject2Security(
|
|
IN PSCE_OBJECT_CHILD_LIST NodeList,
|
|
IN BOOL bFreeComputedSDOnly
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine frees memory allocated by the security object tree.
|
|
|
|
Arguments:
|
|
|
|
ThisNode - one node in the tree
|
|
|
|
Return value:
|
|
|
|
None
|
|
|
|
-- */
|
|
{
|
|
NTSTATUS NtStatus;
|
|
SCESTATUS rc;
|
|
|
|
|
|
if ( NodeList == NULL )
|
|
return(SCESTATUS_SUCCESS);
|
|
|
|
PSCE_OBJECT_CHILD_LIST pTemp,pTemp1;
|
|
PSCE_OBJECT_TREE ThisNode;
|
|
|
|
//
|
|
// free children first
|
|
//
|
|
pTemp = NodeList;
|
|
|
|
while ( pTemp != NULL ) {
|
|
if ( pTemp->Node ) {
|
|
|
|
ThisNode = pTemp->Node;
|
|
|
|
rc = ScepFreeObject2Security(ThisNode->ChildList, bFreeComputedSDOnly);
|
|
//
|
|
// both security descriptors need to be freed for SAP/SMP type
|
|
//
|
|
if ( ThisNode->pApplySecurityDescriptor != NULL &&
|
|
ThisNode->pApplySecurityDescriptor != ThisNode->pSecurityDescriptor ) {
|
|
|
|
NtStatus = RtlDeleteSecurityObject(
|
|
&(ThisNode->pApplySecurityDescriptor)
|
|
);
|
|
ThisNode->pApplySecurityDescriptor = NULL;
|
|
}
|
|
|
|
if (!bFreeComputedSDOnly) {
|
|
|
|
if ( ThisNode->pSecurityDescriptor != NULL )
|
|
ScepFree(ThisNode->pSecurityDescriptor);
|
|
|
|
if ( ThisNode->Name != NULL)
|
|
ScepFree(ThisNode->Name);
|
|
|
|
if ( ThisNode->ObjectFullName != NULL )
|
|
ScepFree(ThisNode->ObjectFullName);
|
|
|
|
if ( ThisNode->aChildNames != NULL ) {
|
|
LocalFree(ThisNode->aChildNames);
|
|
}
|
|
|
|
ScepFree(ThisNode);
|
|
}
|
|
|
|
}
|
|
|
|
pTemp1 = pTemp;
|
|
pTemp = pTemp->Next;
|
|
|
|
if (!bFreeComputedSDOnly) {
|
|
ScepFree(pTemp1);
|
|
}
|
|
}
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepSetSecurityWin32(
|
|
IN PCWSTR ObjectName,
|
|
IN SECURITY_INFORMATION SeInfo,
|
|
IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|
IN SE_OBJECT_TYPE ObjectType
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine set security information to the object and inherited aces
|
|
are set to the object's children by calling Win32 API SetNamedSecurityInfo
|
|
|
|
|
|
Arguments:
|
|
|
|
ObjecName - name of the object to set security to
|
|
|
|
SeInfo - Security information to set
|
|
|
|
pSecurityDescriptor - the security descriptor
|
|
|
|
ObjectType - type of the object
|
|
SE_FILE_OBJECT
|
|
SE_REGISTRY_KEY
|
|
SE_DS_OBJECT
|
|
|
|
Return value:
|
|
|
|
Win32 error code
|
|
|
|
-- */
|
|
{
|
|
|
|
if ( !ObjectName || !pSecurityDescriptor || SeInfo == 0 ) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
DWORD Win32rc = NO_ERROR;
|
|
SECURITY_INFORMATION SeInfoSet;
|
|
|
|
|
|
BOOLEAN tFlag;
|
|
BOOLEAN aclPresent;
|
|
PSID pOwner=NULL;
|
|
PSID pGroup=NULL;
|
|
PACL pDacl=NULL;
|
|
PACL pSacl=NULL;
|
|
SECURITY_DESCRIPTOR_CONTROL Control=0;
|
|
|
|
if ( pSecurityDescriptor != NULL ) {
|
|
|
|
RtlGetControlSecurityDescriptor (
|
|
pSecurityDescriptor,
|
|
&Control,
|
|
&Win32rc // temp use
|
|
);
|
|
//
|
|
// Get Owner address
|
|
// always get the owner in case take ownership occurs
|
|
//
|
|
Win32rc = RtlNtStatusToDosError(
|
|
RtlGetOwnerSecurityDescriptor(
|
|
pSecurityDescriptor,
|
|
&pOwner,
|
|
&tFlag));
|
|
#if 0
|
|
//
|
|
// Get Group address
|
|
//
|
|
|
|
if ( SeInfo & GROUP_SECURITY_INFORMATION ) {
|
|
Win32rc = RtlNtStatusToDosError(
|
|
RtlGetGroupSecurityDescriptor(
|
|
pSecurityDescriptor,
|
|
&pGroup,
|
|
&tFlag));
|
|
}
|
|
#endif
|
|
//
|
|
// Get DACL address
|
|
//
|
|
|
|
if ( SeInfo & DACL_SECURITY_INFORMATION ) {
|
|
Win32rc = RtlNtStatusToDosError(
|
|
RtlGetDaclSecurityDescriptor(
|
|
pSecurityDescriptor,
|
|
&aclPresent,
|
|
&pDacl,
|
|
&tFlag));
|
|
if (Win32rc == NO_ERROR && !aclPresent )
|
|
pDacl = NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Get SACL address
|
|
//
|
|
|
|
if ( SeInfo & SACL_SECURITY_INFORMATION ) {
|
|
Win32rc = RtlNtStatusToDosError(
|
|
RtlGetSaclSecurityDescriptor(
|
|
pSecurityDescriptor,
|
|
&aclPresent,
|
|
&pSacl,
|
|
&tFlag));
|
|
if ( Win32rc == NO_ERROR && !aclPresent )
|
|
pSacl = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// if error occurs for this one, do not set. return
|
|
//
|
|
|
|
if ( Win32rc != NO_ERROR ) {
|
|
|
|
ScepLogOutput3(1, Win32rc, SCEDLL_INVALID_SECURITY, (PWSTR)ObjectName );
|
|
return(Win32rc);
|
|
}
|
|
//
|
|
// set permission
|
|
//
|
|
#ifdef SCE_DBG
|
|
printf("Calling SetNamedSecurityInfo:\n");
|
|
ScepPrintSecurityDescriptor( pSecurityDescriptor, TRUE );
|
|
#endif
|
|
//
|
|
// should set owner/group separately from dacl/sacl
|
|
// if access is denied, take ownership will occur.
|
|
//
|
|
|
|
if ( Win32rc != NO_ERROR ) {
|
|
//
|
|
// ignore the error code from setting owner/group
|
|
//
|
|
Win32rc = NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// set DACL/SACL
|
|
//
|
|
SeInfoSet = 0;
|
|
|
|
if ( (SeInfo & DACL_SECURITY_INFORMATION) && pDacl ) {
|
|
|
|
SeInfoSet |= DACL_SECURITY_INFORMATION;
|
|
|
|
if ( Control & SE_DACL_PROTECTED ) {
|
|
SeInfoSet |= PROTECTED_DACL_SECURITY_INFORMATION;
|
|
}
|
|
}
|
|
|
|
if ( (SeInfo & SACL_SECURITY_INFORMATION) && pSacl ) {
|
|
|
|
SeInfoSet |= SACL_SECURITY_INFORMATION;
|
|
|
|
if ( Control & SE_SACL_PROTECTED ) {
|
|
SeInfoSet |= PROTECTED_SACL_SECURITY_INFORMATION;
|
|
}
|
|
}
|
|
|
|
Win32rc = SetNamedSecurityInfo(
|
|
(LPWSTR)ObjectName,
|
|
ObjectType,
|
|
SeInfoSet,
|
|
NULL,
|
|
NULL,
|
|
pDacl,
|
|
pSacl
|
|
);
|
|
|
|
if ( (Win32rc == ERROR_ACCESS_DENIED || Win32rc == ERROR_CANT_ACCESS_FILE) && NULL != AdminsSid ) {
|
|
//
|
|
// access denied, take ownership and then set
|
|
// should backup the old owner first
|
|
// NOTE: the old owner of this object is already stored in pOwner
|
|
// (pSecurityDescritor) which is queried from ScepGetNewSecurity(...
|
|
//
|
|
|
|
ScepLogOutput3(3,0, SCEDLL_SCP_TAKE_OWNER, (LPWSTR)ObjectName);
|
|
|
|
Win32rc = SetNamedSecurityInfo(
|
|
(LPWSTR)ObjectName,
|
|
ObjectType,
|
|
OWNER_SECURITY_INFORMATION,
|
|
AdminsSid,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if ( Win32rc == NO_ERROR ) {
|
|
//
|
|
// ownership is changed, then set security again
|
|
//
|
|
Win32rc = SetNamedSecurityInfo(
|
|
(LPWSTR)ObjectName,
|
|
ObjectType,
|
|
SeInfoSet,
|
|
NULL,
|
|
NULL,
|
|
pDacl,
|
|
pSacl
|
|
);
|
|
|
|
//
|
|
// set the old owner back (later)
|
|
//
|
|
} else {
|
|
|
|
ScepLogOutput3(2,Win32rc, SCEDLL_ERROR_TAKE_OWNER, (LPWSTR)ObjectName);
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// no takeownership action is taken
|
|
//
|
|
if ( !(SeInfo & OWNER_SECURITY_INFORMATION) ) {
|
|
pOwner = NULL;
|
|
}
|
|
}
|
|
|
|
if ( Win32rc != NO_ERROR ) {
|
|
ScepLogOutput3(1, Win32rc, SCEDLL_ERROR_SET_SECURITY,
|
|
(PWSTR)ObjectName );
|
|
} else {
|
|
|
|
if ( pOwner != NULL || pGroup != NULL ) {
|
|
if ( pOwner != NULL )
|
|
SeInfoSet = OWNER_SECURITY_INFORMATION;
|
|
else
|
|
SeInfoSet = 0;
|
|
if ( pGroup != NULL )
|
|
SeInfoSet |= GROUP_SECURITY_INFORMATION;
|
|
|
|
Win32rc = SetNamedSecurityInfo(
|
|
(LPWSTR)ObjectName,
|
|
ObjectType,
|
|
SeInfoSet,
|
|
pOwner,
|
|
pGroup,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
#if 0
|
|
|
|
#ifdef SCE_DBG
|
|
printf("Calling SetNamedSecurityInfoEx:\n");
|
|
ScepPrintSecurityDescriptor( pSecurityDescriptor, TRUE );
|
|
#endif
|
|
|
|
//
|
|
// convert to the new structure
|
|
//
|
|
PACTRL_ACCESS pAccess=NULL;
|
|
PACTRL_AUDIT pAudit=NULL;
|
|
LPWSTR pOwner=NULL;
|
|
LPWSTR pGroup=NULL;
|
|
|
|
Win32rc = ConvertSecurityDescriptorToAccessNamed(
|
|
ObjectName,
|
|
ObjectType,
|
|
pSecurityDescriptor,
|
|
&pAccess,
|
|
&pAudit,
|
|
&pOwner,
|
|
&pGroup
|
|
);
|
|
|
|
if ( Win32rc == ERROR_SUCCESS ) {
|
|
|
|
//
|
|
// set DACL/SACL
|
|
//
|
|
SeInfoSet = (SeInfo & DACL_SECURITY_INFORMATION) |
|
|
(SeInfo & SACL_SECURITY_INFORMATION);
|
|
|
|
Win32rc = SetNamedSecurityInfoEx(
|
|
ObjectName,
|
|
ObjectType,
|
|
SeInfoSet,
|
|
NULL,
|
|
pAccess,
|
|
pAudit,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if ( (Win32rc == ERROR_ACCESS_DENIED || Win32rc == ERROR_CANT_ACCESS_FILE) && NULL != AdminsSid ) {
|
|
//
|
|
// access denied, take ownership and then set
|
|
// should backup the old owner first
|
|
// NOTE: the old owner of this object is already stored in pOwner
|
|
// (pSecurityDescritor) which is queried from ScepGetNewSecurity(...
|
|
//
|
|
|
|
ScepLogOutput3(3,0, SCEDLL_SCP_TAKE_OWNER, (LPWSTR)ObjectName);
|
|
|
|
Win32rc = SetNamedSecurityInfo(
|
|
(LPWSTR)ObjectName,
|
|
ObjectType,
|
|
OWNER_SECURITY_INFORMATION,
|
|
AdminsSid,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if ( Win32rc == NO_ERROR ) {
|
|
//
|
|
// ownership is changed, then set security again
|
|
//
|
|
Win32rc = SetNamedSecurityInfoEx(
|
|
ObjectName,
|
|
ObjectType,
|
|
SeInfoSet,
|
|
NULL,
|
|
pAccess,
|
|
pAudit,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// set the old owner back (later)
|
|
//
|
|
} else {
|
|
|
|
ScepLogOutput3(2,Win32rc, SCEDLL_ERROR_TAKE_OWNER, (LPWSTR)ObjectName);
|
|
}
|
|
}
|
|
|
|
if ( Win32rc != NO_ERROR ) {
|
|
ScepLogOutput3(1, Win32rc, SCEDLL_ERROR_SET_SECURITY,
|
|
(PWSTR)ObjectName );
|
|
} else {
|
|
|
|
if ( pOwner != NULL || pGroup != NULL ) {
|
|
if ( pOwner != NULL )
|
|
SeInfoSet = OWNER_SECURITY_INFORMATION;
|
|
else
|
|
SeInfoSet = 0;
|
|
if ( pGroup != NULL )
|
|
SeInfoSet |= GROUP_SECURITY_INFORMATION;
|
|
|
|
Win32rc = SetNamedSecurityInfoEx(
|
|
ObjectName,
|
|
ObjectType,
|
|
SeInfoSet,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
pOwner,
|
|
pGroup,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if ( pAccess ) {
|
|
LocalFree(pAccess);
|
|
}
|
|
|
|
if ( pAudit ) {
|
|
LocalFree(pAudit);
|
|
}
|
|
|
|
if ( pGroup ) {
|
|
LocalFree(pGroup);
|
|
}
|
|
|
|
if ( pOwner ) {
|
|
LocalFree(pOwner);
|
|
}
|
|
#endif
|
|
*/
|
|
|
|
if (Win32rc == ERROR_FILE_NOT_FOUND ||
|
|
Win32rc == ERROR_PATH_NOT_FOUND ||
|
|
Win32rc == ERROR_SHARING_VIOLATION ||
|
|
Win32rc == ERROR_ACCESS_DENIED ||
|
|
Win32rc == ERROR_CANT_ACCESS_FILE ||
|
|
Win32rc == ERROR_INVALID_HANDLE ) {
|
|
|
|
gWarningCode = Win32rc;
|
|
|
|
Win32rc = NO_ERROR;
|
|
}
|
|
|
|
return(Win32rc);
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepSetSecurityOverwriteExplicit(
|
|
IN PCWSTR pszRootObjectName,
|
|
IN SECURITY_INFORMATION SeInfo,
|
|
IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN HANDLE Token,
|
|
IN PGENERIC_MAPPING GenericMapping
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
This routine will set security to the current object and all children.
|
|
By calling this function, the existing security descriptor for all children
|
|
will be totally replaced by pSecurityDescriptor if it is a container, or by
|
|
pObjectSecurity if it is a file object.
|
|
|
|
The difference between this function and SetNamedSecurityInfo is that
|
|
SetNamedSecurityInfo only overwrites the inherited aces for all children
|
|
but not the explicit aces.
|
|
|
|
Arguments:
|
|
|
|
ObjectName - The container object's name
|
|
|
|
SeInfo - Security Information to set
|
|
|
|
pSecurityDescriptor - Security descriptor for container type objects
|
|
|
|
ObjectType - The object type
|
|
SE_FILE_OBJECT
|
|
SE_REGISTRY_KEY
|
|
|
|
Return Value:
|
|
|
|
Win32 error codes
|
|
*/
|
|
{
|
|
|
|
PSCEP_STACK_NODE pStackHead = NULL;
|
|
DWORD rc;
|
|
BOOL bPushedOntoStack = FALSE;
|
|
|
|
//
|
|
// for file objects - to avoid excessive heap operations
|
|
//
|
|
struct _wfinddata_t FileInfo = {0};
|
|
|
|
//
|
|
// for registry objects - to avoid excessive heap operations
|
|
//
|
|
|
|
WCHAR Buffer1[261];
|
|
PWSTR ObjectName = NULL;
|
|
|
|
Buffer1[0] = L'\0';
|
|
|
|
rc = ScepStackNodePush(&pStackHead,
|
|
(PWSTR)pszRootObjectName,
|
|
pSecurityDescriptor);
|
|
|
|
if (rc == ERROR_SUCCESS ) {
|
|
|
|
while (pStackHead) {
|
|
|
|
ScepStackNodePop(&pStackHead,
|
|
&ObjectName,
|
|
&pSecurityDescriptor);
|
|
|
|
#ifdef SCE_DBG
|
|
ScepDumpStack(&pStackHead);
|
|
#endif
|
|
|
|
BOOL bHasChild=FALSE;
|
|
|
|
//
|
|
// set security to the current object first
|
|
//
|
|
#ifdef _WIN64
|
|
rc = ScepSetSecurityObjectOnly(
|
|
ObjectName,
|
|
SeInfo,
|
|
pSecurityDescriptor,
|
|
ObjectType,
|
|
(ObjectType == SE_REGISTRY_KEY || ObjectType == SE_REGISTRY_WOW64_32KEY) ? &bHasChild : NULL
|
|
);
|
|
#else
|
|
rc = ScepSetSecurityObjectOnly(
|
|
ObjectName,
|
|
SeInfo,
|
|
pSecurityDescriptor,
|
|
ObjectType,
|
|
(ObjectType == SE_REGISTRY_KEY) ? &bHasChild : NULL
|
|
);
|
|
#endif
|
|
|
|
if ( rc == ERROR_ACCESS_DENIED ||
|
|
rc == ERROR_CANT_ACCESS_FILE ||
|
|
rc == ERROR_FILE_NOT_FOUND ||
|
|
rc == ERROR_PATH_NOT_FOUND ||
|
|
rc == ERROR_SHARING_VIOLATION ||
|
|
rc == ERROR_INVALID_HANDLE ) {
|
|
|
|
gWarningCode = rc;
|
|
|
|
|
|
if (ObjectName != pszRootObjectName) {
|
|
|
|
ScepFree(ObjectName);
|
|
ObjectName = NULL;
|
|
|
|
if (pSecurityDescriptor) {
|
|
RtlDeleteSecurityObject( &pSecurityDescriptor );
|
|
pSecurityDescriptor = NULL;
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if ( rc != ERROR_SUCCESS )
|
|
break;
|
|
|
|
PWSTR Buffer=NULL;
|
|
DWORD BufSize;
|
|
PSECURITY_DESCRIPTOR pObjectSecurity=NULL;
|
|
|
|
|
|
switch ( ObjectType ) {
|
|
case SE_FILE_OBJECT:
|
|
|
|
//
|
|
// find all files under this directory/file
|
|
//
|
|
BufSize = wcslen(ObjectName)+4;
|
|
Buffer = (PWSTR)ScepAlloc( 0, (BufSize+1)*sizeof(WCHAR));
|
|
if ( Buffer == NULL ) {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
swprintf(Buffer, L"%s\\*.*", ObjectName);
|
|
|
|
intptr_t hFile;
|
|
|
|
hFile = _wfindfirst(Buffer, &FileInfo);
|
|
|
|
ScepFree(Buffer);
|
|
Buffer = NULL;
|
|
|
|
if ( hFile != -1 ) {
|
|
|
|
do {
|
|
if ( FileInfo.name[0] == L'.')
|
|
continue;
|
|
|
|
//
|
|
// build the full name for this object
|
|
//
|
|
BufSize = wcslen(ObjectName)+wcslen(FileInfo.name)+1;
|
|
Buffer = (PWSTR)ScepAlloc( 0, (BufSize+1)*sizeof(WCHAR));
|
|
if ( Buffer == NULL ) {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
swprintf(Buffer, L"%s\\%s", ObjectName, FileInfo.name);
|
|
|
|
//
|
|
// compute the new security descriptor because
|
|
// different objects may have different owner and
|
|
// the creator owner ace must be translated correctly
|
|
//
|
|
|
|
rc = ScepGetNewSecurity(
|
|
Buffer,
|
|
pSecurityDescriptor, // parent's SD
|
|
NULL, // object SD
|
|
0, // does not query current object SD
|
|
(BOOLEAN)(FileInfo.attrib & _A_SUBDIR ),
|
|
SeInfo,
|
|
ObjectType,
|
|
Token,
|
|
GenericMapping,
|
|
&pObjectSecurity
|
|
);
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
|
|
if ( FileInfo.attrib & _A_SUBDIR ) {
|
|
|
|
|
|
//
|
|
// enumerate all nodes under this one and "empty" explicit aces by
|
|
// calling NtSetSecurityInfo directly
|
|
//
|
|
/*rc = ScepSetSecurityOverwriteExplicit(
|
|
Buffer,
|
|
SeInfo,
|
|
pObjectSecurity,
|
|
ObjectType,
|
|
Token,
|
|
GenericMapping
|
|
);*/
|
|
|
|
rc = ScepStackNodePush(&pStackHead,
|
|
Buffer,
|
|
pObjectSecurity);
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
bPushedOntoStack = TRUE;
|
|
|
|
} else {
|
|
//
|
|
// this is a file. Set the file security descriptor to this object
|
|
// using NT api
|
|
//
|
|
rc = ScepSetSecurityObjectOnly(
|
|
Buffer,
|
|
SeInfo,
|
|
pObjectSecurity,
|
|
ObjectType,
|
|
NULL
|
|
);
|
|
if ( rc == ERROR_ACCESS_DENIED ||
|
|
rc == ERROR_CANT_ACCESS_FILE ||
|
|
rc == ERROR_FILE_NOT_FOUND ||
|
|
rc == ERROR_PATH_NOT_FOUND ||
|
|
rc == ERROR_SHARING_VIOLATION ||
|
|
rc == ERROR_INVALID_HANDLE ) {
|
|
|
|
gWarningCode = rc;
|
|
rc = NO_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !bPushedOntoStack ) {
|
|
|
|
if (pObjectSecurity) {
|
|
RtlDeleteSecurityObject( &pObjectSecurity );
|
|
pObjectSecurity = NULL;
|
|
}
|
|
|
|
if (Buffer) {
|
|
ScepFree(Buffer);
|
|
Buffer = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
bPushedOntoStack = FALSE;
|
|
|
|
|
|
if ( rc != ERROR_SUCCESS )
|
|
break;
|
|
|
|
} while ( _wfindnext(hFile, &FileInfo) == 0 );
|
|
|
|
_findclose(hFile);
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_REGISTRY_KEY:
|
|
#ifdef _WIN64
|
|
case SE_REGISTRY_WOW64_32KEY:
|
|
#endif
|
|
|
|
if ( bHasChild ) {
|
|
|
|
HKEY hKey;
|
|
|
|
//
|
|
// open the key
|
|
//
|
|
rc = ScepOpenRegistryObject(
|
|
ObjectType,
|
|
(LPWSTR)ObjectName,
|
|
KEY_READ,
|
|
&hKey
|
|
);
|
|
|
|
if ( rc == ERROR_SUCCESS ) {
|
|
|
|
DWORD SubKeyLen;
|
|
DWORD cSubKeys;
|
|
|
|
cSubKeys = 0;
|
|
|
|
rc = RegQueryInfoKey (
|
|
hKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&cSubKeys,
|
|
&SubKeyLen,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if ( rc != NO_ERROR ) {
|
|
|
|
ScepLogOutput3(1, rc, SCEDLL_ERROR_QUERY_INFO, (PWSTR)ObjectName );
|
|
|
|
cSubKeys = 0;
|
|
SubKeyLen = 0;
|
|
|
|
rc = NO_ERROR;
|
|
}
|
|
|
|
if ( cSubKeys && SubKeyLen ) {
|
|
|
|
DWORD index;
|
|
DWORD EnumRc;
|
|
|
|
index = 0;
|
|
//
|
|
// enumerate all subkeys of the key
|
|
//
|
|
|
|
do {
|
|
BufSize = 260;
|
|
|
|
EnumRc = RegEnumKeyEx(hKey,
|
|
index,
|
|
Buffer1,
|
|
&BufSize,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
|
|
if ( EnumRc == ERROR_SUCCESS ) {
|
|
index++;
|
|
|
|
BufSize += wcslen(ObjectName)+1;
|
|
Buffer = (PWSTR)ScepAlloc( 0, (BufSize+1)*sizeof(WCHAR));
|
|
if ( Buffer == NULL ) {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
swprintf(Buffer, L"%s\\%s", ObjectName, Buffer1);
|
|
|
|
//
|
|
// compute the new security descriptor because
|
|
// different objects may have different owner and
|
|
// the creator owner ace must be translated correctly
|
|
//
|
|
|
|
rc = ScepGetNewSecurity(
|
|
Buffer,
|
|
pSecurityDescriptor, // parent's SD
|
|
NULL, // object SD
|
|
0, // does not query current object SD
|
|
(BOOLEAN)TRUE,
|
|
SeInfo,
|
|
ObjectType,
|
|
Token,
|
|
GenericMapping,
|
|
&pObjectSecurity
|
|
);
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
|
|
//
|
|
// enumerate all nodes under this one and "empty" explicit aces by
|
|
// calling NtSetSecurityInfo directly
|
|
//
|
|
/*rc = ScepSetSecurityOverwriteExplicit(
|
|
Buffer,
|
|
SeInfo,
|
|
pObjectSecurity,
|
|
ObjectType,
|
|
Token,
|
|
GenericMapping
|
|
);*/
|
|
|
|
rc = ScepStackNodePush(&pStackHead,
|
|
Buffer,
|
|
pObjectSecurity);
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
bPushedOntoStack = TRUE;
|
|
|
|
|
|
}
|
|
|
|
if ( rc != ERROR_SUCCESS )
|
|
ScepLogOutput3(1, rc, SCEDLL_ERROR_SET_SECURITY, Buffer);
|
|
|
|
if ( !bPushedOntoStack ) {
|
|
|
|
if ( pObjectSecurity ) {
|
|
|
|
RtlDeleteSecurityObject( &pObjectSecurity );
|
|
pObjectSecurity = NULL;
|
|
}
|
|
|
|
ScepFree(Buffer);
|
|
Buffer = NULL;
|
|
}
|
|
|
|
bPushedOntoStack = FALSE;
|
|
|
|
if ( rc != ERROR_SUCCESS )
|
|
break;
|
|
|
|
} else if ( EnumRc != ERROR_NO_MORE_ITEMS ) {
|
|
break;
|
|
}
|
|
|
|
} while ( EnumRc != ERROR_NO_MORE_ITEMS );
|
|
|
|
if ( EnumRc != ERROR_SUCCESS && EnumRc != ERROR_NO_MORE_ITEMS ) {
|
|
ScepLogOutput3(1, EnumRc, SCEDLL_SAP_ERROR_ENUMERATE, (PWSTR)ObjectName );
|
|
if ( rc == ERROR_SUCCESS )
|
|
rc = EnumRc;
|
|
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
} else
|
|
ScepLogOutput3(1, rc, SCEDLL_ERROR_OPEN, (PWSTR)ObjectName );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (ObjectName != pszRootObjectName) {
|
|
|
|
ScepFree(ObjectName);
|
|
ObjectName = NULL;
|
|
|
|
if (pSecurityDescriptor) {
|
|
RtlDeleteSecurityObject( &pSecurityDescriptor );
|
|
pSecurityDescriptor = NULL;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if ( rc != ERROR_SUCCESS ) {
|
|
ScepFreeStack(&pStackHead);
|
|
}
|
|
|
|
}
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
VOID
|
|
ScepFreeStack(
|
|
IN PSCEP_STACK_NODE *ppStackHead
|
|
)
|
|
{
|
|
if (ppStackHead == NULL || *ppStackHead == NULL )
|
|
return;
|
|
|
|
PSCEP_STACK_NODE pNode;
|
|
|
|
while ( pNode = *ppStackHead ) {
|
|
ScepFree( pNode->Buffer );
|
|
RtlDeleteSecurityObject( &(pNode->pObjectSecurity) );
|
|
*ppStackHead = pNode->Next;
|
|
LocalFree(pNode);
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
ScepDumpStack(
|
|
IN PSCEP_STACK_NODE *ppStackHead
|
|
)
|
|
{
|
|
if (ppStackHead == NULL || *ppStackHead == NULL )
|
|
return;
|
|
|
|
PSCEP_STACK_NODE pNode = *ppStackHead;
|
|
|
|
wprintf(L"\n >>>>>>>>> Stack contents");
|
|
|
|
while ( pNode ) {
|
|
if ( pNode->Buffer)
|
|
wprintf(L"\n %s", pNode->Buffer );
|
|
pNode = pNode->Next;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepStackNodePush(
|
|
IN PSCEP_STACK_NODE *ppStackHead,
|
|
IN PWSTR pszObjectName,
|
|
IN PSECURITY_DESCRIPTOR pSecurityDescriptor
|
|
)
|
|
{
|
|
|
|
if (ppStackHead == NULL) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
PSCEP_STACK_NODE pNode = (PSCEP_STACK_NODE) LocalAlloc(LMEM_ZEROINIT, sizeof(SCEP_STACK_NODE));
|
|
|
|
if ( pNode == NULL )
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
pNode->Buffer = pszObjectName;
|
|
pNode->pObjectSecurity = pSecurityDescriptor;
|
|
pNode->Next = *ppStackHead;
|
|
*ppStackHead = pNode;
|
|
|
|
#ifdef SCE_DBG
|
|
gDbgNumPushed ++;
|
|
#endif
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
VOID
|
|
ScepStackNodePop(
|
|
IN OUT PSCEP_STACK_NODE *ppStackHead,
|
|
IN OUT PWSTR *ppszObjectName,
|
|
IN OUT PSECURITY_DESCRIPTOR *ppSecurityDescriptor
|
|
)
|
|
{
|
|
if (ppStackHead == NULL ||
|
|
*ppStackHead == NULL ||
|
|
ppszObjectName == NULL ||
|
|
ppSecurityDescriptor == NULL )
|
|
return;
|
|
|
|
PSCEP_STACK_NODE pNode = *ppStackHead;
|
|
|
|
*ppszObjectName = pNode->Buffer;
|
|
*ppSecurityDescriptor = pNode->pObjectSecurity;
|
|
*ppStackHead = pNode->Next;
|
|
|
|
LocalFree(pNode);
|
|
|
|
#ifdef SCE_DBG
|
|
gDbgNumPopped ++;
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepSetSecurityObjectOnly(
|
|
IN PCWSTR ObjectName,
|
|
IN SECURITY_INFORMATION SeInfo,
|
|
IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
OUT PBOOL pbHasChild
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine set security information to the object only. Security
|
|
for children of this object is not set.
|
|
|
|
Arguments:
|
|
|
|
ObjecName - name of the object to set security to
|
|
|
|
SeInfo - Security information to set
|
|
|
|
pSecurityDescriptor - the security descriptor
|
|
|
|
ObjectType - type of the object (FILE, REGISTRY, ...)
|
|
|
|
Return value:
|
|
|
|
Win32 error code
|
|
|
|
-- */
|
|
{
|
|
DWORD rc=ERROR_SUCCESS;
|
|
HANDLE Handle=NULL;
|
|
NTSTATUS NtStatus;
|
|
DWORD cSubKeys;
|
|
SECURITY_INFORMATION SeInfoToSet=0;
|
|
SECURITY_DESCRIPTOR SD;
|
|
|
|
#ifdef SCE_DBG
|
|
UCHAR psdbuffer[1024];
|
|
PISECURITY_DESCRIPTOR psecuritydescriptor = (PISECURITY_DESCRIPTOR) psdbuffer;
|
|
ULONG bytesneeded = 0;
|
|
ULONG newbytesneeded;
|
|
|
|
printf("Before calling NtSetSecurityObject:\n");
|
|
ScepPrintSecurityDescriptor( pSecurityDescriptor, TRUE );
|
|
#endif
|
|
|
|
//
|
|
// make a absolute format security descriptor which only contains AdminsSid
|
|
// as the owner.
|
|
//
|
|
|
|
switch ( ObjectType ) {
|
|
case SE_FILE_OBJECT:
|
|
//
|
|
// open file object. If it can't be opend due to access denied,
|
|
// take ownership then open again.
|
|
//
|
|
rc = ScepOpenFileObject(
|
|
(LPWSTR)ObjectName,
|
|
ScepGetDesiredAccess(MODIFY_ACCESS_RIGHTS, SeInfo),
|
|
&Handle
|
|
);
|
|
|
|
if ( (rc == ERROR_ACCESS_DENIED || rc == ERROR_CANT_ACCESS_FILE) && NULL != AdminsSid ) {
|
|
//
|
|
// open with access to set owner
|
|
//
|
|
ScepLogOutput3(3,0, SCEDLL_SCP_TAKE_OWNER, (LPWSTR)ObjectName);
|
|
|
|
rc = ScepOpenFileObject(
|
|
(LPWSTR)ObjectName,
|
|
ScepGetDesiredAccess(WRITE_ACCESS_RIGHTS, OWNER_SECURITY_INFORMATION),
|
|
&Handle
|
|
);
|
|
if ( rc == ERROR_SUCCESS ) {
|
|
//
|
|
// make a absolute format of security descriptor
|
|
// to set owner with
|
|
// if error occurs, continue
|
|
//
|
|
|
|
NtStatus = RtlCreateSecurityDescriptor( &SD,
|
|
SECURITY_DESCRIPTOR_REVISION );
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
NtStatus = RtlSetOwnerSecurityDescriptor (
|
|
&SD,
|
|
AdminsSid,
|
|
FALSE
|
|
);
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
NtStatus = NtSetSecurityObject(
|
|
Handle,
|
|
OWNER_SECURITY_INFORMATION,
|
|
&SD
|
|
);
|
|
}
|
|
}
|
|
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
|
|
CloseHandle(Handle);
|
|
|
|
if ( rc == ERROR_SUCCESS ) {
|
|
|
|
//
|
|
// old owner of the object is already stored in the security descriptor
|
|
// passed in, which is created from ScepGetNewSecurity...
|
|
//
|
|
SeInfoToSet = OWNER_SECURITY_INFORMATION;
|
|
|
|
//
|
|
// re-open the file
|
|
//
|
|
rc = ScepOpenFileObject(
|
|
(LPWSTR)ObjectName,
|
|
ScepGetDesiredAccess(MODIFY_ACCESS_RIGHTS, SeInfoToSet | SeInfo), //SeInfo),
|
|
&Handle
|
|
);
|
|
}
|
|
}
|
|
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
ScepLogOutput3(2, rc, SCEDLL_ERROR_TAKE_OWNER, (PWSTR)ObjectName );
|
|
}
|
|
}
|
|
|
|
if (rc == ERROR_SUCCESS ) {
|
|
|
|
//
|
|
// set security to this object
|
|
//
|
|
|
|
SeInfoToSet |= SeInfo;
|
|
ScepAddAutoInheritRequest(pSecurityDescriptor, &SeInfoToSet);
|
|
|
|
NtStatus = NtSetSecurityObject(
|
|
Handle,
|
|
SeInfoToSet,
|
|
pSecurityDescriptor
|
|
);
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
|
|
#ifdef SCE_DBG
|
|
if ( rc == NO_ERROR ) {
|
|
|
|
printf("After calling NtSetSecurityObject:\n");
|
|
|
|
NtStatus = NtQuerySecurityObject( Handle,
|
|
SeInfo,
|
|
psecuritydescriptor,
|
|
1024,
|
|
&bytesneeded);
|
|
|
|
if (STATUS_BUFFER_TOO_SMALL == NtStatus)
|
|
{
|
|
if (NULL != (psecuritydescriptor = (PISECURITY_DESCRIPTOR)
|
|
ScepAlloc(LMEM_ZEROINIT, bytesneeded) ))
|
|
|
|
NtStatus = NtQuerySecurityObject(Handle,
|
|
SeInfo,
|
|
psecuritydescriptor,
|
|
bytesneeded,
|
|
&newbytesneeded);
|
|
}
|
|
if (NT_SUCCESS(NtStatus)) {
|
|
ScepPrintSecurityDescriptor( (PSECURITY_DESCRIPTOR)psecuritydescriptor, TRUE );
|
|
} else
|
|
printf("error occurs: %x\n", NtStatus);
|
|
|
|
if (bytesneeded > 1024)
|
|
ScepFree(psecuritydescriptor);
|
|
|
|
}
|
|
#endif
|
|
CloseHandle(Handle);
|
|
}
|
|
|
|
if ( rc == ERROR_SUCCESS && pbHasChild != NULL ) {
|
|
ScepDoesObjectHasChildren(ObjectType, (PWSTR)ObjectName, pbHasChild);
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_REGISTRY_KEY:
|
|
#ifdef _WIN64
|
|
case SE_REGISTRY_WOW64_32KEY:
|
|
#endif
|
|
//
|
|
// open registry object. If it can't be opened due to access denied,
|
|
// take ownership then open again.
|
|
//
|
|
rc = ScepOpenRegistryObject(
|
|
ObjectType,
|
|
(LPWSTR)ObjectName,
|
|
ScepGetDesiredAccess(WRITE_ACCESS_RIGHTS, SeInfo),
|
|
(PHKEY)&Handle
|
|
);
|
|
|
|
if ( (rc == ERROR_ACCESS_DENIED || rc == ERROR_CANT_ACCESS_FILE) && NULL != AdminsSid ) {
|
|
|
|
ScepLogOutput3(3,0, SCEDLL_SCP_TAKE_OWNER, (LPWSTR)ObjectName);
|
|
|
|
//
|
|
// open registry object with access to set owner
|
|
//
|
|
rc = ScepOpenRegistryObject(
|
|
ObjectType,
|
|
(LPWSTR)ObjectName,
|
|
ScepGetDesiredAccess(WRITE_ACCESS_RIGHTS, OWNER_SECURITY_INFORMATION),
|
|
(PHKEY)&Handle
|
|
);
|
|
if ( rc == ERROR_SUCCESS ) {
|
|
//
|
|
// make a absolute format of security descriptor
|
|
// to set owner with
|
|
// if error occurs, continue
|
|
//
|
|
|
|
NtStatus = RtlCreateSecurityDescriptor( &SD,
|
|
SECURITY_DESCRIPTOR_REVISION );
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
NtStatus = RtlSetOwnerSecurityDescriptor (
|
|
&SD,
|
|
AdminsSid,
|
|
FALSE
|
|
);
|
|
}
|
|
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
rc = RegSetKeySecurity((HKEY)Handle,
|
|
OWNER_SECURITY_INFORMATION,
|
|
&SD);
|
|
|
|
} else {
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
}
|
|
|
|
RegCloseKey((HKEY)Handle);
|
|
|
|
if ( rc == ERROR_SUCCESS ) {
|
|
|
|
//
|
|
// old owner is already stored in the pSecurityDescriptor passed in
|
|
// which is created in ScepGetNewSecurity...
|
|
//
|
|
|
|
SeInfoToSet = OWNER_SECURITY_INFORMATION;
|
|
//
|
|
// re-open the registry key
|
|
//
|
|
rc = ScepOpenRegistryObject(
|
|
ObjectType,
|
|
(LPWSTR)ObjectName,
|
|
ScepGetDesiredAccess(WRITE_ACCESS_RIGHTS, SeInfoToSet | SeInfo),
|
|
(PHKEY)&Handle
|
|
);
|
|
}
|
|
}
|
|
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
|
|
ScepLogOutput3(2, rc, SCEDLL_ERROR_TAKE_OWNER, (PWSTR)ObjectName );
|
|
}
|
|
|
|
}
|
|
|
|
if (rc == ERROR_SUCCESS ) {
|
|
|
|
//
|
|
// set security to the registry key
|
|
//
|
|
SeInfoToSet |= SeInfo;
|
|
ScepAddAutoInheritRequest(pSecurityDescriptor, &SeInfoToSet);
|
|
|
|
rc = RegSetKeySecurity((HKEY)Handle,
|
|
SeInfoToSet,
|
|
pSecurityDescriptor);
|
|
|
|
RegCloseKey((HKEY)Handle);
|
|
|
|
//
|
|
// query key info for subkeys first
|
|
//
|
|
if ( ERROR_SUCCESS == rc && pbHasChild != NULL ) {
|
|
|
|
rc = ScepOpenRegistryObject(
|
|
ObjectType,
|
|
(LPWSTR)ObjectName,
|
|
KEY_READ,
|
|
(PHKEY)&Handle
|
|
);
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
|
|
cSubKeys = 0;
|
|
|
|
rc = RegQueryInfoKey (
|
|
(HKEY)Handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&cSubKeys,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
RegCloseKey((HKEY)Handle);
|
|
}
|
|
|
|
if ( rc != NO_ERROR ) {
|
|
|
|
ScepLogOutput3(1, rc, SCEDLL_ERROR_QUERY_INFO, (PWSTR)ObjectName );
|
|
|
|
cSubKeys = 0;
|
|
|
|
rc = NO_ERROR;
|
|
}
|
|
|
|
if (cSubKeys == 0 )
|
|
*pbHasChild = FALSE;
|
|
else
|
|
// ignore the error, just set has child.
|
|
//
|
|
*pbHasChild = TRUE;
|
|
|
|
}
|
|
|
|
} else
|
|
ScepLogOutput3(1, rc, SCEDLL_ERROR_OPEN, (PWSTR)ObjectName);
|
|
|
|
|
|
break;
|
|
}
|
|
|
|
if ( rc != NO_ERROR )
|
|
ScepLogOutput3(1, rc, SCEDLL_ERROR_SET_SECURITY, (PWSTR)ObjectName);
|
|
|
|
if ( rc == ERROR_INVALID_OWNER ||
|
|
rc == ERROR_INVALID_PRIMARY_GROUP ||
|
|
rc == ERROR_INVALID_SECURITY_DESCR )
|
|
rc = NO_ERROR;
|
|
|
|
return(rc);
|
|
}
|
|
|