You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
11766 lines
368 KiB
11766 lines
368 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
config.c
|
|
|
|
Abstract:
|
|
|
|
Routines to configure system to comply the security profile information
|
|
|
|
Author:
|
|
|
|
Jin Huang (jinhuang) 7-Nov-1996
|
|
|
|
Revision History:
|
|
|
|
jinhuang 27-Jan-1997 split for client-server
|
|
|
|
--*/
|
|
|
|
#include "headers.h"
|
|
#include "serverp.h"
|
|
#include "pfp.h"
|
|
#include "kerberos.h"
|
|
#include "regvalue.h"
|
|
#include "service.h"
|
|
#include <io.h>
|
|
#include <lmcons.h>
|
|
#include <secobj.h>
|
|
#include <netlib.h>
|
|
#include "infp.h"
|
|
#include "sddl.h"
|
|
#include "queue.h"
|
|
#include "splay.h"
|
|
#include "authz.h"
|
|
#include "seopaque.h"
|
|
#include "scesetup.h"
|
|
#include "dsrole.h"
|
|
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// properties of SCP engine (thread safe variables)
|
|
//
|
|
|
|
BYTE Thread scpBuffer[sizeof(SCE_PROFILE_INFO)];
|
|
PSCE_PROFILE_INFO Thread pScpInfo=NULL;
|
|
PSCECONTEXT Thread hProfile=NULL;
|
|
LSA_HANDLE Thread LsaPrivatePolicy=NULL;
|
|
static DSROLE_MACHINE_ROLE gMachineRole = DsRole_RoleStandaloneWorkstation;
|
|
|
|
extern HINSTANCE MyModuleHandle;
|
|
extern AUTHZ_RESOURCE_MANAGER_HANDLE ghAuthzResourceManager;
|
|
extern HANDLE ghEventSamFilterAndPolicyPropExclusion;
|
|
|
|
|
|
#define SCE_PRIV_ADD TEXT("Add:")
|
|
#define SCE_PRIV_REMOVE TEXT("Remove:")
|
|
#define SCEP_NUM_LSA_QUERY_SIDS 2000
|
|
#define MAXDWORD 0xffffffff
|
|
|
|
#define SCEDCPOL_MIN_PASS_AGE 0
|
|
#define SCEDCPOL_MAX_PASS_AGE 42
|
|
#define SCEDCPOL_MIN_PASS_LEN 0
|
|
#define SCEDCPOL_PASS_SIZE 1
|
|
#define SCEDCPOL_PASS_COMP 0
|
|
#define SCEDCPOL_CLEAR_PASS 0
|
|
#define SCEDCPOL_REQUIRE_LOGON 0
|
|
#define SCEDCPOL_FORCE_LOGOFF 0
|
|
#define SCEDCPOL_ENABLE_ADMIN 1
|
|
#define SCEDCPOL_ENABLE_GUEST 0
|
|
#define SCEDCPOL_LOCK_COUNT 0
|
|
#define SCEDCPOL_LOCK_RESET 30
|
|
#define SCEDCPOL_LOCK_DURATION 30
|
|
#define SCEDCPOL_LSA_ANON_LOOKUP 1
|
|
|
|
VOID
|
|
ScepWriteSpecialRegistryValuesIntoPolicy(
|
|
PWSTR pszFileName,
|
|
PSCE_PROFILE_INFO pTemplateProfile,
|
|
PSCE_REGISTRY_VALUE_INFO pLocalRegSettings,
|
|
DWORD dwNumLocalSettings
|
|
);
|
|
|
|
|
|
DWORD
|
|
ScepGetTemplateInformation(
|
|
IN PWSTR pszFilename,
|
|
IN DWORD Area,
|
|
IN HINSTANCE hSceCliDll,
|
|
OUT PSCE_PROFILE_INFO *pProfileInfo
|
|
);
|
|
|
|
DWORD
|
|
ScepConfigureLSAPolicyObject(
|
|
IN DWORD dwLSAAnonymousNameLookup,
|
|
IN DWORD ConfigOptions,
|
|
IN PSCE_ERROR_LOG_INFO *pErrLog OPTIONAL,
|
|
OUT BOOL *pbOldLSAPolicyDifferent
|
|
);
|
|
|
|
DWORD
|
|
ScepAddAceToSecurityDescriptor(
|
|
IN DWORD AceType,
|
|
IN ACCESS_MASK AccessMask,
|
|
IN PSID pSid,
|
|
IN OUT PSECURITY_DESCRIPTOR pSDAbsolute,
|
|
IN PSECURITY_DESCRIPTOR pSDSelfRelative,
|
|
OUT PACL *ppNewAcl
|
|
);
|
|
|
|
//
|
|
// this function is defined in inftojet.cpp
|
|
//
|
|
SCESTATUS
|
|
ScepBuildNewPrivilegeList(
|
|
IN LSA_HANDLE *pPolicyHandle,
|
|
IN PWSTR PrivName,
|
|
IN PWSTR mszUsers,
|
|
IN ULONG dwBuildOption,
|
|
OUT PWSTR *pmszNewUsers,
|
|
OUT DWORD *pNewLen
|
|
);
|
|
|
|
//
|
|
// forward references
|
|
//
|
|
|
|
SCESTATUS
|
|
ScepConfigureInitialize(
|
|
IN PCWSTR InfFileName OPTIONAL,
|
|
IN PWSTR DatabaseName,
|
|
IN BOOL bAdminLogon,
|
|
IN DWORD ConfigOptions,
|
|
IN AREA_INFORMATION Area
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepConfigureSystemAccess(
|
|
IN PSCE_PROFILE_INFO pScpInfo,
|
|
IN DWORD ConfigOptions,
|
|
IN PSCE_ERROR_LOG_INFO *pErrLog,
|
|
IN DWORD QueueFlag
|
|
);
|
|
|
|
NTSTATUS
|
|
ScepManageAdminGuestAccounts(
|
|
IN SAM_HANDLE DomainHandle,
|
|
IN PWSTR NewName,
|
|
IN DWORD ControlFlag,
|
|
IN DWORD AccountType,
|
|
IN DWORD ConfigOptions,
|
|
IN PSCESECTION hSectionDomain,
|
|
IN PSCESECTION hSectionTattoo
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepConfigurePrivileges(
|
|
IN OUT PSCE_PRIVILEGE_VALUE_LIST *ppPrivilegeAssigned,
|
|
IN BOOL bCreateBuiltinAccount,
|
|
IN DWORD Options,
|
|
IN OUT PSCEP_SPLAY_TREE pIgnoreAccounts OPTIONAL
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepGetPrivilegeMask(
|
|
IN PSCECONTEXT hProfile,
|
|
IN SCETYPE ProfileType,
|
|
OUT PDWORD pdLowMask,
|
|
OUT PDWORD pdHighMask
|
|
);
|
|
|
|
DWORD
|
|
ScepCreateBuiltinAccountInLsa(
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN LPTSTR AccountName,
|
|
OUT PSID AccountSid
|
|
);
|
|
|
|
NTSTATUS
|
|
ScepAdjustAccountPrivilegesRights(
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN PSID AccountSid,
|
|
IN DWORD PrivilegeLowRights,
|
|
IN DWORD PrivilegeLowMask,
|
|
IN DWORD PrivilegeHighRights,
|
|
IN DWORD PrivilegeHighMask,
|
|
IN DWORD Options
|
|
);
|
|
|
|
NTSTATUS
|
|
ScepAddOrRemoveAccountRights(
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN PSID AccountSid,
|
|
IN BOOL AddOrRemove,
|
|
IN DWORD PrivLowAdjust,
|
|
IN DWORD PrivHighAdjust
|
|
);
|
|
|
|
NTSTATUS
|
|
ScepValidateUserInGroups(
|
|
IN SAM_HANDLE DomainHandle,
|
|
IN SAM_HANDLE BuiltinDomainHandle,
|
|
IN PSID DomainSid,
|
|
IN UNICODE_STRING UserName,
|
|
IN ULONG UserId,
|
|
IN PSCE_NAME_LIST pGroupsToCheck
|
|
);
|
|
|
|
NTSTATUS
|
|
ScepAddUserToGroup(
|
|
IN SAM_HANDLE DomainHandle,
|
|
IN SAM_HANDLE BuiltinDomainHandle,
|
|
IN ULONG UserId,
|
|
IN PSID AccountSid,
|
|
IN PWSTR GroupName
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepConfigureGroupMembership(
|
|
IN PSCE_GROUP_MEMBERSHIP pGroupMembership,
|
|
IN DWORD ConfigOptions
|
|
);
|
|
|
|
NTSTATUS
|
|
ScepConfigureMembersOfGroup(
|
|
IN PSCESECTION hSectionDomain,
|
|
IN PSCESECTION hSectionTattoo,
|
|
IN SAM_HANDLE DomainHandle,
|
|
IN PSID ThisDomainSid,
|
|
IN ULONG GrpId,
|
|
IN PSID GrpSid,
|
|
IN PWSTR GrpName,
|
|
IN PWSTR GroupSidString,
|
|
IN PSCE_NAME_LIST pMembers,
|
|
IN DWORD ConfigOptions
|
|
);
|
|
|
|
NTSTATUS
|
|
ScepConfigureMembersOfAlias(
|
|
IN PSCESECTION hSectionDomain,
|
|
IN PSCESECTION hSectionTattoo,
|
|
IN SAM_HANDLE DomainHandle,
|
|
IN PSID DomainSid,
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN ULONG GrpId,
|
|
IN PSID GrpSid,
|
|
IN PWSTR GrpName,
|
|
IN PWSTR GroupSidString,
|
|
IN PSCE_NAME_LIST pMembers,
|
|
IN DWORD ConfigOptions
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepValidateGroupInAliases(
|
|
IN SAM_HANDLE DomainHandle,
|
|
IN SAM_HANDLE BuiltinDomainHandle,
|
|
IN PSCESECTION hSectionTattoo,
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN PSID GrpSid,
|
|
IN PSCE_NAME_LIST pAliasList,
|
|
bool fProcessTattoo
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepConfigureObjectSecurity(
|
|
IN PSCE_OBJECT_LIST pSecurityObject,
|
|
IN AREA_INFORMATION Area,
|
|
IN BOOL bPolicyProp,
|
|
IN DWORD ConfigOptions
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepConfigureSystemAuditing(
|
|
IN PSCE_PROFILE_INFO pScpInfo,
|
|
IN DWORD ConfigOptions
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepConfigureAuditEvent(
|
|
IN PSCE_PROFILE_INFO pScpInfo,
|
|
IN PPOLICY_AUDIT_EVENTS_INFO auditEvent,
|
|
IN DWORD Options,
|
|
IN LSA_HANDLE PolicyHandle
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepConfigureDeInitialize(
|
|
IN SCESTATUS rc,
|
|
IN AREA_INFORMATION Area
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepMakePolicyIntoFile(
|
|
IN DWORD Options,
|
|
IN AREA_INFORMATION Area
|
|
);
|
|
|
|
DWORD
|
|
ScepWriteOneAttributeToFile(
|
|
IN LPCTSTR SectionName,
|
|
IN LPCTSTR FileName,
|
|
IN LPCTSTR KeyName,
|
|
IN DWORD dwValue
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepCopyPrivilegesIntoFile(
|
|
IN LPTSTR FileName,
|
|
IN BOOL bInUpgrade
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepCopyPrivilegesFromDatabase(
|
|
IN PSCESECTION hSection,
|
|
IN PWSTR Keyname,
|
|
IN DWORD StrLength,
|
|
IN PWSTR StrValue OPTIONAL,
|
|
OUT PWSTR *pOldValue,
|
|
OUT DWORD *pOldLen
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepDeleteDomainPolicies();
|
|
|
|
SCESTATUS
|
|
ScepConfigurePrivilegesWithMask(
|
|
IN OUT PSCE_PRIVILEGE_VALUE_LIST *ppPrivilegeAssigned,
|
|
IN BOOL bCreateBuiltinAccount,
|
|
IN DWORD Options,
|
|
IN DWORD LowMask,
|
|
IN DWORD HighMask,
|
|
IN OUT PSCE_ERROR_LOG_INFO *pErrLog OPTIONAL,
|
|
IN OUT PSCEP_SPLAY_TREE pIgnoreAccounts OPTIONAL
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepConfigurePrivilegesByRight(
|
|
IN PSCE_PRIVILEGE_ASSIGNMENT pPrivAssign,
|
|
IN DWORD Options,
|
|
IN OUT PSCE_ERROR_LOG_INFO *pErrLog
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepTattooUpdatePrivilegeArrayStatus(
|
|
IN DWORD *pStatusArray,
|
|
IN DWORD rc,
|
|
IN DWORD PrivLowMask,
|
|
IN DWORD PrivHighMask
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepTattooRemovePrivilegeValues(
|
|
IN PSCECONTEXT hProfile,
|
|
IN DWORD *pStatusArray
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepTattooSavePrivilegeValues(
|
|
IN PSCECONTEXT hProfile,
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN DWORD PrivLowMask,
|
|
IN DWORD PrivHighMask,
|
|
IN DWORD ConfigOptions
|
|
);
|
|
|
|
DWORD
|
|
ScepTattooCurrentGroupMembers(
|
|
IN PSID ThisDomainSid,
|
|
IN PSID GrpSid,
|
|
IN SID_NAME_USE GrpUse,
|
|
IN PULONG MemberRids OPTIONAL,
|
|
IN PSID *MemberAliasSids OPTIONAL,
|
|
IN DWORD MemberCount,
|
|
OUT PSCE_NAME_LIST *ppNameList
|
|
);
|
|
|
|
VOID
|
|
ScepBuildDwMaskFromStrArray(
|
|
IN PUNICODE_STRING aUserRights,
|
|
IN ULONG uCountOfRights,
|
|
OUT DWORD *pdwPrivLowThisAccount,
|
|
OUT DWORD *pdwPrivHighThisAccount
|
|
);
|
|
|
|
|
|
#define SCEP_REMOVE_PRIV_BIT(b,pl,ph) \
|
|
if ( b < 32 ) { \
|
|
*pl &= ~(1 << b); \
|
|
} else if ( b >= 32 && b < 64 ) { \
|
|
*ph &= ~( 1 << (b-32)); \
|
|
}
|
|
|
|
#define SCEP_ADD_PRIV_BIT(b,l,h) \
|
|
if ( b < 32 ) { \
|
|
l |= (1 << b); \
|
|
} else if ( b >= 32 && b < 64 ) { \
|
|
h |= ( 1 << (b-32)); \
|
|
}
|
|
|
|
#define SCEP_CHECK_PRIV_BIT(i,pl,ph) \
|
|
( (i < 32) && ( pl & (1 << i)) ) || \
|
|
( (i >= 32) && ( ph & ( 1 << (i-32)) ) )
|
|
|
|
|
|
SCESTATUS
|
|
ScepCheckNetworkLogonRights(
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN OUT DWORD *pLowMask,
|
|
IN OUT DWORD *pHighMask,
|
|
IN OUT PSCE_PRIVILEGE_VALUE_LIST *ppPrivilegeAssigned
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepAddAccountRightToList(
|
|
IN OUT PSCE_PRIVILEGE_VALUE_LIST *ppPrivilegeAssigned,
|
|
IN OUT PSCE_PRIVILEGE_VALUE_LIST *ppParent,
|
|
IN INT idxRight,
|
|
IN PSID AccountSid
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepConfigureLSAAnonymousLookup(
|
|
IN PSCE_PROFILE_INFO pScpInfo,
|
|
IN DWORD ConfigOptions,
|
|
IN PSCE_ERROR_LOG_INFO *pErrLog
|
|
);
|
|
|
|
|
|
//
|
|
// function implementations
|
|
//
|
|
SCESTATUS
|
|
ScepConfigureSystem(
|
|
IN PCWSTR InfFileName OPTIONAL,
|
|
IN PWSTR DatabaseName,
|
|
IN DWORD ConfigOptions,
|
|
IN BOOL bAdminLogon,
|
|
IN AREA_INFORMATION Area,
|
|
OUT PDWORD pdWarning OPTIONAL
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine updates
|
|
This routine is the exported API to configure a system by applying a SCP
|
|
file (INF) to the system. I a INF template is provided, it is first parsed
|
|
and saved in the SAD database. Then the system is configured using the info
|
|
in the template.
|
|
|
|
If any error occurs when loading SCP information, configuration will stop,
|
|
and return the error code. If a error occurs when configure an area, it will
|
|
stop configuring the whole area but continue to configure other left areas.
|
|
All success and fail transactions will be logged to the logfile(or stdout).
|
|
|
|
Log is already initialized before this call
|
|
|
|
Arguments:
|
|
|
|
InfFileName - The SCP file name
|
|
|
|
DatabaseName - The file name of the JET (for future analysis) profile
|
|
|
|
ConfigOptions - if the template provided is to update the system, or overwrite
|
|
|
|
Area - one or more areas to configure.
|
|
AREA_SECURITY_POLICY
|
|
AREA_USER_SETTINGS // block out for beta1
|
|
AREA_GROUP_MEMBERSHIP
|
|
AREA_PRIVILEGES
|
|
AREA_REGISTRY_SECURITY
|
|
AREA_FILE_SECURITY
|
|
AREA_SYSTEM_SERVICE
|
|
|
|
pdWarning - the warning code
|
|
|
|
Return value:
|
|
|
|
SCESTATUS_SUCCESS
|
|
SCESTATUS_NOT_ENOUGH_RESOURCE
|
|
SCESTATUS_INVALID_PARAMETER
|
|
SCESTATUS_ALREADY_RUNNING
|
|
|
|
Status from ScepGetDatabaseInfo
|
|
|
|
-- */
|
|
{
|
|
SCESTATUS rc, Saverc;
|
|
SCESTATUS PendingRc=SCESTATUS_SUCCESS;
|
|
PSCE_ERROR_LOG_INFO pErrlog=NULL;
|
|
PPOLICY_AUDIT_EVENTS_INFO auditEvent=NULL;
|
|
BOOL bAuditOff=FALSE;
|
|
// PBYTE pFullAudit = NULL;
|
|
PSCEP_SPLAY_TREE pNotifyAccounts=NULL;
|
|
DWORD QueueFlag=0;
|
|
|
|
Saverc = ScepConfigureInitialize(
|
|
InfFileName,
|
|
DatabaseName,
|
|
bAdminLogon,
|
|
ConfigOptions,
|
|
Area );
|
|
|
|
if ( Saverc != SCESTATUS_SUCCESS ) {
|
|
|
|
ScepPostProgress(gTotalTicks, 0, NULL);
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_INIT_ERROR);
|
|
|
|
} else if ( !(ConfigOptions & SCE_NO_CONFIG) ) {
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_INIT_SUCCESS);
|
|
|
|
Area &= ~AREA_USER_SETTINGS;
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
(ConfigOptions & SCE_NO_CONFIG_FILEKEY) ) {
|
|
//
|
|
// if within policy propagation (at reboot) and
|
|
// this is the foreground thread, do not configure
|
|
// file and registry sections. They will be configured
|
|
// in background thread separately.
|
|
//
|
|
Area &= ~(AREA_FILE_SECURITY | AREA_REGISTRY_SECURITY);
|
|
}
|
|
|
|
//
|
|
// get information from the notification queue so that
|
|
// pending notifications are ignored
|
|
//
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( (Area & AREA_PRIVILEGES) ||
|
|
(Area & AREA_SECURITY_POLICY) ) ) {
|
|
//
|
|
// return error is ignored so policy prop will overwrite
|
|
//
|
|
|
|
__try {
|
|
|
|
//
|
|
// initialize the root TreeNode
|
|
//
|
|
if ( NULL == (pNotifyAccounts = ScepSplayInitialize(SplayNodeSidType)) ) {
|
|
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
ScepLogOutput3(1, ERROR_NOT_ENOUGH_MEMORY, SCESRV_POLICY_ERROR_SPLAY_INITIALIZE);
|
|
|
|
} else if ( ERROR_SUCCESS != (rc=ScepGetQueueInfo(&QueueFlag, pNotifyAccounts)) ) {
|
|
QueueFlag = 0;
|
|
|
|
ScepLogOutput3(1,rc, SCESRV_POLICY_PENDING_QUERY);
|
|
}
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
QueueFlag = 0;
|
|
rc = ERROR_IO_PENDING;
|
|
|
|
ScepLogOutput3(1,rc, SCESRV_POLICY_PENDING_QUERY);
|
|
}
|
|
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
|
|
PendingRc = ScepDosErrorToSceStatus(rc);
|
|
|
|
ScepPostProgress(gTotalTicks, 0, NULL);
|
|
|
|
goto Done;
|
|
}
|
|
}
|
|
|
|
if ( ConfigOptions & SCE_POLICY_TEMPLATE ) {
|
|
//
|
|
// always resume the queue processing after queue info is queried
|
|
//
|
|
ScepNotificationQControl(0);
|
|
}
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_READ_PROFILE);
|
|
Saverc = ScepGetDatabaseInfo(
|
|
hProfile,
|
|
( ConfigOptions & SCE_POLICY_TEMPLATE ) ?
|
|
SCE_ENGINE_SCP_INTERNAL : SCE_ENGINE_SMP_INTERNAL,
|
|
Area,
|
|
SCE_ACCOUNT_SID,
|
|
&pScpInfo,
|
|
&pErrlog
|
|
);
|
|
|
|
ScepLogWriteError( pErrlog, 1 );
|
|
ScepFreeErrorLog( pErrlog );
|
|
pErrlog = NULL;
|
|
|
|
if ( Saverc != SCESTATUS_SUCCESS ) {
|
|
|
|
ScepPostProgress(gTotalTicks, 0, NULL);
|
|
|
|
goto Done;
|
|
}
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
Saverc = SCESTATUS_SERVICE_NOT_SUPPORT;
|
|
goto Done;
|
|
}
|
|
|
|
/* //
|
|
// 462050 - should not turn off object access auditing to leave a
|
|
// security hole on the system
|
|
//
|
|
// turn off object access auditing if file/key is to be configured
|
|
// in system context.
|
|
//
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( (Area & AREA_FILE_SECURITY) && pScpInfo->pFiles.pOneLevel ) ||
|
|
( (Area & AREA_REGISTRY_SECURITY) && pScpInfo->pRegistryKeys.pOneLevel ) )
|
|
|
|
bAuditOff = TRUE;
|
|
|
|
//
|
|
// if set, this regkey will decide to audit all
|
|
//
|
|
ScepRegQueryBinaryValue(
|
|
HKEY_LOCAL_MACHINE,
|
|
L"System\\CurrentControlSet\\Control\\Lsa",
|
|
L"fullprivilegeauditing",
|
|
&pFullAudit
|
|
);
|
|
|
|
if (pFullAudit) {
|
|
if (*pFullAudit & (BYTE)1)
|
|
bAuditOff = FALSE;
|
|
ScepFree(pFullAudit);
|
|
}
|
|
*/
|
|
Saverc = ScepSaveAndOffAuditing(&auditEvent, bAuditOff, LsaPrivatePolicy);
|
|
|
|
// if ( Saverc != SCESTATUS_SUCCESS )
|
|
// goto Done;
|
|
// if auditing can't be turned on for some reason, e.g., access denied for
|
|
// normal user, just continue
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
Saverc = SCESTATUS_SERVICE_NOT_SUPPORT;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// User Settings area
|
|
//
|
|
Saverc = 0;
|
|
if ( Area & AREA_PRIVILEGES ) {
|
|
|
|
ScepPostProgress(0, AREA_PRIVILEGES, NULL);
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_BEGIN_PRIVILEGES);
|
|
|
|
rc = ScepConfigurePrivileges( &(pScpInfo->OtherInfo.scp.u.pPrivilegeAssignedTo),
|
|
(ConfigOptions & SCE_CREATE_BUILTIN_ACCOUNTS),
|
|
(bAdminLogon ?
|
|
ConfigOptions :
|
|
(ConfigOptions & ~SCE_SYSTEM_DB)),
|
|
(QueueFlag & SCE_QUEUE_INFO_RIGHTS) ? pNotifyAccounts : NULL
|
|
);
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
if ( rc != SCESTATUS_PENDING_IGNORE )
|
|
Saverc = rc;
|
|
else
|
|
PendingRc = rc;
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_PRIVILEGES_ERROR);
|
|
} else {
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_PRIVILEGES_SUCCESS);
|
|
}
|
|
}
|
|
|
|
if ( pNotifyAccounts ) {
|
|
ScepSplayFreeTree(&pNotifyAccounts, TRUE);
|
|
}
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
Saverc = SCESTATUS_SERVICE_NOT_SUPPORT;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Group Membership area
|
|
//
|
|
if ( Area & AREA_GROUP_MEMBERSHIP) {
|
|
|
|
ScepPostProgress(0, AREA_GROUP_MEMBERSHIP, NULL);
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_BEGIN_GROUPMGMT);
|
|
|
|
#if _WIN32_WINNT>=0x0500
|
|
// need to support nested groups
|
|
|
|
if ( ProductType == NtProductLanManNt ) {
|
|
|
|
rc = ScepConfigDsGroups( pScpInfo->pGroupMembership, ConfigOptions );
|
|
|
|
//
|
|
// some groups (such as local groups) may not be configured in DS
|
|
// so try it in SAM
|
|
//
|
|
SCESTATUS rc2 = ScepConfigureGroupMembership(pScpInfo->pGroupMembership, ConfigOptions );
|
|
if ( rc2 != SCESTATUS_SUCCESS )
|
|
rc = rc2;
|
|
|
|
} else {
|
|
#endif
|
|
|
|
rc = ScepConfigureGroupMembership( pScpInfo->pGroupMembership, ConfigOptions );
|
|
|
|
#if _WIN32_WINNT>=0x0500
|
|
}
|
|
#endif
|
|
|
|
if ( rc != SCESTATUS_SUCCESS) {
|
|
Saverc = rc;
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_GROUPMGMT_ERROR);
|
|
} else {
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_GROUPMGMT_SUCCESS);
|
|
}
|
|
|
|
}
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
Saverc = SCESTATUS_SERVICE_NOT_SUPPORT;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Registry Security area
|
|
//
|
|
|
|
if ( Area & AREA_REGISTRY_SECURITY ) {
|
|
|
|
ScepPostProgress(0,
|
|
AREA_REGISTRY_SECURITY,
|
|
NULL);
|
|
|
|
//
|
|
// Disable reflector on ia64 systems
|
|
//
|
|
|
|
#ifdef _WIN64
|
|
Wow64Win32ApiEntry (1, 1, 0);
|
|
#endif
|
|
|
|
rc = ScepConfigureObjectSecurity( pScpInfo->pRegistryKeys.pOneLevel,
|
|
AREA_REGISTRY_SECURITY,
|
|
(ConfigOptions & SCE_POLICY_TEMPLATE) ? TRUE : FALSE,
|
|
ConfigOptions
|
|
);
|
|
//
|
|
// Enable reflector on ia64 systems
|
|
//
|
|
|
|
#ifdef _WIN64
|
|
Wow64Win32ApiEntry (1, 2, 0);
|
|
#endif
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
Saverc = rc;
|
|
}
|
|
}
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
Saverc = SCESTATUS_SERVICE_NOT_SUPPORT;
|
|
goto Done;
|
|
}
|
|
//
|
|
// File Security area
|
|
//
|
|
|
|
if ( Area & AREA_FILE_SECURITY ) {
|
|
|
|
ScepPostProgress(0,
|
|
AREA_FILE_SECURITY,
|
|
NULL);
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_BEGIN_FILE);
|
|
|
|
rc = ScepConfigureObjectSecurity( pScpInfo->pFiles.pOneLevel,
|
|
AREA_FILE_SECURITY,
|
|
(ConfigOptions & SCE_POLICY_TEMPLATE) ? TRUE : FALSE,
|
|
ConfigOptions
|
|
);
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
Saverc = rc;
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_FILE_ERROR);
|
|
} else {
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_FILE_SUCCESS);
|
|
}
|
|
|
|
}
|
|
|
|
#if 0
|
|
#if _WIN32_WINNT>=0x0500
|
|
if ( (ProductType == NtProductLanManNt) && (Area & AREA_DS_OBJECTS) ) {
|
|
|
|
ScepPostProgress(0,
|
|
AREA_DS_OBJECTS,
|
|
NULL);
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_BEGIN_DS);
|
|
|
|
rc = ScepConfigureObjectSecurity( pScpInfo->pDsObjects.pOneLevel,
|
|
AREA_DS_OBJECTS,
|
|
(ConfigOptions & SCE_POLICY_TEMPLATE) ? TRUE : FALSE,
|
|
ConfigOptions
|
|
);
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
Saverc = rc;
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_DS_ERROR);
|
|
} else {
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_DS_SUCCESS);
|
|
}
|
|
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
Saverc = SCESTATUS_SERVICE_NOT_SUPPORT;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// System Service area
|
|
//
|
|
|
|
if ( Area & AREA_SYSTEM_SERVICE ) {
|
|
|
|
ScepPostProgress(0,
|
|
AREA_SYSTEM_SERVICE,
|
|
NULL);
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_BEGIN_GENERALSVC);
|
|
|
|
rc = ScepConfigureGeneralServices( hProfile, pScpInfo->pServices, ConfigOptions );
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
Saverc = rc;
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_GENERALSVC_ERROR);
|
|
} else {
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_GENERALSVC_SUCCESS);
|
|
}
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_BEGIN_ATTACHMENT);
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
rc = SCESTATUS_SERVICE_NOT_SUPPORT;
|
|
|
|
} else {
|
|
|
|
rc = ScepInvokeSpecificServices( hProfile, TRUE, SCE_ATTACHMENT_SERVICE );
|
|
}
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
Saverc = rc;
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_ATTACHMENT_ERROR);
|
|
} else {
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_ATTACHMENT_SUCCESS);
|
|
}
|
|
|
|
}
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
Saverc = SCESTATUS_SERVICE_NOT_SUPPORT;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Security policy
|
|
//
|
|
|
|
if ( Area & AREA_SECURITY_POLICY ) {
|
|
|
|
ScepPostProgress(0,
|
|
AREA_SECURITY_POLICY,
|
|
NULL);
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_BEGIN_POLICY);
|
|
|
|
if ( !( ConfigOptions & SCE_NO_DOMAIN_POLICY ||
|
|
ConfigOptions & SCE_POLICY_TEMPLATE &&
|
|
gMachineRole == DsRole_RoleBackupDomainController) ) {
|
|
|
|
rc = ScepConfigureSystemAccess( pScpInfo, ConfigOptions, NULL, QueueFlag );
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
if ( rc != SCESTATUS_PENDING_IGNORE )
|
|
Saverc = rc;
|
|
else
|
|
PendingRc = rc;
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_ACCESS_ERROR);
|
|
} else {
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_ACCESS_SUCCESS);
|
|
}
|
|
}
|
|
|
|
rc = ScepConfigureLSAAnonymousLookup( pScpInfo, ConfigOptions, NULL );
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
Saverc = rc;
|
|
}
|
|
|
|
ScepPostProgress(TICKS_SYSTEM_ACCESS,
|
|
AREA_SECURITY_POLICY,
|
|
(LPTSTR)szSystemAccess);
|
|
//
|
|
// System Auditing area
|
|
//
|
|
rc = ScepConfigureSystemAuditing( pScpInfo, ConfigOptions );
|
|
|
|
if ( rc == SCESTATUS_SUCCESS && NULL != auditEvent ) {
|
|
|
|
//
|
|
// not in policy prop or
|
|
// no pending notify for audit
|
|
//
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
(QueueFlag & SCE_QUEUE_INFO_AUDIT) ) {
|
|
|
|
|
|
rc = ERROR_IO_PENDING;
|
|
ScepLogOutput3(0, 0, SCESRV_POLICY_PENDING_AUDIT);
|
|
|
|
if (ConfigOptions & SCE_RSOP_CALLBACK)
|
|
ScepRsopLog(SCE_RSOP_AUDIT_EVENT_INFO, rc, NULL,0,0);
|
|
|
|
rc = ScepDosErrorToSceStatus(rc);
|
|
|
|
} else {
|
|
|
|
rc = ScepConfigureAuditEvent(pScpInfo,
|
|
auditEvent,
|
|
bAdminLogon ?
|
|
ConfigOptions :
|
|
(ConfigOptions & ~SCE_SYSTEM_DB),
|
|
LsaPrivatePolicy
|
|
);
|
|
}
|
|
}
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
if ( rc != SCESTATUS_PENDING_IGNORE )
|
|
Saverc = rc;
|
|
else
|
|
PendingRc = rc;
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_AUDIT_ERROR);
|
|
} else {
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_AUDIT_SUCCESS);
|
|
}
|
|
|
|
ScepPostProgress(TICKS_SYSTEM_AUDITING,
|
|
AREA_SECURITY_POLICY,
|
|
(LPTSTR)szAuditEvent);
|
|
|
|
#if _WIN32_WINNT>=0x0500
|
|
if ( ProductType == NtProductLanManNt &&
|
|
!(ConfigOptions & SCE_NO_DOMAIN_POLICY ) ) {
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
rc = SCESTATUS_SERVICE_NOT_SUPPORT;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Kerberos Policy
|
|
//
|
|
rc = ScepConfigureKerberosPolicy( hProfile,
|
|
pScpInfo->pKerberosInfo,
|
|
ConfigOptions );
|
|
}
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
Saverc = rc;
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_KERBEROS_ERROR);
|
|
} else {
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_KERBEROS_SUCCESS);
|
|
}
|
|
|
|
}
|
|
#endif
|
|
ScepPostProgress(TICKS_KERBEROS,
|
|
AREA_SECURITY_POLICY,
|
|
(LPTSTR)szKerberosPolicy);
|
|
|
|
//
|
|
// registry values
|
|
//
|
|
rc = ScepConfigureRegistryValues( hProfile,
|
|
pScpInfo->aRegValues,
|
|
pScpInfo->RegValueCount,
|
|
NULL,
|
|
ConfigOptions,
|
|
NULL );
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
Saverc = rc;
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_REGVALUES_ERROR);
|
|
} else {
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_REGVALUES_SUCCESS);
|
|
}
|
|
|
|
ScepPostProgress(TICKS_REGISTRY_VALUES,
|
|
AREA_SECURITY_POLICY,
|
|
(LPTSTR)szRegistryValues);
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_BEGIN_ATTACHMENT);
|
|
|
|
//
|
|
// implemented in service.cpp
|
|
//
|
|
rc = ScepInvokeSpecificServices( hProfile, TRUE, SCE_ATTACHMENT_POLICY );
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
Saverc = rc;
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_ATTACHMENT_ERROR);
|
|
} else {
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_ATTACHMENT_SUCCESS);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Done:
|
|
|
|
if ( pNotifyAccounts ) {
|
|
ScepSplayFreeTree(&pNotifyAccounts, TRUE);
|
|
}
|
|
|
|
if ( NULL != auditEvent ) {
|
|
if ( bAuditOff && auditEvent->AuditingMode ) {
|
|
|
|
rc = ScepRestoreAuditing(auditEvent, LsaPrivatePolicy);
|
|
}
|
|
LsaFreeMemory(auditEvent);
|
|
}
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_UNINIT);
|
|
|
|
if ( pdWarning ) {
|
|
*pdWarning = gWarningCode;
|
|
}
|
|
|
|
//
|
|
// return failure if invalid data is found in the template
|
|
//
|
|
if ( gbInvalidData ) {
|
|
Saverc = SCESTATUS_INVALID_DATA;
|
|
}
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
!(ConfigOptions & SCE_NO_CONFIG) ) {
|
|
//
|
|
// always resume the queue processing after configuration is done
|
|
//
|
|
ScepNotificationQControl(0);
|
|
}
|
|
|
|
if ( Saverc == SCESTATUS_SUCCESS ) Saverc = PendingRc;
|
|
|
|
ScepConfigureDeInitialize( Saverc, Area);
|
|
|
|
return(Saverc);
|
|
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepConfigureInitialize(
|
|
IN PCWSTR InfFileName OPTIONAL,
|
|
IN PWSTR DatabaseName,
|
|
IN BOOL bAdminLogon,
|
|
IN DWORD ConfigOptions,
|
|
IN AREA_INFORMATION Area
|
|
)
|
|
/* ++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the SCP engine.
|
|
|
|
Arguments:
|
|
|
|
InfFileName - The file name of a SCP file used to configure the sytem
|
|
|
|
DatabaseName - The JET (for future analysis) profile name
|
|
|
|
ConfigOptions - If the template is to update the system instead of overwriting
|
|
|
|
Area - security area to initialize
|
|
|
|
Return value:
|
|
|
|
SCESTATUS_SUCCESS
|
|
SCESTATUS_INVALID_PARAMETER
|
|
SCESTATUS_PROFILE_NOT_FOUND
|
|
SCESTATUS_NOT_ENOUGH_RESOURCE
|
|
SCESTATUS_ALREADY_RUNNING
|
|
|
|
-- */
|
|
{
|
|
|
|
SCESTATUS rc=SCESTATUS_SUCCESS;
|
|
PCHAR FileName=NULL;
|
|
DWORD MBLen=0;
|
|
NTSTATUS NtStatus;
|
|
LARGE_INTEGER CurrentTime;
|
|
PSCE_ERROR_LOG_INFO Errlog=NULL;
|
|
PSECURITY_DESCRIPTOR pSD=NULL;
|
|
SECURITY_INFORMATION SeInfo;
|
|
DWORD SDsize;
|
|
DWORD DbNameLen;
|
|
HKEY hCurrentUser=NULL;
|
|
|
|
//
|
|
// thread variables are not guaranteed to be initialized to NULL
|
|
//
|
|
|
|
hProfile = NULL;
|
|
|
|
//
|
|
// database name can't be NULL because it's already resolved
|
|
//
|
|
|
|
if ( !DatabaseName ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|
}
|
|
|
|
//
|
|
// get other system values
|
|
//
|
|
if ( RtlGetNtProductType (&ProductType) == FALSE ) {
|
|
rc = ScepDosErrorToSceStatus(GetLastError());
|
|
goto Leave;
|
|
}
|
|
|
|
rc = ScepGetDomainRoleInfo(&gMachineRole, NULL, NULL);
|
|
if ( ERROR_SUCCESS != rc)
|
|
goto Leave;
|
|
|
|
//
|
|
// Initialize globals
|
|
//
|
|
gTotalTicks = 0;
|
|
gCurrentTicks = 0;
|
|
gWarningCode = 0;
|
|
gbInvalidData = FALSE;
|
|
|
|
//
|
|
// Initialize engine buffer
|
|
//
|
|
|
|
cbClientFlag = (BYTE)( ConfigOptions & (SCE_CALLBACK_DELTA |
|
|
SCE_CALLBACK_TOTAL ));
|
|
|
|
pScpInfo = (PSCE_PROFILE_INFO)&scpBuffer;
|
|
pScpInfo->Type = SCE_ENGINE_SCP_INTERNAL;
|
|
|
|
//
|
|
// convert WCHAR into ANSI
|
|
//
|
|
|
|
DbNameLen = wcslen(DatabaseName);
|
|
|
|
NtStatus = RtlUnicodeToMultiByteSize(&MBLen, DatabaseName, DbNameLen*sizeof(WCHAR));
|
|
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
//
|
|
// cannot get the length, set default to 512
|
|
//
|
|
MBLen = 512;
|
|
}
|
|
|
|
FileName = (PCHAR)ScepAlloc(LPTR, MBLen+2);
|
|
|
|
if ( FileName == NULL ) {
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
goto Leave;
|
|
}
|
|
|
|
NtStatus = RtlUnicodeToMultiByteN(
|
|
FileName,
|
|
MBLen+1,
|
|
NULL,
|
|
DatabaseName,
|
|
DbNameLen*sizeof(WCHAR)
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
ScepLogOutput3(1, rc, SCEDLL_ERROR_PROCESS_UNICODE, DatabaseName );
|
|
rc = ScepDosErrorToSceStatus(rc);
|
|
goto Leave;
|
|
}
|
|
|
|
if ( RegOpenCurrentUser(
|
|
KEY_READ | KEY_WRITE,
|
|
&hCurrentUser
|
|
) != ERROR_SUCCESS ) {
|
|
hCurrentUser = NULL;
|
|
}
|
|
|
|
if ( hCurrentUser == NULL ) {
|
|
hCurrentUser = HKEY_CURRENT_USER;
|
|
}
|
|
|
|
//
|
|
// delay registry filter (into database) is not needed anymore
|
|
//
|
|
|
|
if ( InfFileName != NULL ) { // || InfHandle != NULL ) {
|
|
|
|
//
|
|
// convert inf to jet
|
|
//
|
|
ScepLogOutput3(3, 0, SCEDLL_PROCESS_TEMPLATE, (PWSTR)InfFileName );
|
|
|
|
if ( bAdminLogon ) {
|
|
//
|
|
// make sure the directories exist for the file
|
|
//
|
|
rc = ConvertTextSecurityDescriptor (
|
|
L"D:P(A;CIOI;GA;;;CO)(A;CIOI;GA;;;BA)(A;CIOI;GA;;;SY)",
|
|
&pSD,
|
|
&SDsize,
|
|
&SeInfo
|
|
);
|
|
if ( rc != NO_ERROR )
|
|
ScepLogOutput3(1, rc, SCEDLL_ERROR_BUILD_SD, DatabaseName );
|
|
}
|
|
|
|
//
|
|
// change revision to ACL_REVISION2 (from 4) because it's for files
|
|
//
|
|
|
|
ScepChangeAclRevision(pSD, ACL_REVISION);
|
|
|
|
ScepCreateDirectory(
|
|
DatabaseName,
|
|
FALSE, // a file name
|
|
pSD //NULL // take parent's security setting
|
|
);
|
|
if ( pSD ) {
|
|
ScepFree(pSD);
|
|
}
|
|
|
|
if ( ConfigOptions & SCE_OVERWRITE_DB ) {
|
|
//
|
|
// only delete existing jet files if jet engine is not running
|
|
// because other threads may use the same version storage
|
|
// for other database.
|
|
//
|
|
// if jet engine is not running, delete version storage files
|
|
// will not force a recovery because overwrite db option means
|
|
// overwrite all previous info in the database.
|
|
//
|
|
SceJetDeleteJetFiles(DatabaseName);
|
|
}
|
|
|
|
//
|
|
// copy the inf sections and data to the jet database SCP table
|
|
//
|
|
|
|
if ( InfFileName != NULL ) {
|
|
|
|
SCEJET_CREATE_TYPE TmpOption;
|
|
|
|
if ( ConfigOptions & SCE_UPDATE_DB ) {
|
|
if ( ConfigOptions & SCE_POLICY_TEMPLATE ) {
|
|
TmpOption = SCEJET_OPEN_DUP;
|
|
} else {
|
|
TmpOption = SCEJET_OPEN_DUP_EXCLUSIVE;
|
|
}
|
|
} else {
|
|
TmpOption = SCEJET_OVERWRITE_DUP;
|
|
}
|
|
|
|
rc = SceJetConvertInfToJet(
|
|
InfFileName,
|
|
(LPSTR)FileName,
|
|
TmpOption,
|
|
bAdminLogon ? ConfigOptions : (ConfigOptions & ~SCE_SYSTEM_DB),
|
|
Area
|
|
);
|
|
}
|
|
|
|
if ( rc != SCESTATUS_SUCCESS ) { // SCESTATUS error code
|
|
goto Leave;
|
|
}
|
|
} else if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
(ConfigOptions & SCE_POLICY_FIRST) &&
|
|
(ConfigOptions & SCE_POLICY_LAST) ) {
|
|
//
|
|
// a policy refresh without any domain GPOs, do the local GPO only
|
|
//
|
|
|
|
rc = SceJetOpenFile(
|
|
(LPSTR)FileName,
|
|
SCEJET_OPEN_READ_WRITE, // SCEJET_OPEN_EXCLUSIVE,
|
|
SCE_TABLE_OPTION_MERGE_POLICY | SCE_TABLE_OPTION_TATTOO,
|
|
&hProfile
|
|
);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
rc = ScepDeleteInfoForAreas(
|
|
hProfile,
|
|
SCE_ENGINE_SCP,
|
|
AREA_ALL
|
|
);
|
|
|
|
if ( ( rc == SCESTATUS_SUCCESS ) ||
|
|
( rc == SCESTATUS_RECORD_NOT_FOUND ) ) {
|
|
|
|
//
|
|
// delete GPO table to start over
|
|
//
|
|
|
|
SceJetDeleteAll( hProfile,
|
|
"SmTblGpo",
|
|
SCEJET_TABLE_GPO
|
|
);
|
|
|
|
//
|
|
// copy local table
|
|
//
|
|
|
|
|
|
ScepLogOutput3(2, rc, SCEDLL_COPY_LOCAL);
|
|
|
|
rc = ScepCopyLocalToMergeTable( hProfile, ConfigOptions,
|
|
(ProductType == NtProductLanManNt) ? SCE_LOCAL_POLICY_DC : 0,
|
|
&Errlog );
|
|
|
|
ScepLogWriteError( Errlog,1 );
|
|
ScepFreeErrorLog( Errlog );
|
|
Errlog = NULL;
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
DWORD dwThisTable = hProfile->Type & 0xF0L;
|
|
|
|
if ( SCEJET_MERGE_TABLE_1 == dwThisTable ||
|
|
SCEJET_MERGE_TABLE_2 == dwThisTable ) {
|
|
|
|
rc = SceJetSetValueInVersion(
|
|
hProfile,
|
|
"SmTblVersion",
|
|
"LastUsedMergeTable",
|
|
(PWSTR)&dwThisTable,
|
|
4,
|
|
JET_prepReplace
|
|
);
|
|
}
|
|
|
|
} else {
|
|
|
|
ScepLogOutput3(1, ScepSceStatusToDosError(rc),
|
|
SCEDLL_ERROR_COPY);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ScepLogOutput3(1, ScepSceStatusToDosError(rc),
|
|
SCEDLL_ERROR_DELETE, L"SCP");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ScepLogOutput3(1, ScepSceStatusToDosError(rc),
|
|
SCEDLL_ERROR_OPEN, DatabaseName );
|
|
}
|
|
|
|
if ( rc != SCESTATUS_SUCCESS ) { // SCESTATUS error code
|
|
goto Leave;
|
|
}
|
|
}
|
|
|
|
//
|
|
// set the default profile into Reg
|
|
//
|
|
rc = ScepRegSetValue(
|
|
bAdminLogon ? HKEY_LOCAL_MACHINE : hCurrentUser,
|
|
SCE_ROOT_PATH,
|
|
L"LastUsedDatabase",
|
|
REG_SZ,
|
|
(BYTE *)DatabaseName,
|
|
(DbNameLen + 1) *sizeof(WCHAR)
|
|
);
|
|
if ( rc != NO_ERROR ) // Win32 error code
|
|
ScepLogOutput3(1, rc, SCEDLL_ERROR_SAVE_REGISTRY, L"LastUsedDatabase");
|
|
|
|
|
|
if ( InfFileName != NULL ) {
|
|
if ( bAdminLogon ) {
|
|
//
|
|
// only save the value if it's not coming from policy prop
|
|
//
|
|
if ( !(ConfigOptions & SCE_POLICY_TEMPLATE) ) {
|
|
|
|
rc = ScepRegSetValue(
|
|
HKEY_LOCAL_MACHINE,
|
|
SCE_ROOT_PATH,
|
|
L"TemplateUsed",
|
|
REG_SZ,
|
|
(BYTE *)InfFileName,
|
|
wcslen(InfFileName)*sizeof(WCHAR)
|
|
);
|
|
} else {
|
|
rc = NO_ERROR;
|
|
}
|
|
} else {
|
|
rc = ScepRegSetValue(
|
|
hCurrentUser, // HKEY_CURRENT_USER
|
|
SCE_ROOT_PATH,
|
|
L"TemplateUsed",
|
|
REG_SZ,
|
|
(BYTE *)InfFileName,
|
|
wcslen(InfFileName)*sizeof(WCHAR)
|
|
);
|
|
}
|
|
if ( rc != NO_ERROR ) // Win32 error code
|
|
ScepLogOutput3(1, rc, SCEDLL_ERROR_SAVE_REGISTRY, L"TemplateUsed");
|
|
}
|
|
|
|
//
|
|
// if no configuration is requested, just return now.
|
|
//
|
|
|
|
if ( ConfigOptions & SCE_NO_CONFIG ) {
|
|
|
|
if ( !(ConfigOptions & SCE_COPY_LOCAL_POLICY) ) {
|
|
//
|
|
// if no policy template is requested
|
|
//
|
|
goto Leave;
|
|
}
|
|
}
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
rc = SCESTATUS_SERVICE_NOT_SUPPORT;
|
|
goto Leave;
|
|
}
|
|
|
|
//
|
|
// open the database now to create some tables and time stamp
|
|
// tattoo is not needed unless it's in policy propagation
|
|
//
|
|
|
|
rc = SceJetOpenFile(
|
|
(LPSTR)FileName,
|
|
( ConfigOptions & (SCE_POLICY_TEMPLATE | SCE_COPY_LOCAL_POLICY) ) ? SCEJET_OPEN_READ_WRITE : SCEJET_OPEN_EXCLUSIVE,
|
|
( ConfigOptions & SCE_POLICY_TEMPLATE ) ? SCE_TABLE_OPTION_TATTOO : 0,
|
|
&hProfile
|
|
);
|
|
|
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|
//
|
|
// sleep for some time and try open again
|
|
//
|
|
|
|
Sleep(2000); // 2 seconds
|
|
|
|
rc = SceJetOpenFile(
|
|
(LPSTR)FileName,
|
|
( ConfigOptions & (SCE_POLICY_TEMPLATE | SCE_COPY_LOCAL_POLICY) ) ? SCEJET_OPEN_READ_WRITE : SCEJET_OPEN_EXCLUSIVE,
|
|
( ConfigOptions & SCE_POLICY_TEMPLATE ) ? SCE_TABLE_OPTION_TATTOO : 0,
|
|
&hProfile
|
|
);
|
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|
|
|
Sleep(2000); // 2 seconds
|
|
|
|
rc = SceJetOpenFile(
|
|
(LPSTR)FileName,
|
|
( ConfigOptions & (SCE_POLICY_TEMPLATE | SCE_COPY_LOCAL_POLICY) ) ? SCEJET_OPEN_READ_WRITE : SCEJET_OPEN_EXCLUSIVE,
|
|
( ConfigOptions & SCE_POLICY_TEMPLATE ) ? SCE_TABLE_OPTION_TATTOO : 0,
|
|
&hProfile
|
|
);
|
|
}
|
|
}
|
|
|
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|
|
|
ScepLogOutput3(0, ScepSceStatusToDosError(rc),
|
|
SCEDLL_ERROR_OPEN,
|
|
DatabaseName );
|
|
goto Leave;
|
|
}
|
|
|
|
SceJetStartTransaction( hProfile );
|
|
|
|
if ( ConfigOptions & SCE_COPY_LOCAL_POLICY ) {
|
|
//
|
|
// Copy domain policies (password, account, kerberos) to the special
|
|
// file %windir%\security\FirstDGPO.inf. The info in database will be
|
|
// deleted
|
|
//
|
|
//
|
|
// copy local policies (audit, and user rights) to the special file
|
|
// %windir%\security\FirstOGPO.inf. The local policy info in the
|
|
// database will still be left in.
|
|
//
|
|
rc = ScepMakePolicyIntoFile( ConfigOptions, Area);
|
|
|
|
if ( rc != SCESTATUS_SUCCESS) {
|
|
|
|
SceJetRollback( hProfile, 0 );
|
|
goto Leave;
|
|
}
|
|
}
|
|
|
|
if ( (hProfile->JetSapID != JET_tableidNil) &&
|
|
!(ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
!(ConfigOptions & SCE_COPY_LOCAL_POLICY) &&
|
|
((ConfigOptions & SCE_NO_CONFIG) == 0) ) {
|
|
|
|
//
|
|
// analysis was performed before
|
|
// delete SAP info for the area
|
|
//
|
|
ScepLogOutput3(3,0, SCEDLL_DELETE_TABLE, L"SAP");
|
|
|
|
// bug 362120
|
|
// after each config, user must re-analyze the computer to get
|
|
// analysis information
|
|
//
|
|
// if ( (ConfigOptions & SCE_OVERWRITE_DB) &&
|
|
// (InfFileName != NULL /*|| InfHandle != NULL */) ) {
|
|
|
|
//
|
|
// if it's reconfigured with a new template, all SAP
|
|
// information is obselote, so delete the whole table
|
|
//
|
|
|
|
rc = SceJetDeleteTable(
|
|
hProfile,
|
|
"SmTblSap",
|
|
SCEJET_TABLE_SAP
|
|
);
|
|
/*
|
|
} else {
|
|
|
|
//
|
|
// the template is incremental, or use the original template
|
|
// just delete sap information for the area, assuming that
|
|
// everything in the area is matched after this configuration
|
|
//
|
|
|
|
rc = ScepDeleteInfoForAreas(
|
|
hProfile,
|
|
SCE_ENGINE_SAP,
|
|
Area
|
|
);
|
|
}
|
|
*/
|
|
if ( rc != SCESTATUS_SUCCESS && rc != SCESTATUS_RECORD_NOT_FOUND ) {
|
|
ScepLogOutput3(1, ScepSceStatusToDosError(rc),
|
|
SCEDLL_ERROR_DELETE, L"SAP");
|
|
|
|
SceJetRollback( hProfile, 0 );
|
|
goto Leave;
|
|
}
|
|
}
|
|
|
|
//
|
|
// set time stamp for this configuration
|
|
//
|
|
|
|
if ( (ConfigOptions & SCE_NO_CONFIG) == 0 ) {
|
|
|
|
NtStatus = NtQuerySystemTime(&CurrentTime);
|
|
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
rc = SceJetSetTimeStamp(
|
|
hProfile,
|
|
FALSE,
|
|
CurrentTime
|
|
);
|
|
if ( rc != SCESTATUS_SUCCESS )
|
|
ScepLogOutput3(1, ScepSceStatusToDosError(rc),
|
|
SCEDLL_TIMESTAMP_ERROR,L"SMP");
|
|
|
|
// do not care the status of this call
|
|
rc = SCESTATUS_SUCCESS;
|
|
|
|
} else
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_TIMESTAMP_ERROR, L"SMP");
|
|
}
|
|
|
|
//
|
|
// commit all changes to this database
|
|
// fatal errors won't get here
|
|
//
|
|
|
|
SceJetCommitTransaction( hProfile, 0 );
|
|
|
|
//
|
|
// now if NO_CONFIG is requested ( with MOVE_POLICY or COPY_POLICY flag )
|
|
// should return now
|
|
//
|
|
if ( ConfigOptions & SCE_NO_CONFIG ) {
|
|
goto Leave;
|
|
}
|
|
|
|
//
|
|
// close the exclusively opened database and
|
|
// open it for read only because config engine read from the database
|
|
// NOTE: SceJetOpenFile will close the previous database if the handle
|
|
// is not NULL. The SceJetCloseFile is called with (theHandle,FALSE,FALSE)
|
|
// so jet session and instance are not terminated
|
|
//
|
|
|
|
rc = SceJetOpenFile(
|
|
(LPSTR)FileName,
|
|
( ConfigOptions & SCE_POLICY_TEMPLATE ) ? SCEJET_OPEN_READ_WRITE : SCEJET_OPEN_READ_ONLY, // tattoo table will be updated in policy
|
|
( ConfigOptions & SCE_POLICY_TEMPLATE ) ? SCE_TABLE_OPTION_TATTOO : 0, // by now the LastUsedMergeTable field is already set
|
|
&hProfile
|
|
);
|
|
if ( rc != SCESTATUS_SUCCESS ) { // SCESTATUS
|
|
ScepLogOutput3(0, ScepSceStatusToDosError(rc),
|
|
SCEDLL_ERROR_OPEN,
|
|
DatabaseName );
|
|
goto Leave;
|
|
}
|
|
|
|
//
|
|
// query the total ticks of this configuration
|
|
//
|
|
|
|
rc = ScepGetTotalTicks(
|
|
NULL,
|
|
hProfile,
|
|
Area,
|
|
( ConfigOptions & SCE_POLICY_TEMPLATE ) ?
|
|
SCE_FLAG_CONFIG_SCP : SCE_FLAG_CONFIG,
|
|
&gTotalTicks
|
|
);
|
|
if ( SCESTATUS_SUCCESS != rc &&
|
|
SCESTATUS_RECORD_NOT_FOUND != rc ) {
|
|
|
|
ScepLogOutput3(1, ScepSceStatusToDosError(rc),
|
|
SCEDLL_TOTAL_TICKS_ERROR);
|
|
|
|
}
|
|
rc = SCESTATUS_SUCCESS;
|
|
|
|
//
|
|
// reset memory buffer
|
|
//
|
|
memset( pScpInfo, '\0',sizeof(SCE_PROFILE_INFO) );
|
|
pScpInfo->Type = SCE_ENGINE_SCP_INTERNAL;
|
|
|
|
//
|
|
// open LSA private policy handle (to block other downlevel changes)
|
|
//
|
|
if ( ( ConfigOptions & SCE_POLICY_TEMPLATE ) &&
|
|
!( ConfigOptions & SCE_NO_CONFIG) &&
|
|
( (Area & AREA_PRIVILEGES) ||
|
|
(Area & AREA_SECURITY_POLICY) ) ) {
|
|
|
|
//
|
|
// enable TCB privilege
|
|
//
|
|
SceAdjustPrivilege( SE_TCB_PRIVILEGE, TRUE, NULL );
|
|
|
|
|
|
LSA_OBJECT_ATTRIBUTES attributes;
|
|
SECURITY_QUALITY_OF_SERVICE service;
|
|
|
|
|
|
memset( &attributes, 0, sizeof(attributes) );
|
|
attributes.Length = sizeof(attributes);
|
|
attributes.SecurityQualityOfService = &service;
|
|
service.Length = sizeof(service);
|
|
service.ImpersonationLevel= SecurityImpersonation;
|
|
service.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
|
service.EffectiveOnly = TRUE;
|
|
|
|
//
|
|
// open the lsa policy first
|
|
//
|
|
|
|
NtStatus = LsaOpenPolicySce( // LsaOpenPolicySce
|
|
NULL,
|
|
&attributes,
|
|
MAXIMUM_ALLOWED,
|
|
&LsaPrivatePolicy
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) || NtStatus == STATUS_TIMEOUT) {
|
|
|
|
if ( STATUS_TIMEOUT == NtStatus ) {
|
|
rc = ERROR_TIMEOUT;
|
|
} else
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
|
|
LsaPrivatePolicy = NULL;
|
|
|
|
ScepLogOutput3(1, rc, SCESRV_ERROR_PRIVATE_LSA );
|
|
rc = ScepDosErrorToSceStatus(rc);
|
|
|
|
} else {
|
|
|
|
ScepNotifyLogPolicy(0, TRUE, L"Policy Prop: Private LSA handle is returned", 0, 0, NULL );
|
|
}
|
|
}
|
|
|
|
Leave:
|
|
|
|
if ( hCurrentUser && hCurrentUser != HKEY_CURRENT_USER ) {
|
|
RegCloseKey(hCurrentUser);
|
|
}
|
|
|
|
if ( FileName ) {
|
|
ScepFree(FileName);
|
|
}
|
|
return(rc);
|
|
|
|
}
|
|
|
|
|
|
/* ANZ hotfix
|
|
requery notification queue for SAM notification items only
|
|
in case another notification slithered-in between the
|
|
previous LSA+SAM query and now
|
|
no need to hard error-out (but log an error) if querying fails since we're only
|
|
trying to raise the bar (or reduce the "notification dropping" window)
|
|
*/
|
|
/*
|
|
*/
|
|
|
|
|
|
#define SCEP_DISALLOW_SAM_FILTER\
|
|
if (!ResetEvent(ghEventSamFilterAndPolicyPropExclusion)){\
|
|
rc = GetLastError();\
|
|
SaveStat = rc;\
|
|
ScepLogOutput3(1,rc, SCESRV_POLICY_SAM_RESET_FILTER_SYNC);\
|
|
/* hard error - otherwise policy prop SAM config -> SAM notification loop might occur */\
|
|
DbgPrint("\nTid =%d PP could not Lock event due to %d\n", GetCurrentThreadId(), rc);\
|
|
goto OtherSettings;\
|
|
}\
|
|
else {\
|
|
DbgPrint("\nTid=%d Policy Propagation Locked event \n", GetCurrentThreadId());\
|
|
}\
|
|
if ( !(QueueFlag & SCE_QUEUE_INFO_SAM) ) {\
|
|
(VOID)ScepGetQueueInfo(&QueueFlag, NULL);\
|
|
}\
|
|
if ((QueueFlag & SCE_QUEUE_INFO_SAM)) {\
|
|
ScepLogOutput3(0, 0, SCESRV_POLICY_NEW_PENDING_SAM);\
|
|
rc = ERROR_IO_PENDING;\
|
|
PendingRc = rc;\
|
|
SCEP_ALLOW_SAM_FILTER\
|
|
goto OtherSettings;\
|
|
}
|
|
|
|
|
|
|
|
#define SCEP_ALLOW_SAM_FILTER\
|
|
if (!SetEvent(ghEventSamFilterAndPolicyPropExclusion)) {\
|
|
rc = GetLastError();\
|
|
SaveStat = rc;\
|
|
bSetEventFailed = TRUE;\
|
|
ScepLogOutput3(1,rc, SCESRV_POLICY_SAM_SET_FILTER_SYNC);\
|
|
/* hard error - otherwise SAM notifications will start getting dropped from now on */\
|
|
DbgPrint("\nTid =%d PP could not Unlock event due to %d\n", GetCurrentThreadId(), rc);\
|
|
}\
|
|
else {\
|
|
DbgPrint("\nTid =%d PP Unlocked event \n", GetCurrentThreadId());\
|
|
}\
|
|
|
|
|
|
SCESTATUS
|
|
ScepConfigureSystemAccess(
|
|
IN PSCE_PROFILE_INFO pScpInfo,
|
|
IN DWORD ConfigOptions,
|
|
IN PSCE_ERROR_LOG_INFO *pErrLog,
|
|
IN DWORD QueueFlag
|
|
)
|
|
/* ++
|
|
|
|
Routine Description:
|
|
|
|
This routine configure the system security in the area of system access
|
|
which includes account policy, rename admin/guest accounts, disable
|
|
no activity account, and some registry keys security, e.g., winlogon keys.
|
|
|
|
Arguments:
|
|
|
|
pScpInfo - The buffer which contains SCP info loaded from the profile
|
|
|
|
ConfigOptions - options in configuration
|
|
|
|
pErrLog - the output log for potential errors
|
|
|
|
QueueFlag - flags for the notification queue, which determines if SAM policy
|
|
should be configured.
|
|
|
|
Return value:
|
|
|
|
SCESTATUS_SUCCESS
|
|
SCESTATUS_NOT_ENOUGH_RESOURCE
|
|
SCESTATUS_INVALID_PARAMETER
|
|
SCESTATUS_OTHER_ERROR
|
|
|
|
-- */
|
|
{
|
|
DWORD rc,PendingRc=0;
|
|
DWORD SaveStat;
|
|
NTSTATUS NtStatus;
|
|
SAM_HANDLE DomainHandle=NULL,
|
|
ServerHandle=NULL,
|
|
UserHandle1=NULL;
|
|
PSID DomainSid=NULL;
|
|
PVOID Buffer=NULL;
|
|
DWORD RegData;
|
|
BOOL bFlagSet;
|
|
BOOL bSetEventFailed = FALSE;
|
|
|
|
SCE_TATTOO_KEYS *pTattooKeys=NULL;
|
|
DWORD cTattooKeys=0;
|
|
|
|
PSCESECTION hSectionDomain=NULL;
|
|
PSCESECTION hSectionTattoo=NULL;
|
|
|
|
#define MAX_PASS_KEYS 7
|
|
#define MAX_LOCKOUT_KEYS 3
|
|
|
|
//
|
|
// Open account domain
|
|
//
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|
}
|
|
|
|
NtStatus = ScepOpenSamDomain(
|
|
MAXIMUM_ALLOWED, // SAM_SERVER_ALL_ACCESS,
|
|
DOMAIN_WRITE_PASSWORD_PARAMS | MAXIMUM_ALLOWED,
|
|
&ServerHandle,
|
|
&DomainHandle,
|
|
&DomainSid,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
rc = RtlNtStatusToDosError( NtStatus );
|
|
SaveStat = rc;
|
|
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
|
|
if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) &&
|
|
pErrLog ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_ACCOUNT_DOMAIN
|
|
);
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_ACCOUNT_DOMAIN);
|
|
}
|
|
|
|
if (ConfigOptions & SCE_RSOP_CALLBACK)
|
|
|
|
ScepRsopLog(SCE_RSOP_PASSWORD_INFO |
|
|
SCE_RSOP_LOCKOUT_INFO |
|
|
SCE_RSOP_LOGOFF_INFO |
|
|
SCE_RSOP_ADMIN_INFO |
|
|
SCE_RSOP_GUEST_INFO,
|
|
rc,
|
|
NULL,
|
|
0,
|
|
0);
|
|
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
//
|
|
// if this is policy propagation, we need to open the sections for
|
|
// updating undo settings if this is not domain controller
|
|
// *** on DCs, domain account policy can't be reset'ed to tattoo
|
|
// on each individual DC. So there is no point to query/save tattoo values
|
|
//
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) ) {
|
|
|
|
ScepTattooOpenPolicySections(
|
|
hProfile,
|
|
szSystemAccess,
|
|
&hSectionDomain,
|
|
&hSectionTattoo
|
|
);
|
|
}
|
|
|
|
//
|
|
// if there is pending notifications for SAM policy
|
|
// ignore policy prop for SAM
|
|
//
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
(QueueFlag & SCE_QUEUE_INFO_SAM) ) {
|
|
|
|
ScepLogOutput3(0, 0, SCESRV_POLICY_PENDING_SAM);
|
|
|
|
rc = ERROR_IO_PENDING;
|
|
PendingRc = rc;
|
|
|
|
if (ConfigOptions & SCE_RSOP_CALLBACK)
|
|
|
|
ScepRsopLog(SCE_RSOP_PASSWORD_INFO |
|
|
SCE_RSOP_LOCKOUT_INFO |
|
|
SCE_RSOP_LOGOFF_INFO,
|
|
rc,
|
|
NULL,
|
|
0,
|
|
0);
|
|
goto OtherSettings;
|
|
|
|
}
|
|
|
|
//
|
|
// Get the current password settings...
|
|
//
|
|
|
|
Buffer=NULL;
|
|
NtStatus = SamQueryInformationDomain(
|
|
DomainHandle,
|
|
DomainPasswordInformation,
|
|
&Buffer
|
|
);
|
|
|
|
rc = RtlNtStatusToDosError( NtStatus );
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
rc = ERROR_SUCCESS;
|
|
|
|
// allocate buffer for the tattoo values if necessary
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) ) {
|
|
|
|
pTattooKeys = (SCE_TATTOO_KEYS *)ScepAlloc(LPTR,MAX_PASS_KEYS*sizeof(SCE_TATTOO_KEYS));
|
|
|
|
if ( !pTattooKeys ) {
|
|
ScepLogOutput3(1, ERROR_NOT_ENOUGH_MEMORY, SCESRV_POLICY_TATTOO_ERROR_CREATE);
|
|
}
|
|
}
|
|
|
|
bFlagSet = FALSE;
|
|
|
|
if ( (pScpInfo->MinimumPasswordLength != SCE_NO_VALUE) ) {
|
|
|
|
//
|
|
// for domain controllers, always use hardcode value as the initial tattoo value
|
|
//
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"MinimumPasswordLength", ConfigOptions,
|
|
(ProductType == NtProductLanManNt) ? SCEDCPOL_MIN_PASS_LEN :
|
|
((DOMAIN_PASSWORD_INFORMATION *)Buffer)->MinPasswordLength);
|
|
|
|
if ( ((USHORT)(pScpInfo->MinimumPasswordLength) != ((DOMAIN_PASSWORD_INFORMATION *)Buffer)->MinPasswordLength) ) {
|
|
|
|
((DOMAIN_PASSWORD_INFORMATION *)Buffer)->MinPasswordLength = (USHORT)(pScpInfo->MinimumPasswordLength);
|
|
bFlagSet = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
if ( (pScpInfo->PasswordHistorySize != SCE_NO_VALUE) ) {
|
|
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"PasswordHistorySize", ConfigOptions,
|
|
(ProductType == NtProductLanManNt) ? SCEDCPOL_PASS_SIZE : ((DOMAIN_PASSWORD_INFORMATION *)Buffer)->PasswordHistoryLength);
|
|
|
|
if ( ((USHORT)(pScpInfo->PasswordHistorySize) != ((DOMAIN_PASSWORD_INFORMATION *)Buffer)->PasswordHistoryLength ) ) {
|
|
|
|
((DOMAIN_PASSWORD_INFORMATION *)Buffer)->PasswordHistoryLength = (USHORT)(pScpInfo->PasswordHistorySize);
|
|
bFlagSet = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( pScpInfo->MaximumPasswordAge == SCE_FOREVER_VALUE ) {
|
|
|
|
RegData = (DWORD) (-1 * (((DOMAIN_PASSWORD_INFORMATION *)Buffer)->MaxPasswordAge.QuadPart /
|
|
(LONGLONG)(10000000L)) );
|
|
RegData /= 3600;
|
|
RegData /= 24;
|
|
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"MaximumPasswordAge", ConfigOptions,
|
|
(ProductType == NtProductLanManNt) ? SCEDCPOL_MAX_PASS_AGE : RegData);
|
|
|
|
if ( ((DOMAIN_PASSWORD_INFORMATION *)Buffer)->MaxPasswordAge.HighPart != MINLONG ||
|
|
((DOMAIN_PASSWORD_INFORMATION *)Buffer)->MaxPasswordAge.LowPart != 0 ) {
|
|
|
|
//
|
|
// Maximum LARGE_INTEGER .ie. never
|
|
//
|
|
|
|
((DOMAIN_PASSWORD_INFORMATION *)Buffer)->MaxPasswordAge.HighPart = MINLONG;
|
|
((DOMAIN_PASSWORD_INFORMATION *)Buffer)->MaxPasswordAge.LowPart = 0;
|
|
bFlagSet = TRUE;
|
|
|
|
}
|
|
|
|
} else if ( pScpInfo->MaximumPasswordAge != SCE_NO_VALUE ) {
|
|
|
|
RegData = (DWORD) (-1 * (((DOMAIN_PASSWORD_INFORMATION *)Buffer)->MaxPasswordAge.QuadPart /
|
|
(LONGLONG)(10000000L)) );
|
|
RegData /= 3600;
|
|
RegData /= 24;
|
|
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"MaximumPasswordAge", ConfigOptions,
|
|
(ProductType == NtProductLanManNt) ? SCEDCPOL_MAX_PASS_AGE : RegData);
|
|
|
|
if ( RegData != pScpInfo->MaximumPasswordAge ) {
|
|
|
|
((DOMAIN_PASSWORD_INFORMATION *)Buffer)->MaxPasswordAge.QuadPart = -1 *
|
|
(LONGLONG)pScpInfo->MaximumPasswordAge*24*3600 * 10000000L;
|
|
bFlagSet = TRUE;
|
|
|
|
}
|
|
}
|
|
|
|
if ( pScpInfo->MinimumPasswordAge != SCE_NO_VALUE ) {
|
|
|
|
RegData = (DWORD) (-1 * (((DOMAIN_PASSWORD_INFORMATION *)Buffer)->MinPasswordAge.QuadPart /
|
|
(LONGLONG)(10000000L)) );
|
|
RegData /= 3600;
|
|
RegData /= 24;
|
|
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"MinimumPasswordAge", ConfigOptions,
|
|
(ProductType == NtProductLanManNt) ? SCEDCPOL_MIN_PASS_AGE : RegData);
|
|
|
|
if ( RegData != pScpInfo->MinimumPasswordAge ) {
|
|
|
|
((DOMAIN_PASSWORD_INFORMATION *)Buffer)->MinPasswordAge.QuadPart = -1 *
|
|
(LONGLONG)pScpInfo->MinimumPasswordAge*24*3600 * 10000000L;
|
|
bFlagSet = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( pScpInfo->PasswordComplexity != SCE_NO_VALUE ) {
|
|
|
|
RegData = ( ((DOMAIN_PASSWORD_INFORMATION *)Buffer)->PasswordProperties & DOMAIN_PASSWORD_COMPLEX) ? 1 : 0;
|
|
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"PasswordComplexity", ConfigOptions,
|
|
(ProductType == NtProductLanManNt) ? SCEDCPOL_PASS_COMP : RegData);
|
|
|
|
if ( pScpInfo->PasswordComplexity != RegData ) {
|
|
|
|
if ( RegData == 0 )
|
|
((DOMAIN_PASSWORD_INFORMATION *)Buffer)->PasswordProperties |= DOMAIN_PASSWORD_COMPLEX;
|
|
else
|
|
((DOMAIN_PASSWORD_INFORMATION *)Buffer)->PasswordProperties &= ~DOMAIN_PASSWORD_COMPLEX;
|
|
bFlagSet = TRUE;
|
|
|
|
}
|
|
}
|
|
|
|
if ( pScpInfo->RequireLogonToChangePassword != SCE_NO_VALUE ) {
|
|
|
|
RegData = ( ((DOMAIN_PASSWORD_INFORMATION *)Buffer)->PasswordProperties & DOMAIN_PASSWORD_NO_ANON_CHANGE) ? 1 : 0;
|
|
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"RequireLogonToChangePassword", ConfigOptions,
|
|
(ProductType == NtProductLanManNt) ? SCEDCPOL_REQUIRE_LOGON : RegData);
|
|
|
|
if ( pScpInfo->RequireLogonToChangePassword != RegData ) {
|
|
|
|
if ( RegData == 0 )
|
|
((DOMAIN_PASSWORD_INFORMATION *)Buffer)->PasswordProperties |= DOMAIN_PASSWORD_NO_ANON_CHANGE;
|
|
else
|
|
((DOMAIN_PASSWORD_INFORMATION *)Buffer)->PasswordProperties &= ~DOMAIN_PASSWORD_NO_ANON_CHANGE;
|
|
bFlagSet = TRUE;
|
|
|
|
}
|
|
}
|
|
|
|
#if _WIN32_WINNT>=0x0500
|
|
if ( pScpInfo->ClearTextPassword != SCE_NO_VALUE ) {
|
|
|
|
RegData = ( ((DOMAIN_PASSWORD_INFORMATION *)Buffer)->PasswordProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT) ? 1 : 0;
|
|
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"ClearTextPassword", ConfigOptions,
|
|
(ProductType == NtProductLanManNt) ? SCEDCPOL_CLEAR_PASS : RegData);
|
|
|
|
if ( pScpInfo->ClearTextPassword != RegData ) {
|
|
|
|
if ( RegData == 0 )
|
|
((DOMAIN_PASSWORD_INFORMATION *)Buffer)->PasswordProperties |= DOMAIN_PASSWORD_STORE_CLEARTEXT;
|
|
else
|
|
((DOMAIN_PASSWORD_INFORMATION *)Buffer)->PasswordProperties &= ~DOMAIN_PASSWORD_STORE_CLEARTEXT;
|
|
bFlagSet = TRUE;
|
|
|
|
}
|
|
}
|
|
#endif
|
|
if ( bFlagSet ) {
|
|
|
|
//
|
|
// if there is pending notifications for SAM policy
|
|
// ignore policy prop for SAM
|
|
//
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
(ProductType == NtProductLanManNt) ) {
|
|
|
|
|
|
// ANZ hotfix
|
|
//
|
|
// turn off policy filter for SAM notification JUST before SAM config
|
|
// (moved here to reduce "SAM notification dropping" window)
|
|
//
|
|
|
|
SCEP_DISALLOW_SAM_FILTER
|
|
|
|
}
|
|
|
|
NtStatus = SamSetInformationDomain(
|
|
DomainHandle,
|
|
DomainPasswordInformation,
|
|
Buffer
|
|
);
|
|
rc = RtlNtStatusToDosError( NtStatus );
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
(ProductType == NtProductLanManNt) ) {
|
|
|
|
// ANZ hotfix
|
|
//
|
|
// turn on policy filter for SAM notification (moved here
|
|
// to reduce "SAM notification dropping" window)
|
|
//
|
|
|
|
SCEP_ALLOW_SAM_FILTER
|
|
}
|
|
}
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) &&
|
|
pTattooKeys && cTattooKeys ) {
|
|
|
|
//
|
|
// even if there is no change,
|
|
// we still need to check if some tattoo values should be deleted
|
|
//
|
|
ScepLogOutput3(3, 0, SCESRV_POLICY_TATTOO_ARRAY, cTattooKeys);
|
|
|
|
//
|
|
// some policy is different than the system setting
|
|
// check if we should save the existing setting as the tattoo value
|
|
// also remove reset'ed tattoo policy
|
|
//
|
|
ScepTattooManageValues(hSectionDomain, hSectionTattoo, pTattooKeys, cTattooKeys, rc);
|
|
|
|
}
|
|
|
|
if ( pTattooKeys ) {
|
|
ScepFree(pTattooKeys);
|
|
pTattooKeys = NULL;
|
|
}
|
|
cTattooKeys = 0;
|
|
|
|
SamFreeMemory(Buffer);
|
|
Buffer = NULL;
|
|
|
|
if ( !NT_SUCCESS( NtStatus ) ) {
|
|
//
|
|
// if error, just log it and continue
|
|
//
|
|
if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) && pErrLog ) {
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_SCP_ERROR_PASSWORD
|
|
);
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_ERROR_PASSWORD);
|
|
}
|
|
SaveStat = rc;
|
|
// goto GETOUT;
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_PASSWORD);
|
|
}
|
|
|
|
} else if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) && pErrLog ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_ERROR_QUERY_PASSWORD
|
|
);
|
|
} else {
|
|
|
|
ScepLogOutput3(1, rc, SCEDLL_ERROR_QUERY_PASSWORD);
|
|
}
|
|
|
|
if (ConfigOptions & SCE_RSOP_CALLBACK)
|
|
|
|
ScepRsopLog(SCE_RSOP_PASSWORD_INFO, rc, NULL, 0, 0);
|
|
|
|
//
|
|
// Configure Lockout information
|
|
//
|
|
|
|
Buffer = NULL;
|
|
NtStatus = SamQueryInformationDomain(
|
|
DomainHandle,
|
|
DomainLockoutInformation,
|
|
&Buffer
|
|
);
|
|
|
|
rc = RtlNtStatusToDosError( NtStatus );
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
rc = ERROR_SUCCESS;
|
|
|
|
// allocate buffer for the tattoo values if necessary
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) ) {
|
|
|
|
pTattooKeys = (SCE_TATTOO_KEYS *)ScepAlloc(LPTR,MAX_LOCKOUT_KEYS*sizeof(SCE_TATTOO_KEYS));
|
|
|
|
if ( !pTattooKeys ) {
|
|
ScepLogOutput3(1, ERROR_NOT_ENOUGH_MEMORY, SCESRV_POLICY_TATTOO_ERROR_CREATE);
|
|
}
|
|
}
|
|
|
|
bFlagSet = FALSE;
|
|
if ( (pScpInfo->LockoutBadCount != SCE_NO_VALUE) ) {
|
|
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"LockoutBadCount", ConfigOptions,
|
|
(ProductType == NtProductLanManNt) ? SCEDCPOL_LOCK_COUNT : ((DOMAIN_LOCKOUT_INFORMATION *)Buffer)->LockoutThreshold);
|
|
|
|
if ( ( ((DOMAIN_LOCKOUT_INFORMATION *)Buffer)->LockoutThreshold != (USHORT)(pScpInfo->LockoutBadCount) ) ) {
|
|
|
|
|
|
((DOMAIN_LOCKOUT_INFORMATION *)Buffer)->LockoutThreshold = (USHORT)(pScpInfo->LockoutBadCount);
|
|
bFlagSet = TRUE;
|
|
|
|
}
|
|
}
|
|
|
|
if ( (pScpInfo->ResetLockoutCount != SCE_NO_VALUE) &&
|
|
( ((DOMAIN_LOCKOUT_INFORMATION *)Buffer)->LockoutThreshold > 0 ) ) {
|
|
|
|
RegData = (DWORD) (-1 * ((DOMAIN_LOCKOUT_INFORMATION *)Buffer)->LockoutObservationWindow.QuadPart /
|
|
(60 * 10000000L) );
|
|
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"ResetLockoutCount", ConfigOptions,
|
|
(ProductType == NtProductLanManNt) ? SCEDCPOL_LOCK_RESET : RegData);
|
|
|
|
if ( RegData != pScpInfo->ResetLockoutCount ) {
|
|
|
|
((DOMAIN_LOCKOUT_INFORMATION *)Buffer)->LockoutObservationWindow.QuadPart = -1 *
|
|
(LONGLONG)pScpInfo->ResetLockoutCount * 60 * 10000000L;
|
|
bFlagSet = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( ((DOMAIN_LOCKOUT_INFORMATION *)Buffer)->LockoutThreshold > 0 ) {
|
|
|
|
if ( pScpInfo->LockoutDuration != SCE_NO_VALUE ) {
|
|
|
|
RegData = (DWORD)(-1 * ((DOMAIN_LOCKOUT_INFORMATION *)Buffer)->LockoutDuration.QuadPart /
|
|
(60 * 10000000L) );
|
|
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"LockoutDuration", ConfigOptions,
|
|
(ProductType == NtProductLanManNt) ? SCEDCPOL_LOCK_DURATION : RegData);
|
|
|
|
}
|
|
|
|
if ( pScpInfo->LockoutDuration == SCE_FOREVER_VALUE ) {
|
|
|
|
if ( ((DOMAIN_LOCKOUT_INFORMATION *)Buffer)->LockoutDuration.HighPart != MINLONG ||
|
|
((DOMAIN_LOCKOUT_INFORMATION *)Buffer)->LockoutDuration.LowPart != 0 ) {
|
|
//
|
|
// forever
|
|
//
|
|
|
|
((DOMAIN_LOCKOUT_INFORMATION *)Buffer)->LockoutDuration.HighPart = MINLONG;
|
|
((DOMAIN_LOCKOUT_INFORMATION *)Buffer)->LockoutDuration.LowPart = 0;
|
|
bFlagSet = TRUE;
|
|
|
|
}
|
|
|
|
} else if ( pScpInfo->LockoutDuration != SCE_NO_VALUE ) {
|
|
|
|
if ( RegData != pScpInfo->LockoutDuration ) {
|
|
|
|
((DOMAIN_LOCKOUT_INFORMATION *)Buffer)->LockoutDuration.QuadPart = -1 *
|
|
(LONGLONG)pScpInfo->LockoutDuration * 60 * 10000000L;
|
|
bFlagSet = TRUE;
|
|
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// make sure to delete these two tattoo values if they exist
|
|
//
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"ResetLockoutCount", ConfigOptions,
|
|
SCE_NO_VALUE);
|
|
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"LockoutDuration", ConfigOptions,
|
|
SCE_NO_VALUE);
|
|
}
|
|
|
|
if ( bFlagSet ) {
|
|
//
|
|
// if there is pending notifications for SAM policy
|
|
// ignore policy prop for SAM
|
|
//
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
(ProductType == NtProductLanManNt) ) {
|
|
|
|
|
|
// ANZ hotfix
|
|
//
|
|
// turn off policy filter for SAM notification JUST before SAM config
|
|
// (moved here to reduce "SAM notification dropping" window)
|
|
//
|
|
|
|
SCEP_DISALLOW_SAM_FILTER
|
|
|
|
}
|
|
|
|
NtStatus = SamSetInformationDomain(
|
|
DomainHandle,
|
|
DomainLockoutInformation,
|
|
Buffer
|
|
);
|
|
rc = RtlNtStatusToDosError( NtStatus );
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
(ProductType == NtProductLanManNt) ) {
|
|
|
|
// ANZ hotfix
|
|
//
|
|
// turn on policy filter for SAM notification (moved here
|
|
// to reduce "SAM notification dropping" window)
|
|
//
|
|
|
|
SCEP_ALLOW_SAM_FILTER
|
|
}
|
|
}
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) &&
|
|
pTattooKeys && cTattooKeys ) {
|
|
|
|
//
|
|
// even if there is no change
|
|
// we still need to check if some of the tattoo values should be deleted
|
|
//
|
|
ScepLogOutput3(3, 0, SCESRV_POLICY_TATTOO_ARRAY, cTattooKeys);
|
|
//
|
|
// some policy is different than the system setting
|
|
// check if we should save the existing setting as the tattoo value
|
|
// also remove reset'ed tattoo policy
|
|
//
|
|
ScepTattooManageValues(hSectionDomain, hSectionTattoo, pTattooKeys, cTattooKeys, rc);
|
|
}
|
|
|
|
if ( pTattooKeys ) {
|
|
ScepFree(pTattooKeys);
|
|
pTattooKeys = NULL;
|
|
}
|
|
cTattooKeys = 0;
|
|
|
|
SamFreeMemory(Buffer);
|
|
Buffer = NULL;
|
|
|
|
if ( !NT_SUCCESS( NtStatus ) ) {
|
|
//
|
|
// if error, just log it and continue
|
|
//
|
|
if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) && pErrLog ) {
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_SCP_ERROR_PASSWORD
|
|
);
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_ERROR_LOCKOUT);
|
|
}
|
|
SaveStat = rc;
|
|
// goto GETOUT;
|
|
} else if ( bFlagSet ) {
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_LOCKOUT);
|
|
}
|
|
} else if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) && pErrLog ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_ERROR_QUERY_LOCKOUT
|
|
);
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_ERROR_QUERY_LOCKOUT);
|
|
}
|
|
|
|
if (ConfigOptions & SCE_RSOP_CALLBACK)
|
|
|
|
ScepRsopLog(SCE_RSOP_LOCKOUT_INFO, rc, NULL, 0, 0);
|
|
|
|
//
|
|
// Force Logoff when hour expire
|
|
//
|
|
|
|
if ( pScpInfo->ForceLogoffWhenHourExpire != SCE_NO_VALUE ) {
|
|
|
|
Buffer = NULL;
|
|
NtStatus = SamQueryInformationDomain(
|
|
DomainHandle,
|
|
DomainLogoffInformation,
|
|
&Buffer
|
|
);
|
|
|
|
rc = RtlNtStatusToDosError( NtStatus );
|
|
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
rc = ERROR_SUCCESS;
|
|
|
|
bFlagSet = FALSE;
|
|
RegData = pScpInfo->ForceLogoffWhenHourExpire;
|
|
|
|
if ( pScpInfo->ForceLogoffWhenHourExpire == 1 ) { // yes
|
|
if ( ((DOMAIN_LOGOFF_INFORMATION *)Buffer)->ForceLogoff.HighPart != 0 ||
|
|
((DOMAIN_LOGOFF_INFORMATION *)Buffer)->ForceLogoff.LowPart != 0 ) {
|
|
|
|
RegData = 0;
|
|
((DOMAIN_LOGOFF_INFORMATION *)Buffer)->ForceLogoff.HighPart = 0;
|
|
((DOMAIN_LOGOFF_INFORMATION *)Buffer)->ForceLogoff.LowPart = 0;
|
|
bFlagSet = TRUE;
|
|
}
|
|
} else {
|
|
if ( ((DOMAIN_LOGOFF_INFORMATION *)Buffer)->ForceLogoff.HighPart != MINLONG ||
|
|
((DOMAIN_LOGOFF_INFORMATION *)Buffer)->ForceLogoff.LowPart != 0 ) {
|
|
|
|
RegData = 1;
|
|
((DOMAIN_LOGOFF_INFORMATION *)Buffer)->ForceLogoff.HighPart = MINLONG;
|
|
((DOMAIN_LOGOFF_INFORMATION *)Buffer)->ForceLogoff.LowPart = 0;
|
|
bFlagSet = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( bFlagSet ) {
|
|
|
|
//
|
|
// if there is pending notifications for SAM policy
|
|
// ignore policy prop for SAM
|
|
//
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
(ProductType == NtProductLanManNt) ) {
|
|
|
|
|
|
// ANZ hotfix
|
|
//
|
|
// turn off policy filter for SAM notification JUST before SAM config
|
|
// (moved here to reduce "SAM notification dropping" window)
|
|
//
|
|
|
|
SCEP_DISALLOW_SAM_FILTER
|
|
|
|
}
|
|
|
|
NtStatus = SamSetInformationDomain(
|
|
DomainHandle,
|
|
DomainLogoffInformation,
|
|
Buffer
|
|
);
|
|
rc = RtlNtStatusToDosError( NtStatus );
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
(ProductType == NtProductLanManNt) ) {
|
|
|
|
// ANZ hotfix
|
|
//
|
|
// turn on policy filter for SAM notification (moved here
|
|
// to reduce "SAM notification dropping" window)
|
|
//
|
|
|
|
SCEP_ALLOW_SAM_FILTER
|
|
}
|
|
|
|
|
|
}
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) ) {
|
|
|
|
//
|
|
// some policy is different than the system setting or this is a domain controller
|
|
// check if we should save the existing setting as the tattoo value
|
|
// also remove reset'ed tattoo policy
|
|
//
|
|
ScepTattooManageOneIntValue(hSectionDomain, hSectionTattoo,
|
|
(PWSTR)L"ForceLogoffWhenHourExpire",
|
|
0,
|
|
(ProductType == NtProductLanManNt) ? SCEDCPOL_FORCE_LOGOFF : RegData, rc);
|
|
|
|
}
|
|
SamFreeMemory(Buffer);
|
|
Buffer = NULL;
|
|
|
|
if ( !NT_SUCCESS( NtStatus ) ) {
|
|
|
|
if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) &&
|
|
pErrLog ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_SCP_ERROR_LOGOFF
|
|
);
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_ERROR_LOGOFF);
|
|
}
|
|
SaveStat = rc;
|
|
// goto GETOUT;
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_LOGOFF);
|
|
}
|
|
|
|
} else if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) && pErrLog ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_ERROR_QUERY_LOGOFF
|
|
);
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_ERROR_QUERY_LOGOFF);
|
|
}
|
|
|
|
if (ConfigOptions & SCE_RSOP_CALLBACK)
|
|
|
|
ScepRsopLog(SCE_RSOP_LOGOFF_INFO, rc, NULL, 0, 0);
|
|
|
|
}
|
|
|
|
OtherSettings:
|
|
|
|
if (Buffer != NULL){
|
|
SamFreeMemory(Buffer);
|
|
Buffer = NULL;
|
|
}
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
rc = SCESTATUS_SERVICE_NOT_SUPPORT;
|
|
SaveStat = rc;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Rename Administrator/Guest account
|
|
//
|
|
|
|
if ( NULL != pScpInfo->NewAdministratorName ) {
|
|
|
|
NtStatus = ScepManageAdminGuestAccounts(DomainHandle,
|
|
pScpInfo->NewAdministratorName,
|
|
0,
|
|
SCE_RENAME_ADMIN,
|
|
ConfigOptions,
|
|
hSectionDomain,
|
|
hSectionTattoo
|
|
);
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
|
|
if ( NT_SUCCESS( NtStatus ) )
|
|
ScepLogOutput3(0, 0, SCEDLL_SCP_RENAME_ADMIN,
|
|
pScpInfo->NewAdministratorName );
|
|
else {
|
|
|
|
if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) &&
|
|
pErrLog ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_SCP_ERROR_ADMINISTRATOR
|
|
);
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_ERROR_ADMINISTRATOR);
|
|
}
|
|
|
|
SaveStat = rc;
|
|
// goto GETOUT;
|
|
}
|
|
|
|
if (ConfigOptions & SCE_RSOP_CALLBACK)
|
|
|
|
ScepRsopLog(SCE_RSOP_ADMIN_INFO, rc, NULL, 0, 0);
|
|
}
|
|
|
|
if ( NULL != pScpInfo->NewGuestName ) {
|
|
|
|
NtStatus = ScepManageAdminGuestAccounts(DomainHandle,
|
|
pScpInfo->NewGuestName,
|
|
0,
|
|
SCE_RENAME_GUEST,
|
|
ConfigOptions,
|
|
hSectionDomain,
|
|
hSectionTattoo
|
|
);
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
|
|
if ( NT_SUCCESS( NtStatus ) ) {
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_RENAME_GUEST,
|
|
pScpInfo->NewGuestName );
|
|
} else {
|
|
|
|
if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) &&
|
|
pErrLog ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_SCP_ERROR_GUEST
|
|
);
|
|
} else {
|
|
ScepLogOutput3(1,rc, SCEDLL_SCP_ERROR_GUEST);
|
|
}
|
|
|
|
SaveStat = rc;
|
|
// goto GETOUT;
|
|
}
|
|
|
|
if (ConfigOptions & SCE_RSOP_CALLBACK)
|
|
|
|
ScepRsopLog(SCE_RSOP_GUEST_INFO, rc, NULL, 0, 0);
|
|
}
|
|
|
|
//
|
|
// disable admin account
|
|
//
|
|
|
|
if ( pScpInfo->EnableAdminAccount != SCE_NO_VALUE ) {
|
|
|
|
NtStatus = ScepManageAdminGuestAccounts(DomainHandle,
|
|
NULL,
|
|
(pScpInfo->EnableAdminAccount > 0) ? 0 : 1,
|
|
SCE_DISABLE_ADMIN,
|
|
ConfigOptions,
|
|
hSectionDomain,
|
|
hSectionTattoo
|
|
);
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
|
|
if ( NT_SUCCESS( NtStatus ) ) {
|
|
|
|
ScepLogOutput3(0, 0, pScpInfo->EnableAdminAccount ?
|
|
SCEDLL_SCP_ENABLE_ADMIN : SCEDLL_SCP_DISABLE_ADMIN);
|
|
|
|
} else {
|
|
|
|
if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) &&
|
|
pErrLog ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_SCP_ERROR_DISABLE_ADMIN
|
|
);
|
|
} else if ( STATUS_SPECIAL_ACCOUNT == NtStatus ) {
|
|
|
|
ScepLogOutput3(0, 0, SCEDLL_SCP_ADMIN_NOT_ALLOWED);
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_ERROR_DISABLE_ADMIN);
|
|
}
|
|
|
|
SaveStat = rc;
|
|
// goto GETOUT;
|
|
}
|
|
|
|
if (ConfigOptions & SCE_RSOP_CALLBACK)
|
|
|
|
ScepRsopLog(SCE_RSOP_DISABLE_ADMIN_INFO, rc, NULL, 0, 0);
|
|
}
|
|
|
|
//
|
|
// disable guest account
|
|
//
|
|
|
|
if ( pScpInfo->EnableGuestAccount != SCE_NO_VALUE ) {
|
|
|
|
NtStatus = ScepManageAdminGuestAccounts(DomainHandle,
|
|
NULL,
|
|
(pScpInfo->EnableGuestAccount > 0) ? 0 : 1,
|
|
SCE_DISABLE_GUEST,
|
|
ConfigOptions,
|
|
hSectionDomain,
|
|
hSectionTattoo
|
|
);
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
|
|
if ( NT_SUCCESS( NtStatus ) ) {
|
|
|
|
ScepLogOutput3(0, 0, pScpInfo->EnableGuestAccount ?
|
|
SCEDLL_SCP_ENABLE_GUEST : SCEDLL_SCP_DISABLE_GUEST);
|
|
|
|
} else {
|
|
|
|
if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) &&
|
|
pErrLog ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_SCP_ERROR_DISABLE_GUEST
|
|
);
|
|
} else if ( STATUS_SPECIAL_ACCOUNT == NtStatus ) {
|
|
ScepLogOutput3(0, 0, SCEDLL_SCP_GUEST_NOT_ALLOWED);
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_ERROR_DISABLE_GUEST);
|
|
}
|
|
|
|
SaveStat = rc;
|
|
// goto GETOUT;
|
|
}
|
|
|
|
if (ConfigOptions & SCE_RSOP_CALLBACK)
|
|
|
|
ScepRsopLog(SCE_RSOP_DISABLE_GUEST_INFO, rc, NULL, 0, 0);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Other Registry Key Values
|
|
//
|
|
bFlagSet = FALSE;
|
|
|
|
if ( bFlagSet && rc == NO_ERROR )
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_OTHER_POLICY);
|
|
|
|
|
|
if ( hSectionDomain ) SceJetCloseSection( &hSectionDomain, TRUE );
|
|
if ( hSectionTattoo ) SceJetCloseSection( &hSectionTattoo, TRUE );
|
|
|
|
//
|
|
// Clear out memory and return
|
|
//
|
|
|
|
SamCloseHandle( DomainHandle );
|
|
SamCloseHandle( ServerHandle );
|
|
if ( DomainSid != NULL )
|
|
SamFreeMemory(DomainSid);
|
|
|
|
if ( SaveStat == ERROR_SUCCESS )
|
|
SaveStat = PendingRc;
|
|
|
|
// ANZ hotfix
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
TRUE == bSetEventFailed) {
|
|
|
|
//
|
|
// set this event just in case it failed before
|
|
//
|
|
|
|
SetEvent(ghEventSamFilterAndPolicyPropExclusion);
|
|
}
|
|
|
|
return(ScepDosErrorToSceStatus(SaveStat));
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
ScepManageAdminGuestAccounts(
|
|
IN SAM_HANDLE DomainHandle,
|
|
IN PWSTR NewName,
|
|
IN DWORD DisableFlag,
|
|
IN DWORD AccountType,
|
|
IN DWORD ConfigOptions,
|
|
IN PSCESECTION hSectionDomain OPTIONAL,
|
|
IN PSCESECTION hSectionTattoo OPTIONAL
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine renames the specified account's name to the new account name
|
|
in the account domain.
|
|
|
|
Arguments:
|
|
|
|
DomainHandle - The account domain handle
|
|
|
|
NewName - New account name to rename to
|
|
|
|
AccountType - indicate it is Administrator account or Guest account
|
|
SCE_RENAME_ADMIN
|
|
SCE_RENAME_GUEST
|
|
SCE_DISABLE_ADMIN
|
|
SCE_DISABLE_GUEST
|
|
|
|
Return value:
|
|
|
|
NTSTATUS error codes
|
|
|
|
-- */
|
|
{
|
|
SAM_HANDLE UserHandle1=NULL;
|
|
USER_NAME_INFORMATION Buffer1, *Buffer=NULL;
|
|
PVOID pInfoBuffer=NULL;
|
|
USER_CONTROL_INFORMATION *pControlBuffer=NULL;
|
|
NTSTATUS NtStatus;
|
|
ULONG UserId;
|
|
PWSTR TempStr=NULL;
|
|
DWORD cb;
|
|
PWSTR KeyName;
|
|
BOOL bDisable = FALSE;
|
|
|
|
|
|
//
|
|
// find the right userid for the account
|
|
//
|
|
|
|
switch ( AccountType ) {
|
|
case SCE_RENAME_ADMIN:
|
|
UserId = DOMAIN_USER_RID_ADMIN;
|
|
KeyName = (PWSTR)L"NewAdministratorName";
|
|
break;
|
|
case SCE_RENAME_GUEST:
|
|
UserId = DOMAIN_USER_RID_GUEST;
|
|
KeyName = (PWSTR)L"NewGuestName";
|
|
break;
|
|
case SCE_DISABLE_ADMIN:
|
|
UserId = DOMAIN_USER_RID_ADMIN;
|
|
KeyName = (PWSTR)L"EnableAdminAccount";
|
|
bDisable = TRUE;
|
|
break;
|
|
case SCE_DISABLE_GUEST:
|
|
UserId = DOMAIN_USER_RID_GUEST;
|
|
KeyName = (PWSTR)L"EnableGuestAccount";
|
|
bDisable = TRUE;
|
|
break;
|
|
default:
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
NtStatus = SamOpenUser(
|
|
DomainHandle,
|
|
MAXIMUM_ALLOWED, //USER_ALL_ACCESS,
|
|
UserId,
|
|
&UserHandle1
|
|
);
|
|
|
|
if ( NT_SUCCESS( NtStatus ) ) {
|
|
|
|
NtStatus = SamQueryInformationUser(
|
|
UserHandle1,
|
|
bDisable? UserControlInformation : UserNameInformation,
|
|
&pInfoBuffer
|
|
);
|
|
|
|
if ( NT_SUCCESS( NtStatus ) ) {
|
|
|
|
if ( bDisable ) {
|
|
//
|
|
// disable the accounts
|
|
//
|
|
pControlBuffer = (USER_CONTROL_INFORMATION *)pInfoBuffer;
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
hSectionDomain && hSectionTattoo &&
|
|
(ProductType != NtProductLanManNt) ) {
|
|
//
|
|
// do not save tattoo value of account controls for domain controllers
|
|
//
|
|
ScepTattooManageOneIntValue(hSectionDomain, hSectionTattoo,
|
|
KeyName, 0,
|
|
(pControlBuffer->UserAccountControl & USER_ACCOUNT_DISABLED) ? 0 : 1,
|
|
RtlNtStatusToDosError(NtStatus)
|
|
);
|
|
}
|
|
//
|
|
// compare the control flag with existing flag
|
|
// if it's different, set the new flag to the system
|
|
//
|
|
if ( DisableFlag != (pControlBuffer->UserAccountControl & USER_ACCOUNT_DISABLED) ) {
|
|
|
|
pControlBuffer->UserAccountControl &= ~USER_ACCOUNT_DISABLED;
|
|
pControlBuffer->UserAccountControl |= DisableFlag;
|
|
|
|
NtStatus = SamSetInformationUser(
|
|
UserHandle1,
|
|
UserControlInformation,
|
|
(PVOID)pControlBuffer
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// rename the accounts
|
|
//
|
|
Buffer = (USER_NAME_INFORMATION *)pInfoBuffer;
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
hSectionDomain && hSectionTattoo &&
|
|
(ProductType != NtProductLanManNt) ) {
|
|
//
|
|
// do not save off account names for domain controllers
|
|
//
|
|
ScepTattooManageOneStringValue(hSectionDomain, hSectionTattoo,
|
|
KeyName, 0,
|
|
Buffer->UserName.Buffer,
|
|
Buffer->UserName.Length/sizeof(WCHAR),
|
|
RtlNtStatusToDosError(NtStatus)
|
|
);
|
|
}
|
|
//
|
|
// compare the new name with existing name
|
|
// if it's different, set the new name to the system
|
|
//
|
|
if ( (Buffer->UserName.Length/sizeof(WCHAR) != wcslen(NewName)) ||
|
|
(_wcsnicmp(NewName, Buffer->UserName.Buffer, Buffer->UserName.Length/sizeof(WCHAR)) != 0) ) {
|
|
|
|
//
|
|
// keep the full name and copy the new account name to username field
|
|
//
|
|
cb = Buffer->FullName.Length+2;
|
|
TempStr = (PWSTR)ScepAlloc( (UINT)0, cb);
|
|
if ( TempStr == NULL ) {
|
|
NtStatus = STATUS_NO_MEMORY;
|
|
} else {
|
|
RtlMoveMemory( TempStr, Buffer->FullName.Buffer, cb );
|
|
|
|
if(!RtlCreateUnicodeString(&(Buffer1.FullName), TempStr)){
|
|
|
|
NtStatus = STATUS_NO_MEMORY;
|
|
|
|
} else {
|
|
|
|
if(!RtlCreateUnicodeString(&(Buffer1.UserName), NewName )){
|
|
|
|
NtStatus = STATUS_NO_MEMORY;
|
|
|
|
} else {
|
|
|
|
NtStatus = SamSetInformationUser(
|
|
UserHandle1,
|
|
UserNameInformation,
|
|
(PVOID)&Buffer1
|
|
);
|
|
|
|
RtlFreeUnicodeString( &(Buffer1.UserName) );
|
|
}
|
|
|
|
RtlFreeUnicodeString( &(Buffer1.FullName) );
|
|
}
|
|
|
|
ScepFree(TempStr);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
SamFreeMemory(pInfoBuffer);
|
|
SamCloseHandle( UserHandle1 );
|
|
}
|
|
|
|
return( NtStatus );
|
|
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepConfigurePrivileges(
|
|
IN OUT PSCE_PRIVILEGE_VALUE_LIST *ppPrivilegeAssigned,
|
|
IN BOOL bCreateBuiltinAccount,
|
|
IN DWORD Options,
|
|
IN OUT PSCEP_SPLAY_TREE pIgnoreAccounts OPTIONAL
|
|
)
|
|
/* ++
|
|
|
|
Routine Description:
|
|
|
|
This routine configure the system security in the area of user privilege/rights.
|
|
|
|
Arguments:
|
|
|
|
ppPrivilegeAssigned - The address of the pointer to a list of user privilege/rights as
|
|
specified in the SCP inf file.
|
|
Note, account in the list is a pointer to SID.
|
|
|
|
bCreateBuiltinAccount - if TRUE, builtin accounts (server ops, account ops, print ops,
|
|
power users) will be created if they don't exist
|
|
|
|
Options - configuration options
|
|
|
|
pIgnoreAccounts - the accounts to ignore in configuration (because of pending notifications)
|
|
|
|
Return value:
|
|
|
|
SCESTATUS_SUCCESS
|
|
SCESTATUS_NOT_ENOUGH_RESOURCE
|
|
SCESTATUS_INVALID_PARAMETER
|
|
SCESTATUS_OTHER_ERROR
|
|
|
|
-- */
|
|
{
|
|
|
|
DWORD rc;
|
|
DWORD PrivLowMask=0;
|
|
DWORD PrivHighMask=0;
|
|
|
|
if ( !ppPrivilegeAssigned ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// get privilege mask from the template
|
|
//
|
|
rc = ScepGetPrivilegeMask(hProfile,
|
|
(Options & SCE_POLICY_TEMPLATE) ? SCE_ENGINE_SCP :SCE_ENGINE_SMP,
|
|
&PrivLowMask,
|
|
&PrivHighMask
|
|
);
|
|
|
|
if ( (rc != ERROR_SUCCESS) && (PrivLowMask == 0) && (PrivHighMask == 0) ) {
|
|
//
|
|
// it's likely not possible to fail here because
|
|
// the previous GetPrivileges succeeded.
|
|
// but if it failed, just return.
|
|
//
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// have to log success for all privileges concerned since
|
|
// later, errors will be OR'd
|
|
// This is to handle the case when Se... = *nothing* which
|
|
// implies implicit configuration success
|
|
//
|
|
|
|
if (Options & SCE_RSOP_CALLBACK) {
|
|
ScepRsopLog(SCE_RSOP_PRIVILEGE_INFO,
|
|
ERROR_SUCCESS,
|
|
NULL,
|
|
PrivLowMask,
|
|
PrivHighMask);
|
|
}
|
|
|
|
rc = ScepConfigurePrivilegesWithMask(ppPrivilegeAssigned,
|
|
bCreateBuiltinAccount,
|
|
Options,
|
|
PrivLowMask,
|
|
PrivHighMask,
|
|
NULL,
|
|
pIgnoreAccounts
|
|
);
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepConfigurePrivilegesWithMask(
|
|
IN OUT PSCE_PRIVILEGE_VALUE_LIST *ppPrivilegeAssigned,
|
|
IN BOOL bCreateBuiltinAccount,
|
|
IN DWORD Options,
|
|
IN DWORD LowMask,
|
|
IN DWORD HighMask,
|
|
IN OUT PSCE_ERROR_LOG_INFO *pErrLog OPTIONAL,
|
|
IN OUT PSCEP_SPLAY_TREE pIgnoreAccounts OPTIONAL
|
|
)
|
|
/* ++
|
|
|
|
Routine Description:
|
|
|
|
This routine configure the system security in the area of user privilege/rights.
|
|
|
|
Arguments:
|
|
|
|
ppPrivilegeAssigned - The address of the pointer to a list of user privilege/rights as
|
|
specified in the SCP inf file.
|
|
Note, account in the list is a pointer to SID.
|
|
|
|
bCreateBuiltinAccount - if TRUE, builtin accounts (server ops, account ops, print ops,
|
|
power users) will be created if they don't exist
|
|
|
|
Options - configuration options
|
|
|
|
PrivLowMask - the privileges (mask) to configure
|
|
|
|
PrivHighMask - more privileges (mask) to configure
|
|
|
|
pErrLog - output error info
|
|
|
|
pIgnoreAccounts - the accounts to ignore in configuration (because of pending notifications)
|
|
|
|
|
|
Return value:
|
|
|
|
SCESTATUS_SUCCESS
|
|
SCESTATUS_NOT_ENOUGH_RESOURCE
|
|
SCESTATUS_INVALID_PARAMETER
|
|
SCESTATUS_OTHER_ERROR
|
|
|
|
-- */
|
|
{
|
|
|
|
TCHAR MsgBuf[256];
|
|
DWORD rc=ERROR_SUCCESS;
|
|
DWORD SaveStat=NO_ERROR;
|
|
DWORD PendingRc=NO_ERROR;
|
|
NTSTATUS NtStatus;
|
|
|
|
LSA_HANDLE PolicyHandle=NULL;
|
|
BYTE SidBuffer[256];
|
|
PSID AccountSid=NULL;
|
|
DWORD SidLength;
|
|
SID_NAME_USE UserType;
|
|
DWORD DomainLength;
|
|
|
|
PSCE_PRIVILEGE_VALUE_LIST pPrivilege;
|
|
DWORD nPrivCount=0;
|
|
PSCE_PRIVILEGE_VALUE_LIST pRemAccounts=NULL;
|
|
PWSTR StringSid=NULL;
|
|
|
|
DWORD ConfigStatus[64];
|
|
DWORD DonePrivLowMask=0;
|
|
DWORD DonePrivHighMask=0;
|
|
DWORD PrivLowMask=0;
|
|
DWORD PrivHighMask=0;
|
|
|
|
if ( !ppPrivilegeAssigned ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// user privilege/rights -- LSA Server
|
|
// open the lsa policy first
|
|
//
|
|
|
|
//
|
|
// since client RSOP logging side uses test-and-set for success/failure, the first error (if any)for
|
|
// a particular privilege will always be seen
|
|
//
|
|
|
|
if ( (Options & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|
}
|
|
|
|
if ( (Options & SCE_POLICY_TEMPLATE) && LsaPrivatePolicy ) {
|
|
|
|
PolicyHandle = LsaPrivatePolicy;
|
|
|
|
if ( !ScepSplayTreeEmpty(pIgnoreAccounts) )
|
|
ScepNotifyLogPolicy(0, FALSE, L"Configuration will ignore pending notified accounts", 0, 0, NULL );
|
|
else
|
|
ScepNotifyLogPolicy(0, FALSE, L"No pending notified accounts", 0, 0, NULL );
|
|
|
|
} else {
|
|
|
|
NtStatus = ScepOpenLsaPolicy(
|
|
MAXIMUM_ALLOWED, //GENERIC_ALL,
|
|
&PolicyHandle,
|
|
(Options & ( SCE_POLICY_TEMPLATE | SCE_SYSTEM_DB) ) ? TRUE : FALSE // do not notify policy filter if within policy prop
|
|
);
|
|
if (NtStatus != ERROR_SUCCESS) {
|
|
|
|
rc = RtlNtStatusToDosError( NtStatus );
|
|
|
|
if ( (Options & SCE_SYSTEM_SETTINGS) && pErrLog ) {
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_LSA_POLICY
|
|
);
|
|
} else {
|
|
|
|
ScepLogOutput3(1, rc, SCEDLL_LSA_POLICY);
|
|
}
|
|
|
|
SaveStat = rc;
|
|
goto Done;
|
|
}
|
|
}
|
|
|
|
AccountSid = (PSID)SidBuffer;
|
|
|
|
ScepIsDomainLocal(NULL);
|
|
|
|
PrivLowMask = LowMask;
|
|
PrivHighMask = HighMask;
|
|
|
|
//
|
|
// make sure Authenticated Users, Everyone and Enterprise Controllers have appropriate rights
|
|
// ignore any error occurred
|
|
//
|
|
|
|
(void)ScepCheckNetworkLogonRights(PolicyHandle,
|
|
&PrivLowMask,
|
|
&PrivHighMask,
|
|
ppPrivilegeAssigned);
|
|
|
|
//
|
|
// save the old privilege settings
|
|
//
|
|
if ( (Options & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) ) {
|
|
|
|
ScepTattooSavePrivilegeValues(hProfile, PolicyHandle,
|
|
PrivLowMask, PrivHighMask,
|
|
Options
|
|
);
|
|
// initialize
|
|
for ( int i=0;i<64;i++) ConfigStatus[i] = (DWORD)-1;
|
|
|
|
}
|
|
|
|
//
|
|
// other area accounts to remove for the privilege mask
|
|
//
|
|
|
|
NtStatus = ScepBuildAccountsToRemove(
|
|
PolicyHandle,
|
|
PrivLowMask, // the privileges to look up
|
|
PrivHighMask,
|
|
SCE_BUILD_IGNORE_UNKNOWN | SCE_BUILD_ACCOUNT_SID,
|
|
*ppPrivilegeAssigned, // accounts in the template already
|
|
Options,
|
|
pIgnoreAccounts,
|
|
&pRemAccounts // accounts to remove
|
|
);
|
|
|
|
if ( (Options & SCE_POLICY_TEMPLATE) &&
|
|
(NtStatus == STATUS_PENDING) ) {
|
|
|
|
// this error is to make sure that policy propagation will be invoked again
|
|
ScepLogOutput3(0,0, SCESRV_POLICY_PENDING_REMOVE_RIGHTS);
|
|
|
|
PendingRc = ERROR_IO_PENDING;
|
|
NtStatus = STATUS_SUCCESS;
|
|
}
|
|
|
|
if ( NT_SUCCESS(NtStatus) && pRemAccounts ) {
|
|
//
|
|
// remove user rights for the accounts first
|
|
//
|
|
|
|
for (pPrivilege = pRemAccounts;
|
|
pPrivilege != NULL;
|
|
pPrivilege = pPrivilege->Next ) {
|
|
|
|
if ( pPrivilege->PrivLowPart == 0 &&
|
|
pPrivilege->PrivHighPart == 0 ) {
|
|
continue;
|
|
}
|
|
//
|
|
// Note: even though it's an invalid account SID,
|
|
// we still should remove it from the system
|
|
// because this account is enumerated from current system.
|
|
//
|
|
/*
|
|
if ( !ScepValidSid( (PSID)(pPrivilege->Name) ) ) {
|
|
continue;
|
|
}
|
|
*/
|
|
//
|
|
// get the user/group sid string (to display)
|
|
//
|
|
ConvertSidToStringSid( (PSID)(pPrivilege->Name), &StringSid );
|
|
|
|
if ( !(Options & SCE_SYSTEM_SETTINGS) ) {
|
|
|
|
//
|
|
// lookup for the user/group name. If it does not exist
|
|
// log an error and continue ? (or stop ?)
|
|
//
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_CONFIGURE, StringSid ? StringSid : L"SID");
|
|
|
|
if ( (Options & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
SaveStat = ERROR_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
DonePrivHighMask |= (pPrivilege->PrivHighPart & PrivHighMask);
|
|
DonePrivLowMask |= (pPrivilege->PrivLowPart & PrivLowMask);
|
|
|
|
//
|
|
// remove the rights
|
|
//
|
|
NtStatus = ScepAddOrRemoveAccountRights(
|
|
PolicyHandle,
|
|
(PSID)(pPrivilege->Name),
|
|
FALSE,
|
|
pPrivilege->PrivLowPart & PrivLowMask,
|
|
pPrivilege->PrivHighPart & PrivHighMask
|
|
);
|
|
|
|
rc = RtlNtStatusToDosError( NtStatus );
|
|
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
|
|
if ( (Options & SCE_SYSTEM_SETTINGS) && pErrLog ) {
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_SCP_ERROR_CONFIGURE,
|
|
StringSid ? StringSid : L"SID"
|
|
);
|
|
} else {
|
|
|
|
ScepLogOutput3(1,rc,SCEDLL_SCP_ERROR_CONFIGURE,
|
|
StringSid ? StringSid : L"SID");
|
|
}
|
|
|
|
// update the tattoo status array
|
|
if ( (Options & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) ) {
|
|
|
|
ScepTattooUpdatePrivilegeArrayStatus(ConfigStatus,
|
|
rc,
|
|
pPrivilege->PrivLowPart & PrivLowMask,
|
|
pPrivilege->PrivHighPart & PrivHighMask
|
|
);
|
|
}
|
|
|
|
SaveStat = rc;
|
|
|
|
if ( Options & SCE_RSOP_CALLBACK){
|
|
|
|
ScepRsopLog(SCE_RSOP_PRIVILEGE_INFO,
|
|
rc,
|
|
NULL,
|
|
pPrivilege->PrivLowPart & PrivLowMask,
|
|
pPrivilege->PrivHighPart & PrivHighMask);
|
|
}
|
|
}
|
|
else if (Options & SCE_RSOP_CALLBACK) {
|
|
|
|
// success - has to be logged because some privilege may want to remove all accounts and
|
|
// processing is over at this point for such privileges
|
|
|
|
ScepRsopLog(SCE_RSOP_PRIVILEGE_INFO,
|
|
rc,
|
|
NULL,
|
|
pPrivilege->PrivLowPart & PrivLowMask,
|
|
pPrivilege->PrivHighPart & PrivHighMask);
|
|
|
|
}
|
|
|
|
|
|
if ( StringSid ) {
|
|
LocalFree(StringSid);
|
|
StringSid = NULL;
|
|
}
|
|
}
|
|
} else if ( !NT_SUCCESS(NtStatus) &&
|
|
( ProductType != NtProductLanManNt ) ) {
|
|
//
|
|
// fail to get the accounts to remove
|
|
// in this case, do not remove any tattoo value
|
|
//
|
|
ScepTattooUpdatePrivilegeArrayStatus(ConfigStatus,
|
|
RtlNtStatusToDosError(NtStatus),
|
|
PrivLowMask,
|
|
PrivHighMask
|
|
);
|
|
}
|
|
|
|
//
|
|
// free the remove account list
|
|
//
|
|
ScepFreePrivilegeValueList(pRemAccounts);
|
|
|
|
if ( (Options & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
SaveStat = ERROR_NOT_SUPPORTED;
|
|
|
|
} else {
|
|
|
|
for (pPrivilege = *ppPrivilegeAssigned;
|
|
pPrivilege != NULL;
|
|
pPrivilege = pPrivilege->Next ) {
|
|
|
|
if ( !(Options & SCE_SYSTEM_SETTINGS) ) {
|
|
|
|
if ( (Options & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
SaveStat = ERROR_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// remember the privileges we touched here
|
|
//
|
|
DonePrivHighMask |= pPrivilege->PrivHighPart;
|
|
DonePrivLowMask |= pPrivilege->PrivLowPart;
|
|
|
|
//
|
|
// note, this list may contain SID or name (when name can't
|
|
// be mapped to SID, such as in dcpromo case)
|
|
// so both name and SID must be handled here.
|
|
// lookup for the user/group name. If it does not exist
|
|
// log an error and continue ? (or stop ?)
|
|
//
|
|
|
|
if ( ScepValidSid( (PSID)(pPrivilege->Name) ) ) {
|
|
//
|
|
// get the user/group sid string (to display)
|
|
//
|
|
ConvertSidToStringSid( (PSID)(pPrivilege->Name), &StringSid );
|
|
|
|
if ( !(Options & SCE_SYSTEM_SETTINGS) &&
|
|
(nPrivCount < TICKS_PRIVILEGE) ) {
|
|
|
|
//
|
|
// only post maximum TICKS_PRIVILEGE ticks because that's the number
|
|
// remembers in the total ticks
|
|
//
|
|
|
|
ScepPostProgress(1, AREA_PRIVILEGES, StringSid);
|
|
nPrivCount++;
|
|
}
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_CONFIGURE, StringSid ? StringSid : L"SID");
|
|
|
|
//
|
|
// check if this account should be ignored
|
|
//
|
|
NtStatus = STATUS_SUCCESS;
|
|
|
|
if ( (Options & SCE_POLICY_TEMPLATE) ) {
|
|
|
|
if ( ScepSplayValueExist( (PVOID)(pPrivilege->Name), pIgnoreAccounts) ) {
|
|
//
|
|
// this one should be ingored in this policy prop
|
|
//
|
|
NtStatus = STATUS_PENDING;
|
|
rc = ERROR_IO_PENDING;
|
|
|
|
ScepLogOutput3(1, 0, SCESRV_POLICY_PENDING_RIGHTS, StringSid ? StringSid : L"SID");
|
|
/*
|
|
} else {
|
|
|
|
ScepLogOutput2(1, 0, L"%s will be configured.", StringSid ? StringSid : L"SID");
|
|
*/ }
|
|
}
|
|
|
|
if ( NT_SUCCESS(NtStatus) && (STATUS_PENDING != NtStatus) ) {
|
|
|
|
NtStatus = ScepAdjustAccountPrivilegesRights(
|
|
PolicyHandle,
|
|
(PSID)(pPrivilege->Name),
|
|
pPrivilege->PrivLowPart,
|
|
PrivLowMask,
|
|
pPrivilege->PrivHighPart,
|
|
PrivHighMask,
|
|
Options
|
|
);
|
|
rc = RtlNtStatusToDosError( NtStatus );
|
|
}
|
|
|
|
if ( !NT_SUCCESS(NtStatus) || (STATUS_PENDING == NtStatus) ) {
|
|
|
|
if ( (Options & SCE_SYSTEM_SETTINGS) && pErrLog ) {
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_SCP_ERROR_CONFIGURE,
|
|
StringSid ? StringSid : L"SID"
|
|
);
|
|
|
|
} else if ( STATUS_PENDING != NtStatus) {
|
|
|
|
ScepLogOutput3(1, rc,
|
|
SCEDLL_SCP_ERROR_CONFIGURE,
|
|
StringSid ? StringSid : L"SID");
|
|
}
|
|
|
|
if ( ERROR_IO_PENDING == rc )
|
|
PendingRc = rc;
|
|
else
|
|
SaveStat = rc;
|
|
|
|
// update tattoo status array
|
|
if ( (Options & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) ) {
|
|
|
|
ScepTattooUpdatePrivilegeArrayStatus(ConfigStatus,
|
|
rc,
|
|
pPrivilege->PrivLowPart,
|
|
pPrivilege->PrivHighPart
|
|
);
|
|
}
|
|
}
|
|
|
|
if ( StringSid ) {
|
|
LocalFree(StringSid);
|
|
StringSid = NULL;
|
|
}
|
|
|
|
} else if (Options & SCE_SYSTEM_SETTINGS ) {
|
|
//
|
|
// if work on system settings directly, the buffer must contain
|
|
// a SID. If not, it's an error
|
|
//
|
|
if ( pErrLog ) {
|
|
ScepBuildErrorLogInfo(
|
|
ERROR_NONE_MAPPED,
|
|
pErrLog,
|
|
SCEDLL_INVALID_GROUP,
|
|
pPrivilege->Name
|
|
);
|
|
}
|
|
|
|
if ( Options & SCE_RSOP_CALLBACK ){
|
|
|
|
ScepRsopLog(SCE_RSOP_PRIVILEGE_INFO,
|
|
ERROR_NONE_MAPPED,
|
|
NULL,
|
|
pPrivilege->PrivLowPart,
|
|
pPrivilege->PrivHighPart);
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( !(Options & SCE_SYSTEM_SETTINGS) &&
|
|
(nPrivCount < TICKS_PRIVILEGE) ) {
|
|
|
|
//
|
|
// only post maximum TICKS_PRIVILEGE ticks because that's the number
|
|
// remembers in the total ticks
|
|
//
|
|
|
|
ScepPostProgress(1, AREA_PRIVILEGES, pPrivilege->Name);
|
|
nPrivCount++;
|
|
}
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_CONFIGURE, pPrivilege->Name);
|
|
|
|
SidLength=256;
|
|
DomainLength=256;
|
|
MsgBuf[0] = L'\0';
|
|
|
|
rc = ERROR_SUCCESS;
|
|
|
|
if ( wcschr(pPrivilege->Name, L'\\') == NULL ) {
|
|
//
|
|
// isolated accounts can't be resolved when reading the configuration
|
|
// no need to try now.
|
|
//
|
|
rc = ERROR_NONE_MAPPED;
|
|
|
|
} else if ( !LookupAccountName(
|
|
NULL,
|
|
pPrivilege->Name,
|
|
AccountSid,
|
|
&SidLength,
|
|
MsgBuf,
|
|
&DomainLength,
|
|
&UserType
|
|
)) {
|
|
|
|
rc = GetLastError();
|
|
}
|
|
|
|
if ( ERROR_SUCCESS != rc && bCreateBuiltinAccount ) {
|
|
|
|
//
|
|
// builtin accounts should be created here
|
|
//
|
|
rc = ScepCreateBuiltinAccountInLsa(
|
|
PolicyHandle,
|
|
pPrivilege->Name,
|
|
AccountSid
|
|
);
|
|
|
|
|
|
}
|
|
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
|
|
ScepLogOutput3(1, rc, SCEDLL_CANNOT_FIND, pPrivilege->Name);
|
|
|
|
if ( Options & SCE_RSOP_CALLBACK){
|
|
|
|
ScepRsopLog(SCE_RSOP_PRIVILEGE_INFO,
|
|
rc,
|
|
NULL,
|
|
pPrivilege->PrivLowPart,
|
|
pPrivilege->PrivHighPart);
|
|
}
|
|
|
|
//
|
|
// for accounts not mapped in the tattoo value
|
|
// ignore them so that the tattoo value can be removed
|
|
// update tattoo status array
|
|
if ( (Options & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) ) {
|
|
|
|
ScepTattooUpdatePrivilegeArrayStatus(ConfigStatus,
|
|
0, // rc, see comment above
|
|
pPrivilege->PrivLowPart,
|
|
pPrivilege->PrivHighPart
|
|
);
|
|
}
|
|
|
|
if ( ERROR_TRUSTED_RELATIONSHIP_FAILURE == rc ) {
|
|
//
|
|
// this error is only returned when the name
|
|
// can't be found locally and trust relationship
|
|
// is broken on the domain
|
|
//
|
|
// for policy propagation, this failure is the same
|
|
// as account not found (locally).
|
|
//
|
|
rc = ERROR_NONE_MAPPED;
|
|
}
|
|
|
|
SaveStat = rc;
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// check if the account should be ignored
|
|
//
|
|
NtStatus = STATUS_SUCCESS;
|
|
|
|
if ( (Options & SCE_POLICY_TEMPLATE) ) {
|
|
|
|
if ( ScepSplayValueExist( (PVOID)AccountSid, pIgnoreAccounts) ) {
|
|
//
|
|
// this one should be ingored in this policy prop
|
|
//
|
|
NtStatus = STATUS_PENDING;
|
|
rc = ERROR_IO_PENDING;
|
|
|
|
ScepLogOutput3(1, 0, SCESRV_POLICY_PENDING_RIGHTS, pPrivilege->Name);
|
|
/*
|
|
} else {
|
|
|
|
ScepLogOutput2(1, 0, L"%s will be configured.", pPrivilege->Name);
|
|
*/ }
|
|
}
|
|
|
|
if ( NT_SUCCESS(NtStatus) && (NtStatus != STATUS_PENDING) ) {
|
|
|
|
NtStatus = ScepAdjustAccountPrivilegesRights(
|
|
PolicyHandle,
|
|
AccountSid,
|
|
pPrivilege->PrivLowPart,
|
|
PrivLowMask,
|
|
pPrivilege->PrivHighPart,
|
|
PrivHighMask,
|
|
Options
|
|
);
|
|
rc = RtlNtStatusToDosError( NtStatus );
|
|
|
|
}
|
|
|
|
if ( !NT_SUCCESS(NtStatus) || (NtStatus == STATUS_PENDING) ) {
|
|
|
|
if ( STATUS_PENDING != NtStatus ) {
|
|
ScepLogOutput3(1, rc,
|
|
SCEDLL_SCP_ERROR_CONFIGURE,
|
|
pPrivilege->Name);
|
|
SaveStat = rc;
|
|
|
|
} else
|
|
PendingRc = rc;
|
|
|
|
if ( (Options & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) ) {
|
|
|
|
ScepTattooUpdatePrivilegeArrayStatus(ConfigStatus,
|
|
rc,
|
|
pPrivilege->PrivLowPart,
|
|
pPrivilege->PrivHighPart
|
|
);
|
|
}
|
|
|
|
// goto Done;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// at this point, if rc == ERROR_SUCCESS we should log all privs concerned with this acct
|
|
//
|
|
if ( rc == ERROR_SUCCESS &&
|
|
(Options & SCE_RSOP_CALLBACK) ){
|
|
|
|
ScepRsopLog(SCE_RSOP_PRIVILEGE_INFO,
|
|
rc,
|
|
NULL,
|
|
pPrivilege->PrivLowPart,
|
|
pPrivilege->PrivHighPart);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
Done:
|
|
|
|
if ( StringSid ) {
|
|
LocalFree(StringSid);
|
|
}
|
|
|
|
if ( !(Options & SCE_SYSTEM_SETTINGS) &&
|
|
(nPrivCount < TICKS_PRIVILEGE) ) {
|
|
|
|
ScepPostProgress(TICKS_PRIVILEGE-nPrivCount,
|
|
AREA_PRIVILEGES, NULL);
|
|
}
|
|
|
|
if ( SaveStat == ERROR_SUCCESS ) SaveStat = PendingRc;
|
|
|
|
if ( (Options & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) ) {
|
|
|
|
ScepTattooUpdatePrivilegeArrayStatus(ConfigStatus,
|
|
0,
|
|
DonePrivLowMask,
|
|
DonePrivHighMask
|
|
);
|
|
if ( SaveStat == ERROR_SUCCESS ) {
|
|
//
|
|
// make sure all privileges are covered
|
|
//
|
|
ScepTattooUpdatePrivilegeArrayStatus(ConfigStatus,
|
|
0,
|
|
PrivLowMask,
|
|
PrivHighMask
|
|
);
|
|
}
|
|
|
|
ScepTattooRemovePrivilegeValues(hProfile,
|
|
ConfigStatus
|
|
);
|
|
|
|
}
|
|
|
|
if ( PolicyHandle != LsaPrivatePolicy )
|
|
LsaClose(PolicyHandle);
|
|
|
|
return( ScepDosErrorToSceStatus(SaveStat) );
|
|
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepGetPrivilegeMask(
|
|
IN PSCECONTEXT hProfile,
|
|
IN SCETYPE ProfileType,
|
|
OUT PDWORD pdLowMask,
|
|
OUT PDWORD pdHighMask
|
|
)
|
|
{
|
|
SCESTATUS rc;
|
|
PSCESECTION hSection=NULL;
|
|
DWORD nLowMask, nHighMask;
|
|
DWORD i;
|
|
|
|
|
|
if ( !hProfile || !pdHighMask || !pdLowMask ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// open the section
|
|
//
|
|
rc = ScepOpenSectionForName(
|
|
hProfile,
|
|
ProfileType,
|
|
szPrivilegeRights,
|
|
&hSection
|
|
);
|
|
|
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|
ScepLogOutput3( 1,
|
|
ScepSceStatusToDosError(rc),
|
|
SCEERR_OPEN,
|
|
(LPTSTR)szPrivilegeRights
|
|
);
|
|
return(rc);
|
|
}
|
|
|
|
nLowMask = 0;
|
|
nHighMask = 0;
|
|
for ( i=0; i<cPrivCnt; i++) {
|
|
|
|
rc = SceJetSeek(
|
|
hSection,
|
|
SCE_Privileges[i].Name,
|
|
wcslen(SCE_Privileges[i].Name)*sizeof(WCHAR),
|
|
SCEJET_SEEK_EQ_NO_CASE
|
|
);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
if ( i < 32 ) {
|
|
|
|
nLowMask |= (1 << i );
|
|
} else {
|
|
nHighMask |= (1 << ( i-32 ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// close the section
|
|
//
|
|
SceJetCloseSection( &hSection, TRUE );
|
|
|
|
*pdLowMask = nLowMask;
|
|
*pdHighMask = nHighMask;
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
DWORD
|
|
ScepCreateBuiltinAccountInLsa(
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN LPTSTR AccountName,
|
|
OUT PSID AccountSid
|
|
)
|
|
{
|
|
DWORD rc;
|
|
WCHAR szTempString[256];
|
|
ULONG Rid;
|
|
|
|
if ( !PolicyHandle || !AccountName || !AccountSid ) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// figure out which constant SID to build
|
|
//
|
|
|
|
Rid = 0;
|
|
szTempString[0] = L'\0';
|
|
|
|
LoadString( MyModuleHandle,
|
|
SCESRV_ALIAS_NAME_SERVER_OPS,
|
|
szTempString,
|
|
255
|
|
);
|
|
if ( _wcsicmp(AccountName, szTempString) == 0 ) {
|
|
//
|
|
// it's server operators
|
|
//
|
|
Rid = DOMAIN_ALIAS_RID_SYSTEM_OPS;
|
|
|
|
} else {
|
|
|
|
szTempString[0] = L'\0';
|
|
|
|
LoadString( MyModuleHandle,
|
|
SCESRV_ALIAS_NAME_ACCOUNT_OPS,
|
|
szTempString,
|
|
255
|
|
);
|
|
if ( _wcsicmp(AccountName, szTempString) == 0 ) {
|
|
//
|
|
// it's account operators
|
|
//
|
|
Rid = DOMAIN_ALIAS_RID_ACCOUNT_OPS;
|
|
|
|
} else {
|
|
|
|
szTempString[0] = L'\0';
|
|
|
|
LoadString( MyModuleHandle,
|
|
SCESRV_ALIAS_NAME_PRINT_OPS,
|
|
szTempString,
|
|
255
|
|
);
|
|
|
|
if ( _wcsicmp(AccountName, szTempString) == 0 ) {
|
|
//
|
|
// it's print operators
|
|
//
|
|
Rid = DOMAIN_ALIAS_RID_PRINT_OPS;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( Rid ) {
|
|
//
|
|
// if found the account, build the SID
|
|
// create the account in lsa database and return the SID
|
|
//
|
|
SID_IDENTIFIER_AUTHORITY sidBuiltinAuthority = SECURITY_NT_AUTHORITY;
|
|
NTSTATUS NtStatus;
|
|
|
|
NtStatus = RtlInitializeSid( AccountSid, &sidBuiltinAuthority, 2 );
|
|
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
*(RtlSubAuthoritySid(AccountSid, 0)) = SECURITY_BUILTIN_DOMAIN_RID;
|
|
*(RtlSubAuthoritySid(AccountSid, 1)) = Rid;
|
|
|
|
//
|
|
// create the account in Lsa
|
|
//
|
|
LSA_HANDLE AccountHandle=NULL;
|
|
|
|
NtStatus = LsaCreateAccount(PolicyHandle,
|
|
AccountSid,
|
|
ACCOUNT_ALL_ACCESS,
|
|
&AccountHandle
|
|
);
|
|
if ( STATUS_OBJECT_NAME_EXISTS == NtStatus ||
|
|
STATUS_OBJECT_NAME_COLLISION == NtStatus ) {
|
|
NtStatus = STATUS_SUCCESS;
|
|
}
|
|
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
|
|
if ( AccountHandle ) {
|
|
LsaClose(AccountHandle);
|
|
}
|
|
|
|
} else {
|
|
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
}
|
|
|
|
ScepLogOutput3(3,rc, SCESRV_ALIAS_CREATE, Rid);
|
|
|
|
} else {
|
|
|
|
rc = ERROR_NONE_MAPPED;
|
|
ScepLogOutput3(3,0, SCESRV_ALIAS_UNSUPPORTED, AccountName);
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ScepBuildAccountsToRemove(
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN DWORD PrivLowMask,
|
|
IN DWORD PrivHighMask,
|
|
IN DWORD dwBuildRule,
|
|
IN PSCE_PRIVILEGE_VALUE_LIST pTemplateList OPTIONAL,
|
|
IN DWORD Options OPTIONAL,
|
|
IN OUT PSCEP_SPLAY_TREE pIgnoreAccounts OPTIONAL,
|
|
OUT PSCE_PRIVILEGE_VALUE_LIST *pRemoveList
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Build a list of accounts which are not in pTemplateList for the privilege(s)
|
|
.
|
|
|
|
Note, the account(s) returned are in SID format when dwBuildRule requests
|
|
SCE_BUILD_ACCOUNT_SID, or in name format if the flag is not set.
|
|
|
|
The reason to return all name format (instead of name/SID string format) is due
|
|
to the default templates (defltdc.inf, dcup.inf) use names instead of SID string
|
|
for account domain accounts (such as the guest account). Even if a sid string
|
|
is used, the sid string and the account name will be treated as two different
|
|
accounts, which will be eventually duplicated out in configuration (where
|
|
account SID is used).
|
|
|
|
*/
|
|
{
|
|
//
|
|
// LSA buffers and variables
|
|
//
|
|
|
|
ULONG uAccountIndex = 0;
|
|
ULONG uCountOfRights = 0;
|
|
DWORD dwPrivLowThisAccount = 0;
|
|
DWORD dwPrivHighThisAccount = 0;
|
|
ULONG uEnumerationContext;
|
|
ULONG uPreferedMaximumLength;
|
|
ULONG uNumAccounts;
|
|
|
|
PLSA_ENUMERATION_INFORMATION aSids = NULL;
|
|
PLSA_TRANSLATED_NAME aNames=NULL;
|
|
PLSA_REFERENCED_DOMAIN_LIST pReferencedDomains=NULL;
|
|
PUNICODE_STRING aUserRights = NULL;
|
|
|
|
//
|
|
// other variables
|
|
//
|
|
|
|
NTSTATUS NtStatus;
|
|
NTSTATUS NtStatusSave=STATUS_SUCCESS;
|
|
NTSTATUS NtStatusRsop = STATUS_SUCCESS;
|
|
|
|
PSCE_NAME_LIST pAccountSidOrName=NULL;
|
|
PSCE_PRIVILEGE_VALUE_LIST pAccountNode=NULL;
|
|
PWSTR pwszStringSid = NULL;
|
|
|
|
SCE_NAME_LIST sNameList;
|
|
PSCE_NAME_LIST psList = &sNameList;
|
|
PWSTR StringSid=NULL;
|
|
BOOL bIgnored = FALSE;
|
|
|
|
if ( !PolicyHandle || !pRemoveList ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if ( PrivLowMask == 0 && PrivHighMask == 0 ) {
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// get all the accounts (potentially with multiple calls to LSA - the while loop)
|
|
//
|
|
|
|
//
|
|
// say each SID has 20 bytes and we'd like to get about SCEP_NUM_LSA_QUERY_SIDS
|
|
// (currently SCEP_NUM_LSA_QUERY_SIDS = 2000 SIDs at a time (approx 40 kB))
|
|
// we might need to tune SCEP_NUM_LSA_QUERY_SIDS depending on LSA memory performance
|
|
//
|
|
|
|
uPreferedMaximumLength = 20 * SCEP_NUM_LSA_QUERY_SIDS;
|
|
uEnumerationContext = 0;
|
|
uNumAccounts = 0;
|
|
|
|
NtStatus = LsaEnumerateAccounts(
|
|
PolicyHandle,
|
|
&uEnumerationContext,
|
|
(PVOID *)&aSids,
|
|
uPreferedMaximumLength,
|
|
&uNumAccounts
|
|
);
|
|
//
|
|
// in case there are more accounts returned, continue processing
|
|
// until all SIDs
|
|
// from LSA are exhausted
|
|
//
|
|
|
|
while ( NtStatus == STATUS_SUCCESS
|
|
&& uNumAccounts > 0
|
|
&& aSids != NULL) {
|
|
|
|
NtStatus = STATUS_SUCCESS;
|
|
|
|
//
|
|
// convert SIDs to names if required
|
|
//
|
|
|
|
if ( !(dwBuildRule & SCE_BUILD_ACCOUNT_SID) &&
|
|
!(dwBuildRule & SCE_BUILD_ACCOUNT_SID_STRING) ) {
|
|
|
|
NtStatus = LsaLookupSids(
|
|
PolicyHandle,
|
|
uNumAccounts,
|
|
(PSID *)aSids,
|
|
&pReferencedDomains,
|
|
&aNames
|
|
);
|
|
}
|
|
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
BOOL bUsed;
|
|
|
|
for ( uAccountIndex = 0; uAccountIndex < uNumAccounts ; uAccountIndex++ ) {
|
|
|
|
ScepFree ( pwszStringSid );
|
|
pwszStringSid = NULL;
|
|
|
|
ScepConvertSidToPrefixStringSid(aSids[uAccountIndex].Sid, &pwszStringSid);
|
|
|
|
//
|
|
// check if this account is in the ignore list
|
|
//
|
|
if ( (Options & SCE_POLICY_TEMPLATE) ) {
|
|
|
|
if ( ScepSplayValueExist( (PVOID)(aSids[uAccountIndex].Sid), pIgnoreAccounts) ) {
|
|
//
|
|
// this one should be ingored in this policy prop
|
|
//
|
|
//
|
|
NtStatusRsop = STATUS_PENDING;
|
|
bIgnored = TRUE;
|
|
|
|
ScepLogOutput2(1, 0, L"\t\tIgnore %s.", pwszStringSid ? pwszStringSid : L"");
|
|
|
|
continue;
|
|
/*
|
|
} else {
|
|
|
|
ScepLogOutput2(1, 0, L"\tSome rights assigned to %s may be removed", pwszStringSid ? pwszStringSid : L"");
|
|
*/
|
|
}
|
|
}
|
|
|
|
uCountOfRights = 0;
|
|
aUserRights = NULL;
|
|
|
|
NtStatus = LsaEnumerateAccountRights(
|
|
PolicyHandle,
|
|
aSids[uAccountIndex].Sid,
|
|
&aUserRights,
|
|
&uCountOfRights
|
|
);
|
|
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
|
|
//
|
|
// log error for this account and continue with the next account
|
|
//
|
|
|
|
ScepLogOutput3(1,
|
|
RtlNtStatusToDosError(NtStatus),
|
|
SCESRV_ERROR_QUERY_ACCOUNT_RIGHTS,
|
|
pwszStringSid);
|
|
|
|
if ( aUserRights ) {
|
|
|
|
LsaFreeMemory( aUserRights );
|
|
|
|
aUserRights = NULL;
|
|
|
|
}
|
|
|
|
NtStatusSave = NtStatus;
|
|
|
|
continue;
|
|
}
|
|
|
|
dwPrivLowThisAccount = 0;
|
|
dwPrivHighThisAccount = 0;
|
|
|
|
ScepBuildDwMaskFromStrArray(
|
|
aUserRights,
|
|
uCountOfRights,
|
|
&dwPrivLowThisAccount,
|
|
&dwPrivHighThisAccount
|
|
);
|
|
|
|
//
|
|
// if account has at least one user right after masking,
|
|
// we have to process it further
|
|
//
|
|
|
|
if ( (dwPrivLowThisAccount & PrivLowMask) ||
|
|
(dwPrivHighThisAccount & PrivHighMask) ) {
|
|
|
|
if ( dwBuildRule & SCE_BUILD_ACCOUNT_SID ) {
|
|
//
|
|
// add the SID to the name list
|
|
//
|
|
(VOID) ScepAddSidToNameList(
|
|
&pAccountSidOrName,
|
|
aSids[uAccountIndex].Sid,
|
|
FALSE,
|
|
&bUsed);
|
|
|
|
} else if ( dwBuildRule & SCE_BUILD_ACCOUNT_SID_STRING ) {
|
|
//
|
|
// add the SID in string format
|
|
//
|
|
if ( ERROR_SUCCESS == ScepConvertSidToPrefixStringSid(
|
|
aSids[uAccountIndex].Sid, &StringSid) ) {
|
|
|
|
sNameList.Name = StringSid;
|
|
sNameList.Next = NULL;
|
|
|
|
pAccountSidOrName = psList;
|
|
} // else out of memory, catch it later
|
|
|
|
} else {
|
|
|
|
//
|
|
// detect if the sid can't be mapped, there are two cases:
|
|
// 1) the domain can't be found, a string format of SID is returned
|
|
// 2) the domain is found. If the domain is builtin and the account
|
|
// name has all digits (the RID), then the builtin account can't be found
|
|
// the second case is solely for the server and DC accounts (PU, SO, AO, PO)
|
|
//
|
|
|
|
if ( (dwBuildRule & SCE_BUILD_IGNORE_UNKNOWN) &&
|
|
( aNames[uAccountIndex].Use == SidTypeInvalid ||
|
|
aNames[uAccountIndex].Use == SidTypeUnknown ) ) {
|
|
|
|
//
|
|
// this name is not mapped, ignore it and
|
|
// continue with the next account
|
|
//
|
|
|
|
if ( aUserRights ) {
|
|
|
|
LsaFreeMemory( aUserRights );
|
|
|
|
aUserRights = NULL;
|
|
|
|
}
|
|
|
|
NtStatusSave = NtStatus;
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// build the full name of each account
|
|
//
|
|
if ( pReferencedDomains->Entries > 0 && aNames[uAccountIndex].Use != SidTypeWellKnownGroup &&
|
|
pReferencedDomains->Domains != NULL &&
|
|
aNames[uAccountIndex].DomainIndex != -1 &&
|
|
(ULONG)(aNames[uAccountIndex].DomainIndex) < pReferencedDomains->Entries &&
|
|
ScepIsDomainLocalBySid(pReferencedDomains->Domains[aNames[uAccountIndex].DomainIndex].Sid) == FALSE &&
|
|
ScepIsDomainLocal(&pReferencedDomains->Domains[aNames[uAccountIndex].DomainIndex].Name) == FALSE ) {
|
|
|
|
// For migrated accounts, sid will map to the new account and we'll lose
|
|
// permissions for the original account. Detect this case by doing a reverse
|
|
// lookup and comparing the SIDs
|
|
// If sid -> name -> sid returns a different sid, then it's a sid history
|
|
// name lookup and the account is from a different domain. Converting to current
|
|
// name will cause it to lose the original sid from the policy. We'll hold on
|
|
// to the original SID.
|
|
|
|
bool bMigratedAccount = false;
|
|
|
|
NtStatus = ScepIsMigratedAccount(
|
|
PolicyHandle,
|
|
&aNames[uAccountIndex].Name,
|
|
&pReferencedDomains->Domains[aNames[uAccountIndex].DomainIndex].Name,
|
|
aSids[uAccountIndex].Sid,
|
|
&bMigratedAccount);
|
|
|
|
if(NT_SUCCESS(NtStatus) && bMigratedAccount) {
|
|
|
|
// add SID string to the list
|
|
|
|
(VOID )ScepAddToNameList(
|
|
&pAccountSidOrName,
|
|
pwszStringSid,
|
|
0);
|
|
|
|
} else {
|
|
|
|
NtStatus = STATUS_SUCCESS; // ignore failure to detect migrated account
|
|
|
|
//
|
|
// add both domain name and account name
|
|
//
|
|
(VOID) ScepAddTwoNamesToNameList(
|
|
&pAccountSidOrName,
|
|
TRUE,
|
|
pReferencedDomains->Domains[aNames[uAccountIndex].DomainIndex].Name.Buffer,
|
|
pReferencedDomains->Domains[aNames[uAccountIndex].DomainIndex].Name.Length/2,
|
|
aNames[uAccountIndex].Name.Buffer,
|
|
aNames[uAccountIndex].Name.Length/2);
|
|
}
|
|
} else {
|
|
//
|
|
// add only the account name
|
|
//
|
|
(VOID) ScepAddToNameList(
|
|
&pAccountSidOrName,
|
|
aNames[uAccountIndex].Name.Buffer,
|
|
aNames[uAccountIndex].Name.Length/2);
|
|
}
|
|
}
|
|
|
|
if ( pAccountSidOrName ) {
|
|
|
|
//
|
|
// if sid/name exists in the template list
|
|
// continue (the explicit mask takes care of remove)
|
|
// else
|
|
// add it to the remove list
|
|
//
|
|
|
|
for ( pAccountNode=pTemplateList;
|
|
pAccountNode != NULL;
|
|
pAccountNode = pAccountNode->Next ) {
|
|
|
|
if ( pAccountNode->Name == NULL ) {
|
|
continue;
|
|
}
|
|
|
|
if ( dwBuildRule & SCE_BUILD_ACCOUNT_SID ) {
|
|
|
|
if ( ScepValidSid( (PSID)(pAccountNode->Name) ) &&
|
|
RtlEqualSid( (PSID)(pAccountSidOrName->Name), (PSID)(pAccountNode->Name) ) ) {
|
|
break;
|
|
}
|
|
} else if ( _wcsicmp(pAccountNode->Name, pAccountSidOrName->Name) == 0 ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// always need to add to the remove list since each sid/name
|
|
// is seen only once in the new algorithm
|
|
//
|
|
|
|
if ( pAccountNode == NULL ) {
|
|
|
|
pAccountNode = (PSCE_PRIVILEGE_VALUE_LIST)ScepAlloc(
|
|
LPTR,
|
|
sizeof(SCE_PRIVILEGE_VALUE_LIST));
|
|
if ( pAccountNode != NULL ) {
|
|
|
|
pAccountNode->Name = pAccountSidOrName->Name;
|
|
pAccountSidOrName->Name = NULL;
|
|
|
|
pAccountNode->PrivLowPart = dwPrivLowThisAccount & PrivLowMask;
|
|
pAccountNode->PrivHighPart = dwPrivHighThisAccount & PrivHighMask;
|
|
|
|
pAccountNode->Next = *pRemoveList;
|
|
*pRemoveList = pAccountNode;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// free the buffer
|
|
//
|
|
if ( pAccountSidOrName->Name ) {
|
|
ScepFree(pAccountSidOrName->Name);
|
|
}
|
|
if ( pAccountSidOrName != psList)
|
|
ScepFree(pAccountSidOrName);
|
|
pAccountSidOrName = NULL;
|
|
|
|
}
|
|
}
|
|
|
|
if ( aUserRights ) {
|
|
|
|
LsaFreeMemory( aUserRights );
|
|
|
|
aUserRights = NULL;
|
|
}
|
|
}
|
|
|
|
} else if ( NtStatus == STATUS_NONE_MAPPED ) {
|
|
//
|
|
// lookup for all sids failed
|
|
//
|
|
NtStatusRsop = NtStatus;
|
|
NtStatus = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
NtStatusRsop = NtStatus;
|
|
ScepLogOutput3(3,0, IDS_ERROR_LOOKUP, NtStatus, uNumAccounts);
|
|
NtStatus = STATUS_SUCCESS; // ignore the error for now
|
|
}
|
|
|
|
//
|
|
// free and reset all parameters except the enumeration context
|
|
// for which state has to be remembered between calls to LSA
|
|
//
|
|
|
|
if (pReferencedDomains) {
|
|
LsaFreeMemory(pReferencedDomains);
|
|
pReferencedDomains = NULL;
|
|
}
|
|
|
|
if (aNames) {
|
|
LsaFreeMemory(aNames);
|
|
aNames = NULL;
|
|
}
|
|
|
|
if (aSids) {
|
|
LsaFreeMemory( aSids );
|
|
aSids = NULL;
|
|
}
|
|
|
|
//
|
|
// attempt to enumerate the next batch of SIDs
|
|
//
|
|
|
|
uNumAccounts = 0;
|
|
|
|
NtStatus = LsaEnumerateAccounts(
|
|
PolicyHandle,
|
|
&uEnumerationContext,
|
|
(PVOID *)&aSids,
|
|
uPreferedMaximumLength,
|
|
&uNumAccounts
|
|
);
|
|
|
|
}
|
|
|
|
if ( aSids ) {
|
|
|
|
LsaFreeMemory( aSids );
|
|
|
|
}
|
|
|
|
ScepFree(pwszStringSid);
|
|
pwszStringSid = NULL;
|
|
|
|
if ( NtStatus == STATUS_NO_MORE_ENTRIES ||
|
|
NtStatus == STATUS_NOT_FOUND ) {
|
|
|
|
//
|
|
// not a real error - just an enumeration warning/status
|
|
//
|
|
|
|
NtStatus = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
//
|
|
// in this scheme in which it is "foreach SID" and not "foreach privilege",
|
|
// either log all in case of failure
|
|
//
|
|
|
|
if ( ! NT_SUCCESS( NtStatus ) ) {
|
|
|
|
ScepRsopLog(SCE_RSOP_PRIVILEGE_INFO,
|
|
RtlNtStatusToDosError(NtStatus),
|
|
NULL,
|
|
PrivLowMask,
|
|
PrivHighMask);
|
|
|
|
ScepLogOutput3(1,
|
|
RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_SAP_ERROR_ENUMERATE,
|
|
L"Accounts from LSA");
|
|
|
|
}
|
|
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
if ( bIgnored ) {
|
|
//
|
|
// if some accounts are ignored, return the pending error
|
|
//
|
|
return(STATUS_PENDING);
|
|
} else
|
|
return NtStatusSave;
|
|
|
|
} else
|
|
return(NtStatus);
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
ScepBuildDwMaskFromStrArray(
|
|
IN PUNICODE_STRING aUserRights,
|
|
IN ULONG uCountOfRights,
|
|
OUT DWORD *pdwPrivLowThisAccount,
|
|
OUT DWORD *pdwPrivHighThisAccount
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine converts a privilege array of unicode strings two DWORD masks.
|
|
|
|
Arguments:
|
|
|
|
aUserRights - an array of unicode strings, each string is a user right
|
|
uCountOfRights - array count
|
|
pdwPrivLowThisAccount - converted privileges' low 32 mask
|
|
pdwPrivHighThisAccount - converted privileges' high 32 mask
|
|
|
|
Return value:
|
|
|
|
None except the low 32 and high 32 masks
|
|
|
|
-- */
|
|
{
|
|
ULONG uAccountIndex;
|
|
DWORD dwRefPrivIndex;
|
|
DWORD dwLowMask = 0;
|
|
DWORD dwHighMask = 0;
|
|
|
|
if (pdwPrivLowThisAccount == NULL ||
|
|
pdwPrivHighThisAccount == NULL ||
|
|
aUserRights == NULL ||
|
|
uCountOfRights == 0 ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (uAccountIndex = 0; uAccountIndex < uCountOfRights; uAccountIndex++ ) {
|
|
for (dwRefPrivIndex = 0; dwRefPrivIndex < cPrivCnt; dwRefPrivIndex++ ) {
|
|
if ( 0 == _wcsnicmp(SCE_Privileges[ dwRefPrivIndex ].Name, aUserRights[ uAccountIndex ].Buffer, aUserRights[ uAccountIndex ].Length/sizeof(WCHAR))) {
|
|
if ( dwRefPrivIndex < 32 ) {
|
|
dwLowMask |= 1 << dwRefPrivIndex;
|
|
}
|
|
else {
|
|
dwHighMask |= 1 << (dwRefPrivIndex - 32) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*pdwPrivLowThisAccount = dwLowMask;
|
|
*pdwPrivHighThisAccount = dwHighMask;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ScepAdjustAccountPrivilegesRights(
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN PSID AccountSid,
|
|
IN DWORD PrivilegeLowRights,
|
|
IN DWORD PrivilegeLowMask,
|
|
IN DWORD PrivilegeHighRights,
|
|
IN DWORD PrivilegeHighMask,
|
|
IN DWORD Options
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine set the privilege/rights as specified in PrivilegeRights
|
|
(DWORD type, each bit represents a privilege/right) to the account
|
|
referenced by AccountSid. This routine compares the current privilege/
|
|
right setting with the "should be" setting and add/remove privileges/
|
|
rights from the account.
|
|
|
|
Arguments:
|
|
|
|
PolicyHandle - Lsa Policy Domain handle
|
|
|
|
AccountSid - The SID for the account
|
|
|
|
PrivilegeRights - Privilege/Rights to set for this account
|
|
|
|
Return value:
|
|
|
|
NTSTATUS
|
|
-- */
|
|
{
|
|
NTSTATUS NtStatus;
|
|
DWORD ExplicitPrivLowRights=0, ExplicitPrivHighRights=0;
|
|
DWORD PrivLowRightAdd,
|
|
PrivLowRightRemove;
|
|
|
|
DWORD PrivHighRightAdd,
|
|
PrivHighRightRemove;
|
|
//
|
|
// Enumerate current explicitly assigned privilege/rights
|
|
//
|
|
|
|
NtStatus = ScepGetAccountExplicitRight(
|
|
PolicyHandle,
|
|
AccountSid,
|
|
&ExplicitPrivLowRights,
|
|
&ExplicitPrivHighRights
|
|
);
|
|
|
|
if ( !NT_SUCCESS(NtStatus) ){
|
|
|
|
if ( Options & SCE_RSOP_CALLBACK){
|
|
|
|
ScepRsopLog(SCE_RSOP_PRIVILEGE_INFO,
|
|
RtlNtStatusToDosError(NtStatus),
|
|
NULL,
|
|
PrivilegeLowRights,
|
|
PrivilegeHighRights);
|
|
}
|
|
|
|
return(NtStatus);
|
|
}
|
|
|
|
//
|
|
// Compare CurrentPrivRights with pRights->PrivilegeRights for add
|
|
// Example: CurrentPrivRights 10101
|
|
// pRights->PrivilegeRights( change to) 11010
|
|
// where 1 means the privilege/right is on
|
|
// So the privileges/rights to add 01010
|
|
// Compare ExplicitPrivRights with pRights->PrivilegeRights for remove
|
|
//
|
|
|
|
PrivLowRightAdd = ~ExplicitPrivLowRights & PrivilegeLowRights;
|
|
PrivLowRightRemove = (~(PrivilegeLowRights) & ExplicitPrivLowRights) & PrivilegeLowMask;
|
|
|
|
PrivHighRightAdd = ~ExplicitPrivHighRights & PrivilegeHighRights;
|
|
PrivHighRightRemove = (~(PrivilegeHighRights) & ExplicitPrivHighRights) & PrivilegeHighMask;
|
|
|
|
//
|
|
// Add
|
|
//
|
|
|
|
if ( PrivLowRightAdd != 0 || PrivHighRightAdd != 0 ) {
|
|
|
|
NtStatus = ScepAddOrRemoveAccountRights(
|
|
PolicyHandle,
|
|
AccountSid,
|
|
TRUE,
|
|
PrivLowRightAdd,
|
|
PrivHighRightAdd
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
|
|
if ( Options & SCE_RSOP_CALLBACK){
|
|
|
|
ScepRsopLog(SCE_RSOP_PRIVILEGE_INFO,
|
|
RtlNtStatusToDosError(NtStatus),
|
|
NULL,
|
|
PrivLowRightAdd,
|
|
PrivHighRightAdd);
|
|
}
|
|
|
|
if ( RtlNtStatusToDosError(NtStatus) != ERROR_ALREADY_EXISTS ){
|
|
|
|
return(NtStatus);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Remove
|
|
//
|
|
|
|
if ( PrivLowRightRemove != 0 || PrivHighRightRemove != 0 ) {
|
|
|
|
NtStatus = ScepAddOrRemoveAccountRights(
|
|
PolicyHandle,
|
|
AccountSid,
|
|
FALSE,
|
|
PrivLowRightRemove,
|
|
PrivHighRightRemove
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) ){
|
|
|
|
if ( Options & SCE_RSOP_CALLBACK){
|
|
|
|
ScepRsopLog(SCE_RSOP_PRIVILEGE_INFO,
|
|
RtlNtStatusToDosError(NtStatus),
|
|
NULL,
|
|
PrivLowRightRemove,
|
|
PrivHighRightRemove);
|
|
}
|
|
return(NtStatus);
|
|
}
|
|
}
|
|
|
|
return (NtStatus);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ScepAddOrRemoveAccountRights(
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN PSID AccountSid,
|
|
IN BOOL AddOrRemove,
|
|
IN DWORD PrivLowAdjust,
|
|
IN DWORD PrivHighAdjust
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine add or remove the privilege/rights as specified in PrivAdjust
|
|
to the account referenced by AccountSid.
|
|
|
|
Arguments:
|
|
|
|
PolicyHandle - Lsa Policy Domain handle
|
|
|
|
AccountSid - The SID for the account
|
|
|
|
AddOrRemove - TRUE = Add, FALSE = remove
|
|
|
|
PrivAdjust - Privilege/Rights to add or remove
|
|
|
|
Return value:
|
|
|
|
NTSTATUS
|
|
-- */
|
|
{
|
|
NTSTATUS NtStatus=STATUS_SUCCESS;
|
|
DWORD cTotal;
|
|
DWORD i, cnt;
|
|
PLSA_UNICODE_STRING UserRightAdjust=NULL;
|
|
|
|
//
|
|
// count how many privileges/rights to adjust
|
|
//
|
|
|
|
i = PrivLowAdjust;
|
|
cTotal = 0;
|
|
|
|
while ( i != 0 ) {
|
|
if ( i & 0x1 )
|
|
cTotal++;
|
|
i /= 2;
|
|
}
|
|
|
|
i = PrivHighAdjust;
|
|
|
|
while ( i != 0 ) {
|
|
if ( i & 0x1 )
|
|
cTotal++;
|
|
i /= 2;
|
|
}
|
|
|
|
if ( cTotal > 0 ) {
|
|
//
|
|
// add names in privileges table
|
|
//
|
|
UserRightAdjust = (PLSA_UNICODE_STRING)ScepAlloc( (UINT)0,
|
|
cTotal*sizeof(LSA_UNICODE_STRING));
|
|
|
|
if ( UserRightAdjust == NULL ) {
|
|
NtStatus = STATUS_NO_MEMORY;
|
|
goto Done;
|
|
}
|
|
|
|
for (i = 0, cnt=0; i < cPrivCnt; i++)
|
|
|
|
if ( ( ( i < 32 ) && ( PrivLowAdjust & (1 << i) ) ) ||
|
|
( ( i >= 32 ) && ( PrivHighAdjust & (1 << ( i-32 )) ) ) ) {
|
|
|
|
RtlInitUnicodeString(&(UserRightAdjust[cnt]), SCE_Privileges[i].Name);
|
|
if (AddOrRemove)
|
|
ScepLogOutput3(2,0, SCEDLL_SCP_ADD, SCE_Privileges[i].Name);
|
|
else
|
|
ScepLogOutput3(2,0, SCEDLL_SCP_REMOVE, SCE_Privileges[i].Name);
|
|
|
|
cnt++;
|
|
}
|
|
|
|
|
|
if (AddOrRemove) {
|
|
// add
|
|
NtStatus = LsaAddAccountRights(
|
|
PolicyHandle,
|
|
AccountSid,
|
|
UserRightAdjust,
|
|
cTotal
|
|
);
|
|
} else {
|
|
// remove
|
|
NtStatus = LsaRemoveAccountRights(
|
|
PolicyHandle,
|
|
AccountSid,
|
|
FALSE,
|
|
UserRightAdjust,
|
|
cTotal
|
|
);
|
|
}
|
|
}
|
|
|
|
Done:
|
|
|
|
if (UserRightAdjust != NULL)
|
|
ScepFree(UserRightAdjust);
|
|
|
|
return(NtStatus);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
ScepValidateUserInGroups(
|
|
IN SAM_HANDLE DomainHandle,
|
|
IN SAM_HANDLE BuiltinDomainHandle,
|
|
IN PSID DomainSid,
|
|
IN UNICODE_STRING UserName,
|
|
IN ULONG UserId,
|
|
IN PSCE_NAME_LIST pGroupsToCheck
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine validates the user's group membership to the list of groups.
|
|
If the user is not in one of the groups, add it to the group. If a group
|
|
has more members, just ignore.
|
|
|
|
Arguments:
|
|
|
|
DomainHandle - The SAM handle of the SAM account domain
|
|
|
|
BuiltinDomainHandle - The SAM handle of the SAM builtin domain
|
|
|
|
DomainSid - The SID of the account domain
|
|
|
|
UserName - The user's name in UNICODE_STRING
|
|
|
|
UserId - The user's relative ID
|
|
|
|
pGroupsToCheck - The group list to check for this user
|
|
|
|
Return value:
|
|
|
|
NTSTATUS
|
|
|
|
-- */
|
|
{
|
|
NTSTATUS NtStatus;
|
|
SAM_HANDLE UserHandle=NULL;
|
|
PSID AccountSid=NULL;
|
|
PSCE_NAME_LIST GroupList=NULL,
|
|
pGroup, pGroup2;
|
|
BOOL FirstTime=TRUE;
|
|
|
|
|
|
if ( pGroupsToCheck == NULL )
|
|
return(ERROR_SUCCESS);
|
|
|
|
NtStatus = SamOpenUser(
|
|
DomainHandle,
|
|
USER_READ | USER_EXECUTE,
|
|
UserId,
|
|
&UserHandle
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
ScepLogOutput3(1,RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_USER_OBJECT);
|
|
return(NtStatus);
|
|
}
|
|
|
|
//
|
|
// Get user's SID
|
|
//
|
|
|
|
NtStatus = ScepDomainIdToSid(
|
|
DomainSid,
|
|
UserId,
|
|
&AccountSid
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) )
|
|
goto Done;
|
|
|
|
//
|
|
// get all current assigned groups of this user.
|
|
//
|
|
|
|
NtStatus = ScepGetGroupsForAccount(
|
|
DomainHandle,
|
|
BuiltinDomainHandle,
|
|
UserHandle,
|
|
AccountSid,
|
|
&GroupList
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) )
|
|
goto Done;
|
|
|
|
UNICODE_STRING uName;
|
|
PWSTR pTemp;
|
|
|
|
for ( pGroup=pGroupsToCheck; pGroup != NULL; pGroup = pGroup->Next ) {
|
|
|
|
//
|
|
// should expect pGroup->Name has domain prefix
|
|
//
|
|
pTemp = wcschr(pGroup->Name, L'\\');
|
|
|
|
if ( pTemp ) {
|
|
|
|
//
|
|
// check if this group is from a different domain
|
|
//
|
|
|
|
uName.Buffer = pGroup->Name;
|
|
uName.Length = ((USHORT)(pTemp-pGroup->Name))*sizeof(TCHAR);
|
|
|
|
if ( !ScepIsDomainLocal(&uName) ) {
|
|
ScepLogOutput3(1, 0, SCEDLL_NO_MAPPINGS, pGroup->Name);
|
|
continue;
|
|
}
|
|
|
|
pTemp++;
|
|
|
|
} else {
|
|
pTemp = pGroup->Name;
|
|
}
|
|
|
|
for ( pGroup2=GroupList; pGroup2 != NULL; pGroup2 = pGroup2->Next ) {
|
|
|
|
if ( _wcsnicmp(pGroup2->Name, pTemp, wcslen(pTemp)) == 0)
|
|
break;
|
|
}
|
|
|
|
if ( pGroup2 == NULL ) {
|
|
//
|
|
// Did not find the group. Add the user to it (pGroup->Name)
|
|
//
|
|
if (FirstTime)
|
|
ScepLogOutput3(2, 0, SCEDLL_SCP_ADDTO, pGroup->Name );
|
|
FirstTime = FALSE;
|
|
|
|
NtStatus = ScepAddUserToGroup(
|
|
DomainHandle,
|
|
BuiltinDomainHandle,
|
|
UserId,
|
|
AccountSid,
|
|
pTemp // pGroup->Name
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) && NtStatus != STATUS_NONE_MAPPED ) {
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_SCP_ERROR_ADDTO, pGroup->Name);
|
|
goto Done;
|
|
}
|
|
}
|
|
}
|
|
|
|
Done:
|
|
|
|
SamCloseHandle(UserHandle);
|
|
|
|
if (AccountSid != NULL)
|
|
ScepFree(AccountSid);
|
|
|
|
ScepFreeNameList(GroupList);
|
|
|
|
return(NtStatus);
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ScepAddUserToGroup(
|
|
IN SAM_HANDLE DomainHandle,
|
|
IN SAM_HANDLE BuiltinDomainHandle,
|
|
IN ULONG UserId,
|
|
IN PSID AccountSid,
|
|
IN PWSTR GroupName
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return value:
|
|
|
|
NTSTATUS
|
|
-- */
|
|
{
|
|
NTSTATUS NtStatus=ERROR_SUCCESS;
|
|
SAM_HANDLE ThisDomain=DomainHandle;
|
|
UNICODE_STRING Name;
|
|
PULONG GrpId=NULL;
|
|
PSID_NAME_USE GrpUse=NULL;
|
|
SAM_HANDLE GroupHandle=NULL;
|
|
|
|
|
|
// initialize a UNICODE_STRING for the group name
|
|
RtlInitUnicodeString(&Name, GroupName);
|
|
|
|
//
|
|
// lookup the group name in account domain first
|
|
//
|
|
NtStatus = SamLookupNamesInDomain(
|
|
DomainHandle,
|
|
1,
|
|
&Name,
|
|
&GrpId,
|
|
&GrpUse
|
|
);
|
|
|
|
if ( NtStatus == STATUS_NONE_MAPPED ) {
|
|
//
|
|
// not found in account domain. Lookup in the builtin domain
|
|
//
|
|
NtStatus = SamLookupNamesInDomain(
|
|
BuiltinDomainHandle,
|
|
1,
|
|
&Name,
|
|
&GrpId,
|
|
&GrpUse
|
|
);
|
|
ThisDomain=BuiltinDomainHandle;
|
|
}
|
|
|
|
if ( !NT_SUCCESS(NtStatus) )
|
|
return(NtStatus);
|
|
|
|
//
|
|
// add the user to the group/alias
|
|
//
|
|
|
|
if (GrpUse != NULL){
|
|
|
|
switch ( GrpUse[0] ) {
|
|
case SidTypeGroup:
|
|
NtStatus = SamOpenGroup(
|
|
ThisDomain,
|
|
GROUP_ADD_MEMBER,
|
|
GrpId[0],
|
|
&GroupHandle
|
|
);
|
|
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
NtStatus = SamAddMemberToGroup(
|
|
GroupHandle,
|
|
UserId,
|
|
SE_GROUP_MANDATORY |
|
|
SE_GROUP_ENABLED_BY_DEFAULT |
|
|
SE_GROUP_ENABLED
|
|
);
|
|
}
|
|
break;
|
|
case SidTypeAlias:
|
|
NtStatus = SamOpenAlias(
|
|
ThisDomain,
|
|
ALIAS_ADD_MEMBER,
|
|
GrpId[0],
|
|
&GroupHandle
|
|
);
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
NtStatus = SamAddMemberToAlias(
|
|
GroupHandle,
|
|
AccountSid
|
|
);
|
|
}
|
|
break;
|
|
default:
|
|
NtStatus = STATUS_DATA_ERROR;
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_NOT_GROUP, GroupName);
|
|
goto Done;
|
|
}
|
|
|
|
}
|
|
|
|
Done:
|
|
|
|
SamFreeMemory(GrpId);
|
|
SamFreeMemory(GrpUse);
|
|
|
|
SamCloseHandle(GroupHandle);
|
|
|
|
return(NtStatus);
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepConfigureGroupMembership(
|
|
IN PSCE_GROUP_MEMBERSHIP pGroupMembership,
|
|
IN DWORD ConfigOptions
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine configure restricted group's membership which includes members
|
|
in the group and groups this group belongs to ( Currently a global group can
|
|
only belong to a local group and a local group can't be a member of other
|
|
groups. But this will change in the future). Members in the group are
|
|
configured exactly as the pMembers list in the restricted group. The group
|
|
is only validated (added) as a member of the MemberOf group list. Other
|
|
existing members in those groups won't be removed.
|
|
|
|
The restricted groups are specified in the SCP profile by group name. It
|
|
could be a global group, or a alias, but must be defined on the local system.
|
|
|
|
Arguments:
|
|
|
|
pGroupMembership - the restricted group list to configure
|
|
|
|
Return Value:
|
|
|
|
SCESTATUS_SUCCESS
|
|
SCESTATUS_NOT_ENOUGH_RESOURCE
|
|
:
|
|
-- */
|
|
{
|
|
NTSTATUS NtStatus;
|
|
NTSTATUS SaveStat=STATUS_SUCCESS;
|
|
PSCE_GROUP_MEMBERSHIP pGroup;
|
|
SAM_HANDLE ServerHandle=NULL,
|
|
DomainHandle=NULL,
|
|
BuiltinDomainHandle=NULL;
|
|
PSID DomainSid=NULL,
|
|
BuiltInDomainSid=NULL;
|
|
|
|
LSA_HANDLE PolicyHandle=NULL;
|
|
|
|
SAM_HANDLE ThisDomain=NULL;
|
|
PSID ThisDomainSid=NULL;
|
|
UNICODE_STRING Name;
|
|
PULONG GrpId=NULL;
|
|
PSID_NAME_USE GrpUse=NULL;
|
|
PSID GrpSid=NULL;
|
|
DWORD GroupLen;
|
|
DWORD rc;
|
|
SCESTATUS scercSave = SCESTATUS_SUCCESS;
|
|
|
|
DWORD nGroupCount=0;
|
|
PSCESECTION hSectionDomain=NULL;
|
|
PSCESECTION hSectionTattoo=NULL;
|
|
PWSTR GroupSidString=NULL;
|
|
|
|
|
|
if (pGroupMembership == NULL) {
|
|
|
|
ScepPostProgress(TICKS_GROUPS,
|
|
AREA_GROUP_MEMBERSHIP,
|
|
NULL);
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// open LSA policy
|
|
//
|
|
NtStatus = ScepOpenLsaPolicy(
|
|
POLICY_VIEW_LOCAL_INFORMATION |
|
|
POLICY_VIEW_AUDIT_INFORMATION |
|
|
POLICY_GET_PRIVATE_INFORMATION |
|
|
POLICY_LOOKUP_NAMES,
|
|
// GENERIC_ALL,
|
|
&PolicyHandle,
|
|
TRUE
|
|
);
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
rc = RtlNtStatusToDosError( NtStatus );
|
|
ScepLogOutput3(1, rc, SCEDLL_LSA_POLICY);
|
|
|
|
ScepPostProgress(TICKS_GROUPS,
|
|
AREA_GROUP_MEMBERSHIP,
|
|
NULL);
|
|
|
|
return(ScepDosErrorToSceStatus(rc));
|
|
}
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
SaveStat = STATUS_NOT_SUPPORTED;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Open SAM domain
|
|
//
|
|
NtStatus = ScepOpenSamDomain(
|
|
SAM_SERVER_ALL_ACCESS,
|
|
MAXIMUM_ALLOWED,
|
|
&ServerHandle,
|
|
&DomainHandle,
|
|
&DomainSid,
|
|
&BuiltinDomainHandle,
|
|
&BuiltInDomainSid
|
|
);
|
|
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_ACCOUNT_DOMAIN);
|
|
SaveStat = NtStatus;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// open policy/tattoo tables
|
|
//
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) ) {
|
|
|
|
ScepTattooOpenPolicySections(
|
|
hProfile,
|
|
szGroupMembership,
|
|
&hSectionDomain,
|
|
&hSectionTattoo
|
|
);
|
|
}
|
|
|
|
//
|
|
// configure each group
|
|
//
|
|
|
|
for ( pGroup=pGroupMembership; pGroup != NULL; pGroup = pGroup->Next ) {
|
|
//
|
|
// Get this group's ID and SID
|
|
// initialize a UNICODE_STRING for the group name
|
|
//
|
|
|
|
if ( (pGroup->Status & SCE_GROUP_STATUS_NC_MEMBERS ) &&
|
|
(pGroup->Status & SCE_GROUP_STATUS_NC_MEMBEROF ) ) {
|
|
|
|
// it's not possible to get invalid tattoo group values into the
|
|
// tattoo table so we don't handle tattoo value here
|
|
|
|
continue;
|
|
}
|
|
|
|
if ( (ProductType == NtProductLanManNt) &&
|
|
(pGroup->Status & SCE_GROUP_STATUS_DONE_IN_DS) ) {
|
|
//
|
|
// this one is already done by DS
|
|
//
|
|
nGroupCount++;
|
|
continue;
|
|
}
|
|
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_CONFIGURE, pGroup->GroupName);
|
|
|
|
if ( nGroupCount < TICKS_GROUPS ) {
|
|
ScepPostProgress(1, AREA_GROUP_MEMBERSHIP, pGroup->GroupName);
|
|
nGroupCount++;
|
|
}
|
|
|
|
LPTSTR pTemp = wcschr(pGroup->GroupName, L'\\');
|
|
if ( pTemp ) {
|
|
//
|
|
// there is a domain name, check it with computer name
|
|
//
|
|
UNICODE_STRING uName;
|
|
|
|
uName.Buffer = pGroup->GroupName;
|
|
uName.Length = ((USHORT)(pTemp-pGroup->GroupName))*sizeof(TCHAR);
|
|
|
|
if ( !ScepIsDomainLocal(&uName) ) {
|
|
|
|
// on member machines we support memberof for domain groups
|
|
|
|
if(ProductType != NtProductLanManNt)
|
|
goto memberof;
|
|
|
|
ScepLogOutput3(1, 0, SCEDLL_NO_MAPPINGS, pGroup->GroupName);
|
|
rc = SCESTATUS_INVALID_DATA;
|
|
continue;
|
|
|
|
}
|
|
pTemp++;
|
|
} else {
|
|
pTemp = pGroup->GroupName;
|
|
}
|
|
|
|
RtlInitUnicodeString(&Name, pTemp);
|
|
|
|
GroupLen = wcslen(pTemp);
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
SaveStat = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// lookup the group name in account domain first
|
|
//
|
|
NtStatus = SamLookupNamesInDomain(
|
|
DomainHandle,
|
|
1,
|
|
&Name,
|
|
&GrpId,
|
|
&GrpUse
|
|
);
|
|
ThisDomain = DomainHandle;
|
|
ThisDomainSid = DomainSid;
|
|
|
|
if ( NtStatus == STATUS_NONE_MAPPED ) {
|
|
//
|
|
// not found in account domain. Lookup in the builtin domain (maybe a alias)
|
|
//
|
|
NtStatus = SamLookupNamesInDomain(
|
|
BuiltinDomainHandle,
|
|
1,
|
|
&Name,
|
|
&GrpId,
|
|
&GrpUse
|
|
);
|
|
ThisDomain=BuiltinDomainHandle;
|
|
ThisDomainSid = BuiltInDomainSid;
|
|
}
|
|
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_NO_MAPPINGS, pGroup->GroupName);
|
|
SaveStat = NtStatus;
|
|
|
|
if (ConfigOptions & SCE_RSOP_CALLBACK)
|
|
ScepRsopLog(SCE_RSOP_GROUP_INFO, RtlNtStatusToDosError(NtStatus), pGroup->GroupName, 0, 0);
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) ) {
|
|
|
|
ScepTattooManageOneMemberListValue(
|
|
hSectionDomain,
|
|
hSectionTattoo,
|
|
pTemp,
|
|
GroupLen,
|
|
NULL,
|
|
TRUE,
|
|
ERROR_NONE_MAPPED
|
|
);
|
|
}
|
|
|
|
// goto Done;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Get the group's account SID
|
|
//
|
|
NtStatus = ScepDomainIdToSid(
|
|
ThisDomainSid,
|
|
GrpId[0],
|
|
&GrpSid
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_NO_MAPPINGS, pGroup->GroupName);
|
|
SaveStat = NtStatus;
|
|
|
|
if (ConfigOptions & SCE_RSOP_CALLBACK)
|
|
ScepRsopLog(SCE_RSOP_GROUP_INFO, RtlNtStatusToDosError(NtStatus), pGroup->GroupName, 0, 0);
|
|
|
|
goto NextGroup;
|
|
}
|
|
|
|
if ( GrpId[0] == DOMAIN_GROUP_RID_USERS ) {
|
|
|
|
//
|
|
// do not configure this one
|
|
// there should never be tattoo values for this setting
|
|
// so we don't check tattoo values here
|
|
//
|
|
goto NextGroup;
|
|
}
|
|
|
|
if ( GrpId[0] == DOMAIN_ALIAS_RID_ADMINS ) {
|
|
|
|
//
|
|
// local builtin administrators alias, make sure local Administrator
|
|
// account is in the members list, if it's not, add it there
|
|
//
|
|
|
|
(VOID) ScepAddAdministratorToThisList(
|
|
DomainHandle,
|
|
&(pGroup->pMembers)
|
|
);
|
|
}
|
|
|
|
//
|
|
// members
|
|
//
|
|
if ( !(pGroup->Status & SCE_GROUP_STATUS_NC_MEMBERS) ) {
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) ) {
|
|
|
|
DWORD rc2 = ScepConvertSidToPrefixStringSid(GrpSid, &GroupSidString);
|
|
|
|
if ( ERROR_SUCCESS != rc2 ) {
|
|
ScepLogOutput3(1,0,SCESRV_POLICY_TATTOO_ERROR_SETTING,rc2,pGroup->GroupName);
|
|
GroupSidString = NULL;
|
|
}
|
|
}
|
|
|
|
switch ( GrpUse[0] ) {
|
|
case SidTypeGroup:
|
|
NtStatus = ScepConfigureMembersOfGroup(
|
|
hSectionDomain,
|
|
hSectionTattoo,
|
|
ThisDomain,
|
|
ThisDomainSid,
|
|
GrpId[0],
|
|
GrpSid,
|
|
pGroup->GroupName,
|
|
GroupSidString,
|
|
pGroup->pMembers,
|
|
ConfigOptions
|
|
);
|
|
|
|
|
|
break;
|
|
case SidTypeAlias:
|
|
NtStatus = ScepConfigureMembersOfAlias(
|
|
hSectionDomain,
|
|
hSectionTattoo,
|
|
ThisDomain,
|
|
ThisDomainSid,
|
|
PolicyHandle,
|
|
GrpId[0],
|
|
GrpSid,
|
|
pGroup->GroupName,
|
|
GroupSidString,
|
|
pGroup->pMembers,
|
|
ConfigOptions
|
|
);
|
|
|
|
break;
|
|
case SidTypeUser:
|
|
if ( pGroup->pMembers != NULL ) {
|
|
ScepLogOutput3(1, 0, SCEDLL_ERROR_USER_MEMBER);
|
|
|
|
NtStatus = STATUS_DATA_ERROR;
|
|
}
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) &&
|
|
GroupSidString ) {
|
|
|
|
ScepTattooManageOneMemberListValue(
|
|
hSectionDomain,
|
|
hSectionTattoo,
|
|
GroupSidString,
|
|
wcslen(GroupSidString),
|
|
NULL,
|
|
TRUE,
|
|
ERROR_NONE_MAPPED
|
|
);
|
|
}
|
|
|
|
break;
|
|
default:
|
|
NtStatus = STATUS_DATA_ERROR;
|
|
ScepLogOutput3(1, 0, SCEDLL_NOT_GROUP, pGroup->GroupName);
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) &&
|
|
GroupSidString ) {
|
|
|
|
ScepTattooManageOneMemberListValue(
|
|
hSectionDomain,
|
|
hSectionTattoo,
|
|
GroupSidString,
|
|
wcslen(GroupSidString),
|
|
NULL,
|
|
TRUE,
|
|
ERROR_NONE_MAPPED
|
|
);
|
|
}
|
|
}
|
|
|
|
if (ConfigOptions & SCE_RSOP_CALLBACK)
|
|
|
|
ScepRsopLog(
|
|
SCE_RSOP_GROUP_INFO,
|
|
RtlNtStatusToDosError(NtStatus),
|
|
pGroup->GroupName,0,0);
|
|
|
|
if ( !NT_SUCCESS(NtStatus) )
|
|
SaveStat = NtStatus;
|
|
|
|
if ( GroupSidString ) {
|
|
ScepFree(GroupSidString);
|
|
GroupSidString = NULL;
|
|
}
|
|
}
|
|
memberof:
|
|
//
|
|
// member of
|
|
//
|
|
if ( !(pGroup->Status & SCE_GROUP_STATUS_NC_MEMBEROF) ) {
|
|
|
|
if (!GrpUse)
|
|
{
|
|
// Account not found locally. Handle only the case of
|
|
// groups and aliases memberof aliases.
|
|
PLSA_REFERENCED_DOMAIN_LIST RefDomains=NULL;
|
|
PLSA_TRANSLATED_SID2 Sids=NULL;
|
|
|
|
NtStatus = ScepLsaLookupNames2(
|
|
PolicyHandle,
|
|
0,
|
|
pGroup->GroupName,
|
|
&RefDomains,
|
|
&Sids
|
|
);
|
|
if (NT_SUCCESS(NtStatus) &&
|
|
Sids &&
|
|
(Sids[0].Use == SidTypeGroup ||
|
|
Sids[0].Use == SidTypeAlias)) {
|
|
SCESTATUS scerc = ScepValidateGroupInAliases(
|
|
DomainHandle,
|
|
BuiltinDomainHandle,
|
|
hSectionTattoo,
|
|
PolicyHandle,
|
|
Sids[0].Sid,
|
|
pGroup->pMemberOf,
|
|
((ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ))?true:false
|
|
);
|
|
if(SCESTATUS_SUCCESS != scerc)
|
|
scercSave = scerc;
|
|
|
|
} else {
|
|
ScepLogOutput3(1, 0, SCEDLL_CANNOT_FIND, pGroup->GroupName);
|
|
}
|
|
|
|
if ( Sids ) {
|
|
LsaFreeMemory(Sids);
|
|
}
|
|
if ( RefDomains ) {
|
|
LsaFreeMemory(RefDomains);
|
|
}
|
|
} else if (pGroup->pMemberOf) {
|
|
|
|
switch ( GrpUse[0] ) {
|
|
case SidTypeGroup:
|
|
{
|
|
//
|
|
// group can be members of alias only
|
|
//
|
|
SCESTATUS scerc = ScepValidateGroupInAliases(
|
|
DomainHandle,
|
|
BuiltinDomainHandle,
|
|
hSectionTattoo,
|
|
PolicyHandle,
|
|
GrpSid,
|
|
pGroup->pMemberOf,
|
|
((ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ))?true:false
|
|
);
|
|
if(SCESTATUS_SUCCESS != scerc)
|
|
scercSave = scerc;
|
|
}
|
|
break;
|
|
|
|
case SidTypeUser:
|
|
NtStatus = ScepValidateUserInGroups(
|
|
DomainHandle,
|
|
BuiltinDomainHandle,
|
|
ThisDomainSid,
|
|
Name,
|
|
GrpId[0],
|
|
pGroup->pMemberOf
|
|
);
|
|
|
|
break;
|
|
|
|
case SidTypeAlias:
|
|
NtStatus = STATUS_DATA_ERROR;
|
|
ScepLogOutput3(1, 0, SCEDLL_ERROR_ALIAS_MEMBER);
|
|
|
|
}
|
|
}
|
|
if ( !NT_SUCCESS(NtStatus) )
|
|
SaveStat = NtStatus;
|
|
}
|
|
|
|
NextGroup:
|
|
|
|
|
|
//
|
|
// free memory for this group
|
|
//
|
|
SamFreeMemory(GrpId);
|
|
GrpId = NULL;
|
|
|
|
SamFreeMemory(GrpUse);
|
|
GrpUse = NULL;
|
|
|
|
ScepFree(GrpSid);
|
|
GrpSid = NULL;
|
|
}
|
|
|
|
Done:
|
|
|
|
if ( GrpId != NULL )
|
|
SamFreeMemory(GrpId);
|
|
|
|
if ( GrpUse != NULL )
|
|
SamFreeMemory(GrpUse);
|
|
|
|
if ( GrpSid != NULL )
|
|
ScepFree(GrpSid);
|
|
|
|
// close sam handles
|
|
SamCloseHandle(DomainHandle);
|
|
SamCloseHandle(BuiltinDomainHandle);
|
|
SamCloseHandle(ServerHandle);
|
|
|
|
if ( DomainSid != NULL )
|
|
SamFreeMemory(DomainSid);
|
|
if ( BuiltInDomainSid != NULL )
|
|
SamFreeMemory(BuiltInDomainSid);
|
|
|
|
LsaClose(PolicyHandle);
|
|
|
|
if ( nGroupCount < TICKS_GROUPS ) {
|
|
ScepPostProgress(TICKS_GROUPS-nGroupCount,
|
|
AREA_GROUP_MEMBERSHIP,
|
|
NULL);
|
|
}
|
|
|
|
SceJetCloseSection(&hSectionDomain, TRUE);
|
|
SceJetCloseSection(&hSectionTattoo, TRUE);
|
|
|
|
rc = RtlNtStatusToDosError(SaveStat);
|
|
|
|
if(STATUS_SUCCESS != rc)
|
|
scercSave = ScepDosErrorToSceStatus(rc);
|
|
|
|
return( scercSave );
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ScepConfigureMembersOfGroup(
|
|
IN PSCESECTION hSectionDomain,
|
|
IN PSCESECTION hSectionTattoo,
|
|
IN SAM_HANDLE DomainHandle,
|
|
IN PSID ThisDomainSid,
|
|
IN ULONG GrpId,
|
|
IN PSID GrpSid,
|
|
IN PWSTR GrpName,
|
|
IN PWSTR GroupSidString,
|
|
IN PSCE_NAME_LIST pMembers,
|
|
IN DWORD ConfigOptions
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine configure a group's members as specified in the SCP profile (
|
|
pMembers ). Less members are added and extra members are removed.
|
|
|
|
Arguments:
|
|
|
|
DomainHandle - the SAM domain's handle
|
|
|
|
GrpId - the group's RID
|
|
|
|
pMembers - the members list as specified in the SCP profile
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS return SAM APIs
|
|
|
|
-- */
|
|
{
|
|
NTSTATUS NtStatus;
|
|
|
|
PUNICODE_STRING MemberNames=NULL;
|
|
PULONG MemberRids=NULL;
|
|
PSID_NAME_USE MemberUse=NULL;
|
|
ULONG MemberCount=0;
|
|
SAM_HANDLE GroupHandle=NULL;
|
|
|
|
PULONG CurrentRids=NULL;
|
|
PULONG Attributes=NULL;
|
|
ULONG CurrentCount=0;
|
|
|
|
DWORD i, j;
|
|
WCHAR MsgBuf[256];
|
|
|
|
PUNICODE_STRING pName=NULL;
|
|
PSID_NAME_USE pUse=NULL;
|
|
PSCE_NAME_LIST pMemberList=NULL;
|
|
BOOL bMemberQueried=FALSE;
|
|
|
|
/*
|
|
if ( pMembers == NULL )
|
|
return(STATUS_SUCCESS);
|
|
*/
|
|
//
|
|
// Accept empty member list
|
|
// look up the members list first (all members should be within this domain
|
|
//
|
|
NtStatus = ScepLookupNamesInDomain(
|
|
DomainHandle,
|
|
pMembers,
|
|
&MemberNames,
|
|
&MemberRids,
|
|
&MemberUse,
|
|
&MemberCount
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_ERROR_LOOKUP, pMembers ? pMembers->Name : L"");
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) &&
|
|
hSectionDomain && hSectionTattoo && GrpSid && GroupSidString &&
|
|
(NtStatus == STATUS_NONE_MAPPED)) {
|
|
|
|
ScepTattooManageOneMemberListValue(
|
|
hSectionDomain,
|
|
hSectionTattoo,
|
|
GroupSidString,
|
|
wcslen(GroupSidString),
|
|
NULL,
|
|
TRUE,
|
|
0
|
|
);
|
|
}
|
|
|
|
return(NtStatus);
|
|
}
|
|
|
|
//
|
|
// open the group to get a handle
|
|
//
|
|
NtStatus = SamOpenGroup(
|
|
DomainHandle,
|
|
MAXIMUM_ALLOWED, // ? GROUP_ALL_ACCESS,
|
|
GrpId,
|
|
&GroupHandle
|
|
);
|
|
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_ERROR_OPEN, L"");
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// get current members of the group
|
|
//
|
|
NtStatus = SamGetMembersInGroup(
|
|
GroupHandle,
|
|
&CurrentRids,
|
|
&Attributes,
|
|
&CurrentCount
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_ERROR_QUERY_INFO, L"");
|
|
goto Done;
|
|
}
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) &&
|
|
hSectionDomain && hSectionTattoo && GrpSid && GroupSidString ) {
|
|
|
|
DWORD rc = ScepTattooCurrentGroupMembers(ThisDomainSid,
|
|
NULL, // GrpSid not needed
|
|
SidTypeGroup,
|
|
CurrentRids,
|
|
NULL,
|
|
CurrentCount,
|
|
&pMemberList
|
|
);
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
//
|
|
// something is wrong when building the list
|
|
// this shoudln't happen unless out of memory etc.
|
|
//
|
|
ScepLogOutput3(1,0,SCESRV_POLICY_TATTOO_ERROR_QUERY,rc,GrpName);
|
|
} else
|
|
bMemberQueried=TRUE;
|
|
}
|
|
|
|
//
|
|
// Compare the member ids with the current ids for adding
|
|
//
|
|
for ( i=0; i<MemberCount; i++ ) {
|
|
#ifdef SCE_DBG
|
|
printf("process member %x for adding\n", MemberRids[i]);
|
|
#endif
|
|
|
|
if (MemberUse[i] == SidTypeInvalid ||
|
|
MemberUse[i] == SidTypeUnknown ||
|
|
MemberUse[i] == SidTypeDeletedAccount)
|
|
continue;
|
|
|
|
for ( j=0; j<CurrentCount; j++)
|
|
if ( MemberRids[i] == CurrentRids[j] )
|
|
break;
|
|
|
|
if ( j >= CurrentCount) {
|
|
//
|
|
// Add this member
|
|
//
|
|
memset(MsgBuf, '\0', 512);
|
|
wcsncat(MsgBuf, MemberNames[i].Buffer, MemberNames[i].Length/2);
|
|
|
|
ScepLogOutput3(2,0, SCEDLL_SCP_ADD, MsgBuf);
|
|
|
|
NtStatus = SamAddMemberToGroup(
|
|
GroupHandle,
|
|
MemberRids[i],
|
|
0
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_SCP_ERROR_ADD, MsgBuf);
|
|
|
|
if ( NtStatus == STATUS_NO_SUCH_MEMBER|| NtStatus == STATUS_OBJECT_NAME_NOT_FOUND ) {
|
|
NtStatus = STATUS_SUCCESS;
|
|
continue;
|
|
}
|
|
|
|
goto Done;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Compare the member ids with the current ids for removing
|
|
//
|
|
for ( i=0; i<CurrentCount; i++ ) {
|
|
#ifdef SCE_DBG
|
|
printf("process member %x for removing\n", CurrentRids[i]);
|
|
#endif
|
|
for ( j=0; j<MemberCount; j++)
|
|
if ( CurrentRids[i] == MemberRids[j] )
|
|
break;
|
|
|
|
if ( j >= MemberCount) {
|
|
//
|
|
// Find the member name
|
|
//
|
|
memset(MsgBuf, '\0', 512);
|
|
pName=NULL;
|
|
pUse=NULL;
|
|
|
|
if ( NT_SUCCESS( SamLookupIdsInDomain(
|
|
DomainHandle,
|
|
1,
|
|
&(CurrentRids[i]),
|
|
&pName,
|
|
&pUse
|
|
) ) ) {
|
|
if ( pName != NULL ) {
|
|
wcsncat(MsgBuf, pName[0].Buffer, pName[0].Length/2);
|
|
} else
|
|
swprintf(MsgBuf, L"(Rid=%d)", CurrentRids[i]);
|
|
|
|
if ( pName != NULL )
|
|
SamFreeMemory( pName );
|
|
|
|
if ( pUse != NULL )
|
|
SamFreeMemory( pUse );
|
|
|
|
} else
|
|
swprintf(MsgBuf, L"(Rid=%d) ", CurrentRids[i]);
|
|
|
|
//
|
|
// remove this member
|
|
//
|
|
ScepLogOutput3(2,0, SCEDLL_SCP_REMOVE, MsgBuf);
|
|
|
|
NtStatus = SamRemoveMemberFromGroup(
|
|
GroupHandle,
|
|
CurrentRids[i]
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
if ( NtStatus == STATUS_SPECIAL_ACCOUNT )
|
|
ScepLogOutput3(2, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_SCP_CANNOT_REMOVE,
|
|
MsgBuf);
|
|
else {
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_SCP_ERROR_REMOVE, MsgBuf);
|
|
goto Done;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Done:
|
|
|
|
if ( MemberNames != NULL )
|
|
RtlFreeHeap(RtlProcessHeap(), 0, MemberNames);
|
|
|
|
if ( MemberRids != NULL )
|
|
SamFreeMemory( MemberRids );
|
|
|
|
if ( MemberUse != NULL )
|
|
SamFreeMemory( MemberUse );
|
|
|
|
if ( CurrentRids != NULL )
|
|
SamFreeMemory( CurrentRids );
|
|
|
|
if ( GroupHandle != NULL )
|
|
SamCloseHandle( GroupHandle );
|
|
|
|
//
|
|
// log the tattoo value
|
|
// if fail to get current value for the group, do not save the tattoo value
|
|
//
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) &&
|
|
hSectionDomain && hSectionTattoo &&
|
|
GrpSid && GroupSidString && bMemberQueried) {
|
|
|
|
ScepTattooManageOneMemberListValue(
|
|
hSectionDomain,
|
|
hSectionTattoo,
|
|
GroupSidString,
|
|
wcslen(GroupSidString),
|
|
pMemberList,
|
|
FALSE,
|
|
RtlNtStatusToDosError(NtStatus)
|
|
);
|
|
}
|
|
|
|
// free name list
|
|
if ( pMemberList )
|
|
ScepFreeNameList(pMemberList);
|
|
|
|
return(NtStatus);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ScepConfigureMembersOfAlias(
|
|
IN PSCESECTION hSectionDomain,
|
|
IN PSCESECTION hSectionTattoo,
|
|
IN SAM_HANDLE DomainHandle,
|
|
IN PSID DomainSid,
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN ULONG GrpId,
|
|
IN PSID GrpSid,
|
|
IN PWSTR GrpName,
|
|
IN PWSTR GroupSidString,
|
|
IN PSCE_NAME_LIST pMembers,
|
|
IN DWORD ConfigOptions
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine configure a local group (alias) members as specified in the
|
|
SCP profile ( pMembers ). Less members are added and extra members are removed.
|
|
|
|
Arguments:
|
|
|
|
DomainHandle - The domains' handle
|
|
|
|
DomainSid - The sid for the domain
|
|
|
|
PolicyHandle - the LSA policy handle
|
|
|
|
GrpId - the alias's RID
|
|
|
|
pMembers - the members list as specified in the SCP profile
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS return SAM APIs
|
|
|
|
-- */
|
|
{
|
|
NTSTATUS NtStatus=STATUS_SUCCESS;
|
|
|
|
ULONG MemberCount=0;
|
|
PUNICODE_STRING MemberNames=NULL;
|
|
PSID *Sids=NULL;
|
|
SAM_HANDLE GroupHandle=NULL;
|
|
PSID *CurrentSids=NULL;
|
|
ULONG CurrentCount=0;
|
|
|
|
DWORD i, j;
|
|
WCHAR MsgBuf[256];
|
|
|
|
PLSA_REFERENCED_DOMAIN_LIST pRefDomain;
|
|
PLSA_TRANSLATED_NAME pLsaName;
|
|
LPTSTR StringSid=NULL;
|
|
PSCE_NAME_LIST pMemberList=NULL;
|
|
BOOL bMemberQueried=FALSE;
|
|
|
|
/*
|
|
if ( pMembers == NULL )
|
|
return(STATUS_SUCCESS);
|
|
*/
|
|
//
|
|
// Accept empty member list
|
|
// find Sids for the pMember list
|
|
//
|
|
NtStatus = ScepGetMemberListSids(
|
|
DomainSid,
|
|
PolicyHandle,
|
|
pMembers,
|
|
&MemberNames,
|
|
&Sids,
|
|
&MemberCount
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_ERROR_LOOKUP, pMembers ? pMembers->Name : L"");
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) &&
|
|
hSectionDomain && hSectionTattoo && GrpSid && GroupSidString &&
|
|
(NtStatus == STATUS_NONE_MAPPED)) {
|
|
|
|
ScepTattooManageOneMemberListValue(
|
|
hSectionDomain,
|
|
hSectionTattoo,
|
|
GroupSidString,
|
|
wcslen(GroupSidString),
|
|
NULL,
|
|
TRUE,
|
|
0
|
|
);
|
|
}
|
|
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// open the alias to get a handle
|
|
//
|
|
NtStatus = SamOpenAlias(
|
|
DomainHandle,
|
|
MAXIMUM_ALLOWED, // ? ALIAS_ALL_ACCESS,
|
|
GrpId,
|
|
&GroupHandle
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_ERROR_OPEN, L"");
|
|
goto Done;
|
|
}
|
|
//
|
|
// get current members of the alias
|
|
// members of alias may exist in everywhere
|
|
//
|
|
NtStatus = SamGetMembersInAlias(
|
|
GroupHandle,
|
|
&CurrentSids,
|
|
&CurrentCount
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_ERROR_QUERY_INFO, L"");
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// build current group membership into the list
|
|
//
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) &&
|
|
hSectionDomain && hSectionTattoo && GrpSid ) {
|
|
|
|
DWORD rc = ScepTattooCurrentGroupMembers(DomainSid,
|
|
GrpSid,
|
|
SidTypeAlias,
|
|
NULL,
|
|
CurrentSids,
|
|
CurrentCount,
|
|
&pMemberList
|
|
);
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
//
|
|
// something is wrong when building the list
|
|
// this shoudln't happen unless out of memory etc.
|
|
//
|
|
ScepLogOutput3(1,0,SCESRV_POLICY_TATTOO_ERROR_QUERY,rc,GrpName);
|
|
} else
|
|
bMemberQueried = TRUE;
|
|
}
|
|
|
|
//
|
|
// Compare the member sids with the current sids for adding
|
|
//
|
|
|
|
for ( i=0; i<MemberCount; i++ ) {
|
|
#ifdef SCE_DBG
|
|
printf("process member %d for adding\n", i);
|
|
#endif
|
|
|
|
memset(MsgBuf, '\0', 512);
|
|
wcsncpy(MsgBuf, MemberNames[i].Buffer, MemberNames[i].Length/2);
|
|
|
|
if ( Sids[i] == NULL ) {
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_CANNOT_FIND, MsgBuf);
|
|
} else {
|
|
|
|
for ( j=0; j<CurrentCount; j++) {
|
|
if ( EqualSid(Sids[i], CurrentSids[j]) ) {
|
|
|
|
ScepLogOutput3(3,0, SCEDLL_STATUS_MATCH, MsgBuf);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( j >= CurrentCount) {
|
|
//
|
|
// Add this member
|
|
//
|
|
ScepLogOutput3(2,0, SCEDLL_SCP_ADD, MsgBuf);
|
|
|
|
NtStatus = SamAddMemberToAlias(
|
|
GroupHandle,
|
|
Sids[i]
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_SCP_ERROR_ADD, MsgBuf);
|
|
|
|
if ( NtStatus == STATUS_NO_SUCH_MEMBER || NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
NtStatus = STATUS_SUCCESS;
|
|
continue;
|
|
}
|
|
|
|
|
|
goto Done;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Compare the member ids with the current ids for adding
|
|
//
|
|
|
|
for ( i=0; i<CurrentCount; i++ ) {
|
|
#ifdef SCE_DBG
|
|
printf("process member %d for removing\n", i);
|
|
#endif
|
|
memset(MsgBuf, '\0', 512);
|
|
|
|
if ( ConvertSidToStringSid(
|
|
CurrentSids[i],
|
|
&StringSid
|
|
) && StringSid ) {
|
|
|
|
swprintf(MsgBuf, L"SID: %s",StringSid);
|
|
LocalFree(StringSid);
|
|
StringSid = NULL;
|
|
|
|
} else {
|
|
ScepLogOutput3(3,GetLastError(), IDS_ERROR_CONVERT_SID);
|
|
swprintf(MsgBuf, L"Member %d",i);
|
|
}
|
|
|
|
for ( j=0; j<MemberCount; j++) {
|
|
if ( Sids[j] != NULL && EqualSid( CurrentSids[i], Sids[j]) ) {
|
|
|
|
ScepLogOutput3(3,0, SCEDLL_STATUS_MATCH, MsgBuf);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( j >= MemberCount) {
|
|
//
|
|
// Find the member name
|
|
//
|
|
pRefDomain=NULL;
|
|
pLsaName=NULL;
|
|
|
|
if ( NT_SUCCESS( LsaLookupSids(
|
|
PolicyHandle,
|
|
1,
|
|
&(CurrentSids[i]),
|
|
&pRefDomain,
|
|
&pLsaName
|
|
) ) ) {
|
|
|
|
if ( pLsaName != NULL ) {
|
|
|
|
if ( pRefDomain != NULL && pRefDomain->Entries > 0 && pLsaName[0].Use != SidTypeWellKnownGroup &&
|
|
pRefDomain->Domains != NULL &&
|
|
pLsaName[0].DomainIndex != -1 &&
|
|
pRefDomain->Domains[pLsaName[0].DomainIndex].Name.Buffer != NULL &&
|
|
ScepIsSidFromAccountDomain( pRefDomain->Domains[pLsaName[0].DomainIndex].Sid ) ) {
|
|
|
|
wcsncpy(MsgBuf, pRefDomain->Domains[pLsaName[0].DomainIndex].Name.Buffer,
|
|
pRefDomain->Domains[pLsaName[0].DomainIndex].Name.Length/2);
|
|
MsgBuf[pRefDomain->Domains[pLsaName[0].DomainIndex].Name.Length/2] = L'\0';
|
|
wcscat(MsgBuf, L"\\");
|
|
}
|
|
|
|
wcsncat(MsgBuf, pLsaName[0].Name.Buffer, pLsaName[0].Name.Length/2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( pRefDomain != NULL ) {
|
|
LsaFreeMemory(pRefDomain);
|
|
pRefDomain = NULL;
|
|
}
|
|
|
|
if ( pLsaName != NULL ){
|
|
LsaFreeMemory(pLsaName);
|
|
pLsaName = NULL;
|
|
}
|
|
//
|
|
// remove this member
|
|
//
|
|
ScepLogOutput3(2,0, SCEDLL_SCP_REMOVE, MsgBuf);
|
|
|
|
NtStatus = SamRemoveMemberFromAlias(
|
|
GroupHandle,
|
|
CurrentSids[i]
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_SCP_ERROR_REMOVE, MsgBuf);
|
|
goto Done;
|
|
}
|
|
}
|
|
}
|
|
|
|
Done:
|
|
|
|
if ( Sids != NULL ) {
|
|
for ( i=0; i<MemberCount; i++ ) {
|
|
if ( Sids[i] != NULL )
|
|
ScepFree( Sids[i] );
|
|
}
|
|
ScepFree( Sids );
|
|
}
|
|
|
|
if ( CurrentSids != NULL )
|
|
LsaFreeMemory(CurrentSids);
|
|
|
|
if ( MemberNames != NULL )
|
|
RtlFreeHeap(RtlProcessHeap(), 0, MemberNames);
|
|
|
|
if ( GroupHandle != NULL )
|
|
SamCloseHandle( GroupHandle );
|
|
|
|
//
|
|
// log the tattoo value
|
|
// if fail to get current value for the group, do not save the tattoo value
|
|
//
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) &&
|
|
hSectionDomain && hSectionTattoo &&
|
|
GrpSid && GroupSidString && bMemberQueried) {
|
|
|
|
ScepTattooManageOneMemberListValue(
|
|
hSectionDomain,
|
|
hSectionTattoo,
|
|
GroupSidString,
|
|
wcslen(GroupSidString),
|
|
pMemberList,
|
|
FALSE,
|
|
RtlNtStatusToDosError(NtStatus)
|
|
);
|
|
}
|
|
|
|
// free name list
|
|
if ( pMemberList )
|
|
ScepFreeNameList(pMemberList);
|
|
|
|
return(NtStatus);
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepParseListConvertStringSidsToNames(
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN OUT PSCE_NAME_LIST pNameList
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine parses the group list (expected to contain only string sids in
|
|
*SID format) and replaces the strings sids with names in domain\name format.
|
|
|
|
Any string that cannot be mapped to a name will be NULL-ed out.
|
|
|
|
Arguments:
|
|
|
|
PolicyHandle - LSA handle
|
|
|
|
pNameList - list of groups
|
|
|
|
Return Value:
|
|
|
|
SCESTATUS - return success if all conversion succeeded or some of the SIDs
|
|
cannot be mapped to a name
|
|
|
|
-- */
|
|
{
|
|
SCESTATUS rc = SCESTATUS_SUCCESS;
|
|
PSCE_NAME_LIST pName = NULL;
|
|
|
|
for(pName = pNameList;
|
|
SCESTATUS_SUCCESS == rc && pName != NULL;
|
|
pName = pName->Next)
|
|
{
|
|
PSID pSid=NULL;
|
|
|
|
if(ConvertStringSidToSid(
|
|
(pName->Name)+1, // skip leading '*'
|
|
&pSid))
|
|
{
|
|
PWSTR pszName = NULL; // no need to free, returned in pNameList
|
|
DWORD dwLen = 0;
|
|
NTSTATUS NtStatus;
|
|
|
|
NtStatus = ScepConvertSidToName(
|
|
PolicyHandle,
|
|
pSid,
|
|
FALSE, // just name, no domain
|
|
&pszName,
|
|
&dwLen);
|
|
|
|
if(NT_SUCCESS(NtStatus) ||
|
|
STATUS_NONE_MAPPED == NtStatus)
|
|
{
|
|
ScepFree(pName->Name);
|
|
pName->Name = pszName; // NULL if failed to map to name
|
|
}
|
|
else
|
|
{
|
|
rc = ScepDosErrorToSceStatus(RtlNtStatusToDosError(NtStatus));
|
|
}
|
|
|
|
LocalFree(pSid);
|
|
}
|
|
else
|
|
{
|
|
rc = ScepDosErrorToSceStatus(GetLastError());
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
SCESTATUS
|
|
ScepParseListConvertNamesToStringSids(
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN OUT PSCE_NAME_LIST pNameList
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine parses the group list (expected to contain only names in domain\name
|
|
format) and replaces them with *SID sid string format
|
|
|
|
Arguments:
|
|
|
|
PolicyHandle - LSA handle
|
|
|
|
pNameList - list of groups
|
|
|
|
Return Value:
|
|
|
|
SCESTATUS - return success if all conversion succeeded
|
|
|
|
-- */
|
|
{
|
|
SCESTATUS rc = SCESTATUS_SUCCESS;
|
|
PSCE_NAME_LIST pName = NULL;
|
|
|
|
for(pName = pNameList;
|
|
pName != NULL && SCESTATUS_SUCCESS == rc;
|
|
pName = pName->Next)
|
|
{
|
|
PWSTR pszName = NULL; // no need to free, returned in pNameList
|
|
DWORD dwLen = 0;
|
|
|
|
rc = ScepConvertNameToSidString(
|
|
PolicyHandle,
|
|
pName->Name,
|
|
FALSE, // accept names w/ domain
|
|
&pszName,
|
|
&dwLen);
|
|
|
|
if(SCESTATUS_SUCCESS != rc)
|
|
{
|
|
break;
|
|
}
|
|
ScepFree(pName->Name);
|
|
pName->Name = pszName;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
bool
|
|
ScepFindInNameList(
|
|
IN PSCE_NAME_LIST pNameList,
|
|
IN PWSTR pszName)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
Searches a name in the list, case insensitive. Name list could contain NULL
|
|
entries. All valid names are presumed from the current machine since they were
|
|
previously successfully opened in SAM.
|
|
|
|
Arguments:
|
|
|
|
pNameList - list of name to search in
|
|
|
|
pszName - Name to be searched for
|
|
|
|
Return:
|
|
|
|
true - if name is found
|
|
-- */
|
|
{
|
|
PSCE_NAME_LIST pCrt;
|
|
PWSTR pszAccountName;
|
|
|
|
for(pCrt = pNameList; pCrt; pCrt = pCrt->Next)
|
|
{
|
|
if(!pCrt->Name)
|
|
continue;
|
|
|
|
pszAccountName = wcschr(pCrt->Name, L'\\');
|
|
|
|
if(pszAccountName)
|
|
pszAccountName++;
|
|
else
|
|
pszAccountName = pCrt->Name;
|
|
|
|
if(0 == _wcsicmp(pszAccountName, pszName))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
NTSTATUS
|
|
ScepSamOpenAlias(
|
|
IN SAM_HANDLE DomainHandle,
|
|
IN SAM_HANDLE BuiltinDomainHandle,
|
|
IN PWSTR pszName,
|
|
OUT SAM_HANDLE *pAliasHandle
|
|
)
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PWSTR pTemp;
|
|
UNICODE_STRING Name;
|
|
PSID_NAME_USE AliasUse=NULL;
|
|
PULONG AliasId=NULL;
|
|
SAM_HANDLE ThisDomain;
|
|
|
|
// should expect pGroup->Name has domain prefix
|
|
|
|
pTemp = wcschr(pszName, L'\\');
|
|
|
|
if ( pTemp )
|
|
{
|
|
// check if this group is from a different domain
|
|
|
|
Name.Buffer = pszName;
|
|
Name.Length = ((USHORT)(pTemp-pszName))*sizeof(TCHAR);
|
|
|
|
if ( !ScepIsDomainLocal(&Name) )
|
|
{
|
|
ScepLogOutput3(1, 0, SCEDLL_ERROR_ALIAS_MEMBEROF, pszName);
|
|
NtStatus = STATUS_NONE_MAPPED;
|
|
}
|
|
else
|
|
{
|
|
pTemp++;
|
|
}
|
|
|
|
} else {
|
|
pTemp = pszName;
|
|
}
|
|
|
|
if(NT_SUCCESS(NtStatus))
|
|
{
|
|
RtlInitUnicodeString( &Name, pTemp);
|
|
|
|
NtStatus = SamLookupNamesInDomain(
|
|
DomainHandle,
|
|
1,
|
|
&Name,
|
|
&AliasId,
|
|
&AliasUse
|
|
);
|
|
|
|
ThisDomain = DomainHandle;
|
|
|
|
if(NtStatus == STATUS_NONE_MAPPED)
|
|
{
|
|
|
|
// not found in account domain. Lookup in the builtin domain
|
|
|
|
NtStatus = SamLookupNamesInDomain(
|
|
BuiltinDomainHandle,
|
|
1,
|
|
&Name,
|
|
&AliasId,
|
|
&AliasUse
|
|
);
|
|
ThisDomain = BuiltinDomainHandle;
|
|
}
|
|
|
|
if ( !NT_SUCCESS(NtStatus) || !AliasUse || !AliasId )
|
|
{
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_CANNOT_FIND, pTemp);
|
|
}
|
|
}
|
|
|
|
if(NT_SUCCESS(NtStatus))
|
|
{
|
|
if ( AliasUse[0] != SidTypeAlias ) {
|
|
ScepLogOutput3(1,0, SCEDLL_ERROR_ALIAS_MEMBEROF, pTemp);
|
|
|
|
NtStatus = STATUS_NONE_MAPPED;
|
|
}
|
|
}
|
|
|
|
if(NT_SUCCESS(NtStatus))
|
|
{
|
|
NtStatus = SamOpenAlias(
|
|
ThisDomain,
|
|
MAXIMUM_ALLOWED,
|
|
AliasId[0],
|
|
pAliasHandle
|
|
);
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_ERROR_OPEN, pszName);
|
|
}
|
|
}
|
|
|
|
if(AliasId)
|
|
{
|
|
SamFreeMemory(AliasId);
|
|
}
|
|
|
|
if(AliasUse)
|
|
{
|
|
SamFreeMemory(AliasUse);
|
|
}
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
SCESTATUS
|
|
ScepValidateGroupInAliases(
|
|
IN SAM_HANDLE DomainHandle,
|
|
IN SAM_HANDLE BuiltinDomainHandle,
|
|
IN PSCESECTION hSectionTattoo,
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN PSID GrpSid,
|
|
IN PSCE_NAME_LIST pAliasList,
|
|
bool fProcessTattoo
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine add the group to a list of alieses to ensure the group's
|
|
membership.
|
|
|
|
Arguments:
|
|
|
|
hSectionTattoo - handle to tatoo table section
|
|
|
|
DomainHandle - The account domain handle
|
|
|
|
BuiltinDomainHandle - The builtin domain handle
|
|
|
|
GrpSid - The group's SID
|
|
|
|
pAliasList - the list of aliases to check
|
|
|
|
fProcessTattoo - true if we need to process tattoo table, ie during
|
|
policy propagation and if not on a DC
|
|
|
|
-- */
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
NTSTATUS NtStatusSave = STATUS_SUCCESS;
|
|
SCESTATUS rc = SCESTATUS_SUCCESS;
|
|
PSCE_NAME_LIST pOldTattooList = NULL;
|
|
PSCE_NAME_LIST pNewTattooList = NULL;
|
|
PSCE_NAME_LIST pAliasDeleteList = NULL;
|
|
SAM_HANDLE AliasHandle=NULL;
|
|
PSCE_NAME_LIST pAlias;
|
|
UNICODE_STRING Name;
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// 1. Retrieve old memberof tattoo list for the group and
|
|
// convert SID strings to names
|
|
//
|
|
// 2. For each group element in effective memberof list
|
|
// if element is valid alias on this machine
|
|
// add the group to alias
|
|
// if successfully added
|
|
// add alias to new tattoo list
|
|
//
|
|
// 3. For each group element in old tattoo list
|
|
// if element exists is effective list
|
|
// add element to new tattoo list
|
|
// else
|
|
// add element to delete list
|
|
//
|
|
// 4. For each element in delete list
|
|
// if element is valid alias on this machine
|
|
// delete group from alias
|
|
// if delete unsuccessful
|
|
// add element to new tattoo list
|
|
//
|
|
// 6. Write new tattoo list to tattoo table after converting
|
|
// names back to SID strings
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
if(fProcessTattoo)
|
|
{
|
|
// Retrieve old memberof tattoo list for the group
|
|
|
|
rc = ScepTattooReadOneMemberOfListValue(
|
|
hSectionTattoo,
|
|
GrpSid,
|
|
&pOldTattooList);
|
|
|
|
// Parse old tattoo list and replace *SIDs with names
|
|
|
|
if(SCESTATUS_SUCCESS == rc)
|
|
{
|
|
rc = ScepParseListConvertStringSidsToNames(
|
|
PolicyHandle,
|
|
pOldTattooList);
|
|
}
|
|
|
|
// tattoo entry could be missing, ignore
|
|
|
|
if(SCESTATUS_RECORD_NOT_FOUND == rc)
|
|
{
|
|
rc = SCESTATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
if(SCESTATUS_SUCCESS == rc)
|
|
{
|
|
// For each group element in effective memberof list
|
|
|
|
for(pAlias = pAliasList; pAlias != NULL; pAlias = pAlias->Next)
|
|
{
|
|
NtStatus = ScepSamOpenAlias(
|
|
DomainHandle,
|
|
BuiltinDomainHandle,
|
|
pAlias->Name,
|
|
&AliasHandle);
|
|
//
|
|
// if element is not valid alias on this machine go to next
|
|
//
|
|
if(STATUS_NONE_MAPPED == NtStatus)
|
|
{
|
|
ScepLogOutput3(1, 0, SCEDLL_CANNOT_FIND, pAlias->Name);
|
|
NtStatusSave = NtStatus;
|
|
|
|
// Alias is not valid on this machine, remove it from the list
|
|
ScepFree(pAlias->Name);
|
|
pAlias->Name = NULL;
|
|
|
|
continue;
|
|
}
|
|
|
|
if(!NT_SUCCESS(NtStatus))
|
|
{
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// element is valid alias, add the group to alias
|
|
//
|
|
NtStatus = SamAddMemberToAlias(
|
|
AliasHandle,
|
|
GrpSid
|
|
);
|
|
//
|
|
// If successfully added, add alias to new tattoo list
|
|
//
|
|
if (NT_SUCCESS(NtStatus))
|
|
{
|
|
ScepLogOutput3(1, 0, SCEDLL_SCP_SUCCESS_ADDTO, pAlias->Name);
|
|
|
|
rc = ScepAddToNameList(
|
|
&pNewTattooList,
|
|
pAlias->Name,
|
|
0);
|
|
|
|
if(SCESTATUS_SUCCESS != rc)
|
|
{
|
|
goto Done;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Ignore error if member was already in the alias
|
|
if(NtStatus == STATUS_MEMBER_IN_ALIAS)
|
|
{
|
|
ScepLogOutput3(1, 0, SCEDLL_SCP_SUCCESS_ADDTO_ALREADYADDED, pAlias->Name);
|
|
|
|
NtStatus = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_SCP_ERROR_ADDTO, pAlias->Name);
|
|
|
|
NtStatusSave = NtStatus;
|
|
}
|
|
}
|
|
|
|
SamCloseHandle(AliasHandle);
|
|
AliasHandle = NULL;
|
|
}
|
|
}
|
|
|
|
if(fProcessTattoo)
|
|
{
|
|
if(SCESTATUS_SUCCESS == rc)
|
|
{
|
|
// For each group element in old tattoo list
|
|
|
|
for(pAlias = pOldTattooList; pAlias != NULL; pAlias = pAlias->Next)
|
|
{
|
|
// Name could be empty if the conversion *SID -> name failed
|
|
|
|
if(!pAlias->Name)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// If element exists is effective list
|
|
|
|
if(ScepFindInNameList(pAliasList, pAlias->Name))
|
|
{
|
|
// Add element to new tattoo list if not already in
|
|
|
|
if(!ScepFindInNameList(pNewTattooList, pAlias->Name))
|
|
{
|
|
// Add element to delete list
|
|
|
|
rc = ScepAddToNameList(
|
|
&pNewTattooList,
|
|
pAlias->Name,
|
|
0);
|
|
|
|
if(SCESTATUS_SUCCESS != rc)
|
|
{
|
|
goto Done;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Add element to delete list
|
|
|
|
rc = ScepAddToNameList(
|
|
&pAliasDeleteList,
|
|
pAlias->Name,
|
|
0);
|
|
|
|
if(SCESTATUS_SUCCESS != rc)
|
|
{
|
|
goto Done;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(SCESTATUS_SUCCESS == rc)
|
|
{
|
|
// For each element in delete list
|
|
|
|
for(pAlias = pAliasDeleteList; pAlias != NULL; pAlias = pAlias->Next)
|
|
{
|
|
NtStatus = ScepSamOpenAlias(
|
|
DomainHandle,
|
|
BuiltinDomainHandle,
|
|
pAlias->Name,
|
|
&AliasHandle);
|
|
|
|
// if element is not valid alias on this machine go to next
|
|
|
|
if(STATUS_NONE_MAPPED == NtStatus)
|
|
{
|
|
NtStatus = STATUS_SUCCESS;
|
|
continue;
|
|
}
|
|
|
|
if(!NT_SUCCESS(NtStatus))
|
|
{
|
|
goto Done;
|
|
}
|
|
|
|
// Delete group from alias
|
|
|
|
NtStatus = SamRemoveMemberFromAlias(
|
|
AliasHandle,
|
|
GrpSid
|
|
);
|
|
|
|
if(NT_SUCCESS(NtStatus))
|
|
{
|
|
ScepLogOutput3(1, 0, SCEDLL_SCP_SUCCESS_REMOVEFROM, pAlias->Name);
|
|
}
|
|
else if(STATUS_SPECIAL_ACCOUNT == NtStatus ||
|
|
STATUS_MEMBER_NOT_IN_ALIAS == NtStatus)
|
|
{
|
|
// Ignore not found or special account
|
|
ScepLogOutput3(1, 0, SCEDLL_SCP_SUCCESS_REMOVEFROM_ALREADYREMOVED, pAlias->Name);
|
|
|
|
NtStatus = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
NtStatusSave = NtStatus;
|
|
|
|
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
|
|
SCEDLL_SCP_ERROR_REMOVEFROM, pAlias->Name);
|
|
|
|
// If delete unsuccessful, add to new tattoo list so we can
|
|
// retry next time
|
|
|
|
rc = ScepAddToNameList(
|
|
&pNewTattooList,
|
|
pAlias->Name,
|
|
0);
|
|
|
|
if(SCESTATUS_SUCCESS != rc)
|
|
{
|
|
goto Done;
|
|
}
|
|
}
|
|
|
|
SamCloseHandle(AliasHandle);
|
|
AliasHandle = NULL;
|
|
}
|
|
}
|
|
|
|
// Convert new tattoo list to *SID format
|
|
|
|
if(SCESTATUS_SUCCESS == rc)
|
|
{
|
|
rc = ScepParseListConvertNamesToStringSids(
|
|
PolicyHandle,
|
|
pNewTattooList);
|
|
}
|
|
|
|
if(SCESTATUS_SUCCESS == rc)
|
|
{
|
|
// Write/delete new tattoo list to tattoo table
|
|
|
|
rc = ScepTattooWriteOneMemberOfListValue(
|
|
hSectionTattoo,
|
|
GrpSid,
|
|
pNewTattooList);
|
|
}
|
|
} // if(fProcessTattoo)
|
|
|
|
Done:
|
|
|
|
ScepFreeNameList(pOldTattooList);
|
|
|
|
ScepFreeNameList(pNewTattooList);
|
|
|
|
ScepFreeNameList(pAliasDeleteList);
|
|
|
|
if ( AliasHandle != NULL )
|
|
SamCloseHandle(AliasHandle);
|
|
|
|
if (SCESTATUS_SUCCESS == rc && !NT_SUCCESS(NtStatusSave))
|
|
rc = ScepDosErrorToSceStatus(RtlNtStatusToDosError(NtStatusSave));
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepConfigureObjectSecurity(
|
|
IN PSCE_OBJECT_LIST pRoots,
|
|
IN AREA_INFORMATION Area,
|
|
IN BOOL bPolicyProp,
|
|
IN DWORD ConfigOptions
|
|
)
|
|
/* ++
|
|
|
|
Routine Description:
|
|
|
|
Configure the security setting on Registry keys as specified in pObject tree
|
|
|
|
Arguments:
|
|
|
|
pRoots - a list of object roots to configure
|
|
|
|
Area - The security area to configure (registry or file)
|
|
|
|
ObjectType - Type of the object tree
|
|
SCEJET_AUDITING
|
|
SCEJET_PERMISSION
|
|
|
|
Return value:
|
|
|
|
SCESTATUS error codes
|
|
|
|
++ */
|
|
{
|
|
|
|
|
|
if (Area == AREA_REGISTRY_SECURITY) {
|
|
#ifdef _WIN64
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_BEGIN_REGISTRY_64KEY);
|
|
#else
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_BEGIN_REGISTRY);
|
|
#endif
|
|
}
|
|
|
|
|
|
if ( bPolicyProp &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
return( SCESTATUS_SERVICE_NOT_SUPPORT );
|
|
}
|
|
|
|
HANDLE Token;
|
|
SCESTATUS rc;
|
|
SCESTATUS SaveStat=SCESTATUS_SUCCESS;
|
|
DWORD Win32rc;
|
|
PSCE_OBJECT_LIST pOneRoot;
|
|
PSCE_OBJECT_CHILD_LIST pSecurityObject=NULL;
|
|
DWORD FileSystemFlags;
|
|
SID_IDENTIFIER_AUTHORITY IdentifierAuthority=SECURITY_NT_AUTHORITY;
|
|
WCHAR theDrive[4];
|
|
UINT DriveType;
|
|
|
|
//
|
|
// get current thread/process's token
|
|
//
|
|
if (!OpenThreadToken( GetCurrentThread(),
|
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
|
TRUE,
|
|
&Token)) {
|
|
|
|
if(ERROR_NO_TOKEN == GetLastError()){
|
|
|
|
if(!OpenProcessToken( GetCurrentProcess(),
|
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
|
&Token)) {
|
|
|
|
|
|
ScepLogOutput3(1, GetLastError(), SCEDLL_ERROR_QUERY_INFO, L"TOKEN");
|
|
return(ScepDosErrorToSceStatus(GetLastError()));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ScepLogOutput3(1, GetLastError(), SCEDLL_ERROR_QUERY_INFO, L"TOKEN");
|
|
return(ScepDosErrorToSceStatus(GetLastError()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Adjust privilege for setting SACL
|
|
//
|
|
Win32rc = SceAdjustPrivilege( SE_SECURITY_PRIVILEGE, TRUE, Token );
|
|
|
|
//
|
|
// if can't adjust privilege, still continue
|
|
//
|
|
|
|
if ( Win32rc != NO_ERROR )
|
|
ScepLogOutput3(1, Win32rc, SCEDLL_ERROR_ADJUST, L"SE_SECURITY_PRIVILEGE");
|
|
|
|
// adjust take ownership privilege
|
|
// if fails, continue
|
|
Win32rc = SceAdjustPrivilege( SE_TAKE_OWNERSHIP_PRIVILEGE, TRUE, Token );
|
|
|
|
if ( Win32rc != NO_ERROR )
|
|
ScepLogOutput3(1, Win32rc, SCEDLL_ERROR_ADJUST, L"SE_TAKE_OWNERSHIP_PRIVILEGE");
|
|
|
|
|
|
// create a sid for administrators
|
|
// if fails, continue
|
|
|
|
|
|
if ( ! NT_SUCCESS ( RtlAllocateAndInitializeSid( &IdentifierAuthority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0,0,0,0,0,0,
|
|
&AdminsSid
|
|
) ) ) {
|
|
ScepLogOutput3(0,ERROR_NOT_ENOUGH_MEMORY,
|
|
SCEDLL_ADMINISTRATORS_SID);
|
|
}
|
|
|
|
|
|
#ifdef _WIN64
|
|
|
|
//
|
|
// declaration for object tree root pointer to remember from the 64-bit phase and use
|
|
// for 32-bit phase for regkeys (only from the HKLM root, since wow6432node resides
|
|
// under this root only). In future, if there are more wow6432node's that need security
|
|
// synchronization, we will have to extend the logic on similar lines to handle them.
|
|
//
|
|
|
|
PSCE_OBJECT_CHILD_LIST pHKLMSubtreeRoot = NULL;
|
|
BOOL bIsHKLMSubtree = FALSE;
|
|
|
|
#endif
|
|
|
|
|
|
// process each tree
|
|
for ( pOneRoot=pRoots; pOneRoot != NULL; pOneRoot=pOneRoot->Next ) {
|
|
|
|
if ( Area == AREA_FILE_SECURITY &&
|
|
(pOneRoot->Status == SCE_STATUS_CHECK ||
|
|
pOneRoot->Status == SCE_STATUS_NO_AUTO_INHERIT ||
|
|
pOneRoot->Status == SCE_STATUS_OVERWRITE) ) {
|
|
|
|
//
|
|
// make sure the input data follows file format
|
|
//
|
|
if ( pOneRoot->Name[1] != L'\0' && pOneRoot->Name[1] != L':') {
|
|
ScepLogOutput3(1, ERROR_INVALID_DATA, SCEDLL_CANNOT_FIND, pOneRoot->Name);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// check if support acl
|
|
//
|
|
theDrive[0] = pOneRoot->Name[0];
|
|
theDrive[1] = L':';
|
|
theDrive[2] = L'\\';
|
|
theDrive[3] = L'\0';
|
|
|
|
DriveType = GetDriveType(theDrive);
|
|
|
|
if ( DriveType == DRIVE_FIXED ||
|
|
DriveType == DRIVE_RAMDISK ) {
|
|
|
|
if ( GetVolumeInformation( theDrive,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&FileSystemFlags,
|
|
NULL,
|
|
0
|
|
) ) {
|
|
|
|
if ( !( FileSystemFlags & FS_PERSISTENT_ACLS) ) {
|
|
|
|
pOneRoot->Status = SCE_STATUS_NO_ACL_SUPPORT;
|
|
ScepLogOutput3(1, 0, SCEDLL_NO_ACL_SUPPORT, theDrive);
|
|
}
|
|
} else {
|
|
ScepLogOutput3(1, GetLastError(),
|
|
SCEDLL_ERROR_QUERY_VOLUME, theDrive);
|
|
}
|
|
} else {
|
|
|
|
pOneRoot->Status = SCE_STATUS_NO_ACL_SUPPORT;
|
|
ScepLogOutput3(1, 0, SCEDLL_NO_ACL_SUPPORT, theDrive);
|
|
}
|
|
|
|
}
|
|
|
|
if ( pOneRoot->Status != SCE_STATUS_CHECK &&
|
|
pOneRoot->Status != SCE_STATUS_NO_AUTO_INHERIT &&
|
|
pOneRoot->Status != SCE_STATUS_OVERWRITE)
|
|
continue;
|
|
|
|
//
|
|
// if system is shutting down within policy propagation,
|
|
// quit as soon as possible
|
|
//
|
|
if ( bPolicyProp &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
rc = SCESTATUS_SERVICE_NOT_SUPPORT;
|
|
break;
|
|
}
|
|
|
|
rc = ScepGetOneSection(
|
|
hProfile,
|
|
Area,
|
|
pOneRoot->Name,
|
|
bPolicyProp ? SCE_ENGINE_SCP : SCE_ENGINE_SMP,
|
|
(PVOID *)&pSecurityObject
|
|
);
|
|
|
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|
SaveStat = rc;
|
|
continue; //goto Done;
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
|
|
//
|
|
// on a 64-bit platform, if the closest ancestor of "Machine\Software\Wow6432Node"
|
|
// specified in the template, has mode 2, we have to insert "Machine\Software\Wow6432Node"
|
|
// in the tree in the SCE_STATUS_IGNORE mode since this 32-bit hive should not be
|
|
// configured by SCE in the 64-bit phase (same situation for '0' mode is handled by MARTA apis)
|
|
//
|
|
|
|
if ( Area == AREA_REGISTRY_SECURITY ) {
|
|
|
|
if ( _wcsnicmp(pSecurityObject->Node->ObjectFullName,
|
|
L"MACHINE",
|
|
sizeof(L"MACHINE")/sizeof(WCHAR) - 1
|
|
) == 0 ){
|
|
|
|
//
|
|
// idea is to find mode of closest ancestor of "Machine\Software\Wow6432Node"
|
|
//
|
|
|
|
PSCE_OBJECT_CHILD_LIST pSearchSwHiveNode = pSecurityObject->Node->ChildList;
|
|
BYTE byClosestAncestorStatus;
|
|
|
|
//
|
|
// we need to do the 32-bit phase only if we get in here
|
|
// so remember HKLM ptr in the tree for 32-bit phase
|
|
//
|
|
|
|
pHKLMSubtreeRoot = pSecurityObject;
|
|
bIsHKLMSubtree = TRUE;
|
|
|
|
//
|
|
// try to find "Machine\Software"
|
|
//
|
|
|
|
while ( pSearchSwHiveNode ) {
|
|
|
|
if ( pSearchSwHiveNode->Node &&
|
|
_wcsnicmp(pSearchSwHiveNode->Node->ObjectFullName + (sizeof(L"MACHINE")/sizeof(WCHAR)),
|
|
L"SOFTWARE",
|
|
sizeof(L"SOFTWARE")/sizeof(WCHAR) - 1
|
|
) == 0 ) {
|
|
|
|
//
|
|
// found "Machine\Software"
|
|
//
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pSearchSwHiveNode = pSearchSwHiveNode->Next;
|
|
}
|
|
|
|
byClosestAncestorStatus = (pSearchSwHiveNode && pSearchSwHiveNode->Node) ? pSearchSwHiveNode->Node->Status : pHKLMSubtreeRoot->Node->Status;
|
|
|
|
//
|
|
// if mode of closest ancestor of "Machine\Software\Wow6432Node" is
|
|
// SCE_STATUS_OVERWRITE or "Machine\Software" has some children
|
|
// need to add "Machine\Software\Wow6432Node" with SCE_STATUS_IGNORE
|
|
// to the tree
|
|
//
|
|
|
|
if ( ( pSearchSwHiveNode && pSearchSwHiveNode->Node &&
|
|
pSearchSwHiveNode->Node->ChildList != NULL) ||
|
|
byClosestAncestorStatus == SCE_STATUS_OVERWRITE ) {
|
|
|
|
rc = ScepBuildObjectTree(
|
|
NULL,
|
|
&pSecurityObject,
|
|
1,
|
|
L'\\',
|
|
L"MACHINE\\SOFTWARE\\WOW6432Node",
|
|
1,
|
|
SCE_STATUS_IGNORE,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|
SaveStat = rc;
|
|
|
|
ScepFreeObject2Security( pSecurityObject, FALSE);
|
|
pSecurityObject = NULL;
|
|
|
|
continue; //goto Done;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// then process each node in the list
|
|
//
|
|
for (PSCE_OBJECT_CHILD_LIST pTemp = pSecurityObject; pTemp != NULL; pTemp=pTemp->Next) {
|
|
|
|
if ( pTemp->Node == NULL ) continue;
|
|
|
|
if ( Area == AREA_FILE_SECURITY ) {
|
|
if ( pTemp->Node->ObjectFullName[1] == L':' &&
|
|
pTemp->Node->ObjectFullName[2] == L'\0' ) {
|
|
|
|
pTemp->Node->ObjectFullName[2] = L'\\';
|
|
pTemp->Node->ObjectFullName[3] = L'\0';
|
|
}
|
|
}
|
|
|
|
if ( bPolicyProp &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
rc = SCESTATUS_SERVICE_NOT_SUPPORT;
|
|
|
|
} else {
|
|
|
|
//
|
|
// calculate the "real" security descriptor for each node
|
|
//
|
|
if ( Area == AREA_FILE_SECURITY ) {
|
|
rc = ScepCalculateSecurityToApply(
|
|
pTemp->Node,
|
|
SE_FILE_OBJECT,
|
|
Token,
|
|
&FileGenericMapping
|
|
);
|
|
} else if ( Area == AREA_REGISTRY_SECURITY ) {
|
|
rc = ScepCalculateSecurityToApply(
|
|
pTemp->Node,
|
|
SE_REGISTRY_KEY,
|
|
Token,
|
|
&KeyGenericMapping
|
|
);
|
|
}
|
|
}
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
if ( bPolicyProp &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
rc = SCESTATUS_SERVICE_NOT_SUPPORT;
|
|
|
|
} else {
|
|
|
|
if ( Area == AREA_FILE_SECURITY ) {
|
|
rc = ScepConfigureObjectTree(
|
|
pTemp->Node,
|
|
SE_FILE_OBJECT,
|
|
Token,
|
|
&FileGenericMapping,
|
|
ConfigOptions
|
|
);
|
|
|
|
} else if ( Area == AREA_REGISTRY_SECURITY ) {
|
|
rc = ScepConfigureObjectTree(
|
|
pTemp->Node,
|
|
SE_REGISTRY_KEY,
|
|
Token,
|
|
&KeyGenericMapping,
|
|
ConfigOptions
|
|
);
|
|
|
|
} else {
|
|
// ds objects
|
|
rc = ScepConfigureDsSecurity( pTemp->Node);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( rc != SCESTATUS_SUCCESS )
|
|
SaveStat = rc;
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
//
|
|
// If 64-bit platform and AREA_REGISTRY_SECURITY and HKLM, do
|
|
// not free the whole subtree , only free the computed SDs
|
|
//
|
|
|
|
if (Area == AREA_FILE_SECURITY)
|
|
ScepFreeObject2Security( pSecurityObject, FALSE);
|
|
else if (Area == AREA_REGISTRY_SECURITY)
|
|
ScepFreeObject2Security( pSecurityObject, bIsHKLMSubtree);
|
|
|
|
bIsHKLMSubtree = FALSE;
|
|
#else
|
|
ScepFreeObject2Security( pSecurityObject, FALSE);
|
|
#endif
|
|
pSecurityObject = NULL;
|
|
|
|
//
|
|
// stop right away if bPolicyProp and system is being shutdown
|
|
//
|
|
|
|
if (rc == SCESTATUS_SERVICE_NOT_SUPPORT)
|
|
break;
|
|
|
|
}
|
|
|
|
if ( Area == AREA_REGISTRY_SECURITY ) {
|
|
|
|
if ( SaveStat != SCESTATUS_SUCCESS ) {
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_REGISTRY_ERROR);
|
|
} else {
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_REGISTRY_SUCCESS);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
#ifdef _WIN64
|
|
|
|
//
|
|
// on a 64-bit platform, if AREA_REGISTRY_SECURITY, will have to recompute
|
|
// security and apply for the same keys as before except that it is for the
|
|
// 32-bit hives this time around (idea is to synchronize 64-bit and 32 bit
|
|
// registry security). There is no need to rebuild the tree from the template.
|
|
//
|
|
|
|
if (rc != SCESTATUS_SERVICE_NOT_SUPPORT && Area == AREA_REGISTRY_SECURITY) {
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_BEGIN_REGISTRY_32KEY);
|
|
|
|
if (pSecurityObject = pHKLMSubtreeRoot) {
|
|
|
|
//
|
|
// nothing needs to be done to the Wow6432Node that was added in SCE_STATUS_IGNORE
|
|
// mode in the 64-bit phase since it is illegal to specify Wow6432Node in the template
|
|
// (the plan is that registry APIs will treat "Wow6432Node" as a reserved keyname)
|
|
//
|
|
|
|
//
|
|
// we will set SCE_STATUS_IGNORE mode to all immediate nodes under HKLM except
|
|
// HKLM\Software. This will take care of HKLM or HKLM\Software being specified
|
|
// in any mode etc. as though it was 32-bit registry configuration, since all
|
|
// we care about now is 32-bit configuration for HKLM\Software and under
|
|
//
|
|
|
|
PSCE_OBJECT_CHILD_LIST pHKLMChild = pSecurityObject->Node->ChildList;
|
|
|
|
while ( pHKLMChild ) {
|
|
|
|
if ( pHKLMChild->Node &&
|
|
_wcsnicmp(pHKLMChild->Node->ObjectFullName + (sizeof(L"MACHINE")/sizeof(WCHAR)),
|
|
L"SOFTWARE",
|
|
sizeof(L"SOFTWARE")/sizeof(WCHAR) - 1
|
|
) != 0 ) {
|
|
|
|
//
|
|
// not "Machine\Software"
|
|
//
|
|
|
|
pHKLMChild->Node->Status = SCE_STATUS_IGNORE;
|
|
|
|
}
|
|
|
|
pHKLMChild = pHKLMChild->Next;
|
|
}
|
|
|
|
|
|
|
|
if ( bPolicyProp &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
rc = SCESTATUS_SERVICE_NOT_SUPPORT;
|
|
|
|
} else {
|
|
|
|
//
|
|
// calculate the "real" security descriptor for each node
|
|
//
|
|
rc = ScepCalculateSecurityToApply(
|
|
pSecurityObject->Node,
|
|
SE_REGISTRY_WOW64_32KEY,
|
|
Token,
|
|
&KeyGenericMapping
|
|
);
|
|
}
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
if ( bPolicyProp &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
rc = SCESTATUS_SERVICE_NOT_SUPPORT;
|
|
|
|
} else {
|
|
|
|
rc = ScepConfigureObjectTree(
|
|
pSecurityObject->Node,
|
|
SE_REGISTRY_WOW64_32KEY,
|
|
Token,
|
|
&KeyGenericMapping,
|
|
ConfigOptions
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free the whole tree now (done with 32-bit phase)
|
|
//
|
|
|
|
ScepFreeObject2Security( pSecurityObject, FALSE);
|
|
pSecurityObject = NULL;
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
SaveStat = rc;
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_REGISTRY_ERROR);
|
|
} else {
|
|
ScepLogOutput3(0,0, SCEDLL_SCP_REGISTRY_SUCCESS);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
if( AdminsSid != NULL ) {
|
|
RtlFreeSid( AdminsSid );
|
|
AdminsSid = NULL;
|
|
}
|
|
|
|
SceAdjustPrivilege( SE_SECURITY_PRIVILEGE, FALSE, Token );
|
|
//
|
|
// disable take ownership privilege, even for administrators
|
|
// because by default it's disabled
|
|
//
|
|
SceAdjustPrivilege( SE_TAKE_OWNERSHIP_PRIVILEGE, FALSE, Token );
|
|
|
|
CloseHandle(Token);
|
|
|
|
if ( pSecurityObject != NULL ) {
|
|
ScepFreeObject2Security( pSecurityObject, FALSE);
|
|
}
|
|
|
|
return(SaveStat);
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepConfigureSystemAuditing(
|
|
IN PSCE_PROFILE_INFO pScpInfo,
|
|
IN DWORD ConfigOptions
|
|
)
|
|
/* ++
|
|
|
|
Routine Description:
|
|
|
|
This routine configure the system security in the area of auditing which
|
|
includes event log setting, audit event setting, SACL for registry, and
|
|
SACL for files.
|
|
|
|
Arguments:
|
|
|
|
scpInfo - The buffer which contains SCP info loaded from the INF file
|
|
|
|
Return value:
|
|
|
|
SCESTATUS_SUCCESS
|
|
SCESTATUS_NOT_ENOUGH_RESOURCE
|
|
SCESTATUS_INVALID_PARAMETER
|
|
SCESTATUS_OTHER_ERROR
|
|
|
|
-- */
|
|
{
|
|
DWORD rc = NO_ERROR;
|
|
DWORD Saverc = NO_ERROR;
|
|
DWORD MaxSize=0;
|
|
DWORD Retention=0;
|
|
DWORD RestrictGuest=0;
|
|
DWORD OldMaxSize,OldRetention,OldGuest;
|
|
DWORD AuditLogRetentionPeriod, RetentionDays;
|
|
TCHAR MsgBuf[256];
|
|
DWORD i;
|
|
BOOL bFlagSet=FALSE;
|
|
|
|
PCWSTR szAuditSection=NULL;
|
|
PSCESECTION hSectionDomain=NULL;
|
|
PSCESECTION hSectionTattoo=NULL;
|
|
|
|
//
|
|
// Set audit log information. Audit Log settings are saved in the Registry
|
|
// under System\CurrentControlSet\Services\EventLog\<LogName>\MaxSize and Retention
|
|
//
|
|
|
|
for ( i=0; i<3; i++) {
|
|
|
|
if ( pScpInfo->MaximumLogSize[i] == SCE_NO_VALUE )
|
|
MaxSize = SCE_NO_VALUE;
|
|
else
|
|
MaxSize = (pScpInfo->MaximumLogSize[i] - (pScpInfo->MaximumLogSize[i] % 64 )) * 1024;
|
|
|
|
switch ( pScpInfo->AuditLogRetentionPeriod[i] ) {
|
|
case SCE_NO_VALUE:
|
|
Retention = SCE_NO_VALUE;
|
|
break;
|
|
case 2: // manually
|
|
Retention = MAXULONG;
|
|
break;
|
|
case 1: // number of days * seconds/day
|
|
if ( pScpInfo->RetentionDays[i] == SCE_NO_VALUE ) {
|
|
Retention = SCE_NO_VALUE;
|
|
} else {
|
|
Retention = pScpInfo->RetentionDays[i] * 24 * 3600;
|
|
}
|
|
break;
|
|
case 0: // as needed
|
|
Retention = 0;
|
|
break;
|
|
}
|
|
|
|
if ( pScpInfo->RestrictGuestAccess[i] == SCE_NO_VALUE )
|
|
RestrictGuest = SCE_NO_VALUE;
|
|
else
|
|
RestrictGuest = (pScpInfo->RestrictGuestAccess[i])? 1 : 0;
|
|
//
|
|
// Different logs have different keys in Registry
|
|
//
|
|
if ( MaxSize != SCE_NO_VALUE || Retention != SCE_NO_VALUE ||
|
|
RestrictGuest != SCE_NO_VALUE ) {
|
|
|
|
bFlagSet = TRUE;
|
|
|
|
switch (i) {
|
|
case 0:
|
|
wcscpy(MsgBuf,L"System\\CurrentControlSet\\Services\\EventLog\\System");
|
|
szAuditSection = szAuditSystemLog;
|
|
break;
|
|
case 1:
|
|
|
|
wcscpy(MsgBuf,L"System\\CurrentControlSet\\Services\\EventLog\\Security");
|
|
szAuditSection = szAuditSecurityLog;
|
|
break;
|
|
default:
|
|
|
|
wcscpy(MsgBuf,L"System\\CurrentControlSet\\Services\\EventLog\\Application");
|
|
szAuditSection = szAuditApplicationLog;
|
|
break;
|
|
}
|
|
|
|
WCHAR StrBuf[2];
|
|
_itow(i, StrBuf, 10);
|
|
|
|
//
|
|
// open policy sections
|
|
//
|
|
if ( ConfigOptions & SCE_POLICY_TEMPLATE ) {
|
|
|
|
ScepTattooOpenPolicySections(
|
|
hProfile,
|
|
szAuditSection,
|
|
&hSectionDomain,
|
|
&hSectionTattoo
|
|
);
|
|
OldMaxSize=0;
|
|
OldRetention=0;
|
|
OldGuest=0;
|
|
}
|
|
|
|
if ( MaxSize != SCE_NO_VALUE ) {
|
|
|
|
if ( ConfigOptions & SCE_POLICY_TEMPLATE ||
|
|
ConfigOptions & SCE_PROMOTE_FLAG_REPLICA ) {
|
|
|
|
//
|
|
// query existing value
|
|
//
|
|
if ( ERROR_SUCCESS != ScepRegQueryIntValue(HKEY_LOCAL_MACHINE,
|
|
MsgBuf,
|
|
L"MaxSize",
|
|
&OldMaxSize
|
|
) )
|
|
OldMaxSize = SCE_NO_VALUE;
|
|
else
|
|
OldMaxSize /= 1024;
|
|
}
|
|
|
|
//
|
|
// on DC Promo, do not reduce the log size if already higher
|
|
//
|
|
|
|
if ( !(ConfigOptions & SCE_PROMOTE_FLAG_REPLICA) ||
|
|
((ConfigOptions & SCE_PROMOTE_FLAG_REPLICA) && (OldMaxSize * 1024 < MaxSize))) {
|
|
|
|
rc = ScepRegSetIntValue( HKEY_LOCAL_MACHINE,
|
|
MsgBuf,
|
|
L"MaxSize",
|
|
MaxSize
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// compare and set if different
|
|
//
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
(OldMaxSize != SCE_NO_VALUE) ) {
|
|
|
|
// even if OldMaxSize = MaxSize, we still need to check if the tattoo value should be deleted
|
|
ScepTattooManageOneIntValue(
|
|
hSectionDomain,
|
|
hSectionTattoo,
|
|
L"MaximumLogSize",
|
|
0,
|
|
OldMaxSize,
|
|
rc
|
|
);
|
|
}
|
|
|
|
if (ConfigOptions & SCE_RSOP_CALLBACK)
|
|
|
|
ScepRsopLog(SCE_RSOP_AUDIT_LOG_MAXSIZE_INFO, rc, StrBuf,0,0);
|
|
}
|
|
|
|
if ( rc == SCESTATUS_SUCCESS && Retention != SCE_NO_VALUE ) {
|
|
|
|
if ( ConfigOptions & SCE_POLICY_TEMPLATE ) {
|
|
|
|
//
|
|
// query existing value
|
|
//
|
|
if ( ERROR_SUCCESS == ScepRegQueryIntValue(HKEY_LOCAL_MACHINE,
|
|
MsgBuf,
|
|
L"Retention",
|
|
&OldRetention
|
|
) ) {
|
|
switch ( OldRetention ) {
|
|
case MAXULONG: // manually
|
|
AuditLogRetentionPeriod = 2;
|
|
RetentionDays = SCE_NO_VALUE;
|
|
break;
|
|
case 0:
|
|
AuditLogRetentionPeriod = 0;
|
|
RetentionDays = SCE_NO_VALUE;
|
|
break;
|
|
default:
|
|
AuditLogRetentionPeriod = 1;
|
|
|
|
// number of days * seconds/day
|
|
RetentionDays = OldRetention / (24 * 3600);
|
|
break;
|
|
}
|
|
} else {
|
|
AuditLogRetentionPeriod = SCE_NO_VALUE;
|
|
RetentionDays = SCE_NO_VALUE;
|
|
}
|
|
}
|
|
|
|
rc = ScepRegSetIntValue( HKEY_LOCAL_MACHINE,
|
|
MsgBuf,
|
|
L"Retention",
|
|
Retention
|
|
);
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
(OldRetention != SCE_NO_VALUE) ) {
|
|
|
|
//
|
|
// handle the RetentionDays first since
|
|
// it depends on auditlogretentionperiod
|
|
//
|
|
if ( RetentionDays != SCE_NO_VALUE ||
|
|
pScpInfo->RetentionDays[i] != SCE_NO_VALUE ) {
|
|
|
|
ScepTattooManageOneIntValueWithDependency(
|
|
hSectionDomain,
|
|
hSectionTattoo,
|
|
L"AuditLogRetentionPeriod",
|
|
0,
|
|
L"RetentionDays",
|
|
RetentionDays,
|
|
rc
|
|
);
|
|
}
|
|
|
|
ScepTattooManageOneIntValue(
|
|
hSectionDomain,
|
|
hSectionTattoo,
|
|
L"AuditLogRetentionPeriod",
|
|
0,
|
|
AuditLogRetentionPeriod,
|
|
rc
|
|
);
|
|
}
|
|
if (ConfigOptions & SCE_RSOP_CALLBACK)
|
|
|
|
ScepRsopLog(SCE_RSOP_AUDIT_LOG_RETENTION_INFO, rc, StrBuf,0,0);
|
|
}
|
|
if ( rc == SCESTATUS_SUCCESS && RestrictGuest != SCE_NO_VALUE ) {
|
|
|
|
if ( ConfigOptions & SCE_POLICY_TEMPLATE ) {
|
|
|
|
//
|
|
// query existing value
|
|
//
|
|
if ( ERROR_SUCCESS != ScepRegQueryIntValue(HKEY_LOCAL_MACHINE,
|
|
MsgBuf,
|
|
L"RestrictGuestAccess",
|
|
&OldGuest
|
|
) )
|
|
OldGuest = SCE_NO_VALUE;
|
|
}
|
|
|
|
rc = ScepRegSetIntValue( HKEY_LOCAL_MACHINE,
|
|
MsgBuf,
|
|
L"RestrictGuestAccess",
|
|
RestrictGuest
|
|
);
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
(OldGuest != SCE_NO_VALUE) ) {
|
|
|
|
ScepTattooManageOneIntValue(
|
|
hSectionDomain,
|
|
hSectionTattoo,
|
|
L"RestrictGuestAccess",
|
|
0,
|
|
OldGuest,
|
|
rc
|
|
);
|
|
}
|
|
if (ConfigOptions & SCE_RSOP_CALLBACK)
|
|
|
|
ScepRsopLog(SCE_RSOP_AUDIT_LOG_GUEST_INFO, rc, StrBuf,0,0);
|
|
}
|
|
|
|
if ( hSectionDomain ) {
|
|
SceJetCloseSection(&hSectionDomain, TRUE);
|
|
hSectionDomain = NULL;
|
|
}
|
|
|
|
if ( hSectionTattoo ) {
|
|
SceJetCloseSection(&hSectionTattoo, TRUE);
|
|
hSectionTattoo = NULL;
|
|
}
|
|
}
|
|
|
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|
Saverc = rc;
|
|
ScepLogOutput3( 1, rc, SCEDLL_SCP_ERROR_LOGSETTINGS);
|
|
}
|
|
}
|
|
|
|
if ( Saverc == SCESTATUS_SUCCESS && bFlagSet )
|
|
ScepLogOutput3(1,0, SCEDLL_SCP_LOGSETTINGS);
|
|
|
|
return(Saverc);
|
|
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepConfigureAuditEvent(
|
|
IN PSCE_PROFILE_INFO pScpInfo,
|
|
IN PPOLICY_AUDIT_EVENTS_INFO auditEvent,
|
|
IN DWORD Options,
|
|
IN LSA_HANDLE PolicyHandle OPTIONAL
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
LSA_HANDLE lsaHandle=NULL;
|
|
DWORD rc = NO_ERROR;
|
|
DWORD Saverc = NO_ERROR;
|
|
// POLICY_AUDIT_FULL_SET_INFO AuditFullSet;
|
|
PPOLICY_AUDIT_FULL_QUERY_INFO AuditFullQry=NULL;
|
|
ULONG i;
|
|
ULONG dwAudit;
|
|
|
|
SCE_TATTOO_KEYS *pTattooKeys=NULL;
|
|
DWORD cTattooKeys=0;
|
|
|
|
PSCESECTION hSectionDomain=NULL;
|
|
PSCESECTION hSectionTattoo=NULL;
|
|
|
|
#define MAX_AUDIT_KEYS 9
|
|
|
|
|
|
if ( (Options & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() ) {
|
|
|
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|
}
|
|
|
|
if ( PolicyHandle == NULL ) {
|
|
|
|
//
|
|
// Set audit event information using LSA APIs
|
|
//
|
|
status = ScepOpenLsaPolicy(
|
|
POLICY_VIEW_AUDIT_INFORMATION |
|
|
POLICY_SET_AUDIT_REQUIREMENTS |
|
|
POLICY_AUDIT_LOG_ADMIN,
|
|
&lsaHandle,
|
|
( Options & (SCE_POLICY_TEMPLATE | SCE_SYSTEM_DB) ) ? TRUE : FALSE // do not notify policy filter if within policy prop
|
|
);
|
|
|
|
if (status != ERROR_SUCCESS) {
|
|
|
|
lsaHandle = NULL;
|
|
rc = RtlNtStatusToDosError( status );
|
|
|
|
ScepLogOutput3( 1, rc, SCEDLL_LSA_POLICY);
|
|
|
|
if (Options & SCE_RSOP_CALLBACK)
|
|
|
|
ScepRsopLog(SCE_RSOP_AUDIT_EVENT_INFO, rc, NULL,0,0);
|
|
|
|
return(ScepDosErrorToSceStatus(rc));
|
|
}
|
|
|
|
} else {
|
|
lsaHandle = PolicyHandle;
|
|
}
|
|
|
|
if ( (Options & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) ) {
|
|
//
|
|
// save off the current auditing settings
|
|
//
|
|
pTattooKeys = (SCE_TATTOO_KEYS *)ScepAlloc(LPTR,MAX_AUDIT_KEYS*sizeof(SCE_TATTOO_KEYS));
|
|
|
|
if ( !pTattooKeys ) {
|
|
ScepLogOutput3(1, ERROR_NOT_ENOUGH_MEMORY, SCESRV_POLICY_TATTOO_ERROR_CREATE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set audit event information
|
|
//
|
|
|
|
if ( !auditEvent->AuditingMode ) {
|
|
// reset the event array
|
|
for ( i=0; i<auditEvent->MaximumAuditEventCount; i++ )
|
|
auditEvent->EventAuditingOptions[i] = POLICY_AUDIT_EVENT_NONE;
|
|
}
|
|
//
|
|
// process each event
|
|
//
|
|
i=0;
|
|
if ( (pScpInfo->AuditSystemEvents != SCE_NO_VALUE) ) {
|
|
|
|
dwAudit = (auditEvent->EventAuditingOptions[AuditCategorySystem] & ~POLICY_AUDIT_EVENT_NONE );
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"AuditSystemEvents", Options,
|
|
dwAudit );
|
|
|
|
if ( (pScpInfo->AuditSystemEvents != dwAudit) ) {
|
|
|
|
auditEvent->EventAuditingOptions[AuditCategorySystem] =
|
|
(pScpInfo->AuditSystemEvents & POLICY_AUDIT_EVENT_SUCCESS) |
|
|
(pScpInfo->AuditSystemEvents & POLICY_AUDIT_EVENT_FAILURE) |
|
|
POLICY_AUDIT_EVENT_NONE;
|
|
i=1;
|
|
}
|
|
}
|
|
|
|
if ( (pScpInfo->AuditLogonEvents != SCE_NO_VALUE) ) {
|
|
|
|
dwAudit = (auditEvent->EventAuditingOptions[AuditCategoryLogon] & ~POLICY_AUDIT_EVENT_NONE );
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"AuditLogonEvents", Options,
|
|
dwAudit );
|
|
|
|
if ( (pScpInfo->AuditLogonEvents != dwAudit) ) {
|
|
|
|
auditEvent->EventAuditingOptions[AuditCategoryLogon] =
|
|
(pScpInfo->AuditLogonEvents & POLICY_AUDIT_EVENT_SUCCESS) |
|
|
(pScpInfo->AuditLogonEvents & POLICY_AUDIT_EVENT_FAILURE) |
|
|
POLICY_AUDIT_EVENT_NONE;
|
|
i=1;
|
|
}
|
|
}
|
|
|
|
if ( (pScpInfo->AuditObjectAccess != SCE_NO_VALUE) ) {
|
|
|
|
dwAudit = (auditEvent->EventAuditingOptions[AuditCategoryObjectAccess] & ~POLICY_AUDIT_EVENT_NONE );
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"AuditObjectAccess", Options,
|
|
dwAudit );
|
|
|
|
if ( (pScpInfo->AuditObjectAccess != dwAudit) ) {
|
|
|
|
auditEvent->EventAuditingOptions[AuditCategoryObjectAccess] =
|
|
(pScpInfo->AuditObjectAccess & POLICY_AUDIT_EVENT_SUCCESS) |
|
|
(pScpInfo->AuditObjectAccess & POLICY_AUDIT_EVENT_FAILURE) |
|
|
POLICY_AUDIT_EVENT_NONE;
|
|
i=1;
|
|
}
|
|
}
|
|
|
|
if ( (pScpInfo->AuditPrivilegeUse != SCE_NO_VALUE) ) {
|
|
|
|
dwAudit = (auditEvent->EventAuditingOptions[AuditCategoryPrivilegeUse] & ~POLICY_AUDIT_EVENT_NONE );
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"AuditPrivilegeUse", Options,
|
|
dwAudit );
|
|
|
|
if ( (pScpInfo->AuditPrivilegeUse != dwAudit) ) {
|
|
|
|
auditEvent->EventAuditingOptions[AuditCategoryPrivilegeUse] =
|
|
(pScpInfo->AuditPrivilegeUse & POLICY_AUDIT_EVENT_SUCCESS) |
|
|
(pScpInfo->AuditPrivilegeUse & POLICY_AUDIT_EVENT_FAILURE) |
|
|
POLICY_AUDIT_EVENT_NONE;
|
|
i=1;
|
|
}
|
|
}
|
|
|
|
if ( (pScpInfo->AuditProcessTracking != SCE_NO_VALUE) ) {
|
|
|
|
dwAudit = (auditEvent->EventAuditingOptions[AuditCategoryDetailedTracking] & ~POLICY_AUDIT_EVENT_NONE );
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"AuditProcessTracking", Options,
|
|
dwAudit );
|
|
|
|
if ( (pScpInfo->AuditProcessTracking != dwAudit) ) {
|
|
|
|
auditEvent->EventAuditingOptions[AuditCategoryDetailedTracking] =
|
|
(pScpInfo->AuditProcessTracking & POLICY_AUDIT_EVENT_SUCCESS) |
|
|
(pScpInfo->AuditProcessTracking & POLICY_AUDIT_EVENT_FAILURE) |
|
|
POLICY_AUDIT_EVENT_NONE;
|
|
i=1;
|
|
}
|
|
}
|
|
|
|
if ( (pScpInfo->AuditPolicyChange != SCE_NO_VALUE) ) {
|
|
|
|
dwAudit = (auditEvent->EventAuditingOptions[AuditCategoryPolicyChange] & ~POLICY_AUDIT_EVENT_NONE );
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"AuditPolicyChange", Options,
|
|
dwAudit );
|
|
|
|
if ( (pScpInfo->AuditPolicyChange != dwAudit) ) {
|
|
|
|
auditEvent->EventAuditingOptions[AuditCategoryPolicyChange] =
|
|
(pScpInfo->AuditPolicyChange & POLICY_AUDIT_EVENT_SUCCESS) |
|
|
(pScpInfo->AuditPolicyChange & POLICY_AUDIT_EVENT_FAILURE) |
|
|
POLICY_AUDIT_EVENT_NONE;
|
|
i=1;
|
|
}
|
|
}
|
|
|
|
if ( (pScpInfo->AuditAccountManage != SCE_NO_VALUE) ) {
|
|
|
|
dwAudit = (auditEvent->EventAuditingOptions[AuditCategoryAccountManagement] & ~POLICY_AUDIT_EVENT_NONE );
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"AuditAccountManage", Options,
|
|
dwAudit );
|
|
|
|
if ( (pScpInfo->AuditAccountManage != dwAudit) ) {
|
|
|
|
auditEvent->EventAuditingOptions[AuditCategoryAccountManagement] =
|
|
(pScpInfo->AuditAccountManage & POLICY_AUDIT_EVENT_SUCCESS) |
|
|
(pScpInfo->AuditAccountManage & POLICY_AUDIT_EVENT_FAILURE) |
|
|
POLICY_AUDIT_EVENT_NONE;
|
|
i=1;
|
|
}
|
|
}
|
|
|
|
if ( (pScpInfo->AuditDSAccess != SCE_NO_VALUE) ) {
|
|
|
|
dwAudit = (auditEvent->EventAuditingOptions[AuditCategoryDirectoryServiceAccess] & ~POLICY_AUDIT_EVENT_NONE );
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"AuditDSAccess", Options,
|
|
dwAudit );
|
|
|
|
if ( (pScpInfo->AuditDSAccess != dwAudit) ) {
|
|
|
|
auditEvent->EventAuditingOptions[AuditCategoryDirectoryServiceAccess] =
|
|
(pScpInfo->AuditDSAccess & POLICY_AUDIT_EVENT_SUCCESS) |
|
|
(pScpInfo->AuditDSAccess & POLICY_AUDIT_EVENT_FAILURE) |
|
|
POLICY_AUDIT_EVENT_NONE;
|
|
i=1;
|
|
}
|
|
}
|
|
|
|
if ( (pScpInfo->AuditAccountLogon != SCE_NO_VALUE) ) {
|
|
|
|
dwAudit = (auditEvent->EventAuditingOptions[AuditCategoryAccountLogon] & ~POLICY_AUDIT_EVENT_NONE );
|
|
ScepTattooCheckAndUpdateArray(pTattooKeys, &cTattooKeys,
|
|
(PWSTR)L"AuditAccountLogon", Options,
|
|
dwAudit );
|
|
|
|
if ( (pScpInfo->AuditAccountLogon != dwAudit) ) {
|
|
|
|
auditEvent->EventAuditingOptions[AuditCategoryAccountLogon] =
|
|
(pScpInfo->AuditAccountLogon & POLICY_AUDIT_EVENT_SUCCESS) |
|
|
(pScpInfo->AuditAccountLogon & POLICY_AUDIT_EVENT_FAILURE) |
|
|
POLICY_AUDIT_EVENT_NONE;
|
|
i=1;
|
|
}
|
|
}
|
|
|
|
if ( i ) {
|
|
//
|
|
// there are some settings to configure
|
|
//
|
|
auditEvent->AuditingMode = FALSE;
|
|
for ( i=0; i<auditEvent->MaximumAuditEventCount; i++ ) {
|
|
if ( auditEvent->EventAuditingOptions[i] & ~POLICY_AUDIT_EVENT_NONE ) {
|
|
auditEvent->AuditingMode = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
status = LsaSetInformationPolicy( lsaHandle,
|
|
PolicyAuditEventsInformation,
|
|
(PVOID)auditEvent
|
|
);
|
|
rc = RtlNtStatusToDosError( status );
|
|
|
|
if ( rc != NO_ERROR ) {
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_ERROR_EVENT_AUDITING);
|
|
|
|
Saverc = rc;
|
|
} else {
|
|
ScepLogOutput3(1, 0, SCEDLL_SCP_EVENT_AUDITING);
|
|
}
|
|
//
|
|
// turn the mode off so auditing won't be "restored" at the end of configuration
|
|
//
|
|
|
|
auditEvent->AuditingMode = FALSE;
|
|
}
|
|
|
|
if ( (Options & SCE_POLICY_TEMPLATE) &&
|
|
( ProductType != NtProductLanManNt ) &&
|
|
pTattooKeys && cTattooKeys ) {
|
|
|
|
ScepTattooOpenPolicySections(
|
|
hProfile,
|
|
szAuditEvent,
|
|
&hSectionDomain,
|
|
&hSectionTattoo
|
|
);
|
|
//
|
|
// some policy is different than the system setting
|
|
// check if we should save the existing setting as the tattoo value
|
|
// also remove reset'ed tattoo policy
|
|
//
|
|
ScepLogOutput3(3,0,SCESRV_POLICY_TATTOO_ARRAY,cTattooKeys);
|
|
|
|
ScepTattooManageValues(hSectionDomain, hSectionTattoo, pTattooKeys, cTattooKeys, rc);
|
|
|
|
if ( hSectionDomain ) SceJetCloseSection(&hSectionDomain,TRUE);
|
|
if ( hSectionTattoo ) SceJetCloseSection(&hSectionTattoo,TRUE);
|
|
|
|
}
|
|
|
|
if ( pTattooKeys )
|
|
ScepFree(pTattooKeys);
|
|
|
|
if (Options & SCE_RSOP_CALLBACK)
|
|
|
|
ScepRsopLog(SCE_RSOP_AUDIT_EVENT_INFO, rc, NULL,0,0);
|
|
|
|
if ( lsaHandle && (PolicyHandle != lsaHandle) )
|
|
LsaClose( lsaHandle );
|
|
|
|
return(ScepDosErrorToSceStatus(Saverc));
|
|
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepConfigureDeInitialize(
|
|
IN SCESTATUS rc,
|
|
IN AREA_INFORMATION Area
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine de-initialize the SCP engine. The operations include
|
|
|
|
clear SCE_PROFILE_INFO buffer and close the SCP profile
|
|
close the error log file
|
|
reset the status
|
|
|
|
Arguments:
|
|
|
|
rc - SCESTATUS error code (from other routines)
|
|
|
|
Area - one or more area configured
|
|
|
|
Return value:
|
|
|
|
SCESTATUS error code
|
|
|
|
++*/
|
|
{
|
|
if ( rc == SCESTATUS_ALREADY_RUNNING ) {
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// free LSA handle
|
|
//
|
|
if ( LsaPrivatePolicy ) {
|
|
|
|
ScepNotifyLogPolicy(0, TRUE, L"Policy Prop: Private LSA handle is to be released", 0, 0, NULL );
|
|
|
|
LsaClose(LsaPrivatePolicy);
|
|
LsaPrivatePolicy = NULL;
|
|
|
|
}
|
|
|
|
//
|
|
// Free memory and close the SCP profile
|
|
//
|
|
|
|
SceFreeMemory( (PVOID)pScpInfo, Area );
|
|
|
|
cbClientFlag = 0;
|
|
gTotalTicks = 0;
|
|
gCurrentTicks = 0;
|
|
gWarningCode = 0;
|
|
|
|
if ( hProfile != NULL ) {
|
|
|
|
SceJetCloseFile( hProfile, TRUE, FALSE );
|
|
}
|
|
|
|
hProfile = NULL;
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
|
|
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepDeleteInfoForAreas(
|
|
IN PSCECONTEXT hProfile,
|
|
IN SCETYPE tblType,
|
|
IN AREA_INFORMATION Area
|
|
)
|
|
{
|
|
SCESTATUS saveRc=SCESTATUS_SUCCESS, rc;
|
|
PSCE_SERVICES pServices=NULL, pNode;
|
|
PSCE_NAME_LIST pList=NULL, pnl;
|
|
|
|
if ( Area & AREA_SECURITY_POLICY ) {
|
|
//
|
|
// delete szSystemAccess section info
|
|
//
|
|
rc = ScepDeleteOneSection(
|
|
hProfile,
|
|
tblType,
|
|
szSystemAccess
|
|
);
|
|
if ( saveRc == SCESTATUS_SUCCESS )
|
|
saveRc = rc;
|
|
|
|
//
|
|
// delete szAuditSystemLog section info
|
|
//
|
|
rc = ScepDeleteOneSection(
|
|
hProfile,
|
|
tblType,
|
|
szAuditSystemLog
|
|
);
|
|
if ( saveRc == SCESTATUS_SUCCESS )
|
|
saveRc = rc;
|
|
|
|
//
|
|
// delete szAuditSecurityLog section info
|
|
//
|
|
rc = ScepDeleteOneSection(
|
|
hProfile,
|
|
tblType,
|
|
szAuditSecurityLog
|
|
);
|
|
if ( saveRc == SCESTATUS_SUCCESS )
|
|
saveRc = rc;
|
|
|
|
//
|
|
// delete szAuditApplicationLog section info
|
|
//
|
|
rc = ScepDeleteOneSection(
|
|
hProfile,
|
|
tblType,
|
|
szAuditApplicationLog
|
|
);
|
|
if ( saveRc == SCESTATUS_SUCCESS )
|
|
saveRc = rc;
|
|
|
|
//
|
|
// delete szAuditEvent section info
|
|
//
|
|
rc = ScepDeleteOneSection(
|
|
hProfile,
|
|
tblType,
|
|
szAuditEvent
|
|
);
|
|
if ( saveRc == SCESTATUS_SUCCESS )
|
|
saveRc = rc;
|
|
|
|
//
|
|
// delete szKerberosPolicy section info
|
|
//
|
|
rc = ScepDeleteOneSection(
|
|
hProfile,
|
|
tblType,
|
|
szKerberosPolicy
|
|
);
|
|
if ( saveRc == SCESTATUS_SUCCESS )
|
|
saveRc = rc;
|
|
|
|
//
|
|
// delete szRegistryValues section info
|
|
//
|
|
rc = ScepDeleteOneSection(
|
|
hProfile,
|
|
tblType,
|
|
szRegistryValues
|
|
);
|
|
if ( saveRc == SCESTATUS_SUCCESS )
|
|
saveRc = rc;
|
|
|
|
//
|
|
// delete each attachment's sections
|
|
//
|
|
rc = ScepEnumServiceEngines( &pServices, SCE_ATTACHMENT_POLICY );
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
for ( pNode = pServices; pNode != NULL; pNode=pNode->Next ) {
|
|
|
|
rc = ScepDeleteOneSection(
|
|
hProfile,
|
|
tblType,
|
|
(PCWSTR)(pNode->ServiceName)
|
|
);
|
|
|
|
if ( saveRc == SCESTATUS_SUCCESS )
|
|
saveRc = rc;
|
|
}
|
|
|
|
SceFreePSCE_SERVICES( pServices );
|
|
|
|
} else if ( rc != SCESTATUS_PROFILE_NOT_FOUND &&
|
|
rc != SCESTATUS_RECORD_NOT_FOUND &&
|
|
saveRc == SCESTATUS_SUCCESS ) {
|
|
saveRc = rc;
|
|
}
|
|
|
|
}
|
|
|
|
if ( Area & AREA_PRIVILEGES ) {
|
|
//
|
|
// delete szPrivilegeRights section info
|
|
//
|
|
rc = ScepDeleteOneSection(
|
|
hProfile,
|
|
tblType,
|
|
szPrivilegeRights
|
|
);
|
|
if ( saveRc == SCESTATUS_SUCCESS )
|
|
saveRc = rc;
|
|
|
|
}
|
|
if ( Area & AREA_GROUP_MEMBERSHIP ) {
|
|
|
|
//
|
|
// delete szGroupMembership section info
|
|
//
|
|
rc = ScepDeleteOneSection(
|
|
hProfile,
|
|
tblType,
|
|
szGroupMembership
|
|
);
|
|
if ( saveRc == SCESTATUS_SUCCESS )
|
|
saveRc = rc;
|
|
}
|
|
|
|
if ( Area & AREA_USER_SETTINGS ) {
|
|
//
|
|
// later - delete the list of profiles/users first
|
|
//
|
|
|
|
//
|
|
// delete szAccountProfiles/szUserList section info
|
|
//
|
|
if ( tblType == SCEJET_TABLE_SAP) {
|
|
rc = ScepDeleteOneSection(
|
|
hProfile,
|
|
tblType,
|
|
szUserList
|
|
);
|
|
} else {
|
|
rc = ScepDeleteOneSection(
|
|
hProfile,
|
|
tblType,
|
|
szAccountProfiles
|
|
);
|
|
}
|
|
if ( saveRc == SCESTATUS_SUCCESS )
|
|
saveRc = rc;
|
|
}
|
|
|
|
if ( Area & AREA_FILE_SECURITY ) {
|
|
|
|
//
|
|
// delete szFileSecurity section info
|
|
//
|
|
rc = ScepDeleteOneSection(
|
|
hProfile,
|
|
tblType,
|
|
szFileSecurity
|
|
);
|
|
if ( saveRc == SCESTATUS_SUCCESS )
|
|
saveRc = rc;
|
|
}
|
|
|
|
if ( Area & AREA_REGISTRY_SECURITY ) {
|
|
|
|
//
|
|
// delete szRegistryKeys section info
|
|
//
|
|
rc = ScepDeleteOneSection(
|
|
hProfile,
|
|
tblType,
|
|
szRegistryKeys
|
|
);
|
|
if ( saveRc == SCESTATUS_SUCCESS )
|
|
saveRc = rc;
|
|
}
|
|
|
|
if ( Area & AREA_DS_OBJECTS ) {
|
|
|
|
//
|
|
// delete szDSSecurity section info
|
|
//
|
|
rc = ScepDeleteOneSection(
|
|
hProfile,
|
|
tblType,
|
|
szDSSecurity
|
|
);
|
|
if ( saveRc == SCESTATUS_SUCCESS )
|
|
saveRc = rc;
|
|
}
|
|
|
|
if ( Area & AREA_SYSTEM_SERVICE ) {
|
|
|
|
//
|
|
// delete szServiceGeneral section info
|
|
//
|
|
rc = ScepDeleteOneSection(
|
|
hProfile,
|
|
tblType,
|
|
szServiceGeneral
|
|
);
|
|
if ( saveRc == SCESTATUS_SUCCESS )
|
|
saveRc = rc;
|
|
//
|
|
// delete each attachment's sections
|
|
//
|
|
rc = ScepEnumServiceEngines( &pServices, SCE_ATTACHMENT_SERVICE );
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
for ( pNode = pServices; pNode != NULL; pNode=pNode->Next ) {
|
|
|
|
rc = ScepDeleteOneSection(
|
|
hProfile,
|
|
tblType,
|
|
(PCWSTR)(pNode->ServiceName)
|
|
);
|
|
|
|
if ( saveRc == SCESTATUS_SUCCESS )
|
|
saveRc = rc;
|
|
}
|
|
|
|
SceFreePSCE_SERVICES( pServices );
|
|
|
|
} else if ( rc != SCESTATUS_PROFILE_NOT_FOUND &&
|
|
rc != SCESTATUS_RECORD_NOT_FOUND &&
|
|
saveRc == SCESTATUS_SUCCESS ) {
|
|
saveRc = rc;
|
|
}
|
|
}
|
|
|
|
if ( Area & AREA_ATTACHMENTS ) {
|
|
//
|
|
// delete attachment sections
|
|
//
|
|
rc = ScepEnumAttachmentSections( hProfile, &pList);
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
for ( pnl = pList; pnl != NULL; pnl=pnl->Next ) {
|
|
|
|
rc = ScepDeleteOneSection(
|
|
hProfile,
|
|
tblType,
|
|
(PCWSTR)(pnl->Name)
|
|
);
|
|
|
|
if ( saveRc == SCESTATUS_SUCCESS )
|
|
saveRc = rc;
|
|
}
|
|
|
|
ScepFreeNameList( pList );
|
|
|
|
} else if ( rc != SCESTATUS_PROFILE_NOT_FOUND &&
|
|
rc != SCESTATUS_RECORD_NOT_FOUND &&
|
|
saveRc == SCESTATUS_SUCCESS ) {
|
|
saveRc = rc;
|
|
}
|
|
}
|
|
|
|
return(saveRc);
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepMakePolicyIntoFile(
|
|
IN DWORD Options,
|
|
IN AREA_INFORMATION Area
|
|
)
|
|
{
|
|
|
|
SCESTATUS rc=SCESTATUS_SUCCESS;
|
|
|
|
if ( Options & SCE_COPY_LOCAL_POLICY ) {
|
|
|
|
PSCE_PROFILE_INFO pTmpBuffer=NULL;
|
|
|
|
HINSTANCE hSceCliDll = LoadLibrary(TEXT("scecli.dll"));
|
|
|
|
if ( hSceCliDll) {
|
|
PFSCEINFWRITEINFO pfSceInfWriteInfo = (PFSCEINFWRITEINFO)GetProcAddress(
|
|
hSceCliDll,
|
|
"SceWriteSecurityProfileInfo");
|
|
if ( pfSceInfWriteInfo ) {
|
|
|
|
//
|
|
// have to query the current system setting for privileges
|
|
// because IIS/MTS accounts do not exist in our database
|
|
// we only support AREA_SECURITY_POLICY and AREA_PRIVILEGES
|
|
//
|
|
|
|
TCHAR FileName[MAX_PATH+50];
|
|
|
|
FileName[0] = L'\0';
|
|
GetSystemWindowsDirectory(FileName, MAX_PATH);
|
|
FileName[MAX_PATH] = L'\0';
|
|
|
|
DWORD WindirLen = wcslen(FileName);
|
|
|
|
if ( Area & AREA_SECURITY_POLICY ) {
|
|
|
|
//
|
|
// get other area's information (AREA_SECURITY_POLICY)
|
|
//
|
|
rc = ScepGetDatabaseInfo(
|
|
hProfile,
|
|
SCE_ENGINE_SMP,
|
|
AREA_SECURITY_POLICY,
|
|
0,
|
|
&pTmpBuffer,
|
|
NULL
|
|
);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
wcscat(FileName, L"\\security\\FirstDGPO.inf\0");
|
|
|
|
rc = ScepWriteOneAttributeToFile(szSystemAccess,
|
|
(LPCTSTR)FileName,
|
|
TEXT("MinimumPasswordAge"),
|
|
pTmpBuffer->MinimumPasswordAge
|
|
);
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
rc = ScepWriteOneAttributeToFile(szSystemAccess,
|
|
(LPCTSTR)FileName,
|
|
TEXT("MaximumPasswordAge"),
|
|
pTmpBuffer->MaximumPasswordAge
|
|
);
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
|
|
rc = ScepWriteOneAttributeToFile(szSystemAccess,
|
|
(LPCTSTR)FileName,
|
|
TEXT("MinimumPasswordLength"),
|
|
pTmpBuffer->MinimumPasswordLength
|
|
);
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
|
|
rc = ScepWriteOneAttributeToFile(szSystemAccess,
|
|
(LPCTSTR)FileName,
|
|
TEXT("PasswordComplexity"),
|
|
pTmpBuffer->PasswordComplexity
|
|
);
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
|
|
rc = ScepWriteOneAttributeToFile(szSystemAccess,
|
|
(LPCTSTR)FileName,
|
|
TEXT("PasswordHistorySize"),
|
|
pTmpBuffer->PasswordHistorySize
|
|
);
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
|
|
rc = ScepWriteOneAttributeToFile(szSystemAccess,
|
|
(LPCTSTR)FileName,
|
|
TEXT("LockoutBadCount"),
|
|
pTmpBuffer->LockoutBadCount
|
|
);
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
|
|
rc = ScepWriteOneAttributeToFile(szSystemAccess,
|
|
(LPCTSTR)FileName,
|
|
TEXT("ResetLockoutCount"),
|
|
pTmpBuffer->ResetLockoutCount
|
|
);
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
|
|
rc = ScepWriteOneAttributeToFile(szSystemAccess,
|
|
(LPCTSTR)FileName,
|
|
TEXT("LockoutDuration"),
|
|
pTmpBuffer->LockoutDuration
|
|
);
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
|
|
rc = ScepWriteOneAttributeToFile(szSystemAccess,
|
|
(LPCTSTR)FileName,
|
|
TEXT("RequireLogonToChangePassword"),
|
|
pTmpBuffer->RequireLogonToChangePassword
|
|
);
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
|
|
rc = ScepWriteOneAttributeToFile(szSystemAccess,
|
|
(LPCTSTR)FileName,
|
|
TEXT("ForceLogoffWhenHourExpire"),
|
|
pTmpBuffer->ForceLogoffWhenHourExpire
|
|
);
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
|
|
rc = ScepWriteOneAttributeToFile(szSystemAccess,
|
|
(LPCTSTR)FileName,
|
|
TEXT("ClearTextPassword"),
|
|
pTmpBuffer->ClearTextPassword
|
|
);
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == rc && pTmpBuffer->pKerberosInfo ) {
|
|
|
|
rc = ScepWriteOneAttributeToFile(szKerberosPolicy,
|
|
(LPCTSTR)FileName,
|
|
TEXT("MaxTicketAge"),
|
|
pTmpBuffer->pKerberosInfo->MaxTicketAge
|
|
);
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
rc = ScepWriteOneAttributeToFile(szKerberosPolicy,
|
|
(LPCTSTR)FileName,
|
|
TEXT("MaxRenewAge"),
|
|
pTmpBuffer->pKerberosInfo->MaxRenewAge
|
|
);
|
|
}
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
rc = ScepWriteOneAttributeToFile(szKerberosPolicy,
|
|
(LPCTSTR)FileName,
|
|
TEXT("MaxServiceAge"),
|
|
pTmpBuffer->pKerberosInfo->MaxServiceAge
|
|
);
|
|
}
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
rc = ScepWriteOneAttributeToFile(szKerberosPolicy,
|
|
(LPCTSTR)FileName,
|
|
TEXT("MaxClockSkew"),
|
|
pTmpBuffer->pKerberosInfo->MaxClockSkew
|
|
);
|
|
}
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
rc = ScepWriteOneAttributeToFile(szKerberosPolicy,
|
|
(LPCTSTR)FileName,
|
|
TEXT("TicketValidateClient"),
|
|
pTmpBuffer->pKerberosInfo->TicketValidateClient
|
|
);
|
|
}
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
//
|
|
// make sure to delete the local policy sections
|
|
//
|
|
WritePrivateProfileSection(
|
|
szAuditSystemLog,
|
|
NULL,
|
|
(LPCTSTR)FileName);
|
|
|
|
WritePrivateProfileSection(
|
|
szAuditSecurityLog,
|
|
NULL,
|
|
(LPCTSTR)FileName);
|
|
|
|
WritePrivateProfileSection(
|
|
szAuditApplicationLog,
|
|
NULL,
|
|
(LPCTSTR)FileName);
|
|
|
|
WritePrivateProfileSection(
|
|
szAuditEvent,
|
|
NULL,
|
|
(LPCTSTR)FileName);
|
|
|
|
WritePrivateProfileSection(
|
|
szRegistryValues,
|
|
NULL,
|
|
(LPCTSTR)FileName);
|
|
|
|
|
|
}
|
|
|
|
ScepLogOutput3(1, rc, IDS_COPY_DOMAIN_GPO);
|
|
|
|
rc = ScepDosErrorToSceStatus(rc);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
wcscpy(FileName+WindirLen, L"\\security\\FirstOGPO.inf\0");
|
|
//
|
|
// do not write registry value section
|
|
//
|
|
DWORD RegValueCount;
|
|
PSCE_REGISTRY_VALUE_INFO pSaveRegValues;
|
|
|
|
RegValueCount = pTmpBuffer->RegValueCount;
|
|
pSaveRegValues = pTmpBuffer->aRegValues;
|
|
|
|
pTmpBuffer->RegValueCount = 0;
|
|
pTmpBuffer->aRegValues = NULL;
|
|
|
|
|
|
PSCE_PROFILE_INFO ExistingTemplateProfileInfo = NULL;
|
|
|
|
//
|
|
// need to get existing information for registry values from default DC GPO
|
|
//
|
|
|
|
rc = ScepGetTemplateInformation(FileName,
|
|
AREA_SECURITY_POLICY,
|
|
hSceCliDll,
|
|
&ExistingTemplateProfileInfo);
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
rc = (*pfSceInfWriteInfo)(
|
|
FileName,
|
|
AREA_SECURITY_POLICY,
|
|
pTmpBuffer,
|
|
NULL
|
|
);
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
SCE_PROFILE_INFO SystemInfo;
|
|
|
|
memset (&SystemInfo , 0, sizeof(SCE_PROFILE_INFO));
|
|
|
|
rc = ScepAnalyzeRegistryValues(NULL,
|
|
SCEREG_VALUE_SYSTEM,
|
|
&SystemInfo
|
|
);
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
ScepWriteSpecialRegistryValuesIntoPolicy(FileName, ExistingTemplateProfileInfo, SystemInfo.aRegValues, SystemInfo.RegValueCount);
|
|
|
|
SceFreeMemory((PVOID)&SystemInfo, AREA_SECURITY_POLICY);
|
|
}
|
|
|
|
}
|
|
|
|
SceFreeMemory((PVOID)ExistingTemplateProfileInfo, AREA_SECURITY_POLICY);
|
|
|
|
ScepFree(ExistingTemplateProfileInfo);
|
|
|
|
}
|
|
|
|
//
|
|
// restore the buffer
|
|
//
|
|
|
|
pTmpBuffer->RegValueCount = RegValueCount;
|
|
pTmpBuffer->aRegValues = pSaveRegValues;
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
//
|
|
// delete the domain policy sections from this file
|
|
//
|
|
WritePrivateProfileSection(
|
|
szSystemAccess,
|
|
NULL,
|
|
(LPCTSTR)FileName);
|
|
|
|
WritePrivateProfileSection(
|
|
szKerberosPolicy,
|
|
NULL,
|
|
(LPCTSTR)FileName);
|
|
/*
|
|
WritePrivateProfileSection(
|
|
szRegistryValues,
|
|
NULL,
|
|
(LPCTSTR)FileName);
|
|
*/
|
|
}
|
|
|
|
ScepLogOutput3(1, rc, IDS_COPY_OU_GPO);
|
|
}
|
|
|
|
//
|
|
// free the temp buffer
|
|
//
|
|
SceFreeMemory((PVOID)pTmpBuffer, Area);
|
|
|
|
} else {
|
|
|
|
ScepLogOutput2(1, ScepSceStatusToDosError(rc), L"Unable to read security policy from database");
|
|
}
|
|
}
|
|
|
|
if ( (SCESTATUS_SUCCESS == rc) &&
|
|
(Area & AREA_PRIVILEGES) ) {
|
|
|
|
//
|
|
// privileges must be processed separately
|
|
// because they are saved in the GPO template
|
|
// as "Add/Remove" format
|
|
//
|
|
|
|
wcscpy(FileName+WindirLen, L"\\security\\FirstOGPO.inf\0");
|
|
|
|
//
|
|
// if security policy is also requested, this must be an upgrade
|
|
//
|
|
|
|
rc = ScepCopyPrivilegesIntoFile(FileName,
|
|
(Area & AREA_SECURITY_POLICY) //TRUE upgrade
|
|
);
|
|
|
|
if ( Area & AREA_SECURITY_POLICY ) {
|
|
ScepLogOutput3(1, ScepSceStatusToDosError(rc), IDS_COPY_PRIVILEGE_UPGRADE);
|
|
} else {
|
|
ScepLogOutput3(1, ScepSceStatusToDosError(rc), IDS_COPY_PRIVILEGE_FRESH);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
ScepLogOutput3(1, GetLastError(), IDS_ERROR_GET_PROCADDR, L"SceWriteSecurityProfileInfo");
|
|
rc = SCESTATUS_MOD_NOT_FOUND;
|
|
}
|
|
|
|
FreeLibrary(hSceCliDll);
|
|
|
|
} else {
|
|
|
|
ScepLogOutput3(1, GetLastError(), SCEDLL_ERROR_LOAD, L"scecli.dll");
|
|
rc = SCESTATUS_MOD_NOT_FOUND;
|
|
}
|
|
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
VOID
|
|
ScepWriteSpecialRegistryValuesIntoPolicy(
|
|
PWSTR pszFileName,
|
|
PSCE_PROFILE_INFO pTemplateProfile,
|
|
PSCE_REGISTRY_VALUE_INFO pLocalRegSettings,
|
|
DWORD dwNumLocalSettings
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine writes certain registry values to the default DC policy
|
|
If the existing system has the registry values configured stronger, those values will win
|
|
|
|
Arguments:
|
|
|
|
pszFileName - the name of the policy file
|
|
pTemplateProfile - the existing policy file settings
|
|
pLocalRegSettings - local registry value policy
|
|
dwNumLocalSettings - number of settings in local registry value policy
|
|
|
|
Return value:
|
|
|
|
none
|
|
|
|
++*/
|
|
{
|
|
WCHAR szValue[MAX_PATH];
|
|
|
|
for (DWORD dwIndex = 0; dwIndex < pTemplateProfile->RegValueCount; dwIndex++ ) {
|
|
|
|
if (pTemplateProfile->aRegValues[dwIndex].ValueType != REG_DWORD) {
|
|
continue;
|
|
}
|
|
|
|
SCE_REGISTRY_VALUE_INFO RegWinner = pTemplateProfile->aRegValues[dwIndex];
|
|
szValue[0] = L'\0';
|
|
|
|
for (DWORD dwLocalIndex = 0; dwLocalIndex < dwNumLocalSettings; dwLocalIndex++ ) {
|
|
|
|
if (pLocalRegSettings[dwLocalIndex].FullValueName != NULL &&
|
|
pTemplateProfile->aRegValues[dwIndex].FullValueName != NULL &&
|
|
0 == _wcsicmp(pLocalRegSettings[dwLocalIndex].FullValueName, pTemplateProfile->aRegValues[dwIndex].FullValueName)) {
|
|
|
|
//
|
|
// determine the winning value
|
|
//
|
|
|
|
if (pLocalRegSettings[dwLocalIndex].Value != NULL && pTemplateProfile->aRegValues[dwIndex].Value != NULL ) {
|
|
if (_wcsicmp(pLocalRegSettings[dwLocalIndex].Value,
|
|
pTemplateProfile->aRegValues[dwIndex].Value) > 0 ) {
|
|
RegWinner = pLocalRegSettings[dwLocalIndex];
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_snwprintf(szValue, MAX_PATH - 1, L"%1d,%s\0", RegWinner.ValueType, RegWinner.Value );
|
|
|
|
WritePrivateProfileString (szRegistryValues, RegWinner.FullValueName, szValue, pszFileName);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepGetTemplateInformation(
|
|
IN PWSTR pszFilename,
|
|
IN DWORD Area,
|
|
IN HINSTANCE hSceCliDll,
|
|
OUT PSCE_PROFILE_INFO *pProfileInfo
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This gets information from a given template using the dynammically loaded scecli DLL
|
|
|
|
Arguments:
|
|
|
|
pszFilename - name of the template to get information from
|
|
Area - areas to get information about
|
|
hSceCliDll - handle to dll
|
|
*pProfileInfo - the profile to be filled in
|
|
|
|
Return value:
|
|
|
|
SCESTATUS error code
|
|
|
|
++*/
|
|
{
|
|
DWORD rc;
|
|
PVOID h_Profile = NULL;
|
|
|
|
PFSCEOPENPROFILE pfnSceOpenProfile = (PFSCEOPENPROFILE)GetProcAddress(
|
|
hSceCliDll,
|
|
"SceOpenProfile");
|
|
|
|
PFSCECLOSEPROFILE pfnSceCloseProfile = (PFSCECLOSEPROFILE)GetProcAddress(
|
|
hSceCliDll,
|
|
"SceCloseProfile");
|
|
|
|
PFSCEGETINFO pfnSceGetSecurityProfileInfo = (PFSCEGETINFO)GetProcAddress(
|
|
hSceCliDll,
|
|
"SceGetSecurityProfileInfo");
|
|
|
|
if (pfnSceGetSecurityProfileInfo == NULL ||
|
|
pfnSceCloseProfile == NULL ||
|
|
pfnSceOpenProfile == NULL) {
|
|
|
|
return SCESTATUS_MOD_NOT_FOUND;
|
|
}
|
|
|
|
rc = ( *pfnSceOpenProfile) (pszFilename,
|
|
SCE_INF_FORMAT,
|
|
&h_Profile);
|
|
|
|
if ( rc == SCESTATUS_SUCCESS && h_Profile ) {
|
|
|
|
rc = ( *pfnSceGetSecurityProfileInfo) (h_Profile,
|
|
SCE_ENGINE_SCP,
|
|
Area,
|
|
pProfileInfo,
|
|
NULL);
|
|
|
|
(* pfnSceCloseProfile) (&h_Profile);
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
ScepWriteOneAttributeToFile(
|
|
IN LPCTSTR SectionName,
|
|
IN LPCTSTR FileName,
|
|
IN LPCTSTR KeyName,
|
|
IN DWORD dwValue
|
|
)
|
|
{
|
|
|
|
TCHAR valBuf[20];
|
|
DWORD rc=NO_ERROR;
|
|
|
|
if ( dwValue != SCE_NO_VALUE ) {
|
|
|
|
swprintf(valBuf, L"%d", dwValue);
|
|
|
|
if ( !WritePrivateProfileString(SectionName,
|
|
KeyName,
|
|
(LPCTSTR)valBuf,
|
|
FileName
|
|
) ) {
|
|
rc = GetLastError();
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepCopyPrivilegesIntoFile(
|
|
IN LPTSTR FileName,
|
|
IN BOOL bInUpgrade
|
|
)
|
|
{
|
|
if ( FileName == NULL ) {
|
|
return SCESTATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
HINF hInf;
|
|
|
|
rc = SceInfpOpenProfile(
|
|
FileName,
|
|
&hInf
|
|
);
|
|
if ( SCESTATUS_SUCCESS != rc ) {
|
|
return rc;
|
|
}
|
|
|
|
INFCONTEXT InfLine;
|
|
WCHAR Keyname[SCE_KEY_MAX_LENGTH];
|
|
PWSTR StrValue=NULL;
|
|
DWORD ValueLen=0;
|
|
TCHAR TmpNull[2];
|
|
|
|
LSA_HANDLE LsaPolicy=NULL;
|
|
|
|
TmpNull[0] = L'\0';
|
|
TmpNull[1] = L'\0';
|
|
|
|
PSCESECTION hSection=NULL;
|
|
|
|
if ( SetupFindFirstLine(hInf,szPrivilegeRights,NULL,&InfLine) ) {
|
|
|
|
//
|
|
// do not need database access to get privilege
|
|
// must query from system at real time
|
|
//
|
|
|
|
//
|
|
// process each line in the section and save to the scp table.
|
|
// Each INF line has a key and a value.
|
|
//
|
|
|
|
do {
|
|
|
|
memset(Keyname, '\0', SCE_KEY_MAX_LENGTH*sizeof(TCHAR));
|
|
rc = SCESTATUS_BAD_FORMAT;
|
|
|
|
if ( SetupGetStringField(&InfLine, 0, Keyname, SCE_KEY_MAX_LENGTH, NULL) ) {
|
|
|
|
//
|
|
// do not save new privileges into the policy file because
|
|
// W2K clients (DCs) do not support them.
|
|
//
|
|
for (DWORD i=cPrivW2k; i<cPrivCnt; i++) {
|
|
if ( _wcsicmp(Keyname, SCE_Privileges[i].Name) == 0 )
|
|
break;
|
|
}
|
|
if ( i < cPrivCnt ) {
|
|
// this is a new user right
|
|
// do not save it in policy
|
|
|
|
rc = SCESTATUS_SUCCESS;
|
|
|
|
if ( !WritePrivateProfileString(szPrivilegeRights,
|
|
Keyname,
|
|
NULL,
|
|
FileName
|
|
) ) {
|
|
rc = ScepDosErrorToSceStatus(GetLastError());
|
|
}
|
|
|
|
ScepLogOutput3( 1, ScepDosErrorToSceStatus(rc), SCEDLL_ERROR_IGNORE_POLICY, Keyname);
|
|
|
|
continue;
|
|
}
|
|
|
|
if ( SetupGetMultiSzField(&InfLine, 1, NULL, 0, &ValueLen) ) {
|
|
|
|
if ( ValueLen > 1 ) {
|
|
//
|
|
// allocate buffer for the multi string
|
|
//
|
|
StrValue = (PWSTR)ScepAlloc( LMEM_ZEROINIT,
|
|
(ValueLen+1)*sizeof(TCHAR));
|
|
|
|
if( StrValue == NULL ) {
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
|
|
} else if( SetupGetMultiSzField(&InfLine, 1, StrValue, ValueLen, NULL) ) {
|
|
|
|
rc = SCESTATUS_SUCCESS;
|
|
|
|
} else {
|
|
ScepFree(StrValue);
|
|
StrValue = NULL;
|
|
}
|
|
|
|
} else
|
|
rc = SCESTATUS_SUCCESS;
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
//
|
|
// another format for user rights (ADD: REMOVE:...)
|
|
// Note, if this is within dcpromo upgrade, the current boot
|
|
// is in the temperatory SAM hive (with a bogus domain SID)
|
|
// IIS/MTS users created during this boot are bogus
|
|
// and any users from the NT4 account domain/trusted domain
|
|
// can't be resolved at this moment.
|
|
// So do not enumerate current privileges, instead, use
|
|
// the settings from local security database.
|
|
//
|
|
PWSTR NewValue=NULL;
|
|
DWORD NewLen=0;
|
|
|
|
rc = ScepBuildNewPrivilegeList(&LsaPolicy,
|
|
Keyname,
|
|
StrValue ? StrValue : TmpNull,
|
|
SCE_BUILD_ENUMERATE_PRIV,
|
|
&NewValue,
|
|
&NewLen);
|
|
|
|
if ( StrValue ) {
|
|
ScepFree(StrValue);
|
|
}
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
//
|
|
// convert the multi-sz string into comma delimted
|
|
// and write the new multi-sz string back to the file
|
|
//
|
|
|
|
if ( NewValue ) {
|
|
ScepConvertMultiSzToDelim(NewValue, NewLen, L'\0', L',');
|
|
}
|
|
|
|
if ( !WritePrivateProfileString(szPrivilegeRights,
|
|
Keyname,
|
|
NewValue ? (LPCTSTR)NewValue : (LPCTSTR)TmpNull,
|
|
FileName
|
|
) ) {
|
|
rc = ScepDosErrorToSceStatus(GetLastError());
|
|
}
|
|
}
|
|
|
|
if ( NewValue ) {
|
|
ScepFree(NewValue);
|
|
}
|
|
NewValue = NULL;
|
|
}
|
|
|
|
StrValue = NULL;
|
|
|
|
}
|
|
|
|
if (rc != SCESTATUS_SUCCESS)
|
|
ScepLogOutput3( 1, ScepSceStatusToDosError(rc),
|
|
SCEDLL_ERROR_CONVERT, Keyname);
|
|
}
|
|
|
|
} while( rc == SCESTATUS_SUCCESS && SetupFindNextLine(&InfLine, &InfLine));
|
|
|
|
}
|
|
|
|
if ( hSection ) {
|
|
|
|
SceJetCloseSection( &hSection, TRUE );
|
|
}
|
|
|
|
SceInfpCloseProfile(hInf);
|
|
|
|
if ( LsaPolicy ) {
|
|
LsaClose(LsaPolicy);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepCopyPrivilegesFromDatabase(
|
|
IN PSCESECTION hSection,
|
|
IN PWSTR Keyname,
|
|
IN DWORD StrLength,
|
|
IN PWSTR StrValue OPTIONAL,
|
|
OUT PWSTR *pOldValue,
|
|
OUT DWORD *pOldLen
|
|
)
|
|
{
|
|
|
|
if ( hSection == NULL ||
|
|
Keyname == NULL ||
|
|
pOldValue == NULL ) {
|
|
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
*pOldValue = NULL;
|
|
*pOldLen = 0;
|
|
|
|
SCESTATUS rc;
|
|
DWORD ValueLen;
|
|
|
|
rc = SceJetGetValue(
|
|
hSection,
|
|
SCEJET_EXACT_MATCH_NO_CASE,
|
|
Keyname,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
&ValueLen
|
|
);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
DWORD Len = wcslen(SCE_PRIV_ADD);
|
|
|
|
*pOldValue = (PWSTR)ScepAlloc(LPTR, (Len+1+StrLength+1)*sizeof(WCHAR)+ValueLen+2);
|
|
|
|
if ( *pOldValue ) {
|
|
|
|
//
|
|
// add the prefix "Add:" first, terminated with a \0 for multi-sz format
|
|
//
|
|
wcscpy(*pOldValue, SCE_PRIV_ADD );
|
|
(*pOldValue)[Len] = L'\0';
|
|
|
|
//
|
|
// query the value from database
|
|
//
|
|
DWORD NewLen=0;
|
|
|
|
rc = SceJetGetValue(
|
|
hSection,
|
|
SCEJET_CURRENT,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
(*pOldValue+Len+1),
|
|
ValueLen,
|
|
&NewLen
|
|
);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
if ( NewLen > ValueLen ) {
|
|
NewLen = ValueLen;
|
|
}
|
|
|
|
//
|
|
// make sure the length is a multiple of 2
|
|
//
|
|
if ( NewLen % 2 != 0 ) {
|
|
NewLen++;
|
|
}
|
|
|
|
//
|
|
// process the end of the multi-sz string, make sure that it only contains one \0
|
|
//
|
|
|
|
while ( NewLen > 0 &&
|
|
( *(*pOldValue+Len+1+NewLen/2-1) == L'\0') ) {
|
|
if ( NewLen > 1 ) {
|
|
NewLen -= 2;
|
|
} else {
|
|
NewLen = 0;
|
|
}
|
|
}
|
|
|
|
if ( NewLen != 0 ) {
|
|
//
|
|
// include one \0
|
|
//
|
|
NewLen += 2;
|
|
}
|
|
|
|
if ( StrValue ) {
|
|
|
|
memcpy((*pOldValue+Len+1+NewLen/2), StrValue, StrLength*sizeof(WCHAR));
|
|
*pOldLen = Len+1+NewLen/2+StrLength;
|
|
|
|
} else {
|
|
|
|
if ( NewLen == 0 ) {
|
|
//
|
|
// no value in both database and template
|
|
//
|
|
ScepFree(*pOldValue);
|
|
*pOldValue = NULL;
|
|
*pOldLen = 0;
|
|
|
|
} else {
|
|
//
|
|
// only has value in database, terminate the string with two \0
|
|
//
|
|
*pOldLen = Len+1+NewLen/2+1;
|
|
*(*pOldValue+Len+1+NewLen/2) = L'\0';
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
ScepFree(*pOldValue);
|
|
*pOldValue = NULL;
|
|
|
|
//
|
|
// ignore error (if can't query from the db)
|
|
//
|
|
rc = SCESTATUS_SUCCESS;
|
|
}
|
|
|
|
} else {
|
|
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// ignore error (if there is no match)
|
|
//
|
|
rc = SCESTATUS_SUCCESS;
|
|
}
|
|
|
|
ScepLogOutput3(1, ScepSceStatusToDosError(rc), IDS_COPY_ONE_PRIVILEGE, Keyname );
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepDeleteDomainPolicies()
|
|
{
|
|
|
|
SCESTATUS rc;
|
|
PSCESECTION hTmpSect=NULL;
|
|
DOUBLE SectionID=0;
|
|
|
|
rc = SceJetGetSectionIDByName(
|
|
hProfile,
|
|
szSystemAccess,
|
|
&SectionID
|
|
);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
rc = SceJetOpenSection(hProfile,
|
|
SectionID,
|
|
SCEJET_TABLE_SCP,
|
|
&hTmpSect
|
|
);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
SceJetDelete(hTmpSect, NULL, FALSE, SCEJET_DELETE_SECTION);
|
|
|
|
SceJetCloseSection(&hTmpSect, TRUE);
|
|
}
|
|
|
|
rc = SceJetOpenSection(hProfile,
|
|
SectionID,
|
|
SCEJET_TABLE_SMP,
|
|
&hTmpSect
|
|
);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
SceJetDelete(hTmpSect, NULL, FALSE, SCEJET_DELETE_SECTION);
|
|
|
|
SceJetCloseSection(&hTmpSect, TRUE);
|
|
}
|
|
}
|
|
|
|
SectionID = 0;
|
|
|
|
rc = SceJetGetSectionIDByName(
|
|
hProfile,
|
|
szKerberosPolicy,
|
|
&SectionID
|
|
);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
rc = SceJetOpenSection(hProfile,
|
|
SectionID,
|
|
SCEJET_TABLE_SCP,
|
|
&hTmpSect
|
|
);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
SceJetDelete(hTmpSect, NULL, FALSE, SCEJET_DELETE_SECTION);
|
|
|
|
SceJetCloseSection(&hTmpSect, TRUE);
|
|
}
|
|
|
|
rc = SceJetOpenSection(hProfile,
|
|
SectionID,
|
|
SCEJET_TABLE_SMP,
|
|
&hTmpSect
|
|
);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
SceJetDelete(hTmpSect, NULL, FALSE, SCEJET_DELETE_SECTION);
|
|
|
|
SceJetCloseSection(&hTmpSect, TRUE);
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
SCESTATUS
|
|
ScepSetupResetLocalPolicy(
|
|
IN PSCECONTEXT Context,
|
|
IN AREA_INFORMATION Area,
|
|
IN PCWSTR SectionName OPTIONAL,
|
|
IN SCETYPE ProfileType,
|
|
IN BOOL bKeepBasicPolicy
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
This routine deletes policies from the local policy table (SMP)
|
|
|
|
If a section name is provided, the single section is deleted; otherwise,
|
|
The area information is used.
|
|
|
|
If bKeepBasicPolicy is set to TRUE, the following inforamtion WON'T be
|
|
deleted from the table even if that area is requested to delete.
|
|
Password, Lockout, Kerberos, Audit, User Rights, Security Options,
|
|
and SMB settings (any existing service extensions)
|
|
*/
|
|
{
|
|
|
|
if ( Context == NULL ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
|
|
if ( SectionName ) {
|
|
|
|
//
|
|
// delete one section
|
|
//
|
|
|
|
rc = ScepDeleteOneSection(
|
|
Context,
|
|
ProfileType,
|
|
SectionName
|
|
);
|
|
|
|
} else {
|
|
|
|
AREA_INFORMATION Area2;
|
|
|
|
if ( bKeepBasicPolicy && ProfileType == SCE_ENGINE_SMP ) {
|
|
Area2 = Area & ~(AREA_SECURITY_POLICY |
|
|
AREA_PRIVILEGES |
|
|
AREA_SYSTEM_SERVICE);
|
|
} else {
|
|
|
|
Area2 = Area;
|
|
}
|
|
|
|
rc = ScepDeleteInfoForAreas(
|
|
Context,
|
|
ProfileType,
|
|
Area2
|
|
);
|
|
|
|
if ( bKeepBasicPolicy &&
|
|
SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// delete log settings sections
|
|
//
|
|
|
|
ScepDeleteOneSection(
|
|
Context,
|
|
ProfileType,
|
|
szAuditSystemLog
|
|
);
|
|
|
|
ScepDeleteOneSection(
|
|
Context,
|
|
ProfileType,
|
|
szAuditSecurityLog
|
|
);
|
|
|
|
ScepDeleteOneSection(
|
|
Context,
|
|
ProfileType,
|
|
szAuditApplicationLog
|
|
);
|
|
|
|
//
|
|
// delete general service section
|
|
//
|
|
|
|
ScepDeleteOneSection(
|
|
Context,
|
|
ProfileType,
|
|
szServiceGeneral
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepSetSystemSecurity(
|
|
IN AREA_INFORMATION Area,
|
|
IN DWORD ConfigOptions,
|
|
IN PSCE_PROFILE_INFO pInfo,
|
|
OUT PSCE_ERROR_LOG_INFO *pErrLog
|
|
)
|
|
/*
|
|
Description:
|
|
|
|
Set security settings directly on the system for security policy area
|
|
and user rights area.
|
|
|
|
If some settings fail to be configured, the settings will be logged in the
|
|
error buffer to output.
|
|
*/
|
|
{
|
|
SCESTATUS Saverc = SCESTATUS_SUCCESS;
|
|
SCESTATUS rc;
|
|
|
|
if ( pInfo == NULL || Area == 0 ) {
|
|
//
|
|
// nothing to set
|
|
//
|
|
return(Saverc);
|
|
}
|
|
|
|
if ( Area & AREA_PRIVILEGES ) {
|
|
|
|
rc = ScepConfigurePrivilegesByRight( pInfo->OtherInfo.smp.pPrivilegeAssignedTo,
|
|
ConfigOptions,
|
|
pErrLog
|
|
);
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
Saverc = rc;
|
|
}
|
|
}
|
|
|
|
|
|
if ( Area & AREA_SECURITY_POLICY ) {
|
|
|
|
if ( pInfo->LockoutBadCount == 0 ) {
|
|
//
|
|
// make sure the other two settings are ignored
|
|
// they might have value SCE_DELETE_VALUE which is not applicable to this mode
|
|
//
|
|
pInfo->ResetLockoutCount = SCE_NO_VALUE;
|
|
pInfo->LockoutDuration = SCE_NO_VALUE;
|
|
}
|
|
|
|
rc = ScepConfigureSystemAccess(pInfo,
|
|
ConfigOptions | SCE_SYSTEM_SETTINGS,
|
|
pErrLog,
|
|
0 );
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
Saverc = rc;
|
|
}
|
|
|
|
rc = ScepConfigureLSAAnonymousLookup( pInfo, ConfigOptions, pErrLog );
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
Saverc = rc;
|
|
}
|
|
|
|
//
|
|
// System Auditing area
|
|
//
|
|
PPOLICY_AUDIT_EVENTS_INFO auditEvent=NULL;
|
|
|
|
rc = ScepSaveAndOffAuditing(&auditEvent, FALSE, NULL);
|
|
|
|
if ( rc == SCESTATUS_SUCCESS && auditEvent ) {
|
|
|
|
rc = ScepConfigureAuditEvent(pInfo,
|
|
auditEvent,
|
|
ConfigOptions | SCE_SYSTEM_SETTINGS,
|
|
NULL
|
|
);
|
|
|
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
ScepSceStatusToDosError(rc),
|
|
pErrLog,
|
|
SCEDLL_SCP_ERROR_EVENT_AUDITING
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
ScepSceStatusToDosError(rc),
|
|
pErrLog,
|
|
SCEDLL_ERROR_QUERY_EVENT_AUDITING
|
|
);
|
|
|
|
}
|
|
|
|
|
|
if ( auditEvent ) {
|
|
LsaFreeMemory(auditEvent);
|
|
}
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
Saverc = rc;
|
|
}
|
|
|
|
//
|
|
// Kerberos Policy
|
|
//
|
|
rc = ScepConfigureKerberosPolicy( NULL, pInfo->pKerberosInfo, ConfigOptions );
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
ScepSceStatusToDosError(rc),
|
|
pErrLog,
|
|
SCEDLL_SCP_ERROR_KERBEROS
|
|
);
|
|
Saverc = rc;
|
|
}
|
|
|
|
//
|
|
// registry values
|
|
//
|
|
rc = ScepConfigureRegistryValues( NULL,
|
|
pInfo->aRegValues,
|
|
pInfo->RegValueCount,
|
|
pErrLog,
|
|
ConfigOptions,
|
|
NULL );
|
|
|
|
if( rc != SCESTATUS_SUCCESS ) {
|
|
Saverc = rc;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
return(Saverc);
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepConfigurePrivilegesByRight(
|
|
IN PSCE_PRIVILEGE_ASSIGNMENT pPrivAssign,
|
|
IN DWORD Options,
|
|
IN OUT PSCE_ERROR_LOG_INFO *pErrLog
|
|
)
|
|
/*
|
|
Description:
|
|
|
|
Configure privileges by PSCE_PRIVILEGE_ASSIGNMENT structure which is
|
|
separated by each user right with a list of accounts assigned to.
|
|
*/
|
|
{
|
|
|
|
|
|
if ( pPrivAssign == NULL ) {
|
|
//
|
|
// nothing to configure
|
|
//
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
LSA_HANDLE LsaPolicy=NULL;
|
|
DWORD rc;
|
|
|
|
|
|
rc = RtlNtStatusToDosError( ScepOpenLsaPolicy(
|
|
POLICY_LOOKUP_NAMES | POLICY_CREATE_ACCOUNT,
|
|
&LsaPolicy,
|
|
FALSE)
|
|
);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
if ( pErrLog ) {
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_LSA_POLICY
|
|
);
|
|
}
|
|
return(rc);
|
|
}
|
|
|
|
PSCE_PRIVILEGE_ASSIGNMENT pPriv;
|
|
INT PrivValue;
|
|
PSCE_NAME_LIST pList;
|
|
DWORD SaveRc=SCESTATUS_SUCCESS;
|
|
BOOL bBufferUsed;
|
|
PSID pAccountSid;
|
|
|
|
DWORD PrivLowMask=0;
|
|
DWORD PrivHighMask=0;
|
|
|
|
PSCE_PRIVILEGE_VALUE_LIST pPrivList=NULL;
|
|
|
|
//
|
|
// convert the privilege assignment structure to privilege value list
|
|
// and build the mask for privileges (PrivLowMask and PrivHighMask)
|
|
//
|
|
for ( pPriv=pPrivAssign; pPriv != NULL; pPriv=pPriv->Next ) {
|
|
|
|
//
|
|
// privilege name is empty, ignore it.
|
|
//
|
|
if ( pPriv->Name == NULL ) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// search for the privilege value
|
|
//
|
|
|
|
PrivValue = ScepLookupPrivByName(pPriv->Name);
|
|
|
|
if ( PrivValue == -1 ) {
|
|
//
|
|
// unknown privilege
|
|
//
|
|
if ( pErrLog ) {
|
|
ScepBuildErrorLogInfo(
|
|
0,
|
|
pErrLog,
|
|
SCEERR_INVALID_PRIVILEGE,
|
|
pPriv->Name
|
|
);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// build privilege mask
|
|
//
|
|
|
|
if ( PrivValue < 32 ) {
|
|
|
|
PrivLowMask |= (1 << PrivValue);
|
|
} else {
|
|
PrivHighMask |= (1 << (PrivValue-32) );
|
|
}
|
|
|
|
for ( pList=pPriv->AssignedTo; pList != NULL; pList=pList->Next ) {
|
|
//
|
|
// translate each one to a SID
|
|
//
|
|
if ( pList->Name == NULL ) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// reset error code for this new account
|
|
//
|
|
rc = ERROR_SUCCESS;
|
|
pAccountSid = NULL;
|
|
bBufferUsed = FALSE;
|
|
|
|
if ( pList->Name[0] == L'*' ) {
|
|
//
|
|
// this is a string SID
|
|
//
|
|
if ( !ConvertStringSidToSid( pList->Name+1, &pAccountSid) ) {
|
|
rc = GetLastError();
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// this is a name, could be in the format of domain\account, or
|
|
// just an isolated account
|
|
//
|
|
rc = RtlNtStatusToDosError(
|
|
ScepConvertNameToSid(
|
|
LsaPolicy,
|
|
pList->Name,
|
|
&pAccountSid
|
|
));
|
|
}
|
|
|
|
if ( rc == ERROR_SUCCESS ) {
|
|
|
|
//
|
|
// add the account SID to privilege value list
|
|
//
|
|
rc = ScepDosErrorToSceStatus(
|
|
ScepAddSidToPrivilegeList(
|
|
&pPrivList,
|
|
pAccountSid,
|
|
TRUE, // reuse the buffer
|
|
PrivValue,
|
|
&bBufferUsed
|
|
));
|
|
|
|
}
|
|
|
|
if ( rc != ERROR_SUCCESS ) {
|
|
//
|
|
// something is wrong with this account. Can't be resolved
|
|
// add it to the error log and continue to process others.
|
|
//
|
|
if ( pErrLog ) {
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_INVALID_GROUP,
|
|
pList->Name
|
|
);
|
|
}
|
|
|
|
SaveRc = ScepDosErrorToSceStatus(rc);
|
|
}
|
|
|
|
if ( !bBufferUsed && pAccountSid ) {
|
|
ScepFree(pAccountSid);
|
|
}
|
|
pAccountSid = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// free LSA handle
|
|
//
|
|
LsaClose(LsaPolicy);
|
|
|
|
//
|
|
// now continue to configure even though there may be errors in
|
|
// the previous processing (the erorrs are logged)
|
|
//
|
|
if ( PrivLowMask > 0 || PrivHighMask > 0 ) {
|
|
|
|
rc = ScepConfigurePrivilegesWithMask(
|
|
&pPrivList,
|
|
FALSE,
|
|
Options | SCE_SYSTEM_SETTINGS,
|
|
PrivLowMask,
|
|
PrivHighMask,
|
|
pErrLog,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
//
|
|
// free privilege list
|
|
//
|
|
|
|
|
|
return(SaveRc);
|
|
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepEnumAttachmentSections(
|
|
IN PSCECONTEXT cxtProfile,
|
|
OUT PSCE_NAME_LIST *ppList
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
cxtProfile - The profile context handle
|
|
|
|
ppList - The output attachment section names
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
-- */
|
|
{
|
|
SCESTATUS rc;
|
|
JET_ERR JetErr;
|
|
DWORD Actual;
|
|
WCHAR Buffer[256];
|
|
DWORD Len;
|
|
|
|
if ( cxtProfile == NULL || ppList == NULL )
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
|
|
if ( cxtProfile->JetTblSecID <= 0) {
|
|
//
|
|
// Section table is not opened yet
|
|
//
|
|
rc = SceJetOpenTable(
|
|
cxtProfile,
|
|
"SmTblSection",
|
|
SCEJET_TABLE_SECTION,
|
|
SCEJET_OPEN_READ_ONLY,
|
|
NULL
|
|
);
|
|
|
|
if ( rc != SCESTATUS_SUCCESS )
|
|
return(rc);
|
|
}
|
|
|
|
*ppList = NULL;
|
|
|
|
//
|
|
// set current index to SecID (the ID)
|
|
//
|
|
JetErr = JetSetCurrentIndex(
|
|
cxtProfile->JetSessionID,
|
|
cxtProfile->JetTblSecID,
|
|
"SecID"
|
|
);
|
|
rc = SceJetJetErrorToSceStatus(JetErr);
|
|
|
|
if ( rc != SCESTATUS_SUCCESS )
|
|
return(rc);
|
|
|
|
//
|
|
// Move to the first record
|
|
//
|
|
JetErr = JetMove(
|
|
cxtProfile->JetSessionID,
|
|
cxtProfile->JetTblSecID,
|
|
JET_MoveFirst,
|
|
0
|
|
);
|
|
rc = SceJetJetErrorToSceStatus(JetErr);
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
//
|
|
// find the section record, retrieve column Name
|
|
//
|
|
do {
|
|
|
|
Len = 255;
|
|
memset(Buffer, '\0', 256*sizeof(WCHAR));
|
|
|
|
JetErr = JetRetrieveColumn(
|
|
cxtProfile->JetSessionID,
|
|
cxtProfile->JetTblSecID,
|
|
cxtProfile->JetSecNameID,
|
|
(void *)Buffer,
|
|
Len*sizeof(WCHAR),
|
|
&Actual,
|
|
0,
|
|
NULL
|
|
);
|
|
rc = SceJetJetErrorToSceStatus(JetErr);
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
//
|
|
// add this name to the output list
|
|
//
|
|
if ( _wcsicmp(szSystemAccess, Buffer) == 0 ||
|
|
_wcsicmp(szPrivilegeRights, Buffer) == 0 ||
|
|
_wcsicmp(szGroupMembership, Buffer) == 0 ||
|
|
_wcsicmp(szRegistryKeys, Buffer) == 0 ||
|
|
_wcsicmp(szFileSecurity, Buffer) == 0 ||
|
|
_wcsicmp(szAuditSystemLog, Buffer) == 0 ||
|
|
_wcsicmp(szAuditSecurityLog, Buffer) == 0 ||
|
|
_wcsicmp(szAuditApplicationLog, Buffer) == 0 ||
|
|
_wcsicmp(szAuditEvent, Buffer) == 0 ||
|
|
_wcsicmp(szKerberosPolicy, Buffer) == 0 ||
|
|
_wcsicmp(szRegistryValues, Buffer) == 0 ||
|
|
_wcsicmp(szServiceGeneral, Buffer) == 0 ||
|
|
_wcsicmp(szAccountProfiles, Buffer) == 0 ||
|
|
_wcsicmp(szDSSecurity, Buffer) == 0 ||
|
|
_wcsicmp(szUserList, Buffer) == 0
|
|
) {
|
|
// this is not the attachment section
|
|
} else {
|
|
rc = ScepAddToNameList(ppList, Buffer, 0);
|
|
}
|
|
}
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
//
|
|
// Move to next line
|
|
//
|
|
JetErr = JetMove(cxtProfile->JetSessionID,
|
|
cxtProfile->JetTblSecID,
|
|
JET_MoveNext,
|
|
0);
|
|
|
|
rc = SceJetJetErrorToSceStatus(JetErr);
|
|
}
|
|
|
|
} while ( SCESTATUS_SUCCESS == rc );
|
|
}
|
|
|
|
if ( rc == SCESTATUS_RECORD_NOT_FOUND ) {
|
|
|
|
rc = SCESTATUS_SUCCESS;
|
|
|
|
} else if ( rc != SCESTATUS_SUCCESS ) {
|
|
//
|
|
// free the output buffer
|
|
//
|
|
ScepFreeNameList(*ppList);
|
|
*ppList = NULL;
|
|
}
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepTattooUpdatePrivilegeArrayStatus(
|
|
IN DWORD *pStatusArray,
|
|
IN DWORD rc,
|
|
IN DWORD PrivLowMask,
|
|
IN DWORD PrivHighMask
|
|
)
|
|
{
|
|
if ( pStatusArray == NULL ||
|
|
(PrivLowMask == 0 && PrivHighMask == 0) ) {
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
for ( DWORD i=0; i<cPrivCnt; i++) {
|
|
|
|
if ( ( (i < 32) && ( PrivLowMask & (1 << i)) ) ||
|
|
( (i >= 32) && ( PrivHighMask & ( 1 << (i-32)) ) ) ) {
|
|
if ( rc != 0 )
|
|
pStatusArray[i] = rc;
|
|
else if ( pStatusArray[i] == (DWORD)-1 )
|
|
pStatusArray[i] = rc;
|
|
|
|
}
|
|
}
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
SCESTATUS
|
|
ScepTattooRemovePrivilegeValues(
|
|
IN PSCECONTEXT hProfile,
|
|
IN DWORD *pStatusArray
|
|
)
|
|
{
|
|
PSCESECTION hSectionDomain=NULL;
|
|
PSCESECTION hSectionTattoo=NULL;
|
|
DWORD i,Len;
|
|
|
|
|
|
if ( hProfile == NULL || pStatusArray == NULL )
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
|
|
//
|
|
// open domain and tattoo sections
|
|
//
|
|
ScepTattooOpenPolicySections(
|
|
hProfile,
|
|
szPrivilegeRights,
|
|
&hSectionDomain,
|
|
&hSectionTattoo
|
|
);
|
|
|
|
if ( hSectionDomain != NULL && hSectionTattoo != NULL ) {
|
|
|
|
for ( i=0; i<cPrivCnt; i++ ) {
|
|
|
|
if ( pStatusArray[i] == 0 ) {
|
|
|
|
//
|
|
// check if this setting comes from domain
|
|
//
|
|
|
|
Len = wcslen(SCE_Privileges[i].Name);
|
|
|
|
BOOL bDomainExist = FALSE;
|
|
|
|
if ( SCESTATUS_SUCCESS == SceJetSeek(
|
|
hSectionDomain,
|
|
SCE_Privileges[i].Name,
|
|
Len*sizeof(WCHAR),
|
|
SCEJET_SEEK_EQ_NO_CASE
|
|
) ) {
|
|
|
|
if ( hSectionDomain->JetColumnGpoID > 0 ) {
|
|
|
|
//
|
|
// check if GpoID > 0
|
|
//
|
|
|
|
LONG GpoID = 0;
|
|
DWORD Actual;
|
|
JET_ERR JetErr;
|
|
|
|
JetErr = JetRetrieveColumn(
|
|
hSectionDomain->JetSessionID,
|
|
hSectionDomain->JetTableID,
|
|
hSectionDomain->JetColumnGpoID,
|
|
(void *)&GpoID,
|
|
4,
|
|
&Actual,
|
|
0,
|
|
NULL
|
|
);
|
|
if ( JET_errSuccess != JetErr ) {
|
|
//
|
|
// if the column is nil (no value), it will return warning
|
|
// but the buffer pGpoID is trashed
|
|
//
|
|
GpoID = 0;
|
|
}
|
|
|
|
if ( GpoID > 0 ) {
|
|
bDomainExist = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( bDomainExist ) {
|
|
// if the setting comes from domain, don't do anything
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// by now, this setting comes from the tattoo table
|
|
// and has been configured successfully
|
|
// now remove the tattoo setting
|
|
//
|
|
|
|
SceJetDelete(hSectionTattoo,
|
|
SCE_Privileges[i].Name,
|
|
FALSE,
|
|
SCEJET_DELETE_LINE_NO_CASE);
|
|
|
|
ScepLogOutput3(2, 0, SCESRV_POLICY_TATTOO_REMOVE_SETTING, SCE_Privileges[i].Name);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( hSectionDomain ) SceJetCloseSection(&hSectionDomain, TRUE);
|
|
if ( hSectionTattoo ) SceJetCloseSection(&hSectionTattoo, TRUE);
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
SCESTATUS
|
|
ScepTattooSavePrivilegeValues(
|
|
IN PSCECONTEXT hProfile,
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN DWORD PrivLowMask,
|
|
IN DWORD PrivHighMask,
|
|
IN DWORD ConfigOptions
|
|
)
|
|
{
|
|
PSCESECTION hSectionDomain=NULL;
|
|
PSCESECTION hSectionTattoo=NULL;
|
|
|
|
NTSTATUS NtStatus;
|
|
ULONG CountReturned;
|
|
UNICODE_STRING UserRight;
|
|
PLSA_ENUMERATION_INFORMATION EnumBuffer=NULL;
|
|
|
|
DWORD i,j,Len;
|
|
BOOL bSettingExist;
|
|
DWORD rc,rc2;
|
|
SCESTATUS saveRc=SCESTATUS_SUCCESS;
|
|
PSCE_NAME_LIST pNameList=NULL;
|
|
|
|
|
|
if ( !(ConfigOptions & SCE_POLICY_TEMPLATE) || hProfile == NULL ||
|
|
PolicyHandle == NULL ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if ( PrivLowMask == 0 && PrivHighMask == 0 ) {
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// open domain and tattoo sections
|
|
//
|
|
ScepTattooOpenPolicySections(
|
|
hProfile,
|
|
szPrivilegeRights,
|
|
&hSectionDomain,
|
|
&hSectionTattoo
|
|
);
|
|
|
|
if ( hSectionDomain != NULL && hSectionTattoo != NULL ) {
|
|
|
|
for ( i=0; i<cPrivCnt; i++ ) {
|
|
|
|
if ( ( (i < 32) && ( PrivLowMask & (1 << i)) ) ||
|
|
( (i >= 32) && ( PrivHighMask & ( 1 << (i-32)) ) ) ) {
|
|
|
|
//
|
|
// check if this setting comes from domain
|
|
//
|
|
|
|
Len = wcslen(SCE_Privileges[i].Name);
|
|
|
|
bSettingExist = FALSE;
|
|
if ( SCESTATUS_SUCCESS == SceJetSeek(
|
|
hSectionTattoo,
|
|
SCE_Privileges[i].Name,
|
|
Len*sizeof(WCHAR),
|
|
SCEJET_SEEK_EQ_NO_CASE
|
|
) ) {
|
|
bSettingExist = TRUE;
|
|
}
|
|
|
|
// if there is tattoo setting already, no need to save undo value
|
|
if ( bSettingExist ) {
|
|
ScepLogOutput3(3, 0, SCESRV_POLICY_TATTOO_EXIST, SCE_Privileges[i].Name);
|
|
continue;
|
|
}
|
|
|
|
bSettingExist = FALSE;
|
|
if ( SCESTATUS_SUCCESS == SceJetSeek(
|
|
hSectionDomain,
|
|
SCE_Privileges[i].Name,
|
|
Len*sizeof(WCHAR),
|
|
SCEJET_SEEK_EQ_NO_CASE
|
|
) ) {
|
|
//
|
|
// since there is no tattoo value exist
|
|
// so if this setting is found in domain table, it must come from domain
|
|
//
|
|
bSettingExist = TRUE;
|
|
}
|
|
|
|
// if the setting doesn't come from domain, no need to query undo value
|
|
if ( !bSettingExist ) continue;
|
|
|
|
//
|
|
// now we need to query the tattoo value for this privilege
|
|
//
|
|
RtlInitUnicodeString( &UserRight, (PCWSTR)(SCE_Privileges[i].Name));
|
|
|
|
//
|
|
// now enumerate all accounts for this user right.
|
|
//
|
|
|
|
NtStatus = LsaEnumerateAccountsWithUserRight(
|
|
PolicyHandle,
|
|
&UserRight,
|
|
(PVOID *)&EnumBuffer, // account SIDs
|
|
&CountReturned
|
|
);
|
|
|
|
if ( NtStatus == STATUS_NO_MORE_ENTRIES ||
|
|
NtStatus == STATUS_NO_SUCH_PRIVILEGE ||
|
|
NtStatus == STATUS_NOT_FOUND ||
|
|
NT_SUCCESS(NtStatus) ) {
|
|
|
|
rc = ERROR_SUCCESS;
|
|
|
|
} else {
|
|
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
}
|
|
|
|
pNameList = NULL;
|
|
|
|
//
|
|
// if fail to get the account list
|
|
// save NULL as the tattoo value
|
|
//
|
|
if ( NT_SUCCESS(NtStatus) && CountReturned > 0 ) {
|
|
|
|
//
|
|
// add the SIDs
|
|
//
|
|
|
|
for ( j=0; j<CountReturned; j++ ) {
|
|
//
|
|
// build each account into the name list
|
|
// Convert using the Rtl functions
|
|
//
|
|
rc2 = ScepAddSidStringToNameList(&pNameList, EnumBuffer[j].Sid);
|
|
|
|
if ( NO_ERROR != rc2 ) {
|
|
rc = rc2;
|
|
}
|
|
}
|
|
}
|
|
|
|
LsaFreeMemory( EnumBuffer );
|
|
EnumBuffer = NULL;
|
|
|
|
//
|
|
// log an error
|
|
//
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
|
|
saveRc = ScepDosErrorToSceStatus(rc);
|
|
ScepLogOutput3(1, 0, SCESRV_POLICY_TATTOO_ERROR_QUERY, rc, SCE_Privileges[i].Name);
|
|
|
|
} else {
|
|
//
|
|
// now save the name list to the tattoo table
|
|
//
|
|
|
|
rc = ScepWriteNameListValue(
|
|
PolicyHandle,
|
|
hSectionTattoo,
|
|
SCE_Privileges[i].Name,
|
|
pNameList,
|
|
SCE_WRITE_EMPTY_LIST,
|
|
4
|
|
);
|
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|
saveRc = rc;
|
|
ScepLogOutput3(1, 0, SCESRV_POLICY_TATTOO_ERROR_SETTING, ScepSceStatusToDosError(rc), SCE_Privileges[i].Name);
|
|
} else {
|
|
ScepLogOutput3(3, 0, SCESRV_POLICY_TATTOO_CHECK, SCE_Privileges[i].Name);
|
|
}
|
|
}
|
|
|
|
if ( pNameList != NULL ) {
|
|
ScepFreeNameList( pNameList );
|
|
pNameList = NULL;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( hSectionDomain ) SceJetCloseSection(&hSectionDomain, TRUE);
|
|
if ( hSectionTattoo ) SceJetCloseSection(&hSectionTattoo, TRUE);
|
|
|
|
return(saveRc);
|
|
}
|
|
|
|
BOOL
|
|
ScepAccountHandledByNetJoin(
|
|
IN PSID AliasSid,
|
|
IN PSID MemberSid,
|
|
OUT BOOL *pfAliasHandled)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
Checks if the current member for the specified alias is handled by net join. Net
|
|
join currently handles the following groups:
|
|
|
|
- in Administrators: Domain Admins
|
|
- in Users: Domain Users
|
|
|
|
Arguments:
|
|
|
|
AliasSid - group's SID
|
|
|
|
MemberSid - group's member SID
|
|
|
|
fAliasHandled - optimization variable, the function is called in a loop, we can
|
|
avoid calling it again if alias is not handled by net join
|
|
|
|
Return value:
|
|
|
|
TRUE - if account is modified by net join
|
|
FALSE - if account not modified or error occured
|
|
-- */
|
|
{
|
|
NTSTATUS NtStatus;
|
|
BOOL fRet = FALSE;
|
|
PSID pSidAdmins = NULL;
|
|
PSID pSidUsers = NULL;
|
|
PSID pSidDomAdmins = NULL;
|
|
PSID pSidDomUsers = NULL;
|
|
PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo=NULL;
|
|
PPOLICY_PRIMARY_DOMAIN_INFO PrimaryDomainInfo=NULL;
|
|
|
|
*pfAliasHandled = FALSE;
|
|
|
|
if (ERROR_SUCCESS == ScepGetBuiltinSid(DOMAIN_ALIAS_RID_ADMINS, &pSidAdmins) &&
|
|
ERROR_SUCCESS == ScepGetBuiltinSid(DOMAIN_ALIAS_RID_USERS, &pSidUsers))
|
|
{
|
|
//
|
|
// check if group SID is one of the accounts net join changes, otherwise
|
|
// there's no need to further process it
|
|
//
|
|
if (EqualSid(AliasSid, pSidAdmins) ||
|
|
EqualSid(AliasSid, pSidUsers))
|
|
{
|
|
*pfAliasHandled = TRUE;
|
|
|
|
NtStatus = ScepGetLsaDomainInfo(
|
|
&AccountDomainInfo,
|
|
&PrimaryDomainInfo
|
|
);
|
|
|
|
if(NT_SUCCESS(NtStatus) &&
|
|
NT_SUCCESS(ScepDomainIdToSid(PrimaryDomainInfo->Sid, DOMAIN_GROUP_RID_ADMINS, &pSidDomAdmins)) &&
|
|
NT_SUCCESS(ScepDomainIdToSid(PrimaryDomainInfo->Sid, DOMAIN_GROUP_RID_USERS, &pSidDomUsers)))
|
|
{
|
|
//
|
|
// check if the member group is changed by net join
|
|
//
|
|
if(EqualSid(AliasSid, pSidAdmins) && EqualSid(MemberSid,pSidDomAdmins) ||
|
|
EqualSid(AliasSid, pSidUsers) && EqualSid(MemberSid,pSidDomUsers))
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(pSidAdmins) {
|
|
ScepFree(pSidAdmins);
|
|
}
|
|
if(pSidUsers) {
|
|
ScepFree(pSidUsers);
|
|
}
|
|
if(pSidDomAdmins) {
|
|
ScepFree(pSidDomAdmins);
|
|
}
|
|
if(pSidDomUsers) {
|
|
ScepFree(pSidDomUsers);
|
|
}
|
|
if(AccountDomainInfo != NULL) {
|
|
LsaFreeMemory(AccountDomainInfo);
|
|
}
|
|
if(PrimaryDomainInfo != NULL) {
|
|
LsaFreeMemory(PrimaryDomainInfo);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
DWORD
|
|
ScepTattooCurrentGroupMembers(
|
|
IN PSID ThisDomainSid,
|
|
IN PSID GrpSid OPTIONAL,
|
|
IN SID_NAME_USE GrpUse,
|
|
IN PULONG MemberRids OPTIONAL,
|
|
IN PSID *MemberAliasSids OPTIONAL,
|
|
IN DWORD MemberCount,
|
|
OUT PSCE_NAME_LIST *ppNameList
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine builds the current group membership into a name list (in SID string
|
|
format).
|
|
|
|
Arguments:
|
|
|
|
ThisDomainSid - The domain SID
|
|
|
|
GrpUse - The "type" of the group
|
|
|
|
MemberRids - the member RIDs (for SidTypeGroup)
|
|
|
|
MemberAliasSids - the member SIDs (for SidTypeAlias)
|
|
|
|
MemberCount - number of members
|
|
|
|
ppNameList - the output name list
|
|
|
|
Return value:
|
|
|
|
WIN32 errors
|
|
-- */
|
|
{
|
|
NTSTATUS NtStatus=ERROR_SUCCESS;
|
|
DWORD j;
|
|
DWORD saveRc=ERROR_SUCCESS;
|
|
DWORD rc;
|
|
|
|
if ( ppNameList == NULL ) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
*ppNameList = NULL;
|
|
|
|
switch ( GrpUse ) {
|
|
case SidTypeGroup:
|
|
//
|
|
// member IDs are passed in as Rids
|
|
// DomainHandle must point to a account domain because builtin domain
|
|
// won't have SidTypeGroup account
|
|
//
|
|
if ( ThisDomainSid == NULL )
|
|
saveRc = ERROR_INVALID_PARAMETER;
|
|
|
|
else if ( MemberRids ) {
|
|
|
|
PSID AccountSid=NULL;
|
|
|
|
for (j=0; j<MemberCount; j++) {
|
|
|
|
NtStatus = ScepDomainIdToSid(
|
|
ThisDomainSid,
|
|
MemberRids[j],
|
|
&AccountSid
|
|
);
|
|
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
rc = ScepAddSidStringToNameList(ppNameList, AccountSid);
|
|
|
|
ScepFree(AccountSid);
|
|
AccountSid = NULL;
|
|
}
|
|
|
|
if ( ERROR_SUCCESS != rc ) saveRc = rc;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SidTypeAlias:
|
|
//
|
|
// members are passed in as SIDs
|
|
// add them to the output list directly
|
|
//
|
|
if ( MemberAliasSids ) {
|
|
|
|
BOOL fAliasHandled = TRUE; // optimization variable, set to FALSE by ScepAccountHandledByNetJoin
|
|
// if group is not handled by net join so we avoid calling
|
|
// ScepAccountHandledByNetJoin unnecessarily
|
|
|
|
for ( j=0; j<MemberCount; j++ ) {
|
|
if ( MemberAliasSids[j] != NULL ) {
|
|
//
|
|
// add member to the list
|
|
//
|
|
|
|
//
|
|
// Some builtin groups are modified by net join. To avoid undoing net join's changes,
|
|
// we'll save those domain specific accounts handled by net join only as relative SIDs.
|
|
// Upon restore from tattoo table, we'll rebuild the full SID based on the current
|
|
// domain (e.g. so we don't restore old domain Domain Admin, but current one)
|
|
//
|
|
|
|
if (fAliasHandled &&
|
|
ScepAccountHandledByNetJoin(
|
|
GrpSid,
|
|
MemberAliasSids[j],
|
|
&fAliasHandled)) {
|
|
rc = ScepAddRelativeSidToNameList(ppNameList, MemberAliasSids[j]);
|
|
} else {
|
|
rc = ScepAddSidStringToNameList(ppNameList, MemberAliasSids[j]);
|
|
}
|
|
|
|
if ( ERROR_SUCCESS != rc ) saveRc = rc;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
saveRc = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
|
|
return(saveRc);
|
|
}
|
|
|
|
SCESTATUS
|
|
ScepCheckNetworkLogonRights(
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN OUT DWORD *pLowMask,
|
|
IN OUT DWORD *pHighMask,
|
|
IN OUT PSCE_PRIVILEGE_VALUE_LIST *ppPrivilegeAssigned
|
|
)
|
|
/*
|
|
Description:
|
|
|
|
This function is to make sure that Authenticated Users already have
|
|
"Network Logon Right" and Authenticated Users & Everyone must not
|
|
have "Deny network logon right".
|
|
|
|
If the network logon right or deny network logon right are not defined
|
|
in the privilege mask, no change is made since the user rights are not
|
|
defined in the configuration.
|
|
|
|
If Authenticated Users or Everyone is not defined in the privilege list,
|
|
this function will add them in (hard coded). The output of this function
|
|
ppPrivilegeAssigned may contain new added nodes for the hard coded accounts.
|
|
|
|
*/
|
|
{
|
|
INT i;
|
|
INT idxAllow = -1;
|
|
INT idxDeny = -1;
|
|
INT idxLocal = -1;
|
|
INT idxDenyLocal = -1;
|
|
|
|
DWORD PrivHighMask = *pHighMask;
|
|
DWORD PrivLowMask = *pLowMask;
|
|
|
|
//
|
|
// check first if Network logon right is defined
|
|
//
|
|
i = ScepLookupPrivByName(SE_NETWORK_LOGON_NAME);
|
|
if ( i != -1 ) {
|
|
if ( SCEP_CHECK_PRIV_BIT(i,PrivLowMask,PrivHighMask) ) {
|
|
//
|
|
// network logon right is defined
|
|
//
|
|
idxAllow = i;
|
|
}
|
|
}
|
|
|
|
//
|
|
// check if Deny Network logon right is defined
|
|
//
|
|
|
|
i = ScepLookupPrivByName(SE_DENY_NETWORK_LOGON_NAME);
|
|
if ( i != -1 ) {
|
|
|
|
if ( SCEP_CHECK_PRIV_BIT(i,PrivLowMask,PrivHighMask) ) {
|
|
//
|
|
// deny network logon right is defined
|
|
//
|
|
idxDeny = i;
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// check if logon locally right is defined
|
|
//
|
|
|
|
i = ScepLookupPrivByName(SE_INTERACTIVE_LOGON_NAME);
|
|
if ( i != -1 ) {
|
|
|
|
if ( SCEP_CHECK_PRIV_BIT(i,PrivLowMask,PrivHighMask) ) {
|
|
//
|
|
// logon locally right is defined
|
|
//
|
|
idxLocal = i;
|
|
}
|
|
}
|
|
|
|
//
|
|
// check if deny logon locally right is defined
|
|
//
|
|
|
|
i = ScepLookupPrivByName(SE_DENY_INTERACTIVE_LOGON_NAME);
|
|
if ( i != -1 ) {
|
|
|
|
if ( SCEP_CHECK_PRIV_BIT(i,PrivLowMask,PrivHighMask) ) {
|
|
//
|
|
// deny logon locally right is defined
|
|
//
|
|
idxDenyLocal = i;
|
|
}
|
|
}
|
|
|
|
if ( idxAllow == -1 && idxDeny == -1 && idxLocal == -1 && idxDenyLocal == -1 ) {
|
|
|
|
//
|
|
// none of them is defined so do not enforce anything
|
|
//
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// build well known SIDs for the enforcement
|
|
//
|
|
|
|
SID EveryoneSid;
|
|
SID AuthSid;
|
|
SID ControllerSid;
|
|
PSID AdminUserSid=NULL;
|
|
|
|
SID_IDENTIFIER_AUTHORITY WorldAuth = SECURITY_WORLD_SID_AUTHORITY;
|
|
SID_IDENTIFIER_AUTHORITY NtAuth = SECURITY_NT_AUTHORITY;
|
|
|
|
|
|
//
|
|
// initialize Administrators group sid
|
|
//
|
|
|
|
if ( ! NT_SUCCESS ( RtlAllocateAndInitializeSid( &NtAuth,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0,0,0,0,0,0,
|
|
&AdminsSid
|
|
) ) ) {
|
|
ScepLogOutput3(0,ERROR_NOT_ENOUGH_MEMORY,
|
|
SCEDLL_ADMINISTRATORS_SID);
|
|
|
|
//
|
|
// failure to initialize this one SID will still continue to other SIDs
|
|
//
|
|
}
|
|
|
|
//
|
|
// initialize administrator SID
|
|
//
|
|
|
|
if ( idxDenyLocal != -1 ) {
|
|
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Query the account domain SID
|
|
// failure to initialize this one SID will still continue to
|
|
// enforce other SIDs
|
|
//
|
|
|
|
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo=NULL;
|
|
|
|
Status = LsaQueryInformationPolicy( PolicyHandle,
|
|
PolicyAccountDomainInformation,
|
|
(PVOID *)&PolicyAccountDomainInfo );
|
|
|
|
|
|
if ( NT_SUCCESS(Status) && PolicyAccountDomainInfo &&
|
|
PolicyAccountDomainInfo->DomainSid ) {
|
|
|
|
Status = ScepDomainIdToSid(
|
|
PolicyAccountDomainInfo->DomainSid,
|
|
DOMAIN_USER_RID_ADMIN,
|
|
&AdminUserSid
|
|
);
|
|
|
|
}
|
|
|
|
if ( PolicyAccountDomainInfo ) {
|
|
LsaFreeMemory( PolicyAccountDomainInfo );
|
|
}
|
|
|
|
if ( AdminUserSid == NULL ) {
|
|
|
|
ScepLogOutput3(0, RtlNtStatusToDosError(Status),
|
|
SCEDLL_ADMINISTRATORS_SID);
|
|
}
|
|
}
|
|
|
|
//
|
|
// initialize well known SIDs
|
|
//
|
|
|
|
RtlInitializeSid ( &EveryoneSid, &WorldAuth, 1);
|
|
*RtlSubAuthoritySid ( &EveryoneSid, 0 ) = SECURITY_WORLD_RID;
|
|
|
|
RtlInitializeSid ( &AuthSid, &NtAuth, 1);
|
|
*RtlSubAuthoritySid ( &AuthSid, 0 ) = SECURITY_AUTHENTICATED_USER_RID;
|
|
|
|
RtlInitializeSid ( &ControllerSid, &NtAuth, 1);
|
|
*RtlSubAuthoritySid ( &ControllerSid, 0 ) = SECURITY_ENTERPRISE_CONTROLLERS_RID;
|
|
|
|
|
|
PSCE_PRIVILEGE_VALUE_LIST pTemp=*ppPrivilegeAssigned;
|
|
PSCE_PRIVILEGE_VALUE_LIST pParent=NULL;
|
|
|
|
BOOL bFindEveryone=FALSE;
|
|
BOOL bFindAuthUsers=FALSE;
|
|
BOOL bFindLocal=FALSE;
|
|
BOOL bFindController=FALSE;
|
|
BOOL bFindAdminUser=FALSE;
|
|
|
|
//
|
|
// loop through each one defined in the list to match the above SIDs
|
|
//
|
|
|
|
for ( ; pTemp != NULL; pParent=pTemp, pTemp=pTemp->Next) {
|
|
|
|
if ( pTemp->Name == NULL ) continue;
|
|
|
|
if ( (idxLocal != -1 || idxDenyLocal != -1) && !bFindLocal && AdminsSid &&
|
|
( bFindLocal = RtlEqualSid( (PSID)(pTemp->Name), AdminsSid) ) ) {
|
|
|
|
//
|
|
// make sure Administrators always have the interactive logon right
|
|
//
|
|
if ( idxLocal != -1 ) {
|
|
|
|
if ( !SCEP_CHECK_PRIV_BIT(idxLocal,pTemp->PrivLowPart,pTemp->PrivHighPart) ) {
|
|
|
|
ScepLogOutput3(0,0, SCESRV_ENFORCE_LOCAL_RIGHT, SE_INTERACTIVE_LOGON_NAME);
|
|
SCEP_ADD_PRIV_BIT(idxLocal, pTemp->PrivLowPart, pTemp->PrivHighPart)
|
|
}
|
|
}
|
|
|
|
//
|
|
// make sure administrators don't have deny interactive logon right
|
|
//
|
|
if ( idxDenyLocal != -1 ) {
|
|
|
|
if ( SCEP_CHECK_PRIV_BIT(idxDenyLocal,pTemp->PrivLowPart,pTemp->PrivHighPart) ) {
|
|
|
|
ScepLogOutput3(0,0, SCESRV_ENFORCE_DENY_LOCAL_RIGHT, SE_DENY_INTERACTIVE_LOGON_NAME);
|
|
SCEP_REMOVE_PRIV_BIT(idxDenyLocal, &(pTemp->PrivLowPart), &(pTemp->PrivHighPart))
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( (idxDeny != -1 || idxDenyLocal != -1) &&
|
|
( !bFindAuthUsers && ( bFindAuthUsers = RtlEqualSid( (PSID)(pTemp->Name), &AuthSid )) ) ||
|
|
( !bFindEveryone && ( bFindEveryone = RtlEqualSid( (PSID)(pTemp->Name), &EveryoneSid )) ) ) {
|
|
|
|
//
|
|
// find Authenticated Users or Everyone
|
|
// make sure they do not have the deny rights
|
|
//
|
|
|
|
if ( idxDenyLocal != -1 ) {
|
|
|
|
//
|
|
// remove the deny logon locally bit
|
|
//
|
|
|
|
if ( SCEP_CHECK_PRIV_BIT(idxDenyLocal,pTemp->PrivLowPart,pTemp->PrivHighPart) ) {
|
|
|
|
ScepLogOutput3(0,0, SCESRV_ENFORCE_DENY_LOCAL_RIGHT, SE_DENY_INTERACTIVE_LOGON_NAME);
|
|
SCEP_REMOVE_PRIV_BIT(idxDenyLocal, &(pTemp->PrivLowPart), &(pTemp->PrivHighPart))
|
|
}
|
|
}
|
|
|
|
if ( (idxDeny != -1) && (ProductType == NtProductLanManNt) ) {
|
|
|
|
//
|
|
// remove the deny network logon bit on domain controllers
|
|
//
|
|
|
|
if ( SCEP_CHECK_PRIV_BIT(idxDeny,pTemp->PrivLowPart,pTemp->PrivHighPart) ) {
|
|
|
|
ScepLogOutput3(0,0, SCESRV_ENFORCE_DENY_NETWORK_RIGHT, SE_DENY_NETWORK_LOGON_NAME);
|
|
SCEP_REMOVE_PRIV_BIT(idxDeny, &(pTemp->PrivLowPart), &(pTemp->PrivHighPart))
|
|
}
|
|
}
|
|
|
|
} else if ( !bFindController && (ProductType == NtProductLanManNt) &&
|
|
( bFindController = RtlEqualSid( (PSID)(pTemp->Name), &ControllerSid )) ) {
|
|
|
|
//
|
|
// find domain controller SID
|
|
// make sure it have network logon right and must not have deny network logon right
|
|
//
|
|
|
|
if ( idxDeny != -1 ) {
|
|
|
|
//
|
|
// remove the deny network logon bit
|
|
//
|
|
if ( SCEP_CHECK_PRIV_BIT(idxDeny,pTemp->PrivLowPart,pTemp->PrivHighPart) ) {
|
|
|
|
ScepLogOutput3(0,0, SCESRV_ENFORCE_DENY_NETWORK_RIGHT, SE_DENY_NETWORK_LOGON_NAME);
|
|
SCEP_REMOVE_PRIV_BIT(idxDeny, &(pTemp->PrivLowPart), &(pTemp->PrivHighPart))
|
|
}
|
|
}
|
|
|
|
if ( idxAllow != -1 ) {
|
|
|
|
//
|
|
// add the network logon bit
|
|
//
|
|
if ( !SCEP_CHECK_PRIV_BIT(idxAllow,pTemp->PrivLowPart,pTemp->PrivHighPart) ) {
|
|
|
|
ScepLogOutput3(0,0, SCESRV_ENFORCE_NETWORK_RIGHT, SE_NETWORK_LOGON_NAME);
|
|
SCEP_ADD_PRIV_BIT(idxAllow, pTemp->PrivLowPart, pTemp->PrivHighPart)
|
|
}
|
|
}
|
|
|
|
} else if ( idxDenyLocal != -1 && !bFindAdminUser && AdminUserSid &&
|
|
( bFindAdminUser = RtlEqualSid( (PSID)(pTemp->Name), AdminUserSid) ) ) {
|
|
|
|
//
|
|
// make sure administrator account don't have the deny right
|
|
//
|
|
|
|
if ( SCEP_CHECK_PRIV_BIT(idxDenyLocal,pTemp->PrivLowPart,pTemp->PrivHighPart) ) {
|
|
|
|
ScepLogOutput3(0,0, SCESRV_ENFORCE_DENY_LOCAL_RIGHT, SE_DENY_INTERACTIVE_LOGON_NAME);
|
|
SCEP_REMOVE_PRIV_BIT(idxDenyLocal, &(pTemp->PrivLowPart), &(pTemp->PrivHighPart))
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// all enforcement is done, break the loop now
|
|
//
|
|
|
|
if ( (idxLocal == -1 || bFindLocal) &&
|
|
( (idxDeny == -1 && idxDenyLocal == -1) || (bFindAuthUsers && bFindEveryone) ) &&
|
|
( bFindController || (ProductType != NtProductLanManNt) ) &&
|
|
(idxDenyLocal == -1 || bFindAdminUser) ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
SCESTATUS rc=SCESTATUS_SUCCESS;
|
|
|
|
if ( idxLocal != -1 && !bFindLocal && AdminsSid ) {
|
|
|
|
//
|
|
// make sure administrators have "logon locally right"
|
|
// add a new node the the end of the list
|
|
//
|
|
|
|
rc = ScepAddAccountRightToList(
|
|
ppPrivilegeAssigned,
|
|
&pParent,
|
|
idxLocal,
|
|
AdminsSid
|
|
);
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
ScepLogOutput3(0,0, SCESRV_ENFORCE_LOCAL_RIGHT, SE_INTERACTIVE_LOGON_NAME);
|
|
} else {
|
|
ScepLogOutput3(0,ERROR_NOT_ENOUGH_MEMORY, SCESRV_ERROR_ENFORCE_LOCAL_RIGHT, SE_INTERACTIVE_LOGON_NAME);
|
|
}
|
|
}
|
|
|
|
//
|
|
// if enterprise controllers is not found in the list
|
|
// and it's on a DC, should add it
|
|
//
|
|
|
|
rc=SCESTATUS_SUCCESS;
|
|
|
|
if ( idxAllow != -1 && !bFindController &&
|
|
( ProductType == NtProductLanManNt ) ) {
|
|
|
|
//
|
|
// make sure enterprise controllers have "network logon right"
|
|
//
|
|
|
|
rc = ScepAddAccountRightToList(
|
|
ppPrivilegeAssigned,
|
|
&pParent,
|
|
idxAllow,
|
|
&ControllerSid
|
|
);
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
ScepLogOutput3(0,0, SCESRV_ENFORCE_NETWORK_RIGHT, SE_NETWORK_LOGON_NAME);
|
|
} else {
|
|
ScepLogOutput3(0,ERROR_NOT_ENOUGH_MEMORY, SCESRV_ERROR_ENFORCE_NETWORK_RIGHT, SE_NETWORK_LOGON_NAME);
|
|
}
|
|
}
|
|
|
|
//
|
|
// free memory
|
|
//
|
|
|
|
if ( AdminsSid ) {
|
|
RtlFreeSid( AdminsSid );
|
|
AdminsSid = NULL;
|
|
}
|
|
|
|
if ( AdminUserSid ) {
|
|
RtlFreeSid( AdminUserSid );
|
|
}
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
SCESTATUS
|
|
ScepAddAccountRightToList(
|
|
IN OUT PSCE_PRIVILEGE_VALUE_LIST *ppPrivilegeAssigned,
|
|
IN OUT PSCE_PRIVILEGE_VALUE_LIST *ppParent,
|
|
IN INT idxRight,
|
|
IN PSID AccountSid
|
|
)
|
|
/*
|
|
Description:
|
|
|
|
Create a new node linked to the end of the link list
|
|
|
|
The new node contains the AccountSid for the specified user right "idxRight"
|
|
|
|
*/
|
|
{
|
|
SCESTATUS rc=SCESTATUS_SUCCESS;
|
|
|
|
PSCE_PRIVILEGE_VALUE_LIST pPriv = (PSCE_PRIVILEGE_VALUE_LIST)ScepAlloc( LMEM_ZEROINIT,
|
|
sizeof(SCE_PRIVILEGE_VALUE_LIST));
|
|
if ( pPriv != NULL ) {
|
|
|
|
DWORD Length = RtlLengthSid ( AccountSid );
|
|
|
|
//
|
|
// allocate the sid buffer, note it's stored in the name field
|
|
//
|
|
|
|
pPriv->Name = (PWSTR)ScepAlloc( LMEM_ZEROINIT, Length);
|
|
|
|
if ( pPriv->Name != NULL ) {
|
|
|
|
//
|
|
// copy the SID in
|
|
//
|
|
|
|
RtlCopySid( Length, (PSID)(pPriv->Name), AccountSid );
|
|
|
|
//
|
|
// add the interactive logon right bit
|
|
//
|
|
|
|
SCEP_ADD_PRIV_BIT(idxRight, pPriv->PrivLowPart, pPriv->PrivHighPart)
|
|
|
|
//
|
|
// link to the list
|
|
//
|
|
|
|
if ( *ppParent != NULL )
|
|
(*ppParent)->Next = pPriv;
|
|
else
|
|
*ppPrivilegeAssigned = pPriv;
|
|
|
|
*ppParent = pPriv;
|
|
|
|
} else {
|
|
|
|
ScepFree(pPriv);
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
}
|
|
|
|
} else {
|
|
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepAddAceToSecurityDescriptor(
|
|
IN DWORD AceType,
|
|
IN ACCESS_MASK AccessMask,
|
|
IN PSID pSid,
|
|
IN OUT PSECURITY_DESCRIPTOR pSDAbsolute,
|
|
IN PSECURITY_DESCRIPTOR pSDSelfRelative,
|
|
OUT PACL *ppNewAcl
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
This routine adds an ACE to a Security Descriptor (at the head only).
|
|
|
|
Two optimizations are attempted in adding the ACE.
|
|
|
|
Arguments:
|
|
|
|
AceType - type of ACE to add
|
|
|
|
AccessMask - access mask of ACE to set
|
|
|
|
pSid - sid for ACE to add
|
|
|
|
pSDAbsolute - absolute SD ptr to build. pSDAbsolute must be empty.
|
|
It's vacuous in the caller's stack hence no SD member
|
|
should be freed outside this routine.
|
|
|
|
pSDSelfRelative - self relative SD to get DACL information from
|
|
|
|
ppNewAcl - ptr to the new DACL which needs to be freed outside
|
|
|
|
Return Value:
|
|
|
|
Win32 error code
|
|
*/
|
|
{
|
|
|
|
DWORD rc = ERROR_SUCCESS;
|
|
BOOL bOrMaskInOldDacl = FALSE;
|
|
|
|
if (ppNewAcl == NULL ||
|
|
pSDAbsolute == NULL ||
|
|
pSDSelfRelative == NULL ||
|
|
(AceType != ACCESS_ALLOWED_ACE_TYPE && AceType != ACCESS_DENIED_ACE_TYPE )
|
|
) {
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
PACL pNewAcl = *ppNewAcl = NULL;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
BOOLEAN bAclPresent = FALSE;
|
|
PACL pOldAcl = NULL;
|
|
BOOLEAN bDaclDefaulted = FALSE;
|
|
DWORD dwNewAclSize = 0;
|
|
DWORD dwAceSize = 0;
|
|
ACE_HEADER *pFirstAce = NULL;
|
|
DWORD dwFirstAceSize = 0;
|
|
|
|
NtStatus = RtlGetDaclSecurityDescriptor(
|
|
pSDSelfRelative,
|
|
&bAclPresent,
|
|
&pOldAcl,
|
|
&bDaclDefaulted);
|
|
|
|
rc = RtlNtStatusToDosError( NtStatus );
|
|
|
|
if ( rc != ERROR_SUCCESS )
|
|
goto Cleanup;
|
|
|
|
//
|
|
// null DACL should never happen - CliffV
|
|
// we shouldn't set the DACL with the one
|
|
// anonymous ACE only since it will deny
|
|
// all other SID's any access
|
|
//
|
|
|
|
if ( !bAclPresent ||
|
|
pOldAcl == NULL ||
|
|
pOldAcl->AceCount == 0 ) {
|
|
|
|
rc = ERROR_INVALID_ACL;
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
NtStatus = RtlGetAce( pOldAcl,
|
|
0,
|
|
(PVOID *) &pFirstAce);
|
|
|
|
rc = RtlNtStatusToDosError( NtStatus );
|
|
|
|
if ( rc != ERROR_SUCCESS )
|
|
goto Cleanup;
|
|
|
|
//
|
|
// if the first ACE is for the SID passed in attempt two optimizations
|
|
//
|
|
|
|
if ( RtlValidSid((PSID)&((PKNOWN_ACE)pFirstAce)->SidStart) &&
|
|
RtlEqualSid((PSID)&((PKNOWN_ACE)pFirstAce)->SidStart, pSid)) {
|
|
|
|
if (pFirstAce->AceType == AceType) {
|
|
|
|
//
|
|
// Optimization 1:
|
|
// simply OR in the mask
|
|
//
|
|
|
|
((PKNOWN_ACE)pFirstAce)->Mask |= AccessMask;
|
|
|
|
bOrMaskInOldDacl = TRUE;
|
|
|
|
goto SetDacl;
|
|
}
|
|
|
|
else if (((PKNOWN_ACE)pFirstAce)->Mask == AccessMask ) {
|
|
|
|
//
|
|
// Optimization 2:
|
|
// if only AccessMask is turned on, later on
|
|
// (a) prepare a new ACE
|
|
// (b) copy the old ACL except the first ACE
|
|
//
|
|
|
|
//
|
|
// remember the size of the first ACE since we need to skip it
|
|
//
|
|
|
|
dwFirstAceSize = (DWORD)(((PKNOWN_ACE)pFirstAce)->Header.AceSize);
|
|
}
|
|
}
|
|
|
|
|
|
switch (AceType) {
|
|
case ACCESS_ALLOWED_ACE_TYPE:
|
|
dwAceSize = sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(pSid) - sizeof(ULONG);
|
|
break;
|
|
case ACCESS_DENIED_ACE_TYPE:
|
|
dwAceSize = sizeof(ACCESS_DENIED_ACE) + RtlLengthSid(pSid) - sizeof(ULONG);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
dwNewAclSize = dwAceSize + pOldAcl->AclSize - dwFirstAceSize;
|
|
|
|
*ppNewAcl = pNewAcl = (PACL) LocalAlloc(LMEM_ZEROINIT, dwNewAclSize);
|
|
|
|
if ( pNewAcl == NULL ) {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// initialize the ACL
|
|
//
|
|
|
|
pNewAcl->AclSize = (USHORT) dwNewAclSize;
|
|
pNewAcl->AclRevision = ACL_REVISION;
|
|
pNewAcl->AceCount = 0;
|
|
|
|
//
|
|
// add allow/deny ACE to the head of the ACL
|
|
//
|
|
|
|
switch (AceType) {
|
|
case ACCESS_ALLOWED_ACE_TYPE:
|
|
|
|
if ( ! AddAccessAllowedAce(
|
|
pNewAcl,
|
|
ACL_REVISION,
|
|
AccessMask,
|
|
pSid
|
|
) ) {
|
|
rc = GetLastError();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ACCESS_DENIED_ACE_TYPE:
|
|
|
|
if ( ! AddAccessDeniedAce(
|
|
pNewAcl,
|
|
ACL_REVISION,
|
|
AccessMask,
|
|
pSid
|
|
) ) {
|
|
rc = GetLastError();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ( rc != ERROR_SUCCESS)
|
|
goto Cleanup;
|
|
|
|
//
|
|
// copy all the ACEs in the old ACL after the newly added ACE
|
|
// (potentially skipping the first ACE in the old ACL)
|
|
//
|
|
|
|
memcpy((PUCHAR)pNewAcl + sizeof(ACL) + dwAceSize,
|
|
(PUCHAR)pOldAcl + sizeof(ACL) + dwFirstAceSize,
|
|
pOldAcl->AclSize - (sizeof(ACL) + dwFirstAceSize) );
|
|
|
|
pNewAcl->AceCount += pOldAcl->AceCount;
|
|
|
|
if ( dwFirstAceSize != 0 )
|
|
--pNewAcl->AceCount;
|
|
|
|
SetDacl:
|
|
|
|
//
|
|
// either set the adjusted-ACE ACL, or the added-ACE ACL in the SD
|
|
//
|
|
|
|
if ( rc == ERROR_SUCCESS ) {
|
|
|
|
NtStatus = RtlSetDaclSecurityDescriptor (
|
|
pSDAbsolute,
|
|
TRUE,
|
|
( bOrMaskInOldDacl ? pOldAcl : pNewAcl),
|
|
FALSE
|
|
);
|
|
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
|
|
}
|
|
|
|
if ( rc == ERROR_SUCCESS ) {
|
|
|
|
if ( !IsValidSecurityDescriptor(pSDAbsolute) )
|
|
|
|
rc = ERROR_INVALID_SECURITY_DESCR;
|
|
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
if (pNewAcl)
|
|
LocalFree(pNewAcl);
|
|
*ppNewAcl = NULL;
|
|
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD
|
|
ScepConfigureLSAPolicyObject(
|
|
IN DWORD dwLSAAnonymousNameLookup,
|
|
IN DWORD ConfigOptions,
|
|
IN PSCE_ERROR_LOG_INFO *pErrLog OPTIONAL,
|
|
OUT BOOL *pbOldLSAPolicyDifferent
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
This routine *actually* configures the LSA policy security descriptor ONLY if required.
|
|
|
|
Arguments:
|
|
|
|
dwLSAAnonymousNameLookup - the value of the desired setting
|
|
|
|
ConfigOptions - configuration options
|
|
|
|
pErrLog - ptr to error log list
|
|
|
|
pbOldLSAPolicyDifferent - ptr to boolean that says whether or not the
|
|
existing setting is different from the desired setting
|
|
this information is required for tattooing
|
|
|
|
Return Value:
|
|
|
|
Win32 error code
|
|
*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
DWORD rc = ERROR_SUCCESS;
|
|
PACL pNewAcl = NULL;
|
|
DWORD dwAceType;
|
|
BOOL bAddAce = FALSE;
|
|
PSECURITY_DESCRIPTOR pSDCurrentLsaPolicyObject = NULL;
|
|
SECURITY_DESCRIPTOR SDAbsoluteToBuildAndSet;
|
|
|
|
if (pbOldLSAPolicyDifferent == NULL ||
|
|
(dwLSAAnonymousNameLookup != 0 && dwLSAAnonymousNameLookup != 1))
|
|
{
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
LSA_HANDLE LsaHandle = NULL;
|
|
|
|
if ( LsaPrivatePolicy == NULL ) {
|
|
|
|
NtStatus = ScepOpenLsaPolicy(
|
|
MAXIMUM_ALLOWED,
|
|
&LsaHandle,
|
|
TRUE
|
|
);
|
|
|
|
rc = RtlNtStatusToDosError( NtStatus );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
LsaHandle = LsaPrivatePolicy;
|
|
|
|
}
|
|
|
|
if ( !NT_SUCCESS( NtStatus ) ) {
|
|
|
|
if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) && pErrLog ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_LSA_POLICY
|
|
);
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_LSA_POLICY);
|
|
}
|
|
}
|
|
|
|
if ( rc == ERROR_SUCCESS ) {
|
|
|
|
NtStatus = LsaQuerySecurityObject(
|
|
LsaHandle,
|
|
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
|
&pSDCurrentLsaPolicyObject
|
|
);
|
|
|
|
rc = RtlNtStatusToDosError( NtStatus );
|
|
|
|
if ( !NT_SUCCESS( NtStatus ) ) {
|
|
|
|
if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) && pErrLog ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_SCP_ERROR_LSAPOLICY_QUERY
|
|
);
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_ERROR_LSAPOLICY_QUERY);
|
|
}
|
|
}
|
|
|
|
if ( rc == ERROR_SUCCESS ) {
|
|
|
|
LPTSTR pwszSDlsaPolicyObject = NULL;
|
|
|
|
//
|
|
// log the SDDL SD for diagnostics
|
|
//
|
|
|
|
if ( ConvertSecurityDescriptorToStringSecurityDescriptor(
|
|
pSDCurrentLsaPolicyObject,
|
|
SDDL_REVISION_1,
|
|
DACL_SECURITY_INFORMATION,
|
|
&pwszSDlsaPolicyObject,
|
|
NULL
|
|
) ){
|
|
|
|
ScepLogOutput3(1,0,SCEDLL_SCP_INFO_LSAPOLICY_EXISTING_SDDL, pwszSDlsaPolicyObject);
|
|
|
|
LocalFree(pwszSDlsaPolicyObject);
|
|
|
|
}
|
|
|
|
//
|
|
// use AUTHZ to check if desired access is existing access
|
|
//
|
|
|
|
if ( ghAuthzResourceManager ) {
|
|
|
|
SID AnonymousSid;
|
|
SID_IDENTIFIER_AUTHORITY NtAuth = SECURITY_NT_AUTHORITY;
|
|
AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClientContext = NULL;
|
|
LUID Identifier = {0};
|
|
|
|
RtlInitializeSid ( &AnonymousSid, &NtAuth, 1);
|
|
*RtlSubAuthoritySid ( &AnonymousSid, 0 ) = SECURITY_ANONYMOUS_LOGON_RID;
|
|
|
|
if ( AuthzInitializeContextFromSid(0,
|
|
&AnonymousSid,
|
|
ghAuthzResourceManager,
|
|
0,
|
|
Identifier,
|
|
NULL,
|
|
&hAuthzClientContext) ) {
|
|
|
|
AUTHZ_ACCESS_REPLY AuthzReply;
|
|
AUTHZ_ACCESS_REQUEST AuthzRequest;
|
|
ACCESS_MASK GrantedAccessMask;
|
|
DWORD AuthzError;
|
|
|
|
AuthzReply.ResultListLength = 1;
|
|
AuthzReply.GrantedAccessMask = &GrantedAccessMask;
|
|
AuthzReply.Error = &AuthzError;
|
|
AuthzReply.SaclEvaluationResults = NULL;
|
|
|
|
memset(&AuthzRequest, 0, sizeof(AuthzRequest));
|
|
AuthzRequest.DesiredAccess = POLICY_LOOKUP_NAMES;
|
|
|
|
DWORD AceType = 0;
|
|
|
|
if ( AuthzAccessCheck(0,
|
|
hAuthzClientContext,
|
|
&AuthzRequest,
|
|
NULL,
|
|
pSDCurrentLsaPolicyObject,
|
|
NULL,
|
|
NULL,
|
|
&AuthzReply,
|
|
NULL) ) {
|
|
|
|
//
|
|
// check if existing access is different from desired access
|
|
// if so, add the appropriate ACE or manipulate existing ACEs
|
|
// to get the desired permissions
|
|
//
|
|
|
|
if ( GrantedAccessMask & POLICY_LOOKUP_NAMES ) {
|
|
//ASSERT(AuthzError == ERROR_SUCCESS);
|
|
if ( !dwLSAAnonymousNameLookup ) {
|
|
|
|
bAddAce = TRUE;
|
|
AceType = ACCESS_DENIED_ACE_TYPE;
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
//ASSERT(AuthzError == ERROR_ACCESS_DENIED || AuthzError == ERROR_PRIVILEGE_NOT_HELD);
|
|
if ( dwLSAAnonymousNameLookup ) {
|
|
|
|
bAddAce = TRUE;
|
|
AceType = ACCESS_ALLOWED_ACE_TYPE;
|
|
|
|
}
|
|
}
|
|
|
|
if ( bAddAce ) {
|
|
|
|
*pbOldLSAPolicyDifferent = TRUE;
|
|
|
|
if ( InitializeSecurityDescriptor( &SDAbsoluteToBuildAndSet, SECURITY_DESCRIPTOR_REVISION) ) {
|
|
|
|
rc = ScepAddAceToSecurityDescriptor(
|
|
AceType,
|
|
POLICY_LOOKUP_NAMES,
|
|
&AnonymousSid,
|
|
&SDAbsoluteToBuildAndSet,
|
|
pSDCurrentLsaPolicyObject,
|
|
&pNewAcl
|
|
);
|
|
|
|
if ( rc == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// log the SDDL SD for diagnostics
|
|
//
|
|
pwszSDlsaPolicyObject = NULL;
|
|
|
|
if ( ConvertSecurityDescriptorToStringSecurityDescriptor(
|
|
&SDAbsoluteToBuildAndSet,
|
|
SDDL_REVISION_1,
|
|
DACL_SECURITY_INFORMATION,
|
|
&pwszSDlsaPolicyObject,
|
|
NULL
|
|
) ){
|
|
|
|
ScepLogOutput3(1,0,SCEDLL_SCP_INFO_LSAPOLICY_COMPUTED_SDDL, pwszSDlsaPolicyObject);
|
|
|
|
LocalFree(pwszSDlsaPolicyObject);
|
|
|
|
}
|
|
|
|
NtStatus = LsaSetSecurityObject(
|
|
LsaHandle,
|
|
DACL_SECURITY_INFORMATION,
|
|
&SDAbsoluteToBuildAndSet
|
|
);
|
|
|
|
LocalFree(pNewAcl);
|
|
|
|
rc = RtlNtStatusToDosError( NtStatus );
|
|
|
|
if ( !NT_SUCCESS( NtStatus ) ) {
|
|
|
|
if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) && pErrLog ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_SCP_ERROR_LSAPOLICY_SET
|
|
);
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_ERROR_LSAPOLICY_SET);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) && pErrLog ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_SCP_ERROR_LSAPOLICY_BUILDDACL
|
|
);
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_ERROR_LSAPOLICY_BUILDDACL);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rc = GetLastError();
|
|
|
|
if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) && pErrLog ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_SCP_ERROR_LSAPOLICY_SD_INIT
|
|
);
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_ERROR_LSAPOLICY_SD_INIT);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rc = GetLastError();
|
|
|
|
if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) && pErrLog ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_SCP_ERROR_LSAPOLICY_AUTHZ
|
|
);
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_ERROR_LSAPOLICY_AUTHZ);
|
|
}
|
|
|
|
}
|
|
|
|
AuthzFreeContext( hAuthzClientContext );
|
|
|
|
} else {
|
|
|
|
rc = GetLastError();
|
|
|
|
if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) && pErrLog ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_SCP_ERROR_LSAPOLICY_AUTHZ
|
|
);
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_ERROR_LSAPOLICY_AUTHZ);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rc = ERROR_RESOURCE_NOT_PRESENT;
|
|
|
|
if ( (ConfigOptions & SCE_SYSTEM_SETTINGS) && pErrLog ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_SCP_ERROR_LSAPOLICY_AUTHZ
|
|
);
|
|
} else {
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_ERROR_LSAPOLICY_AUTHZ);
|
|
}
|
|
|
|
}
|
|
|
|
LsaFreeMemory(pSDCurrentLsaPolicyObject);
|
|
|
|
}
|
|
|
|
if ( LsaPrivatePolicy == NULL ) {
|
|
|
|
LsaClose(LsaHandle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
SCESTATUS
|
|
ScepConfigureLSAAnonymousLookup(
|
|
IN PSCE_PROFILE_INFO pScpInfo,
|
|
IN DWORD ConfigOptions,
|
|
IN PSCE_ERROR_LOG_INFO *pErrLog)
|
|
|
|
/* ++
|
|
|
|
Routine Description:
|
|
|
|
This routine configures LSA anonymous lookup policy
|
|
|
|
Arguments:
|
|
|
|
pScpInfo - The buffer which contains SCP info loaded from the profile
|
|
|
|
ConfigOptions - options in configuration
|
|
|
|
pErrLog - the output log for potential errors
|
|
|
|
-- */
|
|
{
|
|
DWORD rc=ERROR_SUCCESS;
|
|
PSCESECTION hSectionDomain=NULL;
|
|
PSCESECTION hSectionTattoo=NULL;
|
|
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
ScepIsSystemShutDown() )
|
|
{
|
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|
}
|
|
|
|
if ( pScpInfo->LSAAnonymousNameLookup != SCE_NO_VALUE )
|
|
{
|
|
BOOL bImpliedOldLSAPolicyDifferent = FALSE;
|
|
DWORD dwImpliedOldLSAAnonymousNameLookup =
|
|
pScpInfo->LSAAnonymousNameLookup;
|
|
|
|
rc = ScepConfigureLSAPolicyObject(
|
|
pScpInfo->LSAAnonymousNameLookup,
|
|
ConfigOptions,
|
|
pErrLog,
|
|
&bImpliedOldLSAPolicyDifferent
|
|
);
|
|
|
|
if (bImpliedOldLSAPolicyDifferent)
|
|
{
|
|
dwImpliedOldLSAAnonymousNameLookup =
|
|
(pScpInfo->LSAAnonymousNameLookup ? 0 : 1);
|
|
}
|
|
|
|
//
|
|
// if this is policy propagation, we need to open the sections for
|
|
// updating undo settings if this is not domain controller
|
|
// *** on DCs, domain account policy can't be reset'ed to tattoo
|
|
// on each individual DC. So there is no point to query/save tattoo values
|
|
//
|
|
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
|
|
(ProductType != NtProductLanManNt))
|
|
{
|
|
ScepTattooOpenPolicySections(
|
|
hProfile,
|
|
szSystemAccess,
|
|
&hSectionDomain,
|
|
&hSectionTattoo
|
|
);
|
|
|
|
ScepTattooManageOneIntValue(
|
|
hSectionDomain,
|
|
hSectionTattoo,
|
|
(PWSTR)L"LSAAnonymousNameLookup",
|
|
0,
|
|
dwImpliedOldLSAAnonymousNameLookup,
|
|
rc);
|
|
}
|
|
|
|
if ((ConfigOptions & SCE_SYSTEM_SETTINGS) &&
|
|
pErrLog )
|
|
{
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrLog,
|
|
SCEDLL_SCP_LSAPOLICY
|
|
);
|
|
}
|
|
else
|
|
{
|
|
ScepLogOutput3(1, rc, SCEDLL_SCP_LSAPOLICY);
|
|
}
|
|
|
|
if (ConfigOptions & SCE_RSOP_CALLBACK)
|
|
{
|
|
ScepRsopLog(SCE_RSOP_LSA_POLICY_INFO, rc, NULL, 0, 0);
|
|
}
|
|
}
|
|
|
|
if ( hSectionDomain )
|
|
{
|
|
SceJetCloseSection( &hSectionDomain, TRUE );
|
|
}
|
|
if ( hSectionTattoo )
|
|
{
|
|
SceJetCloseSection( &hSectionTattoo, TRUE );
|
|
}
|
|
|
|
return(ScepDosErrorToSceStatus(rc));
|
|
}
|