You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2379 lines
62 KiB
2379 lines
62 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
srvutil.cpp
|
|
|
|
Abstract:
|
|
|
|
Server Service attachment APIs
|
|
|
|
Author:
|
|
|
|
Jin Huang (jinhuang) 23-Jun-1997
|
|
|
|
Revision History:
|
|
|
|
jinhuang 23-Jan-1998 splitted to client-server
|
|
--*/
|
|
#include "serverp.h"
|
|
#include "srvutil.h"
|
|
#include "infp.h"
|
|
#include "pfp.h"
|
|
|
|
#include <io.h>
|
|
#pragma hdrstop
|
|
|
|
DWORD Thread gMaxRegTicks=0;
|
|
DWORD Thread gMaxFileTicks=0;
|
|
DWORD Thread gMaxDsTicks=0;
|
|
WCHAR Thread theAcctDomName[MAX_PATH+1];
|
|
WCHAR Thread ComputerName[MAX_COMPUTERNAME_LENGTH+1];
|
|
CHAR Thread sidAuthBuf[32];
|
|
CHAR Thread sidBuiltinBuf[32];
|
|
DWORD Thread t_pebSize=0;
|
|
LPVOID Thread t_pebClient=NULL;
|
|
|
|
SCESTATUS
|
|
ScepQueryInfTicks(
|
|
IN PWSTR TemplateName,
|
|
IN AREA_INFORMATION Area,
|
|
OUT PDWORD pTotalTicks
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepGetObjectCount(
|
|
IN PSCECONTEXT Context,
|
|
IN PCWSTR SectionName,
|
|
IN BOOL bPolicyProp,
|
|
OUT PDWORD pTotalTicks
|
|
);
|
|
|
|
|
|
LPTSTR
|
|
ScepSearchClientEnv(
|
|
IN LPTSTR varName,
|
|
IN DWORD dwSize
|
|
);
|
|
|
|
//
|
|
// implementations
|
|
//
|
|
|
|
|
|
SCESTATUS
|
|
ScepGetTotalTicks(
|
|
IN PCWSTR TemplateName,
|
|
IN PSCECONTEXT Context,
|
|
IN AREA_INFORMATION Area,
|
|
IN SCEFLAGTYPE nFlag,
|
|
OUT PDWORD pTotalTicks
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Retrieve the total count of objects from the inf template and/or the
|
|
database for the area specified.
|
|
|
|
Arguments:
|
|
|
|
TemplateName - the INF template Name
|
|
|
|
Context - the database context
|
|
|
|
Area - the security area
|
|
|
|
nFlag - the flag to indicate operation which determines where the count is
|
|
retrieved:
|
|
|
|
SCE_FLAG_CONFIG
|
|
SCE_FLAG_CONFIG_APPEND
|
|
SCE_FLAG_ANALYZE
|
|
SCE_FLAG_ANALYZE_APPEND
|
|
|
|
pTotalTicks - the output count
|
|
|
|
Return Value:
|
|
|
|
SCE Status
|
|
*/
|
|
{
|
|
if ( pTotalTicks == NULL ||
|
|
( NULL == TemplateName && NULL == Context) ) {
|
|
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
SCESTATUS rc=SCESTATUS_SUCCESS;
|
|
DWORD nTicks=0;
|
|
|
|
*pTotalTicks = 0;
|
|
gMaxRegTicks=0;
|
|
gMaxFileTicks=0;
|
|
gMaxDsTicks=0;
|
|
|
|
if ( Area & (AREA_FILE_SECURITY |
|
|
AREA_REGISTRY_SECURITY) ) { // |
|
|
// AREA_DS_OBJECTS) ) {
|
|
|
|
switch ( nFlag ) {
|
|
case SCE_FLAG_CONFIG:
|
|
case SCE_FLAG_CONFIG_APPEND:
|
|
case SCE_FLAG_CONFIG_SCP:
|
|
case SCE_FLAG_CONFIG_SCP_APPEND:
|
|
|
|
if ( TemplateName != NULL ) {
|
|
|
|
//
|
|
// use the template if there is any
|
|
//
|
|
rc = ScepQueryInfTicks(
|
|
(LPTSTR)TemplateName,
|
|
Area & (AREA_FILE_SECURITY |
|
|
AREA_REGISTRY_SECURITY), // |
|
|
// AREA_DS_OBJECTS),
|
|
pTotalTicks
|
|
);
|
|
}
|
|
if ( Context != NULL &&
|
|
(nFlag == SCE_FLAG_CONFIG_APPEND ||
|
|
nFlag == SCE_FLAG_CONFIG_SCP_APPEND ||
|
|
TemplateName == NULL) ) {
|
|
|
|
//
|
|
// use the existing database
|
|
//
|
|
|
|
if ( Area & AREA_REGISTRY_SECURITY ) {
|
|
|
|
nTicks = 0;
|
|
rc = ScepGetObjectCount(Context,
|
|
szRegistryKeys,
|
|
(nFlag >= SCE_FLAG_CONFIG_SCP) ? TRUE : FALSE,
|
|
&nTicks);
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
gMaxRegTicks += nTicks;
|
|
*pTotalTicks += nTicks;
|
|
}
|
|
}
|
|
if ( rc == SCESTATUS_SUCCESS && (Area & AREA_FILE_SECURITY) ) {
|
|
|
|
nTicks = 0;
|
|
rc = ScepGetObjectCount(Context,
|
|
szFileSecurity,
|
|
(nFlag >= SCE_FLAG_CONFIG_SCP) ? TRUE : FALSE,
|
|
&nTicks);
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
gMaxFileTicks += nTicks;
|
|
*pTotalTicks += nTicks;
|
|
}
|
|
}
|
|
#if 0
|
|
if ( rc == SCESTATUS_SUCCESS && (Area & AREA_DS_OBJECTS) ) {
|
|
|
|
nTicks = 0;
|
|
rc = ScepGetObjectCount(Context,
|
|
szDSSecurity,
|
|
(nFlag >= SCE_FLAG_CONFIG_SCP) ? TRUE : FALSE,
|
|
&nTicks);
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
gMaxDsTicks += nTicks;
|
|
*pTotalTicks += nTicks;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
break;
|
|
case SCE_FLAG_ANALYZE:
|
|
case SCE_FLAG_ANALYZE_APPEND:
|
|
|
|
if ( Context != NULL ) {
|
|
//
|
|
// use the existing database
|
|
//
|
|
if ( Area & AREA_REGISTRY_SECURITY ) {
|
|
|
|
nTicks = 0;
|
|
rc = ScepGetObjectCount(Context,
|
|
szRegistryKeys,
|
|
(nFlag >= SCE_FLAG_CONFIG_SCP) ? TRUE : FALSE,
|
|
&nTicks);
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
gMaxRegTicks += nTicks;
|
|
*pTotalTicks += nTicks;
|
|
}
|
|
}
|
|
if ( rc == SCESTATUS_SUCCESS &&
|
|
Area & AREA_FILE_SECURITY ) {
|
|
|
|
nTicks = 0;
|
|
rc = ScepGetObjectCount(Context,
|
|
szFileSecurity,
|
|
(nFlag >= SCE_FLAG_CONFIG_SCP) ? TRUE : FALSE,
|
|
&nTicks);
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
gMaxFileTicks += nTicks;
|
|
*pTotalTicks += nTicks;
|
|
}
|
|
}
|
|
#if 0
|
|
if ( rc == SCESTATUS_SUCCESS &&
|
|
Area & AREA_DS_OBJECTS ) {
|
|
|
|
nTicks = 0;
|
|
rc = ScepGetObjectCount(Context,
|
|
szDSSecurity,
|
|
(nFlag >= SCE_FLAG_CONFIG_SCP) ? TRUE : FALSE,
|
|
&nTicks);
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
gMaxDsTicks += nTicks;
|
|
*pTotalTicks += nTicks;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if ( rc == SCESTATUS_SUCCESS && TemplateName != NULL &&
|
|
(nFlag == SCE_FLAG_ANALYZE_APPEND || Context == NULL) ) {
|
|
|
|
//
|
|
// get handle in template
|
|
//
|
|
|
|
DWORD nTempTicks=0;
|
|
|
|
rc = ScepQueryInfTicks(
|
|
(LPTSTR)TemplateName,
|
|
Area & (AREA_FILE_SECURITY |
|
|
AREA_REGISTRY_SECURITY), // |
|
|
// AREA_DS_OBJECTS),
|
|
&nTempTicks
|
|
);
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
*pTotalTicks += nTempTicks;
|
|
}
|
|
}
|
|
|
|
break;
|
|
default:
|
|
return SCESTATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
if ( Area & AREA_SECURITY_POLICY )
|
|
*pTotalTicks += TICKS_SECURITY_POLICY_DS + TICKS_SPECIFIC_POLICIES;
|
|
|
|
if ( Area & AREA_GROUP_MEMBERSHIP )
|
|
*pTotalTicks += TICKS_GROUPS;
|
|
|
|
if ( Area & AREA_PRIVILEGES )
|
|
*pTotalTicks += TICKS_PRIVILEGE;
|
|
|
|
if ( Area & AREA_SYSTEM_SERVICE )
|
|
*pTotalTicks += TICKS_GENERAL_SERVICES + TICKS_SPECIFIC_SERVICES;
|
|
/*
|
|
if ( *pTotalTicks ) {
|
|
*pTotalTicks += 10; // for jet engine initialization
|
|
}
|
|
*/
|
|
}
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepQueryInfTicks(
|
|
IN PWSTR TemplateName,
|
|
IN AREA_INFORMATION Area,
|
|
OUT PDWORD pTotalTicks
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Query total number of objects in the inf template for the specified area.
|
|
|
|
Arguments:
|
|
|
|
Return:
|
|
|
|
*/
|
|
{
|
|
LONG Count=0;
|
|
HINF InfHandle;
|
|
|
|
SCESTATUS rc = SceInfpOpenProfile(
|
|
TemplateName,
|
|
&InfHandle
|
|
);
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
if ( Area & AREA_REGISTRY_SECURITY ) {
|
|
|
|
Count = SetupGetLineCount(InfHandle, szRegistryKeys);
|
|
gMaxRegTicks += Count;
|
|
|
|
}
|
|
if ( Area & AREA_FILE_SECURITY ) {
|
|
|
|
Count += SetupGetLineCount(InfHandle, szFileSecurity);
|
|
gMaxFileTicks += Count;
|
|
}
|
|
#if 0
|
|
if ( Area & AREA_DS_OBJECTS ) {
|
|
|
|
Count += SetupGetLineCount(InfHandle, szDSSecurity);
|
|
gMaxDsTicks += Count;
|
|
}
|
|
#endif
|
|
SceInfpCloseProfile(InfHandle);
|
|
}
|
|
|
|
*pTotalTicks = Count;
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
SCESTATUS
|
|
ScepGetObjectCount(
|
|
IN PSCECONTEXT Context,
|
|
IN PCWSTR SectionName,
|
|
IN BOOL bPolicyProp,
|
|
OUT PDWORD pTotalTicks
|
|
)
|
|
{
|
|
if ( Context == NULL || SectionName == NULL ||
|
|
pTotalTicks == NULL ) {
|
|
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
PSCESECTION hSection=NULL;
|
|
SCESTATUS rc;
|
|
DWORD count=0;
|
|
|
|
rc = ScepOpenSectionForName(
|
|
Context,
|
|
bPolicyProp ? SCE_ENGINE_SCP : SCE_ENGINE_SMP,
|
|
SectionName,
|
|
&hSection
|
|
);
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
rc = SceJetGetLineCount(
|
|
hSection,
|
|
NULL,
|
|
FALSE,
|
|
&count
|
|
);
|
|
|
|
if ( rc == SCESTATUS_SUCCESS )
|
|
*pTotalTicks += count;
|
|
|
|
SceJetCloseSection( &hSection, TRUE);
|
|
}
|
|
|
|
if ( SCESTATUS_RECORD_NOT_FOUND == rc)
|
|
rc = SCESTATUS_SUCCESS;
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
BOOL
|
|
ScepIsEngineRecovering()
|
|
{
|
|
TCHAR TempFileName[MAX_PATH];
|
|
PWSTR SysRoot=NULL;
|
|
DWORD SysLen;
|
|
DWORD rc;
|
|
BOOL bFindIt=FALSE;
|
|
|
|
SysLen = 0;
|
|
rc = ScepGetNTDirectory( &SysRoot, &SysLen, SCE_FLAG_WINDOWS_DIR );
|
|
|
|
if ( rc == NO_ERROR && SysRoot != NULL ) {
|
|
|
|
swprintf(TempFileName, L"%s\\Security\\tmp.edb", SysRoot);
|
|
TempFileName[MAX_PATH-1] = L'\0';
|
|
|
|
if ( 0xFFFFFFFF != GetFileAttributes(TempFileName) ) {
|
|
|
|
bFindIt = TRUE;
|
|
}
|
|
|
|
ScepFree(SysRoot);
|
|
|
|
}
|
|
|
|
return bFindIt;
|
|
|
|
}
|
|
|
|
|
|
|
|
SCESTATUS
|
|
ScepSaveAndOffAuditing(
|
|
OUT PPOLICY_AUDIT_EVENTS_INFO *ppAuditEvent,
|
|
IN BOOL bTurnOffAuditing,
|
|
IN LSA_HANDLE PolicyHandle OPTIONAL
|
|
)
|
|
{
|
|
LSA_HANDLE lsaHandle=NULL;
|
|
NTSTATUS status;
|
|
SCESTATUS rc;
|
|
POLICY_AUDIT_EVENT_OPTIONS lSaveAudit;
|
|
|
|
//
|
|
// open Lsa policy for read/write
|
|
//
|
|
|
|
if ( PolicyHandle == NULL ) {
|
|
|
|
ACCESS_MASK access=0;
|
|
|
|
if ( bTurnOffAuditing ) {
|
|
access = POLICY_SET_AUDIT_REQUIREMENTS | POLICY_AUDIT_LOG_ADMIN;
|
|
}
|
|
|
|
status = ScepOpenLsaPolicy(
|
|
POLICY_VIEW_AUDIT_INFORMATION | access,
|
|
&lsaHandle,
|
|
TRUE
|
|
);
|
|
|
|
if (status != ERROR_SUCCESS) {
|
|
|
|
lsaHandle = NULL;
|
|
rc = RtlNtStatusToDosError( status );
|
|
ScepLogOutput3( 1, rc, SCEDLL_LSA_POLICY);
|
|
|
|
return(ScepDosErrorToSceStatus(rc));
|
|
}
|
|
|
|
} else {
|
|
|
|
lsaHandle = PolicyHandle;
|
|
}
|
|
//
|
|
// Query audit event information
|
|
//
|
|
|
|
status = LsaQueryInformationPolicy( lsaHandle,
|
|
PolicyAuditEventsInformation,
|
|
(PVOID *)ppAuditEvent
|
|
);
|
|
rc = RtlNtStatusToDosError( status );
|
|
|
|
if ( NT_SUCCESS( status ) && bTurnOffAuditing && (*ppAuditEvent)->AuditingMode ) {
|
|
|
|
//
|
|
// turn off object access auditing
|
|
//
|
|
if ( AuditCategoryObjectAccess < (*ppAuditEvent)->MaximumAuditEventCount ) {
|
|
lSaveAudit = (*ppAuditEvent)->EventAuditingOptions[AuditCategoryObjectAccess];
|
|
(*ppAuditEvent)->EventAuditingOptions[AuditCategoryObjectAccess] = POLICY_AUDIT_EVENT_NONE;
|
|
|
|
status = LsaSetInformationPolicy( lsaHandle,
|
|
PolicyAuditEventsInformation,
|
|
(PVOID)(*ppAuditEvent)
|
|
);
|
|
|
|
//
|
|
// restore the object access auditing mode
|
|
//
|
|
|
|
(*ppAuditEvent)->EventAuditingOptions[AuditCategoryObjectAccess] = lSaveAudit;
|
|
|
|
}
|
|
|
|
rc = RtlNtStatusToDosError( status );
|
|
|
|
|
|
if ( rc == NO_ERROR )
|
|
ScepLogOutput3( 2, 0, SCEDLL_EVENT_IS_OFF);
|
|
else
|
|
ScepLogOutput3( 1, rc, SCEDLL_SCP_ERROR_EVENT_AUDITING);
|
|
|
|
} else if ( rc != NO_ERROR)
|
|
ScepLogOutput3( 1, rc, SCEDLL_ERROR_QUERY_EVENT_AUDITING);
|
|
|
|
//
|
|
// free LSA handle if it's opened in this function
|
|
//
|
|
if ( lsaHandle && (PolicyHandle == NULL) )
|
|
LsaClose( lsaHandle );
|
|
|
|
return(ScepDosErrorToSceStatus(rc));
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ScepGetAccountExplicitRight(
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN PSID AccountSid,
|
|
OUT PDWORD PrivilegeLowRights,
|
|
OUT PDWORD PrivilegeHighRights
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine queries the explicitly assigned privilege/rights to a account
|
|
(referenced by AccountSid) and stores in a DWORD type variable PrivilegeRights,
|
|
in which each bit represents a privilege/right.
|
|
|
|
Arguments:
|
|
|
|
PolicyHandle - Lsa Policy Domain handle
|
|
|
|
AccountSid - The SID for the account
|
|
|
|
PrivilegeRights - Privilege/Rights of this account
|
|
|
|
Return value:
|
|
|
|
NTSTATUS
|
|
-- */
|
|
{
|
|
NTSTATUS NtStatus;
|
|
|
|
DWORD CurrentPrivLowRights=0, CurrentPrivHighRights=0;
|
|
LONG index;
|
|
PUNICODE_STRING UserRightEnum=NULL;
|
|
ULONG i, cnt=0;
|
|
LUID LuidValue;
|
|
|
|
//
|
|
// Enumerate user privilege/rights
|
|
//
|
|
|
|
NtStatus = LsaEnumerateAccountRights(
|
|
PolicyHandle,
|
|
AccountSid,
|
|
&UserRightEnum,
|
|
&cnt
|
|
);
|
|
if ( NtStatus == STATUS_NO_SUCH_PRIVILEGE ||
|
|
NtStatus == STATUS_OBJECT_NAME_NOT_FOUND ) {
|
|
|
|
NtStatus = ERROR_SUCCESS;
|
|
goto Done;
|
|
}
|
|
|
|
if ( !NT_SUCCESS( NtStatus) ) {
|
|
ScepLogOutput3(1,
|
|
RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_SAP_ERROR_ENUMERATE,
|
|
L"LsaEnumerateAccountRights");
|
|
goto Done;
|
|
}
|
|
|
|
if (UserRightEnum != NULL)
|
|
|
|
for ( i=0; i < cnt; i++) {
|
|
if ( UserRightEnum[i].Length == 0 )
|
|
continue;
|
|
|
|
NtStatus = LsaLookupPrivilegeValue(
|
|
PolicyHandle,
|
|
&UserRightEnum[i],
|
|
&LuidValue
|
|
);
|
|
|
|
if ( NtStatus == STATUS_NO_SUCH_PRIVILEGE ) {
|
|
index = ScepLookupPrivByName( UserRightEnum[i].Buffer );
|
|
NtStatus = ERROR_SUCCESS;
|
|
} else if ( NT_SUCCESS(NtStatus) ) {
|
|
index = ScepLookupPrivByValue( LuidValue.LowPart );
|
|
} else
|
|
index = -1;
|
|
|
|
if ( index == -1 ) {
|
|
|
|
//
|
|
// not found
|
|
//
|
|
|
|
NtStatus = STATUS_NOT_FOUND;
|
|
ScepLogOutput3(1,
|
|
RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_USERRIGHT_NOT_DEFINED);
|
|
goto Done;
|
|
|
|
} else {
|
|
if ( index < 32 ) {
|
|
CurrentPrivLowRights |= (1 << index);
|
|
} else {
|
|
CurrentPrivHighRights |= (1 << (index-32) );
|
|
}
|
|
}
|
|
}
|
|
|
|
Done:
|
|
|
|
*PrivilegeLowRights = CurrentPrivLowRights;
|
|
*PrivilegeHighRights = CurrentPrivHighRights;
|
|
|
|
if (UserRightEnum != NULL)
|
|
LsaFreeMemory(UserRightEnum);
|
|
|
|
return (NtStatus);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ScepGetMemberListSids(
|
|
IN PSID DomainSid,
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN PSCE_NAME_LIST pMembers,
|
|
OUT PUNICODE_STRING *MemberNames,
|
|
OUT PSID** Sids,
|
|
OUT PULONG MemberCount
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Lookup each account in the name list pMembers and return the lookup information
|
|
in the output buffer - MemberNames, Sids, MemberCount.
|
|
|
|
if an account can't be resolved, the corresponding SID will be empty.
|
|
|
|
*/
|
|
{
|
|
NTSTATUS NtStatus=STATUS_SUCCESS;
|
|
PSCE_NAME_LIST pUser;
|
|
|
|
PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains=NULL;
|
|
PLSA_TRANSLATED_SID2 MemberSids=NULL;
|
|
DWORD i;
|
|
PSID DomainSidToUse=NULL;
|
|
ULONG Cnt=0;
|
|
|
|
//
|
|
// build a UNICODE_STRING for the member list to look up
|
|
//
|
|
for (pUser=pMembers;
|
|
pUser != NULL;
|
|
pUser = pUser->Next) {
|
|
|
|
if ( pUser->Name == NULL ) {
|
|
continue;
|
|
}
|
|
Cnt++;
|
|
}
|
|
|
|
if ( Cnt > 0 ) {
|
|
|
|
*MemberNames = (PUNICODE_STRING)RtlAllocateHeap(
|
|
RtlProcessHeap(),
|
|
0,
|
|
Cnt * sizeof (UNICODE_STRING)
|
|
);
|
|
|
|
if ( *MemberNames == NULL )
|
|
return(STATUS_NO_MEMORY);
|
|
|
|
*Sids = (PSID *)ScepAlloc( LMEM_ZEROINIT, Cnt*sizeof(PSID));
|
|
if ( *Sids == NULL ) {
|
|
NtStatus = STATUS_NO_MEMORY;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Lookup each UNICODE_STRING
|
|
//
|
|
|
|
for (pUser=pMembers, Cnt=0;
|
|
pUser != NULL;
|
|
pUser = pUser->Next) {
|
|
|
|
if ( pUser->Name == NULL ) {
|
|
continue;
|
|
}
|
|
|
|
RtlInitUnicodeString(&((*MemberNames)[Cnt]), pUser->Name);
|
|
|
|
NtStatus = ScepLsaLookupNames2(
|
|
PolicyHandle,
|
|
LSA_LOOKUP_ISOLATED_AS_LOCAL,
|
|
pUser->Name,
|
|
&ReferencedDomains,
|
|
&MemberSids
|
|
);
|
|
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_ERROR_LOOKUP);
|
|
goto Done;
|
|
}
|
|
|
|
DWORD SidLength=0;
|
|
|
|
//
|
|
// translate the LSA_TRANSLATED_SID into PSID
|
|
//
|
|
|
|
if ( MemberSids &&
|
|
MemberSids[0].Use != SidTypeInvalid &&
|
|
MemberSids[0].Use != SidTypeUnknown &&
|
|
MemberSids[0].Sid != NULL ) {
|
|
|
|
SidLength = RtlLengthSid(MemberSids[0].Sid);
|
|
|
|
if ( ((*Sids)[Cnt] = (PSID) ScepAlloc( (UINT)0, SidLength)) == NULL ) {
|
|
NtStatus = STATUS_NO_MEMORY;
|
|
} else {
|
|
|
|
//
|
|
// copy the SID
|
|
// if failed, memory will be freed at cleanup
|
|
//
|
|
|
|
NtStatus = RtlCopySid( SidLength, (*Sids)[Cnt], MemberSids[0].Sid );
|
|
|
|
}
|
|
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
goto Done;
|
|
}
|
|
}
|
|
|
|
if ( ReferencedDomains != NULL ){
|
|
LsaFreeMemory(ReferencedDomains);
|
|
ReferencedDomains = NULL;
|
|
}
|
|
|
|
if ( MemberSids != NULL ){
|
|
LsaFreeMemory(MemberSids);
|
|
MemberSids = NULL;
|
|
}
|
|
|
|
Cnt++;
|
|
}
|
|
|
|
}
|
|
*MemberCount = Cnt;
|
|
Done:
|
|
|
|
if (!NT_SUCCESS(NtStatus) ) {
|
|
if ( *Sids != NULL ) {
|
|
for ( i=0; i<Cnt; i++ )
|
|
if ( (*Sids)[i] != NULL )
|
|
ScepFree( (*Sids)[i] );
|
|
ScepFree( *Sids );
|
|
*Sids = NULL;
|
|
}
|
|
if ( *MemberNames != NULL )
|
|
RtlFreeHeap(RtlProcessHeap(), 0, *MemberNames);
|
|
*MemberNames = NULL;
|
|
}
|
|
if ( ReferencedDomains != NULL )
|
|
LsaFreeMemory(ReferencedDomains);
|
|
|
|
if ( MemberSids != NULL )
|
|
LsaFreeMemory(MemberSids);
|
|
|
|
return(NtStatus);
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepOpenFileObject(
|
|
IN LPWSTR pObjectName,
|
|
IN ACCESS_MASK AccessMask,
|
|
OUT PHANDLE Handle
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
opens the specified file (or directory) object
|
|
|
|
Arguments:
|
|
|
|
pObjectName - the name of the file object
|
|
|
|
AccessMask - Desired Access
|
|
|
|
Handle - the just opened handle to the object
|
|
|
|
Return value:
|
|
|
|
Win32 errro code
|
|
*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
DWORD Status = ERROR_SUCCESS;
|
|
OBJECT_ATTRIBUTES Attributes;
|
|
IO_STATUS_BLOCK Isb;
|
|
UNICODE_STRING FileName;
|
|
PVOID FreeBuffer;
|
|
|
|
//
|
|
// cut and paste code from windows\base\advapi\security.c SetFileSecurityW
|
|
//
|
|
if (RtlDosPathNameToNtPathName_U(
|
|
pObjectName,
|
|
&FileName,
|
|
NULL,
|
|
NULL
|
|
))
|
|
{
|
|
FreeBuffer = FileName.Buffer;
|
|
|
|
InitializeObjectAttributes(
|
|
&Attributes,
|
|
&FileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
|
|
NtStatus = NtOpenFile( Handle,
|
|
AccessMask,
|
|
&Attributes,
|
|
&Isb,
|
|
FILE_SHARE_READ |
|
|
FILE_SHARE_WRITE |
|
|
FILE_SHARE_DELETE,
|
|
FILE_OPEN_REPARSE_POINT); // bug 635098: set permissions on junction point,
|
|
// not on target directory
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
Status = RtlNtStatusToDosError(NtStatus);
|
|
}
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
|
|
} else
|
|
{
|
|
Status = ERROR_INVALID_NAME;
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepOpenRegistryObject(
|
|
IN SE_OBJECT_TYPE ObjectType,
|
|
IN LPWSTR pObjectName,
|
|
IN ACCESS_MASK AccessMask,
|
|
OUT PHKEY Handle
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
opens the specified registry key object
|
|
|
|
Arguments:
|
|
|
|
pObjectName - the name of the object
|
|
|
|
AccessMask - Desired access
|
|
|
|
Handle - the just opened handle to the object
|
|
|
|
Return value:
|
|
|
|
Win32 error code
|
|
|
|
Note:
|
|
The code is cut/pasted from windows\base\accctrl\src\registry.cxx and modified
|
|
--*/
|
|
{
|
|
DWORD status=NO_ERROR;
|
|
HKEY basekey;
|
|
LPWSTR usename, basekeyname, keyname;
|
|
|
|
if (pObjectName) {
|
|
|
|
//
|
|
// save a copy of the name since we must crack it.
|
|
//
|
|
if (NULL != (usename = (LPWSTR)ScepAlloc( LMEM_ZEROINIT,
|
|
(wcslen(pObjectName) + 1) * sizeof(WCHAR)))) {
|
|
|
|
wcscpy(usename,pObjectName);
|
|
|
|
basekeyname = usename;
|
|
keyname = wcschr(usename, L'\\');
|
|
if (keyname != NULL) {
|
|
*keyname = L'\0';
|
|
keyname++;
|
|
}
|
|
|
|
if (0 == _wcsicmp(basekeyname, L"MACHINE")) {
|
|
basekey = HKEY_LOCAL_MACHINE;
|
|
} else if (0 == _wcsicmp(basekeyname, L"USERS")) {
|
|
basekey = HKEY_USERS;
|
|
} else if ( 0 == _wcsicmp(basekeyname, L"CLASSES_ROOT")) {
|
|
basekey = HKEY_CLASSES_ROOT;
|
|
} else {
|
|
status = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (NO_ERROR == status) {
|
|
if ( keyname == NULL ) {
|
|
*Handle = basekey;
|
|
} else {
|
|
//
|
|
// open the key
|
|
//
|
|
|
|
#ifdef _WIN64
|
|
if (ObjectType == SE_REGISTRY_WOW64_32KEY) {
|
|
AccessMask |= KEY_WOW64_32KEY;
|
|
}
|
|
#endif
|
|
|
|
status = RegOpenKeyEx(
|
|
basekey,
|
|
keyname,
|
|
0 ,
|
|
AccessMask,
|
|
Handle
|
|
);
|
|
}
|
|
}
|
|
ScepFree(usename);
|
|
} else {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
} else {
|
|
status = ERROR_INVALID_NAME;
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
|
|
|
|
SCESTATUS
|
|
ScepGetNameInLevel(
|
|
IN PCWSTR ObjectFullName,
|
|
IN DWORD Level,
|
|
IN WCHAR Delim,
|
|
OUT PWSTR Buffer,
|
|
OUT PBOOL LastOne
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine parses a full path name and returns the component for the
|
|
level. For example, a object name "c:\winnt\system32" will return c: for
|
|
level 1, winnt for level 2, and system32 for level 3. This routine is
|
|
used when add a object to the security tree.
|
|
|
|
Arguments:
|
|
|
|
ObjectFullName - The full path name of the object
|
|
|
|
Level - the level of component to return
|
|
|
|
Delim - the deliminator to look for
|
|
|
|
Buffer - The address of buffer for the component name
|
|
|
|
LastOne - Flag to indicate if the component is the last one
|
|
|
|
Return value:
|
|
|
|
SCESTATUS
|
|
|
|
-- */
|
|
{
|
|
PWSTR pTemp, pStart;
|
|
DWORD i;
|
|
|
|
if ( ObjectFullName == NULL )
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
|
|
//
|
|
// loop through the object name to find the level
|
|
// if there is no such level, return INVALID_PARAMETER
|
|
//
|
|
pStart = (PWSTR)ObjectFullName;
|
|
for ( i=0; i<Level; i++) {
|
|
|
|
pTemp = wcschr(pStart, Delim);
|
|
|
|
if ( pTemp == pStart ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if ( i == Level-1 ) {
|
|
//
|
|
// find the right level
|
|
//
|
|
if ( pTemp == NULL ) {
|
|
wcscpy(Buffer, pStart);
|
|
*LastOne = TRUE;
|
|
} else {
|
|
wcsncpy(Buffer, pStart, (size_t)(pTemp - pStart));
|
|
if ( *(pTemp+1) == L'\0' )
|
|
*LastOne = TRUE;
|
|
else
|
|
*LastOne = FALSE;
|
|
}
|
|
} else {
|
|
if ( pTemp == NULL )
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
else
|
|
pStart = pTemp + 1;
|
|
}
|
|
}
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
SCESTATUS
|
|
ScepTranslateFileDirName(
|
|
IN PWSTR oldFileName,
|
|
OUT PWSTR *newFileName
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine converts a generic file/directory name to a real used name
|
|
for the current system. The following generic file/directory names are handled:
|
|
%systemroot% - Windows NT root directory (e.g., c:\winnt)
|
|
%systemDirectory% - Windows NT system32 directory (e.g., c:\winnt\system32)
|
|
|
|
Arguments:
|
|
|
|
oldFileName - the file name to convert, which includes "%" to represent
|
|
some directory names
|
|
|
|
newFileName - the real file name, in which the "%" name is replaced with
|
|
the real directory name
|
|
|
|
Return values:
|
|
|
|
Win32 error code
|
|
|
|
-- */
|
|
{
|
|
PWSTR pTemp=NULL, pStart, TmpBuf, szVar;
|
|
DWORD rc=NO_ERROR;
|
|
DWORD newFileSize, cSize;
|
|
BOOL bContinue;
|
|
|
|
//
|
|
// match for %systemroot%
|
|
//
|
|
|
|
rc = ScepExpandEnvironmentVariable(oldFileName,
|
|
L"%SYSTEMROOT%",
|
|
SCE_FLAG_WINDOWS_DIR,
|
|
newFileName);
|
|
|
|
if ( rc != ERROR_FILE_NOT_FOUND ) {
|
|
return rc;
|
|
}
|
|
|
|
//
|
|
// match for %systemdirectory%
|
|
//
|
|
|
|
rc = ScepExpandEnvironmentVariable(oldFileName,
|
|
L"%SYSTEMDIRECTORY%",
|
|
SCE_FLAG_SYSTEM_DIR,
|
|
newFileName);
|
|
|
|
if ( rc != ERROR_FILE_NOT_FOUND ) {
|
|
return rc;
|
|
}
|
|
|
|
//
|
|
// match for systemdrive
|
|
//
|
|
|
|
rc = ScepExpandEnvironmentVariable(oldFileName,
|
|
L"%SYSTEMDRIVE%",
|
|
SCE_FLAG_WINDOWS_DIR,
|
|
newFileName);
|
|
|
|
if ( rc != ERROR_FILE_NOT_FOUND ) {
|
|
return rc;
|
|
}
|
|
|
|
//
|
|
// match for boot drive
|
|
//
|
|
|
|
rc = ScepExpandEnvironmentVariable(oldFileName,
|
|
L"%BOOTDRIVE%",
|
|
SCE_FLAG_BOOT_DRIVE,
|
|
newFileName);
|
|
|
|
if ( rc != ERROR_FILE_NOT_FOUND ) {
|
|
return rc;
|
|
}
|
|
|
|
rc = ERROR_SUCCESS;
|
|
//
|
|
// search for environment variable in the current process
|
|
//
|
|
pStart = wcschr(oldFileName, L'%');
|
|
|
|
if ( pStart ) {
|
|
pTemp = wcschr(pStart+1, L'%');
|
|
if ( pTemp ) {
|
|
|
|
bContinue = TRUE;
|
|
//
|
|
// find a environment variable to translate
|
|
//
|
|
TmpBuf = (PWSTR)ScepAlloc(0, ((UINT)(pTemp-pStart))*sizeof(WCHAR));
|
|
if ( TmpBuf ) {
|
|
|
|
wcsncpy(TmpBuf, pStart+1, (size_t)(pTemp-pStart-1));
|
|
TmpBuf[pTemp-pStart-1] = L'\0';
|
|
|
|
//
|
|
// try search in the client environment block
|
|
//
|
|
|
|
szVar = ScepSearchClientEnv(TmpBuf, (DWORD)(pTemp-pStart-1));
|
|
|
|
if ( szVar ) {
|
|
|
|
// ScepLogOutput2(3,0,L"\tFind client env %s=%s", TmpBuf, szVar);
|
|
//
|
|
// find it in the client's environment block, use it
|
|
// get info in szVar
|
|
//
|
|
bContinue = FALSE;
|
|
|
|
newFileSize = ((DWORD)(pStart-oldFileName))+wcslen(szVar)+wcslen(pTemp+1)+1;
|
|
|
|
*newFileName = (PWSTR)ScepAlloc(0, newFileSize*sizeof(TCHAR));
|
|
|
|
if (*newFileName ) {
|
|
if ( pStart != oldFileName ) {
|
|
wcsncpy(*newFileName, oldFileName, (size_t)(pStart-oldFileName));
|
|
}
|
|
|
|
swprintf((PWSTR)(*newFileName+(pStart-oldFileName)), L"%s%s", szVar, pTemp+1);
|
|
|
|
} else {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
//
|
|
// DO NOT free szVar because it's a ref pointer to the env block
|
|
//
|
|
} else {
|
|
|
|
cSize = GetEnvironmentVariable( TmpBuf,
|
|
NULL,
|
|
0 );
|
|
|
|
if ( cSize > 0 ) {
|
|
//
|
|
// does not find it in the client environment block,
|
|
// find it in the current server process environment, use it
|
|
//
|
|
szVar = (PWSTR)ScepAlloc(0, (cSize+1)*sizeof(WCHAR));
|
|
|
|
if ( szVar ) {
|
|
cSize = GetEnvironmentVariable(TmpBuf,
|
|
szVar,
|
|
cSize);
|
|
if ( cSize > 0 ) {
|
|
//
|
|
// get info in szVar
|
|
//
|
|
bContinue = FALSE;
|
|
|
|
newFileSize = ((DWORD)(pStart-oldFileName))+cSize+wcslen(pTemp+1)+1;
|
|
|
|
*newFileName = (PWSTR)ScepAlloc(0, newFileSize*sizeof(TCHAR));
|
|
|
|
if (*newFileName ) {
|
|
if ( pStart != oldFileName )
|
|
wcsncpy(*newFileName, oldFileName, (size_t)(pStart-oldFileName));
|
|
|
|
swprintf((PWSTR)(*newFileName+(pStart-oldFileName)), L"%s%s", szVar, pTemp+1);
|
|
|
|
} else
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
ScepFree(szVar);
|
|
|
|
} else
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
}
|
|
}
|
|
|
|
ScepFree(TmpBuf);
|
|
|
|
} else
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
if ( NO_ERROR != rc || !bContinue ) {
|
|
//
|
|
// if errored, or do not continue
|
|
//
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// not found in environment blob,
|
|
// continue to search for DSDIT/DSLOG/SYSVOL in registry
|
|
//
|
|
if ( ProductType == NtProductLanManNt ) {
|
|
|
|
//
|
|
// search for DSDIT
|
|
//
|
|
|
|
rc = ScepExpandEnvironmentVariable(oldFileName,
|
|
L"%DSDIT%",
|
|
SCE_FLAG_DSDIT_DIR,
|
|
newFileName);
|
|
|
|
if ( rc != ERROR_FILE_NOT_FOUND ) {
|
|
return rc;
|
|
}
|
|
|
|
//
|
|
// search for DSLOG
|
|
//
|
|
|
|
rc = ScepExpandEnvironmentVariable(oldFileName,
|
|
L"%DSLOG%",
|
|
SCE_FLAG_DSLOG_DIR,
|
|
newFileName);
|
|
|
|
if ( rc != ERROR_FILE_NOT_FOUND ) {
|
|
return rc;
|
|
}
|
|
|
|
//
|
|
// search for SYSVOL
|
|
//
|
|
rc = ScepExpandEnvironmentVariable(oldFileName,
|
|
L"%SYSVOL%",
|
|
SCE_FLAG_SYSVOL_DIR,
|
|
newFileName);
|
|
|
|
if ( rc != ERROR_FILE_NOT_FOUND ) {
|
|
return rc;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// search for PROFILES
|
|
//
|
|
rc = ScepExpandEnvironmentVariable(oldFileName,
|
|
L"%PROFILES%",
|
|
SCE_FLAG_PROFILES_DIR,
|
|
newFileName);
|
|
|
|
if ( rc != ERROR_FILE_NOT_FOUND ) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
//
|
|
// Otherwise, just copy the old name to a new buffer and return ERROR_PATH_NOT_FOUND
|
|
//
|
|
*newFileName = (PWSTR)ScepAlloc(0, (wcslen(oldFileName)+1)*sizeof(TCHAR));
|
|
|
|
if (*newFileName != NULL) {
|
|
wcscpy(*newFileName, _wcsupr(oldFileName) );
|
|
rc = ERROR_PATH_NOT_FOUND;
|
|
} else
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
LPTSTR
|
|
ScepSearchClientEnv(
|
|
IN LPTSTR varName,
|
|
IN DWORD dwSize
|
|
)
|
|
{
|
|
if ( !varName || dwSize == 0 ||
|
|
!t_pebClient || t_pebSize == 0 ) {
|
|
return NULL;
|
|
}
|
|
|
|
LPTSTR pTemp = (LPTSTR)t_pebClient;
|
|
|
|
while ( pTemp && *pTemp != L'\0' ) {
|
|
|
|
|
|
if ( _wcsnicmp(varName, pTemp, dwSize) == 0 &&
|
|
L'=' == *(pTemp+dwSize) ) {
|
|
//
|
|
// find the variable
|
|
//
|
|
return pTemp+dwSize+1;
|
|
break;
|
|
}
|
|
DWORD Len = wcslen(pTemp);
|
|
pTemp += Len+1;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepConvertLdapToJetIndexName(
|
|
IN PWSTR TempName,
|
|
OUT PWSTR *OutName
|
|
)
|
|
{
|
|
PWSTR pTemp1;
|
|
PWSTR pTemp2;
|
|
INT i,j;
|
|
DWORD Len;
|
|
|
|
//
|
|
// Ldap name are in the format of CN=,DC=,...O=
|
|
// Jet Index requires names in the O=,...DC=,CN= format
|
|
//
|
|
// semicolon is converted to , and spaces are stripped out
|
|
//
|
|
if ( TempName == NULL || OutName == NULL ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
Len = wcslen(TempName);
|
|
pTemp1 = TempName + Len - 1;
|
|
|
|
//
|
|
// skip the trailing spaces, commas, or semicolons
|
|
//
|
|
while ( pTemp1 >= TempName &&
|
|
(*pTemp1 == L' ' || *pTemp1 == L';' || *pTemp1 == L',') ) {
|
|
pTemp1--;
|
|
}
|
|
|
|
if ( pTemp1 < TempName ) {
|
|
//
|
|
// all spaces or ; in the name
|
|
//
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// allocate output buffer
|
|
//
|
|
*OutName = (PWSTR)ScepAlloc(0, ((UINT)(pTemp1-TempName+2))*sizeof(WCHAR));
|
|
if ( *OutName != NULL ) {
|
|
|
|
pTemp2 = *OutName;
|
|
|
|
while ( pTemp1 >= TempName ) {
|
|
|
|
//
|
|
// find the previous ; or ,
|
|
//
|
|
i = 0;
|
|
while ( pTemp1-i >= TempName && *(pTemp1-i) != L',' &&
|
|
*(pTemp1-i) != L';' ) {
|
|
i++;
|
|
}
|
|
//
|
|
// either reach the head, or a ; or , is encountered
|
|
//
|
|
i--; // i must be >= 0
|
|
|
|
//
|
|
// skip the leading spaces
|
|
//
|
|
j = 0;
|
|
while ( *(pTemp1-i+j) == L' ' && j <= i ) {
|
|
j++;
|
|
}
|
|
//
|
|
// copy the component
|
|
//
|
|
if ( i >= j ) {
|
|
|
|
if ( pTemp2 != *OutName ) {
|
|
*pTemp2++ = L',';
|
|
}
|
|
wcsncpy(pTemp2, pTemp1-i+j, i-j+1);
|
|
pTemp2 += (i-j+1);
|
|
|
|
} else {
|
|
//
|
|
// all spaces
|
|
//
|
|
}
|
|
pTemp1 -= (i+1);
|
|
//
|
|
// skip the trailing spaces, commas, or semicolons
|
|
//
|
|
while ( pTemp1 >= TempName &&
|
|
(*pTemp1 == L' ' || *pTemp1 == L';' || *pTemp1 == L',') ) {
|
|
pTemp1--;
|
|
}
|
|
}
|
|
if ( pTemp2 == *OutName ) {
|
|
//
|
|
// nothing got copied to the output buffer, WRONG!!!
|
|
//
|
|
ScepFree(*OutName);
|
|
*OutName = NULL;
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
|
|
} else {
|
|
//
|
|
// teminate the string
|
|
//
|
|
*pTemp2 = L'\0';
|
|
_wcslwr(*OutName);
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
} else
|
|
return(SCESTATUS_NOT_ENOUGH_RESOURCE);
|
|
}
|
|
|
|
|
|
|
|
SCESTATUS
|
|
ScepRestoreAuditing(
|
|
IN PPOLICY_AUDIT_EVENTS_INFO auditEvent,
|
|
IN LSA_HANDLE PolicyHandle OPTIONAL
|
|
)
|
|
{
|
|
LSA_HANDLE lsaHandle=NULL;
|
|
NTSTATUS status;
|
|
SCESTATUS rc;
|
|
|
|
if ( auditEvent == NULL )
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
|
|
if ( PolicyHandle == NULL ) {
|
|
|
|
// open Lsa policy for read/write
|
|
status = ScepOpenLsaPolicy(
|
|
POLICY_VIEW_AUDIT_INFORMATION |
|
|
POLICY_SET_AUDIT_REQUIREMENTS |
|
|
POLICY_AUDIT_LOG_ADMIN,
|
|
&lsaHandle,
|
|
TRUE
|
|
);
|
|
|
|
if (status != ERROR_SUCCESS) {
|
|
|
|
lsaHandle = NULL;
|
|
rc = RtlNtStatusToDosError( status );
|
|
ScepLogOutput3( 1, rc, SCEDLL_LSA_POLICY);
|
|
|
|
return(ScepDosErrorToSceStatus(rc));
|
|
}
|
|
|
|
} else {
|
|
lsaHandle = PolicyHandle;
|
|
}
|
|
|
|
// restore
|
|
status = LsaSetInformationPolicy( lsaHandle,
|
|
PolicyAuditEventsInformation,
|
|
(PVOID)(auditEvent)
|
|
);
|
|
rc = RtlNtStatusToDosError( status );
|
|
|
|
if ( rc == NO_ERROR )
|
|
ScepLogOutput3( 2, 0, SCEDLL_EVENT_RESTORED);
|
|
else
|
|
ScepLogOutput3( 1, rc, SCEDLL_SCP_ERROR_EVENT_AUDITING);
|
|
|
|
if ( lsaHandle && (lsaHandle != PolicyHandle) )
|
|
LsaClose( lsaHandle );
|
|
|
|
return(ScepDosErrorToSceStatus(rc));
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepGetDefaultDatabase(
|
|
IN LPCTSTR JetDbName OPTIONAL,
|
|
IN DWORD LogOptions,
|
|
IN LPCTSTR LogFileName OPTIONAL,
|
|
OUT PBOOL pAdminLogon OPTIONAL,
|
|
OUT PWSTR *ppDefDatabase
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Get the default SCE database for the current logged on user.
|
|
|
|
Arguments:
|
|
|
|
JetDbName - optional jet database name
|
|
|
|
LogOptions - options for the log, if there is any
|
|
|
|
LogFileName - the log file
|
|
|
|
pAdminLogon - output flag to indicate if administrative privileged user logged on
|
|
|
|
ppDefDatabase - the default database name
|
|
|
|
Return Value:
|
|
|
|
SCESTATUS
|
|
*/
|
|
{
|
|
if ( !ppDefDatabase ) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
if ( LogOptions & SCE_DISABLE_LOG) {
|
|
|
|
ScepEnableDisableLog(FALSE);
|
|
} else {
|
|
ScepEnableDisableLog(TRUE);
|
|
}
|
|
|
|
if ( LogOptions & SCE_DEBUG_LOG ) {
|
|
|
|
ScepSetVerboseLog(3);
|
|
|
|
} else if ( LogOptions & SCE_VERBOSE_LOG ) {
|
|
//
|
|
// by default it's not verbose
|
|
//
|
|
ScepSetVerboseLog(2);
|
|
|
|
} else {
|
|
ScepSetVerboseLog(-1);
|
|
}
|
|
|
|
if ( ScepLogInitialize( LogFileName ) == ERROR_INVALID_NAME ) {
|
|
ScepLogOutput3(1,0, SCEDLL_LOGFILE_INVALID, LogFileName );
|
|
}
|
|
|
|
|
|
DWORD rc=ERROR_SUCCESS;
|
|
BOOL bAdminLogon=FALSE;
|
|
|
|
//
|
|
// determine if admin logs on
|
|
//
|
|
|
|
if ( pAdminLogon || !JetDbName || wcslen(JetDbName) < 1) {
|
|
|
|
rc = ScepIsAdminLoggedOn(&bAdminLogon, TRUE);
|
|
if ( rc != NO_ERROR ) {
|
|
ScepLogOutput3(1, rc, SCEDLL_UNKNOWN_LOGON_USER);
|
|
}
|
|
|
|
if ( bAdminLogon ) {
|
|
ScepLogOutput3(3, 0, SCEDLL_ADMIN_LOGON);
|
|
}
|
|
}
|
|
|
|
//
|
|
// find the databae name
|
|
//
|
|
|
|
if ( JetDbName && wcslen(JetDbName) > 0 ) {
|
|
|
|
*ppDefDatabase = (LPTSTR)JetDbName;
|
|
|
|
} else {
|
|
|
|
//
|
|
// query if the profile name (or the default ) in registry
|
|
//
|
|
|
|
rc = ScepGetProfileSetting(
|
|
L"DefaultProfile",
|
|
bAdminLogon,
|
|
ppDefDatabase
|
|
);
|
|
|
|
if ( rc != NO_ERROR || *ppDefDatabase == NULL ) { // return is Win32 error code
|
|
ScepLogOutput3(1,rc, SCEDLL_UNKNOWN_DBLOCATION);
|
|
}
|
|
}
|
|
|
|
if ( pAdminLogon ) {
|
|
*pAdminLogon = bAdminLogon;
|
|
}
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
ScepIsDomainLocal(
|
|
IN PUNICODE_STRING pDomainName OPTIONAL
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine checks if the domain is on the local machine by comparing
|
|
the domain name with the local machine's computer name.
|
|
|
|
Arguments:
|
|
|
|
pDomainName - the domain's name to check
|
|
|
|
Return Value:
|
|
|
|
TRUE if it is local
|
|
|
|
-- */
|
|
{
|
|
NTSTATUS NtStatus;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
LSA_HANDLE PolicyHandle;
|
|
DWORD NameLen=MAX_COMPUTERNAME_LENGTH;
|
|
|
|
|
|
if ( pDomainName == NULL ) {
|
|
//
|
|
// reset the buffer
|
|
//
|
|
ComputerName[0] = L'\0';
|
|
theAcctDomName[0] = L'\0';
|
|
sidBuiltinBuf[0] = '\0';
|
|
sidAuthBuf[0] = '\0';
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
if ( pDomainName->Length <= 0 ||
|
|
pDomainName->Buffer == NULL )
|
|
return(TRUE);
|
|
|
|
if ( ComputerName[0] == L'\0' ) {
|
|
memset(ComputerName, '\0', (MAX_COMPUTERNAME_LENGTH+1)*sizeof(WCHAR));
|
|
GetComputerName(ComputerName, &NameLen);
|
|
}
|
|
|
|
NameLen = wcslen(ComputerName);
|
|
|
|
if ( _wcsnicmp(ComputerName, pDomainName->Buffer, pDomainName->Length/2 ) == 0 &&
|
|
(LONG)NameLen == pDomainName->Length/2 )
|
|
return(TRUE);
|
|
|
|
if ( theAcctDomName[0] == L'\0' ) {
|
|
|
|
//
|
|
// query the current account domain name (for DC case)
|
|
//
|
|
|
|
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo=NULL;
|
|
|
|
//
|
|
// Open the policy database
|
|
//
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
NULL, // Name
|
|
0, // Attributes
|
|
NULL, // Root
|
|
NULL ); // Security Descriptor
|
|
|
|
NtStatus = LsaOpenPolicy( NULL,
|
|
&ObjectAttributes,
|
|
POLICY_VIEW_LOCAL_INFORMATION,
|
|
&PolicyHandle );
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
//
|
|
// Query the account domain information
|
|
//
|
|
|
|
NtStatus = LsaQueryInformationPolicy( PolicyHandle,
|
|
PolicyAccountDomainInformation,
|
|
(PVOID *)&PolicyAccountDomainInfo );
|
|
|
|
LsaClose( PolicyHandle );
|
|
}
|
|
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
if ( PolicyAccountDomainInfo->DomainName.Buffer ) {
|
|
|
|
wcsncpy(theAcctDomName,
|
|
PolicyAccountDomainInfo->DomainName.Buffer,
|
|
PolicyAccountDomainInfo->DomainName.Length/2);
|
|
|
|
theAcctDomName[PolicyAccountDomainInfo->DomainName.Length/2] = L'\0';
|
|
|
|
|
|
}
|
|
LsaFreeMemory(PolicyAccountDomainInfo);
|
|
}
|
|
}
|
|
|
|
NameLen = wcslen(theAcctDomName);
|
|
|
|
if ( _wcsnicmp(theAcctDomName, pDomainName->Buffer, pDomainName->Length/2) == 0 &&
|
|
(LONG)NameLen == pDomainName->Length/2 )
|
|
return(TRUE);
|
|
else
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
ScepIsDomainLocalBySid(
|
|
PSID pSidLookup
|
|
)
|
|
{
|
|
|
|
if ( pSidLookup == NULL ) {
|
|
return FALSE;
|
|
}
|
|
|
|
NTSTATUS NtStatus;
|
|
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
|
|
|
//
|
|
// search for "NT Authority" name
|
|
//
|
|
if ( sidAuthBuf[0] == '\0' ) { // sid revision can't be 0
|
|
|
|
//
|
|
// build the NT authority sid
|
|
//
|
|
NtStatus = RtlInitializeSid(
|
|
(PSID)sidAuthBuf,
|
|
&NtAuthority,
|
|
0
|
|
);
|
|
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
|
|
sidAuthBuf[0] = '\0';
|
|
}
|
|
|
|
}
|
|
|
|
if ( sidAuthBuf[0] != '\0' &&
|
|
RtlEqualSid((PSID)sidAuthBuf, pSidLookup) ) {
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
if ( sidBuiltinBuf[0] == '\0' ) {
|
|
//
|
|
// build the builtin domain sid
|
|
//
|
|
|
|
NtStatus = RtlInitializeSid(
|
|
(PSID)sidBuiltinBuf,
|
|
&NtAuthority,
|
|
1
|
|
);
|
|
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
*(RtlSubAuthoritySid((PSID)sidBuiltinBuf, 0)) = SECURITY_BUILTIN_DOMAIN_RID;
|
|
|
|
} else {
|
|
|
|
sidBuiltinBuf[0] = '\0';
|
|
}
|
|
}
|
|
|
|
if ( sidBuiltinBuf[0] != '\0' &&
|
|
RtlEqualSid((PSID)sidBuiltinBuf, pSidLookup) ) {
|
|
|
|
return(TRUE);
|
|
|
|
} else {
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ScepAddAdministratorToThisList(
|
|
IN SAM_HANDLE DomainHandle OPTIONAL,
|
|
IN OUT PSCE_NAME_LIST *ppList
|
|
)
|
|
{
|
|
NTSTATUS NtStatus;
|
|
SAM_HANDLE AccountDomain=NULL;
|
|
SAM_HANDLE UserHandle=NULL;
|
|
SAM_HANDLE ServerHandle=NULL;
|
|
PSID DomainSid=NULL;
|
|
|
|
USER_NAME_INFORMATION *BufName=NULL;
|
|
DOMAIN_NAME_INFORMATION *DomainName=NULL;
|
|
PSCE_NAME_LIST pName=NULL;
|
|
|
|
if (!ppList ) {
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if ( !DomainHandle ) {
|
|
|
|
//
|
|
// open the sam account domain
|
|
//
|
|
|
|
NtStatus = ScepOpenSamDomain(
|
|
SAM_SERVER_ALL_ACCESS,
|
|
MAXIMUM_ALLOWED,
|
|
&ServerHandle,
|
|
&AccountDomain,
|
|
&DomainSid,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
ScepLogOutput3(1,RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_ERROR_OPEN, L"SAM");
|
|
return(NtStatus);
|
|
}
|
|
|
|
} else {
|
|
AccountDomain = DomainHandle;
|
|
}
|
|
|
|
//
|
|
// query account domain name
|
|
//
|
|
NtStatus = SamQueryInformationDomain(
|
|
AccountDomain,
|
|
DomainNameInformation,
|
|
(PVOID *)&DomainName
|
|
);
|
|
|
|
if ( NT_SUCCESS( NtStatus ) && DomainName &&
|
|
DomainName->DomainName.Length > 0 && DomainName->DomainName.Buffer ) {
|
|
|
|
NtStatus = SamOpenUser(
|
|
AccountDomain,
|
|
MAXIMUM_ALLOWED,
|
|
DOMAIN_USER_RID_ADMIN,
|
|
&UserHandle
|
|
);
|
|
|
|
if ( NT_SUCCESS( NtStatus ) ) {
|
|
|
|
NtStatus = SamQueryInformationUser(
|
|
UserHandle,
|
|
UserNameInformation,
|
|
(PVOID *)&BufName
|
|
);
|
|
|
|
if ( NT_SUCCESS( NtStatus ) && BufName &&
|
|
BufName->UserName.Length > 0 && BufName->UserName.Buffer ) {
|
|
|
|
//
|
|
// add it to the members list, check duplicate
|
|
//
|
|
LONG NameLen;
|
|
PWSTR pTemp;
|
|
|
|
for ( pName = *ppList; pName; pName=pName->Next ) {
|
|
|
|
if ( !pName->Name ) {
|
|
continue;
|
|
}
|
|
|
|
pTemp = wcschr( pName->Name, L'\\');
|
|
|
|
if ( pTemp ) {
|
|
//
|
|
// has a domain prefix
|
|
//
|
|
pTemp++;
|
|
} else {
|
|
pTemp = pName->Name;
|
|
}
|
|
NameLen = wcslen(pTemp);
|
|
|
|
if ( NameLen == BufName->UserName.Length/2 &&
|
|
_wcsnicmp(pTemp,
|
|
BufName->UserName.Buffer,
|
|
BufName->UserName.Length/2) == 0 ) {
|
|
//
|
|
// now, match the domain prefix
|
|
//
|
|
if ( pTemp != pName->Name ) {
|
|
|
|
if ( (pTemp-pName->Name-1) == DomainName->DomainName.Length/2 &&
|
|
_wcsnicmp(pName->Name,
|
|
DomainName->DomainName.Buffer,
|
|
DomainName->DomainName.Length/2) == 0 ) {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !pName ) {
|
|
|
|
//
|
|
// allocate a new node, if no resource, ignore the addition
|
|
//
|
|
pName = (PSCE_NAME_LIST)ScepAlloc( (UINT)0, sizeof(SCE_NAME_LIST));
|
|
|
|
if ( pName ) {
|
|
|
|
pName->Name = (PWSTR)ScepAlloc( LMEM_ZEROINIT, BufName->UserName.Length+DomainName->DomainName.Length+4);
|
|
|
|
if ( pName->Name == NULL ) {
|
|
ScepFree(pName);
|
|
} else {
|
|
//
|
|
// add the node to the front of the members list
|
|
//
|
|
NameLen = DomainName->DomainName.Length/2;
|
|
|
|
wcsncpy(pName->Name, DomainName->DomainName.Buffer,
|
|
NameLen);
|
|
pName->Name[NameLen] = L'\\';
|
|
|
|
wcsncpy(pName->Name+NameLen+1, BufName->UserName.Buffer,
|
|
BufName->UserName.Length/2);
|
|
pName->Name[NameLen+1+BufName->UserName.Length/2] = L'\0';
|
|
|
|
pName->Next = *ppList;
|
|
*ppList = pName;
|
|
}
|
|
}
|
|
} else {
|
|
// else find it in the member list already, do nothing
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// close the user handle
|
|
//
|
|
SamCloseHandle(UserHandle);
|
|
UserHandle = NULL;
|
|
}
|
|
}
|
|
|
|
if ( AccountDomain != DomainHandle ) {
|
|
//
|
|
// domain is opened
|
|
//
|
|
SamCloseHandle(AccountDomain);
|
|
|
|
SamCloseHandle( ServerHandle );
|
|
if ( DomainSid != NULL )
|
|
SamFreeMemory(DomainSid);
|
|
}
|
|
|
|
if ( BufName ) {
|
|
SamFreeMemory(BufName);
|
|
}
|
|
|
|
if ( DomainName ) {
|
|
SamFreeMemory(DomainName);
|
|
}
|
|
|
|
return(NtStatus);
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
ScepDatabaseAccessGranted(
|
|
IN LPTSTR DatabaseName,
|
|
IN DWORD DesiredAccess,
|
|
IN BOOL bCreate
|
|
)
|
|
{
|
|
|
|
if ( DatabaseName == NULL || DesiredAccess == 0 ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
HANDLE hToken = NULL, hNewToken = NULL;
|
|
DWORD Win32rc = NO_ERROR;
|
|
|
|
//
|
|
// get current client token
|
|
//
|
|
if (!OpenThreadToken( GetCurrentThread(),
|
|
TOKEN_IMPERSONATE | TOKEN_READ | TOKEN_DUPLICATE,
|
|
TRUE,
|
|
&hToken)) {
|
|
|
|
if(ERROR_NO_TOKEN == GetLastError()){
|
|
|
|
if(!OpenProcessToken( GetCurrentProcess(),
|
|
TOKEN_IMPERSONATE | TOKEN_READ | TOKEN_DUPLICATE,
|
|
&hToken )){
|
|
|
|
return ( GetLastError() );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return( GetLastError() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Duplicate it so it can be used for impersonation
|
|
//
|
|
|
|
if (!DuplicateTokenEx(hToken, TOKEN_IMPERSONATE | TOKEN_QUERY,
|
|
NULL, SecurityImpersonation, TokenImpersonation,
|
|
&hNewToken))
|
|
{
|
|
CloseHandle (hToken);
|
|
return ( GetLastError() );
|
|
}
|
|
|
|
CloseHandle (hToken);
|
|
|
|
|
|
PSECURITY_DESCRIPTOR pCurrentSD=NULL;
|
|
PRIVILEGE_SET PrivSet;
|
|
DWORD PrivSetLength = sizeof(PRIVILEGE_SET);
|
|
DWORD dwGrantedAccess;
|
|
BOOL bAccessStatus = TRUE;
|
|
|
|
if ( !bCreate ) {
|
|
|
|
Win32rc = ScepGetNamedSecurityInfo(
|
|
DatabaseName,
|
|
SE_FILE_OBJECT,
|
|
OWNER_SECURITY_INFORMATION |
|
|
GROUP_SECURITY_INFORMATION |
|
|
DACL_SECURITY_INFORMATION,
|
|
&pCurrentSD
|
|
);
|
|
|
|
if ( Win32rc == ERROR_PATH_NOT_FOUND ||
|
|
Win32rc == ERROR_FILE_NOT_FOUND ) {
|
|
|
|
pCurrentSD = NULL;
|
|
|
|
Win32rc = NO_ERROR;
|
|
|
|
}
|
|
}
|
|
|
|
if ( Win32rc == NO_ERROR ) {
|
|
|
|
if ( pCurrentSD == NULL ) {
|
|
//
|
|
// either this database is to be overwritten (re-created)
|
|
// or it doesn't exist. In both cases, hand the call over to Jet
|
|
// which will do the right access checking.
|
|
//
|
|
} else {
|
|
|
|
if ( !AccessCheck (
|
|
pCurrentSD,
|
|
hNewToken,
|
|
DesiredAccess,
|
|
&FileGenericMapping,
|
|
&PrivSet,
|
|
&PrivSetLength,
|
|
&dwGrantedAccess,
|
|
&bAccessStatus
|
|
) ) {
|
|
|
|
Win32rc = GetLastError();
|
|
|
|
} else {
|
|
|
|
if ( bAccessStatus &&
|
|
(dwGrantedAccess == DesiredAccess ) ) {
|
|
Win32rc = NO_ERROR;
|
|
} else {
|
|
Win32rc = ERROR_ACCESS_DENIED;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if ( pCurrentSD ) {
|
|
|
|
LocalFree(pCurrentSD);
|
|
}
|
|
|
|
CloseHandle (hNewToken);
|
|
|
|
return( Win32rc );
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepAddSidToNameList(
|
|
OUT PSCE_NAME_LIST *pNameList,
|
|
IN PSID pSid,
|
|
IN BOOL bReuseBuffer,
|
|
OUT BOOL *pbBufferUsed
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine adds a SID to the name list. The new added
|
|
node is always placed as the head of the list for performance reason.
|
|
|
|
Arguments:
|
|
|
|
pNameList - The address of the name list to add to.
|
|
|
|
pSid - the Sid to add
|
|
|
|
Return value:
|
|
|
|
Win32 error code
|
|
-- */
|
|
{
|
|
|
|
PSCE_NAME_LIST pList=NULL;
|
|
ULONG Length;
|
|
|
|
//
|
|
// check arguments
|
|
//
|
|
if ( pNameList == NULL ||
|
|
pbBufferUsed == NULL )
|
|
return(ERROR_INVALID_PARAMETER);
|
|
|
|
*pbBufferUsed = FALSE;
|
|
|
|
if ( pSid == NULL )
|
|
return(NO_ERROR);
|
|
|
|
if ( !RtlValidSid(pSid) ) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// check if the SID is already in the name list
|
|
//
|
|
for ( pList=*pNameList; pList!=NULL; pList=pList->Next ) {
|
|
if ( pList->Name == NULL ) {
|
|
continue;
|
|
}
|
|
if ( ScepValidSid( (PSID)(pList->Name) ) &&
|
|
RtlEqualSid( (PSID)(pList->Name), pSid ) ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( pList ) {
|
|
//
|
|
// the SID is already in the list
|
|
//
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
//
|
|
// allocate a new node
|
|
//
|
|
pList = (PSCE_NAME_LIST)ScepAlloc( (UINT)0, sizeof(SCE_NAME_LIST));
|
|
|
|
if ( pList == NULL )
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
if ( bReuseBuffer ) {
|
|
|
|
pList->Name = (PWSTR)pSid;
|
|
*pbBufferUsed = TRUE;
|
|
|
|
} else {
|
|
|
|
Length = RtlLengthSid ( pSid );
|
|
|
|
pList->Name = (PWSTR)ScepAlloc( LMEM_ZEROINIT, Length);
|
|
if ( pList->Name == NULL ) {
|
|
ScepFree(pList);
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
//
|
|
// add the node to the front of the list and link its next to the old list
|
|
//
|
|
RtlCopySid( Length, (PSID)(pList->Name), pSid );
|
|
}
|
|
|
|
pList->Next = *pNameList;
|
|
*pNameList = pList;
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
BOOL
|
|
ScepValidSid(
|
|
PSID Sid
|
|
)
|
|
{
|
|
if ( RtlValidSid(Sid) ) {
|
|
|
|
PISID Isid = (PISID) Sid;
|
|
|
|
if ( Isid->Revision == SID_REVISION ) {
|
|
return(TRUE);
|
|
} else {
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
BOOL
|
|
ScepBinarySearch(
|
|
IN PWSTR *aPszPtrs,
|
|
IN DWORD dwSize_aPszPtrs,
|
|
IN PWSTR pszNameToFind
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine determines if a string is found in a sorted array of strings.
|
|
The complexity of this search is logarithmic (log(n)) in the size of the
|
|
input array.
|
|
|
|
Arguments:
|
|
|
|
aPszPtrs - the array of string pointers to search in
|
|
|
|
dwSize_aPszPtrs - the size of the above array
|
|
|
|
pszNameToFind - the string to search for
|
|
|
|
Return value:
|
|
|
|
TRUE if string is found
|
|
FALSE if string is not found
|
|
|
|
-- */
|
|
{
|
|
if ( aPszPtrs == NULL || dwSize_aPszPtrs == 0 || pszNameToFind == NULL ) {
|
|
return FALSE;
|
|
}
|
|
|
|
int iLow = 0;
|
|
int iHigh = dwSize_aPszPtrs - 1;
|
|
int iMid;
|
|
int iCmp;
|
|
|
|
while (iLow <= iHigh ) {
|
|
|
|
iMid = (iLow + iHigh ) / 2;
|
|
|
|
iCmp = _wcsicmp( aPszPtrs[iMid], pszNameToFind );
|
|
|
|
if ( iCmp == 0 )
|
|
return TRUE;
|
|
else if ( iCmp < 0 )
|
|
iLow = iMid + 1;
|
|
else
|
|
iHigh = iMid - 1;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine adds a relative SID to the SID list in the format "#-RSID", eg "#-512"
|
|
for Domain Admins. Upon membership restore the groups stores as relative SIDs will be
|
|
from the tattoo table, the full SID will be restored based on current domain.
|
|
|
|
|
|
Arguments:
|
|
|
|
aPszPtrs - the array of string pointers to search in
|
|
|
|
dwSize_aPszPtrs - the size of the above array
|
|
|
|
pszNameToFind - the string to search for
|
|
|
|
Return value:
|
|
|
|
TRUE if string is found
|
|
FALSE if string is not found
|
|
|
|
-- */
|
|
DWORD
|
|
ScepAddRelativeSidToNameList(
|
|
IN OUT PSCE_NAME_LIST *pNameList,
|
|
IN PSID pSid)
|
|
{
|
|
DWORD rc;
|
|
PWSTR pwszSid = NULL;
|
|
WCHAR *pchRelativeSid;
|
|
|
|
rc = ScepConvertSidToPrefixStringSid(pSid, &pwszSid);
|
|
if(ERROR_SUCCESS == rc)
|
|
{
|
|
//
|
|
// find the relative SID suffix
|
|
//
|
|
pchRelativeSid = wcsrchr(pwszSid, STRING_SID_SUBAUTH_SEPARATOR);
|
|
if(!pchRelativeSid || L'\0'==*(pchRelativeSid+1))
|
|
{
|
|
rc = SCESTATUS_INVALID_DATA;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Add the relative SID to list in format "#-RSID"
|
|
//
|
|
rc = ScepAddTwoNamesToNameList(
|
|
pNameList,
|
|
FALSE,
|
|
RELATIVE_SID_PREFIX_SZ,
|
|
1,
|
|
pchRelativeSid,
|
|
wcslen(pchRelativeSid));
|
|
}
|
|
}
|
|
|
|
if(pwszSid)
|
|
{
|
|
ScepFree(pwszSid);
|
|
}
|
|
|
|
return rc;
|
|
}
|