windows-nt/Source/XPSP1/NT/ds/security/services/scerpc/server/pfget.cpp

6417 lines
186 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
pfget.cpp
Abstract:
Routines to get information from jet database (configuration/analysis
info).
Author:
Jin Huang (jinhuang) 28-Oct-1996
Revision History:
jinhuang 26-Jan-1998 splitted to client-server
--*/
#include "serverp.h"
#include <io.h>
#include "pfp.h"
#include "kerberos.h"
#include "regvalue.h"
#include <sddl.h>
#pragma hdrstop
//#define SCE_DBG 1
#define SCE_INTERNAL_NP 0x80
#define SCE_ALLOC_MAX_NODE 10
typedef struct _SCE_BROWSE_CALLBACK_VALUE {
DWORD Len;
UCHAR *Value;
} SCE_BROWSE_CALLBACK_VALUE;
//
// Forward references
//
SCESTATUS
ScepGetSystemAccess(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
OUT PSCE_PROFILE_INFO pProfileInfo,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
);
SCESTATUS
ScepGetVariableValue(
IN PSCESECTION hSection,
IN SCETYPE ProfileType,
IN PCWSTR KeyName,
OUT PWSTR *Value,
OUT PDWORD ValueLen
);
SCESTATUS
ScepAddToPrivilegeList(
OUT PSCE_PRIVILEGE_VALUE_LIST *pPrivilegeList,
IN PWSTR Name,
IN DWORD Len,
IN DWORD PrivValue
);
SCESTATUS
ScepGetGroupMembership(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
OUT PSCE_GROUP_MEMBERSHIP *pGroupMembership,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
);
SCESTATUS
ScepGetGroupMembershipFromOneTable(
IN LSA_HANDLE LsaPolicy,
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
OUT PSCE_GROUP_MEMBERSHIP *pGroupMembership,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
);
SCESTATUS
ScepGetObjectList(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN PCWSTR SectionName,
OUT PSCE_OBJECT_LIST *pObjectRoots,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
);
SCESTATUS
ScepGetDsRoot(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN PCWSTR SectionName,
OUT PSCE_OBJECT_LIST *pObjectRoots,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
);
SCESTATUS
ScepBuildDsTree(
OUT PSCE_OBJECT_CHILD_LIST *TreeRoot,
IN ULONG Level,
IN WCHAR Delim,
IN PCWSTR ObjectFullName
);
SCESTATUS
ScepGetObjectFromOneTable(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN PCWSTR SectionName,
OUT PSCE_OBJECT_LIST *pObjectRoots,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
);
SCESTATUS
ScepGetObjectChildrenFromOneTable(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN AREA_INFORMATION Area,
IN PWSTR ObjectPrefix,
IN SCE_SUBOBJECT_TYPE Option,
OUT PVOID *Buffer,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
);
BYTE
ScepGetObjectStatusFlag(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN AREA_INFORMATION Area,
IN PWSTR ObjectPrefix,
IN BOOL bLookForParent
);
SCESTATUS
ScepGetAuditing(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
OUT PSCE_PROFILE_INFO pProfileInfo,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
);
SCESTATUS
ScepGetPrivilegesFromOneTable(
IN LSA_HANDLE LsaPolicy,
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN DWORD dwAccountFormat,
OUT PVOID *pPrivileges,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
);
SCESTATUS
ScepGetSystemServices(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
OUT PSCE_SERVICES *pServiceList,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
);
BOOL
ScepSearchItemInChildren(
IN PWSTR ItemName,
IN DWORD NameLen,
IN PSCE_OBJECT_CHILDREN_NODE *pArrObject,
IN DWORD arrCount,
OUT LONG *pFindIndex
);
DWORD
ScepAddItemToChildren(
IN PSCE_OBJECT_CHILDREN_NODE ThisNode OPTIONAL,
IN PWSTR ItemName,
IN DWORD NameLen,
IN BOOL IsContainer,
IN BYTE Status,
IN DWORD ChildCount,
IN OUT PSCE_OBJECT_CHILDREN_NODE **ppArrObject,
IN OUT DWORD *pArrCount,
IN OUT DWORD *pMaxCount,
IN OUT LONG *pFindIndex
);
//
// function definitions
//
SCESTATUS
ScepGetDatabaseInfo(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN AREA_INFORMATION Area,
IN DWORD dwAccountFormat,
OUT PSCE_PROFILE_INFO *ppInfoBuffer,
IN OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
)
/**++
Function Description:
This function reads all or part of information from a SCP/SAP/SMP profile
depending on the ProfileType, into the InfoBuffer. ProfileType is saved in
the ppInfoBuffer's Type field.
A handle to the profile (Jet database) is passed into the routine every
time this routine is called. Area specifies one or more pre-defined security
areas to get information. One area's information may be saved in multiple
sections in the profile.
The memory related to the area(s) will be reset/freed before loading
information from the profile. If the return code is SCESTATUS_SUCCESS, then
the output InfoBuffer contains the requested information. Otherwise,
InfoBuffer contains nothing for the area(s) specified.
Arguments:
hProfile - The handle to the profile to read from.
ProfileType - value to indicate engine type.
SCE_ENGINE_SCP
SCE_ENGINE_SAP
SCE_ENGINE_SMP
Area - area(s) for which to get information from
AREA_SECURITY_POLICY
AREA_PRIVILEGES
AREA_GROUP_MEMBERSHIP
AREA_REGISTRY_SECURITY
AREA_SYSTEM_SERVICE
AREA_FILE_SECURITY
ppInfoBuffer - The address of SCP/SAP/SMP buffers. If it is NULL, a buffer
will be created which must be freed by LocalFree. The
output is the information requested if successful, or
nothing if fail.
Errlog - A buffer to hold all error codes/text encountered when
parsing the INF file. If Errlog is NULL, no further error
information is returned except the return DWORD
Return Value:
SCESTATUS_SUCCESS
SCESTATUS_PROFILE_NOT_FOUND
SCESTATUS_NOT_ENOUGH_RESOURCE
SCESTATUS_INVALID_PARAMETER
SCESTATUS_BAD_FORMAT
SCESTATUS_INVALID_DATA
-- **/
{
SCESTATUS rc=SCESTATUS_SUCCESS;
DWORD Len;
BOOL bBufAlloc=FALSE;
NT_PRODUCT_TYPE theType;
//
// if the JET database is not opened then return
//
if ( hProfile == NULL ) {
return( SCESTATUS_INVALID_PARAMETER );
}
//
// address for InfoBuffer cannot be NULL
//
if ( ppInfoBuffer == NULL ) {
return( SCESTATUS_INVALID_PARAMETER );
}
//
// check scetype
//
if ( ProfileType > SCE_ENGINE_SMP ) {
return(SCESTATUS_INVALID_PARAMETER);
}
//
// check to see if there is a SMP or SCP table
//
if ( hProfile->JetSmpID == JET_tableidNil ||
hProfile->JetScpID == JET_tableidNil ) {
return(SCESTATUS_PROFILE_NOT_FOUND);
}
if ( ProfileType == SCE_ENGINE_GPO &&
hProfile->JetScpID == hProfile->JetSmpID ) {
//
// there is no domain GPO policy
//
return(SCESTATUS_PROFILE_NOT_FOUND);
}
//
// design on this part is changed.
// if there is no SAP table which means the system has not been
// analyzed based on the template in SMP, return error and UI
// will display "no analysis is performed"
//
if ( ProfileType == SCE_ENGINE_SAP &&
hProfile->JetSapID == JET_tableidNil) {
return(SCESTATUS_PROFILE_NOT_FOUND);
}
//
// create buffer if it is NULL
//
if ( *ppInfoBuffer == NULL) {
//
// allocate memory
//
Len = sizeof(SCE_PROFILE_INFO);
*ppInfoBuffer = (PSCE_PROFILE_INFO)ScepAlloc( (UINT)0, Len);
if ( *ppInfoBuffer == NULL ) {
return( SCESTATUS_NOT_ENOUGH_RESOURCE );
}
memset(*ppInfoBuffer, '\0', Len);
bBufAlloc = TRUE;
(*ppInfoBuffer)->Type = ( ProfileType==SCE_ENGINE_GPO) ? SCE_ENGINE_SCP : ProfileType;
}
/*
// Design changed. Checking is moved above creating the buffer.
if ( ProfileType == SCE_ENGINE_SAP &&
hProfile->JetSapID == JET_tableidNil) {
//
// if no SAP table is there, which means configuration is done
// but analysis is not done, we treat it as everything is fine
// reset the buffer to SCE_NO_VALUE
//
ScepResetSecurityPolicyArea(*ppInfoBuffer);
// return(SCESTATUS_PROFILE_NOT_FOUND);
return(SCESTATUS_SUCCESS);
}
*/
//
// Free related memory and reset the buffer before parsing
// there is a problem here for now. it clears the handle and
// filename too. So comment it out.
SceFreeMemory( (PVOID)(*ppInfoBuffer), (DWORD)Area );
//
// system access
//
if ( Area & AREA_SECURITY_POLICY ) {
rc = ScepGetSystemAccess(
hProfile,
ProfileType,
*ppInfoBuffer,
Errlog
);
if( rc != SCESTATUS_SUCCESS )
goto Done;
//
// system auditing
//
rc = ScepGetAuditing(hProfile,
ProfileType,
*ppInfoBuffer,
Errlog
);
if( rc != SCESTATUS_SUCCESS )
goto Done;
#if _WIN32_WINNT>=0x0500
if ( RtlGetNtProductType(&theType) ) {
if ( theType == NtProductLanManNt ) {
rc = ScepGetKerberosPolicy(
hProfile,
ProfileType,
&((*ppInfoBuffer)->pKerberosInfo),
Errlog
);
if ( rc != SCESTATUS_SUCCESS )
goto Done;
}
}
#endif
//
// registry values
//
rc = ScepGetRegistryValues(
hProfile,
ProfileType,
&((*ppInfoBuffer)->aRegValues),
&((*ppInfoBuffer)->RegValueCount),
Errlog
);
if ( rc != SCESTATUS_SUCCESS )
goto Done;
}
//
// privilege/rights
//
if ( Area & AREA_PRIVILEGES ) {
//
// SCP/SMP/SAP privilegeAssignedTo are all in the same address in the
// SCE_PROFILE_INFO structure.
//
rc = ScepGetPrivileges(
hProfile,
ProfileType,
dwAccountFormat,
(PVOID *)&( (*ppInfoBuffer)->OtherInfo.scp.u.pPrivilegeAssignedTo ),
Errlog
);
if( rc != SCESTATUS_SUCCESS )
goto Done;
}
//
// group memberships
//
if ( (Area & AREA_GROUP_MEMBERSHIP) &&
(ProfileType != SCE_ENGINE_GPO) ) {
rc = ScepGetGroupMembership(
hProfile,
ProfileType,
&((*ppInfoBuffer)->pGroupMembership),
Errlog
);
if( rc != SCESTATUS_SUCCESS )
goto Done;
}
//
// registry keys security
//
if ( (Area & AREA_REGISTRY_SECURITY) &&
(ProfileType != SCE_ENGINE_GPO) ) {
rc = ScepGetObjectList(
hProfile,
ProfileType,
szRegistryKeys,
&((*ppInfoBuffer)->pRegistryKeys.pOneLevel),
Errlog
);
if ( rc != SCESTATUS_SUCCESS )
goto Done;
}
//
// file security
//
if ( (Area & AREA_FILE_SECURITY) &&
(ProfileType != SCE_ENGINE_GPO) ) {
rc = ScepGetObjectList(
hProfile,
ProfileType,
szFileSecurity,
&((*ppInfoBuffer)->pFiles.pOneLevel),
Errlog
);
if ( rc != SCESTATUS_SUCCESS )
goto Done;
}
//
// DS object security
//
#if 0
#if _WIN32_WINNT>=0x0500
if ( (Area & AREA_DS_OBJECTS) &&
(ProfileType != SCE_ENGINE_GPO) &&
RtlGetNtProductType(&theType) ) {
if ( theType == NtProductLanManNt ) {
rc = ScepGetDsRoot(
hProfile,
ProfileType,
szDSSecurity,
&((*ppInfoBuffer)->pDsObjects.pOneLevel),
Errlog
);
if ( rc != SCESTATUS_SUCCESS )
goto Done;
}
}
#endif
#endif
if ( (Area & AREA_SYSTEM_SERVICE) &&
(ProfileType != SCE_ENGINE_GPO) ) {
rc = ScepGetSystemServices(
hProfile,
ProfileType,
&((*ppInfoBuffer)->pServices),
Errlog
);
if ( rc != SCESTATUS_SUCCESS )
goto Done;
}
Done:
if ( rc != SCESTATUS_SUCCESS ) {
//
// need free memory because some fatal error happened
//
if ( bBufAlloc ) {
SceFreeProfileMemory(*ppInfoBuffer);
*ppInfoBuffer = NULL;
} else
SceFreeMemory( (PVOID)(*ppInfoBuffer), (DWORD)Area );
}
return(rc);
}
SCESTATUS
ScepGetSystemAccess(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
OUT PSCE_PROFILE_INFO pProfileInfo,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
)
/*++
Routine Description:
This routine retrieves system access area information from the Jet database
and stores in the output buffer pProfileInfo. System access information
includes information in [System Access] sections.
Arguments:
hProfile - The profile handle context
pProfileinfo - the output buffer to hold profile info (SCP or SAP).
Errlog - A buffer to hold all error codes/text encountered when
parsing the INF file. If Errlog is NULL, no further error
information is returned except the return DWORD
Return value:
SCESTATUS - SCESTATUS_SUCCESS
SCESTATUS_NOT_ENOUGH_RESOURCE
SCESTATUS_INVALID_PARAMETER
SCESTATUS_BAD_FORMAT
SCESTATUS_INVALID_DATA
--*/
{
SCESTATUS rc;
PSCESECTION hSection=NULL;
SCE_KEY_LOOKUP AccessKeys[] = {
{(PWSTR)TEXT("MinimumPasswordAge"), offsetof(struct _SCE_PROFILE_INFO, MinimumPasswordAge), 'D'},
{(PWSTR)TEXT("MaximumPasswordAge"), offsetof(struct _SCE_PROFILE_INFO, MaximumPasswordAge), 'D'},
{(PWSTR)TEXT("MinimumPasswordLength"), offsetof(struct _SCE_PROFILE_INFO, MinimumPasswordLength), 'D'},
{(PWSTR)TEXT("PasswordComplexity"), offsetof(struct _SCE_PROFILE_INFO, PasswordComplexity), 'D'},
{(PWSTR)TEXT("PasswordHistorySize"), offsetof(struct _SCE_PROFILE_INFO, PasswordHistorySize), 'D'},
{(PWSTR)TEXT("LockoutBadCount"), offsetof(struct _SCE_PROFILE_INFO, LockoutBadCount), 'D'},
{(PWSTR)TEXT("ResetLockoutCount"), offsetof(struct _SCE_PROFILE_INFO, ResetLockoutCount), 'D'},
{(PWSTR)TEXT("LockoutDuration"), offsetof(struct _SCE_PROFILE_INFO, LockoutDuration), 'D'},
{(PWSTR)TEXT("RequireLogonToChangePassword"),offsetof(struct _SCE_PROFILE_INFO, RequireLogonToChangePassword),'D'},
{(PWSTR)TEXT("ForceLogoffWhenHourExpire"),offsetof(struct _SCE_PROFILE_INFO, ForceLogoffWhenHourExpire),'D'},
{(PWSTR)TEXT("ClearTextPassword"), offsetof(struct _SCE_PROFILE_INFO, ClearTextPassword), 'D'},
{(PWSTR)TEXT("LSAAnonymousNameLookup"), offsetof(struct _SCE_PROFILE_INFO, LSAAnonymousNameLookup), 'D'},
{(PWSTR)TEXT("EnableAdminAccount"), offsetof(struct _SCE_PROFILE_INFO, EnableAdminAccount), 'D'},
{(PWSTR)TEXT("EnableGuestAccount"), offsetof(struct _SCE_PROFILE_INFO, EnableGuestAccount), 'D'}
};
DWORD cKeys = sizeof(AccessKeys) / sizeof(SCE_KEY_LOOKUP);
DWORD DataSize=0;
PWSTR Strvalue=NULL;
DWORD SDsize=0;
PSECURITY_DESCRIPTOR pTempSD=NULL;
if ( pProfileInfo == NULL ) {
return(SCESTATUS_INVALID_PARAMETER);
}
rc = ScepGetFixValueSection(
hProfile,
szSystemAccess,
AccessKeys,
cKeys,
ProfileType,
(PVOID)pProfileInfo,
&hSection,
Errlog
);
if ( rc != SCESTATUS_SUCCESS )
return(rc);
//
// get new administrator for SCP and SMP types
//
rc = ScepGetVariableValue(
hSection,
ProfileType,
L"NewAdministratorName",
&Strvalue,
&DataSize
);
if ( rc != SCESTATUS_RECORD_NOT_FOUND &&
rc != SCESTATUS_SUCCESS ) {
ScepBuildErrorLogInfo( ERROR_READ_FAULT,
Errlog, SCEERR_QUERY_VALUE,
L"NewAdministratorName"
);
goto Done;
}
rc = SCESTATUS_SUCCESS;
if ( Strvalue ) {
if ( Strvalue[0] != L'\0') {
pProfileInfo->NewAdministratorName = Strvalue;
} else {
pProfileInfo->NewAdministratorName = NULL;
ScepFree(Strvalue);
}
Strvalue = NULL;
}
//
// NewGuestName
//
rc = ScepGetVariableValue(
hSection,
ProfileType,
L"NewGuestName",
&Strvalue,
&DataSize
);
if ( rc != SCESTATUS_RECORD_NOT_FOUND &&
rc != SCESTATUS_SUCCESS ) {
ScepBuildErrorLogInfo( ERROR_READ_FAULT,
Errlog, SCEERR_QUERY_VALUE,
L"NewGuestName"
);
goto Done;
}
rc = SCESTATUS_SUCCESS;
if ( Strvalue ) {
if ( Strvalue[0] != L'\0') {
pProfileInfo->NewGuestName = Strvalue;
} else {
pProfileInfo->NewGuestName = NULL;
ScepFree(Strvalue);
}
Strvalue = NULL;
}
Done:
SceJetCloseSection(&hSection, TRUE);
if ( pTempSD != NULL )
ScepFree(pTempSD);
if ( Strvalue != NULL )
ScepFree( Strvalue );
return(rc);
}
SCESTATUS
ScepGetFixValueSection(
IN PSCECONTEXT hProfile,
IN PCWSTR SectionName,
IN SCE_KEY_LOOKUP *Keys,
IN DWORD cKeys,
IN SCETYPE ProfileType,
OUT PVOID pInfo,
OUT PSCESECTION *phSection,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
)
/* ++
-- */
{
SCESTATUS rc;
DWORD i;
TCHAR Value[25];
DWORD RetValueLen;
LONG Keyvalue;
rc = ScepOpenSectionForName(
hProfile,
(ProfileType==SCE_ENGINE_GPO)? SCE_ENGINE_SCP : ProfileType,
SectionName,
phSection
);
if ( SCESTATUS_SUCCESS != rc ) {
ScepBuildErrorLogInfo( ERROR_INVALID_DATA,
Errlog, SCEERR_OPEN,
SectionName
);
return(rc);
}
JET_COLUMNID ColGpoID = 0;
JET_ERR JetErr;
LONG GpoID=0;
DWORD Actual;
if ( ProfileType == SCE_ENGINE_GPO ) {
JET_COLUMNDEF ColumnGpoIDDef;
JetErr = JetGetTableColumnInfo(
(*phSection)->JetSessionID,
(*phSection)->JetTableID,
"GpoID",
(VOID *)&ColumnGpoIDDef,
sizeof(JET_COLUMNDEF),
JET_ColInfo
);
if ( JET_errSuccess == JetErr ) {
ColGpoID = ColumnGpoIDDef.columnid;
}
}
//
// get each key in the access array
//
for ( i=0; i<cKeys; i++ ) {
memset(Value, '\0', 50);
RetValueLen = 0;
rc = SceJetGetValue(
*phSection,
SCEJET_EXACT_MATCH_NO_CASE,
(PWSTR)(Keys[i].KeyString),
NULL,
0,
NULL,
Value,
48,
&RetValueLen
);
if ( RetValueLen > 0 )
Value[RetValueLen/2] = L'\0';
if ( rc == SCESTATUS_SUCCESS ) {
GpoID = 1;
if ( ProfileType == SCE_ENGINE_GPO ) {
//
// query if the setting comes from a GPO
// get GPO ID field from the current line
//
GpoID = 0;
if ( ColGpoID > 0 ) {
JetErr = JetRetrieveColumn(
(*phSection)->JetSessionID,
(*phSection)->JetTableID,
ColGpoID,
(void *)&GpoID,
4,
&Actual,
0,
NULL
);
}
}
if ( GpoID > 0 && RetValueLen > 0 && Value[0] != L'\0' )
Keyvalue = _wtol(Value);
else
Keyvalue = SCE_NO_VALUE;
} else if ( rc == SCESTATUS_RECORD_NOT_FOUND ) {
rc = SCESTATUS_SUCCESS; // it is OK not find a record
Keyvalue = SCE_NO_VALUE;
} else {
ScepBuildErrorLogInfo( ERROR_READ_FAULT,
Errlog,
SCEERR_QUERY_VALUE,
Keys[i].KeyString
);
goto Done;
}
#ifdef SCE_DBG
printf("Get info %s (%d) for ", Value, Keyvalue);
wprintf(L"%s. rc=%d, Return Length=%d\n",
Keys[i].KeyString, rc, RetValueLen);
#endif
switch (Keys[i].BufferType ) {
case 'B':
*((BOOL *)((CHAR *)pInfo+Keys[i].Offset)) = (Keyvalue == 1) ? TRUE : FALSE;
break;
case 'D':
*((DWORD *)((CHAR *)pInfo+Keys[i].Offset)) = Keyvalue;
break;
default:
rc = SCESTATUS_INVALID_DATA;
ScepBuildErrorLogInfo( ERROR_INVALID_DATA,
Errlog,
SCEERR_CANT_FIND_DATATYPE,
Keys[i].KeyString
);
goto Done;
}
}
Done:
//
// close the section
//
if ( rc != SCESTATUS_SUCCESS ) {
SceJetCloseSection(phSection, TRUE);
}
return(rc);
}
SCESTATUS
ScepGetVariableValue(
IN PSCESECTION hSection,
IN SCETYPE ProfileType,
IN PCWSTR KeyName,
OUT PWSTR *Value,
OUT PDWORD ValueLen
)
/* ++
-- */
{
SCESTATUS rc;
rc = SceJetGetValue(
hSection,
SCEJET_EXACT_MATCH_NO_CASE,
(PWSTR)KeyName,
NULL,
0,
NULL,
NULL,
0,
ValueLen
);
if ( rc == SCESTATUS_SUCCESS && *ValueLen > 0 ) {
LONG GpoID=1;
if ( ProfileType == SCE_ENGINE_GPO ) {
JET_COLUMNDEF ColumnGpoIDDef;
JET_COLUMNID ColGpoID = 0;
JET_ERR JetErr;
DWORD Actual;
JetErr = JetGetTableColumnInfo(
hSection->JetSessionID,
hSection->JetTableID,
"GpoID",
(VOID *)&ColumnGpoIDDef,
sizeof(JET_COLUMNDEF),
JET_ColInfo
);
GpoID = 0;
if ( JET_errSuccess == JetErr ) {
ColGpoID = ColumnGpoIDDef.columnid;
//
// query if the setting comes from a GPO
// get GPO ID field from the current line
//
JetErr = JetRetrieveColumn(
hSection->JetSessionID,
hSection->JetTableID,
ColGpoID,
(void *)&GpoID,
4,
&Actual,
0,
NULL
);
}
}
if ( GpoID > 0 ) {
//
// if DataSize = 0 then the security descriptor is NULL also
//
*Value = (PWSTR)ScepAlloc( LMEM_ZEROINIT, *ValueLen+2);
if( *Value == NULL ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
} else {
rc = SceJetGetValue(
hSection,
SCEJET_CURRENT,
(PWSTR)KeyName,
NULL,
0,
NULL,
*Value,
*ValueLen,
ValueLen
);
}
} else {
rc = SCESTATUS_RECORD_NOT_FOUND;
}
}
return(rc);
}
SCESTATUS
ScepGetPrivileges(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN DWORD dwAccountFormat,
OUT PVOID *pPrivileges,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
)
{
SCESTATUS rc;
LSA_HANDLE LsaHandle=NULL;
rc = RtlNtStatusToDosError(
ScepOpenLsaPolicy(
MAXIMUM_ALLOWED,
&LsaHandle,
TRUE
));
if ( ERROR_SUCCESS != rc ) {
ScepBuildErrorLogInfo(
rc,
Errlog,
SCEDLL_LSA_POLICY
);
return(ScepDosErrorToSceStatus(rc));
}
PSCE_PRIVILEGE_ASSIGNMENT pTempList=NULL, pNode, pPriv, pParent, pTemp;
rc = ScepGetPrivilegesFromOneTable(
LsaHandle,
hProfile,
ProfileType,
dwAccountFormat,
pPrivileges,
Errlog
);
if ( SCESTATUS_SUCCESS == rc && SCE_ENGINE_SAP == ProfileType ) {
//
// get the remaining stuff from SMP
//
rc = ScepGetPrivilegesFromOneTable(
LsaHandle,
hProfile,
SCE_ENGINE_SCP, // SCE_ENGINE_SMP,
dwAccountFormat,
(PVOID *)&pTempList,
Errlog
);
if ( rc == SCESTATUS_SUCCESS ) {
//
// add non-exist nodes to pPrivileges
//
pNode=pTempList;
pParent=NULL;
while ( pNode ) {
//
// if this node does not exist in the SAP
// this node is analyzed with "match" status
// if it already exists in SAP, it is a "mismatched" item
// duplication is prevented by the last argument TRUE
//
for ( pPriv=(PSCE_PRIVILEGE_ASSIGNMENT)(*pPrivileges);
pPriv != NULL; pPriv=pPriv->Next ) {
if ( pPriv->Status & SCE_INTERNAL_NP &&
_wcsicmp( pPriv->Name, pNode->Name) == 0 )
break;
}
if ( pPriv ) {
//
// find the entry in SAP, mismatched item
//
if ( pPriv->Status & SCE_STATUS_ERROR_NOT_AVAILABLE ) {
pPriv->Status = SCE_STATUS_ERROR_NOT_AVAILABLE;
} else {
pPriv->Status = SCE_STATUS_MISMATCH;
}
pParent = pNode;
pNode = pNode->Next;
} else {
//
// does not exist in SAP.
// just move this node to SAP, with status SCE_STATUS_GOOD
//
if ( pParent )
pParent->Next = pNode->Next;
else
pTempList = pNode->Next;
pTemp = pNode;
pNode=pNode->Next;
pTemp->Next = (PSCE_PRIVILEGE_ASSIGNMENT)(*pPrivileges);
*((PSCE_PRIVILEGE_ASSIGNMENT *)pPrivileges) = pTemp;
}
}
//
// priv exist in analysis but not in template
//
for ( pPriv=(PSCE_PRIVILEGE_ASSIGNMENT)(*pPrivileges);
pPriv != NULL; pPriv=pPriv->Next ) {
if ( pPriv->Status & SCE_INTERNAL_NP )
pPriv->Status = SCE_STATUS_NOT_CONFIGURED;
}
} else if ( rc == SCESTATUS_RECORD_NOT_FOUND ) {
rc = SCESTATUS_SUCCESS;
} else {
//
// pPrivileges will be freed outside
//
}
if ( pTempList )
ScepFreePrivilege(pTempList);
}
if ( LsaHandle ) {
LsaClose(LsaHandle);
}
return(rc);
}
SCESTATUS
ScepGetPrivilegesFromOneTable(
IN LSA_HANDLE LsaPolicy,
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN DWORD dwAccountFormat,
OUT PVOID *pPrivileges,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
)
/* ++
Routine Description:
Arguments:
Return Value:
-- */
{
SCESTATUS rc;
PSCESECTION hSection=NULL;
WCHAR KeyName[36];
PWSTR Value=NULL;
PSCE_PRIVILEGE_ASSIGNMENT pPrivilegeAssigned=NULL;
PSCE_PRIVILEGE_VALUE_LIST pPrivilegeList=NULL;
DWORD KeyLen=0;
DWORD ValueLen;
DWORD Len;
PWSTR pTemp;
DWORD PrivValue;
if ( pPrivileges == NULL )
return(SCESTATUS_INVALID_PARAMETER);
rc = ScepOpenSectionForName(
hProfile,
(ProfileType==SCE_ENGINE_GPO)? SCE_ENGINE_SCP : ProfileType,
szPrivilegeRights,
&hSection
);
if ( rc != SCESTATUS_SUCCESS ) {
ScepBuildErrorLogInfo( ERROR_INVALID_DATA,
Errlog, SCEERR_OPEN,
szPrivilegeRights
);
return(rc);
}
JET_COLUMNID ColGpoID = 0;
JET_ERR JetErr;
LONG GpoID;
if ( ProfileType == SCE_ENGINE_GPO ) {
JET_COLUMNDEF ColumnGpoIDDef;
JetErr = JetGetTableColumnInfo(
hSection->JetSessionID,
hSection->JetTableID,
"GpoID",
(VOID *)&ColumnGpoIDDef,
sizeof(JET_COLUMNDEF),
JET_ColInfo
);
if ( JET_errSuccess == JetErr ) {
ColGpoID = ColumnGpoIDDef.columnid;
}
}
//
// goto the first line of this section
//
// memset(KeyName, '\0', 72); KeyName will be manually terminated later
rc = SceJetGetValue(
hSection,
SCEJET_PREFIX_MATCH,
NULL,
KeyName,
70,
&KeyLen,
NULL,
0,
&ValueLen
);
while ( rc == SCESTATUS_SUCCESS ||
rc == SCESTATUS_BUFFER_TOO_SMALL ) {
//
// terminate the string
//
KeyName[KeyLen/2] = L'\0';
//
// lookup privilege's value
// ignore unknown privileges
//
if ( ( PrivValue = ScepLookupPrivByName(KeyName) ) == -1 ) {
ScepBuildErrorLogInfo( ERROR_INVALID_DATA,
Errlog,
SCEERR_INVALID_PRIVILEGE,
KeyName
);
rc = SceJetGetValue(
hSection,
SCEJET_NEXT_LINE,
NULL,
KeyName,
70,
&KeyLen,
NULL,
0,
&ValueLen
);
continue;
// rc = SCESTATUS_INVALID_DATA;
// goto Done;
}
GpoID = 1;
if ( ProfileType == SCE_ENGINE_GPO ) {
GpoID = 0;
if ( ColGpoID > 0 ) {
DWORD Actual;
JetErr = JetRetrieveColumn(
hSection->JetSessionID,
hSection->JetTableID,
ColGpoID,
(void *)&GpoID,
4,
&Actual,
0,
NULL
);
}
}
if ( ProfileType == SCE_ENGINE_GPO &&
GpoID <= 0 ) {
//
// not domain GPO settings
//
rc = SceJetGetValue(
hSection,
SCEJET_NEXT_LINE,
NULL,
KeyName,
70,
&KeyLen,
NULL,
0,
&ValueLen
);
continue;
}
//
// allocate memory for the group name and value string
//
Value = (PWSTR)ScepAlloc( LMEM_ZEROINIT, ValueLen+2);
if ( Value == NULL ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
goto Done;
}
//
// Get the group and its value
//
rc = SceJetGetValue(
hSection,
SCEJET_CURRENT,
NULL,
NULL,
0,
NULL,
Value,
ValueLen,
&ValueLen
);
if ( rc != SCESTATUS_SUCCESS )
goto Done;
//
// create a node for this privilege
//
if ( ProfileType == SCE_ENGINE_SAP ||
ProfileType == SCE_ENGINE_SMP ||
ProfileType == SCE_ENGINE_GPO ||
ProfileType == SCE_ENGINE_SCP ) {
//
// a sce_privilege_assignment structure. allocate buffer
//
pPrivilegeAssigned = (PSCE_PRIVILEGE_ASSIGNMENT)ScepAlloc( LMEM_ZEROINIT,
sizeof(SCE_PRIVILEGE_ASSIGNMENT) );
if ( pPrivilegeAssigned == NULL ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
goto Done;
}
pPrivilegeAssigned->Name = (PWSTR)ScepAlloc( (UINT)0, (wcslen(KeyName)+1)*sizeof(WCHAR));
if ( pPrivilegeAssigned->Name == NULL ) {
ScepFree(pPrivilegeAssigned);
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
goto Done;
}
wcscpy(pPrivilegeAssigned->Name, KeyName);
pPrivilegeAssigned->Value = PrivValue;
if ( SCE_ENGINE_SAP == ProfileType )
pPrivilegeAssigned->Status = SCE_INTERNAL_NP;
else
pPrivilegeAssigned->Status = SCE_STATUS_GOOD;
}
//
// add the multi-sz value string to the node, depending on the value type
//
PSID pSid=NULL;
BOOL bBufferUsed;
pTemp = Value;
if (pTemp != NULL && pTemp[0] == L'\0' && ValueLen > 1) {
pTemp ++;
}
while ( rc == SCESTATUS_SUCCESS && pTemp != NULL && pTemp[0]) {
Len = wcslen(pTemp);
if ( (ProfileType == SCE_ENGINE_SAP) &&
(_wcsicmp( SCE_ERROR_STRING, pTemp) == 0) ) {
//
// this is an errored item
//
pPrivilegeAssigned->Status |= SCE_STATUS_ERROR_NOT_AVAILABLE;
break;
}
//
// convert pTemp (may be a name, or *SID format) to the right
// format (SID_STRING, Name, or ACCOUNT_SID)
//
switch ( dwAccountFormat ) {
case SCE_ACCOUNT_SID:
if ( pTemp[0] == L'*' ) {
//
// this is the *SID format, convert to SID
//
if ( !ConvertStringSidToSid( pTemp+1, &pSid) ) {
//
// if failed to convert from sid string to sid,
// treat it as any name
//
rc = GetLastError();
}
} else {
//
// lookup name for a sid
//
rc = RtlNtStatusToDosError(
ScepConvertNameToSid(
LsaPolicy,
pTemp,
&pSid
));
}
if ( ERROR_SUCCESS == rc && pSid ) {
if ( ProfileType == SCE_ENGINE_SAP ||
ProfileType == SCE_ENGINE_SMP ||
ProfileType == SCE_ENGINE_GPO ||
ProfileType == SCE_ENGINE_SCP ) {
rc = ScepAddSidToNameList(
&(pPrivilegeAssigned->AssignedTo),
pSid,
TRUE, // reuse the buffer
&bBufferUsed
);
} else {
//
// add to privilege list (as Sid)
//
rc = ScepAddSidToPrivilegeList(
&pPrivilegeList,
pSid,
TRUE, // reuse the buffer
PrivValue,
&bBufferUsed
);
}
if ( rc == ERROR_SUCCESS && bBufferUsed ) {
pSid = NULL;
}
rc = ScepDosErrorToSceStatus(rc);
} else {
//
// add as name format
//
if ( ProfileType == SCE_ENGINE_SAP ||
ProfileType == SCE_ENGINE_SMP ||
ProfileType == SCE_ENGINE_GPO ||
ProfileType == SCE_ENGINE_SCP ) {
rc = ScepAddToNameList(&(pPrivilegeAssigned->AssignedTo), pTemp, Len );
rc = ScepDosErrorToSceStatus(rc);
} else {
//
// pPrivilegeList is a privilege_value list for each user/group.
// the LowValue and HighValue fields are combination of all privileges assigned to the user
//
rc = ScepAddToPrivilegeList(&pPrivilegeList, pTemp, Len, PrivValue);
}
}
if ( pSid ) {
LocalFree(pSid);
pSid = NULL;
}
break;
default:
if ( (dwAccountFormat != SCE_ACCOUNT_SID_STRING) &&
(pTemp[0] == L'*') ) {
//
// this is a *SID format, must be converted into Domain\Account format
//
if ( ProfileType == SCE_ENGINE_SAP ||
ProfileType == SCE_ENGINE_SMP ||
ProfileType == SCE_ENGINE_GPO ||
ProfileType == SCE_ENGINE_SCP ) {
rc = ScepLookupSidStringAndAddToNameList(
LsaPolicy,
&(pPrivilegeAssigned->AssignedTo),
pTemp, // +1,
Len // -1
);
} else {
//
// add to privilege value list
//
PWSTR strName=NULL;
DWORD strLen=0;
if ( ConvertStringSidToSid( pTemp+1, &pSid) ) {
rc = RtlNtStatusToDosError(
ScepConvertSidToName(
LsaPolicy,
pSid,
TRUE, // want domain\account format
&strName,
&strLen
));
LocalFree(pSid);
pSid = NULL;
} else {
rc = GetLastError();
}
if ( rc == ERROR_SUCCESS ) {
//
// add the name to the privilege list
//
rc = ScepAddToPrivilegeList(&pPrivilegeList, strName, strLen, PrivValue);
} else {
//
// if couldn't lookup for the name, add *SID to the list
//
rc = ScepAddToPrivilegeList(&pPrivilegeList, pTemp, Len, PrivValue);
}
if ( strName ) {
ScepFree(strName);
strName = NULL;
}
}
} else {
if ( ProfileType == SCE_ENGINE_SAP ||
ProfileType == SCE_ENGINE_SMP ||
ProfileType == SCE_ENGINE_GPO ||
ProfileType == SCE_ENGINE_SCP ) {
rc = ScepDosErrorToSceStatus(
ScepAddToNameList(&(pPrivilegeAssigned->AssignedTo),
pTemp,
Len ));
} else {
//
// pPrivilegeList is a privilege_value list for each user/group.
// the LowValue and HighValue fields are combination of all privileges assigned to the user
//
rc = ScepAddToPrivilegeList(&pPrivilegeList, pTemp, Len, PrivValue);
#ifdef SCE_DBG
wprintf(L"\tAdd Priv %d for %s (%d bytes)\n", PrivValue, pTemp, Len);
#endif
}
}
break;
}
pTemp += Len +1;
if ( rc != SCESTATUS_SUCCESS ) {
ScepBuildErrorLogInfo( ERROR_WRITE_FAULT,
Errlog,
SCEERR_ADD,
KeyName
);
}
}
//
// Free memory
//
if ( rc != SCESTATUS_SUCCESS ) {
if ( pPrivilegeAssigned != NULL )
ScepFreePrivilege(pPrivilegeAssigned);
if ( pPrivilegeList != NULL )
ScepFreePrivilegeValueList(pPrivilegeList);
goto Done;
}
//
// link this to the PSCE_PRIVILEGE_ASSIGNMENT list in pPrivileges
//
if ( ProfileType == SCE_ENGINE_SAP ||
ProfileType == SCE_ENGINE_SMP ||
ProfileType == SCE_ENGINE_GPO ||
ProfileType == SCE_ENGINE_SCP ) {
pPrivilegeAssigned->Next = *((PSCE_PRIVILEGE_ASSIGNMENT *)pPrivileges);
*((PSCE_PRIVILEGE_ASSIGNMENT *)pPrivileges) = pPrivilegeAssigned;
pPrivilegeAssigned = NULL;
}
ScepFree(Value);
Value = NULL;
//
// read next line
//
// memset(KeyName, '\0', 72); KeyName will be manually terminated
rc = SceJetGetValue(
hSection,
SCEJET_NEXT_LINE,
NULL,
KeyName,
70,
&KeyLen,
NULL,
0,
&ValueLen
);
}
if ( rc == SCESTATUS_RECORD_NOT_FOUND )
rc = SCESTATUS_SUCCESS;
if ( rc == SCESTATUS_SUCCESS ) {
if ( ProfileType == SCE_ENGINE_SCP_INTERNAL ||
ProfileType == SCE_ENGINE_SMP_INTERNAL )
*((PSCE_PRIVILEGE_VALUE_LIST *)pPrivileges) = pPrivilegeList;
}
Done:
//
// close the find index range
//
SceJetGetValue(
hSection,
SCEJET_CLOSE_VALUE,
NULL,
NULL,
0,
NULL,
NULL,
0,
NULL
);
if ( Value != NULL )
ScepFree(Value);
//
// close the section
//
SceJetCloseSection( &hSection, TRUE );
return(rc);
}
SCESTATUS
ScepAddToPrivilegeList(
OUT PSCE_PRIVILEGE_VALUE_LIST *pPrivilegeList,
IN PWSTR Name,
IN DWORD Len,
IN DWORD PrivValue
)
{
PSCE_PRIVILEGE_VALUE_LIST pPriv,
LastOne=NULL;
if ( pPrivilegeList == NULL || Name == NULL || Len == 0 )
return(SCESTATUS_INVALID_PARAMETER);
for ( pPriv = *pPrivilegeList;
pPriv != NULL;
LastOne=pPriv, pPriv = pPriv->Next ) {
if ( ( wcslen(pPriv->Name) == Len ) &&
( _wcsnicmp( pPriv->Name, Name, Len ) == 0 ) ) {
if ( PrivValue < 32 ) {
pPriv->PrivLowPart |= (1 << PrivValue);
} else {
pPriv->PrivHighPart |= (1 << (PrivValue-32) );
}
break;
}
}
if ( pPriv == NULL ) {
//
// Create a new one
//
pPriv = (PSCE_PRIVILEGE_VALUE_LIST)ScepAlloc( LMEM_ZEROINIT,
sizeof(SCE_PRIVILEGE_VALUE_LIST));
if ( pPriv == NULL )
return(SCESTATUS_NOT_ENOUGH_RESOURCE);
pPriv->Name = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (Len+1)*sizeof(WCHAR));
if ( pPriv->Name == NULL ) {
ScepFree(pPriv);
return(SCESTATUS_NOT_ENOUGH_RESOURCE);
}
wcsncpy(pPriv->Name, Name, Len);
if ( PrivValue < 32 ) {
pPriv->PrivLowPart |= (1 << PrivValue);
} else {
pPriv->PrivHighPart |= (1 << (PrivValue-32) );
}
//
// link to the list
//
if ( LastOne != NULL )
LastOne->Next = pPriv;
else
*pPrivilegeList = pPriv;
}
return(SCESTATUS_SUCCESS);
}
SCESTATUS
ScepAddSidToPrivilegeList(
OUT PSCE_PRIVILEGE_VALUE_LIST *pPrivilegeList,
IN PSID pSid,
IN BOOL bReuseBuffer,
IN DWORD PrivValue,
OUT BOOL *pbBufferUsed
)
{
if ( pPrivilegeList == NULL || pbBufferUsed == NULL )
return(SCESTATUS_INVALID_PARAMETER);
*pbBufferUsed = FALSE;
if ( pSid == NULL ) {
return(SCESTATUS_SUCCESS);
}
if ( !ScepValidSid(pSid) ) {
return(SCESTATUS_INVALID_PARAMETER);
}
PSCE_PRIVILEGE_VALUE_LIST pPriv,
LastOne=NULL;
//
// check if the sid is already in the list
//
for ( pPriv = *pPrivilegeList;
pPriv != NULL;
LastOne=pPriv, pPriv = pPriv->Next ) {
if ( pPriv->Name == NULL ) {
continue;
}
if ( ScepValidSid( (PSID)(pPriv->Name) ) &&
RtlEqualSid( (PSID)(pPriv->Name), pSid ) ) {
if ( PrivValue < 32 ) {
pPriv->PrivLowPart |= (1 << PrivValue);
} else {
pPriv->PrivHighPart |= (1 << (PrivValue-32) );
}
break;
}
}
if ( pPriv == NULL ) {
//
// Create a new one
//
pPriv = (PSCE_PRIVILEGE_VALUE_LIST)ScepAlloc( LMEM_ZEROINIT,
sizeof(SCE_PRIVILEGE_VALUE_LIST));
if ( pPriv == NULL )
return(SCESTATUS_NOT_ENOUGH_RESOURCE);
if ( bReuseBuffer ) {
pPriv->Name = (PWSTR)pSid;
*pbBufferUsed = TRUE;
} else {
DWORD Length = RtlLengthSid ( pSid );
pPriv->Name = (PWSTR)ScepAlloc( LMEM_ZEROINIT, Length);
if ( pPriv->Name == NULL ) {
ScepFree(pPriv);
return(SCESTATUS_NOT_ENOUGH_RESOURCE);
}
RtlCopySid( Length, (PSID)(pPriv->Name), pSid );
}
if ( PrivValue < 32 ) {
pPriv->PrivLowPart |= (1 << PrivValue);
} else {
pPriv->PrivHighPart |= (1 << (PrivValue-32) );
}
//
// link to the list
//
if ( LastOne != NULL )
LastOne->Next = pPriv;
else
*pPrivilegeList = pPriv;
}
return(SCESTATUS_SUCCESS);
}
SCESTATUS
ScepGetGroupMembership(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
OUT PSCE_GROUP_MEMBERSHIP *pGroupMembership,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
)
{
SCESTATUS rc;
DWORD OneStatus;
PSCE_GROUP_MEMBERSHIP pTempList=NULL, pNode, pGroup2,
pParent, pTemp;
LSA_HANDLE LsaHandle=NULL;
rc = RtlNtStatusToDosError(
ScepOpenLsaPolicy(
MAXIMUM_ALLOWED,
&LsaHandle,
TRUE
));
if ( ERROR_SUCCESS != rc ) {
ScepBuildErrorLogInfo(
rc,
Errlog,
SCEDLL_LSA_POLICY
);
return(ScepDosErrorToSceStatus(rc));
}
//
// get groups from the requested table first
//
rc = ScepGetGroupMembershipFromOneTable(
LsaHandle,
hProfile,
ProfileType,
pGroupMembership,
Errlog
);
//
// return all groups if it is requested for SAP entry
//
if ( SCESTATUS_SUCCESS == rc && SCE_ENGINE_SAP == ProfileType ) {
//
// get the remaining stuff from SMP
//
rc = ScepGetGroupMembershipFromOneTable(
LsaHandle,
hProfile,
SCE_ENGINE_SCP, //SCE_ENGINE_SMP,
&pTempList,
Errlog
);
if ( rc == SCESTATUS_SUCCESS ) {
//
// add non-exist nodes to pObjectRoots
//
pNode=pTempList;
pParent=NULL;
while ( pNode ) {
//
// if this node does not exist in the SAP
// this node is analyzed with "match" status
// if it already exists in SAP, it is a "mismatched" item
// duplication is prevented by the last argument TRUE
//
for ( pGroup2=*pGroupMembership; pGroup2 != NULL; pGroup2=pGroup2->Next ) {
if ( (pGroup2->Status & SCE_INTERNAL_NP) &&
_wcsicmp( pGroup2->GroupName, pNode->GroupName) == 0 )
break;
}
if ( pGroup2 ) {
//
// find the entry in SAP, mismatched item
// maybe pMembers, or pMemberOf
// or not analyzed item, or error items
//
OneStatus = pGroup2->Status;
pGroup2->Status = 0;
if ( (OneStatus & SCE_GROUP_STATUS_NOT_ANALYZED) ) {
// this item is added after last inspection
pGroup2->Status = SCE_GROUP_STATUS_NOT_ANALYZED;
} else if ( (OneStatus & SCE_GROUP_STATUS_ERROR_ANALYZED) ) {
// this item errored when analyzing
pGroup2->Status = SCE_GROUP_STATUS_ERROR_ANALYZED;
} else {
if ( pNode->Status & SCE_GROUP_STATUS_NC_MEMBERS ) {
pGroup2->Status |= SCE_GROUP_STATUS_NC_MEMBERS;
} else {
if ( !(OneStatus & SCE_GROUP_STATUS_NC_MEMBERS) ) {
pGroup2->Status |= SCE_GROUP_STATUS_MEMBERS_MISMATCH;
} else {
// a matched members, pGroup2->pMembers should be NULL;
if ( pGroup2->pMembers ) {
ScepFreeNameList(pGroup2->pMembers);
}
pGroup2->pMembers = pNode->pMembers;
pNode->pMembers = NULL;
}
}
if ( pNode->Status & SCE_GROUP_STATUS_NC_MEMBEROF ) {
pGroup2->Status |= SCE_GROUP_STATUS_NC_MEMBEROF;
} else {
if ( !(OneStatus & SCE_GROUP_STATUS_NC_MEMBEROF) ) {
pGroup2->Status |= SCE_GROUP_STATUS_MEMBEROF_MISMATCH;
} else {
// a matched memberof, pGroup2->pMemberOf should be NULL;
if ( pGroup2->pMemberOf ) {
ScepFreeNameList(pGroup2->pMemberOf);
}
pGroup2->pMemberOf = pNode->pMemberOf;
pNode->pMemberOf = NULL;
}
}
}
pParent = pNode;
pNode = pNode->Next;
} else {
//
// does not exist in SAP.
// this is a matched item on pMembers, and/or pMemberOf
// just move this node to SAP, with status NC_MEMBERS, or NC_MEMBEROF, or 0
//
if ( pParent )
pParent->Next = pNode->Next;
else
pTempList = pNode->Next;
pTemp = pNode;
pNode=pNode->Next;
pTemp->Next = *pGroupMembership;
*pGroupMembership = pTemp;
}
}
//
// group exist in analysis but not in template
//
for ( pGroup2=*pGroupMembership; pGroup2 != NULL; pGroup2=pGroup2->Next ) {
if ( pGroup2->Status & SCE_INTERNAL_NP )
pGroup2->Status = SCE_GROUP_STATUS_NC_MEMBERS | SCE_GROUP_STATUS_NC_MEMBEROF;
}
} else if ( rc == SCESTATUS_RECORD_NOT_FOUND ) {
rc = SCESTATUS_SUCCESS;
} else {
//
// pGroupMembership will be freed outside
//
}
if ( pTempList ) {
ScepFreeGroupMembership(pTempList);
}
}
//
// now the group name may be in *SID format, conver it now to name
//
if ( SCESTATUS_SUCCESS == rc && *pGroupMembership ) {
for ( pGroup2=*pGroupMembership; pGroup2 != NULL; pGroup2=pGroup2->Next ) {
if ( pGroup2->GroupName == NULL ) {
continue;
}
if ( pGroup2->GroupName[0] == L'*' ) {
//
// *SID format, convert it
//
PSID pSid=NULL;
if ( ConvertStringSidToSid( (pGroup2->GroupName)+1, &pSid) ) {
PWSTR strName=NULL;
DWORD strLen=0;
if (NT_SUCCESS( ScepConvertSidToName(
LsaHandle,
pSid,
TRUE, // want domain\account format
&strName,
&strLen
)) && strName ) {
ScepFree(pGroup2->GroupName);
pGroup2->GroupName = strName;
strName = NULL;
}
LocalFree(pSid);
pSid = NULL;
}
}
}
}
if ( LsaHandle ) {
LsaClose(LsaHandle);
}
return(rc);
}
SCESTATUS
ScepGetGroupMembershipFromOneTable(
IN LSA_HANDLE LsaPolicy,
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
OUT PSCE_GROUP_MEMBERSHIP *pGroupMembership,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
)
/* ++
Routine Description:
This routine retrieves group membership information from the Jet databasae
and stores in the output buffer pGroupMembership. Group membership information
is in [Group Membership] section.
Arguments:
hProfile - the profile handle context
ProfileType - Type of the Profile
SCE_ENGINE_SAP
SCE_ENGINE_SMP
SCE_ENGINE_SCP
pGroupMembership - the output buffer to hold group membership info.
Errlog - the error list for errors encountered in this routine.
Return value:
SCESTATUS - SCESTATUS_SUCCESS
SCESTATUS_NOT_ENOUGH_RESOURCE
SCESTATUS_INVALID_PARAMETER
SCESTATUS_BAD_FORMAT
SCESTATUS_INVALID_DATA
-- */
{
SCESTATUS rc;
PSCESECTION hSection=NULL;
PSCE_GROUP_MEMBERSHIP pGroup=NULL;
DWORD GroupLen, ValueLen;
PWSTR GroupName=NULL;
PWSTR Value=NULL;
DWORD ValueType;
ULONG Len;
PWSTR pTemp;
if ( pGroupMembership == NULL )
return(SCESTATUS_INVALID_PARAMETER);
rc = ScepOpenSectionForName(
hProfile,
ProfileType,
szGroupMembership,
&hSection
);
if ( rc != SCESTATUS_SUCCESS ) {
ScepBuildErrorLogInfo( ERROR_INVALID_DATA,
Errlog,
SCEERR_OPEN,
szGroupMembership
);
return(rc);
}
//
// goto the first line of this section
//
rc = SceJetGetValue(
hSection,
SCEJET_PREFIX_MATCH,
NULL,
NULL,
0,
&GroupLen,
NULL,
0,
&ValueLen
);
while ( rc == SCESTATUS_SUCCESS ) {
//
// allocate memory for the group name and value string
//
GroupName = (PWSTR)ScepAlloc( LMEM_ZEROINIT, GroupLen+2);
Value = (PWSTR)ScepAlloc( LMEM_ZEROINIT, ValueLen+2);
if ( GroupName == NULL || Value == NULL ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
goto Done;
}
//
// Get the group and its value
//
rc = SceJetGetValue(
hSection,
SCEJET_CURRENT,
NULL,
GroupName,
GroupLen,
&GroupLen,
Value,
ValueLen,
&ValueLen
);
if ( rc != SCESTATUS_SUCCESS )
goto Done;
GroupName[GroupLen/2] = L'\0';
Value[ValueLen/2] = L'\0';
#ifdef SCE_DBG
wprintf(L"rc=%d, group membership: %s=%s\n", rc, GroupName, Value);
#endif
if (pTemp = ScepWcstrr(GroupName, szMembers) )
ValueType = 0;
else if (pTemp = ScepWcstrr(GroupName, szMemberof) )
ValueType = 1;
else if (pTemp = ScepWcstrr(GroupName, szPrivileges) )
ValueType = 2;
if ( pTemp == NULL ) {
ScepBuildErrorLogInfo( ERROR_INVALID_DATA,
Errlog,
SCEERR_CANT_FIND_KEYWORD,
GroupName
);
rc = SCESTATUS_INVALID_DATA;
goto NextLine; //Done;
}
Len = (DWORD)(pTemp - GroupName);
//
// if this is the first group, or a different group, create another node
// Note, the group name may be in SID string format now.
// Will be converted later (in the calling function) because we don't want
// to lookup for the same group name several times (each group may have
// multiple records).
//
if ( *pGroupMembership == NULL ||
_wcsnicmp((*pGroupMembership)->GroupName, GroupName, Len) != 0 ||
(*pGroupMembership)->GroupName[Len] != L'\0' ) {
//
// a new group. allocate buffer
//
pGroup = (PSCE_GROUP_MEMBERSHIP)ScepAlloc( LMEM_ZEROINIT, sizeof(SCE_GROUP_MEMBERSHIP) );
if ( pGroup == NULL ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
goto Done;
}
pGroup->GroupName = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (Len+1)*sizeof(WCHAR));
if ( pGroup->GroupName == NULL ) {
ScepFree(pGroup);
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
goto Done;
}
//
// get right case for group name
//
wcsncpy(pGroup->GroupName, GroupName, Len);
// do not care return codes
ScepGetGroupCase(pGroup->GroupName, Len);
pGroup->Next = *pGroupMembership;
// if ( SCE_ENGINE_SAP == ProfileType )
pGroup->Status = SCE_GROUP_STATUS_NC_MEMBERS | SCE_GROUP_STATUS_NC_MEMBEROF;
// else
// pGroup->Status = 0;
if ( SCE_ENGINE_SAP == ProfileType )
pGroup->Status |= SCE_INTERNAL_NP;
}
//
// add the multi-sz value string to the group node, depending on the value type
//
pTemp = Value;
while ( rc == SCESTATUS_SUCCESS && pTemp != NULL && pTemp[0] ) {
while ( *pTemp && L' ' == *pTemp ) {
pTemp++;
}
if ( SCE_ENGINE_SAP == ProfileType ) {
if ( !(*pTemp) ) {
// this is an not analyzed item
pGroup->Status = SCE_GROUP_STATUS_NOT_ANALYZED |
SCE_INTERNAL_NP;
break;
} else if ( _wcsicmp(SCE_ERROR_STRING, pTemp) == 0 ) {
// this is error item
pGroup->Status = SCE_GROUP_STATUS_ERROR_ANALYZED |
SCE_INTERNAL_NP;
break;
}
}
if ( !(*pTemp) ) {
// empty string is not allowed
break;
}
Len = wcslen(pTemp);
if ( ValueType != 0 && ValueType != 1 ) {
#if 0
//
// privilege with optional via group name
//
Status = (*((CHAR *)pTemp)-'0')*10 + ((*((CHAR *)pTemp+1)) - '0');
PWSTR strName=NULL;
DWORD strLen=0;
if ( pTemp[1] == L'*' ) {
//
// convert the SID string into name format
//
PSID pSid=NULL;
if ( ConvertStringSidToSid( pTemp+2, &pSid) ) {
rc = RtlNtStatusToDosError(
ScepConvertSidToName(
LsaPolicy,
pSid,
TRUE, // want domain\account format
&strName,
&strLen
));
LocalFree(pSid);
pSid = NULL;
} else {
rc = GetLastError();
}
}
if ( ERROR_SUCCESS == rc && strName ) {
rc = ScepAddToNameStatusList(&(pGroup->pPrivilegesHeld),
strName,
strLen,
Status);
} else {
//
// if failed to convert, or it's a name format already
// just add it to the list
//
rc = ScepAddToNameStatusList(&(pGroup->pPrivilegesHeld),
pTemp+1, Len-1, Status);
}
if ( strName ) {
ScepFree(strName);
strName = NULL;
}
#endif
} else {
//
// members (0) of memberof (1)
//
if ( pTemp[0] == L'*' ) {
//
// *SID format, convert to name, and add to the list
//
rc = ScepLookupSidStringAndAddToNameList(LsaPolicy,
(ValueType == 0) ?
&(pGroup->pMembers):
&(pGroup->pMemberOf),
pTemp, // +1,
Len // -1
);
} else {
rc = ScepAddToNameList((ValueType == 0) ?
&(pGroup->pMembers):
&(pGroup->pMemberOf),
pTemp,
Len );
}
}
#ifdef SCE_DBG
wprintf(L"Add %s to group list\n", pTemp);
#endif
pTemp += Len +1;
}
//
// Free memory
//
if ( rc != SCESTATUS_SUCCESS && pGroup != *pGroupMembership ) {
pGroup->Next = NULL;
ScepFreeGroupMembership( pGroup );
goto Done;
}
switch ( ValueType ) {
case 0: // members
pGroup->Status &= ~SCE_GROUP_STATUS_NC_MEMBERS;
break;
case 1:
pGroup->Status &= ~SCE_GROUP_STATUS_NC_MEMBEROF;
break;
}
*pGroupMembership = pGroup;
NextLine:
ScepFree(GroupName);
GroupName = NULL;
ScepFree(Value);
Value = NULL;
//
// read next line
//
rc = SceJetGetValue(
hSection,
SCEJET_NEXT_LINE,
NULL,
NULL,
0,
&GroupLen,
NULL,
0,
&ValueLen
);
}
if ( rc == SCESTATUS_RECORD_NOT_FOUND )
rc = SCESTATUS_SUCCESS;
Done:
//
// close the find index range
//
SceJetGetValue(
hSection,
SCEJET_CLOSE_VALUE,
NULL,
NULL,
0,
NULL,
NULL,
0,
NULL
);
if ( GroupName != NULL )
ScepFree(GroupName);
if ( Value != NULL )
ScepFree(Value);
//
// close the section
//
SceJetCloseSection( &hSection, TRUE );
return(rc);
}
SCESTATUS
ScepOpenSectionForName(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN PCWSTR SectionName,
OUT PSCESECTION *phSection
)
{
SCESTATUS rc;
DOUBLE SectionID;
SCEJET_TABLE_TYPE tblType;
//
// table type
//
switch ( ProfileType ) {
case SCE_ENGINE_SCP:
case SCE_ENGINE_SCP_INTERNAL:
tblType = SCEJET_TABLE_SCP;
break;
case SCE_ENGINE_SMP:
case SCE_ENGINE_SMP_INTERNAL:
tblType = SCEJET_TABLE_SMP;
break;
case SCE_ENGINE_SAP:
tblType = SCEJET_TABLE_SAP;
break;
default:
return(SCESTATUS_INVALID_PARAMETER);
}
//
// get section id
//
rc = SceJetGetSectionIDByName(
hProfile,
SectionName,
&SectionID
);
if ( rc != SCESTATUS_SUCCESS )
return(rc);
rc = SceJetOpenSection(
hProfile,
SectionID,
tblType,
phSection
);
return(rc);
}
SCESTATUS
ScepGetDsRoot(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN PCWSTR SectionName,
OUT PSCE_OBJECT_LIST *pObjectRoots,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
)
/*
DS object root has only one entry, which is the DS domain name
So the list contains only one entry.
The format of the DS domain name is dc=<domain>,dc=<domain1>,...o=internet,
which is the DNS name of the DS domain in LDAP format
*/
{
SCESTATUS rc;
PSCESECTION hSection=NULL;
PSCE_OBJECT_LIST pDsRoot=NULL;
PWSTR JetName=NULL;
BOOL IsContainer, LastOne;
DWORD Count, ValueLen;
BYTE Status;
WCHAR StatusFlag=L'\0';
rc = ScepOpenSectionForName(
hProfile,
ProfileType,
SectionName,
&hSection
);
if ( rc != SCESTATUS_SUCCESS ) {
ScepBuildErrorLogInfo( ERROR_INVALID_DATA,
Errlog,
SCEERR_OPEN,
SectionName
);
return(rc);
}
rc = ScepLdapOpen(NULL);
if ( rc == SCESTATUS_SUCCESS ) {
rc = ScepEnumerateDsObjectRoots(
NULL,
&pDsRoot
);
ScepLdapClose(NULL);
}
if ( rc == SCESTATUS_SUCCESS ) {
if ( pDsRoot == NULL ) {
rc = SCESTATUS_PROFILE_NOT_FOUND;
} else {
//
// Convert domain root
//
rc = ScepConvertLdapToJetIndexName(
pDsRoot->Name,
&JetName
);
}
}
if ( rc == SCESTATUS_SUCCESS ) {
//
// goto the line matching the domain root
//
rc = SceJetSeek(
hSection,
JetName,
wcslen(JetName)*sizeof(WCHAR),
SCEJET_SEEK_GE
);
if ( rc == SCESTATUS_RECORD_NOT_FOUND ) {
if ( ProfileType == SCE_ENGINE_SAP ) {
//
// the domain is not in the table, try another one
//
SceJetCloseSection(&hSection, FALSE);
rc = ScepOpenSectionForName(
hProfile,
SCE_ENGINE_SCP, // SCE_ENGINE_SMP,
SectionName,
&hSection
);
if ( rc == SCESTATUS_SUCCESS ) {
//
// get count under the domain
//
Count = 0;
rc = SceJetGetLineCount(
hSection,
JetName,
FALSE,
&Count);
if ( rc == SCESTATUS_SUCCESS ||
rc == SCESTATUS_RECORD_NOT_FOUND ) {
if ( rc == SCESTATUS_SUCCESS )
pDsRoot->Status = SCE_STATUS_CHECK;
else
pDsRoot->Status = SCE_STATUS_NOT_CONFIGURED;
pDsRoot->IsContainer = TRUE;
pDsRoot->Count = Count;
*pObjectRoots = pDsRoot;
pDsRoot = NULL;
rc = SCESTATUS_SUCCESS;
}
}
}
rc = SCESTATUS_SUCCESS;
} else if ( rc == SCESTATUS_SUCCESS ) {
//
// something of the domain exist, get value and count of the domain
//
rc = SceJetGetValue(
hSection,
SCEJET_EXACT_MATCH,
JetName,
NULL,
0,
NULL,
(PWSTR)&StatusFlag, // two bytes buffer
2,
&ValueLen
);
if ( rc == SCESTATUS_SUCCESS ||
rc == SCESTATUS_BUFFER_TOO_SMALL ||
rc == SCESTATUS_RECORD_NOT_FOUND ) {
if ( rc != SCESTATUS_RECORD_NOT_FOUND ) {
LastOne = TRUE;
Status = *((BYTE *)&StatusFlag);
IsContainer = *((CHAR *)&StatusFlag+1) != '0' ? TRUE : FALSE;
} else {
LastOne = FALSE;
IsContainer = TRUE;
if ( ProfileType == SCE_ENGINE_SAP )
Status = SCE_STATUS_GOOD;
else
Status = SCE_STATUS_CHECK;
}
//
// get count under the domain
//
rc = SceJetGetLineCount(
hSection,
JetName,
FALSE,
&Count);
if ( rc == SCESTATUS_SUCCESS ) {
if ( LastOne )
Count--;
if ( !IsContainer && Count > 0 ) {
IsContainer = TRUE;
}
//
// the proper domain name is in pDsRoot
//
pDsRoot->Status = Status;
pDsRoot->IsContainer = IsContainer;
pDsRoot->Count = Count;
*pObjectRoots = pDsRoot;
pDsRoot = NULL;
}
}
}
if ( SCESTATUS_RECORD_NOT_FOUND == rc ) {
rc = SCESTATUS_SUCCESS;
}
if ( rc != SCESTATUS_SUCCESS ) {
ScepBuildErrorLogInfo(ScepSceStatusToDosError(rc),
Errlog, SCEERR_QUERY_INFO,
L"SCP/SMP");
}
if ( JetName != NULL ) {
ScepFree(JetName);
}
} else {
ScepBuildErrorLogInfo(ScepSceStatusToDosError(rc),
Errlog, SCEERR_QUERY_INFO,
SectionName);
}
ScepFreeObjectList(pDsRoot);
SceJetCloseSection(&hSection, TRUE);
return(rc);
}
SCESTATUS
ScepGetObjectList(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN PCWSTR SectionName,
OUT PSCE_OBJECT_LIST *pObjectRoots,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
)
/* ++
Routine Description:
This routine retrieves registry or files security information from the JET
database for the root only. To get detail under a root object, call
ScepGetChildrentObject.
For Profiletype "SCE_ENGINE_SAP" (analysis info), a combination of SMP and SAP
are returned for a complete set of "analyzed" objects.
Arguments:
hProfile - the profile handle context
ProfileType - value to indicate engine type.
SCE_ENGINE_SCP
SCE_ENGINE_SAP
SCE_ENGINE_SMP
SectionName - The section name for the objects to retrieve.
pObjectRoots - The output list of object roots
Errlog - the cummulative error list to hold errors encountered in this routine.
Return value:
SCESTATUS - SCESTATUS_SUCCESS
SCESTATUS_NOT_ENOUGH_RESOURCE
SCESTATUS_INVALID_PARAMETER
SCESTATUS_BAD_FORMAT
SCESTATUS_INVALID_DATA
-- */
{
SCESTATUS rc;
PSCE_OBJECT_LIST pTempList=NULL,
pNode;
//
// get roots from the first table first
//
rc = ScepGetObjectFromOneTable(
hProfile,
ProfileType,
SectionName,
pObjectRoots,
Errlog
);
//
// Ds objects only return the domain name, no need to search SMP
//
if ( rc == SCESTATUS_SUCCESS && ProfileType == SCE_ENGINE_SAP ) {
//
// get the stuff from SMP
//
rc = ScepGetObjectFromOneTable(
hProfile,
SCE_ENGINE_SCP, // SCE_ENGINE_SMP,
SectionName,
&pTempList,
Errlog
);
if ( rc == SCESTATUS_SUCCESS ) {
//
// add non-exist nodes to pObjectRoots
//
for ( pNode=pTempList; pNode != NULL; pNode = pNode->Next ) {
//
// if this node does not exist in the SAP
// this node is analyzed with "match" status and
// no bad children under the node
// duplication is prevented by the last argument
//
rc = ScepAddToObjectList(pObjectRoots, pNode->Name, 0,
pNode->IsContainer, SCE_STATUS_GOOD, 0, SCE_CHECK_DUP);
if ( rc != ERROR_SUCCESS ) {
ScepBuildErrorLogInfo( rc,
Errlog,
SCEERR_ADD,
pNode->Name
);
//
// only the following two errors could be returned
//
if ( rc == ERROR_NOT_ENOUGH_MEMORY ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
break;
} else
rc = SCESTATUS_INVALID_PARAMETER;
}
}
} else if ( rc == SCESTATUS_RECORD_NOT_FOUND ) {
rc = SCESTATUS_SUCCESS;
} else {
//
// pObjectRoots will be freed outside
//
}
if ( pTempList ) {
ScepFreeObjectList(pTempList);
}
}
return(rc);
}
SCESTATUS
ScepGetObjectFromOneTable(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN PCWSTR SectionName,
OUT PSCE_OBJECT_LIST *pObjectRoots,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
)
/* ++
Routine Description:
This routine retrieves registry or files security information from the JET
database for the root only. To get detail under a root object, call
ScepGetChildrentObject.
Arguments:
hProfile - the profile handle context
ProfileType - value to indicate engine type.
SCE_ENGINE_SCP
SCE_ENGINE_SAP
SCE_ENGINE_SMP
SectionName - The section name for the objects to retrieve.
pObjectRoots - The output list of object roots
Errlog - the cummulative error list to hold errors encountered in this routine.
Return value:
SCESTATUS - SCESTATUS_SUCCESS
SCESTATUS_NOT_ENOUGH_RESOURCE
SCESTATUS_INVALID_PARAMETER
SCESTATUS_BAD_FORMAT
SCESTATUS_INVALID_DATA
-- */
{
SCESTATUS rc;
PSCESECTION hSection=NULL;
DWORD ObjectLen=0;
WCHAR ObjectName[21];
WCHAR StatusFlag=L'\0';
BYTE Status=0;
BOOL IsContainer=TRUE;
DWORD Len, Count;
WCHAR Buffer[21];
BOOL LastOne;
DWORD ValueLen=0;
rc = ScepOpenSectionForName(
hProfile,
ProfileType,
SectionName,
&hSection
);
if ( rc != SCESTATUS_SUCCESS ) {
ScepBuildErrorLogInfo( ERROR_INVALID_DATA,
Errlog,
SCEERR_OPEN,
SectionName
);
return(rc);
}
//
// goto the first line of this section
//
rc = SceJetSeek(
hSection,
NULL,
0,
SCEJET_SEEK_GE
);
while ( rc == SCESTATUS_SUCCESS ||
rc == SCESTATUS_BUFFER_TOO_SMALL ) {
memset(ObjectName, '\0', 21*sizeof(WCHAR));
memset(Buffer, '\0', 21*sizeof(WCHAR));
rc = SceJetGetValue(
hSection,
SCEJET_CURRENT,
NULL,
ObjectName,
20*sizeof(WCHAR),
&ObjectLen,
(PWSTR)&StatusFlag, // two bytes buffer
2,
&ValueLen
);
#ifdef SCE_DBG
wprintf(L"ObjectLen=%d, StatusFlag=%x, ValueLen=%d, rc=%d, ObjectName=%s \n",
ObjectLen, StatusFlag, ValueLen, rc, ObjectName);
#endif
if ( rc != SCESTATUS_SUCCESS && rc != SCESTATUS_BUFFER_TOO_SMALL ) {
ScepBuildErrorLogInfo( ERROR_READ_FAULT,
Errlog,
SCEERR_QUERY_VALUE,
SectionName
);
break;
}
//
// get first component of the object
//
if ( ObjectLen <= 40 )
ObjectName[ObjectLen/sizeof(WCHAR)] = L'\0';
rc = ScepGetNameInLevel(
ObjectName,
1,
L'\\',
Buffer,
&LastOne
);
if ( rc == SCESTATUS_SUCCESS ) {
Len = wcslen(Buffer);
if ( LastOne ) {
Status = *((BYTE *)&StatusFlag);
IsContainer = *((CHAR *)&StatusFlag+1) != '0' ? TRUE : FALSE;
} else {
IsContainer = TRUE;
if ( ProfileType == SCE_ENGINE_SAP )
Status = SCE_STATUS_GOOD;
else
Status = SCE_STATUS_CHECK;
}
#ifdef SCE_DBG
printf("\nStatus=%d, StatusFlag=%x, Len=%d, Buffer=%ws\n", Status, StatusFlag, Len, Buffer);
#endif
//
// get count of this object
//
rc = SceJetGetLineCount(
hSection,
Buffer,
FALSE,
&Count);
if ( rc == SCESTATUS_SUCCESS ||
rc == SCESTATUS_RECORD_NOT_FOUND ) {
if ( LastOne )
Count--;
if ( !IsContainer && Count > 0 ) {
IsContainer = TRUE;
}
//
// the root of registry and file are always upper cased
//
_wcsupr(Buffer);
rc = ScepAddToObjectList(pObjectRoots, Buffer, Len,
IsContainer, Status, Count, 0);
if ( rc != ERROR_SUCCESS ) {
ScepBuildErrorLogInfo( rc,
Errlog,
SCEERR_ADD,
Buffer
);
// only the following two errors could be returned
if ( rc == ERROR_NOT_ENOUGH_MEMORY )
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
else
rc = SCESTATUS_INVALID_PARAMETER;
}
}
if ( rc == SCESTATUS_SUCCESS ) {
//
// seek to the next one
//
Buffer[Len-1] = (WCHAR)( Buffer[Len-1] + 1);
rc = SceJetSeek(
hSection,
Buffer,
Len*sizeof(TCHAR),
SCEJET_SEEK_GT_NO_CASE
);
if ( rc != SCESTATUS_SUCCESS && rc != SCESTATUS_RECORD_NOT_FOUND )
ScepBuildErrorLogInfo( ERROR_READ_FAULT,
Errlog,
SCEERR_QUERY_VALUE,
SectionName
);
}
}
}
if ( rc == SCESTATUS_RECORD_NOT_FOUND )
rc = SCESTATUS_SUCCESS;
//
// close the section
//
SceJetCloseSection( &hSection, TRUE );
return(rc);
}
SCESTATUS
ScepGetAuditing(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
OUT PSCE_PROFILE_INFO pProfileInfo,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
)
/* ++
Routine Description:
This routine retrieves system auditing information from the JET database
and stores in the output buffer pProfileInfo. The auditing information
is stored in [System Log], [Security Log], [Application Log], [Audit Event],
[Audit Registry], and [Audit File] sections.
Arguments:
hProfile - the profile handle context
pProfileInfo - the output buffer to hold profile info.
Errlog - The cummulative error list to hold errors encountered in this routine.
Return value:
SCESTATUS - SCESTATUS_SUCCESS
SCESTATUS_NOT_ENOUGH_RESOURCE
SCESTATUS_INVALID_PARAMETER
SCESTATUS_BAD_FORMAT
SCESTATUS_INVALID_DATA
-- */
{
SCESTATUS rc;
SCE_KEY_LOOKUP LogKeys[]={
{(PWSTR)TEXT("MaximumLogSize"), offsetof(struct _SCE_PROFILE_INFO, MaximumLogSize), 'D'},
{(PWSTR)TEXT("AuditLogRetentionPeriod"),offsetof(struct _SCE_PROFILE_INFO, AuditLogRetentionPeriod), 'D'},
{(PWSTR)TEXT("RetentionDays"), offsetof(struct _SCE_PROFILE_INFO, RetentionDays), 'D'},
{(PWSTR)TEXT("RestrictGuestAccess"), offsetof(struct _SCE_PROFILE_INFO, RestrictGuestAccess), 'D'}
};
SCE_KEY_LOOKUP EventKeys[]={
{(PWSTR)TEXT("AuditSystemEvents"), offsetof(struct _SCE_PROFILE_INFO, AuditSystemEvents), 'D'},
{(PWSTR)TEXT("AuditLogonEvents"), offsetof(struct _SCE_PROFILE_INFO, AuditLogonEvents), 'D'},
{(PWSTR)TEXT("AuditObjectAccess"), offsetof(struct _SCE_PROFILE_INFO, AuditObjectAccess), 'D'},
{(PWSTR)TEXT("AuditPrivilegeUse"), offsetof(struct _SCE_PROFILE_INFO, AuditPrivilegeUse), 'D'},
{(PWSTR)TEXT("AuditPolicyChange"), offsetof(struct _SCE_PROFILE_INFO, AuditPolicyChange), 'D'},
{(PWSTR)TEXT("AuditAccountManage"), offsetof(struct _SCE_PROFILE_INFO, AuditAccountManage), 'D'},
{(PWSTR)TEXT("AuditProcessTracking"),offsetof(struct _SCE_PROFILE_INFO, AuditProcessTracking),'D'},
{(PWSTR)TEXT("AuditDSAccess"), offsetof(struct _SCE_PROFILE_INFO, AuditDSAccess), 'D'},
{(PWSTR)TEXT("AuditAccountLogon"), offsetof(struct _SCE_PROFILE_INFO, AuditAccountLogon), 'D'}};
DWORD cKeys = sizeof(EventKeys) / sizeof(SCE_KEY_LOOKUP);
PCWSTR szAuditLog;
DWORD i, j;
PSCESECTION hSection=NULL;
if ( hProfile == NULL ||
pProfileInfo == NULL ) {
return(SCESTATUS_INVALID_PARAMETER);
}
for ( i=0; i<3; i++) {
//
// Get Event Log setting for system log, security log and application log
//
switch (i) {
case 0:
szAuditLog = szAuditSystemLog;
break;
case 1:
szAuditLog = szAuditSecurityLog;
break;
default:
szAuditLog = szAuditApplicationLog;
break;
}
//
// get DWORD values for the section
//
rc = ScepGetFixValueSection(
hProfile,
szAuditLog,
LogKeys,
4,
ProfileType,
(PVOID)pProfileInfo,
&hSection,
Errlog
);
if ( rc != SCESTATUS_SUCCESS )
goto Done;
// close the section
SceJetCloseSection( &hSection, FALSE );
//
// update the Offset for next section
//
for ( j=0; j<4; j++ )
LogKeys[j].Offset += sizeof(DWORD);
}
//
// Get Audit Event info
//
//
// get DWORD values for the section
//
rc = ScepGetFixValueSection(
hProfile,
szAuditEvent,
EventKeys,
cKeys,
ProfileType,
(PVOID)pProfileInfo,
&hSection,
Errlog
);
if ( rc != SCESTATUS_SUCCESS )
goto Done;
// close the section
SceJetCloseSection( &hSection, TRUE );
Done:
// close the section
if ( rc != SCESTATUS_SUCCESS )
SceJetCloseSection( &hSection, TRUE );
return(rc);
}
//////////////////////////////
// helper APIs
//////////////////////////////
SCESTATUS
ScepGetUserSection(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN PWSTR Name,
OUT PVOID *ppInfo,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
)
/* ++
Function Description:
This routine get a dynamic section's information for a security area.
Dynamic sections are those created dynamically, based on other sections'
related information. Dynamic sections in a profile include User Security
Profiles for SCP and User Settings for SAP/SMP. Name contains the section's
identifier, either the section's name, or a partial name (e.g., a user
name) for the section. The output must be casted to different structure,
depending on the ProfileType and Area.
The output buffer contains one instance of the requested information,
e.g., one user security profile or one user's setting. To get all dynamic
sections, this routine must be called repeatly. The output buffer must
be freed by LocalFree after its use.
Arguments:
hProfile - The handle of the profile
ProfileType - The type of the profile to read
Name - The dynamic section's identifier
ppInfo - Output buffer (PSCE_USER_PROFILE or PSCE_USER_SETTING)
Errlog - The error log buffer
Return Value:
SCESTATUS_SUCCESS
SCESTATUS_PROFILE_NOT_FOUND
SCESTATUS_NOT_ENOUGH_RESOURCE
SCESTATUS_INVALID_PARAMETER
SCESTATUS_BAD_FORMAT
SCESTATUS_INVALID_DATA
-- */
{
//
// not support area
// if need this area later, refer to usersav directory for archived code
//
return(SCESTATUS_SERVICE_NOT_SUPPORT);
}
SCESTATUS
ScepGetObjectChildren(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN AREA_INFORMATION Area,
IN PWSTR ObjectPrefix,
IN SCE_SUBOBJECT_TYPE Option,
OUT PVOID *Buffer,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
)
/*
Routine Description
This routine is the same as ScepGetObjectChildrenFromOneTable, except when
ProfileType is SCE_ENGINE_SAP, in which case, object children in SMP is also
looked up and returned so the returned list contains the complete set of
the objects analyzed.
Arguments:
See ScepGetObjectChildrenFromOneTable
Return Value:
See ScepGetObjectChildrenFromOneTable
*/
{
SCESTATUS rc;
rc = ScepGetObjectChildrenFromOneTable(
hProfile,
ProfileType,
Area,
ObjectPrefix,
Option,
Buffer,
Errlog
);
if ( rc == SCESTATUS_RECORD_NOT_FOUND ) {
rc = SCESTATUS_SUCCESS;
}
if ( rc == SCESTATUS_SERVICE_NOT_SUPPORT &&
ProfileType == SCE_ENGINE_SAP &&
Option == SCE_IMMEDIATE_CHILDREN ) {
return( SCESTATUS_RECORD_NOT_FOUND); // no acl support, do not allow children
}
if ( rc == SCESTATUS_SUCCESS &&
ProfileType == SCE_ENGINE_SAP &&
Option == SCE_IMMEDIATE_CHILDREN ) {
PSCE_OBJECT_CHILDREN pTempList=NULL;
PSCE_OBJECT_CHILDREN_NODE *pArrObject=NULL;
DWORD arrCount=0, MaxCount=0;
LONG FindIndex;
if ( *Buffer ) {
arrCount = ((PSCE_OBJECT_CHILDREN)(*Buffer))->nCount;
MaxCount = ((PSCE_OBJECT_CHILDREN)(*Buffer))->MaxCount;
pArrObject = &(((PSCE_OBJECT_CHILDREN)(*Buffer))->arrObject);
}
//
// get object children from SMP table too
//
rc = ScepGetObjectChildrenFromOneTable(
hProfile,
SCE_ENGINE_SCP, //SCE_ENGINE_SMP,
Area,
ObjectPrefix,
Option,
(PVOID *)(&pTempList),
Errlog
);
if ( rc == SCESTATUS_SUCCESS && pTempList ) {
//
// add non-exist nodes to Buffer
//
DWORD i;
PSCE_OBJECT_CHILDREN_NODE *pTmpObject= &(pTempList->arrObject);
for ( i=0; i<pTempList->nCount; i++ ) {
//
// if this node does not exist in the SAP
// this node is analyzed with "match" status and
// no bad children under the node
// duplication is prevented by the last argument
//
if ( pTmpObject[i] == NULL ||
pTmpObject[i]->Name == NULL ) {
continue;
}
FindIndex = -1;
pTmpObject[i]->Status = SCE_STATUS_GOOD;
rc = ScepAddItemToChildren(
pTmpObject[i],
pTmpObject[i]->Name,
0,
pTmpObject[i]->IsContainer,
pTmpObject[i]->Status,
pTmpObject[i]->Count,
&pArrObject,
&arrCount,
&MaxCount,
&FindIndex
);
if ( rc == ERROR_SUCCESS ) {
//
// successfully added
//
pTmpObject[i] = NULL;
} else if ( rc == ERROR_DUP_NAME ) {
//
// node already exist, ignore the error
//
rc = ERROR_SUCCESS;
} else {
ScepBuildErrorLogInfo( rc,
Errlog,
SCEERR_ADD,
pTmpObject[i]->Name
);
//
// only the following two errors could be returned
//
if ( rc == ERROR_NOT_ENOUGH_MEMORY ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
break;
} else
rc = SCESTATUS_INVALID_PARAMETER;
}
}
} else if ( rc == SCESTATUS_RECORD_NOT_FOUND ) {
rc = SCESTATUS_SUCCESS;
}
if ( pTempList ) {
ScepFreeObjectChildren(pTempList);
}
if ( rc == SCESTATUS_SUCCESS ) {
//
// detect if status of this container or any of its "immediate" parent
// is in "auto-inherit" status. If so, query from the system to
// get good items.
//
BYTE ParentStatus = ScepGetObjectStatusFlag(
hProfile,
SCE_ENGINE_SCP, //SCE_ENGINE_SMP,
Area,
ObjectPrefix,
TRUE);
BYTE AnalysisStatus = ScepGetObjectStatusFlag(
hProfile,
SCE_ENGINE_SAP,
Area,
ObjectPrefix,
FALSE);
//
// compute the status to be used for all enumerated objects
//
BYTE NewStatus;
if ( AnalysisStatus == SCE_STATUS_ERROR_NOT_AVAILABLE ||
AnalysisStatus == SCE_STATUS_NOT_ANALYZED ) {
NewStatus = SCE_STATUS_NOT_ANALYZED;
} else if ( ParentStatus == SCE_STATUS_OVERWRITE ) {
NewStatus = SCE_STATUS_GOOD;
} else {
NewStatus = SCE_STATUS_NOT_CONFIGURED;
}
//
// even though there is no parent in SMP, still return all objects
//
// if ( (BYTE)-1 != ParentStatus ) {
// if any child is found for this level
// get the remaining "good" status nodes from system
//
PWSTR WildCard=NULL;
DWORD BufSize;
switch ( Area ) {
case AREA_FILE_SECURITY:
struct _wfinddata_t FileInfo;
intptr_t hFile;
BOOL BackSlashExist;
BufSize = wcslen(ObjectPrefix)+4;
WildCard = (PWSTR)ScepAlloc( 0, (BufSize+1)*sizeof(WCHAR));
if ( !WildCard ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
break;
}
BackSlashExist = ScepLastBackSlash(ObjectPrefix);
if ( BackSlashExist )
swprintf(WildCard, L"%s*.*", ObjectPrefix);
else
swprintf(WildCard, L"%s\\*.*", ObjectPrefix);
hFile = _wfindfirst(WildCard, &FileInfo);
ScepFree(WildCard);
WildCard = NULL;
if ( hFile != -1 ) {
do {
if ( wcscmp(L"..", FileInfo.name) == 0 ||
wcscmp(L".", FileInfo.name) == 0 )
continue;
FindIndex = -1;
rc = ScepAddItemToChildren(
NULL,
FileInfo.name,
0,
(FileInfo.attrib & _A_SUBDIR) ? TRUE : FALSE,
NewStatus,
0,
&pArrObject,
&arrCount,
&MaxCount,
&FindIndex
);
if ( rc == ERROR_DUP_NAME ) {
rc = ERROR_SUCCESS;
} else if ( rc != ERROR_SUCCESS ) {
ScepBuildErrorLogInfo( rc,
Errlog,
SCEERR_ADD,
FileInfo.name
);
//
// only the following two errors could be returned
//
if ( rc == ERROR_NOT_ENOUGH_MEMORY ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
break;
} else
rc = SCESTATUS_INVALID_PARAMETER;
}
} while ( _wfindnext(hFile, &FileInfo) == 0 );
_findclose(hFile);
}
break;
case AREA_REGISTRY_SECURITY:
HKEY hKey;
DWORD index;
DWORD EnumRc;
//
// open the key (on a 64-bit platform, 64-bit
// registry only will be done if SCE_ENGINE_SAP)
//
rc = ScepOpenRegistryObject(
SE_REGISTRY_KEY,
ObjectPrefix,
KEY_READ,
&hKey
);
if ( rc == ERROR_SUCCESS ) {
index = 0;
//
// enumerate all subkeys of the key
//
do {
WildCard = (PWSTR)ScepAlloc(LMEM_ZEROINIT, MAX_PATH*sizeof(WCHAR));
if ( WildCard == NULL ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
break;
}
BufSize = MAX_PATH;
EnumRc = RegEnumKeyEx(hKey,
index,
WildCard,
&BufSize,
NULL,
NULL,
NULL,
NULL);
if ( EnumRc == ERROR_SUCCESS ) {
index++;
//
// add the name to the object list
//
FindIndex = -1;
rc = ScepAddItemToChildren(
NULL,
WildCard,
BufSize,
TRUE,
NewStatus,
0,
&pArrObject,
&arrCount,
&MaxCount,
&FindIndex
);
if ( rc == ERROR_DUP_NAME ) {
rc = ERROR_SUCCESS;
} else if ( rc != ERROR_SUCCESS ) {
ScepBuildErrorLogInfo( rc,
Errlog,
SCEERR_ADD,
WildCard
);
//
// only the following two errors could be returned
//
if ( rc == ERROR_NOT_ENOUGH_MEMORY ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
break;
} else
rc = SCESTATUS_INVALID_PARAMETER;
}
}
ScepFree(WildCard);
WildCard = NULL;
} while ( EnumRc != ERROR_NO_MORE_ITEMS );
RegCloseKey(hKey);
} else {
rc = ScepDosErrorToSceStatus(rc);
}
break;
#if 0
case AREA_DS_OBJECTS:
PSCE_NAME_LIST pTemp, pList=NULL;
rc = ScepLdapOpen(NULL);
if ( rc == SCESTATUS_SUCCESS ) {
//
// detect if the Ds object exist
//
rc = ScepDsObjectExist(ObjectPrefix);
if ( rc == SCESTATUS_SUCCESS ) {
rc = ScepEnumerateDsOneLevel(ObjectPrefix, &pList);
//
// add each one to the object list
//
for (pTemp=pList; pTemp != NULL; pTemp = pTemp->Next ) {
//
// look for the first ldap component
//
WildCard = wcschr(pTemp->Name, L',');
if ( WildCard ) {
BufSize = (DWORD)(WildCard - pTemp->Name);
} else {
BufSize = 0;
}
rc = ScepAddItemToChildren(
NULL,
pTemp->Name,
BufSize,
TRUE,
NewStatus,
0,
&pArrObject,
&arrCount,
&MaxCount,
&FindIndex
);
if ( rc != ERROR_SUCCESS ) {
ScepBuildErrorLogInfo( rc,
Errlog,
SCEERR_ADD,
pTemp->Name
);
//
// only the following two errors could be returned
//
if ( rc == ERROR_NOT_ENOUGH_MEMORY ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
break;
} else
rc = SCESTATUS_INVALID_PARAMETER;
}
}
if ( pList ) {
//
// free the list
//
ScepFreeNameList(pList);
}
}
ScepLdapClose(NULL);
}
break;
#endif
}
//
// ignore other errors except out of memory
//
if ( rc != SCESTATUS_NOT_ENOUGH_RESOURCE ) {
rc = SCESTATUS_SUCCESS;
}
// }
}
/*
if ( *Buffer ) {
((PSCE_OBJECT_CHILDREN)(*Buffer))->nCount = arrCount;
((PSCE_OBJECT_CHILDREN)(*Buffer))->MaxCount = MaxCount;
((PSCE_OBJECT_CHILDREN)(*Buffer))->arrObject = pArrObject;
}
*/
if ( pArrObject ) {
*Buffer = (PVOID)((PBYTE)pArrObject - 2*sizeof(DWORD));
((PSCE_OBJECT_CHILDREN)(*Buffer))->nCount = arrCount;
((PSCE_OBJECT_CHILDREN)(*Buffer))->MaxCount = MaxCount;
}
if ( rc != SCESTATUS_SUCCESS ) {
//
// free Buffer
//
ScepFreeObjectChildren((PSCE_OBJECT_CHILDREN)(*Buffer));
*Buffer = NULL;
}
}
if ( (SCESTATUS_SUCCESS == rc) &&
(*Buffer == NULL) ) {
//
// get nothing
//
rc = SCESTATUS_RECORD_NOT_FOUND;
}
return(rc);
}
BYTE
ScepGetObjectStatusFlag(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN AREA_INFORMATION Area,
IN PWSTR ObjectPrefix,
IN BOOL bLookForParent
)
/*
Routine Description:
To find the status for the closest parent node (immediate/non immediate)
for the Object in the table.
Arguments:
hProfile - the databaes handle
ProfileType - the table type
Area - the area information
ObjectPrefix - the object's full name
Return Value:
Byte - the status flag for the nearest parent if one is found
*/
{
LPCTSTR SectionName;
PSCESECTION hSection=NULL;
WCHAR Delim;
BYTE Status=(BYTE)-1;
SCESTATUS rc;
PWSTR JetName=NULL;
switch ( Area) {
case AREA_FILE_SECURITY:
SectionName = szFileSecurity;
JetName = ObjectPrefix;
Delim = L'\\';
break;
case AREA_REGISTRY_SECURITY:
SectionName = szRegistryKeys;
JetName = ObjectPrefix;
Delim = L'\\';
break;
#if 0
case AREA_DS_OBJECTS:
SectionName = szDSSecurity;
Delim = L',';
rc = ScepConvertLdapToJetIndexName(
ObjectPrefix,
&JetName
);
if ( rc != SCESTATUS_SUCCESS ) {
return (BYTE)-1;
}
break;
#endif
default:
return (BYTE)-1;
}
rc = ScepOpenSectionForName(
hProfile,
ProfileType,
SectionName,
&hSection
);
if ( SCESTATUS_SUCCESS == rc ) {
Status = ScepGetObjectAnalysisStatus(hSection,
JetName,
bLookForParent
);
}
SceJetCloseSection(&hSection, TRUE);
if ( JetName != ObjectPrefix ) {
ScepFree(JetName);
}
if ( SCESTATUS_SUCCESS == rc ) {
return Status;
}
return (BYTE)-1;
}
SCESTATUS
ScepGetObjectChildrenFromOneTable(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN AREA_INFORMATION Area,
IN PWSTR ObjectPrefix,
IN SCE_SUBOBJECT_TYPE Option,
OUT PVOID *Buffer,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
)
/* ++
Routine Description:
This routine is used for Registry and File Security ONLY.
This routine takes a object prefix ( e.g., a parent node<EFBFBD>s full path name)
and outputs all files and sub directories under the object, or the immediate
children under the object, based on Option. When all files and sub
directories are outputted, the output information is in a n-tree structure
(SCE_OBJECT_TREE). If only the immediate children are outputted, the
output information is in a list structure (SCE_OBJECT_CHILDREN). The output buffer
must be freed by LocalFree after its use.
Arguments:
hProfile - The handle to the profile
ProifleType - The type of the profile to read
Area - The security area to read info
AREA_REGISTRY_SECURITY
AREA_FILE_SECURITY
ObjectPrefix- The parent node<EFBFBD>s full path name (e.g., c:\winnt)
Option - The option for output information. Valid values are
SCE_ALL_CHILDREN
SCE_IMMEDIATE_CHILDREN
Buffer - The output buffer.
Errlog - The error log buffer.
Return Value:
SCESTATUS_SUCCESS
SCESTATUS_PROFILE_NOT_FOUND
SCESTATUS_NOT_ENOUGH_RESOURCE
SCESTATUS_INVALID_PARAMETER
SCESTATUS_BAD_FORMAT
SCESTATUS_INVALID_DATA
-- */
{
SCESTATUS rc = SCESTATUS_SUCCESS;
PCWSTR SectionName=NULL;
PWSTR JetName;
WCHAR Delim=L'\\';
if ( ObjectPrefix == NULL || ObjectPrefix[0] == L'\0' )
return(SCESTATUS_INVALID_PARAMETER);
if ( Option == SCE_ALL_CHILDREN &&
ProfileType == SCE_ENGINE_SAP )
return(SCESTATUS_INVALID_PARAMETER);
switch (Area) {
case AREA_REGISTRY_SECURITY:
SectionName = szRegistryKeys;
JetName = ObjectPrefix;
break;
case AREA_FILE_SECURITY:
SectionName = szFileSecurity;
JetName = ObjectPrefix;
break;
#if 0
case AREA_DS_OBJECTS:
SectionName = szDSSecurity;
Delim = L',';
rc = ScepConvertLdapToJetIndexName(
ObjectPrefix,
&JetName
);
if ( rc != SCESTATUS_SUCCESS )
return(rc);
*Buffer = NULL;
break;
#endif
default:
return(SCESTATUS_INVALID_PARAMETER);
}
DWORD PrefixLen;
PWSTR NewPrefix;
PWSTR ObjectName=NULL;
PWSTR Value=NULL;
DWORD ObjectLen, ValueLen;
PWSTR Buffer1=NULL;
//
// make a new prefix to force a Delim at the end
//
PrefixLen = wcslen(JetName);
if ( Option != SCE_ALL_CHILDREN ) {
if ( JetName[PrefixLen-1] != Delim )
PrefixLen++;
NewPrefix = (PWSTR)ScepAlloc(0, (PrefixLen+1)*sizeof(WCHAR));
if ( NewPrefix == NULL ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
} else {
wcscpy(NewPrefix, JetName);
NewPrefix[PrefixLen-1] = Delim;
NewPrefix[PrefixLen] = L'\0';
}
} else
NewPrefix = JetName;
if ( rc != SCESTATUS_SUCCESS ) {
if ( Area == AREA_DS_OBJECTS )
ScepFree(JetName);
return(rc);
}
PSCESECTION hSection=NULL;
DWORD i;
PSCE_OBJECT_CHILDREN_NODE *pArrObject=NULL;
DWORD arrCount=0;
DWORD MaxCount=0;
LONG LastIndex=-1;
LONG FindIndex=-1;
//
// open the section
//
rc = ScepOpenSectionForName(
hProfile,
ProfileType,
SectionName,
&hSection
);
if ( rc == SCESTATUS_SUCCESS ) {
if ( ProfileType == SCE_ENGINE_SAP &&
Option != SCE_ALL_CHILDREN &&
PrefixLen > 2 ) {
//
// find if this drive support ACL
//
WCHAR StatusFlag=L'\0';
WCHAR SaveChr = NewPrefix[3];
NewPrefix[3] = L'\0';
rc = SceJetGetValue(
hSection,
SCEJET_EXACT_MATCH_NO_CASE,
NewPrefix,
NULL,
0,
NULL,
(PWSTR)&StatusFlag, // two bytes buffer
2,
&i
);
NewPrefix[3] = SaveChr;
if ( SCESTATUS_SUCCESS == rc ||
SCESTATUS_BUFFER_TOO_SMALL == rc ) {
i = *((BYTE *)&StatusFlag);
if ( i == (BYTE)SCE_STATUS_NO_ACL_SUPPORT ||
i == (DWORD)SCE_STATUS_NO_ACL_SUPPORT ) {
rc = SCESTATUS_SERVICE_NOT_SUPPORT;
} else {
rc = SCESTATUS_SUCCESS;
}
} else {
rc = SCESTATUS_SUCCESS;
}
}
} else {
ScepBuildErrorLogInfo( ERROR_INVALID_HANDLE,
Errlog,
SCEERR_OPEN,
SectionName
);
}
if ( rc == SCESTATUS_SUCCESS ) {
DWORD Level;
PWSTR pTemp;
DWORD SDsize=0;
pTemp = wcschr(JetName, Delim);
Level=1;
while ( pTemp ) {
pTemp++;
if ( pTemp[0] != 0 )
Level++;
pTemp = wcschr(pTemp, Delim);
}
Level++;
if ( Option == SCE_ALL_CHILDREN ) {
//
// find the first record in the section
//
rc = SceJetGetValue(
hSection,
SCEJET_PREFIX_MATCH_NO_CASE,
JetName,
NULL,
0,
&SDsize, // temp use for ObjectLen,
NULL,
0,
&i // temp use for ValueLen
);
} else {
//
// find the first record matching prefix in the section
//
rc = SceJetSeek(
hSection,
NewPrefix,
PrefixLen*sizeof(TCHAR),
SCEJET_SEEK_GE_NO_CASE
);
if ( rc == SCESTATUS_SUCCESS ) {
//
// start the Ldap server
//
if ( Area == AREA_DS_OBJECTS) {
rc = ScepLdapOpen(NULL);
if ( rc != SCESTATUS_SUCCESS ) {
ScepBuildErrorLogInfo( 0,
Errlog,
SCEERR_CONVERT_LDAP,
L""
);
}
}
if ( rc == SCESTATUS_SUCCESS ) {
rc = SceJetGetValue(
hSection,
SCEJET_CURRENT,
NULL,
NULL,
0,
&SDsize, // temp use for ObjectLen,
NULL,
0,
&i // temp use for ValueLen
);
}
}
}
DWORD Count=0;
BYTE Status;
BOOL IsContainer;
SCEJET_FIND_TYPE FindFlag;
while ( rc == SCESTATUS_SUCCESS ) {
//
// allocate memory for the group name and value string
//
ObjectName = (PWSTR)ScepAlloc( LMEM_ZEROINIT, SDsize+2); // ObjectLen
Value = (PWSTR)ScepAlloc( LMEM_ZEROINIT, i+2); //ValueLen
if ( ObjectName == NULL || Value == NULL ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
goto Done;
}
//
// Get the group and its value
//
rc = SceJetGetValue(
hSection,
SCEJET_CURRENT,
NULL,
ObjectName,
SDsize,
&ObjectLen,
Value,
i,
&ValueLen
);
if ( rc != SCESTATUS_SUCCESS ) {
ScepBuildErrorLogInfo( ERROR_READ_FAULT,
Errlog,
SCEERR_QUERY_VALUE,
SectionName
);
goto Done;
}
//
// teminate the string
//
if ( ObjectLen > SDsize )
ObjectLen = SDsize;
if ( ValueLen > i )
ValueLen = i;
ObjectName[ObjectLen/2] = L'\0';
Value[ValueLen/2] = L'\0';
if ( Option == SCE_ALL_CHILDREN ) {
//
// add this object to the object tree
//
PSECURITY_DESCRIPTOR pTempSD=NULL;
SECURITY_INFORMATION SeInfo;
//
// use i temperatorily
//
i = ConvertTextSecurityDescriptor(
Value+1,
&pTempSD,
&SDsize,
&SeInfo
);
if ( i == NO_ERROR ) {
if ( Area != AREA_DS_OBJECTS ) {
ScepChangeAclRevision(pTempSD, ACL_REVISION);
}
Status = *((BYTE *)Value);
IsContainer = *((CHAR *)Value+1) != '0' ? TRUE : FALSE;
if ( Area == AREA_DS_OBJECTS && *Buffer == NULL ) {
//
// build the first node separately because the first node
// is always the domain name with its DNS name as full name
//
rc = ScepBuildDsTree(
(PSCE_OBJECT_CHILD_LIST *)Buffer,
Level-1,
Delim,
JetName
);
if ( rc == SCESTATUS_SUCCESS ) {
if ( _wcsicmp(ObjectName, JetName) == 0 ) {
//
// exact match
//
(*((PSCE_OBJECT_TREE *)Buffer))->IsContainer = IsContainer;
(*((PSCE_OBJECT_TREE *)Buffer))->Status = Status;
(*((PSCE_OBJECT_TREE *)Buffer))->pSecurityDescriptor = pTempSD;
(*((PSCE_OBJECT_TREE *)Buffer))->SeInfo = SeInfo;
} else {
rc = ScepBuildObjectTree(
NULL,
(PSCE_OBJECT_CHILD_LIST *)Buffer,
Level-1,
Delim,
ObjectName,
IsContainer,
Status,
pTempSD,
SeInfo
);
}
}
} else {
rc = ScepBuildObjectTree(
NULL,
(PSCE_OBJECT_CHILD_LIST *)Buffer,
(Area == AREA_DS_OBJECTS) ? Level : 1,
Delim,
ObjectName,
IsContainer,
Status,
pTempSD,
SeInfo
);
}
if ( rc != SCESTATUS_SUCCESS ) {
ScepBuildErrorLogInfo( ScepSceStatusToDosError(rc),
Errlog,
SCEERR_BUILD_OBJECT
);
ScepFree(pTempSD);
}
} else {
ScepBuildErrorLogInfo( i,
Errlog,
SCEERR_BUILD_SD,
ObjectName // Value+1
);
rc = ScepDosErrorToSceStatus(i);
}
FindFlag = SCEJET_NEXT_LINE;
} else {
INT CompFlag;
DWORD ListHeadLen;
// verify it is within the right range
CompFlag = _wcsnicmp(ObjectName, NewPrefix, PrefixLen);
if ( pArrObject != NULL && LastIndex >= 0 && LastIndex < (LONG)arrCount ) {
ListHeadLen = wcslen(pArrObject[LastIndex]->Name);
} else
ListHeadLen = 0;
if ( (CompFlag == 0 && PrefixLen == ObjectLen/2) ||
CompFlag < 0 ) {
// CompFlag < 0 should be impossible!!!
// if it is the exact match with ObjectPrefix, ignore
//
// Every next level node is returned in the ObjectList
// with either
// Count=0 ( no sub children ), or
// Count > 0 && Status=SCE_STATUS_GOOD (this one is good)
// Status=mismatch/unknown/ignore/check
// should not count the object itself
//
rc = SceJetMoveNext(hSection);
} else if (CompFlag > 0 ) {
rc = SCESTATUS_RECORD_NOT_FOUND;
} else if (pArrObject != NULL && LastIndex >= 0 && LastIndex < (LONG)arrCount &&
PrefixLen+ListHeadLen < ObjectLen/2 &&
ObjectName[PrefixLen+ListHeadLen] == Delim &&
_wcsnicmp( pArrObject[LastIndex]->Name, ObjectName+PrefixLen,
ListHeadLen ) == 0 ) {
//
// if the list is not NULL, check the list head (new added item)
// to see if the ObjectName is already in. If yes, skip
//
Buffer1 = (PWSTR)ScepAlloc(0, (ListHeadLen+PrefixLen+2)*sizeof(WCHAR));
if ( Buffer1 == NULL ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
} else {
swprintf(Buffer1, L"%s%s", NewPrefix, pArrObject[LastIndex]->Name);
Buffer1[PrefixLen+ListHeadLen] = (WCHAR) (Delim + 1);
Buffer1[PrefixLen+ListHeadLen+1] = L'\0';
//
// skip the block
//
rc = SceJetSeek(
hSection,
Buffer1,
(PrefixLen+ListHeadLen+1)*sizeof(TCHAR),
SCEJET_SEEK_GE_DONT_CARE //SCEJET_SEEK_GE_NO_CASE
);
ScepFree(Buffer1);
Buffer1 = NULL;
}
} else {
DWORD Len;
BOOL LastOne;
//
// searching for the right level component
//
PWSTR pStart = ObjectName;
for ( i=0; i<Level; i++) {
pTemp = wcschr(pStart, Delim);
if ( i == Level-1 ) {
//
// find the right level
//
if ( pTemp == NULL ) {
LastOne = TRUE;
Len = ObjectLen/2; // wcslen(pStart); from begining
} else {
Len = (DWORD)(pTemp - ObjectName); // pStart; from begining
if ( *(pTemp+1) == L'\0' )
LastOne = TRUE;
else
LastOne = FALSE;
}
SDsize = (DWORD)(pStart - ObjectName);
} else {
if ( pTemp == NULL ) {
rc = SCESTATUS_INVALID_PARAMETER;
break;
} else
pStart = pTemp + 1;
}
}
if ( rc == SCESTATUS_SUCCESS && Len > SDsize ) {
Buffer1 = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (Len+1)*sizeof(WCHAR));
if ( Buffer1 == NULL )
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
else {
// wcsncpy(Buffer1, pStart, Len );
wcsncpy(Buffer1, ObjectName, Len);
Count = 1;
if ( LastOne ) {
Count = 0;
Status = *((BYTE *)Value);
IsContainer = *((CHAR *)Value+1) != '0' ? TRUE : FALSE;
} else {
IsContainer = TRUE;
if ( ProfileType == SCE_ENGINE_SAP )
Status = SCE_STATUS_GOOD;
else
Status = SCE_STATUS_CHECK;
}
}
}
if ( rc != SCESTATUS_SUCCESS ) {
ScepBuildErrorLogInfo( ERROR_READ_FAULT,
Errlog,
SCEERR_PROCESS_OBJECT,
ObjectName
);
} else if ( Buffer1 != NULL) {
//
// check to see if Buffer1 is already in the list
//
i=0; // temp. use of i for skip flag
if ( pArrObject && LastIndex >= 0 && LastIndex < (LONG)arrCount ) {
if ( ScepSearchItemInChildren(Buffer1+SDsize,
Len-SDsize,
pArrObject,
arrCount,
&FindIndex
)
) {
//
// Buffer1 is already in the list, skip the block
// use pStart temporarily
//
pStart = (PWSTR)ScepAlloc(0, (Len+2)*sizeof(WCHAR));
if ( pStart == NULL ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
} else {
//
// skip the block
//
wcscpy(pStart, Buffer1);
pStart[Len] = (WCHAR) ( Delim+1);
pStart[Len+1] = L'\0';
rc = SceJetSeek(
hSection,
pStart,
(Len+1)*sizeof(TCHAR),
SCEJET_SEEK_GE_DONT_CARE //cannot use GT cause it will skip the section
);
ScepFree(pStart);
pStart = NULL;
i=1;
LastIndex = FindIndex;
}
}
}
if ( 0 == i && SCESTATUS_SUCCESS == rc ) {
//
// get count
//
pStart = (PWSTR)ScepAlloc(0, (Len+2)*sizeof(WCHAR));
if ( pStart == NULL ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
} else {
wcscpy(pStart, Buffer1);
pStart[Len] = Delim;
pStart[Len+1] = L'\0';
rc = SceJetGetLineCount(
hSection,
pStart,
FALSE,
&Count);
if ( rc == SCESTATUS_SUCCESS ||
rc == SCESTATUS_RECORD_NOT_FOUND ) {
if ( !IsContainer && Count > 0 ) {
IsContainer = TRUE;
}
//
// make buffer1 approprate case
//
switch (Area) {
case AREA_REGISTRY_SECURITY:
rc = ScepGetRegKeyCase(Buffer1, SDsize, Len-SDsize);
break;
case AREA_FILE_SECURITY:
rc = ScepGetFileCase(Buffer1, SDsize, Len-SDsize);
break;
case AREA_DS_OBJECTS:
//
// need convert name first from o=,dc=,cn= to cn=,dc=,o=
//
pTemp=NULL;
rc = ScepConvertJetNameToLdapCase(
Buffer1,
TRUE, // Last component only
SCE_CASE_PREFERED, // right case
&pTemp
);
if ( rc != ERROR_FILE_NOT_FOUND && pTemp != NULL ) {
rc = ScepAddItemToChildren(NULL,
pTemp,
wcslen(pTemp),
IsContainer,
Status,
Count,
&pArrObject,
&arrCount,
&MaxCount,
&FindIndex
);
if ( rc != ERROR_SUCCESS ) {
ScepBuildErrorLogInfo( rc,
Errlog,
SCEERR_ADD,
pTemp
);
} else {
LastIndex = FindIndex;
}
ScepFree(pTemp);
pTemp = NULL;
}
rc = ScepDosErrorToSceStatus(rc);
break;
}
/*
if ( rc == SCESTATUS_PROFILE_NOT_FOUND ) {
//
// if the object does not exist, do not add
//
rc = SCESTATUS_SUCCESS;
} else if ( Area != AREA_DS_OBJECTS ) {
*/
if ( rc != SCESTATUS_PROFILE_NOT_FOUND &&
Area != AREA_DS_OBJECTS ) {
rc = ScepAddItemToChildren(NULL,
Buffer1+SDsize,
Len-SDsize,
IsContainer,
Status,
Count,
&pArrObject,
&arrCount,
&MaxCount,
&FindIndex
);
if ( rc != ERROR_SUCCESS ) {
ScepBuildErrorLogInfo( rc,
Errlog,
SCEERR_ADD,
Buffer1
);
rc = ScepDosErrorToSceStatus(rc);
} else {
LastIndex = FindIndex;
}
}
}
if ( rc == SCESTATUS_SUCCESS ) {
//
// seek to the original one
//
// Buffer1[Len-1] = (WCHAR) (Buffer1[Len-1] + 1);
rc = SceJetSeek(
hSection,
Buffer1,
Len*sizeof(TCHAR),
SCEJET_SEEK_GE_NO_CASE
);
//
// should be success, move to next line
//
rc = SceJetMoveNext(hSection);
} else if ( rc == SCESTATUS_PROFILE_NOT_FOUND ) {
pStart[Len] = (WCHAR) ( Delim+1);
pStart[Len+1] = L'\0';
rc = SceJetSeek(
hSection,
pStart,
(Len+1)*sizeof(TCHAR),
SCEJET_SEEK_GE_DONT_CARE //cannot use GT cause it will skip the section
);
}
ScepFree(pStart);
pStart = NULL;
}
}
ScepFree(Buffer1);
Buffer1 = NULL;
} else
rc = SceJetMoveNext(hSection);
}
FindFlag = SCEJET_CURRENT;
}
ScepFree(ObjectName);
ObjectName = NULL;
ScepFree(Value);
Value = NULL;
if ( rc != SCESTATUS_SUCCESS )
break;
//
// read next line
//
rc = SceJetGetValue(
hSection,
FindFlag,
NULL,
NULL,
0,
&SDsize, // temp use for ObjectLen
NULL,
0,
&i // temp use for ValueLen
);
}
if ( rc == SCESTATUS_RECORD_NOT_FOUND )
rc = SCESTATUS_SUCCESS;
}
Done:
if ( Area == AREA_DS_OBJECTS ) {
if ( Area == AREA_DS_OBJECTS ) {
if ( JetName != NULL )
ScepFree(JetName);
}
ScepLdapClose(NULL);
}
if ( Option != SCE_ALL_CHILDREN ) {
ScepFree(NewPrefix);
}
if ( Buffer1 != NULL )
ScepFree(Buffer1);
if ( ObjectName != NULL )
ScepFree(ObjectName);
if ( Value != NULL )
ScepFree(Value);
//
// close the find index range
//
SceJetGetValue(
hSection,
SCEJET_CLOSE_VALUE,
NULL,
NULL,
0,
NULL,
NULL,
0,
NULL
);
SceJetCloseSection( &hSection, TRUE);
if ( ( rc == SCESTATUS_SUCCESS ) &&
( Option != SCE_ALL_CHILDREN ) ) {
if ( pArrObject ) {
*Buffer = (PVOID)((PBYTE)pArrObject-sizeof(DWORD)*2);
((PSCE_OBJECT_CHILDREN)(*Buffer))->nCount = arrCount;
((PSCE_OBJECT_CHILDREN)(*Buffer))->MaxCount = MaxCount;
} else {
*Buffer = NULL;
}
/*
*Buffer = ScepAlloc(0, sizeof(SCE_OBJECT_CHILDREN));
if ( *Buffer ) {
((PSCE_OBJECT_CHILDREN)(*Buffer))->nCount = arrCount;
((PSCE_OBJECT_CHILDREN)(*Buffer))->MaxCount = MaxCount;
((PSCE_OBJECT_CHILDREN)(*Buffer))->arrObject = pArrObject;
} else {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
}
*/
}
if ( rc != SCESTATUS_SUCCESS ) {
//
// free (PVOID *)Buffer
//
if ( Option == SCE_ALL_CHILDREN ) {
// OBJECT_CHILD_LIST structure
ScepFreeObject2Security((PSCE_OBJECT_CHILD_LIST)(*Buffer), FALSE);
} else if ( pArrObject ) {
// OBJECT_CHILDREN structure
ScepFreeObjectChildren((PSCE_OBJECT_CHILDREN)((PBYTE)pArrObject-sizeof(DWORD)*2));
}
*Buffer = NULL;
}
return(rc);
}
SCESTATUS
ScepBuildDsTree(
OUT PSCE_OBJECT_CHILD_LIST *TreeRoot,
IN ULONG Level,
IN WCHAR Delim,
IN PCWSTR ObjectFullName
)
{
TCHAR Buffer[MAX_PATH];
BOOL LastOne=FALSE;
SCESTATUS rc;
if ( TreeRoot == NULL || ObjectFullName == NULL ) {
return(SCESTATUS_INVALID_PARAMETER);
}
memset(Buffer, '\0', MAX_PATH*sizeof(TCHAR));
rc = ScepGetNameInLevel(ObjectFullName,
Level,
Delim,
Buffer,
&LastOne);
if ( rc != SCESTATUS_SUCCESS )
return(rc);
*TreeRoot = (PSCE_OBJECT_CHILD_LIST)ScepAlloc(LPTR, sizeof(SCE_OBJECT_CHILD_LIST));
if ( *TreeRoot == NULL )
return(SCESTATUS_NOT_ENOUGH_RESOURCE);
PSCE_OBJECT_TREE Node;
//
// allocate buffer for the node
//
Node = (PSCE_OBJECT_TREE)ScepAlloc((UINT)0, sizeof(SCE_OBJECT_TREE));
if ( Node == NULL ) {
ScepFree(*TreeRoot);
*TreeRoot = NULL;
return(SCESTATUS_NOT_ENOUGH_RESOURCE);
}
//
// allocate buffer for the object name
//
Node->Name = (PWSTR)ScepAlloc((UINT)0,
(wcslen(Buffer)+1) * sizeof(TCHAR));
if ( Node->Name != NULL ) {
Node->ObjectFullName = (PWSTR)ScepAlloc( 0, (wcslen(ObjectFullName)+1)*sizeof(TCHAR));
if ( Node->ObjectFullName != NULL ) {
//
// initialize
//
wcscpy(Node->Name, Buffer);
wcscpy(Node->ObjectFullName, ObjectFullName);
Node->ChildList = NULL;
Node->Parent = NULL;
Node->pApplySecurityDescriptor = NULL;
Node->pSecurityDescriptor = NULL;
Node->SeInfo = 0;
Node->IsContainer = TRUE;
Node->Status = SCE_STATUS_CHECK;
(*TreeRoot)->Node = Node;
} else {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
ScepFree( Node->Name );
ScepFree( Node );
ScepFree( *TreeRoot );
*TreeRoot = NULL;
}
} else {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
ScepFree( Node );
ScepFree( *TreeRoot );
*TreeRoot = NULL;
}
return(rc);
}
SCESTATUS
ScepGetObjectSecurity(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN AREA_INFORMATION Area,
IN PWSTR ObjectName,
OUT PSCE_OBJECT_SECURITY *ObjSecurity
)
/*
Get security for a single object
*/
{
SCESTATUS rc;
PCWSTR SectionName=NULL;
PSCESECTION hSection=NULL;
PWSTR Value=NULL;
DWORD ValueLen;
PSECURITY_DESCRIPTOR pTempSD=NULL;
SECURITY_INFORMATION SeInfo;
DWORD SDsize, Win32Rc;
if ( hProfile == NULL || ObjectName == NULL ||
ObjSecurity == NULL ) {
return(SCESTATUS_INVALID_PARAMETER);
}
switch (Area) {
case AREA_REGISTRY_SECURITY:
SectionName = szRegistryKeys;
break;
case AREA_FILE_SECURITY:
SectionName = szFileSecurity;
break;
#if 0
case AREA_DS_OBJECTS:
SectionName = szDSSecurity;
break;
#endif
default:
return(SCESTATUS_INVALID_PARAMETER);
}
rc = ScepOpenSectionForName(
hProfile,
ProfileType,
SectionName,
&hSection
);
if ( rc == SCESTATUS_SUCCESS ) {
rc = SceJetGetValue(
hSection,
SCEJET_EXACT_MATCH_NO_CASE,
ObjectName,
NULL,
0,
NULL,
NULL,
0,
&ValueLen
);
if ( rc == SCESTATUS_SUCCESS ) {
//
// allocate memory for value string
//
Value = (PWSTR)ScepAlloc( LMEM_ZEROINIT, ValueLen+2);
if ( Value == NULL ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
goto Done;
}
//
// Get the value
//
rc = SceJetGetValue(
hSection,
SCEJET_CURRENT,
NULL,
NULL,
0,
NULL,
Value,
ValueLen,
&ValueLen
);
if ( rc == SCESTATUS_SUCCESS ) {
//
// convert security descriptor
//
Win32Rc = ConvertTextSecurityDescriptor(
Value+1,
&pTempSD,
&SDsize,
&SeInfo
);
if ( Win32Rc == NO_ERROR ) {
if ( Area != AREA_DS_OBJECTS ) {
ScepChangeAclRevision(pTempSD, ACL_REVISION);
}
//
// allocate output buffer (SCE_OBJECT_SECURITY)
//
*ObjSecurity = (PSCE_OBJECT_SECURITY)ScepAlloc(0, sizeof(SCE_OBJECT_SECURITY));
if ( *ObjSecurity == NULL ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
goto Done;
}
(*ObjSecurity)->Name = (PWSTR)ScepAlloc(0, (wcslen(ObjectName)+1)*sizeof(TCHAR));
if ( (*ObjSecurity)->Name == NULL ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
ScepFree(*ObjSecurity);
*ObjSecurity = NULL;
goto Done;
}
/*
(*ObjSecurity)->SDspec = (PWSTR)ScepAlloc(0, ValueLen);
if ( (*ObjSecurity)->SDspec == NULL ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
ScepFree((*ObjSecurity)->Name);
ScepFree(*ObjSecurity);
*ObjSecurity = NULL;
goto Done;
}
*/
//
// build the structure
//
(*ObjSecurity)->Status = *((BYTE *)Value);
(*ObjSecurity)->IsContainer = *((CHAR *)Value+1) != '0' ? TRUE : FALSE;
wcscpy( (*ObjSecurity)->Name, ObjectName);
(*ObjSecurity)->pSecurityDescriptor = pTempSD;
pTempSD = NULL;
(*ObjSecurity)->SeInfo = SeInfo;
// wcscpy( (*ObjSecurity)->SDspec, Value+1);
// (*ObjSecurity)->SDsize = ValueLen/2-1;
} else
rc = ScepDosErrorToSceStatus(Win32Rc);
}
}
}
Done:
SceJetCloseSection( &hSection, TRUE);
if ( pTempSD )
ScepFree(pTempSD);
if ( Value )
ScepFree(Value);
return(rc);
}
SCESTATUS
ScepGetSystemServices(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
OUT PSCE_SERVICES *pServiceList,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
)
/*
Routine Description:
Read all services defined in the Jet table into the service list
Arguments:
hProfile - the jet profile handle
ProfileType - The table to read from
SCE_ENGINE_SCP
SCE_ENGINE_SAP
SCE_ENGINE_SMP
pServiceList - The service list to output
Errlog - the error messages to output
Return Value:
SCESTATUS_SUCCESS
SCESTATUS error codes
*/
{
SCESTATUS rc;
DWORD Win32Rc;
PSCESECTION hSection=NULL;
DWORD ServiceLen=0, ValueLen=0;
PWSTR ServiceName=NULL,
Value=NULL;
PSECURITY_DESCRIPTOR pTempSD=NULL;
SECURITY_INFORMATION SeInfo;
DWORD SDsize;
PSCE_SERVICES ServiceNode;
PSCE_SERVICES pServices=NULL, pNode, pParent;
if ( hProfile == NULL ||
pServiceList == NULL ) {
return(SCESTATUS_INVALID_PARAMETER);
}
//
// open the section
//
rc = ScepOpenSectionForName(
hProfile,
ProfileType,
szServiceGeneral,
&hSection
);
if ( rc == SCESTATUS_RECORD_NOT_FOUND ) {
return(SCESTATUS_SUCCESS);
}
if ( rc != SCESTATUS_SUCCESS ) {
ScepBuildErrorLogInfo( ERROR_INVALID_DATA,
Errlog,
SCEERR_OPEN,
szServiceGeneral
);
return(rc);
}
//
// enumerate all service names from the system.
// do not care the error code
//
SceEnumerateServices(&pServices, TRUE);
//
// goto the first line of this section
//
rc = SceJetGetValue(
hSection,
SCEJET_PREFIX_MATCH,
NULL,
NULL,
0,
&ServiceLen,
NULL,
0,
&ValueLen
);
while ( rc == SCESTATUS_SUCCESS ) {
//
// allocate memory for the service name and value string
//
ServiceName = (PWSTR)ScepAlloc( LMEM_ZEROINIT, ServiceLen+2);
if ( ServiceName != NULL ) {
Value = (PWSTR)ScepAlloc( LMEM_ZEROINIT, ValueLen+2);
if ( Value != NULL ) {
//
// Get the service and its value
//
rc = SceJetGetValue(
hSection,
SCEJET_CURRENT,
NULL,
ServiceName,
ServiceLen,
&ServiceLen,
Value,
ValueLen,
&ValueLen
);
if ( rc == SCESTATUS_SUCCESS ) {
ServiceName[ServiceLen/2] = L'\0';
Value[ValueLen/2] = L'\0';
#ifdef SCE_DBG
wprintf(L"rc=%d, service: %s=%s\n", rc, ServiceName, Value);
#endif
//
// convert to security descriptor
//
Win32Rc = ConvertTextSecurityDescriptor(
Value+1,
&pTempSD,
&SDsize,
&SeInfo
);
if ( Win32Rc == NO_ERROR ) {
ScepChangeAclRevision(pTempSD, ACL_REVISION);
//
// create this service node
//
ServiceNode = (PSCE_SERVICES)ScepAlloc( LMEM_FIXED, sizeof(SCE_SERVICES) );
if ( ServiceNode != NULL ) {
//
// find the right name for the service
//
for ( pNode=pServices, pParent=NULL; pNode != NULL;
pParent=pNode, pNode=pNode->Next ) {
if ( _wcsicmp(pNode->ServiceName, ServiceName) == 0 ) {
break;
}
}
if ( pNode != NULL ) {
//
// got it
//
ServiceNode->ServiceName = pNode->ServiceName;
ServiceNode->DisplayName = pNode->DisplayName;
//
// free the node
//
if ( pParent != NULL ) {
pParent->Next = pNode->Next;
} else {
pServices = pNode->Next;
}
// General is NULL becuase the enumerate call asks only for names
ScepFree(pNode);
pNode = NULL;
} else {
//
// did not find it
//
ServiceNode->ServiceName = ServiceName;
ServiceNode->DisplayName = NULL;
ServiceName = NULL;
}
ServiceNode->Status = *((BYTE *)Value);
ServiceNode->Startup = *((BYTE *)Value+1);
ServiceNode->General.pSecurityDescriptor = pTempSD;
ServiceNode->SeInfo = SeInfo;
ServiceNode->Next = *pServiceList;
*pServiceList = ServiceNode;
//
// DO NOT free the following buffers
//
pTempSD = NULL;
} else {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
ScepFree(pTempSD);
}
} else {
ScepBuildErrorLogInfo( Win32Rc,
Errlog,
SCEERR_BUILD_SD,
ServiceName
);
rc = ScepDosErrorToSceStatus(Win32Rc);
}
}
ScepFree(Value);
} else
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
//
// ServiceName could be used in the service node
//
if ( ServiceName )
ScepFree(ServiceName);
} else
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
if ( rc == SCESTATUS_SUCCESS ) {
//
// read next line
//
rc = SceJetGetValue(
hSection,
SCEJET_NEXT_LINE,
NULL,
NULL,
0,
&ServiceLen,
NULL,
0,
&ValueLen
);
}
}
if ( rc == SCESTATUS_RECORD_NOT_FOUND )
rc = SCESTATUS_SUCCESS;
//
// close the find index range
//
SceJetGetValue(
hSection,
SCEJET_CLOSE_VALUE,
NULL,
NULL,
0,
NULL,
NULL,
0,
NULL
);
//
// close the section
//
SceJetCloseSection( &hSection, TRUE );
if ( rc != SCESTATUS_SUCCESS ) {
//
// free the service list
//
SceFreePSCE_SERVICES(*pServiceList);
*pServiceList = NULL;
}
SceFreePSCE_SERVICES(pServices);
return(rc);
}
SCESTATUS
ScepCopyObjects(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN PWSTR InfFile,
IN PCWSTR SectionName,
IN AREA_INFORMATION Area,
IN OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
)
/* ++
Routine Description:
This routine copies registry/file/ds/service object in SMP table to the specified
inf template.
Arguments:
hProfile - The handle to the profile
InfFile - The INF template name
SectionName - the section name where data is stored
Area - The security area to read info
AREA_REGISTRY_SECURITY
AREA_FILE_SECURITY
AREA_DS_OBJECTS
Errlog - The error log buffer.
Return Value:
SCESTATUS_SUCCESS
SCESTATUS_PROFILE_NOT_FOUND
SCESTATUS_NOT_ENOUGH_RESOURCE
SCESTATUS_INVALID_PARAMETER
SCESTATUS_BAD_FORMAT
SCESTATUS_INVALID_DATA
-- */
{
SCESTATUS rc = SCESTATUS_SUCCESS;
PSCESECTION hSection=NULL;
PWSTR ObjectName=NULL;
PWSTR Value=NULL;
DWORD ObjectLen, ValueLen;
BYTE Status;
PWSTR NewValue=NULL;
DWORD Count=0;
WCHAR KeyName[10];
if ( InfFile == NULL || hProfile == NULL )
return(SCESTATUS_INVALID_PARAMETER);
//
// open the section
//
rc = ScepOpenSectionForName(
hProfile,
ProfileType,
SectionName,
&hSection
);
if ( rc == SCESTATUS_SUCCESS ) {
//
// empty the section first.
//
WritePrivateProfileSection(
SectionName,
NULL,
(LPCTSTR)InfFile);
//
// find the first record in the section
//
rc = SceJetGetValue(
hSection,
SCEJET_PREFIX_MATCH,
NULL,
NULL,
0,
&ObjectLen,
NULL,
0,
&ValueLen
);
while ( rc == SCESTATUS_SUCCESS ) {
Count++;
//
// allocate memory for the group name and value string
//
ObjectName = (PWSTR)ScepAlloc( LMEM_ZEROINIT, ObjectLen+2);
Value = (PWSTR)ScepAlloc( LMEM_ZEROINIT, ValueLen+2);
if ( ObjectName == NULL || Value == NULL ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
goto Done;
}
//
// Get the group and its value
//
rc = SceJetGetValue(
hSection,
SCEJET_CURRENT,
NULL,
ObjectName,
ObjectLen,
&ObjectLen,
Value,
ValueLen,
&ValueLen
);
if ( rc != SCESTATUS_SUCCESS ) {
ScepBuildErrorLogInfo( ERROR_READ_FAULT,
Errlog,
SCEERR_QUERY_VALUE,
SectionName
);
goto Done;
}
#ifdef SCE_DBG
wprintf(L"Addr: %x %x, %s=%s\n", ObjectName, Value, ObjectName, Value+1);
#endif
if ( Area == AREA_SYSTEM_SERVICE )
Status = *((BYTE *)Value+1);
else
Status = *((BYTE *)Value);
NewValue = (PWSTR)ScepAlloc(0, ObjectLen+ValueLen+18);
if ( NewValue == NULL ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
goto Done;
}
swprintf(NewValue, L"\"%s\", %d, \"%s\"\0", ObjectName, Status, Value+1);
swprintf(KeyName, L"%x\0", Count);
//
// write this line to the inf file
//
if ( !WritePrivateProfileString(
SectionName,
KeyName,
NewValue,
InfFile
) ) {
ScepBuildErrorLogInfo( GetLastError(),
Errlog,
SCEERR_WRITE_INFO,
ObjectName
);
rc = ScepDosErrorToSceStatus(GetLastError());
}
ScepFree(ObjectName);
ObjectName = NULL;
ScepFree(Value);
Value = NULL;
ScepFree(NewValue);
NewValue = NULL;
if ( rc != SCESTATUS_SUCCESS )
break;
//
// read next line
//
rc = SceJetGetValue(
hSection,
SCEJET_NEXT_LINE,
NULL,
NULL,
0,
&ObjectLen,
NULL,
0,
&ValueLen
);
}
if ( rc == SCESTATUS_RECORD_NOT_FOUND )
rc = SCESTATUS_SUCCESS;
} else
ScepBuildErrorLogInfo( ERROR_INVALID_HANDLE,
Errlog,
SCEERR_OPEN,
SectionName
);
Done:
if ( ObjectName != NULL )
ScepFree(ObjectName);
if ( Value != NULL )
ScepFree(Value);
if ( NewValue != NULL )
ScepFree(NewValue);
//
// close the find index range
//
SceJetGetValue(
hSection,
SCEJET_CLOSE_VALUE,
NULL,
NULL,
0,
NULL,
NULL,
0,
NULL
);
SceJetCloseSection( &hSection, TRUE);
return(rc);
}
SCESTATUS
ScepGetAnalysisSummary(
IN PSCECONTEXT Context,
IN AREA_INFORMATION Area,
OUT PDWORD pCount
)
{
SCESTATUS rc=SCESTATUS_INVALID_PARAMETER;
DWORD count;
DWORD total=0;
PSCESECTION hSection=NULL;
if ( Context == NULL || pCount == NULL )
return(SCESTATUS_INVALID_PARAMETER);
*pCount = 0;
if ( Area & AREA_SECURITY_POLICY ) {
//
// system access
//
rc = ScepOpenSectionForName(
Context,
SCE_ENGINE_SAP,
szSystemAccess,
&hSection
);
if ( rc == SCESTATUS_SUCCESS ) {
rc = SceJetGetLineCount(
hSection,
NULL,
FALSE,
&count
);
}
SceJetCloseSection( &hSection, TRUE);
if ( rc != SCESTATUS_SUCCESS )
return(rc);
total += count;
//
// System Log
//
rc = ScepOpenSectionForName(
Context,
SCE_ENGINE_SAP,
szAuditSystemLog,
&hSection
);
if ( rc == SCESTATUS_SUCCESS ) {
rc = SceJetGetLineCount(
hSection,
NULL,
FALSE,
&count
);
}
SceJetCloseSection( &hSection, TRUE);
if ( rc != SCESTATUS_SUCCESS )
return(rc);
total += count;
//
// Security Log
//
rc = ScepOpenSectionForName(
Context,
SCE_ENGINE_SAP,
szAuditSecurityLog,
&hSection
);
if ( rc == SCESTATUS_SUCCESS ) {
rc = SceJetGetLineCount(
hSection,
NULL,
FALSE,
&count
);
}
SceJetCloseSection( &hSection, TRUE);
if ( rc != SCESTATUS_SUCCESS )
return(rc);
total += count;
//
// Application Log
//
rc = ScepOpenSectionForName(
Context,
SCE_ENGINE_SAP,
szAuditApplicationLog,
&hSection
);
if ( rc == SCESTATUS_SUCCESS ) {
rc = SceJetGetLineCount(
hSection,
NULL,
FALSE,
&count
);
}
SceJetCloseSection( &hSection, TRUE);
if ( rc != SCESTATUS_SUCCESS )
return(rc);
total += count;
//
// Event Audit
//
rc = ScepOpenSectionForName(
Context,
SCE_ENGINE_SAP,
szAuditEvent,
&hSection
);
if ( rc == SCESTATUS_SUCCESS ) {
rc = SceJetGetLineCount(
hSection,
NULL,
FALSE,
&count
);
}
SceJetCloseSection( &hSection, TRUE);
if ( rc != SCESTATUS_SUCCESS )
return(rc);
total += count;
}
if ( Area & AREA_PRIVILEGES ) {
//
// Privileges
//
rc = ScepOpenSectionForName(
Context,
SCE_ENGINE_SAP,
szPrivilegeRights,
&hSection
);
if ( rc == SCESTATUS_SUCCESS ) {
rc = SceJetGetLineCount(
hSection,
NULL,
FALSE,
&count
);
}
SceJetCloseSection( &hSection, TRUE);
if ( rc != SCESTATUS_SUCCESS )
return(rc);
total += count;
}
if ( Area & AREA_GROUP_MEMBERSHIP) {
//
// Group Membership
//
rc = ScepOpenSectionForName(
Context,
SCE_ENGINE_SAP,
szGroupMembership,
&hSection
);
if ( rc == SCESTATUS_SUCCESS ) {
rc = SceJetGetLineCount(
hSection,
NULL,
FALSE,
&count
);
}
SceJetCloseSection( &hSection, TRUE);
if ( rc != SCESTATUS_SUCCESS )
return(rc);
total += count;
}
if ( Area & AREA_SYSTEM_SERVICE ) {
//
// system service
//
rc = ScepOpenSectionForName(
Context,
SCE_ENGINE_SAP,
szServiceGeneral,
&hSection
);
if ( rc == SCESTATUS_SUCCESS ) {
rc = SceJetGetLineCount(
hSection,
NULL,
FALSE,
&count
);
}
SceJetCloseSection( &hSection, TRUE);
if ( rc != SCESTATUS_SUCCESS )
return(rc);
total += count;
}
if ( Area & AREA_REGISTRY_SECURITY ) {
//
// Registry security
//
rc = ScepOpenSectionForName(
Context,
SCE_ENGINE_SAP,
szRegistryKeys,
&hSection
);
if ( rc == SCESTATUS_SUCCESS ) {
rc = SceJetGetLineCount(
hSection,
NULL,
FALSE,
&count
);
}
SceJetCloseSection( &hSection, TRUE);
if ( rc != SCESTATUS_SUCCESS )
return(rc);
total += count;
}
if ( Area & AREA_FILE_SECURITY ) {
//
// File Security
//
rc = ScepOpenSectionForName(
Context,
SCE_ENGINE_SAP,
szFileSecurity,
&hSection
);
if ( rc == SCESTATUS_SUCCESS ) {
rc = SceJetGetLineCount(
hSection,
NULL,
FALSE,
&count
);
}
SceJetCloseSection( &hSection, TRUE);
if ( rc != SCESTATUS_SUCCESS )
return(rc);
total += count;
}
#if 0
#if _WIN32_WINNT>=0x0500
if ( Area & AREA_DS_OBJECTS &&
RtlGetNtProductType(&theType) ) {
if ( theType == NtProductLanManNt ) {
//
// DS object security
//
rc = ScepOpenSectionForName(
Context,
SCE_ENGINE_SAP,
szDSSecurity,
&hSection
);
if ( rc == SCESTATUS_SUCCESS ) {
rc = SceJetGetLineCount(
hSection,
NULL,
FALSE,
&count
);
}
SceJetCloseSection( &hSection, TRUE);
if ( rc != SCESTATUS_SUCCESS )
return(rc);
total += count;
}
}
#endif
#endif
*pCount = total;
return(rc);
}
SCESTATUS
ScepBrowseTableSection(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN PCWSTR SectionName,
IN DWORD Options
)
{
SCESTATUS rc;
PSCESECTION hSection=NULL;
SceClientBrowseCallback(
0,
(PWSTR)SectionName,
NULL,
NULL
);
rc = ScepOpenSectionForName(
hProfile,
ProfileType,
SectionName,
&hSection
);
if ( rc != SCESTATUS_SUCCESS ) {
return(rc);
}
JET_ERR JetErr;
//
// goto the first line of this section
//
DWORD KeyLen, ValueLen, Actual;
LONG GpoID=0;
PWSTR KeyName=NULL;
PWSTR Value=NULL;
TCHAR GpoName[MAX_PATH];
SCE_BROWSE_CALLBACK_VALUE ValBuf;
ValBuf.Len = 0;
ValBuf.Value = NULL;
rc = SceJetGetValue(
hSection,
SCEJET_PREFIX_MATCH,
NULL,
NULL,
0,
&KeyLen,
NULL,
0,
&ValueLen
);
while ( rc == SCESTATUS_SUCCESS ) {
//
// get GPO ID field from the current line
//
GpoID = 0;
if ( hSection->JetColumnGpoID > 0 ) {
JetErr = JetRetrieveColumn(
hSection->JetSessionID,
hSection->JetTableID,
hSection->JetColumnGpoID,
(void *)&GpoID,
4,
&Actual,
0,
NULL
);
}
if ( (Options & SCEBROWSE_DOMAIN_POLICY) &&
(GpoID <= 0) ) {
//
// do not need this line, continue to next line
//
} else {
KeyName = (PWSTR)ScepAlloc(LMEM_ZEROINIT, KeyLen+2);
//
// allocate memory for the group name and value string
//
Value = (PWSTR)ScepAlloc( LMEM_ZEROINIT, ValueLen+2);
if ( KeyName == NULL || Value == NULL ) {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
goto Done;
}
//
// Get the key and value
//
DWORD NewKeyLen, NewValueLen;
rc = SceJetGetValue(
hSection,
SCEJET_CURRENT,
NULL,
KeyName,
KeyLen,
&NewKeyLen,
Value,
ValueLen,
&NewValueLen
);
if ( rc != SCESTATUS_SUCCESS )
goto Done;
//
// terminate the string
//
KeyName[KeyLen/2] = L'\0';
Value[ValueLen/2] = L'\0';
GpoName[0] = L'\0';
if ( hSection->JetColumnGpoID > 0 && GpoID > 0 ) {
Actual = MAX_PATH;
SceJetGetGpoNameByID(
hProfile,
GpoID,
GpoName,
&Actual,
NULL,
NULL
);
}
if ( Value && Value[0] != L'\0' &&
( Options & SCEBROWSE_MULTI_SZ) ) {
if (0 == _wcsicmp( KeyName, szLegalNoticeTextKeyName) ) {
//
// check for commas and escape them with ","
// k=7,a",",b,c
// pValueStr will be a,\0b\0c\0\0 which we should make
// a","\0b\0c\0\0
//
DWORD dwCommaCount = 0;
for ( DWORD dwIndex = 1; dwIndex < ValueLen/2 ; dwIndex++) {
if ( Value[dwIndex] == L',' )
dwCommaCount++;
}
if ( dwCommaCount > 0 ) {
//
// in this case we have to escape commas
//
PWSTR pszValueEscaped;
DWORD dwBytes = (ValueLen/2 + 1 + (dwCommaCount*2))*sizeof(WCHAR);
pszValueEscaped = (PWSTR)ScepAlloc(LMEM_ZEROINIT, dwBytes);
if (pszValueEscaped) {
memset(pszValueEscaped, '\0', dwBytes);
ValueLen = 2 * ScepEscapeString(Value,
ValueLen/2,
L',',
L'"',
pszValueEscaped
);
ScepFree(Value);
Value = pszValueEscaped;
} else {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
goto Done;
}
}
}
ScepConvertMultiSzToDelim(Value+1, ValueLen/2-1, L'\0', L',');
}
__try {
ValBuf.Len = Value ? (ValueLen+2) : 0 ;
ValBuf.Value = (UCHAR *)Value;
SceClientBrowseCallback(
GpoID,
KeyName,
GpoName,
(SCEPR_SR_SECURITY_DESCRIPTOR *)&ValBuf
);
} __except(EXCEPTION_EXECUTE_HANDLER) {
}
ScepFree(Value);
Value = NULL;
ScepFree(KeyName);
KeyName = NULL;
}
//
// read next line
//
rc = SceJetGetValue(
hSection,
SCEJET_NEXT_LINE,
NULL,
NULL,
0,
&KeyLen,
NULL,
0,
&ValueLen
);
}
if ( rc == SCESTATUS_RECORD_NOT_FOUND )
rc = SCESTATUS_SUCCESS;
Done:
//
// close the find index range
//
SceJetGetValue(
hSection,
SCEJET_CLOSE_VALUE,
NULL,
NULL,
0,
NULL,
NULL,
0,
NULL
);
if ( Value != NULL )
ScepFree(Value);
if ( KeyName != NULL )
ScepFree(KeyName);
//
// close the section
//
SceJetCloseSection( &hSection, TRUE );
return(rc);
}
BOOL
ScepSearchItemInChildren(
IN PWSTR ItemName,
IN DWORD NameLen,
IN PSCE_OBJECT_CHILDREN_NODE *pArrObject,
IN DWORD arrCount,
OUT LONG *pFindIndex
)
/*
Routine Description:
Search the item name in the array specified. If found, the index to the
array is returned in pFindIndex.
Return Value:
TRUE - find it
FALSE - doesn't find it
*/
{
if ( pFindIndex == NULL ) {
return(FALSE);
}
//
// note pFindIndex stores the closest node, not necessary mean
// the index is the match.
//
*pFindIndex = -1;
if ( ItemName == NULL ||
pArrObject == NULL ||
arrCount == 0 ) {
return(FALSE);
}
DWORD idxStart=0;
DWORD idxEnd=arrCount-1;
DWORD theIndex;
INT CompFlag=-1;
do {
//
// choose the middle
//
theIndex = (idxStart + idxEnd)/2;
if ( pArrObject[theIndex] == NULL ||
pArrObject[theIndex]->Name == NULL ) {
//
// this is a bad node, check the start node
//
while ( (pArrObject[idxStart] == NULL ||
pArrObject[idxStart]->Name == NULL) &&
idxStart <= idxEnd ) {
idxStart++;
}
if ( idxStart <= idxEnd ) {
//
// check the start node
//
CompFlag = _wcsicmp(ItemName, pArrObject[idxStart]->Name);
*pFindIndex = idxStart;
if ( CompFlag == 0 ) {
// find it
break;
} else if ( CompFlag < 0 ) {
//
// the item is less than idxStart - no match
//
break;
} else {
//
// the item is between theStart and idxEnd
//
if ( idxStart == idxEnd ) {
// empty now. quit
break;
} else {
idxStart++;
}
}
}
} else {
CompFlag = _wcsicmp(ItemName, pArrObject[theIndex]->Name);
*pFindIndex = theIndex;
if ( CompFlag == 0 ) {
// find it
break;
} else if ( CompFlag < 0 ) {
//
// the item is between index idxStart and theIndex
//
if ( theIndex == idxStart ) {
// empty now. quit
break;
} else {
idxEnd = theIndex-1;
}
} else {
//
// the item is between theIndex and idxEnd
//
if ( theIndex == idxEnd ) {
// empty now. quit
break;
} else {
idxStart = theIndex+1;
}
}
}
} while ( idxStart <= idxEnd );
if ( CompFlag == 0 ) {
return(TRUE);
} else {
return(FALSE);
}
}
DWORD
ScepAddItemToChildren(
IN PSCE_OBJECT_CHILDREN_NODE ThisNode OPTIONAL,
IN PWSTR ItemName,
IN DWORD NameLen,
IN BOOL IsContainer,
IN BYTE Status,
IN DWORD ChildCount,
IN OUT PSCE_OBJECT_CHILDREN_NODE **ppArrObject,
IN OUT DWORD *pArrCount,
IN OUT DWORD *pMaxCount,
IN OUT LONG *pFindIndex
)
/*
Routine Description:
Add a node to the children array. If the node is allocated, the pointer
will be added to the array; otherwise, a new allocation is made for the
new node.
The node's name will be first checked in the array for duplicate. If
pFindIndex is specified (not -1), the index will be first used to locate
the node. If the new node's name is found in the array, it won't be
added.
Return Value:
ERROR_DUP_NAME duplicate node name is found, node is not added to the array
ERROR_SUCCESS succeed
other errors
*/
{
if ( ItemName == NULL ||
ppArrObject == NULL ||
pArrCount == NULL ||
pMaxCount == NULL ||
pFindIndex == NULL ) {
return(ERROR_INVALID_PARAMETER);
}
DWORD rc=ERROR_SUCCESS;
if ( *ppArrObject == NULL ||
*pArrCount == 0 ) {
*pArrCount = 0;
*pMaxCount = 0;
*pFindIndex = -1;
} else if ( ( *pFindIndex < 0 ) ||
( *pFindIndex >= (LONG)(*pArrCount) ) ||
( (*ppArrObject)[*pFindIndex] == NULL ) ||
( (*ppArrObject)[*pFindIndex]->Name == NULL) ) {
//
// should search for the closest node
//
if ( ScepSearchItemInChildren(
ItemName,
NameLen,
*ppArrObject,
*pArrCount,
pFindIndex
) ) {
return(ERROR_DUP_NAME);
}
}
INT CompFlag=-1;
if ( *pFindIndex >= 0 ) {
//
// check if the closest node matches the new node
//
CompFlag = _wcsicmp( ItemName, (*ppArrObject)[*pFindIndex]->Name );
if ( CompFlag == 0 ) {
return(ERROR_DUP_NAME);
}
}
PSCE_OBJECT_CHILDREN_NODE pNodeToAdd;
if ( ThisNode == NULL ) {
//
// allocate a new node
//
pNodeToAdd = (PSCE_OBJECT_CHILDREN_NODE)ScepAlloc(0, sizeof(SCE_OBJECT_CHILDREN_NODE));
if ( NameLen == 0 ) {
NameLen = wcslen(ItemName);
}
if ( pNodeToAdd ) {
pNodeToAdd->Name = (PWSTR)ScepAlloc(0, (NameLen+1)*sizeof(WCHAR));
if ( pNodeToAdd->Name ) {
wcscpy(pNodeToAdd->Name, ItemName);
pNodeToAdd->IsContainer = IsContainer;
pNodeToAdd->Status = Status;
pNodeToAdd->Count = ChildCount;
} else {
rc = ERROR_NOT_ENOUGH_MEMORY;
ScepFree(pNodeToAdd);
pNodeToAdd = NULL;
}
} else {
rc = ERROR_NOT_ENOUGH_MEMORY;
}
} else {
pNodeToAdd = ThisNode;
}
if ( ERROR_SUCCESS == rc ) {
LONG idxAdd, i;
if ( *pFindIndex >= 0 ) {
if ( CompFlag < 0 ) {
//
// add the new node before pFindIndex
//
idxAdd = *pFindIndex;
} else {
//
// add the new node after pFindIndex
//
idxAdd = *pFindIndex+1;
}
} else {
idxAdd = 0;
}
if ( *pArrCount >= *pMaxCount ) {
//
// there is not enough array nodes to hold the new node
//
PSCE_OBJECT_CHILDREN_NODE *pNewArray;
PBYTE pTmpBuffer;
pTmpBuffer = (PBYTE)ScepAlloc(0, 2*sizeof(DWORD)+(*pMaxCount+SCE_ALLOC_MAX_NODE)*sizeof(PSCE_OBJECT_CHILDREN_NODE));
if ( pTmpBuffer == NULL ) {
rc = ERROR_NOT_ENOUGH_MEMORY;
} else {
//
// need to shift two DWORDs for the array start
//
pNewArray = (PSCE_OBJECT_CHILDREN_NODE *)(pTmpBuffer + 2*sizeof(DWORD));
LONG idxStart1, idxEnd1, idxStart2, idxEnd2;
if ( *pFindIndex >= 0 ) {
if ( CompFlag < 0 ) {
//
// add the new node before pFindIndex
//
idxEnd1 = *pFindIndex-1;
idxStart2 = *pFindIndex;
} else {
//
// add the new node after pFindIndex
//
idxEnd1 = *pFindIndex;
idxStart2 = *pFindIndex+1;
}
idxStart1 = 0;
idxEnd2 = *pArrCount-1;
} else {
idxStart1 = -1;
idxEnd1 = -1;
idxStart2 = 0;
idxEnd2 = *pArrCount-1;
}
//
// make the copy
//
LONG j=0;
for ( i=idxStart1; i<=idxEnd1 && i>=0; i++ ) {
pNewArray[j++] = (*ppArrObject)[i];
}
pNewArray[idxAdd] = pNodeToAdd;
j = idxAdd+1;
for ( i=idxStart2; i<=idxEnd2 && i>=0; i++ ) {
pNewArray[j++] = (*ppArrObject)[i];
}
(*pMaxCount) += SCE_ALLOC_MAX_NODE;
(*pArrCount)++;
//
// free the old list
//
if ( *ppArrObject ) {
ScepFree((PBYTE)(*ppArrObject)-2*sizeof(DWORD));
}
*ppArrObject = pNewArray;
*pFindIndex = idxAdd;
}
} else {
//
// the buffer is big enough, just add the node to the buffer
//
//
// make the copy
//
for ( i=*pArrCount-1; i>=idxAdd && i>=0; i-- ) {
(*ppArrObject)[i+1] = (*ppArrObject)[i];
}
(*ppArrObject)[idxAdd] = pNodeToAdd;
(*pArrCount)++;
*pFindIndex = idxAdd;
}
}
//
// release memory if it fails
//
if ( ERROR_SUCCESS != rc &&
pNodeToAdd &&
pNodeToAdd != ThisNode ) {
ScepFree(pNodeToAdd->Name);
ScepFree(pNodeToAdd);
}
return(rc);
}