Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

10568 lines
321 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"
#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;
extern HINSTANCE MyModuleHandle;
extern AUTHZ_RESOURCE_MANAGER_HANDLE ghAuthzResourceManager;
#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
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 PSID GrpSid,
IN PSCE_NAME_LIST pAliasList
);
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 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
);
//
// 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 queued
//
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;
}
//
// 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);
rc = ScepConfigureObjectSecurity( pScpInfo->pRegistryKeys.pOneLevel,
AREA_REGISTRY_SECURITY,
(ConfigOptions & SCE_POLICY_TEMPLATE) ? TRUE : FALSE,
ConfigOptions
);
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 ) ) {
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);
}
}
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;
//
// 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;
}
//
// 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;GRGW;;;WD)(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
//
PSCE_ERROR_LOG_INFO Errlog=NULL;
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*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 );
NTSTATUS NtStatus;
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);
}
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;
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 ) {
NtStatus = SamSetInformationDomain(
DomainHandle,
DomainPasswordInformation,
Buffer
);
rc = RtlNtStatusToDosError( NtStatus );
}
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);
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 ) {
NtStatus = SamSetInformationDomain(
DomainHandle,
DomainLockoutInformation,
Buffer
);
rc = RtlNtStatusToDosError( NtStatus );
}
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);
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 ) {
NtStatus = SamSetInformationDomain(
DomainHandle,
DomainLogoffInformation,
Buffer
);
rc = RtlNtStatusToDosError( NtStatus );
}
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);
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 ( (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);
}
//
// LSAAnonymousNameLookup
//
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 ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
( ProductType != NtProductLanManNt ) ) {
ScepTattooManageOneIntValue(hSectionDomain,
hSectionTattoo,
(PWSTR)L"LSAAnonymousNameLookup",
0,
(ProductType == NtProductLanManNt) ? SCEDCPOL_LSA_ANON_LOOKUP : dwImpliedOldLSAAnonymousNameLookup, rc);
}
if ( rc != ERROR_SUCCESS ) {
SaveStat = rc;
}
else {
ScepLogOutput3(1, 0, SCEDLL_SCP_LSAPOLICY);
}
if (ConfigOptions & SCE_RSOP_CALLBACK)
ScepRsopLog(SCE_RSOP_LSA_POLICY_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;
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 );
RtlCreateUnicodeString(&(Buffer1.FullName), TempStr);
RtlCreateUnicodeString(&(Buffer1.UserName), NewName );
NtStatus = SamSetInformationUser(
UserHandle1,
UserNameInformation,
(PVOID)&Buffer1
);
RtlFreeUnicodeString( &(Buffer1.FullName) );
RtlFreeUnicodeString( &(Buffer1.UserName) );
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);
}
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,
256
);
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,
256
);
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,
256
);
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 ) {
//
// 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;
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) ) {
//
// it's not possible to get a foreign domain group into the tattoo
// table so we don't handle the tattoo values here
//
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;
}
}
//
// member of
//
if ( (pGroup->pMemberOf != NULL) &&
!(pGroup->Status & SCE_GROUP_STATUS_NC_MEMBEROF) ) {
switch ( GrpUse[0] ) {
case SidTypeGroup:
//
// group can be members of alias only
//
NtStatus = ScepValidateGroupInAliases(
DomainHandle,
BuiltinDomainHandle,
GrpSid,
pGroup->pMemberOf
);
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);
return( ScepDosErrorToSceStatus(rc) );
}
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,
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);
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,
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);
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
ScepValidateGroupInAliases(
IN SAM_HANDLE DomainHandle,
IN SAM_HANDLE BuiltinDomainHandle,
IN PSID GrpSid,
IN PSCE_NAME_LIST pAliasList
)
/* ++
Routine Description:
This routine add the group to a list of alieses to ensure the group's
membership.
Arguments:
DomainHandle - The account domain handle
BuiltinDomainHandle - The builtin domain handle
GrpSid - The group's SID
pAliasList - the list of aliases to check
-- */
{
NTSTATUS NtStatus;
PSCE_NAME_LIST pAlias;
UNICODE_STRING Name;
PULONG AliasId=NULL;
PSID_NAME_USE AliasUse=NULL;
SAM_HANDLE ThisDomain;
SAM_HANDLE AliasHandle=NULL;
PWSTR pTemp;
UNICODE_STRING uName;
//
// Process each alias in the list
//
for ( pAlias=pAliasList; pAlias != NULL; pAlias = pAlias->Next ) {
//
// should expect pGroup->Name has domain prefix
//
pTemp = wcschr(pAlias->Name, L'\\');
if ( pTemp ) {
//
// check if this group is from a different domain
//
uName.Buffer = pAlias->Name;
uName.Length = ((USHORT)(pTemp-pAlias->Name))*sizeof(TCHAR);
if ( !ScepIsDomainLocal(&uName) ) {
ScepLogOutput3(1, 0, SCEDLL_NO_MAPPINGS, pAlias->Name);
continue;
}
pTemp++;
} else {
pTemp = pAlias->Name;
}
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_NO_MAPPINGS, pTemp);
return(NtStatus);
}
//
// add the group to the alias
//
if ( AliasUse[0] != SidTypeAlias ) {
ScepLogOutput3(1,0, SCEDLL_ERROR_ALIAS_MEMBEROF);
SamFreeMemory(AliasId);
AliasId = NULL;
SamFreeMemory(AliasUse);
AliasUse = NULL;
continue; // ignore this error goto Done;
}
NtStatus = SamOpenAlias(
ThisDomain,
MAXIMUM_ALLOWED, // ? ALIAS_ALL_ACCESS,
AliasId[0],
&AliasHandle
);
if ( !NT_SUCCESS(NtStatus) ) {
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
SCEDLL_ERROR_OPEN, pAlias->Name);
goto Done;
}
NtStatus = SamAddMemberToAlias(
AliasHandle,
GrpSid
);
//
// if group is already in alias, ignore the error
//
if ( NtStatus == STATUS_MEMBER_IN_ALIAS )
NtStatus = STATUS_SUCCESS;
if ( !NT_SUCCESS(NtStatus) ) {
ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
SCEDLL_SCP_ERROR_ADDTO, pAlias->Name);
goto Done;
}
//
// free memory for this group
//
SamCloseHandle(AliasHandle);
AliasHandle = NULL;
SamFreeMemory(AliasId);
AliasId = NULL;
SamFreeMemory(AliasUse);
AliasUse = NULL;
}
Done:
if ( AliasHandle != NULL )
SamCloseHandle(AliasHandle);
if ( AliasId != NULL )
SamFreeMemory(AliasId);
if ( AliasUse != NULL )
SamFreeMemory(AliasUse);
return(NtStatus);
}
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,
FALSE,
&Token)) {
if (!OpenProcessToken( GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&Token)) {
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
) == TRUE ) {
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 ) {
//
// query existing value
//
if ( ERROR_SUCCESS != ScepRegQueryIntValue(HKEY_LOCAL_MACHINE,
MsgBuf,
L"MaxSize",
&OldMaxSize
) )
OldMaxSize = SCE_NO_VALUE;
else
OldMaxSize /= 1024;
}
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 Buffer[MAX_PATH+1];
TCHAR FileName[MAX_PATH+50];
Buffer[0] = L'\0';
GetSystemWindowsDirectory(Buffer, MAX_PATH);
Buffer[MAX_PATH] = L'\0';
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 ) {
wcscpy(FileName, Buffer);
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, Buffer);
wcscat(FileName, 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;
rc = (*pfSceInfWriteInfo)(
FileName,
AREA_SECURITY_POLICY,
pTmpBuffer,
NULL
);
//
// 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, Buffer);
wcscat(FileName, 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;
}
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;
}
//
// 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);
}
DWORD
ScepTattooCurrentGroupMembers(
IN PSID ThisDomainSid,
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 ) {
for ( j=0; j<MemberCount; j++ ) {
if ( MemberAliasSids[j] != NULL ) {
//
// add member to the list
//
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(AUTHZ_SKIP_TOKEN_GROUPS,
&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;
}