447 lines
14 KiB
C
447 lines
14 KiB
C
/*++
|
||
|
||
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;
|
||
}
|
||
|
||
|