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