MORE INFORMATION
This is normally accomplished by enabling the SeBackupPrivilege and calling
RegSaveKey. The operation can fail with ERROR_ACCESS_DENIED if the caller
does not have access to portions of the key, such as the registry key
HKEY_LOCAL_MACHINE\SECURITY.
If you do not have access to the key, but have backup privilege, pass the
REG_OPTION_BACKUP_RESTORE flag to RegCreateKeyEx in the dwOptions
parameter. This has an effect similar to FILE_FLAG_BACKUP_SEMANTICS with
CreateFile, allowing you to open the key for backup. The resultant key
handle can be used in a subsequent call to RegSaveKey.
To back up the registry from the root, it is necessary to enumerate the
subkeys from the root, opening each subkey with RegCreateKeyEx and saving
the subkey with RegSaveKey.
Sample Code
The following sample source code saves the HKEY_LOCAL_MACHINE registry
key, with each subkey saved to a filename matching the subkey name.
The following function performs the save operation:
LONG SaveRegistrySubKey(
HKEY hKey, // handle of key to save
LPTSTR szSubKey, // pointer to subkey name to save
LPTSTR szSaveFileName // pointer to save path/filename
)
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is an error value.
/* Save HKEY_LOCAL_MACHINE registry key, each subkey saved to a file of
* name subkey
*
* this allows us to get around security restrictions which prevent
* the use of RegSaveKey() on the root key
*
* the optional target machine name is specified in argv[1]
*
* v1.21
* Scott Field (sfield) 01-Apr-1995
*/
#define RTN_OK 0
#define RTN_USAGE 1
#define RTN_ERROR 13
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
LONG SaveRegistrySubKey(HKEY hKey, LPTSTR szSubKey, LPTSTR szSaveFileName);
void PERR(LPTSTR szAPI, DWORD dwLastError);
int main(int argc, char *argv[])
{
TOKEN_PRIVILEGES tp;
HANDLE hToken;
LUID luid;
LONG rc; // contains error value returned by Regxxx()
HKEY hKey; // handle to key we are interested in
LPTSTR MachineName=NULL; // pointer to machine name
DWORD dwSubKeyIndex=0; // index into key
char szSubKey[_MAX_FNAME]; // this should be dynamic.
// _MAX_FNAME is good because this
// is what we happen to save the
// subkey as
DWORD dwSubKeyLength=_MAX_FNAME; // length of SubKey buffer
/*
if (argc != 2) // usage
{
fprintf(stderr,"Usage: %s [<MachineName>]\n", argv[0]);
return RTN_USAGE;
}
*/
// set MachineName == argv[1], if appropriate
if (argc == 2) MachineName=argv[1];
//
// enable backup privilege
//
if(!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES,
&hToken ))
{
PERR("OpenProcessToken", GetLastError() );
return RTN_ERROR;
}
if(!LookupPrivilegeValue(MachineName, SE_BACKUP_NAME, &luid))
{
PERR("LookupPrivilegeValue", GetLastError() );
return RTN_ERROR;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES),
NULL, NULL );
if (GetLastError() != ERROR_SUCCESS)
{
PERR("AdjustTokenPrivileges", GetLastError() );
return RTN_ERROR;
}
// only connect if a machine name specified
if (MachineName != NULL)
{
if((rc=RegConnectRegistry(MachineName,
HKEY_LOCAL_MACHINE,
&hKey)) != ERROR_SUCCESS)
{
PERR("RegConnectRegistry", rc);
return RTN_ERROR;
}
}
else hKey=HKEY_LOCAL_MACHINE;
while((rc=RegEnumKeyEx(
hKey,
dwSubKeyIndex,
szSubKey,
&dwSubKeyLength,
NULL,
NULL,
NULL,
NULL)
) != ERROR_NO_MORE_ITEMS) { // are we done?
if(rc == ERROR_SUCCESS)
{
LONG lRetVal; // return value from SaveRegistrySubKey
#ifdef DEBUG
fprintf(stdout,"Saving %s\n", szSubKey);
#endif
// save registry subkey szSubKey to filename szSubKey
if( (lRetVal=SaveRegistrySubKey(hKey, szSubKey, szSubKey)
) != ERROR_SUCCESS)
{
PERR("SaveRegistrySubKey", lRetVal);
}
// increment index into the key
dwSubKeyIndex++;
// reset buffer size
dwSubKeyLength=_MAX_FNAME;
// Continue the festivities
continue;
}
else
{
//
// note: we need to watch for ERROR_MORE_DATA
// this indicates we need a bigger szSubKey buffer
//
PERR("RegEnumKeyEx", rc);
return RTN_ERROR;
}
} // RegEnumKeyEx
// close registry key we have been working with
RegCloseKey(hKey);
// Revoke all privileges this process holds (including backup)
AdjustTokenPrivileges( hToken, TRUE, NULL, 0, NULL, NULL);
// close handle to process token
CloseHandle(hToken);
return RTN_OK;
}
LONG SaveRegistrySubKey(
HKEY hKey, // handle of key to save
LPTSTR szSubKey, // pointer to subkey name to save
LPTSTR szSaveFileName // pointer to save path/filename
)
{
HKEY hKeyToSave; // Handle of subkey to save
LONG rc; // result code from RegXxx
DWORD dwDisposition;
if((rc=RegCreateKeyEx(hKey,
szSubKey, // Name of subkey to open
0,
NULL,
REG_OPTION_BACKUP_RESTORE, // in winnt.h
KEY_QUERY_VALUE, // minimal access
NULL,
&hKeyToSave,
&dwDisposition)
) == ERROR_SUCCESS)
{
// Save registry subkey. If the registry is remote, files will
// be saved on the remote machine
rc=RegSaveKey(hKeyToSave, szSaveFileName, NULL);
// close registry key we just tried to save
RegCloseKey(hKeyToSave);
}
// return the last registry result code
return rc;
}
void PERR(
LPTSTR szAPI, // pointer to failed API name
DWORD dwLastError // last error value associated with API
)
{
LPTSTR MessageBuffer;
DWORD dwBufferLength;
//
// TODO get this fprintf out of here!
//
fprintf(stderr,"%s error! (rc=%lu)\n", szAPI, dwLastError);
if(dwBufferLength=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwLastError,
LANG_NEUTRAL,
(LPTSTR) &MessageBuffer,
0,
NULL))
{
DWORD dwBytesWritten;
//
// Output message string on stderr
//
WriteFile(GetStdHandle(STD_ERROR_HANDLE),
MessageBuffer,
dwBufferLength,
&dwBytesWritten,
NULL);
//
// free the buffer allocated by the system
//
LocalFree(MessageBuffer);
}
}