windows-nt/Source/XPSP1/NT/base/ntsetup/opktools/factory/winpenet.c
2020-09-26 16:20:57 +08:00

433 lines
13 KiB
C

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
winpenet.c
Abstract:
This module contains code to control the startup of the network in the WinPE environment.
It relies upon the existence of WINBOM.INI and the following sections:
[WinPE.net]
Startnet = YES | NO - Specifies whether to start networking.
Ipconfig = DHCP | x.x.x.x - Specifies DHCP or a static IP address.
SubnetMask = x.x.x.x - SubnetMask for the static IP.
Gateway = x.x.x.x - Default gateway for the static IP.
Author:
Adrian Cosma (acosma) - 1/18/2001
Revision History:
--*/
//
// Includes
//
#include "factoryp.h"
#include <winsock2.h>
//
// Defines
//
typedef HRESULT (PASCAL *PRegisterServer)(VOID);
//
// Static strings
//
const static TCHAR DEF_GATEWAY_METRIC[] = _T("1\0"); // Need to NULLCHRs at the end since this goes into a REG_MULTI_SZ.
const static TCHAR REGSTR_TCPIP[] = _T("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\");
//
// Local function declarations
//
static BOOL InstallNetComponents(VOID);
static BOOL RegisterDll(VOID);
//
// Function implementations
//
static BOOL InstallNetComponents(VOID)
{
TCHAR szCmdLine[MAX_PATH] = NULLSTR;
DWORD dwExitCode = 0;
BOOL bRet = TRUE;
lstrcpyn(szCmdLine, _T("-winpe"), AS ( szCmdLine ) ) ;
if ( !InvokeExternalApplicationEx(_T("netcfg"), szCmdLine, &dwExitCode, INFINITE, TRUE) )
{
FacLogFile(0 | LOG_ERR, IDS_ERR_NETWORKCOMP);
bRet = FALSE;
}
return bRet;
}
static BOOL RegisterDll(VOID)
{
HMODULE hDll = NULL;
BOOL bRet = FALSE;
PRegisterServer pRegisterServer = NULL;
if ( (hDll = LoadLibrary(_T("netcfgx.dll"))) &&
(pRegisterServer = (PRegisterServer) GetProcAddress(hDll, "DllRegisterServer")) &&
(S_OK == pRegisterServer()) )
{
FacLogFileStr(3, _T("Succesfully registered netcfg.dll.\n"));
bRet = TRUE;
}
else
{
FacLogFile(0 | LOG_ERR, IDS_ERR_REGISTERNETCFG);
}
if (hDll)
FreeLibrary(hDll);
return bRet;
}
BOOL WinpeNet(LPSTATEDATA lpStateData)
{
LPTSTR lpszWinBOMPath = lpStateData->lpszWinBOMPath;
SC_HANDLE hSCM = NULL;
TCHAR szBuf[MAX_WINPE_PROFILE_STRING] = NULLSTR;
BOOL bRet = TRUE;
// Make sure that the user wants us to do networking.
//
GetPrivateProfileString(INI_KEY_WBOM_WINPE_NET, INI_KEY_WBOM_WINPE_NET_STARTNET, NULLSTR, szBuf, AS(szBuf), lpszWinBOMPath);
// If user does not want to start networking just return success.
//
if ( 0 == LSTRCMPI(szBuf, WBOM_NO) )
return TRUE;
// Register dll.
// Run netcfg -winpe.
// Install network card.
// See if the user wants to use a static IP.
//
if ( RegisterDll() &&
SetupMiniNT() &&
InstallNetComponents() &&
ConfigureNetwork(g_szWinBOMPath)
)
{
//
// Start Services for networking.
//
if ( hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS) )
{
// DHCP also starts tcpip and netbt.
// The workstation service should already be started by the installer.
//
if ( (StartMyService(_T("dhcp"), hSCM) != NO_ERROR) ||
(StartMyService(_T("nla"), hSCM) != NO_ERROR)
)
{
FacLogFile(0 | LOG_ERR, IDS_ERR_NETSERVICES);
bRet = FALSE;
}
CloseServiceHandle(hSCM);
}
else
{
FacLogFile(0 | LOG_ERR, IDS_ERR_SCM);
bRet = FALSE;
}
}
else
{
FacLogFile(0 | LOG_ERR, IDS_ERR_SETUPNETWORK);
bRet = FALSE;
}
return bRet;
}
BOOL DisplayWinpeNet(LPSTATEDATA lpStateData)
{
return ( !IniSettingExists(lpStateData->lpszWinBOMPath, INI_KEY_WBOM_WINPE_NET, INI_KEY_WBOM_WINPE_NET_STARTNET, INI_VAL_WBOM_NO) );
}
BOOL ConfigureNetwork(LPTSTR lpszWinBOMPath)
{
TCHAR szBuf[MAX_WINPE_PROFILE_STRING] = NULLSTR;
CHAR szBufA[MAX_WINPE_PROFILE_STRING] = { 0 };
TCHAR szReg[MAX_WINPE_PROFILE_STRING] = NULLSTR;
TCHAR szIpAddress[MAX_WINPE_PROFILE_STRING] = NULLSTR;
TCHAR szSubnetMask[MAX_WINPE_PROFILE_STRING] = NULLSTR;
HKEY hKey = NULL; // Reg Key to interfaces.
HKEY hKeyI = NULL; // Reg Key to specific network interface.
DWORD dwDis = 0;
TCHAR szRegKey[MAX_PATH] = NULLSTR;
DWORD dwEnableDHCP = 0;
BOOL fErr = FALSE;
szBuf[0] = NULLCHR;
GetPrivateProfileString(INI_KEY_WBOM_WINPE_NET, WBOM_WINPE_NET_IPADDRESS, NULLSTR, szBuf, MAX_WINPE_PROFILE_STRING, lpszWinBOMPath);
// Convert the string to ANSI
//
if ( szBuf[0] &&
WideCharToMultiByte(CP_ACP, 0, szBuf, -1, szBufA, AS(szBufA), NULL, NULL) )
{
// If it's DHCP don't do anything. Just return TRUE.
//
if ( 0 == LSTRCMPI(szBuf, _T("DHCP")) )
return TRUE;
if ( INADDR_NONE == inet_addr(szBufA) )
{
FacLogFile(0 | LOG_ERR, IDS_ERR_INVALIDIP , szBuf);
return FALSE;
}
}
else // if there is no IpConfig entry return success (same as DHCP)
return TRUE;
// Save the IpAddress.
lstrcpyn(szIpAddress, szBuf, AS ( szIpAddress ) );
szBuf[0] = NULLCHR;
GetPrivateProfileString(INI_KEY_WBOM_WINPE_NET, WBOM_WINPE_NET_SUBNETMASK, NULLSTR, szBuf, MAX_WINPE_PROFILE_STRING, lpszWinBOMPath);
// Convert the string to ANSI
//
if ( szBuf[0] &&
WideCharToMultiByte(CP_ACP,0, szBuf, -1, szBufA, AS(szBufA), NULL, NULL) )
{
if ( INADDR_NONE == inet_addr(szBufA) )
{
FacLogFile(0 | LOG_ERR, IDS_ERR_INVALIDMASK , szBuf);
return FALSE;
}
}
else // If we got this far we need to have a subnet mask
{
FacLogFile(0 | LOG_ERR, IDS_ERR_NOMASK);
return FALSE;
}
// Save the SubnetMask.
lstrcpyn(szSubnetMask, szBuf, AS ( szSubnetMask ) );
//
// Write the settings to the registry.
//
// Make sure that the strings are terminated by two NULLCHRs.
//
szIpAddress[lstrlen(szIpAddress) + 1] = NULLCHR;
szSubnetMask[lstrlen(szSubnetMask) + 1] = NULLCHR;
// Assuming that there is only one interface in the system.
//
if ( (RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGSTR_TCPIP, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDis) == ERROR_SUCCESS) &&
(RegEnumKey(hKey, 0, szRegKey, AS(szRegKey)) == ERROR_SUCCESS) &&
szRegKey[0] &&
(RegCreateKeyEx(hKey, szRegKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyI, &dwDis) == ERROR_SUCCESS) )
{
if ( ERROR_SUCCESS != (RegSetValueEx(hKeyI, _T("IPAddress"), 0, REG_MULTI_SZ, (CONST LPBYTE) szIpAddress, ( lstrlen(szIpAddress) + 2 ) * sizeof(TCHAR))) ||
ERROR_SUCCESS != (RegSetValueEx(hKeyI, _T("SubnetMask"), 0, REG_MULTI_SZ, (CONST LPBYTE) szSubnetMask, ( lstrlen(szSubnetMask) + 2 ) * sizeof(TCHAR))) ||
ERROR_SUCCESS != (RegSetValueEx(hKeyI, _T("EnableDHCP"), 0, REG_DWORD, (CONST LPBYTE) &dwEnableDHCP, sizeof(dwEnableDHCP))) )
{
FacLogFile(0 | LOG_ERR, IDS_ERR_IPREGISTRY);
fErr = TRUE;
}
else
{
//
// If the gateway is not specified we don't care. We're just not going to add this
// if it's not there.
//
szBuf[0] = NULLCHR;
GetPrivateProfileString(INI_KEY_WBOM_WINPE_NET, WBOM_WINPE_NET_GATEWAY, NULLSTR, szBuf, MAX_WINPE_PROFILE_STRING, lpszWinBOMPath);
if ( szBuf[0] &&
WideCharToMultiByte(CP_ACP,0, szBuf, -1, szBufA, AS(szBufA), NULL, NULL) )
{
if ( INADDR_NONE == inet_addr(szBufA) )
{
FacLogFile(0 | LOG_ERR, IDS_ERR_INVALIDGW, szBuf);
fErr = TRUE;
}
else
{
szBuf[lstrlen(szBuf) + 1] = NULLCHR;
if ( (RegSetValueEx(hKeyI, _T("DefaultGateway"), 0, REG_MULTI_SZ, (CONST LPBYTE) szBuf, ( lstrlen(szBuf) + 2 ) * sizeof(TCHAR)) != ERROR_SUCCESS) ||
(RegSetValueEx(hKeyI, _T("DefaultGatewayMetric"), 0, REG_MULTI_SZ, (CONST LPBYTE) DEF_GATEWAY_METRIC, ( lstrlen(DEF_GATEWAY_METRIC) + 2 ) * sizeof(TCHAR)) != ERROR_SUCCESS) )
{
FacLogFile(0 | LOG_ERR, IDS_ERR_GWREGISTRY);
fErr = TRUE;
}
}
}
}
RegCloseKey(hKeyI);
}
else
{
FacLogFile(0 | LOG_ERR, IDS_ERR_IPREGISTRY);
}
// It is possible that the subkey failed to open so this takes care of a possible leak.
//
if (hKey)
RegCloseKey(hKey);
return (!fErr);
}
static DWORD WaitForServiceStart(SC_HANDLE schService)
{
SERVICE_STATUS ssStatus;
DWORD dwOldCheckPoint;
DWORD dwStartTickCount;
DWORD dwWaitTime;
DWORD dwStatus = NO_ERROR;
if ( schService )
{
//
// Service start is now pending.
// Check the status until the service is no longer start pending.
//
if ( QueryServiceStatus( schService, &ssStatus) )
{
// Save the tick count and initial checkpoint.
//
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
while (ssStatus.dwCurrentState == SERVICE_START_PENDING)
{
// Do not wait longer than the wait hint. A good interval is
// one tenth the wait hint, but no less than 1 second and no
// more than 10 seconds.
//
dwWaitTime = ssStatus.dwWaitHint / 10;
if( dwWaitTime < 1000 )
dwWaitTime = 1000;
else if ( dwWaitTime > 10000 )
dwWaitTime = 10000;
Sleep( dwWaitTime );
// Check the status again.
//
if (!QueryServiceStatus(
schService, // handle to service
&ssStatus) ) // address of structure
break;
if ( ssStatus.dwCheckPoint > dwOldCheckPoint )
{
// The service is making progress.
//
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
}
else
{
if(GetTickCount()-dwStartTickCount > ssStatus.dwWaitHint)
{
// No progress made within the wait hint
//
break;
}
}
}
if (ssStatus.dwCurrentState == SERVICE_RUNNING)
{
dwStatus = NO_ERROR;
}
else
{
// Set the return value to the last error.
//
dwStatus = GetLastError();
}
}
}
return dwStatus;
}
DWORD WaitForServiceStartName(LPTSTR lpszServiceName)
{
SC_HANDLE hSCM = NULL;
SC_HANDLE schService = NULL;
DWORD dwStatus = NO_ERROR;
if ( lpszServiceName )
{
if ( hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS) )
{
if ( schService = OpenService(hSCM, lpszServiceName, SERVICE_ALL_ACCESS) )
{
dwStatus = WaitForServiceStart(schService);
CloseServiceHandle(schService);
}
else
{
dwStatus = GetLastError();
FacLogFile(0 | LOG_ERR, IDS_ERR_SERVICE, lpszServiceName);
}
CloseServiceHandle(hSCM);
}
else
{
dwStatus = GetLastError();
FacLogFile(0 | LOG_ERR, IDS_ERR_SCM);
}
}
else
{
dwStatus = E_INVALIDARG;
}
return dwStatus;
}
// Start a service.
//
DWORD StartMyService(LPTSTR lpszServiceName, SC_HANDLE schSCManager)
{
SC_HANDLE schService;
DWORD dwStatus = NO_ERROR;
FacLogFileStr(3, _T("Starting service: %s\n"), lpszServiceName);
if ( NULL != (schService = OpenService(schSCManager, lpszServiceName, SERVICE_ALL_ACCESS)) &&
StartService(schService, 0, NULL) )
{
dwStatus = WaitForServiceStart(schService);
}
if ( schService )
CloseServiceHandle(schService);
return dwStatus;
}