2025-04-27 07:49:33 -04:00

1459 lines
35 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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 <stdio.h>
#include <wbemidl.h>
#include <flexarry.h>
#include <secedit.h>
#include <md5wbem.h>
#include <oahelp.inl>
//***************************************************************************
//
// 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:
// <pName> 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:
// <pszDomain> 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:
// <pszDomainName> 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:
// <pUser> User who is logging in.
// <pPassword> Password
// <pDomain> Authority (Format: "NTLMDOMAIN:xxx") or NULL
// <dwReserved> Must be zero.
// <pSecEdit> 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:
// <n> The 0-based index of the user to retrieve.
//
// Return value:
// The CWbemUser user object. The name may be NULL if <n> 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:
// <pszUser> A read-only pointer to the user name to delete.
// <bCreate> 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:
// <User> 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:
// <pszUserName>
//
// Return value:
// TRUE if found, FALSE if not. If FALSE is returned <User> 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:
// <n> The index of the group to retrieve.
//
// Return value:
// A CWbemGroup object. This will be empty if the index <n> 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:
// <pszGroup> 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:
// <Group> 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:
// <pszGroupName>
//
// Return value:
// TRUE if found, FALSE if not. If FALSE is returned <Group> 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;
}