|
|
/*++
Copyright (c) 1997-1999 Microsoft Corporation
Module Name:
config.c
Abstract:
GetConfigParam reads a configuration keyword from the registry.
Author:
David Orbits - June-1999 Complete Rewrite to make table driven.
Environment:
Revision History:
--*/
#include <ntreppch.h>
#pragma hdrstop
#include <ctype.h>
#include <frs.h>
#include <ntfrsapi.h>
#define FULL_KEY_BUFF_SIZE 8192
VOID FrsRegPostEventLog( IN PFRS_REGISTRY_KEY KeyCtx, IN PWCHAR KeyArg1, IN ULONG Flags, IN LONG IDScode );
PGEN_TABLE ReparseTagTable;
//
// Possible errors are:
// required key not present
// required value not present
// value out of range
//
// **** NOTE: Also use this for FRS tuning parameters to select between
// workstation and server operation modes. Create a table with a list of the
// parameter codes and override values for the min, max and defaults.
// Apply during startup to reduce server footprint.
//
typedef struct _FRS_REG_KEY_REVISIONS {
LONG FrsKeyCode; // Frs code name for this key.
DWORD ValueMin; // Minimum data value, or string len
DWORD ValueMax; // Maximum Data value, or string len
DWORD ValueDefault; // Default data value if not present.
} FRS_REG_KEY_REVISIONS, *PFRS_REG_KEY_REVISIONS;
FRS_REG_KEY_REVISIONS FrsRegKeyRevisionTable[] = {
{FKC_DEBUG_MAX_LOG , 0 , MAXLONG, 10000 }, {FKC_MAX_REPLICA_THREADS , 2 , 10, 2 }, {FKC_MAX_RPC_SERVER_THREADS , 2 , 10, 2 }, {FKC_MAX_INSTALLCS_THREADS , 2 , 10, 2 }, {FKC_MAX_STAGE_GENCS_THREADS, 2 , 10, 2 }, {FKC_MAX_STAGE_FETCHCS_THREADS, 2 , 10, 2 }, {FKC_MAX_INITSYNCCS_THREADS, 2 , 10, 2 }, {FKC_SNDCS_MAXTHREADS_PAR , 2 , 10, 2 }, {FKC_MAX_NUMBER_REPLICA_SETS, 1 , 10, 5 }, {FKC_MAX_NUMBER_JET_SESSIONS, 1 , 50, 50 },
{FKC_END_OF_TABLE, 0, 0, 0 } };
//
// See sdk\inc\ntconfig.h if more registry data types are added.
//
#define NUMBER_OF_REG_DATATYPES 12
PWCHAR RegDataTypeNames[NUMBER_OF_REG_DATATYPES] = {
L"REG_NONE" , // ( 0 ) No value type
L"REG_SZ" , // ( 1 ) Unicode nul terminated string
L"REG_EXPAND_SZ" , // ( 2 ) Unicode nul terminated string (with environment variable references)
L"REG_BINARY" , // ( 3 ) Free form binary
L"REG_DWORD" , // ( 4 ) 32-bit number
L"REG_DWORD_BIG_ENDIAN" , // ( 5 ) 32-bit number
L"REG_LINK" , // ( 6 ) Symbolic Link (unicode)
L"REG_MULTI_SZ" , // ( 7 ) Multiple Unicode strings
L"REG_RESOURCE_LIST" , // ( 8 ) Resource list in the resource map
L"REG_FULL_RESOURCE_DESCRIPTOR" , // ( 9 ) Resource list in the hardware description
L"REG_RESOURCE_REQUIREMENTS_LIST" , // ( 10 )
L"REG_QWORD" // ( 11 ) 64-bit number
};
#define REG_DT_NAME(_code_) \
(((_code_) < NUMBER_OF_REG_DATATYPES) ? \ RegDataTypeNames[(_code_)] : RegDataTypeNames[0])
//
//
// If a range check fails the event EVENT_FRS_PARAM_OUT_OF_RANGE is logged if
// FRS_RKF_LOG_EVENT is set.
//
// If a syntax check fails the event EVENT_FRS_PARAM_INVALID_SYNTAX is logged if
// FRS_RKF_LOG_EVENT is set.
//
// If a required parameter is missing the event EVENT_FRS_PARAM_MISSING is logged
// if FRS_RKF_LOG_EVENT is set.
//
BOOL Win2kPro;
FLAG_NAME_TABLE RkfFlagNameTable[] = { {FRS_RKF_KEY_PRESENT , "KeyPresent " }, {FRS_RKF_VALUE_PRESENT , "ValuePresent " }, {FRS_RKF_DISPLAY_ERROR , "ShowErrorMsg " }, {FRS_RKF_LOG_EVENT , "ShowEventMsg " },
{FRS_RKF_READ_AT_START , "ReadAtStart " }, {FRS_RKF_READ_AT_POLL , "ReadAtPoll " }, {FRS_RKF_RANGE_CHECK , "RangeCheck " }, {FRS_RKF_SYNTAX_CHECK , "SyntaxCheck " },
{FRS_RKF_KEY_MUST_BE_PRESENT , "KeyMustBePresent " }, {FRS_RKF_VALUE_MUST_BE_PRESENT , "ValueMustBePresent " }, {FRS_RKF_OK_TO_USE_DEFAULT , "DefaultOK " }, {FRS_RKF_FORCE_DEFAULT_VALUE , "ForceDefault " },
{FRS_RKF_DEBUG_MODE_ONLY , "DebugMode " }, {FRS_RKF_TEST_MODE_ONLY , "TestMode " }, {FRS_RKF_API_ACCESS_CHECK_KEY , "DoAPIAccessChk " }, {FRS_RKF_CREATE_KEY , "CreateKey " },
{FRS_RKF_KEEP_EXISTING_VALUE , "KeepExistingValue " }, {FRS_RKF_KEY_ACCCHK_READ , "DoReadAccessChk " }, {FRS_RKF_KEY_ACCCHK_WRITE , "DoWriteAccessChk " }, {FRS_RKF_RANGE_SATURATE , "RangeSaturate " },
{FRS_RKF_DEBUG_PARAM , "DisplayAsDebugPar " },
{0, NULL} };
//
// The following describes the registry keys used by FRS.
// KeyName ValueName DataUnits
// RegValueType DataValueType Min Max Default EventCode
// FrsKeyCode Flags
//
//
// Notation for keyName field. Multiple key components separated by commas.
// Break on commas. Open leading key then create/open each successive component.
// ARG1 means substitute the Arg1 PWSTR parameter passed to the function for this
// key component. Most often this is a stringized guid. The string FRS_RKEY_SET_N
// below will end up opening/creating the following key:
//
// "System\\CurrentControlSet\\Services\\NtFrs\\Parameters\\Replica Sets\\27d6d1c4-d6b8-480b-9f18b5ea390a0178"
// assuming the argument passed in was "27d6d1c4-d6b8-480b-9f18b5ea390a0178"
//
// see FrsRegOpenKey() for details.
//
FRS_REGISTRY_KEY FrsRegistryKeyTable[] = {
/******************************************************************************
******************************************************************************* ** ** ** S e r v i c e D e b u g K e y s ** ** ** ** ** ******************************************************************************* ******************************************************************************/
// Number of assert files
{FRS_CONFIG_SECTION, L"Debug Assert Files", UNITS_NONE, REG_DWORD, DT_ULONG, 0, 1000, 5, EVENT_FRS_BAD_REG_DATA, NULL, FKC_DEBUG_ASSERT_FILES, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_RANGE_CHECK | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// Force an assert after N seconds (0 == don't assert)
{FRS_CONFIG_SECTION, L"Debug Force Assert in N Seconds", UNITS_SECONDS, REG_DWORD, DT_ULONG, 0, 1000, 0, EVENT_FRS_BAD_REG_DATA, NULL, FKC_DEBUG_ASSERT_SECONDS, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_RANGE_CHECK | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT | FRS_RKF_TEST_MODE_ONLY},
// Share for copying log/assert files
{FRS_CONFIG_SECTION, L"Debug Share for Assert Files", UNITS_NONE, REG_SZ, DT_UNICODE, 0, 0, 0, EVENT_FRS_NONE, NULL, FKC_DEBUG_ASSERT_SHARE, FRS_RKF_READ_AT_START | FRS_RKF_DEBUG_PARAM},
// If TRUE, Break into the debugger, if present
{FRS_CONFIG_SECTION, L"Debug Break", UNITS_NONE, REG_DWORD, DT_BOOL, FALSE, TRUE, FALSE, EVENT_FRS_NONE, NULL, FKC_DEBUG_BREAK, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_TEST_MODE_ONLY | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// If TRUE, copy log files into assert share
{FRS_CONFIG_SECTION, L"Debug Copy Log Files into Assert Share", UNITS_NONE, REG_DWORD, DT_BOOL, FALSE, TRUE, FALSE, EVENT_FRS_BAD_REG_DATA, NULL, FKC_DEBUG_COPY_LOG_FILES, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// Force real out of disk space errors on database operations
{FRS_CONFIG_SECTION, L"Debug Dbs Out Of Space", UNITS_NONE, REG_DWORD, DT_ULONG, 0, DBG_DBS_OUT_OF_SPACE_OP_MAX, 0, EVENT_FRS_BAD_REG_DATA, NULL, FKC_DEBUG_DBS_OUT_OF_SPACE, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_READ_AT_POLL | FRS_RKF_TEST_MODE_ONLY | FRS_RKF_RANGE_CHECK | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// Force Jet Err simulated out of disk space errors on database operations
{FRS_CONFIG_SECTION, L"Debug Dbs Out Of Space Trigger", UNITS_NONE, REG_DWORD, DT_ULONG, 0, MAXLONG, 0, EVENT_FRS_BAD_REG_DATA, NULL, FKC_DEBUG_DBS_OUT_OF_SPACE_TRIGGER, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_READ_AT_POLL | FRS_RKF_TEST_MODE_ONLY | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// If TRUE, debug log file generation (DPRINTS and CO Trace output) is off.
{FRS_CONFIG_SECTION, L"Debug Disable", UNITS_NONE, REG_DWORD, DT_BOOL, FALSE, TRUE, FALSE, EVENT_FRS_NONE, NULL, FKC_DEBUG_DISABLE, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// The directory path for the FRS debug logs.
{FRS_CONFIG_SECTION, L"Debug Log File", UNITS_NONE, REG_EXPAND_SZ, DT_UNICODE, 0, 0, 0, EVENT_FRS_BAD_REG_DATA, L"%SystemRoot%\\debug", FKC_DEBUG_LOG_FILE, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_DEBUG_PARAM | FRS_RKF_SYNTAX_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Number of debug log files to keep as history
{FRS_CONFIG_SECTION, L"Debug Log Files", UNITS_NONE, REG_DWORD, DT_ULONG, 0, 300, 5, EVENT_FRS_BAD_REG_DATA, NULL, FKC_DEBUG_LOG_FILES, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_RANGE_CHECK | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// Number of debug log records written between file flushes.
// btw: Severity 0 log records always force a log file flush.
{FRS_CONFIG_SECTION, L"Debug Log Flush Interval", UNITS_NONE, REG_DWORD, DT_LONG, 1, MAXLONG, 20000, EVENT_FRS_BAD_REG_DATA, NULL, FKC_DEBUG_LOG_FLUSH_INTERVAL, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_RANGE_CHECK | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// Print debug msgs with severity level LE DEBUG_LOG_SEVERITY to debug log.
// 0 - Most severe, eg. fatal inconsistency, mem alloc fail. Least noisey.
// 1 - Important info, eg. Key config parameters, unexpected conditions
// 2 - File tracking records.
// 3 - Change Order Process trace records.
// 4 - Status results, e.g. table lookup failures, new entry inserted
// 5 - Information level messages to show flow. Noisest level. Maybe in a loop
// see also DEBUG_SEVERITY.
{FRS_CONFIG_SECTION, L"Debug Log Severity", UNITS_NONE, REG_DWORD, DT_ULONG, 0, 5, 2, EVENT_FRS_BAD_REG_DATA, NULL, FKC_DEBUG_LOG_SEVERITY, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// Max number of debug log messages output before opening a new log file.
{FRS_CONFIG_SECTION, L"Debug Maximum Log Messages", UNITS_NONE, REG_DWORD, DT_ULONG, 0, MAXLONG, 20000, EVENT_FRS_BAD_REG_DATA, NULL, FKC_DEBUG_MAX_LOG, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_READ_AT_POLL | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// If >0, then track and check all mem alloc / dealloc. (slow)
// 1 - checks allocs and frees and prints stack of unalloced mem at exit
// 2 - checks for mem alloc region overwrite on each alloc/free - very slow.
//
{FRS_CONFIG_SECTION, L"Debug Mem", UNITS_NONE, REG_DWORD, DT_ULONG, 0, 4, 0, EVENT_FRS_NONE, NULL, FKC_DEBUG_MEM, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_TEST_MODE_ONLY | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// If TRUE, then call HeapCompact(GetProcessHeap(), 0) on mem dealloc. (slower)
{FRS_CONFIG_SECTION, L"Debug Mem Compact", UNITS_NONE, REG_DWORD, DT_BOOL, FALSE, TRUE, FALSE, EVENT_FRS_NONE, NULL, FKC_DEBUG_MEM_COMPACT, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_TEST_MODE_ONLY | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// Mail profile for sending mail notifications. (future)
{FRS_CONFIG_SECTION, L"Debug Profile", UNITS_NONE, REG_SZ, DT_UNICODE, 0, 0, 0, EVENT_FRS_NONE, NULL, FKC_DEBUG_PROFILE, FRS_RKF_READ_AT_START | FRS_RKF_DEBUG_PARAM | FRS_RKF_READ_AT_POLL},
// If TRUE, then check consistency of command queues on each queue op. (slow)
{FRS_CONFIG_SECTION, L"Debug Queues", UNITS_NONE, REG_DWORD, DT_BOOL, FALSE, TRUE, FALSE, EVENT_FRS_NONE, NULL, FKC_DEBUG_QUEUES, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_TEST_MODE_ONLY | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// Mail recipients for sending mail notifications. (future)
{FRS_CONFIG_SECTION, L"Debug Recipients", UNITS_NONE, REG_EXPAND_SZ, DT_UNICODE, 0, 0, 0, EVENT_FRS_NONE, NULL, FKC_DEBUG_RECIPIENTS, FRS_RKF_READ_AT_START | FRS_RKF_DEBUG_PARAM | FRS_RKF_READ_AT_POLL},
// Restart the service after an assertion failure iff the service was able
// to run for at least DEBUG_RESTART_SECONDS before the assert hit.
{FRS_CONFIG_SECTION, L"Debug Restart if Assert after N Seconds", UNITS_SECONDS, REG_DWORD, DT_ULONG, 0, MAXLONG, 600, EVENT_FRS_BAD_REG_DATA, NULL, FKC_DEBUG_RESTART_SECONDS, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_LOG_EVENT | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// Print debug msgs with severity level LE DEBUG_SEVERITY to
// stdout if running as -notservice.
// see also DEBUG_LOG_SEVERITY.
{FRS_CONFIG_SECTION, L"Debug Severity", UNITS_NONE, REG_DWORD, DT_ULONG, 0, 5, 0, EVENT_FRS_BAD_REG_DATA, NULL, FKC_DEBUG_SEVERITY, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_LOG_EVENT | FRS_RKF_RANGE_CHECK | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// If FALSE, Print debug msgs with severity level LE DEBUG_SEVERITY to
// an attached debugger. (slow)
// see also DEBUG_LOG_SEVERITY.
{FRS_CONFIG_SECTION, L"Debug Suppress", UNITS_NONE, REG_DWORD, DT_BOOL, FALSE, TRUE, TRUE, EVENT_FRS_NONE, NULL, FKC_DEBUG_SUPPRESS, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// Suppress debug prints from components in the DEBUG_SYSTEMS list.
// default is all components print.
{FRS_CONFIG_SECTION, L"Debug Systems", UNITS_NONE, REG_EXPAND_SZ, DT_UNICODE, 0, 0, 0, EVENT_FRS_NONE, NULL, FKC_DEBUG_SYSTEMS, FRS_RKF_READ_AT_START | FRS_RKF_DEBUG_PARAM | FRS_RKF_READ_AT_POLL},
// Test code name for FRS_DEBUG_TEST_POINT macro.
//
{FRS_CONFIG_SECTION, L"Debug Test Code Name", UNITS_NONE, REG_EXPAND_SZ, DT_UNICODE, 0, 0, 0, EVENT_FRS_NONE, NULL, FKC_DEBUG_TEST_CODE_NAME, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_DEBUG_PARAM},
// Test sub-code number for FRS_DEBUG_TEST_POINT macro.
//
{FRS_CONFIG_SECTION, L"Debug Test Code Number", UNITS_NONE, REG_DWORD, DT_ULONG, 0xFFFFFFFF, 0, 0, EVENT_FRS_NONE, NULL, FKC_DEBUG_TEST_CODE_NUMBER, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// Initial test trigger count for FRS_DEBUG_TEST_POINT macro.
//
{FRS_CONFIG_SECTION, L"Debug Test Trigger Count", UNITS_NONE, REG_DWORD, DT_ULONG, 0xFFFFFFFF, 0, 0, EVENT_FRS_NONE, NULL, FKC_DEBUG_TEST_TRIGGER_COUNT, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// Test trigger refresh value for FRS_DEBUG_TEST_POINT macro.
//
{FRS_CONFIG_SECTION, L"Debug Test Trigger Refresh", UNITS_NONE, REG_DWORD, DT_ULONG, 0xFFFFFFFF, 0, 0, EVENT_FRS_NONE, NULL, FKC_DEBUG_TEST_TRIGGER_REFRESH, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_DEBUG_PARAM | FRS_RKF_OK_TO_USE_DEFAULT},
// hklm\software\microsoft\windows nt\current version\buildlab
{FRS_CURRENT_VER_SECTION, L"buildlab", UNITS_NONE, REG_SZ, DT_UNICODE, 0, 0, 0, EVENT_FRS_NONE, NULL, FKC_DEBUG_BUILDLAB, FRS_RKF_READ_AT_START | FRS_RKF_DEBUG_PARAM},
/******************************************************************************
******************************************************************************* ** ** ** S e r v i c e C o n f i g K e y s ** ** ** ** ** ******************************************************************************* ******************************************************************************/
#define FRS_MUTUAL_AUTHENTICATION_IS \
L"Mutual authentication is [" FRS_IS_ENABLED L" or " FRS_IS_DISABLED L"]"
// Comm Timeout In Milliseconds
// Unjoin the cxtion if the partner doesn't respond soon enough
{FRS_CONFIG_SECTION, L"Comm Timeout In Milliseconds", UNITS_MILLISEC, REG_DWORD, DT_ULONG, 0, MAXLONG, (5 * 60 * 1000), EVENT_FRS_BAD_REG_DATA, NULL, FKC_COMM_TIMEOUT, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_OK_TO_USE_DEFAULT},
// The directory filter exclusion list. Default: None
// Don't supply a default here. See FRS_DS_COMPOSE_FILTER_LIST for why.
{FRS_CONFIG_SECTION, L"Directory Exclusion Filter List", UNITS_NONE, REG_SZ, DT_FILE_LIST, 0, 0, 0, EVENT_FRS_BAD_REG_DATA, NULL, FKC_DIR_EXCL_FILTER_LIST, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_SYNTAX_CHECK | FRS_RKF_READ_AT_POLL},
// The directory filter inclusion list. Default: None
{FRS_CONFIG_SECTION, L"Directory Inclusion Filter List", UNITS_NONE, REG_SZ, DT_FILE_LIST, 0, 0, 0, EVENT_FRS_BAD_REG_DATA, NULL, FKC_DIR_INCL_FILTER_LIST, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_SYNTAX_CHECK | FRS_RKF_CREATE_KEY | FRS_RKF_OK_TO_USE_DEFAULT | FRS_RKF_READ_AT_POLL},
// Minutes between polls of the DS when data does not appear to be changing.
{FRS_CONFIG_SECTION, L"DS Polling Long Interval in Minutes", UNITS_MINUTES, REG_DWORD, DT_ULONG, NTFRSAPI_MIN_INTERVAL, NTFRSAPI_MAX_INTERVAL, NTFRSAPI_DEFAULT_LONG_INTERVAL, EVENT_FRS_BAD_REG_DATA, NULL, FKC_DS_POLLING_LONG_INTERVAL, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_LOG_EVENT | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Minutes between polls of the DS when data does appear to be changing.
// If no data in the DS has changed after 8 (DS_POLLING_MAX_SHORTS) short
// polling intervals then we fall back to DS_POLLING_LONG_INTERVAL.
// Note: if FRS is running on a DC always use the short interval.
{FRS_CONFIG_SECTION, L"DS Polling Short Interval in Minutes", UNITS_MINUTES, REG_DWORD, DT_ULONG, NTFRSAPI_MIN_INTERVAL, NTFRSAPI_MAX_INTERVAL, NTFRSAPI_DEFAULT_SHORT_INTERVAL, EVENT_FRS_BAD_REG_DATA, NULL, FKC_DS_POLLING_SHORT_INTERVAL, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_LOG_EVENT | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Enumerate Directory Buffer Size in Bytes (WHY DO WE NEED THIS???)
{FRS_CONFIG_SECTION, L"Enumerate Directory Buffer Size in Bytes", UNITS_BYTES, REG_DWORD, DT_ULONG, MINIMUM_ENUMERATE_DIRECTORY_SIZE, 1024*1024, 4*1024, EVENT_FRS_BAD_REG_DATA, NULL, FKC_ENUMERATE_DIRECTORY_SIZE, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_LOG_EVENT | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// The file filter exclusion list.
// Don't supply a default here. See FRS_DS_COMPOSE_FILTER_LIST for why.
{FRS_CONFIG_SECTION, L"File Exclusion Filter List", UNITS_NONE, REG_SZ, DT_FILE_LIST, 0, 0, 0, EVENT_FRS_BAD_REG_DATA, NULL, FKC_FILE_EXCL_FILTER_LIST, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_READ_AT_POLL},
// The file filter inclusion list. Default: L""
{FRS_CONFIG_SECTION, L"File Inclusion Filter List", UNITS_NONE, REG_SZ, DT_FILE_LIST, 0, 0, 0, EVENT_FRS_BAD_REG_DATA, L"", FKC_FILE_INCL_FILTER_LIST, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_SYNTAX_CHECK | FRS_RKF_CREATE_KEY | FRS_RKF_OK_TO_USE_DEFAULT | FRS_RKF_READ_AT_POLL},
// The name of the FRS eventlog message file.
// Default value: "%SystemRoot%\system32\ntfrsres.dll"
// WHY DO WE NEED TO BE ABLE TO CHANGE THIS???
{FRS_CONFIG_SECTION, L"Message File Path", UNITS_NONE, REG_EXPAND_SZ, DT_UNICODE, 2, 0, 0, EVENT_FRS_NONE, DEFAULT_MESSAGE_FILE_PATH, FKC_FRS_MESSAGE_FILE_PATH, FRS_RKF_READ_AT_START | FRS_RKF_OK_TO_USE_DEFAULT},
// Mutual authentication is [Enabled or Disabled]
{FRS_CONFIG_SECTION, FRS_MUTUAL_AUTHENTICATION_IS, UNITS_NONE, REG_SZ, DT_UNICODE, 2, 200, 0, EVENT_FRS_NONE, FRS_IS_DEFAULT_ENABLED, FKC_FRS_MUTUAL_AUTHENTICATION_IS, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT},
// Maximum Join Retry time In MilliSeconds Default: 1 hr.
{FRS_CONFIG_SECTION, L"Maximum Join Retry In MilliSeconds", UNITS_MILLISEC, REG_DWORD, DT_ULONG, 30*1000, 10*3600*1000, (60 * 60 * 1000), EVENT_FRS_NONE, NULL, FKC_MAX_JOIN_RETRY, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Maximum Replica Command Server Threads Default: 16
// The replica command server services commands for configuration changes
// and replication.
{FRS_CONFIG_SECTION, L"Maximum Replica Command Server Threads", UNITS_NONE, REG_DWORD, DT_ULONG, 2, 200, (16), EVENT_FRS_NONE, NULL, FKC_MAX_REPLICA_THREADS, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Max Rpc Server Threads Default: 16
// Maximum number of concurrent RPC calls
{FRS_CONFIG_SECTION, L"Max Rpc Server Threads", UNITS_NONE, REG_DWORD, DT_ULONG, 2, 200, (16), EVENT_FRS_NONE, NULL, FKC_MAX_RPC_SERVER_THREADS, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// User specified Rpc port assignment Default: 0
//
{FRS_CONFIG_SECTION, L"Rpc TCP/IP Port Assignment", UNITS_NONE, REG_DWORD, DT_ULONG, 0, 0xffffffff, (0), EVENT_FRS_NONE, NULL, FKC_RPC_PORT_ASSIGNMENT, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Maximum Install Command Server Threads Default: 4
{FRS_CONFIG_SECTION, L"Maximum Install Command Server Threads", UNITS_NONE, REG_DWORD, DT_ULONG, 2, 200, (4), EVENT_FRS_NONE, NULL, FKC_MAX_INSTALLCS_THREADS, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Maximum Stage Gen Command Server Threads Default: 4
{FRS_CONFIG_SECTION, L"Maximum Stage Gen Command Server Threads", UNITS_NONE, REG_DWORD, DT_ULONG, 2, 200, (4), EVENT_FRS_NONE, NULL, FKC_MAX_STAGE_GENCS_THREADS, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Maximum Stage Fetch Command Server Threads Default: 4
{FRS_CONFIG_SECTION, L"Maximum Stage Fetch Command Server Threads", UNITS_NONE, REG_DWORD, DT_ULONG, 2, 200, (4), EVENT_FRS_NONE, NULL, FKC_MAX_STAGE_FETCHCS_THREADS, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Maximum Initial SYnc Command Server Threads Default: 4
{FRS_CONFIG_SECTION, L"Maximum Initial Sync Command Server Threads", UNITS_NONE, REG_DWORD, DT_ULONG, 2, 200, (4), EVENT_FRS_NONE, NULL, FKC_MAX_INITSYNCCS_THREADS, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Minimum Join Retry time In MilliSeconds Default: 10 sec.
// Retry a join every MinJoinRetry milliseconds, doubling the interval
// every retry. Stop retrying when the interval is greater than MaxJoinRetry.
{FRS_CONFIG_SECTION, L"Minimum Join Retry In MilliSeconds", UNITS_MILLISEC, REG_DWORD, DT_ULONG, 500, 10*3600*1000, (10 * 1000), EVENT_FRS_NONE, NULL, FKC_MIN_JOIN_RETRY, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Partner Clock Skew In Minutes Default: 30 min.
// Partners are not allowed to join if their clocks are out-of-sync
{FRS_CONFIG_SECTION, L"Partner Clock Skew In Minutes", UNITS_MINUTES, REG_DWORD, DT_ULONG, 1, 10*60, 30, EVENT_FRS_NONE, NULL, FKC_PARTNER_CLOCK_SKEW, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// ChangeOrder Reconcile Event Time Window In Minutes Default: 30 min.
{FRS_CONFIG_SECTION, L"Reconcile Time Window In Minutes", UNITS_MINUTES, REG_DWORD, DT_ULONG, 1, 120, 30, EVENT_FRS_NONE, NULL, FKC_RECONCILE_WINDOW, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// ChangeOrder Inlog retry interval in seconds Default: 60 sec.
{FRS_CONFIG_SECTION, L"Inlog Retry Time In Seconds", UNITS_SECONDS, REG_DWORD, DT_ULONG, 1, 24*3600, 60, EVENT_FRS_NONE, NULL, FKC_INLOG_RETRY_TIME, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// ChangeOrder Aging Delay in seconds Default: 3 sec.
// Should be a min of 3 sec to allow file system tunnel cache info to propagate.
{FRS_CONFIG_SECTION, L"Changeorder Aging Delay In Seconds", UNITS_SECONDS, REG_DWORD, DT_ULONG, 3, 30*60, 3, EVENT_FRS_NONE, NULL, FKC_CO_AGING_DELAY, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Outlog File Repeat Interval In Seconds Default: 30 sec.
// A CO update for a given file will not be sent out more frequently than this.
// Set to zero to disable the Outlog dominant file update optimization.
{FRS_CONFIG_SECTION, L"Outlog File Repeat Interval In Seconds", UNITS_SECONDS, REG_DWORD, DT_ULONG, 0, 24*3600, 30, EVENT_FRS_NONE, NULL, FKC_OUTLOG_REPEAT_INTERVAL, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Sysvol Promotion Timeout In Milliseconds Default: 10 min.
{FRS_CONFIG_SECTION, L"Sysvol Promotion Timeout In Milliseconds", UNITS_MILLISEC, REG_DWORD, DT_ULONG, 0, 3600*1000, (10 * 60 * 1000), EVENT_FRS_NONE, NULL, FKC_PROMOTION_TIMEOUT, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Replica Start Timeout In MilliSeconds Default: 0 means can't start without DS.
// Start replication even if the DS could not be accessed
// 0: no DS == no start replicas
// N: start replicas in N milliseconds
{FRS_CONFIG_SECTION, L"Replica Start Timeout In MilliSeconds", UNITS_MILLISEC, REG_DWORD, DT_ULONG, 0, 3600*1000, (0), EVENT_FRS_NONE, NULL, FKC_REPLICA_START_TIMEOUT, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Replica Tombstone in Days Default: 32
// The length of time we will hold onto the database state for a replica
// set after we see our membership in the DS has been deleted. Since
// delete is not explicit (except for DC Demote) it may just be that the
// DC is missing our objects or an admin erroneously deleted our subscriber
// or member object. Once this time has lapsed we will delete the tables
// from the database.
{FRS_CONFIG_SECTION, L"Replica Tombstone in Days", UNITS_DAYS, REG_DWORD, DT_ULONG, 3, MAXLONG, (32), EVENT_FRS_NONE, NULL, FKC_REPLICA_TOMBSTONE, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Shutdown Timeout in Seconds Default: 90 sec.
// The max time FRS main will wait for all threads to exit during shutdown.
{FRS_CONFIG_SECTION, L"Shutdown Timeout in Seconds", UNITS_SECONDS, REG_DWORD, DT_ULONG, 30, 24*60*60, DEFAULT_SHUTDOWN_TIMEOUT, EVENT_FRS_NONE, NULL, FKC_SHUTDOWN_TIMEOUT, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Maximum Send Command Server Threads Default: 16
{FRS_CONFIG_SECTION, L"Maximum Send Command Server Threads", UNITS_NONE, REG_DWORD, DT_ULONG, 2, 200, (16), EVENT_FRS_NONE, NULL, FKC_SNDCS_MAXTHREADS_PAR, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Staging Space Limit in KB Default: 660 MB
{FRS_CONFIG_SECTION, L"Staging Space Limit in KB", UNITS_KBYTES, REG_DWORD, DT_ULONG, 10*1024, MAXLONG, (660 * 1024), EVENT_FRS_BAD_REG_DATA, NULL, FKC_STAGING_LIMIT, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT | FRS_RKF_LOG_EVENT},
// VvJoin Limit in Change Orders Default: 16 ChangeOrders
// Max number of VVJoin gened COs to prevent flooding.
{FRS_CONFIG_SECTION, L"VvJoin Limit in Change Orders", UNITS_NONE, REG_DWORD, DT_ULONG, 2, 128, (16), EVENT_FRS_NONE, NULL, FKC_VVJOIN_LIMIT, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// VVJoin Outbound Log Throttle Timeout Default: 1 sec.
// The time FRS VVJoin thread waits after generating VVJOIN_LIMIT COs.
{FRS_CONFIG_SECTION, L"VvJoin Timeout in Milliseconds", UNITS_MILLISEC, REG_DWORD, DT_ULONG, 100, 10*60*1000, (1000), EVENT_FRS_NONE, NULL, FKC_VVJOIN_TIMEOUT, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// The FRS working dir is where the Jet (ESENT) database is created.
// If this dir does not exist or can't be created FRS will fail to startup.
{FRS_CONFIG_SECTION, L"Working Directory", UNITS_NONE, REG_SZ, DT_DIR_PATH, 4, 10*(MAX_PATH+1), 4, EVENT_FRS_BAD_REG_DATA, NULL, FKC_WORKING_DIRECTORY, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT | FRS_RKF_SYNTAX_CHECK | FRS_RKF_LOG_EVENT },
// The FRS Log File Directory allows the Jet Logs to created on a different volume.
// By default they are placed in a Log subdir under the "Working Directory".
// If this dir does not exist or can't be created FRS will fail to startup.
{FRS_CONFIG_SECTION, L"DB Log File Directory", UNITS_NONE, REG_SZ, DT_DIR_PATH, 4, 10*(MAX_PATH+1), 4, EVENT_FRS_BAD_REG_DATA, NULL, FKC_DBLOG_DIRECTORY, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_SYNTAX_CHECK | FRS_RKF_LOG_EVENT },
// Ntfs Journal size in MB Default: 128 Meg
{FRS_CONFIG_SECTION, L"Ntfs Journal size in MB", UNITS_MBYTES, REG_DWORD, DT_ULONG, 4, 10000, (128), EVENT_FRS_BAD_REG_DATA, NULL, FKC_NTFS_JRNL_SIZE, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Maximum Number of Replica Sets Default: 200.
{FRS_CONFIG_SECTION, L"Maximum Number of Replica Sets", UNITS_NONE, REG_DWORD, DT_ULONG, 1, 5000, (200), EVENT_FRS_BAD_REG_DATA, NULL, FKC_MAX_NUMBER_REPLICA_SETS, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Maximum Number of Jet Sessions Default: 128.
{FRS_CONFIG_SECTION, L"Maximum Number of Jet Sessions", UNITS_NONE, REG_DWORD, DT_ULONG, 1, 5000, (128), EVENT_FRS_BAD_REG_DATA, NULL, FKC_MAX_NUMBER_JET_SESSIONS, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// Maximum Number of outstanding CO's per outbound connection. Default: 8.
{FRS_CONFIG_SECTION, L"Max Num Outbound COs Per Connection", UNITS_NONE, REG_DWORD, DT_ULONG, 1, 100, (8), EVENT_FRS_BAD_REG_DATA, NULL, FKC_OUT_LOG_CO_QUOTA, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// If TRUE, Preserve OIDs on files whenever possible Default: False
// -- See Bug 352250 for why this is a risky thing to do.
{FRS_CONFIG_SECTION, L"Preserve File OID", UNITS_NONE, REG_DWORD, DT_BOOL, FALSE, TRUE, (FALSE), EVENT_FRS_NONE, NULL, FKC_PRESERVE_FILE_OID, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT}, //
// Disable compression support. Need a non-auth restore to
// make sure we don't have any old compressed staging files
// when this key is turned on. Default: True
//
{FRS_CONFIG_SECTION, L"Debug Disable Compression", UNITS_NONE, REG_DWORD, DT_BOOL, FALSE, TRUE, (FALSE), EVENT_FRS_NONE, NULL, FKC_DEBUG_DISABLE_COMPRESSION, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
//
// Compress staging files for local changes. Set to FALSE to disable.
// This member will continue to install and propagate compressed files.
// This is useful if the customer has content that originates on this member
// which is either already compressed or doesn't compress well.
// Default: True
{FRS_CONFIG_SECTION, L"Compress Staging Files", UNITS_NONE, REG_DWORD, DT_BOOL, FALSE, TRUE, (TRUE), EVENT_FRS_NONE, NULL, FKC_COMPRESS_STAGING_FILES, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
//
// This controls automatic reclaim of staging space by using an
// LRU algorithm. Default: True
//
{FRS_CONFIG_SECTION, L"Reclaim Staging Space", UNITS_NONE, REG_DWORD, DT_BOOL, FALSE, TRUE, (TRUE), EVENT_FRS_NONE, NULL, FKC_RECLAIM_STAGING_SPACE, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
//
// Client side ldap search timeout value. Default: 10 minutes.
//
{FRS_CONFIG_SECTION, L"Ldap Search Timeout In Minutes", UNITS_MINUTES, REG_DWORD, DT_ULONG, 1, 120, (10), EVENT_FRS_BAD_REG_DATA, NULL, FKC_LDAP_SEARCH_TIMEOUT_IN_MINUTES, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT}, //
// Client side ldap_connect timeout value. Default: 30 seconds.
//
{FRS_CONFIG_SECTION, L"Ldap Bind Timeout In Seconds", UNITS_SECONDS, REG_DWORD, DT_ULONG, 2, MAXLONG, (30), EVENT_FRS_BAD_REG_DATA, NULL, FKC_LDAP_BIND_TIMEOUT_IN_SECONDS, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
//
// The length of time we retry a change order before aborting it.
// e.g. A file create waiting for the create of a parent dir that
// never comes. Default: 7 days
//
{FRS_CONFIG_SECTION, L"Maximum CO Retry Timeout in Minutes", UNITS_MINUTES, REG_DWORD, DT_ULONG, 1, 525600, (10080), EVENT_FRS_BAD_REG_DATA, NULL, FKC_MAX_CO_RETRY_TIMEOUT_MINUTES, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_LOG_EVENT | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
//
// The number of retries applied to a change order before aborting it.
// e.g. A file create waiting for the create of a parent dir that
// never comes. Default: 3000
//
{FRS_CONFIG_SECTION, L"Maximum CO Retry Count", UNITS_NONE, REG_DWORD, DT_ULONG, 2, MAXLONG, (3000), EVENT_FRS_BAD_REG_DATA, NULL, FKC_MAX_CO_RETRY_TIMEOUT_COUNT, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_LOG_EVENT | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
//
// Enable automatic restore on journal wrap or journal recreation.
// This occurs when the replica set gets into either state
// REPLICA_STATE_JRNL_WRAP_ERROR or REPLICA_STATE_MISMATCHED_JOURNAL_ID.
// The default is FALSE because a non-auth restore will move the replica
// tree to the pre-existing dir and make the files unavailable on a DFS
// alternate. Customers did not like this.
//
{FRS_CONFIG_SECTION, L"Enable Journal Wrap Automatic Restore", UNITS_NONE, REG_DWORD, DT_BOOL, FALSE, TRUE, (FALSE), EVENT_FRS_NONE, NULL, FKC_ENABLE_JOURNAL_WRAP_AUTOMATIC_RESTORE, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
//
// If True then hold the ReplicaList lock for the duration of an outlog cleanup
// cycle (which could be many minutes). If False then don't hold the lock.
//
{FRS_CONFIG_SECTION, L"Enable Locked Outlog Cleanup", UNITS_NONE, REG_DWORD, DT_BOOL, FALSE, TRUE, (FALSE), EVENT_FRS_NONE, NULL, FKC_LOCKED_OUTLOG_CLEANUP, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
//
// This controls how long the change orders will stay in the outlog.
// Change orders are kept in the outlog to satisfy future vvjoins
// without having to scan the idtable. Default: 1 week.
//
{FRS_CONFIG_SECTION, L"Outlog Change History In Minutes", UNITS_MINUTES, REG_DWORD, DT_ULONG, 1, MAXLONG, (10080), EVENT_FRS_NONE, NULL, FKC_OUTLOG_CHANGE_HISTORY, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
//
// This controls how long whether COs in the outlog even after they have
// been ACK ed by all the partners. The longer the COs stay in the outlog
// the greater the chances of avoiding complete vvjoins. The period is
// controlled by the FKC_OUTLOG_CHANGE_HISTORY key above. The
// FKC_SAVE_OUTLOG_CHANGE_HISTORY turns this feature off. Turn this off in
// cases where the outlog is getting very large. Even when
// FKC_SAVE_OUTLOG_CHANGE_HISTORY is turned off FKC_OUTLOG_CHANGE_HISTORY
// can be set to trim outlog to protect FRS against members that do not
// come back.
// Default: True
{FRS_CONFIG_SECTION, L"Debug Save Outlog Change History", UNITS_NONE, REG_DWORD, DT_BOOL, FALSE, TRUE, (TRUE), EVENT_FRS_NONE, NULL, FKC_SAVE_OUTLOG_CHANGE_HISTORY, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
//
// The "Suppress Identical Updates To Files" key controls whether FRS
// tries to identify and suppress updates that do not change the content
// (everything that is used to calculate the MD5 and attributes) of the
// file.
// Default: True
{FRS_CONFIG_SECTION, L"Suppress Identical Updates To Files", UNITS_NONE, REG_DWORD, DT_BOOL, FALSE, TRUE, (TRUE), EVENT_FRS_NONE, NULL, FKC_SUPPRESS_IDENTICAL_UPDATES, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
//
// If true, Install Override tells FRS to attempt to rename an opened
// target file out of the way in order to allow installation of a new
// updated version of the file. E.G. an open .exe or .dll file would
// be treated this way. Normally (i.e. when FALSE) FRS will wait until
// it can open the target with write access. Install override only works
// if FRS can open the file for rename. This requires DELETE access to
// the file so if the target file is currently open with a sharing mode
// that denies DELETE access to other opens then FRS will not be able to
// install the updated version until the file is closed.
// *NOTE* Install Override only applies to files, not directories.
//
// Default: FALSE
{FRS_CONFIG_SECTION, L"Enable Install Override", UNITS_NONE, REG_DWORD, DT_BOOL, FALSE, TRUE, (FALSE), EVENT_FRS_NONE, NULL, FKC_ENABLE_INSTALL_OVERRIDE, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
//
// If true, then remote change orders that update existing files will
// always use a pre-install file in which to build the content followed
// by a rename to insert the file into its target location in the replica
// tree. The benefit is that if FRS runs out of disk space during the
// install phase or the system crashes then a partial file (or a truncated file)
// is not left in the tree. The old content is left in place. The
// drawback of this is the need for enough disk space to hold two copies of
// the target file.
// Default: FALSE
{FRS_CONFIG_SECTION, L"Enable Rename Based File Updates", UNITS_NONE, REG_DWORD, DT_BOOL, FALSE, TRUE, (FALSE), EVENT_FRS_NONE, NULL, FKC_ENABLE_RENAME_BASED_UPDATES, FRS_RKF_READ_AT_START | FRS_RKF_READ_AT_POLL | FRS_RKF_RANGE_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// add ReplDirLevelLimit as a reg key
// add code support for the following
//FKC_SET_N_DIR_EXCL_FILTER_LIST,
//FKC_SET_N_DIR_INCL_FILTER_LIST,
//FKC_SET_N_FILE_EXCL_FILTER_LIST,
//FKC_SET_N_FILE_INCL_FILTER_LIST,
//FKC_SET_N_SYSVOL_DIR_EXCL_FILTER_LIST,
//FKC_SET_N_SYSVOL_DIR_INCL_FILTER_LIST,
//FKC_SET_N_SYSVOL_FILE_EXCL_FILTER_LIST,
//FKC_SET_N_SYSVOL_FILE_INCL_FILTER_LIST,
/******************************************************************************
******************************************************************************* ** ** ** P e r - R e p l i c a S e t K e y s ** ** ** ** ** ******************************************************************************* ******************************************************************************/
#define FRS_RKEY_SETS_SECTION FRS_CONFIG_SECTION L",Replica Sets"
#define FRS_RKEY_SET_N FRS_CONFIG_SECTION L",Replica Sets,ARG1"
#define FRS_RKEY_CUM_SET_N FRS_CONFIG_SECTION L",Cumulative Replica Sets,ARG1"
#define FRS_RKEY_CUM_SET_SECTION FRS_CONFIG_SECTION L",Cumulative Replica Sets"
//
// FRS Sets parameter data. Lives in
// "System\\CurrentControlSet\\Services\\NtFrs\\Parameters\\Replica Sets\\[RS-guid]"
// Used for sysvols currently.
//
// No event log messages are generated for these keys since currently
// they are only created by the service or NTFRSAPI so if they get
// fouled up there is nothing the USER can do to correct the problem.
//
// Cumulative Replica Sets *NOTE* This is a key def only.
{FRS_RKEY_SETS_SECTION, L"*KeyOnly*", UNITS_NONE, REG_SZ, DT_UNICODE, 0, MAXLONG, 0, EVENT_FRS_NONE, NULL, FKC_SET_SECTION_KEY, 0},
// The FRS working dir is where the Jet (ESENT) database is created.
// Replica Sets\Database Directory
{FRS_RKEY_SETS_SECTION, JET_PATH, UNITS_NONE, REG_SZ, DT_DIR_PATH, 4, 10*1024, 4, EVENT_FRS_NONE, NULL, FKC_SETS_JET_PATH, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT | FRS_RKF_SYNTAX_CHECK},
// Replica Sets\Guid\Replica Set Name
{FRS_RKEY_SET_N, REPLICA_SET_NAME, UNITS_NONE, REG_SZ, DT_UNICODE, 4, 512, 0, EVENT_FRS_NONE, NULL, FKC_SET_N_REPLICA_SET_NAME, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT},
// The root of the replica tree.
// Replica Sets\Guid\Replica Set Root
{FRS_RKEY_SET_N, REPLICA_SET_ROOT, UNITS_NONE, REG_SZ, DT_DIR_PATH, 4, 10*1024, 4, EVENT_FRS_NONE, NULL, FKC_SET_N_REPLICA_SET_ROOT, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT | FRS_RKF_SYNTAX_CHECK},
// The staging area for this replica set.
// Replica Sets\Guid\Replica Set Stage
{FRS_RKEY_SET_N, REPLICA_SET_STAGE, UNITS_NONE, REG_SZ, DT_DIR_PATH, 4, 10*1024, 4, EVENT_FRS_NONE, NULL, FKC_SET_N_REPLICA_SET_STAGE, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT | FRS_RKF_SYNTAX_CHECK},
// The replica set type code. ( SYSVOL, DFS, ...)
// Replica Sets\Guid\Replica Set Type
{FRS_RKEY_SET_N, REPLICA_SET_TYPE, UNITS_NONE, REG_SZ, DT_UNICODE, 2, 1024, 0, EVENT_FRS_NONE, NULL, FKC_SET_N_REPLICA_SET_TYPE, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT},
// The directory filter exclusion list. Default: None
// Don't supply a default here. See FRS_DS_COMPOSE_FILTER_LIST for why.
{FRS_RKEY_SET_N, L"Directory Exclusion Filter List", UNITS_NONE, REG_SZ, DT_FILE_LIST, 0, 0, 0, EVENT_FRS_BAD_REG_DATA, NULL, FKC_SET_N_DIR_EXCL_FILTER_LIST, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_SYNTAX_CHECK | FRS_RKF_READ_AT_POLL},
// The directory filter inclusion list. Default: None
{FRS_RKEY_SET_N, L"Directory Inclusion Filter List", UNITS_NONE, REG_SZ, DT_FILE_LIST, 0, 0, 0, EVENT_FRS_BAD_REG_DATA, NULL, FKC_SET_N_DIR_INCL_FILTER_LIST, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_SYNTAX_CHECK | FRS_RKF_CREATE_KEY | FRS_RKF_OK_TO_USE_DEFAULT | FRS_RKF_READ_AT_POLL},
// The file filter exclusion list.
// Don't supply a default here. See FRS_DS_COMPOSE_FILTER_LIST for why.
{FRS_RKEY_SET_N, L"File Exclusion Filter List", UNITS_NONE, REG_SZ, DT_FILE_LIST, 0, 0, 0, EVENT_FRS_BAD_REG_DATA, NULL, FKC_SET_N_FILE_EXCL_FILTER_LIST, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_READ_AT_POLL},
// The file filter inclusion list. Default: ~clbcatq.*
{FRS_RKEY_SET_N, L"File Inclusion Filter List", UNITS_NONE, REG_SZ, DT_FILE_LIST, 0, 0, 0, EVENT_FRS_BAD_REG_DATA, L"~clbcatq.*", FKC_SET_N_FILE_INCL_FILTER_LIST, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_SYNTAX_CHECK | FRS_RKF_CREATE_KEY | FRS_RKF_OK_TO_USE_DEFAULT | FRS_RKF_READ_AT_POLL},
// The tombstone state of this replica set.
// Replica Sets\Guid\Replica Set Tombstoned
{FRS_RKEY_SET_N, REPLICA_SET_TOMBSTONED, UNITS_NONE, REG_DWORD, DT_BOOL, 0, 1, 0, EVENT_FRS_NONE, NULL, FKC_SET_N_REPLICA_SET_TOMBSTONED, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT},
// The operation to perform on the replica set.
// Replica Sets\Guid\Replica Set Command
{FRS_RKEY_SET_N, REPLICA_SET_COMMAND, UNITS_NONE, REG_SZ, DT_UNICODE, 2, 1024, 0, EVENT_FRS_NONE, NULL, FKC_SET_N_REPLICA_SET_COMMAND, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT},
// If TRUE this is the first member of a replica set and we init the DB
// with the contents of the replica tree.
// Replica Sets\Guid\Replica Set Primary
{FRS_RKEY_SET_N, REPLICA_SET_PRIMARY, UNITS_NONE, REG_DWORD, DT_BOOL, 0, 1, 0, EVENT_FRS_NONE, NULL, FKC_SET_N_REPLICA_SET_PRIMARY, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT},
// LDAP error Status return if we have a problem creating sysvol.
// Replica Sets\Guid\Replica Set Status
{FRS_RKEY_SET_N, REPLICA_SET_STATUS, UNITS_NONE, REG_DWORD, DT_ULONG, 0, MAXLONG, 0, EVENT_FRS_NONE, NULL, FKC_SET_N_REPLICA_SET_STATUS, FRS_RKF_READ_AT_START},
// Cumulative Replica Sets *NOTE* This is a key def only.
{FRS_RKEY_CUM_SET_SECTION, L"*KeyOnly*", UNITS_NONE, REG_SZ, DT_UNICODE, 0, MAXLONG, 0, EVENT_FRS_NONE, NULL, FKC_CUMSET_SECTION_KEY, 0},
// Number of inbound and outbound partners for this replica set.
// Cumulative Replica Sets\Guid\Number Of Partners
{FRS_RKEY_CUM_SET_N, L"Number Of Partners", UNITS_NONE, REG_DWORD, DT_ULONG, 0, MAXLONG, 0, EVENT_FRS_NONE, NULL, FKC_CUMSET_N_NUMBER_OF_PARTNERS, FRS_RKF_READ_AT_START},
// Backup / Restore flags for this replica set.
// Cumulative Replica Sets\Guid\BurFlags
{FRS_RKEY_CUM_SET_N, FRS_VALUE_BURFLAGS, UNITS_NONE, REG_DWORD, DT_ULONG, 0, MAXLONG, 0, EVENT_FRS_NONE, NULL, FKC_CUMSET_N_BURFLAGS, FRS_RKF_READ_AT_START},
/******************************************************************************
******************************************************************************* ** ** ** S y s t e m V o l u m e R e l a t e d K e y s ** ** ** ** ** ******************************************************************************* ******************************************************************************/
#define FRS_RKEY_SYSVOL_SET_N FRS_CONFIG_SECTION L",SysVol,ARG1"
#define FRS_RKEY_SYSVOL_SEED_N FRS_CONFIG_SECTION L",SysVol Seeding,ARG1"
#define FRS_RKEY_SYSVOL_SEEDING_SECTION FRS_CONFIG_SECTION L",SysVol Seeding"
//
// No event log messages are generated for these keys since currently
// they are only created by the service or NTFRSAPI so if they get
// fouled up there is nothing the USER can do to correct the problem.
//
// TRUE if sysvol is ready. Notifies NetLogon to publish computer as a DC.
// Netlogon\\Parameters\SysvolReady
{NETLOGON_SECTION, SYSVOL_READY, UNITS_NONE, REG_DWORD, DT_BOOL, 0, 1, 0, EVENT_FRS_NONE, NULL, FKC_SYSVOL_READY, FRS_RKF_READ_AT_START},
// SysVol Section *NOTE* THis is a key only. It has no value.
{FRS_SYSVOL_SECTION, L"*KeyOnly*", UNITS_NONE, REG_SZ, DT_UNICODE, 2, 10*1024, 0, EVENT_FRS_NONE, NULL, FKC_SYSVOL_SECTION_KEY, 0},
// TRUE if sysvol data is all present in registry.
// Tells us that DCPromo completed.
// NtFrs\Parameters\SysVol\SysVol Information is Committed
{FRS_SYSVOL_SECTION, SYSVOL_INFO_IS_COMMITTED, UNITS_NONE, REG_DWORD, DT_BOOL, 0, 1, 0, EVENT_FRS_NONE, NULL, FKC_SYSVOL_INFO_COMMITTED, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT},
//
// Note that the following keys are a repeat of those in the "Per-Replica
// set" section above except the Key location in the registry is
// FRS_CONFIG_SECTION\SysVol instead of FRS_CONFIG_SECTION\Replica Sets
// unfortunate but something more to clean up later perhaps with a
// second parameter (ARG2).
//
// SysVol\<Guid>\Replica Set Name
{FRS_RKEY_SYSVOL_SET_N, REPLICA_SET_NAME, UNITS_NONE, REG_SZ, DT_UNICODE, 4, 512, 0, EVENT_FRS_NONE, NULL, FKC_SET_N_SYSVOL_NAME, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT},
// The root of the replica tree.
// SysVol\<Guid>\Replica Set Root
{FRS_RKEY_SYSVOL_SET_N, REPLICA_SET_ROOT, UNITS_NONE, REG_SZ, DT_DIR_PATH, 4, 10*1024, 4, EVENT_FRS_NONE, NULL, FKC_SET_N_SYSVOL_ROOT, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT | FRS_RKF_SYNTAX_CHECK},
// The staging area for this replica set.
// SysVol\<Guid>\Replica Set Stage
{FRS_RKEY_SYSVOL_SET_N, REPLICA_SET_STAGE, UNITS_NONE, REG_SZ, DT_DIR_PATH, 4, 10*1024, 4, EVENT_FRS_NONE, NULL, FKC_SET_N_SYSVOL_STAGE, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT | FRS_RKF_SYNTAX_CHECK},
// The replica set type code. ( SYSVOL, DFS, ...)
// SysVol\<Guid>\Replica Set Type
{FRS_RKEY_SYSVOL_SET_N, REPLICA_SET_TYPE, UNITS_NONE, REG_SZ, DT_UNICODE, 2, 1024, 0, EVENT_FRS_NONE, NULL, FKC_SET_N_SYSVOL_TYPE, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT},
// The directory filter exclusion list. Default: None
// Don't supply a default here. See FRS_DS_COMPOSE_FILTER_LIST for why.
{FRS_RKEY_SYSVOL_SET_N, L"Directory Exclusion Filter List", UNITS_NONE, REG_SZ, DT_FILE_LIST, 0, 0, 0, EVENT_FRS_BAD_REG_DATA, NULL, FKC_SET_N_SYSVOL_DIR_EXCL_FILTER_LIST, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_SYNTAX_CHECK | FRS_RKF_READ_AT_POLL},
// The directory filter inclusion list. Default: None
{FRS_RKEY_SYSVOL_SET_N, L"Directory Inclusion Filter List", UNITS_NONE, REG_SZ, DT_FILE_LIST, 0, 0, 0, EVENT_FRS_BAD_REG_DATA, NULL, FKC_SET_N_SYSVOL_DIR_INCL_FILTER_LIST, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_SYNTAX_CHECK | FRS_RKF_CREATE_KEY | FRS_RKF_OK_TO_USE_DEFAULT | FRS_RKF_READ_AT_POLL},
// The file filter exclusion list.
// Don't supply a default here. See FRS_DS_COMPOSE_FILTER_LIST for why.
{FRS_RKEY_SYSVOL_SET_N, L"File Exclusion Filter List", UNITS_NONE, REG_SZ, DT_FILE_LIST, 0, 0, 0, EVENT_FRS_BAD_REG_DATA, NULL, FKC_SET_N_SYSVOL_FILE_EXCL_FILTER_LIST, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_READ_AT_POLL},
// The file filter inclusion list. Default: ~clbcatq.*
{FRS_RKEY_SYSVOL_SET_N, L"File Inclusion Filter List", UNITS_NONE, REG_SZ, DT_FILE_LIST, 0, 0, 0, EVENT_FRS_BAD_REG_DATA, L"~clbcatq.*", FKC_SET_N_SYSVOL_FILE_INCL_FILTER_LIST, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_SYNTAX_CHECK | FRS_RKF_CREATE_KEY | FRS_RKF_OK_TO_USE_DEFAULT | FRS_RKF_READ_AT_POLL},
// The operation to perform on the replica set.
// SysVol\<Guid>\Replica Set Command
{FRS_RKEY_SYSVOL_SET_N, REPLICA_SET_COMMAND, UNITS_NONE, REG_SZ, DT_UNICODE, 2, 1024, 0, EVENT_FRS_NONE, NULL, FKC_SET_N_SYSVOL_COMMAND, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT},
// The RPC binding string for the parent computer to seed from.
// SysVol\<Guid>\Replica Set Parent
{FRS_RKEY_SYSVOL_SET_N, REPLICA_SET_PARENT, UNITS_NONE, REG_SZ, DT_UNICODE, 2, 10*1024, 0, EVENT_FRS_NONE, NULL, FKC_SET_N_SYSVOL_PARENT, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT},
// If TRUE this is the first member of a replica set and we init the DB
// with the contents of the replica tree.
// SysVol\<Guid>\Replica Set Primary
{FRS_RKEY_SYSVOL_SET_N, REPLICA_SET_PRIMARY, UNITS_NONE, REG_DWORD, DT_BOOL, 0, 1, 0, EVENT_FRS_NONE, NULL, FKC_SET_N_SYSVOL_PRIMARY, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT},
// LDAP error Status return if we have a problem creating sysvol.
// SysVol\<Guid>\Replica Set Status
{FRS_RKEY_SYSVOL_SET_N, REPLICA_SET_STATUS, UNITS_NONE, REG_DWORD, DT_ULONG, 0, MAXLONG, 0, EVENT_FRS_NONE, NULL, FKC_SET_N_SYSVOL_STATUS, FRS_RKF_READ_AT_START},
// The RPC binding string for the parent computer to seed from.
// SysVol Seeding\ReplicaSetName(ARG1)\Replica Set Parent
{FRS_RKEY_SYSVOL_SEED_N, REPLICA_SET_PARENT, UNITS_NONE, REG_SZ, DT_UNICODE, 2, 10*1024, 0, EVENT_FRS_NONE, NULL, FKC_SYSVOL_SEEDING_N_PARENT, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT},
// SysVol Seeding\ReplicaSetName(ARG1)\Replica Set Name
{FRS_RKEY_SYSVOL_SEED_N, REPLICA_SET_NAME, UNITS_NONE, REG_SZ, DT_UNICODE, 2, 10*1024, 0, EVENT_FRS_NONE, NULL, FKC_SYSVOL_SEEDING_N_RSNAME, FRS_RKF_READ_AT_START | FRS_RKF_RANGE_CHECK | FRS_RKF_VALUE_MUST_BE_PRESENT},
// SysVol Seeding *NOTE* THis is a key only. It has no value.
{FRS_RKEY_SYSVOL_SEEDING_SECTION, L"*KeyOnly*", UNITS_NONE, REG_SZ, DT_UNICODE, 2, 10*1024, 0, EVENT_FRS_NONE, NULL, FKC_SYSVOL_SEEDING_SECTION_KEY, 0},
/******************************************************************************
******************************************************************************* ** ** ** E v e n t L o g g i n g C o n f i g K e y s ** ** ** ** ** ******************************************************************************* ******************************************************************************/
#define FRS_RKEY_EVENTLOG EVENTLOG_ROOT L",ARG1"
#define FRS_RKEY_EVENTLOG_SOURCE EVENTLOG_ROOT L"," SERVICE_LONG_NAME L",ARG1"
// EventLog\File Replication Service\File
{FRS_RKEY_EVENTLOG, L"File", UNITS_NONE, REG_EXPAND_SZ, DT_FILENAME, 4, 0, 0, EVENT_FRS_NONE, L"%SystemRoot%\\system32\\config\\NtFrs.Evt", FKC_EVENTLOG_FILE, FRS_RKF_READ_AT_START | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// EventLog\File Replication Service\DisplayNameFile
{FRS_RKEY_EVENTLOG, L"DisplayNameFile", UNITS_NONE, REG_EXPAND_SZ, DT_FILENAME, 4, 0, 0, EVENT_FRS_NONE, L"%SystemRoot%\\system32\\els.dll", FKC_EVENTLOG_DISPLAY_FILENAME,FRS_RKF_READ_AT_START | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// EventLog\File Replication Service\EventMessageFile
// EventLog\NTFRS\EventMessageFile
// Default value: "%SystemRoot%\system32\ntfrsres.dll"
{FRS_RKEY_EVENTLOG_SOURCE, L"EventMessageFile", UNITS_NONE, REG_EXPAND_SZ, DT_FILENAME, 4, 0, 0, EVENT_FRS_NONE, DEFAULT_MESSAGE_FILE_PATH, FKC_EVENTLOG_EVENT_MSG_FILE, FRS_RKF_READ_AT_START | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// EventLog\File Replication Service\Sources
{FRS_RKEY_EVENTLOG, L"Sources", UNITS_NONE, REG_MULTI_SZ, DT_UNICODE, 4, 0, 0, EVENT_FRS_NONE, (SERVICE_NAME L"\0" SERVICE_LONG_NAME L"\0"), FKC_EVENTLOG_SOURCES, FRS_RKF_READ_AT_START | FRS_RKF_CREATE_KEY | FRS_RKF_OK_TO_USE_DEFAULT},
// EventLog\File Replication Service\Retention
{FRS_RKEY_EVENTLOG, L"Retention", UNITS_NONE, REG_DWORD, DT_ULONG, 0, MAXLONG, 0, EVENT_FRS_BAD_REG_DATA, NULL, FKC_EVENTLOG_RETENTION, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_CREATE_KEY | FRS_RKF_OK_TO_USE_DEFAULT},
// EventLog\File Replication Service\MaxSize
{FRS_RKEY_EVENTLOG, L"MaxSize", UNITS_NONE, REG_DWORD, DT_ULONG, 0, MAXLONG, 0x80000, EVENT_FRS_BAD_REG_DATA, NULL, FKC_EVENTLOG_MAXSIZE, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_CREATE_KEY | FRS_RKF_OK_TO_USE_DEFAULT},
// EventLog\File Replication Service\DisplayNameID
{FRS_RKEY_EVENTLOG, L"DisplayNameID", UNITS_NONE, REG_DWORD, DT_ULONG, 0, MAXLONG, 259, EVENT_FRS_NONE, NULL, FKC_EVENTLOG_DISPLAY_NAMEID, FRS_RKF_READ_AT_START | FRS_RKF_CREATE_KEY | FRS_RKF_OK_TO_USE_DEFAULT},
// EventLog\File Replication Service\CustomSD
// CustomSD that is used to protect the FRS log. It is essentially the default SD
// that is used to protect the custom logs, with "restrict guest access" option.
// The following permission bits are in use:
// READ=0x1, WRITE=0x2, CLEAR=0x4, BACKUP=0x20
//
// The SD is as follows:
// Owner/Group = Local system
// DACL:
// Deny: Full control, Anonymous
// Deny: Full control, Domain Guests
// Allow: Full control, Local system
// Allow: Read|Clear, Builtin Admins
// Allow: Backup, Backup operators
// Allow: Read|Clear, System operators
// Allow: Read, Everyone
// Allow: Write, Local service
// Allow: Write, Network service
//
// The resultant string is: O:SYG:SYD:(D;;0x27;;;AN)(D;;0x27;;;DG)(A;;0x27;;;SY)(A;;0x5;;;BA)(A;;0x20;;;BO)(A;;0x5;;;SO)(A;;0x1;;;WD)(A;;0x2;;;LS)(A;;0x2;;;NS)
{FRS_RKEY_EVENTLOG, L"CustomSD", UNITS_NONE, REG_EXPAND_SZ, DT_UNICODE, 4, 0, 0, EVENT_FRS_NONE, L"O:SYG:SYD:(D;;0x27;;;AN)(D;;0x27;;;DG)(A;;0x27;;;SY)(A;;0x5;;;BA)(A;;0x20;;;BO)(A;;0x5;;;SO)(A;;0x1;;;WD)(A;;0x2;;;LS)(A;;0x2;;;NS)", FKC_EVENTLOG_CUSTOM_SD,FRS_RKF_READ_AT_START | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_OK_TO_USE_DEFAULT},
// EventLog\File Replication Service\TypesSupported
{FRS_RKEY_EVENTLOG_SOURCE, L"TypesSupported", UNITS_NONE, REG_DWORD, DT_ULONG, 0, MAXLONG, FRS_EVENT_TYPES, EVENT_FRS_NONE, NULL, FKC_EVENTLOG_TYPES_SUPPORTED, FRS_RKF_READ_AT_START | FRS_RKF_CREATE_KEY | FRS_RKF_OK_TO_USE_DEFAULT},
/******************************************************************************
******************************************************************************* ** ** ** F R S A P I A c c e s s C h e c k K e y s ** ** ** ** ** ******************************************************************************* ******************************************************************************/
#define FRS_RKEY_ACCCHK_PERFMON \
FRS_CONFIG_SECTION L",Access Checks," ACK_COLLECT_PERFMON_DATA
// Access Checks\Get Perfmon Data\Access checks are [Enabled or Disabled]
{FRS_RKEY_ACCCHK_PERFMON, ACCESS_CHECKS_ARE, UNITS_NONE, REG_SZ, DT_ACCESS_CHK, 2, 200, 0, EVENT_FRS_BAD_REG_DATA, ACCESS_CHECKS_ARE_DEFAULT_ENABLED, FKC_ACCCHK_PERFMON_ENABLE, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_RANGE_CHECK},
// Access Checks\Get Perfmon Data\Access checks require [Full Control or Read]
{FRS_RKEY_ACCCHK_PERFMON, ACCESS_CHECKS_REQUIRE, UNITS_NONE, REG_SZ, DT_ACCESS_CHK, 2, 200, 0, EVENT_FRS_BAD_REG_DATA, ACCESS_CHECKS_REQUIRE_DEFAULT_READ, FKC_ACCCHK_PERFMON_RIGHTS, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_RANGE_CHECK},
#define FRS_RKEY_ACCCHK_GETDS_POLL \
FRS_CONFIG_SECTION L",Access Checks," ACK_GET_DS_POLL
// Access Checks\Get Ds Polling Interval\Access checks are [Enabled or Disabled]
{FRS_RKEY_ACCCHK_GETDS_POLL, ACCESS_CHECKS_ARE, UNITS_NONE, REG_SZ, DT_ACCESS_CHK, 2, 200, 0, EVENT_FRS_BAD_REG_DATA, ACCESS_CHECKS_ARE_DEFAULT_ENABLED, FKC_ACCCHK_GETDS_POLL_ENABLE, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_RANGE_CHECK},
// Access Checks\Get Ds Polling Interval\Access checks require [Full Control or Read]
{FRS_RKEY_ACCCHK_GETDS_POLL, ACCESS_CHECKS_REQUIRE, UNITS_NONE, REG_SZ, DT_ACCESS_CHK, 2, 200, 0, EVENT_FRS_BAD_REG_DATA, ACCESS_CHECKS_REQUIRE_DEFAULT_READ, FKC_ACCCHK_GETDS_POLL_RIGHTS, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_RANGE_CHECK},
#define FRS_RKEY_ACCCHK_GET_INFO \
FRS_CONFIG_SECTION L",Access Checks," ACK_INTERNAL_INFO
// Access Checks\Get Internal Information\Access checks are [Enabled or Disabled]
{FRS_RKEY_ACCCHK_GET_INFO, ACCESS_CHECKS_ARE, UNITS_NONE, REG_SZ, DT_ACCESS_CHK, 2, 200, 0, EVENT_FRS_BAD_REG_DATA, ACCESS_CHECKS_ARE_DEFAULT_ENABLED, FKC_ACCCHK_GET_INFO_ENABLE, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_RANGE_CHECK},
// Access Checks\Get Internal Information\Access checks require [Full Control or Read]
{FRS_RKEY_ACCCHK_GET_INFO, ACCESS_CHECKS_REQUIRE, UNITS_NONE, REG_SZ, DT_ACCESS_CHK, 2, 200, 0, EVENT_FRS_BAD_REG_DATA, ACCESS_CHECKS_REQUIRE_DEFAULT_WRITE, FKC_ACCCHK_GET_INFO_RIGHTS, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_RANGE_CHECK},
#define FRS_RKEY_ACCCHK_SETDS_POLL \
FRS_CONFIG_SECTION L",Access Checks," ACK_SET_DS_POLL
// Access Checks\set Ds Polling Interval\Access checks are [Enabled or Disabled]
{FRS_RKEY_ACCCHK_SETDS_POLL, ACCESS_CHECKS_ARE, UNITS_NONE, REG_SZ, DT_ACCESS_CHK, 2, 200, 0, EVENT_FRS_BAD_REG_DATA, ACCESS_CHECKS_ARE_DEFAULT_ENABLED, FKC_ACCCHK_SETDS_POLL_ENABLE, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_RANGE_CHECK},
// Access Checks\Set Ds Polling Interval\Access checks require [Full Control or Read]
{FRS_RKEY_ACCCHK_SETDS_POLL, ACCESS_CHECKS_REQUIRE, UNITS_NONE, REG_SZ, DT_ACCESS_CHK, 2, 200, 0, EVENT_FRS_BAD_REG_DATA, ACCESS_CHECKS_REQUIRE_DEFAULT_WRITE, FKC_ACCCHK_SETDS_POLL_RIGHTS, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_RANGE_CHECK},
#define FRS_RKEY_ACCCHK_STARTDS_POLL \
FRS_CONFIG_SECTION L",Access Checks," ACK_START_DS_POLL
// Access Checks\Start Ds Polling\Access checks are [Enabled or Disabled]
{FRS_RKEY_ACCCHK_STARTDS_POLL, ACCESS_CHECKS_ARE, UNITS_NONE, REG_SZ, DT_ACCESS_CHK, 2, 200, 0, EVENT_FRS_BAD_REG_DATA, ACCESS_CHECKS_ARE_DEFAULT_ENABLED, FKC_ACCCHK_STARTDS_POLL_ENABLE, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_RANGE_CHECK},
// Access Checks\Start Ds Polling\Access checks require [Full Control or Read]
{FRS_RKEY_ACCCHK_STARTDS_POLL, ACCESS_CHECKS_REQUIRE, UNITS_NONE, REG_SZ, DT_ACCESS_CHK, 2, 200, 0, EVENT_FRS_BAD_REG_DATA, ACCESS_CHECKS_REQUIRE_DEFAULT_READ, FKC_ACCCHK_STARTDS_POLL_RIGHTS, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_RANGE_CHECK},
#define FRS_RKEY_ACCCHK_DCPROMO \
FRS_CONFIG_SECTION L",Access Checks," ACK_DCPROMO
// Access Checks\dcpromo\Access checks are [Enabled or Disabled]
{FRS_RKEY_ACCCHK_DCPROMO, ACCESS_CHECKS_ARE, UNITS_NONE, REG_SZ, DT_ACCESS_CHK, 2, 200, 0, EVENT_FRS_BAD_REG_DATA, ACCESS_CHECKS_ARE_DEFAULT_ENABLED, FKC_ACCESS_CHK_DCPROMO_ENABLE, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_RANGE_CHECK},
// Access Checks\dcpromo\Access checks require [Full Control or Read]
{FRS_RKEY_ACCCHK_DCPROMO, ACCESS_CHECKS_REQUIRE, UNITS_NONE, REG_SZ, DT_ACCESS_CHK, 2, 200, 0, EVENT_FRS_BAD_REG_DATA, ACCESS_CHECKS_REQUIRE_DEFAULT_WRITE, FKC_ACCESS_CHK_DCPROMO_RIGHTS, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_RANGE_CHECK},
#define FRS_RKEY_ACCCHK_IS_PATH_REPLICATED \
FRS_CONFIG_SECTION L",Access Checks," ACK_IS_PATH_REPLICATED
// Access Checks\Is Path Replicated\Access checks are [Enabled or Disabled]
{FRS_RKEY_ACCCHK_IS_PATH_REPLICATED, ACCESS_CHECKS_ARE, UNITS_NONE, REG_SZ, DT_ACCESS_CHK, 2, 200, 0, EVENT_FRS_BAD_REG_DATA, ACCESS_CHECKS_ARE_DEFAULT_ENABLED, FKC_ACCESS_CHK_IS_PATH_REPLICATED_ENABLE, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_RANGE_CHECK},
// Access Checks\Is Path Replicated\Access checks require [Full Control or Read]
{FRS_RKEY_ACCCHK_IS_PATH_REPLICATED, ACCESS_CHECKS_REQUIRE, UNITS_NONE, REG_SZ, DT_ACCESS_CHK, 2, 200, 0, EVENT_FRS_BAD_REG_DATA, ACCESS_CHECKS_REQUIRE_DEFAULT_READ, FKC_ACCESS_CHK_IS_PATH_REPLICATED_RIGHTS, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_RANGE_CHECK},
#define FRS_RKEY_ACCCHK_WRITER_COMMANDS \
FRS_CONFIG_SECTION L",Access Checks," ACK_WRITER_COMMANDS
// Access Checks\Writer Commands\Access checks are [Enabled or Disabled]
{FRS_RKEY_ACCCHK_WRITER_COMMANDS, ACCESS_CHECKS_ARE, UNITS_NONE, REG_SZ, DT_ACCESS_CHK, 2, 200, 0, EVENT_FRS_BAD_REG_DATA, ACCESS_CHECKS_ARE_DEFAULT_ENABLED, FKC_ACCESS_CHK_WRITER_COMMANDS_ENABLE, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_RANGE_CHECK},
// Access Checks\Writer Commands\Access checks require [Full Control or Read]
{FRS_RKEY_ACCCHK_WRITER_COMMANDS, ACCESS_CHECKS_REQUIRE, UNITS_NONE, REG_SZ, DT_ACCESS_CHK, 2, 200, 0, EVENT_FRS_BAD_REG_DATA, ACCESS_CHECKS_REQUIRE_DEFAULT_WRITE, FKC_ACCESS_CHK_WRITER_COMMANDS_RIGHTS, FRS_RKF_READ_AT_START | FRS_RKF_LOG_EVENT | FRS_RKF_CREATE_KEY | FRS_RKF_SYNTAX_CHECK | FRS_RKF_RANGE_CHECK},
/******************************************************************************
******************************************************************************* ** ** ** F R S B a c k u p / R e s t o r e R e l a t e d K e y s ** ** ** ** ** ******************************************************************************* ******************************************************************************/
//
// No event log messages are generated for these keys since currently
// they are only created by the service or NTFRSAPI so if they get
// fouled up there is nothing the USER can do to correct the problem.
//
#define FRS_RKEY_BACKUP_STARTUP_SET_N_SECTION FRS_BACKUP_RESTORE_MV_SETS_SECTION L",ARG1"
/*
Used in NtfrsApi.c to pass to backup/restore.
#define FRS_NEW_FILES_NOT_TO_BACKUP L"SYSTEM\\CurrentControlSet\\Control\\BackupRestore\\FilesNotToBackup"
FRS_NEW_FILES_NOT_TO_BACKUP REG_MULTI_SZ key
#define FRS_OLD_FILES_NOT_TO_BACKUP L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FilesNotToBackup"
FRS_OLD_FILES_NOT_TO_BACKUP REG_MULTI_SZ key
*/
// Backup/Restore
// *NOTE* THis is a key only. It has no value.
{FRS_BACKUP_RESTORE_SECTION, L"*KeyOnly*", UNITS_NONE, REG_SZ, DT_UNICODE, 2, 10*1024, 0, EVENT_FRS_NONE, NULL, FKC_BKUP_SECTION_KEY, 0},
// Backup/Restore\\Stop NtFrs from Starting
// *NOTE* THis is a key only. It has no value.
{FRS_BACKUP_RESTORE_STOP_SECTION, L"*KeyOnly*", UNITS_NONE, REG_SZ, DT_UNICODE, 2, 10*1024, 0, EVENT_FRS_NONE, NULL, FKC_BKUP_STOP_SECTION_KEY, 0},
// Backup/Restore\Process at Startup\Replica Sets
// *NOTE* THis is a key only. It has no value.
{FRS_BACKUP_RESTORE_MV_SETS_SECTION, L"*KeyOnly*", UNITS_NONE, REG_SZ, DT_UNICODE, 2, 10*1024, 0, EVENT_FRS_NONE, NULL, FKC_BKUP_MV_SETS_SECTION_KEY, 0},
// Backup/Restore\Process at Startup\Cumulative Replica Sets
// *NOTE* THis is a key only. It has no value.
{FRS_BACKUP_RESTORE_MV_CUMULATIVE_SETS_SECTION, L"*KeyOnly*", UNITS_NONE, REG_SZ, DT_UNICODE, 2, 10*1024, 0, EVENT_FRS_NONE, NULL, FKC_BKUP_MV_CUMSETS_SECTION_KEY, 0},
// Global Backup / Restore flags.
// backup/restore\Process at Startup\BurFlags
{FRS_BACKUP_RESTORE_MV_SECTION, FRS_VALUE_BURFLAGS, UNITS_NONE, REG_DWORD, DT_ULONG, 0, MAXLONG, NTFRSAPI_BUR_FLAGS_NONE, EVENT_FRS_NONE, NULL, FKC_BKUP_STARTUP_GLOBAL_BURFLAGS, FRS_RKF_READ_AT_START | FRS_RKF_OK_TO_USE_DEFAULT},
// Backup / Restore flags for this replica set in "Process at Startup"
// backup/restore\Process at Startup\Replica Sets\<guid>\BurFlags
{FRS_RKEY_BACKUP_STARTUP_SET_N_SECTION, FRS_VALUE_BURFLAGS, UNITS_NONE, REG_DWORD, DT_ULONG, 0, MAXLONG, 0, EVENT_FRS_NONE, NULL, FKC_BKUP_STARTUP_SET_N_BURFLAGS, FRS_RKF_READ_AT_START},
/******************************************************************************
******************************************************************************* ** ** ** F R S P E R F M O N R e l a t e d K e y s ** ** ** ** ** ******************************************************************************* ******************************************************************************/
//
// No event log messages are generated for these keys since currently
// they are only created by the service so if they get
// fouled up there is nothing the USER can do to correct the problem.
//
//
// Note: We can't really use thes yet since some of them are in the DLL
// which doesn't link with this module. Also some are MULTI_SZ which
// needs more work in CfgRegReadString and writestring.
#define FRS_RKEY_REPLICA_SET_PERFMON \
L"SYSTEM\\CurrentControlSet\\Services\\FileReplicaSet\\Performance"
#define FRS_RKEY_REPLICA_SET_PERF_LINKAGE \
L"SYSTEM\\CurrentControlSet\\Services\\FileReplicaSet\\Linkage"
#define FRS_RKEY_CXTION_PERFMON \
L"SYSTEM\\CurrentControlSet\\Services\\FileReplicaConn\\Performance"
#define FRS_RKEY_CXTION_PERF_LINKAGE \
L"SYSTEM\\CurrentControlSet\\Services\\FileReplicaConn\\Linkage"
// FileReplicaSet\\Performance\First Counter
{FRS_RKEY_REPLICA_SET_PERFMON, L"First Counter", UNITS_NONE, REG_DWORD, DT_ULONG, 0, MAXLONG, 0, EVENT_FRS_NONE, NULL, FKC_REPLICA_SET_FIRST_CTR, FRS_RKF_READ_AT_START},
// FileReplicaSet\\Performance\First Help
{FRS_RKEY_REPLICA_SET_PERFMON, L"First Help", UNITS_NONE, REG_DWORD, DT_ULONG, 0, MAXLONG, 0, EVENT_FRS_NONE, NULL, FKC_REPLICA_SET_FIRST_HELP, FRS_RKF_READ_AT_START},
// FileReplicaSet\\Linkage\Export
{FRS_RKEY_REPLICA_SET_PERF_LINKAGE, L"Export", UNITS_NONE, REG_MULTI_SZ, DT_UNICODE, 0, MAXLONG, 0, EVENT_FRS_NONE, NULL, FKC_REPLICA_SET_LINKAGE_EXPORT, FRS_RKF_READ_AT_START},
// FileReplicaConn\\Performance\First Counter
{FRS_RKEY_CXTION_PERFMON, L"First Counter", UNITS_NONE, REG_DWORD, DT_ULONG, 0, MAXLONG, 0, EVENT_FRS_NONE, NULL, FKC_REPLICA_CXTION_FIRST_CTR, FRS_RKF_READ_AT_START},
// FileReplicaConn\\Performance\First Help
{FRS_RKEY_CXTION_PERFMON, L"First Help", UNITS_NONE, REG_DWORD, DT_ULONG, 0, MAXLONG, 0, EVENT_FRS_NONE, NULL, FKC_REPLICA_CXTION_FIRST_HELP, FRS_RKF_READ_AT_START},
// FileReplicaConn\\Linkage\Export
{FRS_RKEY_CXTION_PERF_LINKAGE, L"Export", UNITS_NONE, REG_MULTI_SZ, DT_UNICODE, 0, MAXLONG, 0, EVENT_FRS_NONE, NULL, FKC_REPLICA_CXTION_LINKAGE_EXPORT, FRS_RKF_READ_AT_START},
#define FRS_RKEY_REPARSE_TAG \
FRS_REPARSE_TAG_SECTION L",ARG1"
// Reparse Tag Section *NOTE* THis is a key only. It has no value.
{FRS_REPARSE_TAG_SECTION, L"*KeyOnly*", UNITS_NONE, REG_SZ, DT_UNICODE, 2, 10*1024, 0, EVENT_FRS_NONE, NULL, FKC_REPARSE_TAG_KEY, 0},
//
{FRS_RKEY_REPARSE_TAG, L"Reparse Tag Type", UNITS_NONE, REG_DWORD, DT_ULONG, 0, MAXLONG, 0, EVENT_FRS_NONE, NULL, FKC_REPARSE_TAG_TYPE, FRS_RKF_READ_AT_START},
{FRS_RKEY_REPARSE_TAG, L"Data to Replicate [None or File Data or Reparse Point]", UNITS_NONE, REG_SZ, DT_UNICODE, 0, 0, 0, EVENT_FRS_NONE, NULL, FKC_REPARSE_TAG_REPLICATION_TYPE, FRS_RKF_READ_AT_START},
{L"End of table", NULL, UNITS_NONE, REG_SZ, DT_UNSPECIFIED, 0, 0, 0, EVENT_FRS_NONE, NULL, FKC_END_OF_TABLE, 0}
}; // End of FrsRegistryKeyTable
PFRS_REGISTRY_KEY FrsRegFindKeyContext( IN FRS_REG_KEY_CODE KeyIndex ) { /*++
Routine Description:
This function takes an FRS Registry Key code and returns a pointer to the associated key context data.
Arguments:
KeyIndex - An entry from the FRS_REG_KEY_CODE enum
Return Value:
Ptr to the matching Key context entry or NULL if not found.
--*/ #undef DEBSUB
#define DEBSUB "FrsRegFindKeyContext:"
PFRS_REGISTRY_KEY KeyCtx;
//DPRINT(0, "function entry\n");
FRS_ASSERT((KeyIndex > 0) && (KeyIndex < FRS_REG_KEY_CODE_MAX));
if (KeyIndex >= FRS_REG_KEY_CODE_MAX) { return NULL; }
KeyCtx = FrsRegistryKeyTable;
while (KeyCtx->FrsKeyCode > FKC_END_OF_TABLE) { if (KeyIndex == KeyCtx->FrsKeyCode) { //
// Found it.
//
return KeyCtx; } KeyCtx += 1; }
//
// Not found.
//
return NULL;
}
PWCHAR CfgRegGetValueName( IN FRS_REG_KEY_CODE KeyIndex ) { /*++
Routine Description:
This function returns a ptr to the value name string in the key context. This is NOT a ptr to an allocated string so it should NOT be freed.
Arguments:
KeyIndex - An entry from the FRS_REG_KEY_CODE enum
Return Value:
Ptr to value name string. NULL if KeyIndex lookup fails.
--*/ #undef DEBSUB
#define DEBSUB "CfgRegGetValueName:"
PFRS_REGISTRY_KEY KeyCtx;
//
// Find the key context assoicated with the supplied index.
//
KeyCtx = FrsRegFindKeyContext(KeyIndex); if (KeyCtx == NULL) { DPRINT1(0, ":FK: ERROR - Key contxt not found for key code number %d\n", KeyIndex); return L"<null>"; }
return KeyCtx->ValueName;
}
DWORD FrsRegExpandKeyStr( IN PFRS_REGISTRY_KEY Kc, IN PWCHAR KeyArg1, IN ULONG Flags, OUT PWCHAR *FullKeyStr ) { /*++
Routine Description:
This function only expands a key field in the given KeyContext and returns the result in FullKeyStr. This is used primarily for error messages but is also used to open registry access check keys.
The syntax for the the key field in the KeyContext consists of multiple key components separated by commas. This function splits the key field on the commas. It then opens the leading key followed by either a create or open of each successive component. If a component matches the string L"ARG1" then we substitute the KeyArg1 parameter passed to this function for this key component. Most often this is a stringized guid. For example, the string FRS_RKEY_SET_N is defined as:
FRS_CONFIG_SECTION L",Replica Sets,ARG1"
This will end up opening/creating the following key:
"System\\CurrentControlSet\\Services\\NtFrs\\Parameters\\ Replica Sets\\ 27d6d1c4-d6b8-480b-9f18b5ea390a0178"
assuming the argument passed in was "27d6d1c4-d6b8-480b-9f18b5ea390a0178".
Arguments:
Kc - A ptr to the key context struct for the desired reg key.
KeyArg1 - An optional caller supplied key component. NULL if not provided.
Flags - Modifer flags
FullKeyStr - ptr to return buffer for expanded key string. NOTE: The buffer is allocated here. Caller must free it.
Return Value:
Win32 status of the result of the operation. FullKeyStr is returned NULL if operation fails.
--*/ #undef DEBSUB
#define DEBSUB "FrsRegExpandKeyStr:"
UNICODE_STRING TempUStr, FirstArg;
PWCHAR FullKey = NULL; ULONG Len, FullKeyLen; WCHAR KeyStr[MAX_PATH];
//DPRINT(0, "function entry\n");
*FullKeyStr = NULL;
FullKey = FrsAlloc(FULL_KEY_BUFF_SIZE*sizeof(WCHAR)); FullKey[0] = UNICODE_NULL; FullKeyLen = 1;
//
// If there are any commas in this key then we need to do a nested
// key open (perhaps creating nested keys as we go). If the key
// component matches the string L"ARG1" then we use KeyArg1 supplied by
// the caller.
//
RtlInitUnicodeString(&TempUStr, Kc->KeyName);
//
// Parse the comma list.
//
while (FrsDissectCommaList(TempUStr, &FirstArg, &TempUStr)) {
if ((FirstArg.Length == 0) || (FirstArg.Length >= sizeof(KeyStr))) { DPRINT1(0, ":FK: ERROR - Bad keyName in Key contxt %ws\n", Kc->KeyName); goto ERROR_RETURN; }
//
// null terminate the key component string.
//
CopyMemory(KeyStr, FirstArg.Buffer, FirstArg.Length); KeyStr[FirstArg.Length/sizeof(WCHAR)] = UNICODE_NULL;
//
// Check the Key Component for a match on ARG1 and substitute.
//
if (wcscmp(KeyStr, L"ARG1") == 0) {
if (wcslen(KeyArg1)*sizeof(WCHAR) > sizeof(KeyStr)) { DPRINT1(0, ":FK: ERROR - ARG1 too big %ws\n", KeyArg1); goto ERROR_RETURN; } wcscpy(KeyStr, KeyArg1); }
Len = wcslen(KeyStr); if (FullKeyLen + Len + 1 > FULL_KEY_BUFF_SIZE) { goto ERROR_RETURN; }
if (FullKeyLen > 1) { wcscat(FullKey, L"\\"); FullKeyLen += 1; }
wcscat(FullKey, KeyStr); FullKeyLen += Len;
} // end while()
if (FullKeyLen <= 1) { goto ERROR_RETURN; }
DPRINT1(4, ":FK: Expanded key name is \"%ws\"\n", FullKey);
//
// Return the expanded key to the caller.
//
*FullKeyStr = FullKey;
return ERROR_SUCCESS;
ERROR_RETURN:
DPRINT1(0, ":FK: ERROR - FrsRegExpandKeyStr Failed on %ws", Kc->KeyName);
FrsFree(FullKey);
return ERROR_INVALID_PARAMETER;
}
DWORD FrsRegOpenKey( IN PFRS_REGISTRY_KEY Kc, IN PWCHAR KeyArg1, IN ULONG Flags, OUT PHKEY hKeyRet ) { /*++
Routine Description:
This function opens a registry key and returns a handle.
See FrsRegExpandKeyStr() for a description of the key field syntax.
Arguments:
Kc - A ptr to the key context struct for the desired reg key.
KeyArg1 - An optional caller supplied key component. NULL if not provided.
Flags - Modifer flags FRS_RKF_KEY_ACCCHK_READ means only do a read access check on the key. FRS_RKF_KEY_ACCCHK_WRITE means only do a KEY_ALL_ACCESS access check on the key.
if FRS_RKF_CREATE_KEY is set and FRS_RKF_KEY_MUST_BE_PRESENT is clear and the given key component is not found, this function creates it.
hKeyRet - ptr to HKEY for returned key handle.
Return Value:
Win32 status of the result of the registry operation. hKeyRet is returned only on a success.
--*/ #undef DEBSUB
#define DEBSUB "FrsRegOpenKey:"
UNICODE_STRING TempUStr, FirstArg; ULONG WStatus; PWCHAR FullKey = NULL;
HKEY hKey = HKEY_LOCAL_MACHINE; HKEY hKeyParent = INVALID_HANDLE_VALUE;
ULONG AccessRights; PCHAR AccessName; WCHAR KeyStr[MAX_PATH];
FrsFlagsToStr(Flags, RkfFlagNameTable, sizeof(KeyStr), (PCHAR)KeyStr); DPRINT2(4, ":FK: %ws Caller Flags [%s]\n", Kc->ValueName, (PCHAR)KeyStr); FrsFlagsToStr(Kc->Flags, RkfFlagNameTable, sizeof(KeyStr), (PCHAR)KeyStr); DPRINT2(4, ":FK: %ws KeyCtx Flags [%s]\n", Kc->ValueName, (PCHAR)KeyStr);
//DPRINT(0, "function entry\n");
//
// If this is a call to make a read or write access check then we must
// first build the entire key string and then try the open. The
// caller has done an impersonation.
//
if (BooleanFlagOn(Flags | Kc->Flags, FRS_RKF_KEY_ACCCHK_READ | FRS_RKF_KEY_ACCCHK_WRITE)) {
AccessRights = KEY_READ; AccessName = "KEY_READ";
if (BooleanFlagOn(Flags | Kc->Flags, FRS_RKF_KEY_ACCCHK_WRITE)) { AccessRights = KEY_ALL_ACCESS; AccessName = "KEY_ALL_ACCESS"; }
//
// Expand the key string.
//
FrsRegExpandKeyStr(Kc, KeyArg1, Flags, &FullKey); if (FullKey == NULL) { return ERROR_INVALID_PARAMETER; }
DPRINT2(4, ":FK: Doing Access Check (%s) on key \"%ws\"\n", AccessName, FullKey);
WStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, FullKey, 0, AccessRights, &hKey); if (!WIN_SUCCESS(WStatus)) { DPRINT1_WS(0, ":FK: ERROR - Access Check failed on %ws;", FullKey, WStatus); FrsFree(FullKey); return WStatus; }
//
// Return the key handle to the caller.
//
*hKeyRet = hKey;
FrsFree(FullKey); return ERROR_SUCCESS; }
//
// Not a key access check. Do normal key open processing.
//
//
// If there are any commas in this key then we need to do a nested
// key open (perhaps creating nested keys as we go). If the key
// component matches the string L"ARG1" then we use KeyArg1 supplied by
// the caller.
//
RtlInitUnicodeString(&TempUStr, Kc->KeyName);
//
// Parse the comma list.
//
while (FrsDissectCommaList(TempUStr, &FirstArg, &TempUStr)) {
if ((FirstArg.Length == 0) || (FirstArg.Length >= sizeof(KeyStr))) { DPRINT1(0, ":FK: ERROR - Bad keyName in Key contxt %ws\n", Kc->KeyName); WStatus = ERROR_INVALID_PARAMETER; goto RETURN; }
//
// null terminate the key component string.
//
CopyMemory(KeyStr, FirstArg.Buffer, FirstArg.Length); KeyStr[FirstArg.Length/sizeof(WCHAR)] = UNICODE_NULL;
hKeyParent = hKey; hKey = INVALID_HANDLE_VALUE;
//
// Check the Key Component for a match on ARG1 and substitute.
//
if (wcscmp(KeyStr, L"ARG1") == 0) {
if (wcslen(KeyArg1)*sizeof(WCHAR) > sizeof(KeyStr)) { DPRINT1(0, ":FK: ERROR - ARG1 too big %ws\n", KeyArg1); WStatus = ERROR_INVALID_PARAMETER; goto RETURN; } wcscpy(KeyStr, KeyArg1); }
//
// Open the next key component.
//
DPRINT1(5, ":FK: Opening next key component [%ws]\n", KeyStr); WStatus = RegOpenKeyEx(hKeyParent, KeyStr, 0, KEY_ALL_ACCESS, &hKey); if (!WIN_SUCCESS(WStatus)) {
//
// If the key is supposed to be there then return error to caller.
//
if (BooleanFlagOn(Flags | Kc->Flags, FRS_RKF_KEY_MUST_BE_PRESENT)) { DPRINT1_WS(0, ":FK: Could not open key component [%ws].", KeyStr, WStatus);
FrsRegPostEventLog(Kc, KeyArg1, Flags, IDS_REG_KEY_NOT_FOUND); goto RETURN; }
if (BooleanFlagOn(Flags | Kc->Flags, FRS_RKF_CREATE_KEY)) { //
// Try to create the key.
//
DPRINT1(4, ":FK: Creating key component [%ws]\n", KeyStr); WStatus = RegCreateKeyW(hKeyParent, KeyStr, &hKey); CLEANUP1_WS(0, ":FK: Could not create key component [%ws].", KeyStr, WStatus, RETURN); } else { //
// Key not there and not supposed to create it. Let caller know.
//
goto RETURN; } }
if (hKeyParent != HKEY_LOCAL_MACHINE) { FRS_REG_CLOSE(hKeyParent); } } // end while()
//
// Return the key handle to the caller.
//
*hKeyRet = hKey; WStatus = ERROR_SUCCESS;
RETURN:
if (hKeyParent != HKEY_LOCAL_MACHINE) { FRS_REG_CLOSE(hKeyParent); }
if (!WIN_SUCCESS(WStatus)) { DPRINT_WS(5, "ERROR - FrsRegOpenKey Failed.", WStatus);
if (hKey != HKEY_LOCAL_MACHINE) { FRS_REG_CLOSE(hKey); } }
return WStatus;
}
DWORD CfgRegReadDWord( IN FRS_REG_KEY_CODE KeyIndex, IN PWCHAR KeyArg1, IN ULONG Flags, OUT PULONG DataRet ) { /*++
Routine Description:
This function reads a keyword value from the registry.
Arguments:
KeyIndex - An entry from the FRS_REG_KEY_CODE enum
KeyArg1 - An optional caller supplied key component. NULL if not provided.
Flags - Modifer flags
DataRet - ptr to DWORD for returned result.
Return Value:
Win32 status of the result of the registry operation. Data is returned only on a success.
--*/ #undef DEBSUB
#define DEBSUB "CfgRegReadDWord:"
DWORD WStatus; HKEY hKey = INVALID_HANDLE_VALUE; DWORD Type; DWORD Len; DWORD Data; BOOL DefaultValueUseOk; PFRS_REGISTRY_KEY KeyCtx;
//DPRINT(0, "function entry\n");
//
// Find the key context assoicated with the supplied index.
//
KeyCtx = FrsRegFindKeyContext(KeyIndex); if (KeyCtx == NULL) { DPRINT1(0, ":FK: ERROR - Key contxt not found for key code number %d\n", KeyIndex); return ERROR_INVALID_PARAMETER; }
DefaultValueUseOk = BooleanFlagOn(Flags | KeyCtx->Flags, FRS_RKF_OK_TO_USE_DEFAULT);
FRS_ASSERT(KeyCtx->ValueName != NULL);
DPRINT2(4, ":FK: Reading parameter [%ws] \"%ws\" \n", KeyCtx->KeyName, KeyCtx->ValueName);
//
// Table entry better be REG_DWORD.
//
if (KeyCtx->RegValueType != REG_DWORD) { DPRINT3(4, ":FK: Mismatch on KeyCtx->RegValueType for [%ws] \"%ws\". Expected REG_DWORD, Found type: %d\n", KeyCtx->KeyName, KeyCtx->ValueName, KeyCtx->RegValueType);
FRS_ASSERT(!"Mismatch on KeyCtx->RegValueType, Expected REG_DWORD"); return ERROR_INVALID_PARAMETER; }
//
// Open the key.
//
WStatus = FrsRegOpenKey(KeyCtx, KeyArg1, Flags, &hKey);
if (!WIN_SUCCESS(WStatus)) { goto RETURN; }
//
// Read the value
//
Len = sizeof(Data); Type = REG_DWORD; WStatus = RegQueryValueEx(hKey, KeyCtx->ValueName, NULL, &Type, (PUCHAR)&Data, &Len);
if (!WIN_SUCCESS(WStatus)) { DPRINT_WS(5, "ERROR - RegQueryValueEx Failed.", WStatus);
if (WStatus == ERROR_FILE_NOT_FOUND) { //
// If the value is supposed to be there then return error to caller.
//
if (BooleanFlagOn(Flags | KeyCtx->Flags, FRS_RKF_VALUE_MUST_BE_PRESENT)) { DPRINT2_WS(0, ":FK: Value not found [%ws] \"%ws\".", KeyCtx->KeyName, KeyCtx->ValueName, WStatus); FrsRegPostEventLog(KeyCtx, KeyArg1, Flags, IDS_REG_VALUE_NOT_FOUND); goto RETURN; } } else { //
// Check for expected registry datatype if we found a value.
// Check for buffer size OK. 4 bytes for DWORDs.
//
if (WIN_BUF_TOO_SMALL(WStatus) || (Type != REG_DWORD)) { DPRINT4(0, ":FK: Invalid registry data type for [%ws] \"%ws\". Found Type %d, Expecting Type %d\n", KeyCtx->KeyName, KeyCtx->ValueName, Type, REG_DWORD); FrsRegPostEventLog(KeyCtx, KeyArg1, Flags, IDS_REG_VALUE_WRONG_TYPE); } }
WStatus = ERROR_INVALID_PARAMETER; } else {
//
// Found a value, Check type. If wrong, use default.
//
if (Type != REG_DWORD) { DPRINT4(0, ":FK: Invalid registry data type for [%ws] \"%ws\". Found Type %d, Expecting Type %d\n", KeyCtx->KeyName, KeyCtx->ValueName, Type, REG_DWORD); FrsRegPostEventLog(KeyCtx, KeyArg1, Flags, IDS_REG_VALUE_WRONG_TYPE); WStatus = ERROR_INVALID_PARAMETER; } }
if (!WIN_SUCCESS(WStatus) && DefaultValueUseOk) { //
// Not found or wrong type but Ok to use the default value from key context.
//
Type = KeyCtx->RegValueType; Data = KeyCtx->ValueDefault; WStatus = ERROR_SUCCESS; DPRINT2(4, ":FK: Using internal default value for [%ws] \"%ws\".\n", KeyCtx->KeyName, KeyCtx->ValueName); //
// Only use it once though.
//
DefaultValueUseOk = FALSE; }
if (WIN_SUCCESS(WStatus)) { //
// Perform syntax check based on data type in KeyCtx->DataValueType?
//
if (BooleanFlagOn(Flags | KeyCtx->Flags, FRS_RKF_SYNTAX_CHECK)) { NOTHING; }
//
// Perform Range check? (Applies to default value too)
//
if (BooleanFlagOn(Flags | KeyCtx->Flags, FRS_RKF_RANGE_CHECK)) {
if ((Data < KeyCtx->ValueMin) || ( Data > KeyCtx->ValueMax)) {
DPRINT5(0, ":FK: Value out of range for [%ws] \"%ws\". Found %d, must be between %d and %d\n", KeyCtx->KeyName, KeyCtx->ValueName, Data, KeyCtx->ValueMin, KeyCtx->ValueMax);
FrsRegPostEventLog(KeyCtx, KeyArg1, Flags, IDS_REG_VALUE_RANGE_ERROR);
if (DefaultValueUseOk) { //
// out of range but Ok to use the default value from key context.
//
DPRINT2(4, ":FK: Using internal default value for [%ws] \"%ws\".\n", KeyCtx->KeyName, KeyCtx->ValueName); Type = KeyCtx->RegValueType; Data = KeyCtx->ValueDefault; WStatus = ERROR_SUCCESS;
//
// Recheck the range.
//
if ((Data < KeyCtx->ValueMin) || ( Data > KeyCtx->ValueMax)) { DPRINT5(0, ":FK: Default Value out of range for [%ws] \"%ws\". Found %d, must be between %d and %d\n", KeyCtx->KeyName, KeyCtx->ValueName, Data, KeyCtx->ValueMin, KeyCtx->ValueMax); WStatus = ERROR_INVALID_PARAMETER; goto RETURN; }
} else { WStatus = ERROR_INVALID_PARAMETER; goto RETURN; } } }
//
// Data valid and in range. Return it and save it.
//
*DataRet = Data;
DPRINT3(3, ":FK: [%ws] \"%ws\" = %d\n", KeyCtx->KeyName, KeyCtx->ValueName, Data); }
RETURN:
if (hKey != HKEY_LOCAL_MACHINE) { FRS_REG_CLOSE(hKey); }
return WStatus;
}
DWORD CfgRegReadString( IN FRS_REG_KEY_CODE KeyIndex, IN PWCHAR KeyArg1, IN ULONG Flags, OUT PWSTR *pStrRet ) { /*++
Routine Description:
This function reads a keyword string value from the registry. The return buffer is allocated here with FrsAlloc(). Caller must free.
Arguments:
KeyIndex - An entry from the FRS_REG_KEY_CODE enum
KeyArg1 - An optional caller supplied key component. NULL if not provided.
Flags - Modifer flags
pStrRet - ptr to address of string buffer for returned result else NULL.
NOTE: The return buffer is allocated here, caller must free it.
Return Value:
Win32 status of the result of the registry operation. Data is returned only on a success.
--*/ #undef DEBSUB
#define DEBSUB "CfgRegReadString:"
DWORD WStatus; HKEY hKey = INVALID_HANDLE_VALUE; DWORD Type; DWORD Len, NewLen; PWCHAR Data, NewData; BOOL DefaultValueUseOk; PFRS_REGISTRY_KEY KeyCtx; WCHAR TStr[4];
// add support or new func for REG_MULTI_SZ?
//DPRINT(0, "function entry\n");
Data = NULL;
//
// Find the key context assoicated with the supplied index.
//
KeyCtx = FrsRegFindKeyContext(KeyIndex); if (KeyCtx == NULL) { DPRINT1(0, ":FK: ERROR - Key contxt not found for key code number %d\n", KeyIndex); *pStrRet = NULL; return ERROR_INVALID_PARAMETER; }
DefaultValueUseOk = BooleanFlagOn(Flags | KeyCtx->Flags, FRS_RKF_OK_TO_USE_DEFAULT);
FRS_ASSERT(KeyCtx->ValueName != NULL);
DPRINT2(4, ":FK: Reading parameter [%ws] \"%ws\" \n", KeyCtx->KeyName, KeyCtx->ValueName);
//
// Table entry better be some kind of string.
//
if ((KeyCtx->RegValueType != REG_SZ) && (KeyCtx->RegValueType != REG_EXPAND_SZ)) { DPRINT3(0, ":FK: Mismatch on KeyCtx->RegValueType for [%ws] \"%ws\". Expected REG_SZ or REG_EXPAND_SZ, Found type: %d\n", KeyCtx->KeyName, KeyCtx->ValueName, KeyCtx->RegValueType); // don't return a null ptr since calling parameter may be wrong size.
FRS_ASSERT(!"Mismatch on KeyCtx->RegValueType, Expected REG_SZ or REG_EXPAND_SZ"); return ERROR_INVALID_PARAMETER; }
*pStrRet = NULL;
//
// Open the key.
//
WStatus = FrsRegOpenKey(KeyCtx, KeyArg1, Flags, &hKey);
if (!WIN_SUCCESS(WStatus)) { goto RETURN; }
//
// Get the size and type for the value.
//
WStatus = RegQueryValueEx(hKey, KeyCtx->ValueName, NULL, &Type, NULL, &Len);
if (!WIN_SUCCESS(WStatus)) { DPRINT1_WS(5, ":FK: RegQueryValueEx(%ws);", KeyCtx->ValueName, WStatus); Len = 0; }
//
// If the value is supposed to be there then return error to caller.
//
if ((Len == 0) && BooleanFlagOn(Flags | KeyCtx->Flags, FRS_RKF_VALUE_MUST_BE_PRESENT)) { DPRINT2_WS(0, ":FK: Value not found [%ws] \"%ws\".", KeyCtx->KeyName, KeyCtx->ValueName, WStatus); FrsRegPostEventLog(KeyCtx, KeyArg1, Flags, IDS_REG_VALUE_NOT_FOUND); goto RETURN; }
if (WIN_SUCCESS(WStatus)) {
//
// Should be a string.
//
if ((Type != REG_SZ) && (Type != REG_EXPAND_SZ)) { DPRINT4(0, ":FK: Invalid registry data type for [%ws] \"%ws\". Found Type %d, Expecting Type %d\n", KeyCtx->KeyName, KeyCtx->ValueName, Type, KeyCtx->RegValueType); WStatus = ERROR_INVALID_PARAMETER; FrsRegPostEventLog(KeyCtx, KeyArg1, Flags, IDS_REG_VALUE_WRONG_TYPE); goto CHECK_DEFAULT; }
//
// If the string is too long or too short then complain and use default.
// If KeyCtx->ValueMax is zero then no maximum length check.
//
if (BooleanFlagOn(Flags | KeyCtx->Flags, FRS_RKF_RANGE_CHECK) && (Len < KeyCtx->ValueMin*sizeof(WCHAR)) || ((KeyCtx->ValueMax != 0) && (Len > KeyCtx->ValueMax*sizeof(WCHAR)))) { DPRINT4(0, ":FK: String size out of range for [%ws] \"%ws\". Min: %d Max: %d\n", KeyCtx->KeyName, KeyCtx->ValueName, KeyCtx->ValueMin, KeyCtx->ValueMax); WStatus = ERROR_INVALID_PARAMETER; FrsRegPostEventLog(KeyCtx, KeyArg1, Flags, IDS_REG_VALUE_RANGE_ERROR); goto CHECK_DEFAULT; }
//
// Alloc the return buffer and read the data.
//
Data = (PWCHAR) FrsAlloc (Len+1); WStatus = RegQueryValueEx(hKey, KeyCtx->ValueName, NULL, &Type, (PUCHAR)Data, &Len);
if (!WIN_SUCCESS(WStatus)) { DPRINT2(0, ":FK: RegQueryValueEx(%ws); WStatus %s\n", KeyCtx->ValueName, ErrLabelW32(WStatus)); Data = (PWCHAR) FrsFree(Data); goto RETURN; } }
CHECK_DEFAULT:
if (!WIN_SUCCESS(WStatus) && DefaultValueUseOk) { //
// Not found or wrong type but Ok to use the default value from key context.
//
Data = (PWCHAR) FrsFree(Data); if (KeyCtx->StringDefault == NULL) { DPRINT2(4, ":FK: Using internal default value for [%ws] \"%ws\" = NULL\n", KeyCtx->KeyName, KeyCtx->ValueName); goto RETURN; } Type = KeyCtx->RegValueType; Data = FrsWcsDup(KeyCtx->StringDefault);
WStatus = ERROR_SUCCESS; DPRINT3(4, ":FK: Using internal default value for [%ws] \"%ws\" = %ws\n", KeyCtx->KeyName, KeyCtx->ValueName, Data); }
if (WIN_SUCCESS(WStatus) && (Data != NULL)) { //
// Perform syntax check based on data type in KeyCtx->DataValueType?
//
if (BooleanFlagOn(Flags | KeyCtx->Flags, FRS_RKF_SYNTAX_CHECK)) { NOTHING; }
DPRINT3(4, ":FK: [%ws] \"%ws\" = \"%ws\"\n", KeyCtx->KeyName, KeyCtx->ValueName, Data);
//
// Expand system strings if needed
//
if (Type == REG_EXPAND_SZ) {
NewLen = ExpandEnvironmentStrings(Data, TStr, 0);
while (TRUE) { NewData = (PWCHAR) FrsAlloc ((NewLen+1) * sizeof(WCHAR));
Len = ExpandEnvironmentStrings(Data, NewData, NewLen); if (Len == 0) { WStatus = GetLastError(); DPRINT2_WS(5, ":FK: [%ws] \"%ws\" Param not expanded.", KeyCtx->KeyName, KeyCtx->ValueName, WStatus); Data = FrsFree(Data); NewData = FrsFree(NewData); break; }
if (Len <= NewLen) { //
// Free the original buffer and set to return expanded string.
//
FrsFree(Data); Data = NewData; Len = NewLen; WStatus = ERROR_SUCCESS; break; }
//
// Get a bigger buffer.
//
NewData = (PWCHAR) FrsFree(NewData); NewLen = Len; } }
//
// Return ptr to buffer and save a copy for debug printouts.
//
*pStrRet = Data;
DPRINT3(3, ":FK: [%ws] \"%ws\" = \"%ws\"\n", KeyCtx->KeyName, KeyCtx->ValueName, (Data != NULL) ? Data : L"<null>"); }
//
// Close the handle if one was opened.
//
RETURN:
if (hKey != HKEY_LOCAL_MACHINE) { FRS_REG_CLOSE(hKey); }
return WStatus; }
#if 0
// multisz example)
void RegQueryMULTISZ( HKEY hkey, LPSTR szSubKey, LPSTR szValue )
/*++
Routine Description:
This function queries MULTISZ value in the registry using the hkey and szSubKey as the registry key info. If the value is not found in the registry, it is added with a zero value.
Arguments:
hkey - handle to a registry key szSubKey - pointer to a subkey string
Return Value:
registry value
--*/
{ DWORD rc; DWORD len; DWORD dwType; char buf[1024];
len = sizeof(buf); rc = RegQueryValueEx( hkey, szSubKey, 0, &dwType, (LPBYTE)buf, &len ); if (!WIN_SUCCESS(rc)) { if (rc == ERROR_FILE_NOT_FOUND) { buf[0] = 0; buf[1] = 0; len = 2; RegSetMULTISZ( hkey, szSubKey, buf ); } }
CopyMemory( szValue, buf, len ); } #endif
DWORD CfgRegWriteDWord( IN FRS_REG_KEY_CODE KeyIndex, IN PWCHAR KeyArg1, IN ULONG Flags, IN ULONG NewData ) { /*++
Routine Description:
This function reads a keyword value from the registry.
Arguments:
KeyIndex - An entry from the FRS_REG_KEY_CODE enum
KeyArg1 - An optional caller supplied key component. NULL if not provided.
Flags - Modifer flags FRS_RKF_FORCE_DEFAULT_VALUE - if set then ignore NewData and write the default key value from the keyCtx into the registry.
NewData - DWORD to write to registry.
Return Value:
Win32 status of the result of the registry operation.
--*/ #undef DEBSUB
#define DEBSUB "CfgRegWriteDWord:"
DWORD WStatus; HKEY hKey = INVALID_HANDLE_VALUE; DWORD Len; PFRS_REGISTRY_KEY KeyCtx;
//DPRINT(0, "function entry\n");
//
// Find the key context assoicated with the supplied index.
//
KeyCtx = FrsRegFindKeyContext(KeyIndex); if (KeyCtx == NULL) { DPRINT1(0, ":FK: ERROR - Key contxt not found for key code number %d\n", KeyIndex); return ERROR_INVALID_PARAMETER; }
FRS_ASSERT(KeyCtx->ValueName != NULL);
//
// Table entry better be REG_DWORD.
//
if (KeyCtx->RegValueType != REG_DWORD) { DPRINT3(0, ":FK: Mismatch on KeyCtx->RegValueType for [%ws] \"%ws\". Expected REG_DWORD, Found type: %d\n", KeyCtx->KeyName, KeyCtx->ValueName, KeyCtx->RegValueType); FRS_ASSERT(!"Mismatch on KeyCtx->RegValueType, Expected REG_DWORD"); return ERROR_INVALID_PARAMETER; }
//
// Open the key.
//
WStatus = FrsRegOpenKey(KeyCtx, KeyArg1, Flags, &hKey);
if (!WIN_SUCCESS(WStatus)) { goto RETURN; }
//
// Keep existing value if caller says so.
//
if (BooleanFlagOn(Flags, FRS_RKF_KEEP_EXISTING_VALUE)) { WStatus = RegQueryValueEx(hKey, KeyCtx->ValueName, NULL, NULL, NULL, NULL); if (WIN_SUCCESS(WStatus)) { DPRINT2(4, ":FK: Retaining existing value for parameter [%ws] \"%ws\"\n", KeyCtx->KeyName, KeyCtx->ValueName); goto RETURN; } }
//
// Check if we are writing the default value to the registry.
//
if (BooleanFlagOn(Flags, FRS_RKF_FORCE_DEFAULT_VALUE)) {
NewData = KeyCtx->ValueDefault; DPRINT1(4, ":FK: Using internal default value = %d\n", NewData); }
//
// Perform Range check? (Applies to default value too)
//
if (BooleanFlagOn(Flags | KeyCtx->Flags, FRS_RKF_RANGE_CHECK | FRS_RKF_RANGE_SATURATE)) {
if ((NewData < KeyCtx->ValueMin) || ( NewData > KeyCtx->ValueMax)) {
DPRINT5(0, ":FK: Value out of range for [%ws] \"%ws\". Found %d, must be between %d and %d\n", KeyCtx->KeyName, KeyCtx->ValueName, NewData, KeyCtx->ValueMin, KeyCtx->ValueMax);
if (!BooleanFlagOn(Flags | KeyCtx->Flags, FRS_RKF_RANGE_SATURATE)) { WStatus = ERROR_INVALID_PARAMETER; FrsRegPostEventLog(KeyCtx, KeyArg1, Flags, IDS_REG_VALUE_RANGE_ERROR); goto RETURN; }
//
// Set the value to either the min or max of the allowed range.
// WARNING: The only current use of this flag is in setting the
// DS polling interval. This flag should be used with caution
// since if a user miss-specifies a parameter and we jam
// it to the min or max value the resulting effect could be
// VERY UNDESIREABLE.
//
if (NewData < KeyCtx->ValueMin) { DPRINT2(4, ":FK: Value (%d) below of range. Using Min value (%d)\n", NewData, KeyCtx->ValueMin); NewData = KeyCtx->ValueMin; } else
if (NewData > KeyCtx->ValueMax) { DPRINT2(4, ":FK: Value (%d) above of range. Using Max value (%d)\n", NewData, KeyCtx->ValueMax); NewData = KeyCtx->ValueMax; }
} }
//
// Write the value and save it.
//
Len = sizeof(NewData); WStatus = RegSetValueEx(hKey, KeyCtx->ValueName, 0, REG_DWORD, (PCHAR)&NewData, Len);
if (!WIN_SUCCESS(WStatus)) { DPRINT_WS(0, ":FK: ERROR - RegSetValueEx Failed.", WStatus); } else { DPRINT3(3, ":FK: [%ws] \"%ws\" = %d\n", KeyCtx->KeyName, KeyCtx->ValueName, NewData); }
RETURN:
if (hKey != HKEY_LOCAL_MACHINE) { FRS_REG_CLOSE(hKey); }
return WStatus;
}
DWORD CfgRegWriteString( IN FRS_REG_KEY_CODE KeyIndex, IN PWCHAR KeyArg1, IN ULONG Flags, IN PWSTR NewStr ) { /*++
Routine Description:
This function reads a keyword string value from the registry. The return buffer is allocated here with FrsAlloc(). Caller must free.
Arguments:
KeyIndex - An entry from the FRS_REG_KEY_CODE enum
KeyArg1 - An optional caller supplied key component. NULL if not provided.
Flags - Modifer flags FRS_RKF_FORCE_DEFAULT_VALUE - if set then ignore NewStr and write the default key value from the keyCtx into the registry.
NewStr - ptr to buffer for new string data.
Return Value:
Win32 status of the result of the registry operation.
--*/ #undef DEBSUB
#define DEBSUB "CfgRegWriteString:"
DWORD WStatus; HKEY hKey = INVALID_HANDLE_VALUE; DWORD Type; DWORD Len, NewLen; PFRS_REGISTRY_KEY KeyCtx;
// add support or new func for REG_MULTI_SZ
//DPRINT(0, "function entry\n");
//
// Find the key context assoicated with the supplied index.
//
KeyCtx = FrsRegFindKeyContext(KeyIndex); if (KeyCtx == NULL) { DPRINT1(0, ":FK: ERROR - Key contxt not found for key code number %d\n", KeyIndex); return ERROR_INVALID_PARAMETER; }
//
// Table entry better be some kind of string.
//
if ((KeyCtx->RegValueType != REG_SZ) && // (KeyCtx->RegValueType != REG_MULTI_SZ) &&
(KeyCtx->RegValueType != REG_EXPAND_SZ)) { DPRINT3(0, ":FK: Mismatch on KeyCtx->RegValueType for [%ws] \"%ws\". Expected REG_SZ or REG_EXPAND_SZ, Found type: %d\n", KeyCtx->KeyName, KeyCtx->ValueName, KeyCtx->RegValueType); FRS_ASSERT(!"Mismatch on KeyCtx->RegValueType, Expected REG_SZ or REG_EXPAND_SZ"); return ERROR_INVALID_PARAMETER; }
//
// Open the key.
//
WStatus = FrsRegOpenKey(KeyCtx, KeyArg1, Flags, &hKey); if (!WIN_SUCCESS(WStatus)) { goto RETURN; }
FRS_ASSERT(KeyCtx->ValueName != NULL);
//
// Keep existing value if caller says so.
//
if (BooleanFlagOn(Flags, FRS_RKF_KEEP_EXISTING_VALUE)) { WStatus = RegQueryValueEx(hKey, KeyCtx->ValueName, NULL, NULL, NULL, NULL); if (WIN_SUCCESS(WStatus)) { DPRINT2(4, ":FK: Retaining existing value for parameter [%ws] \"%ws\"\n", KeyCtx->KeyName, KeyCtx->ValueName); goto RETURN; } }
//
// Check if we are writing the default value to the registry.
//
if (BooleanFlagOn(Flags, FRS_RKF_FORCE_DEFAULT_VALUE)) { if (KeyCtx->StringDefault == NULL) { DPRINT2(0, ":FK: ERROR - Key contxt has no default value for [%ws] \"%ws\" \n", KeyCtx->KeyName, KeyCtx->ValueName); WStatus = ERROR_INVALID_PARAMETER; FRS_ASSERT(!"Key contxt has no default value"); goto RETURN; }
NewStr = KeyCtx->StringDefault; DPRINT1(4, ":FK: Using internal default value = \"%ws\" \n", NewStr); }
//
// Perform Range check? (Applies to default value too)
// If the string is too long or too short then complain and use default.
// If KeyCtx->ValueMax is zero then no maximum length check.
//
// Note: for REG_MULTI_SZ we need to look for double null at end of str
// or use a unique symbol for the string separator and cvt to \0 before write.
Len = (wcslen(NewStr) + 1) * sizeof(WCHAR); if (BooleanFlagOn(Flags | KeyCtx->Flags, FRS_RKF_RANGE_CHECK) && (Len < KeyCtx->ValueMin*sizeof(WCHAR)) || ((KeyCtx->ValueMax != 0) && (Len > KeyCtx->ValueMax*sizeof(WCHAR)))) { DPRINT4(0, ":FK: String size out of range for [%ws] \"%ws\". Min: %d Max: %d\n", KeyCtx->KeyName, KeyCtx->ValueName, KeyCtx->ValueMin, KeyCtx->ValueMax); WStatus = ERROR_INVALID_PARAMETER; FrsRegPostEventLog(KeyCtx, KeyArg1, Flags, IDS_REG_VALUE_RANGE_ERROR); goto RETURN; }
WStatus = RegSetValueEx(hKey, KeyCtx->ValueName, 0, KeyCtx->RegValueType, (PCHAR)NewStr, Len);
if (!WIN_SUCCESS(WStatus)) { DPRINT_WS(0, ":FK: ERROR - RegSetValueEx Failed.", WStatus); } else {
// note: won't work for MULTI_SZ
DPRINT3(3, ":FK: [%ws] \"%ws\" = %ws\n", KeyCtx->KeyName, KeyCtx->ValueName, (NewStr != NULL) ? NewStr : L"<null>"); }
#if 0
// Multi_Sz example
//
// Event Message File
//
// WStatus = RegSetValueEx(FrsEventLogKey,
// L"Sources",
// 0,
// REG_MULTI_SZ,
// (PCHAR)(SERVICE_NAME L"\0"
// SERVICE_LONG_NAME L"\0"),
// (wcslen(SERVICE_NAME) +
// wcslen(SERVICE_LONG_NAME) +
// 3) * sizeof(WCHAR));
//
// Another example
//
void RegSetMULTISZ( HKEY hkey, LPSTR szSubKey, LPSTR szValue )
/*++
Routine Description:
This function changes a Multi_SZ value in the registry using the hkey and szSubKey as the registry key info.
Arguments:
hkey - handle to a registry key szSubKey - pointer to a subkey string szValue - new registry value
Return Value:
None.
--*/
{ ULONG i = 1; ULONG j = 0; LPSTR p = szValue; while( TRUE ) { j = strlen( p ) + 1; i += j; p += j; if (!*p) { break; } } RegSetValueEx( hkey, szSubKey, 0, REG_MULTI_SZ, (PUCHAR)szValue, i ); }
#endif
//
// Close the handle if one was opened.
//
RETURN:
if (hKey != HKEY_LOCAL_MACHINE) { FRS_REG_CLOSE(hKey); }
return WStatus; }
DWORD CfgRegDeleteValue( IN FRS_REG_KEY_CODE KeyIndex, IN PWCHAR KeyArg1, IN ULONG Flags ) { /*++
Routine Description:
This function deletes a keyword value from the registry.
Arguments:
KeyIndex - An entry from the FRS_REG_KEY_CODE enum
KeyArg1 - An optional caller supplied key component. NULL if not provided.
Flags - Modifer flags
Return Value:
Win32 status of the result of the registry operation.
--*/ #undef DEBSUB
#define DEBSUB "CfgRegDeleteValue:"
DWORD WStatus; HKEY hKey = INVALID_HANDLE_VALUE; PFRS_REGISTRY_KEY KeyCtx;
//DPRINT(0, "function entry\n");
//
// Find the key context assoicated with the supplied index.
//
KeyCtx = FrsRegFindKeyContext(KeyIndex); if (KeyCtx == NULL) { DPRINT1(0, ":FK: ERROR - Key contxt not found for key code number %d\n", KeyIndex); return ERROR_INVALID_PARAMETER; }
FRS_ASSERT(KeyCtx->ValueName != NULL);
//
// Open the key.
//
WStatus = FrsRegOpenKey(KeyCtx, KeyArg1, Flags, &hKey); if (!WIN_SUCCESS(WStatus)) { goto RETURN; }
DPRINT2(3, ":FK: Deleting parameter [%ws] \"%ws\" \n", KeyCtx->KeyName, KeyCtx->ValueName);
//
// Delete the value.
//
WStatus = RegDeleteValue(hKey, KeyCtx->ValueName); DPRINT2_WS(0, ":FK: WARN - Cannot delete key for [%ws] \"%ws\";", KeyCtx->KeyName, KeyCtx->ValueName, WStatus);
RETURN:
if (hKey != HKEY_LOCAL_MACHINE) { FRS_REG_CLOSE(hKey); }
return WStatus;
}
DWORD CfgRegOpenKey( IN FRS_REG_KEY_CODE KeyIndex, IN PWCHAR KeyArg1, IN ULONG Flags, OUT HKEY *RethKey ) { /*++
Routine Description:
This function Opens the key associated with the entry from the FRS registry key context table. It performs the normal substitution, key component creation, etc.
Arguments:
KeyIndex - An entry from the FRS_REG_KEY_CODE enum
KeyArg1 - An optional caller supplied key component. NULL if not provided.
Flags - Modifer flags
RethKey -- ptr to HKEY to return the key handle. Caller must close the key with RegCloseKey().
Return Value:
Win32 status of the result of the registry operation.
--*/ #undef DEBSUB
#define DEBSUB "CfgRegOpenKey:"
DWORD WStatus; HKEY hKey = INVALID_HANDLE_VALUE; PFRS_REGISTRY_KEY KeyCtx;
//DPRINT(0, "function entry\n");
FRS_ASSERT(RethKey != NULL);
*RethKey = INVALID_HANDLE_VALUE;
//
// Find the key context assoicated with the supplied index.
//
KeyCtx = FrsRegFindKeyContext(KeyIndex); if (KeyCtx == NULL) { DPRINT1(0, ":FK: ERROR - Key contxt not found for key code number %d\n", KeyIndex); return ERROR_INVALID_PARAMETER; }
//
// Open the key.
//
WStatus = FrsRegOpenKey(KeyCtx, KeyArg1, Flags, &hKey); if (!WIN_SUCCESS(WStatus)) { return WStatus; }
DPRINT1(4, ":FK: Registry key opened [%ws]\n", KeyCtx->KeyName);
*RethKey = hKey;
return ERROR_SUCCESS;
}
DWORD CfgRegCheckEnable( IN FRS_REG_KEY_CODE KeyIndex, IN PWCHAR KeyArg1, IN ULONG Flags, OUT PBOOL Enabled, OUT PBOOL EnabledAndRequired ) /*++
Routine Description:
This function Opens the key associated with the entry from the FRS registry key context table. It performs the normal substitution, key component creation, etc. It then checks to see if the data value is "Enabled" or "Disabled" and returns the boolean result.
Arguments:
KeyIndex - An entry from the FRS_REG_KEY_CODE enum
KeyArg1 - An optional caller supplied key component. NULL if not provided.
Flags - Modifer flags
Enabled -- ptr to BOOL to return the Enable / Disable state of the key.
EnabledAndRequired -- ptr to BOOL to return TRUE if the state is "Enabled and Required", FALSE otherwise
Return Value:
Win32 status of the result of the registry operation.
--*/ #undef DEBSUB
#define DEBSUB "CfgRegCheckEnable:"
{
ULONG WStatus; PWCHAR WStr = NULL;
//DPRINT(0, "function entry\n");
WStatus = CfgRegReadString(KeyIndex, KeyArg1, Flags, &WStr);
if ((WStr == NULL) || WSTR_EQ(WStr, FRS_IS_DEFAULT_DISABLED)|| WSTR_EQ(WStr, FRS_IS_DEFAULT_ENABLED) || WSTR_EQ(WStr, FRS_IS_DEFAULT_ENABLED_AND_REQUIRED) ) { //
// The key is in the default state so we can clobber it with a
// new default.
//
WStatus = CfgRegWriteString(KeyIndex, KeyArg1, FRS_RKF_FORCE_DEFAULT_VALUE, NULL); DPRINT1_WS(0, ":FK: WARN - Cannot create Enable key [%ws];", CfgRegGetValueName(KeyIndex), WStatus);
//
// Now reread the key for the new default.
//
WStr = FrsFree(WStr); WStatus = CfgRegReadString(KeyIndex, KeyArg1, Flags, &WStr); }
if ((WStr != NULL) && (WSTR_EQ(WStr, FRS_IS_ENABLED) || WSTR_EQ(WStr, FRS_IS_DEFAULT_ENABLED))) { *Enabled = TRUE; *EnabledAndRequired = FALSE; DPRINT1(4, ":FK: %ws is enabled\n", CfgRegGetValueName(KeyIndex)); } else if ((WStr != NULL) && (WSTR_EQ(WStr, FRS_IS_ENABLED_AND_REQUIRED) || WSTR_EQ(WStr, FRS_IS_DEFAULT_ENABLED_AND_REQUIRED))) { *Enabled = TRUE; *EnabledAndRequired = TRUE; } else { *Enabled = FALSE; *EnabledAndRequired = FALSE; DPRINT1_WS(0, ":FK: WARN - %ws is not enabled.", CfgRegGetValueName(KeyIndex), WStatus); }
WStr = FrsFree(WStr);
return WStatus;
}
BOOL IsWin2KPro ( VOID ) /*++
Routine Description:
Check OS version for Win 2000 Professional (aka NT Workstation).
Arguments:
None.
Return Value:
True if running on win 2K professional.
--*/ #undef DEBSUB
#define DEBSUB "IsWin2KPro:"
{ OSVERSIONINFOEX Osvi; DWORDLONG ConditionMask = 0;
//
// Initialize the OSVERSIONINFOEX structure.
//
ZeroMemory(&Osvi, sizeof(OSVERSIONINFOEX)); Osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); Osvi.dwMajorVersion = 5; Osvi.wProductType = VER_NT_WORKSTATION;
//
// Initialize the condition mask.
//
VER_SET_CONDITION( ConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL ); VER_SET_CONDITION( ConditionMask, VER_PRODUCT_TYPE, VER_EQUAL );
//
// Perform the test.
//
return VerifyVersionInfo(&Osvi, VER_MAJORVERSION | VER_PRODUCT_TYPE, ConditionMask); }
VOID CfgRegAdjustTuningDefaults( VOID ) /*++
Routine Description:
This function walks thru the FrsRegKeyRevisionTable and applies new min, max and default values to the specified keys. The objective is to reduce the footprint of FRS on the workstation.
Arguments:
None.
Return Value:
None.
--*/ #undef DEBSUB
#define DEBSUB "CfgRegAdjustTuningDefaults:"
{
PFRS_REG_KEY_REVISIONS Rev; PFRS_REGISTRY_KEY KeyCtx;
Win2kPro = IsWin2KPro();
if (!Win2kPro) { //
// Only adjust tunables on a workstation.
//
return; }
Rev = FrsRegKeyRevisionTable;
while (Rev->FrsKeyCode != FKC_END_OF_TABLE) {
KeyCtx = FrsRegFindKeyContext(Rev->FrsKeyCode); if (KeyCtx == NULL) { DPRINT1(0, ":FK: ERROR - Key contxt not found for key code number %d\n", Rev->FrsKeyCode); continue; }
//
// Table entry better be REG_DWORD.
//
if (KeyCtx->RegValueType != REG_DWORD) { DPRINT3(0, ":FK: Mismatch on KeyCtx->RegValueType for [%ws] \"%ws\". Expected REG_DWORD, Found type: %d\n", KeyCtx->KeyName, KeyCtx->ValueName, KeyCtx->RegValueType); continue; }
//
// Apply the new range and default values from the table.
//
KeyCtx->ValueMin = Rev->ValueMin; KeyCtx->ValueMax = Rev->ValueMax; KeyCtx->ValueDefault = Rev->ValueDefault;
Rev += 1; } }
#define BACKUP_STAR L"*"
#define BACKUP_APPEND L"\\* /s"
VOID CfgFilesNotToBackup( IN PGEN_TABLE Replicas ) /*++
Routine Description:
Set the backup registry key to prevent backing up the jet database, staging directories, preinstall directories, ...
Set the restore registry key KeysNotToRestore so that NtBackup will retain the ntfrs restore keys by moving them into the final restored registry.
Arguments:
Table of replicas
Return Value:
None.
--*/ { #undef DEBSUB
#define DEBSUB "CfgFilesNotToBackup:"
DWORD WStatus; PVOID Key; PREPLICA Replica; PWCHAR MStr = NULL; DWORD Size = 0; DWORD Idx = 0; HKEY HOldBackupKey = INVALID_HANDLE_VALUE; HKEY HNewBackupKey = INVALID_HANDLE_VALUE; HKEY HKeysNotToRestore = INVALID_HANDLE_VALUE;
//DPRINT(0, "function entry\n");
//
// "<Jetpath>\* /s"
//
FrsAddToMultiString(JetPath, &Size, &Idx, &MStr); FrsCatToMultiString(BACKUP_APPEND, &Size, &Idx, &MStr);
//
// "<DebugInfo.LogFile>\NtFrs*" Default: "%SystemRoot%\debug\NtFrs*"
//
FrsAddToMultiString(DebugInfo.LogFile, &Size, &Idx, &MStr); FrsCatToMultiString(NTFRS_DBG_LOG_FILE, &Size, &Idx, &MStr); FrsCatToMultiString(BACKUP_STAR, &Size, &Idx, &MStr);
GTabLockTable(Replicas); Key = NULL; while (Replica = GTabNextDatumNoLock(Replicas, &Key)) { //
// Ignore tombstoned sets
//
if (!IS_TIME_ZERO(Replica->MembershipExpires)) { continue; }
//
// Preinstall directories
//
if (Replica->Root) { FrsAddToMultiString(Replica->Root, &Size, &Idx, &MStr); FrsCatToMultiString(L"\\", &Size, &Idx, &MStr); FrsCatToMultiString(NTFRS_PREINSTALL_DIRECTORY, &Size, &Idx, &MStr); FrsCatToMultiString(BACKUP_APPEND, &Size, &Idx, &MStr); } //
// Preexisting directories
//
if (Replica->Root) { FrsAddToMultiString(Replica->Root, &Size, &Idx, &MStr); FrsCatToMultiString(L"\\", &Size, &Idx, &MStr); FrsCatToMultiString(NTFRS_PREEXISTING_DIRECTORY, &Size, &Idx, &MStr); FrsCatToMultiString(BACKUP_APPEND, &Size, &Idx, &MStr); } //
// Staging directories
//
if (Replica->Stage) { FrsAddToMultiString(Replica->Stage, &Size, &Idx, &MStr); FrsCatToMultiString(L"\\", &Size, &Idx, &MStr); FrsCatToMultiString(GENERIC_PREFIX, &Size, &Idx, &MStr); FrsCatToMultiString(BACKUP_STAR, &Size, &Idx, &MStr); } } GTabUnLockTable(Replicas);
// Note: remove old_files_not_to_backup once existance of new key
// has been verified.
//
// FilesNotToBackup
// "SOFTWARE\Microsoft\Windows NT\CurrentVersion\FilesNotToBackup"
//
WStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, FRS_OLD_FILES_NOT_TO_BACKUP, 0, KEY_SET_VALUE, &HOldBackupKey); CLEANUP1_WS(4, ":FK: WARN - RegOpenKeyEx(%ws);", FRS_OLD_FILES_NOT_TO_BACKUP, WStatus, NEW_FILES_NOT_TO_BACKUP);
//
// Set the ntfrs multistring value
//
WStatus = RegSetValueEx(HOldBackupKey, SERVICE_NAME, 0, REG_MULTI_SZ, (PCHAR)MStr, (Idx + 1) * sizeof(WCHAR)); CLEANUP2_WS(4, ":FK: ERROR - RegSetValueEx(%ws\\%ws);", FRS_OLD_FILES_NOT_TO_BACKUP, SERVICE_NAME, WStatus, NEW_FILES_NOT_TO_BACKUP);
NEW_FILES_NOT_TO_BACKUP: //
// FilesNotToBackup
// "SYSTEM\CurrentControlSet\Control\BackupRestore\FilesNotToBackup"
//
WStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, FRS_NEW_FILES_NOT_TO_BACKUP, 0, KEY_SET_VALUE, &HNewBackupKey); CLEANUP1_WS(4, ":FK: WARN - RegOpenKeyEx(%ws);", FRS_NEW_FILES_NOT_TO_BACKUP, WStatus, CLEANUP);
//
// Set the ntfrs multistring value
//
WStatus = RegSetValueEx(HNewBackupKey, SERVICE_NAME, 0, REG_MULTI_SZ, (PCHAR)MStr, (Idx + 1) * sizeof(WCHAR)); CLEANUP2_WS(4, ":FK: ERROR - RegSetValueEx(%ws\\%ws);", FRS_NEW_FILES_NOT_TO_BACKUP, SERVICE_NAME, WStatus, CLEANUP);
//
// KeysNotToRestore
//
// Set the restore registry key KeysNotToRestore so that NtBackup will
// retain the ntfrs restore keys by moving them into the final restored
// registry.
//
// CurrentControlSet\Services\<SERVICE_NAME>\Parameters\Backup/Restore\Process at Startup\"
//
MStr = FrsFree(MStr); Size = 0; Idx = 0; FrsAddToMultiString(FRS_VALUE_FOR_KEYS_NOT_TO_RESTORE, &Size, &Idx, &MStr);
//
// KeysNotToRestore
// "SYSTEM\CurrentControlSet\Control\BackupRestore\KeysNotToRestore"
//
WStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, FRS_KEYS_NOT_TO_RESTORE, 0, KEY_SET_VALUE, &HKeysNotToRestore); CLEANUP1_WS(4, ":FK: WARN - RegOpenKeyEx(%ws);", FRS_KEYS_NOT_TO_RESTORE, WStatus, CLEANUP);
//
// Set the ntfrs multistring value
//
WStatus = RegSetValueEx(HKeysNotToRestore, SERVICE_NAME, 0, REG_MULTI_SZ, (PCHAR)MStr, (Idx + 1) * sizeof(WCHAR)); CLEANUP2_WS(4, ":FK: ERROR - RegSetValueEx(%ws\\%ws);", FRS_KEYS_NOT_TO_RESTORE, SERVICE_NAME, WStatus, CLEANUP);
//
// DONE
//
WStatus = ERROR_SUCCESS;
CLEANUP: FRS_REG_CLOSE(HOldBackupKey); FRS_REG_CLOSE(HNewBackupKey); FRS_REG_CLOSE(HKeysNotToRestore); FrsFree(MStr); }
VOID FrsRegPostEventLog( IN PFRS_REGISTRY_KEY KeyCtx, IN PWCHAR KeyArg1, IN ULONG Flags, IN LONG IDScode ) /*++
Routine Description:
This Posts an event log message for a problem with a registry key.
Arguments:
KeyCtx - Ptr to the Key Context struct for this key.
KeyArg1 - An optional caller supplied key component. NULL if not provided.
Flags - Modifer flags
IDSCode - the error message code for a resource string to put in the message.
Return Value:
None.
--*/ #undef DEBSUB
#define DEBSUB "FrsRegPostEventLog:"
{
#define LEN_DEFAULT_VALUE 48
#define LEN_RANGE_STR 256
PWCHAR ErrorStr, UnitsStr, RangeStrFmt, ValStr, FullKeyStr; WCHAR RangeStr[LEN_RANGE_STR];
//DPRINT(0, "function entry\n");
//
// Are we posting an event log message for this key?
//
if (!BooleanFlagOn(Flags | KeyCtx->Flags, FRS_RKF_LOG_EVENT) || (KeyCtx->EventCode == EVENT_FRS_NONE)) { return; }
//
// Post Eventlog message. Include KeyString, ValueName,
// MustBePresent, Expected Type, TypeMismatch or not,
// Value out of range (with range allowed), Default Value Used,
// regedit instrs to fix the problem,
//
UnitsStr = FrsGetResourceStr(XLATE_IDS_UNITS(KeyCtx->Units)); ErrorStr = FrsGetResourceStr(IDScode);
if (KeyCtx->RegValueType == REG_DWORD) {
//
// Get the range format string from the string resource.
//
RangeStrFmt = FrsGetResourceStr(IDS_RANGE_DWORD); //
// Show default value used if default is ok.
//
if (BooleanFlagOn(Flags | KeyCtx->Flags, FRS_RKF_OK_TO_USE_DEFAULT)) { ValStr = FrsAlloc(LEN_DEFAULT_VALUE * sizeof(WCHAR)); _snwprintf(ValStr, LEN_DEFAULT_VALUE, L"%d", KeyCtx->ValueDefault); } else { ValStr = FrsGetResourceStr(IDS_NO_DEFAULT); } } else { //
// No default allowed.
//
RangeStrFmt = FrsGetResourceStr(IDS_RANGE_STRING); ValStr = FrsGetResourceStr(IDS_NO_DEFAULT); }
//
// Build the range string.
//
_snwprintf(RangeStr, LEN_RANGE_STR, RangeStrFmt, KeyCtx->ValueMin, KeyCtx->ValueMax); RangeStr[LEN_RANGE_STR-1] = UNICODE_NULL;
//
// Expand the key string.
//
FrsRegExpandKeyStr(KeyCtx, KeyArg1, Flags, &FullKeyStr); if (FullKeyStr == NULL) { FullKeyStr = FrsWcsDup(KeyCtx->KeyName); }
//
// Post the event log message using the keycode in the KeyContext and cleanup.
//
if (KeyCtx->EventCode == EVENT_FRS_BAD_REG_DATA) { EPRINT9(KeyCtx->EventCode, ErrorStr, // %1
FullKeyStr, // %2
KeyCtx->ValueName, // %3
REG_DT_NAME(KeyCtx->RegValueType), // %4
RangeStr, // %5
UnitsStr, // %6
ValStr, // %7
FullKeyStr, // %8
KeyCtx->ValueName); // %9
} else { //
// Don't know this event code but put out something.
//
DPRINT1(0, ":FK: ERROR - Unexpected EventCode number (%d). Cannot post message.\n", KeyCtx->EventCode); }
DPRINT1(0, ":FK: EventCode number : %d\n" , (KeyCtx->EventCode & 0xFFFF)); DPRINT1(0, ":FK: Error String : %ws\n", ErrorStr); DPRINT1(0, ":FK: Key String : %ws\n", FullKeyStr); DPRINT1(0, ":FK: Value Name : %ws\n", KeyCtx->ValueName); DPRINT1(0, ":FK: Expected Reg Type : %ws\n", REG_DT_NAME(KeyCtx->RegValueType)); DPRINT1(0, ":FK: Parameter Range : %ws\n", RangeStr); DPRINT1(0, ":FK: Parameter units : %ws\n", UnitsStr);
FrsFree(ErrorStr); FrsFree(RangeStrFmt); FrsFree(UnitsStr); FrsFree(ValStr); FrsFree(FullKeyStr);
}
DWORD CfgRegReadReparseTagInfo( VOID ) { #undef DEBSUB
#define DEBSUB "CfgRegReadReparseTagInfo:"
DWORD WStatus = ERROR_SUCCESS; HKEY hKey = INVALID_HANDLE_VALUE; DWORD Index = 0; WCHAR SubKey[MAX_PATH]; DWORD SubKeySize = MAX_PATH; FILETIME LastWriteTime; DWORD *ReparseTagType = NULL; PREPARSE_TAG_TABLE_ENTRY ReparseTagTableEntry = NULL; PREPARSE_TAG_TABLE_ENTRY ExistingEntry = NULL;
GTabLockTable(ReparseTagTable);
//
// First clear the data in the table.
//
GTabEmptyTableNoLock(ReparseTagTable, FrsFreeType);
//
// Seed the table with the default values.
//
ReparseTagType = FrsAlloc(sizeof(DWORD)); *ReparseTagType = IO_REPARSE_TAG_HSM; ReparseTagTableEntry = FrsAllocTypeSize(REPARSE_TAG_TABLE_ENTRY_TYPE, (wcslen(REPARSE_TAG_REPLICATION_TYPE_FILE_DATA) + 1) * sizeof(WCHAR)); wcscpy(ReparseTagTableEntry->ReplicationType, REPARSE_TAG_REPLICATION_TYPE_FILE_DATA); ExistingEntry = GTabInsertUniqueEntryNoLock(ReparseTagTable, ReparseTagTableEntry, ReparseTagType, NULL); FRS_ASSERT(ExistingEntry == NULL);
ReparseTagType = FrsAlloc(sizeof(DWORD)); *ReparseTagType = IO_REPARSE_TAG_SIS; ReparseTagTableEntry = FrsAllocTypeSize(REPARSE_TAG_TABLE_ENTRY_TYPE, (wcslen(REPARSE_TAG_REPLICATION_TYPE_FILE_DATA) + 1) * sizeof(WCHAR)); wcscpy(ReparseTagTableEntry->ReplicationType, REPARSE_TAG_REPLICATION_TYPE_FILE_DATA); ExistingEntry = GTabInsertUniqueEntryNoLock(ReparseTagTable, ReparseTagTableEntry, ReparseTagType, NULL); FRS_ASSERT(ExistingEntry == NULL);
ReparseTagType = FrsAlloc(sizeof(DWORD)); *ReparseTagType = IO_REPARSE_TAG_DFS; ReparseTagTableEntry = FrsAllocTypeSize(REPARSE_TAG_TABLE_ENTRY_TYPE, (wcslen(REPARSE_TAG_REPLICATION_TYPE_REPARSE_POINT) + 1) * sizeof(WCHAR)); wcscpy(ReparseTagTableEntry->ReplicationType, REPARSE_TAG_REPLICATION_TYPE_REPARSE_POINT); ExistingEntry = GTabInsertUniqueEntryNoLock(ReparseTagTable, ReparseTagTableEntry, ReparseTagType, NULL); FRS_ASSERT(ExistingEntry == NULL);
//
// Read the info from the registry.
//
WStatus = CfgRegOpenKey(FKC_REPARSE_TAG_KEY, NULL, 0, &hKey); CLEANUP_WS(4, "++ WARN - Cannot open reparse tag key.", WStatus, Exit);
while(WStatus == ERROR_SUCCESS) { SubKeySize = MAX_PATH;
ReparseTagTableEntry = FrsAllocTypeSize(REPARSE_TAG_TABLE_ENTRY_TYPE, 0);
ReparseTagType = FrsAlloc(sizeof(DWORD));
WStatus = RegEnumKeyEx(hKey, // handle to key to enumerate
Index, // subkey index
SubKey, // subkey name
&SubKeySize, // size of subkey buffer
NULL, // reserved
NULL, // class string buffer
NULL, // size of class string buffer
&LastWriteTime // last write time
);
if(WStatus == ERROR_SUCCESS) { WStatus = CfgRegReadDWord(FKC_REPARSE_TAG_TYPE, SubKey, 0, ReparseTagType); }
if(WStatus == ERROR_SUCCESS) { WStatus = CfgRegReadString(FKC_REPARSE_TAG_REPLICATION_TYPE, SubKey, 0, &(ReparseTagTableEntry->ReplicationType)); }
if(WStatus == ERROR_SUCCESS){ ExistingEntry = GTabInsertUniqueEntryNoLock(ReparseTagTable, ReparseTagTableEntry, ReparseTagType, NULL); if(ExistingEntry) { //
// There is already an entry for this reparse tag type.
// Replace it.
//
FrsFree(ExistingEntry->ReplicationType); ExistingEntry->ReplicationType = ReparseTagTableEntry->ReplicationType; ReparseTagTableEntry->ReplicationType = NULL;
//
// The entry we allocated wasn't used.
// Free it up.
//
FrsFreeType(ReparseTagTableEntry); ReparseTagTableEntry = NULL;
} Index++; }
ReparseTagTableEntry = NULL; ReparseTagType = NULL;
}
Exit:
GTabUnLockTable(ReparseTagTable);
FRS_REG_CLOSE(hKey); return WStatus; }
|