You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
735 lines
21 KiB
735 lines
21 KiB
/*++
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
pnpreg.c
|
|
|
|
Abstract:
|
|
|
|
This module contains code to performs "locking" and "unlocking" of the Plug
|
|
and Play "Enum" branch in the registry. It is for development purposes
|
|
only.
|
|
|
|
The tool "locks" the Enum branch by granting Full Control of the Enum key
|
|
and all subkeys to LocalSystem only. All others are granted Read access,
|
|
except for the "Device Parameters" subkeys of each instance key, to which
|
|
Admins are always granted Full Control. This is the default security
|
|
configuration on the Enum branch.
|
|
|
|
The tool "unlocks" the Enum branch by granting Full Control to
|
|
Administrators and LocalSystem to all subkeys. Effectively, all Enum
|
|
subkeys have the same permissions as the "Device Parameters" key. This mode
|
|
lowers the barrier for users to make changes to the registry directly,
|
|
rather than by the Plug and Play manager. This configuration level should
|
|
not be maintained on a running system for any length of time.
|
|
|
|
Author:
|
|
|
|
Robert B. Nelson (robertn) 10-Feb-1998
|
|
|
|
Revision History:
|
|
|
|
10-Feb-1998 Robert B. Nelson (robertn)
|
|
|
|
Creation and initial implementation.
|
|
|
|
17-Apr-2002 James G. Cavalaris (jamesca)
|
|
|
|
Modified ACLs to reflect current Enum branch permissions.
|
|
|
|
--*/
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <tchar.h>
|
|
#include <aclapi.h>
|
|
#include <regstr.h>
|
|
#include <strsafe.h>
|
|
|
|
|
|
PSID g_pWorldSid;
|
|
PSID g_pAdminSid;
|
|
PSID g_pSystemSid;
|
|
|
|
SECURITY_DESCRIPTOR g_DeviceParametersSD;
|
|
PACL g_pDeviceParametersDacl;
|
|
|
|
SECURITY_DESCRIPTOR g_LockedPrivateKeysSD;
|
|
PACL g_pLockedPrivateKeysDacl;
|
|
|
|
|
|
#if DBG || UMODETEST
|
|
#define DBGF_ERRORS 0x00000001
|
|
#define DBGF_WARNINGS 0x00000002
|
|
|
|
#define DBGF_REGISTRY 0x00000010
|
|
|
|
void RegFixDebugMessage(LPTSTR format, ...);
|
|
#define DBGTRACE(l, x) (g_RegFixDebugFlag & (l) ? RegFixDebugMessage x : (void)0)
|
|
|
|
DWORD g_RegFixDebugFlag = DBGF_WARNINGS | DBGF_ERRORS;
|
|
|
|
TCHAR g_szCurrentKeyName[4096];
|
|
DWORD g_dwCurrentKeyNameLength = 0;
|
|
|
|
#else
|
|
#define DBGTRACE(l, x)
|
|
#endif
|
|
|
|
|
|
|
|
VOID
|
|
FreeSecurityDescriptors(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function deallocates the data structures allocated and initialized by
|
|
CreateDeviceParametersSD.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (g_pDeviceParametersDacl != NULL) {
|
|
LocalFree(g_pDeviceParametersDacl);
|
|
g_pDeviceParametersDacl = NULL;
|
|
}
|
|
|
|
if (g_pLockedPrivateKeysDacl != NULL) {
|
|
LocalFree(g_pLockedPrivateKeysDacl);
|
|
g_pLockedPrivateKeysDacl = NULL;
|
|
}
|
|
|
|
if (g_pAdminSid != NULL) {
|
|
FreeSid(g_pAdminSid);
|
|
g_pAdminSid = NULL;
|
|
}
|
|
|
|
if (g_pWorldSid != NULL) {
|
|
FreeSid(g_pWorldSid);
|
|
g_pWorldSid = NULL;
|
|
}
|
|
|
|
if (g_pSystemSid != NULL) {
|
|
FreeSid(g_pSystemSid);
|
|
g_pSystemSid = NULL;
|
|
}
|
|
|
|
return;
|
|
|
|
} // FreeSecurityDescriptors
|
|
|
|
|
|
|
|
BOOL
|
|
CreateSecurityDescriptors(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates a properly initialized Security Descriptor for the
|
|
Device Parameters key and its subkeys. The SIDs and DACL created by this
|
|
routine must be freed by calling FreeDeviceParametersSD.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE if all required security descriptors were successfully created,
|
|
otherwise returns FALSE.
|
|
|
|
--*/
|
|
|
|
{
|
|
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
|
SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
|
|
|
|
EXPLICIT_ACCESS ExplicitAccess[3];
|
|
|
|
DWORD dwError;
|
|
BOOL bSuccess;
|
|
|
|
DWORD i;
|
|
|
|
//
|
|
// Create SIDs - Admins and System
|
|
//
|
|
|
|
bSuccess = AllocateAndInitializeSid( &NtAuthority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0, 0, 0, 0, 0, 0,
|
|
&g_pAdminSid);
|
|
|
|
bSuccess = bSuccess && AllocateAndInitializeSid( &NtAuthority,
|
|
1,
|
|
SECURITY_LOCAL_SYSTEM_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&g_pSystemSid);
|
|
|
|
bSuccess = bSuccess && AllocateAndInitializeSid( &WorldAuthority,
|
|
1,
|
|
SECURITY_WORLD_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&g_pWorldSid);
|
|
|
|
if (bSuccess) {
|
|
|
|
//
|
|
// Initialize Access structures describing the ACEs we want:
|
|
// System Full Control
|
|
// World Read
|
|
// Admins Full Control
|
|
//
|
|
// We'll take advantage of the fact that the unlocked private keys is
|
|
// the same as the device parameters key and they are a superset of the
|
|
// locked private keys.
|
|
//
|
|
// When we create the DACL for the private key we'll specify a subset of
|
|
// the ExplicitAccess array.
|
|
//
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
ExplicitAccess[i].grfAccessMode = SET_ACCESS;
|
|
ExplicitAccess[i].grfInheritance = CONTAINER_INHERIT_ACE;
|
|
ExplicitAccess[i].Trustee.pMultipleTrustee = NULL;
|
|
ExplicitAccess[i].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
|
|
ExplicitAccess[i].Trustee.TrusteeForm = TRUSTEE_IS_SID;
|
|
ExplicitAccess[i].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
|
|
}
|
|
|
|
ExplicitAccess[0].grfAccessPermissions = KEY_ALL_ACCESS;
|
|
ExplicitAccess[0].Trustee.ptstrName = (LPTSTR)g_pSystemSid;
|
|
|
|
ExplicitAccess[1].grfAccessPermissions = KEY_READ;
|
|
ExplicitAccess[1].Trustee.ptstrName = (LPTSTR)g_pWorldSid;
|
|
|
|
ExplicitAccess[2].grfAccessPermissions = KEY_ALL_ACCESS;
|
|
ExplicitAccess[2].Trustee.ptstrName = (LPTSTR)g_pAdminSid;
|
|
|
|
//
|
|
// Create the DACL with all of the above ACEs for the DeviceParameters
|
|
//
|
|
dwError = SetEntriesInAcl( 3,
|
|
ExplicitAccess,
|
|
NULL,
|
|
&g_pDeviceParametersDacl );
|
|
|
|
if (dwError == ERROR_SUCCESS) {
|
|
//
|
|
// Create the DACL with just the system and world ACEs for the
|
|
// locked private keys.
|
|
//
|
|
dwError = SetEntriesInAcl( 2,
|
|
ExplicitAccess,
|
|
NULL,
|
|
&g_pLockedPrivateKeysDacl );
|
|
}
|
|
|
|
bSuccess = dwError == ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Initialize the DeviceParameters security descriptor
|
|
//
|
|
bSuccess = bSuccess && InitializeSecurityDescriptor( &g_DeviceParametersSD,
|
|
SECURITY_DESCRIPTOR_REVISION );
|
|
|
|
//
|
|
// Set the new DACL in the security descriptor
|
|
//
|
|
bSuccess = bSuccess && SetSecurityDescriptorDacl( &g_DeviceParametersSD,
|
|
TRUE,
|
|
g_pDeviceParametersDacl,
|
|
FALSE);
|
|
|
|
//
|
|
// validate the new security descriptor
|
|
//
|
|
bSuccess = bSuccess && IsValidSecurityDescriptor( &g_DeviceParametersSD );
|
|
|
|
|
|
//
|
|
// Initialize the DeviceParameters security descriptor
|
|
//
|
|
bSuccess = bSuccess && InitializeSecurityDescriptor( &g_LockedPrivateKeysSD,
|
|
SECURITY_DESCRIPTOR_REVISION );
|
|
|
|
//
|
|
// Set the new DACL in the security descriptor
|
|
//
|
|
bSuccess = bSuccess && SetSecurityDescriptorDacl( &g_LockedPrivateKeysSD,
|
|
TRUE,
|
|
g_pLockedPrivateKeysDacl,
|
|
FALSE);
|
|
|
|
//
|
|
// validate the new security descriptor
|
|
//
|
|
bSuccess = bSuccess && IsValidSecurityDescriptor( &g_LockedPrivateKeysSD );
|
|
|
|
|
|
if (!bSuccess) {
|
|
FreeSecurityDescriptors();
|
|
}
|
|
|
|
return bSuccess;
|
|
|
|
} // CreateSecurityDescriptors
|
|
|
|
|
|
|
|
VOID
|
|
EnumKeysAndApplyDacls(
|
|
IN HKEY hParentKey,
|
|
IN LPTSTR pszKeyName,
|
|
IN DWORD dwLevel,
|
|
IN BOOL bInDeviceParameters,
|
|
IN BOOL bApplyTopDown,
|
|
IN PSECURITY_DESCRIPTOR pPrivateKeySD,
|
|
IN PSECURITY_DESCRIPTOR pDeviceParametersSD
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function applies the DACL in pSD to all the keys rooted at hKey
|
|
including hKey itself.
|
|
|
|
Arguments:
|
|
|
|
hParentKey Handle to a registry key.
|
|
pszKeyName Name of the key.
|
|
dwLevel Number of levels remaining to recurse.
|
|
pSD Pointer to a security descriptor containing a DACL.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG RegStatus;
|
|
DWORD dwMaxSubKeySize;
|
|
LPTSTR pszSubKey;
|
|
DWORD index;
|
|
HKEY hKey;
|
|
BOOL bNewInDeviceParameters;
|
|
|
|
#if DBG || UMODETEST
|
|
DWORD dwStartKeyNameLength = g_dwCurrentKeyNameLength;
|
|
|
|
if (g_dwCurrentKeyNameLength != 0) {
|
|
g_szCurrentKeyName[ g_dwCurrentKeyNameLength++ ] = TEXT('\\');
|
|
}
|
|
|
|
if (SUCCEEDED(StringCchCopy(
|
|
&g_szCurrentKeyName[g_dwCurrentKeyNameLength],
|
|
(sizeof(g_szCurrentKeyName) / sizeof(g_szCurrentKeyName[0])) -
|
|
g_dwCurrentKeyNameLength,
|
|
pszKeyName))) {
|
|
g_dwCurrentKeyNameLength += (DWORD)_tcslen(pszKeyName);
|
|
}
|
|
|
|
#endif
|
|
|
|
DBGTRACE( DBGF_REGISTRY,
|
|
(TEXT("EnumKeysAndApplyDacls(0x%08X, \"%s\", %d, %s, %s, 0x%08X, 0x%08X)\n"),
|
|
hParentKey,
|
|
g_szCurrentKeyName,
|
|
dwLevel,
|
|
bInDeviceParameters ? TEXT("TRUE") : TEXT("FALSE"),
|
|
bApplyTopDown ? TEXT("TRUE") : TEXT("FALSE"),
|
|
pPrivateKeySD,
|
|
pDeviceParametersSD) );
|
|
|
|
if (bApplyTopDown) {
|
|
|
|
RegStatus = RegOpenKeyEx( hParentKey,
|
|
pszKeyName,
|
|
0,
|
|
WRITE_DAC,
|
|
&hKey
|
|
);
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
DBGTRACE( DBGF_ERRORS,
|
|
(TEXT("EnumKeysAndApplyDacls(\"%s\") RegOpenKeyEx() failed, error = %d\n"),
|
|
g_szCurrentKeyName, RegStatus));
|
|
|
|
return;
|
|
}
|
|
|
|
DBGTRACE( DBGF_REGISTRY,
|
|
(TEXT("Setting security on %s on the way down\n"),
|
|
g_szCurrentKeyName) );
|
|
|
|
//
|
|
// apply the new security to the registry key
|
|
//
|
|
RegStatus = RegSetKeySecurity( hKey,
|
|
DACL_SECURITY_INFORMATION,
|
|
bInDeviceParameters ?
|
|
pDeviceParametersSD :
|
|
pPrivateKeySD
|
|
);
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
DBGTRACE( DBGF_ERRORS,
|
|
(TEXT("EnumKeysAndApplyDacls(\"%s\") RegSetKeySecurity() failed, error = %d\n"),
|
|
g_szCurrentKeyName, RegStatus));
|
|
}
|
|
|
|
//
|
|
// Close the key and reopen it later for read (which hopefully was just
|
|
// granted in the DACL we just wrote
|
|
//
|
|
RegCloseKey( hKey );
|
|
}
|
|
|
|
RegStatus = RegOpenKeyEx( hParentKey,
|
|
pszKeyName,
|
|
0,
|
|
KEY_READ | WRITE_DAC,
|
|
&hKey
|
|
);
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
DBGTRACE( DBGF_ERRORS,
|
|
(TEXT("EnumKeysAndApplyDacls(\"%s\") RegOpenKeyEx() failed, error = %d\n"),
|
|
g_szCurrentKeyName, RegStatus));
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Determine length of longest subkey
|
|
//
|
|
RegStatus = RegQueryInfoKey( hKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&dwMaxSubKeySize,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL );
|
|
|
|
if (RegStatus == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Allocate a buffer to hold the subkey names. RegQueryInfoKey returns the
|
|
// size in characters and doesn't include the NUL terminator.
|
|
//
|
|
pszSubKey = LocalAlloc(0, ++dwMaxSubKeySize * sizeof(TCHAR));
|
|
|
|
if (pszSubKey != NULL) {
|
|
|
|
//
|
|
// Enumerate all the subkeys and then call ourselves recursively for each
|
|
// until dwLevel reaches 0.
|
|
//
|
|
|
|
for (index = 0; ; index++) {
|
|
|
|
RegStatus = RegEnumKey( hKey,
|
|
index,
|
|
pszSubKey,
|
|
dwMaxSubKeySize
|
|
);
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
|
|
if (RegStatus != ERROR_NO_MORE_ITEMS) {
|
|
|
|
DBGTRACE( DBGF_ERRORS,
|
|
(TEXT("EnumKeysAndApplyDacls(\"%s\") RegEnumKeyEx() failed, error = %d\n"),
|
|
g_szCurrentKeyName,
|
|
RegStatus) );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
bNewInDeviceParameters = bInDeviceParameters ||
|
|
(dwLevel == 3 &&
|
|
_tcsicmp( pszSubKey,
|
|
REGSTR_KEY_DEVICEPARAMETERS ) == 0);
|
|
|
|
EnumKeysAndApplyDacls( hKey,
|
|
pszSubKey,
|
|
dwLevel + 1,
|
|
bNewInDeviceParameters,
|
|
bApplyTopDown,
|
|
pPrivateKeySD,
|
|
pDeviceParametersSD
|
|
);
|
|
}
|
|
|
|
LocalFree( pszSubKey );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGTRACE( DBGF_ERRORS,
|
|
(TEXT("EnumKeysAndApplyDacls(\"%s\") RegQueryInfoKey() failed, error = %d\n"),
|
|
g_szCurrentKeyName, RegStatus));
|
|
}
|
|
|
|
if (!bApplyTopDown) {
|
|
|
|
DBGTRACE( DBGF_REGISTRY,
|
|
(TEXT("Setting security on %s on the way back up\n"),
|
|
g_szCurrentKeyName) );
|
|
|
|
//
|
|
// apply the new security to the registry key
|
|
//
|
|
RegStatus = RegSetKeySecurity( hKey,
|
|
DACL_SECURITY_INFORMATION,
|
|
bInDeviceParameters ?
|
|
pDeviceParametersSD :
|
|
pPrivateKeySD
|
|
);
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
DBGTRACE( DBGF_ERRORS,
|
|
(TEXT("EnumKeysAndApplyDacls(\"%s\") RegSetKeySecurity() failed, error = %d\n"),
|
|
g_szCurrentKeyName, RegStatus));
|
|
}
|
|
}
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
#if DBG || UMODETEST
|
|
g_dwCurrentKeyNameLength = dwStartKeyNameLength;
|
|
g_szCurrentKeyName[g_dwCurrentKeyNameLength] = TEXT('\0');
|
|
#endif
|
|
|
|
return;
|
|
|
|
} // EnumKeysAndApplyDacls
|
|
|
|
|
|
|
|
VOID
|
|
LockUnlockEnumTree(
|
|
LPTSTR pszMachineName,
|
|
BOOL bLock
|
|
)
|
|
{
|
|
HKEY hParentKey = NULL;
|
|
LONG RegStatus;
|
|
|
|
if (pszMachineName != NULL) {
|
|
|
|
RegStatus = RegConnectRegistry( pszMachineName,
|
|
HKEY_LOCAL_MACHINE,
|
|
&hParentKey );
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
DBGTRACE( DBGF_ERRORS,
|
|
(TEXT("Could not connect to remote registry on %s, status = %d\n"),
|
|
pszMachineName,
|
|
RegStatus) );
|
|
return;
|
|
}
|
|
|
|
} else {
|
|
|
|
hParentKey = HKEY_LOCAL_MACHINE;
|
|
}
|
|
|
|
if (CreateSecurityDescriptors()) {
|
|
|
|
EnumKeysAndApplyDacls( hParentKey,
|
|
REGSTR_PATH_SYSTEMENUM,
|
|
0,
|
|
FALSE,
|
|
!bLock,
|
|
bLock ? &g_LockedPrivateKeysSD : &g_DeviceParametersSD,
|
|
&g_DeviceParametersSD
|
|
);
|
|
|
|
FreeSecurityDescriptors();
|
|
}
|
|
|
|
if (pszMachineName != NULL) {
|
|
RegCloseKey(hParentKey);
|
|
}
|
|
|
|
return;
|
|
|
|
} // LockUnlockEnumTree
|
|
|
|
|
|
|
|
#if DBG || UMODETEST
|
|
void
|
|
RegFixDebugMessage(
|
|
LPTSTR format,
|
|
...
|
|
)
|
|
{
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
|
|
|
_vtprintf(format, args);
|
|
|
|
return;
|
|
|
|
} // RegFixDebugMessage
|
|
#endif
|
|
|
|
|
|
|
|
#if UMODETEST
|
|
void
|
|
usage(int argc, TCHAR **argv)
|
|
{
|
|
PTCHAR pszProgram;
|
|
|
|
UNREFERENCED_PARAMETER(argc);
|
|
|
|
if ((pszProgram = _tcsrchr(argv[0], TEXT('\\'))) != NULL) {
|
|
pszProgram++;
|
|
} else {
|
|
pszProgram = argv[0];
|
|
}
|
|
|
|
_tprintf(TEXT("%s: Lock or Unlock PnP Registry (Enum key)\n\n"), pszProgram);
|
|
_tprintf(TEXT("Usage: %s [-m <machine>] -l | -u\n"), pszProgram);
|
|
_tprintf(TEXT(" -m <machine> Remote machine without leading \\\\\n"));
|
|
_tprintf(TEXT(" -l Locks Enum key\n"));
|
|
_tprintf(TEXT(" -u Unlocks Enum key\n\n"));
|
|
_tprintf(TEXT("Note: -m is optional. Only one of -l or -u may be used.\n"));
|
|
return;
|
|
}
|
|
|
|
int __cdecl
|
|
_tmain(int argc, TCHAR **argv)
|
|
{
|
|
LPTSTR pszMachineName = NULL;
|
|
LPTSTR pszArg;
|
|
int idxArg;
|
|
|
|
if ( argc == 1 )
|
|
{
|
|
usage(argc, argv);
|
|
return 0;
|
|
}
|
|
|
|
for (idxArg = 1; idxArg < argc; idxArg++)
|
|
{
|
|
pszArg = argv[ idxArg ];
|
|
|
|
if (*pszArg == '/' || *pszArg == '-')
|
|
{
|
|
pszArg++;
|
|
|
|
while (pszArg != NULL && *pszArg != '\0') {
|
|
|
|
switch (*pszArg)
|
|
{
|
|
case '/': // Ignore these, caused by cmds like /m/l
|
|
pszArg++;
|
|
break;
|
|
|
|
case 'l':
|
|
case 'L':
|
|
pszArg++;
|
|
LockUnlockEnumTree( pszMachineName, TRUE );
|
|
break;
|
|
|
|
case 'm':
|
|
case 'M':
|
|
pszArg++;
|
|
|
|
if (*pszArg == ':' || *pszArg == '=')
|
|
{
|
|
if (pszArg[ 1 ] != '\0')
|
|
{
|
|
pszMachineName = ++pszArg;
|
|
}
|
|
}
|
|
else if (*pszArg != '\0')
|
|
{
|
|
pszMachineName = pszArg;
|
|
}
|
|
else if ((idxArg + 1) < argc && (argv[ idxArg + 1 ][0] != '/' && argv[ idxArg + 1 ][0] != '-'))
|
|
{
|
|
pszMachineName = argv[ ++idxArg ];
|
|
}
|
|
|
|
if (pszMachineName == NULL)
|
|
{
|
|
_tprintf(
|
|
TEXT("%c%c : missing machine name argument\n"),
|
|
argv[ idxArg ][ 0 ], pszArg [ - 1 ]
|
|
);
|
|
|
|
usage(argc, argv);
|
|
|
|
return 1;
|
|
}
|
|
pszArg = NULL;
|
|
break;
|
|
|
|
case 'u':
|
|
case 'U':
|
|
pszArg++;
|
|
|
|
LockUnlockEnumTree( pszMachineName, FALSE );
|
|
break;
|
|
|
|
case 'v':
|
|
case 'V':
|
|
pszArg++;
|
|
|
|
g_RegFixDebugFlag |= DBGF_REGISTRY;
|
|
break;
|
|
|
|
default:
|
|
_tprintf(
|
|
TEXT("%c%c : invalid option\n"),
|
|
argv[ idxArg ][ 0 ], *pszArg
|
|
);
|
|
pszArg++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
|