1156 lines
27 KiB
C
1156 lines
27 KiB
C
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
migdlls.c
|
|
|
|
Abstract:
|
|
|
|
The functions in this module are used to support migration DLLs.
|
|
|
|
Author:
|
|
|
|
Jim Schmidt (jimschm) 04-Feb-1997
|
|
|
|
Revision History:
|
|
|
|
jimschm 23-Sep-1998 Changed to use new IPC mechanism
|
|
jimschm 22-Apr-1998 Added USERPROFILE environment variable to MigrateUserNT
|
|
jimschm 08-Jan-1997 Added alive event, giving certain DLLs up to 30 minutes
|
|
to complete their work.
|
|
jimschm 08-Dec-1997 Added support for domains (MigrateUserNT's user name
|
|
param is multi-sz)
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
#include "migmainp.h"
|
|
|
|
#ifndef UNICODE
|
|
#error UNICODE required
|
|
#endif
|
|
|
|
|
|
HANDLE g_AliveEvent;
|
|
|
|
|
|
BOOL
|
|
pConnectToDll (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
pDisconnectFromDll (
|
|
VOID
|
|
);
|
|
|
|
DWORD
|
|
pRunMigrationDll (
|
|
VOID
|
|
);
|
|
|
|
DWORD
|
|
pCallInitializeNt (
|
|
IN PCTSTR WorkingDir,
|
|
IN PCTSTR *SourceDirArray,
|
|
IN PVOID Reserved,
|
|
IN DWORD ReservedBytes
|
|
);
|
|
|
|
DWORD
|
|
pCallMigrateUserNt (
|
|
IN PCTSTR WorkingDir,
|
|
IN PCTSTR UnattendFile,
|
|
IN PCTSTR RootKey,
|
|
IN PCTSTR Win9xUserName,
|
|
IN PCTSTR UserDomain,
|
|
IN PCTSTR FixedUserName,
|
|
IN PVOID Reserved,
|
|
IN DWORD ReservedBytes
|
|
);
|
|
|
|
DWORD
|
|
pCallMigrateSystemNt (
|
|
IN PCTSTR WorkingDir,
|
|
IN PCTSTR UnattendFile,
|
|
IN PVOID Reserved,
|
|
IN DWORD ReservedBytes
|
|
);
|
|
|
|
static
|
|
VOID
|
|
pSetCwd (
|
|
OUT PTSTR SavedWorkDir,
|
|
IN PCTSTR NewWorkDir
|
|
);
|
|
|
|
|
|
static TCHAR g_DllPath[MAX_TCHAR_PATH];
|
|
static TCHAR g_WorkingDir[MAX_TCHAR_PATH];
|
|
static TCHAR g_DllDesc[MAX_TCHAR_PATH];
|
|
static VENDORINFOW g_VendorInfo;
|
|
static TCHAR g_FixedUser[MAX_USER_NAME];
|
|
static TCHAR g_UserOnWin9x[MAX_USER_NAME];
|
|
|
|
static HINSTANCE g_hLibrary;
|
|
P_INITIALIZE_NT InitializeNT;
|
|
P_MIGRATE_USER_NT MigrateUserNT;
|
|
P_MIGRATE_SYSTEM_NT MigrateSystemNT;
|
|
|
|
|
|
|
|
VOID
|
|
pLogDllFailure (
|
|
IN HWND Parent,
|
|
IN UINT MessageId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pLogDllFailure prepares arguments for the specified MessageId, and then
|
|
displays a popup and adds a log entry. This function gives the user
|
|
information on what to do when the DLL fails.
|
|
|
|
Arguments:
|
|
|
|
Parent - Specifies the parent window handle of the popup, or NULL if no
|
|
popup is to be displayed.
|
|
MessageId - Specifies the message ID for the error.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCTSTR FixupPhone;
|
|
PCTSTR FixupUrl;
|
|
PCTSTR FixupInstructions;
|
|
PCTSTR LineBreak = S_EMPTY;
|
|
PCTSTR ArgArray[1];
|
|
|
|
//
|
|
// Generate fixup strings
|
|
//
|
|
|
|
if (g_VendorInfo.SupportNumber[0]) {
|
|
ArgArray[0] = g_VendorInfo.SupportNumber;
|
|
FixupPhone = ParseMessageID (MSG_MIGDLL_SUPPORT_PHONE_FIXUP, ArgArray);
|
|
LineBreak = TEXT("\n");
|
|
} else {
|
|
FixupPhone = S_EMPTY;
|
|
}
|
|
|
|
if (g_VendorInfo.SupportUrl[0]) {
|
|
ArgArray[0] = g_VendorInfo.SupportUrl;
|
|
FixupUrl = ParseMessageID (MSG_MIGDLL_SUPPORT_URL_FIXUP, ArgArray);
|
|
LineBreak = TEXT("\n");
|
|
} else {
|
|
FixupUrl = S_EMPTY;
|
|
}
|
|
|
|
if (g_VendorInfo.InstructionsToUser[0]) {
|
|
ArgArray[0] = g_VendorInfo.InstructionsToUser;
|
|
FixupInstructions = ParseMessageID (MSG_MIGDLL_INSTRUCTIONS_FIXUP, ArgArray);
|
|
LineBreak = TEXT("\n");
|
|
} else {
|
|
FixupInstructions = S_EMPTY;
|
|
}
|
|
|
|
//
|
|
// Display popup and log the error
|
|
//
|
|
LOG ((
|
|
LOG_ERROR,
|
|
(PCSTR) MessageId,
|
|
g_DllDesc,
|
|
g_VendorInfo.CompanyName,
|
|
FixupPhone,
|
|
FixupUrl,
|
|
FixupInstructions,
|
|
LineBreak
|
|
));
|
|
}
|
|
|
|
|
|
VOID
|
|
pSetCwd (
|
|
OUT PTSTR SavedWorkDir,
|
|
IN PCTSTR NewWorkDir
|
|
)
|
|
{
|
|
GetCurrentDirectory (MAX_TCHAR_PATH, SavedWorkDir);
|
|
SetCurrentDirectory (NewWorkDir);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
pCreateEnvironment (
|
|
PVOID *BlockPtr
|
|
)
|
|
{
|
|
return CreateEnvironmentBlock (BlockPtr, NULL, FALSE);
|
|
}
|
|
|
|
|
|
VOID
|
|
pSetEnvironmentBlock (
|
|
PVOID Block
|
|
)
|
|
{
|
|
DEBUGMSG ((DBG_VERBOSE, "Block: %s", Block));
|
|
}
|
|
|
|
|
|
DWORD
|
|
ProcessMigrationDLLs (
|
|
DWORD Request
|
|
)
|
|
{
|
|
MEMDB_ENUM e;
|
|
DWORD rc;
|
|
DWORD Ticks = 0;
|
|
|
|
if (Request == REQUEST_QUERYTICKS) {
|
|
if (MemDbEnumItems (&e, MEMDB_CATEGORY_MIGRATION_DLL)) {
|
|
do {
|
|
Ticks += TICKS_MIGRATION_DLL;
|
|
} while (MemDbEnumNextValue (&e));
|
|
}
|
|
|
|
return Ticks;
|
|
}
|
|
|
|
#ifdef PRERELEASE
|
|
|
|
if (g_ConfigOptions.DiffMode) {
|
|
TakeSnapShot();
|
|
}
|
|
|
|
#endif
|
|
|
|
if (MemDbEnumItems (&e, MEMDB_CATEGORY_MIGRATION_DLL)) {
|
|
|
|
do {
|
|
//
|
|
// Retrieve DLL location and settings
|
|
//
|
|
|
|
// Obtain the DLL name and working directory
|
|
if (!MemDbGetEndpointValueEx (
|
|
MEMDB_CATEGORY_MIGRATION_DLL,
|
|
e.szName,
|
|
MEMDB_FIELD_DLL,
|
|
g_DllPath)
|
|
) {
|
|
LOG ((LOG_ERROR, "DLL path for %s is not listed in memdb; DLL not processed", e.szName));
|
|
continue; // not expected
|
|
}
|
|
|
|
// Obtain the working directory
|
|
if (!MemDbGetEndpointValueEx (
|
|
MEMDB_CATEGORY_MIGRATION_DLL,
|
|
e.szName,
|
|
MEMDB_FIELD_WD,
|
|
g_WorkingDir)
|
|
) {
|
|
LOG ((LOG_ERROR, "Working Directory for %s is not listed in memdb; DLL not processed", e.szName));
|
|
continue; // not expected
|
|
}
|
|
|
|
// Obtain a description
|
|
if (!MemDbGetEndpointValueEx (
|
|
MEMDB_CATEGORY_MIGRATION_DLL,
|
|
e.szName,
|
|
MEMDB_FIELD_DESC,
|
|
g_DllDesc
|
|
)) {
|
|
|
|
StringCopy (g_DllDesc, GetString (MSG_DEFAULT_MIGDLL_DESC));
|
|
}
|
|
|
|
ZeroMemory (&g_VendorInfo, sizeof (g_VendorInfo));
|
|
|
|
MemDbGetEndpointValueEx (
|
|
MEMDB_CATEGORY_MIGRATION_DLL,
|
|
e.szName,
|
|
MEMDB_FIELD_COMPANY_NAME,
|
|
g_VendorInfo.CompanyName
|
|
);
|
|
|
|
MemDbGetEndpointValueEx (
|
|
MEMDB_CATEGORY_MIGRATION_DLL,
|
|
e.szName,
|
|
MEMDB_FIELD_SUPPORT_PHONE,
|
|
g_VendorInfo.SupportNumber
|
|
);
|
|
|
|
MemDbGetEndpointValueEx (
|
|
MEMDB_CATEGORY_MIGRATION_DLL,
|
|
e.szName,
|
|
MEMDB_FIELD_SUPPORT_URL,
|
|
g_VendorInfo.SupportUrl
|
|
);
|
|
|
|
MemDbGetEndpointValueEx (
|
|
MEMDB_CATEGORY_MIGRATION_DLL,
|
|
e.szName,
|
|
MEMDB_FIELD_SUPPORT_INSTRUCTIONS,
|
|
g_VendorInfo.InstructionsToUser
|
|
);
|
|
|
|
//
|
|
// Establish connection with migisol.exe
|
|
//
|
|
|
|
if (!pConnectToDll()) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Tell migisol.exe to load migration DLL and call NT functions
|
|
//
|
|
|
|
rc = pRunMigrationDll();
|
|
|
|
//
|
|
// If not success, return a setup failure
|
|
//
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError (rc);
|
|
pLogDllFailure (g_ParentWnd, MSG_MIGDLL_ERROR);
|
|
}
|
|
|
|
//
|
|
// Disconnect from migisol.exe and kill the potentially
|
|
// stalled process
|
|
//
|
|
|
|
pDisconnectFromDll();
|
|
|
|
TickProgressBarDelta (TICKS_MIGRATION_DLL);
|
|
|
|
} while (MemDbEnumNextValue (&e));
|
|
|
|
} /* if */
|
|
|
|
#ifdef PRERELEASE
|
|
|
|
if (g_ConfigOptions.DiffMode) {
|
|
CHAR szMigdllDifPath[] = "c:\\migdll.dif";
|
|
if (ISPC98()) {
|
|
szMigdllDifPath[0] = (CHAR)g_System32Dir[0];
|
|
}
|
|
GenerateDiffOutputA (szMigdllDifPath, NULL, TRUE);
|
|
}
|
|
|
|
#endif
|
|
|
|
return ERROR_SUCCESS;
|
|
} /* ProcessMigrationDLLs */
|
|
|
|
|
|
BOOL
|
|
pConnectToDll (
|
|
VOID
|
|
)
|
|
{
|
|
BOOL b = TRUE;
|
|
TCHAR MigIsolPath[MAX_TCHAR_PATH];
|
|
|
|
g_AliveEvent = CreateEvent (NULL, FALSE, FALSE, TEXT("MigDllAlive"));
|
|
DEBUGMSG_IF ((!g_AliveEvent, DBG_WHOOPS, "Could not create MigDllAlive event"));
|
|
|
|
if (!g_ConfigOptions.TestDlls) {
|
|
//
|
|
// Establish IPC connection
|
|
//
|
|
|
|
wsprintf (MigIsolPath, TEXT("%s\\%s"), g_System32Dir, S_MIGISOL_EXE);
|
|
|
|
b = OpenIpc (FALSE, MigIsolPath, g_DllPath, g_System32Dir);
|
|
|
|
if (!b) {
|
|
LOG ((LOG_WARNING, "Can't establish IPC connection for %s, wd=%s", g_DllPath, g_System32Dir));
|
|
pLogDllFailure (g_ParentWnd, MSG_CREATE_PROCESS_ERROR);
|
|
}
|
|
} else {
|
|
g_hLibrary = LoadLibrary (g_DllPath);
|
|
|
|
// If it fails, assume the DLL does not want to be loaded
|
|
if (!g_hLibrary) {
|
|
LOG ((LOG_ERROR, "Cannot load %s", g_DllPath));
|
|
return FALSE;
|
|
}
|
|
|
|
// Get proc addresses for NT-side functions
|
|
InitializeNT = (P_INITIALIZE_NT) GetProcAddress (g_hLibrary, PLUGIN_INITIALIZE_NT);
|
|
MigrateUserNT = (P_MIGRATE_USER_NT) GetProcAddress (g_hLibrary, PLUGIN_MIGRATE_USER_NT);
|
|
MigrateSystemNT = (P_MIGRATE_SYSTEM_NT) GetProcAddress (g_hLibrary, PLUGIN_MIGRATE_SYSTEM_NT);
|
|
|
|
if (!InitializeNT || !MigrateUserNT || !MigrateSystemNT) {
|
|
b = FALSE;
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
VOID
|
|
pDisconnectFromDll (
|
|
VOID
|
|
)
|
|
{
|
|
if (g_AliveEvent) {
|
|
CloseHandle (g_AliveEvent);
|
|
g_AliveEvent = NULL;
|
|
}
|
|
|
|
if (!g_ConfigOptions.TestDlls) {
|
|
CloseIpc();
|
|
}
|
|
else {
|
|
if (g_hLibrary) {
|
|
FreeLibrary (g_hLibrary);
|
|
g_hLibrary = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
pGetUserFromIndex (
|
|
DWORD Index
|
|
)
|
|
|
|
{
|
|
USERPOSITION up;
|
|
DWORD rc;
|
|
|
|
g_UserOnWin9x[0] = 0;
|
|
|
|
if (Index == INDEX_DEFAULT_USER) {
|
|
|
|
StringCopy (g_FixedUser, g_DefaultUserName);
|
|
|
|
} else if (Index == INDEX_LOGON_PROMPT) {
|
|
|
|
StringCopy (g_FixedUser, S_DOT_DEFAULT);
|
|
|
|
} else if (Index == INDEX_ADMINISTRATOR) {
|
|
|
|
StringCopy (g_FixedUser, g_AdministratorStr);
|
|
|
|
} else {
|
|
|
|
rc = Win95RegGetFirstUser (&up, g_FixedUser);
|
|
if (rc != ERROR_SUCCESS) {
|
|
LOG ((LOG_ERROR, "Get User From Index: Win95RegGetFirstUser failed"));
|
|
return FALSE;
|
|
}
|
|
|
|
for (Index -= INDEX_MAX ; Win95RegHaveUser(&up) && Index > 0 ; Index--) {
|
|
Win95RegGetNextUser (&up, g_FixedUser);
|
|
}
|
|
|
|
if (!Win95RegHaveUser(&up)) {
|
|
return FALSE;
|
|
}
|
|
|
|
StringCopy (g_UserOnWin9x, g_FixedUser);
|
|
GetFixedUserName (g_FixedUser);
|
|
}
|
|
|
|
if (!g_UserOnWin9x[0]) {
|
|
StringCopy (g_UserOnWin9x, g_FixedUser);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD
|
|
pRunMigrationDll (
|
|
VOID
|
|
)
|
|
{
|
|
DWORD rc;
|
|
BOOL AbortThisDll;
|
|
BOOL UnloadRegKey;
|
|
TCHAR UnattendFile[MAX_TCHAR_PATH];
|
|
TCHAR RootKey[MAX_REGISTRY_KEY];
|
|
TCHAR HiveFile[MAX_TCHAR_PATH];
|
|
DWORD Index;
|
|
BOOL IsLogonPromptAccount;
|
|
PCTSTR SourceDirArray[2];
|
|
PCTSTR I386SourceDir;
|
|
PCTSTR p;
|
|
TCHAR Domain[MAX_USER_NAME];
|
|
BOOL Env;
|
|
PVOID Block;
|
|
HKEY NewHkcu;
|
|
LONG MapResult;
|
|
|
|
//
|
|
// Initialize unattend file and root key
|
|
//
|
|
|
|
wsprintf (UnattendFile, TEXT("%s\\system32\\$winnt$.inf"), g_WinDir);
|
|
|
|
//
|
|
// Call InitializeNT
|
|
//
|
|
|
|
if (ISPC98()) {
|
|
I386SourceDir = JoinPaths (g_SourceDir, TEXT("NEC98"));
|
|
} else {
|
|
I386SourceDir = JoinPaths (g_SourceDir, TEXT("I386"));
|
|
}
|
|
|
|
if (!I386SourceDir) {
|
|
return GetLastError();
|
|
}
|
|
|
|
SourceDirArray[0] = I386SourceDir;
|
|
SourceDirArray[1] = NULL;
|
|
rc = pCallInitializeNt (g_WorkingDir, SourceDirArray, NULL, 0);
|
|
if (rc != ERROR_SUCCESS) {
|
|
return rc;
|
|
}
|
|
|
|
FreePathString (I386SourceDir);
|
|
|
|
//
|
|
// The user loop
|
|
//
|
|
|
|
// For each user, call DLL's MigrateUser function
|
|
AbortThisDll = FALSE;
|
|
Index = 0;
|
|
|
|
while (!AbortThisDll) {
|
|
|
|
if (Index == INDEX_LOGON_PROMPT) {
|
|
wsprintf (RootKey, TEXT("HKU\\%s"), S_DOT_DEFAULT);
|
|
IsLogonPromptAccount = TRUE;
|
|
} else {
|
|
wsprintf (RootKey, TEXT("HKU\\%s"), S_TEMP_USER_KEY);
|
|
IsLogonPromptAccount = FALSE;
|
|
}
|
|
|
|
if (!pGetUserFromIndex (Index)) {
|
|
break;
|
|
}
|
|
|
|
Index++;
|
|
|
|
//
|
|
// If the following lookup fails, it is because the user isn't supposed to
|
|
// migrate, or migration failed.
|
|
//
|
|
|
|
if (!IsLogonPromptAccount) {
|
|
if (-1 == pSetupStringTableLookUpStringEx (
|
|
g_HiveTable,
|
|
g_FixedUser,
|
|
STRTAB_CASE_INSENSITIVE,
|
|
HiveFile,
|
|
sizeof (HiveFile)
|
|
)
|
|
) {
|
|
DEBUGMSG ((
|
|
DBG_VERBOSE,
|
|
"pRunMigrationDll: pSetupStringTableLookUpStringEx could not find name of hive for user %s",
|
|
g_FixedUser
|
|
));
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Load NT user hive
|
|
//
|
|
|
|
UnloadRegKey = FALSE;
|
|
Env = FALSE;
|
|
NewHkcu = NULL;
|
|
MapResult = 0;
|
|
|
|
if (!AbortThisDll) {
|
|
|
|
// Don't load .default
|
|
if (!IsLogonPromptAccount) {
|
|
|
|
rc = RegUnLoadKey (HKEY_USERS, S_TEMP_USER_KEY);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
DumpOpenKeys ();
|
|
SetLastError (rc);
|
|
DEBUGMSG_IF ((rc != ERROR_INVALID_PARAMETER, DBG_ERROR, "Error unloading regkey!"));
|
|
}
|
|
|
|
rc = RegLoadKey (HKEY_USERS, S_TEMP_USER_KEY, HiveFile);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError(rc);
|
|
LOG ((
|
|
LOG_ERROR,
|
|
"Run Migration Dll: RegLoadKey could not load user hive for %s (%s)",
|
|
g_FixedUser,
|
|
HiveFile
|
|
));
|
|
|
|
AbortThisDll = TRUE;
|
|
} else {
|
|
UnloadRegKey = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!AbortThisDll) {
|
|
NewHkcu = OpenRegKeyStr (RootKey);
|
|
if (NewHkcu) {
|
|
MapResult = RegOverridePredefKey (HKEY_CURRENT_USER, NewHkcu);
|
|
if (MapResult != ERROR_SUCCESS) {
|
|
LOG ((LOG_ERROR, "Can't override HKCU"));
|
|
}
|
|
}
|
|
|
|
Env = pCreateEnvironment (&Block);
|
|
if (Env) {
|
|
pSetEnvironmentBlock (&Block);
|
|
DestroyEnvironmentBlock (&Block);
|
|
}
|
|
}
|
|
|
|
// Call loaded DLL's MigrateUser function
|
|
if (!AbortThisDll) {
|
|
|
|
if (g_DomainUserName) {
|
|
p = _tcschr (g_DomainUserName, TEXT('\\'));
|
|
} else {
|
|
p = NULL;
|
|
}
|
|
|
|
if (p) {
|
|
StringCopyAB (Domain, g_DomainUserName, p);
|
|
} else {
|
|
Domain[0] = 0;
|
|
}
|
|
|
|
rc = pCallMigrateUserNt (
|
|
g_WorkingDir,
|
|
UnattendFile,
|
|
RootKey,
|
|
IsLogonPromptAccount ? TEXT("") : g_UserOnWin9x,
|
|
Domain,
|
|
IsLogonPromptAccount ? TEXT("") : g_FixedUser,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
AbortThisDll = TRUE;
|
|
}
|
|
}
|
|
|
|
// Restore predefined key
|
|
if (NewHkcu && MapResult == ERROR_SUCCESS) {
|
|
MapResult = RegOverridePredefKey (HKEY_CURRENT_USER, NULL);
|
|
if (MapResult != ERROR_SUCCESS) {
|
|
LOG ((LOG_ERROR, "Can't restore HKCU"));
|
|
}
|
|
|
|
CloseRegKey (NewHkcu);
|
|
}
|
|
|
|
// Unload temporary key
|
|
if (UnloadRegKey) {
|
|
UnloadRegKey = FALSE;
|
|
rc = RegUnLoadKey (HKEY_USERS, S_TEMP_USER_KEY);
|
|
if (rc != ERROR_SUCCESS) {
|
|
DumpOpenKeys ();
|
|
SetLastError (rc);
|
|
DEBUGMSG_IF ((rc != ERROR_INVALID_PARAMETER, DBG_ERROR, "Error unloading regkey (second case)!"));
|
|
|
|
}
|
|
}
|
|
} /* while */
|
|
|
|
//
|
|
// System processing
|
|
//
|
|
|
|
Env = pCreateEnvironment (&Block);
|
|
if (Env) {
|
|
pSetEnvironmentBlock (&Block);
|
|
DestroyEnvironmentBlock (&Block);
|
|
}
|
|
|
|
// Call MigrateSystemNT
|
|
if (!AbortThisDll) {
|
|
rc = pCallMigrateSystemNt (
|
|
g_WorkingDir,
|
|
UnattendFile,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
AbortThisDll = TRUE;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD
|
|
pFinishHandshake (
|
|
IN PCTSTR FunctionName
|
|
)
|
|
{
|
|
DWORD TechnicalLogId;
|
|
DWORD GuiLogId;
|
|
DWORD rc = ERROR_SUCCESS;
|
|
BOOL b;
|
|
UINT Count = 40; // about 5 minutes
|
|
UINT AliveAllowance = 10; // about 30 minutes
|
|
|
|
do {
|
|
//
|
|
// No OUT parameters on the NT side, so we don't care
|
|
// about the return data
|
|
//
|
|
|
|
b = GetIpcCommandResults (
|
|
IPC_GET_RESULTS_NT,
|
|
NULL,
|
|
NULL,
|
|
&rc,
|
|
&TechnicalLogId,
|
|
&GuiLogId
|
|
);
|
|
|
|
//
|
|
// If error code is returned, stuff it in setupact.log
|
|
//
|
|
|
|
if (b && rc != ERROR_SUCCESS) {
|
|
LOG ((
|
|
LOG_WARNING,
|
|
"Migration DLL %s returned %u (0x%08X) in %s",
|
|
g_DllDesc,
|
|
rc,
|
|
rc,
|
|
FunctionName
|
|
));
|
|
}
|
|
|
|
|
|
//
|
|
// Loop if no data received, but process is alive
|
|
//
|
|
|
|
if (!b) {
|
|
if (!IsIpcProcessAlive()) {
|
|
rc = ERROR_NOACCESS;
|
|
break;
|
|
}
|
|
|
|
// continue if command was not sent yet but exe is still OK
|
|
Count--;
|
|
if (Count == 0) {
|
|
if (WaitForSingleObject (g_AliveEvent, 0) == WAIT_OBJECT_0) {
|
|
DEBUGMSG ((DBG_WARNING, "Alive allowance given to migration DLL"));
|
|
|
|
AliveAllowance--;
|
|
if (AliveAllowance) {
|
|
Count = 24; // about 3 minutes
|
|
}
|
|
}
|
|
|
|
if (Count == 0) {
|
|
rc = ERROR_SEM_TIMEOUT;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
} while (!b);
|
|
|
|
if (b) {
|
|
//
|
|
// Recognize log messages
|
|
//
|
|
if (TechnicalLogId) {
|
|
//
|
|
// LOG message with three args: DllDesc, DllPath, User
|
|
//
|
|
|
|
LOG ((
|
|
LOG_ERROR,
|
|
(PCSTR) TechnicalLogId,
|
|
g_DllDesc,
|
|
g_DllPath,
|
|
g_FixedUser
|
|
));
|
|
}
|
|
if (GuiLogId) {
|
|
LOG ((
|
|
LOG_ERROR,
|
|
(PCSTR) GuiLogId,
|
|
g_DllDesc,
|
|
g_DllPath,
|
|
g_FixedUser
|
|
));
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
pCallInitializeNt (
|
|
IN PCTSTR WorkingDir,
|
|
IN PCTSTR *SourceDirArray,
|
|
IN PVOID Reserved,
|
|
IN DWORD ReservedBytes
|
|
)
|
|
{
|
|
DWORD rc = ERROR_SUCCESS;
|
|
GROWBUFFER GrowBuf = GROWBUF_INIT;
|
|
INT Count;
|
|
PBYTE BufPtr;
|
|
PDWORD ReservedBytesPtr;
|
|
TCHAR SavedCwd [MAX_TCHAR_PATH];
|
|
|
|
if (!g_ConfigOptions.TestDlls) {
|
|
__try {
|
|
MultiSzAppend (&GrowBuf, WorkingDir);
|
|
|
|
//
|
|
// Prepare multi-sz directory list
|
|
//
|
|
|
|
for (Count = 0 ; SourceDirArray[Count] ; Count++) {
|
|
MultiSzAppend (&GrowBuf, SourceDirArray[Count]);
|
|
}
|
|
|
|
MultiSzAppend (&GrowBuf, S_EMPTY);
|
|
|
|
ReservedBytesPtr = (PDWORD) GrowBuffer (&GrowBuf, sizeof (ReservedBytes));
|
|
*ReservedBytesPtr = ReservedBytes;
|
|
|
|
if (ReservedBytes) {
|
|
BufPtr = GrowBuffer (&GrowBuf, ReservedBytes);
|
|
CopyMemory (BufPtr, Reserved, ReservedBytes);
|
|
}
|
|
|
|
if (!SendIpcCommand (
|
|
IPC_INITIALIZE,
|
|
GrowBuf.Buf,
|
|
GrowBuf.End
|
|
)) {
|
|
|
|
LOG ((LOG_ERROR, "Call InitializeNT failed to send command"));
|
|
rc = GetLastError();
|
|
__leave;
|
|
}
|
|
|
|
rc = pFinishHandshake (TEXT("InitializeNT"));
|
|
if (rc != ERROR_SUCCESS) {
|
|
LOG ((
|
|
LOG_ERROR,
|
|
"Call InitializeNT failed to complete handshake, rc=%u",
|
|
rc
|
|
));
|
|
}
|
|
}
|
|
__finally {
|
|
FreeGrowBuffer (&GrowBuf);
|
|
}
|
|
}
|
|
else {
|
|
|
|
pSetCwd (
|
|
SavedCwd, // old
|
|
WorkingDir // new
|
|
);
|
|
|
|
__try {
|
|
//
|
|
// Prepare multi-sz directory list
|
|
//
|
|
|
|
for (Count = 0 ; SourceDirArray[Count] ; Count++) {
|
|
MultiSzAppend (&GrowBuf, SourceDirArray[Count]);
|
|
}
|
|
|
|
MultiSzAppend (&GrowBuf, S_EMPTY);
|
|
|
|
rc = InitializeNT (WorkingDir, (PCTSTR) GrowBuf.Buf, Reserved);
|
|
|
|
FreeGrowBuffer (&GrowBuf);
|
|
}
|
|
__finally {
|
|
SetCurrentDirectory (SavedCwd);
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
pCallMigrateUserNt (
|
|
IN PCTSTR WorkingDir,
|
|
IN PCTSTR UnattendFile,
|
|
IN PCTSTR RootKey,
|
|
IN PCTSTR Win9xUserName,
|
|
IN PCTSTR UserDomain,
|
|
IN PCTSTR FixedUserName,
|
|
IN PVOID Reserved,
|
|
IN DWORD ReservedBytes
|
|
)
|
|
{
|
|
DWORD rc = ERROR_SUCCESS;
|
|
GROWBUFFER GrowBuf = GROWBUF_INIT;
|
|
PDWORD ReservedBytesPtr;
|
|
PVOID BufPtr;
|
|
TCHAR SavedCwd [MAX_TCHAR_PATH];
|
|
TCHAR UserBuf[MAX_USER_NAME * 3];
|
|
PTSTR p;
|
|
TCHAR OrgUserProfilePath[MAX_TCHAR_PATH];
|
|
TCHAR UserProfilePath[MAX_TCHAR_PATH];
|
|
|
|
if (FixedUserName[0]) {
|
|
GetUserProfilePath (FixedUserName, &p);
|
|
StackStringCopy (UserProfilePath, p);
|
|
FreePathString (p);
|
|
|
|
DEBUGMSG ((DBG_VERBOSE, "Profile path for %s is %s", FixedUserName, UserProfilePath));
|
|
} else {
|
|
UserProfilePath[0] = 0;
|
|
}
|
|
|
|
GetEnvironmentVariable (S_USERPROFILE, OrgUserProfilePath, MAX_TCHAR_PATH);
|
|
SetEnvironmentVariable (S_USERPROFILE, UserProfilePath);
|
|
|
|
if (!g_ConfigOptions.TestDlls) {
|
|
__try {
|
|
MultiSzAppend (&GrowBuf, UnattendFile);
|
|
MultiSzAppend (&GrowBuf, RootKey);
|
|
MultiSzAppend (&GrowBuf, Win9xUserName);
|
|
MultiSzAppend (&GrowBuf, UserDomain);
|
|
MultiSzAppend (&GrowBuf, FixedUserName);
|
|
MultiSzAppend (&GrowBuf, UserProfilePath);
|
|
|
|
ReservedBytesPtr = (PDWORD) GrowBuffer (&GrowBuf, sizeof (ReservedBytes));
|
|
*ReservedBytesPtr = ReservedBytes;
|
|
|
|
if (ReservedBytes) {
|
|
BufPtr = GrowBuffer (&GrowBuf, ReservedBytes);
|
|
CopyMemory (BufPtr, Reserved, ReservedBytes);
|
|
}
|
|
|
|
if (!SendIpcCommand (
|
|
IPC_MIGRATEUSER,
|
|
GrowBuf.Buf,
|
|
GrowBuf.End
|
|
)) {
|
|
|
|
LOG ((LOG_ERROR, "Call MigrateUserNT failed to send command"));
|
|
rc = GetLastError();
|
|
__leave;
|
|
}
|
|
|
|
rc = pFinishHandshake (TEXT("MigrateUserNT"));
|
|
if (rc != ERROR_SUCCESS) {
|
|
LOG ((
|
|
LOG_ERROR,
|
|
"Call MigrateUserNT failed to complete handshake, rc=%u",
|
|
rc
|
|
));
|
|
}
|
|
}
|
|
__finally {
|
|
FreeGrowBuffer (&GrowBuf);
|
|
}
|
|
|
|
} else {
|
|
|
|
pSetCwd (
|
|
SavedCwd, // old
|
|
WorkingDir // new
|
|
);
|
|
|
|
__try {
|
|
|
|
HINF UnattendHandle;
|
|
HKEY UserRegHandle;
|
|
|
|
UnattendHandle = InfOpenInfFile (UnattendFile);
|
|
if (UnattendHandle == INVALID_HANDLE_VALUE) {
|
|
__leave;
|
|
}
|
|
|
|
UserRegHandle = OpenRegKeyStr (RootKey);
|
|
if (!UserRegHandle) {
|
|
rc = GetLastError();
|
|
InfCloseInfFile (UnattendHandle);
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// Transfer user, user domain and fixed name to a buffer
|
|
//
|
|
|
|
if (Win9xUserName) {
|
|
StringCopy (UserBuf, Win9xUserName);
|
|
} else {
|
|
UserBuf[0] = 0;
|
|
}
|
|
|
|
p = GetEndOfString (UserBuf) + 1;
|
|
|
|
if (UserDomain) {
|
|
StringCopy (p, UserDomain);
|
|
} else {
|
|
p[0] = 0;
|
|
}
|
|
|
|
p = GetEndOfString (p) + 1;
|
|
|
|
if (UserDomain) {
|
|
StringCopy (p, FixedUserName);
|
|
} else {
|
|
p[0] = 0;
|
|
}
|
|
|
|
//
|
|
// Call the entry point
|
|
//
|
|
|
|
rc = MigrateUserNT (
|
|
UnattendHandle,
|
|
UserRegHandle,
|
|
UserBuf[0] ? UserBuf : NULL,
|
|
Reserved
|
|
);
|
|
|
|
CloseRegKey (UserRegHandle);
|
|
InfCloseInfFile (UnattendHandle);
|
|
}
|
|
__finally {
|
|
SetCurrentDirectory (SavedCwd);
|
|
}
|
|
}
|
|
|
|
SetEnvironmentVariable (S_USERPROFILE, OrgUserProfilePath);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
pCallMigrateSystemNt (
|
|
IN PCTSTR WorkingDir,
|
|
IN PCTSTR UnattendFile,
|
|
IN PVOID Reserved,
|
|
IN DWORD ReservedBytes
|
|
)
|
|
{
|
|
DWORD rc = ERROR_SUCCESS;
|
|
GROWBUFFER GrowBuf = GROWBUF_INIT;
|
|
PDWORD ReservedBytesPtr;
|
|
PVOID BufPtr;
|
|
TCHAR SavedCwd [MAX_TCHAR_PATH];
|
|
|
|
if (!g_ConfigOptions.TestDlls) {
|
|
__try {
|
|
MultiSzAppend (&GrowBuf, UnattendFile);
|
|
|
|
ReservedBytesPtr = (PDWORD) GrowBuffer (&GrowBuf, sizeof (ReservedBytes));
|
|
*ReservedBytesPtr = ReservedBytes;
|
|
|
|
if (ReservedBytes) {
|
|
BufPtr = GrowBuffer (&GrowBuf, ReservedBytes);
|
|
CopyMemory (BufPtr, Reserved, ReservedBytes);
|
|
}
|
|
|
|
if (!SendIpcCommand (IPC_MIGRATESYSTEM, GrowBuf.Buf, GrowBuf.End)) {
|
|
LOG ((LOG_ERROR, "Call MigrateSystemNT failed to send command"));
|
|
rc = GetLastError();
|
|
__leave;
|
|
}
|
|
|
|
rc = pFinishHandshake (TEXT("MigrateSystemNT"));
|
|
if (rc != ERROR_SUCCESS) {
|
|
LOG ((
|
|
LOG_ERROR,
|
|
"Call MigrateSystemNT failed to complete handshake, rc=%u",
|
|
rc
|
|
));
|
|
}
|
|
}
|
|
__finally {
|
|
FreeGrowBuffer (&GrowBuf);
|
|
}
|
|
}
|
|
else {
|
|
pSetCwd (
|
|
SavedCwd, // old
|
|
WorkingDir // new
|
|
);
|
|
|
|
__try {
|
|
HINF UnattendHandle;
|
|
|
|
UnattendHandle = InfOpenInfFile (UnattendFile);
|
|
if (UnattendHandle == INVALID_HANDLE_VALUE) {
|
|
rc = GetLastError();
|
|
__leave;
|
|
}
|
|
|
|
rc = MigrateSystemNT (UnattendHandle, Reserved);
|
|
|
|
InfCloseInfFile (UnattendHandle);
|
|
}
|
|
__finally {
|
|
SetCurrentDirectory (SavedCwd);
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|