1155 lines
25 KiB
C++
1155 lines
25 KiB
C++
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1992 - 1995
|
||
|
//
|
||
|
// File: cgroup.cxx
|
||
|
//
|
||
|
// Contents: Group object
|
||
|
//
|
||
|
// History: 11-1-95 krishnag Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include "winnt.hxx"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
// Class CWinNTGroup -> GlobalGroup DS class
|
||
|
|
||
|
DEFINE_IDispatch_ExtMgr_Implementation(CWinNTGroup)
|
||
|
DEFINE_IADsExtension_ExtMgr_Implementation(CWinNTGroup)
|
||
|
DEFINE_IADs_TempImplementation(CWinNTGroup)
|
||
|
DEFINE_IADs_PutGetImplementation(CWinNTGroup,GroupClass,gdwGroupTableSize)
|
||
|
DEFINE_IADsPropertyList_Implementation(CWinNTGroup, GroupClass,gdwGroupTableSize)
|
||
|
|
||
|
CWinNTGroup::CWinNTGroup():
|
||
|
_pDispMgr(NULL),
|
||
|
_pExtMgr(NULL),
|
||
|
_pPropertyCache(NULL),
|
||
|
_ParentType(0),
|
||
|
_DomainName(NULL),
|
||
|
_ServerName(NULL)
|
||
|
{
|
||
|
ENLIST_TRACKING(CWinNTGroup);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
CWinNTGroup::CreateGroup(
|
||
|
BSTR Parent,
|
||
|
ULONG ParentType,
|
||
|
BSTR DomainName,
|
||
|
BSTR ServerName,
|
||
|
BSTR GroupName,
|
||
|
ULONG GroupType,
|
||
|
DWORD dwObjectState,
|
||
|
PSID pSid, // OPTIONAL
|
||
|
REFIID riid,
|
||
|
CWinNTCredentials& Credentials,
|
||
|
void **ppvObj
|
||
|
)
|
||
|
{
|
||
|
CWinNTGroup FAR * pGroup = NULL;
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
BOOL fAccountSid = TRUE;
|
||
|
|
||
|
hr = AllocateGroupObject(&pGroup);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
ADsAssert(pGroup->_pDispMgr);
|
||
|
|
||
|
|
||
|
hr = pGroup->InitializeCoreObject(
|
||
|
Parent,
|
||
|
GroupName,
|
||
|
GROUP_CLASS_NAME,
|
||
|
GROUP_SCHEMA_NAME,
|
||
|
CLSID_WinNTGroup,
|
||
|
dwObjectState
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
hr = ADsAllocString(DomainName, &pGroup->_DomainName);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
hr = ADsAllocString(ServerName, &pGroup->_ServerName);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
pGroup->_ParentType = ParentType;
|
||
|
pGroup->_GroupType = GroupType;
|
||
|
|
||
|
hr = SetDWORDPropertyInCache(
|
||
|
pGroup->_pPropertyCache,
|
||
|
TEXT("groupType"),
|
||
|
GroupType,
|
||
|
TRUE // fExplicit
|
||
|
);
|
||
|
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Try to determine if object corresponds to a account
|
||
|
// domain
|
||
|
//
|
||
|
if (pSid) {
|
||
|
|
||
|
//
|
||
|
// A domain account sid has:
|
||
|
// (1) a identifier authority of SECURITY_NT_AUTHORITY
|
||
|
// (2) at least one subauth identifier
|
||
|
// (3) the first subauth identifier is SECURITY_NT_NON_UNIQUE
|
||
|
//
|
||
|
|
||
|
PSID_IDENTIFIER_AUTHORITY pSidIdentAuth = NULL;
|
||
|
SID_IDENTIFIER_AUTHORITY NtAuthIdentAuth = SECURITY_NT_AUTHORITY;
|
||
|
|
||
|
PDWORD pdwSidSubAuth = NULL;
|
||
|
|
||
|
fAccountSid = FALSE;
|
||
|
|
||
|
pSidIdentAuth = GetSidIdentifierAuthority(pSid);
|
||
|
ADsAssert(pSidIdentAuth);
|
||
|
|
||
|
if (memcmp(pSidIdentAuth, &NtAuthIdentAuth, sizeof(SID_IDENTIFIER_AUTHORITY)) == 0) {
|
||
|
|
||
|
if (GetSidSubAuthorityCount(pSid) > 0) {
|
||
|
|
||
|
pdwSidSubAuth = GetSidSubAuthority(pSid, 0);
|
||
|
ADsAssert(pdwSidSubAuth);
|
||
|
|
||
|
if (*pdwSidSubAuth == SECURITY_NT_NON_UNIQUE) {
|
||
|
fAccountSid = TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pGroup->_Credentials = Credentials;
|
||
|
hr = pGroup->_Credentials.Ref(ServerName, DomainName, ParentType);
|
||
|
if (fAccountSid) {
|
||
|
//
|
||
|
// We permit this to fail if we can determine it is not a account
|
||
|
// sid, since we won't be able to ref credentials on a non-existent
|
||
|
// pseudo-domain like NT AUTHORITY (e.g., the well-known sids)
|
||
|
//
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Load ext mgr and extensions
|
||
|
//
|
||
|
|
||
|
hr = ADSILoadExtensionManager(
|
||
|
GROUP_CLASS_NAME,
|
||
|
(IADsGroup *) pGroup,
|
||
|
pGroup->_pDispMgr,
|
||
|
Credentials,
|
||
|
&pGroup->_pExtMgr
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
ADsAssert(pGroup->_pExtMgr);
|
||
|
|
||
|
//
|
||
|
// Prepopulate the object
|
||
|
//
|
||
|
hr = pGroup->Prepopulate(TRUE,
|
||
|
pSid);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
// check if the call is from UMI
|
||
|
if(Credentials.GetFlags() & ADS_AUTH_RESERVED) {
|
||
|
//
|
||
|
// we do not pass riid to InitUmiObject below. This is because UMI object
|
||
|
// does not support IDispatch. There are several places in ADSI code where
|
||
|
// riid passed into this function is defaulted to IID_IDispatch -
|
||
|
// IADsContainer::Create for example. To handle these cases, we always
|
||
|
// request IID_IUnknown from the UMI object. Subsequent code within UMI
|
||
|
// will QI for the appropriate interface.
|
||
|
//
|
||
|
if(3 == pGroup->_dwNumComponents) {
|
||
|
pGroup->_CompClasses[0] = L"Domain";
|
||
|
pGroup->_CompClasses[1] = L"Computer";
|
||
|
pGroup->_CompClasses[2] = L"Group";
|
||
|
}
|
||
|
else if(2 == pGroup->_dwNumComponents) {
|
||
|
if(NULL == DomainName) {
|
||
|
// workstation services not started. See getobj.cxx.
|
||
|
pGroup->_CompClasses[0] = L"Computer";
|
||
|
pGroup->_CompClasses[1] = L"Group";
|
||
|
}
|
||
|
else if(NULL == ServerName) {
|
||
|
pGroup->_CompClasses[0] = L"Domain";
|
||
|
pGroup->_CompClasses[1] = L"Group";
|
||
|
}
|
||
|
else
|
||
|
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
|
||
|
}
|
||
|
else
|
||
|
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
|
||
|
|
||
|
hr = pGroup->InitUmiObject(
|
||
|
pGroup->_Credentials,
|
||
|
GroupClass,
|
||
|
gdwGroupTableSize,
|
||
|
pGroup->_pPropertyCache,
|
||
|
(IUnknown *) (INonDelegatingUnknown *) pGroup,
|
||
|
pGroup->_pExtMgr,
|
||
|
IID_IUnknown,
|
||
|
ppvObj
|
||
|
);
|
||
|
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
//
|
||
|
// UMI object was created and the interface was obtained successfully.
|
||
|
// UMI object now has a reference to the inner unknown of IADs, since
|
||
|
// the call to Release() below is not going to be made in this case.
|
||
|
//
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
hr = pGroup->QueryInterface(riid, ppvObj);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
pGroup->Release();
|
||
|
|
||
|
RRETURN(hr);
|
||
|
|
||
|
error:
|
||
|
delete pGroup;
|
||
|
|
||
|
RRETURN_EXP_IF_ERR(hr);
|
||
|
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
CWinNTGroup::CreateGroup(
|
||
|
BSTR Parent,
|
||
|
ULONG ParentType,
|
||
|
BSTR DomainName,
|
||
|
BSTR ServerName,
|
||
|
BSTR GroupName,
|
||
|
ULONG GroupType,
|
||
|
DWORD dwObjectState,
|
||
|
REFIID riid,
|
||
|
CWinNTCredentials& Credentials,
|
||
|
void **ppvObj
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
hr = CWinNTGroup::CreateGroup(
|
||
|
Parent,
|
||
|
ParentType,
|
||
|
DomainName,
|
||
|
ServerName,
|
||
|
GroupName,
|
||
|
GroupType,
|
||
|
dwObjectState,
|
||
|
NULL,
|
||
|
riid,
|
||
|
Credentials,
|
||
|
ppvObj
|
||
|
);
|
||
|
|
||
|
RRETURN_EXP_IF_ERR(hr);
|
||
|
}
|
||
|
|
||
|
CWinNTGroup::~CWinNTGroup( )
|
||
|
{
|
||
|
ADsFreeString(_DomainName);
|
||
|
ADsFreeString(_ServerName);
|
||
|
|
||
|
delete _pExtMgr; // created last, destroyed first
|
||
|
|
||
|
delete _pDispMgr;
|
||
|
|
||
|
delete _pPropertyCache;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Function: QueryInterface
|
||
|
//
|
||
|
// Synopsis: If this object is aggregated within another object, then
|
||
|
// all calls will delegate to the outer object. Otherwise, the
|
||
|
// non-delegating QI is called
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// iid interface requested
|
||
|
// ppInterface Returns pointer to interface requested. NULL if interface
|
||
|
// is not supported.
|
||
|
//
|
||
|
// Returns: S_OK on success. Error code otherwise.
|
||
|
//
|
||
|
// Modifies: *ppInterface to return interface pointer
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
STDMETHODIMP CWinNTGroup::QueryInterface(
|
||
|
REFIID iid,
|
||
|
LPVOID *ppInterface
|
||
|
)
|
||
|
{
|
||
|
if(_pUnkOuter != NULL)
|
||
|
RRETURN(_pUnkOuter->QueryInterface(
|
||
|
iid,
|
||
|
ppInterface
|
||
|
));
|
||
|
|
||
|
RRETURN(NonDelegatingQueryInterface(
|
||
|
iid,
|
||
|
ppInterface
|
||
|
));
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Function: AddRef
|
||
|
//
|
||
|
// Synopsis: IUnknown::AddRef. If this object is aggregated within
|
||
|
// another, all calls will delegate to the outer object.
|
||
|
// Otherwise, the non-delegating AddRef is called
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// None
|
||
|
//
|
||
|
// Returns: New reference count
|
||
|
//
|
||
|
// Modifies: Nothing
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
STDMETHODIMP_(ULONG) CWinNTGroup::AddRef(void)
|
||
|
{
|
||
|
if(_pUnkOuter != NULL)
|
||
|
RRETURN(_pUnkOuter->AddRef());
|
||
|
|
||
|
RRETURN(NonDelegatingAddRef());
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Function: Release
|
||
|
//
|
||
|
// Synopsis: IUnknown::Release. If this object is aggregated within
|
||
|
// another, all calls will delegate to the outer object.
|
||
|
// Otherwise, the non-delegating Release is called
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// None
|
||
|
//
|
||
|
// Returns: New reference count
|
||
|
//
|
||
|
// Modifies: Nothing
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
STDMETHODIMP_(ULONG) CWinNTGroup::Release(void)
|
||
|
{
|
||
|
if(_pUnkOuter != NULL)
|
||
|
RRETURN(_pUnkOuter->Release());
|
||
|
|
||
|
RRETURN(NonDelegatingRelease());
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CWinNTGroup::NonDelegatingQueryInterface(
|
||
|
REFIID iid,
|
||
|
LPVOID FAR* ppv
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
if (ppv == NULL) {
|
||
|
RRETURN(E_POINTER);
|
||
|
}
|
||
|
|
||
|
if (IsEqualIID(iid, IID_IUnknown))
|
||
|
{
|
||
|
*ppv = (IADsGroup FAR *) this;
|
||
|
}
|
||
|
else if (IsEqualIID(iid, IID_IADsGroup))
|
||
|
{
|
||
|
*ppv = (IADsGroup FAR *) this;
|
||
|
}
|
||
|
else if (IsEqualIID(iid, IID_IADs))
|
||
|
{
|
||
|
*ppv = (IADsGroup FAR *) this;
|
||
|
}
|
||
|
else if (IsEqualIID(iid, IID_IADsPropertyList))
|
||
|
{
|
||
|
*ppv = (IADsPropertyList FAR *) this;
|
||
|
}
|
||
|
else if (IsEqualIID(iid, IID_IDispatch))
|
||
|
{
|
||
|
*ppv = (IADsGroup FAR *) this;
|
||
|
}
|
||
|
else if (IsEqualIID(iid, IID_ISupportErrorInfo))
|
||
|
{
|
||
|
*ppv = (ISupportErrorInfo FAR *) this;
|
||
|
}
|
||
|
else if( (_pDispatch != NULL) &&
|
||
|
IsEqualIID(iid, IID_IADsExtension) )
|
||
|
{
|
||
|
*ppv = (IADsExtension *) this;
|
||
|
}
|
||
|
else if (_pExtMgr)
|
||
|
{
|
||
|
RRETURN( _pExtMgr->QueryInterface(iid, ppv));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*ppv = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
AddRef();
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/* ISupportErrorInfo method */
|
||
|
STDMETHODIMP
|
||
|
CWinNTGroup::InterfaceSupportsErrorInfo(
|
||
|
THIS_ REFIID riid
|
||
|
)
|
||
|
{
|
||
|
if (IsEqualIID(riid, IID_IADs) ||
|
||
|
IsEqualIID(riid, IID_IADsGroup) ||
|
||
|
IsEqualIID(riid, IID_IADsPropertyList)) {
|
||
|
RRETURN(S_OK);
|
||
|
} else {
|
||
|
RRETURN(S_FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* IADs methods */
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CWinNTGroup::SetInfo(THIS)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
NET_API_STATUS nasStatus;
|
||
|
WCHAR szHostServerName[MAX_PATH];
|
||
|
LPBYTE lpBuffer = NULL;
|
||
|
DWORD dwGroupType = _GroupType;
|
||
|
|
||
|
|
||
|
//
|
||
|
// We need to see if the cache has changed a value for
|
||
|
// groupType and use that info down the line.
|
||
|
//
|
||
|
|
||
|
hr = GetDWORDPropertyFromCache(
|
||
|
_pPropertyCache,
|
||
|
TEXT("groupType"),
|
||
|
&dwGroupType
|
||
|
);
|
||
|
|
||
|
if (SUCCEEDED(hr)) {
|
||
|
//
|
||
|
// Verify the value
|
||
|
//
|
||
|
if ((dwGroupType != WINNT_GROUP_LOCAL)
|
||
|
&& (dwGroupType != WINNT_GROUP_GLOBAL)) {
|
||
|
|
||
|
//
|
||
|
// This is bad value so we need to BAIL
|
||
|
//
|
||
|
hr = E_ADS_BAD_PARAMETER;
|
||
|
}
|
||
|
else {
|
||
|
if (GetObjectState() == ADS_OBJECT_UNBOUND)
|
||
|
_GroupType = dwGroupType;
|
||
|
else
|
||
|
if (_GroupType != dwGroupType) {
|
||
|
hr = E_ADS_BAD_PARAMETER;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
dwGroupType = _GroupType;
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
|
||
|
if (_ParentType == WINNT_DOMAIN_ID) {
|
||
|
|
||
|
hr = WinNTGetCachedDCName(
|
||
|
_DomainName,
|
||
|
szHostServerName,
|
||
|
_Credentials.GetFlags()
|
||
|
);
|
||
|
} else {
|
||
|
|
||
|
hr = MakeUncName(
|
||
|
_ServerName,
|
||
|
szHostServerName
|
||
|
);
|
||
|
}
|
||
|
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
|
||
|
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
|
||
|
|
||
|
if (dwGroupType == WINNT_GROUP_GLOBAL) {
|
||
|
|
||
|
if (_ParentType == WINNT_DOMAIN_ID) {
|
||
|
|
||
|
hr = WinNTCreateGlobalGroup(
|
||
|
szHostServerName + 2,
|
||
|
_Name
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
|
||
|
}else {
|
||
|
|
||
|
hr = WinNTCreateGlobalGroup(
|
||
|
_ServerName,
|
||
|
_Name
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
//
|
||
|
// Group type has to be local
|
||
|
//
|
||
|
|
||
|
hr = WinNTCreateLocalGroup(
|
||
|
szHostServerName + 2,
|
||
|
_Name
|
||
|
);
|
||
|
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
}
|
||
|
|
||
|
SetObjectState(ADS_OBJECT_BOUND);
|
||
|
|
||
|
} // if Object not bound
|
||
|
|
||
|
if (dwGroupType == WINNT_GROUP_GLOBAL) {
|
||
|
|
||
|
nasStatus = NetGroupGetInfo(
|
||
|
szHostServerName,
|
||
|
_Name,
|
||
|
1,
|
||
|
&lpBuffer
|
||
|
);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
nasStatus = NetLocalGroupGetInfo(
|
||
|
szHostServerName,
|
||
|
_Name,
|
||
|
1,
|
||
|
&lpBuffer
|
||
|
);
|
||
|
|
||
|
}
|
||
|
|
||
|
hr = HRESULT_FROM_WIN32(nasStatus);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
hr = Marshall_Set_Level1(
|
||
|
szHostServerName,
|
||
|
TRUE,
|
||
|
lpBuffer
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
if(SUCCEEDED(hr))
|
||
|
_pPropertyCache->ClearModifiedFlags();
|
||
|
|
||
|
//
|
||
|
// objectSid not writable
|
||
|
//
|
||
|
|
||
|
error:
|
||
|
if (lpBuffer) {
|
||
|
NetApiBufferFree(lpBuffer);
|
||
|
}
|
||
|
|
||
|
RRETURN_EXP_IF_ERR(hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CWinNTGroup::GetInfo(THIS)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
|
||
|
|
||
|
RRETURN_EXP_IF_ERR(E_ADS_OBJECT_UNBOUND);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
_pPropertyCache->flushpropcache();
|
||
|
|
||
|
//
|
||
|
// Need to add the group type attribute here.
|
||
|
//
|
||
|
hr = SetDWORDPropertyInCache(
|
||
|
_pPropertyCache,
|
||
|
TEXT("groupType"),
|
||
|
_GroupType,
|
||
|
TRUE // fExplicit
|
||
|
);
|
||
|
//
|
||
|
// GROUP_INFO
|
||
|
//
|
||
|
|
||
|
hr = GetInfo(1, TRUE);
|
||
|
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
//
|
||
|
// objectSid
|
||
|
//
|
||
|
|
||
|
hr = GetInfo(20, TRUE);
|
||
|
|
||
|
error :
|
||
|
|
||
|
RRETURN(hr);
|
||
|
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CWinNTGroup::ImplicitGetInfo(THIS)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
|
||
|
|
||
|
RRETURN_EXP_IF_ERR(E_ADS_OBJECT_UNBOUND);
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Need to add the group type attribute here.
|
||
|
//
|
||
|
hr = SetDWORDPropertyInCache(
|
||
|
_pPropertyCache,
|
||
|
TEXT("groupType"),
|
||
|
_GroupType,
|
||
|
FALSE // fExplicit
|
||
|
);
|
||
|
//
|
||
|
// GROUP_INFO
|
||
|
//
|
||
|
|
||
|
hr = GetInfo(1, FALSE);
|
||
|
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
//
|
||
|
// objectSid
|
||
|
//
|
||
|
|
||
|
hr = GetInfo(20, FALSE);
|
||
|
|
||
|
error :
|
||
|
|
||
|
RRETURN(hr);
|
||
|
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
CWinNTGroup::AllocateGroupObject(
|
||
|
CWinNTGroup ** ppGroup
|
||
|
)
|
||
|
{
|
||
|
CWinNTGroup FAR * pGroup = NULL;
|
||
|
CAggregatorDispMgr FAR * pDispMgr = NULL;
|
||
|
CPropertyCache FAR * pPropertyCache = NULL;
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
|
||
|
pGroup = new CWinNTGroup();
|
||
|
if (pGroup == NULL) {
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
pDispMgr = new CAggregatorDispMgr;
|
||
|
if (pDispMgr == NULL) {
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
hr = LoadTypeInfoEntry(
|
||
|
pDispMgr,
|
||
|
LIBID_ADs,
|
||
|
IID_IADsGroup,
|
||
|
(IADsGroup *)pGroup,
|
||
|
DISPID_REGULAR
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
hr = LoadTypeInfoEntry(
|
||
|
pDispMgr,
|
||
|
LIBID_ADs,
|
||
|
IID_IADsPropertyList,
|
||
|
(IADsPropertyList *)pGroup,
|
||
|
DISPID_VALUE
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
hr = CPropertyCache::createpropertycache(
|
||
|
GroupClass,
|
||
|
gdwGroupTableSize,
|
||
|
(CCoreADsObject *)pGroup,
|
||
|
&pPropertyCache
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
pDispMgr->RegisterPropertyCache(
|
||
|
pPropertyCache
|
||
|
);
|
||
|
|
||
|
pGroup->_pPropertyCache = pPropertyCache;
|
||
|
pGroup->_pDispMgr = pDispMgr;
|
||
|
*ppGroup = pGroup;
|
||
|
|
||
|
RRETURN(hr);
|
||
|
|
||
|
error:
|
||
|
|
||
|
delete pPropertyCache;
|
||
|
delete pDispMgr;
|
||
|
delete pGroup;
|
||
|
|
||
|
RRETURN(hr);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// For current implementation in clocgroup:
|
||
|
// If this function is called as a public function (ie. by another
|
||
|
// modual/class), fExplicit must be FALSE since the cache is NOT
|
||
|
// flushed in this function.
|
||
|
//
|
||
|
// External functions should ONLY call GetInfo(no param) for explicit
|
||
|
// GetInfo. This will flush the cache properly.
|
||
|
//
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CWinNTGroup::GetInfo(
|
||
|
THIS_ DWORD dwApiLevel,
|
||
|
BOOL fExplicit
|
||
|
)
|
||
|
{
|
||
|
|
||
|
HRESULT hr=E_FAIL;
|
||
|
|
||
|
switch (dwApiLevel) {
|
||
|
|
||
|
case 1:
|
||
|
|
||
|
hr = GetStandardInfo(
|
||
|
dwApiLevel,
|
||
|
fExplicit
|
||
|
);
|
||
|
RRETURN_EXP_IF_ERR(hr);
|
||
|
|
||
|
case 20:
|
||
|
|
||
|
hr = GetSidInfo(
|
||
|
fExplicit
|
||
|
);
|
||
|
RRETURN_EXP_IF_ERR(hr);
|
||
|
|
||
|
default:
|
||
|
|
||
|
RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
CWinNTGroup::GetStandardInfo(
|
||
|
DWORD dwApiLevel,
|
||
|
BOOL fExplicit
|
||
|
)
|
||
|
{
|
||
|
|
||
|
NET_API_STATUS nasStatus;
|
||
|
LPBYTE lpBuffer = NULL;
|
||
|
HRESULT hr;
|
||
|
WCHAR szHostServerName[MAX_PATH];
|
||
|
|
||
|
|
||
|
|
||
|
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
|
||
|
|
||
|
RRETURN_EXP_IF_ERR(E_ADS_OBJECT_UNBOUND);
|
||
|
}
|
||
|
|
||
|
if (_ParentType == WINNT_DOMAIN_ID) {
|
||
|
|
||
|
hr = WinNTGetCachedDCName(
|
||
|
_DomainName,
|
||
|
szHostServerName,
|
||
|
_Credentials.GetFlags()
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
}else {
|
||
|
|
||
|
hr = MakeUncName(
|
||
|
_ServerName,
|
||
|
szHostServerName
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Since the object is bound, the groupType has to be
|
||
|
// _GroupType and cannot change.
|
||
|
//
|
||
|
|
||
|
if (_GroupType == WINNT_GROUP_GLOBAL) {
|
||
|
|
||
|
nasStatus = NetGroupGetInfo(
|
||
|
szHostServerName,
|
||
|
_Name,
|
||
|
dwApiLevel,
|
||
|
&lpBuffer
|
||
|
);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
nasStatus = NetLocalGroupGetInfo(
|
||
|
szHostServerName,
|
||
|
_Name,
|
||
|
dwApiLevel,
|
||
|
&lpBuffer
|
||
|
);
|
||
|
|
||
|
}
|
||
|
|
||
|
hr = HRESULT_FROM_WIN32(nasStatus);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
hr = UnMarshall(
|
||
|
lpBuffer,
|
||
|
dwApiLevel,
|
||
|
fExplicit
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
error:
|
||
|
if (lpBuffer) {
|
||
|
NetApiBufferFree(lpBuffer);
|
||
|
}
|
||
|
|
||
|
RRETURN_EXP_IF_ERR(hr);
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
CWinNTGroup::UnMarshall(
|
||
|
LPBYTE lpBuffer,
|
||
|
DWORD dwApiLevel,
|
||
|
BOOL fExplicit
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
ADsAssert(lpBuffer);
|
||
|
switch (dwApiLevel) {
|
||
|
case 1:
|
||
|
hr = UnMarshall_Level1(fExplicit, lpBuffer);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
hr = E_FAIL;
|
||
|
|
||
|
}
|
||
|
RRETURN_EXP_IF_ERR(hr);
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
CWinNTGroup::UnMarshall_Level1(BOOL fExplicit, LPBYTE pBuffer)
|
||
|
{
|
||
|
BSTR bstrData = NULL;
|
||
|
LPGROUP_INFO_1 pGroupInfo1 = NULL;
|
||
|
LPLOCALGROUP_INFO_1 pLocalGroupInfo1 = NULL;
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
hr = SetLPTSTRPropertyInCache(
|
||
|
_pPropertyCache,
|
||
|
TEXT("Name"),
|
||
|
_Name,
|
||
|
fExplicit
|
||
|
);
|
||
|
|
||
|
if (_GroupType == WINNT_GROUP_GLOBAL) {
|
||
|
|
||
|
pGroupInfo1 = (LPGROUP_INFO_1)pBuffer;
|
||
|
|
||
|
hr = SetLPTSTRPropertyInCache(
|
||
|
_pPropertyCache,
|
||
|
TEXT("Description"),
|
||
|
pGroupInfo1->grpi1_comment,
|
||
|
fExplicit
|
||
|
);
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
pLocalGroupInfo1 = (LPLOCALGROUP_INFO_1) pBuffer;
|
||
|
|
||
|
hr = SetLPTSTRPropertyInCache(
|
||
|
_pPropertyCache,
|
||
|
TEXT("Description"),
|
||
|
pLocalGroupInfo1->lgrpi1_comment,
|
||
|
fExplicit
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
CWinNTGroup::Prepopulate(
|
||
|
BOOL fExplicit,
|
||
|
PSID pSid // OPTIONAL
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
DWORD dwErr = 0;
|
||
|
DWORD dwSidLength = 0;
|
||
|
|
||
|
if (pSid) {
|
||
|
|
||
|
//
|
||
|
// On NT4 for some reason GetLengthSID does not set lasterror to 0
|
||
|
//
|
||
|
SetLastError(NO_ERROR);
|
||
|
|
||
|
dwSidLength = GetLengthSid((PSID) pSid);
|
||
|
|
||
|
//
|
||
|
// This is an extra check to make sure that we have the
|
||
|
// correct length.
|
||
|
//
|
||
|
dwErr = GetLastError();
|
||
|
if (dwErr != NO_ERROR) {
|
||
|
hr = HRESULT_FROM_WIN32(dwErr);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
}
|
||
|
|
||
|
hr = SetOctetPropertyInCache(
|
||
|
_pPropertyCache,
|
||
|
TEXT("objectSid"),
|
||
|
(PBYTE) pSid,
|
||
|
dwSidLength,
|
||
|
TRUE
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
}
|
||
|
|
||
|
error:
|
||
|
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
CWinNTGroup::Marshall_Set_Level1(
|
||
|
LPWSTR szHostServerName,
|
||
|
BOOL fExplicit,
|
||
|
LPBYTE pBuffer
|
||
|
)
|
||
|
{
|
||
|
LPGROUP_INFO_1 pGroupInfo1 = NULL;
|
||
|
LPLOCALGROUP_INFO_1 pLocalGroupInfo1 = NULL;
|
||
|
HRESULT hr = S_OK;
|
||
|
NET_API_STATUS nasStatus;
|
||
|
DWORD dwParmErr;
|
||
|
LPWSTR pszDescription = NULL;
|
||
|
|
||
|
hr = GetLPTSTRPropertyFromCache(
|
||
|
_pPropertyCache,
|
||
|
TEXT("Description"),
|
||
|
&pszDescription
|
||
|
);
|
||
|
|
||
|
if(SUCCEEDED(hr)) {
|
||
|
|
||
|
if (_GroupType == WINNT_GROUP_GLOBAL) {
|
||
|
|
||
|
// hr = UM_GET_BSTR_PROPERTY(_pGenInfo,Description, bstrData);
|
||
|
|
||
|
//
|
||
|
// This should in reality call a virtual function of a derived
|
||
|
// class, beta fix!
|
||
|
//
|
||
|
|
||
|
pGroupInfo1 = (LPGROUP_INFO_1)pBuffer;
|
||
|
pGroupInfo1->grpi1_comment = pszDescription;
|
||
|
|
||
|
//
|
||
|
// Now perform the Set call.
|
||
|
//
|
||
|
|
||
|
nasStatus = NetGroupSetInfo(
|
||
|
szHostServerName,
|
||
|
_Name,
|
||
|
1,
|
||
|
(LPBYTE)pGroupInfo1,
|
||
|
&dwParmErr
|
||
|
);
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
pLocalGroupInfo1 = (LPLOCALGROUP_INFO_1)pBuffer;
|
||
|
pLocalGroupInfo1->lgrpi1_comment = pszDescription;
|
||
|
|
||
|
nasStatus = NetLocalGroupSetInfo(
|
||
|
szHostServerName,
|
||
|
_Name,
|
||
|
1,
|
||
|
(LPBYTE)pLocalGroupInfo1,
|
||
|
&dwParmErr
|
||
|
);
|
||
|
|
||
|
}
|
||
|
|
||
|
hr = HRESULT_FROM_WIN32(nasStatus);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
}else {
|
||
|
|
||
|
//
|
||
|
// This is because there is no data to marshall
|
||
|
//
|
||
|
|
||
|
hr = S_OK;
|
||
|
|
||
|
}
|
||
|
|
||
|
error:
|
||
|
|
||
|
if (pszDescription) {
|
||
|
FreeADsStr(pszDescription);
|
||
|
}
|
||
|
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
CWinNTGroup::Marshall_Create_Level1(
|
||
|
LPWSTR szHostServerName,
|
||
|
LPGROUP_INFO_1 pGroupInfo1
|
||
|
)
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// This routine is not called from anywhere ???
|
||
|
//
|
||
|
HRESULT hr = S_OK;
|
||
|
NET_API_STATUS nasStatus = ERROR_INVALID_DATA;
|
||
|
DWORD dwParmErr;
|
||
|
|
||
|
if (_GroupType == WINNT_GROUP_GLOBAL) {
|
||
|
|
||
|
pGroupInfo1->grpi1_name = _Name;
|
||
|
pGroupInfo1->grpi1_comment = NULL;
|
||
|
nasStatus = NetGroupAdd(
|
||
|
szHostServerName,
|
||
|
1,
|
||
|
(LPBYTE)pGroupInfo1,
|
||
|
&dwParmErr
|
||
|
);
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
ADsAssert(!"Group type is bad internally!");
|
||
|
|
||
|
/*
|
||
|
pLocalGroupInfo1->lgrp1_name = _Name;
|
||
|
pLocalGroupInfo1->grp1_comment = NULL;
|
||
|
nasStatus = NetLocalGroupAdd(
|
||
|
szHostServerName,
|
||
|
1,
|
||
|
(LPBYTE)pLocalGroupInfo1,
|
||
|
&dwParmErr
|
||
|
);
|
||
|
*/
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
hr = HRESULT_FROM_WIN32(nasStatus);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
error:
|
||
|
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
CWinNTGroup::GetSidInfo(
|
||
|
IN BOOL fExplicit
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = E_FAIL;
|
||
|
WCHAR szHostServerName[MAX_PATH];
|
||
|
|
||
|
//
|
||
|
// Get Server Name
|
||
|
//
|
||
|
|
||
|
if (_ParentType == WINNT_DOMAIN_ID) {
|
||
|
|
||
|
hr = WinNTGetCachedDCName(
|
||
|
_DomainName,
|
||
|
szHostServerName,
|
||
|
_Credentials.GetFlags()
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
}else {
|
||
|
|
||
|
hr = MakeUncName(
|
||
|
_ServerName,
|
||
|
szHostServerName
|
||
|
);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get Sid of this group and store in cache if fExplicit.
|
||
|
//
|
||
|
|
||
|
hr = GetSidIntoCache(
|
||
|
szHostServerName,
|
||
|
_Name,
|
||
|
_pPropertyCache,
|
||
|
fExplicit
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
|
||
|
error:
|
||
|
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|