|
|
//---------------------------------------------------------------------------
//
// 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 ); BAIL_ON_FAILURE(hr); }
//
// Get Sid of this group and store in cache if fExplicit.
//
hr = GetSidIntoCache( szHostServerName, _Name, _pPropertyCache, fExplicit ); BAIL_ON_FAILURE(hr);
error:
RRETURN(hr); }
|