1459 lines
35 KiB
C++
1459 lines
35 KiB
C++
/*++
|
||
|
||
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;
|
||
}
|
||
|
||
|
||
|
||
|