mirror of https://github.com/lianthony/NT4.0
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.
5905 lines
217 KiB
5905 lines
217 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// File: caccctrl.cxx
|
|
//
|
|
// Copyright (c) 1996-1996, Microsoft Corp. All rights reserved.
|
|
//
|
|
// Description: This file contains the method definitions of the DCOM
|
|
// IAccessControl implementation classes
|
|
//
|
|
// Classes: COAccessControl - This is the implementation component of DCOM
|
|
// IAccessControl. For aggregation support, the
|
|
// COAccessControl component is implemented as a
|
|
// nested class containing the CImpAccessControl
|
|
// class. The COAccessControl object itself
|
|
// contains a non-delegating implementation of
|
|
// IUknown that exposed the IUnknown, IPersist,
|
|
// IPersistStream, and the IAccessControl
|
|
// interfaces.
|
|
// CImpAccessControl - This is the class nested within the
|
|
// COAccessControl component class. It
|
|
// contains the implementation of IAccessControl
|
|
// and IPersistStream and an implementation
|
|
// of IUnknown that always delegates the call
|
|
// to the controlling unknown.
|
|
// CFAccessControl - The class factory for manufacturing COAccessControl
|
|
// objects.
|
|
//
|
|
// CODEWORK:
|
|
// Use PrivMemAllow everywhere.
|
|
// Always check m_bInitialized before argument validation.
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
#include "ole2int.h"
|
|
#include <windows.h>
|
|
#include <objbase.h>
|
|
#include <stdio.h>
|
|
|
|
#ifdef _CHICAGO_
|
|
#include <svrapi.h> // 16-bit LAN Manager NetAccess API
|
|
#endif
|
|
|
|
#include "oleext.h" // IAccessControl interface definition
|
|
#include "Cache.h" // Effective permissions cache
|
|
#include "acpickl.h" // Pickling support
|
|
#include "caccctrl.h" // COAccessControl, CImpAccessControl and CFAccessControl
|
|
// class declarations.
|
|
|
|
// External variables
|
|
#include "acext.h"
|
|
|
|
#ifndef _CHICAGO_
|
|
GENERIC_MAPPING gDummyMapping = {0,0,0,0};
|
|
PRIVILEGE_SET gDummyPrivilege = {1,0};
|
|
SID gEveryone = {1,1,SECURITY_WORLD_SID_AUTHORITY,
|
|
SECURITY_WORLD_RID};
|
|
SID gSystem = {1,1,SECURITY_NT_AUTHORITY,
|
|
SECURITY_LOCAL_SYSTEM_RID};
|
|
#else
|
|
const SHORT EXTRA_ACES = 5;
|
|
#endif
|
|
|
|
// Internal function prototypes, please see the function headers for details
|
|
void AddACEToStreamACL (STREAM_ACE *, PCB *);
|
|
void CleanAllMemoryResources (ACL_DESCRIPTOR *, PCB *);
|
|
void CleanUpStreamACL (STREAM_ACL *pStreamACL);
|
|
HRESULT EnlargeStreamACL (PCB *, ULONG);
|
|
void FreePicklingBuff (PCB *);
|
|
BOOL IsValidAccessMask (DWORD);
|
|
void *LocalMemAlloc (ULONG);
|
|
void LocalMemFree (void *);
|
|
HRESULT MapStreamACLToAccessList (PCB *, PACTRL_ACCESSW *);
|
|
HRESULT ResizePicklingBuff (PCB *, ULONG);
|
|
HRESULT ValidateTrusteeString (LPWSTR);
|
|
HRESULT ValidateTrustee (PTRUSTEE_W);
|
|
HRESULT ValidateAccessCheckClient (PTRUSTEE_W);
|
|
HRESULT ValidateAndTransformAccReqList(PACTRL_ACCESSW ,STREAM_ACE **, void **, ULONG *, ULONG *, ULONG *);
|
|
|
|
#ifdef _CHICAGO_
|
|
void AddACEToACLImage (access_list_2 *, ULONG, ACL_DESCRIPTOR *);
|
|
HRESULT AllocACLImage (ACL_IMAGE *, SHORT);
|
|
void CleanFileResource (ACL_IMAGE *);
|
|
void CleanUpACLImage (ACL_IMAGE *);
|
|
HRESULT ComputeEffectiveAccess (LPWSTR,DWORD *, ACL_DESCRIPTOR *);
|
|
void DeleteACEFromACLImage (CHAR *, ACL_IMAGE *);
|
|
BOOL DeleteACEFromStreamACL (PTRUSTEE_W, ULONG, PCB *);
|
|
HRESULT EnsureACLImage (ACL_IMAGE *, ULONG);
|
|
HRESULT GenerateFile (LPTSTR *);
|
|
HRESULT MapStreamACLToChicagoACL (STREAM_ACE *, ACL_IMAGE *, SHORT);
|
|
HRESULT ReadACLFromStream (IStream *, PCB *);
|
|
SHORT StandardMaskToLANManagerMask (DWORD *, USHORT *);
|
|
HRESULT ValidateAndFixStreamACL (STREAM_ACL *);
|
|
HRESULT WStringToMBString (LPWSTR, CHAR **);
|
|
#else
|
|
HRESULT ComputeEffectiveAccess (ACL_DESCRIPTOR *, STREAM_ACL *, HANDLE, DWORD *);
|
|
BOOL DeleteACEFromStreamACL (PTRUSTEE_W, ULONG, ACL_DESCRIPTOR *, PCB *);
|
|
HRESULT GetSIDFromName (PSID *, LPWSTR, TRUSTEE_TYPE *);
|
|
HRESULT GetNameFromSID (LPWSTR *, PSID, TRUSTEE_TYPE *);
|
|
HRESULT InitSecDescInACLDesc (ACL_DESCRIPTOR *);
|
|
void NTMaskToStandardMask (ACCESS_MASK *, DWORD *);
|
|
HRESULT PutStreamACLIntoSecDesc (STREAM_ACL *, ACL_DESCRIPTOR *);
|
|
HRESULT ReadACLFromStream (IStream *, PCB *, ACL_DESCRIPTOR *);
|
|
void StandardMaskToNTMask (DWORD *, ACCESS_MASK *);
|
|
HRESULT ValidateAndFixStreamACL (STREAM_ACL *, ULONG *, ULONG *);
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// CFAccessControl methods (Class Factory)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: CFAccessControl::CFAccessControl , public
|
|
//
|
|
// Summary: Contructor of CFAccessControl. This function initializes the
|
|
// object's reference count to zero.
|
|
//
|
|
// Args: void
|
|
//
|
|
// Modifies: m_cRefs.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
CFAccessControl::CFAccessControl(void)
|
|
{
|
|
m_cRefs = 0;
|
|
} // CFAccessControl::CFAccessControl
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: CFAccessControl::~CFAccessControl , public
|
|
//
|
|
// Summary: Destructor for CFAccessControl. This function does nothing at the
|
|
// moment.
|
|
//
|
|
// Args: void
|
|
//
|
|
// Modifies:
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
CFAccessControl::~CFAccessControl(void)
|
|
{
|
|
return;
|
|
} // CFAccessControl::~CFAccessControl
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: CFAccessControl::QueryInterface() , public
|
|
//
|
|
// Summary: This function queries the CFAccessControl object itself
|
|
// for an interface pointer and returns it to the caller.
|
|
// Note that *ppv will be set to NULL if the fucntion fails
|
|
// to retrieve an interface pointer for the caller.
|
|
//
|
|
// Args: [in] REFIID riid - Reference to the identifier of the interface
|
|
// that the client wants.
|
|
// [out] void **ppv - Address of the interface pointer returned by
|
|
// this function. The space for storing the returned
|
|
// pointer should be allocated by the caller.
|
|
//
|
|
// Modifies: m_cRefs - The object's reference count will be incremented
|
|
// if the function can provide the requested interface
|
|
// pointer.
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded
|
|
// - E_NOINTERFACE: The requested interface is not supported
|
|
// by the .
|
|
// - E_INVALIDARG: ppv was NULL
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(HRESULT)
|
|
CFAccessControl::QueryInterface
|
|
(
|
|
REFIID riid,
|
|
void **ppv
|
|
)
|
|
{
|
|
|
|
// Checks for really foolish mistake made by the
|
|
// client like passing in a NULLpointer as the
|
|
// address of the returned interface pointer.
|
|
if (ppv == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
} // if
|
|
|
|
// The CFAccessControl object only supports the
|
|
// IUnknown interface and the IClassFactory interface.
|
|
if (IsEqualGUID(riid, IID_IUnknown) ||
|
|
IsEqualGUID(riid, IID_IClassFactory ))
|
|
{
|
|
// Since CFAccessControl doesn't inherit from multiple
|
|
// virtual classes, no type casting on the returned
|
|
// interface pointer is required.
|
|
*ppv = this;
|
|
// Obeys the COM reference counting rule by calling AddRef
|
|
// on the output pointer.
|
|
((IUnknown *)(*ppv))->AddRef();
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
} // if
|
|
|
|
} // CFAccessControl::QueryInterface
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: CFAccessControl::AddRef(), public
|
|
//
|
|
// Summary: This function increments the CFAccessControl object
|
|
// reference count by one. All modifications of the object's reference
|
|
// count must be made thread-safe by using the InterlockedIncrement
|
|
// and the InterlockedDecrement functions.
|
|
//
|
|
// Args: void
|
|
//
|
|
// Modifies: m_cRefs.
|
|
//
|
|
// Return: ULONG
|
|
// New reference count of the object. This number may not be accurate in a
|
|
// multi-threaded environment.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(ULONG)
|
|
CFAccessControl::AddRef
|
|
(
|
|
void
|
|
)
|
|
{
|
|
ULONG cRefs = m_cRefs + 1;
|
|
InterlockedIncrement(&m_cRefs);
|
|
return cRefs;
|
|
|
|
} // CFAccessControl::AddRef
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: CFAccessControl::Release(), public
|
|
//
|
|
// Summary: This function decrements the CFAccessControl object reference
|
|
// count and deletes the object when the reference count drops to
|
|
// zero. After the deletion of the object, this function will
|
|
// also decrement the object count of the server. Modification
|
|
// of object reference count and object count must be made
|
|
// thread-safe by using the InterlockedIncrement or InterlockedDecrement
|
|
// functions
|
|
//
|
|
// Args: void
|
|
//
|
|
// Modifies: m_cRefs.
|
|
//
|
|
// Return: ULONG
|
|
// New reference count of the object. This number may not be accurate
|
|
// in a multi-threaded environment.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(ULONG)
|
|
CFAccessControl::Release
|
|
(
|
|
void
|
|
)
|
|
{
|
|
ULONG cRefs = m_cRefs - 1;
|
|
if(InterlockedDecrement(&m_cRefs) == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return cRefs;
|
|
}
|
|
|
|
} // CFAccessControl::Release
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: CFAccessControl::CreateInstance(), public
|
|
//
|
|
// Summary: This function creates an instance of the CAccesControl object
|
|
// and returns a requested interface pointer to the object. If the
|
|
// caller of this method intends to aggregate with the COAccessControl
|
|
// component, it will pass it's IUnknown pointer to this method which
|
|
// will in turn be passed into the COAccessControl contructor.
|
|
// Owing to the fact that the COAccessControl object supports
|
|
// aggregation, and COM rules dictate that a client must only ask for
|
|
// the IUnknown interface at creation of an aggregatable object,
|
|
// the caller must pass in IID_IUnknown as the riid parameter,
|
|
// otherwise this call will fail and return E_INVALIDARG.
|
|
//
|
|
// Args: IUnknown *pUnkOuter [in] - IUnknown pointer to the controlling object which
|
|
// can be NULL if the COAccessControl object is not
|
|
// created as part of an aggregate.
|
|
// REFIID riid [in] - Reference to the identifier of the interface that
|
|
// the client has requested.
|
|
// void **ppv [out] - Reference to the interface pointer to be returned to
|
|
// the caller.
|
|
//
|
|
// Return: HRESULT -S_OK: Succeeded.
|
|
// E_INVALIDARG: ppv is NULL, or the client ask for an interface
|
|
// other than IUnknown
|
|
// E_OUTOFMEMORY: Not enough memory to create new object.
|
|
// E_NOINTERFACE: The interface requested by the client
|
|
// was not supported by the COM IAccessControl
|
|
// object.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
|
|
STDMETHODIMP_(HRESULT)
|
|
CFAccessControl::CreateInstance
|
|
(
|
|
IUnknown *pUnkOuter,
|
|
REFIID riid,
|
|
void **ppv
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
COAccessControl *pAccessControl = NULL;
|
|
|
|
if(ppv == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
} // if
|
|
|
|
*ppv = NULL;
|
|
|
|
// Since COAccessControl is designed to support
|
|
// aggregation, the client has to ask for
|
|
// the IUnknown pointer the first time the
|
|
// COAccessControl object is created as part
|
|
// of an aggregate.
|
|
if(!IsEqualGUID(IID_IUnknown, riid) && pUnkOuter != NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
} // if
|
|
|
|
pAccessControl = new COAccessControl;
|
|
if(!pAccessControl)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
if(FAILED(hr = pAccessControl->Init(pUnkOuter)))
|
|
{
|
|
delete pAccessControl;
|
|
return hr;
|
|
} // if
|
|
} // if
|
|
|
|
if(FAILED(hr = pAccessControl->QueryInterface(riid, ppv)))
|
|
{
|
|
delete pAccessControl;
|
|
}
|
|
|
|
return hr;
|
|
} // CFAccessControl::CreateInstance
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: CFAccessControl::LockServer() , public
|
|
//
|
|
// Summary: This function either increases of decreases the server lock count.
|
|
//
|
|
// Args: BOOL fLock [in] - This flag tells the function whether to increment or
|
|
// decrement the server lock count.
|
|
// TRUE - Increment the server lock count.
|
|
// FALSE - Decrement the server lock count.
|
|
// The server can be unloaded if the server lock count
|
|
// and the object count are both zero.
|
|
//
|
|
// Return: S_OK: This function cannot fail.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
|
|
STDMETHODIMP_(HRESULT)
|
|
CFAccessControl::LockServer
|
|
(
|
|
BOOL fLock
|
|
)
|
|
{
|
|
return S_OK;
|
|
} // CFAccessControl::LockServer
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// COAccessControl methods
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Constructor, destructor
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::COAccessControl(), public
|
|
//
|
|
// Summary: Object constructor. This function sets the object's reference count
|
|
// to zero.
|
|
//
|
|
// Args: void
|
|
//
|
|
// Modifies: m_cRefs
|
|
//
|
|
// Return: void
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
COAccessControl::COAccessControl
|
|
(
|
|
void
|
|
)
|
|
{
|
|
// Set object reference count to zero
|
|
m_cRefs = 0;
|
|
m_ImpObj = NULL;
|
|
return;
|
|
|
|
} // COAccessControl::COAccessControl
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::Init(), public
|
|
//
|
|
// Summary: COAccessControl initialization method. Notice that this function
|
|
// initialize the COAccessControl object in a sense different from
|
|
// that of COAccessControl::Load. COAccessControl::Load initializes
|
|
// COAccessControl
|
|
//
|
|
// Args: IUnknown pUnkOuter - Pointer to the controlling object. This pointer
|
|
// can be NULL if the COAccessControl object
|
|
// is not part of an aggregate.
|
|
//
|
|
// Modifies: m_ImpObj
|
|
//
|
|
// Return: void
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(HRESULT)
|
|
COAccessControl::Init
|
|
(
|
|
IUnknown *pUnkOuter
|
|
)
|
|
{
|
|
|
|
// Initialize inner object
|
|
m_ImpObj = new CImpAccessControl(this, pUnkOuter);
|
|
if(m_ImpObj == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
return m_ImpObj->Load( NULL );
|
|
}
|
|
|
|
} // COAccessControl::Init
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::~COAccessControl(), public
|
|
//
|
|
// Summary: Object destructor. This function does nothing at the moment.
|
|
//
|
|
// Args: void
|
|
//
|
|
// Return: void
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
COAccessControl::~COAccessControl
|
|
(
|
|
void
|
|
)
|
|
{
|
|
// Destroy inner object
|
|
delete m_ImpObj;
|
|
return;
|
|
} // COAccessControl::~COAccessControl
|
|
|
|
// IUnknown methods
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::QueryInterface() , public
|
|
//
|
|
// Summary: This function queries the COAccessControl object for an
|
|
// interface pointer for the caller.
|
|
//
|
|
// Args: [in] REFIID riid - Reference to the identifier of the interface
|
|
// that the client wants.
|
|
// [out] void **ppv - Interface pointer returned.
|
|
//
|
|
// Modifies: m_cRefs.
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// - E_NOINTERFACE: The requested interface is not supported.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
|
|
STDMETHODIMP_(HRESULT)
|
|
COAccessControl::QueryInterface
|
|
(
|
|
REFIID riid,
|
|
void **ppv
|
|
)
|
|
{
|
|
|
|
HRESULT hr = E_NOINTERFACE;
|
|
|
|
// Since the CImpAccessControl class inherits from multiple
|
|
// virtual classes, it is important that the interface pointer
|
|
// returned is type cast properly.
|
|
if (IsEqualGUID(riid, IID_IUnknown))
|
|
{
|
|
*ppv = (IUnknown *)this;
|
|
}
|
|
else if (IsEqualGUID(riid, IID_IPersist))
|
|
{
|
|
*ppv = (IPersist *)m_ImpObj;
|
|
}
|
|
else if (IsEqualGUID(riid, IID_IPersistStream))
|
|
{
|
|
*ppv = (IPersistStream *)m_ImpObj;
|
|
}
|
|
else if (IsEqualGUID(riid, IID_IAccessControl))
|
|
{
|
|
*ppv = (IAccessControl *)m_ImpObj;
|
|
}
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
}
|
|
|
|
if(*ppv != NULL)
|
|
{
|
|
|
|
// Obey COM reference counting rules, call
|
|
// AddRef on the interface pointer returned.
|
|
((IUnknown *)(*ppv))->AddRef();
|
|
hr = S_OK;
|
|
}
|
|
return hr;
|
|
|
|
} // COAccessControl::QueryInterface
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::AddRef(), public
|
|
//
|
|
// Summary: Increments the COAccessControl object reference count.
|
|
//
|
|
// Args: void
|
|
//
|
|
// Modifies: m_cRefs.
|
|
//
|
|
// Return: ULONG
|
|
// New reference count of the object.
|
|
//
|
|
// Remark: The modification of m_cRefs is made thread-safe by using the
|
|
// InterlockedIncrement function.
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(ULONG)
|
|
COAccessControl::AddRef
|
|
(
|
|
void
|
|
)
|
|
{
|
|
ULONG cRefs = m_cRefs + 1;
|
|
InterlockedIncrement(&m_cRefs);
|
|
return cRefs;
|
|
} // COAccessControl::AddRef
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::Release(), public
|
|
//
|
|
// Summary: Decrements the COAccessControl object reference count and deletes
|
|
// the object when the reference drops to zero. After the object itself
|
|
// is destroyed, this function will also decrement the server's object
|
|
// count. Modification of object's reference count and the server's
|
|
// object count must be made thread-safe by using the
|
|
// InterlockedIncrement and the InterlockedDecrement functions.
|
|
//
|
|
// Args: void
|
|
//
|
|
// Modifies: m_cRefs.
|
|
//
|
|
// Return: ULONG
|
|
// New reference count of the object. This number may not be accurate
|
|
// in a multithreaded environment.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(ULONG)
|
|
COAccessControl::Release
|
|
(
|
|
void
|
|
)
|
|
{
|
|
ULONG cRefs = m_cRefs - 1;
|
|
if(InterlockedDecrement(&m_cRefs) == 0)
|
|
{
|
|
// self-destruct
|
|
delete this;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return cRefs;
|
|
}
|
|
|
|
} // COAccessControl::Release
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// CImpAccessControl
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Constructor, destructor
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::CImpAccessControl::CImpAccessControl, public
|
|
//
|
|
// Summary: Object contructor. This function is responsible for initializing
|
|
// the initialization flag and the dirty flag to false, setting
|
|
// the object's two major structures, the ACL descriptor and the
|
|
// pickling control block, to NULL, and initializing the object's
|
|
// outer unknown pointer to point to the appropriate object depending
|
|
// on whether the COAccessControl object is part of an aggregate.
|
|
//
|
|
// Args: IUnknown *pBackPtr [in] - IUnknown pointer to the outer object ie.
|
|
// the COAccessControl control that contains
|
|
// the current CImpAccessControl object.
|
|
// IUnknown *pUnkOuter [in] - IUnknown pointer to the controlling unknown
|
|
// which is NULL if the COAccessControl object
|
|
// is not part of an aggregation.
|
|
//
|
|
// Modifies: m_bDirty, m_bInitialized, m_pUnkOuter, m_ACLDesc, m_pcb
|
|
//
|
|
// Return: void
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
|
|
COAccessControl::CImpAccessControl::CImpAccessControl
|
|
(
|
|
IUnknown *pBackPtr,
|
|
IUnknown *pUnkOuter
|
|
)
|
|
{
|
|
m_pUnkOuter = (pUnkOuter == NULL) ? pBackPtr : pUnkOuter;
|
|
m_bInitialized = FALSE;
|
|
m_bDirty = FALSE;
|
|
// Initialize the structures within the object...
|
|
memset(&m_ACLDesc, 0, sizeof(ACL_DESCRIPTOR));
|
|
memset(&m_pcb, 0, sizeof(PCB));
|
|
|
|
InitializeCriticalSection(&m_ACLLock);
|
|
return;
|
|
} // COAccessControl::CImpAccessControl::CImpAccessControl
|
|
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::CImpAccessControl::~CImpAccessControl(), public
|
|
//
|
|
// Summary: Object destructor. This function releases all the memory allocated
|
|
// for an initialized CImpAccessControl object and destroys the
|
|
// critical section object for guarding the internal from concurrent
|
|
// access.
|
|
//
|
|
// Args: void
|
|
//
|
|
// Modifies: m_ACLDesc, m_pcb.
|
|
//
|
|
// Return: void
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
COAccessControl::CImpAccessControl::~CImpAccessControl
|
|
(
|
|
void
|
|
)
|
|
{
|
|
if(m_bInitialized)
|
|
{
|
|
#ifdef _CHICAGO_
|
|
CleanFileResource(&(m_ACLDesc.DenyACL));
|
|
CleanFileResource(&(m_ACLDesc.GrantACL));
|
|
#endif
|
|
CleanAllMemoryResources(&m_ACLDesc, &m_pcb);
|
|
} // if
|
|
DeleteCriticalSection(&m_ACLLock);
|
|
} //COAccessControl::CImpAccessControl:~CImpAccessControl
|
|
|
|
// IUnknown methods
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::CImpAccessControl::QueryInterface(), public
|
|
//
|
|
// Summary: This function simply delegates the QueryInterface call to the
|
|
// outer unknown's QueryInterface method.
|
|
//
|
|
// Args: REFIID riif [in] - Reference to the interface identifier that signifies
|
|
// the interface that the client wanted.
|
|
//
|
|
//
|
|
// Return: HRESULT - See outer unknown implementation for details.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(HRESULT)
|
|
COAccessControl::CImpAccessControl::QueryInterface
|
|
(
|
|
REFIID riid,
|
|
void **ppv
|
|
)
|
|
{
|
|
return m_pUnkOuter->QueryInterface(riid, ppv);
|
|
} // COAccessControl:CImpAccessControl::QueryInterface
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::CImpAccessControl::AddRef(), public
|
|
//
|
|
// Summary: This function simply delegates the AddRef call to the outer unknown's
|
|
// AddRef method.
|
|
//
|
|
// Args: void
|
|
//
|
|
// Modifies: Outer unknown reference count.
|
|
//
|
|
// Return: HRESULT - See outer unknown implementation for details
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(ULONG)
|
|
COAccessControl::CImpAccessControl::AddRef
|
|
(
|
|
void
|
|
)
|
|
{
|
|
// AddRef of the outer object must be thread-safe
|
|
return m_pUnkOuter->AddRef();
|
|
} // COAccessControl::CImpAccessControl::AddRef
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::CImpAccessControl::Release(), public
|
|
//
|
|
// Summary: This function simply delegates the Release call to the outer unknown's
|
|
// Release method.
|
|
//
|
|
// Args: void
|
|
//
|
|
// Modifies: Outer unknown reference count
|
|
//
|
|
// Return: ULONG - See outer unknown implementation for details.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(ULONG)
|
|
COAccessControl::CImpAccessControl::Release
|
|
(
|
|
void
|
|
)
|
|
{
|
|
// Release of the outer object must be thread safe
|
|
return m_pUnkOuter->Release();
|
|
} // COAccessControl::CImpAccessControl::Release
|
|
|
|
// IPersist method
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::CImpAccessControl::GetClassID(), public
|
|
//
|
|
// Summary: This function returns the class id of the COAccessControl component.
|
|
// pClassID must be pointing to a valid memory block big enough to
|
|
// hold the returned class ID.
|
|
//
|
|
// Args: CLSID *pCLSID [out] - Pointer to the returned CLSID.
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
// Return: HRESULT - E_INVALIDARG: pClassID == NULL.
|
|
// S_OK: Succeeded.
|
|
// CO_E_ACNOTINITIALIZED: This method was called before
|
|
// the DCOM IAccessControl object
|
|
// was initialized by the Load method.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(HRESULT)
|
|
COAccessControl::CImpAccessControl::GetClassID
|
|
(
|
|
CLSID *pClassID
|
|
)
|
|
{
|
|
if (pClassID == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
} // if
|
|
*pClassID = CLSID_DCOMAccessControl;
|
|
return S_OK;
|
|
} // COAccessControl::CImpAccessControl::GetClassID
|
|
|
|
// IPersistStream methods
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::CImpAccessControl::IsDirty(), public
|
|
//
|
|
// Summary: This function returns TRUE if the object has been modified since
|
|
// the last time it was saved and FALSE otherwise.
|
|
//
|
|
// Args: void.
|
|
//
|
|
// Return: HRESULT - S_OK: The object has changed since the last save.
|
|
// S_FALSE: The object has not changed since the last save.
|
|
// CO_E_ACNOTINITIALIZED: This method was called before
|
|
// the DCOM IAccessControl object
|
|
// was initialized by the Load method.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(HRESULT)
|
|
COAccessControl::CImpAccessControl::IsDirty
|
|
(
|
|
void
|
|
)
|
|
{
|
|
if(!m_bInitialized)
|
|
return CO_E_ACNOTINITIALIZED;
|
|
|
|
return (m_bDirty? S_OK:S_FALSE);
|
|
} // COAccessControl::CimpAccessControl::IsDirty
|
|
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::CImpAccessControl::Load(), public
|
|
//
|
|
// Summary: This function is the initialization method of CImpAccessControl
|
|
// and it must be called before any non-IUnknown methods.
|
|
//
|
|
// Args: IStream *pStm [in] - Interface pointer to a stream object from which
|
|
// access control data is loaded into the object.
|
|
// The seek pointer of the stream should be at the
|
|
// beginning of the stream header.
|
|
// If pStm is NULL, this function will initialize
|
|
// an empty DCOM IAccessControl object.
|
|
//
|
|
// Modifies: m_ACLDesc, m_pcb
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// E_INVALIDARG: This method will return E_INVALIDARG if
|
|
// either
|
|
// a) the ACL in the stream provided by the
|
|
// user contains an invalid access mask, or
|
|
// b) one of STREAM_ACE structure in the ACL
|
|
// provided by the user contains a null
|
|
// pTrusteeName pointer.
|
|
// E_OUTOFMEMORY: The system ran out of memory for some
|
|
// crucial operation.
|
|
// CO_E_FAILEDTOGETWINDIR: (Windows 95 only)Unable to obtain
|
|
// the Windows directory.
|
|
// CO_E_PATHTOOLONG: (Windows 95 only)The path generated by
|
|
// the GenerateFile function was longer
|
|
// than the system's limit.
|
|
// CO_E_FAILEDTOGENUUID: (Windows 95 only)Unable to generate
|
|
// a uuid using the UuidCreate funciton.
|
|
// CO_E_FAILEDTOCREATEFILE: (Windows 95 only)Unable to create
|
|
// a dummy file.
|
|
// CO_E_FAILEDTOCLOSEHANDLE: Unable to close a serialization
|
|
// handle.
|
|
// CO_E_SETSERLHNDLFAILED: Unable to (re)set a serialization
|
|
// handle.
|
|
// CO_E_EXCEEDSYSACLLIMIT: The number of ACEs in the ACL
|
|
// provided by the user exceeded the
|
|
// limit imposed by the system that
|
|
// is loading the ACL. On Windows 95,
|
|
// the system can handle 32767
|
|
// ACTRL_ACCESS_DENIED ACEs and 32767
|
|
// ACTRL_ACCESS_ALLOWED ACEs. On Windows NT,
|
|
// the system can only handle 32767
|
|
// ACTRL_ACCESS_DENIED and ACTRL_ACCESS_ALLOWED ACEs
|
|
// combined.
|
|
// CO_E_ACESINWRONGORDER: Not all ACTRL_ACCESS_DENIED ACEs in the ACL
|
|
// provided by the user were arranged
|
|
// in front of the ACTRL_ACCESS_ALLOWED ACEs.
|
|
// CO_E_WRONGTRUSTEENAMESYNTAX: The ACL provided by the user
|
|
// contained a trustee name
|
|
// string that didn't conform
|
|
// to the <Domain>\<Account>
|
|
// syntax.
|
|
// CO_E_INVALIDSID: (Windows NT only)The ACL provided by the
|
|
// user contained an invalid security
|
|
// identifier.
|
|
// CO_E_LOOKUPACCNAMEFAILED: (Window NT only) The system call,
|
|
// LookupAccountName, failed. The
|
|
// user can call GetLastError to
|
|
// obtain extended error information.
|
|
// CO_E_NOMATCHINGSIDFOUND: (Windows NT only) At least one of
|
|
// the trustee name in the ACL provided
|
|
// by the user had no corresponding
|
|
// security identifier.
|
|
// CO_E_CONVERSIONFAILED: (Windows 95 only) WideCharToMultiByte
|
|
// failed.
|
|
//
|
|
// CO_E_FAILEDTOOPENPROCESSTOKEN: (Windows NT only)The system
|
|
// call, OpenProcessToken,
|
|
// failed. The user can get
|
|
// extended information by
|
|
// calling GetLastError.
|
|
// CO_E_FAILEDTOGETTOKENINFO: (Windows Nt only)The system call,
|
|
// GetTokenInformation, failed.
|
|
// The user can call GetLastError to
|
|
// get extended error information.
|
|
// CO_E_DECODEFAILED: Unable to decode the ACL in the
|
|
// IStream object.
|
|
// CO_E_INCOMPATIBLESTREAMVERSION: The version code in the
|
|
// stream header was not
|
|
// supported by this version
|
|
// of IAccessControl.
|
|
// Error codes from IStream::Read - See the Win32 SDK
|
|
// documentation for detail descriptions of the following
|
|
// error codes.
|
|
// STG_E_ACCESSDENIED:
|
|
// STG_E_INVALIDPOINTER:
|
|
// STG_E_REVERTED:
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(HRESULT)
|
|
COAccessControl::CImpAccessControl::Load
|
|
(
|
|
IStream *pStm
|
|
)
|
|
{
|
|
|
|
HRESULT hr; // Function return code
|
|
ACL_DESCRIPTOR ACLDescBackup; // Backup of the original ACL descriptor in the object
|
|
PCB PCBBackup; // Backup of the original PCB in the object.
|
|
#ifdef _CHICAGO_
|
|
SHORT sNumOfDenyEntries = 0; // Number of deny entries in the stream
|
|
SHORT sNumOfGrantEntries = 0; // Number of grant entries in the stream
|
|
CHAR *pszDenyFilename; // Name of the deny ACL dummy file
|
|
CHAR *pszGrantFilename; // Name of the grant ACL dummy file
|
|
#endif
|
|
|
|
// There are too much things happening in this
|
|
// function so I'll simply lock the whole thing
|
|
EnterCriticalSection(&m_ACLLock);
|
|
|
|
// Take a snapshot of the old ACL so that if anything goes wrong, I can restore to the
|
|
// old configuration
|
|
memcpy(&PCBBackup, &m_pcb, sizeof(PCB));
|
|
memcpy(&ACLDescBackup,&m_ACLDesc,sizeof(ACL_DESCRIPTOR));
|
|
|
|
// Set the original ACL descritpor and the PCB to NULL just to be save
|
|
memset(&m_ACLDesc, 0, sizeof(ACL_DESCRIPTOR));
|
|
memset(&m_pcb, 0, sizeof(PCB));
|
|
|
|
#ifdef _CHICAGO_
|
|
// Generate new dummy files if this is the first time the object
|
|
// is initialized, reuse the old ones otherwise
|
|
if (m_bInitialized)
|
|
{
|
|
pszDenyFilename = ACLDescBackup.DenyACL.pACL->acc1_resource_name;
|
|
pszGrantFilename = ACLDescBackup.GrantACL.pACL->acc1_resource_name;
|
|
} // if
|
|
else
|
|
{
|
|
if (FAILED(hr = GenerateFile(&pszDenyFilename)))
|
|
{
|
|
goto Error;
|
|
} // if
|
|
|
|
if (FAILED(hr = GenerateFile(&pszGrantFilename)))
|
|
{
|
|
goto Error;
|
|
} // if
|
|
} // if
|
|
#endif
|
|
|
|
if (pStm != NULL)
|
|
{
|
|
|
|
// Read the ACL in the stream into the pickle control block
|
|
#ifdef _CHICAGO_
|
|
if(FAILED(hr = ReadACLFromStream(pStm, &m_pcb)))
|
|
#else
|
|
if(FAILED(hr = ReadACLFromStream(pStm, &m_pcb, &m_ACLDesc)))
|
|
#endif
|
|
{
|
|
#ifndef _CHICAGO_
|
|
if(hr != CO_E_NOMATCHINGSIDFOUND && hr != CO_E_LOOKUPACCNAMEFAILED)
|
|
{
|
|
#endif
|
|
goto Error;
|
|
#ifndef _CHICAGO_
|
|
} // if
|
|
#endif
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
if (FAILED(hr = EnlargeStreamACL(&m_pcb, 10)))
|
|
{
|
|
goto Error;
|
|
}
|
|
m_pcb.ulBytesUsed = sizeof(STREAM_ACL)
|
|
+ sizeof(STREAM_ACE)
|
|
+ 256;
|
|
m_pcb.bPickled = FALSE;
|
|
if (FAILED(hr = ResizePicklingBuff(&m_pcb, m_pcb.ulBytesUsed + 800)))
|
|
{
|
|
goto Error;
|
|
}
|
|
|
|
|
|
} // if (pStm != NULL)
|
|
m_pcb.ulNumOfStreamACEs = m_pcb.StreamACL.ulNumOfDenyEntries
|
|
+ m_pcb.StreamACL.ulNumOfGrantEntries;
|
|
|
|
#ifdef _CHICAGO_
|
|
// Allocate memory for the two ACL images
|
|
// NT ACL that contains more than 32767 may be too large to fit
|
|
// into the LAN Manager ACL
|
|
sNumOfDenyEntries = (SHORT)(m_pcb.StreamACL.ulNumOfDenyEntries);
|
|
hr = AllocACLImage(&(m_ACLDesc.DenyACL), sNumOfDenyEntries + EXTRA_ACES);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Error;
|
|
} // if
|
|
m_ACLDesc.DenyACL.pACL->acc1_count = sNumOfDenyEntries;
|
|
m_ACLDesc.DenyACL.pACL->acc1_resource_name = pszDenyFilename;
|
|
|
|
// NT ACL that contains more than 32767 may be too large to fit
|
|
// into the LAN Manager ACL
|
|
sNumOfGrantEntries = (SHORT)(m_pcb.StreamACL.ulNumOfGrantEntries);
|
|
hr = AllocACLImage(&(m_ACLDesc.GrantACL), sNumOfGrantEntries + EXTRA_ACES);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Error;
|
|
} // if
|
|
m_ACLDesc.GrantACL.pACL->acc1_count = sNumOfGrantEntries;
|
|
m_ACLDesc.GrantACL.pACL->acc1_resource_name = pszGrantFilename;
|
|
|
|
|
|
// Map Stream ACL to Chicago ACL
|
|
if(FAILED(hr = MapStreamACLToChicagoACL( m_pcb.StreamACL.pACL
|
|
, &(m_ACLDesc.DenyACL)
|
|
, sNumOfDenyEntries)))
|
|
{
|
|
goto Error;
|
|
} // if
|
|
|
|
if(FAILED(hr = MapStreamACLToChicagoACL( m_pcb.StreamACL.pACL
|
|
+ sNumOfDenyEntries
|
|
, &(m_ACLDesc.GrantACL)
|
|
, sNumOfGrantEntries)))
|
|
{
|
|
goto Error;
|
|
} // if
|
|
|
|
m_ACLDesc.DenyACL.bDirtyACL = TRUE;
|
|
m_ACLDesc.GrantACL.bDirtyACL = TRUE;
|
|
|
|
#else
|
|
|
|
if(FAILED(hr = InitSecDescInACLDesc(&m_ACLDesc)))
|
|
{
|
|
goto Error;
|
|
} // if
|
|
|
|
#endif
|
|
// Create a new pickling handle for the new ACL
|
|
if (MesEncodeFixedBufferHandleCreate( m_pcb.pPicklingBuff
|
|
, m_pcb.ulPicklingBuffSize
|
|
, &(m_pcb.ulBytesUsed)
|
|
, &(m_pcb.PickleHandle)) != RPC_S_OK)
|
|
{
|
|
hr = CO_E_SETSERLHNDLFAILED;
|
|
goto Error;
|
|
} // if
|
|
|
|
m_pcb.bDirtyHandle = FALSE;
|
|
|
|
if(m_bInitialized)
|
|
{
|
|
CleanAllMemoryResources(&ACLDescBackup, &PCBBackup);
|
|
#ifdef _CHICAGO_
|
|
m_Cache.FlushCache();
|
|
#else
|
|
m_CacheString.FlushCache();
|
|
m_CacheSID.FlushCache();
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
m_bInitialized = TRUE;
|
|
} // if
|
|
// Set dirty flag to false
|
|
m_bDirty = FALSE;
|
|
|
|
LeaveCriticalSection(&m_ACLLock);
|
|
return S_OK;
|
|
|
|
// Error handling code
|
|
Error:
|
|
#ifdef _CHICAGO_
|
|
|
|
// Cleanup the ACL images
|
|
if (m_ACLDesc.GrantACL.pACL != NULL)
|
|
{
|
|
CleanUpACLImage(&(m_ACLDesc.GrantACL));
|
|
}
|
|
|
|
if (m_ACLDesc.DenyACL.pACL != NULL)
|
|
{
|
|
CleanUpACLImage(&(m_ACLDesc.DenyACL));
|
|
}
|
|
|
|
// Destroy all the generated files if the
|
|
// object has been initialized before
|
|
if (!m_bInitialized)
|
|
{
|
|
if (pszGrantFilename != NULL)
|
|
{
|
|
DeleteFileA(pszGrantFilename);
|
|
LocalMemFree(pszGrantFilename);
|
|
} // if
|
|
|
|
if (pszDenyFilename != NULL)
|
|
{
|
|
DeleteFileA(pszDenyFilename);
|
|
LocalMemFree(pszDenyFilename);
|
|
} // if
|
|
} // if
|
|
#endif
|
|
|
|
// Cleanup the stream ACL
|
|
if(m_pcb.StreamACL.pACL != NULL)
|
|
{
|
|
CleanUpStreamACL(&(m_pcb.StreamACL));
|
|
}// if
|
|
|
|
// Release the decoding handle
|
|
if (m_pcb.PickleHandle != NULL)
|
|
{
|
|
MesHandleFree(m_pcb.PickleHandle);
|
|
} // if
|
|
|
|
// Release the pickling buffer
|
|
if (m_pcb.pPicklingBuff != NULL)
|
|
{
|
|
FreePicklingBuff(&m_pcb);
|
|
} // if
|
|
|
|
// Restore the old ACL
|
|
memcpy(&m_pcb, &PCBBackup, sizeof(PCB));
|
|
memcpy(&m_ACLDesc, &ACLDescBackup, sizeof(ACL_DESCRIPTOR));
|
|
LeaveCriticalSection(&m_ACLLock);
|
|
return hr;
|
|
|
|
} // COAccessControl::CImpAccessControl::Load
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::CImpAccessControl::Save(), public
|
|
//
|
|
// Summary: This function saves the object's ACL to a user provided stream.
|
|
//
|
|
// Args: IStream *pStm [in,out] - Pointer to a user provided stream object.
|
|
// BOOL fClearDirty [in] - Flag indicating whether the object should clear
|
|
// its dirty flag after the save.
|
|
//
|
|
// Modifies: m_bDirty
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// CO_E_ACNOTINITIALIZED: This method was called before
|
|
// the DCOM IAccessControl object
|
|
// was initialized by the Load method.
|
|
// E_INVALIDARG: pStm was NULL.
|
|
// CO_E_SETSERLHNDLFAILED - Failed to (re)set serializtion
|
|
// handle.
|
|
// Error codes that can be returned by the write operation.
|
|
// See Win32 SDK help for details
|
|
// STG_E_MEDIUMFULL
|
|
// STG_E_ACCESSDENIED
|
|
// STG_E_CANTSAVE
|
|
// STG_E_INVALIDPOINTER
|
|
// STG_E_REVERTED
|
|
// STG_E_WRITEFAULT
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(HRESULT)
|
|
COAccessControl::CImpAccessControl::Save
|
|
(
|
|
IStream *pStm,
|
|
BOOL fClearDirty
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
handle_t HeaderHandle;
|
|
CHAR HeaderBuffer[64];
|
|
CHAR *pHeaderBuffPtr;
|
|
STREAM_HEADER StreamHeader;
|
|
LARGE_INTEGER liOffset;
|
|
ULONG ulEncodedSize;
|
|
|
|
if(!m_bInitialized)
|
|
return CO_E_ACNOTINITIALIZED;
|
|
|
|
if (pStm == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
} // if
|
|
|
|
// Other threads shouldn't mess with the object
|
|
// when the object is saving its state
|
|
|
|
EnterCriticalSection(&m_ACLLock);
|
|
|
|
if (m_pcb.bDirtyHandle)
|
|
{
|
|
|
|
if (MesBufferHandleReset( m_pcb.PickleHandle
|
|
, MES_FIXED_BUFFER_HANDLE
|
|
, MES_ENCODE
|
|
, &(m_pcb.pPicklingBuff)
|
|
, m_pcb.ulPicklingBuffSize
|
|
, &(m_pcb.ulBytesUsed)) != RPC_S_OK)
|
|
|
|
{
|
|
hr = CO_E_SETSERLHNDLFAILED;
|
|
goto Error;
|
|
} // if
|
|
|
|
m_pcb.bDirtyHandle = FALSE;
|
|
|
|
} // if
|
|
|
|
if (!(m_pcb.bPickled))
|
|
{
|
|
// Encode the STREAM_ACL structure into the pickling buffer
|
|
STREAM_ACL_Encode(m_pcb.PickleHandle, &(m_pcb.StreamACL));
|
|
m_pcb.bPickled = TRUE;
|
|
m_pcb.bDirtyHandle = TRUE;
|
|
} // if
|
|
|
|
pHeaderBuffPtr = (CHAR *)(((ULONG)HeaderBuffer + 8) & ~7);
|
|
|
|
// Create encoding handle
|
|
if (MesEncodeFixedBufferHandleCreate( pHeaderBuffPtr
|
|
, 56
|
|
, &ulEncodedSize
|
|
, &HeaderHandle ) != RPC_S_OK)
|
|
{
|
|
hr = CO_E_SETSERLHNDLFAILED;
|
|
goto Error;
|
|
} // if
|
|
|
|
|
|
StreamHeader.ulStreamVersion = STREAM_VERSION;
|
|
StreamHeader.ulPickledSize = m_pcb.ulBytesUsed;
|
|
|
|
STREAM_HEADER_Encode(HeaderHandle, &StreamHeader);
|
|
|
|
MesHandleFree(HeaderHandle);
|
|
|
|
if(FAILED(hr = pStm->Write(pHeaderBuffPtr, ulEncodedSize, NULL)))
|
|
{
|
|
goto Error;
|
|
} // if
|
|
|
|
// Write encoded buffer to stream
|
|
hr = pStm->Write(m_pcb.pPicklingBuff, m_pcb.ulBytesUsed, NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Error;
|
|
} // if
|
|
|
|
// Reset the object's dirty flag if the user say so
|
|
if (fClearDirty)
|
|
{
|
|
m_bDirty = FALSE;
|
|
} // if
|
|
|
|
Error:
|
|
LeaveCriticalSection(&m_ACLLock);
|
|
return hr;
|
|
|
|
} // COAccessControl::CImpAccessControl::Save
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::CImpAccessControl::GetSizeMax(), public
|
|
//
|
|
// Summary: This function returns the number of bytes required to store the
|
|
// object's ACL to a stream. Notice that only the lower 32-bit of the
|
|
// the ULARGE_INTEGER *pcbSize is used.
|
|
//
|
|
// Args: ULARGE_INTEGER *pcbSize [in] - Number of bytes required to store the
|
|
// object's ACL.
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// CO_E_ACNOTINITIALIZED: This method was called before
|
|
// the DCOM IAccessControl object
|
|
// was initialized by the Load method.
|
|
// CO_E_SETSERLHNDLFAILED: Failed to reset the serialization
|
|
// handle.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(HRESULT)
|
|
COAccessControl::CImpAccessControl::GetSizeMax
|
|
(
|
|
ULARGE_INTEGER *pcbSize
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
STREAM_HEADER StreamHeader;
|
|
|
|
if(!m_bInitialized)
|
|
return CO_E_ACNOTINITIALIZED;
|
|
if (pcbSize == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
EnterCriticalSection(&m_ACLLock);
|
|
if (m_pcb.bDirtyHandle)
|
|
{
|
|
|
|
if (MesBufferHandleReset( m_pcb.PickleHandle
|
|
, MES_FIXED_BUFFER_HANDLE
|
|
, MES_ENCODE
|
|
, &(m_pcb.pPicklingBuff)
|
|
, m_pcb.ulPicklingBuffSize
|
|
, &(m_pcb.ulBytesUsed)) != RPC_S_OK)
|
|
|
|
{
|
|
hr = CO_E_SETSERLHNDLFAILED;
|
|
goto Error;
|
|
} // if
|
|
|
|
m_pcb.bDirtyHandle = FALSE;
|
|
|
|
} // if
|
|
|
|
if (!(m_pcb.bPickled))
|
|
{
|
|
STREAM_ACL_Encode(m_pcb.PickleHandle, &(m_pcb.StreamACL));
|
|
m_pcb.bPickled = TRUE;
|
|
m_pcb.bDirtyHandle = TRUE;
|
|
|
|
} // if
|
|
|
|
pcbSize->HighPart = 0;
|
|
pcbSize->LowPart = m_pcb.ulBytesUsed + g_ulHeaderSize;
|
|
|
|
Error:
|
|
LeaveCriticalSection(&m_ACLLock);
|
|
return hr;
|
|
} // COAccessControl::CImpAccessControl::GetSizeMax
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::CImpAccessControl::GrantAccessRights()
|
|
//
|
|
// Args:
|
|
// PACTRL_ACCESSW [in] - The array of ACTRL_ACCCESS_ENTRY structures to
|
|
// be processed.
|
|
// Modifies: m_ACLDesc, m_bDirty
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// CO_E_ACNOTINITIALIZED: This method was called before
|
|
// the DCOM IAccessControl object
|
|
// was initialized by the Load method.
|
|
// E_INVALIDARG: This method will return E_INVALIDARG if
|
|
// one of the following is true:
|
|
// 1) One of the access mask specfied by the user is
|
|
// invalid.
|
|
// 2) The pMultipleTrustee field in one of the user
|
|
// specified TRUSTEE_W structure is not NULL.
|
|
// 3) The MultipleTrusteeOPeration field in one of the
|
|
// user specified TRUSTEE_W structure is not
|
|
// NO_MULTIPLE_TRUSTEE.
|
|
// 4) The TrusteeType field in one of the user specified
|
|
// TRUSTEE_W structure has the value TRUSTEE_IS_UNKNOWN.
|
|
// 5) (On Windows 95 only) The TrusteeForm field in one
|
|
// of the user specified TRUSTEE_W structure has
|
|
// the value TRUSTEE_IS_SID.
|
|
// E_OUTOFMEMORY: The system ran out of memory for some
|
|
// crucial operations.
|
|
// CO_E_WRONGTRUSTEENAMESYNTAX: One of the trustee name
|
|
// specified by the client didn't conform to the
|
|
// <Domain>\<Account> syntax.
|
|
// CO_E_INVALIDSID: One of the security identifiers
|
|
// specified by the client was invalid.
|
|
// CO_E_NOMATCHINGNAMEFOUND: No matching account name
|
|
// could be found for one of the security identifiers
|
|
// specified by the client.
|
|
// CO_E_LOOKUPACCSIDFAILED: The system function,
|
|
// LookupAccountSID, failed during the reprocessing
|
|
// of the ACL. The client can call GetLastError to
|
|
// obtain extended error inforamtion.
|
|
// CO_E_NOMATCHINGSIDFOUND: No matching security identifier
|
|
// could be found for one of the
|
|
// trustee name specified by the
|
|
// client.
|
|
// CO_E_LOOKUPACCNAMEFAILED: The system function,
|
|
// LookupAccountName, failed during the reprocessing
|
|
// of the ACL. The client can call GetLastError
|
|
// to obtain extended error information.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(HRESULT)
|
|
COAccessControl::CImpAccessControl::GrantAccessRights
|
|
(
|
|
PACTRL_ACCESSW pAccessList
|
|
)
|
|
{
|
|
|
|
STREAM_ACE *pStreamACEReqs; // Pointer to an array
|
|
// of stream ACEs
|
|
// converted from the
|
|
// access request list
|
|
ULONG ulEstPickledSize;
|
|
HRESULT hr = S_OK;
|
|
void *pACEReqs;
|
|
ULONG cGrant;
|
|
ULONG cDeny;
|
|
|
|
if(!m_bInitialized)
|
|
return CO_E_ACNOTINITIALIZED;
|
|
|
|
if (FAILED(hr = ValidateAndTransformAccReqList( pAccessList
|
|
, &pStreamACEReqs
|
|
, &pACEReqs
|
|
, &ulEstPickledSize
|
|
, &cGrant
|
|
, &cDeny )))
|
|
{
|
|
return hr;
|
|
} // if
|
|
|
|
EnterCriticalSection(&m_ACLLock);
|
|
|
|
hr = AddAccessList( pStreamACEReqs, pACEReqs, ulEstPickledSize, cGrant,
|
|
cDeny );
|
|
|
|
LeaveCriticalSection(&m_ACLLock);
|
|
|
|
CleanupAccessList( FAILED(hr), pStreamACEReqs, pACEReqs, cGrant, cDeny );
|
|
return hr;
|
|
|
|
} // COAccessControl::CImpAccessControl::GrantAccessRights
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
//
|
|
// Method: COAccessControl::CImpAccessControl::CleanupAccessList()
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(void)
|
|
COAccessControl::CImpAccessControl::CleanupAccessList
|
|
(
|
|
BOOL fReleaseAll,
|
|
STREAM_ACE *pStreamACEReqs,
|
|
void *pvACEReqs,
|
|
ULONG cGrant,
|
|
ULONG cDeny
|
|
)
|
|
{
|
|
ULONG cCount;
|
|
ULONG i;
|
|
#ifdef _CHICAGO_
|
|
access_list_2 *pACEReqs = (access_list_2 *) pvACEReqs;
|
|
access_list_2 *pACE; // Pointer for stepping through
|
|
// the LAN Manager ACL in the ACLimage
|
|
#endif
|
|
STREAM_ACE *pStreamACEReqsPtr; // Pointer for stepping
|
|
// through the array of
|
|
// access requests
|
|
// transformed into
|
|
// STREAM_ACE structures
|
|
|
|
if (fReleaseAll)
|
|
{
|
|
cCount = cGrant + cDeny;
|
|
pStreamACEReqsPtr = pStreamACEReqs;
|
|
#ifdef _CHICAGO_
|
|
pACE = pACEReqs;
|
|
#endif
|
|
for (i = 0; i < cCount; i++, pStreamACEReqsPtr++)
|
|
{
|
|
midl_user_free(pStreamACEReqsPtr->pTrusteeName);
|
|
#ifdef _CHICAGO_
|
|
LocalMemFree(pACE->acl2_ugname);
|
|
pACE++;
|
|
#else
|
|
midl_user_free(pStreamACEReqsPtr->pSID);
|
|
#endif
|
|
|
|
} // for
|
|
}
|
|
LocalMemFree(pStreamACEReqs);
|
|
#ifdef _CHICAGO_
|
|
LocalMemFree(pACEReqs);
|
|
#endif
|
|
}
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
//
|
|
// Method: COAccessControl::CImpAccessControl::AddAccessList()
|
|
//
|
|
// Notes: This function assumes that the access list has been validated. It
|
|
// Can only fail if it runs out of memory. In all failure conditions
|
|
// the object's state is unchanged. The caller must take the lock.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(HRESULT)
|
|
COAccessControl::CImpAccessControl::AddAccessList
|
|
(
|
|
STREAM_ACE *pStreamACEReqs,
|
|
void *pvACEReqs,
|
|
ULONG ulEstPickledSize,
|
|
ULONG cGrant,
|
|
ULONG cDeny
|
|
)
|
|
{
|
|
|
|
ULONG i; // Loop counters
|
|
STREAM_ACE *pStreamACEReqsPtr; // Pointer for stepping
|
|
// through the array of
|
|
// access requests
|
|
// transformed into
|
|
// STREAM_ACE structures
|
|
HRESULT hr = S_OK;
|
|
ULONG cCount;
|
|
#ifdef _CHICAGO_
|
|
access_list_2 *pACEReqs = (access_list_2 *) pvACEReqs;
|
|
access_list_2 *pACE; // Pointer for stepping through
|
|
// the LAN Manager ACL in the ACLimage
|
|
#endif
|
|
|
|
// Extend the stream ACL, the ACL image and the pickling
|
|
// buffer to accomodate the new entries
|
|
cCount = cGrant + cDeny;
|
|
if(FAILED(hr = EnlargeStreamACL( &m_pcb
|
|
, m_pcb.ulNumOfStreamACEs
|
|
+ cCount)))
|
|
{
|
|
return hr;
|
|
} // if
|
|
|
|
if(FAILED(hr = ResizePicklingBuff( &m_pcb, m_pcb.ulBytesUsed
|
|
+ ulEstPickledSize
|
|
+ 800)))
|
|
{
|
|
return hr;
|
|
} // if
|
|
m_pcb.ulBytesUsed += ulEstPickledSize;
|
|
|
|
#ifdef _CHICAGO_
|
|
if (FAILED(hr = EnsureACLImage(&m_ACLDesc.GrantACL, cGrant)))
|
|
{
|
|
return hr;
|
|
} // if
|
|
if (FAILED(hr = EnsureACLImage(&m_ACLDesc.DenyACL, cDeny)))
|
|
{
|
|
return hr;
|
|
} // if
|
|
pACE = pACEReqs;
|
|
|
|
#endif
|
|
|
|
for ( pStreamACEReqsPtr = pStreamACEReqs,i = 0
|
|
; i < cCount
|
|
; i++
|
|
#ifdef _CHICAGO_
|
|
, pACE++
|
|
#endif
|
|
, pStreamACEReqsPtr++)
|
|
{
|
|
|
|
|
|
#ifdef _CHICAGO_
|
|
AddACEToACLImage(pACE, pStreamACEReqsPtr->grfAccessMode, &m_ACLDesc);
|
|
#else
|
|
m_ACLDesc.ulSIDSize += GetLengthSid(pStreamACEReqsPtr->pSID);
|
|
#endif
|
|
AddACEToStreamACL(pStreamACEReqsPtr, &m_pcb);
|
|
|
|
} // for
|
|
|
|
// fixing up the cache
|
|
#ifdef _CHICAGO_
|
|
m_Cache.FlushCache();
|
|
#else
|
|
m_CacheString.FlushCache();
|
|
m_CacheSID.FlushCache();
|
|
#endif
|
|
|
|
// Re-compute the encoded size of the stream ACL
|
|
m_pcb.bPickled = FALSE;
|
|
m_bDirty = TRUE;
|
|
#ifdef _CHICAGO_
|
|
if (cGrant != 0)
|
|
m_ACLDesc.GrantACL.bDirtyACL = TRUE;
|
|
if (cDeny != 0)
|
|
m_ACLDesc.DenyACL.bDirtyACL = TRUE;
|
|
#else
|
|
m_ACLDesc.bDirtyACL = TRUE;
|
|
#endif
|
|
return S_OK;
|
|
|
|
} // COAccessControl::CImpAccessControl::GrantAccessRights
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::CImpAccessControl::SetOwner(), public
|
|
//
|
|
// Summary: This method is not implemented at this moment
|
|
//
|
|
// Args:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Return: HRESULT - This method will always return E_NOTIMPL.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(HRESULT)
|
|
COAccessControl::CImpAccessControl::SetOwner
|
|
(
|
|
PTRUSTEEW pOwner,
|
|
PTRUSTEEW pGroup
|
|
)
|
|
{
|
|
return E_NOTIMPL;
|
|
} // COAccessControl::CimpAccessControl::SetOwner
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::CImpAccessControl::SetAccessRights(), public
|
|
//
|
|
// Summary: This function replace the internal ACL with an array of
|
|
// ACTRL_ACCESS_ENTRY structures provided by the caller of this method.
|
|
// Note that this function does not literally replace the internal
|
|
// ACL, instead it will map the array of ACTTRL_ACCESS_ENTRY structures
|
|
// into the internal representation of an ACL.
|
|
// This function will also merge entries with the same access mode
|
|
// and trustee name together into one internal ACE.
|
|
//
|
|
// Args:
|
|
// PACTRL_ACCESSW [in] - The array of ACTRL_ACCCESS_ENTRY structures to
|
|
// be processed.
|
|
//
|
|
// Modifies: m_ACLDesc, m_bDirty, m_pcb
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// E_INVALIDARG: This method will return E_INVALIDARG if one of
|
|
// the following is true:
|
|
// 1) pExplicitAccessList is a NULL pointer.
|
|
// 2) Inside one of the ACTRL_ACCESS_ENTRY structures specified
|
|
// by the client, either
|
|
// i) the grfAccessPermissions field contained an invalid
|
|
// access mask, or
|
|
// ii) the grfAccessMode field was neither ACTRL_ACCESS_ALLOWED
|
|
// nor ACTRL_ACCESS_DENIED, or
|
|
// iii) the grfInheritace field was not NO_INHERITANCE or
|
|
// iv) the pMultipleTrustee field in the TRUSTEE_W structure
|
|
// was not NULL, or
|
|
// v) the MultipleTrusteeOperation field in the TRUSTEE_W
|
|
// structure was not NO_MULTIPLE_TRUSTEE, or
|
|
// vi) the TrusteeType field in the TRUSTEE_Wstructure was
|
|
// TRUSTEE_IS_UNKNOWN, or
|
|
// vii) the ptstrNameFiled in the TRUSTEE_W structure was
|
|
// NULL, or
|
|
// On Windows 95 only:
|
|
// viii) the TrusteeForm field inside the TRUSTEE_W
|
|
// structure was TRUSTEE_IS_SID.
|
|
// E_OUTOFMEMORY: The system ran out of memory for crucial
|
|
// operation.
|
|
// CO_E_ACNOTINITIALIZED: The DCOM IAccessCOntrol object was
|
|
// not initialized by the load method
|
|
// before this method is called.
|
|
// CO_E_WRONGTRUSTEENAMESYNTAX: The trustee name in the
|
|
// TRUSTEE_W structure inside one of the ACTRL_ACCESS_ENTRY
|
|
// structure specified by the client didn't conform to the
|
|
// <Domain>\<Account> syntax.
|
|
// CO_E_INVALIDSID: The security identifier in the TRUSTEE_W
|
|
// structure inside one of the ACTRL_ACCESS_ENTRY
|
|
// structure specified by the client was
|
|
// invalid.
|
|
// (The following error codes are for Windows NT only)
|
|
// CO_E_NOMATCHINGNAMEFOUND: No matching account name
|
|
// could be found for one of the security identifiers
|
|
// specified by the client.
|
|
// CO_E_LOOKUPACCSIDFAILED: The system function,
|
|
// LookupAccountSID, failed during the reprocessing
|
|
// of the ACL. The client can call GetLastError to
|
|
// obtain extended error inforamtion.
|
|
// CO_E_NOMATCHINGSIDFOUND: No matching security identifier
|
|
// could be found for one of the
|
|
// trustee name specified by the
|
|
// client.
|
|
// CO_E_LOOKUPACCNAMEFAILED: The system function,
|
|
// LookupAccountName, failed during the reprocessing
|
|
// of the ACL. The client can call GetLastError to
|
|
// obtain extended error information.
|
|
//
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(HRESULT)
|
|
COAccessControl::CImpAccessControl::SetAccessRights
|
|
(
|
|
PACTRL_ACCESSW pAccessList
|
|
)
|
|
{
|
|
ACL_DESCRIPTOR ACLDescBackup; // Backup copy of the object's
|
|
// original ACL descriptor
|
|
PCB pcbBackup; // Backup copy of the object's
|
|
// original pickle control
|
|
// block
|
|
STREAM_ACE *pStreamACEReqs; // Pointer to an array
|
|
// of stream ACEs
|
|
// converted from the
|
|
// access request list
|
|
ULONG ulEstPickledSize;
|
|
HRESULT hr = S_OK;
|
|
void *pACEReqs;
|
|
ULONG cGrant;
|
|
ULONG cDeny;
|
|
|
|
if(!m_bInitialized)
|
|
return CO_E_ACNOTINITIALIZED;
|
|
|
|
if (FAILED(hr = ValidateAndTransformAccReqList( pAccessList
|
|
, &pStreamACEReqs
|
|
, &pACEReqs
|
|
, &ulEstPickledSize
|
|
, &cGrant
|
|
, &cDeny )))
|
|
{
|
|
return hr;
|
|
} // if
|
|
|
|
EnterCriticalSection(&m_ACLLock);
|
|
|
|
// Take a snapshot of the old ACL descriptor and the old PCB
|
|
memcpy(&ACLDescBackup, &m_ACLDesc, sizeof(ACL_DESCRIPTOR));
|
|
memset(&m_ACLDesc, 0, sizeof(ACL_DESCRIPTOR));
|
|
|
|
memcpy(&pcbBackup, &m_pcb, sizeof(PCB));
|
|
memset(&m_pcb, 0, sizeof(PCB));
|
|
|
|
// Try to add the new entries.
|
|
hr = AddAccessList( pStreamACEReqs, pACEReqs, ulEstPickledSize, cGrant,
|
|
cDeny );
|
|
|
|
// If successful, move some resources from the backup
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
#ifdef _CHICAGO_
|
|
// Reuse the old dummy file name
|
|
m_ACLDesc.DenyACL.pACL->acc1_resource_name =
|
|
ACLDescBackup.DenyACL.pACL->acc1_resource_name;
|
|
m_ACLDesc.GrantACL.pACL->acc1_resource_name =
|
|
ACLDescBackup.GrantACL.pACL->acc1_resource_name;
|
|
#else
|
|
memcpy(&(m_ACLDesc.SecDesc),&(ACLDescBackup.SecDesc), sizeof(SECURITY_DESCRIPTOR));
|
|
ACLDescBackup.SecDesc.Owner = NULL;
|
|
ACLDescBackup.SecDesc.Group = NULL;
|
|
m_ACLDesc.bDirtyACL = TRUE;
|
|
#endif
|
|
m_pcb.PickleHandle = pcbBackup.PickleHandle;
|
|
pcbBackup.PickleHandle = NULL;
|
|
|
|
// Free the old ACL descriptor and PCB
|
|
CleanAllMemoryResources(&ACLDescBackup, &pcbBackup);
|
|
}
|
|
|
|
// Restore the orignal ACL and PCB
|
|
else
|
|
{
|
|
// Free the new ACL descriptor and PCB
|
|
CleanAllMemoryResources(&m_ACLDesc, &m_pcb);
|
|
|
|
memcpy(&m_ACLDesc, &ACLDescBackup, sizeof(ACL_DESCRIPTOR));
|
|
memcpy(&m_pcb, &pcbBackup, sizeof(PCB));
|
|
}
|
|
LeaveCriticalSection(&m_ACLLock);
|
|
|
|
CleanupAccessList( FAILED(hr), pStreamACEReqs, pACEReqs, cGrant, cDeny );
|
|
return hr;
|
|
|
|
} // COAccessControl::CImpAccessControl::SetAccessRights
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::CImpAccessControl::RevokeAccessRights()
|
|
// , public
|
|
//
|
|
// Summary: This function removes all ACEs (both ACTRL_ACCESS_ALLOWED mode and
|
|
// ACTRL_ACCESS_DENIED mode entries) associated with the list of of trustees
|
|
// listed in pTrustee from the object's internal ACL.
|
|
//
|
|
// Args:
|
|
// LPWSTR lpProperty [in] - Property name, must be NULL.
|
|
// ULONG cCount [in] - Number of trustee to be revoked from the
|
|
// ACL.
|
|
// TRUSTEE_W pTrustee [in] - A list of trustees to be revoked.
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// CO_E_ACNOTINITIALIZED
|
|
// E_INVALIDARG: Either pTrustee was NULL, or cCount was
|
|
// zero, or one of the following was true
|
|
// about at least one of the TRUSTEE_W structure
|
|
// specified by the user:
|
|
//
|
|
// 1) The value of the pMultipleTrustee field in the TRUSTEE_W
|
|
// structure was not NULL.
|
|
// 2) The value of the MultipleTrusteeOperation field in the
|
|
// TRUSTEE_W structure was not NO_MULTIPLE_TRUSTEE.
|
|
// 3) The value of the TrusteeType field in the TRUSTEE_W
|
|
// structure was TRUSTEE_IS_UNKNOWN.
|
|
// 4) The value of the ptstrName field in the TRUSTEE_W structure
|
|
// was NULL.
|
|
// On Windows 95 only:
|
|
// 5) The value of the TrusteeForm field in the TRUSTEE_W structure
|
|
// was TRUSTEE_IS_SID.
|
|
// CO_E_WORNGTRUSTEENAMESYNTAX: At least one of the TRUSTEE_W
|
|
// structures specified by the
|
|
// user contained a trustee name
|
|
// that did not conform to the
|
|
// <Domain>/<Account Name>
|
|
// syntax.
|
|
// CO_E_INVALIDSID: At least one of the TRUSTEE_W structures
|
|
// specified by the user contained an invalid
|
|
// security identifier.
|
|
// E_OUTOFMEMORY: There was not enough memory for allocating
|
|
// a string conversion buffer.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(HRESULT)
|
|
COAccessControl::CImpAccessControl::RevokeAccessRights
|
|
(
|
|
LPWSTR lpProperty,
|
|
ULONG cCount,
|
|
TRUSTEE_W pTrustee[]
|
|
)
|
|
{
|
|
BOOL bDeleted = FALSE; // This flag indicates if any entry is
|
|
// removed from theACL.
|
|
ULONG i; // Loop counter
|
|
HRESULT hr; // Function return code
|
|
TRUSTEE_W *pLocalTrustee; // Pointer for traversing the list of
|
|
// trustees.
|
|
#ifdef _CHICAGO_
|
|
ULONG ulStrLen; // Length of the trustee string in
|
|
// multibyte characters
|
|
ULONG ulMaxLen = 0; // Maximum length of all the trustee names
|
|
// converted into multibyte strings.
|
|
CHAR *pcszTrusteeName; // Pointer to trustee name in multibyte
|
|
// characters.
|
|
#endif
|
|
|
|
|
|
if(!m_bInitialized)
|
|
return CO_E_ACNOTINITIALIZED;
|
|
|
|
if (cCount == 0 || lpProperty != NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
} // if
|
|
|
|
|
|
// The following loop validates the TRUSTEE_W structures
|
|
// specified by the user. On Windows 95, this function
|
|
// will also determine the length of the longest trustee
|
|
// name in multibyte characters.
|
|
pLocalTrustee = pTrustee;
|
|
for (i = 0; i < cCount; i++, pLocalTrustee++)
|
|
{
|
|
|
|
if(FAILED(hr = ValidateTrustee(pLocalTrustee)))
|
|
{
|
|
return hr;
|
|
} // if
|
|
|
|
#ifdef _CHICAGO_
|
|
ulStrLen = WideCharToMultiByte( g_uiCodePage
|
|
, WC_COMPOSITECHECK | WC_SEPCHARS
|
|
, pLocalTrustee->ptstrName
|
|
, -1
|
|
, NULL
|
|
, NULL
|
|
, NULL
|
|
, NULL );
|
|
if (ulStrLen > ulMaxLen)
|
|
{
|
|
ulMaxLen = ulStrLen;
|
|
} //if
|
|
#endif
|
|
} // for
|
|
|
|
#ifdef _CHICAGO_
|
|
|
|
// Allocate a buffer for converting Unicode trustee name into
|
|
// multibyte trustee name. An extra 5 bytes is allocated for
|
|
// extra safety.
|
|
ulMaxLen += 5;
|
|
pcszTrusteeName = (CHAR *)LocalMemAlloc(ulMaxLen);
|
|
if(pcszTrusteeName == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
} // if
|
|
#endif
|
|
|
|
EnterCriticalSection(&m_ACLLock);
|
|
|
|
|
|
pLocalTrustee = pTrustee;
|
|
for (i = 0; i < cCount ; i++, pLocalTrustee++)
|
|
{
|
|
#ifdef _CHICAGO_
|
|
ulStrLen = WideCharToMultiByte ( g_uiCodePage
|
|
, WC_COMPOSITECHECK | WC_SEPCHARS
|
|
, pLocalTrustee->ptstrName
|
|
, -1
|
|
, pcszTrusteeName
|
|
, ulMaxLen
|
|
, NULL
|
|
, NULL);
|
|
pcszTrusteeName[ulStrLen] = '\0';
|
|
#endif
|
|
if (DeleteACEFromStreamACL( pLocalTrustee
|
|
, ACTRL_ACCESS_DENIED
|
|
#ifndef _CHICAGO_
|
|
, &m_ACLDesc
|
|
#endif
|
|
, &m_pcb))
|
|
{
|
|
#ifdef _CHICAGO_
|
|
DeleteACEFromACLImage( pcszTrusteeName
|
|
, &(m_ACLDesc.DenyACL));
|
|
m_ACLDesc.DenyACL.bDirtyACL = TRUE;
|
|
#endif
|
|
bDeleted = TRUE;
|
|
} // if
|
|
|
|
if (DeleteACEFromStreamACL( pLocalTrustee
|
|
, ACTRL_ACCESS_ALLOWED
|
|
#ifndef _CHICAGO_
|
|
, &m_ACLDesc
|
|
#endif
|
|
, &m_pcb))
|
|
{
|
|
#ifdef _CHICAGO_
|
|
DeleteACEFromACLImage( pcszTrusteeName
|
|
, &(m_ACLDesc.GrantACL));
|
|
m_ACLDesc.GrantACL.bDirtyACL = TRUE;
|
|
#endif
|
|
bDeleted = TRUE;
|
|
} // if
|
|
|
|
} // for
|
|
|
|
if (bDeleted)
|
|
{
|
|
m_bDirty = TRUE;
|
|
#ifndef _CHICAGO_
|
|
m_ACLDesc.bDirtyACL = TRUE;
|
|
#endif
|
|
// Fix up the cache
|
|
#ifdef _CHICAGO_
|
|
m_Cache.FlushCache();
|
|
#else
|
|
m_CacheString.FlushCache();
|
|
m_CacheSID.FlushCache();
|
|
#endif
|
|
m_pcb.bPickled = FALSE;
|
|
} // if
|
|
|
|
#ifdef _CHICAGO_
|
|
LocalMemFree(pcszTrusteeName);
|
|
#endif
|
|
|
|
LeaveCriticalSection(&m_ACLLock);
|
|
|
|
return S_OK;
|
|
|
|
} // COAccessControl::CImpAccessControl::RevokeAccessRights
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::CImpAccessControl::IsAccessAllowed(), public
|
|
//
|
|
// Summary: This function performs access checking for the client.
|
|
// Only the execute permission is supported at this moment and the
|
|
// the trustee specified by the client must be the client itself.
|
|
//
|
|
// Args:
|
|
// TRUSTEE *pTrustee [in] - Pointer to the trustee to
|
|
// perform access check for.
|
|
// LPWSTR lpProperty [in] - Must be NULL.
|
|
// ACCESS_RIGHTS AccessRights [in] - A bit mask representing the set
|
|
// of permissions the client wants
|
|
// to check.
|
|
// BOOL *pfAccessAllowed [out] - Set TRUE only if trustee has
|
|
// requested access.
|
|
//
|
|
// Common on both Windows 95 and Windows NT:
|
|
// Return: HRESULT - S_OK: Succeeded, and the requested access was granted to
|
|
// the trustee.
|
|
// CO_E_ACNOTINITIALIZED: The COM IAccessControl object
|
|
// was not initialized before
|
|
// this method was called.
|
|
// E_ACCESSDENIED: The requested access was denied
|
|
// from the trustee.
|
|
// E_INVALIDARG: Either one of the following was true:
|
|
//
|
|
// 1) The value of the pMultipleTrustee field in the TRUSTEE_W
|
|
// structure was not NULL.
|
|
// 2) The value of the MultipleTrusteeOperation field in the
|
|
// TRUSTEE_W structure was not NO_MULTIPLE_TRUSTEE.
|
|
// 3) The value of the TrusteeType field in the TRUSTEE_W
|
|
// structure was TRUSTEE_IS_UNKNOWN.
|
|
// 4) The value of the ptstrName field in the TRUSTEE_W structure
|
|
// was NULL.
|
|
//
|
|
// CO_E_TRUSTEEDOESNTMATCHCLIENT: The trustee specified by the
|
|
// client was not the current
|
|
// ORPC client.
|
|
// CO_E_WRONGTRUSTEENAMESYNTAX: The trustee name inside the
|
|
// TRUSTEE_W structure specified
|
|
// by the user is not of the
|
|
// form <Domain>\<Account Name>.
|
|
// CO_E_FAILEDTOQUERYCLIENTBLANKET: Unable to query for the
|
|
// client's security blanket.
|
|
// E_UNEXPECTED: This function should not return E_UNEXPECTED
|
|
// under all circumstances.
|
|
//
|
|
//
|
|
// On Windows 95
|
|
// Return: HRESULT - E_INVALIDARG: In addition to the four cases stated above,
|
|
// E_INVALIDARG will be returned if the
|
|
// TrusteeForm field of the TRUSTEE_W structure
|
|
// pointed to by the pTrustee parameter is
|
|
// TRUSTEE_IS_SID.
|
|
// CO_E_NETACCESSAPIFAILED: Either the NetAccessAdd API or
|
|
// the NetAccessDel APi returned
|
|
// an error code in
|
|
// ComputeEffectiveAccess.
|
|
// CO_E_CONVERSIONFAILED: WideCharToMultiByte returned zero.
|
|
// The caller can get extended error
|
|
// information by calling GetLastError.
|
|
// E_OUTOFMEMORY: Either there was not enough memory to
|
|
// convert the Unicode trustee name into a
|
|
// multibyte string in
|
|
// ValidateAccessCheckClient of there
|
|
// was not enough memory to do the same in
|
|
// ComputeEffectiveAccess.
|
|
// On Windows NT:
|
|
// CO_E_FAILEDTOGETSECCTX: Failed to obtain an IServerSecurity
|
|
// pointer to the current server
|
|
// security context.
|
|
// CO_E_FAILEDTOIMPERSONATE: The GetEffAccUsingSID/Name was
|
|
// unable to impersonate
|
|
// the client who calls this
|
|
// function.
|
|
// CO_E_FAILEDOPENTHREADTOKEN: The GetEffAccUsingSID/Name
|
|
// method was unable to open the
|
|
// access token assciated
|
|
// with the current thread. The
|
|
// client of this method can
|
|
// call GetLastError to get
|
|
// extended error information.
|
|
// CO_E_FAILEDTOGETTOKENINFO: The GetEffAccUsingSID/Name
|
|
// method was unable to obtain
|
|
// obtain information from the
|
|
// access token associated with
|
|
// the current thread. The client
|
|
// of this method can call
|
|
// GetLastError to get extended
|
|
// error information.
|
|
// CO_E_ACCESSCHECKFAILED: The system function, AccessCheck,
|
|
// returned FALSE in
|
|
// ComputeEffectiveAccess. The
|
|
// caller of this method can call
|
|
// GetLastError to obtain extended
|
|
// error information.
|
|
// CO_E_INVALIDSID: At least one of the TRUSTEE_W structures
|
|
// specified by the user contained an invalid
|
|
// security identifier.
|
|
// CO_E_FAILEDTOSETDACL: SetSecurityDescriptorDacl returned
|
|
// false inside PutStreamACLIntoSecDesc.
|
|
// The client of this method can call
|
|
// GetLastError to get extended error
|
|
// information.
|
|
// E_OUTOFMEMORY: The system ran out of memory for mapping the
|
|
// DCOM IAccessControl object's STREAM_ACL
|
|
// structure to an NT ACL or the system
|
|
// could not allocate memory for the TOKEN_USER
|
|
// structure returned by GetTokenInformation.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(HRESULT)
|
|
COAccessControl::CImpAccessControl::IsAccessAllowed
|
|
(
|
|
TRUSTEE_W *pTrustee,
|
|
LPWSTR lpProperty,
|
|
ACCESS_RIGHTS AccessRights,
|
|
BOOL *pfAccessAllowed
|
|
)
|
|
{
|
|
DWORD dwPermissions = 0;
|
|
HRESULT hr;
|
|
|
|
// Initialize access allowed to FALSE.
|
|
if (pfAccessAllowed == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
*pfAccessAllowed = FALSE;
|
|
|
|
// Validate the arguments.
|
|
if (!IsValidAccessMask(AccessRights) ||
|
|
lpProperty != NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
} // if
|
|
if (FAILED(hr = ValidateAccessCheckClient(pTrustee)))
|
|
{
|
|
return hr;
|
|
} // if
|
|
|
|
if(!m_bInitialized)
|
|
return CO_E_ACNOTINITIALIZED;
|
|
|
|
#ifdef _CHICAGO_
|
|
EnterCriticalSection(&m_ACLLock);
|
|
if (!m_Cache.LookUpEntry(pTrustee->ptstrName, &dwPermissions))
|
|
{
|
|
if(FAILED(hr = ComputeEffectiveAccess( pTrustee->ptstrName
|
|
, &dwPermissions
|
|
, &m_ACLDesc)))
|
|
{
|
|
LeaveCriticalSection(&m_ACLLock);
|
|
return hr;
|
|
} // if
|
|
m_Cache.WriteEntry(pTrustee->ptstrName, dwPermissions);
|
|
} // if
|
|
|
|
LeaveCriticalSection(&m_ACLLock);
|
|
#else
|
|
|
|
if (pTrustee->TrusteeForm == TRUSTEE_IS_NAME)
|
|
hr = GetEffAccRightsUsingName( pTrustee->ptstrName
|
|
, &dwPermissions );
|
|
else
|
|
hr = GetEffAccRightsUsingSID( (PSID)(pTrustee->ptstrName)
|
|
, &dwPermissions );
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
#endif
|
|
|
|
// Indicate failure by setting pfAccessAllowed.
|
|
if ((dwPermissions & AccessRights) == AccessRights)
|
|
{
|
|
*pfAccessAllowed = TRUE;
|
|
}
|
|
return S_OK;
|
|
|
|
} // COAccessControl::CImpAccessControl::IsAccessAllowed
|
|
|
|
#ifndef _CHICAGO_
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::CImpAccessControl::GetEffAccRightsUsingName, Private
|
|
//
|
|
// Summary: Given a Unicode string representing the name of a user, this
|
|
// function computes the effective access permission that the
|
|
// specified user has on the secured object. Notice that the current
|
|
// implementation of this mehtod linits the trustee specified by the
|
|
// client to be the name of the same client calling this method.
|
|
//
|
|
// Args: LPWSTR pwszTrusteeName [in] - Pointer to a Unicode string
|
|
// representing the user whose effective
|
|
// access permissions on the secured object
|
|
// is about to be determined by this
|
|
// method. Notice that this parameter must
|
|
// specify the name of the client calling
|
|
// this function.
|
|
// DWORD *pdwRights [out] - Address of an access mask representing the
|
|
// set of effective access rights the user
|
|
// specified by the pwszTrusteeName parameter
|
|
// has on the secured object.
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// CO_E_FAILEDTOGETSECCTX: Failed to obtain an IServerSecurity
|
|
// pointer to the current server
|
|
// security context.
|
|
// CO_E_FAILEDTOIMPERSONATE: This method was unable to
|
|
// impersonate the client who calls
|
|
// this function.
|
|
// CO_E_FAILEDOPENTHREADTOKEN: This method was unable to
|
|
// open the access token assciated
|
|
// with the current thread. The
|
|
// client of this method can call
|
|
// GetLastError to get extended
|
|
// error information.
|
|
// CO_E_FAILEDTOGETTOKENINFO: This method was unable to obtain
|
|
// obtain information from the
|
|
// access token associated with
|
|
// the current thread. The client
|
|
// of this method can call
|
|
// GetLAstError to get extended
|
|
// error information.
|
|
// CO_E_FAILEDTOQUERYCLIENTBLANKET: Failed to query for the
|
|
// client's security blanket.
|
|
// CO_E_ACCESSCHECKFAILED: The system function, AccessCheck,
|
|
// returned FALSE in
|
|
// ComputeEffectiveAccess. The
|
|
// caller of this method can call
|
|
// GetLastError to obtain extended
|
|
// error information.
|
|
// CO_E_FAILEDTOSETDACL: SetSecurityDescriptorDacl returned
|
|
// false inside PutStreamACLIntoSecDesc.
|
|
// The client of this method can call
|
|
// GetLastError to get extended error
|
|
// information.
|
|
// E_OUTOFMEMORY: The system ran out of memory for mapping the
|
|
// DCOM IAccessControl object's STREAM_ACL
|
|
// structure to an NT ACL or the system
|
|
// could not allocate memory for the TOKEN_USER
|
|
// structure returned by GetTokenInformation.
|
|
//
|
|
// Remarks: It is neccessary for this method to impersonate the client
|
|
// in order to obtain the client's access token for access checking.
|
|
// This method is designed in such a way that if the server has already
|
|
// been impersonating the client, this method will not perform
|
|
// impersonation and it will obtain the currrent thread's access token
|
|
// directly. On the other hand, if the server wasn't impersonating the
|
|
// client before this method is called, this method will perform the
|
|
// impersonation before opening the access token associated with
|
|
// current thread. In either one of the forementioned cases, this method
|
|
// will retain the impersonation status of the server after it has
|
|
// finished its own processing. Ie. if the server is impersonating the
|
|
// client before this method is called, the server will still be
|
|
// impersonating the client after this method has finished processing
|
|
// and vice versa.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(HRESULT)
|
|
COAccessControl::CImpAccessControl::GetEffAccRightsUsingName
|
|
(
|
|
LPWSTR pwszTrusteeName,
|
|
DWORD *pdwRights
|
|
)
|
|
{
|
|
IServerSecurity *pSSec; // Current security call context
|
|
HRESULT hr = S_OK; // Result handle
|
|
BOOL bIsImpersonating; // This flag indicates whether the
|
|
// server is impersonating the client
|
|
// when the function is called
|
|
HANDLE TokenHandle; // Handle to the client's access
|
|
// token
|
|
HANDLE ThreadHandle; // Handle to the current thread.
|
|
// This is used for obtaining the access
|
|
// token associated with the current
|
|
// thread.
|
|
TOKEN_USER *pClientInfo; // Pointer to the TOKEN_USER structure
|
|
// returned by GetTokenInformation.
|
|
DWORD dwInfoLength; // Size of the TOKEN_USER structure
|
|
// returned by GetTokenInformation.
|
|
|
|
// Set the handles to invalid values and pointers to null
|
|
TokenHandle = INVALID_HANDLE_VALUE;
|
|
ThreadHandle = INVALID_HANDLE_VALUE;
|
|
pClientInfo = NULL;
|
|
pSSec = NULL;
|
|
bIsImpersonating = TRUE;
|
|
|
|
// Call get call context to obtain an IServerSecurity
|
|
// pointer corresponding to the call context of the
|
|
// current thread.
|
|
|
|
if(FAILED(CoGetCallContext( IID_IServerSecurity
|
|
, (void **)&pSSec)))
|
|
{
|
|
return CO_E_FAILEDTOGETSECCTX;
|
|
} // if
|
|
|
|
EnterCriticalSection(&m_ACLLock);
|
|
|
|
if(!m_CacheString.LookUpEntry(pwszTrusteeName, pdwRights))
|
|
{
|
|
|
|
// Check if the server has been impersonating the client already
|
|
// and impersonate the client if not
|
|
if(!(bIsImpersonating = pSSec->IsImpersonating()))
|
|
{
|
|
if(FAILED(hr = pSSec->ImpersonateClient()))
|
|
{
|
|
hr = CO_E_FAILEDTOIMPERSONATE;
|
|
goto Error;
|
|
} // if
|
|
} // if
|
|
|
|
// Get the current thread handle. The handle
|
|
// is going to be used in the OpenThreadToken function.
|
|
ThreadHandle = GetCurrentThread();
|
|
|
|
// Open the current thread token, it should be the
|
|
// access token of the client.
|
|
if(!OpenThreadToken( ThreadHandle
|
|
, TOKEN_READ
|
|
, TRUE
|
|
, &TokenHandle))
|
|
{
|
|
hr = CO_E_FAILEDTOOPENTHREADTOKEN;
|
|
goto Error;
|
|
} // hr
|
|
|
|
// Get the SID from the access token for cache lookup
|
|
GetTokenInformation( TokenHandle
|
|
, TokenUser
|
|
, pClientInfo
|
|
, 0
|
|
, &dwInfoLength );
|
|
DWORD dwLastError;
|
|
dwLastError = GetLastError();
|
|
if (dwLastError == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
// Allocate buffer for token information
|
|
pClientInfo = (TOKEN_USER *)LocalMemAlloc(dwInfoLength);
|
|
if ( pClientInfo == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
} // if
|
|
|
|
if(!GetTokenInformation( TokenHandle
|
|
, TokenUser
|
|
, pClientInfo
|
|
, dwInfoLength
|
|
, &dwInfoLength ))
|
|
{
|
|
hr = CO_E_FAILEDTOGETTOKENINFO;
|
|
goto Error;
|
|
} // if
|
|
}
|
|
else
|
|
{
|
|
hr = CO_E_FAILEDTOGETTOKENINFO;
|
|
} // if
|
|
|
|
// Use the SID inside ClientInfo to lookup the
|
|
// the effective access rights in the cache
|
|
if(!(m_CacheSID.LookUpEntry(pClientInfo->User.Sid, pdwRights)))
|
|
{
|
|
// Perform access checking
|
|
if(FAILED(hr = ComputeEffectiveAccess( &m_ACLDesc
|
|
, &(m_pcb.StreamACL)
|
|
, TokenHandle
|
|
, pdwRights)) < 0)
|
|
{
|
|
goto Error;
|
|
} // if
|
|
m_CacheSID.WriteEntry(((TOKEN_USER *)pClientInfo)->User.Sid, *pdwRights);
|
|
}
|
|
|
|
// Write the effective access permissions to the string cache
|
|
m_CacheString.WriteEntry(pwszTrusteeName, *pdwRights);
|
|
|
|
} // if
|
|
|
|
Error:
|
|
// Free the user info structure
|
|
if (pClientInfo != NULL)
|
|
{
|
|
LocalMemFree(pClientInfo);
|
|
}
|
|
|
|
// Release the token handle
|
|
if (TokenHandle != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(TokenHandle);
|
|
}
|
|
|
|
// Restore the impersonation status
|
|
if(!bIsImpersonating)
|
|
{
|
|
pSSec->RevertToSelf();
|
|
} // if
|
|
|
|
// Release the IServerSecurity pointer
|
|
if (pSSec != NULL)
|
|
{
|
|
pSSec->Release();
|
|
} // if
|
|
|
|
// There is no need to free the thread handle
|
|
// because it is a pseudo handle
|
|
LeaveCriticalSection(&m_ACLLock);
|
|
return hr;
|
|
|
|
} // COAccessControl::CImpAccessControl:GetEffAccRightsUsingName
|
|
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::CImpAccessControl::GetEffAccRightsUsingSID, private
|
|
//
|
|
// Summary: Given a security identifier of a user, this function computes the
|
|
// effective access rights the user has on the object secured by the
|
|
// current DCOM IAccessControl implementation object. Notice that
|
|
// the current implementation of this mehtod limits the security
|
|
// identifier to be the one that corresponds to the client that calls
|
|
// this function.
|
|
//
|
|
// Args: PSID pSID [in] - Pointer to a security identifier of a user whose
|
|
// effective permissions on the secured object are
|
|
// computed upon the client's request. Notice that
|
|
// this security identifier must be the security
|
|
// identifier of the client who calls this function
|
|
// in the current implementation.
|
|
// DWORD *pdwRights [out] - Address of the access mask representing the
|
|
// effective permissions that the user specified
|
|
// by the pSID parameter has on the secured
|
|
// object.
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// CO_E_FAILEDTOGETSECCTX: Failed to obtain an IServerSecurity
|
|
// pointer to the current server
|
|
// security context.
|
|
// CO_E_FAILEDTOIMPERSONET: This method was unable to
|
|
// impersonate the client who calls
|
|
// this function.
|
|
// CO_E_FAILEDOPENTHREADTOKEN: This method was unable to
|
|
// open the access token assciated
|
|
// with the current thread. The
|
|
// client of this method can call
|
|
// GetLastError to get extended
|
|
// error information.
|
|
// CO_E_FAILEDTOGETTOKENINFO: This method was unable to obtain
|
|
// obtain information from the
|
|
// access token associated with
|
|
// the current thread. The client
|
|
// of this method can call
|
|
// GetLAstError to get extended
|
|
// error information.
|
|
// CO_E_ACCESSCHECKFAILED: The system function, AccessCheck,
|
|
// returned FALSE in
|
|
// ComputeEffectiveAccess. The
|
|
// caller of this method can call
|
|
// GetLastError to obtain extended
|
|
// error information.
|
|
// CO_E_FAILEDTOSETDACL: SetSecurityDescriptorDacl returned
|
|
// false inside PutStreamACLIntoSecDesc.
|
|
// The client of this method can call
|
|
// GetLastError to get extended error
|
|
// information.
|
|
// E_OUTOFMEMORY: The system ran out of memory for mapping the
|
|
// DCOM IAccessControl object's STREAM_ACL
|
|
// structure to an NT ACL or the system could
|
|
// not allocate memory for the TOKEN_USEr
|
|
// structure returned by GetTokenInformation.
|
|
//
|
|
// Remarks: It is neccessary for this method to impersonate the client
|
|
// in order to obtain the client's access token for access checking.
|
|
// This method is designed in such a way that if the server has already
|
|
// been impersonating the client, this method will not perform
|
|
// impersonation and it will obtain the currrent thread's access token
|
|
// directly. On the other hand, if the server wasn't impersonating the
|
|
// client before this method is called, this method will perform the
|
|
// impersonation before opening the access token associated with
|
|
// current thread. In either one of the forementioned cases, this
|
|
// method will retain the impersonation status of the server after it
|
|
// has finished its own processing. Ie. if the server is impersonating
|
|
// the client before this method is called, the server will still be
|
|
// impersonating the client after this method has finished processing
|
|
// and vice versa.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(HRESULT)
|
|
COAccessControl::CImpAccessControl::GetEffAccRightsUsingSID
|
|
(
|
|
PSID pSID,
|
|
DWORD *pdwRights
|
|
)
|
|
{
|
|
IServerSecurity *pSSec; // Current security call context
|
|
HRESULT hr; // Result handle
|
|
BOOL bIsImpersonating; // This flag indicates whether the
|
|
// server is impersonating the client
|
|
// when the function is called
|
|
HANDLE TokenHandle; // Handle to the client's access
|
|
// token
|
|
TOKEN_USER *pClientInfo; // Pointer to a TOKEN_USER structure.
|
|
// This structure should contain the
|
|
// security identifier of the current
|
|
// client.
|
|
DWORD dwInfoLength; // Size of the TOKEN_USER info structure
|
|
// returned by GetTokenInfo.
|
|
LPWSTR pwszClientName; // Pointer to the name of the client in
|
|
// Unicode.
|
|
BOOL fSuccess;
|
|
|
|
// Set the handles to invalid values and pointers to null
|
|
TokenHandle = INVALID_HANDLE_VALUE;
|
|
pClientInfo = NULL;
|
|
pSSec = NULL;
|
|
|
|
// Call get call context to obtain an IServerSecurity
|
|
// pointer corresponding to the call context of the
|
|
// current thread.
|
|
|
|
if(FAILED(hr = CoGetCallContext( IID_IServerSecurity
|
|
, (void **)&pSSec)))
|
|
{
|
|
hr = CO_E_FAILEDTOGETSECCTX;
|
|
goto Error;
|
|
} // if
|
|
|
|
// Check if the server is impersonating the client.
|
|
// If not, this function would do the impersonation.
|
|
if(!(bIsImpersonating = pSSec->IsImpersonating()))
|
|
{
|
|
if(FAILED(hr = pSSec->ImpersonateClient()))
|
|
{
|
|
hr = CO_E_FAILEDTOIMPERSONATE;
|
|
goto Error;
|
|
}
|
|
} // if
|
|
|
|
// Call OpenThreadToken to obtain the access token.
|
|
// The access token should belong to the DCOM client
|
|
fSuccess = OpenThreadToken( GetCurrentThread()
|
|
, TOKEN_READ
|
|
, TRUE
|
|
, &TokenHandle);
|
|
|
|
// Restore the impersonation status
|
|
if(!bIsImpersonating)
|
|
{
|
|
pSSec->RevertToSelf();
|
|
} // if
|
|
|
|
if (!fSuccess)
|
|
{
|
|
hr = CO_E_FAILEDTOOPENTHREADTOKEN;
|
|
goto Error;
|
|
} // if
|
|
|
|
// Call GetTokenInformation to obtain the SID inside
|
|
// the access token.
|
|
GetTokenInformation( TokenHandle
|
|
, TokenUser
|
|
, pClientInfo
|
|
, 0
|
|
, &dwInfoLength);
|
|
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
pClientInfo = (TOKEN_USER *)LocalMemAlloc(dwInfoLength);
|
|
if (pClientInfo == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
} // if
|
|
|
|
if(!GetTokenInformation( TokenHandle
|
|
, TokenUser
|
|
, pClientInfo
|
|
, dwInfoLength
|
|
, &dwInfoLength))
|
|
{
|
|
hr = CO_E_FAILEDTOGETTOKENINFO;
|
|
goto Error;
|
|
} // if
|
|
|
|
}
|
|
else
|
|
{
|
|
hr = CO_E_FAILEDTOGETTOKENINFO;
|
|
goto Error;
|
|
} // if
|
|
|
|
// Check to see if the trustee provided is same as the
|
|
// current client. If not, return CO_E_TRUSTEEDOESNTMATCHCLIENT.
|
|
if(!EqualSid(pClientInfo->User.Sid, pSID))
|
|
{
|
|
hr = CO_E_TRUSTEEDOESNTMATCHCLIENT;
|
|
goto Error;
|
|
} // if
|
|
|
|
EnterCriticalSection(&m_ACLLock);
|
|
if(!m_CacheSID.LookUpEntry(pSID, pdwRights))
|
|
{
|
|
// Call QueryBlanket to obtain the client name.
|
|
if (FAILED(hr = pSSec->QueryBlanket( NULL
|
|
, NULL
|
|
, NULL
|
|
, NULL
|
|
, NULL
|
|
, (void **)&pwszClientName
|
|
, NULL)))
|
|
{
|
|
hr = CO_E_FAILEDTOQUERYCLIENTBLANKET;
|
|
goto Error2;
|
|
} // if
|
|
|
|
|
|
// Use the client name to lookup the effective
|
|
// access permissions
|
|
if(!m_CacheString.LookUpEntry(pwszClientName, pdwRights))
|
|
{
|
|
// Has to call ComputeEffectiveAccessRights
|
|
if(FAILED(hr = ComputeEffectiveAccess( &m_ACLDesc
|
|
, &(m_pcb.StreamACL)
|
|
, TokenHandle
|
|
, pdwRights)))
|
|
{
|
|
goto Error2;
|
|
} // if
|
|
m_CacheString.WriteEntry( pwszClientName
|
|
, *pdwRights);
|
|
|
|
} //if
|
|
m_CacheSID.WriteEntry(pSID, *pdwRights);
|
|
} // if
|
|
|
|
hr = S_OK;
|
|
Error2:
|
|
LeaveCriticalSection(&m_ACLLock);
|
|
Error:
|
|
// Free the user info structure
|
|
if (pClientInfo != NULL)
|
|
{
|
|
LocalMemFree(pClientInfo);
|
|
}
|
|
|
|
// Release the token handle
|
|
if (TokenHandle != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(TokenHandle);
|
|
}
|
|
|
|
// Release the IServerSecurity pointer
|
|
if (pSSec != NULL)
|
|
{
|
|
pSSec->Release();
|
|
} // if
|
|
|
|
// There is no need to free the thread handle
|
|
// because it is a pseudo handle
|
|
return hr;
|
|
|
|
} // COAccessControl::CImpAccessControl::GetEffAccRightsUsingSID
|
|
#endif
|
|
|
|
//M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
|
|
// Method: COAccessControl::CImpAccessControl::GetAllAccessRights(), public
|
|
//
|
|
// Summary: This function returns an array of ACTRL_ACCESS_ENTRY structures which
|
|
// represents the ACL that belongs to the secured object. Notice
|
|
// that memory is allocated by the callee for the array of
|
|
// structures and the trustee string within each
|
|
// structure. The client of this method must call
|
|
// CoTaskMemFree to free those memory blocks when they are no longer
|
|
// in use. Notice that in a multi-threaded environment, the array
|
|
// returned may not accurately represent the object's ACL by
|
|
// the time the caller receives it.
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// E_OUTOFMEMORY: Not enough memory to allocate the
|
|
// ACTRL_ACCESS_ENTRY array to be return.
|
|
// E_INVALIDARG: If one of the arguments passed in is NULL
|
|
// CO_E_ACNOTINITIALIZED: The DCOM IAccessControl implementation
|
|
// object was not initialized properly
|
|
// by the load method before this method
|
|
// was called.
|
|
//
|
|
//M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M
|
|
STDMETHODIMP_(HRESULT)
|
|
COAccessControl::CImpAccessControl::GetAllAccessRights
|
|
(
|
|
LPWSTR lpProperty,
|
|
PACTRL_ACCESSW *ppAccessList,
|
|
PTRUSTEEW *ppOwner,
|
|
PTRUSTEEW *ppGroup
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(!m_bInitialized)
|
|
return CO_E_ACNOTINITIALIZED;
|
|
|
|
// Validate the arguments
|
|
if (lpProperty != NULL || ppAccessList == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
} // if
|
|
|
|
if (ppOwner != NULL)
|
|
{
|
|
*ppOwner = NULL;
|
|
}
|
|
if (ppGroup != NULL)
|
|
{
|
|
*ppGroup = NULL;
|
|
}
|
|
|
|
EnterCriticalSection(&m_ACLLock);
|
|
|
|
hr = MapStreamACLToAccessList( &m_pcb, ppAccessList );
|
|
|
|
LeaveCriticalSection(&m_ACLLock);
|
|
return hr;
|
|
} // COAccessControl::CImpAccessControl::GetAllAccessRights
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Miscellaneous utility functions
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// functions that are common on both platform
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: ResizePicklingBuff
|
|
//
|
|
// Summary: This function resize the pickling buffer within a pickling
|
|
// control block. Note that this function doesn't copy the content
|
|
// in the old buffer over to the new buffer.
|
|
//
|
|
// Args: PCB *ppcb [in,out] - Pointer to the pickling control block
|
|
// that contains the pickling buffer to be resized.
|
|
// ULONG ulBytesRequired [in] - Number of bytes required in the new
|
|
// pickling buffer.
|
|
//
|
|
// Return: HRESULT - S_OK: Success.
|
|
// E_OUTOFMEMORY: Out of memory.
|
|
//
|
|
// Called by: COAccessControl::CImpAccessControl::Load
|
|
// AddACEToACL
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT ResizePicklingBuff
|
|
(
|
|
PCB *ppcb,
|
|
ULONG ulBytesRequired
|
|
)
|
|
{
|
|
CHAR *pNewTruePointer;
|
|
|
|
if (ulBytesRequired > ppcb->ulPicklingBuffSize)
|
|
{
|
|
pNewTruePointer = (CHAR *)LocalMemAlloc((ulBytesRequired + 7));
|
|
// At most 7 more bytes are needed to align the pickling buffer
|
|
if (pNewTruePointer == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
} // if
|
|
|
|
LocalMemFree(ppcb->pTruePicklingBuff);
|
|
|
|
ppcb->pTruePicklingBuff = pNewTruePointer;
|
|
// 8-byte align the pickling buffer
|
|
ppcb->pPicklingBuff = (char *)(((ULONG)(pNewTruePointer + 7))&~7);
|
|
ppcb->ulPicklingBuffSize = ulBytesRequired;
|
|
ppcb->bDirtyHandle = TRUE;
|
|
} // if
|
|
return S_OK;
|
|
} // ResizePicklingBuff
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: FreePicklingBuff
|
|
//
|
|
// Summary: This function releases the memmory allocated for a pickling
|
|
// buffer.
|
|
//
|
|
// Args: PCB *ppcb [in] - Pickling control block that contains the pickling
|
|
// buffer to be released
|
|
//
|
|
// Return: void
|
|
//
|
|
// Called by: CleanAllMemoryResources
|
|
// COAccessControl::CImpAccessControl::Load
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
void FreePicklingBuff
|
|
(
|
|
PCB *ppcb
|
|
)
|
|
{
|
|
LocalMemFree(ppcb->pTruePicklingBuff);
|
|
ppcb->pPicklingBuff = NULL;
|
|
ppcb->pTruePicklingBuff = NULL;
|
|
ppcb->ulPicklingBuffSize = 0;
|
|
|
|
} // FreePicklingBuff
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: EnlargeStreamACL
|
|
//
|
|
// Summary: This function reallocates the stream ACE array inside a pickle
|
|
// control block to a bigger memory block in order to accomodate the
|
|
// the extra number of stream ACEs needed by the user.
|
|
//
|
|
// Args: PCB *ppcb [in] - Pickle control block containing the stream ACE array
|
|
// to be resized.
|
|
//
|
|
// Return: HRESULT - S_OK: Success
|
|
// E_OUTOFMEMORY: Out of memory
|
|
//
|
|
// Called by: AddACEToACL
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT EnlargeStreamACL
|
|
(
|
|
PCB *ppcb,
|
|
ULONG ulNumOfEntries
|
|
)
|
|
{
|
|
ULONG ulNewSize;
|
|
ULONG ulOldSize;
|
|
STREAM_ACE *pNewStreamACL;
|
|
|
|
if (ulNumOfEntries + ppcb->ulNumOfStreamACEs > ppcb->ulMaxNumOfStreamACEs)
|
|
{
|
|
ulNewSize = ppcb->ulMaxNumOfStreamACEs + ulNumOfEntries;
|
|
|
|
pNewStreamACL = (STREAM_ACE *)midl_user_allocate((ulNewSize + 10)
|
|
* sizeof(STREAM_ACE));
|
|
if (pNewStreamACL == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
} // if
|
|
|
|
if (ppcb->StreamACL.pACL != NULL)
|
|
{
|
|
memcpy( pNewStreamACL
|
|
, ppcb->StreamACL.pACL
|
|
, ppcb->ulNumOfStreamACEs * sizeof(STREAM_ACE));
|
|
midl_user_free(ppcb->StreamACL.pACL);
|
|
} // if
|
|
|
|
ppcb->ulMaxNumOfStreamACEs = ulNewSize;
|
|
ppcb->StreamACL.pACL = pNewStreamACL;
|
|
} // if
|
|
|
|
return S_OK;
|
|
} // EnlargeStreamACL
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: ReadACLFromStream
|
|
//
|
|
// Summary: This function reads an ACL from an IStream object into the
|
|
// STREAM_ACL struture of an pickle control block.
|
|
//
|
|
// Args: IStream *pStm [in] - Pointer to an IStream object containing
|
|
// an ACL.
|
|
// PCB *ppcb [in,out] - Pointer to a PCB structure containing the
|
|
// STREAM_ACL into which the ACL in the IStream
|
|
// object is going to be decoded.
|
|
//
|
|
// Return: HRESULT - S_OK: Success.
|
|
// E_OUTOFMEMORY: The system ran out of memory for some
|
|
// crucial operation.
|
|
// CO_E_SETSERLHNDLFAILED: Unable to (re)set a serialization
|
|
// handle.
|
|
// CO_E_DECODEFAILED: Unable to decode the ACL in the
|
|
// IStream object.
|
|
// CO_E_INCOMPATIBLESTREAMVERSION: The version code in the
|
|
// stream header was not
|
|
// supported by this version
|
|
// of IAccessControl.
|
|
// CO_E_FAILEDTOCLOSEHANDLE: Unable to close a serialization
|
|
// handle.
|
|
// CO_E_EXCEEDSYSACLLIMIT: The number of ACEs in the ACL
|
|
// provided by the user exceeded the
|
|
// limit imposed by the system that
|
|
// is loading the ACL. On Windows 95,
|
|
// the system can handle 32767
|
|
// ACTRL_ACCESS_DENIED ACEs and 32767
|
|
// ACTRL_ACCESS_ALLOWED ACEs. On Windows NT,
|
|
// the system can only handle 32767
|
|
// ACTRL_ACCESS_DENIED and ACTRL_ACCESS_ALLOWED ACEs
|
|
// combined.
|
|
// E_INVALIDARG: This method will return E_INVALIDARG if
|
|
// either
|
|
// a) the ACL in the stream provided by the
|
|
// user contains an invalid access mask, or
|
|
// b) one of STREAM_ACE structure in the ACL
|
|
// provided by the user contains a null
|
|
// pTrusteeName pointer.
|
|
// CO_E_ACESINWRONGORDER: Not all ACTRL_ACCESS_DENIED ACEs in the ACL
|
|
// provided by the user were arranged
|
|
// in front of the ACTRL_ACCESS_ALLOWED ACEs.
|
|
// CO_E_WRONGTRUSTEENAMESYNTAX: The ACL provided by the user
|
|
// contained a trustee name
|
|
// string that didn't conform
|
|
// to the <Domain>\<Account>
|
|
// syntax.
|
|
// CO_E_LOOKUPACCNAMEFAILED: (Window NT only) The system call,
|
|
// LookupAccountName, failed. The user can
|
|
// call GetLastError to obtain extended error
|
|
// information.
|
|
// CO_E_NOMATCHINGSIDFOUND: No matching security identifier
|
|
// could be found for one of the
|
|
// trustee name specified by the
|
|
// client.
|
|
//
|
|
// Called by: COAccessControl:CImpAccessControl::Load
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT ReadACLFromStream
|
|
(
|
|
IStream *pStm,
|
|
PCB *ppcb
|
|
#ifndef _CHICAGO_
|
|
,ACL_DESCRIPTOR *pACLDesc
|
|
#endif
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG ulBuffSize = 0;
|
|
STREAM_HEADER StreamHeader;
|
|
#ifndef _CHICAGO_
|
|
ULONG ulTotalSIDSize;
|
|
ULONG ulEstAdditionalSIDSize;
|
|
#endif
|
|
|
|
if (FAILED(hr = ResizePicklingBuff(ppcb, g_ulHeaderSize)))
|
|
{
|
|
return hr;
|
|
} // if
|
|
|
|
// Set up fixed buffer decoding handle
|
|
if ( MesDecodeBufferHandleCreate( ppcb->pPicklingBuff
|
|
, g_ulHeaderSize
|
|
, &(ppcb->PickleHandle)) != RPC_S_OK )
|
|
{
|
|
return CO_E_SETSERLHNDLFAILED;
|
|
} // if
|
|
|
|
if (FAILED(hr = pStm->Read((void *)(ppcb->pPicklingBuff), g_ulHeaderSize, NULL)))
|
|
{
|
|
return hr;
|
|
} // if
|
|
|
|
// Decode the stream header
|
|
RpcTryExcept
|
|
{
|
|
STREAM_HEADER_Decode(ppcb->PickleHandle, &StreamHeader);
|
|
}
|
|
RpcExcept(1)
|
|
{
|
|
return CO_E_DECODEFAILED;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if (StreamHeader.ulStreamVersion != STREAM_VERSION)
|
|
{
|
|
return CO_E_INCOMPATIBLESTREAMVERSION;
|
|
} // if
|
|
|
|
ulBuffSize = StreamHeader.ulPickledSize;
|
|
|
|
// Allocate a buffer that is big enough to hold the
|
|
// the stream
|
|
if (FAILED(hr = ResizePicklingBuff(ppcb, ulBuffSize + 800)))
|
|
{
|
|
return hr;
|
|
} // if
|
|
|
|
if(FAILED(hr = pStm->Read((void *)(ppcb->pPicklingBuff), ulBuffSize, NULL)))
|
|
{
|
|
return hr;
|
|
} // if
|
|
|
|
// Re-create a decoding handle
|
|
if (MesBufferHandleReset( ppcb->PickleHandle
|
|
, MES_FIXED_BUFFER_HANDLE
|
|
, MES_DECODE
|
|
, &(ppcb->pPicklingBuff)
|
|
, ppcb->ulPicklingBuffSize
|
|
, &(ppcb->ulBytesUsed)) != RPC_S_OK)
|
|
{
|
|
return CO_E_SETSERLHNDLFAILED;
|
|
} // if
|
|
|
|
// Decode the stream content into the stream ACL
|
|
RpcTryExcept
|
|
{
|
|
STREAM_ACL_Decode(ppcb->PickleHandle, &(ppcb->StreamACL));
|
|
}
|
|
RpcExcept(1)
|
|
{
|
|
return CO_E_DECODEFAILED;
|
|
}
|
|
RpcEndExcept
|
|
|
|
ppcb->ulBytesUsed = ulBuffSize;
|
|
|
|
// Free the decoding handle
|
|
hr = MesHandleFree(ppcb->PickleHandle);
|
|
ppcb->PickleHandle = NULL;
|
|
if (hr != RPC_S_OK)
|
|
{
|
|
return CO_E_FAILEDTOCLOSEHANDLE;
|
|
} // if
|
|
|
|
ppcb->bPickled = TRUE;
|
|
|
|
// Validate the stream ACL
|
|
#ifdef _CHICAGO_
|
|
if(FAILED(hr = ValidateAndFixStreamACL(&(ppcb->StreamACL))))
|
|
#else
|
|
if(FAILED(hr = ValidateAndFixStreamACL( &(ppcb->StreamACL)
|
|
, &ulTotalSIDSize
|
|
, &ulEstAdditionalSIDSize)))
|
|
#endif
|
|
{
|
|
if((hr != CO_E_NOMATCHINGSIDFOUND) && (hr != CO_E_LOOKUPACCNAMEFAILED))
|
|
{
|
|
return hr;
|
|
} // if
|
|
} // if
|
|
|
|
#ifndef _CHICAGO_
|
|
// Windows NT, the size of the ACL may have changed after
|
|
// fixing the stream ACL so we may have to reallocate the
|
|
// pickling buffer
|
|
if (ulEstAdditionalSIDSize > 0)
|
|
{
|
|
if(FAILED(hr = ResizePicklingBuff( ppcb
|
|
, ppcb->ulBytesUsed
|
|
+ ulEstAdditionalSIDSize
|
|
+ 800)))
|
|
{
|
|
return hr;
|
|
} // if
|
|
ppcb->bPickled = FALSE;
|
|
} // if
|
|
|
|
pACLDesc->ulSIDSize = ulTotalSIDSize;
|
|
|
|
#endif
|
|
return hr;
|
|
} // ReadACLFromStream
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: AddACEToStreamACL
|
|
//
|
|
// Summary: This function inserts a STREAM_ACE structure into an existing
|
|
// STREAM_ACE array in a PCB structure. This function assumes that
|
|
// the STREAM_ACL inside the pcb is large enough to hold the new entry.
|
|
//
|
|
// Args: STREAM_ACE *pStreamACE [in] - Pointer to the StreamACE structure to be added
|
|
//
|
|
// PCB *ppcb [in,out] - Pointer to the pickle control block that contains
|
|
// the stream ACL to which the new stream ACE is added.
|
|
//
|
|
// Return: void
|
|
//
|
|
// Called by: COAccessControl:CImpAccessControl::GrantAccessRights
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
void AddACEToStreamACL
|
|
(
|
|
STREAM_ACE *pStreamACE,
|
|
PCB *ppcb
|
|
)
|
|
{
|
|
STREAM_ACE *pLastEntry; // Pointer to the last ACE with the specified
|
|
// access mode
|
|
STREAM_ACE *pInsertionPoint; // Pointer to STREAM_ACE slot in the STREAM_ACE
|
|
// array that the new STREAM_ACE structure will be
|
|
// inserted.
|
|
|
|
pLastEntry = ppcb->StreamACL.pACL
|
|
+ ppcb->ulNumOfStreamACEs;
|
|
if (pStreamACE->grfAccessMode == ACTRL_ACCESS_DENIED)
|
|
{
|
|
pInsertionPoint = ppcb->StreamACL.pACL
|
|
+ ppcb->StreamACL.ulNumOfDenyEntries;
|
|
memcpy(pLastEntry, pInsertionPoint, sizeof(STREAM_ACE));
|
|
ppcb->StreamACL.ulNumOfDenyEntries++;
|
|
}
|
|
else
|
|
{
|
|
pInsertionPoint = pLastEntry;
|
|
ppcb->StreamACL.ulNumOfGrantEntries++;
|
|
}
|
|
|
|
memcpy(pInsertionPoint, pStreamACE, sizeof(STREAM_ACE));
|
|
ppcb->ulNumOfStreamACEs++;
|
|
|
|
} // AddACEToStreamACL
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: IsValidAccessMask
|
|
//
|
|
// Summary: This function checks if an access permission mask provided by
|
|
// the user is valid or not.
|
|
//
|
|
// Args: DWORD stdmask [in] - Standard mask to be validated.
|
|
//
|
|
// Return: BOOL - TRUE: The mask is valid
|
|
// FALSE: Otherwise
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
BOOL IsValidAccessMask
|
|
(
|
|
DWORD stdmask
|
|
)
|
|
{
|
|
return ((stdmask & ~COM_RIGHTS_ALL) ? FALSE : TRUE);
|
|
} // IsValidAccessMask
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: DeleteACEFromStreamACL
|
|
//
|
|
// Summary: This function remove all the ACEs that matches the input trustee
|
|
// name from the stream ACL.
|
|
//
|
|
// Args: LPWSTR pTrustee [in] - Pointer to the trustee string that identifies
|
|
// the ACE to be removed from the stream ACL.
|
|
// ULONG AccessMode [in] - Access mode of the entry that the
|
|
// the caller is interested in removing.
|
|
// SID_TRUSTEE *pSIDTrustee [out] - (Windows NT only) Pointer to
|
|
// a SID_TRUSTEE structure. This structure is used to pass
|
|
// out the string name and the SID of first ACE removed from
|
|
// the STREAM_ACL. These two pieces of information are
|
|
// used by the caller to update the cache and the
|
|
// caller must free the memory for the SID and
|
|
// trustee name afterwards.
|
|
// PCB *ppcb [in,out] - Pointer to the pickle control block which
|
|
// contains a STREAM_ACL structure.
|
|
//
|
|
// Return: BOOL FALSE: Successful completion of the operation but the trustee
|
|
// could not be found in the relevant portion of the
|
|
// STREAM_ACE array inside the STREAM_ACL structure.
|
|
// TRUE: Successful completion of the operation. All the
|
|
// ACEs that have a matching trustee name from the
|
|
// relevant portion of STREAM_ACE array.
|
|
//
|
|
// Called by: COAccessControl::CImpAccessControl::RevokeAccessRights.
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
BOOL DeleteACEFromStreamACL
|
|
(
|
|
PTRUSTEE_W pTrustee,
|
|
ULONG AccessMode,
|
|
#ifndef _CHICAGO_
|
|
ACL_DESCRIPTOR *pACLDesc,
|
|
#endif
|
|
PCB *ppcb
|
|
)
|
|
{
|
|
ULONG i; // Loop counter
|
|
STREAM_ACE *pStreamACE; // Pointer for traversing the array
|
|
// of STREAM_ACE structures inside the
|
|
// STREAM_ACL structure of the pickle control block.
|
|
STREAM_ACE *pLastEntry; // Pointer to the 'last' ACE with the
|
|
// the specified access mode.
|
|
ULONG *pulNumOfEntries; // The total number of ACEs in the STREAM_ACL
|
|
// structure with the specified
|
|
// acces mode.
|
|
BOOL bResult = FALSE; // Internal function return code.
|
|
|
|
switch (AccessMode)
|
|
{
|
|
case ACTRL_ACCESS_DENIED:
|
|
pulNumOfEntries = &(ppcb->StreamACL.ulNumOfDenyEntries);
|
|
pStreamACE = ppcb->StreamACL.pACL;
|
|
break;
|
|
case ACTRL_ACCESS_ALLOWED:
|
|
pulNumOfEntries = &(ppcb->StreamACL.ulNumOfGrantEntries);
|
|
pStreamACE = ppcb->StreamACL.pACL
|
|
+ ppcb->StreamACL.ulNumOfDenyEntries;
|
|
break;
|
|
} // switch
|
|
|
|
pLastEntry = ppcb->StreamACL.pACL
|
|
+ ppcb->StreamACL.ulNumOfGrantEntries
|
|
+ ppcb->StreamACL.ulNumOfDenyEntries - 1;
|
|
|
|
for (i = 0; i < *pulNumOfEntries ; i++ )
|
|
{
|
|
|
|
// The following while loop is necessary to handle
|
|
// cases where the matching STREAM_ACEs are bunched
|
|
// up at the 'end' of the relevant portion of the
|
|
// STREAM_ACE array.
|
|
#ifdef _CHICAGO_
|
|
while( (i < *pulNumOfEntries) &&
|
|
(lstrcmpiW( pTrustee->ptstrName
|
|
, pStreamACE->pTrusteeName) == 0))
|
|
|
|
#else
|
|
while( (i < *pulNumOfEntries) &&
|
|
(((pTrustee->TrusteeForm == TRUSTEE_IS_NAME) &&
|
|
(lstrcmpiW( pTrustee->ptstrName
|
|
, pStreamACE->pTrusteeName) == 0)) ||
|
|
((pTrustee->TrusteeForm == TRUSTEE_IS_SID) &&
|
|
(pStreamACE->pSID != NULL &&
|
|
EqualSid( (PSID)(pTrustee->ptstrName)
|
|
, (PSID)(pStreamACE->pSID))))))
|
|
#endif
|
|
{
|
|
(*pulNumOfEntries)--;
|
|
ppcb->ulNumOfStreamACEs--;
|
|
#ifndef _CHICAGO_
|
|
if (pStreamACE->pSID != NULL)
|
|
{
|
|
pACLDesc->ulSIDSize -= GetLengthSid(pStreamACE->pSID);
|
|
midl_user_free(pStreamACE->pSID);
|
|
} // if
|
|
#endif
|
|
midl_user_free(pStreamACE->pTrusteeName);
|
|
switch(AccessMode)
|
|
{
|
|
case ACTRL_ACCESS_DENIED:
|
|
if (i < (*pulNumOfEntries))
|
|
{
|
|
memcpy( pStreamACE
|
|
, ppcb->StreamACL.pACL + *pulNumOfEntries
|
|
, sizeof(STREAM_ACE));
|
|
} // if
|
|
memcpy( ppcb->StreamACL.pACL + *pulNumOfEntries
|
|
, pLastEntry
|
|
, sizeof(STREAM_ACE));
|
|
|
|
break;
|
|
case ACTRL_ACCESS_ALLOWED:
|
|
if (i < (*pulNumOfEntries))
|
|
{
|
|
memcpy(pStreamACE, pLastEntry, sizeof(STREAM_ACE));
|
|
} // if
|
|
break;
|
|
} // switch
|
|
|
|
memset(pLastEntry, 0, sizeof(STREAM_ACE));
|
|
pLastEntry--;
|
|
bResult = TRUE;
|
|
} // while
|
|
pStreamACE++;
|
|
} // for
|
|
return bResult;
|
|
|
|
} // DeleteACEFromStreamACL
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: MapStreamACLToAccessList
|
|
//
|
|
// Summary: This function maps a stream ACL to an array of
|
|
// ACTRL_ACCESS_ENTRY structures. This function allocates all
|
|
// memory needed for the output access list. It cleans up all
|
|
// memory in case of error.
|
|
//
|
|
// Return: HRESULT S_OK: Succeeded
|
|
// E_OUTOFMEMORY: The system ran out of memory for allocating
|
|
// the trustee identifiers to be returned.
|
|
//
|
|
// Called by: COAccessControl::CImpAccessControl::GetAllAccessRights
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT MapStreamACLToAccessList
|
|
(
|
|
PCB *ppcb,
|
|
PACTRL_ACCESSW *ppAccessList
|
|
)
|
|
{
|
|
PACTRL_ACCESSW pAccessList;
|
|
PACTRL_PROPERTY_ENTRYW pProperty;
|
|
PACTRL_ACCESS_ENTRY_LISTW pEntryList;
|
|
PACTRL_ACCESS_ENTRYW pEntry;
|
|
PACTRL_ACCESS_ENTRYW pCurrEntry;
|
|
char *pTrusteeName;
|
|
|
|
STREAM_ACE *pStreamACEsPtr; // Pointer for stepping through
|
|
// the stream ACL
|
|
ULONG i = 0;
|
|
LPWSTR pwszName; // Pointer to the trustee name
|
|
// inside the stream ACE of the
|
|
// current iteration
|
|
ULONG ulNumOfEntries; // Total number of stream ACEs to map
|
|
ULONG ulSize;
|
|
|
|
// Compute the amount of memory needed for the trustee names and sids.
|
|
ulNumOfEntries = ppcb->ulNumOfStreamACEs;
|
|
pStreamACEsPtr = ppcb->StreamACL.pACL;
|
|
ulSize = 0;
|
|
for (i = 0; i < ulNumOfEntries; i++)
|
|
{
|
|
#ifndef _CHICAGO_
|
|
if(pStreamACEsPtr->TrusteeForm == TRUSTEE_IS_NAME)
|
|
{
|
|
#endif
|
|
ulSize += (lstrlenW(pStreamACEsPtr->pTrusteeName) + 1) *
|
|
sizeof(WCHAR);
|
|
#ifndef _CHICAGO_
|
|
}
|
|
else
|
|
{
|
|
ulSize += GetLengthSid((PISID)pStreamACEsPtr->pSID);
|
|
} // if
|
|
#endif
|
|
pStreamACEsPtr++;
|
|
} // for
|
|
|
|
// Allocate memory for everything
|
|
ulSize += sizeof(ACTRL_ACCESSW) + sizeof(ACTRL_PROPERTY_ENTRYW) +
|
|
sizeof(ACTRL_ACCESS_ENTRY_LISTW) +
|
|
sizeof(ACTRL_ACCESS_ENTRYW) * ulNumOfEntries;
|
|
pAccessList = (PACTRL_ACCESSW) LocalMemAlloc( ulSize );
|
|
if (pAccessList == NULL)
|
|
{
|
|
*ppAccessList = NULL;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
pProperty = (PACTRL_PROPERTY_ENTRYW) (pAccessList + 1);
|
|
pEntryList = (PACTRL_ACCESS_ENTRY_LISTW) (pProperty + 1);
|
|
if (ulNumOfEntries != 0)
|
|
{
|
|
pEntry = (PACTRL_ACCESS_ENTRYW) (pEntryList + 1);
|
|
pTrusteeName = (char *) (pEntry + ulNumOfEntries);
|
|
}
|
|
else
|
|
{
|
|
pEntry = NULL;
|
|
}
|
|
|
|
// Initialize the top three levels of structures.
|
|
pAccessList->cEntries = 1;
|
|
pAccessList->pPropertyAccessList = pProperty;
|
|
pProperty->lpProperty = NULL;
|
|
pProperty->pAccessEntryList = pEntryList;
|
|
pProperty->fListFlags = 0;
|
|
pEntryList->cEntries = ulNumOfEntries;
|
|
pEntryList->pAccessList = pEntry;
|
|
|
|
pCurrEntry = pEntry;
|
|
pStreamACEsPtr = ppcb->StreamACL.pACL;
|
|
for (i = 0; i < ulNumOfEntries; i++)
|
|
{
|
|
pwszName = pStreamACEsPtr->pTrusteeName;
|
|
|
|
// On Windows 95, the only form of trustee identifier supported is
|
|
// a Unicode string while a security identifier or a Unicode string
|
|
// can be used to specify a trustee on Windows NT.
|
|
#ifndef _CHICAGO_
|
|
if(pStreamACEsPtr->TrusteeForm == TRUSTEE_IS_NAME)
|
|
{
|
|
#endif
|
|
ulSize = (lstrlenW(pwszName) + 1) * sizeof(WCHAR);
|
|
memcpy( pTrusteeName, pwszName, ulSize );
|
|
#ifndef _CHICAGO_
|
|
}
|
|
else
|
|
{
|
|
ulSize = GetLengthSid((PISID)pStreamACEsPtr->pSID);
|
|
CopySid(ulSize, (PSID)pTrusteeName, pStreamACEsPtr->pSID);
|
|
} // if
|
|
#endif
|
|
pCurrEntry->Trustee.ptstrName = (WCHAR *) pTrusteeName;
|
|
pCurrEntry->Trustee.TrusteeType = pStreamACEsPtr->TrusteeType;
|
|
pCurrEntry->Trustee.TrusteeForm = pStreamACEsPtr->TrusteeForm;
|
|
pCurrEntry->Trustee.pMultipleTrustee = NULL; // Not supported
|
|
pCurrEntry->Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; // Not supported
|
|
pCurrEntry->Access = pStreamACEsPtr->grfAccessPermissions;
|
|
pCurrEntry->ProvSpecificAccess = 0;
|
|
pCurrEntry->Inheritance = NO_INHERITANCE; // Not supported
|
|
pCurrEntry->lpInheritProperty = NULL;
|
|
pCurrEntry->fAccessFlags = pStreamACEsPtr->grfAccessMode;
|
|
pTrusteeName += ulSize;
|
|
pStreamACEsPtr++;
|
|
pCurrEntry++;
|
|
} // for
|
|
|
|
*ppAccessList = pAccessList;
|
|
return S_OK;
|
|
} // MapStreamACLToAccessList
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: CleanAllMemoryResources()
|
|
//
|
|
// Summary: This function frees all the memory allocated for an initialized
|
|
// COAccessControl object. On Windows 95, this function will release
|
|
// all the memory allocated for the ACL_DESCRIPTOR structure except
|
|
// for the two resource name in the LAN Manager ACL embedded in the
|
|
// ACL_DESCRIPTOR structure. The idea behind such an arrange is to
|
|
// reuse existing resource as much as possible so that performanace
|
|
// can be improved.
|
|
//
|
|
// Args: ACL_DESCRIPTOR *pACLDesc [in,out] - This structure describes
|
|
// how DCOM IAccessControl implementaion object packages
|
|
// platform specific ACL.
|
|
// PCB *ppcb [in,out] - The pickling control block owned by the
|
|
// same object.
|
|
//
|
|
// Return: void
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
void CleanAllMemoryResources
|
|
(
|
|
ACL_DESCRIPTOR *pACLDesc,
|
|
PCB *ppcb
|
|
)
|
|
{
|
|
// Clean up old Stream ACL
|
|
FreePicklingBuff(ppcb);
|
|
MesHandleFree(ppcb->PickleHandle);
|
|
CleanUpStreamACL(&(ppcb->StreamACL));
|
|
|
|
// Cleanup the ACL images
|
|
#ifdef _CHICAGO_
|
|
CleanUpACLImage(&(pACLDesc->DenyACL));
|
|
CleanUpACLImage(&(pACLDesc->GrantACL));
|
|
#else
|
|
LocalMemFree(pACLDesc->pACLBuffer);
|
|
LocalMemFree(pACLDesc->SecDesc.Owner);
|
|
LocalMemFree(pACLDesc->SecDesc.Group);
|
|
#endif
|
|
|
|
} // CleanAllMemoryResources
|
|
|
|
#ifdef _CHICAGO_
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: ComputeEffectiveAccess, Chicago version
|
|
//
|
|
// Summary: Given the trustee name, and the ACL descritpor, this function
|
|
// computes the effective access rights that a the trustee has.
|
|
//
|
|
// Args: LPWSTR pTrustee [in] - Pointer to a NULL terminated Unicode string
|
|
// that represents the trustee.
|
|
// DWORD *pEffectiveRights [out] - Reference to a 32-bit bit mask that
|
|
// represents the set of access rights
|
|
// the trustee has.
|
|
// ACL_DESCRIPTOR *pACLDesc [in] - Platform dependent representation
|
|
// of the ACL.
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// E_OUTOFMEMORY: Not enough memory to transform the Unicode
|
|
// trustee string to a multibyte string.
|
|
// CO_E_CONVERSIONFAILED: WideCharToMultiByte returned
|
|
// error. The user can call
|
|
// GetLastError to get extended
|
|
// error information.
|
|
// CO_E_NETACCESSAPIFAILED: One one the NetAccess functions
|
|
// called in this function
|
|
// returned an error code.
|
|
//
|
|
// Called by: COAccessControl::CImpAccessControl::IsAccessAllowed
|
|
// COAccessControl::CImpAccessControl::GetEffectiveAccessRights
|
|
//
|
|
// Notes: NetAccessAdd on some machines adds "*" when you call with a list
|
|
// with no entries.
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT ComputeEffectiveAccess
|
|
(
|
|
LPWSTR pTrustee,
|
|
DWORD *pEffectivePermissions,
|
|
ACL_DESCRIPTOR *pACLDesc
|
|
)
|
|
{
|
|
CHAR *pName;
|
|
API_RET_TYPE uReturnCode;
|
|
CHAR *pResource;
|
|
access_info_1 *pACLHeader;
|
|
USHORT uResult;
|
|
HRESULT hr = S_OK;
|
|
|
|
if(FAILED(hr = WStringToMBString(pTrustee, &pName)))
|
|
{
|
|
return hr;
|
|
}
|
|
// Start checking from the list of deny entries
|
|
|
|
// See if the deny mode list is dirty, and update the registry if necessary
|
|
pACLHeader = pACLDesc->DenyACL.pACL;
|
|
pResource = pACLHeader->acc1_resource_name;
|
|
|
|
// Skip this if the ACL is empty.
|
|
if (pACLHeader->acc1_count != 0)
|
|
{
|
|
if (pACLDesc->DenyACL.bDirtyACL)
|
|
{
|
|
NetAccessDel(NULL, pResource);
|
|
|
|
// Notice that NetAccessAdd puts data into the registry
|
|
if( NERR_Success != NetAccessAdd( NULL
|
|
, 2
|
|
, (char *)pACLHeader
|
|
, sizeof(access_info_1)
|
|
+ pACLHeader->acc1_count
|
|
* sizeof(access_list_2)))
|
|
{
|
|
hr = CO_E_NETACCESSAPIFAILED;
|
|
goto Error;
|
|
} // if
|
|
pACLDesc->DenyACL.bDirtyACL = FALSE;
|
|
} // if
|
|
|
|
if ( NERR_Success != NetAccessCheck( NULL
|
|
, pName
|
|
, pResource
|
|
, CHICAGO_RIGHTS_EXECUTE
|
|
, &uResult) )
|
|
{
|
|
hr = CO_E_NETACCESSAPIFAILED;
|
|
goto Error;
|
|
} // if
|
|
|
|
// Negate the result of access checking on the deny list.
|
|
// I.e. if the result is positive, the user is explicitly denied
|
|
// access to the object.
|
|
|
|
if (uResult == 0)
|
|
{
|
|
*pEffectivePermissions = 0; // hard coded to zero
|
|
LocalMemFree(pName);
|
|
return S_OK;
|
|
} // if
|
|
}
|
|
|
|
// If the previous result is negative, we have to
|
|
// move on to see if the user is granted access through
|
|
// the grant ACL.
|
|
pACLHeader = pACLDesc->GrantACL.pACL;
|
|
pResource = pACLHeader->acc1_resource_name;
|
|
|
|
// If there are no Allow ACEs, deny access.
|
|
if (pACLHeader->acc1_count == 0)
|
|
{
|
|
*pEffectivePermissions = 0; // hard coded to zero
|
|
LocalMemFree(pName);
|
|
return S_OK;
|
|
} // if
|
|
|
|
// See if the grant mode list is dirty and update the registry if necessary
|
|
if (pACLDesc->GrantACL.bDirtyACL)
|
|
{
|
|
NetAccessDel(NULL, pResource);
|
|
|
|
if( NERR_Success != NetAccessAdd( NULL
|
|
, 2
|
|
, (char *)pACLHeader
|
|
, sizeof(access_info_1)
|
|
+ pACLHeader->acc1_count
|
|
* sizeof(access_list_2)))
|
|
{
|
|
hr = CO_E_NETACCESSAPIFAILED;
|
|
goto Error;
|
|
} // if
|
|
pACLDesc->GrantACL.bDirtyACL = FALSE;
|
|
} // if
|
|
|
|
if ( NERR_Success != NetAccessCheck( NULL
|
|
, pName
|
|
, pResource
|
|
, CHICAGO_RIGHTS_EXECUTE
|
|
, &uResult) )
|
|
{
|
|
hr = CO_E_NETACCESSAPIFAILED;
|
|
goto Error;
|
|
} // if
|
|
|
|
if (uResult == 0)
|
|
{
|
|
*pEffectivePermissions = COM_RIGHTS_EXECUTE;
|
|
}
|
|
else
|
|
{
|
|
*pEffectivePermissions = 0;
|
|
} // if
|
|
|
|
|
|
Error:
|
|
LocalMemFree(pName);
|
|
return hr;
|
|
|
|
} // ComputeEffectiveAccess
|
|
#else
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: ComputeEffectiveAccess, NT version
|
|
//
|
|
// Summary: Given a handle to an access token representing a user, an
|
|
// ACL_DESCRIPTOR structure and a STREAM_ACL structure , this function
|
|
// will compute the effective access permissions that the user
|
|
// represented by the access token has.
|
|
//
|
|
// Args: ACL_DESCRIPTOR *pACLDesc [in,out] - Pointer to the NT version of the
|
|
// ACL_DESCRIPTOR structure. Thsi structure should contain
|
|
// a buffer for the NT ACL structure, a NT security
|
|
// descriptor, a control flag and size information.
|
|
// STREAM_ACL *pStreamACL [in] - It may be the case that the STREAM_ACL
|
|
// structure of an DCOM IAccessControl implementation object
|
|
// has not been mapped into the security descriptor's dacl
|
|
// inside the ACL_DESCRIPTOR, so it is necessary that object
|
|
// that calls this function to pass in its STREAM_ACL
|
|
// structure. In fact, this is only place where a STREAM_ACL
|
|
// will be mapped into a dacl.
|
|
// HANDLE TokenHandle [in] - This should be the access token of the
|
|
// user that the caller wants to compute the effective access
|
|
// permissions for.
|
|
// DWORD *pdwRights [out] - Address of the effective access permissions
|
|
// that the user corresponding to the
|
|
// access token specified in the TokenHandle
|
|
// has on the secured object.
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// E_OUTOFMEMORY: The system ran out of memory for
|
|
// allocating the NT ACL.
|
|
// CO_E_FAILEDTOSETDACL: SetSecurityDescriptorDacl returned
|
|
// false inside PutStreamACLIntoSecDesc.
|
|
// The client of this method can call
|
|
// GetLastError to get extended error
|
|
// information.
|
|
// CO_E_ACCESSCHECKFAILED: The system function, AccessCheck,
|
|
// returned FALSE in
|
|
// ComputeEffectiveAccess. The
|
|
// caller of this method can call
|
|
// GetLastError to obtain extended
|
|
// error information.
|
|
//
|
|
//
|
|
// Called by: COAccessControl:CImpAccessControl:GetEffAccRightsUsingName
|
|
// COAccessControl:CImpAccessControl:GetEffAccRightsUsingSID
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT ComputeEffectiveAccess
|
|
(
|
|
ACL_DESCRIPTOR *pACLDesc,
|
|
STREAM_ACL *pStreamACL,
|
|
HANDLE TokenHandle,
|
|
DWORD *pdwRights
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ACCESS_MASK AccessMaskOut = 0; // Access mask returned by
|
|
// AccessCheck
|
|
ACCESS_MASK AccessMaskIn = 0; // Access permissions to check for
|
|
BOOL bAccessStatus; // Access checking status.
|
|
// TRUE - Access granted.
|
|
// FALSE - Access denied.
|
|
// This function doesn't really care
|
|
// about this result, all it wants
|
|
// is the set the of permissions
|
|
// that a user effectively has.
|
|
DWORD dwSetLen; // Length of the privilege set.
|
|
|
|
dwSetLen = sizeof(gDummyPrivilege);
|
|
|
|
// If the ACL has not been set into the security
|
|
// security inside the ACL descriptor, do so now.
|
|
if (pACLDesc->bDirtyACL)
|
|
{
|
|
if(FAILED(hr = PutStreamACLIntoSecDesc( pStreamACL
|
|
, pACLDesc)))
|
|
{
|
|
return hr;
|
|
} // if
|
|
|
|
} // if
|
|
|
|
// Call access check
|
|
if(!AccessCheck( &(pACLDesc->SecDesc)
|
|
, TokenHandle
|
|
, NT_RIGHTS_ALL
|
|
, &gDummyMapping
|
|
, &gDummyPrivilege
|
|
, &dwSetLen
|
|
, &AccessMaskOut
|
|
, &bAccessStatus))
|
|
{
|
|
return CO_E_ACCESSCHECKFAILED;
|
|
} // if
|
|
|
|
// Convert the NT access mask back to IAccessControl access mask.
|
|
NTMaskToStandardMask(&AccessMaskOut, pdwRights);
|
|
|
|
return S_OK;
|
|
|
|
|
|
} // ComputeEffectiveAccess
|
|
|
|
#endif
|
|
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: ValidateAndTransformAccReqList
|
|
//
|
|
// Summary: This function validates the fields inside a list of ACCESS_REQUEST
|
|
// structures and transform it into a list of stream ACE structures.
|
|
// This function is
|
|
// also responsible for estimating the total size of the STREAM_ACE
|
|
// structures returned to the caller if they are serialized into a
|
|
// buffer using RPC serialization service. On WIndows 95, this function
|
|
// will set up an array of access_list_2 structures representing the
|
|
// input access request list for the caller. On Windows NT, this function
|
|
// will lookup the SID or the trustee name for each access request depending
|
|
// on which one is specified by the caller.
|
|
//
|
|
// Args: PACCESS_REQUEST_W pAccReqList [in] - Pointer to the access request to
|
|
// be validated and transformed.
|
|
// ULONG ulNumOfRequestIn [in] - Number of ACCESS_REQUEST_W structures
|
|
// STREAM_ACE **ppStreamACEs [out] - Pointer to an array of stream ACEs
|
|
// transformed from the access request list. The array of
|
|
// STREAM_ACE structures and the SID and trustee name inside
|
|
// each of the STREAM_ACE structure returned are allocated by
|
|
// this function using midl_user_allocate so the caller should
|
|
// release the memory allocated for these structures using
|
|
// midl_user_allocate.
|
|
// access_list_2 **ppACEs [out] - (Chicago only)Address of a pointer to
|
|
// an array of access_list_2 structures to be returned to the
|
|
// caller. Notice that this function will allocate memory
|
|
// for the array and the User/group name in each of
|
|
// access_list_2 structure returned using LocalMemAlloc.
|
|
// Once the caller receives this output parameter, it
|
|
// becomes the caller's responsiblility to release the
|
|
// memory allocated for this structure when it is no
|
|
// longer in use.
|
|
// ULONG *pulEstPickledSize [out] - Pointer to the estimated number of
|
|
// bytes needed for serializing the
|
|
// STREAM_ACE structures returned. The
|
|
// estimated
|
|
// number of bytes required to serialize
|
|
// a STREAM_ACE structure into a buffer
|
|
// using RPC serialization service is
|
|
// computed by the folowing formula:
|
|
// Size of the Unicode trustee string + Size of the SID + Size of the
|
|
// STREAM_ACE structure + 48
|
|
// The number 48 is an arbitrary large number that should account for
|
|
// all the extra space required by RPC to align the data structure and
|
|
// to add additional information to the header.
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// E_OUTOFMEMORY: The system ran out of memory for some
|
|
// crucial operations.
|
|
// E_INVALIDARG: The access mask in one of the
|
|
// ACCESS_REQUEST_W structures was invalid of
|
|
// the TRUSTEE structure provided by the user
|
|
// was invalid.
|
|
// CO_E_CONVERSIONFAILED: WideCharToMultiByte returned zero.
|
|
// The caller can get extended error
|
|
// information by calling GetLastError.
|
|
// CO_E_INVALIDSID: At least one of the TRUSTEE_W structures
|
|
// specified by the user contained an invalid
|
|
// security identifier.
|
|
// CO_E_NOMATCHINGNAMEFOUND: No matching account name
|
|
// could be found for one of the security identifiers
|
|
// specified by the client.
|
|
// CO_E_LOOKUPACCSIDFAILED: The system function,
|
|
// LookupAccountSID, failed. The client can call
|
|
// GetLastError to obtain extended error inforamtion.
|
|
// CO_E_NOMATCHINGSIDFOUND: No matching security identifier
|
|
// could be found for one of the
|
|
// trustee name specified by the
|
|
// client.
|
|
// CO_E_LOOKUPACCNAMEFAILED: The system function,
|
|
// LookupAccountName, failed. The client can call
|
|
// GetLastError to obtain extended error information.
|
|
//
|
|
// Called by: COAccessControl::CImpAccessControl::GrantAccessRights
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT ValidateAndTransformAccReqList
|
|
(
|
|
PACTRL_ACCESSW pAccessList,
|
|
STREAM_ACE **ppStreamACEs,
|
|
void **ppACEs,
|
|
ULONG *pulEstPickledSize,
|
|
ULONG *pcGrant,
|
|
ULONG *pcDeny
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
STREAM_ACE *pStreamACEs; // Pointer to an array of stream ACEs
|
|
STREAM_ACE *pStreamACEsPtr; // Pointer for traversing the
|
|
// array of stream ACEs
|
|
PACTRL_ACCESS_ENTRYW pCurrEntry; // Pointer for traversing the
|
|
// access request list
|
|
PTRUSTEE_W pTrustee; // Pointer to the TRUSTEE structure in
|
|
// the access request structure
|
|
#ifdef _CHICAGO_
|
|
DWORD dwLastError; // GetLastError return code holder
|
|
access_list_2 *pACEs; // Pointer to an array of access_list_2
|
|
// structures to be returned to the caller
|
|
access_list_2 *pACEsPtr; // Pointer for traversing the array of
|
|
// access_list_2 structures.
|
|
#else
|
|
ULONG ulSIDLen; // Length of the SID that is currently being
|
|
// examined.
|
|
#endif
|
|
ULONG ulStrLen; // Length of the trustee string in number
|
|
// of Unicode characters
|
|
ULONG i,j; // Loop counters
|
|
ULONG ulEstPickledSize = 0; // Estimated pickled size of the access
|
|
// requests if they all turn into stream ACEs
|
|
TRUSTEE_TYPE TrusteeType = TRUSTEE_IS_UNKNOWN;
|
|
ULONG cCount;
|
|
|
|
// Initialize ACE counts.
|
|
*pcGrant = 0;
|
|
*pcDeny = 0;
|
|
|
|
// Validate the top three levels of the structure.
|
|
if (pAccessList == NULL ||
|
|
pAccessList->cEntries != 1 ||
|
|
pAccessList->pPropertyAccessList == NULL ||
|
|
pAccessList->pPropertyAccessList->lpProperty != NULL ||
|
|
pAccessList->pPropertyAccessList->fListFlags != 0 ||
|
|
pAccessList->pPropertyAccessList->pAccessEntryList == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
cCount = pAccessList->pPropertyAccessList->pAccessEntryList->cEntries;
|
|
pCurrEntry = pAccessList->pPropertyAccessList->pAccessEntryList->pAccessList;
|
|
if (cCount != 0 && pCurrEntry == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// Allocate an array of stream ACEs
|
|
pStreamACEs = (STREAM_ACE *)LocalMemAlloc( sizeof(STREAM_ACE) * cCount);
|
|
if (pStreamACEs == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
} // if
|
|
|
|
#ifdef _CHICAGO_
|
|
pACEs = (access_list_2 *)midl_user_allocate( sizeof(access_list_2)
|
|
* cCount);
|
|
|
|
if (pACEs == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
}
|
|
pACEsPtr = pACEs;
|
|
#endif
|
|
|
|
// Map the access requests to stream ACEs and validates the fields in
|
|
// of the access requests as we go along
|
|
pStreamACEsPtr = pStreamACEs;
|
|
for (i = 0; i < cCount; i++)
|
|
{
|
|
pTrustee = &(pCurrEntry->Trustee);
|
|
TrusteeType = pTrustee->TrusteeType;
|
|
|
|
// Validate this entry.
|
|
if (!IsValidAccessMask(pCurrEntry->Access))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Error;
|
|
} // if
|
|
if(FAILED(hr = ValidateTrustee(pTrustee)))
|
|
{
|
|
goto Error;
|
|
}
|
|
if (pCurrEntry->ProvSpecificAccess != 0 ||
|
|
pCurrEntry->Inheritance != NO_INHERITANCE ||
|
|
pCurrEntry->lpInheritProperty != NULL ||
|
|
(pCurrEntry->fAccessFlags != ACTRL_ACCESS_ALLOWED &&
|
|
pCurrEntry->fAccessFlags != ACTRL_ACCESS_DENIED))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Error;
|
|
}
|
|
|
|
#ifndef _CHICAGO_
|
|
if (pTrustee->TrusteeForm == TRUSTEE_IS_NAME)
|
|
{
|
|
#endif
|
|
ulStrLen = lstrlenW(pTrustee->ptstrName);
|
|
ulEstPickledSize += (ulStrLen + 1) * sizeof(WCHAR);
|
|
pStreamACEsPtr->pTrusteeName = (LPWSTR)
|
|
midl_user_allocate( (ulStrLen + 1) * sizeof(WCHAR));
|
|
if (pStreamACEsPtr->pTrusteeName == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
}
|
|
|
|
memcpy( pStreamACEsPtr->pTrusteeName
|
|
, pTrustee->ptstrName
|
|
, sizeof(WCHAR) * (ulStrLen + 1));
|
|
pStreamACEsPtr->pSID = NULL;
|
|
#ifndef _CHICAGO_
|
|
|
|
if (FAILED(hr = GetSIDFromName( (void **)&(pStreamACEsPtr->pSID)
|
|
, pStreamACEsPtr->pTrusteeName
|
|
, &TrusteeType)))
|
|
{
|
|
LocalMemFree(pStreamACEsPtr->pTrusteeName);
|
|
goto Error;
|
|
} // if
|
|
ulEstPickledSize += GetLengthSid(pStreamACEsPtr->pSID);
|
|
}
|
|
else
|
|
{
|
|
|
|
// Copy the SID to the stream ACE strusture
|
|
ulSIDLen = GetLengthSid((PISID)(pTrustee->ptstrName));
|
|
ulEstPickledSize += ulSIDLen;
|
|
pStreamACEsPtr->pSID = (PSTREAM_SID)midl_user_allocate(ulSIDLen);
|
|
if (pStreamACEsPtr->pSID == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
} //if
|
|
CopySid(ulSIDLen, (PSID)(pStreamACEsPtr->pSID),
|
|
(PSID)(pTrustee->ptstrName));
|
|
|
|
if(FAILED(hr = GetNameFromSID( &(pStreamACEsPtr->pTrusteeName)
|
|
, (PSID)(pStreamACEsPtr->pSID)
|
|
, &TrusteeType)))
|
|
{
|
|
LocalMemFree(pStreamACEsPtr->pSID);
|
|
goto Error;
|
|
} // if
|
|
|
|
ulEstPickledSize += lstrlenW(pStreamACEsPtr->pTrusteeName);
|
|
} // if
|
|
|
|
#endif
|
|
pStreamACEsPtr->TrusteeForm = pCurrEntry->Trustee.TrusteeForm;
|
|
pStreamACEsPtr->grfAccessPermissions = pCurrEntry->Access;
|
|
pStreamACEsPtr->TrusteeType = TrusteeType;
|
|
pStreamACEsPtr->grfAccessMode = (ACCESS_MODE) pCurrEntry->fAccessFlags;
|
|
if (pCurrEntry->fAccessFlags == ACTRL_ACCESS_ALLOWED)
|
|
{
|
|
(*pcGrant)++;
|
|
}
|
|
else
|
|
{
|
|
(*pcDeny)++;
|
|
}
|
|
pStreamACEsPtr++;
|
|
|
|
#ifdef _CHICAGO_
|
|
if (FAILED(hr = WStringToMBString(pTrustee->ptstrName, &(pACEsPtr->acl2_ugname))))
|
|
{
|
|
LocalMemFree(pStreamACEsPtr->pTrusteeName);
|
|
goto Error;
|
|
} // if
|
|
StandardMaskToLANManagerMask( &(pCurrEntry->Access)
|
|
, &(pACEsPtr->acl2_access));
|
|
if (pTrustee->TrusteeType == TRUSTEE_IS_GROUP)
|
|
{
|
|
pACEsPtr->acl2_access |= ACCESS_GROUP;
|
|
} // if
|
|
|
|
pACEsPtr++;
|
|
#endif
|
|
pCurrEntry++;
|
|
|
|
} // for
|
|
|
|
#ifdef _CHICAGO_
|
|
*ppACEs = pACEs;
|
|
#endif
|
|
*ppStreamACEs = pStreamACEs;
|
|
*pulEstPickledSize = ulEstPickledSize
|
|
+ cCount
|
|
* (sizeof(WCHAR)
|
|
+ 48 + sizeof(STREAM_ACE));
|
|
return S_OK;
|
|
|
|
Error:
|
|
pStreamACEsPtr = pStreamACEs;
|
|
#ifdef _CHICAGO_
|
|
pACEsPtr = pACEs;
|
|
#endif
|
|
|
|
// Release the memory allocated for the
|
|
// trustee strings and SIDs inside the
|
|
// each of the STREAM_ACE and access_list_2
|
|
// structures.
|
|
for ( j = 0; j < i; j++, pStreamACEsPtr++)
|
|
{
|
|
LocalMemFree(pStreamACEsPtr->pTrusteeName);
|
|
#ifdef _CHICAGO_
|
|
LocalMemFree(pACEsPtr->acl2_ugname);
|
|
pACEsPtr++;
|
|
#else
|
|
LocalMemFree(pStreamACEsPtr->pSID);
|
|
#endif
|
|
} // for
|
|
|
|
#ifdef _CHICAGO_
|
|
// Release the array of access_list_2 structures
|
|
if (pACEs != NULL)
|
|
{
|
|
LocalMemFree(pACEs);
|
|
|
|
} // if
|
|
#endif
|
|
|
|
// Release the array of STREAM_ACE structures
|
|
if (pStreamACEs != NULL)
|
|
{
|
|
LocalMemFree(pStreamACEs);
|
|
}
|
|
*pulEstPickledSize = 0;
|
|
*ppStreamACEs = NULL;
|
|
return hr;
|
|
|
|
} // ValidateAndTransformAccessRequests
|
|
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: ValidateAndFixStreamACL
|
|
//
|
|
// Summary: This function validates the fields in a STREAM_ACL structure and all
|
|
// the STREAM_ACE structures that it contains. On Windows 95, this function
|
|
// will make sure that the value of the TrusteeType field in
|
|
// each of the STREAM_ACE structure is TRUSTEE_IS_NAME. On Windows NT,
|
|
// this function will make sure that each STREAM_ACE structure contains
|
|
// both the trustee name and the SID. Besides making sure that both the
|
|
// trustee name and the SID are in every STREAM_ACE structure, this function
|
|
// has to compute the total size in bytes of all the SIDs in the
|
|
// stream ACL and the estimated "pickled" size of all the SIDs that
|
|
// this function has found missing in the original stream ACL on
|
|
// Windows NT.
|
|
//
|
|
// Args: STREAM_ACL *pStreamACL [in] - Pointer to the STREAM_ACL strucutre to be
|
|
// validated.
|
|
// On Windows NT:
|
|
// ULONG *pulTotalSIDSize [out] - Address of the total size of all the SIDs
|
|
// in the stream ACL in bytes. This number
|
|
// is used by other parts of the module to
|
|
// compute the expected size of the NT
|
|
// ACL.
|
|
// ULONG *pulEstAdditionalSIDSize [out] - Address of the estimated total
|
|
// size of all the missing SID
|
|
// that this function has filled-
|
|
// in when they are serialized into
|
|
// a buffer using the RPC serialization
|
|
// service. This number is used
|
|
// by the caller to estimate
|
|
// size of the buffer required to
|
|
// serialize the STREAM_ACL structure.
|
|
// The estimated number of bytes
|
|
// required for serializing each
|
|
// additonal SID is computed by
|
|
// the following formula:
|
|
// Size of the SID + 32
|
|
// Notice that it is neccessary to add extra bytes to the estimate
|
|
// because RPC may need extra bytes for alignment and additional
|
|
// information in the header. 32 is an arbitrary number that should
|
|
// be big enough to accomodate the extra bytes required for alignment
|
|
// and extra header information. Any estimate that produces a number
|
|
// greater than or equal to the actual serialized size of an SID
|
|
// should be considered as good asthe the one provided above.
|
|
//
|
|
// Return: HRESULT - S_OK: Success.
|
|
// CO_E_EXCEEDSYSACLLIMIT: The number of ACEs in the ACL
|
|
// provided by the user exceeded the
|
|
// limit imposed by the system that
|
|
// is loading the ACL. On Windows 95,
|
|
// the system can handle 32767
|
|
// ACTRL_ACCESS_DENIED ACEs and 32767
|
|
// ACTRL_ACCESS_ALLOWED ACEs. On Windows NT,
|
|
// the system can only handle 32767
|
|
// ACTRL_ACCESS_DENIED and ACTRL_ACCESS_ALLOWED ACEs
|
|
// combined.
|
|
// E_INVALIDARG: This function will return E_INVALIDARG if
|
|
// either
|
|
// a) the ACL in the stream provided by the
|
|
// user contains an invalid access mask, or
|
|
// b) one of STREAM_ACE structure in the ACL
|
|
// provided by the user contains a null
|
|
// pTrusteeName pointer.
|
|
// CO_E_ACESINWRONGORDER: Not all ACTRL_ACCESS_DENIED ACEs in the ACL
|
|
// provided by the user were arranged
|
|
// in front of the ACTRL_ACCESS_ALLOWED ACEs.
|
|
// CO_E_WRONGTRUSTEENAMESYNTAX: The ACL provided by the user
|
|
// contained a trustee name
|
|
// string that didn't conform
|
|
// to the <Domain>\<Account>
|
|
// syntax.
|
|
// CO_E_LOOKUPACCNAMEFAILED: (Window NT only) The system call,
|
|
// LookupAccountName, failed. The user can
|
|
// call GetLastError to obtain extended error
|
|
// information.
|
|
// E_OUTOFMEMORY: The system ran out of memory for some
|
|
// crucial operation.
|
|
// CO_E_NOMATCHINGSIDFOUND: (Windows NT only) At least one of the trustee
|
|
// name in the ACL provided by the user had
|
|
// no corresponding security identifier.
|
|
//
|
|
// Called by: ReadACLFromStream
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT ValidateAndFixStreamACL
|
|
(
|
|
#ifdef _CHICAGO_
|
|
STREAM_ACL *pStreamACL
|
|
#else
|
|
STREAM_ACL *pStreamACL,
|
|
ULONG *pulTotalSIDSize,
|
|
ULONG *pulEstAdditionalSIDSize
|
|
#endif
|
|
)
|
|
{
|
|
ULONG ulNumOfDenyEntries;
|
|
ULONG ulNumOfEntries;
|
|
STREAM_ACE *pStreamACEsPtr;
|
|
ULONG i;
|
|
ULONG AccessMode;
|
|
HRESULT hr = S_OK;
|
|
|
|
#ifndef _CHICAGO_
|
|
*pulTotalSIDSize = 0;
|
|
*pulEstAdditionalSIDSize = 0;
|
|
#endif
|
|
|
|
AccessMode = ACTRL_ACCESS_DENIED;
|
|
ulNumOfDenyEntries = pStreamACL->ulNumOfDenyEntries;
|
|
ulNumOfEntries = ulNumOfDenyEntries + pStreamACL->ulNumOfGrantEntries;
|
|
|
|
// Chicago cannot handle more than 32767 entries in each list
|
|
#ifdef _CHICAGO_
|
|
if(ulNumOfDenyEntries > 32767 || pStreamACL->ulNumOfGrantEntries > 32767)
|
|
{
|
|
return CO_E_EXCEEDSYSACLLIMIT;
|
|
} // if
|
|
#else // NT cannot handle more than 32767 entries combined
|
|
if(ulNumOfEntries > 32767)
|
|
{
|
|
return CO_E_EXCEEDSYSACLLIMIT;
|
|
} // if
|
|
#endif
|
|
|
|
for ( i = 0, pStreamACEsPtr = pStreamACL->pACL
|
|
; i < ulNumOfEntries
|
|
; i++, pStreamACEsPtr++)
|
|
{
|
|
if (i == ulNumOfDenyEntries)
|
|
{
|
|
AccessMode = ACTRL_ACCESS_ALLOWED;
|
|
} // if
|
|
|
|
if (!IsValidAccessMask(pStreamACEsPtr->grfAccessPermissions) ||
|
|
((pStreamACEsPtr->TrusteeType != TRUSTEE_IS_USER) &&
|
|
(pStreamACEsPtr->TrusteeType != TRUSTEE_IS_GROUP)))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
} // if
|
|
if((ULONG) pStreamACEsPtr->grfAccessMode != AccessMode)
|
|
{
|
|
// The stream ACL is either a) not in proper order, or
|
|
// b) doesn't contain the number of stream ACEs
|
|
// stated in the header.
|
|
hr = CO_E_ACESINWRONGORDER;
|
|
break;
|
|
} // if
|
|
|
|
if (FAILED(hr = ValidateTrusteeString(pStreamACEsPtr->pTrusteeName) ))
|
|
{
|
|
break;
|
|
} // if
|
|
|
|
#ifdef _CHICAGO_
|
|
pStreamACEsPtr->TrusteeForm = TRUSTEE_IS_NAME;
|
|
#else
|
|
if(pStreamACEsPtr->pSID == NULL)
|
|
{
|
|
if(!(FAILED(hr = GetSIDFromName( (void **)&(pStreamACEsPtr->pSID)
|
|
, pStreamACEsPtr->pTrusteeName
|
|
, &pStreamACEsPtr->TrusteeType))))
|
|
{
|
|
// 32 more bytes is added to the estimated pickled size of the SID
|
|
// because the RPC serialization mechanism may need extra space
|
|
// in the header and alignment.
|
|
*pulEstAdditionalSIDSize += GetLengthSid(pStreamACEsPtr->pSID)
|
|
+ 32;
|
|
} // if
|
|
|
|
|
|
} // if
|
|
else
|
|
{
|
|
if(!IsValidSid(pStreamACEsPtr->pSID))
|
|
{
|
|
hr = CO_E_INVALIDSID;
|
|
break;
|
|
} // if
|
|
} // if
|
|
|
|
if(pStreamACEsPtr->pSID != NULL)
|
|
{
|
|
*pulTotalSIDSize += GetLengthSid(pStreamACEsPtr->pSID);
|
|
}
|
|
else
|
|
{
|
|
pStreamACEsPtr->TrusteeType = TRUSTEE_IS_UNKNOWN;
|
|
} // if
|
|
|
|
#endif
|
|
|
|
} // for
|
|
return hr;
|
|
|
|
} // ValidateAndFixStreamACL
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: ValidateTrusteeString
|
|
//
|
|
// Summary: This function checks if a trustee string is not NULL.
|
|
//
|
|
// Args: LPWSTR pTrusteeName [in] - Pointer to the trustee name to be
|
|
// validated.
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT ValidateTrusteeString
|
|
(
|
|
LPWSTR pTrusteeName
|
|
)
|
|
{
|
|
if(pTrusteeName == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
} //if
|
|
|
|
// If we see the magic string that specifies everyone,
|
|
// we return S_OK.
|
|
if(pTrusteeName[0] == L'*' && pTrusteeName[1] == L'\0')
|
|
{
|
|
return S_OK;
|
|
} // if
|
|
|
|
// A more sophisticated check can be put in here
|
|
while(*pTrusteeName != L'\0')
|
|
{
|
|
if (*pTrusteeName == L'\\')
|
|
return S_OK;
|
|
pTrusteeName++;
|
|
}
|
|
return CO_E_WRONGTRUSTEENAMESYNTAX;
|
|
} // ValidateTrusteeString
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: ValidateTrustee
|
|
//
|
|
// Summary: This function validates the fields in a TRUSTEE_Wstructure.
|
|
//
|
|
// Args: PTRUSTEE_W pTrustee [in] - Pointer to the TRUSTEE_W structure
|
|
// to be validated.
|
|
//
|
|
// Return: HRESULT - S_OK: The TRUSTEE structure provided by the user was valid.
|
|
// E_INVALIDARG: The TRUSTEE structure provided by the user
|
|
// contained values that were not supported by
|
|
// the COM implementation of IAccessControl.
|
|
// CO_E_WRONGTRUSTEENAMESYNTAX: The trustee string doesn't
|
|
// contain the '\' character.
|
|
// Windows NT only
|
|
// CO_E_INVALIDSID: At least one of the TRUSTEE_W structures
|
|
// specified by the user contained an invalid
|
|
// security identifier.
|
|
//
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT ValidateTrustee
|
|
(
|
|
PTRUSTEE_W pTrustee
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if( (pTrustee == NULL) ||
|
|
(pTrustee->pMultipleTrustee != NULL) ||
|
|
(pTrustee->MultipleTrusteeOperation != NO_MULTIPLE_TRUSTEE) ||
|
|
#ifdef _CHICAGO_
|
|
(pTrustee->TrusteeForm != TRUSTEE_IS_NAME) ||
|
|
#else
|
|
((pTrustee->TrusteeForm != TRUSTEE_IS_NAME) &&
|
|
(pTrustee->TrusteeForm != TRUSTEE_IS_SID)) ||
|
|
#endif
|
|
((pTrustee->TrusteeType != TRUSTEE_IS_USER) &&
|
|
(pTrustee->TrusteeType != TRUSTEE_IS_GROUP)) ||
|
|
(pTrustee->ptstrName == NULL) )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
#ifdef _CHICAGO_
|
|
if (pTrustee->ptstrName[0] == L'*' &&
|
|
pTrustee->ptstrName[1] == L'\0' &&
|
|
pTrustee->TrusteeType != TRUSTEE_IS_GROUP)
|
|
{
|
|
return E_INVALIDARG;
|
|
} // if
|
|
|
|
#else
|
|
if (pTrustee->TrusteeForm == TRUSTEE_IS_NAME)
|
|
{
|
|
#endif
|
|
if(FAILED(hr = ValidateTrusteeString(pTrustee->ptstrName)))
|
|
{
|
|
return hr;
|
|
}
|
|
#ifndef _CHICAGO_
|
|
}
|
|
else
|
|
{
|
|
if(!IsValidSid((PSID)(pTrustee->ptstrName)))
|
|
{
|
|
return CO_E_INVALIDSID;
|
|
}
|
|
} // if
|
|
#endif
|
|
|
|
return S_OK;
|
|
} // ValidateTrustee
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: ValidateAccessCheckClient
|
|
//
|
|
// Summary: This function checks to see if the current ORPC client matches
|
|
// the trustee name provided for access checking and it also validates
|
|
// the fields in the TRUSTEE structure.
|
|
//
|
|
// Args: PTRUSTEE_W pTrustee [in] - Pointer to the trustee structure
|
|
// which contains the trustee name for
|
|
// comparison with the name with the current
|
|
// ORPC client.
|
|
//
|
|
// Return: HRESULT S_OK: The TRUSTEE structure provided by the user was valid
|
|
// and it specfied the current ORPC client.
|
|
// CO_E_TRUSTEEDOESNTMATCHCLIENT: The trustee specified by the
|
|
// client was not the current
|
|
// ORPC client.
|
|
// CO_E_FAILEDTOQUERYCLIENTBLANKET: Unable to query for the
|
|
// client's security blanket.
|
|
// CO_E_WRONGTRUSTEENAMESYNTAX: The trustee name inside the
|
|
// TRUSTEE_W structure specified
|
|
// by the user is not of the
|
|
// form <Domain>\<Account Name>.
|
|
// E_INVALIDARG: The TRUSTEE structure provided by the user
|
|
// contained values that were not supported by
|
|
// the COM implementation of IAccessControl.
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT ValidateAccessCheckClient
|
|
(
|
|
PTRUSTEE_W pTrustee
|
|
)
|
|
{
|
|
|
|
WCHAR *pwcszClientName; // Pointer to the name of the ORPC client
|
|
// in multibyte format.
|
|
HRESULT hr;
|
|
|
|
if (FAILED(hr = ValidateTrustee(pTrustee)))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
#ifndef _CHICAGO_
|
|
if (pTrustee->TrusteeForm == TRUSTEE_IS_NAME)
|
|
#endif
|
|
{
|
|
if(FAILED(CoQueryClientBlanket( NULL
|
|
, NULL
|
|
, NULL
|
|
, NULL
|
|
, NULL
|
|
, (RPC_AUTHZ_HANDLE *)&pwcszClientName
|
|
, NULL)))
|
|
{
|
|
return CO_E_FAILEDTOQUERYCLIENTBLANKET;
|
|
} // if
|
|
|
|
if (lstrcmpiW(pwcszClientName, pTrustee->ptstrName) != 0)
|
|
{
|
|
return CO_E_TRUSTEEDOESNTMATCHCLIENT;
|
|
} // if
|
|
}
|
|
return S_OK;
|
|
|
|
} // ValidateAccessCheckClient
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: LocalMemAlloc
|
|
//
|
|
// Summary: This fucntion makes memory allocation more efficient by using the
|
|
// cached g_pIMalloc pointer.
|
|
//
|
|
// Args: ULONG cb [in] = Number of bytes to be allocated.
|
|
//
|
|
// Return: void * - Pointer to the a newly allocated memory block.
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
void * LocalMemAlloc(ULONG cb)
|
|
{
|
|
return g_pIMalloc->Alloc(cb);
|
|
} // LocalMemAlloc
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: LocalMemFree
|
|
//
|
|
// Summary: This function frees memory allocated by LocalMemAlloc.
|
|
//
|
|
// Args: void *pBlock - Pointer to the memory block to be freed.
|
|
//
|
|
// Return: void
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
void LocalMemFree(void *pBlock)
|
|
{
|
|
g_pIMalloc->Free(pBlock);
|
|
} // LocalMemFree
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: CleanUpStreamACL, Common
|
|
//
|
|
// Summary: This function releases all the memory allocated for the array
|
|
// of STREAM_ACE structures inside a STREAM_ACL structure. This
|
|
// includes all the trustee string and SID inside each of the
|
|
// STREAM_ACE structure.
|
|
//
|
|
// Args: STREAM_ACL *pStreamACL [in] - Pointer to the stream ACL structure
|
|
// to be cleaned up.
|
|
//
|
|
// Return: void
|
|
//
|
|
// Called by: COAccessControl::CImpAccessControl::Load()
|
|
// COAccessControl::CImpAccessControl::ReplaceAllAccessRights()
|
|
// CleanAllMemoryResources
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
void CleanUpStreamACL
|
|
(
|
|
STREAM_ACL *pStreamACL
|
|
)
|
|
{
|
|
ULONG ulNumOfEntries; // Total number of entries in the stream ACL
|
|
ULONG i; // Loop index
|
|
STREAM_ACE *pACE; // Pointer to elements in the stream ACL
|
|
|
|
ulNumOfEntries = pStreamACL->ulNumOfDenyEntries
|
|
+ pStreamACL->ulNumOfGrantEntries;
|
|
|
|
pACE = pStreamACL->pACL;
|
|
|
|
for (i = 0; i < ulNumOfEntries; i++)
|
|
{
|
|
midl_user_free(pACE->pTrusteeName);
|
|
midl_user_free(pACE->pSID);
|
|
pACE++;
|
|
} // for
|
|
|
|
pStreamACL->ulNumOfDenyEntries = 0;
|
|
pStreamACL->ulNumOfGrantEntries = 0;
|
|
|
|
// free the stream ACL itself and set the pointer to NULL
|
|
midl_user_free(pStreamACL->pACL);
|
|
pStreamACL->pACL = NULL;
|
|
|
|
} // CleanUpStreamACL
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Functions that are specific to the Chicago platform
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
#ifdef _CHICAGO_
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: AddACEToACLImage
|
|
//
|
|
// Summary: This function adds an ACE to an ACL image and it assumes that the
|
|
// ACL image has enough space to hold the new entry.
|
|
//
|
|
// Args: access_list_2 *pNewACE [in] - The new access_list_2 structure to be
|
|
// added to the LAN Manager ACL in the
|
|
// ACL image.
|
|
// ULONG AccessMode [in] - Grant or Deny
|
|
// ACL_DESCRIPTOR ACLDesc [in,out] - Contains the grant and deny
|
|
// Chicago ACL image structures.
|
|
// The new access_list_2 structure is
|
|
// added to the appropriate one.
|
|
//
|
|
// Return: void
|
|
//
|
|
// Called by: AddACEToACL
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
void AddACEToACLImage
|
|
(
|
|
access_list_2 *pNewACE,
|
|
ULONG AccessMode,
|
|
ACL_DESCRIPTOR *ACLDesc
|
|
)
|
|
{
|
|
ULONG ulStrLen;
|
|
access_list_2 *pACE;
|
|
ACL_IMAGE *pACLImage = AccessMode == ACTRL_ACCESS_ALLOWED ? &ACLDesc->GrantACL :
|
|
&ACLDesc->DenyACL;
|
|
|
|
pACE = (access_list_2 *)(pACLImage->pACL + 1)
|
|
+ pACLImage->pACL->acc1_count;
|
|
|
|
memcpy(pACE, pNewACE, sizeof(access_list_2));
|
|
pACLImage->pACL->acc1_count++;
|
|
|
|
} // AddACEToACLImage
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: CleanFileResource
|
|
//
|
|
// Summary: This function deletes the dummy file created for an ACL image and
|
|
// removes the security entries associated with that file in the system
|
|
// registry.
|
|
// Args: ACL_IMAGE *pACLImage [in,out] - Pointer to the ACL image that contains
|
|
// the dummy file name.
|
|
//
|
|
// Return: void
|
|
//
|
|
// Called by: COAccessControl::CImpAccessControl::~CImpAccessControl
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
void CleanFileResource
|
|
(
|
|
ACL_IMAGE *pACLImage
|
|
)
|
|
{
|
|
CHAR *pszFileName;
|
|
|
|
pszFileName = pACLImage->pACL->acc1_resource_name;
|
|
NetAccessDel(NULL, pszFileName);
|
|
DeleteFileA(pszFileName);
|
|
LocalMemFree(pszFileName);
|
|
|
|
} // CleanFileResource
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: DeleteACEFromACLImage, Chicago specific
|
|
//
|
|
// Summary: This function removes the ACEs of a trustee from an ACL image.
|
|
//
|
|
// Args: LPWSTR pTrustee [in] - Pointer to the trustee to be removed from the
|
|
// ACL image.
|
|
// ACL_IMAGE *pACLImage [in,out] - Pointer to the ACL image to remove the
|
|
// trustee from
|
|
//
|
|
// Return: void
|
|
//
|
|
// Called by: COAccessControl::CImpAccessControl::RevokeAccessRights
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
void DeleteACEFromACLImage
|
|
(
|
|
CHAR *pcszTrusteeName,
|
|
ACL_IMAGE *pACLImage
|
|
)
|
|
{
|
|
SHORT i; // Loop counter
|
|
access_list_2 *pACE; // Pointer for browsing LAN Manager ACEs
|
|
// in the ACL image
|
|
SHORT sDiff; // The difference between the indices of
|
|
// the last entry and the the entry to
|
|
// be removed
|
|
|
|
pACE = (access_list_2 *)(pACLImage->pACL + 1);
|
|
for (i=0; i < pACLImage->pACL->acc1_count; i++, pACE++)
|
|
{
|
|
while((i < pACLImage->pACL->acc1_count) &&
|
|
(lstrcmpiA(pcszTrusteeName, pACE->acl2_ugname) == 0))
|
|
{
|
|
pACLImage->pACL->acc1_count--;
|
|
LocalMemFree(pACE->acl2_ugname);
|
|
|
|
// If the current entry is not the last entry in the ACL image
|
|
if (i != pACLImage->pACL->acc1_count)
|
|
{
|
|
// Compute the difference between the
|
|
// indices of the last entry and the current current entry
|
|
// Note that acc1_count has already
|
|
// been decremented so it should
|
|
// now contain the index of the last
|
|
// element in the ACL
|
|
sDiff = pACLImage->pACL->acc1_count;
|
|
memcpy(pACE, pACE + sDiff, sizeof(access_list_2));
|
|
} // if
|
|
break;
|
|
} // if
|
|
} // if
|
|
|
|
} // DeleteACEFromACLImage
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: AllocACLImage, Chicago specific
|
|
//
|
|
// Summary: This function allocates memory for an ACL image large enough to hold
|
|
// the specified number of ACEs excluding the user name inside the
|
|
// access_list_2 structure.
|
|
//
|
|
// Args: ACL_IMAGE *pACLImage [in,out] - Pointer to the ACL image to allocate
|
|
// memory for.
|
|
// SHORT sNumOfEntries [in] - Number of ACEs to be allocated.
|
|
//
|
|
// Return: HRESULT - S_OK: Success.
|
|
// E_OUTOFMEMORY: Not enough memory to allocate the LAN
|
|
// Manager ACL.
|
|
//
|
|
// Called by: COAccessControl::CImpAccessControl::Load
|
|
// EnsureACLImage
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT AllocACLImage
|
|
(
|
|
ACL_IMAGE *pACLImage,
|
|
SHORT sNumOfEntries
|
|
)
|
|
{
|
|
ULONG ulACLSize;
|
|
|
|
ulACLSize = sizeof(access_info_1) + sNumOfEntries * sizeof(access_list_2);
|
|
|
|
if ((pACLImage->pACL = (access_info_1 *)LocalMemAlloc(ulACLSize)) == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
} // if
|
|
|
|
// It is not really necessary to set the ACL buffer to zero, but is safer
|
|
// to do so.
|
|
memset(pACLImage->pACL, 0, ulACLSize);
|
|
pACLImage->sMaxNumOfACEs = sNumOfEntries;
|
|
|
|
return S_OK;
|
|
|
|
} // AllocACLImage
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: EnsureACLImage, Chicago specific
|
|
//
|
|
// Summary: This function enlarge an existing ACL image to accomodate more ACEs.
|
|
//
|
|
// Args: ACL_IMAGE *pACLImage [in] - Pointer to the ACL image to be enlarged.
|
|
// SHORT sAddEntries [out] - Number of free slots to be added.
|
|
//
|
|
// Return: HRESULT S_OK: Success
|
|
// E_OUTOFMEMORY: Out of memory.
|
|
//
|
|
// Called by: AddACEToACLImage
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT EnsureACLImage
|
|
(
|
|
ACL_IMAGE *pACLImage,
|
|
ULONG lAddEntries
|
|
)
|
|
{
|
|
ACL_IMAGE LocalImage; // A local ACL_IMAGE structure for backing up the
|
|
// the old list
|
|
SHORT sNewSize; // The new size of the ACL
|
|
HRESULT hr = S_OK;
|
|
|
|
// If there is no ACL, just make one.
|
|
if (pACLImage->pACL == NULL)
|
|
return AllocACLImage( pACLImage, (SHORT) lAddEntries + EXTRA_ACES );
|
|
|
|
// If the ACL is large enough, return.
|
|
if (pACLImage->pACL->acc1_count + lAddEntries <
|
|
(ULONG) pACLImage->sMaxNumOfACEs)
|
|
return S_OK;
|
|
sNewSize = (SHORT) (pACLImage->pACL->acc1_count + lAddEntries + EXTRA_ACES);
|
|
|
|
// Take a snapshot of the old list
|
|
memcpy(&LocalImage, pACLImage, sizeof(ACL_IMAGE));
|
|
|
|
if(FAILED(hr = AllocACLImage(pACLImage, sNewSize)))
|
|
{
|
|
goto Error;
|
|
} // if
|
|
|
|
// Copy the content of the old list over to the new list
|
|
memcpy( pACLImage->pACL
|
|
, LocalImage.pACL
|
|
, sizeof(access_info_1)
|
|
+ sizeof(access_list_2)
|
|
* LocalImage.pACL->acc1_count);
|
|
|
|
// free the memory used by the old list
|
|
LocalMemFree(LocalImage.pACL);
|
|
return S_OK;
|
|
|
|
Error:
|
|
// Restore the old list
|
|
memcpy(pACLImage, &LocalImage, sizeof(ACL_IMAGE));
|
|
return hr;
|
|
|
|
} // EnsureACLImage
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: CleanUpACLImage, Chicago specific
|
|
//
|
|
// Summary: This function releases the memory that has been allocated for
|
|
// an ACL image except for the resource name in the ACL header.
|
|
//
|
|
// Args: ACL_IMAGE *pACLImage [in] - Pointer to the ACL image to be released.
|
|
//
|
|
// Return: void
|
|
//
|
|
// Called by: COAccessControl::CImpAccessControl::Load
|
|
// COAccessControl::CImpAccessControl::ReplaceAllAccessRights
|
|
// CleanAllMemoryResources()
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
void CleanUpACLImage
|
|
(
|
|
ACL_IMAGE *pACLImage
|
|
)
|
|
{
|
|
access_list_2 *pACE; // Pointer for traversing the LAN Manager ACL
|
|
SHORT sNumOfACEs; // Total number of LAN Manager ACEs to release
|
|
SHORT i; // Loop counter
|
|
|
|
pACE = (access_list_2 *)(pACLImage->pACL + 1);
|
|
sNumOfACEs = pACLImage->pACL->acc1_count;
|
|
|
|
// For each access_list_2 structure in the LAN Manager ACL, we have
|
|
// to free the user/group name string in it.
|
|
for (i = 0; i < sNumOfACEs; i++, pACE++)
|
|
{
|
|
LocalMemFree(pACE->acl2_ugname);
|
|
} // for
|
|
|
|
LocalMemFree(pACLImage->pACL);
|
|
pACLImage->pACL = NULL;
|
|
} // CleanUpACLImage
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: WStringToMBString
|
|
//
|
|
// Summary: This function converts a Unicode string into a multibyte string
|
|
// using the current console code page. This function will allocate
|
|
// memory for the mulitbyte string which is returned to the caller
|
|
// so the caller must free the string when the string is no longer
|
|
// in use. Notice that the WC_COMPOSITECHECK and the WC_SEPCHARS
|
|
// flags are hard-coded in the conversion but this may not be
|
|
// the perfect setting for all languages. A more suitable approach
|
|
// is to set up a global mask that defines the proper behaviour of
|
|
// converting composite character when the server is started.
|
|
//
|
|
// Args: LPWSTR pwszString [in] - The Unicode string to be converted.
|
|
// CHAR **pcszString [out] - Address of the pointer to the
|
|
// converted multibyte string.
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// CO_E_CONVERSIONFAILED: WideCharToMultiByte returned zero.
|
|
// The caller can get extended error
|
|
// information by calling GetLastError.
|
|
// E_OUTOFMEMORY: The system ran out of memory for the
|
|
// converted string.
|
|
//
|
|
// Called by: ComputeEffectiveAccess
|
|
// ValidateAndTransformAccReqList
|
|
//
|
|
// Remarks: This function relies on the global variable, g_uiCodePage, for
|
|
// the conversion.
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT WStringToMBString
|
|
(
|
|
LPWSTR pwszString,
|
|
CHAR **ppcszString
|
|
)
|
|
{
|
|
ULONG ulStrLen; // Lenght of the multibyte string
|
|
|
|
// The first call to WideCharToMultiByte is to figure out the length
|
|
// of the converted string so that enough memoy can be allocated for
|
|
// it.
|
|
ulStrLen = WideCharToMultiByte( g_uiCodePage
|
|
, WC_SEPCHARS | WC_COMPOSITECHECK
|
|
, pwszString
|
|
, -1
|
|
, NULL
|
|
, NULL
|
|
, NULL
|
|
, NULL );
|
|
if (ulStrLen == 0)
|
|
{
|
|
return CO_E_CONVERSIONFAILED;
|
|
} // if
|
|
|
|
*ppcszString = (CHAR *)LocalMemAlloc(ulStrLen + 1);
|
|
if (*ppcszString == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
} // if
|
|
|
|
WideCharToMultiByte( g_uiCodePage
|
|
, WC_SEPCHARS | WC_COMPOSITECHECK
|
|
, pwszString
|
|
, -1
|
|
, *ppcszString
|
|
, ulStrLen + 1
|
|
, NULL
|
|
, NULL );
|
|
|
|
return S_OK;
|
|
} // WStringToMBString
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: GenerateFile, Chicago specific
|
|
//
|
|
// Summary: This function generates a file on the system with a (supposed)
|
|
// unique name composed by a randomly generated uuid and the current
|
|
// process id. Notice that this function allocates memory for the
|
|
// gernerated filename to be returned to the caller and it also
|
|
// creates the file with the generated filename on the file system,
|
|
// so it is up to the caller to release these sytem resorces when
|
|
// they are no longer in use. The syntax fo the file name generated
|
|
// can be described by the expression:
|
|
// <Windows directory>/<Current process ID>_<UUID>.tmp
|
|
//
|
|
// Args: LPTSTR *pFileName [out] - Address of the generated filename string
|
|
// which is returned to the caller.
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// E_OUTOFMEMORY: The system ran out of memory for some
|
|
// crucial operation.
|
|
// CO_E_FAILEDTOGETWINDIR: (Windows 95 only)Unable to obtain
|
|
// the Windows directory.
|
|
// CO_E_PATHTOOLONG: (Windows 95 only)The path generated by
|
|
// the GenerateFile function was longer
|
|
// than the system's limit.
|
|
// CO_E_FAILEDTOGENUUID: (Windows 95 only)Unable to generate
|
|
// a uuid using the UuidCreate funciton.
|
|
// CO_E_FAILEDTOCREATEFILE: (Windows 95 only)Unable to create
|
|
// a dummy file.
|
|
//
|
|
// Called by: COAccessControl::CImpAccessControl::Load()
|
|
//
|
|
// Remarks: This function relies on the fact that there is global variable
|
|
// named g_dwProcessID containing the current process ID.
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT GenerateFile
|
|
(
|
|
LPTSTR *pFileName
|
|
)
|
|
{
|
|
HRESULT hr = S_OK; // Function return code
|
|
UUID uuid; // The UUID generated by CreateUuid
|
|
LPTSTR pszPathName; // Pointer to the full pathname
|
|
LPTSTR pszFileName; // Pointer to the filename
|
|
SHORT sStrLen; // Temporary variable to keep track of the
|
|
// intermediate length of the path
|
|
HANDLE FileHandle; // Handle for file management.
|
|
|
|
pszPathName = NULL;
|
|
|
|
// Allocate memory for the full path of the file that is going to be
|
|
// generated
|
|
pszPathName = (LPTSTR)LocalMemAlloc(sizeof(TCHAR) * MAX_PATH);
|
|
if (pszPathName == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
} // if
|
|
|
|
|
|
sStrLen = GetWindowsDirectory(pszPathName, MAX_PATH);
|
|
if(sStrLen == 0)
|
|
{
|
|
hr = CO_E_FAILEDTOGETWINDIR;
|
|
goto Error;
|
|
} // if
|
|
|
|
// We should worry about the case where the Windows directory is the
|
|
// root directory where the '\' character has already been added to
|
|
// the path at the end. We should add the '\' character at the
|
|
// end of the Windows path otherwise.
|
|
if(pszPathName[sStrLen - 1] != '\\')
|
|
{
|
|
pszPathName[sStrLen] = '\\';
|
|
sStrLen++;
|
|
} //if
|
|
|
|
pszFileName = pszPathName + sStrLen;
|
|
// Compose the filename with the process id
|
|
_ultoa( g_dwProcessID, pszFileName, 16 );
|
|
sStrLen = sStrLen + strlen(pszFileName);
|
|
pszFileName = pszPathName + sStrLen;
|
|
*(pszFileName++) = '_';
|
|
sStrLen += 1;
|
|
|
|
// See if the buffer can hold everything..
|
|
// UUID and extension etc.
|
|
if (sStrLen + 43 > MAX_PATH)
|
|
{
|
|
hr = CO_E_PATHTOOLONG;
|
|
goto Error;
|
|
} // if
|
|
|
|
// Compose the filename with a UUID
|
|
if(UuidCreate(&uuid) != RPC_S_OK)
|
|
{
|
|
hr = CO_E_FAILEDTOGENUUID;
|
|
goto Error;
|
|
} // if
|
|
|
|
// Put the uuid into the filename
|
|
wStringFromGUID2A( uuid, pszFileName, GUID_SIZE+1 );
|
|
|
|
// Attach a .tmp extension to the end
|
|
strcpy(pszFileName + GUID_SIZE, ".tmp");
|
|
|
|
// return the string to caller
|
|
*pFileName = pszPathName;
|
|
|
|
// Create the file
|
|
if ((FileHandle = CreateFileA( pszPathName
|
|
, GENERIC_READ | GENERIC_WRITE
|
|
, FILE_SHARE_READ
|
|
, NULL
|
|
, CREATE_NEW
|
|
, FILE_ATTRIBUTE_TEMPORARY
|
|
, NULL )) == INVALID_HANDLE_VALUE )
|
|
{
|
|
// There are two distinct possibilities that an error creating the file may occur:
|
|
// 1. The filename generated by GenerateFile has already existed in the file system.
|
|
// This is highly improbable because an UUID is used in the filename generation.
|
|
// 2. The system runs out of memory
|
|
hr = CO_E_FAILEDTOCREATEFILE;
|
|
goto Error;
|
|
} // if
|
|
|
|
|
|
// Close the file immediately since we don't really
|
|
// access the file
|
|
if (!CloseHandle(FileHandle))
|
|
{
|
|
Win4Assert( !"Unable to close file handle." );
|
|
} // if
|
|
|
|
return hr;
|
|
|
|
Error:
|
|
if (pszPathName != NULL)
|
|
{
|
|
LocalMemFree(pszPathName);
|
|
} // if
|
|
*pFileName = NULL;
|
|
return hr;
|
|
|
|
} // GenerateFile
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: MapStreamACLToChicagoACL, Chicago specific
|
|
//
|
|
// Summary: This function maps a standard stream format ACL to a preallocated
|
|
// in-Femory ACL image specifically designed to work with the
|
|
// LAN Manager API supported on Chicago.
|
|
//
|
|
// Args: STREAM_ACE *pStreamACEs [in] - Pointer to an array of ACEs in
|
|
// standard stream format.
|
|
// ACL_IMAGE *pACLImage [in,out] - The in memory representation of an
|
|
// ACL image.
|
|
// SHORT sNumOfEntries [in] - The number of stream format ACEs to
|
|
// be mapped to the in-memory ACL image.
|
|
//
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// CO_E_CONVERSIONFAILED: WideCharToMultiByte returned zero.
|
|
// The caller can get extended error
|
|
// information by calling GetLastError.
|
|
// E_OUTOFMEMORY: The system ran out of memory for the
|
|
// converted string.
|
|
//
|
|
// Called by: COAccessControl::CImpAccessControl::Load
|
|
// COAccessControl::CImpAccessControl::ReplaceAllAccessRights
|
|
// ComputeEffectiveAccess
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT MapStreamACLToChicagoACL
|
|
(
|
|
STREAM_ACE *pStreamACEs,
|
|
ACL_IMAGE *pACLImage,
|
|
SHORT sNumOfEntries
|
|
)
|
|
{
|
|
USHORT i,j; // Loop counters
|
|
STREAM_ACE *pStreamACEsPtr; // Pointer to an array of stream format ACEs
|
|
access_list_2 *pACE; // Pointer to ACEs in the LAN Manager ACL
|
|
ULONG ulStrLen; // Length of the trustee string
|
|
HRESULT hr;
|
|
|
|
// Set up the ACL header
|
|
pACLImage->pACL->acc1_attr = 0; // Audit all by default
|
|
pACLImage->pACL->acc1_count = sNumOfEntries;
|
|
|
|
// Set the stream ACE pointer to point to the first stream ACE
|
|
pStreamACEsPtr = pStreamACEs;
|
|
|
|
pACE = (access_list_2 *)(pACLImage->pACL + 1);
|
|
|
|
for (i = 0; i < sNumOfEntries; i++)
|
|
{
|
|
|
|
if (FAILED(hr = WStringToMBString( pStreamACEsPtr->pTrusteeName
|
|
, &(pACE->acl2_ugname))))
|
|
{
|
|
goto Error;
|
|
} // if
|
|
|
|
// Map stream security mask to Chicago security mask
|
|
StandardMaskToLANManagerMask( &(pStreamACEsPtr->grfAccessPermissions)
|
|
, &(pACE->acl2_access));
|
|
|
|
// Set up the group bit if necessary
|
|
if (pStreamACEsPtr->TrusteeType == TRUSTEE_IS_GROUP)
|
|
{
|
|
pACE->acl2_access |= ACCESS_GROUP;
|
|
} // if
|
|
|
|
pACE++;
|
|
|
|
pStreamACEsPtr++;
|
|
|
|
} // for
|
|
|
|
return S_OK;
|
|
|
|
Error:
|
|
pACE = (access_list_2 *)(pACLImage->pACL + 1);
|
|
for (j = 0; j < i; j++, pACE++)
|
|
{
|
|
LocalMemFree(pACE->acl2_ugname);
|
|
} // for
|
|
return hr;
|
|
|
|
} // MapStreamToChicagoACL
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: StandardMaskToLANManagerMask, Chicago specific
|
|
//
|
|
// Summary: This function maps the content of a access permissions
|
|
// supported by IAccessControl to the corresponding LAN
|
|
// Mamager access mask.
|
|
//
|
|
// Args: DWORD *pStdMask [in] - The standard mask to be converted to NT
|
|
// mask.
|
|
// ACCESS_MASK *pNTMask [out] - Reference to the converted mask.
|
|
//
|
|
//
|
|
// Return: void
|
|
//
|
|
// Called by:
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
SHORT StandardMaskToLANManagerMask
|
|
(
|
|
DWORD *pStdMask,
|
|
USHORT *pLMMask
|
|
)
|
|
{
|
|
*pLMMask= 0;
|
|
|
|
|
|
if ((*pStdMask & COM_RIGHTS_EXECUTE) != 0)
|
|
{
|
|
*pLMMask |= CHICAGO_RIGHTS_EXECUTE;
|
|
} // if
|
|
|
|
return 0;
|
|
|
|
} // StandardMaskToLANManagerMask
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: lstrcmpiW, Chicago specific
|
|
//
|
|
// Summary: This function is equivalent to lstrcmpiW on Windows NT.
|
|
// Unlike the Windows NT version of lstrcmpiW, this function can
|
|
// treats a null pointer as a null string instead of spewing out an
|
|
// access violation error.
|
|
//
|
|
// Remarks: See the section on lstrcmpi inside the Win32 SDK documentation.
|
|
// This function relies on a global variable named g_uiCodePage
|
|
// storing the current console code page.
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
SHORT FoolstrcmpiW(LPWSTR pwsz1, LPWSTR pwsz2)
|
|
{
|
|
SHORT sResult; // The result of the comparision
|
|
WCHAR *pwchar1 = pwsz1; // Pointer for browsing through the first string
|
|
// character by character.
|
|
WCHAR *pwchar2 = pwsz2; // Pointer for browsing through the second string
|
|
// character by character.
|
|
WCHAR wchar1;
|
|
WCHAR wchar2;
|
|
|
|
// The following block of code handles case where
|
|
// either one of the input string is a NULL pointer.
|
|
// By convention a string represented by a NULL pointer
|
|
// is an empty string.
|
|
if(pwchar1 == NULL)
|
|
{
|
|
if(pwchar2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
} // if
|
|
}
|
|
else if (pwchar2 == NULL)
|
|
{
|
|
return 1;
|
|
} // if
|
|
|
|
for(;;)
|
|
{
|
|
wchar1 = *pwchar1;
|
|
wchar2 = *pwchar2;
|
|
|
|
#if 0
|
|
// Checking to see if the current code page is the
|
|
// ANSI code page may not be enough to cover all the
|
|
// cases where a language has the concept of upper and lower
|
|
// case letters.
|
|
if (g_uiCodePage == CP_ACP)
|
|
{
|
|
#endif
|
|
// All lower-case characters in the both strings are
|
|
// converted to upper-case characters before
|
|
// making the comparison.
|
|
if ((L'a' <= *pwchar1)&& (*pwchar1 <= L'z'))
|
|
{
|
|
wchar1 = *pwchar1 - L'a' + L'A';
|
|
} // if
|
|
|
|
if ((L'a' <= *pwchar2) && (*pwchar2 <= L'z'))
|
|
{
|
|
wchar2 = *pwchar2 - L'a' + L'A';
|
|
} // if
|
|
#if 0
|
|
} // if
|
|
#endif
|
|
if(wchar1 == 0 && wchar2 == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else if (wchar1 > wchar2)
|
|
{
|
|
return 1;
|
|
}
|
|
else if (wchar1 < wchar2)
|
|
{
|
|
return -1;
|
|
} // if
|
|
|
|
// Increment the string pointers to point to the next character
|
|
// for comparison
|
|
pwchar1++;
|
|
pwchar2++;
|
|
} // if
|
|
} // if
|
|
|
|
#else
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Functions that are specific to the Windows NT platform
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: InitSecDescInACLDesc, NT specific
|
|
//
|
|
// Summary: This function initializes the group field and the user field of the
|
|
// security descriptor in an ACL_DESCRIPTOR structure the user SID of
|
|
// the current process.
|
|
//
|
|
// Args: ACL_DESCRIPTOR pACLDesc [in,out] - Pointer to ACL descriptor containing
|
|
// the security identifier to be
|
|
// initialized.
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// CO_E_FAILEDTOOPENPROCESSTOKEN: The system call,
|
|
// OpenProcessToken, failed.
|
|
// The user can get extended
|
|
// information by calling
|
|
// GetLastError.
|
|
// CO_E_FAILEDTOGETTOKENINFO: The system call,
|
|
// GetTokenInformation, failed.
|
|
// The user can call GetLastError
|
|
// to get extended error
|
|
// information.
|
|
// E_OUTOFMEMORY: There was not enough memory for allocating
|
|
// the SIDs in the security descriptor.
|
|
//
|
|
// Called by: COAccessControl:CImpAccessControl:Load
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT InitSecDescInACLDesc
|
|
(
|
|
ACL_DESCRIPTOR *pACLDesc
|
|
)
|
|
{
|
|
// Set up a security descriptor with the current process owner
|
|
// and primary group
|
|
TOKEN_USER *pTokenUser = NULL;
|
|
HANDLE hToken;
|
|
ULONG ulLen;
|
|
HANDLE hProcess;
|
|
DWORD dwLastError;
|
|
PSID pOwner = NULL;
|
|
PSID pGroup = NULL;
|
|
DWORD dwSIDLen;
|
|
HRESULT hr = S_OK;
|
|
|
|
hProcess = GetCurrentProcess();
|
|
|
|
if(!OpenProcessToken( hProcess
|
|
, TOKEN_QUERY
|
|
, &hToken ))
|
|
{
|
|
hr = CO_E_FAILEDTOOPENPROCESSTOKEN;
|
|
goto Error;
|
|
} // if
|
|
|
|
GetTokenInformation( hToken
|
|
, TokenUser
|
|
, pTokenUser
|
|
, 0
|
|
, &ulLen);
|
|
dwLastError = GetLastError();
|
|
if (dwLastError == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
pTokenUser = (TOKEN_USER *)LocalMemAlloc(ulLen);
|
|
if (pTokenUser == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
} // if
|
|
|
|
if(!GetTokenInformation( hToken
|
|
, TokenUser
|
|
, pTokenUser
|
|
, ulLen
|
|
, &ulLen))
|
|
{
|
|
hr = CO_E_FAILEDTOGETTOKENINFO;
|
|
goto Error;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
hr = CO_E_FAILEDTOGETTOKENINFO;
|
|
goto Error;
|
|
} // if
|
|
|
|
dwSIDLen = GetLengthSid(pTokenUser->User.Sid);
|
|
|
|
pOwner = (PSID)LocalMemAlloc(dwSIDLen);
|
|
if(pOwner == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
} // if
|
|
|
|
pGroup = (PSID)LocalMemAlloc(dwSIDLen);
|
|
if(pGroup == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
} // if
|
|
|
|
CopySid(dwSIDLen, pOwner, pTokenUser->User.Sid);
|
|
CopySid(dwSIDLen, pGroup, pTokenUser->User.Sid);
|
|
|
|
InitializeSecurityDescriptor( &(pACLDesc->SecDesc)
|
|
, SECURITY_DESCRIPTOR_REVISION);
|
|
pACLDesc->SecDesc.Owner = pOwner;
|
|
pACLDesc->SecDesc.Group = pGroup;
|
|
|
|
// Close the token handle
|
|
CloseHandle(hToken);
|
|
// Free the token user buffer
|
|
LocalMemFree(pTokenUser);
|
|
|
|
pACLDesc->bDirtyACL = TRUE;
|
|
return hr;
|
|
|
|
Error:
|
|
if (pTokenUser != NULL)
|
|
{
|
|
LocalMemFree(pTokenUser);
|
|
} // if
|
|
if (pOwner != NULL)
|
|
{
|
|
LocalMemFree(pOwner);
|
|
} // if
|
|
if (pGroup != NULL)
|
|
{
|
|
LocalMemFree(pGroup);
|
|
} // if
|
|
return hr;
|
|
|
|
} // InitSecDescInACLDesc
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: GetSIDFromName, NT specific
|
|
//
|
|
// Summary: This function takes an account name of the form <Domain>\<User name>
|
|
// as an input and returns the corresponding security identifier (SID).
|
|
// This function will automatically allocates memory for the SID
|
|
// returned to the caller so the caller should release the SID pointer
|
|
// using LocalMemFree as soon as the SID is no longer in use.
|
|
//
|
|
// Args: PSID *ppSID [out] - Address of the pointer to the returned security
|
|
// identifier. The caller must free the memory
|
|
// allocated for the securrity identifier using
|
|
// LocalMemFree when the security identifier is no
|
|
// longer in use.
|
|
// LPWSTR pwszTrustee [in] - Pointer to the trustee name of the form
|
|
// <Domain>\<User name>. The SID returned
|
|
// should belong to this trustee.
|
|
// TRUSTEE_TYPE TrusteeType [in] - Type of the trustee which is either
|
|
// TRUSTE_IS_NAME or TRUSTEE_IS_GROUP
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// CO_E_NOMATCHINGSIDFOUND: No matching security identifier
|
|
// could be found for the
|
|
// trustee name specified by the
|
|
// client.
|
|
// CO_E_LOOKUPACCNAMEFAILED: The system function,
|
|
// LookupAccountName, failed. The client can
|
|
// call GetLastError to obtain extended error
|
|
// information.
|
|
// E_OUTOFMEMORY: The system ran out of memory for
|
|
// allocating the SID to be returned
|
|
// the caller.
|
|
//
|
|
//
|
|
// Called by: ValidateAndFixStreamACL
|
|
// ValidateAndTransformAccReqList
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT GetSIDFromName
|
|
(
|
|
PSID *ppSID,
|
|
LPWSTR pwszTrustee,
|
|
TRUSTEE_TYPE *pTrusteeType
|
|
)
|
|
{
|
|
PSID pSID; // Pointer to the SID to be retrieved
|
|
DWORD dwSIDSize; // Buffer size for the SID
|
|
LPWSTR pwszUserName; // Pointer to the user name portion of the
|
|
// trustee
|
|
DWORD dwLastError; // Error code obtained from GetLastError
|
|
DWORD dwDomainLength; // Length of domain name
|
|
LPWSTR pwszDomainName; // Pointer to the domain name returned by
|
|
// LookupAccountName.
|
|
SID_NAME_USE SIDUse; // The type of SID returned.
|
|
HRESULT hr;
|
|
|
|
// We trap the magic string "*' which specifies everyone
|
|
if (pwszTrustee[0] == L'*' && pwszTrustee[1] == L'\0')
|
|
{
|
|
if (*pTrusteeType != TRUSTEE_IS_GROUP)
|
|
{
|
|
return E_INVALIDARG;
|
|
} // if
|
|
|
|
if(*ppSID = (PSID)LocalMemAlloc(sizeof(gEveryone)))
|
|
{
|
|
CopySid(sizeof(gEveryone), *ppSID, &gEveryone);
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
} // if
|
|
} // if
|
|
|
|
// NT 4 does not map the domain NT Authority correctly
|
|
if (lstrcmpiW(pwszTrustee, L"NT Authority\\system") == 0)
|
|
{
|
|
if (*pTrusteeType != TRUSTEE_IS_USER)
|
|
{
|
|
return E_INVALIDARG;
|
|
} // if
|
|
|
|
if(*ppSID = (PSID)LocalMemAlloc(sizeof(gSystem)))
|
|
{
|
|
CopySid(sizeof(gSystem), *ppSID, &gSystem);
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
} // if
|
|
} // if
|
|
|
|
// Assign an arbitrarily large SID size so that the function
|
|
// can avoid LookupAccountName twice for most of the time.
|
|
pwszUserName = pwszTrustee;
|
|
dwDomainLength = 64;
|
|
dwSIDSize = 64;
|
|
pSID = (PSID)midl_user_allocate(dwSIDSize);
|
|
if (pSID == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
} // if
|
|
|
|
dwDomainLength++;
|
|
pwszDomainName = (LPWSTR)LocalMemAlloc(sizeof(WCHAR) * dwDomainLength);
|
|
if (pwszDomainName == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
} // if
|
|
|
|
if (!LookupAccountNameW( NULL
|
|
, pwszUserName
|
|
, pSID
|
|
, &dwSIDSize
|
|
, pwszDomainName
|
|
, &dwDomainLength
|
|
, &SIDUse))
|
|
|
|
{
|
|
dwLastError = GetLastError();
|
|
|
|
if (dwLastError = ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
|
|
// If it is not the domain buffer that is too small, it must be
|
|
// the SID that is too small. In this cas, we should expand the
|
|
// buffer and call LookupAccountW again.
|
|
LocalMemFree(pSID);
|
|
pSID = (PSID)midl_user_allocate(dwSIDSize);
|
|
if (pSID== NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
} // if
|
|
|
|
if(!LookupAccountNameW( NULL
|
|
, pwszUserName
|
|
, pSID
|
|
, &dwSIDSize
|
|
, pwszDomainName
|
|
, &dwDomainLength
|
|
, &SIDUse ))
|
|
{
|
|
// If LookupAccountW crashes again, we quit and return
|
|
// an error code.
|
|
hr = CO_E_LOOKUPACCNAMEFAILED;
|
|
goto Error;
|
|
} // if
|
|
}
|
|
else
|
|
{
|
|
// LookupAccountW may not be able to find the SID for the
|
|
// trustee or some other fatal errors occured. In any case, we
|
|
// return an error code and the caller can look at the details
|
|
// by calling GetLastError
|
|
hr = CO_E_LOOKUPACCNAMEFAILED;
|
|
goto Error;
|
|
} // if
|
|
} // if
|
|
|
|
// Check to see if the trustee type provided by the caller matches the SID
|
|
// type obtained from LookupAccountName. If not, we're in trouble. All
|
|
// well known SIDs are of type SidTypeWellKnownGroup.
|
|
if( !(SIDUse == SidTypeUser && *pTrusteeType == TRUSTEE_IS_USER) &&
|
|
!(SIDUse == SidTypeGroup && *pTrusteeType == TRUSTEE_IS_GROUP) &&
|
|
SIDUse != SidTypeWellKnownGroup && SIDUse != SidTypeAlias)
|
|
{
|
|
hr = CO_E_NOMATCHINGSIDFOUND;
|
|
goto Error;
|
|
} // if
|
|
|
|
LocalMemFree(pwszDomainName);
|
|
*ppSID = pSID;
|
|
return 0;
|
|
|
|
Error:
|
|
if (pwszDomainName != NULL)
|
|
{
|
|
LocalMemFree(pwszDomainName);
|
|
}
|
|
if (pSID != NULL)
|
|
{
|
|
midl_user_free(pSID);
|
|
}
|
|
return hr;
|
|
} // GetSIDFromName
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: GetNameFromSID, NT specific
|
|
//
|
|
// Summary: This function takes a security identifier (SID) as an input
|
|
// and finds the trustee name in the form <Domain>\<User name> that
|
|
// corresponds to the SID. This function will allocate memory for
|
|
// the trustee name returned to the caller so the caller should
|
|
// release the trustee name pointer using LocalMemFree whem the
|
|
// trustee name is no longer in use.
|
|
//
|
|
// Args: LPWSTR *ppwszTrustee [out] - Address of the pointer to the trustee
|
|
// name to be returned to the caller. The
|
|
// trustee name returned is in the form
|
|
// <Domain>\<User name>. The caller is
|
|
// responsible for releasiung the memory
|
|
// allocated for the trustee string once
|
|
// it is no longer in use.
|
|
//
|
|
// PSID pSID [in] - Pointer to a security identifier. This function
|
|
// will return the trustee name corresponding to
|
|
// this security identifier through the ppwszTrustee
|
|
// argument.
|
|
//
|
|
// TRUSTEE_TYPE TrusteeType [in] - The type associating with the
|
|
// trustee name that the caller is
|
|
// expecting.
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// CO_E_NOMATCHINGNAMEFOUND: No matching account name
|
|
// could be found for one of the security identifiers
|
|
// specified by the client.
|
|
// CO_E_LOOKUPACCSIDFAILED: The system function,
|
|
// LookupAccountSID, failed. The client can call
|
|
// GetLastError to obtain extended error inforamtion.
|
|
// E_OUTOFMEMORY: The system ran out of memory.
|
|
//
|
|
// Called by: ValidateAndTransformAccReqList
|
|
//
|
|
// Notes: On error LookupAccountSid returns strlen+1, on success it returns
|
|
// only strlen.
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT GetNameFromSID
|
|
(
|
|
LPWSTR *ppwszTrustee,
|
|
PSID pSID,
|
|
TRUSTEE_TYPE *pTrusteeType
|
|
)
|
|
{
|
|
LPWSTR pwszDomainName; // Pointer to the domain name returned
|
|
// by LookupAccountSid.
|
|
DWORD dwDomainLength; // Length of the domain string
|
|
LPWSTR pwszAccountName; // Pointer to the account name returned by
|
|
// LookupAccountSid
|
|
DWORD dwAccountLength; // Length of the account string
|
|
LPWSTR pwszTrustee; // Pointer to the trustee string in the form
|
|
// <Domain>\<User name>
|
|
DWORD dwLastError; // Return code obtained from GetLastError
|
|
HRESULT hr = S_OK;
|
|
SID_NAME_USE SIDUse; // An enumerated variable indicating
|
|
// what the SID returned by LookupAccountSD.
|
|
|
|
// We trap the magic SID that specifies everyone
|
|
if (EqualSid(&gEveryone, pSID))
|
|
{
|
|
|
|
if (*pTrusteeType != TRUSTEE_IS_GROUP)
|
|
{
|
|
return E_INVALIDARG;
|
|
} // if
|
|
|
|
if (*ppwszTrustee = (LPWSTR)LocalMemAlloc(2*sizeof(WCHAR)))
|
|
{
|
|
(*ppwszTrustee)[0] = L'*';
|
|
(*ppwszTrustee)[1] = L'\0';
|
|
*pTrusteeType = TRUSTEE_IS_GROUP;
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
} // if
|
|
|
|
|
|
// Assign some arbitrary large number as the size of the domain name and
|
|
// the account name. Hopefully, these numbers are large enough so that
|
|
// the function can avoid calling LookupAccountSidW the second time
|
|
dwDomainLength = 32;
|
|
dwAccountLength = 64;
|
|
|
|
// Initilize the domain name pointer and the account name pointer to NULL
|
|
pwszDomainName = NULL;
|
|
pwszAccountName = NULL;
|
|
|
|
// Allocate big buffers for the domain name and the account name
|
|
// to minimize the chance of call LookupAccountSid twice.
|
|
pwszDomainName = (LPWSTR)LocalMemAlloc(dwDomainLength * sizeof(WCHAR));
|
|
|
|
if (pwszDomainName == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
} // if
|
|
|
|
pwszAccountName = (LPWSTR)LocalMemAlloc(dwAccountLength * sizeof(WCHAR));
|
|
if (pwszAccountName == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
} // if
|
|
|
|
if(!LookupAccountSidW( NULL
|
|
, pSID
|
|
, pwszAccountName
|
|
, &dwAccountLength
|
|
, pwszDomainName
|
|
, &dwDomainLength
|
|
, &SIDUse))
|
|
{
|
|
dwLastError = GetLastError();
|
|
if (dwLastError == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
if(dwDomainLength > 32)
|
|
{
|
|
LocalMemFree(pwszDomainName);
|
|
pwszDomainName = (LPWSTR)LocalMemAlloc(dwDomainLength *
|
|
sizeof(WCHAR));
|
|
if (pwszDomainName == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
} //if
|
|
} // if
|
|
|
|
if(dwAccountLength > 64)
|
|
{
|
|
LocalMemFree(pwszAccountName);
|
|
pwszAccountName = (LPWSTR)LocalMemAlloc(dwAccountLength *
|
|
sizeof(WCHAR));
|
|
if (pwszAccountName == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
} // if
|
|
} // if
|
|
|
|
if(!LookupAccountSidW( NULL
|
|
, pSID
|
|
, pwszAccountName
|
|
, &dwAccountLength
|
|
, pwszDomainName
|
|
, &dwDomainLength
|
|
, &SIDUse ))
|
|
{
|
|
// Either the SID doesn't belong to any account or something
|
|
// has gone terribly wrong. In either case, the caller should
|
|
// call GetLastError to get more information about the error
|
|
hr = CO_E_LOOKUPACCSIDFAILED;
|
|
goto Error;
|
|
} // if
|
|
|
|
} // if
|
|
else
|
|
{
|
|
// The caller should call GetLastError to obtain more information
|
|
hr = CO_E_LOOKUPACCSIDFAILED;
|
|
goto Error;
|
|
} // if
|
|
|
|
} // if
|
|
|
|
// Check to see if the SIDtype retuned by LookupAccountSidW matches the
|
|
// trustee type provided by the caller. If not, we're in trouble.
|
|
// SidTypeWellKnownGroup and SidTypeAlias can be either.
|
|
if( !(SIDUse == SidTypeUser && *pTrusteeType == TRUSTEE_IS_USER) &&
|
|
!(SIDUse == SidTypeGroup && *pTrusteeType == TRUSTEE_IS_GROUP) &&
|
|
SIDUse != SidTypeWellKnownGroup && SIDUse != SidTypeAlias)
|
|
{
|
|
hr = CO_E_NOMATCHINGSIDFOUND;
|
|
goto Error;
|
|
} // if
|
|
|
|
// Allocate memory for the trustee string to be returned
|
|
// Add 2 for null terminating the string and '\\'
|
|
pwszTrustee = (LPWSTR)midl_user_allocate( (lstrlenW(pwszDomainName)
|
|
+ lstrlenW(pwszAccountName)
|
|
+ 2) * sizeof(WCHAR)
|
|
);
|
|
|
|
if (pwszTrustee == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
} // if
|
|
|
|
// Compose the trustee string
|
|
memcpy(pwszTrustee, pwszDomainName, dwDomainLength * sizeof(WCHAR));
|
|
pwszTrustee[dwDomainLength] = L'\\';
|
|
memcpy(&pwszTrustee[dwDomainLength+1], pwszAccountName, (dwAccountLength+1) * sizeof(WCHAR));
|
|
|
|
*ppwszTrustee = pwszTrustee;
|
|
|
|
Error:
|
|
// Release the domain name string and the account name string
|
|
if (pwszAccountName != NULL)
|
|
{
|
|
LocalMemFree(pwszAccountName);
|
|
} // if
|
|
if (pwszDomainName != NULL)
|
|
{
|
|
LocalMemFree(pwszDomainName);
|
|
} // if
|
|
return hr;
|
|
} // GetNameFromSID
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: PutStreamACLIntoSecDesc, NT specific
|
|
//
|
|
// Summary: This functions takes a STREAM_ACL structure and maps it to a
|
|
// discretionary ACL in a security descriptor. The buffer for the
|
|
// discretionary ACL and the security descriptor are packaged
|
|
// into the NT version of ACL_DESCRICPTOR.
|
|
//
|
|
// Args: STREAM_ACL *pStreamACL [in] - The STREAM_ACL structure to be mapped
|
|
// to a discretionary ACL.
|
|
// ACL_DESCRIPTOR *pACLDesc [in,out] - The NT version of ACL_DESCRIPTOR
|
|
// structure. This structure contains
|
|
// a buffer for the discretionary
|
|
// ACL, a security descriptor, size
|
|
// information, and a control flag.
|
|
//
|
|
// Return: HRESULT - S_OK: Succeeded.
|
|
// CO_E_FAILEDTOSETDACL: SetSecurityDescriptorDacl returned
|
|
// false inside PutStreamACLIntoSecDesc.
|
|
// The client of this method can call
|
|
// GetLastError to get extended error
|
|
// information.
|
|
// E_OUTOFMEMORY: The system ran out of memory for allocating
|
|
// the NT ACL.
|
|
//
|
|
// Called by: ComputeEffectiveAccess
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
HRESULT PutStreamACLIntoSecDesc
|
|
(
|
|
STREAM_ACL *pStreamACL,
|
|
ACL_DESCRIPTOR *pACLDesc
|
|
)
|
|
{
|
|
ACL *pACLHeader; // Pointer to the ACL structure in the ACL
|
|
// buffer.
|
|
ULONG i; // Loop counter
|
|
CHAR *pBufferPtr; // Pointer for traversing the ACL buffer.
|
|
ULONG ulNumOfStreamACEs; // Total number of STREAM_ACE structures to map.
|
|
STREAM_ACE *pStreamACEsPtr; // Pointer for traversing the array of
|
|
// of STREAM_ACE structures to be mapped.
|
|
ACE_HEADER *pACEHeader; // Pointer to the header of an ACE.
|
|
ULONG ulACLSize;
|
|
WORD wSIDSize; // Size of the SID to be copied into an ACE.
|
|
|
|
// Compute the total size of the ACL buffer
|
|
ulACLSize = pACLDesc->ulSIDSize
|
|
+ (pStreamACL->ulNumOfGrantEntries + pStreamACL->ulNumOfDenyEntries)
|
|
* (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD))
|
|
+ sizeof(ACL);
|
|
|
|
// Reallocate a new buffer for the NT ACL if the current buffer is not
|
|
// big enough. Note that an extra 64 bytes is padded at the end to
|
|
// minimize the need for reallocating the buffer if the internal ACL
|
|
// is changed in a minor way.
|
|
if (pACLDesc->ulACLBufferSize < ulACLSize)
|
|
{
|
|
LocalMemFree(pACLDesc->pACLBuffer);
|
|
pACLDesc->pACLBuffer = (CHAR *)LocalMemAlloc(ulACLSize + 64);
|
|
if (pACLDesc->pACLBuffer == NULL)
|
|
{
|
|
pACLDesc->ulACLBufferSize = 0;
|
|
return E_OUTOFMEMORY;
|
|
} // if
|
|
pACLDesc->ulACLBufferSize = ulACLSize + 64;
|
|
} // if
|
|
|
|
// Map the stream ACL to the NT ACL
|
|
ulNumOfStreamACEs = pStreamACL->ulNumOfDenyEntries
|
|
+ pStreamACL->ulNumOfGrantEntries;
|
|
|
|
// Set up the ACL header first
|
|
pACLHeader = (ACL *)(pACLDesc->pACLBuffer);
|
|
pACLHeader->AclRevision = ACL_REVISION2;
|
|
pACLHeader->AclSize = (USHORT)ulACLSize;
|
|
pACLHeader->AceCount = (USHORT)ulNumOfStreamACEs;
|
|
|
|
|
|
pBufferPtr = (CHAR *)(pACLDesc->pACLBuffer) + sizeof(ACL);
|
|
pStreamACEsPtr = pStreamACL->pACL;
|
|
|
|
// The following for loop maps the STREAM_ACE structures into the
|
|
// ACL buffer for NT.
|
|
for (i = 0; i < ulNumOfStreamACEs; i++)
|
|
{
|
|
// ACCESS_ALLOWED_ACE and ACCESS_DENIED_ACE are
|
|
// structurally equivalent, so I may as well use one of them
|
|
pACEHeader = &(((ACCESS_ALLOWED_ACE *)pBufferPtr)->Header);
|
|
|
|
// Skip ACEs with NULL SID
|
|
if(pStreamACEsPtr->pSID == NULL)
|
|
{
|
|
continue;
|
|
} // if
|
|
|
|
if (pStreamACEsPtr->grfAccessMode == ACTRL_ACCESS_DENIED)
|
|
{
|
|
pACEHeader->AceType = ACCESS_DENIED_ACE_TYPE;
|
|
}
|
|
else
|
|
{
|
|
pACEHeader->AceType = ACCESS_ALLOWED_ACE_TYPE;
|
|
} // if
|
|
|
|
pACEHeader->AceFlags = NULL;
|
|
StandardMaskToNTMask( &(pStreamACEsPtr->grfAccessPermissions)
|
|
, &(((ACCESS_ALLOWED_ACE *)pBufferPtr)->Mask));
|
|
wSIDSize = (USHORT)GetLengthSid(pStreamACEsPtr->pSID);
|
|
CopySid( wSIDSize
|
|
, &(((ACCESS_ALLOWED_ACE *)pBufferPtr)->SidStart)
|
|
, pStreamACEsPtr->pSID);
|
|
pACEHeader->AceSize = sizeof(ACCESS_ALLOWED_ACE)
|
|
- sizeof(DWORD)
|
|
+ wSIDSize;
|
|
|
|
// Increment the ACL buffer to the next available slot
|
|
// for the the next ACE
|
|
pBufferPtr += pACEHeader->AceSize;
|
|
|
|
// Increment the stream ACE porinter to point to the next
|
|
// STREAM_ACE structure to be mapped
|
|
pStreamACEsPtr++;
|
|
} // for
|
|
|
|
// Call SetSecurityDescriptorDACL to put the mapped
|
|
// NT ACL into the security desriptor. The security should be initialized
|
|
// with a group SID and a group SID by now. See the
|
|
// COAccessControl::CImpAccessControl:Load method for details.
|
|
if(!SetSecurityDescriptorDacl( &(pACLDesc->SecDesc)
|
|
, TRUE
|
|
, (ACL *)(pACLDesc->pACLBuffer)
|
|
, FALSE))
|
|
{
|
|
return CO_E_FAILEDTOSETDACL;
|
|
} // if
|
|
|
|
pACLDesc->bDirtyACL = FALSE;
|
|
return 0;
|
|
|
|
} // PutStreamACLIntoSecurityDescriptor
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// The access mask conversion routines
|
|
//
|
|
// Notes: The DCOM implementation of IAccessControl only supports the
|
|
// execute permission and so the following functions are hard-coded to
|
|
// convert the execute permission only. However, these function can be
|
|
// extended to support a wider range of permissions without
|
|
// substantantial changes in the rest of the code. For an even more
|
|
// generic architecture, a table of mask conversion can be used.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: StandardMaskToNTMask
|
|
//
|
|
// Summary: This function maps the content of a access permissions
|
|
// supported by IAccessControl to the corresponding NT
|
|
// security access mask.
|
|
//
|
|
// Args: DWORD *pStdMask [in] - The standard mask to be converted to NT
|
|
// mask.
|
|
// ACCESS_MASK *pNTMask [out] - Reference to the converted mask.
|
|
//
|
|
//
|
|
// Return: void
|
|
//
|
|
// Called by: PutStreamACLIntoSecDesc
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
void StandardMaskToNTMask
|
|
(
|
|
DWORD *pStdMask,
|
|
ACCESS_MASK *pNTMask
|
|
)
|
|
{
|
|
*pNTMask= 0;
|
|
|
|
|
|
if ((*pStdMask & COM_RIGHTS_EXECUTE) != 0)
|
|
{
|
|
*pNTMask |= NT_RIGHTS_EXECUTE;
|
|
} // if
|
|
|
|
} // StandardMaskToNTMask
|
|
|
|
//F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
|
|
// Function: NTMaskToStandardMask, NT specific
|
|
//
|
|
// Summary: This function maps the content of an NT access mask to a
|
|
// corresponding IAccessControl access mask.
|
|
//
|
|
// Args: ACCESS_MASK *pNTMask [in] - Address of the NT mask to be covnverted.
|
|
// DWORD *pStdMask [in] - Address of the converted IAccessControl
|
|
// access mask.
|
|
//
|
|
// Return: void
|
|
//
|
|
// Called by: ComputeEffectiveAccess
|
|
//
|
|
//F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F
|
|
void NTMaskToStandardMask
|
|
(
|
|
ACCESS_MASK *pNTMask,
|
|
DWORD *pStdMask
|
|
)
|
|
{
|
|
*pStdMask= 0;
|
|
|
|
if ((*pNTMask & NT_RIGHTS_EXECUTE) != 0)
|
|
{
|
|
*pStdMask |= COM_RIGHTS_EXECUTE;
|
|
} // if
|
|
|
|
} // NTMaskToStandardMask
|
|
|
|
#endif // #ifdef _CHICAGO_, #else
|
|
// End of caccctrl.cxx
|
|
|