//-------------------------------------------------------------- // // File: common // // Contents: Functions shared between ScanState and LoadState. // //--------------------------------------------------------------- #include #include #include #include #include #include #include #include //--------------------------------------------------------------- // 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; }