461 lines
13 KiB
C
461 lines
13 KiB
C
|
/*
|
|||
|
|
|||
|
regback.c - registry backup program
|
|||
|
|
|||
|
this program allows the user to back up active registry hives,
|
|||
|
while the system is running.
|
|||
|
|
|||
|
basic structure:
|
|||
|
|
|||
|
DoFullBackup ennumerate entries in HiveList, computes which
|
|||
|
ones to save and where, and calls DoSpecificBackup for each.
|
|||
|
|
|||
|
Three argument case of app is just a call to DoSpecificBackup.
|
|||
|
|
|||
|
*/
|
|||
|
|
|||
|
#include "regutil.h"
|
|||
|
|
|||
|
#define MACH_NAME L"machine"
|
|||
|
#define USERS_NAME L"users"
|
|||
|
|
|||
|
BOOLEAN DumpUserHive;
|
|||
|
PWSTR DirectoryPath;
|
|||
|
PWSTR UserHiveFileName;
|
|||
|
PWSTR HivePath;
|
|||
|
HKEY HiveRoot;
|
|||
|
PWSTR HiveName;
|
|||
|
|
|||
|
LONG
|
|||
|
DoFullBackup(
|
|||
|
PWSTR DirectoryPath,
|
|||
|
PWSTR UserHiveFileName
|
|||
|
);
|
|||
|
|
|||
|
LONG
|
|||
|
DoSpecificBackup(
|
|||
|
PWSTR HivePath,
|
|||
|
HKEY HiveRoot,
|
|||
|
PWSTR HiveName
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
CtrlCHandler(
|
|||
|
IN ULONG CtrlType
|
|||
|
)
|
|||
|
{
|
|||
|
RTDisconnectFromRegistry( &RegistryContext );
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
int
|
|||
|
__cdecl
|
|||
|
main(
|
|||
|
int argc,
|
|||
|
char *argv[]
|
|||
|
)
|
|||
|
{
|
|||
|
char *s;
|
|||
|
LONG Error;
|
|||
|
PWSTR w;
|
|||
|
|
|||
|
if (!RTEnableBackupRestorePrivilege()) {
|
|||
|
FatalError( "Unable to enable backup/restore priviledge.", 0, 0 );
|
|||
|
}
|
|||
|
|
|||
|
InitCommonCode( CtrlCHandler,
|
|||
|
"REGBACK",
|
|||
|
"directoryPath [-u | -U outputFile]",
|
|||
|
"directoryPath specifies where to save the output files.\n"
|
|||
|
"\n"
|
|||
|
"-u specifies to dump the logged on user's profile. Default name is\n"
|
|||
|
" username.dat User -U with a file name to save it under a different name.\n"
|
|||
|
"\n"
|
|||
|
"outputFile specifies the file name to use for the user profile\n"
|
|||
|
"\n"
|
|||
|
"If the -m switch is specified to backup the registry of a remote machine\n"
|
|||
|
" then the directoryPath is relative to that machine.\n"
|
|||
|
);
|
|||
|
|
|||
|
DirectoryPath = NULL;
|
|||
|
UserHiveFileName = NULL;
|
|||
|
HivePath = NULL;
|
|||
|
HiveRoot = NULL;
|
|||
|
HiveName = NULL;
|
|||
|
while (--argc) {
|
|||
|
s = *++argv;
|
|||
|
if (*s == '-' || *s == '/') {
|
|||
|
while (*++s) {
|
|||
|
switch( tolower( *s ) ) {
|
|||
|
case 'u':
|
|||
|
DumpUserHive = TRUE;
|
|||
|
if (*s == 'U') {
|
|||
|
if (!--argc) {
|
|||
|
Usage( "Missing argument to -U switch", 0 );
|
|||
|
}
|
|||
|
|
|||
|
UserHiveFileName = GetArgAsUnicode( *++argv );
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
CommonSwitchProcessing( &argc, &argv, *s );
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
if (DirectoryPath == NULL) {
|
|||
|
HivePath = DirectoryPath = GetArgAsUnicode( s );
|
|||
|
}
|
|||
|
else
|
|||
|
if (HivePath != NULL) {
|
|||
|
if (HiveRoot == NULL) {
|
|||
|
w = GetArgAsUnicode( s );
|
|||
|
if (!_wcsicmp( w, MACH_NAME )) {
|
|||
|
HiveRoot = HKEY_LOCAL_MACHINE;
|
|||
|
}
|
|||
|
else
|
|||
|
if (!_wcsicmp( w, USERS_NAME )) {
|
|||
|
HiveRoot = HKEY_USERS;
|
|||
|
}
|
|||
|
else {
|
|||
|
Usage( "Invalid hive type specified (%ws)", (ULONG_PTR)w );
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
if (HiveName == NULL) {
|
|||
|
HiveName = GetArgAsUnicode( s );
|
|||
|
}
|
|||
|
else {
|
|||
|
Usage( "Too many arguments specified.", 0 );
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
Usage( NULL, 0 );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (DirectoryPath == NULL) {
|
|||
|
Usage( NULL, 0 );
|
|||
|
}
|
|||
|
|
|||
|
Error = RTConnectToRegistry( MachineName,
|
|||
|
HiveFileName,
|
|||
|
HiveRootName,
|
|||
|
Win95Path,
|
|||
|
Win95UserPath,
|
|||
|
NULL,
|
|||
|
&RegistryContext
|
|||
|
);
|
|||
|
if (Error != NO_ERROR) {
|
|||
|
FatalError( "Unable to access registry specifed (%u)", Error, 0 );
|
|||
|
}
|
|||
|
|
|||
|
if (HiveRoot == NULL) {
|
|||
|
Error = DoFullBackup( DirectoryPath, UserHiveFileName );
|
|||
|
}
|
|||
|
else {
|
|||
|
Error = DoSpecificBackup( HivePath, HiveRoot, HiveName );
|
|||
|
}
|
|||
|
|
|||
|
RTDisconnectFromRegistry( &RegistryContext );
|
|||
|
return Error;
|
|||
|
}
|
|||
|
|
|||
|
typedef BOOL (*PFNGETPROFILESDIRECTORYW)(LPWSTR lpProfile, LPDWORD dwSize);
|
|||
|
|
|||
|
|
|||
|
LONG
|
|||
|
DoFullBackup(
|
|||
|
PWSTR DirectoryPath,
|
|||
|
PWSTR UserHiveFileName
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Scan the hivelist, for each hive which has a file (i.e. not hardware)
|
|||
|
if the file is in the config dir (e.g. not some remote profile) call
|
|||
|
DoSpecificBackup to save the hive out.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DirectoryPath - specifies where to write the output files.
|
|||
|
|
|||
|
UserHiveFileName - optional parameter that specifies the name of the file
|
|||
|
to use when saving the user profile. If NULL, then
|
|||
|
username.dat is used.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
0 for success, otherwise, non-zero error code.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PWSTR w;
|
|||
|
LONG Error;
|
|||
|
HKEY HiveListKey;
|
|||
|
PWSTR KeyName;
|
|||
|
PWSTR FileName;
|
|||
|
PWSTR Name;
|
|||
|
DWORD ValueIndex;
|
|||
|
DWORD ValueType;
|
|||
|
DWORD ValueNameLength;
|
|||
|
DWORD ValueDataLength;
|
|||
|
WCHAR ConfigPath[ MAX_PATH ];
|
|||
|
WCHAR ProfilePath[ MAX_PATH ];
|
|||
|
WCHAR HiveName[ MAX_PATH ];
|
|||
|
WCHAR HivePath[ MAX_PATH ];
|
|||
|
WCHAR FilePath[ MAX_PATH ];
|
|||
|
DWORD dwSize;
|
|||
|
HANDLE hInstDll;
|
|||
|
PFNGETPROFILESDIRECTORYW pfnGetProfilesDirectory;
|
|||
|
|
|||
|
|
|||
|
hInstDll = LoadLibrary (TEXT("userenv.dll"));
|
|||
|
|
|||
|
if (!hInstDll) {
|
|||
|
return (GetLastError());
|
|||
|
}
|
|||
|
|
|||
|
pfnGetProfilesDirectory = (PFNGETPROFILESDIRECTORYW)GetProcAddress (hInstDll,
|
|||
|
"GetProfilesDirectoryW");
|
|||
|
|
|||
|
if (!pfnGetProfilesDirectory) {
|
|||
|
FreeLibrary (hInstDll);
|
|||
|
return (GetLastError());
|
|||
|
}
|
|||
|
|
|||
|
dwSize = MAX_PATH;
|
|||
|
if (!pfnGetProfilesDirectory(ProfilePath, &dwSize)) {
|
|||
|
FreeLibrary (hInstDll);
|
|||
|
return (GetLastError());
|
|||
|
}
|
|||
|
|
|||
|
FreeLibrary (hInstDll);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// get handle to hivelist key
|
|||
|
//
|
|||
|
KeyName = L"HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Hivelist";
|
|||
|
Error = RTOpenKey( &RegistryContext,
|
|||
|
NULL,
|
|||
|
KeyName,
|
|||
|
MAXIMUM_ALLOWED,
|
|||
|
0,
|
|||
|
&HiveListKey
|
|||
|
);
|
|||
|
|
|||
|
if (Error != NO_ERROR) {
|
|||
|
FatalError( "Unable to open key '%ws' (%u)\n",
|
|||
|
(ULONG_PTR)KeyName,
|
|||
|
(ULONG)Error
|
|||
|
);
|
|||
|
return Error;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// get path data for system hive, which will allow us to compute
|
|||
|
// path name to config dir in form that hivelist uses.
|
|||
|
// (an NT internal form of path) this is NOT the way the path to
|
|||
|
// the config directory should generally be computed.
|
|||
|
//
|
|||
|
|
|||
|
ValueDataLength = sizeof( ConfigPath );
|
|||
|
Error = RTQueryValueKey( &RegistryContext,
|
|||
|
HiveListKey,
|
|||
|
L"\\Registry\\Machine\\System",
|
|||
|
&ValueType,
|
|||
|
&ValueDataLength,
|
|||
|
ConfigPath
|
|||
|
);
|
|||
|
if (Error != NO_ERROR) {
|
|||
|
FatalError( "Unable to query 'SYSTEM' hive path.", 0, Error );
|
|||
|
}
|
|||
|
w = wcsrchr( ConfigPath, L'\\' );
|
|||
|
if (w) {
|
|||
|
*w = UNICODE_NULL;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// ennumerate entries in hivelist. for each entry, find it's hive file
|
|||
|
// path. if it's file path matches ConfigPath, then save it.
|
|||
|
// else, print a message telling the user that it must be saved
|
|||
|
// manually, unless the file name is of the form ....\username\ntuser.dat
|
|||
|
// in which case save it as username.dat
|
|||
|
//
|
|||
|
for (ValueIndex = 0; TRUE; ValueIndex++) {
|
|||
|
ValueType = REG_NONE;
|
|||
|
ValueNameLength = sizeof( HiveName ) / sizeof( WCHAR );
|
|||
|
ValueDataLength = sizeof( HivePath );
|
|||
|
Error = RTEnumerateValueKey( &RegistryContext,
|
|||
|
HiveListKey,
|
|||
|
ValueIndex,
|
|||
|
&ValueType,
|
|||
|
&ValueNameLength,
|
|||
|
HiveName,
|
|||
|
&ValueDataLength,
|
|||
|
HivePath
|
|||
|
);
|
|||
|
if (Error == ERROR_NO_MORE_ITEMS) {
|
|||
|
break;
|
|||
|
}
|
|||
|
else
|
|||
|
if (Error != NO_ERROR) {
|
|||
|
return Error;
|
|||
|
}
|
|||
|
|
|||
|
if (ValueType == REG_SZ && ValueDataLength > sizeof( UNICODE_NULL )) {
|
|||
|
//
|
|||
|
// there's a file, compute it's path, hive branch, etc
|
|||
|
//
|
|||
|
|
|||
|
if (w = wcsrchr( HivePath, L'\\' )) {
|
|||
|
*w++ = UNICODE_NULL;
|
|||
|
}
|
|||
|
FileName = w;
|
|||
|
|
|||
|
if (w = wcsrchr( HiveName, L'\\' )) {
|
|||
|
*w++ = UNICODE_NULL;
|
|||
|
}
|
|||
|
Name = w;
|
|||
|
|
|||
|
HiveRoot = NULL;
|
|||
|
if (w = wcsrchr( HiveName, L'\\' )) {
|
|||
|
w += 1;
|
|||
|
if (!_wcsicmp( w, L"MACHINE" )) {
|
|||
|
HiveRoot = HKEY_LOCAL_MACHINE;
|
|||
|
}
|
|||
|
else
|
|||
|
if (!_wcsicmp( w, L"USER" )) {
|
|||
|
HiveRoot = HKEY_USERS;
|
|||
|
}
|
|||
|
else {
|
|||
|
Error = ERROR_PATH_NOT_FOUND;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (FileName != NULL && Name != NULL && HiveRoot != NULL) {
|
|||
|
if (!wcscmp( ConfigPath, HivePath )) {
|
|||
|
//
|
|||
|
// hive's file is in config dir, we can back it up
|
|||
|
// without fear of collision
|
|||
|
//
|
|||
|
swprintf( FilePath, L"%s\\%s", DirectoryPath, FileName );
|
|||
|
Error = DoSpecificBackup( FilePath,
|
|||
|
HiveRoot,
|
|||
|
Name
|
|||
|
);
|
|||
|
}
|
|||
|
else
|
|||
|
if (DumpUserHive && !_wcsnicmp( ProfilePath, HivePath, wcslen( ProfilePath ) )) {
|
|||
|
//
|
|||
|
// hive's file is in profile dir, we can back it up
|
|||
|
// without fear of collision if we use username.dat
|
|||
|
// for the file name.
|
|||
|
//
|
|||
|
if (UserHiveFileName != NULL) {
|
|||
|
FileName = UserHiveFileName;
|
|||
|
}
|
|||
|
else {
|
|||
|
FileName = wcsrchr(HivePath, '\\') + 1;
|
|||
|
}
|
|||
|
swprintf( FilePath, L"%s\\%s.dat", DirectoryPath, FileName );
|
|||
|
|
|||
|
printf( "%ws %ws %ws\n",
|
|||
|
FilePath,
|
|||
|
HiveRoot == HKEY_LOCAL_MACHINE ? MACH_NAME : USERS_NAME,
|
|||
|
Name
|
|||
|
);
|
|||
|
Error = DoSpecificBackup( FilePath,
|
|||
|
HiveRoot,
|
|||
|
Name
|
|||
|
);
|
|||
|
}
|
|||
|
else {
|
|||
|
printf( "\n***Hive = '%ws'\\'%ws'\nStored in file '%ws'\\'%ws'\n",
|
|||
|
HiveName,
|
|||
|
Name,
|
|||
|
HivePath,
|
|||
|
FileName
|
|||
|
);
|
|||
|
printf( "Must be backed up manually\n" );
|
|||
|
printf( "regback <filename you choose> %ws %ws\n\n",
|
|||
|
HiveRoot == HKEY_LOCAL_MACHINE ? MACH_NAME : USERS_NAME,
|
|||
|
Name
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return Error;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LONG
|
|||
|
DoSpecificBackup(
|
|||
|
PWSTR HivePath,
|
|||
|
HKEY HiveRoot,
|
|||
|
PWSTR HiveName
|
|||
|
)
|
|||
|
/*
|
|||
|
Do backup of one hive to one file. Any valid hive and any
|
|||
|
valid file will do. RegSaveKey does all the real work.
|
|||
|
|
|||
|
Arguments:
|
|||
|
HivePath - file name to pass directly to OS
|
|||
|
|
|||
|
HiveRoot - HKEY_LOCAL_MACHINE or HKEY_USERS
|
|||
|
|
|||
|
HiveName - 1st level subkey under machine or users
|
|||
|
*/
|
|||
|
{
|
|||
|
HKEY HiveKey;
|
|||
|
ULONG Disposition;
|
|||
|
LONG Error;
|
|||
|
char *Reason;
|
|||
|
|
|||
|
//
|
|||
|
// print some status
|
|||
|
//
|
|||
|
printf( "saving %ws to %ws", HiveName, HivePath );
|
|||
|
|
|||
|
//
|
|||
|
// get a handle to the hive. use special create call what will
|
|||
|
// use privileges
|
|||
|
//
|
|||
|
|
|||
|
Reason = "accessing";
|
|||
|
Error = RTCreateKey( &RegistryContext,
|
|||
|
HiveRoot,
|
|||
|
HiveName,
|
|||
|
KEY_READ,
|
|||
|
REG_OPTION_BACKUP_RESTORE,
|
|||
|
NULL,
|
|||
|
&HiveKey,
|
|||
|
&Disposition
|
|||
|
);
|
|||
|
if (Error == NO_ERROR) {
|
|||
|
Reason = "saving";
|
|||
|
Error = RegSaveKey( HiveKey, HivePath, NULL );
|
|||
|
RTCloseKey( &RegistryContext, HiveKey );
|
|||
|
}
|
|||
|
|
|||
|
if (Error != NO_ERROR) {
|
|||
|
printf( " - error %s (%u)\n", Reason, Error );
|
|||
|
}
|
|||
|
else {
|
|||
|
printf( "\n" );
|
|||
|
}
|
|||
|
return Error;
|
|||
|
}
|