windows-nt/Source/XPSP1/NT/ds/netapi/svcimgs/ntrepl/util/config.c
2020-09-26 16:20:57 +08:00

3735 lines
139 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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
);
//
// 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_LOG_FILES , 0 , 8, 2 },
{FKC_DEBUG_LOG_SEVERITY , 0 , 5, 0 },
{FKC_DEBUG_MAX_LOG , 0 , MAXULONG, 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_STAGING_LIMIT , 2*1024, 64*1024, 16*1024 },
{FKC_NTFS_JRNL_SIZE , 1 , 128, 8 },
{FKC_MAX_NUMBER_REPLICA_SETS, 1 , 30, 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, MAXULONG, 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, MAXULONG, 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, MAXULONG, 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},
// 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, MAXULONG, (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},
// 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, MAXULONG, (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, MAXULONG, (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: 32 Meg
{FRS_CONFIG_SECTION, L"Ntfs Journal size in MB", UNITS_MBYTES,
REG_DWORD, DT_ULONG, 4, 128, (32), 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.
//
{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.
//
{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},
//
// Disable compression of staging files for local changes.
// This member will continue to install and send compressed files
// unless compression support it explicilt turned off by the
// Debug Disable Compression key.
// OBSOLETE -- WILL BE REMOVED.
//
{FRS_CONFIG_SECTION, L"Disable Compression of Staging Files", UNITS_NONE,
REG_DWORD, DT_BOOL, FALSE, TRUE, (FALSE), EVENT_FRS_NONE, NULL,
FKC_DISABLE_COMPRESSION_STAGING_FILE, FRS_RKF_READ_AT_START |
FRS_RKF_RANGE_CHECK |
FRS_RKF_OK_TO_USE_DEFAULT},
//
// Client side ldap search timeout value. Default is 10 minutes.
//
{FRS_CONFIG_SECTION, L"Ldap Search Timeout In Minutes", UNITS_NONE,
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 is 30 seconds.
//
{FRS_CONFIG_SECTION, L"Ldap Bind Timeout In Seconds", UNITS_NONE,
REG_DWORD, DT_ULONG, 2, MAXULONG, (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},
// 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.
//
// 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, MAXULONG, 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, MAXULONG, 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, MAXULONG, 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, MAXULONG, 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.
// Netlogon\\Parameters\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, MAXULONG, 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, MAXULONG, 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, MAXULONG, 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, MAXULONG, 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\TypesSupported
{FRS_RKEY_EVENTLOG_SOURCE, L"TypesSupported", UNITS_NONE,
REG_DWORD, DT_ULONG, 0, MAXULONG, 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},
/******************************************************************************
*******************************************************************************
** **
** 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, MAXULONG, 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, MAXULONG, 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, MAXULONG, 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, MAXULONG, 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, MAXULONG, 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, MAXULONG, 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, MAXULONG, 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, MAXULONG, 0, EVENT_FRS_NONE, NULL,
FKC_REPLICA_CXTION_LINKAGE_EXPORT, 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) {
RegCloseKey(hKeyParent);
hKeyParent = INVALID_HANDLE_VALUE;
}
} // end while()
//
// Return the key handle to the caller.
//
*hKeyRet = hKey;
WStatus = ERROR_SUCCESS;
RETURN:
if ((hKeyParent != HKEY_LOCAL_MACHINE) && HANDLE_IS_VALID(hKeyParent)) {
RegCloseKey(hKeyParent);
}
if (!WIN_SUCCESS(WStatus)) {
DPRINT_WS(5, "ERROR - FrsRegOpenKey Failed.", WStatus);
if ((hKey != HKEY_LOCAL_MACHINE) && HANDLE_IS_VALID(hKey)) {
RegCloseKey(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) && HANDLE_IS_VALID(hKey)) {
RegCloseKey(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) * sizeof(WCHAR));
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) && HANDLE_IS_VALID(hKey)) {
RegCloseKey(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) && HANDLE_IS_VALID(hKey)) {
RegCloseKey(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) && HANDLE_IS_VALID(hKey)) {
RegCloseKey(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) && HANDLE_IS_VALID(hKey)) {
RegCloseKey(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
)
/*++
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.
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)) {
//
// 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;
DPRINT1(4, ":FK: %ws is enabled\n", CfgRegGetValueName(KeyIndex));
} else {
*Enabled = 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 = 0;
HKEY HNewBackupKey = 0;
HKEY HKeysNotToRestore = 0;
//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:
if (HOldBackupKey) {
RegCloseKey(HOldBackupKey);
}
if (HNewBackupKey) {
RegCloseKey(HNewBackupKey);
}
if (HKeysNotToRestore) {
RegCloseKey(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);
}