/*++ Copyright (C) 1996-2001 Microsoft Corporation Module Name: Abstract: History: --*/ //*************************************************************************** // // SECEDIT.CPP // // Support classes for WBEM Security Editor. // // raymcc 11-Jul-97 Created // raymcc 29-Jan-98 Updated for v1 Revised Security // raymcc 5-Feb-98 Fixed some return codes // //*************************************************************************** #include "precomp.h" #include #include #include #include #include #include //*************************************************************************** // // String helpers // //*************************************************************************** inline wchar_t *Macro_CloneLPWSTR(LPCWSTR src) { if (!src) return 0; wchar_t *dest = new wchar_t[wcslen(src) + 1]; if (!dest) return 0; return wcscpy(dest, src); } LPWSTR GetExpandedSlashes(LPWSTR pszUserName) { static WCHAR wcBuff[MAX_PATH]; memset(wcBuff,0,MAX_PATH*2); WCHAR * pTo; for(pTo = wcBuff; *pszUserName; pTo++, pszUserName++) { if(*pszUserName == '\\') { *pTo = '\\'; pTo++; } *pTo = *pszUserName; } return wcBuff; } // Version which takes nulls into consideration. BOOL StringTest(LPWSTR psz1, LPWSTR psz2) { if (psz1 == 0 && psz2 == 0) return TRUE; if (psz1 == 0 || psz2 == 0) return FALSE; return _wcsicmp(psz1, psz2) == 0; } //*************************************************************************** // // CWbemSubject default constructor. // //*************************************************************************** // ok CWbemSubject::CWbemSubject(DWORD dwType) { m_pName = 0; m_pAuthority = Macro_CloneLPWSTR(L"."); m_dwFlags = 0; m_dwType = dwType; } //*************************************************************************** // // CWbemSubject destructor. // //*************************************************************************** // ok CWbemSubject::~CWbemSubject() { delete [] m_pName; delete [] m_pAuthority; } //*************************************************************************** // // CWbemSubject copy constructor. // //*************************************************************************** // ok CWbemSubject::CWbemSubject(CWbemSubject & Src) { m_pName = 0; m_dwFlags = 0; m_dwType = 0; m_pAuthority = 0; *this = Src; } //*************************************************************************** // // CWbemSubject assignment operator. // //*************************************************************************** // ok CWbemSubject & CWbemSubject::operator = (CWbemSubject & Src) { delete [] m_pName; delete [] m_pAuthority; m_pName = Macro_CloneLPWSTR(Src.m_pName); m_pAuthority = Macro_CloneLPWSTR(Src.m_pAuthority); m_dwFlags = Src.m_dwFlags; m_dwType = Src.m_dwType; return *this; } //*************************************************************************** // // CWbemSubject::operator == // // Comparison operator. // // Tests only the name, domain and type. Other functionality relies on // this test *not* being extended. Don't touch it! // //*************************************************************************** // ok int CWbemSubject::operator ==(CWbemSubject &Test) { if (Test.m_dwType != m_dwType) return 0; if (StringTest(Test.m_pName, m_pName) == FALSE) return 0; if (StringTest(Test.m_pAuthority, m_pAuthority) == FALSE) return 0; return TRUE; } //*************************************************************************** // // CWbemSubject::SetName // // Sets the subject 'name' field. // // Parameters: // The new 'name' string (read-only). // // Return values: // InvalidParameter, NoError // //*************************************************************************** // ok int CWbemSubject::SetName(LPWSTR pName) { if (pName == 0 || wcslen(pName) == 0) return InvalidParameter; m_pName = Macro_CloneLPWSTR(pName); return NoError; } //*************************************************************************** // // CWbemSubject::IsValid // // Determines whether the subject is valid (capable of being written to // the database). // // Return value: // TRUE if the user has enough data to allow it to be written, FALSE // if not. // //*************************************************************************** // ok BOOL CWbemSubject::IsValid() { if (m_pName == 0 || wcslen(m_pName) == 0) return FALSE; if (m_dwType == 0) return FALSE; return TRUE; } //*************************************************************************** // // CWbemUser::CWbemUser // // Default constructor // //*************************************************************************** // ok CWbemUser::CWbemUser() : CWbemSubject(CWbemSubject::Type_User) { } //*************************************************************************** // // CWbemUser::~CWbemUser // // Destructor // //*************************************************************************** // ok CWbemUser::~CWbemUser() { } //*************************************************************************** // // CWbemUser copy constructor // //*************************************************************************** // ok CWbemUser::CWbemUser(CWbemUser &Src) : CWbemSubject(Src) { *this = Src; } //*************************************************************************** // // CWbemUser::operator = // // Assignment operator // //*************************************************************************** // ok CWbemUser & CWbemUser::operator =(CWbemUser &Src) { CWbemSubject::operator=(Src); // Copy base class stuff return *this; } //*************************************************************************** // // CWbemUser::SetNtlmDomain // // Sets the domain name if NTLM authentication is in use. // Authentication_NTLM must be set before calling this method. // // Parameters: // The domain name to authenticate againt. // // Return value: // NoError, InvalidParameter // //*************************************************************************** // ok int CWbemUser::SetNtlmDomain( LPWSTR pszDomain ) { if (pszDomain) m_pAuthority = Macro_CloneLPWSTR(pszDomain); else m_pAuthority = Macro_CloneLPWSTR(L"."); return NoError; } //*************************************************************************** // // CWbemUser::IsValid // // Determines whether the subject is valid (capable of being written to // the database). // // Return value: // TRUE if the user has enough data to allow it to be written, FALSE // if not. // //*************************************************************************** // ok BOOL CWbemUser::IsValid() { return CWbemSubject::IsValid(); } //*************************************************************************** // // CWbemGroup default constructor // //*************************************************************************** // ok CWbemGroup::CWbemGroup() : CWbemSubject(CWbemSubject::Type_Group) { m_dwGroupFlags = 0; } //*************************************************************************** // // CWbemGroup // // Destructor // //*************************************************************************** // ok CWbemGroup::~CWbemGroup() { } //*************************************************************************** // // CWbemGroup copy constructor // //*************************************************************************** // ok CWbemGroup::CWbemGroup(CWbemGroup &Src) : CWbemSubject(Src) { m_dwGroupFlags = 0; *this = Src; } //*************************************************************************** // // CWbemGroup assignment operator // //*************************************************************************** // ok CWbemGroup & CWbemGroup::operator =(CWbemGroup &Src) { CWbemSubject::operator=(Src); // Copy base class stuff m_dwGroupFlags = Src.m_dwGroupFlags; return *this; } //*************************************************************************** // // CWbemGroup::IsValid // // Determines whether the subject is valid (capable of being written to // the database). // // Return value: // TRUE if the group has enough data to allow it to be written, FALSE // if not. // //*************************************************************************** // ok BOOL CWbemGroup::IsValid() { if (m_dwGroupFlags == 0) return FALSE; if (m_dwGroupFlags & GroupType_NTLM_Global) { if (m_pAuthority == 0 || wcslen(m_pAuthority) == 0) return FALSE; } return CWbemSubject::IsValid(); } //*************************************************************************** // // CWbemGroup::SetNtlmDomain // // Sets the domain name for the group if the group is an NTLM group. // Caller must call SetFlags() with GroupType_NTLM before calling // this method. // // Parameters: // The domain name for the group // // Return value: // // //*************************************************************************** // ok BOOL CWbemGroup::SetNtlmDomain( LPWSTR pszDomainName ) { if (!( (m_dwGroupFlags & GroupType_NTLM_Global) || (m_dwGroupFlags & GroupType_NTLM_Local) )) return FALSE; delete [] m_pAuthority; if (pszDomainName) m_pAuthority = Macro_CloneLPWSTR(pszDomainName); else m_pAuthority = Macro_CloneLPWSTR(L"."); return TRUE; } //*************************************************************************** // // CWbemSecurity::Login // // Object factory used to log in to the security editor classes. // // Parameters: // User who is logging in. // Password // Authority (Format: "NTLMDOMAIN:xxx") or NULL // Must be zero. // If NoError is returned, receives the // pointer to a new CWbemSecurity object. // Group must deallocate using operator delete. // // Return value: // NoError, Failed, AccessDenied // //*************************************************************************** // ok int CWbemSecurity::Login( LPWSTR pUser, LPWSTR pPassword, LPWSTR pDomain, DWORD dwReserved, CWbemSecurity **pSecEdit ) { *pSecEdit = 0; IWbemLocator *pLoc = 0; DWORD dwRes = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc ); if (dwRes != S_OK) { return Failed; } IWbemServices *pSvc = 0; HRESULT hRes = pLoc->ConnectServer( CBSTR(L"\\\\.\\ROOT\\SECURITY"), CBSTR(pUser), // user CBSTR(pPassword), // passwrd 0, 0, // Login type CBSTR(pDomain), 0, &pSvc ); if (hRes) { pLoc->Release(); return AccessDenied; } CWbemSecurity *pNew = new CWbemSecurity; pNew->m_pSecurity = pSvc; pNew->Load(); *pSecEdit = pNew; return NoError; } //*************************************************************************** // // CWbemSecurity::GetUser // // Retrieves a user by index. // // Parameters: // The 0-based index of the user to retrieve. // // Return value: // The CWbemUser user object. The name may be NULL if was out of // range. // //*************************************************************************** // ok CWbemUser CWbemSecurity::GetUser(int n) { CWbemUser RetUser; if (n >= m_aUsers.Size()) return RetUser; RetUser = *(CWbemUser *) m_aUsers[n]; return RetUser; } //*************************************************************************** // // CWbemSecurity::DeleteUser // // Removes the user from the database. // // Parameters: // A read-only pointer to the user name to delete. // If TRUE, then create-only. Otherwise, update-only. // // Return value: // NoError, NotFound, InvalidParameter // //*************************************************************************** // ok int CWbemSecurity::DeleteUser( LPWSTR pszUser, LPWSTR pszDomain ) { if (pszUser == 0 || wcslen(pszUser) == 0) return InvalidParameter; BOOL bRes = FALSE; // Remove user from main list. // =========================== for (int i = 0; i < m_aUsers.Size(); i++) { CWbemUser *pTest = (CWbemUser *) m_aUsers[i]; if (StringTest(pTest->GetName(), pszUser) == TRUE && StringTest(pTest->GetAuthority(), pszDomain) == TRUE ) { delete pTest; m_aUsers.RemoveAt(i); bRes = TRUE; break; } } if (bRes == FALSE) return NotFound; return NoError; } //*************************************************************************** // // CWbemSecurity::PutUser // // Writes the user to the database. Creates it if not present, or // overwrites the existing definition. // // Parameters: // A copy of the user to write. // // Return value: // NoError, InvalidUser, AlreadyExists, ExistsAsGroup // //*************************************************************************** // ok int CWbemSecurity::PutUser( CWbemUser &User, BOOL bCreate ) { if (!User.IsValid()) return InvalidUser; // Replace, if possible. // ===================== for (int i = 0; i < m_aUsers.Size(); i++) { CWbemUser *p = (CWbemUser *) m_aUsers[i]; if (*p == User) { if (bCreate) return AlreadyExists; *p = User; return NoError; } } // If here, a new user. Make sure that there is no group by this name. // ==================================================================== CWbemGroup Grp; if (FindGroup(User.GetName(), User.GetAuthority(), Grp) == TRUE) return ExistsAsGroup; // If here, we can safely add the user. // ==================================== CWbemUser *pNew = new CWbemUser(User); m_aUsers.Add(pNew); return NoError; } //*************************************************************************** // // CWbemSecurity::FindUser // // Finds a user based on the name. // // Parameters: // // // Return value: // TRUE if found, FALSE if not. If FALSE is returned is not // set to a valid user. // //*************************************************************************** // ok BOOL CWbemSecurity::FindUser( IN LPWSTR pszUserName, IN LPWSTR pszDomain, OUT CWbemUser &User ) { if (pszUserName == 0 || wcslen(pszUserName) == 0) return FALSE; for (int i = 0; i < m_aUsers.Size(); i++) { CWbemUser *pTest = (CWbemUser *) m_aUsers[i]; if (StringTest(pTest->GetName(), pszUserName) == TRUE && StringTest(pTest->GetAuthority(), pszDomain) == TRUE ) { User = *pTest; return TRUE; } } return FALSE; } //*************************************************************************** // // CWbemSecurity::GetGroup // // Retrieves the specified group by 0-based index. // // Parameters: // The index of the group to retrieve. // // Return value: // A CWbemGroup object. This will be empty if the index was out // of range. (Call CWbemGroup::IsValid() to determine this. // //*************************************************************************** // ok CWbemGroup CWbemSecurity::GetGroup(int n) { CWbemGroup RetGroup; if (n >= m_aGroups.Size()) return RetGroup; RetGroup = *(CWbemGroup *) m_aGroups[n]; return RetGroup; } //*************************************************************************** // // CWbemSecurity::DeleteGroup // // Deletes a particular group. // // Parameters: // A read-only pointer to the name of the group to delete // // Return value: // InvalidParameter, NoError, NotFound // //*************************************************************************** // ok int CWbemSecurity::DeleteGroup( LPWSTR pszGroup, LPWSTR pszDomain ) { if (pszGroup == 0 || wcslen(pszGroup) == 0) return InvalidParameter; BOOL bRes = FALSE; // Remove group from main list. // ============================ for (int i = 0; i < m_aGroups.Size(); i++) { CWbemGroup *pTest = (CWbemGroup *) m_aGroups[i]; if (StringTest(pTest->GetName(), pszGroup) == TRUE && StringTest(pTest->GetAuthority(), pszDomain) == TRUE ) { delete pTest; m_aGroups.RemoveAt(i); return NoError; } } return NotFound; } //*************************************************************************** // // CWbemSecurity::PutGroup // // Writes a group definition. Recursively updates any occurrences // of the group within other groups. // // Parameters: // A copy of the CWbemGroup object to add. // // Return value: // InvalidGroup, NoError, ExistsAsUser // //*************************************************************************** // ok int CWbemSecurity::PutGroup( CWbemGroup &Group ) { if (!Group.IsValid()) return InvalidGroup; // Replace, if possible. // ====================== for (int i = 0; i < m_aGroups.Size(); i++) { CWbemGroup *p = (CWbemGroup *) m_aGroups[i]; if (*p == Group) { *p = Group; return NoError; } } // If here, a new group. Make sure that there is no user by this name. // ==================================================================== CWbemUser User; if (FindUser(Group.GetName(), Group.GetAuthority(), User) == TRUE) return ExistsAsUser; // If here, a new group. // ===================== CWbemGroup *pNew = new CWbemGroup(Group); m_aGroups.Add(pNew); return NoError; } //*************************************************************************** // // CWbemSecurity::FindGroup // // Finds a group based on the name. // // Parameters: // // // Return value: // TRUE if found, FALSE if not. If FALSE is returned is not // set to a valid group name. // //*************************************************************************** // ok BOOL CWbemSecurity::FindGroup( IN LPWSTR pszGroupName, IN LPWSTR pszDomain, OUT CWbemGroup &Group ) { if (pszGroupName == 0 || wcslen(pszGroupName) == 0) return FALSE; for (int i = 0; i < m_aGroups.Size(); i++) { CWbemGroup *pTest = (CWbemGroup *) m_aGroups[i]; if (StringTest(pTest->GetName(), pszGroupName) == TRUE && StringTest(pTest->GetAuthority(), pszDomain) == TRUE ) { Group = *pTest; return TRUE; } } return FALSE; } //*************************************************************************** // // CWbemSecurity destructor // //*************************************************************************** // ok CWbemSecurity::~CWbemSecurity() { if (m_pSecurity) m_pSecurity->Release(); for (int i = 0; i < m_aGroups.Size(); i++) { CWbemGroup *pTest = (CWbemGroup *) m_aGroups[i]; delete pTest; } for (i = 0; i < m_aUsers.Size(); i++) { CWbemUser *pTest = (CWbemUser *) m_aUsers[i]; delete pTest; } for (i = 0; i < m_aOriginalObjects.Size(); i++) { IWbemClassObject *pObj = (IWbemClassObject *) m_aOriginalObjects[i]; pObj->Release(); } } //*************************************************************************** // // CWbemSecurity::Load // // Loads the editing classes with the entire user base and their // memberships. // // Under the Revised Security Schema for V1, the query specified actually // returns NTLM // //*************************************************************************** // ok DWORD CWbemSecurity::Load() { // Query for all users and groups. // =============================== CBSTR Language(L"WQL"); CBSTR Query(L"select * from __Subject"); IEnumWbemClassObject *pEnum = 0; HRESULT hRes = m_pSecurity->ExecQuery( Language, Query, WBEM_FLAG_FORWARD_ONLY, // Flags 0, // Context &pEnum ); if (hRes != 0) return QueryFailure; ULONG uTotal = 0; for (;;) { IWbemClassObject *pObj = 0; ULONG uReturned = 0; hRes = pEnum->Next( 0, // timeout 1, // one object &pObj, &uReturned ); uTotal += uReturned; if (uReturned == 0) break; // If here, another user or group to add to the database. // ====================================================== DWORD dwRes = LoadObject(pObj); // Save the object back so that when we write we can // write just diffs. // ================================================= if (dwRes == 0) m_aOriginalObjects.Add(pObj); else pObj->Release(); // Release objects we don't own. } pEnum->Release(); return NoError; } //*************************************************************************** // // CWbemSecurity::LoadObject // // Loads a single object. This might be a user or a group. // //*************************************************************************** // ok DWORD CWbemSecurity::LoadObject( IWbemClassObject *pObj ) { // Determine if the object is a user or a group by examining // its class. We are looking for // ========================================================= BOOL bUser = FALSE; BOOL bGroup = FALSE; CVARIANT vClass; pObj->Get(CBSTR(L"__CLASS"), 0, &vClass, 0, 0); if (_wcsicmp(vClass, L"__NTLMUser") == 0) bUser = TRUE; else if (_wcsicmp(vClass, L"__NTLMGroup") == 0) bGroup = TRUE; else { // If here, it was a __Subject not related to our security, // so we must leave it alone. return AlienSubject; } // Query for properties common to groups and users. // ================================================ CVARIANT vName; CVARIANT vEnabled; CVARIANT vEditSecurity; CVARIANT vExecMethods; CVARIANT vPermissions; pObj->Get(CBSTR(L"Name"), 0, &vName, 0, 0); pObj->Get(CBSTR(L"Enabled"), 0, &vEnabled, 0, 0); pObj->Get(CBSTR(L"Permissions"), 0, &vPermissions, 0, 0); pObj->Get(CBSTR(L"EditSecurity"), 0, &vEditSecurity, 0, 0); pObj->Get(CBSTR(L"ExecuteMethods"), 0, &vExecMethods, 0, 0); // Set up the permissions flags. // ============================= DWORD dwFlags = 0; if (vEnabled.GetBool()) dwFlags |= CWbemSubject::Perm_Enabled; if (LONG(vPermissions) == 0) dwFlags |= CWbemSubject::Perm_Read; else if (LONG(vPermissions) == 1) dwFlags |= CWbemSubject::Perm_WriteInstance; else if (LONG(vPermissions) == 2) dwFlags |= CWbemSubject::Perm_WriteClass; if (vEditSecurity.GetBool()) dwFlags |= CWbemSubject::Perm_EditSecurity; if (vExecMethods.GetBool()) dwFlags |= CWbemSubject::Perm_ExecuteMethods; // Determine whether a group or user and add in the specific parts. // ================================================================ if (bUser) { // If a user, set up user-specific parts. // ====================================== CVARIANT vDomain; pObj->Get(CBSTR(L"Authority"), 0, &vDomain, 0, 0); CWbemUser User; User.SetName(vName); User.SetFlags(dwFlags); User.SetNtlmDomain(vDomain); PutUser(User, TRUE); } else { // If a group, add in the group-specific parts. // ============================================ CWbemGroup Group; Group.SetName(vName); Group.SetFlags(dwFlags); CVARIANT vGroupType; pObj->Get(CBSTR(L"GroupType"), 0, &vGroupType, 0, 0); if (LONG(vGroupType) == 0) Group.SetGroupFlags(CWbemGroup::GroupType_NTLM_Local); else { CVARIANT vDomain; pObj->Get(CBSTR(L"Authority"), 0, &vDomain, 0, 0); Group.SetGroupFlags(CWbemGroup::GroupType_NTLM_Global); Group.SetNtlmDomain(vDomain); } PutGroup(Group); } return NoError; } //*************************************************************************** // // CWbemSecurity::BuildUser // //*************************************************************************** // ok DWORD CWbemSecurity::BuildUser( CWbemUser &User, IWbemClassObject *pUser ) { CVARIANT vUser(User.GetName()); HRESULT hRes = pUser->Put(CBSTR(L"Name"), 0, &vUser, 0); DWORD dwFlags = User.GetFlags(); if (dwFlags & CWbemSubject::Perm_Enabled) { pUser->Put(CBSTR(L"Enabled"), 0, CVARIANT(TRUE), 0); } DWORD dwValue = 0; // Read-only by default if (dwFlags & CWbemSubject::Perm_WriteInstance) dwValue = 1; if (dwFlags & CWbemSubject::Perm_WriteClass) dwValue = 2; CVARIANT vPermissions; vPermissions.SetLONG(LONG(dwValue)); pUser->Put(CBSTR(L"Permissions"), 0, &vPermissions, 0); if (dwFlags & CWbemSubject::Perm_EditSecurity) { pUser->Put(CBSTR(L"EditSecurity"), 0, CVARIANT(TRUE), 0); } if (dwFlags & CWbemSubject::Perm_ExecuteMethods) { pUser->Put(CBSTR(L"ExecuteMethods"), 0, CVARIANT(TRUE), 0); } // Get the NTLM domain. // ==================== CVARIANT vDomain; LPWSTR pDom = User.GetNtlmDomain(); if (pDom == 0) pDom = L"."; vDomain.SetStr(pDom); pUser->Put(CBSTR(L"Authority"), 0, &vDomain, 0); // Write the instance. // =================== hRes = m_pSecurity->PutInstance(pUser, 0, 0, 0); if (hRes) return Failed; return NoError; } //*************************************************************************** // // CWbemSecurity::BuildNewUserList // //*************************************************************************** // ok DWORD CWbemSecurity::BuildNewUserList() { // Get the class definition. // ========================= IWbemClassObject *pUserClass = 0; HRESULT hRes = m_pSecurity->GetObject(CBSTR(L"__NtlmUser"), 0, 0, &pUserClass, 0); if (hRes) return Failed; // Assert all the users. // ===================== for (int i = 0; i < GetNumUsers(); i++) { CWbemUser User = GetUser(i); if (!User.IsValid()) continue; IWbemClassObject *pUser = 0; hRes = pUserClass->SpawnInstance(0, &pUser); if (hRes) return Failed; if (BuildUser(User, pUser)) return Failed; pUser->Release(); } // Release class definitions. // ========================== pUserClass->Release(); return NoError; } //*************************************************************************** // // CWbemSecurity::BuildNewGroupBase // //*************************************************************************** // ok DWORD CWbemSecurity::BuildNewGroupList() { HRESULT hRes; // Create all the groups. // ====================== IWbemClassObject *pNtlmGroupClass = 0; hRes = m_pSecurity->GetObject(CBSTR(L"__NTLMGroup"), 0, 0, &pNtlmGroupClass, 0); if (hRes) return Failed; for (int i = 0; i < GetNumGroups(); i++) { CWbemGroup Group = GetGroup(i); if (!Group.IsValid()) continue; IWbemClassObject *pGroup = 0; hRes = pNtlmGroupClass->SpawnInstance(0, &pGroup); if (hRes) return Failed; if (BuildGroup(Group, pGroup)) return Failed; pGroup->Release(); } pNtlmGroupClass->Release(); return NoError; } //*************************************************************************** // // CWbemSecurity::BuildGroup // //*************************************************************************** // ok DWORD CWbemSecurity::BuildGroup( CWbemGroup &Group, IWbemClassObject *pGroup ) { CVARIANT vUser(Group.GetName()); HRESULT hRes = pGroup->Put(CBSTR(L"Name"), 0, &vUser, 0); DWORD dwFlags = Group.GetFlags(); if (dwFlags & CWbemSubject::Perm_Enabled) { pGroup->Put(CBSTR(L"Enabled"), 0, CVARIANT(TRUE), 0); } DWORD dwValue = 0; // Read-only by default if (dwFlags & CWbemSubject::Perm_WriteInstance) dwValue = 1; if (dwFlags & CWbemSubject::Perm_WriteClass) dwValue = 2; CVARIANT vPermissions; vPermissions.SetLONG(LONG(dwValue)); pGroup->Put(CBSTR(L"Permissions"), 0, vPermissions, 0); if (dwFlags & CWbemSubject::Perm_EditSecurity) { pGroup->Put(CBSTR(L"EditSecurity"), 0, CVARIANT(TRUE), 0); } if (dwFlags & CWbemSubject::Perm_ExecuteMethods) { pGroup->Put(CBSTR(L"ExecuteMethods"), 0, CVARIANT(TRUE), 0); } // Get the group type. // =================== CVARIANT vGroupType; DWORD dwGroupFlags = Group.GetGroupFlags(); if (dwGroupFlags == CWbemGroup::GroupType_NTLM_Local) vGroupType.SetLONG(0); else if (dwGroupFlags == CWbemGroup::GroupType_NTLM_Global) vGroupType.SetLONG(1); pGroup->Put(CBSTR(L"GroupType"), 0, &vGroupType, 0); // Get the NTLM domain // =================== CVARIANT vDomain; LPWSTR pDom = Group.GetNtlmDomain(); if (pDom == 0) pDom = L"."; vDomain.SetStr(pDom); pGroup->Put(CBSTR(L"Authority"), 0, &vDomain, 0); // Write the group // =============== hRes = m_pSecurity->PutInstance(pGroup, 0, 0, 0); if (hRes) return Failed; return NoError; } //*************************************************************************** // // CWbemSecurity::CommitChanges // // This will invoke a complex sequence to update ROOT\SECURITY. // // The algorithm is as follows: // // (1) We want to update the database in such a way that at no point are // all the users deleted. For example, if we delete all __Subjects, // we actually can erase subjects which we don't own, and if a power // failure occurred, all subjects could get wiped out. // (2) During the Load() sequence, we save all the original objects returned // from the query. All objects which we own are saved. Ones we don't // understand are simply ignored during the Load() sequence. // (3) When the user is finished editing, we have a 'new' list of users // and a copy of the 'old' list. We now want to put all 'new' users // so as to write any changes. Any users that were deleted // will appear in the 'old' list, but not the 'new' one. For these, // we simply get the object path and delete them. // //*************************************************************************** // ? int CWbemSecurity::CommitChanges() { if (BuildNewUserList()) return Failed; if (BuildNewGroupList()) return Failed; if (PurgeDeletedSubjects()) return Failed; // Reload so that any additional commits will work off the just saved list rather // than the original. Load(); return NoError; } //*************************************************************************** // // CWbemSecurity::PurgeDeletedSubjects // //*************************************************************************** DWORD CWbemSecurity::PurgeDeletedSubjects() { // Loop through all __Subjects looking for __NTLMGroup or // __NTLMUser instancs which are not in the aGroups[] or aUsers[] // arrays. These will all be deleted. int i, iu, ig; HRESULT hRes; for (i = 0; i < m_aOriginalObjects.Size(); i++) { IWbemClassObject *pObj = (IWbemClassObject *) m_aOriginalObjects[i]; CVARIANT vName; pObj->Get(CBSTR(L"Name"), 0, &vName, 0, 0); CVARIANT vDom; pObj->Get(CBSTR(L"Authority"), 0, &vDom, 0, 0); CVARIANT vPath; pObj->Get(CBSTR(L"__PATH"), 0, &vPath, 0, 0); BOOL bDelete = TRUE; // Now see if there are any users/groups with this name. // ===================================================== for (iu = 0; iu < GetNumUsers(); iu++) { CWbemUser User = GetUser(iu); if (!User.IsValid()) continue; if (StringTest(User.GetName(), vName) == TRUE && StringTest(User.GetAuthority(), vDom) == TRUE ) { bDelete = FALSE; goto DeleteTest; } } for (ig = 0; ig < GetNumGroups(); ig++) { CWbemGroup Group = GetGroup(ig); if (!Group.IsValid()) continue; if (StringTest(Group.GetName(), vName) == TRUE && StringTest(Group.GetAuthority(), vDom) == TRUE ) { bDelete = FALSE; goto DeleteTest; } } DeleteTest: if (bDelete) { hRes = m_pSecurity->DeleteInstance(vPath, 0, 0, 0); if (hRes) return Failed; } } return NoError; }