525 lines
15 KiB
C++
525 lines
15 KiB
C++
|
//--------------------------------------------------------------
|
||
|
//
|
||
|
// File: common
|
||
|
//
|
||
|
// Contents: Functions shared between ScanState and LoadState.
|
||
|
//
|
||
|
//---------------------------------------------------------------
|
||
|
|
||
|
#include <common.hxx>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <errno.h>
|
||
|
#include <io.h>
|
||
|
#include <malloc.h>
|
||
|
#include <objerror.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
// Constants.
|
||
|
|
||
|
const DWORD LINEBUFSIZE = 1024;
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
// Types.
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
TOKEN_PRIVILEGES tp;
|
||
|
LUID_AND_ATTRIBUTES luid2;
|
||
|
} TOKEN_PRIVILEGES2;
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
// Globals.
|
||
|
|
||
|
HANDLE Console = INVALID_HANDLE_VALUE;
|
||
|
BOOL CopyFiles = TRUE;
|
||
|
BOOL CopySystem = TRUE;
|
||
|
BOOL CopyUser = TRUE;
|
||
|
HKEY CurrentUser = NULL;
|
||
|
BOOL DebugOutput = FALSE;
|
||
|
BOOL ExcludeByDefault = TRUE;
|
||
|
HINF InputInf = INVALID_HANDLE_VALUE;
|
||
|
HANDLE LogFile = INVALID_HANDLE_VALUE;
|
||
|
BOOL OutputAnsi = FALSE;
|
||
|
HANDLE OutputFile = INVALID_HANDLE_VALUE;
|
||
|
char *MigrationPath = NULL;
|
||
|
WCHAR wcsMigrationPath[MAX_PATH + 1];
|
||
|
BOOL ReallyCopyFiles = TRUE;
|
||
|
BOOL SchedSystem = TRUE;
|
||
|
HANDLE STDERR = INVALID_HANDLE_VALUE;
|
||
|
BOOL TestMode = FALSE;
|
||
|
BOOL UserPortion = FALSE;
|
||
|
BOOL Verbose = FALSE;
|
||
|
BOOL VerboseReg = FALSE;
|
||
|
BOOL Win9x = TRUE;
|
||
|
|
||
|
MRtlConvertSidToUnicodeString GRtlConvertSidToUnicodeString = NULL;
|
||
|
MRtlInitUnicodeString GRtlInitUnicodeString = NULL;
|
||
|
MRtlFreeUnicodeString GRtlFreeUnicodeString = NULL;
|
||
|
MDuplicateTokenEx GDuplicateTokenEx = NULL;
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
DWORD OpenFiles()
|
||
|
{
|
||
|
DWORD result = ERROR_SUCCESS;
|
||
|
|
||
|
// Open the console.
|
||
|
Console = CreateFileA( "CONOUT$", GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
|
||
|
0, NULL );
|
||
|
if (Console == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
result = GetLastError();
|
||
|
goto cleanup;
|
||
|
}
|
||
|
STDERR = GetStdHandle(STD_ERROR_HANDLE);
|
||
|
|
||
|
cleanup:
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
void CloseFiles()
|
||
|
{
|
||
|
// Don't close Console.
|
||
|
if (InputInf != INVALID_HANDLE_VALUE)
|
||
|
SetupCloseInfFile( InputInf );
|
||
|
if (LogFile != INVALID_HANDLE_VALUE)
|
||
|
CloseHandle( LogFile );
|
||
|
if (OutputFile != INVALID_HANDLE_VALUE)
|
||
|
CloseHandle( OutputFile );
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
DWORD EnableBackupPrivilege()
|
||
|
{
|
||
|
HANDLE process = NULL;
|
||
|
HANDLE process2 = NULL;
|
||
|
TOKEN_PRIVILEGES2 tp;
|
||
|
LUID backup;
|
||
|
LUID restore;
|
||
|
BOOL success;
|
||
|
DWORD result = ERROR_SUCCESS;
|
||
|
|
||
|
// Do nothing on Win9x.
|
||
|
if (Win9x)
|
||
|
return ERROR_SUCCESS;
|
||
|
result = NtImports();
|
||
|
LOG_ASSERT( result );
|
||
|
|
||
|
// Get the process token
|
||
|
success = OpenProcessToken( GetCurrentProcess(),
|
||
|
TOKEN_DUPLICATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
||
|
&process );
|
||
|
LOG_ASSERT_GLE( success, result );
|
||
|
|
||
|
// Convert it into an impersonation token.
|
||
|
success = GDuplicateTokenEx( process,
|
||
|
MAXIMUM_ALLOWED,
|
||
|
NULL, SecurityImpersonation, TokenImpersonation,
|
||
|
&process2 );
|
||
|
LOG_ASSERT_GLE( success, result );
|
||
|
|
||
|
// Get LUID for backup privilege.
|
||
|
success = LookupPrivilegeValue(
|
||
|
NULL, // lookup privilege on local system
|
||
|
SE_BACKUP_NAME,
|
||
|
&backup );
|
||
|
LOG_ASSERT_GLE( success, result );
|
||
|
|
||
|
// Get LUID for restore privilege.
|
||
|
success = LookupPrivilegeValue(
|
||
|
NULL, // lookup privilege on local system
|
||
|
SE_RESTORE_NAME,
|
||
|
&restore );
|
||
|
LOG_ASSERT_GLE( success, result );
|
||
|
|
||
|
// Fill in the token privilege structure.
|
||
|
tp.tp.PrivilegeCount = 2;
|
||
|
tp.tp.Privileges[0].Luid = backup;
|
||
|
tp.tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||
|
tp.tp.Privileges[1].Luid = restore;
|
||
|
tp.tp.Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
|
||
|
|
||
|
// Enable the privilege or disable all privileges.
|
||
|
success = AdjustTokenPrivileges( process2, FALSE, &tp.tp, 0, NULL, NULL );
|
||
|
LOG_ASSERT_GLE( success, result );
|
||
|
|
||
|
// Save the token on the thread.
|
||
|
success = SetThreadToken( NULL, process2 );
|
||
|
LOG_ASSERT_GLE( success, result );
|
||
|
|
||
|
// Close the token handles.
|
||
|
cleanup:
|
||
|
if (process != NULL)
|
||
|
CloseHandle( process );
|
||
|
if (process2 != NULL)
|
||
|
CloseHandle( process2 );
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
DWORD MakeUnicode( char *buffer, WCHAR **wbuffer )
|
||
|
{
|
||
|
DWORD len;
|
||
|
DWORD wlen;
|
||
|
|
||
|
// Allocate a buffer to hold the unicode string.
|
||
|
len = strlen( buffer ) + 1;
|
||
|
wlen = MultiByteToWideChar( CP_ACP, 0, buffer, len, NULL, 0 );
|
||
|
*wbuffer = (WCHAR *) malloc( wlen*sizeof(WCHAR) );
|
||
|
if (*wbuffer == NULL)
|
||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
|
||
|
// Convert the buffer to unicode.
|
||
|
wlen = MultiByteToWideChar( CP_ACP, 0, buffer, len, *wbuffer, wlen );
|
||
|
if (wlen == 0)
|
||
|
return GetLastError();
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
DWORD NtImports()
|
||
|
{
|
||
|
DWORD result = ERROR_SUCCESS;
|
||
|
HINSTANCE ntdll;
|
||
|
HINSTANCE advapi32;
|
||
|
|
||
|
// Do nothing on Win9x.
|
||
|
if (Win9x || GRtlConvertSidToUnicodeString != NULL)
|
||
|
return ERROR_SUCCESS;
|
||
|
|
||
|
// Load ntdll.dll
|
||
|
ntdll = LoadLibraryA( "ntdll.dll" );
|
||
|
if (ntdll == NULL)
|
||
|
{
|
||
|
result = GetLastError();
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
// Get the functions
|
||
|
GRtlConvertSidToUnicodeString = (MRtlConvertSidToUnicodeString) GetProcAddress( ntdll, "RtlConvertSidToUnicodeString" );
|
||
|
GRtlInitUnicodeString = (MRtlInitUnicodeString) GetProcAddress( ntdll, "RtlInitUnicodeString" );
|
||
|
GRtlFreeUnicodeString = (MRtlFreeUnicodeString) GetProcAddress( ntdll, "RtlFreeUnicodeString" );
|
||
|
|
||
|
// Make sure all the functions were found.
|
||
|
if ( GRtlConvertSidToUnicodeString == NULL
|
||
|
|| GRtlInitUnicodeString == NULL
|
||
|
|| GRtlFreeUnicodeString == NULL
|
||
|
)
|
||
|
{
|
||
|
result = GetLastError();
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
// Load advapi32.dll
|
||
|
advapi32 = LoadLibraryA( "advapi32.dll" );
|
||
|
if (advapi32 == NULL)
|
||
|
{
|
||
|
result = GetLastError();
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
// Get the functions.
|
||
|
GDuplicateTokenEx = (MDuplicateTokenEx) GetProcAddress( advapi32, "DuplicateTokenEx" );
|
||
|
if (GDuplicateTokenEx == NULL)
|
||
|
{
|
||
|
result = GetLastError();
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
cleanup:
|
||
|
if (result != ERROR_SUCCESS)
|
||
|
{
|
||
|
GRtlConvertSidToUnicodeString = NULL;
|
||
|
GRtlInitUnicodeString = NULL;
|
||
|
GRtlFreeUnicodeString = NULL;
|
||
|
GDuplicateTokenEx = NULL;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
DWORD OpenInf( char *file )
|
||
|
{
|
||
|
BOOL success;
|
||
|
UINT errorline;
|
||
|
DWORD result = ERROR_SUCCESS;
|
||
|
char *error;
|
||
|
|
||
|
// If there have not been any INF files, open this as the first.
|
||
|
if (InputInf == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
InputInf = SetupOpenInfFileA( file, NULL, INF_STYLE_WIN4, &errorline );
|
||
|
success = InputInf != INVALID_HANDLE_VALUE;
|
||
|
}
|
||
|
else
|
||
|
success = SetupOpenAppendInfFileA( file, InputInf, &errorline );
|
||
|
|
||
|
// If the open failed, print a message and exit.
|
||
|
if (!success)
|
||
|
{
|
||
|
result = GetLastError();
|
||
|
Win32PrintfResourceA( Console, IDS_OPEN_INF_ERROR, file );
|
||
|
error = NULL;
|
||
|
FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||
|
0, result,
|
||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||
|
(char *)&error, 0, NULL );
|
||
|
if (error != NULL)
|
||
|
{
|
||
|
Win32Printf( Console, error );
|
||
|
LocalFree( error );
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
BOOL PopupError( char *expr, char *file, DWORD line )
|
||
|
{
|
||
|
char szModuleName[128];
|
||
|
char errMessage[128]; // generated error string
|
||
|
DWORD tid = GetCurrentThreadId();
|
||
|
DWORD pid = GetCurrentProcessId();
|
||
|
char *pszModuleName;
|
||
|
|
||
|
// Compute the name of the process.
|
||
|
if (GetModuleFileNameA(NULL, szModuleName, 128))
|
||
|
{
|
||
|
pszModuleName = strrchr(szModuleName, '\\');
|
||
|
if (!pszModuleName)
|
||
|
{
|
||
|
pszModuleName = szModuleName;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pszModuleName++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pszModuleName = "Unknown";
|
||
|
}
|
||
|
|
||
|
// Compute a title for the popup.
|
||
|
wsprintfA(errMessage,"Process: %s File: %s line %u, thread id %d.%d",
|
||
|
pszModuleName, file, line, pid, tid);
|
||
|
|
||
|
// Return the result of the message bux.
|
||
|
return MessageBoxA( NULL, expr, errMessage,
|
||
|
MB_SETFOREGROUND | MB_TASKMODAL | MB_ICONEXCLAMATION |
|
||
|
MB_OKCANCEL );
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
void PrintHelp( BOOL scan )
|
||
|
{
|
||
|
Win32PrintfResourceA( Console, IDS_WHAT );
|
||
|
Win32PrintfResourceA( Console, scan ? IDS_CMD1S : IDS_CMD1L );
|
||
|
Win32PrintfResourceA( Console, IDS_CMD2 );
|
||
|
Win32PrintfResourceA( Console, IDS_CMD_I );
|
||
|
Win32PrintfResourceA( Console, IDS_CMD_L );
|
||
|
Win32PrintfResourceA( Console, IDS_CMD_V );
|
||
|
if ( Verbose | VerboseReg | DebugOutput )
|
||
|
Win32PrintfResourceA( Console, IDS_CMD_V_BITS );
|
||
|
Win32PrintfResourceA( Console, IDS_CMD_X );
|
||
|
Win32PrintfResourceA( Console, IDS_CMD_U );
|
||
|
Win32PrintfResourceA( Console, IDS_CMD_F );
|
||
|
Win32PrintfResourceA( Console, IDS_CMD_PATH );
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
// This function converts a Win32 result into a resource id.
|
||
|
DWORD ResultToRC( DWORD result )
|
||
|
{
|
||
|
if (result == ERROR_WRITE_FAULT)
|
||
|
return IDS_WRITE_FAULT;
|
||
|
else if (result == ERROR_NOT_ENOUGH_MEMORY)
|
||
|
return IDS_NOT_ENOUGH_MEMORY;
|
||
|
else if (result == ERROR_ACCESS_DENIED ||
|
||
|
result == ERROR_PRIVILEGE_NOT_HELD)
|
||
|
return IDS_MUST_BE_ADMIN;
|
||
|
else if (result == SPAPI_E_SECTION_NOT_FOUND)
|
||
|
return IDS_SECTION_NOT_FOUND;
|
||
|
else
|
||
|
return IDS_FAILED;
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
// This function prints from a resource string as a format string
|
||
|
// to a unicode win32 file handle. It is not thread safe.
|
||
|
// %s in a format string means a ascii parameter.
|
||
|
DWORD Win32PrintfResourceA( HANDLE file, DWORD resource_id, ... )
|
||
|
{
|
||
|
BOOL success;
|
||
|
DWORD len;
|
||
|
va_list va;
|
||
|
char *buffer = NULL;
|
||
|
DWORD written;
|
||
|
DWORD wlen;
|
||
|
WCHAR *wbuffer = NULL;
|
||
|
DWORD result = ERROR_SUCCESS;
|
||
|
CHAR PrintBuffer[LINEBUFSIZE];
|
||
|
|
||
|
// Try to load the string.
|
||
|
len = LoadStringA( NULL, resource_id, PrintBuffer, LINEBUFSIZE );
|
||
|
DEBUG_ASSERT( len != 0 && len < LINEBUFSIZE );
|
||
|
|
||
|
// Format the message.
|
||
|
va_start( va, resource_id );
|
||
|
success = FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
|
||
|
PrintBuffer, 0,
|
||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||
|
(char *) &buffer, 0, &va );
|
||
|
va_end( va );
|
||
|
DEBUG_ASSERT( success );
|
||
|
if (!success)
|
||
|
{
|
||
|
result = GetLastError();
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
// When printing to the console or logfile use ascii.
|
||
|
// When printing to the migration file use Unicode.
|
||
|
len = strlen(buffer);
|
||
|
if (file != OutputFile)
|
||
|
{
|
||
|
wbuffer = (WCHAR *) buffer;
|
||
|
wlen = len;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Allocate a buffer to hold the unicode string.
|
||
|
wlen = MultiByteToWideChar( CP_ACP, 0, buffer, len, NULL, 0 );
|
||
|
wbuffer = (WCHAR *) _alloca( wlen*sizeof(WCHAR) );
|
||
|
if (wbuffer == NULL)
|
||
|
{
|
||
|
result = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
// Convert the buffer to unicode.
|
||
|
wlen = MultiByteToWideChar( CP_ACP, 0, buffer, len, wbuffer, wlen );
|
||
|
if (wlen == 0)
|
||
|
{
|
||
|
result = GetLastError();
|
||
|
goto cleanup;
|
||
|
}
|
||
|
wlen *= sizeof(WCHAR);
|
||
|
}
|
||
|
|
||
|
// Write the unicode string.
|
||
|
success = WriteFile( file, wbuffer, wlen, &written, NULL );
|
||
|
if (!success || wlen != written)
|
||
|
{
|
||
|
result = GetLastError();
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
if (file == STDERR)
|
||
|
{
|
||
|
//Also write to the log file for these
|
||
|
success = WriteFile( LogFile, wbuffer, wlen, &written, NULL );
|
||
|
if (!success || wlen != written)
|
||
|
{
|
||
|
result = GetLastError();
|
||
|
goto cleanup;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cleanup:
|
||
|
if (buffer != NULL)
|
||
|
LocalFree( buffer );
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
// This function prints from a resource string as a format string
|
||
|
// to a unicode win32 file handle. It is not thread safe.
|
||
|
// %s in a format string means a unicode parameter.
|
||
|
DWORD Win32PrintfResourceW( HANDLE file, DWORD resource_id, ... )
|
||
|
{
|
||
|
BOOL success;
|
||
|
DWORD len;
|
||
|
va_list va;
|
||
|
CHAR *buffer = NULL;
|
||
|
DWORD written;
|
||
|
DWORD wlen;
|
||
|
WCHAR *wbuffer = NULL;
|
||
|
DWORD result = ERROR_SUCCESS;
|
||
|
WCHAR PrintBuffer[LINEBUFSIZE];
|
||
|
|
||
|
// Try to load the string.
|
||
|
wlen = LoadStringW( NULL, resource_id, PrintBuffer, LINEBUFSIZE );
|
||
|
DEBUG_ASSERT( wlen != 0 && wlen < LINEBUFSIZE );
|
||
|
|
||
|
// Format the message.
|
||
|
va_start( va, resource_id );
|
||
|
success = FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
|
||
|
PrintBuffer, 0,
|
||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||
|
(WCHAR *) &wbuffer, 0, &va );
|
||
|
va_end( va );
|
||
|
DEBUG_ASSERT( success && "The resource ids are probably wrong, try doing a clean compile" );
|
||
|
if (!success)
|
||
|
{
|
||
|
result = GetLastError();
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
// When printing to the console or logfile use ascii.
|
||
|
// When printing to the migration file use Unicode.
|
||
|
wlen = wcslen(wbuffer);
|
||
|
if (file == OutputFile)
|
||
|
{
|
||
|
buffer = (CHAR *) wbuffer;
|
||
|
len = wlen * sizeof(WCHAR);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Allocate a buffer to hold the ascii string.
|
||
|
len = WideCharToMultiByte( CP_ACP, 0, wbuffer, wlen, NULL, 0, NULL, NULL );
|
||
|
buffer = (CHAR *) _alloca( len );
|
||
|
if (buffer == NULL)
|
||
|
{
|
||
|
result = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
// Convert the buffer to unicode.
|
||
|
len = WideCharToMultiByte( CP_ACP, 0, wbuffer, wlen, buffer, len, NULL, NULL );
|
||
|
if (len == 0)
|
||
|
{
|
||
|
result = GetLastError();
|
||
|
goto cleanup;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Write the unicode string.
|
||
|
success = WriteFile( file, buffer, len, &written, NULL );
|
||
|
if (!success || len != written)
|
||
|
{
|
||
|
result = GetLastError();
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
if (file == STDERR)
|
||
|
{
|
||
|
//Also write to the log file for these
|
||
|
success = WriteFile( LogFile, wbuffer, wlen, &written, NULL );
|
||
|
if (!success || wlen != written)
|
||
|
{
|
||
|
result = GetLastError();
|
||
|
goto cleanup;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cleanup:
|
||
|
if (wbuffer != NULL)
|
||
|
LocalFree( wbuffer );
|
||
|
return result;
|
||
|
}
|