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.
 
 
 
 
 
 

5972 lines
170 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
setupcln.cpp
Abstract:
SCE setup 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 "scerpc.h"
#include "scesetup.h"
#include "sceutil.h"
#include "clntutil.h"
#include "scedllrc.h"
#include "infp.h"
#include <ntrpcp.h>
#include <io.h>
//#include "gpedit.h"
//#include <initguid.h>
#include <lmaccess.h>
#include "commonrc.h"
#include <aclapi.h>
#include <rpcasync.h>
#include <sddl.h>
typedef HRESULT (*PFREGISTERSERVER)(void);
extern BOOL gbClientInDcPromo;
static SCEPR_CONTEXT hSceSetupHandle=NULL;
extern PVOID theCallBack;
extern HANDLE hCallbackWnd;
extern DWORD CallbackType;
extern HINSTANCE MyModuleHandle;
TCHAR szCallbackPrefix[MAX_PATH];
#define STR_GUID_LEN 36
#define SCESETUP_BACKUP_SECURITY 0x40
#define PRODUCT_UNKNOWN 0
#define EFS_NOTIFY_PATH TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Notify\\EFS")
DWORD dwThisMachine = PRODUCT_UNKNOWN;
WCHAR szUpInfFile[MAX_PATH*2+1] = {'\0'};
BOOL bIsNT5 = TRUE;
DWORD
WhichNTProduct();
BOOL
ScepAddAuthUserToLocalGroup();
DWORD dwCallbackTotal=0;
DWORD
ScepSetupOpenSecurityDatabase(
IN BOOL bSystemOrAdmin
);
DWORD
ScepSetupCloseSecurityDatabase();
typedef enum _SCESETUP_OPERATION_TYPE {
SCESETUP_UPDATE=1,
SCESETUP_MOVE
} SCESETUP_OPERATION_TYPE;
typedef enum _SCESETUP_OBJECT_TYPE {
SCESETUP_FILE=1,
SCESETUP_KEY,
SCESETUP_SERVICE
} SCESETUP_OBJECT_TYPE;
DWORD
SceSetuppLogComponent(
IN DWORD ErrCode,
IN SCESETUP_OBJECT_TYPE ObjType,
IN SCESETUP_OPERATION_TYPE OptType,
IN PWSTR Name,
IN PWSTR SDText OPTIONAL,
IN PWSTR SecondName OPTIONAL
);
SCESTATUS
ScepSetupWriteOneError(
IN HANDLE hFile,
IN DWORD rc,
IN LPTSTR buf
);
SCESTATUS
ScepSetupWriteError(
IN LPTSTR LogFileName,
IN PSCE_ERROR_LOG_INFO pErrlog
);
SCESTATUS
ScepUpdateBackupSecurity(
IN PCTSTR pszSetupInf,
IN PCTSTR pszWindowsFolder,
IN BOOL bIsDC
);
BOOL
pCreateDefaultGPOsInSysvol(
IN LPTSTR DomainDnsName,
IN LPTSTR szSysvolPath,
IN DWORD Options,
IN LPTSTR LogFileName
);
BOOL
pCreateSysvolContainerForGPO(
IN LPCTSTR strGuid,
IN LPTSTR szPath,
IN DWORD dwStart
);
BOOL
pCreateOneGroupPolicyObject(
IN PWSTR pszGPOSysPath,
IN BOOL bDomainLevel,
IN PWSTR LogFileName
);
DWORD
ScepDcPromoSharedInfo(
IN HANDLE ClientToken,
IN BOOL bDeleteLog,
IN BOOL bSetSecurity,
IN DWORD dwPromoteOptions,
IN PSCE_PROMOTE_CALLBACK_ROUTINE pScePromoteCallBack OPTIONAL
);
NTSTATUS
ScepDcPromoRemoveUserRights();
NTSTATUS
ScepDcPromoRemoveTwoRights(
IN LSA_HANDLE PolicyHandle,
IN SID_IDENTIFIER_AUTHORITY *pIA,
IN UCHAR SubAuthCount,
IN DWORD Rid1,
IN DWORD Rid2
);
DWORD
ScepSystemSecurityInSetup(
IN PWSTR InfName,
IN PCWSTR LogFileName OPTIONAL,
IN AREA_INFORMATION Area,
IN UINT nFlag,
IN PSCE_NOTIFICATION_CALLBACK_ROUTINE pSceNotificationCallBack OPTIONAL,
IN OUT PVOID pValue OPTIONAL
);
DWORD
ScepMoveRegistryValue(
IN HKEY hKey,
IN PWSTR KeyFrom,
IN PWSTR ValueFrom,
IN PWSTR KeyTo OPTIONAL,
IN PWSTR ValueTo OPTIONAL
);
DWORD
ScepBreakSDDLToMultiFields(
IN PWSTR pszObjName,
IN PWSTR pszSDDL,
IN DWORD dwSDDLsize,
IN BYTE ObjStatus,
OUT PWSTR *ppszAdjustedInfLine
);
SCESTATUS
SceInfpBreakTextIntoMultiFields(
IN PWSTR szText,
IN DWORD dLen,
OUT LPDWORD pnFields,
OUT LPDWORD *arrOffset
);
#ifndef _WIN64
BOOL
GetIsWow64 (
VOID
);
#endif // _WIN64
//
// Client APIs in scesetup.h (for setup integration)
//
DWORD
WINAPI
SceSetupUpdateSecurityFile(
IN PWSTR FileFullName,
IN UINT nFlag,
IN PWSTR SDText
)
/*
Routine Description:
This routine applies the security specified in SDText to the file on
local system and update the SDDL security information to the SCE
database.
Arguments:
FileFullName - the full path name of the file to update
nFlag - reserved flag for file option
SDText - the SDDL format security descriptor
Return Value:
WIN32 error code for the status of this operation
*/
{
if ( FileFullName == NULL || SDText == NULL ) {
return(ERROR_INVALID_PARAMETER);
}
//
// global database handle
//
SCESTATUS rc = ScepSetupOpenSecurityDatabase(FALSE);
if ( rc == NO_ERROR ) {
RpcTryExcept {
//
// update the file
//
rc = SceRpcSetupUpdateObject(
hSceSetupHandle,
(wchar_t *)FileFullName,
(DWORD)SE_FILE_OBJECT,
nFlag,
(wchar_t *)SDText
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
//
// get exception code (DWORD)
//
rc = RpcExceptionCode();
} RpcEndExcept;
}
SceSetuppLogComponent(rc,
SCESETUP_FILE,
SCESETUP_UPDATE,
FileFullName,
SDText,
NULL);
return rc;
}
DWORD
WINAPI
SceSetupUpdateSecurityService(
IN PWSTR ServiceName,
IN DWORD StartType,
IN PWSTR SDText
)
/*
Routine Description:
This routine applies the security specified in SDText to the service on
local system and update the SDDL security information to the SCE
database.
Arguments:
ServiceName - the name of the service to update
StartType - startup type of the service
SDText - the SDDL format security descriptor
Return Value:
WIN32 error code for the status of this operation
*/
{
if ( ServiceName == NULL || SDText == NULL )
return(ERROR_INVALID_PARAMETER);
//
// global database handle
//
SCESTATUS rc = ScepSetupOpenSecurityDatabase(FALSE);
if ( rc == NO_ERROR ) {
RpcTryExcept {
//
// Update the object information
//
rc = SceRpcSetupUpdateObject(
hSceSetupHandle,
(wchar_t *)ServiceName,
(DWORD)SE_SERVICE,
(UINT)StartType,
(wchar_t *)SDText
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
//
// get exception code (DWORD)
//
rc = RpcExceptionCode();
} RpcEndExcept;
}
SceSetuppLogComponent(rc,
SCESETUP_SERVICE,
SCESETUP_UPDATE,
ServiceName,
SDText,
NULL);
return rc;
}
// Registry object names returned by NtQueryObject are prefixed by
// the following
#define REG_OBJ_TAG L"\\REGISTRY\\"
#define REG_OBJ_TAG_LEN (sizeof(REG_OBJ_TAG) / sizeof(WCHAR) - 1)
DWORD
WINAPI
SceSetupUpdateSecurityKey(
IN HKEY hKeyRoot,
IN PWSTR KeyPath,
IN UINT nFlag,
IN PWSTR SDText
)
/*
Routine Description:
This routine applies the security specified in SDText to the registry key
on local system and update the SDDL security information to the SCE
database.
on a 64 bit platform; if the client is 64 bit, then we secure the 64 bit
registry. if the client is 32 bit, then we secure the 32 bit registry. Unless,
SCE_SETUP_32KEY is set in the flags, in which case will secure always the 32 bit
registry; or if the SCE_SETUP_64KEY is set in the flags, in which case will secure the
64 bit registry always. if both are defined the SCE_SETUP_32KEY takes precedence.
Arguments:
hKeyRoot - root handle of the key
KeyPath - the subdir key path relative to the root
nFlag - reserved flag for key option
SDText - the SDDL format security descriptor
Return Value:
WIN32 error code for the status of this operation
*/
{
if ( hKeyRoot == NULL || SDText == NULL )
return(ERROR_INVALID_PARAMETER);
DWORD rc = ERROR_SUCCESS;
PWSTR KeyFullName=NULL;
DWORD Len= 16;
DWORD cLen=0;
POBJECT_NAME_INFORMATION pNI=NULL;
NTSTATUS Status;
LPWSTR pwszPath=NULL;
DWORD cchPath=0;
#ifndef _WIN64
static BOOL bGetWow64 = TRUE;
static BOOL bIsWow64 = FALSE;
#endif //_WIN64
//
// translate the root key first
// to determine the length required for the full name
//
if ( hKeyRoot != HKEY_LOCAL_MACHINE &&
hKeyRoot != HKEY_USERS &&
hKeyRoot != HKEY_CLASSES_ROOT ) {
//
// First, determine the size of the buffer we need...
//
Status = NtQueryObject(hKeyRoot,
ObjectNameInformation,
pNI,
0,
&cLen);
if ( NT_SUCCESS(Status) ||
Status == STATUS_BUFFER_TOO_SMALL ||
Status == STATUS_INFO_LENGTH_MISMATCH ||
Status == STATUS_BUFFER_OVERFLOW ) {
//
// allocate a buffer to get name information
//
pNI = (POBJECT_NAME_INFORMATION)LocalAlloc(LPTR, cLen);
if ( pNI == NULL ) {
rc = ERROR_NOT_ENOUGH_MEMORY;
} else {
Status = NtQueryObject(hKeyRoot,
ObjectNameInformation,
pNI,
cLen,
NULL);
if (!NT_SUCCESS(Status))
{
rc = RtlNtStatusToDosError(Status);
}
else if ( pNI && pNI->Name.Buffer && pNI->Name.Length > 0 )
{
//
// Server doesn't like \REGISTRY as a prefix -- get
// rid of it and the backslash that follows it.
//
DWORD dwSize = sizeof(L"\\REGISTRY\\") - sizeof(WCHAR);
DWORD dwLen = dwSize / sizeof(WCHAR);
if (_wcsnicmp(pNI->Name.Buffer,
L"\\REGISTRY\\",
min(dwLen,
pNI->Name.Length / sizeof(WCHAR))) == 0)
{
RtlMoveMemory(pNI->Name.Buffer,
pNI->Name.Buffer + dwLen,
pNI->Name.Length - dwSize);
pNI->Name.Length -= (USHORT) dwSize;
}
//
// get the required length, plus one space for the backslash,
// and one for null
//
Len = pNI->Name.Length/sizeof(WCHAR) + 2;
}
else
{
rc = ERROR_INVALID_PARAMETER;
}
}
} else {
rc = RtlNtStatusToDosError(Status);
}
}
if ( rc == ERROR_SUCCESS ) {
//
// make a full path name for the key
//
if ( KeyPath != NULL ) {
Len += wcslen(KeyPath);
}
KeyFullName = (PWSTR)LocalAlloc(LMEM_ZEROINIT, Len*sizeof(WCHAR));
if ( KeyFullName == NULL ) {
rc = ERROR_NOT_ENOUGH_MEMORY;
}
}
if ( rc == ERROR_SUCCESS ) {
//
// translate the root key
//
if ( hKeyRoot == HKEY_LOCAL_MACHINE ) {
wcscpy(KeyFullName, L"MACHINE");
} else if ( hKeyRoot == HKEY_USERS ) {
wcscpy(KeyFullName, L"USERS");
} else if ( hKeyRoot == HKEY_CLASSES_ROOT ) {
wcscpy(KeyFullName, L"CLASSES_ROOT");
} else if ( pNI && pNI->Name.Buffer && pNI->Name.Length > 0 ) {
//
// copy the name of the key
//
memcpy(KeyFullName, pNI->Name.Buffer, pNI->Name.Length);
KeyFullName[pNI->Name.Length/sizeof(WCHAR)] = L'\0';
} else {
rc = ERROR_INVALID_PARAMETER;
}
if ( rc == ERROR_SUCCESS && KeyPath != NULL ) {
wcscat(KeyFullName, L"\\");
wcscat(KeyFullName, KeyPath);
}
}
if ( rc == ERROR_SUCCESS ) {
//
// global database handle
//
rc = ScepSetupOpenSecurityDatabase(FALSE);
if ( NO_ERROR == rc ) {
//
// since the server side only understands SCE_SETUP_32KEY,
// and otherwise will set the 64 bit registry then:
//
// we have three possible running enviroments:
// 1. 64 bit scecli -> do nothing
// 2. 32 bit scecli running on 32 bit OS -> do nothing
// 3. 32 bit scecli running on wow64 ->
// a. if SCE_SETUP_64KEY is set -> do nothing
// b. if SCE_SETUP_64KEY is not set -> set SCE_SETUP_32KEY
//
#ifndef _WIN64
if( bGetWow64 ){
bIsWow64 = GetIsWow64();
bGetWow64 = FALSE;
}
if( bIsWow64 ){
if( (nFlag & SCE_SETUP_64KEY) == 0){
nFlag |= SCE_SETUP_32KEY;
}
}
//
// clear out noise going to the server side
//
nFlag &= ~(SCE_SETUP_64KEY);
#endif
RpcTryExcept {
//
// update the object
//
rc = SceRpcSetupUpdateObject(
hSceSetupHandle,
(wchar_t *)KeyFullName,
(DWORD)SE_REGISTRY_KEY,
nFlag,
(wchar_t *)SDText
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
//
// get exception code (DWORD)
//
rc = RpcExceptionCode();
} RpcEndExcept;
}
}
SceSetuppLogComponent(rc,
SCESETUP_KEY,
SCESETUP_UPDATE,
KeyFullName ? KeyFullName : KeyPath,
SDText,
NULL);
if ( KeyFullName )
LocalFree(KeyFullName);
if ( pNI )
LocalFree(pNI);
return(rc);
}
DWORD
WINAPI
SceSetupMoveSecurityFile(
IN PWSTR FileToSetSecurity,
IN PWSTR FileToSaveInDB OPTIONAL,
IN PWSTR SDText OPTIONAL
)
{
if ( !FileToSetSecurity ) {
return(ERROR_INVALID_PARAMETER);
}
//
// if I am in setup, query the security policy/user rights for any
// policy changes within setup (such as NT4 PDC upgrade where the policy
// filter will fail to save the change)
//
DWORD dwInSetup=0;
DWORD rc = ERROR_SUCCESS;
ScepRegQueryIntValue(HKEY_LOCAL_MACHINE,
TEXT("System\\Setup"),
TEXT("SystemSetupInProgress"),
&dwInSetup
);
if ( dwInSetup ) {
rc = ScepSetupOpenSecurityDatabase(FALSE);
if ( NO_ERROR == rc ) {
RpcTryExcept {
//
// move the object
//
rc = SceRpcSetupMoveFile(
hSceSetupHandle,
(wchar_t *)FileToSetSecurity,
(wchar_t *)FileToSaveInDB,
(wchar_t *)SDText
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
//
// get exception code (DWORD)
//
rc = RpcExceptionCode();
} RpcEndExcept;
}
if ( FileToSaveInDB == NULL &&
rc != NO_ERROR ) {
//
// error occured to delete this file,
// do not report error
//
rc = NO_ERROR;
}
SceSetuppLogComponent(rc,
SCESETUP_FILE,
SCESETUP_MOVE,
FileToSetSecurity,
SDText,
FileToSaveInDB
);
} else {
SceSetuppLogComponent(rc,
SCESETUP_FILE,
SCESETUP_MOVE,
FileToSetSecurity,
NULL,
L"Operation aborted - not in setup"
);
}
return(rc);
}
DWORD
WINAPI
SceSetupUnwindSecurityFile(
IN PWSTR FileFullName,
IN PSECURITY_DESCRIPTOR pSDBackup
)
/*
Routine Description:
This routine reset security settings for the file in SCE database (unwind)
used by two-phase copy file process in setupapi.
Arguments:
FileFullName - The full path name for the file to undo.
pSDBackup - The backup security descriptor
Return Value:
WIN32 error code for the status of this operation
*/
{
if ( !FileFullName || !pSDBackup ) {
return(ERROR_INVALID_PARAMETER);
}
DWORD dwInSetup=0;
DWORD rc = ERROR_SUCCESS;
ScepRegQueryIntValue(HKEY_LOCAL_MACHINE,
TEXT("System\\Setup"),
TEXT("SystemSetupInProgress"),
&dwInSetup
);
if ( dwInSetup ) {
rc = ScepSetupOpenSecurityDatabase(FALSE);
PWSTR TextSD=NULL;
DWORD TextSize;
if ( NO_ERROR == rc ) {
rc = ConvertSecurityDescriptorToText(
pSDBackup,
0xF, // all security component
&TextSD,
&TextSize
);
}
if ( NO_ERROR == rc && TextSD ) {
RpcTryExcept {
//
// update security in the database only
//
rc = SceRpcSetupUpdateObject(
hSceSetupHandle,
(wchar_t *)FileFullName,
(DWORD)SE_FILE_OBJECT,
SCESETUP_UPDATE_DB_ONLY,
(wchar_t *)TextSD
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
//
// get exception code (DWORD)
//
rc = RpcExceptionCode();
} RpcEndExcept;
}
if ( TextSD ) {
LocalFree(TextSD);
}
}
return(rc);
}
DWORD
WINAPI
SceSetupGenerateTemplate(
IN LPTSTR SystemName OPTIONAL,
IN LPTSTR JetDbName OPTIONAL,
IN BOOL bFromMergedTable,
IN LPTSTR InfTemplateName,
IN LPTSTR LogFileName OPTIONAL,
IN AREA_INFORMATION Area
)
/*
Routine Description:
This routine generate a INF format template from the SCE database specified
by JetDbName, or the default SCE database if JetDbName is NULL.
Arguments:
JetDbName - the SCE database name (optional) to get information from.
If NULL, the default security database is used.
InfTemplateName - the inf template name to generate
LogFileName - the log file name (optional)
Area - the security area to generate
Return Value:
WIN32 error code for the status of this operation
*/
{
DWORD rc;
handle_t binding_h;
NTSTATUS NtStatus;
PSCE_ERROR_LOG_INFO pErrlog=NULL;
//
// verify the InfTemplateName for invalid path error
// or access denied error
//
rc = ScepVerifyTemplateName(InfTemplateName, &pErrlog);
if ( NO_ERROR == rc ) {
//
// RPC bind to the server
//
NtStatus = ScepBindSecureRpc(
SystemName,
L"scerpc",
0,
&binding_h
);
if ( NT_SUCCESS(NtStatus) ) {
SCEPR_CONTEXT Context;
RpcTryExcept {
//
// pass to the server site to generate template
//
rc = SceRpcGenerateTemplate(
binding_h,
(wchar_t *)JetDbName,
(wchar_t *)LogFileName,
(PSCEPR_CONTEXT)&Context
);
if ( SCESTATUS_SUCCESS == rc) {
//
// a context handle is opened to generate this template
//
rc = SceCopyBaseProfile(
(PVOID)Context,
bFromMergedTable ? SCE_ENGINE_SCP : SCE_ENGINE_SMP,
(wchar_t *)InfTemplateName,
Area,
&pErrlog
);
ScepSetupWriteError(LogFileName, pErrlog);
ScepFreeErrorLog(pErrlog);
//
// close the context
//
SceRpcCloseDatabase(&Context);
}
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
//
// get exception code (DWORD)
//
rc = RpcExceptionCode();
} RpcEndExcept;
} else {
rc = RtlNtStatusToDosError( NtStatus );
}
if ( binding_h ) {
//
// Free the binding handle
//
RpcpUnbindRpc( binding_h );
}
} else {
ScepSetupWriteError(LogFileName, pErrlog);
ScepFreeErrorLog(pErrlog);
}
return(rc);
}
DWORD
ScepMoveRegistryValue(
IN HKEY hKey,
IN PWSTR KeyFrom,
IN PWSTR ValueFrom,
IN PWSTR KeyTo OPTIONAL,
IN PWSTR ValueTo OPTIONAL
)
/*
Some registry values are moved to new locations on NT5. This routine is to migrate
the registry values from their old location on NT4 (KeyFrom, ValueFrom) to their
new location on NT5 (KeyTo, ValueTo).
If destination key or value is not specified, the registry value is moved in the same
key or with different value name. Both KeyTo and ValueTo can't be NULL at the same
time.
*/
{
if ( hKey == NULL || KeyFrom == NULL || ValueFrom == NULL ||
(KeyTo == NULL && ValueTo == NULL) ) {
return(ERROR_INVALID_PARAMETER);
}
DWORD rc=ERROR_SUCCESS;
HKEY hKey1=NULL;
HKEY hKey2=NULL;
DWORD RegType=0;
DWORD dSize=0;
//
// open the destination to see if the value already exist
//
if ( KeyTo ) {
rc = RegOpenKeyEx(hKey,
KeyTo,
0,
KEY_READ | KEY_WRITE,
&hKey2);
if ( ERROR_SUCCESS == rc ) {
//
// open the origin
//
rc = RegOpenKeyEx(hKey,
KeyFrom,
0,
KEY_READ,
&hKey1);
}
} else {
//
// if a reg value is moved to the same key as origin,
// open the key with appropriate access
//
rc = RegOpenKeyEx(hKey,
KeyFrom,
0,
KEY_READ | KEY_WRITE,
&hKey2);
hKey1 = hKey2;
}
if ( ERROR_SUCCESS == rc ) {
// query destination
rc = RegQueryValueEx(hKey2,
ValueTo ? ValueTo : ValueFrom,
0,
&RegType,
NULL,
&dSize
);
if ( ERROR_FILE_NOT_FOUND == rc ) {
//
// only move value if the destination doesn't have the value
//
rc = RegQueryValueEx(hKey1,
ValueFrom,
0,
&RegType,
NULL,
&dSize
);
if ( ERROR_SUCCESS == rc ) {
PWSTR pValue = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (dSize+1)*sizeof(TCHAR));
if ( pValue != NULL ) {
rc = RegQueryValueEx(hKey1,
ValueFrom,
0,
&RegType,
(BYTE *)pValue,
&dSize
);
if ( ERROR_SUCCESS == rc ) {
//
// set the value to its new location
//
rc = RegSetValueEx( hKey2,
ValueTo ? ValueTo : ValueFrom,
0,
RegType,
(BYTE *)pValue,
dSize
);
}
ScepFree(pValue);
}
}
}
}
if ( hKey1 && hKey1 != hKey2 ) {
RegCloseKey(hKey1);
}
if ( hKey2 ) {
RegCloseKey(hKey2);
}
return(rc);
}
DWORD
WINAPI
SceSetupSystemByInfName(
IN PWSTR InfName,
IN PCWSTR LogFileName OPTIONAL,
IN AREA_INFORMATION Area,
IN UINT nFlag,
IN PSCE_NOTIFICATION_CALLBACK_ROUTINE pSceNotificationCallBack OPTIONAL,
IN OUT PVOID pValue OPTIONAL
)
/*
Routine Description:
nFlag Operation
SCESETUP_CONFIGURE_SECURITY overwrite security with the template info
SCESETUP_UPDATE_SECURITY apply template on top of existing security
(do not overwrite the security database)
SCESETUP_QUERY_TICKS query total number of ticks for the operation
Note: when nFlag is SCESETUP_QUERY_TICKS, pValue is PDWORD to output total number of ticks
but when nFlag is the other two values, pValue is a input window handle used
for setup's gauge window (required by the call back routine)
*/
{
DWORD rc;
LONG Count=0;
//
// Initialize the SCP engine
//
if ( InfName == NULL ) {
return(ERROR_INVALID_PARAMETER);
}
//
// always configure security policy, user rights, but NO ds objects
// (because this is in setup clean install, no DC available)
//
AREA_INFORMATION Area2;
if ( (nFlag & SCESETUP_UPGRADE_SYSTEM) ||
(nFlag & SCESETUP_UPDATE_FILE_KEY) ) {
Area2 = 0;
if ( nFlag & SCESETUP_UPGRADE_SYSTEM ) {
Area2 = AREA_SECURITY_POLICY |
AREA_PRIVILEGES;
}
if ( nFlag & SCESETUP_UPDATE_FILE_KEY ) {
Area2 |= (Area & ~AREA_DS_OBJECTS);
}
} else {
//
// LSA/SAM are initialized by now (starting 1823)
// configure security policies
//
Area2 = AREA_SECURITY_POLICY |
AREA_PRIVILEGES |
AREA_GROUP_MEMBERSHIP |
(Area & ~AREA_DS_OBJECTS);
// Area2 = (Area & ~AREA_DS_OBJECTS);
}
if ( nFlag & SCESETUP_QUERY_TICKS ) {
//
// only queries ticks from the inf file.
// for the case of updating security, there might be existing objects in
// the SCE database.
//
if ( pValue == NULL ) {
return(ERROR_INVALID_PARAMETER);
}
Count = 0;
HINF InfHandle;
if ( !(nFlag & SCESETUP_UPGRADE_SYSTEM) ||
(nFlag & SCESETUP_UPDATE_FILE_KEY) ) {
InfHandle = SetupOpenInfFile(
InfName,
NULL,
INF_STYLE_WIN4,
NULL
);
if ( InfHandle != INVALID_HANDLE_VALUE ) {
if ( Area2 & AREA_REGISTRY_SECURITY ) {
Count += SetupGetLineCount(InfHandle, szRegistryKeys);
}
if ( Area2 & AREA_FILE_SECURITY ) {
Count += SetupGetLineCount(InfHandle, szFileSecurity);
}
SetupCloseInfFile(InfHandle);
} else {
dwCallbackTotal = 0;
return(GetLastError() );
}
}
else {
//Upgrade
memset(szUpInfFile, 0, sizeof(WCHAR) * (MAX_PATH + 1));
GetSystemWindowsDirectory(szUpInfFile, MAX_PATH);
DWORD TsInstalled = 0;
bIsNT5 = IsNT5();
dwThisMachine = WhichNTProduct();
switch (dwThisMachine) {
case NtProductWinNt:
wcscat(szUpInfFile, L"\\inf\\dwup.inf\0");
break;
case NtProductServer:
//
// determine if this is a terminal server in app mode
//
if ( bIsNT5 ) {
//
// on NT5, check the TSAppCompat value // TSEnabled value
//
ScepRegQueryIntValue(HKEY_LOCAL_MACHINE,
TEXT("System\\CurrentControlSet\\Control\\Terminal Server"),
TEXT("TSAppCompat"),
&TsInstalled
);
if ( TsInstalled != 1 ) {
//
// Terminal server is enabled when the value is set to 0x1
//
TsInstalled = 0;
}
} else {
//
// on NT4, base on the ProductSuite value
//
PWSTR pSuite=NULL;
DWORD RegType=0;
DWORD Rcode;
HKEY hKey=NULL;
DWORD dSize=0;
if(( Rcode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"),
0,
KEY_READ,
&hKey
)) == ERROR_SUCCESS ) {
if(( Rcode = RegQueryValueEx(hKey,
TEXT("ProductSuite"),
0,
&RegType,
NULL,
&dSize
)) == ERROR_SUCCESS ) {
pSuite = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (dSize+1)*sizeof(TCHAR));
if ( pSuite != NULL ) {
Rcode = RegQueryValueEx(hKey,
TEXT("ProductSuite"),
0,
&RegType,
(BYTE *)pSuite,
&dSize
);
if ( Rcode == ERROR_SUCCESS ) {
if ( RegType == REG_MULTI_SZ ) {
//
// check if the value contains "Terminal Server"
//
PWSTR pTemp=pSuite;
while ( pTemp[0] != L'\0' ) {
if ( lstrcmpi(TEXT("Terminal Server"),pTemp) == 0 ) {
TsInstalled = 1;
break;
} else {
pTemp += wcslen(pTemp)+1;
}
}
} else if ( RegType == REG_SZ ) {
if (lstrcmpi(TEXT("Terminal Server"), pSuite) == 0) {
TsInstalled = 1;
}
}
}
ScepFree(pSuite);
}
}
RegCloseKey( hKey );
}
}
if ( TsInstalled ) {
//
// if terminal server is installed, use the
// special terminal server template
//
wcscat(szUpInfFile, L"\\inf\\dsupt.inf\0");
} else {
wcscat(szUpInfFile, L"\\inf\\dsup.inf\0");
}
break;
case NtProductLanManNt:
if ( bIsNT5 ) {
wcscat(szUpInfFile, L"\\inf\\dcup5.inf\0");
}
else {
szUpInfFile[0] = L'\0';
}
break;
default:
szUpInfFile[0] = L'\0';
}
if (szUpInfFile[0] != L'\0') {
InfHandle = SetupOpenInfFile(
szUpInfFile,
NULL,
INF_STYLE_WIN4,
NULL
);
if ( InfHandle != INVALID_HANDLE_VALUE ) {
if ( Area2 & AREA_REGISTRY_SECURITY ) {
Count += SetupGetLineCount(InfHandle, szRegistryKeys);
}
if ( Area2 & AREA_FILE_SECURITY ) {
Count += SetupGetLineCount(InfHandle, szFileSecurity);
}
SetupCloseInfFile(InfHandle);
} else {
dwCallbackTotal = 0;
return(GetLastError() );
}
}
//
// migrate registry values
// should do this for both NT4 and NT5 upgrades since previous NT5
// may be upgraded from NT4
//
// Having the registry value in the right place will help to fix
// the tattoo problem in the new design
//
ScepMoveRegistryValue(
HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
L"DisableCAD",
L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
NULL
);
ScepMoveRegistryValue(
HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
L"DontDisplayLastUserName",
L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
NULL
);
ScepMoveRegistryValue(
HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
L"LegalNoticeCaption",
L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
NULL
);
ScepMoveRegistryValue(
HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
L"LegalNoticeText",
L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
NULL
);
ScepMoveRegistryValue(
HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
L"ShutdownWithoutLogon",
L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
NULL
);
ScepMoveRegistryValue(
HKEY_LOCAL_MACHINE,
L"System\\CurrentControlSet\\Services\\Rdr\\Parameters",
L"EnableSecuritySignature",
L"System\\CurrentControlSet\\Services\\LanmanWorkstation\\Parameters",
NULL
);
ScepMoveRegistryValue(
HKEY_LOCAL_MACHINE,
L"System\\CurrentControlSet\\Services\\Rdr\\Parameters",
L"RequireSecuritySignature",
L"System\\CurrentControlSet\\Services\\LanmanWorkstation\\Parameters",
NULL
);
ScepMoveRegistryValue(
HKEY_LOCAL_MACHINE,
L"System\\CurrentControlSet\\Services\\Rdr\\Parameters",
L"EnablePlainTextPassword",
L"System\\CurrentControlSet\\Services\\LanmanWorkstation\\Parameters",
NULL
);
}
if ( Area2 & AREA_SECURITY_POLICY )
Count += TICKS_SECURITY_POLICY_DS + TICKS_SPECIFIC_POLICIES;
if ( Area2 & AREA_GROUP_MEMBERSHIP )
Count += TICKS_GROUPS;
if ( Area2 & AREA_PRIVILEGES )
Count += TICKS_PRIVILEGE;
if ( Area2 & AREA_SYSTEM_SERVICE )
Count += TICKS_GENERAL_SERVICES + TICKS_SPECIFIC_SERVICES;
if ( nFlag & SCESETUP_UPGRADE_SYSTEM ) {
Count += (4*TICKS_MIGRATION_SECTION+TICKS_MIGRATION_V11);
}
*(PDWORD)pValue = Count;
dwCallbackTotal = Count;
return(ERROR_SUCCESS);
}
//
// delete the temp policy filter files and registry value
//
ScepClearPolicyFilterTempFiles(TRUE);
//
// make sure the log file is not too big
//
DWORD dwLogSize=0;
HANDLE hFile = CreateFile(LogFileName,
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);
CloseHandle(hFile);
}
if ( dwLogSize >= (0x1 << 23) ) {
DWORD nRequired = wcslen(LogFileName);
LPTSTR szTempName = (LPTSTR)LocalAlloc(0, (nRequired+1)*sizeof(TCHAR));
if ( szTempName ) {
wcscpy(szTempName, LogFileName);
szTempName[nRequired-3] = L'o';
szTempName[nRequired-2] = L'l';
szTempName[nRequired-1] = L'd';
CopyFile( LogFileName, szTempName, FALSE );
LocalFree(szTempName);
}
DeleteFile(LogFileName);
}
//
// configure the system now
//
rc = ScepSystemSecurityInSetup(
InfName,
LogFileName,
Area,
(nFlag & 0xFL), // block out other flags such as BIND_NO_AUTH
pSceNotificationCallBack,
pValue
);
if ( rc == ERROR_DATABASE_FAILURE ) {
//
// setup category error - log to eventlog
//
(void) InitializeEvents(L"SceCli");
LogEvent(MyModuleHandle,
STATUS_SEVERITY_ERROR,
SCEEVENT_ERROR_JET_DATABASE,
IDS_ERROR_OPEN_JET_DATABASE,
L"%windir%\\security\\database\\secedit.sdb"
);
(void) ShutdownEvents();
}
return rc;
}
DWORD
ScepSystemSecurityInSetup(
IN PWSTR InfName,
IN PCWSTR LogFileName OPTIONAL,
IN AREA_INFORMATION Area,
IN UINT nFlag,
IN PSCE_NOTIFICATION_CALLBACK_ROUTINE pSceNotificationCallBack OPTIONAL,
IN OUT PVOID pValue OPTIONAL
)
{
SCESTATUS rc;
DWORD ConfigOptions;
handle_t binding_h;
NTSTATUS NtStatus;
//
// always configure security policy, user rights, but NO ds objects
// (because this is in setup clean install, no DC available)
//
AREA_INFORMATION Area2;
if ( (nFlag & SCESETUP_UPGRADE_SYSTEM) ||
(nFlag & SCESETUP_UPDATE_FILE_KEY) ) {
/*
//
// should allow policy filter on W2K DC upgrade (dcup5)
// policy filter is ignored for non DCs in the filter code
// so it's not needed to add condition here
//
// turn off policy filter if this is upgrade
// clean install, policy filter has not been registered yet.
//
ScepRegSetIntValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("PolicyFilterOff"),
1
);
*/
ConfigOptions = SCE_UPDATE_DB | SCE_SERVICE_NO_REALTIME_ENFORCE;
Area2 = 0;
if ( nFlag & SCESETUP_UPGRADE_SYSTEM ) {
Area2 = AREA_SECURITY_POLICY |
AREA_PRIVILEGES;
}
if ( nFlag & SCESETUP_UPDATE_FILE_KEY ) {
Area2 |= (Area & ~AREA_DS_OBJECTS);
}
} else if ( nFlag & SCESETUP_BACKUP_SECURITY ) {
ConfigOptions = SCE_UPDATE_DB | SCE_SERVICE_NO_REALTIME_ENFORCE;
Area2 = Area;
} else {
ConfigOptions = SCE_OVERWRITE_DB;
//
// LSA/SAM are initialized by now (starting 1823)
// configure security policies
//
Area2 = AREA_SECURITY_POLICY |
AREA_PRIVILEGES |
AREA_GROUP_MEMBERSHIP |
(Area & ~AREA_DS_OBJECTS);
// Area2 = (Area & ~AREA_DS_OBJECTS);
}
//
// a callback routine is passed in
//
ScepSetCallback((PVOID)pSceNotificationCallBack,
(HANDLE)pValue,
SCE_SETUP_CALLBACK
);
//
// should we close the database opened by single
// object update ?
// ScepSetupCloseSecurityDatabase();
//
// RPC bind to the server
//
NtStatus = ScepBindRpc(
NULL,
L"scerpc",
L"security=impersonation dynamic false",
&binding_h
);
/*
if ( nFlag & SCESETUP_BIND_NO_AUTH ) {
NtStatus = ScepBindRpc(
NULL,
L"scerpc",
L"security=impersonation dynamic false",
&binding_h
);
} else {
NtStatus = ScepBindSecureRpc(
NULL,
L"scerpc",
L"security=impersonation dynamic false",
&binding_h
);
}*/
if (NT_SUCCESS(NtStatus)){
//
// if there is notification handle, set the notify bit
//
if ( pSceNotificationCallBack ) {
ConfigOptions |= SCE_CALLBACK_DELTA;
}
LPVOID pebClient = GetEnvironmentStrings();
DWORD ebSize = ScepGetEnvStringSize(pebClient);
RpcTryExcept {
DWORD dWarn=0;
if ( nFlag & SCESETUP_RECONFIG_SECURITY ) {
ConfigOptions = SCE_UPDATE_DB;
Area2 = AREA_FILE_SECURITY;//AREA_ALL;
rc = SceRpcConfigureSystem(
binding_h,
(wchar_t *)InfName,
NULL,
(wchar_t *)LogFileName,
ConfigOptions | SCE_DEBUG_LOG,
(AREAPR)Area2,
ebSize,
(UCHAR *)pebClient,
&dWarn
);
}
else if ( (ConfigOptions & SCE_UPDATE_DB) &&
(nFlag & SCESETUP_UPGRADE_SYSTEM) ) {
//
// save a flag to indicate this is an upgrade
//
if ( ScepRegSetIntValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("SetupUpgraded"),
1
) != ERROR_SUCCESS) {
//
// try again to create the key and then set the value
// don't worry about error this time around
//
HKEY hKey = NULL;
DWORD dwValue = 1;
if ( ERROR_SUCCESS == RegCreateKeyEx (HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE | KEY_SET_VALUE,
NULL,
&hKey,
NULL) ) {
RegSetValueEx( hKey,
TEXT("SetupUpgraded"),
0,
REG_DWORD,
(BYTE *)&dwValue,
4
);
RegCloseKey(hKey);
}
}
//
// Migrate databases if necessary
// if NT4 upgrade, create the database
// this call will also empty the local policy table if necessary
// ignore this error
//
if ( dwThisMachine == NtProductLanManNt &&
!bIsNT5 ) {
//
// NT4 DC upgrade. Should snapshot account policy into the database
// because SAM won't be available in dcpormo (later on)
//
rc = SceRpcAnalyzeSystem(
binding_h,
NULL,
NULL,
(wchar_t *)LogFileName,
AREA_SECURITY_POLICY,
ConfigOptions | SCE_DEBUG_LOG | SCE_NO_ANALYZE | SCE_RE_ANALYZE,
ebSize,
(UCHAR *)pebClient,
&dWarn
);
} else {
//
// everything else, just create/migrate the database
//
rc = SceRpcAnalyzeSystem(
binding_h,
NULL,
NULL,
(wchar_t *)LogFileName,
0,
ConfigOptions | SCE_DEBUG_LOG | SCE_NO_ANALYZE,
ebSize,
(UCHAR *)pebClient,
&dWarn
);
}
rc = SCESTATUS_SUCCESS;
if ( nFlag & SCESETUP_UPDATE_FILE_KEY ) {
Area2 = (Area & ~(AREA_DS_OBJECTS | AREA_SECURITY_POLICY | AREA_PRIVILEGES) );
rc = SceRpcConfigureSystem(
binding_h,
(wchar_t *)InfName,
NULL,
(wchar_t *)LogFileName,
ConfigOptions | SCE_DEBUG_LOG,
(AREAPR)Area2,
ebSize,
(UCHAR *)pebClient,
&dWarn
);
}
if ( !(nFlag & SCESETUP_BIND_NO_AUTH) ) {
if ( szUpInfFile[0] != L'\0' ) {
if (dwThisMachine == NtProductServer || dwThisMachine == NtProductWinNt) {
Area2 = AREA_ALL;
}
else {
Area2 = AREA_FILE_SECURITY | AREA_REGISTRY_SECURITY |
AREA_PRIVILEGES | AREA_SECURITY_POLICY;
// DS is not running, do not configure account policies.
// ConfigOptions |= SCE_NO_DOMAIN_POLICY;
}
rc = SceRpcConfigureSystem(
binding_h,
(wchar_t *)szUpInfFile,
NULL,
(wchar_t *)LogFileName,
ConfigOptions | SCE_DEBUG_LOG,
(AREAPR)Area2,
ebSize,
(UCHAR *)pebClient,
&dWarn
);
}
// should add Authenticated Users to Users group on DC too
// if (dwThisMachine == NtProductServer || dwThisMachine == NtProductWinNt) {
if (!ScepAddAuthUserToLocalGroup()) {
LogEventAndReport(MyModuleHandle,
(wchar_t *)LogFileName,
STATUS_SEVERITY_WARNING,
SCEEVENT_WARNING_BACKUP_SECURITY,
IDS_ERR_ADD_AUTH_USER );
}
// }
}
} else {
//
// clean install, the upgraded flag should be 0
// no need to set it; clear the log
//
if ( LogFileName ) {
DeleteFile(LogFileName);
}
rc = SceRpcConfigureSystem(
binding_h,
(wchar_t *)InfName,
NULL,
(wchar_t *)LogFileName,
ConfigOptions | SCE_DEBUG_LOG,
(AREAPR)Area2,
ebSize,
(UCHAR *)pebClient,
&dWarn
);
}
rc = ScepSceStatusToDosError(rc);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
//
// get exception code (DWORD)
//
rc = RpcExceptionCode();
} RpcEndExcept;
if(pebClient)
{
FreeEnvironmentStrings((LPTSTR)pebClient);
}
} else {
rc = RtlNtStatusToDosError(NtStatus);
}
if ( binding_h ) {
//
// Free the binding handle
//
RpcpUnbindRpc( binding_h );
}
ScepSetCallback(NULL, NULL, 0);
dwCallbackTotal = 0;
/*
//
// should allow policy filter on W2K DC upgrade (dcup5)
// policy filter is ignored for non DCs in the filter code
// so it's not needed to add condition here
//
if ( (nFlag & SCESETUP_UPGRADE_SYSTEM) ||
(nFlag & SCESETUP_UPDATE_FILE_KEY) ) {
DWORD rCode = ScepRegDeleteValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("PolicyFilterOff")
);
if ( rCode != ERROR_SUCCESS &&
rCode != ERROR_FILE_NOT_FOUND &&
rCode != ERROR_PATH_NOT_FOUND ) {
// if can't delete the value, set the value to 0
ScepRegSetIntValue( HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("PolicyFilterOff"),
0
);
}
}
*/
return(rc);
}
DWORD
WINAPI
SceDcPromoteSecurity(
IN DWORD dwPromoteOptions,
IN PSCE_PROMOTE_CALLBACK_ROUTINE pScePromoteCallBack OPTIONAL
)
{
return SceDcPromoteSecurityEx(NULL, dwPromoteOptions, pScePromoteCallBack);
}
DWORD
WINAPI
SceDcPromoteSecurityEx(
IN HANDLE ClientToken,
IN DWORD dwPromoteOptions,
IN PSCE_PROMOTE_CALLBACK_ROUTINE pScePromoteCallBack OPTIONAL
)
/*
Routine Description:
This routine promote security for a domain controller when a server is
promoted to a DC.
Arguments:
dwPromoteOptions - options for the promotion, for example, create a new domain
or joining an existing domain
pScePromoteCallBack - the call back pointer
Return Value:
WIN32 error code
*/
{
BOOL bDeleteLog;
if ( (dwPromoteOptions & SCE_PROMOTE_FLAG_REPLICA) ||
(dwPromoteOptions & SCE_PROMOTE_FLAG_DEMOTE) ) {
bDeleteLog = TRUE;
} else {
bDeleteLog = FALSE;
}
//
// delete temporary filter file generated in setup if it hasn't been
// processed by policy prop
// because we are setting up a new product.
// Note, this is a special case for NT4 DC upgrade
//
ScepClearPolicyFilterTempFiles(TRUE);
//
// configure security for both replica and first domain case.
//
DWORD rc32 = ScepDcPromoSharedInfo(ClientToken,
bDeleteLog, // delete log
TRUE, // not set security
dwPromoteOptions,
pScePromoteCallBack
);
TCHAR Buffer[MAX_PATH+1];
TCHAR szNewName[MAX_PATH+51];
Buffer[0] = L'\0';
GetSystemWindowsDirectory(Buffer, MAX_PATH);
Buffer[MAX_PATH] = L'\0';
szNewName[0] = L'\0';
//
// make sure the log file is re-created
//
wcscpy(szNewName, Buffer);
wcscat(szNewName, L"\\security\\logs\\scedcpro.log\0");
DWORD rcSave = rc32;
//
// generate the updated database (for emergency repair)
// even if there is an error configuring security
//
if ( dwPromoteOptions & SCE_PROMOTE_FLAG_DEMOTE ) {
rc32 = SceSetupBackupSecurity(NULL);
}
else {
rc32 = SceSetupBackupSecurity(szNewName);
}
//
// re-register the notify dll (seclogon.dll) so that
// at next logon after reboot, the group policy object
// can be created.
//
// if it's a replica created, EFS policy should come from
// the domain so no need to create group policy object
//
if ( !(dwPromoteOptions & SCE_PROMOTE_FLAG_REPLICA) &&
!(dwPromoteOptions & SCE_PROMOTE_FLAG_DEMOTE) ) {
(void) InitializeEvents(L"SceCli");
HINSTANCE hNotifyDll = LoadLibrary(TEXT("sclgntfy.dll"));
if ( hNotifyDll) {
PFREGISTERSERVER pfRegisterServer = (PFREGISTERSERVER)GetProcAddress(
hNotifyDll,
"DllRegisterServer");
if ( pfRegisterServer ) {
//
// do not care errors
//
(void) (*pfRegisterServer)();
LogEvent(MyModuleHandle,
STATUS_SEVERITY_INFORMATIONAL,
SCEEVENT_INFO_REGISTER,
0,
TEXT("sclgntfy.dll")
);
} else {
LogEvent(MyModuleHandle,
STATUS_SEVERITY_WARNING,
SCEEVENT_WARNING_REGISTER,
IDS_ERROR_GET_PROCADDR,
GetLastError(),
TEXT("DllRegisterServer in sclgntfy.dll")
);
}
FreeLibrary(hNotifyDll);
} else {
LogEvent(MyModuleHandle,
STATUS_SEVERITY_WARNING,
SCEEVENT_WARNING_REGISTER,
IDS_ERROR_LOADDLL,
GetLastError(),
TEXT("sclgntfy.dll")
);
}
(void) ShutdownEvents();
}
if ( rcSave )
return(rcSave);
else
return(rc32);
}
DWORD
WINAPI
SceDcPromoCreateGPOsInSysvol(
IN LPTSTR DomainDnsName,
IN LPTSTR SysvolRoot,
IN DWORD dwPromoteOptions,
IN PSCE_PROMOTE_CALLBACK_ROUTINE pScePromoteCallBack OPTIONAL
)
{
return SceDcPromoCreateGPOsInSysvolEx(NULL, DomainDnsName, SysvolRoot,
dwPromoteOptions, pScePromoteCallBack
);
}
DWORD
WINAPI
SceDcPromoCreateGPOsInSysvolEx(
IN HANDLE ClientToken,
IN LPTSTR DomainDnsName,
IN LPTSTR SysvolRoot,
IN DWORD dwPromoteOptions,
IN PSCE_PROMOTE_CALLBACK_ROUTINE pScePromoteCallBack OPTIONAL
)
{
//
// create default policy object for domain and domain controllers ou
// if it's not an replica
//
if ( NULL == DomainDnsName || NULL == SysvolRoot ) {
return ERROR_INVALID_PARAMETER;
}
DWORD rc32=ERROR_SUCCESS;
TCHAR Buffer[MAX_PATH+1];
TCHAR szGenName[MAX_PATH+51];
Buffer[0] = L'\0';
GetSystemWindowsDirectory(Buffer, MAX_PATH);
Buffer[MAX_PATH] = L'\0';
if ( !(dwPromoteOptions & SCE_PROMOTE_FLAG_REPLICA) ) {
rc32 = ScepDcPromoSharedInfo(ClientToken,
TRUE, // delete log
FALSE, // not set security
dwPromoteOptions,
pScePromoteCallBack
);
if ( rc32 == ERROR_SUCCESS ) {
//
// now create the GPOs in sysvol
//
(void) InitializeEvents(L"SceCli");
TCHAR szNewName[MAX_PATH+51];
wcscpy(szNewName, Buffer);
wcscat(szNewName, L"\\security\\logs\\scedcpro.log\0");
wcscpy(szGenName, Buffer);
wcscat(szGenName, L"\\security\\FirstDGPO.inf\0");
intptr_t hFile;
struct _wfinddata_t FileInfo;
hFile = _wfindfirst(szGenName, &FileInfo);
if ( hFile == -1 ) {
rc32 = ERROR_OBJECT_NOT_FOUND;
LogEventAndReport(MyModuleHandle,
szNewName,
STATUS_SEVERITY_ERROR,
SCEEVENT_ERROR_CREATE_GPO,
IDS_ERROR_GETGPO_FILE_PATH,
rc32,
szGenName
);
} else {
_findclose(hFile);
wcscpy(szGenName, Buffer);
wcscat(szGenName, L"\\security\\FirstOGPO.inf\0");
hFile = _wfindfirst(szGenName, &FileInfo);
if ( hFile == -1 ) {
rc32 = ERROR_OBJECT_NOT_FOUND;
LogEventAndReport(MyModuleHandle,
szNewName,
STATUS_SEVERITY_ERROR,
SCEEVENT_ERROR_CREATE_GPO,
IDS_ERROR_GETGPO_FILE_PATH,
rc32,
szGenName
);
} else {
_findclose(hFile);
if ( FALSE == pCreateDefaultGPOsInSysvol( DomainDnsName,
SysvolRoot,
dwPromoteOptions,
szNewName ) ) {
rc32 = GetLastError();
}
}
}
(void) ShutdownEvents();
}
}
//
// make sure the temp files are deleted
//
wcscpy(szGenName, Buffer);
wcscat(szGenName, L"\\security\\FirstDGPO.inf\0");
DeleteFile(szGenName);
wcscpy(szGenName, Buffer);
wcscat(szGenName, L"\\security\\FirstOGPO.inf\0");
DeleteFile(szGenName);
return rc32;
}
DWORD
ScepDcPromoSharedInfo(
IN HANDLE ClientToken,
IN BOOL bDeleteLog,
IN BOOL bSetSecurity,
IN DWORD dwPromoteOptions,
IN PSCE_PROMOTE_CALLBACK_ROUTINE pScePromoteCallBack OPTIONAL
)
{
SCESTATUS rc;
DWORD rc32=NO_ERROR;
TCHAR Buffer[MAX_PATH+1];
TCHAR szGenName[MAX_PATH+51];
TCHAR szNewName[MAX_PATH+51];
handle_t binding_h;
NTSTATUS NtStatus;
ScepRegSetIntValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("PolicyFilterOff"),
1
);
ScepRegSetIntValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("PolicyPropOff"),
1
);
//
// a callback routine is passed in
//
ScepSetCallback((PVOID)pScePromoteCallBack,
NULL,
SCE_DCPROMO_CALLBACK
);
//
// should we close the database opened by single
// object update ?
// ScepSetupCloseSecurityDatabase();
//
// RPC bind to the server
//
NtStatus = ScepBindRpc(
NULL,
L"scerpc",
L"security=impersonation dynamic false", // 0
&binding_h
);
/*
NtStatus = ScepBindSecureRpc(
NULL,
L"scerpc",
0,
&binding_h
);
*/
if (NT_SUCCESS(NtStatus)){
//
// if there is notification handle, set the notify bit
//
DWORD ConfigOptions = SCE_UPDATE_DB | SCE_DEBUG_LOG;
if ( pScePromoteCallBack ) {
ConfigOptions |= SCE_CALLBACK_DELTA;
}
//
// the following calls shouldn't fail because Buffer is big enough
//
Buffer[0] = L'\0';
GetSystemWindowsDirectory(Buffer, MAX_PATH);
Buffer[MAX_PATH] = L'\0';
//
// if it's not set security (then it's create GPOs)
// make sure FirstOGPO and FirstDGPO are initialized properly
//
if ( bSetSecurity == FALSE ) {
//
// this code should be only called for non replica promotion
//
wcscpy(szNewName, Buffer);
if ( dwPromoteOptions & SCE_PROMOTE_FLAG_UPGRADE ) {
//
// upgrade from NT4 DC to NT5 DC
//
wcscat(szNewName, L"\\inf\\dcup.inf\0");
} else {
wcscat(szNewName, L"\\inf\\defltdc.inf\0");
}
wcscpy(szGenName, Buffer);
wcscat(szGenName, L"\\security\\FirstOGPO.inf\0");
// DeleteFile(szGenName);
CopyFile(szNewName, szGenName, FALSE);
//
// delete the sections do not belong to local policy object
//
WritePrivateProfileSection(
szSystemAccess,
NULL,
(LPCTSTR)szGenName);
WritePrivateProfileSection(
szGroupMembership,
NULL,
(LPCTSTR)szGenName);
WritePrivateProfileSection(
szAccountProfiles,
NULL,
(LPCTSTR)szGenName);
WritePrivateProfileSection(
szRegistryKeys,
NULL,
(LPCTSTR)szGenName);
WritePrivateProfileSection(
szFileSecurity,
NULL,
(LPCTSTR)szGenName);
WritePrivateProfileSection(
szDSSecurity,
NULL,
(LPCTSTR)szGenName);
WritePrivateProfileSection(
L"LanManServer",
NULL,
(LPCTSTR)szGenName);
WritePrivateProfileSection(
szServiceGeneral,
NULL,
(LPCTSTR)szGenName);
WritePrivateProfileSection(
szKerberosPolicy,
NULL,
(LPCTSTR)szGenName);
/*
WritePrivateProfileSection(
szRegistryValues,
NULL,
(LPCTSTR)szGenName);
*/
WritePrivateProfileSection(
szAuditSystemLog,
NULL,
(LPCTSTR)szGenName);
WritePrivateProfileSection(
szAuditSecurityLog,
NULL,
(LPCTSTR)szGenName);
WritePrivateProfileSection(
szAuditApplicationLog,
NULL,
(LPCTSTR)szGenName);
wcscpy(szGenName, Buffer);
wcscat(szGenName, L"\\security\\FirstDGPO.inf\0");
//
// prepare the temp domain and local policy template
// write default kerberos policy into the temp domain template
//
szNewName[0] = L'\0';
wcscpy(szNewName, Buffer);
wcscat(szNewName, L"\\inf\\Dcfirst.inf\0");
CopyFile(szNewName, szGenName, FALSE);
}
//
// make sure the log file is re-created
//
wcscpy(szNewName, Buffer);
wcscat(szNewName, L"\\security\\logs\\scedcpro.log\0");
if ( bDeleteLog ) {
DeleteFile(szNewName);
}
//
// choose the template to use
//
szGenName[0] = L'\0';
wcscpy(szGenName, Buffer);
if ( dwPromoteOptions & SCE_PROMOTE_FLAG_UPGRADE ) {
//
// upgrade from NT4 DC to NT5 DC
//
wcscat(szGenName, L"\\inf\\dcup.inf\0");
} else if ( dwPromoteOptions & SCE_PROMOTE_FLAG_DEMOTE ) {
//
// demote from DC to server
//
wcscat(szGenName, L"\\inf\\defltsv.inf\0");
} else{
wcscat(szGenName, L"\\inf\\defltdc.inf\0");
}
LPVOID pebClient = GetEnvironmentStrings();
DWORD ebSize = ScepGetEnvStringSize(pebClient);
//
// impersonate
//
BOOL bImpersonated = FALSE;
if ( ClientToken ) {
if ( !ImpersonateLoggedOnUser(ClientToken) ) {
LogEventAndReport(MyModuleHandle,
(wchar_t *)szNewName,
0,
0,
IDS_ERROR_PROMOTE_IMPERSONATE,
GetLastError()
);
} else {
bImpersonated = TRUE;
}
}
szCallbackPrefix[0] = L'\0';
LoadString( MyModuleHandle,
bSetSecurity ? SCECLI_CALLBACK_PREFIX : SCECLI_CREATE_GPO_PREFIX,
szCallbackPrefix,
MAX_PATH
);
szCallbackPrefix[MAX_PATH-1] = L'\0';
if ( szCallbackPrefix[0] == L'\0' ) {
//
// in case loadString fails
//
if ( bSetSecurity ) {
wcscpy(szCallbackPrefix, L"Securing ");
} else {
wcscpy(szCallbackPrefix, L"Creating ");
}
}
//
// revert
//
if ( ClientToken && bImpersonated ) {
if ( !RevertToSelf() ) {
LogEventAndReport(MyModuleHandle,
(wchar_t *)szNewName,
0,
0,
IDS_ERROR_PROMOTE_REVERT,
GetLastError()
);
}
}
//
// configure security
//
DWORD dWarn;
AREA_INFORMATION Area;
rc = SCESTATUS_SUCCESS;
RpcTryExcept {
//
// also make sure the builtin accounts for NT5 DC are
// created if they are not there (which will be created in reboot after dcpromo)
//
LPTSTR pTemplateFile;
if ( bSetSecurity == FALSE ) {
Area = AREA_PRIVILEGES;
if ( dwPromoteOptions & SCE_PROMOTE_FLAG_UPGRADE ) {
//
// upgrade from NT4 DC to NT5 DC, need copy the current policy setting
//
Area |= AREA_SECURITY_POLICY;
}
ConfigOptions |= (SCE_COPY_LOCAL_POLICY |
SCE_NO_CONFIG |
SCE_DCPROMO_WAIT |
SCE_NO_DOMAIN_POLICY );
pTemplateFile = NULL; // szGenName;
} else {
//
// flag it so that special registry values (such as LmCompatibilityLevel) can be handled
//
ScepRegSetIntValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("PromoteUpgradeInProgress"),
(dwPromoteOptions & SCE_PROMOTE_FLAG_UPGRADE) ? 1 : 0
);
if ( dwPromoteOptions & SCE_PROMOTE_FLAG_DEMOTE ) {
//
// security policy, privileges, and group membership must be configured
// at reboot (in policy propagation) so these settings must
// be imported to the tattoo table first (when SCE_DC_DEMOTE is set)
// Plus SAM will be recreated at reboot
//
Area = AREA_SECURITY_POLICY | AREA_PRIVILEGES | AREA_GROUP_MEMBERSHIP;
ConfigOptions |= SCE_NO_CONFIG | SCE_DCPROMO_WAIT | SCE_DC_DEMOTE;
}
else {
//
// remove "Power Users" explcitly
// since privileges are not configured anymore
//
ScepDcPromoRemoveUserRights();
if ( dwPromoteOptions & SCE_PROMOTE_FLAG_UPGRADE ) {
// NT4 DC upgrade.
// import AREA_SECURITY_POLICY from dsup.inf
// so that registry values gets secured correctly
// on NT4 DC upgrades.
//
DWORD dwSize = (wcslen(TEXT("\\inf\\dsup.inf")) + wcslen(Buffer) + 1)*sizeof(WCHAR);
PWSTR pszTempName = (PWSTR) ScepAlloc(LMEM_ZEROINIT, dwSize);
if(pszTempName){
Area = AREA_SECURITY_POLICY;
wcscpy(pszTempName, Buffer);
wcscat(pszTempName, TEXT("\\inf\\dsup.inf"));
rc = SceRpcConfigureSystem(binding_h,
(wchar_t *)pszTempName,
NULL,
(wchar_t *)szNewName,
ConfigOptions | SCE_NO_CONFIG | SCE_NO_DOMAIN_POLICY,
(AREAPR)Area,
ebSize,
(UCHAR *)pebClient,
&dWarn
);
ScepFree(pszTempName);
pszTempName = NULL;
}
else{
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
}
}
Area = AREA_FILE_SECURITY | AREA_REGISTRY_SECURITY |
AREA_SYSTEM_SERVICE | AREA_SECURITY_POLICY;
ConfigOptions |= ( SCE_NO_DOMAIN_POLICY |
SCE_SERVICE_NO_REALTIME_ENFORCE );
//
// user rights need to be configured for first DC as well as replica
// because there are new user rights that are not defined in group policies.
//
Area |= AREA_PRIVILEGES;
ConfigOptions |= (SCE_DCPROMO_WAIT | SCE_CREATE_BUILTIN_ACCOUNTS);
}
pTemplateFile = szGenName;
}
if(SCESTATUS_SUCCESS == rc){
rc = SceRpcConfigureSystem(
binding_h,
(wchar_t *)pTemplateFile,
NULL,
(wchar_t *)szNewName,
ConfigOptions,
(AREAPR)Area,
ebSize,
(UCHAR *)pebClient,
&dWarn
);
}
rc32 = ScepSceStatusToDosError(rc);
if ( bSetSecurity == TRUE ) {
//
// reset the flag
//
ScepRegDeleteValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("PromoteUpgradeInProgress")
);
}
if ( rc32 == NO_ERROR && (dwPromoteOptions & SCE_PROMOTE_FLAG_DEMOTE) ) {
//
// Now we need to import the file/registry/services
// permissions from dsup.inf (vs. getting them
// from "defltsv.inf") because we are using "0" mode
// in dsup.inf which allows protected acls for components
// to be preserved, thus not break on demotion.
// Also, on demotion we need to import "syscomp.inf"
// so we can get the Consol apps lock down
//
TCHAR szTempName[MAX_PATH + 51] = {0};
wcscpy(szTempName, Buffer);
wcscat(szTempName, TEXT("\\inf\\dsup.inf"));
//
// remove the SCE_DC_DEMOTE flag so we don't delete the existing
// security in the database.
//
ConfigOptions &= ~(SCE_DC_DEMOTE);
//
// Areas with acls
//
Area = AREA_FILE_SECURITY | AREA_REGISTRY_SECURITY | AREA_SYSTEM_SERVICE;
//
// import "dsup.inf"
//
rc = SceRpcConfigureSystem(
binding_h,
(wchar_t *)szTempName,
NULL,
(wchar_t *)szNewName,
ConfigOptions,
(AREAPR)Area,
ebSize,
(UCHAR *)pebClient,
&dWarn
);
if(SCESTATUS_SUCCESS == rc){
//
// Now "syscomp.inf"
//
wcscpy(szTempName, Buffer);
wcscat(szTempName, TEXT("\\inf\\syscomp.inf"));
//
// only file security section
//
Area = AREA_FILE_SECURITY;
//
// import "syscomp.inf"
//
rc = SceRpcConfigureSystem(
binding_h,
(wchar_t *)szTempName,
NULL,
(wchar_t *)szNewName,
ConfigOptions,
(AREAPR)Area,
ebSize,
(UCHAR *)pebClient,
&dWarn
);
if(SCESTATUS_SUCCESS == rc){
//
// can't reset account policy since SAM is going away (re-created)
//
Area = AREA_FILE_SECURITY | AREA_REGISTRY_SECURITY | AREA_SYSTEM_SERVICE;
ConfigOptions = SCE_DEBUG_LOG | SCE_DCPROMO_WAIT | SCE_NO_DOMAIN_POLICY | SCE_SERVICE_NO_REALTIME_ENFORCE;
if ( pScePromoteCallBack ) {
ConfigOptions |= SCE_CALLBACK_DELTA;
}
rc = SceRpcConfigureSystem(
binding_h,
NULL,
NULL,
(wchar_t *)szNewName,
ConfigOptions,
(AREAPR)Area,
ebSize,
(UCHAR *)pebClient,
&dWarn
);
}
}
rc32 = ScepSceStatusToDosError(rc);
//
// reset the previousPolicyArea so that at reboot after demotion
// the above policy will get reset
//
ScepRegSetIntValue(
HKEY_LOCAL_MACHINE,
GPT_SCEDLL_NEW_PATH,
TEXT("PreviousPolicyAreas"),
AREA_SECURITY_POLICY | AREA_PRIVILEGES | AREA_GROUP_MEMBERSHIP
);
}
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
//
// get exception code (DWORD)
//
rc32 = RpcExceptionCode();
LogEventAndReport(MyModuleHandle,
(wchar_t *)szNewName,
STATUS_SEVERITY_WARNING,
SCEEVENT_WARNING_PROMOTE_SECURITY,
IDS_ERROR_PROMOTE_SECURITY,
rc32
);
} RpcEndExcept;
//
// Free the binding handle
//
RpcpUnbindRpc( binding_h );
if(pebClient)
{
FreeEnvironmentStrings((LPTSTR)pebClient);
}
} else {
rc32 = RtlNtStatusToDosError(NtStatus);
}
ScepSetCallback(NULL, NULL, 0);
rc = ScepRegDeleteValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("PolicyFilterOff")
);
if ( rc != ERROR_SUCCESS &&
rc != ERROR_FILE_NOT_FOUND &&
rc != ERROR_PATH_NOT_FOUND ) {
// if can't delete the value, set the value to 0
ScepRegSetIntValue( HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("PolicyFilterOff"),
0
);
}
rc = ScepRegDeleteValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("PolicyPropOff")
);
if ( rc != ERROR_SUCCESS &&
rc != ERROR_FILE_NOT_FOUND &&
rc != ERROR_PATH_NOT_FOUND ) {
// if can't delete the value, set the value to 0
ScepRegSetIntValue( HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("PolicyPropOff"),
0
);
}
if ( dwPromoteOptions & SCE_PROMOTE_FLAG_DEMOTE ) {
ScepRegSetIntValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("DemoteInProgress"),
1
);
}
return(rc32);
}
NTSTATUS
ScepDcPromoRemoveUserRights()
{
NTSTATUS NtStatus;
LSA_HANDLE PolicyHandle=NULL;
SID_IDENTIFIER_AUTHORITY ia=SECURITY_NT_AUTHORITY;
SID_IDENTIFIER_AUTHORITY ia2=SECURITY_WORLD_SID_AUTHORITY;
PSID AccountSid=NULL;
//
// open LSA policy
//
NtStatus = ScepOpenLsaPolicy(
MAXIMUM_ALLOWED, //GENERIC_ALL,
&PolicyHandle,
TRUE
);
if ( NT_SUCCESS(NtStatus) ) {
//
// remove Power Users account totally
//
NtStatus = RtlAllocateAndInitializeSid (&ia,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_POWER_USERS,
0, 0, 0, 0, 0, 0,
&AccountSid);
if ( NT_SUCCESS(NtStatus) ) {
NtStatus = LsaRemoveAccountRights(
PolicyHandle,
AccountSid,
TRUE, // remove all rights
NULL,
0
);
RtlFreeSid(AccountSid);
}
//
// Users
//
ScepDcPromoRemoveTwoRights(PolicyHandle,
&ia,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_USERS
);
//
// Guests
//
ScepDcPromoRemoveTwoRights(PolicyHandle,
&ia,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_GUESTS
);
//
// Authenticated Users
//
ScepDcPromoRemoveTwoRights(PolicyHandle,
&ia,
1,
SECURITY_AUTHENTICATED_USER_RID,
0
);
//
// Everyone
//
ScepDcPromoRemoveTwoRights(PolicyHandle,
&ia2,
1,
SECURITY_WORLD_RID,
0
);
LsaClose(PolicyHandle);
}
return NtStatus;
}
NTSTATUS
ScepDcPromoRemoveTwoRights(
IN LSA_HANDLE PolicyHandle,
IN SID_IDENTIFIER_AUTHORITY *pIA,
IN UCHAR SubAuthCount,
IN DWORD Rid1,
IN DWORD Rid2
)
{
//
// remove "logon locally" and "shutdown system" from the following accounts
//
LSA_UNICODE_STRING UserRightRemove[2];
RtlInitUnicodeString(&(UserRightRemove[0]), SE_INTERACTIVE_LOGON_NAME);
RtlInitUnicodeString(&(UserRightRemove[1]), SE_SHUTDOWN_NAME);
PSID AccountSid=NULL;
NTSTATUS NtStatus;
NtStatus = RtlAllocateAndInitializeSid (pIA,
SubAuthCount,
Rid1,
Rid2,
0, 0, 0, 0, 0, 0,
&AccountSid);
if ( NT_SUCCESS(NtStatus) ) {
NtStatus = LsaRemoveAccountRights(
PolicyHandle,
AccountSid,
FALSE,
UserRightRemove,
2
);
RtlFreeSid(AccountSid);
}
return(NtStatus);
}
//
// private APIs
//
DWORD
ScepSetupOpenSecurityDatabase(
IN BOOL bSystemOrAdmin
)
{
if ( hSceSetupHandle != NULL ) {
return ERROR_SUCCESS;
}
//
// get the default template name (on local system because setup only
// runs on local system
//
SCESTATUS rc;
BOOL bAdminLogon;
PWSTR DefProfile=NULL;
//
// don't care if error occurs to detect who is currently logged on
// setup always work on local computer so no remoate is supported here
//
if ( bSystemOrAdmin ) {
bAdminLogon = TRUE;
} else {
ScepIsAdminLoggedOn(&bAdminLogon, FALSE);
}
rc = ScepGetProfileSetting(
L"DefaultProfile",
bAdminLogon,
&DefProfile
);
if ( rc != NO_ERROR ) // return is Win32 error code
return(rc);
if (DefProfile == NULL ) {
return(ERROR_FILE_NOT_FOUND);
}
handle_t binding_h;
NTSTATUS NtStatus;
//
// RPC bind to the server (secure is not required)
//
NtStatus = ScepBindRpc(
NULL,
L"scerpc",
0,
&binding_h
);
/*
NtStatus = ScepBindSecureRpc(
NULL,
L"scerpc",
0,
&binding_h
);
*/
if (NT_SUCCESS(NtStatus)){
RpcTryExcept {
//
// should create file if it does not exist
//
rc = SceRpcOpenDatabase(
binding_h,
(wchar_t *)DefProfile,
SCE_OPEN_OPTION_TATTOO,
&hSceSetupHandle
);
rc = ScepSceStatusToDosError(rc);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
//
// get exception code (DWORD)
//
rc = RpcExceptionCode();
} RpcEndExcept;
//
// Free the binding handle
//
RpcpUnbindRpc( binding_h );
} else {
rc = RtlNtStatusToDosError( NtStatus );
}
ScepFree( DefProfile );
return(rc);
}
DWORD
ScepSetupCloseSecurityDatabase()
{
DWORD rc;
if ( hSceSetupHandle != NULL ) {
//
// close the database, without terminating the jet engine
//
rc = ScepSceStatusToDosError(
SceCloseProfile((PVOID *)&hSceSetupHandle) );
if ( rc != ERROR_SUCCESS ) {
//
// not valid handle, or can't close the database
//
return(rc);
}
}
//
// free other environments, if any
//
hSceSetupHandle = NULL;
return(ERROR_SUCCESS);
}
//
// the RPC callback
//
SCEPR_STATUS
SceClientCallback(
IN DWORD ncbTicks,
IN DWORD ncbTotalTicks,
IN AREAPR cbArea,
IN wchar_t *szcbName OPTIONAL
)
/*
Routine Description:
The RPC client callback routine which is called from the server when
the callback flag is set. This routine is registered in scerpc.idl.
The callbacks are registered to SCE as arguments when calling from setup
or from dcpromo, for progress indicating.
Arguments:
ncbTicks - the ticks has passed since last call back
szcbName - the item name to call back
Return Value:
SCEPR_STATUS
*/
{
//
// the static variables holding callback pointer to client
//
if ( theCallBack != NULL ) {
switch ( CallbackType ) {
case SCE_SETUP_CALLBACK:
//
// callback to setup
//
if ( ncbTicks != (DWORD)-1 ) {
PSCE_NOTIFICATION_CALLBACK_ROUTINE pcb;
pcb = (PSCE_NOTIFICATION_CALLBACK_ROUTINE)theCallBack;
DWORD cbCount;
if ( dwCallbackTotal >= ncbTicks ) {
dwCallbackTotal -= ncbTicks;
cbCount = ncbTicks;
} else {
cbCount = dwCallbackTotal;
dwCallbackTotal = 0;
}
if ( cbCount > 0 ) {
__try {
//
// calls the client procedure with the prarmeters.
//
if ( !((*pcb)(hCallbackWnd,
SCESETUP_NOTIFICATION_TICKS,
0,
ncbTicks)) ) {
return SCESTATUS_SERVICE_NOT_SUPPORT;
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
return(SCESTATUS_INVALID_PARAMETER);
}
}
}
break;
case SCE_DCPROMO_CALLBACK:
//
// callback to dcpromo
//
if ( szcbName ) {
PSCE_PROMOTE_CALLBACK_ROUTINE pcb;
pcb = (PSCE_PROMOTE_CALLBACK_ROUTINE)theCallBack;
__try {
//
// callback to dcpromo process
//
PWSTR Buffer = (PWSTR)ScepAlloc(LPTR, (wcslen(szCallbackPrefix)+wcslen(szcbName)+1)*sizeof(WCHAR));
if ( Buffer ) {
if (wcsstr(szCallbackPrefix, L"%s")) {
//
// LoadString succeeded
//
swprintf(Buffer, szCallbackPrefix, szcbName);
}
else {
wcscpy(Buffer, szCallbackPrefix);
wcscat(Buffer, szcbName);
}
if ( (*pcb)(Buffer) != ERROR_SUCCESS ) {
ScepFree(Buffer);
Buffer = NULL;
return SCESTATUS_SERVICE_NOT_SUPPORT;
}
ScepFree(Buffer);
Buffer = NULL;
} else {
return SCESTATUS_NOT_ENOUGH_RESOURCE;
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
return(SCESTATUS_INVALID_PARAMETER);
}
}
break;
case SCE_AREA_CALLBACK:
//
// callback to SCE UI for area progress
//
PSCE_AREA_CALLBACK_ROUTINE pcb;
pcb = (PSCE_AREA_CALLBACK_ROUTINE)theCallBack;
__try {
//
// callback to UI process
//
if ( !((*pcb)(hCallbackWnd,
(AREA_INFORMATION)cbArea,
ncbTotalTicks,
ncbTicks)) ) {
return SCESTATUS_SERVICE_NOT_SUPPORT;
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
return(SCESTATUS_INVALID_PARAMETER);
}
break;
}
}
return(SCESTATUS_SUCCESS);
}
SCESTATUS
ScepSetupWriteError(
IN LPTSTR LogFileName,
IN PSCE_ERROR_LOG_INFO pErrlog
)
/* ++
Routine Description:
This routine outputs the error message in each node of the SCE_ERROR_LOG_INFO
list to the log file
Arguments:
LogFileName - the log file name
pErrlog - the error list
Return value:
None
-- */
{
if ( !pErrlog ) {
return(SCESTATUS_SUCCESS);
}
HANDLE hFile=INVALID_HANDLE_VALUE;
if ( LogFileName ) {
hFile = CreateFile(LogFileName,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile != INVALID_HANDLE_VALUE) {
DWORD dwBytesWritten;
SetFilePointer (hFile, 0, NULL, FILE_BEGIN);
BYTE TmpBuf[3];
TmpBuf[0] = 0xFF;
TmpBuf[1] = 0xFE;
TmpBuf[2] = 0;
WriteFile (hFile, (LPCVOID)TmpBuf, 2,
&dwBytesWritten,
NULL);
SetFilePointer (hFile, 0, NULL, FILE_END);
}
}
PSCE_ERROR_LOG_INFO pErr;
for ( pErr=pErrlog; pErr != NULL; pErr = pErr->next ) {
if ( pErr->buffer != NULL ) {
ScepSetupWriteOneError( hFile, pErr->rc, pErr->buffer );
}
}
if ( INVALID_HANDLE_VALUE != hFile ) {
CloseHandle(hFile);
}
return(SCESTATUS_SUCCESS);
}
SCESTATUS
ScepSetupWriteOneError(
IN HANDLE hFile,
IN DWORD rc,
IN LPTSTR buf
)
{
LPVOID lpMsgBuf=NULL;
if ( !buf ) {
return(SCESTATUS_SUCCESS);
}
if ( rc != NO_ERROR ) {
//
// get error description of rc
//
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
rc,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)&lpMsgBuf,
0,
NULL
);
}
if ( INVALID_HANDLE_VALUE != hFile ) {
//
// The log file is initialized
//
if ( lpMsgBuf != NULL )
ScepWriteVariableUnicodeLog( hFile, TRUE, L"%s %s", (PWSTR)lpMsgBuf, buf );
else
ScepWriteSingleUnicodeLog(hFile, TRUE, buf);
}
if ( lpMsgBuf != NULL )
LocalFree(lpMsgBuf);
return(SCESTATUS_SUCCESS);
}
DWORD
SceSetuppLogComponent(
IN DWORD ErrCode,
IN SCESETUP_OBJECT_TYPE ObjType,
IN SCESETUP_OPERATION_TYPE OptType,
IN PWSTR Name,
IN PWSTR SDText OPTIONAL,
IN PWSTR SecondName OPTIONAL
)
{
//
// check if this log should be generated
//
DWORD dwDebugLog=0;
ScepRegQueryIntValue(HKEY_LOCAL_MACHINE,
TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Secedit"),
TEXT("SetupCompDebugLevel"),
&dwDebugLog
);
if ( dwDebugLog == 0 ) {
return(ERROR_SUCCESS);
}
//
// build the component log file name %windir%\security\logs\scecomp.log
//
WCHAR LogName[MAX_PATH+51];
GetSystemWindowsDirectory(LogName, MAX_PATH);
LogName[MAX_PATH] = L'\0';
wcscat(LogName, L"\\security\\logs\\scecomp.log\0");
HANDLE hFile = CreateFile(LogName,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if ( INVALID_HANDLE_VALUE != hFile ) {
DWORD dwBytesWritten;
SetFilePointer (hFile, 0, NULL, FILE_BEGIN);
BYTE TmpBuf[3];
TmpBuf[0] = 0xFF;
TmpBuf[1] = 0xFE;
TmpBuf[2] = 0;
WriteFile (hFile, (LPCVOID)TmpBuf, 2,
&dwBytesWritten,
NULL);
SetFilePointer (hFile, 0, NULL, FILE_END);
//
// print a time stamp
//
LARGE_INTEGER CurrentTime;
LARGE_INTEGER SysTime;
TIME_FIELDS TimeFields;
NTSTATUS NtStatus;
NtStatus = NtQuerySystemTime(&SysTime);
RtlSystemTimeToLocalTime (&SysTime,&CurrentTime);
if ( NT_SUCCESS(NtStatus) &&
(CurrentTime.LowPart != 0 || CurrentTime.HighPart != 0) ) {
memset(&TimeFields, 0, sizeof(TIME_FIELDS));
RtlTimeToTimeFields (
&CurrentTime,
&TimeFields
);
if ( TimeFields.Month > 0 && TimeFields.Month <= 12 &&
TimeFields.Day > 0 && TimeFields.Day <= 31 &&
TimeFields.Year > 1600 ) {
ScepWriteVariableUnicodeLog(hFile, FALSE,
L"%02d/%02d/%04d %02d:%02d:%02d",
TimeFields.Month, TimeFields.Day, TimeFields.Year,
TimeFields.Hour, TimeFields.Minute, TimeFields.Second);
} else {
ScepWriteVariableUnicodeLog(hFile, FALSE, L"%08x08x",
CurrentTime.HighPart, CurrentTime.LowPart);
}
} else {
ScepWriteSingleUnicodeLog(hFile, FALSE, L"Unknown time");
}
//
// print operation status code
//
if ( ErrCode ) {
ScepWriteVariableUnicodeLog(hFile, FALSE, L"\tError=%d", ErrCode);
} else {
ScepWriteSingleUnicodeLog(hFile, FALSE, L"\tSucceed");
}
//
// printf operation type
//
switch (OptType) {
case SCESETUP_UPDATE:
ScepWriteSingleUnicodeLog(hFile, FALSE, L"\tUpdate");
break;
case SCESETUP_MOVE:
ScepWriteSingleUnicodeLog(hFile, FALSE, L"\tMove");
break;
default:
ScepWriteSingleUnicodeLog(hFile, FALSE, L"\tUnknown");
break;
}
//
// print object type
//
switch (ObjType) {
case SCESETUP_FILE:
ScepWriteSingleUnicodeLog(hFile, TRUE, L"\tFile");
break;
case SCESETUP_KEY:
ScepWriteSingleUnicodeLog(hFile, TRUE, L"\tKey");
break;
case SCESETUP_SERVICE:
ScepWriteSingleUnicodeLog(hFile, TRUE, L"\tService");
break;
default:
ScepWriteSingleUnicodeLog(hFile, TRUE, L"\tUnknown");
break;
}
__try {
//
// print the name(s)
//
ScepWriteSingleUnicodeLog(hFile, FALSE, L"\t");
if ( SecondName && Name ) {
// Name\tSecondName\n
ScepWriteSingleUnicodeLog(hFile, FALSE, Name);
ScepWriteSingleUnicodeLog(hFile, FALSE, L"\t");
ScepWriteSingleUnicodeLog(hFile, TRUE, SecondName);
} else if ( Name ) {
ScepWriteSingleUnicodeLog(hFile, TRUE, Name);
}
//
// print the SDDL string
//
if ( SDText ) {
ScepWriteSingleUnicodeLog(hFile, FALSE, L"\tSecurity=");
ScepWriteSingleUnicodeLog(hFile, TRUE, SDText);
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
return(ERROR_INVALID_PARAMETER);
}
CloseHandle(hFile);
} else {
return(GetLastError());
}
return(ERROR_SUCCESS);
}
DWORD
WINAPI
SceSetupBackupSecurity(
IN LPTSTR LogFileName OPTIONAL // default to %windir%\security\logs\backup.log
)
{
TCHAR Buffer[MAX_PATH+1];
DWORD rc32;
TCHAR szGenName[MAX_PATH*2], szNewName[MAX_PATH+51];
DWORD eProductType;
eProductType = WhichNTProduct();
Buffer[0] = L'\0';
GetSystemWindowsDirectory(Buffer, MAX_PATH);
Buffer[MAX_PATH] = L'\0';
szNewName[0] = L'\0';
if ( LogFileName == NULL ) {
wcscpy(szNewName, Buffer);
wcscat(szNewName, L"\\security\\logs\\backup.log\0");
}
(void) InitializeEvents(L"SceCli");
//
// if I am in setup, query the security policy/user rights for any
// policy changes within setup (such as NT4 PDC upgrade where the policy
// filter will fail to save the change)
//
DWORD dwInSetup=0;
DWORD dwUpgraded=0;
ScepRegQueryIntValue(HKEY_LOCAL_MACHINE,
TEXT("System\\Setup"),
TEXT("SystemSetupInProgress"),
&dwInSetup
);
if ( dwInSetup ) {
//
// delete the temp local group policy template
//
wcscpy(szGenName, Buffer);
wcscat(szGenName, L"\\system32\\grouppolicy\\machine\\microsoft\\windows nt\\secedit\\gpttmpl.inf\0");
DeleteFile(szGenName);
ScepRegQueryIntValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("SetupUpgraded"),
(DWORD *)&dwUpgraded
);
/*
if ( dwUpgraded ) {
//
// in GUI setup, snapshot the system security/user rights
// query the upgrade flag, only query the system (again) when
// it's upgraded, because for the case of NT4 PDC upgrade to NT5
// any back office apps installed in GUI setup (user rights) won't
// get saved to the GPO storage correctly (ProductType is wrong)
//
rc32 = ScepSystemSecurityInSetup(
szNewName, // not used
LogFileName ? LogFileName : szNewName,
0,
SCESETUP_UPGRADE_SYSTEM | SCESETUP_BIND_NO_AUTH,
NULL,
NULL
);
if ( NO_ERROR != rc32 ) {
LogEventAndReport(MyModuleHandle,
LogFileName ? LogFileName : szNewName,
0,
0,
IDS_ERROR_SNAPSHOT_SECURITY,
rc32
);
} else {
LogEventAndReport(MyModuleHandle,
LogFileName ? LogFileName : szNewName,
0,
0,
IDS_SNAPSHOT_SECURITY_POLICY
);
}
}
//
// reset the value
//
ScepRegSetIntValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("SetupUpgraded"),
0
);
*/
}
//
// open the database
//
rc32 = ScepSetupOpenSecurityDatabase(TRUE);
BOOL bUpgradeNt5 = (BOOL)(dwUpgraded && IsNT5());
if ( NO_ERROR == rc32 ) {
wcscpy(szGenName, Buffer);
wcscat(szGenName, L"\\security\\setup.inf\0");
//
// generate the updated database (for emergency repair)
// %windir%\security\templates\setup security.inf
//
PSCE_ERROR_LOG_INFO pErrlog=NULL;
rc32 = ScepSceStatusToDosError(
SceCopyBaseProfile(
(PVOID)hSceSetupHandle,
SCE_ENGINE_SMP,
(wchar_t *)szGenName,
dwInSetup ?
AREA_ALL :
(AREA_REGISTRY_SECURITY |
AREA_FILE_SECURITY |
AREA_SYSTEM_SERVICE),
&pErrlog
));
ScepSetupWriteError(LogFileName ? LogFileName : szNewName, pErrlog);
ScepFreeErrorLog(pErrlog);
if ( rc32 != NO_ERROR ) {
LogEventAndReport(MyModuleHandle,
LogFileName ? LogFileName : szNewName,
STATUS_SEVERITY_ERROR,
SCEEVENT_ERROR_BACKUP_SECURITY,
IDS_ERROR_GENERATE,
rc32,
szGenName,
LogFileName ? LogFileName : szNewName
);
}
if (NO_ERROR == rc32 && bUpgradeNt5) {
//
// when upgrading from win2k, update (merge) "setup security.inf" or "DC security.inf"
// with the information in the backup security template
//
rc32 = ScepUpdateBackupSecurity(szGenName,
Buffer,
(NtProductLanManNt == eProductType)?TRUE:FALSE
);
}
//
// check if we should trigger a policy propagation manually
//
DWORD dwResetOption=0;
if ( dwInSetup && dwUpgraded )
dwResetOption |= SCE_RESET_POLICY_ENFORCE_ATREBOOT;
//
// remove local policies from the database
// for NT4 DC upgrade case, keep the local policy setting until dcpromo
//
if ( dwInSetup && dwUpgraded && !IsNT5() &&
NtProductLanManNt == eProductType )
dwResetOption |= SCE_RESET_POLICY_KEEP_LOCAL;
//
// if it's after dcpromo, need to empty tattoo table
// if LogFileName is NULL and it's not in setup, it's in DC demotion in which case
// we want to leave the tattoo table (w/ reset settings)
//
if ( !dwInSetup && (LogFileName != NULL) )
dwResetOption |= SCE_RESET_POLICY_TATTOO;
DWORD rCode = SceRpcSetupResetLocalPolicy(
(PVOID)hSceSetupHandle,
AREA_ALL,
NULL,
dwResetOption
);
LogEventAndReport(MyModuleHandle,
LogFileName ? LogFileName : szNewName,
0,
0,
IDS_ERROR_REMOVE_DEFAULT_POLICY,
rCode,
dwResetOption
);
//
// close the context
//
ScepSetupCloseSecurityDatabase();
if ( NO_ERROR == rc32 ){
//
// template is always generated, copy it to %windir%\security\templates and
// to %windir%\repair
//
szNewName[0] = L'0';
//
// Load string for the description
//
LoadString( MyModuleHandle,
dwInSetup ? IDS_BACKUP_OUTBOX_DESCRIPTION : IDS_BACKUP_DC_DESCRIPTION,
szNewName,
MAX_PATH
);
//
// re-write descriptoin for there backup files.
//
WritePrivateProfileSection(
L"Profile Description",
NULL,
(LPCTSTR)szGenName);
if ( szNewName[0] ) {
WritePrivateProfileString(
L"Profile Description",
L"Description",
szNewName,
(LPCTSTR)szGenName);
}
//
// copy the file to its destination
//
szNewName[0] = L'0';
wcscpy(szNewName, Buffer);
if ( (!dwInSetup && (LogFileName == NULL)) ||
(dwInSetup && (NtProductLanManNt != eProductType))){
wcscat(szNewName, L"\\security\\templates\\setup security.inf\0");
}
else{
wcscat(szNewName, L"\\security\\templates\\DC security.inf\0");
}
if ( CopyFile( szGenName, szNewName, FALSE ) ) {
LogEvent(MyModuleHandle,
STATUS_SEVERITY_INFORMATIONAL,
SCEEVENT_INFO_BACKUP_SECURITY,
0,
szNewName
);
wcscpy(szNewName, Buffer);
if ( (!dwInSetup && (LogFileName == NULL)) ||
(dwInSetup && (NtProductLanManNt != eProductType))){
wcscat(szNewName, L"\\repair\\secsetup.inf\0");
} else {
wcscat(szNewName, L"\\repair\\secDC.inf\0");
}
CopyFile( szGenName, szNewName, FALSE );
} else {
rc32 = GetLastError();
wcscpy(szNewName, Buffer);
if ( (!dwInSetup && (LogFileName == NULL)) ||
(dwInSetup && (NtProductLanManNt != eProductType))){
wcscat(szNewName, L"\\repair\\secsetup.inf\0");
} else {
wcscat(szNewName, L"\\repair\\secDC.inf\0");
}
if ( CopyFile( szGenName, szNewName, FALSE ) ) {
LogEvent(MyModuleHandle,
STATUS_SEVERITY_WARNING,
SCEEVENT_WARNING_BACKUP_SECURITY,
0,
szNewName
);
rc32 = ERROR_SUCCESS;
} else {
rc32 = GetLastError();
LogEvent(MyModuleHandle,
STATUS_SEVERITY_ERROR,
SCEEVENT_ERROR_BACKUP_SECURITY,
IDS_ERROR_BACKUP,
rc32
);
}
}
DeleteFile(szGenName);
}
} else {
LogEventAndReport(MyModuleHandle,
LogFileName ? LogFileName : szNewName,
STATUS_SEVERITY_ERROR,
SCEEVENT_ERROR_BACKUP_SECURITY,
IDS_ERROR_OPEN_DATABASE,
rc32
);
}
if ( dwInSetup ) {
dwThisMachine = eProductType;
if ((dwThisMachine == NtProductServer || dwThisMachine == NtProductWinNt) ||
((dwThisMachine == NtProductLanManNt) && IsNT5())) {
//
// reconfigure file
//
TCHAR szLogName[MAX_PATH+51], szTempName[MAX_PATH+51];
wcscpy(szLogName, Buffer);
wcscat(szLogName, L"\\security\\logs\\scesetup.log\0");
wcscpy(szTempName, Buffer);
wcscat(szTempName, L"\\inf\\syscomp.inf\0");
rc32 = ScepSystemSecurityInSetup(
szTempName,
szLogName,
0,
SCESETUP_RECONFIG_SECURITY | SCESETUP_BIND_NO_AUTH,
NULL,
NULL
);
if ( NO_ERROR != rc32 ) {
LogEventAndReport(MyModuleHandle,
szLogName,
0,
0,
IDS_ERR_RECONFIG_FILES,
rc32
);
}
//
// append syscomp.inf to "setup security.inf" or
// "DC security.inf"
//
PVOID hProfile = NULL;
PSCE_PROFILE_INFO pReConfFile = NULL;
SCESTATUS rcSce = SCESTATUS_SUCCESS;
//
// first export the syscomp.inf data from the database
// so we can get the enviroment variables resolved
// which allows us to do a successful merge with
// setup/DC security.inf
//
wcscpy(szTempName, Buffer);
wcscat(szTempName, L"\\security\\templates\\syscomp.inf\0");
//
// open the database
//
rcSce = ScepSetupOpenSecurityDatabase(TRUE);
if(SCESTATUS_SUCCESS == rcSce){
//
// export syscomp data to a temp file
//
rcSce = SceCopyBaseProfile((PVOID)hSceSetupHandle,
SCE_ENGINE_SMP,
(wchar_t *)szTempName,
AREA_FILE_SECURITY,
NULL
);
if(SCESTATUS_SUCCESS == rcSce){
//
// open the temp file and read the file section
//
rcSce = SceOpenProfile(szTempName,
SCE_INF_FORMAT,
&hProfile
);
if(SCESTATUS_SUCCESS == rcSce){
rcSce = SceGetSecurityProfileInfo(hProfile,
SCE_ENGINE_SCP,
AREA_FILE_SECURITY,
&pReConfFile,
NULL
);
if(SCESTATUS_SUCCESS == rcSce){
//
// append the data to setup/DC security.inf
//
wcscpy(szTempName, Buffer);
if(dwThisMachine == NtProductLanManNt){
wcscat(szTempName, L"\\security\\templates\\DC security.inf\0");
}
else{
wcscat(szTempName, L"\\security\\templates\\setup security.inf\0");
}
rcSce = SceAppendSecurityProfileInfo(szTempName,
AREA_FILE_SECURITY,
pReConfFile,
NULL
);
SceFreeProfileMemory(pReConfFile);
}
SceCloseProfile(&hProfile);
}
//
// delete the temp file
//
wcscpy(szTempName, Buffer);
wcscat(szTempName, L"\\security\\templates\\syscomp.inf\0");
DeleteFile(szTempName);
}
//
// remove local policies from the database
//
(void)SceRpcSetupResetLocalPolicy(
(PVOID)hSceSetupHandle,
AREA_FILE_SECURITY,
NULL,
0
);
ScepSetupCloseSecurityDatabase();
}
if(SCESTATUS_SUCCESS != rcSce){
rc32 = ScepSceStatusToDosError(rcSce);
wcscpy(szTempName, Buffer);
wcscat(szTempName, L"\\security\\templates\\setup security.inf\0");
LogEventAndReport(MyModuleHandle,
szLogName,
STATUS_SEVERITY_ERROR,
SCEEVENT_ERROR_BACKUP_SECURITY,
IDS_ERROR_MERGE_BACKUP_SECURITY,
rc32,
szTempName
);
}
}
}
(void) ShutdownEvents();
return(rc32);
}
SCESTATUS
ScepUpdateBackupSecurity(
IN PCTSTR pszSetupInf,
IN PCTSTR pszWindowsFolder,
IN BOOL bIsDC
)
/*
Routine Description:
This routine updates the exisitng setup security.inf or DC security.inf
(depends on if the code runs on a domain controler) based on the information
in the passed in security template.
All areas except file security, registry key security and services security
are "merged" but sections for file and registry keys are only taken from the
new security template file, because in setup upgrade,
all system files/keys/services are re-ACL'ed properly.
Note, this routine should only be called when ugpraded from W2K.
Arguments:
pszSetupInf - the full path name of the temporary setup security template exported from system db
pszWindowsFolder - the windows root path
bIsDC - TRUE - this is a domain controller
Return Value:
SCE error
*/
{
TCHAR szTempName[MAX_PATH + 51] = {0};
TCHAR szNewTemplateName[MAX_PATH + 51] = {0};
PVOID hProfile = NULL;
PSCE_PROFILE_INFO pSetupSecurity = NULL;
SCESTATUS rcSce = SCESTATUS_SUCCESS;
//
// validate parameters
//
if(!pszSetupInf || !pszWindowsFolder){
return SCESTATUS_INVALID_PARAMETER;
}
//
// find which template to update
//
wcscpy(szTempName, pszWindowsFolder);
if(bIsDC){
//
// if DC, update DC Security.inf
//
wcscat(szTempName, TEXT("\\security\\templates\\DC security.inf"));
} else {
//
// if not DC, update Setup Security.inf
//
wcscat(szTempName, TEXT("\\security\\templates\\setup security.inf"));
}
//
// first copy the template to a temp scratch file
//
wcscpy(szNewTemplateName, pszWindowsFolder);
wcscat(szNewTemplateName, TEXT("\\security\\NewSecurity.inf"));
if(!CopyFile(szTempName, szNewTemplateName, FALSE)){
rcSce = ScepDosErrorToSceStatus(GetLastError());
goto ExitHandler;
}
//
// Second, Read all the information of what we secured during
// setup
//
//
// Open the template that was exported from the database table
// we used to secure the system during setup
//
rcSce = SceOpenProfile(pszSetupInf,
SCE_INF_FORMAT,
&hProfile
);
if(SCESTATUS_SUCCESS != rcSce){
goto ExitHandler;
}
//
// read out all the information
//
rcSce = SceGetSecurityProfileInfo(hProfile,
SCE_ENGINE_SCP,
AREA_ALL,
&pSetupSecurity,
NULL
);
if(SCESTATUS_SUCCESS != rcSce){
goto ExitHandler;
}
//
// then append all section except Files, Registry and services sections
// to the scratch template ("setup security" or "DC security" copy)
//
rcSce = SceAppendSecurityProfileInfo(szNewTemplateName,
AREA_SECURITY_POLICY |
AREA_GROUP_MEMBERSHIP |
AREA_PRIVILEGES,
pSetupSecurity,
NULL
);
if(SCESTATUS_SUCCESS != rcSce){
goto ExitHandler;
}
//
// then overwrite the files, registry and services sections.
// because all the information we need is in the upgrade template
// and there is not need to merge those with the old info.
//
rcSce = SceWriteSecurityProfileInfo(szNewTemplateName,
AREA_SYSTEM_SERVICE |
AREA_FILE_SECURITY |
AREA_REGISTRY_SECURITY,
pSetupSecurity,
NULL
);
if(SCESTATUS_SUCCESS != rcSce){
goto ExitHandler;
}
//
// if all that succeeded then copy back the scartch template
// to its original template
//
if(!CopyFile(szNewTemplateName, pszSetupInf, FALSE)){
rcSce = ScepDosErrorToSceStatus(GetLastError());
goto ExitHandler;
}
ExitHandler:
//
// clean up
//
if(hProfile){
SceCloseProfile(&hProfile);
}
if(pSetupSecurity){
SceFreeProfileMemory(pSetupSecurity);
}
DeleteFile(szNewTemplateName);
return ScepSceStatusToDosError(rcSce);
}
DWORD
WINAPI
SceSetupConfigureServices(
IN UINT SetupProductType
)
{
TCHAR Buffer[MAX_PATH+1];
DWORD rc32 = SCESTATUS_SUCCESS;
TCHAR szNewName[MAX_PATH+51];
Buffer[0] = L'\0';
GetSystemWindowsDirectory(Buffer, MAX_PATH);
Buffer[MAX_PATH] = L'\0';
szNewName[0] = L'\0';
wcscpy(szNewName, Buffer);
wcscat(szNewName, L"\\security\\logs\\backup.log\0");
//
// if I am in setup, query the security policy/user rights for any
// policy changes within setup (such as NT4 PDC upgrade where the policy
// filter will fail to save the change)
//
DWORD dwInSetup=0;
DWORD dwUpgraded=0;
ScepRegQueryIntValue(HKEY_LOCAL_MACHINE,
TEXT("System\\Setup"),
TEXT("SystemSetupInProgress"),
&dwInSetup
);
if ( dwInSetup ) {
//
// in GUI setup, snapshot the system security/user rights
// query the upgrade flag, only query the system (again) when
// it's upgraded, because for the case of NT4 PDC upgrade to NT5
// any back office apps installed in GUI setup (user rights) won't
// get saved to the GPO storage correctly (ProductType is wrong)
//
ScepRegQueryIntValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("SetupUpgraded"),
(DWORD *)&dwUpgraded
);
if ( !dwUpgraded ) {
//
// configure service area
//
rc32 = ScepSystemSecurityInSetup(
(SetupProductType == PRODUCT_WORKSTATION) ? L"defltwk.inf" : L"defltsv.inf",
szNewName,
AREA_SYSTEM_SERVICE,
SCESETUP_BACKUP_SECURITY | SCESETUP_BIND_NO_AUTH,
NULL,
NULL
);
}
}
return(rc32);
}
BOOL
pCreateDefaultGPOsInSysvol(
IN LPTSTR DomainDnsName,
IN LPTSTR szSysvolPath,
IN DWORD Options,
IN LPTSTR LogFileName
)
/*++
Routine Description:
Creates the default domain-wide account policy object and the default
policy object for local policies in sysvol.
The GUID to use is queried from registry.
Arguments:
DomainDnsName - the new domain's DNS name, e.g., JINDOM4.ntdev.microsoft.com
Options - the promotion options
LogFileName - the log file for debug info
Return:
WIN32 error
--*/
{
/*
//
// get sysvol share location
//
TCHAR szSysvolPath[MAX_PATH+1];
szSysvolPath[0] = L'\0';
GetEnvironmentVariable( L"SYSVOL",
szSysvolPath,
MAX_PATH);
*/
//
// create \\?\%sysvol%\sysvol\<DnsName>\Policies directory
// the \\?\ is for the case of longer than MAX_PATH chars
//
DWORD Len = 4 + wcslen(szSysvolPath) + wcslen(TEXT("\\sysvol\\Policies\\")) +
wcslen(DomainDnsName);
PWSTR pszPoliciesPath = (PWSTR)ScepAlloc(LPTR, (Len+wcslen(TEXT("\\{}\\MACHINE"))+
STR_GUID_LEN+1)*sizeof(WCHAR));
if ( !pszPoliciesPath ) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
swprintf(pszPoliciesPath, L"\\\\?\\%s\\sysvol\\%s\\Policies\0", szSysvolPath, DomainDnsName);
DWORD Win32rc = ScepSceStatusToDosError(
ScepCreateDirectory(
pszPoliciesPath,
TRUE,
NULL
));
if ( ERROR_SUCCESS == Win32rc ) {
//
// create sub directory for the first GPO GUID1 and machine, user, GPT.ini
//
if ( pCreateSysvolContainerForGPO(STR_DEFAULT_DOMAIN_GPO_GUID,
pszPoliciesPath,
Len) ) {
//
// when it's returned success from the previous
// pszPoliciesPath is already changed to the machine's root
// with the guid info.
//
if ( pCreateOneGroupPolicyObject(
pszPoliciesPath,
TRUE, // domain level
LogFileName) ) {
//
// create sub directory for the second GPO
//
if ( pCreateSysvolContainerForGPO(STR_DEFAULT_DOMAIN_CONTROLLER_GPO_GUID,
pszPoliciesPath,
Len) ) {
//
// when it's returned success from the previous
// pszPoliciesPath is already changed to the machine's root
// with the guid info.
//
if ( pCreateOneGroupPolicyObject(
pszPoliciesPath,
FALSE, // not domain level
LogFileName) ) {
//
// log a entry to the log
//
LogEventAndReport(MyModuleHandle,
LogFileName,
0,
0,
IDS_SUCCESS_DEFAULT_GPO,
L"in sysvol"
);
} else {
Win32rc = GetLastError();
}
} else {
Win32rc = GetLastError();
LogEventAndReport(MyModuleHandle,
LogFileName,
STATUS_SEVERITY_ERROR,
SCEEVENT_ERROR_CREATE_GPO,
IDS_ERROR_CREATE_DIRECTORY,
Win32rc,
STR_DEFAULT_DOMAIN_CONTROLLER_GPO_GUID
);
}
} else {
Win32rc = GetLastError();
}
} else {
Win32rc = GetLastError();
LogEventAndReport(MyModuleHandle,
LogFileName,
STATUS_SEVERITY_ERROR,
SCEEVENT_ERROR_CREATE_GPO,
IDS_ERROR_CREATE_DIRECTORY,
Win32rc,
STR_DEFAULT_DOMAIN_GPO_GUID
);
}
} else {
LogEventAndReport(MyModuleHandle,
LogFileName,
STATUS_SEVERITY_ERROR,
SCEEVENT_ERROR_CREATE_GPO,
IDS_ERROR_CREATE_DIRECTORY,
Win32rc,
pszPoliciesPath
);
}
ScepFree(pszPoliciesPath);
SetLastError( Win32rc );
//
// if this function fails, it will fail DCPROMO and the sysvol directory
// should be cleaned up by dcpromo/ntfrs
//
return ( ERROR_SUCCESS == Win32rc );
}
BOOL
pCreateSysvolContainerForGPO(
IN LPCTSTR strGuid,
IN LPTSTR szPath,
IN DWORD dwStart
)
{
swprintf(szPath+dwStart, L"\\{%s}\\USER", strGuid);
DWORD Win32rc = ScepSceStatusToDosError(
ScepCreateDirectory(
szPath,
TRUE,
NULL
));
if ( ERROR_SUCCESS == Win32rc ) {
//
// the directory for the GUID is created
// now create the GPT.INI
//
swprintf(szPath+dwStart, L"\\{%s}\\GPT.INI", strGuid);
WritePrivateProfileString (TEXT("General"), TEXT("Version"), TEXT("1"),
szPath); // does it work with prefix "\\?\" ?
//
// create the machine directory
// since all the parent directories are already created by the call
// to create USER directory, there is no need to loop again
// call CreateDirectory directly
//
swprintf(szPath+dwStart, L"\\{%s}\\MACHINE", strGuid);
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = FALSE;
if ( CreateDirectory(
szPath,
&sa
) == FALSE ) {
if ( GetLastError() != ERROR_ALREADY_EXISTS ) {
Win32rc = GetLastError();
}
}
}
SetLastError(Win32rc);
return (ERROR_SUCCESS == Win32rc);
}
BOOL
pCreateOneGroupPolicyObject(
IN PWSTR pszGPOSysPath,
IN BOOL bDomainLevel,
IN PWSTR LogFileName
)
/*++
Routine Description:
Creates a group policy object in sysvol.
Arguments:
pszGPOSysPath- the GPO's sysvol path (up to root of machine)
bDomainLevel - create the object for domain level if TRUE, otherwise,
create the GPO for "domain controllers" OU
LogFileName - the dcpromo log file to track info
Return:
TRUE - success
FALSE - fail, use GetLastError()
--*/
{
//
// create the default domain policy object
//
LPTSTR SceTemplateName = (LPTSTR) LocalAlloc(LPTR,(lstrlen(pszGPOSysPath)+
lstrlen(GPTSCE_TEMPLATE)+2)*sizeof(TCHAR));
DWORD Win32rc;
if (SceTemplateName) {
//
// build the template path first
//
lstrcpy(SceTemplateName,pszGPOSysPath);
lstrcat(SceTemplateName,L"\\");
lstrcat(SceTemplateName, GPTSCE_TEMPLATE);
//
// Create the template directory if there isn't one already
//
Win32rc = ScepSceStatusToDosError(
ScepCreateDirectory(
SceTemplateName,
FALSE,
NULL
));
if ( ERROR_SUCCESS == Win32rc ) {
TCHAR pszGPOTempName[MAX_PATH+51];
pszGPOTempName[0] = L'\0';
GetSystemWindowsDirectory(pszGPOTempName, MAX_PATH);
pszGPOTempName[MAX_PATH] = L'\0';
if ( bDomainLevel ) {
//
// create the default domain GPO
// copy template from %windir%\security\FirstDGPO.inf
//
wcscat(pszGPOTempName, L"\\security\\FirstDGPO.inf\0");
} else {
//
// create the default GPO for "domain controllers" OU
// copy template from %windir%\security\FirstOGPO.inf
//
wcscat(pszGPOTempName, L"\\security\\FirstOGPO.inf\0");
}
DWORD rc=ERROR_SUCCESS;
HINF hInf=NULL;
AREA_INFORMATION Area = AREA_SECURITY_POLICY | AREA_PRIVILEGES;
PSCE_PROFILE_INFO pSceInfo=NULL;
rc = SceInfpOpenProfile(
pszGPOTempName,
&hInf
);
if ( SCESTATUS_SUCCESS == rc ) {
//
// do not do sid->name->sid translation in DCPromo (bug 462994)
//
gbClientInDcPromo = TRUE;
//
// load informatin from the template
//
rc = SceInfpGetSecurityProfileInfo(
hInf,
Area,
&pSceInfo,
NULL
);
gbClientInDcPromo = FALSE;
if ( SCESTATUS_SUCCESS != rc ) {
LogEventAndReport(MyModuleHandle,
LogFileName,
STATUS_SEVERITY_ERROR,
SCEEVENT_ERROR_CREATE_GPO,
IDS_ERROR_GETGPO_FILE_PATH,
rc,
pszGPOTempName
);
}
SceInfpCloseProfile(hInf);
} else {
LogEventAndReport(MyModuleHandle,
LogFileName,
STATUS_SEVERITY_ERROR,
SCEEVENT_ERROR_CREATE_GPO,
IDS_ERROR_GETGPO_FILE_PATH,
rc,
pszGPOTempName
);
}
if ( ERROR_SUCCESS == rc && pSceInfo ) {
//
// Write to GPO instead of copy, this way the GPO will be unicode.
//
//??? pSceInfo->Type = SCE_ENGINE_SMP;
rc = SceWriteSecurityProfileInfo(SceTemplateName,
Area,
(PSCE_PROFILE_INFO)pSceInfo,
NULL
);
if ( SCESTATUS_SUCCESS != rc ) {
LogEventAndReport(MyModuleHandle,
LogFileName,
STATUS_SEVERITY_ERROR,
SCEEVENT_ERROR_CREATE_GPO,
IDS_ERROR_GETGPO_FILE_PATH,
rc,
pszGPOTempName
);
}
}
if ( pSceInfo != NULL ) {
SceFreeProfileMemory(pSceInfo);
}
#if 0
if ( !CopyFile( pszGPOTempName,
SceTemplateName,
FALSE ) ) {
Win32rc = GetLastError();
LogEventAndReport(MyModuleHandle,
LogFileName,
STATUS_SEVERITY_ERROR,
SCEEVENT_ERROR_CREATE_GPO,
IDS_ERROR_COPY_TEMPLATE,
Win32rc,
SceTemplateName
);
}
#endif
DeleteFile(pszGPOTempName);
} else {
LogEventAndReport(MyModuleHandle,
LogFileName,
STATUS_SEVERITY_ERROR,
SCEEVENT_ERROR_CREATE_GPO,
IDS_ERROR_CREATE_DIRECTORY,
Win32rc,
SceTemplateName
);
}
LocalFree(SceTemplateName);
} else {
Win32rc = ERROR_NOT_ENOUGH_MEMORY;
LogEventAndReport(
MyModuleHandle,
LogFileName,
STATUS_SEVERITY_ERROR,
SCEEVENT_ERROR_CREATE_GPO,
IDS_ERROR_NO_MEMORY
);
}
SetLastError(Win32rc);
return ( ERROR_SUCCESS == Win32rc);
}
//NT_PRODUCT_TYPE
DWORD
WhichNTProduct()
{
HKEY hKey;
DWORD dwBufLen=32;
TCHAR szProductType[32];
LONG lRet;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"),
0,
KEY_QUERY_VALUE,
&hKey) != ERROR_SUCCESS) {
// return Unknown
return PRODUCT_UNKNOWN;
}
lRet = RegQueryValueEx(hKey,
TEXT("ProductType"),
NULL,
NULL,
(LPBYTE)szProductType,
&dwBufLen);
RegCloseKey(hKey);
if(lRet != ERROR_SUCCESS) {
// return Unknown
return PRODUCT_UNKNOWN;
}
// check product options, in order of likelihood
if (lstrcmpi(TEXT("WINNT"), szProductType) == 0) {
return NtProductWinNt;
}
if (lstrcmpi(TEXT("SERVERNT"), szProductType) == 0) {
return NtProductServer;
}
if (lstrcmpi(TEXT("LANMANNT"), szProductType) == 0) {
return NtProductLanManNt;
}
// return Unknown
return PRODUCT_UNKNOWN;
}
BOOL
ScepAddAuthUserToLocalGroup()
{
//
// Attempt to add Authenticated Users and Interactive back into Users group.
//
DWORD rc1;
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 && rc1 != ERROR_MEMBER_IN_ALIAS ) {
return FALSE;
}
}
else {
return FALSE;
}
return TRUE;
}
DWORD
SceSysPrep()
{
SCESTATUS rc=0;
handle_t binding_h=NULL;
NTSTATUS NtStatus;
//
// open system database
//
rc = ScepSetupOpenSecurityDatabase(TRUE);
rc = ScepSceStatusToDosError(rc);
if ( ERROR_SUCCESS == rc ) {
RpcTryExcept {
// reset policy
// all tables
rc = SceRpcSetupResetLocalPolicy(
(PVOID)hSceSetupHandle,
AREA_ALL,
NULL,
SCE_RESET_POLICY_SYSPREP
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
//
// get exception code (DWORD)
//
rc = RpcExceptionCode();
} RpcEndExcept;
//
// close the database
//
ScepSetupCloseSecurityDatabase();
}
HKEY hKey;
DWORD Interval;
DWORD RegType;
DWORD DataSize;
if ( ERROR_SUCCESS == rc ) {
//
// update local policy version #
// so policy will be propagated at reboot
//
ScepEnforcePolicyPropagation();
}
//
// re-register seclogon.dll to recreate EFS recovery policy
// at first logon
//
HINSTANCE hNotifyDll = LoadLibrary(TEXT("sclgntfy.dll"));
if ( hNotifyDll) {
PFREGISTERSERVER pfRegisterServer = (PFREGISTERSERVER)GetProcAddress(
hNotifyDll,
"DllRegisterServer");
if ( pfRegisterServer ) {
//
// do not care errors - shouldn't fail
//
(void) (*pfRegisterServer)();
}
FreeLibrary(hNotifyDll);
}
if(( rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
EFS_NOTIFY_PATH,
0,
MAXIMUM_ALLOWED,
&hKey
)) == ERROR_SUCCESS ) {
//
// set a flag to registry
// this shouldn't fail since admin logon
//
Interval = 1;
rc = RegSetValueEx( hKey,
TEXT("SystemCloned"),
0,
REG_DWORD,
(BYTE *)&Interval,
4
);
RegCloseKey( hKey );
}
return(rc);
}
DWORD ScepCompareDaclWithStringSD(
IN PCWSTR pcwszSD,
IN PACL pDacl,
OUT PBOOL pbDifferent)
{
DWORD dwRet = ERROR_SUCCESS;
BOOL bDaclPresent, bDaclDefaulted;
PSECURITY_DESCRIPTOR pSD = NULL;
PACL pDaclFromSD = NULL;
if ( !ConvertStringSecurityDescriptorToSecurityDescriptor(
pcwszSD,
SDDL_REVISION_1,
&pSD,
NULL) ) {
dwRet = GetLastError();
}
if ( ERROR_SUCCESS == dwRet ) {
if ( !GetSecurityDescriptorDacl(
pSD,
&bDaclPresent,
&pDaclFromSD,
&bDaclDefaulted) ) {
dwRet = GetLastError();
}
}
if ( ERROR_SUCCESS == dwRet ) {
dwRet = ScepCompareExplicitAcl(
SE_FILE_OBJECT,
TRUE, // IsContainer
pDaclFromSD,
pDacl,
pbDifferent);
}
if ( pSD )
LocalFree(pSD);
return dwRet;
}
DWORD
WINAPI
SceSetupRootSecurity()
/*
Description:
This function should be called in GUI setup after system security is
configured (SceSetupSystemSecurityByName). The function calls to NTMARTA
API to set security on the root of boot partition (where Windows is installed).
This task will take quite long time depending on the size of the drive.
Therefore, setup should call this function in a asynchronous thread.
This function will NOT set security on the root drive if one of the following
conditions is met:
1) FAT partition
2) Security on the root drive was modified by user in a previous install.
This is determined by comparing the security on the root drive to the
default security from NTFS format, NTFS convert tool on both NT4 and
Windows 2000 systems.
*/
{
DWORD rc=NO_ERROR;
WCHAR szRootDir[MAX_PATH+1];
WCHAR szSetupInfFile[MAX_PATH+1];
WCHAR LogFileName[MAX_PATH+51];
UINT DriveType;
DWORD FileSystemFlags;
//
// get the time stamp
//
TCHAR pvBuffer[100];
pvBuffer[0] = L'\0';
ScepGetTimeStampString(pvBuffer);
szRootDir[0] = L'\0';
//
// get the root drive of Windows directory
//
if ( GetSystemWindowsDirectory( szRootDir, MAX_PATH ) == 0 ) {
return(GetLastError());
}
szRootDir[MAX_PATH] = L'\0';
wcscpy(LogFileName, szRootDir);
wcscat(LogFileName, L"\\security\\logs\\SceRoot.log");
//
// attempt to write root SDDL so that it is useful for FAT->NTFS conversion
// if default is different from hardcoded value, it will be overwritten later...
//
//
// insert the root security SDDL into %windir%\security\templates\setup security.inf
// this will be useful for the new API which implements convert behavior.
//
wcscpy(szSetupInfFile, szRootDir);
wcscat(szSetupInfFile, L"\\security\\templates\\setup security.inf");
// the first two letters are X:
szRootDir[2] = L'\\';
szRootDir[3] = L'\0';
//
// independent of future errors/file systemtypr etc., attempt to
// write default root acl to %windir%\security\templates\setup security.inf
// used in FAT->NTFS convert
//
PWSTR pszDefltInfStringToWrite = NULL;
DWORD rcDefltRootBackup = ERROR_SUCCESS;
rcDefltRootBackup = ScepBreakSDDLToMultiFields(
szRootDir,
SDDLRoot,
sizeof(SDDLRoot)+1,
0,
&pszDefltInfStringToWrite
);
if ( rcDefltRootBackup == ERROR_SUCCESS && pszDefltInfStringToWrite) {
if ( !WritePrivateProfileString(szFileSecurity, L"0", pszDefltInfStringToWrite, szSetupInfFile) ) {
LogEventAndReport(MyModuleHandle,
(wchar_t *)LogFileName,
0,
0,
IDS_ROOT_ERROR_INFWRITE,
GetLastError(),
SDDLRoot
);
}
ScepFree(pszDefltInfStringToWrite);
}
else {
LogEventAndReport(MyModuleHandle,
(wchar_t *)LogFileName,
0,
0,
IDS_ROOT_ERROR_INFWRITE,
rcDefltRootBackup,
SDDLRoot
);
}
//
// log the time stamp
//
if ( pvBuffer[0] != L'\0' ) {
LogEventAndReport(MyModuleHandle,
(wchar_t *)LogFileName,
0,
0,
0,
pvBuffer
);
}
//
// detect if the partition is FAT
//
DriveType = GetDriveType(szRootDir);
if ( DriveType == DRIVE_FIXED ||
DriveType == DRIVE_RAMDISK ) {
if ( GetVolumeInformation(szRootDir,
NULL,
0,
NULL,
NULL,
&FileSystemFlags,
NULL,
0
) == TRUE ) {
if ( !(FileSystemFlags & FS_PERSISTENT_ACLS) ) {
//
// only set security on NTFS partition
//
LogEventAndReport(MyModuleHandle,
(wchar_t *)LogFileName,
0,
0,
IDS_ROOT_NON_NTFS,
szRootDir
);
return(rc);
}
} else {
//
// something is wrong
//
rc = GetLastError();
LogEventAndReport(MyModuleHandle,
(wchar_t *)LogFileName,
0,
0,
IDS_ROOT_ERROR_QUERY_VOLUME,
rc,
szRootDir
);
return rc;
}
} else {
//
// do not set security on remote drives
//
LogEventAndReport(MyModuleHandle,
(wchar_t *)LogFileName,
0,
0,
IDS_ROOT_NOT_FIXED_VOLUME,
szRootDir
);
return(rc);
}
PSECURITY_DESCRIPTOR pSDSet=NULL, pSDOld=NULL;
DWORD dwSize=0;
SECURITY_INFORMATION SeInfo=0;
PACL pDacl=NULL;
ACCESS_ALLOWED_ACE *pAce=NULL;
SID_IDENTIFIER_AUTHORITY Authority=SECURITY_WORLD_SID_AUTHORITY;
PSID pSid;
BYTE SidEveryone[20];
BOOLEAN tFlag;
BOOLEAN aclPresent;
SECURITY_DESCRIPTOR_CONTROL Control=0;
ULONG Revision;
NTSTATUS NtStatus;
BOOL bDefault;
LogEventAndReport(MyModuleHandle,
(wchar_t *)LogFileName,
0,
0,
IDS_ROOT_NTFS_VOLUME,
szRootDir
);
//
// It's NTFS volume. Let's convert the security descriptor
//
rc = ConvertTextSecurityDescriptor (SDDLRoot,
&pSDSet,
&dwSize,
&SeInfo
);
if ( rc != NO_ERROR ) {
LogEventAndReport(MyModuleHandle,
(wchar_t *)LogFileName,
0,
0,
IDS_ROOT_ERROR_CONVERT,
rc,
SDDLRoot
);
return(rc);
}
if ( !(SeInfo & DACL_SECURITY_INFORMATION) ) {
LogEventAndReport(MyModuleHandle,
(wchar_t *)LogFileName,
0,
0,
IDS_ROOT_INVALID_SDINFO,
SDDLRoot
);
LocalFree(pSDSet);
return(ERROR_INVALID_PARAMETER);
}
//
// It's NTFS volume. Now get existing security of the root drive
//
rc = GetNamedSecurityInfo(szRootDir,
SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
&pDacl,
NULL,
&pSDOld
);
if ( rc == ERROR_SUCCESS && pDacl ) {
//
// Detect if permissions are the default from a clean install or upgrade (NT4 or win2k).
// There are several possible defaults to be found, DC vs srv and wks, and clean NT4 or
// win2k vs upgrades.
//
bDefault=FALSE;
if ( pDacl ) {
PCWSTR rpcwszOldDefaultDacl[] = {
SDDLOldRootDefault1, // everyone - full control (CIOI)
SDDLOldRootDefault2, // admin, system, creator/owner - full(CIOI); everyone - change(CIOI)
SDDLOldRootDefault3, // admin, system, creator/owner - full(CIOI); everyone, server op - change(CIOI)
};
int cOldDefaultDacls = ARRAYSIZE(rpcwszOldDefaultDacl);
for(int i=0; i<cOldDefaultDacls; i++)
{
BOOL bDifferent;
rc = ScepCompareDaclWithStringSD(
rpcwszOldDefaultDacl[i],
pDacl,
&bDifferent);
if ( ERROR_SUCCESS != rc)
break;
if ( FALSE == bDifferent) {
bDefault = TRUE;
break;
}
}
}
if ( ERROR_SUCCESS == rc )
{
if ( bDefault && pSDSet ) {
//
// only set security if it's default
//
RtlGetControlSecurityDescriptor (
pSDSet,
&Control,
&Revision
);
//
// Get DACL address
//
pDacl = NULL;
rc = RtlNtStatusToDosError(
RtlGetDaclSecurityDescriptor(
pSDSet,
&aclPresent,
&pDacl,
&tFlag));
if (rc == NO_ERROR && !aclPresent )
pDacl = NULL;
//
// if error occurs for this one, do not set. return
//
if ( rc == ERROR_SUCCESS ) {
//
// set permission
//
if ( Control & SE_DACL_PROTECTED ) {
SeInfo |= PROTECTED_DACL_SECURITY_INFORMATION;
}
pvBuffer[0] = L'\0';
ScepGetTimeStampString(pvBuffer);
LogEventAndReport(MyModuleHandle,
(wchar_t *)LogFileName,
0,
0,
IDS_ROOT_SECURITY_DEFAULT,
szRootDir,
pvBuffer
);
rc = SetNamedSecurityInfo(szRootDir,
SE_FILE_OBJECT,
SeInfo,
NULL,
NULL,
pDacl,
NULL
);
pvBuffer[0] = L'\0';
ScepGetTimeStampString(pvBuffer);
LogEventAndReport(MyModuleHandle,
(wchar_t *)LogFileName,
0,
0,
IDS_ROOT_MARTA_RETURN,
rc,
pvBuffer,
szRootDir
);
} else {
LogEventAndReport(MyModuleHandle,
(wchar_t *)LogFileName,
0,
0,
IDS_ROOT_ERROR_DACL,
rc
);
}
} else {
//
// convert the old security descriptor to text and log it
//
PWSTR pszOldSDDL=NULL;
PWSTR pszInfStringToWrite = NULL;
DWORD rcRootBackup = ERROR_SUCCESS;
ConvertSecurityDescriptorToText (
pSDOld,
DACL_SECURITY_INFORMATION,
&pszOldSDDL,
&dwSize
);
//
// also, overwrite this SDDL to %windir%\security\templates\setup security.inf
// since this is the "default" root security. This will be used later if
// SCE is invoked to do security configuration during NTFS->FAT->NTFS conversion.
//
if (pszOldSDDL) {
rcRootBackup = ScepBreakSDDLToMultiFields(
szRootDir,
pszOldSDDL,
dwSize,
0,
&pszInfStringToWrite
);
if (rcRootBackup == ERROR_SUCCESS && pszInfStringToWrite) {
if ( !WritePrivateProfileString(szFileSecurity, L"0", pszInfStringToWrite, szSetupInfFile) ) {
LogEventAndReport(MyModuleHandle,
(wchar_t *)LogFileName,
0,
0,
IDS_ROOT_ERROR_INFWRITE,
GetLastError(),
pszOldSDDL
);
}
ScepFree(pszInfStringToWrite);
} else {
LogEventAndReport(MyModuleHandle,
(wchar_t *)LogFileName,
0,
0,
IDS_ROOT_ERROR_INFWRITE,
rcRootBackup,
pszOldSDDL
);
}
}
LogEventAndReport(MyModuleHandle,
(wchar_t *)LogFileName,
0,
0,
IDS_ROOT_SECURITY_MODIFIED,
szRootDir,
pszOldSDDL ? pszOldSDDL : L""
);
if ( pszOldSDDL ) {
LocalFree(pszOldSDDL);
}
}
} else {
LogEventAndReport(MyModuleHandle,
(wchar_t *)LogFileName,
0,
0,
IDS_ROOT_ERROR_COMPARE_SECURITY,
rc,
szRootDir
);
}
LocalFree(pSDOld);
} else {
LogEventAndReport(MyModuleHandle,
(wchar_t *)LogFileName,
0,
0,
IDS_ROOT_ERROR_QUERY_SECURITY,
rc,
szRootDir
);
}
LocalFree(pSDSet);
return(rc);
}
DWORD
WINAPI
SceEnforceSecurityPolicyPropagation()
{
return(ScepEnforcePolicyPropagation());
}
DWORD
WINAPI
SceConfigureConvertedFileSecurity(
IN PWSTR pszDriveName,
IN DWORD dwConvertDisposition
)
/*++
Routine Description:
Exported API called by convert.exe to configure setup style security for drives converted from FAT to NTFS.
Briefly, this API will
EITHER (dwConvertDisposition == 0)
convert the volume in question immediately (in an asynchronous thread after RPC'ing over to the server)
OR (dwConvertDisposition == 1)
will schedule a conversion to happen at the time of reboot (in an asynchronous thread during reboot).
Scheduling is done by entering pszDriveName(s) in a REG_MULTI_SZ registry value
SCE_ROOT_PATH\FatNtfsConvertedDrives.
Arguments:
pszDriveName - Name of the volume to be converted
dwConvertDisposition - 0 implies volume can be converted immediately
1 implies volume cannot be converted immediately and is scheduled for conversion
Return:
win32 error code
--*/
{
DWORD rc = ERROR_SUCCESS;
if ( pszDriveName == NULL ||
wcslen(pszDriveName) == 0 ||
(dwConvertDisposition != 0 && dwConvertDisposition != 1) ) {
return ERROR_INVALID_PARAMETER;
}
//
// validate drive name - has to end in ":"
//
if ( pszDriveName [wcslen( pszDriveName ) - 1] != L':') {
return ERROR_INVALID_PARAMETER;
}
if (dwConvertDisposition == 0) {
//
// configure setup-style security immediately
// RPC over to scesrv
//
NTSTATUS NtStatus = NO_ERROR;
handle_t binding_h = NULL;
//
// RPC bind to the server - don't use secure RPC
//
NtStatus = ScepBindRpc(
NULL,
L"scerpc",
0,
&binding_h
);
/*
NtStatus = ScepBindSecureRpc(
NULL,
L"scerpc",
0,
&binding_h
);
*/
if (NT_SUCCESS(NtStatus)) {
RpcTryExcept {
//
// make the RPC call
//
rc = SceRpcConfigureConvertedFileSecurityImmediately(
binding_h,
pszDriveName
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
//
// get exception code
//
rc = RpcExceptionCode();
} RpcEndExcept;
//
// Free the binding handle
//
RpcpUnbindRpc( binding_h );
} else {
rc = RtlNtStatusToDosError( NtStatus );
}
}
else if (dwConvertDisposition == 1) {
//
// schedule conversion for reboot time - i.e. enter into MULTI_SZ registry value
//
rc = ScepAppendCreateMultiSzRegValue(HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
L"FatNtfsConvertedDrives",
pszDriveName
);
}
return rc;
}
DWORD
ScepBreakSDDLToMultiFields(
IN PWSTR pszObjName,
IN PWSTR pszSDDL,
IN DWORD dwSDDLsize,
IN BYTE ObjStatus,
OUT PWSTR *ppszAdjustedInfLine
)
/*++
Routine Description:
Inf files have a limitation w.r.t. line size - so break up SDDL if need be
Arguments:
pszObjName - name of the object
pszSDDL - SDDL string that might be velry long
dwSDDLsize - size of pszSDDL
ObjStatus - 0/1/2
ppszAdjustedInfLine - ptr to adjusted string
Return:
win32 error code
--*/
{
DWORD rc;
PWSTR Strvalue=NULL;
DWORD nFields;
DWORD *aFieldOffset=NULL;
DWORD i;
DWORD dwObjSize = 0;
if ( pszObjName == NULL ||
pszSDDL == NULL ||
ppszAdjustedInfLine == NULL )
return ERROR_INVALID_PARAMETER;
rc = SceInfpBreakTextIntoMultiFields(pszSDDL, dwSDDLsize, &nFields, &aFieldOffset);
if ( SCESTATUS_SUCCESS != rc ) {
rc = ScepSceStatusToDosError(rc);
goto Done;
}
//
// each extra field will use 3 more chars : ,"<field>"
//
dwObjSize = wcslen(pszObjName)+8 + dwSDDLsize;
if ( nFields ) {
dwObjSize += 3*nFields;
} else {
dwObjSize += 2;
}
//
// allocate the output buffer
//
Strvalue = (PWSTR)ScepAlloc(LMEM_ZEROINIT, (dwObjSize+1) * sizeof(WCHAR) );
if ( Strvalue == NULL ) {
rc = ERROR_NOT_ENOUGH_MEMORY;
goto Done;
}
//
// copy data into the buffer
//
if ( nFields == 0 || !aFieldOffset ) {
swprintf(Strvalue, L"\"%s\",%1d,\"%s\"", pszObjName, ObjStatus, pszSDDL);
} else {
//
// loop through the fields
//
swprintf(Strvalue, L"\"%s\",%1d\0", pszObjName, ObjStatus);
for ( i=0; i<nFields; i++ ) {
if ( aFieldOffset[i] < dwSDDLsize ) {
wcscat(Strvalue, L",\"");
if ( i == nFields-1 ) {
//
// the last field
//
wcscat(Strvalue, pszSDDL+aFieldOffset[i]);
} else {
wcsncat(Strvalue, pszSDDL+aFieldOffset[i],
aFieldOffset[i+1]-aFieldOffset[i]);
}
wcscat(Strvalue, L"\"");
}
}
}
*ppszAdjustedInfLine = Strvalue;
Done:
if ( aFieldOffset ) {
ScepFree(aFieldOffset);
}
return(rc);
}
#ifndef _WIN64
BOOL
GetIsWow64 (
VOID
)
/*++
Routine Description:
Determine if we're running on WOW64 or not.
Arguments:
none
Return value:
TRUE if running under WOW64 (and special Wow64 features available)
--*/
{
ULONG_PTR ul = 0;
NTSTATUS st;
//
// If this call succeeds and sets ul non-zero
// it's a 32-bit process running on Win64
//
st = NtQueryInformationProcess(NtCurrentProcess(),
ProcessWow64Information,
&ul,
sizeof(ul),
NULL);
if (NT_SUCCESS(st) && (0 != ul)) {
// 32-bit code running on Win64
return TRUE;
}
return FALSE;
}
#endif // _WIN64