Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3749 lines
111 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
polclnt.cpp
Abstract:
SCE policy integration Client APIs
Author:
Jin Huang (jinhuang) 23-Jun-1997 created
Revision History:
jinhuang 23-Jan-1998 split to client-server model
--*/
#include "headers.h"
#include "sceutil.h"
#include "clntutil.h"
#include "infp.h"
#include <io.h>
#include <userenv.h>
//#include <shlwapi.h>
//#include "userenvp.h"
#include "scedllrc.h"
#include "dsrole.h"
#include "commonrc.h"
#include "precedence.h"
#include "cgenericlogger.h"
#pragma hdrstop
#include <wincrypt.h>
#include <ntlsa.h>
#include <lmaccess.h>
CRITICAL_SECTION DiagnosisPolicypropSync;
static HANDLE ghAsyncThread = NULL;
extern HINSTANCE MyModuleHandle;
BOOL gbAsyncWinlogonThread;
//
// global into which the RSOP namespace ptr is stashed
// for use when server calls back - diagnosis mode only
//
IWbemServices *tg_pWbemServices = NULL;
//
// global into which the RSOP synch status is stashed
// for use when server calls back - diagnosis mode only
//
HRESULT gHrSynchRsopStatus;
//
// global into which the RSOP asynch status is stashed
// for use when asynch thread done - diagnosis mode only
//
HRESULT gHrAsynchRsopStatus;
typedef DWORD (WINAPI *PFGETDOMAININFO)(LPCWSTR, DSROLE_PRIMARY_DOMAIN_INFO_LEVEL, PBYTE *);
typedef VOID (WINAPI *PFDSFREE)( PVOID );
//
// no need to critical section these variables because propagation always call to
// this dll in sequence.
//
BOOL gbThisIsDC = FALSE;
BOOL gbDCQueried = FALSE;
PWSTR gpwszDCDomainName = NULL;
GUID SceExtGuid = { 0x827D319E, 0x6EAC, 0x11D2, { 0xA4, 0xEA, 0x0, 0xC0, 0x4F, 0x79, 0xF8, 0x3A } };
typedef enum _SCE_ATTACHMENT_TYPE_ {
SCE_ATTACHMENT_SERVICE,
SCE_ATTACHMENT_POLICY
} SCE_ATTACHMENT_TYPE;
typedef struct {
ASYNCCOMPLETIONHANDLE pHandle;
LPWSTR szTemplateName;
LPWSTR szLogName;
AREA_INFORMATION Area;
DWORD dwDiagOptions;
LPSTREAM pStream;
} ENGINEARGS;
static HMODULE hSceDll=NULL;
//
// private functions
//
DWORD
ScepPolStatusCallback(
IN PFNSTATUSMESSAGECALLBACK pStatusCallback OPTIONAL,
IN BOOL bVerbose,
IN INT nId
);
BOOL
ScepShouldTerminateProcessing(
IN BOOL *pbAbort,
IN BOOL bCheckDcpromo
);
BOOL
ScepClearGPObjects(
IN BOOL bPlanning
);
DWORD
ScepControlNotificationQProcess(
IN PWSTR szLogFileName,
IN BOOL bThisIsDC,
IN DWORD ControlFlag
);
/*
BOOL
ScepCheckDemote();
*/
DWORD
SceProcessBeforeRSOPLogging(
IN BOOL bPlanningMode,
IN DWORD dwFlags,
IN HANDLE hUserToken,
IN HKEY hKeyRoot,
IN PGROUP_POLICY_OBJECT pDeletedGPOList OPTIONAL,
IN PGROUP_POLICY_OBJECT pChangedGPOList,
IN ASYNCCOMPLETIONHANDLE pHandle OPTIONAL,
IN BOOL *pbAbort,
IN PFNSTATUSMESSAGECALLBACK pStatusCallback OPTIONAL,
OUT AREA_INFORMATION *pAllAreas OPTIONAL,
OUT BOOL *pb OPTIONAL,
OUT PWSTR *pszLogFileName OPTIONAL,
OUT DWORD *pdwWinlogonLog OPTIONAL
);
DWORD
SceProcessAfterRSOPLogging(
IN DWORD dwFlags,
IN ASYNCCOMPLETIONHANDLE pHandle,
IN BOOL *pbAbort,
IN PFNSTATUSMESSAGECALLBACK pStatusCallback,
IN AREA_INFORMATION ThisAreas,
IN BOOL b,
IN PWSTR *ppszLogFileName,
IN DWORD dwWinlogonLog,
IN DWORD dwDiagOptions
);
DWORD
ScepProcessSecurityPolicyInOneGPO(
IN BOOL bPlanningMode,
IN DWORD dwFlags,
IN PGROUP_POLICY_OBJECT pGpoInfo,
IN LPTSTR szLogFileName OPTIONAL,
IN OUT AREA_INFORMATION *pTotalArea
);
AREA_INFORMATION
ScepGetAvailableArea(
IN BOOL bPlanningMode,
IN LPCTSTR SysPathRoot,
IN LPCTSTR DSPath,
IN LPTSTR InfName,
IN GPO_LINK LinkInfo,
IN BOOL bIsDC
);
DWORD
ScepLogLastConfigTime();
DWORD
ScepWinlogonThreadFunc(LPVOID lpv);
DWORD
ScepEnumerateAttachments(
OUT PSCE_NAME_LIST *pEngineList,
IN SCE_ATTACHMENT_TYPE aType
);
DWORD
ScepConfigureEFSPolicy(
IN PUCHAR pEfsBlob,
IN DWORD dwSize,
IN DWORD dwDebugLevel
);
DWORD
ScepWaitConfigSystem(
IN LPTSTR SystemName OPTIONAL,
IN PWSTR InfFileName OPTIONAL,
IN PWSTR DatabaseName OPTIONAL,
IN PWSTR LogFileName OPTIONAL,
IN DWORD ConfigOptions,
IN AREA_INFORMATION Area,
IN PSCE_AREA_CALLBACK_ROUTINE pCallback OPTIONAL,
IN HANDLE hCallbackWnd OPTIONAL,
OUT PDWORD pdWarning OPTIONAL
);
DSROLE_MACHINE_ROLE gMachineRole = DsRole_RoleStandaloneWorkstation;
//
// the new interface - client side extension for RSOP Planning mode
//
DWORD
WINAPI
SceGenerateGroupPolicy(
IN DWORD dwFlags,
IN BOOL *pAbort,
IN WCHAR *pwszSite,
IN PRSOP_TARGET pComputerTarget,
IN PRSOP_TARGET pUserTarget
)
/*
Description:
This is the new interface called from winlogon/userenv to generate planning
RSOP data. The dll name and procedure name are registered to winlogon under
GpExtensions.
This routine simulates a SCE group policy template to the current system.
The template can be in domain level, OU level, or user level.
The input argument contains info about the GPOs to be simulated and a namespace
pointer to log the RSOP data.
This interface shouldn't be called for user policy.
Arguments:
dwFlags - the GPO Info flags
GPO_INFO_FLAG_MACHINE
GPO_INFO_FLAG_SLOWLINK
GPO_INFO_FLAG_BACKGROUND
GPO_INFO_FLAG_VERBOSE
GPO_INFO_FLAG_NOCHANGES
pwszSite - unused now
pComputerTarget - RSOP machine structure having GPOList, token (unused now) etc.
pUserTarget - RSOP user structure having GPOList, token (unused now) etc.
pbAbort - processing of GPO should be aborted if this is set to TRUE
(in case of system shutdown or user log off)
*/
{
DWORD rcGPOCreate = ERROR_SUCCESS;
DWORD rcLogging = ERROR_SUCCESS;
PWSTR szLogFileName = NULL;
//
// put a try except block in case arguments are invalid or wbem logging fails
//
__try {
if (pComputerTarget == NULL || pComputerTarget->pWbemServices == NULL)
return ERROR_INVALID_PARAMETER;
(void) InitializeEvents(L"SceCli");
rcGPOCreate = SceProcessBeforeRSOPLogging(
TRUE,
dwFlags,
pComputerTarget->pRsopToken,
0,
NULL,
pComputerTarget->pGPOList,
NULL,
pAbort,
NULL,
NULL,
NULL,
&szLogFileName,
NULL
);
if (rcGPOCreate != ERROR_OPERATION_ABORTED && pComputerTarget->pGPOList)
rcLogging = SceLogSettingsPrecedenceGPOs(
pComputerTarget->pWbemServices,
TRUE,
&szLogFileName);
if (szLogFileName)
ScepFree(szLogFileName);
(void) ShutdownEvents();
} __except(EXCEPTION_EXECUTE_HANDLER) {
rcGPOCreate = ERROR_INVALID_PARAMETER;
}
//
// rcGPOCreate dominates rcLogging
//
return (rcGPOCreate != ERROR_SUCCESS ? rcGPOCreate : rcLogging );
}
//
// the new interface - client side extension for RSOP Diagnosis mode
//
DWORD
WINAPI
SceProcessSecurityPolicyGPOEx(
IN DWORD dwFlags,
IN HANDLE hUserToken,
IN HKEY hKeyRoot,
IN PGROUP_POLICY_OBJECT pDeletedGPOList,
IN PGROUP_POLICY_OBJECT pChangedGPOList,
IN ASYNCCOMPLETIONHANDLE pHandle,
IN BOOL *pbAbort,
IN PFNSTATUSMESSAGECALLBACK pStatusCallback,
IN IWbemServices *pWbemServices,
OUT HRESULT *pHrRsopStatus
)
/*
Description:
This is the new interface called from winlogon/userenv to process GPOs and log
RSOP data. The dll name and procedure name are registered to winlogon under
GpExtensions.
This routine applies a SCE group policy template to the current system.
The template can be in domain level, OU level, or user level. The template
is applied incrementally to the current system. RSOP data is also logged if
a valid namespace pointer is passed in. The server side callbacks log statuses
to all settings with precedence 1 (which corresponds to the merged settings
in the server side JET database)
This interface can be called during system boot, or every GPFrequency hours
after logon. The input argument contains info for where this interface is
called and under which context (user, or machine) this interface is called.
This interface shouldn't be called for user policy.
Arguments:
dwFlags - the GPO Info flags
GPO_INFO_FLAG_MACHINE
GPO_INFO_FLAG_SLOWLINK
GPO_INFO_FLAG_BACKGROUND
GPO_INFO_FLAG_VERBOSE
GPO_INFO_FLAG_NOCHANGES
hUserToken - the user token for which the user policy should be applied
if it's the machine policy, hUserToken refers to system
hKeyRoot - the root for the policy in registry
pDeletedGPOList - all deleted GPOs to process
pChangedGPOList - all GPOs that are either changed or not changed
pHandle - for asynchronous processing
pbAbort - processing of GPO should be aborted if this is set to TRUE
(in case of system shutdown or user log off)
pStatusCallback - Callback function for displaying status messages
*/
{
if ( dwFlags & GPO_INFO_FLAG_SAFEMODE_BOOT ) {
// call me next time
return(ERROR_OVERRIDE_NOCHANGES);
}
DWORD rcGPOCreate = ERROR_SUCCESS;
DWORD rcConfig = ERROR_SUCCESS;
DWORD rcLogging = ERROR_SUCCESS;
AREA_INFORMATION AllAreas = 0;
BOOL b;
PWSTR szLogFileName = NULL;
DWORD dwWinlogonLog = 0;
DWORD dwDiagOptions = 0;
//
// this will protect the RSOP global vars from multiple diagnosis'/policy props
// if asynch thread is spawned successfully, will be released there
// else released in synch main thread
//
EnterCriticalSection(&DiagnosisPolicypropSync);
if ( ghAsyncThread != NULL) {
//
// bug# 173858
// on chk'd builds, LeaveCriticalSection() matches thread id's
// so get the existing behavior in the asynch thread
// with a wait
//
//
// allow waiting thread to continue on wait error
// don't care for error since the spawned thread will log errors etc. and
// other policy propagation threads have to continue
//
WaitForSingleObject( ghAsyncThread, INFINITE);
CloseHandle(ghAsyncThread);
ghAsyncThread = NULL;
}
//
// initialize gbAsyncWinlogonThread so it can be set to TRUE if slow thread is spawned
//
gbAsyncWinlogonThread = FALSE;
gHrSynchRsopStatus = WBEM_S_NO_ERROR;
gHrAsynchRsopStatus = WBEM_S_NO_ERROR;
//
// put a try except block in case arguments are invalid
//
__try {
tg_pWbemServices = pWbemServices;
//
// if the namespace parameter is valid, increment the reference count
// the reference count is decremented by the async thread if spawned
// else by the sync thread
//
if (tg_pWbemServices) {
tg_pWbemServices->AddRef();
}
(void) InitializeEvents(L"SceCli");
rcGPOCreate = SceProcessBeforeRSOPLogging(
FALSE,
dwFlags,
hUserToken,
hKeyRoot,
pDeletedGPOList,
pChangedGPOList,
pHandle,
pbAbort,
pStatusCallback,
&AllAreas,
&b,
&szLogFileName,
&dwWinlogonLog
);
// actually *pRsopStatus should be set after callbacks are successful
// log RSOP data if valid namespace ptr
if ( rcGPOCreate != ERROR_OPERATION_ABORTED &&
rcGPOCreate != ERROR_OVERRIDE_NOCHANGES && pWbemServices )
rcLogging = ScepDosErrorToWbemError(SceLogSettingsPrecedenceGPOs(
pWbemServices,
FALSE,
&szLogFileName
));
if (pHrRsopStatus) {
*pHrRsopStatus = ScepDosErrorToWbemError(rcLogging);
}
if (rcGPOCreate == ERROR_SUCCESS) {
if (pWbemServices != NULL)
dwDiagOptions |= SCE_RSOP_CALLBACK;
rcConfig = SceProcessAfterRSOPLogging(
dwFlags,
pHandle,
pbAbort,
pStatusCallback,
AllAreas,
b,
&szLogFileName,
dwWinlogonLog,
dwDiagOptions
);
}
if (pHrRsopStatus && *pHrRsopStatus == S_OK && gHrSynchRsopStatus != S_OK) {
*pHrRsopStatus = gHrSynchRsopStatus;
}
if ( szLogFileName ) {
//
// szLogFileName is NULL if it was freed somewhere in the sync thread
// this thread will free if the asynch thread was not spawned
//
LocalFree(szLogFileName);
szLogFileName = NULL;
}
//
// clear callback status
//
ScepPolStatusCallback(pStatusCallback, FALSE, 0);
(void) ShutdownEvents();
if (!gbAsyncWinlogonThread) {
if (tg_pWbemServices) {
tg_pWbemServices->Release();
tg_pWbemServices = NULL;
}
if (gpwszDCDomainName) {
LocalFree(gpwszDCDomainName);
gpwszDCDomainName = NULL;
}
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
rcGPOCreate = ERROR_INVALID_PARAMETER;
}
//
// if slow winlogon async thread was not spawned, this thread needs to release cs
//
LeaveCriticalSection(&DiagnosisPolicypropSync);
//
// make sure to release policy notification queue processing
// if it's not released yet.
//
ScepControlNotificationQProcess(NULL, gbThisIsDC, 0);
return(rcGPOCreate != ERROR_SUCCESS ? ERROR_OVERRIDE_NOCHANGES :
(rcConfig != ERROR_SUCCESS ? ERROR_OVERRIDE_NOCHANGES: ERROR_SUCCESS));
}
//
// old API support
// but if extension is RSOP enabled SceProcessSecurityPolicyGPOEx is called
//
DWORD
WINAPI
SceProcessSecurityPolicyGPO(
IN DWORD dwFlags,
IN HANDLE hUserToken,
IN HKEY hKeyRoot,
IN PGROUP_POLICY_OBJECT pDeletedGPOList,
IN PGROUP_POLICY_OBJECT pChangedGPOList,
IN ASYNCCOMPLETIONHANDLE pHandle,
IN BOOL *pbAbort,
IN PFNSTATUSMESSAGECALLBACK pStatusCallback
)
/*
Description:
This is the old interface called from winlogon/userenv to process GPOs. The dll
name and procedure name are registered to winlogon under GpExtensions.
This routine applies a SCE group policy template to the current system.
The template can be in domain level, OU level, or user level. The template
is applied incrementally to the current system.
This interface can be called during system boot, or every GPFrequency hours
after logon. The input argument contains info for where this interface is
called and under which context (user, or machine) this interface is called.
This interface shouldn't be called for user policy.
Arguments:
dwFlags - the GPO Info flags
GPO_INFO_FLAG_MACHINE
GPO_INFO_FLAG_SLOWLINK
GPO_INFO_FLAG_BACKGROUND
GPO_INFO_FLAG_VERBOSE
GPO_INFO_FLAG_NOCHANGES
hUserToken - the user token for which the user policy should be applied
if it's the machine policy, hUserToken refers to system
hKeyRoot - the root for the policy in registry
pDeletedGPOList - all deleted GPOs to process
pChangedGPOList - all GPOs that are either changed or not changed
pHandle - for asynchronous processing
pbAbort - processing of GPO should be aborted if this is set to TRUE
(in case of system shutdown or user log off)
pStatusCallback - Callback function for displaying status messages
*/
{
if ( dwFlags & GPO_INFO_FLAG_SAFEMODE_BOOT ) {
// call me next time
return(ERROR_OVERRIDE_NOCHANGES);
}
DWORD rc = ERROR_SUCCESS;
AREA_INFORMATION AllAreas = 0;
BOOL b;
PWSTR szLogFileName = NULL;
DWORD dwWinlogonLog = 0;
//
// this will protect the RSOP global vars from multiple diagnosis'/policy props
// if asynch is spawned successfully, will be released there
// else released in synch main thread
//
EnterCriticalSection(&DiagnosisPolicypropSync);
if ( ghAsyncThread != NULL) {
//
// bug# 173858
// on chk'd builds, LeaveCriticalSection() matches thread id's
// so get the existing behavior in the asynch thread
// with a wait
//
//
// allow waiting thread to continue on wait error
// don't care for error since the spawned thread will log errors etc. and
// other policy propagation threads have to continue
//
WaitForSingleObject( ghAsyncThread, INFINITE);
CloseHandle(ghAsyncThread);
ghAsyncThread = NULL;
}
//
// initialize gbAsyncWinlogonThread so it can be set to TRUE if slow thread is spawned
//
gbAsyncWinlogonThread = FALSE;
__try {
(void) InitializeEvents(L"SceCli");
rc = SceProcessBeforeRSOPLogging(
FALSE,
dwFlags,
hUserToken,
hKeyRoot,
pDeletedGPOList,
pChangedGPOList,
pHandle,
pbAbort,
pStatusCallback,
&AllAreas,
&b,
&szLogFileName,
&dwWinlogonLog
);
if (rc == ERROR_SUCCESS) {
rc = SceProcessAfterRSOPLogging(
dwFlags,
pHandle,
pbAbort,
pStatusCallback,
AllAreas,
b,
&szLogFileName,
dwWinlogonLog,
0
);
}
if ( szLogFileName ) {
//
// szLogFileName is NULL if it was freed somewhere in the sync thread
// this thread will free if the asynch thread was not spawned
//
LocalFree(szLogFileName);
szLogFileName = NULL;
}
if (!gbAsyncWinlogonThread) {
if (gpwszDCDomainName) {
LocalFree(gpwszDCDomainName);
gpwszDCDomainName = NULL;
}
}
//
// clear callback status
//
ScepPolStatusCallback(pStatusCallback, FALSE, 0);
(void) ShutdownEvents();
} __except(EXCEPTION_EXECUTE_HANDLER) {
rc = ERROR_INVALID_PARAMETER;
}
//
// if slow winlogon async thread was not spawned, this thread needs to release cs
//
LeaveCriticalSection(&DiagnosisPolicypropSync);
// if (!gbAsyncWinlogonThread) {
// LeaveCriticalSection(&DiagnosisPolicypropSync);
// }
//
// ready to copy GPOs from the sysvol location
// should stop queue processing now
//
ScepControlNotificationQProcess(NULL, gbThisIsDC, 0);
return(rc != ERROR_SUCCESS ? ERROR_OVERRIDE_NOCHANGES : ERROR_SUCCESS);
}
DWORD
SceProcessBeforeRSOPLogging(
IN BOOL bPlanningMode,
IN DWORD dwFlags,
IN HANDLE hUserToken,
IN HKEY hKeyRoot,
IN PGROUP_POLICY_OBJECT pDeletedGPOList OPTIONAL,
IN PGROUP_POLICY_OBJECT pChangedGPOList,
IN ASYNCCOMPLETIONHANDLE pHandle OPTIONAL,
IN BOOL *pbAbort,
IN PFNSTATUSMESSAGECALLBACK pStatusCallback OPTIONAL,
OUT AREA_INFORMATION *pAllAreas OPTIONAL,
OUT BOOL *pb OPTIONAL,
OUT PWSTR *pszLogFileName OPTIONAL,
OUT DWORD *pdwWinlogonLog OPTIONAL
)
/*
Description:
This routine is called for both planning and diagnosis modes. In this routine,
all GPOs are copied locally into a cache for use by the logging routines and/or
configuration routines after this routine.
SceProcessAfterRSOPLogging is a sister function that is called for diagnosis mode only.
This interface shouldn't be called for user policy but within the routine,
a checking is still made to make sure that user level policies is not processed.
For domain or OU level policies, This routine categories policy: 1) policy
must be enforced before user logon (security policy and user rights),
2) policy can be applied after user logon (for example, file security). For diagnosis mode,
The 2nd category is applied asynchronously (in a separate thread).
Arguments:
dwFlags - the GPO Info flags
GPO_INFO_FLAG_MACHINE
GPO_INFO_FLAG_SLOWLINK
GPO_INFO_FLAG_BACKGROUND
GPO_INFO_FLAG_VERBOSE
GPO_INFO_FLAG_NOCHANGES
hUserToken - the user token for which the user policy should be applied
if it's the machine policy, hUserToken refers to system
hKeyRoot - the root for the policy in registry
pDeletedGPOList - all deleted GPOs to process
pChangedGPOList - all GPOs that are either changed or not changed
pHandle - for asynchronous processing
pbAbort - processing of GPO should be aborted if this is set to TRUE
(in case of system shutdown or user log off)
pStatusCallback - Callback function for displaying status messages
Return Value:
Win32 error
ERROR_SUCCESS
E_PENDING if asynchonous processing
other errors
Note, if error is returned, the previous cached GPO list will be used for
next propagation (because it didn't succeed this time).
*/
{
// validate input parameters
if ( !bPlanningMode && !hUserToken ) {
return(ERROR_INVALID_PARAMETER);
}
//
// for diagnosis, continue even if the GPO list is empty because of local security database
//
if ( bPlanningMode && pChangedGPOList == NULL ) {
return(ERROR_SUCCESS);
}
DWORD rc = ERROR_SUCCESS;
DWORD rcSave = ERROR_SUCCESS;
DWORD nRequired=0;
BOOL b = FALSE;
DWORD nMinutes;
/*
DWORD dPeriodInDays=0;
DWORD dLastSeconds=0;
DWORD dCurrentSeconds=0;
*/
LARGE_INTEGER CurrentTime;
AREA_INFORMATION AllAreas=0;
HANDLE hfTemp=INVALID_HANDLE_VALUE;
//
// variables for log file names
//
LPTSTR szLogFileName=NULL;
BOOL bSuspend=FALSE;
//
// check if system is shutdown, or dcpromo is going
//
if ( ScepShouldTerminateProcessing( pbAbort, FALSE ) ) {
return(ERROR_OPERATION_ABORTED);
}
if (!bPlanningMode) {
rc = RtlNtStatusToDosError( ScepIsSystemContext(hUserToken,&b) );
}
if ( !bPlanningMode && !b ) {
//
// can't get current user SID or it's not system SID (maybe user policy)
//
if ( ERROR_SUCCESS != rc ) {
//
// error occurs when querying/comparing user token
//
LogEvent(MyModuleHandle,
STATUS_SEVERITY_ERROR,
SCEPOL_ERROR_PROCESS_GPO,
IDS_ERROR_GET_TOKEN_USER,
rc
);
return( rc );
} else {
//
// this is not the machine (system) token, return
//
return( ERROR_SUCCESS );
}
}
if (!bPlanningMode) {
//
// it is machine policy since user policy is filtered out before this
// try to get the thread/process token to check if it is the system context
//
HANDLE hToken = NULL;
if (!OpenThreadToken( GetCurrentThread(),
TOKEN_QUERY,
TRUE,
&hToken)) {
if (!OpenProcessToken( GetCurrentProcess(),
TOKEN_QUERY,
&hToken)) {
rc = GetLastError();
}
}
if ( ERROR_SUCCESS == rc ) {
rc = RtlNtStatusToDosError( ScepIsSystemContext(hToken,&b) );
if (hToken)
CloseHandle(hToken);
}
if (!b) {
if ( ERROR_SUCCESS != rc ) {
//
// error occurs when querying/comparing system token in machine policy
//
LogEvent(MyModuleHandle,
STATUS_SEVERITY_ERROR,
SCEPOL_ERROR_PROCESS_GPO,
IDS_ERROR_GET_TOKEN_MACHINE,
rc
);
return( rc );
} else {
//
// this is not the machine (system) token, return
//
return( ERROR_SUCCESS );
}
}
}
//
// check if system is shutdown, or dcpromo is going
//
if ( ScepShouldTerminateProcessing( pbAbort, FALSE ) ) {
return(ERROR_OPERATION_ABORTED);
}
//
// build log name %windir%\security\logs\winlogon.log
// if the registry flag is set
//
DWORD dwLog = 0;
ScepRegQueryIntValue(
HKEY_LOCAL_MACHINE,
GPT_SCEDLL_NEW_PATH,
(bPlanningMode ? TEXT("ExtensionRsopPlanningDebugLevel") : TEXT("ExtensionDebugLevel")),
&dwLog
);
if ( dwLog != 0 ) {
nRequired = GetSystemWindowsDirectory(NULL, 0);
if ( nRequired ) {
if (bPlanningMode) {
szLogFileName = (LPTSTR)LocalAlloc(0, (nRequired+1+
lstrlen(PLANNING_LOG_PATH))*sizeof(TCHAR));
}
else{
szLogFileName = (LPTSTR)LocalAlloc(0, (nRequired+1+
lstrlen(WINLOGON_LOG_PATH))*sizeof(TCHAR));
}
if ( szLogFileName ){
GetSystemWindowsDirectory(szLogFileName, nRequired);
szLogFileName[nRequired] = L'\0';
lstrcat(szLogFileName, (bPlanningMode ? PLANNING_LOG_PATH : WINLOGON_LOG_PATH));
}else{
// should not occur
// ignore this error, log is NULL}
} // else ignore, log is NULL} // else log is NULL
}
}
//
// find out if this machine is a domain controller
//
if ( !gbDCQueried ) {
DSROLE_MACHINE_ROLE MachineRole;
PWSTR pwszDomainNameFlat = NULL;
rc = ScepGetDomainRoleInfo(&gMachineRole, NULL, &gpwszDCDomainName);
if (rc == ERROR_SUCCESS)
{
gbDCQueried = TRUE;
if ( gMachineRole == DsRole_RolePrimaryDomainController ||
gMachineRole == DsRole_RoleBackupDomainController ) {
gbThisIsDC = TRUE;
}
}
}
//
// check if system is shutdown, or dcpromo is going
//
if ( ScepShouldTerminateProcessing( pbAbort, FALSE ) ) {
rcSave = ERROR_OPERATION_ABORTED;
goto CleanUp;
}
//
// set the MaxNoGPOListChangesInterval back
//
if ( !bPlanningMode && (ERROR_SUCCESS == ScepRegQueryIntValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("GPOSavedInterval"),
&nMinutes
) ) ) {
// ANZ sysprep fix
//
// conservative behavior - if cached value was 1, might be due to
// some race condition via secedit etc., so set it back to 960
//
if (nMinutes == 1) {
nMinutes = 960;
}
ScepRegSetIntValue(
HKEY_LOCAL_MACHINE,
GPT_SCEDLL_NEW_PATH,
TEXT("MaxNoGPOListChangesInterval"),
nMinutes
);
ScepRegDeleteValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("GPOSavedInterval")
);
}
//
// process any policy filter temp files created in setup
// (if this is the reboot after seutp on DC)
//
if (!bPlanningMode)
ScepProcessPolicyFilterTempFiles(szLogFileName);
//
// prepare the log file
//
if ( !bPlanningMode && szLogFileName ) {
//
// check the log size and wrap it if it's over 1M
//
DWORD dwLogSize=0;
HANDLE hFile = CreateFile(szLogFileName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS, // OPEN_EXISTING
FILE_ATTRIBUTE_NORMAL,
NULL);
if ( INVALID_HANDLE_VALUE != hFile ) {
dwLogSize = GetFileSize(hFile, NULL);
if ( dwLogSize < (0x1 << 20) ) {
//
// log a line to separate multiple propagation.
//
SetFilePointer (hFile, 0, NULL, FILE_END);
ScepWriteSingleUnicodeLog(hFile, TRUE, L"**************************");
}
CloseHandle(hFile);
}
if ( dwLogSize >= (0x1 << 20) ) {
nRequired = wcslen(szLogFileName);
LPTSTR szTempName = (LPTSTR)LocalAlloc(0, (nRequired+1)*sizeof(TCHAR));
if ( szTempName ) {
wcscpy(szTempName, szLogFileName);
szTempName[nRequired-3] = L'o';
szTempName[nRequired-2] = L'l';
szTempName[nRequired-1] = L'd';
CopyFile( szLogFileName, szTempName, FALSE );
LocalFree(szTempName);
}
DeleteFile(szLogFileName);
}
}
//
// check if system is shutdown, or dcpromo is going
//
if ( ScepShouldTerminateProcessing( pbAbort, FALSE ) ) {
rcSave = ERROR_OPERATION_ABORTED;
goto CleanUp;
}
if ( !ScepClearGPObjects(bPlanningMode) ) {
rc = GetLastError();
LogEvent(MyModuleHandle,
STATUS_SEVERITY_ERROR,
SCEPOL_ERROR_PROCESS_GPO,
IDS_ERR_DELETE_GP_CACHE,
rc
);
SetLastError(rc);
rcSave = ERROR_OPERATION_ABORTED;
goto CleanUp;
}
//
// callback for status display
//
if (!bPlanningMode)
ScepPolStatusCallback(pStatusCallback, FALSE, IDS_APPLY_SECURITY_POLICY);
//
// process each GPO in the changed gpo list
// deleted GPOs are ignored for security policy
//
PGROUP_POLICY_OBJECT pGpo;
rc = ERROR_SUCCESS;
bSuspend=FALSE;
for ( pGpo = pChangedGPOList; pGpo != NULL; pGpo=pGpo->pNext ) {
//
// callback for status display
//
if (!bPlanningMode && pStatusCallback ) {
pStatusCallback(TRUE, pGpo->lpDisplayName);
}
//
// we don't have security policy in local template. ignore it
// the local security policy is stored in the ESE database.
//
if ( pGpo->GPOLink == GPLinkMachine ) {
continue;
}
if (!bPlanningMode && !bSuspend ) {
//
// ready to copy GPOs from the sysvol location
// should stop queue processing now
//
rc = ScepControlNotificationQProcess(szLogFileName, gbThisIsDC, 1);
if ( gbThisIsDC && (ERROR_OVERRIDE_NOCHANGES == rc) ) {
//
// there is policy notification going on right now
//
rcSave = rc;
break;
}
bSuspend = TRUE;
}
rc = ScepProcessSecurityPolicyInOneGPO( bPlanningMode,
dwFlags,
pGpo,
szLogFileName,
&AllAreas
);
if ( rc != ERROR_SUCCESS ) {
//
// continue logging for planning and diagnosis but do not config
//
rcSave = rc;
}
//
// check if system is shutdown, or dcpromo is going
//
if ( ScepShouldTerminateProcessing( pbAbort, FALSE ) ) {
//
// clear callback status
//
if (!bPlanningMode)
ScepPolStatusCallback(pStatusCallback, FALSE, 0);
rcSave = rc = ERROR_OPERATION_ABORTED;
break;
}
}
CleanUp:
if (pb) *pb = b;
if (pszLogFileName)
*pszLogFileName = szLogFileName;
else if (szLogFileName)
LocalFree(szLogFileName);
if (pAllAreas) *pAllAreas = AllAreas;
if (pdwWinlogonLog) *pdwWinlogonLog = dwLog;
return rcSave;
}
DWORD
SceProcessAfterRSOPLogging(
IN DWORD dwFlags,
IN ASYNCCOMPLETIONHANDLE pHandle,
IN BOOL *pbAbort,
IN PFNSTATUSMESSAGECALLBACK pStatusCallback,
IN AREA_INFORMATION ThisAreas,
IN BOOL b,
IN PWSTR *ppszLogFileName,
IN DWORD dwWinlogonLog,
IN DWORD dwDiagOptions
)
/*
Description:
Routine that is called for diagnosis mode only where the actual configuration is done.
*/
{
DWORD rc = ERROR_SUCCESS;
//
// no error, process all policies on local machine
//
PWSTR Buffer=NULL;
AREA_INFORMATION AllAreas=ThisAreas;
//
// dynamic allocate stack
//
SafeAllocaAllocate( Buffer, (MAX_PATH+50)*sizeof(WCHAR) );
if ( Buffer == NULL ) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
Buffer[0] = L'\0';
GetSystemWindowsDirectory(Buffer, MAX_PATH);
DWORD BufLen = wcslen(Buffer);
wcscat(Buffer, L"\\security\\templates\\policies\\gpt*.*");
intptr_t hFile;
struct _wfinddata_t FileInfo;
LONG NoMoreFiles=0;
hFile = _wfindfirst(Buffer, &FileInfo);
DWORD dConfigOpt=0;
//
// AllAreas contains the areas defined in current set of GPOs
// query the areas in previous policy propagation
//
AREA_INFORMATION PrevAreas = 0;
ScepRegQueryIntValue(
HKEY_LOCAL_MACHINE,
GPT_SCEDLL_NEW_PATH,
TEXT("PreviousPolicyAreas"),
&PrevAreas
);
// there is no tattoo value for these areas
PrevAreas &= ~(AREA_FILE_SECURITY | AREA_REGISTRY_SECURITY | AREA_DS_OBJECTS);
AllAreas |= PrevAreas;
if ( hFile != -1 && ThisAreas > 0 ) {
//
// query the configure frequency which is set by GPE on DC
// do not care errors. Note, security policy is not controlled
// by the configure frequency
// not used
//
b = TRUE; // the first template
do {
LogEventAndReport(MyModuleHandle,
(ppszLogFileName ? *ppszLogFileName : NULL),
0,
0,
IDS_PROCESS_TEMPLATE,
FileInfo.name
);
wcscpy(Buffer+BufLen, L"\\security\\templates\\policies\\");
wcscat(Buffer, FileInfo.name);
NoMoreFiles = _wfindnext(hFile, &FileInfo);
//
// Buffer contains the real template name to process
//
//
// if it's not the last template, just update the template
// without really configuring
//
dConfigOpt = SCE_UPDATE_DB | SCE_POLICY_TEMPLATE;
switch ( dwWinlogonLog ) {
case 0:
dConfigOpt |= SCE_DISABLE_LOG;
break;
case 1:
dConfigOpt |= SCE_VERBOSE_LOG;
break;
default:
dConfigOpt |= SCE_DEBUG_LOG;
}
if ( b ) {
dConfigOpt |= SCE_POLICY_FIRST;
if ( gbThisIsDC ) {
dConfigOpt |= SCE_NOCOPY_DOMAIN_POLICY;
}
b = FALSE; // next tempalte is not the first one
}
//
// check if system is shutdown, or dcpromo is going
//
if ( ScepShouldTerminateProcessing( pbAbort, TRUE ) ) {
rc = GetLastError();
if ( ppszLogFileName && *ppszLogFileName ) {
LocalFree(*ppszLogFileName);
*ppszLogFileName = NULL;
}
//
// clear callback status
//
ScepPolStatusCallback(pStatusCallback, FALSE, 0);
SafeAllocaFree( Buffer );
return(rc);
}
if ( NoMoreFiles == 0 ) {
//
// this is not the last one, import the template to engine
// no matter if the current thread is background or foreground
// NO_CONFIG yet.
//
dConfigOpt |= SCE_NO_CONFIG;
if ( gbThisIsDC && wcsstr(Buffer, L".inf") != NULL ) {
//
// this is not a domain GPO
// since this machine is a DC, do not take domain policy from this GPO
//
dConfigOpt |= SCE_NO_DOMAIN_POLICY;
LogEventAndReport(MyModuleHandle,
(ppszLogFileName ? *ppszLogFileName : NULL),
0,
0,
IDS_NOT_LAST_GPO_DC,
L""
);
} else {
LogEventAndReport(MyModuleHandle,
(ppszLogFileName ? *ppszLogFileName : NULL),
0,
0,
IDS_NOT_LAST_GPO,
L""
);
}
rc = ScepWaitConfigSystem(
NULL, // local system
Buffer,
NULL,
(ppszLogFileName ? *ppszLogFileName : NULL),
dConfigOpt | SCE_POLBIND_NO_AUTH,
AllAreas, // not used when NO_CONFIG is specified
NULL, // no callback
NULL, // no callback window
NULL // no warning
);
if ( ERROR_NOT_SUPPORTED == rc ) {
//
// server is not ready
// log an event log to warn users
//
LogEvent(MyModuleHandle,
STATUS_SEVERITY_WARNING,
SCEPOL_ERROR_PROCESS_GPO,
IDS_PROPAGATE_NOT_READY,
rc
);
break;
} else if ( ERROR_IO_PENDING == rc ) {
rc = ERROR_OVERRIDE_NOCHANGES;
break;
} else if (ERROR_SUCCESS != rc ) {
//
// log an event log to warn users
//
LPVOID lpMsgBuf=NULL;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
rc,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)&lpMsgBuf,
0,
NULL
);
if ( !(dConfigOpt & SCE_NO_CONFIG) &&
(ERROR_SPECIAL_ACCOUNT == rc) ) {
LogEvent(MyModuleHandle,
STATUS_SEVERITY_WARNING,
SCEPOL_WARNING_PROCESS_GPO,
IDS_WARNING_PROPAGATE_SPECIAL,
rc,
lpMsgBuf ? (PWSTR)lpMsgBuf : L"\r\n"
);
rc = ERROR_OVERRIDE_NOCHANGES;
} else {
switch (rc) {
case ERROR_NONE_MAPPED:
LogEvent(MyModuleHandle,
STATUS_SEVERITY_WARNING,
SCEPOL_WARNING_PROCESS_GPO,
IDS_WARNING_PROPAGATE_NOMAP,
rc,
lpMsgBuf ? (PWSTR)lpMsgBuf : L"\r\n"
);
break;
case ERROR_TIMEOUT:
LogEvent(MyModuleHandle,
STATUS_SEVERITY_WARNING,
SCEPOL_WARNING_PROCESS_GPO,
IDS_WARNING_PROPAGATE_TIMEOUT,
rc,
lpMsgBuf ? (PWSTR)lpMsgBuf : L"\r\n"
);
break;
default:
LogEvent(MyModuleHandle,
STATUS_SEVERITY_WARNING,
SCEPOL_WARNING_PROCESS_GPO,
IDS_WARNING_PROPAGATE,
rc,
lpMsgBuf ? (PWSTR)lpMsgBuf : L"\r\n"
);
}
}
if ( lpMsgBuf ) {
LocalFree(lpMsgBuf);
}
break;
}
} else {
//
// this is the last template in this cycle
// should trigger configuration now
//
dConfigOpt |= SCE_POLICY_LAST;
AREA_INFORMATION AreaSave, Area, AreaToConfigure;
AreaSave = AllAreas & (AREA_FILE_SECURITY | AREA_REGISTRY_SECURITY | AREA_DS_OBJECTS ); // background areas
Area = AllAreas & ~AreaSave;
//
// callback for status display
//
ScepPolStatusCallback(pStatusCallback, TRUE, IDS_CONFIGURE_POLICY);
//
// always use incremental modal to update security policy first
//
if ( dwFlags & GPO_INFO_FLAG_BACKGROUND ) {
//
// this GPT thread is currently running in the background
// so configure all security together
//
AreaToConfigure = Area | AreaSave;
} else {
//
// this GPT thread is currently running in the foreground
// or configure frequency condition is not qualified for other areas
//
// configure security policy in this thread first
//
AreaToConfigure = Area;
}
if ( gbThisIsDC && wcsstr(Buffer, L".inf") != NULL ) {
//
// this is not a domain GPO, import the template first
// since this machine is a DC, do not take domain policy from this GPO
// this is the last one, we need to pass this GPO in
// without domain policy but domain policy should be configured
// if it come from the domain level
// so pass the GPO in first with NO_CONFIG, then call again
// to configure
//
dConfigOpt |= SCE_NO_DOMAIN_POLICY | SCE_NO_CONFIG;
LogEventAndReport(MyModuleHandle,
(ppszLogFileName ? *ppszLogFileName : NULL),
0,
0,
IDS_LAST_GPO_DC,
L""
);
rc = ScepWaitConfigSystem(
NULL, // local system
Buffer,
NULL,
(ppszLogFileName ? *ppszLogFileName : NULL),
dConfigOpt | SCE_POLBIND_NO_AUTH,
AreaToConfigure | AreaSave,
NULL, // no callback
NULL, // no callback window
NULL // no warning
);
if ( ERROR_SUCCESS == rc ) {
//
// this is a DC and it's not been configured yet
// configure now
//
dConfigOpt = SCE_POLICY_TEMPLATE |
SCE_UPDATE_DB;
switch ( dwWinlogonLog ) {
case 0:
dConfigOpt |= SCE_DISABLE_LOG;
break;
case 1:
dConfigOpt |= SCE_VERBOSE_LOG;
break;
default:
dConfigOpt |= SCE_DEBUG_LOG;
break;
}
if (dwDiagOptions & SCE_RSOP_CALLBACK)
dConfigOpt |= SCE_RSOP_CALLBACK;
rc = ScepSceStatusToDosError(
ScepConfigSystem(
NULL, // local system
NULL,
NULL,
(ppszLogFileName ? *ppszLogFileName : NULL),
dConfigOpt | SCE_POLBIND_NO_AUTH,
AreaToConfigure,
NULL, // no callback
NULL, // no callback window
NULL // no warning
));
}
} else {
//
// import/configure the system
// Note, if it's running in foreground thread
// and this last template contains file/key policy
// we need to import file/key policy but not configure them.
// They will be configured in the background thread.
//
if ( (AreaSave > 0) &&
!(dwFlags & GPO_INFO_FLAG_BACKGROUND) ) {
dConfigOpt |= SCE_NO_CONFIG_FILEKEY;
}
if (dwDiagOptions & SCE_RSOP_CALLBACK)
dConfigOpt |= SCE_RSOP_CALLBACK;
rc = ScepWaitConfigSystem(
NULL, // local system
Buffer,
NULL,
(ppszLogFileName ? *ppszLogFileName : NULL),
dConfigOpt | SCE_POLBIND_NO_AUTH,
AreaToConfigure | AreaSave,
NULL, // no callback
NULL, // no callback window
NULL // no warning
);
LogEventAndReport(MyModuleHandle,
(ppszLogFileName ? *ppszLogFileName : NULL),
0,
0,
IDS_LAST_GPO,
L""
);
}
if ( ERROR_NOT_SUPPORTED == rc ) {
//
// server is not ready
// log an event log to warn users
//
LogEvent(MyModuleHandle,
STATUS_SEVERITY_WARNING,
SCEPOL_ERROR_PROCESS_GPO,
IDS_PROPAGATE_NOT_READY,
rc
);
break;
} else if ( ERROR_IO_PENDING == rc ) {
rc = ERROR_OVERRIDE_NOCHANGES;
break;
} else if ( ERROR_SUCCESS != rc ) {
//
// log an event log to warn users
//
LPVOID lpMsgBuf=NULL;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
rc,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)&lpMsgBuf,
0,
NULL
);
if ( !(dConfigOpt & SCE_NO_CONFIG) &&
(ERROR_SPECIAL_ACCOUNT == rc) ) {
LogEvent(MyModuleHandle,
STATUS_SEVERITY_WARNING,
SCEPOL_WARNING_PROCESS_GPO,
IDS_WARNING_PROPAGATE_SPECIAL,
rc,
lpMsgBuf ? (PWSTR)lpMsgBuf : L"\r\n"
);
rc = ERROR_OVERRIDE_NOCHANGES;
} else {
switch ( rc ) {
case ERROR_NONE_MAPPED:
LogEvent(MyModuleHandle,
STATUS_SEVERITY_WARNING,
SCEPOL_WARNING_PROCESS_GPO,
IDS_WARNING_PROPAGATE_NOMAP,
rc,
lpMsgBuf ? (PWSTR)lpMsgBuf : L"\r\n"
);
break;
case ERROR_TIMEOUT:
LogEvent(MyModuleHandle,
STATUS_SEVERITY_WARNING,
SCEPOL_WARNING_PROCESS_GPO,
IDS_WARNING_PROPAGATE_TIMEOUT,
rc,
lpMsgBuf ? (PWSTR)lpMsgBuf : L"\r\n"
);
break;
default:
LogEvent(MyModuleHandle,
STATUS_SEVERITY_WARNING,
SCEPOL_WARNING_PROCESS_GPO,
IDS_WARNING_PROPAGATE,
rc,
lpMsgBuf ? (PWSTR)lpMsgBuf : L"\r\n"
);
break;
}
}
if ( lpMsgBuf ) {
LocalFree(lpMsgBuf);
}
break;
}
if ( (AreaSave > 0) &&
!(dwFlags & GPO_INFO_FLAG_BACKGROUND) ) {
//
// The current thread is on winlogon's main thread,
// Create a separate thread to run this "slow" stuff
// so winlogon is not blocked
//
LogEventAndReport(MyModuleHandle,
(ppszLogFileName ? *ppszLogFileName : NULL),
0,
0,
IDS_GPO_FOREGROUND_THREAD,
L""
);
//
// variables for the second thread
//
ULONG idThread;
HANDLE hThread;
ENGINEARGS *pEA;
pEA = (ENGINEARGS *)LocalAlloc(0, sizeof(ENGINEARGS));
if ( pEA ) {
LPSTREAM pStream = NULL;
//
// marshall the namespace parameter so the async
// thread can log RSOP data during callbacks
//
if (tg_pWbemServices)
CoMarshalInterThreadInterfaceInStream(IID_IWbemServices, tg_pWbemServices, &pStream);
pEA->szTemplateName = NULL;
pEA->szLogName = (ppszLogFileName ? *ppszLogFileName : NULL);
pEA->Area = AreaSave;
pEA->pHandle = pHandle;
pEA->dwDiagOptions = dwDiagOptions;
pEA->pStream = pStream;
hSceDll = LoadLibrary(TEXT("scecli.dll"));
//
// the second thread runs ScepWinlogonThreadFunc with
// arguments pEA
//
hThread = CreateThread(NULL,
0,
(PTHREAD_START_ROUTINE)ScepWinlogonThreadFunc,
(LPVOID)pEA,
0,
&idThread);
ghAsyncThread = hThread;
if (hThread) {
gbAsyncWinlogonThread = TRUE;
//
// need not be freed in synch thread - the asynch thread will free it
//
if (ppszLogFileName)
*ppszLogFileName = NULL;
//
// do not wait, return to winlogon
// buffer will be freed by the other thread
//
//CloseHandle(hThread);
rc = (DWORD)E_PENDING;
} else {
rc = GetLastError();
LocalFree(pEA);
//
// error occurs to create the thread, the library won't
// be freed by the thread, so free it here
//
if ( hSceDll ) {
FreeLibrary(hSceDll);
}
}
} else {
rc = ERROR_NOT_ENOUGH_MEMORY;
}
}
}
} while ( NoMoreFiles == 0 );
_findclose(hFile);
} else {
//
// there is no SCE GPOs but we still need to take the local policy
//
dConfigOpt = SCE_UPDATE_DB |
SCE_POLICY_TEMPLATE | SCE_POLICY_FIRST | SCE_POLICY_LAST;
switch ( dwWinlogonLog ) {
case 0:
dConfigOpt |= SCE_DISABLE_LOG;
break;
case 1:
dConfigOpt |= SCE_VERBOSE_LOG;
break;
default:
dConfigOpt |= SCE_DEBUG_LOG;
break;
}
if ( gbThisIsDC ) {//
// this is not a domain GPO, no domain policy should be
// set from the local policy table.
//
dConfigOpt |= SCE_NO_DOMAIN_POLICY |
SCE_NOCOPY_DOMAIN_POLICY;
}
//
// callback for status display
//
ScepPolStatusCallback(pStatusCallback, TRUE, IDS_CONFIGURE_POLICY);
//
// the server may not be initialized yet
// wait for some time and try again
//
rc = ScepWaitConfigSystem(
NULL, // local system
NULL,
NULL,
(ppszLogFileName ? *ppszLogFileName : NULL),
dConfigOpt | SCE_POLBIND_NO_AUTH,
AllAreas, //AREA_SECURITY_POLICY | AREA_PRIVILEGES,
NULL, // no callback
NULL, // no callback window
NULL // no warning
);
if ( ERROR_NOT_SUPPORTED == rc ) {
//
// server is not ready
// log an event log to warn users
//
LogEvent(MyModuleHandle,
STATUS_SEVERITY_WARNING,
SCEPOL_ERROR_PROCESS_GPO,
IDS_PROPAGATE_NOT_READY,
rc
);
} else if ( ERROR_IO_PENDING == rc ) {
rc = ERROR_OVERRIDE_NOCHANGES;
} else if ( ERROR_SUCCESS != rc ) {
LPVOID lpMsgBuf=NULL;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
rc,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)&lpMsgBuf,
0,
NULL
);
if ( !(dConfigOpt & SCE_NO_CONFIG) &&
(ERROR_SPECIAL_ACCOUNT == rc) ) {
LogEvent(MyModuleHandle,
STATUS_SEVERITY_WARNING,
SCEPOL_WARNING_PROCESS_GPO,
IDS_WARNING_PROPAGATE_SPECIAL,
rc,
lpMsgBuf ? (PWSTR)lpMsgBuf : L"\r\n"
);
rc = ERROR_OVERRIDE_NOCHANGES;
} else {
switch ( rc ) {
case ERROR_NONE_MAPPED:
LogEvent(MyModuleHandle,
STATUS_SEVERITY_WARNING,
SCEPOL_WARNING_PROCESS_GPO,
IDS_WARNING_PROPAGATE_NOMAP,
rc,
lpMsgBuf ? (PWSTR)lpMsgBuf : L"\r\n"
);
break;
case ERROR_TIMEOUT:
LogEvent(MyModuleHandle,
STATUS_SEVERITY_WARNING,
SCEPOL_WARNING_PROCESS_GPO,
IDS_WARNING_PROPAGATE_TIMEOUT,
rc,
lpMsgBuf ? (PWSTR)lpMsgBuf : L"\r\n"
);
break;
default:
LogEvent(MyModuleHandle,
STATUS_SEVERITY_WARNING,
SCEPOL_WARNING_PROCESS_GPO,
IDS_WARNING_PROPAGATE,
rc,
lpMsgBuf ? (PWSTR)lpMsgBuf : L"\r\n"
);
break;
}
}
if ( lpMsgBuf ) {
LocalFree(lpMsgBuf);
}
}
}
//
// save configuration time to registry, only care security policy status
// error from the second thread won't be tracked
//
if ( ERROR_SUCCESS == rc ||
E_PENDING == rc ) {
ScepLogLastConfigTime();
//
// log an informational event to state security policy is applied
//
LogEvent(MyModuleHandle,
STATUS_SEVERITY_INFORMATIONAL,
SCEPOL_INFO_GPO_COMPLETED,
0,
TEXT("")
);
//
// save ThisAreas for next policy prop (to reset tattoo)
//
ScepRegSetIntValue(
HKEY_LOCAL_MACHINE,
GPT_SCEDLL_NEW_PATH,
TEXT("PreviousPolicyAreas"),
ThisAreas
);
} else {
//
// Something failed when propagate this set of policy
// tattoo values from previous policy may not be reset yet.
// To make sure undefined areas are covered in the next prop
// we have to save AllAreas for next policy prop (to reset tattoo)
//
ScepRegSetIntValue(
HKEY_LOCAL_MACHINE,
GPT_SCEDLL_NEW_PATH,
TEXT("PreviousPolicyAreas"),
AllAreas
);
}
if ( rc == ERROR_DATABASE_FAILURE ) {
//
// policy propagation category error - log to eventlog
//
LogEvent(MyModuleHandle,
STATUS_SEVERITY_ERROR,
SCEEVENT_ERROR_JET_DATABASE,
IDS_ERROR_OPEN_JET_DATABASE,
L"%windir%\\security\\database\\secedit.sdb"
);
}
SafeAllocaFree( Buffer );
return rc;
}
DWORD
ScepPolStatusCallback(
IN PFNSTATUSMESSAGECALLBACK pStatusCallback OPTIONAL,
IN BOOL bVerbose,
IN INT nId
)
{
if ( NULL == pStatusCallback ) {
// no callback
return ERROR_SUCCESS;
}
if ( nId > 0 ) {
TCHAR szMsg[MAX_PATH];
if (LoadString (MyModuleHandle, nId, szMsg, MAX_PATH)) {
pStatusCallback(bVerbose, szMsg);
return ERROR_SUCCESS;
}
}
pStatusCallback(bVerbose, NULL);
return ERROR_SUCCESS;
}
BOOL
ScepShouldTerminateProcessing(
IN BOOL *pbAbort,
IN BOOL bCheckDcpromo
)
/*
Check if the policy propagation should be terminated. There are two
conditions: 1) system is requesting a shutdown
2) dcpromo is going on
*/
{
if ( pbAbort && *pbAbort ) {
SetLastError( ERROR_OPERATION_ABORTED );
return TRUE;
}
if ( bCheckDcpromo ) {
DWORD dwPolicyPropOff=0;
ScepRegQueryIntValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("PolicyPropOff"),
&dwPolicyPropOff
);
if ( dwPolicyPropOff ) {
SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
return TRUE;
}
}
return FALSE;
}
DWORD
ScepProcessSecurityPolicyInOneGPO(
IN BOOL bPlanningMode,
IN DWORD dwFlags,
IN PGROUP_POLICY_OBJECT pGpoInfo,
IN LPTSTR szLogFileName OPTIONAL,
IN OUT AREA_INFORMATION *pTotalArea
)
{
//
// build the template name and log name
//
if ( pGpoInfo == NULL || pGpoInfo->lpFileSysPath == NULL) {
return(ERROR_INVALID_PARAMETER);
}
DWORD rc;
DWORD nRequired=0;
LPTSTR szTemplateName=NULL;
//
// build security template name for this GPO
//
nRequired = lstrlen(pGpoInfo->lpFileSysPath)+2+
lstrlen(GPTSCE_TEMPLATE);
szTemplateName = (LPTSTR)LocalAlloc(0, nRequired*sizeof(TCHAR));
if ( szTemplateName ) {
swprintf(szTemplateName, L"%s\\%s\0",
pGpoInfo->lpFileSysPath,
GPTSCE_TEMPLATE);
//
// detect what area is available in the template
//
AREA_INFORMATION Area = ScepGetAvailableArea(bPlanningMode,
pGpoInfo->lpFileSysPath,
pGpoInfo->lpDSPath,
szTemplateName,
pGpoInfo->GPOLink,
gbThisIsDC);
//
// if Area is 0, there must be an error occured to open the template
//
if ( Area == 0 ) {
rc = GetLastError();
} else {
rc = 0;
}
*pTotalArea |= Area;
//
// log GPT header information into the log file
//
if ( Area == 0 && rc != 0 ) {
//
// template can't be accessed, log the error to event log
// don't log it if this is a DC (so all GPOs are accessed locally)
// bug the DC is too busy (rc = 1450)
//
if ( !gbThisIsDC || ( ERROR_NO_SYSTEM_RESOURCES != rc) ) {
LogEventAndReport(MyModuleHandle,
szLogFileName,
STATUS_SEVERITY_ERROR,
SCEPOL_ERROR_PROCESS_GPO,
IDS_ERROR_ACCESS_TEMPLATE,
rc,
szTemplateName
);
}
} else if ( szLogFileName ) {
if ( Area == 0 ) {
//
// template not defined at this level
//
LogEventAndReport(MyModuleHandle,
szLogFileName,
0,
0,
IDS_INFO_NO_TEMPLATE,
pGpoInfo->lpFileSysPath
);
} else{
//
// process the template
//
LogEventAndReport(MyModuleHandle,
szLogFileName,
0,
0,
IDS_INFO_COPY_TEMPLATE,
szTemplateName
);
HANDLE hfTemp = CreateFile(szLogFileName,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if ( hfTemp != INVALID_HANDLE_VALUE ) {
DWORD dwBytesWritten;
SetFilePointer (hfTemp, 0, NULL, FILE_BEGIN);
BYTE TmpBuf[3];
TmpBuf[0] = 0xFF;
TmpBuf[1] = 0xFE;
TmpBuf[2] = 0;
WriteFile (hfTemp, (LPCVOID)TmpBuf, 2,
&dwBytesWritten,
NULL);
SetFilePointer (hfTemp, 0, NULL, FILE_END);
// ScepWriteVariableUnicodeLog( hfTemp, FALSE, "\tGPO Area %x Flag %x (", Area, dwFlags);
BOOL bCRLF;
if ( dwFlags & GPO_INFO_FLAG_BACKGROUND )
bCRLF = FALSE;
else
bCRLF = TRUE;
switch ( pGpoInfo->GPOLink ) {
case GPLinkDomain:
ScepWriteSingleUnicodeLog(hfTemp, bCRLF, L"GPLinkDomain ");
break;
case GPLinkMachine:
ScepWriteSingleUnicodeLog(hfTemp, bCRLF, L"GPLinkMachine ");
break;
case GPLinkSite:
ScepWriteSingleUnicodeLog(hfTemp, bCRLF, L"GPLinkSite ");
break;
case GPLinkOrganizationalUnit:
ScepWriteSingleUnicodeLog(hfTemp, bCRLF, L"GPLinkOrganizationUnit ");
break;
default:
ScepWriteVariableUnicodeLog(hfTemp, bCRLF, L"0x%x ", pGpoInfo->GPOLink);
break;
}
if ( dwFlags & GPO_INFO_FLAG_BACKGROUND )
ScepWriteSingleUnicodeLog(hfTemp, TRUE, L"GPO_INFO_FLAG_BACKGROUND )");
// if ( pGpoInfo->pNext == NULL ) // last one
// ScepWriteVariableUnicodeLog( hfTemp, FALSE, " Total area %x", *pTotalArea);
CloseHandle(hfTemp);
}
}
}
LocalFree(szTemplateName);
} else {
rc = ERROR_NOT_ENOUGH_MEMORY;
}
return rc;
}
AREA_INFORMATION
ScepGetAvailableArea(
IN BOOL bPlanningMode,
IN LPCTSTR SysPathRoot,
IN LPCTSTR DSPath,
IN LPTSTR InfName,
IN GPO_LINK LinkInfo,
IN BOOL bIsDC
)
{
int index=0;
PWSTR Buffer=NULL, Buf2=NULL;
//
// dynamic allocate stack variables
//
SafeAllocaAllocate(Buffer, (MAX_PATH+50)*sizeof(WCHAR));
if ( Buffer == NULL ) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return 0;
}
SafeAllocaAllocate(Buf2, (MAX_PATH+50)*sizeof(WCHAR));
if ( Buf2 == NULL ) {
SafeAllocaFree(Buffer);
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return 0;
}
intptr_t hFile;
struct _wfinddata_t FileInfo;
Buf2[0] = L'\0';
GetSystemWindowsDirectory(Buf2, MAX_PATH);
DWORD WindirLen = wcslen(Buf2);
wcscpy(Buffer, Buf2);
if (bPlanningMode) {
swprintf(Buf2+WindirLen,
PLANNING_GPT_DIR L"tmpgptfl.inf\0"
);
}
else {
swprintf(Buf2+WindirLen,
DIAGNOSIS_GPT_DIR L"tmpgptfl.inf\0"
);
}
DeleteFile(Buf2);
CopyFile( InfName, Buf2, FALSE );
SetFileAttributes(Buf2, FILE_ATTRIBUTE_NORMAL);
SetLastError(ERROR_SUCCESS);
AREA_INFORMATION Area = SceGetAreas(Buf2);
if ( Area != 0 ) {
//
// for diagnosis mode
// copy the template to local machine %windir%\\security\\templates\\policies\gpt*.* (inf or dom)
// for planning mode
// copy the template to local machine %TMP%\\guid\gpt*.* (inf or dom)
//
if (bPlanningMode) {
swprintf(Buffer+WindirLen,
PLANNING_GPT_DIR L"gpt%05d.*\0",
index);
}
else {
swprintf(Buffer+WindirLen,
DIAGNOSIS_GPT_DIR L"gpt%05d.*\0",
index);
}
hFile = _wfindfirst(Buffer, &FileInfo);
while ( hFile != -1 ) {
_findclose(hFile);
index++;
if (bPlanningMode) {
swprintf(Buffer+WindirLen,
PLANNING_GPT_DIR L"gpt%05d.*\0",
index);
}
else {
swprintf(Buffer+WindirLen,
DIAGNOSIS_GPT_DIR L"gpt%05d.*\0",
index);
}
hFile = _wfindfirst(Buffer, &FileInfo);
}
DWORD Len=wcslen(Buffer);
if ( LinkInfo == GPLinkDomain ) {
//
// this is a domain GPO
//
Buffer[Len-1] = L'd';
Buffer[Len] = L'o';
Buffer[Len+1] = L'm';
Buffer[Len+2] = L'\0';
} else {
//
// this is not domain GPO
//
Buffer[Len-1] = L'i';
Buffer[Len] = L'n';
Buffer[Len+1] = L'f';
Buffer[Len+2] = L'\0';
if ( bIsDC ) {
/*
LogEvent(MyModuleHandle,
STATUS_SEVERITY_INFORMATIONAL,
SCEPOL_INFO_IGNORE_DOMAINPOLICY,
0,
SysPathRoot
);
*/
}
}
if ( FALSE == CopyFile( Buf2, Buffer, FALSE ) ) {
//
// copy failed, report error (GetLastError)
//
Area = 0;
} else {
//
// save the GPO sys path in this template
//
PWSTR pTemp = wcsstr(_wcsupr((LPTSTR)SysPathRoot), L"\\POLICIES");
if ( pTemp && *(pTemp+10) != L'\0' ) {
WritePrivateProfileString (TEXT("Version"),
TEXT("GPOPath"),
pTemp+10,
Buffer);
} else {
WritePrivateProfileString (TEXT("Version"),
TEXT("GPOPath"),
NULL,
Buffer);
}
//
// save the stripped GPO DS path in this template to extract canonical GPOID later
//
Len = 0;
PWSTR GpoPath = NULL;
if (DSPath &&
(Len = wcslen(DSPath)) &&
(GpoPath = (PWSTR) ScepAlloc(LMEM_ZEROINIT, (Len + 3) * sizeof(WCHAR)))){
swprintf(GpoPath,
L"\"%s\"",
ScepStripPrefix((LPTSTR)DSPath)
);
WritePrivateProfileString (TEXT("Version"),
TEXT("DSPath"),
GpoPath,
Buffer);
ScepFree(GpoPath);
}
else
WritePrivateProfileString (TEXT("Version"),
TEXT("DSPath"),
TEXT("NoName"),
Buffer);
//
// save the GPO LinkInfo in this template to extract SOMID later
//
WCHAR StringBuf[10];
_itow((int)LinkInfo, StringBuf, 10);
WritePrivateProfileString (TEXT("Version"),
TEXT("SOMID"),
StringBuf,
Buffer);
}
} else if ( GetLastError() == ERROR_FILE_NOT_FOUND ||
GetLastError() == ERROR_PATH_NOT_FOUND ) {
//
// two reasons that this will fail:
// first, the template does not exist; second, FRS/sysvol/network failed
//
if ( 0xFFFFFFFF == GetFileAttributes((LPTSTR)SysPathRoot) ) {
SetLastError(ERROR_PATH_NOT_FOUND);
} else {
//
// the sysvol/network is ok so SCE template is not there (including sub directories)
//
SetLastError(ERROR_SUCCESS);
}
}
SafeAllocaFree(Buffer);
SafeAllocaFree(Buf2);
return(Area);
}
AREA_INFORMATION
SceGetAreas(
LPTSTR InfName
)
{
if ( InfName == NULL ) {
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
SCESTATUS rc;
HINF hInf;
INFCONTEXT InfLine;
AREA_INFORMATION Area=0;
rc = SceInfpOpenProfile(
InfName,
&hInf
);
if ( SCESTATUS_SUCCESS == rc ) {
//
// policy attachments sections can't be determined here. So always take security policy section
//
if( SetupFindFirstLine(hInf, szSystemAccess, NULL, &InfLine) ||
SetupFindFirstLine(hInf, szAuditSystemLog, NULL, &InfLine) ||
SetupFindFirstLine(hInf, szAuditSecurityLog, NULL, &InfLine) ||
SetupFindFirstLine(hInf, szAuditApplicationLog, NULL, &InfLine) ||
SetupFindFirstLine(hInf, szAuditEvent, NULL, &InfLine) ||
SetupFindFirstLine(hInf, szKerberosPolicy, NULL, &InfLine) ||
SetupFindFirstLine(hInf, szRegistryValues, NULL, &InfLine) ) {
Area |= AREA_SECURITY_POLICY;
} else {
PSCE_NAME_LIST pList=NULL, pTemp;
rc = ScepEnumerateAttachments(&pList, SCE_ATTACHMENT_POLICY);
if ( ERROR_SUCCESS == rc && pList ) {
//
// find policy attachments
//
for ( pTemp = pList; pTemp != NULL; pTemp = pTemp->Next ) {
if ( SetupFindFirstLine(hInf, pTemp->Name, NULL, &InfLine) ) {
Area |= AREA_SECURITY_POLICY;
break;
}
}
ScepFreeNameList(pList);
}
}
if(SetupFindFirstLine(hInf,szPrivilegeRights,NULL,&InfLine)) {
Area |= AREA_PRIVILEGES;
}
if(SetupFindFirstLine(hInf,szGroupMembership,NULL,&InfLine)) {
Area |= AREA_GROUP_MEMBERSHIP;
}
if(SetupFindFirstLine(hInf,szRegistryKeys,NULL,&InfLine)) {
Area |= AREA_REGISTRY_SECURITY;
}
if(SetupFindFirstLine(hInf,szFileSecurity,NULL,&InfLine)) {
Area |= AREA_FILE_SECURITY;
}
#if 0
if(SetupFindFirstLine(hInf,szDSSecurity,NULL,&InfLine)) {
Area |= AREA_DS_OBJECTS;
}
#endif
if(SetupFindFirstLine(hInf,szServiceGeneral,NULL,&InfLine)) {
Area |= AREA_SYSTEM_SERVICE;
} else {
PSCE_NAME_LIST pList=NULL, pTemp;
rc = ScepEnumerateAttachments(&pList, SCE_ATTACHMENT_SERVICE);
if ( ERROR_SUCCESS == rc && pList ) {
//
// find policy attachments
//
for ( pTemp = pList; pTemp != NULL; pTemp = pTemp->Next ) {
if ( SetupFindFirstLine(hInf, pTemp->Name, NULL, &InfLine) ) {
Area |= AREA_SYSTEM_SERVICE;
break;
}
}
ScepFreeNameList(pList);
}
}
//
// close the inf file
//
SceInfpCloseProfile(hInf);
SetLastError(ERROR_SUCCESS);
}
return Area;
}
BOOL
ScepClearGPObjects(
IN BOOL bPlanningMode
)
{
PWSTR Buffer=NULL;
DWORD rc = ERROR_SUCCESS;
//
// dynamic allocate stack
//
SafeAllocaAllocate(Buffer, (MAX_PATH+50)*sizeof(WCHAR));
if ( Buffer == NULL ) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
Buffer[0] = L'\0';
GetSystemWindowsDirectory(Buffer, MAX_PATH);
Buffer[MAX_PATH] = L'\0';
DWORD WindirLen = wcslen(Buffer);
//
// make sure policies or policies\planning directory exist
// don't worry about errors - later it will be caught
wcscat(Buffer, DIAGNOSIS_GPT_DIR);
CreateDirectory(Buffer, NULL);
if (bPlanningMode) {
wcscat(Buffer, L"planning");
CreateDirectory(Buffer, NULL);
}
wcscpy(Buffer+WindirLen, (bPlanningMode ? PLANNING_GPT_DIR : DIAGNOSIS_GPT_DIR));
if (!bPlanningMode)
SetFileAttributes(Buffer, FILE_ATTRIBUTE_HIDDEN);
wcscat(Buffer, L"gpt*.*");
intptr_t hFile;
struct _wfinddata_t FileInfo;
hFile = _wfindfirst(Buffer, &FileInfo);
if ( hFile != -1 ) {
do {
wcscpy(Buffer+WindirLen, (bPlanningMode ? PLANNING_GPT_DIR : DIAGNOSIS_GPT_DIR));
wcscat(Buffer, FileInfo.name);
// ANZ and KB Q310741
//
// in case antivirus etc. marks sysvol/cached
// copy as read-only, need to set it back
// to normal in order to delete
//
SetFileAttributes(Buffer, FILE_ATTRIBUTE_NORMAL);
if ( !DeleteFile(Buffer) ){
rc = GetLastError();
break;
}
} while ( _wfindnext(hFile, &FileInfo) == 0 );
_findclose(hFile);
}
SafeAllocaFree(Buffer);
if (rc != ERROR_SUCCESS) {
SetLastError(rc);
return(FALSE);
}
return(TRUE);
}
DWORD
ScepWinlogonThreadFunc(
IN LPVOID lpv
)
/*
Routine Description:
The working thread to apply slow GPT polices. These policies include file
security, registry security, DS object security if on a DC,
system service security, and any other SCE extensions security.
The SCE library is loaded before this thread is created (in order to keep
the ref count non zero) so the SCE library is freed when this thread exits.
Memory allocated in the input argument (by primary thread) are freed in this
thread too.
Arguments:
lpv - the input info in ENGINEARGS structure, in which
szTemplateName is the group policy template name to apply
szLogName is the optional log file name
Return Value:
Win32 errors
*/
{
ENGINEARGS *pEA;
DWORD rc;
//
// try-except block to ensure critical section is freed if this thread is entered
// need two - due to two return's
//
if ( lpv ) {
pEA = (ENGINEARGS *)lpv;
if ( hSceDll ) {
__try {
//
// need to initialize the COM library to use the unmarshalling functions
//
if (pEA->pStream) {
CoInitializeEx( NULL, COINIT_MULTITHREADED );
VOID *pV = NULL;
if (S_OK == CoGetInterfaceAndReleaseStream(pEA->pStream, IID_IWbemServices, &pV))
tg_pWbemServices = (IWbemServices *) pV;
else
tg_pWbemServices = NULL;
}
//
// only apply template to the system if SCE library is loaded in memory
// otherwise, access violation occurs when access code.
//
DWORD dConfigOpt = SCE_UPDATE_DB |
SCE_POLICY_TEMPLATE |
SCE_POLBIND_NO_AUTH;
DWORD dwWinlogonLog=0;
ScepRegQueryIntValue(
HKEY_LOCAL_MACHINE,
GPT_SCEDLL_NEW_PATH,
TEXT("ExtensionDebugLevel"),
&dwWinlogonLog
);
switch ( dwWinlogonLog ) {
case 2:
dConfigOpt |= SCE_DEBUG_LOG;
break;
case 1:
dConfigOpt |= SCE_VERBOSE_LOG;
break;
default:
dConfigOpt |= SCE_DISABLE_LOG;
}
if (pEA->dwDiagOptions & SCE_RSOP_CALLBACK)
dConfigOpt |= SCE_RSOP_CALLBACK;
rc = ScepSceStatusToDosError(
ScepConfigSystem(
NULL,
pEA->szTemplateName,
NULL,
pEA->szLogName,
(tg_pWbemServices == NULL ? dConfigOpt & ~SCE_RSOP_CALLBACK : dConfigOpt), //rsop not supported
pEA->Area,
NULL, // no callback
NULL, // no callback window
NULL // no warning
));
if (tg_pWbemServices) {
tg_pWbemServices->Release();
tg_pWbemServices = NULL;
}
if (pEA->pStream)
CoUninitialize();
if (gpwszDCDomainName) {
LocalFree(gpwszDCDomainName);
gpwszDCDomainName = NULL;
}
if ( ERROR_SUCCESS == rc ) {
//
// Log the last config time
//
ScepLogLastConfigTime();
}
//
// set status back to GP framework with the new API
//
ProcessGroupPolicyCompletedEx(
&SceExtGuid,
pEA->pHandle,
rc,
gHrAsynchRsopStatus); //WBEM_E_INVALID_PARAMETER
//
// free memory allocated by the primary thread
//
if ( pEA->szTemplateName ) {
LocalFree(pEA->szTemplateName);
}
if ( pEA->szLogName ) {
LocalFree(pEA->szLogName);
}
LocalFree(pEA);
} __except(EXCEPTION_EXECUTE_HANDLER) {
rc = (DWORD)EVENT_E_INTERNALEXCEPTION;
}
//
// leave the cs before returning/exiting
//
// LeaveCriticalSection(&DiagnosisPolicypropSync);
//
// free library and exit the thread
//
FreeLibraryAndExitThread(hSceDll, rc );
return(rc);
} else {
rc = ERROR_INVALID_PARAMETER;
}
} else {
rc = ERROR_INVALID_PARAMETER;
}
//
// the main spawner thread is relying on this thread to release the cs
// before we exit this thread, under any circumstances, release the cs to enable other
// diagnosis/policy prop threads to enter
//
// LeaveCriticalSection(&DiagnosisPolicypropSync);
ExitThread(rc);
return(rc);
}
DWORD
ScepLogLastConfigTime()
{
DWORD dCurrentSeconds=0;
LARGE_INTEGER CurrentTime;
DWORD rc;
NTSTATUS NtStatus;
NtStatus = NtQuerySystemTime(&CurrentTime);
if ( NT_SUCCESS(NtStatus) ) {
//
// Convert to seconds to save
//
if ( RtlTimeToSecondsSince1980 (&CurrentTime, &dCurrentSeconds) ) {
rc = ScepRegSetIntValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("LastWinLogonConfig"),
dCurrentSeconds
);
} else {
rc = GetLastError();
}
} else {
rc = RtlNtStatusToDosError(NtStatus);
}
return(rc);
}
DWORD
ScepEnumerateAttachments(
OUT PSCE_NAME_LIST *pEngineList,
IN SCE_ATTACHMENT_TYPE aType
)
/*
Routine Description:
Query all services which has a service engine for security manager
The service engine information is in the registry:
MACHINE\Software\Microsoft\Windows NT\CurrentVersion\SeCEdit
Arguments:
pEngineList - the service engine name list
aType - attachment type (service or policy)
Return Value:
SCE status
*/
{
if ( pEngineList == NULL ) {
return(ERROR_INVALID_PARAMETER);
}
DWORD Win32Rc;
HKEY hKey=NULL;
switch ( aType ) {
case SCE_ATTACHMENT_SERVICE:
Win32Rc = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
SCE_ROOT_SERVICE_PATH,
0,
KEY_READ,
&hKey
);
break;
case SCE_ATTACHMENT_POLICY:
Win32Rc = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
SCE_ROOT_POLICY_PATH,
0,
KEY_READ,
&hKey
);
break;
default:
return ERROR_INVALID_PARAMETER;
}
if ( Win32Rc == ERROR_SUCCESS ) {
TCHAR Buffer[MAX_PATH];
DWORD BufSize;
DWORD index = 0;
DWORD EnumRc;
//
// enumerate all subkeys of the key
//
do {
memset(Buffer, '\0', MAX_PATH*sizeof(WCHAR));
BufSize = MAX_PATH;
EnumRc = RegEnumKeyEx(
hKey,
index,
Buffer,
&BufSize,
NULL,
NULL,
NULL,
NULL);
if ( EnumRc == ERROR_SUCCESS ) {
index++;
//
// get the attachment name
//
Win32Rc = ScepAddToNameList(pEngineList, Buffer, BufSize+1);
if ( Win32Rc != ERROR_SUCCESS ) {
break;
}
}
} while ( EnumRc != ERROR_NO_MORE_ITEMS );
RegCloseKey(hKey);
//
// remember the error code from enumeration
//
if ( EnumRc != ERROR_SUCCESS && EnumRc != ERROR_NO_MORE_ITEMS ) {
if ( Win32Rc == ERROR_SUCCESS )
Win32Rc = EnumRc;
}
}
if ( Win32Rc != NO_ERROR && *pEngineList != NULL ) {
//
// free memory allocated for the list
//
ScepFreeNameList(*pEngineList);
*pEngineList = NULL;
}
return( Win32Rc );
}
DWORD
WINAPI
SceProcessEFSRecoveryGPO(
IN DWORD dwFlags,
IN HANDLE hUserToken,
IN HKEY hKeyRoot,
IN PGROUP_POLICY_OBJECT pDeletedGPOList,
IN PGROUP_POLICY_OBJECT pChangedGPOList,
IN ASYNCCOMPLETIONHANDLE pHandle,
IN BOOL *pbAbort,
IN PFNSTATUSMESSAGECALLBACK pStatusCallback
)
/*
Description:
This is a interface called from winlogon/userenv to process GPOs. The dll
name and procedure name are registered to winlogon under GpExtensions.
This routine applies a EFS recovery policy to the current system. The EFS
recovery policy is stored in registry as EfsBlob and will be loaded by
the registry extension into hKeyRoot. So this extension requires that
registry.pol must be loaded successfully by the registry extension.
This interface can be called during system boot, or every GPFrequency hours
after logon. The input argument contains info for where this interface is
called and under which context (user, or machine) this interface is called.
This interface shouldn't be called for user policy but within the routine,
a checking is still made to make sure that user level policies is not processed.
Arguments:
dwFlags - the GPO Info flags
GPO_INFO_FLAG_MACHINE
GPO_INFO_FLAG_SLOWLINK
GPO_INFO_FLAG_BACKGROUND
GPO_INFO_FLAG_VERBOSE
GPO_INFO_FLAG_NOCHANGES
hUserToken - the user token for which the user policy should be applied
if it's the machine policy, hUserToken refers to system
hKeyRoot - the root for the policy in registry
pDeletedGPOList - all deleted GPOs to process
pChangedGPOList - all GPOs that are either changed or not changed
pHandle - for asynchronous processing
pbAbort - processing of GPO should be aborted if this is set to TRUE
(in case of system shutdown or user log off)
pStatusCallback - Callback function for displaying status messages
Return Value:
Win32 error
ERROR_SUCCESS
other errors
Note, if error is returned, the previous cached GPO list will be used for
next propagation (because it didn't succeed this time).
*/
{
// validate input parameters
if ( !hKeyRoot || !hUserToken ) {
return(ERROR_INVALID_PARAMETER);
}
//Check if demote flag is set need to add Auth user and Interactive to users group.
// group membership should be configured by SCE/demote via tattoo table. This is not needed
// ScepCheckDemote();
//
// check if system is shutdown, or dcpromo is going
//
if ( ScepShouldTerminateProcessing( pbAbort, FALSE ) ) {
return(ERROR_OPERATION_ABORTED);
}
DWORD rc;
BOOL b;
//
// put a try except block in case arguments are invalid
//
__try {
rc = RtlNtStatusToDosError( ScepIsSystemContext(hUserToken, &b) );
(void) InitializeEvents(L"SceEfs");
if ( !b ) {
//
// can't get current user SID or it's not system SID
//
if ( ERROR_SUCCESS != rc ) {
//
// error occurs when querying/comparing user token
//
LogEvent(MyModuleHandle,
STATUS_SEVERITY_ERROR,
SCEPOL_ERROR_PROCESS_GPO,
IDS_ERROR_GET_TOKEN_USER,
rc
);
ShutdownEvents();
return( rc );
} else {
//
// this is not the machine (system) token, return
//
ShutdownEvents();
return( ERROR_SUCCESS );
}
}
//
// check if system is shutdown, or dcpromo is going
//
if ( ScepShouldTerminateProcessing( pbAbort, FALSE ) ) {
ShutdownEvents();
return(ERROR_OPERATION_ABORTED);
}
//
// check if debug log is requested
//
DWORD dwDebugLevel=0;
ScepRegQueryIntValue(
HKEY_LOCAL_MACHINE, // always save the time in HKEY_LOCAL_MACHINE
GPT_EFS_NEW_PATH,
TEXT("ExtensionDebugLevel"),
&dwDebugLevel
);
//
// if there is no change to EFS policy
//
if ( dwFlags & GPO_INFO_FLAG_NOCHANGES ) {
if ( dwDebugLevel ) {
LogEvent(MyModuleHandle,
STATUS_SEVERITY_INFORMATIONAL,
SCEPOL_INFO_PROCESS_GPO,
IDS_EFS_NOT_CHANGE
);
ShutdownEvents();
}
return(ERROR_SUCCESS);
}
//
// process EFS policy
//
HKEY hKey=NULL;
DWORD RegType=0;
DWORD dSize=0;
PUCHAR pEfsBlob=NULL;
if ( (rc = RegOpenKeyEx(
hKeyRoot,
CERT_EFSBLOB_REGPATH,
0,
KEY_READ,
&hKey
)) == ERROR_SUCCESS ) {
//
// query value for EfsBlob
//
if(( rc = RegQueryValueEx(hKey,
CERT_EFSBLOB_VALUE_NAME,
0,
&RegType,
NULL,
&dSize
)) == ERROR_SUCCESS ) {
if ( REG_BINARY == RegType ) {
//
// must be binary type data
//
pEfsBlob = (PUCHAR)ScepAlloc( LMEM_ZEROINIT, dSize+1);
if ( !pEfsBlob ) {
rc = ERROR_NOT_ENOUGH_MEMORY;
} else {
rc = RegQueryValueEx(
hKey,
CERT_EFSBLOB_VALUE_NAME,
0,
&RegType,
(BYTE *)pEfsBlob,
&dSize
);
if ( ERROR_SUCCESS != rc ) {
ScepFree(pEfsBlob);
pEfsBlob = NULL;
dSize = 0;
}
}
} else {
rc = ERROR_INVALID_DATATYPE;
}
}
RegCloseKey(hKey);
}
if ( rc == ERROR_FILE_NOT_FOUND ) {
//
// if the key or the value doesn't exist
// ignore the error (no EFS policy)
//
rc = ERROR_SUCCESS;
}
//
// if pEfsBlob is NULL, it means that there is no EFS policy defined
//
if ( ERROR_SUCCESS == rc ) {
//
// check if system is shutdown, or dcpromo is going
//
if ( !ScepShouldTerminateProcessing( pbAbort, FALSE ) ) {
rc = ScepConfigureEFSPolicy( pEfsBlob, dSize, dwDebugLevel );
} else {
rc = GetLastError();
}
ScepFree(pEfsBlob);
} else if ( dwDebugLevel ) {
LogEvent(MyModuleHandle,
STATUS_SEVERITY_ERROR,
SCEPOL_INFO_PROCESS_GPO,
IDS_NO_EFS_TOTAL,
rc
);
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
rc = ERROR_INVALID_PARAMETER;
}
ShutdownEvents();
return rc;
}
DWORD
ScepConfigureEFSPolicy(
IN PUCHAR pEfsBlob,
IN DWORD dwSize,
IN DWORD dwDebugLevel
)
/*
Routine Description:
This routine writes EFS recovery policy defined in the policy storage
(all processed by the registry extension) to LSA storage.
Arguments:
pEfsBlob - the EFS blob
Return Value:
Win32 error code
*/
{
DWORD rc=ERROR_SUCCESS;
NTSTATUS NtStatus;
BOOL bSet;
LSA_HANDLE PolicyHandle=NULL;
PPOLICY_DOMAIN_EFS_INFO Buffer=NULL;
POLICY_DOMAIN_EFS_INFO EfsInfo;
//
// only set to LSA if there is EFS policy defined in any level
// NO EFS policy is defined as 0 certificated but the EFS blob shouldn't be NULL
//
// open LSA policy
//
bSet = TRUE; // if to set EFS policy
NtStatus = ScepOpenLsaPolicy(
MAXIMUM_ALLOWED, //GENERIC_ALL,
&PolicyHandle,
TRUE
);
if (NT_SUCCESS(NtStatus)) {
//
// query existing EFS policy blob
// ignore errors from query
//
NtStatus = LsaQueryDomainInformationPolicy(
PolicyHandle,
PolicyDomainEfsInformation,
(PVOID *)&Buffer
);
if ( NT_SUCCESS(NtStatus) && Buffer ) {
//
// compare the length and/or buffer to determine if
// blob is changed because every time data is set to LSA
// EFS server will get notified even when policy
// is changed.
//
if ( Buffer->InfoLength != dwSize ||
(Buffer->EfsBlob && pEfsBlob == NULL) ||
(Buffer->EfsBlob == NULL && pEfsBlob ) ||
(Buffer->EfsBlob &&
memcmp(pEfsBlob, Buffer->EfsBlob, (size_t)dwSize) != 0) ) {
//
// the new EFS blob is different than existing one
//
bSet = TRUE;
} else {
bSet = FALSE;
}
}
//
// free memory allocated by LSA
//
if ( Buffer ) {
LsaFreeMemory((PVOID)Buffer);
Buffer = NULL;
}
//
// set EFS policy if bSet is TRUE
//
if ( bSet ) {
EfsInfo.InfoLength = dwSize;
EfsInfo.EfsBlob = pEfsBlob;
NtStatus = LsaSetDomainInformationPolicy(
PolicyHandle,
PolicyDomainEfsInformation,
(PVOID)&EfsInfo
);
rc = RtlNtStatusToDosError(NtStatus);
if ( !NT_SUCCESS(NtStatus) ) {
LogEvent(MyModuleHandle,
STATUS_SEVERITY_ERROR,
SCEPOL_ERROR_PROCESS_GPO,
IDS_SAVE_EFS,
rc,
dwSize
);
} else if ( dwDebugLevel ) {
LogEvent(MyModuleHandle,
STATUS_SEVERITY_INFORMATIONAL,
SCEPOL_INFO_PROCESS_GPO,
IDS_SAVE_EFS,
0,
dwSize
);
}
} else if ( dwDebugLevel ) {
LogEvent(MyModuleHandle,
STATUS_SEVERITY_INFORMATIONAL,
SCEPOL_INFO_PROCESS_GPO,
IDS_EFS_NOT_CHANGE
);
}
//
// close LSA policy
//
LsaClose(PolicyHandle);
} else {
rc = RtlNtStatusToDosError( NtStatus );
LogEvent(MyModuleHandle,
STATUS_SEVERITY_ERROR,
SCEPOL_ERROR_PROCESS_GPO,
IDS_ERROR_OPEN_LSAEFS,
rc
);
}
return(rc);
}
DWORD
ScepWaitConfigSystem(
IN LPTSTR SystemName OPTIONAL,
IN PWSTR InfFileName OPTIONAL,
IN PWSTR DatabaseName OPTIONAL,
IN PWSTR LogFileName OPTIONAL,
IN DWORD ConfigOptions,
IN AREA_INFORMATION Area,
IN PSCE_AREA_CALLBACK_ROUTINE pCallback OPTIONAL,
IN HANDLE hCallbackWnd OPTIONAL,
OUT PDWORD pdWarning OPTIONAL
)
{
INT cnt=0;
DWORD rc;
while (cnt < 24) {
rc = ScepSceStatusToDosError(
ScepConfigSystem(
SystemName,
InfFileName,
DatabaseName,
LogFileName,
ConfigOptions,
Area,
pCallback,
hCallbackWnd,
pdWarning
));
if ( rc != ERROR_NOT_SUPPORTED ) {
//
// the server is initialized now.
//
break;
}
LogEventAndReport(MyModuleHandle,
LogFileName,
0,
0,
IDS_POLICY_TIMEOUT,
cnt+1
);
Sleep(5000); // 5 second
cnt++;
}
return(rc);
}
/*
BOOL
ScepCheckDemote()
{
//
// If sucess lets see if user just did demote and reboot.
//
DWORD dwDemoteInProgress=0;
ScepRegQueryIntValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("DemoteInProgress"),
&dwDemoteInProgress
);
if (dwDemoteInProgress) {
DWORD rc1;
//
// Attempt to add Authenticated Users and Interactive back into Users group.
//
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
PSID AuthenticatedUsers = NULL;
PSID Interactive = NULL;
WCHAR Name[36];
BOOL b;
LOCALGROUP_MEMBERS_INFO_0 lgrmi0[2];
HMODULE hMod = GetModuleHandle(L"scecli.dll");
LoadString(hMod, IDS_NAME_USERS, Name, 36);
b = AllocateAndInitializeSid (
&NtAuthority,
1,
SECURITY_AUTHENTICATED_USER_RID,
0, 0, 0, 0, 0, 0, 0,
&AuthenticatedUsers
);
if (b) {
lgrmi0[0].lgrmi0_sid = AuthenticatedUsers;
b = AllocateAndInitializeSid (
&NtAuthority,
1,
SECURITY_INTERACTIVE_RID,
0, 0, 0, 0, 0, 0, 0,
&Interactive
);
if (b) {
lgrmi0[1].lgrmi0_sid = Interactive;
rc1 = NetLocalGroupAddMembers(
NULL,
Name,
0,
(PBYTE) &lgrmi0,
2
);
}
else {
if ( AuthenticatedUsers ) {
FreeSid( AuthenticatedUsers );
}
return FALSE;
}
if ( AuthenticatedUsers ) {
FreeSid( AuthenticatedUsers );
}
if ( Interactive ) {
FreeSid( Interactive );
}
if (rc1 == ERROR_SUCCESS) {
// Need to delete the value.
rc1 = ScepRegDeleteValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("DemoteInProgress")
);
if ( rc1 != ERROR_SUCCESS &&
rc1 != ERROR_FILE_NOT_FOUND &&
rc1 != ERROR_PATH_NOT_FOUND ) {
// if can't delete the value, set the value to 0
ScepRegSetIntValue( HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("DemoteInProgress"),
0
);
}
}
else {
return FALSE;
}
}
else {
return FALSE;
}
}
return TRUE;
}
*/