1476 lines
44 KiB
C++
1476 lines
44 KiB
C++
|
|
#include "precomp.h"
|
|
#include <tchar.h>
|
|
#include "wmiauthz.h"
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
Win32 Authz prototypes
|
|
***************************************************************************/
|
|
|
|
typedef BOOL (WINAPI*PAuthzAccessCheck)(
|
|
IN DWORD Flags,
|
|
IN AUTHZ_CLIENT_CONTEXT_HANDLE AuthzClientContext,
|
|
IN PAUTHZ_ACCESS_REQUEST pRequest,
|
|
IN AUTHZ_AUDIT_EVENT_HANDLE AuditInfo OPTIONAL,
|
|
IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|
IN PSECURITY_DESCRIPTOR *OptionalSecurityDescriptorArray OPTIONAL,
|
|
IN DWORD OptionalSecurityDescriptorCount,
|
|
IN OUT PAUTHZ_ACCESS_REPLY pReply,
|
|
OUT PAUTHZ_ACCESS_CHECK_RESULTS_HANDLE pAuthzHandle OPTIONAL );
|
|
|
|
typedef BOOL (WINAPI*PAuthzInitializeResourceManager)(
|
|
IN DWORD AuthzFlags,
|
|
IN PFN_AUTHZ_DYNAMIC_ACCESS_CHECK pfnAccessCheck OPTIONAL,
|
|
IN PFN_AUTHZ_COMPUTE_DYNAMIC_GROUPS pfnComputeDynamicGroups OPTIONAL,
|
|
IN PFN_AUTHZ_FREE_DYNAMIC_GROUPS pfnFreeDynamicGroups OPTIONAL,
|
|
IN PCWSTR szResourceManagerName,
|
|
OUT PAUTHZ_RESOURCE_MANAGER_HANDLE pAuthzResourceManager
|
|
);
|
|
|
|
typedef BOOL (WINAPI*PAuthzInitializeContextFromSid)(
|
|
IN DWORD Flags,
|
|
IN PSID UserSid,
|
|
IN AUTHZ_RESOURCE_MANAGER_HANDLE AuthzResourceManager,
|
|
IN PLARGE_INTEGER pExpirationTime OPTIONAL,
|
|
IN LUID Identifier,
|
|
IN PVOID DynamicGroupArgs OPTIONAL,
|
|
OUT PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContext
|
|
);
|
|
|
|
typedef BOOL (WINAPI*PAuthzInitializeContextFromToken)(
|
|
IN HANDLE TokenHandle,
|
|
IN AUTHZ_RESOURCE_MANAGER_HANDLE AuthzResourceManager,
|
|
IN PLARGE_INTEGER pExpirationTime OPTIONAL,
|
|
IN LUID Identifier,
|
|
IN DWORD Flags,
|
|
IN PVOID DynamicGroupArgs OPTIONAL,
|
|
OUT PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContext
|
|
);
|
|
|
|
typedef BOOL (WINAPI*PAuthzFreeContext)( AUTHZ_CLIENT_CONTEXT_HANDLE );
|
|
typedef BOOL (WINAPI*PAuthzFreeResourceManager)( AUTHZ_RESOURCE_MANAGER_HANDLE );
|
|
|
|
BOOL WINAPI ComputeDynamicGroups(
|
|
IN AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClientContext,
|
|
IN PVOID Args,
|
|
OUT PSID_AND_ATTRIBUTES *pSidAttrArray,
|
|
OUT PDWORD pSidCount,
|
|
OUT PSID_AND_ATTRIBUTES *pRestrictedSidAttrArray,
|
|
OUT PDWORD pRestrictedSidCount
|
|
)
|
|
{
|
|
BOOL bRet;
|
|
*pRestrictedSidAttrArray = NULL;
|
|
*pRestrictedSidCount = 0;
|
|
|
|
//
|
|
// if sid is not local system, then don't need to do anything.
|
|
//
|
|
|
|
*pSidAttrArray = NULL;
|
|
*pSidCount = 0;
|
|
|
|
if ( !*(BOOL*)(Args) )
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// need to add authenticated users and everyone groups.
|
|
//
|
|
|
|
PSID_AND_ATTRIBUTES psa = new SID_AND_ATTRIBUTES[2];
|
|
|
|
if ( psa != NULL )
|
|
{
|
|
ZeroMemory( psa, sizeof(SID_AND_ATTRIBUTES)*2 );
|
|
|
|
SID_IDENTIFIER_AUTHORITY wid = SECURITY_WORLD_SID_AUTHORITY;
|
|
SID_IDENTIFIER_AUTHORITY ntid = SECURITY_NT_AUTHORITY;
|
|
|
|
if ( bRet = AllocateAndInitializeSid( &wid,
|
|
1,
|
|
SECURITY_WORLD_RID,
|
|
0,0,0,0,0,0,0,
|
|
&psa[0].Sid ) )
|
|
{
|
|
if ( bRet = AllocateAndInitializeSid( &ntid,
|
|
1,
|
|
SECURITY_AUTHENTICATED_USER_RID,
|
|
0,0,0,0,0,0,0,
|
|
&psa[1].Sid ) )
|
|
{
|
|
*pSidCount = 2;
|
|
*pSidAttrArray = psa;
|
|
}
|
|
else
|
|
{
|
|
FreeSid( &psa[0].Sid );
|
|
delete psa;
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
delete psa;
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
void WINAPI FreeDynamicGroups( PSID_AND_ATTRIBUTES psa )
|
|
{
|
|
if ( psa != NULL )
|
|
{
|
|
FreeSid( psa[0].Sid );
|
|
FreeSid( psa[1].Sid );
|
|
delete [] psa;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
CWmiAuthzApi
|
|
***************************************************************************/
|
|
|
|
#define FUNCMEMBER(FUNC) P ## FUNC m_fp ## FUNC;
|
|
|
|
class CWmiAuthzApi
|
|
{
|
|
HMODULE m_hMod;
|
|
|
|
public:
|
|
|
|
FUNCMEMBER(AuthzInitializeContextFromToken)
|
|
FUNCMEMBER(AuthzInitializeContextFromSid)
|
|
FUNCMEMBER(AuthzInitializeResourceManager)
|
|
FUNCMEMBER(AuthzAccessCheck)
|
|
FUNCMEMBER(AuthzFreeContext)
|
|
FUNCMEMBER(AuthzFreeResourceManager)
|
|
|
|
CWmiAuthzApi() { ZeroMemory( this, sizeof(CWmiAuthzApi) ); }
|
|
~CWmiAuthzApi() { if ( m_hMod != NULL ) FreeLibrary( m_hMod ); }
|
|
|
|
HRESULT Initialize();
|
|
};
|
|
|
|
#define SETFUNC(FUNC) \
|
|
m_fp ## FUNC = (P ## FUNC) GetProcAddress( m_hMod, #FUNC ); \
|
|
if ( m_fp ## FUNC == NULL ) return WBEM_E_NOT_SUPPORTED;
|
|
|
|
HRESULT CWmiAuthzApi::Initialize()
|
|
{
|
|
m_hMod = LoadLibrary( _T("authz") );
|
|
|
|
if ( m_hMod == NULL )
|
|
{
|
|
return WBEM_E_NOT_SUPPORTED;
|
|
}
|
|
|
|
SETFUNC(AuthzInitializeContextFromToken)
|
|
SETFUNC(AuthzInitializeResourceManager)
|
|
SETFUNC(AuthzInitializeContextFromSid)
|
|
SETFUNC(AuthzInitializeContextFromToken)
|
|
SETFUNC(AuthzAccessCheck)
|
|
SETFUNC(AuthzFreeContext)
|
|
SETFUNC(AuthzFreeResourceManager)
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
};
|
|
|
|
/**************************************************************************
|
|
CWmiAuthz
|
|
***************************************************************************/
|
|
|
|
#define CALLFUNC(API,FUNC) (*API->m_fp ## FUNC)
|
|
|
|
CWmiAuthz::CWmiAuthz( CLifeControl* pControl )
|
|
: CUnkBase<IWbemTokenCache,&IID_IWbemTokenCache>( pControl ),
|
|
m_hResMgr(NULL), m_pApi(NULL), m_pAdministratorsSid(NULL),
|
|
m_pLocalSystemSid(NULL)
|
|
{
|
|
|
|
}
|
|
|
|
HRESULT CWmiAuthz::EnsureInitialized()
|
|
{
|
|
HRESULT hr;
|
|
|
|
CInCritSec ics( &m_cs );
|
|
|
|
if ( m_hResMgr != NULL )
|
|
{
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// try to create the API object.
|
|
//
|
|
|
|
if ( m_pApi == NULL )
|
|
{
|
|
m_pApi = new CWmiAuthzApi;
|
|
|
|
if ( m_pApi == NULL )
|
|
{
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
hr = m_pApi->Initialize();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
delete m_pApi;
|
|
m_pApi = NULL;
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
//
|
|
// initialize the authz res mgr.
|
|
//
|
|
|
|
if ( !CALLFUNC(m_pApi,AuthzInitializeResourceManager)
|
|
( AUTHZ_RM_FLAG_NO_AUDIT,
|
|
NULL,
|
|
ComputeDynamicGroups,
|
|
FreeDynamicGroups,
|
|
NULL,
|
|
&m_hResMgr ) )
|
|
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
//
|
|
// allocate and initialize well known sids for authz special casing.
|
|
//
|
|
|
|
SID_IDENTIFIER_AUTHORITY id = SECURITY_NT_AUTHORITY;
|
|
|
|
if ( !AllocateAndInitializeSid( &id,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0,0,0,0,0,0,
|
|
&m_pAdministratorsSid) )
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
if ( !AllocateAndInitializeSid( &id,
|
|
1,
|
|
SECURITY_LOCAL_SYSTEM_RID,
|
|
0,0,0,0,0,0,0,
|
|
&m_pLocalSystemSid) )
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
STDMETHODIMP CWmiAuthz::Shutdown()
|
|
{
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
CWmiAuthz::~CWmiAuthz()
|
|
{
|
|
if ( m_hResMgr != NULL )
|
|
{
|
|
CALLFUNC(m_pApi,AuthzFreeResourceManager)( m_hResMgr );
|
|
}
|
|
|
|
if ( m_pApi != NULL )
|
|
{
|
|
delete m_pApi;
|
|
}
|
|
|
|
if ( m_pAdministratorsSid != NULL )
|
|
{
|
|
FreeSid( m_pAdministratorsSid );
|
|
}
|
|
|
|
if ( m_pLocalSystemSid != NULL )
|
|
{
|
|
FreeSid( m_pLocalSystemSid );
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP CWmiAuthz::GetToken( const BYTE* pSid, IWbemToken** ppToken )
|
|
{
|
|
HRESULT hr;
|
|
|
|
*ppToken = NULL;
|
|
|
|
hr = EnsureInitialized();
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
AUTHZ_CLIENT_CONTEXT_HANDLE hCtx = NULL;
|
|
LUID luid;
|
|
|
|
ZeroMemory( &luid, sizeof(LUID) );
|
|
|
|
DWORD dwFlags = 0;
|
|
BOOL bLocalSystem = FALSE;
|
|
|
|
if ( EqualSid( PSID(pSid), m_pAdministratorsSid ) )
|
|
{
|
|
//
|
|
// this is a group sid, so specify this in the flags so
|
|
// authz can handle it properly.
|
|
//
|
|
dwFlags = AUTHZ_SKIP_TOKEN_GROUPS;
|
|
}
|
|
else if ( EqualSid( PSID(pSid), m_pLocalSystemSid ) )
|
|
{
|
|
//
|
|
// authz doesn't handle local system so have to workaround
|
|
// by disabling authz's group computation and do it ourselves.
|
|
//
|
|
bLocalSystem = TRUE;
|
|
dwFlags = AUTHZ_SKIP_TOKEN_GROUPS;
|
|
}
|
|
|
|
if ( !CALLFUNC(m_pApi,AuthzInitializeContextFromSid)( dwFlags,
|
|
PSID(pSid),
|
|
m_hResMgr,
|
|
NULL,
|
|
luid,
|
|
&bLocalSystem,
|
|
&hCtx ) )
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
*ppToken = new CWmiAuthzToken( this, hCtx );
|
|
|
|
if ( *ppToken == NULL )
|
|
{
|
|
CALLFUNC(m_pApi,AuthzFreeContext)(hCtx);
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
(*ppToken)->AddRef();
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/***************************************************************************
|
|
CWmiAuthzToken
|
|
****************************************************************************/
|
|
|
|
CWmiAuthzToken::CWmiAuthzToken( CWmiAuthz* pOwner, AUTHZ_CLIENT_CONTEXT_HANDLE hCtx )
|
|
: CUnkBase<IWbemToken,&IID_IWbemToken>(NULL), m_hCtx(hCtx), m_pOwner(pOwner)
|
|
{
|
|
//
|
|
// we want to keep the owner alive, in case the caller has released theirs
|
|
//
|
|
m_pOwner->AddRef();
|
|
}
|
|
|
|
CWmiAuthzToken::~CWmiAuthzToken()
|
|
{
|
|
CWmiAuthzApi* pApi = m_pOwner->GetApi();
|
|
CALLFUNC(pApi,AuthzFreeContext)(m_hCtx);
|
|
m_pOwner->Release();
|
|
}
|
|
|
|
STDMETHODIMP CWmiAuthzToken::AccessCheck( DWORD dwDesiredAccess,
|
|
const BYTE* pSD,
|
|
DWORD* pdwGrantedAccess )
|
|
{
|
|
HRESULT hr;
|
|
|
|
AUTHZ_ACCESS_REQUEST AccessReq;
|
|
ZeroMemory( &AccessReq, sizeof(AUTHZ_ACCESS_REQUEST) );
|
|
AccessReq.DesiredAccess = dwDesiredAccess;
|
|
|
|
AUTHZ_ACCESS_REPLY AccessRep;
|
|
DWORD dwError;
|
|
|
|
ZeroMemory( &AccessRep, sizeof(AUTHZ_ACCESS_REPLY) );
|
|
AccessRep.GrantedAccessMask = pdwGrantedAccess;
|
|
AccessRep.ResultListLength = 1;
|
|
AccessRep.Error = &dwError;
|
|
AccessRep.SaclEvaluationResults = NULL;
|
|
|
|
CWmiAuthzApi* pApi = m_pOwner->GetApi();
|
|
|
|
if ( !CALLFUNC(pApi,AuthzAccessCheck)( 0,
|
|
m_hCtx,
|
|
&AccessReq,
|
|
NULL,
|
|
PSECURITY_DESCRIPTOR(pSD),
|
|
NULL,
|
|
NULL,
|
|
&AccessRep,
|
|
NULL ) )
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
WILL NOT BE COMPILED IN PRESENCE OF AUTHZ LIBRARY
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#ifndef __AUTHZ_H__
|
|
|
|
#include <ArrTempl.h>
|
|
#include <lmaccess.h>
|
|
#include <lmapibuf.h>
|
|
#include <lmwksta.h>
|
|
#include <wbemcomn.h>
|
|
#include <comutl.h>
|
|
|
|
|
|
/****************************************************************************
|
|
CWmiNoAuthzToken
|
|
*****************************************************************************/
|
|
|
|
STDMETHODIMP CWmiNoAuthzToken::AccessCheck( DWORD dwDesiredAccess,
|
|
const BYTE* pSD,
|
|
DWORD* pdwGrantedAccess )
|
|
{
|
|
PACL pDacl;
|
|
BOOL bDaclPresent, bDaclDefault;
|
|
|
|
*pdwGrantedAccess = 0;
|
|
|
|
if ( !GetSecurityDescriptorDacl( PSECURITY_DESCRIPTOR(pSD),
|
|
&bDaclPresent,
|
|
&pDacl,
|
|
&bDaclDefault) )
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
if ( !bDaclPresent )
|
|
{
|
|
*pdwGrantedAccess = 0xffffffff;
|
|
}
|
|
|
|
NTSTATUS stat = WmiAuthzGetAccessMask( m_Sid.GetPtr(), pDacl, pdwGrantedAccess );
|
|
|
|
if ( stat != 0 )
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
Functions moved from GroupForUser
|
|
****************************************************************************/
|
|
// critical section to keep us from tripping over our threads
|
|
// during initialization
|
|
CCritSec CSSamStartup;
|
|
CCritSec CSNetAPIStartup;
|
|
CCritSec CSAdvAPIStartup;
|
|
|
|
// copied here to make it easy for this file to be included elsewhere
|
|
bool IsPlatformNT(void)
|
|
{
|
|
OSVERSIONINFO os;
|
|
os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
if(!GetVersionEx(&os))
|
|
return false; // should never happen
|
|
return os.dwPlatformId == VER_PLATFORM_WIN32_NT;
|
|
}
|
|
|
|
|
|
|
|
|
|
class CUnicodeString : public UNICODE_STRING
|
|
{
|
|
public:
|
|
CUnicodeString()
|
|
{
|
|
MaximumLength = Length = 0;
|
|
Buffer = NULL;
|
|
}
|
|
CUnicodeString(LPCWSTR wsz)
|
|
{
|
|
Buffer = NULL;
|
|
MaximumLength = Length = 0;
|
|
*this = wsz;
|
|
}
|
|
~CUnicodeString()
|
|
{
|
|
delete [] Buffer;
|
|
}
|
|
void operator=(LPCWSTR wsz)
|
|
{
|
|
delete [] Buffer;
|
|
MaximumLength = sizeof(WCHAR) * (wcslen(wsz)+1);
|
|
Buffer = new WCHAR[MaximumLength];
|
|
Length = MaximumLength - sizeof(WCHAR);
|
|
wcscpy(Buffer, wsz);
|
|
}
|
|
operator LPCWSTR() {return Buffer;}
|
|
};
|
|
|
|
|
|
typedef NTSTATUS (NTAPI *PSamConnect)(IN PUNICODE_STRING ServerName,
|
|
OUT PSAM_HANDLE ServerHandle, IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes);
|
|
|
|
typedef NTSTATUS (NTAPI *PSamCloseHandle)( OUT SAM_HANDLE SamHandle );
|
|
typedef NTSTATUS (NTAPI *PSamFreeMemory)( PVOID p );
|
|
typedef NTSTATUS (NTAPI *PSamLookupDomainInSamServer)(
|
|
IN SAM_HANDLE ServerHandle,
|
|
IN PUNICODE_STRING Name, OUT PSID * DomainId );
|
|
|
|
typedef NTSTATUS (NTAPI *PSamLookupNamesInDomain)(
|
|
IN SAM_HANDLE DomainHandle, IN ULONG Count,
|
|
IN PUNICODE_STRING Names, OUT PULONG *RelativeIds,
|
|
OUT PSID_NAME_USE *Use);
|
|
|
|
typedef NTSTATUS (NTAPI *PSamOpenDomain)( IN SAM_HANDLE ServerHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN PSID DomainId, OUT PSAM_HANDLE DomainHandle );
|
|
|
|
typedef NTSTATUS (NTAPI *PSamOpenUser)( IN SAM_HANDLE DomainHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN ULONG UserId, OUT PSAM_HANDLE UserHandle );
|
|
|
|
typedef NTSTATUS (NTAPI *PSamGetGroupsForUser)( IN SAM_HANDLE UserHandle,
|
|
OUT PGROUP_MEMBERSHIP * Groups, OUT PULONG MembershipCount);
|
|
|
|
typedef NTSTATUS (NTAPI *PSamGetAliasMembership)( IN SAM_HANDLE DomainHandle, IN ULONG PassedCount,
|
|
IN PSID *Sids, OUT PULONG MembershipCount, OUT PULONG *Aliases);
|
|
|
|
|
|
// class to encapsulate the SAM APIs
|
|
// make sure that we always free the lib, etc.
|
|
class CSamRun
|
|
{
|
|
public:
|
|
CSamRun()
|
|
{
|
|
}
|
|
|
|
|
|
~CSamRun()
|
|
{
|
|
// oh, all right - DON'T free the lib.
|
|
// FreeLibrary(m_hSamDll);
|
|
}
|
|
|
|
bool RunSamRun(void);
|
|
|
|
//protected:
|
|
// okay, so I should make these all protected
|
|
// and write accessor functions. Maybe I will someday.
|
|
static HINSTANCE m_hSamDll;
|
|
static PSamConnect m_pfnSamConnect;
|
|
static PSamCloseHandle m_pfnSamCloseHandle;
|
|
static PSamFreeMemory m_pfnSamFreeMemory;
|
|
static PSamLookupDomainInSamServer m_pfnSamLookupDomainInSamServer;
|
|
static PSamLookupNamesInDomain m_pfnSamLookupNamesInDomain;
|
|
static PSamOpenDomain m_pfnSamOpenDomain;
|
|
static PSamOpenUser m_pfnSamOpenUser;
|
|
static PSamGetGroupsForUser m_pfnSamGetGroupsForUser;
|
|
static PSamGetAliasMembership m_pfnSamGetAliasMembership;
|
|
};
|
|
|
|
HINSTANCE CSamRun::m_hSamDll = NULL;
|
|
PSamConnect CSamRun::m_pfnSamConnect = NULL;
|
|
PSamCloseHandle CSamRun::m_pfnSamCloseHandle = NULL;
|
|
PSamFreeMemory CSamRun::m_pfnSamFreeMemory = NULL;
|
|
PSamLookupDomainInSamServer CSamRun::m_pfnSamLookupDomainInSamServer = NULL;
|
|
PSamLookupNamesInDomain CSamRun::m_pfnSamLookupNamesInDomain = NULL;
|
|
PSamOpenDomain CSamRun::m_pfnSamOpenDomain = NULL;
|
|
PSamOpenUser CSamRun::m_pfnSamOpenUser = NULL;
|
|
PSamGetGroupsForUser CSamRun::m_pfnSamGetGroupsForUser = NULL;
|
|
PSamGetAliasMembership CSamRun::m_pfnSamGetAliasMembership = NULL;
|
|
|
|
|
|
bool CSamRun::RunSamRun()
|
|
{
|
|
CInCritSec runInACriticalSectionSam(&CSSamStartup);
|
|
|
|
if(m_hSamDll)
|
|
return true;
|
|
|
|
m_hSamDll = LoadLibrary(_T("samlib.dll"));
|
|
if(m_hSamDll == NULL)
|
|
return false;
|
|
|
|
m_pfnSamConnect =
|
|
(PSamConnect)GetProcAddress(m_hSamDll, "SamConnect");
|
|
if(m_pfnSamConnect == NULL)
|
|
return false;
|
|
|
|
m_pfnSamCloseHandle =
|
|
(PSamCloseHandle)GetProcAddress(m_hSamDll, "SamCloseHandle");
|
|
if(m_pfnSamCloseHandle == NULL)
|
|
return false;
|
|
|
|
m_pfnSamFreeMemory =
|
|
(PSamFreeMemory)GetProcAddress(m_hSamDll, "SamFreeMemory");
|
|
if(m_pfnSamFreeMemory == NULL)
|
|
return false;
|
|
|
|
m_pfnSamLookupDomainInSamServer =
|
|
(PSamLookupDomainInSamServer)GetProcAddress(m_hSamDll,
|
|
"SamLookupDomainInSamServer");
|
|
if(m_pfnSamLookupDomainInSamServer == NULL)
|
|
return false;
|
|
|
|
m_pfnSamLookupNamesInDomain =
|
|
(PSamLookupNamesInDomain)GetProcAddress(m_hSamDll,
|
|
"SamLookupNamesInDomain");
|
|
if(m_pfnSamLookupNamesInDomain == NULL)
|
|
return false;
|
|
|
|
m_pfnSamOpenDomain =
|
|
(PSamOpenDomain)GetProcAddress(m_hSamDll,
|
|
"SamOpenDomain");
|
|
if(m_pfnSamOpenDomain == NULL)
|
|
return false;
|
|
|
|
m_pfnSamOpenUser =
|
|
(PSamOpenUser)GetProcAddress(m_hSamDll,
|
|
"SamOpenUser");
|
|
if(m_pfnSamOpenUser == NULL)
|
|
return false;
|
|
|
|
m_pfnSamGetGroupsForUser =
|
|
(PSamGetGroupsForUser)GetProcAddress(m_hSamDll,
|
|
"SamGetGroupsForUser");
|
|
if(m_pfnSamGetGroupsForUser == NULL)
|
|
return false;
|
|
|
|
m_pfnSamGetAliasMembership =
|
|
(PSamGetAliasMembership)GetProcAddress(m_hSamDll,
|
|
"SamGetAliasMembership");
|
|
if(m_pfnSamGetAliasMembership == NULL)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
typedef BOOL (NTAPI* PLookupAccountSidW) (
|
|
LPCWSTR lpSystemName, // name of local or remote computer
|
|
PSID Sid, // security identifier
|
|
LPWSTR Name, // account name buffer
|
|
LPDWORD cbName, // size of account name buffer
|
|
LPWSTR DomainName, // domain name
|
|
LPDWORD cbDomainName, // size of domain name buffer
|
|
PSID_NAME_USE peUse // SID type
|
|
);
|
|
|
|
typedef NET_API_STATUS (NTAPI* PNetGetAnyDCName)(
|
|
LPCWSTR servername,
|
|
LPCWSTR domainname,
|
|
LPBYTE *bufptr
|
|
);
|
|
|
|
typedef NET_API_STATUS (NTAPI* PNetGetDCName)(
|
|
LPCWSTR servername,
|
|
LPCWSTR domainname,
|
|
LPBYTE *bufptr
|
|
);
|
|
|
|
|
|
typedef NET_API_STATUS (NTAPI* PNetApiBufferFree)(
|
|
LPVOID Buffer
|
|
);
|
|
|
|
typedef NET_API_STATUS (NTAPI* PNetWkstaGetInfo)(
|
|
LPWSTR servername,
|
|
DWORD level,
|
|
LPBYTE *bufptr
|
|
);
|
|
|
|
|
|
|
|
|
|
// dynamically load NetAPI32.DLL
|
|
// so we can run without it on 9X
|
|
class NetApiDLL
|
|
{
|
|
public:
|
|
bool Init(void);
|
|
|
|
static PNetGetAnyDCName m_pfnNetGetAnyDCName;
|
|
static PNetGetAnyDCName m_pfnNetGetDCName;
|
|
static PNetApiBufferFree m_pfnNetApiBufferFree;
|
|
static PNetWkstaGetInfo m_pfnNetWkstaGetInfo;
|
|
|
|
static HINSTANCE m_hDll;
|
|
|
|
};
|
|
|
|
PNetGetAnyDCName NetApiDLL::m_pfnNetGetAnyDCName = NULL;
|
|
PNetGetDCName NetApiDLL::m_pfnNetGetDCName = NULL;
|
|
PNetApiBufferFree NetApiDLL::m_pfnNetApiBufferFree = NULL;
|
|
PNetWkstaGetInfo NetApiDLL::m_pfnNetWkstaGetInfo = NULL;
|
|
HINSTANCE NetApiDLL::m_hDll = NULL;
|
|
|
|
bool NetApiDLL::Init(void)
|
|
{
|
|
CInCritSec inCS(&CSNetAPIStartup);
|
|
|
|
bool bRet = false;
|
|
|
|
if (m_hDll)
|
|
bRet = true;
|
|
else if (m_hDll = LoadLibrary(_T("NetAPI32.dll")))
|
|
{
|
|
m_pfnNetGetAnyDCName = (PNetGetAnyDCName) GetProcAddress(m_hDll, "NetGetAnyDCName");
|
|
m_pfnNetGetDCName = (PNetGetDCName) GetProcAddress(m_hDll, "NetGetDCName");
|
|
m_pfnNetApiBufferFree = (PNetApiBufferFree) GetProcAddress(m_hDll, "NetApiBufferFree");
|
|
m_pfnNetWkstaGetInfo = (PNetWkstaGetInfo) GetProcAddress(m_hDll, "NetWkstaGetInfo");
|
|
|
|
bRet = ((m_pfnNetGetAnyDCName != NULL) &&
|
|
(m_pfnNetGetDCName != NULL) &&
|
|
(m_pfnNetApiBufferFree != NULL) &&
|
|
(m_pfnNetWkstaGetInfo != NULL));
|
|
|
|
if (!bRet)
|
|
{
|
|
FreeLibrary(m_hDll);
|
|
m_hDll = NULL;
|
|
}
|
|
}
|
|
else
|
|
ERRORTRACE((LOG_ESS, "Failed to load NetAPI32.dll, 0x%X", GetLastError()));
|
|
|
|
|
|
return bRet;
|
|
}
|
|
|
|
// dynamically load AdvAPI32.DLL
|
|
// so we can run without it on 9X
|
|
class AdvApiDLL
|
|
{
|
|
public:
|
|
bool Init(void);
|
|
|
|
static PLookupAccountSidW m_pfnLookupAccountSidW;
|
|
|
|
static HINSTANCE m_hDll;
|
|
|
|
};
|
|
|
|
PLookupAccountSidW AdvApiDLL::m_pfnLookupAccountSidW = NULL;
|
|
HINSTANCE AdvApiDLL::m_hDll = NULL;
|
|
|
|
bool AdvApiDLL::Init(void)
|
|
{
|
|
CInCritSec inCS(&CSAdvAPIStartup);
|
|
|
|
bool bRet = false;
|
|
|
|
if (m_hDll)
|
|
bRet = true;
|
|
else if (m_hDll = LoadLibrary(_T("AdvAPI32.dll")))
|
|
{
|
|
m_pfnLookupAccountSidW = (PLookupAccountSidW) GetProcAddress(m_hDll, "LookupAccountSidW");
|
|
|
|
bRet = (m_pfnLookupAccountSidW != NULL);
|
|
}
|
|
else
|
|
ERRORTRACE((LOG_ESS, "Failed to load AdvAPI32.dll, 0x%X", GetLastError()));
|
|
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
class CSamHandle
|
|
{
|
|
private:
|
|
SAM_HANDLE m_hHandle;
|
|
CSamRun& m_sam;
|
|
|
|
protected:
|
|
void Close();
|
|
public:
|
|
CSamHandle(CSamRun& sam) : m_sam(sam), m_hHandle(NULL)
|
|
{ }
|
|
|
|
~CSamHandle();
|
|
|
|
// same as operator SAM_HANDLE*()
|
|
// gosh, I sure do love C!
|
|
operator void**()
|
|
{return &((void*)m_hHandle); }
|
|
|
|
operator SAM_HANDLE()
|
|
{return m_hHandle; }
|
|
|
|
};
|
|
|
|
CSamHandle::~CSamHandle()
|
|
{
|
|
Close();
|
|
}
|
|
|
|
void CSamHandle::Close()
|
|
{
|
|
if (m_hHandle)
|
|
m_sam.m_pfnSamCloseHandle(m_hHandle);
|
|
|
|
m_hHandle = NULL;
|
|
}
|
|
|
|
|
|
class CSamFreeMe
|
|
{
|
|
protected:
|
|
void* m_p;
|
|
CSamRun m_sam;
|
|
public:
|
|
CSamFreeMe(CSamRun& sam, void* p) : m_p(p), m_sam(sam) {}
|
|
~CSamFreeMe() {m_sam.m_pfnSamFreeMemory(m_p);}
|
|
};
|
|
|
|
|
|
|
|
class CHeapFreeMe
|
|
{
|
|
protected:
|
|
void* m_p;
|
|
public:
|
|
CHeapFreeMe(void* p) : m_p(p){}
|
|
~CHeapFreeMe()
|
|
{
|
|
if (m_p)
|
|
HeapFree(GetProcessHeap(), 0, m_p);
|
|
}
|
|
};
|
|
|
|
|
|
PSID CreateUserSid(PSID pDomainSid, DWORD dwUserRid)
|
|
{
|
|
DWORD dwOldLen = GetLengthSid(pDomainSid);
|
|
// PISID pSid = (PISID)new BYTE[dwOldLen + sizeof(DWORD)];
|
|
|
|
PISID pSid = (PISID)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwOldLen + sizeof(DWORD));
|
|
|
|
if (pSid)
|
|
{
|
|
memcpy(pSid, pDomainSid, dwOldLen);
|
|
pSid->SubAuthority[pSid->SubAuthorityCount] = dwUserRid;
|
|
pSid->SubAuthorityCount++;
|
|
}
|
|
return pSid;
|
|
}
|
|
|
|
|
|
|
|
class CHeapBigPointerArrayCleanerUpper
|
|
{
|
|
public:
|
|
CHeapBigPointerArrayCleanerUpper(void** pArray = NULL, DWORD count = 0) :
|
|
m_pArray(pArray), m_count(count) {}
|
|
|
|
~CHeapBigPointerArrayCleanerUpper()
|
|
{
|
|
if (m_pArray)
|
|
for (DWORD i = 0; i < m_count; i++)
|
|
if (m_pArray[i])
|
|
HeapFree(GetProcessHeap(), 0, m_pArray[i]);
|
|
}
|
|
|
|
protected:
|
|
void** m_pArray;
|
|
DWORD m_count;
|
|
};
|
|
|
|
|
|
|
|
// returns STATUS_SUCCESS if user is in group
|
|
// STATUS_ACCESS_DENIED if not
|
|
// some error code or other on error
|
|
NTSTATUS IsUserInGroup(PSID pSidUser, PSID pSidGroup)
|
|
{
|
|
if (!IsPlatformNT())
|
|
return STATUS_NOT_SUPPORTED;
|
|
|
|
PSID* pSids = NULL;
|
|
DWORD dwCount;
|
|
|
|
NTSTATUS stat = EnumGroupsForUser(pSidUser, NULL, &pSids, &dwCount);
|
|
|
|
// if we can't get to the domain controller, try just local groups
|
|
if (stat)
|
|
{
|
|
WCHAR machineName[MAX_COMPUTERNAME_LENGTH + 1];
|
|
DWORD size = MAX_COMPUTERNAME_LENGTH +1;
|
|
GetComputerNameW(machineName, &size);
|
|
stat = EnumGroupsForUser(pSidUser, machineName, &pSids, &dwCount);
|
|
}
|
|
|
|
// arrange for clean up no matter how we exit
|
|
CHeapFreeMe freeArray(pSids);
|
|
CHeapBigPointerArrayCleanerUpper cleanSids(pSids, dwCount);
|
|
|
|
if (stat == STATUS_SUCCESS)
|
|
{
|
|
stat = STATUS_ACCESS_DENIED;
|
|
for(DWORD i = 0; i < dwCount; i++)
|
|
if (EqualSid(pSidGroup, pSids[i]))
|
|
stat = STATUS_SUCCESS;
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
// returns STATUS_SUCCESS if user is in admin group
|
|
// STATUS_ACCESS_DENIED if not
|
|
// some error code or other on error
|
|
NTSTATUS IsUserAdministrator(PSID pSidUser)
|
|
{
|
|
if (!IsPlatformNT())
|
|
return STATUS_NOT_SUPPORTED;
|
|
|
|
NTSTATUS stat = STATUS_ACCESS_DENIED;
|
|
|
|
PSID pSidAdmins;
|
|
SID_IDENTIFIER_AUTHORITY id = SECURITY_NT_AUTHORITY;
|
|
|
|
if (AllocateAndInitializeSid(&id, 2,
|
|
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
|
|
0,0,0,0,0,0,&pSidAdmins))
|
|
{
|
|
stat = WmiAuthzIsUserInGroup(pSidUser, pSidAdmins);
|
|
|
|
// We're done with this
|
|
FreeSid(pSidAdmins);
|
|
}
|
|
else
|
|
{
|
|
stat = GetLastError();
|
|
ERRORTRACE((LOG_ESS, "AllocateAndInitializeSid failed, error 0x%X\n", stat));
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
// retireves access mask corresponding to permissions granted
|
|
// by dacl to account denoted in pSid
|
|
// only deals with the ACCESS_ALLOWED/DENIED type aces
|
|
// including the ACCESS_ALLOWED/DENIED_OBJECT_ACEs
|
|
// - will error out if it finds a SYSTEM_AUDIT or unrecognized type.
|
|
NTSTATUS GetAccessMask(PSID pSid, PACL pDacl, DWORD* pAccessMask)
|
|
{
|
|
if (!IsPlatformNT())
|
|
return STATUS_NOT_SUPPORTED;
|
|
|
|
NTSTATUS stat = STATUS_SUCCESS;
|
|
|
|
// let's zero this puppy out
|
|
// lest someone not check the return code & compare against garbage
|
|
*pAccessMask = 0;
|
|
|
|
// will compute each & knock them against each other
|
|
DWORD accessAllowed = 0;
|
|
DWORD accessDenied = 0;
|
|
PSID* pSids = NULL;
|
|
DWORD dwCount;
|
|
LPVOID pAce;
|
|
|
|
stat = EnumGroupsForUser(pSid, NULL, &pSids, &dwCount);
|
|
|
|
// arrange for clean up no matter how we exit
|
|
CHeapFreeMe freeArray(pSids);
|
|
CHeapBigPointerArrayCleanerUpper cleanSids(pSids, dwCount);
|
|
|
|
// de buggy test harness
|
|
// char name[300];
|
|
// char domain[300];
|
|
// DWORD x = 300, y = 300;
|
|
// SID_NAME_USE eUse;
|
|
|
|
//for (int q = 0; q < dwCount; q++)
|
|
//{
|
|
// x = y = 300;
|
|
// LookupAccountSid(NULL, pSids[q], name, &x, domain, &y, &eUse);
|
|
//}
|
|
|
|
if (stat == STATUS_SUCCESS)
|
|
// iterate through all of the ACE's in the ACL
|
|
// for each, iterate through all of the groups for the user
|
|
// if one matches, OR in its allowed/disallowed mask
|
|
for (DWORD nAce = 0; nAce < pDacl->AceCount; nAce++)
|
|
if (GetAce(pDacl, nAce, &pAce))
|
|
{
|
|
// de buggy test harness
|
|
// x = y = 300;
|
|
// LookupAccountSid(NULL, &(((ACCESS_ALLOWED_ACE*)pAce)->SidStart), name, &x, domain, &y, &eUse);
|
|
for (DWORD nSid = 0; nSid < dwCount; nSid++)
|
|
{
|
|
// de buggy test harness
|
|
// x = y = 300;
|
|
// if (!LookupAccountSid(NULL, pSids[nSid], name, &x, domain, &y, &eUse))
|
|
// DWORD gubl = GetLastError();
|
|
switch (((ACE_HEADER*)pAce)->AceType)
|
|
{
|
|
case ACCESS_ALLOWED_ACE_TYPE:
|
|
if (EqualSid(&(((ACCESS_ALLOWED_ACE*)pAce)->SidStart), pSids[nSid]))
|
|
accessAllowed |= ((ACCESS_ALLOWED_ACE*)pAce)->Mask;
|
|
break;
|
|
case ACCESS_DENIED_ACE_TYPE:
|
|
if (EqualSid(&(((ACCESS_DENIED_ACE*)pAce)->SidStart), pSids[nSid]))
|
|
accessDenied |= ((ACCESS_DENIED_ACE*)pAce)->Mask;
|
|
break;
|
|
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
|
|
if (EqualSid(&(((ACCESS_ALLOWED_OBJECT_ACE*)pAce)->SidStart), pSids[nSid]))
|
|
accessAllowed |= ((ACCESS_ALLOWED_OBJECT_ACE*)pAce)->Mask;
|
|
break;
|
|
case ACCESS_DENIED_OBJECT_ACE_TYPE:
|
|
if (EqualSid(&(((ACCESS_DENIED_OBJECT_ACE*)pAce)->SidStart), pSids[nSid]))
|
|
accessDenied |= ((ACCESS_DENIED_OBJECT_ACE*)pAce)->Mask;
|
|
break;
|
|
default:
|
|
// in too deep - bail!
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// GetAce failed
|
|
|
|
DWORD dwErr = GetLastError();
|
|
ERRORTRACE((LOG_ESS, "GetAce failed, error 0x%X", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
if (stat == STATUS_SUCCESS)
|
|
*pAccessMask = accessAllowed & ~accessDenied;
|
|
|
|
return stat;
|
|
}
|
|
|
|
|
|
|
|
|
|
// given a SID & server name
|
|
// will return all groups from the local domain of which user is a member
|
|
// callers responsibility to HeapFree apSids & the memory to which they point.
|
|
// pdwCount points to dword to receive count of group sids returned.
|
|
// serverName may be NULL, in which case this function will look up
|
|
// the sid on the local computer
|
|
NTSTATUS EnumGroupsForUser(PSID pSid, LPCWSTR serverName, PSID** apGroupSids, DWORD* pdwCount)
|
|
{
|
|
if (!IsPlatformNT())
|
|
return STATUS_NOT_SUPPORTED;
|
|
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
NetApiDLL netDll;
|
|
AdvApiDLL advDll;
|
|
|
|
if (!(netDll.Init() && advDll.Init()))
|
|
status = STATUS_DLL_INIT_FAILED;
|
|
else
|
|
{
|
|
// retrieve user name & domain name
|
|
DWORD domainSize = 0,
|
|
nameSize = 0;
|
|
SID_NAME_USE sidUse;
|
|
|
|
// call once to find out how big a buffer we need
|
|
advDll.m_pfnLookupAccountSidW(serverName, pSid, NULL, &nameSize, NULL, &domainSize, &sidUse);
|
|
|
|
// buy bunches o' bigger buffers
|
|
LPWSTR pAccountName = NULL,
|
|
pDomainName = NULL;
|
|
|
|
pAccountName = new WCHAR[nameSize];
|
|
pDomainName = new WCHAR[domainSize];
|
|
|
|
CDeleteMe<WCHAR> delAcct(pAccountName);
|
|
CDeleteMe<WCHAR> delDomain(pDomainName);
|
|
|
|
if (pAccountName && pDomainName)
|
|
{
|
|
if (advDll.m_pfnLookupAccountSidW(serverName, pSid,
|
|
pAccountName, &nameSize,
|
|
pDomainName, &domainSize,
|
|
&sidUse))
|
|
{
|
|
WKSTA_INFO_100 *pstInfo = NULL ;
|
|
|
|
LPWSTR samServerName;
|
|
// may not get filled in, careful...
|
|
WCHAR serverNameBuffer[MAX_COMPUTERNAME_LENGTH +1] = L"\0";
|
|
|
|
if (serverName == NULL)
|
|
{
|
|
DWORD dNameSize = MAX_COMPUTERNAME_LENGTH +1;
|
|
WCHAR computerName[MAX_COMPUTERNAME_LENGTH +1] = L"\0";
|
|
GetComputerNameW(computerName, &dNameSize);
|
|
if (_wcsicmp(computerName, pDomainName) == 0)
|
|
// local domain is the machine
|
|
samServerName = pDomainName;
|
|
else
|
|
// go grab the Domain Controller
|
|
{
|
|
// use the local domain!
|
|
status = netDll.m_pfnNetWkstaGetInfo( NULL , 100 , ( LPBYTE * ) &pstInfo );
|
|
|
|
if (status == 0)
|
|
{
|
|
LPBYTE dcName = NULL;
|
|
status = netDll.m_pfnNetGetDCName(NULL, pstInfo->wki100_langroup, &dcName);
|
|
// if we can't find a/the PDC, try for a backup...
|
|
// if ((status == 0x54B) || (status == 0x995))
|
|
if (status)
|
|
status = netDll.m_pfnNetGetAnyDCName(NULL, pstInfo->wki100_langroup, &dcName);
|
|
netDll.m_pfnNetApiBufferFree(pstInfo);
|
|
|
|
if (status == 0)
|
|
{
|
|
LPWSTR dcNameWithoutWhacks = (LPWSTR)dcName;
|
|
// name is prefaced with "\\"
|
|
dcNameWithoutWhacks += 2;
|
|
wcscpy(serverNameBuffer, dcNameWithoutWhacks);
|
|
samServerName = serverNameBuffer;
|
|
netDll.m_pfnNetApiBufferFree(dcName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
// tweren't NULL - we'll use it
|
|
samServerName = (LPWSTR)serverName;
|
|
|
|
if (status == 0)
|
|
status = EnumGroupsForUser(pAccountName, pDomainName, samServerName, apGroupSids, pdwCount);
|
|
}
|
|
else
|
|
{
|
|
// lookup account sid failed - dunno why.
|
|
status = GetLastError();
|
|
ERRORTRACE((LOG_ESS, "LookupAccountSid failed: 0x%X\n", status));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERRORTRACE((LOG_ESS, "Allocation Failure\n"));
|
|
// couldn't allocate name buffers
|
|
status = STATUS_NO_MEMORY;
|
|
}
|
|
} // if netDll.Init
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
// given user name, domain name & server name
|
|
// will return all groups of which user is a member
|
|
// callers responsibility to HeapFree apSids & the memory to which they point.
|
|
// pdwCount points to dword to receive count of group sids returned.
|
|
NTSTATUS EnumGroupsForUser(LPCWSTR userName, LPCWSTR domainName, LPCWSTR serverName, PSID** apGroupSids, DWORD* pdwCount)
|
|
{
|
|
if (!IsPlatformNT())
|
|
return STATUS_NOT_SUPPORTED;
|
|
|
|
CSamRun sam;
|
|
|
|
if (!sam.RunSamRun())
|
|
return STATUS_DLL_INIT_FAILED;
|
|
else
|
|
{
|
|
// will reuse this puppy without remorse.
|
|
CUnicodeString buffer;
|
|
|
|
NTSTATUS ntst = STATUS_SUCCESS;
|
|
|
|
// get local handles
|
|
CSamHandle hLocalSam(sam);
|
|
ntst = sam.m_pfnSamConnect(NULL, (void**)hLocalSam,
|
|
SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
|
|
NULL);
|
|
if(ntst)
|
|
{
|
|
ERRORTRACE((LOG_ESS, "SamConnect Failed, error 0x%X\n", ntst));
|
|
return ntst;
|
|
}
|
|
|
|
PSID pBuiltinDomainId = NULL;
|
|
buffer = L"BUILTIN";
|
|
ntst = sam.m_pfnSamLookupDomainInSamServer(hLocalSam, &buffer, &pBuiltinDomainId);
|
|
if(ntst)
|
|
{
|
|
ERRORTRACE((LOG_ESS, "SamLookupDomainInSamServer Failed on BUILTIN domain, error 0x%X\n", ntst));
|
|
return ntst;
|
|
}
|
|
CSamFreeMe freeBuiltinDomain(sam, pBuiltinDomainId);
|
|
|
|
CSamHandle hBuiltinDomain(sam);
|
|
ntst = sam.m_pfnSamOpenDomain(hLocalSam,
|
|
DOMAIN_GET_ALIAS_MEMBERSHIP | DOMAIN_LOOKUP,
|
|
pBuiltinDomainId, (void**)hBuiltinDomain);
|
|
if(ntst)
|
|
{
|
|
ERRORTRACE((LOG_ESS, "SamOpenDomain Failed on BUILTIN domain, error 0x%X\n", ntst));
|
|
return ntst;
|
|
}
|
|
|
|
// make an 'everyone' sid
|
|
PSID pSidEveryoneHeapAlloc = NULL;
|
|
PSID pSidEveryone = NULL;
|
|
SID_IDENTIFIER_AUTHORITY sa = SECURITY_WORLD_SID_AUTHORITY;
|
|
if (AllocateAndInitializeSid(&sa, 1, SECURITY_WORLD_RID, 0,0,0,0,0,0,0, &pSidEveryone))
|
|
{
|
|
DWORD len = GetLengthSid(pSidEveryone);
|
|
|
|
pSidEveryoneHeapAlloc = (PISID)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
|
|
|
|
if (!pSidEveryoneHeapAlloc)
|
|
{
|
|
FreeSid(pSidEveryone);
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
memcpy(pSidEveryoneHeapAlloc, pSidEveryone, len);
|
|
|
|
FreeSid(pSidEveryone);
|
|
pSidEveryone = NULL;
|
|
}
|
|
else
|
|
{
|
|
ntst = GetLastError();
|
|
ERRORTRACE((LOG_ESS, "AllocateAndInitializeSid failed, error 0x%X\n", ntst));
|
|
return ntst;
|
|
}
|
|
|
|
CSamHandle hSam(sam);
|
|
|
|
// connect & determine global groups
|
|
buffer = serverName;
|
|
ntst = sam.m_pfnSamConnect(&buffer, (void **)hSam,
|
|
SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
|
|
NULL);
|
|
if (ntst)
|
|
{
|
|
ERRORTRACE((LOG_ESS, "SamConnect Failed on %S, error 0x%X\n", serverName, ntst));
|
|
return ntst;
|
|
}
|
|
|
|
DWORD dwMembershipCount;
|
|
DWORD dwUserId;
|
|
|
|
PSID* apSids;
|
|
|
|
PSID pDomainId = NULL;
|
|
buffer = domainName;
|
|
ntst = sam.m_pfnSamLookupDomainInSamServer((SAM_HANDLE)hSam, &buffer, &pDomainId);
|
|
|
|
if ( ntst == 0 )
|
|
{
|
|
CSamFreeMe freeDomain(sam, pDomainId);
|
|
CSamHandle hDomain(sam);
|
|
|
|
ntst = sam.m_pfnSamOpenDomain((SAM_HANDLE)hSam,
|
|
DOMAIN_GET_ALIAS_MEMBERSHIP | DOMAIN_LOOKUP,
|
|
pDomainId, (void**)hDomain);
|
|
|
|
if(ntst)
|
|
return ntst;
|
|
|
|
CSamHandle hUser(sam);
|
|
|
|
buffer = userName;
|
|
ULONG* pdwUserId = NULL;
|
|
SID_NAME_USE* psnu = NULL;
|
|
|
|
ntst = sam.m_pfnSamLookupNamesInDomain(hDomain, 1, &buffer, &pdwUserId, &psnu);
|
|
|
|
if(ntst)
|
|
{
|
|
ERRORTRACE((LOG_ESS, "SamLookupNamesInDomain Failed on %S, error 0x%X\n", userName, ntst));
|
|
|
|
return ntst;
|
|
}
|
|
|
|
|
|
CSamFreeMe freeSnu(sam, psnu);
|
|
|
|
dwUserId = *pdwUserId;
|
|
sam.m_pfnSamFreeMemory(pdwUserId);
|
|
|
|
ntst = sam.m_pfnSamOpenUser(hDomain, USER_LIST_GROUPS, dwUserId, (void**)hUser);
|
|
if(ntst)
|
|
return ntst;
|
|
|
|
GROUP_MEMBERSHIP* aMemberships = NULL;
|
|
ntst = sam.m_pfnSamGetGroupsForUser(hUser, &aMemberships, &dwMembershipCount);
|
|
if(ntst)
|
|
return ntst;
|
|
CSamFreeMe freeMembers(sam, aMemberships);
|
|
|
|
// got everything we need for the first bunch...
|
|
apSids = (PSID*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PSID) * (dwMembershipCount +2));
|
|
|
|
if (apSids)
|
|
{
|
|
PSID pSid = CreateUserSid(pDomainId, dwUserId);
|
|
if (!pSid)
|
|
return STATUS_NO_MEMORY;
|
|
|
|
apSids[0] = pSid;
|
|
apSids[1] = pSidEveryoneHeapAlloc;
|
|
for(DWORD i = 0; i < dwMembershipCount; i++)
|
|
{
|
|
pSid = CreateUserSid(pDomainId, aMemberships[i].RelativeId);
|
|
if (pSid)
|
|
apSids[i+2] = pSid;
|
|
else
|
|
{
|
|
CHeapBigPointerArrayCleanerUpper cleanSids(apSids, dwMembershipCount +1);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
apSids = (PSID*) HeapAlloc( GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(PSID) * 2 );
|
|
if (!apSids)
|
|
{
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
WCHAR wszDomain[256];
|
|
DWORD cDomain = 256;
|
|
SID_NAME_USE psnu;
|
|
|
|
DWORD cSid = 256;
|
|
apSids[0] = (PSID)HeapAlloc( GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
cSid );
|
|
if ( apSids[0] == NULL )
|
|
{
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
//
|
|
// have to join the domain name and user name strings. This is
|
|
// to qualify the name passed to LookupAccountName, but it also
|
|
// provides a significant performance improvement in the call.
|
|
//
|
|
|
|
WCHAR wszFullName[512];
|
|
int cDomainName = wcslen(domainName);
|
|
wcscpy(wszFullName,domainName);
|
|
wszFullName[cDomainName] = '\\';
|
|
wcscpy(wszFullName+cDomainName+1, userName);
|
|
|
|
if ( !LookupAccountNameW( NULL,
|
|
wszFullName,
|
|
apSids[0],
|
|
&cSid,
|
|
wszDomain,
|
|
&cDomain,
|
|
&psnu ) )
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
dwMembershipCount = 0;
|
|
apSids[1] = pSidEveryoneHeapAlloc;
|
|
}
|
|
|
|
CHeapFreeMe freeArray(apSids);
|
|
|
|
// do it again for the local case
|
|
DWORD dwLocalGroupCount;
|
|
DWORD* pdwLocalGroups;
|
|
ntst = sam.m_pfnSamGetAliasMembership(hBuiltinDomain, dwMembershipCount+2, apSids, &dwLocalGroupCount,
|
|
&pdwLocalGroups);
|
|
if (ntst)
|
|
{
|
|
ERRORTRACE((LOG_ESS, "SamGetAliasMembership Failed, error 0x%X\n", ntst));
|
|
return ntst;
|
|
}
|
|
CSamFreeMe freeGroups(sam, pdwLocalGroups);
|
|
|
|
// got both the global & the local - build us an array to hold them all:
|
|
PSID* apAllSids = (PSID*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PSID) * (dwMembershipCount + dwLocalGroupCount +2));
|
|
|
|
if (apSids)
|
|
{
|
|
for(DWORD i = 0; i < dwMembershipCount +2; i++)
|
|
apAllSids[i] = apSids[i];
|
|
|
|
for (i = 0; i < dwLocalGroupCount; i++)
|
|
{
|
|
PSID pSid = CreateUserSid(pBuiltinDomainId, pdwLocalGroups[i]);
|
|
if (pSid)
|
|
apAllSids[i +dwMembershipCount +2] = pSid;
|
|
else
|
|
// lazy man's cleanup - let the dtors do all the work;
|
|
{
|
|
ERRORTRACE((LOG_ESS, "Allocation Failure\n"));
|
|
|
|
CHeapFreeMe freeArray(apAllSids);
|
|
CHeapBigPointerArrayCleanerUpper cleanAllSids(apAllSids, dwMembershipCount + dwLocalGroupCount +1);
|
|
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
*apGroupSids = apAllSids;
|
|
*pdwCount = dwMembershipCount + dwLocalGroupCount +2;
|
|
}
|
|
else
|
|
{
|
|
ERRORTRACE((LOG_ESS, "Allocation Failure\n"));
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|