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.
447 lines
14 KiB
447 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
shadowse.c
|
|
|
|
Abstract:
|
|
|
|
This module implements all security related functions for disconnected
|
|
operation of Client Side Caching
|
|
|
|
Revision History:
|
|
|
|
Balan Sethu Raman [SethuR] 6-October-1997
|
|
|
|
Notes:
|
|
|
|
In NT ACL(Access Control lists) provide the necessary mechanism for
|
|
denying/granting permissions to users. Each user is associated with a SID.
|
|
The ACLs are specified in terms of SIDs associated with groups of users as
|
|
well as individual users. Each user is associated with a token at runtime
|
|
which details the various groups a user is a member of and this token is
|
|
used to evaluate the ACLs. This is complicated by the fact that there are
|
|
local groups associated with various machines. Therefore the token/context
|
|
associated with an user varies from machine.
|
|
|
|
In connected mode the credentials associated with a given user are shipped
|
|
to the server where they are validated and the appropriate token created.
|
|
This token is used subsequently in the evaluation of ACLs.
|
|
|
|
This presents us with two options in implementing security for disconnected
|
|
operation -- lazy evaluation and eager evaluation. In lazy evaluation the
|
|
evaluation of ACLs is done on demand but the preparatory work for this
|
|
evaluation is done in connected mode. On the other hand in eager evaluation
|
|
the ACLs are evaluated and the maximal rights are stored as part of the CSC
|
|
database. These rights are used to determine the appropriate access.
|
|
|
|
The advantage of lazy evaluation is that the database is no longer constrained
|
|
by previous access requirements while in eager evaluation we require that the
|
|
user have accessed the file in connected mode in order to correctly determine
|
|
the rights in disconnected mode. The flip side is that Lazy Evaluation is
|
|
tougher to implement ( requires modifications in security/DS ) while the
|
|
eager evaluation implementation is very easy.
|
|
|
|
The current implementation corresponds to a simplified form of eager evaluation
|
|
strategy. Appropriate encapsulation has been provided to allow us to
|
|
swicth over to a lazy evaluation mode easily.
|
|
|
|
There are three facets of the implementation
|
|
|
|
1) Storing/Retreiving Access information
|
|
|
|
2) Denying/Granting access based upon the stored access information.
|
|
|
|
3) Persisting the SID/index mapping
|
|
|
|
Currently associated with each file/directory in the CSC database there is a
|
|
security blob. This blob is an in
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#pragma code_seg("PAGE")
|
|
|
|
DWORD
|
|
CscUpdateCachedSecurityInformation(
|
|
PCACHED_SECURITY_INFORMATION pCachedSecurityInformation,
|
|
ULONG CachedSecurityInformationLength,
|
|
ULONG NumberOfSids,
|
|
PCSC_SID_ACCESS_RIGHTS pSidAccessRights)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine updates the access rights for a given number of sids in the
|
|
given cached security information structure. This routine centralizes the
|
|
update process required for share level security as well as the object level
|
|
security into a single routine since the on disk format for both these
|
|
cases are the same. However, different APIs are required to update the
|
|
in memory data structures.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
pCachedSecurityInformation - the cached security information instance
|
|
|
|
CachedSecurityInformationLength - the length of the cached information
|
|
|
|
NumberOfSids - the number of sids for which the access rights needs to be
|
|
updated
|
|
|
|
pSidAccessRights - an array of the sids and the corresponding access rights.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful, otherwise appropriate error
|
|
|
|
Notes:
|
|
|
|
The current implementation of this routine is based upon the assumption that
|
|
the number of Sid mappings stored on a per file basis is very small ( 8 at most).
|
|
If this assumption is changed this routine needs to be reworked.
|
|
|
|
--*/
|
|
{
|
|
DWORD Status = ERROR_SUCCESS;
|
|
ULONG i,j,cntNewRights=0;
|
|
CACHED_SECURITY_INFORMATION NewSecurityInformation;
|
|
|
|
ASSERT(CachedSecurityInformationLength == sizeof(CACHED_SECURITY_INFORMATION));
|
|
|
|
if (NumberOfSids > CSC_MAXIMUM_NUMBER_OF_CACHED_SID_INDEXES) {
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
} else if (NumberOfSids == 0) {
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
// NB assumption, CSC_INVALID_INDEX is 0
|
|
memset(&NewSecurityInformation, 0, sizeof(NewSecurityInformation));
|
|
|
|
|
|
// from the array of new rights
|
|
for (i = 0; i < NumberOfSids; i++) {
|
|
CSC_SID_INDEX SidIndex;
|
|
|
|
// map the sid to a sid index
|
|
SidIndex = CscMapSidToIndex(
|
|
pSidAccessRights[i].pSid,
|
|
pSidAccessRights[i].SidLength);
|
|
|
|
if (SidIndex == CSC_INVALID_SID_INDEX) {
|
|
// Map the new sid
|
|
Status = CscAddSidToDatabase(
|
|
pSidAccessRights[i].pSid,
|
|
pSidAccessRights[i].SidLength,
|
|
&SidIndex);
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
}
|
|
|
|
NewSecurityInformation.AccessRights[i].SidIndex = SidIndex;
|
|
NewSecurityInformation.AccessRights[i].MaximalRights =
|
|
(USHORT)pSidAccessRights[i].MaximalAccessRights;
|
|
|
|
cntNewRights++;
|
|
}
|
|
|
|
// now copy the cached rights from old array for those sids which are not already
|
|
// there in the new array, till all slots in the new array are full
|
|
// this ensures a round robin scheme
|
|
|
|
ASSERT(cntNewRights && (cntNewRights <= CSC_MAXIMUM_NUMBER_OF_CACHED_SID_INDEXES));
|
|
|
|
for (i=0; i<CSC_MAXIMUM_NUMBER_OF_CACHED_SID_INDEXES; ++i)
|
|
{
|
|
// if all slots in the new array are filled up, break
|
|
if (cntNewRights==CSC_MAXIMUM_NUMBER_OF_CACHED_SID_INDEXES)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// if this is a valid sid index
|
|
if (pCachedSecurityInformation->AccessRights[i].SidIndex != CSC_INVALID_SID_INDEX)
|
|
{
|
|
BOOLEAN fFound;
|
|
|
|
fFound = FALSE;
|
|
|
|
// check if it is already there in the new array.
|
|
|
|
for (j=0; j< cntNewRights; ++j)
|
|
{
|
|
if (NewSecurityInformation.AccessRights[j].SidIndex ==
|
|
pCachedSecurityInformation->AccessRights[i].SidIndex)
|
|
{
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if it isn't in the new array, then we need to copy it
|
|
if (!fFound)
|
|
{
|
|
NewSecurityInformation.AccessRights[cntNewRights] =
|
|
pCachedSecurityInformation->AccessRights[i];
|
|
|
|
++cntNewRights; // the new array has
|
|
}
|
|
}
|
|
}
|
|
|
|
// update the cached security info and pass it back
|
|
*pCachedSecurityInformation = NewSecurityInformation;
|
|
|
|
return Status;
|
|
}
|
|
|
|
DWORD
|
|
CscAddMaximalAccessRightsForSids(
|
|
HSHADOW hParent,
|
|
HSHADOW hFile,
|
|
ULONG NumberOfSids,
|
|
PCSC_SID_ACCESS_RIGHTS pSidAccessRights)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine updates the access rights for a given number of sids on the
|
|
given file
|
|
|
|
Arguments:
|
|
|
|
hParent - the parent directory shadow handle
|
|
|
|
hFile - the shadow handle
|
|
|
|
NumberOfSids - the number of sids for which the access rights needs to be
|
|
updated
|
|
|
|
pSidAccessRights - an array of the sids and the corresponding access rights.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful, otherwise appropriate error
|
|
|
|
Notes:
|
|
|
|
The current implementation of this routine is based upon the assumption that
|
|
the number of Sid mappings stored on a per file basis is very small ( 8 at most).
|
|
If this assumption is changed this routine needs to be reworked.
|
|
|
|
--*/
|
|
{
|
|
DWORD Status = ERROR_SUCCESS;
|
|
|
|
CACHED_SECURITY_INFORMATION CachedSecurityInformation;
|
|
|
|
ULONG BytesReturned, BytesWritten;
|
|
|
|
BytesReturned = sizeof(CachedSecurityInformation);
|
|
|
|
Status = GetShadowInfoEx(
|
|
hParent,
|
|
hFile,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&CachedSecurityInformation,
|
|
&BytesReturned);
|
|
|
|
if ((Status == ERROR_SUCCESS) &&
|
|
((BytesReturned == 0) ||
|
|
(BytesReturned == sizeof(CachedSecurityInformation)))) {
|
|
|
|
Status = CscUpdateCachedSecurityInformation(
|
|
&CachedSecurityInformation,
|
|
BytesReturned,
|
|
NumberOfSids,
|
|
pSidAccessRights);
|
|
|
|
if (Status == ERROR_SUCCESS) {
|
|
BytesWritten = sizeof(CachedSecurityInformation);
|
|
|
|
Status = SetShadowInfoEx(
|
|
hParent,
|
|
hFile,
|
|
NULL,
|
|
0,
|
|
SHADOW_FLAGS_OR,
|
|
NULL,
|
|
&CachedSecurityInformation,
|
|
&BytesWritten);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
DWORD
|
|
CscAddMaximalAccessRightsForShare(
|
|
HSERVER hShare,
|
|
ULONG NumberOfSids,
|
|
PCSC_SID_ACCESS_RIGHTS pSidAccessRights)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine updates the access rights for a given number of sids on the
|
|
given share
|
|
|
|
Arguments:
|
|
|
|
hShare - the parent directory shadow handle
|
|
|
|
NumberOfSids - the number of sids for which the access rights needs to be
|
|
updated
|
|
|
|
pSidAccessRights - an array of the sids and the corresponding access rights.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful, otherwise appropriate error
|
|
|
|
Notes:
|
|
|
|
The current implementation of this routine is based upon the assumption that
|
|
the number of Sid mappings stored on a per file basis is very small ( 8 at most).
|
|
If this assumption is changed this routine needs to be reworked.
|
|
|
|
--*/
|
|
{
|
|
DWORD Status = ERROR_SUCCESS;
|
|
|
|
CACHED_SECURITY_INFORMATION CachedSecurityInformation;
|
|
|
|
ULONG BytesReturned, BytesWritten;
|
|
|
|
BytesReturned = sizeof(CachedSecurityInformation);
|
|
|
|
Status = GetShareInfoEx(
|
|
hShare,
|
|
NULL,
|
|
NULL,
|
|
&CachedSecurityInformation,
|
|
&BytesReturned);
|
|
|
|
if ((Status == ERROR_SUCCESS) &&
|
|
((BytesReturned == 0) ||
|
|
(BytesReturned == sizeof(CachedSecurityInformation)))) {
|
|
|
|
Status = CscUpdateCachedSecurityInformation(
|
|
&CachedSecurityInformation,
|
|
BytesReturned,
|
|
NumberOfSids,
|
|
pSidAccessRights);
|
|
|
|
if (Status == ERROR_SUCCESS) {
|
|
BytesWritten = sizeof(CachedSecurityInformation);
|
|
|
|
if (SetShareStatusEx(
|
|
hShare,
|
|
0,
|
|
SHADOW_FLAGS_OR,
|
|
&CachedSecurityInformation,
|
|
&BytesWritten) >= 0)
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
DWORD
|
|
CscRemoveMaximalAccessRightsForSid(
|
|
HSHADOW hParent,
|
|
HSHADOW hFile,
|
|
PVOID pSid,
|
|
ULONG SidLength)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine removes the cached access rights for a given number of sids on
|
|
the given file
|
|
|
|
Arguments:
|
|
|
|
hParent - the parent directory shadow handle
|
|
|
|
hFile - the shadow handle
|
|
|
|
pSid - the sid for which the cached access rights are revoked.
|
|
|
|
SidLength - the length of the sid.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful, otherwise appropriate error
|
|
|
|
--*/
|
|
{
|
|
DWORD Status = ERROR_SUCCESS;
|
|
USHORT SidIndex;
|
|
ULONG BytesRead,BytesWritten,i;
|
|
|
|
CACHED_SECURITY_INFORMATION CachedSecurityInformation;
|
|
|
|
SidIndex = CscMapSidToIndex(
|
|
pSid,
|
|
SidLength);
|
|
|
|
if (SidIndex != CSC_INVALID_SID_INDEX) {
|
|
BytesRead = sizeof(CachedSecurityInformation);
|
|
|
|
Status = GetShadowInfoEx(
|
|
hParent,
|
|
hFile,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&CachedSecurityInformation,
|
|
&BytesRead);
|
|
|
|
if ((Status == ERROR_SUCCESS) &&
|
|
(BytesRead == sizeof(CachedSecurityInformation))) {
|
|
for (i = 0; i < CSC_MAXIMUM_NUMBER_OF_CACHED_SID_INDEXES; i++) {
|
|
if (CachedSecurityInformation.AccessRights[i].SidIndex == SidIndex) {
|
|
CachedSecurityInformation.AccessRights[i].SidIndex =
|
|
CSC_INVALID_SID_INDEX;
|
|
|
|
BytesWritten = sizeof(CachedSecurityInformation);
|
|
|
|
Status = SetShadowInfoEx(
|
|
hParent,
|
|
hFile,
|
|
NULL,
|
|
0,
|
|
SHADOW_FLAGS_OR,
|
|
NULL,
|
|
&CachedSecurityInformation,
|
|
&BytesWritten);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|