mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1157 lines
32 KiB
1157 lines
32 KiB
#include "setupp.h"
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// List of characters that are not legal in netnames.
|
|
//
|
|
PCWSTR IllegalNetNameChars = L"\"/\\[]:|<>+=;,?*";
|
|
|
|
//
|
|
// Computer name.
|
|
//
|
|
WCHAR ComputerName[DNS_MAX_LABEL_LENGTH+1];
|
|
WCHAR Win32ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
|
|
BOOL IsNameTruncated;
|
|
BOOL IsNameNonRfc;
|
|
|
|
//
|
|
// Copy disincentive name/organization strings.
|
|
//
|
|
WCHAR NameOrgName[MAX_NAMEORG_NAME+1];
|
|
WCHAR NameOrgOrg[MAX_NAMEORG_ORG+1];
|
|
|
|
#ifdef DOLOCALUSER
|
|
//
|
|
// User name and password
|
|
//
|
|
WCHAR UserName[MAX_USERNAME+1];
|
|
WCHAR UserPassword[MAX_PASSWORD+1];
|
|
BOOL CreateUserAccount = FALSE;
|
|
#endif // def DOLOCALUSER
|
|
|
|
//
|
|
// Administrator password.
|
|
//
|
|
WCHAR CurrentAdminPassword[MAX_PASSWORD+1];
|
|
WCHAR AdminPassword[MAX_PASSWORD+1];
|
|
BOOL EncryptedAdminPasswordSet = FALSE;
|
|
BOOL DontChangeAdminPassword = FALSE;
|
|
|
|
|
|
|
|
VOID
|
|
GenerateName(
|
|
OUT PWSTR GeneratedString,
|
|
IN DWORD DesiredStrLen
|
|
)
|
|
{
|
|
static DWORD Seed = 98725757;
|
|
static PCWSTR UsableChars = L"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
|
|
//
|
|
// How many characters will come from the org/name string.
|
|
//
|
|
DWORD BaseLength = 8;
|
|
DWORD i,j;
|
|
DWORD UsableCount;
|
|
|
|
if( DesiredStrLen < BaseLength ) {
|
|
BaseLength = DesiredStrLen - 1;
|
|
}
|
|
|
|
|
|
if( NameOrgOrg[0] ) {
|
|
wcscpy( GeneratedString, NameOrgOrg );
|
|
} else if( NameOrgName[0] ) {
|
|
wcscpy( GeneratedString, NameOrgName );
|
|
} else {
|
|
wcscpy( GeneratedString, TEXT("X") );
|
|
for( i = 1; i < BaseLength; i++ ) {
|
|
wcscat( GeneratedString, TEXT("X") );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get him upper-case for our filter...
|
|
//
|
|
CharUpper(GeneratedString);
|
|
|
|
//
|
|
// Now we want to put a '-' at the end
|
|
// of our GeneratedString. We'd like it to
|
|
// be placed in the BASE_LENGTH character, but
|
|
// the string may be shorter than that, or may
|
|
// even have a ' ' in it. Figure out where to
|
|
// put the '-' now.
|
|
//
|
|
for( i = 0; i <= BaseLength; i++ ) {
|
|
|
|
//
|
|
// Check for a short string.
|
|
//
|
|
if( (GeneratedString[i] == 0 ) ||
|
|
(GeneratedString[i] == L' ') ||
|
|
(!wcschr(UsableChars, GeneratedString[i])) ||
|
|
(i == BaseLength )
|
|
) {
|
|
GeneratedString[i] = L'-';
|
|
GeneratedString[i+1] = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Special case the scenario where we had no usable
|
|
// characters.
|
|
//
|
|
if( GeneratedString[0] == L'-' ) {
|
|
GeneratedString[0] = 0;
|
|
}
|
|
|
|
UsableCount = lstrlen(UsableChars);
|
|
Seed ^= GetCurrentTime();
|
|
srand( Seed );
|
|
|
|
j = lstrlen( GeneratedString );
|
|
for( i = j; i < DesiredStrLen; i++ ) {
|
|
GeneratedString[i] = UsableChars[rand() % UsableCount];
|
|
}
|
|
GeneratedString[i] = 0;
|
|
|
|
//
|
|
// In the normal case, the edit control in the wizard page
|
|
// has the ES_UPPER bit set. In the normal unattend case
|
|
// there is code in unattend.txt that uppercases the name.
|
|
// But if we get to generating the name then then the text
|
|
// in unattend.txt was * and we thus never had any text in
|
|
// the edit control or unattend.txt to be uppercased.
|
|
//
|
|
CharUpper(GeneratedString);
|
|
}
|
|
|
|
|
|
BOOL
|
|
ContainsDot(
|
|
IN PCWSTR NameToCheck
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine whether a given name contains a '.'
|
|
|
|
Arguments:
|
|
|
|
NameToCheck - supplies name to be checked.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the name contains a '.'; FALSE if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT Length,u;
|
|
|
|
if (!NameToCheck)
|
|
return FALSE;
|
|
|
|
Length = lstrlen(NameToCheck);
|
|
|
|
for (u = 0; u < Length; u++) {
|
|
if (NameToCheck[u] == L'.')
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsNetNameValid(
|
|
IN PCWSTR NameToCheck,
|
|
IN BOOL AlphaNumericOnly
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine whether a given name is valid as a netname, such as
|
|
a computer name.
|
|
|
|
Arguments:
|
|
|
|
NameToCheck - supplies name to be checked.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the name is valid; FALSE if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT Length,u;
|
|
|
|
Length = lstrlen(NameToCheck);
|
|
|
|
//
|
|
// Want at least one character.
|
|
//
|
|
if(!Length) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Leading/trailing spaces are invalid.
|
|
//
|
|
if((NameToCheck[0] == L' ') || (NameToCheck[Length-1] == L' ')) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Control chars are invalid, as are characters in the illegal chars list.
|
|
//
|
|
for(u=0; u<Length; u++) {
|
|
if (AlphaNumericOnly) {
|
|
if (NameToCheck[u] == L'-' || NameToCheck[u] == L'_') {
|
|
continue;
|
|
}
|
|
if (!iswalnum(NameToCheck[u])) {
|
|
return(FALSE);
|
|
}
|
|
} else {
|
|
if((NameToCheck[u] < L' ') || wcschr(IllegalNetNameChars,NameToCheck[u])) {
|
|
return(FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// We got here, name is ok.
|
|
//
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL SetIMEOpenStatus(
|
|
IN HWND hDlg,
|
|
IN BOOL bSetActive)
|
|
{
|
|
typedef HIMC (WINAPI* PFN_IMMGETCONTEXT)(HWND);
|
|
typedef BOOL (WINAPI* PFN_IMMSETOPENSTATUS)(HIMC,BOOL);
|
|
typedef BOOL (WINAPI* PFN_IMMGETOPENSTATUS)(HIMC);
|
|
typedef BOOL (WINAPI* PFN_IMMRELEASECONTEXT)(HWND,HIMC);
|
|
|
|
PFN_IMMGETCONTEXT PFN_ImmGetContext;
|
|
PFN_IMMSETOPENSTATUS PFN_ImmSetOpenStatus;
|
|
PFN_IMMGETOPENSTATUS PFN_ImmGetOpenStatus;
|
|
PFN_IMMRELEASECONTEXT PFN_ImmReleaseContext;
|
|
|
|
HIMC hIMC;
|
|
HKL hKL;
|
|
HMODULE hImmDll;
|
|
static BOOL bImeEnable=TRUE;
|
|
|
|
hKL = GetKeyboardLayout(0);
|
|
|
|
if ((HIWORD(HandleToUlong(hKL)) & 0xF000) != 0xE000) {
|
|
//
|
|
// not an IME, do nothing !
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
hImmDll = GetModuleHandle(TEXT("IMM32.DLL"));
|
|
|
|
if (hImmDll == NULL) {
|
|
//
|
|
// weird case, if the kbd layout is an IME, then
|
|
// Imm32.dll should have already been loaded into process.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
PFN_ImmGetContext = (PFN_IMMGETCONTEXT) GetProcAddress(hImmDll,"ImmGetContext");
|
|
if (PFN_ImmGetContext == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
PFN_ImmReleaseContext = (PFN_IMMRELEASECONTEXT) GetProcAddress(hImmDll,"ImmReleaseContext");
|
|
if (PFN_ImmReleaseContext == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
PFN_ImmSetOpenStatus = (PFN_IMMSETOPENSTATUS) GetProcAddress(hImmDll,"ImmSetOpenStatus");
|
|
if (PFN_ImmSetOpenStatus == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
PFN_ImmGetOpenStatus = (PFN_IMMGETOPENSTATUS) GetProcAddress(hImmDll,"ImmGetOpenStatus");
|
|
if (PFN_ImmGetOpenStatus == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Get Current Input Context.
|
|
//
|
|
hIMC = PFN_ImmGetContext(hDlg);
|
|
if (hIMC == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (bSetActive) {
|
|
PFN_ImmSetOpenStatus(hIMC,bImeEnable);
|
|
}
|
|
else {
|
|
//
|
|
// Save Current Status.
|
|
//
|
|
bImeEnable = PFN_ImmGetOpenStatus(hIMC);
|
|
//
|
|
// Close IME.
|
|
//
|
|
PFN_ImmSetOpenStatus(hIMC,FALSE);
|
|
}
|
|
|
|
PFN_ImmReleaseContext(hDlg,hIMC);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// returns TRUE if the name is valid, FALSE if it is not
|
|
BOOL ValidateNameOrgName (
|
|
WCHAR* pszName
|
|
)
|
|
{
|
|
WCHAR adminName[MAX_USERNAME+1];
|
|
WCHAR guestName[MAX_USERNAME+1];
|
|
|
|
LoadString(MyModuleHandle,IDS_ADMINISTRATOR,adminName,MAX_USERNAME+1);
|
|
LoadString(MyModuleHandle,IDS_GUEST,guestName,MAX_USERNAME+1);
|
|
|
|
if ( pszName == NULL )
|
|
return FALSE;
|
|
|
|
if(pszName[0] == 0)
|
|
return FALSE;
|
|
|
|
if(lstrcmpi(pszName,adminName) == 0 )
|
|
return FALSE;
|
|
|
|
if ( lstrcmpi(pszName,guestName) == 0 )
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
INT_PTR
|
|
CALLBACK
|
|
NameOrgDlgProc(
|
|
IN HWND hdlg,
|
|
IN UINT msg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
NMHDR *NotifyParams;
|
|
|
|
switch(msg) {
|
|
|
|
case WM_INITDIALOG: {
|
|
|
|
//
|
|
// Limit text fields to maximum lengths
|
|
//
|
|
|
|
SendDlgItemMessage(hdlg,IDT_NAME,EM_LIMITTEXT,MAX_NAMEORG_NAME,0);
|
|
SendDlgItemMessage(hdlg,IDT_ORGANIZATION,EM_LIMITTEXT,MAX_NAMEORG_ORG,0);
|
|
|
|
//
|
|
// Set Initial Values
|
|
//
|
|
|
|
SetDlgItemText(hdlg,IDT_NAME,NameOrgName);
|
|
SetDlgItemText(hdlg,IDT_ORGANIZATION,NameOrgOrg);
|
|
|
|
break;
|
|
}
|
|
case WM_IAMVISIBLE:
|
|
//
|
|
// If an error occured during out INIT phase, show the box to the
|
|
// user so that they know there is a problem
|
|
//
|
|
MessageBoxFromMessage(hdlg,MSG_NO_NAMEORG_NAME,NULL,IDS_ERROR,
|
|
MB_OK | MB_ICONSTOP);
|
|
SetFocus(GetDlgItem(hdlg,IDT_NAME));
|
|
break;
|
|
case WM_SIMULATENEXT:
|
|
// Simulate the next button somehow
|
|
PropSheet_PressButton( GetParent(hdlg), PSBTN_NEXT);
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
if (HIWORD(wParam) == EN_CHANGE) {
|
|
if(LOWORD(wParam) == IDT_ORGANIZATION) {
|
|
GetDlgItemText( hdlg, IDT_ORGANIZATION, NameOrgOrg, MAX_NAMEORG_ORG+1);
|
|
#ifdef DOLOCALUSER
|
|
} else if(LOWORD(wParam) == IDT_NAME) {
|
|
GetDlgItemText( hdlg, IDT_NAME, NameOrgName, MAX_NAMEORG_NAME+1);
|
|
#endif
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case WMX_VALIDATE:
|
|
//
|
|
// lParam == 0 for no UI, or 1 for UI
|
|
// Return 1 for success, -1 for error.
|
|
//
|
|
|
|
GetDlgItemText(hdlg,IDT_ORGANIZATION,NameOrgOrg,MAX_NAMEORG_ORG+1);
|
|
GetDlgItemText(hdlg,IDT_NAME,NameOrgName,MAX_NAMEORG_NAME+1);
|
|
|
|
// JMH - NameOrgName cannot be "Administrator", "Guest" or "" (blank).
|
|
|
|
if(ValidateNameOrgName(NameOrgName) == FALSE) {
|
|
//
|
|
// Skip UI?
|
|
//
|
|
|
|
if (!lParam) {
|
|
return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
|
|
}
|
|
|
|
//
|
|
// Tell user he must at least enter a name, and
|
|
// don't allow next page to be activated.
|
|
//
|
|
if (Unattended) {
|
|
UnattendErrorDlg(hdlg,IDD_NAMEORG);
|
|
} // if
|
|
MessageBoxFromMessage(hdlg,MSG_NO_NAMEORG_NAME,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
|
|
SetFocus(GetDlgItem(hdlg,IDT_NAME));
|
|
|
|
return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
|
|
}
|
|
|
|
return ReturnDlgResult (hdlg, VALIDATE_DATA_OK);
|
|
|
|
case WM_NOTIFY:
|
|
|
|
NotifyParams = (NMHDR *)lParam;
|
|
|
|
switch(NotifyParams->code) {
|
|
|
|
case PSN_SETACTIVE:
|
|
TESTHOOK(503);
|
|
BEGIN_SECTION(L"Personalize Your Software Page");
|
|
SetWizardButtons(hdlg,WizPageNameOrg);
|
|
|
|
if (Unattended) {
|
|
if (!UnattendSetActiveDlg(hdlg,IDD_NAMEORG)) {
|
|
break;
|
|
}
|
|
}
|
|
// Page becomes active, make page visible.
|
|
SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
|
|
//
|
|
// Set focus on the name edit control.
|
|
//
|
|
SetFocus(GetDlgItem(hdlg,IDT_NAME));
|
|
|
|
//
|
|
// Open/Close IME.
|
|
//
|
|
SetIMEOpenStatus(hdlg,TRUE);
|
|
|
|
break;
|
|
|
|
case PSN_WIZNEXT:
|
|
case PSN_WIZFINISH:
|
|
|
|
UnattendAdvanceIfValid (hdlg); // see WMX_VALIDATE
|
|
break;
|
|
|
|
case PSN_KILLACTIVE:
|
|
WizardKillHelp(hdlg);
|
|
SetWindowLongPtr(hdlg, DWLP_MSGRESULT, FALSE);
|
|
|
|
//
|
|
// Close IME.
|
|
//
|
|
SetIMEOpenStatus(hdlg,FALSE);
|
|
|
|
END_SECTION(L"Personalize Your Software Page");
|
|
break;
|
|
|
|
case PSN_HELP:
|
|
WizardBringUpHelp(hdlg,WizPageNameOrg);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
INT_PTR
|
|
CALLBACK
|
|
ComputerNameDlgProc(
|
|
IN HWND hdlg,
|
|
IN UINT msg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
NMHDR *NotifyParams;
|
|
DWORD err, Win32NameSize = MAX_COMPUTERNAME_LENGTH + 1;
|
|
static BOOL EncryptedAdminPasswordBad = FALSE;
|
|
static BOOL bPersonal = FALSE;
|
|
|
|
switch(msg) {
|
|
|
|
case WM_INITDIALOG: {
|
|
|
|
bPersonal = ( GetProductFlavor() == 4);
|
|
//
|
|
// Limit text to maximum length
|
|
//
|
|
SendDlgItemMessage(hdlg,IDT_EDIT1,EM_LIMITTEXT,DNS_MAX_LABEL_LENGTH,0);
|
|
if (!bPersonal)
|
|
{
|
|
SendDlgItemMessage(hdlg,IDT_EDIT2,EM_LIMITTEXT,MAX_PASSWORD,0);
|
|
SendDlgItemMessage(hdlg,IDT_EDIT3,EM_LIMITTEXT,MAX_PASSWORD,0);
|
|
}
|
|
//
|
|
// Set the Edit boxes to the initial text
|
|
//
|
|
|
|
//
|
|
// Generate a computer name if we're unattended and
|
|
// the user has requested a random name, or if we're
|
|
// attended.
|
|
//
|
|
|
|
GenerateName( ComputerName, 15 );
|
|
if( (Unattended) &&
|
|
(UnattendAnswerTable[UAE_COMPNAME].Answer.String) &&
|
|
(UnattendAnswerTable[UAE_COMPNAME].Answer.String[0] == L'*') ) {
|
|
//
|
|
// The unattend engine has asked us to generate a Computer
|
|
// name. Let's write the data back into the unattend
|
|
// database.
|
|
//
|
|
MyFree( UnattendAnswerTable[UAE_COMPNAME].Answer.String );
|
|
UnattendAnswerTable[UAE_COMPNAME].Answer.String = ComputerName;
|
|
}
|
|
|
|
if (!bPersonal)
|
|
{
|
|
if(DontChangeAdminPassword) {
|
|
EnableWindow(GetDlgItem(hdlg,IDT_EDIT2),FALSE);
|
|
EnableWindow(GetDlgItem(hdlg,IDT_EDIT3),FALSE);
|
|
} else {
|
|
SetDlgItemText(hdlg,IDT_EDIT2,AdminPassword);
|
|
SetDlgItemText(hdlg,IDT_EDIT3,AdminPassword);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_IAMVISIBLE:
|
|
MessageBoxFromMessage(
|
|
hdlg,
|
|
ComputerName[0] ? MSG_BAD_COMPUTER_NAME1 : MSG_BAD_COMPUTER_NAME2,
|
|
NULL,
|
|
IDS_ERROR,MB_OK|MB_ICONSTOP);
|
|
break;
|
|
|
|
case WM_SIMULATENEXT:
|
|
// Simulate the next button somehow
|
|
PropSheet_PressButton( GetParent(hdlg), PSBTN_NEXT);
|
|
break;
|
|
|
|
case WMX_VALIDATE:
|
|
//
|
|
// lParam == 0 for no UI, or 1 for UI
|
|
// Return 1 for success, -1 for error.
|
|
//
|
|
|
|
IsNameNonRfc = FALSE;
|
|
IsNameTruncated = FALSE;
|
|
|
|
GetDlgItemText(hdlg,IDT_EDIT1,ComputerName,DNS_MAX_LABEL_LENGTH+1);
|
|
|
|
// StrTrim removes both leading and trailing spaces
|
|
StrTrim(ComputerName, TEXT(" "));
|
|
|
|
if (ContainsDot(ComputerName)) {
|
|
err = ERROR_INVALID_NAME;
|
|
} else {
|
|
err = DnsValidateDnsName_W(ComputerName);
|
|
if (err == DNS_ERROR_NON_RFC_NAME) {
|
|
IsNameNonRfc = TRUE;
|
|
err = ERROR_SUCCESS;
|
|
}
|
|
|
|
if(err == ERROR_SUCCESS) {
|
|
//The name is a valid DNS name. Now verify that it is
|
|
//also a valid WIN32 computer name.
|
|
|
|
if (!DnsHostnameToComputerNameW(ComputerName,
|
|
Win32ComputerName,
|
|
&Win32NameSize) ||
|
|
!IsNetNameValid(Win32ComputerName, FALSE)) {
|
|
err = ERROR_INVALID_NAME;
|
|
}
|
|
else {
|
|
if (Win32NameSize < (UINT)lstrlen(ComputerName) ) {
|
|
//The DNSName was truncated to get a Win32 ComputerName.
|
|
IsNameTruncated = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the name has non-RFC characters or if it was truncated, warn
|
|
// user if it is not an unattended install and we have GUI.
|
|
//
|
|
if (err == ERROR_SUCCESS && !Unattended && lParam) {
|
|
|
|
if (IsNameNonRfc) {
|
|
//ComputerName has non-standard characters.
|
|
if (MessageBoxFromMessage(
|
|
hdlg,
|
|
MSG_DNS_NON_RFC_NAME,
|
|
NULL,
|
|
IDS_SETUP,MB_YESNO|MB_ICONWARNING,
|
|
ComputerName) == IDNO) {
|
|
|
|
SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
|
|
SendDlgItemMessage(hdlg,IDT_EDIT1,EM_SETSEL,0,-1);
|
|
return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
|
|
|
|
}
|
|
}
|
|
|
|
if (IsNameTruncated) {
|
|
//The computer name was truncated.
|
|
if (MessageBoxFromMessage(
|
|
hdlg,
|
|
MSG_DNS_NAME_TRUNCATED,
|
|
NULL,
|
|
IDS_SETUP,MB_YESNO|MB_ICONWARNING,
|
|
ComputerName, Win32ComputerName) == IDNO) {
|
|
|
|
SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
|
|
SendDlgItemMessage(hdlg,IDT_EDIT1,EM_SETSEL,0,-1);
|
|
return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if(err == ERROR_SUCCESS) {
|
|
WCHAR pw1[MAX_PASSWORD+1],pw2[MAX_PASSWORD+1];
|
|
if (bPersonal)
|
|
{
|
|
// if we are in personal we are done.
|
|
return ReturnDlgResult (hdlg, VALIDATE_DATA_OK);
|
|
}
|
|
//
|
|
// Good computer name. Now make sure passwords match.
|
|
//
|
|
GetDlgItemText(hdlg,IDT_EDIT2,pw1,MAX_PASSWORD+1);
|
|
GetDlgItemText(hdlg,IDT_EDIT3,pw2,MAX_PASSWORD+1);
|
|
if(lstrcmp(pw1,pw2)) {
|
|
//
|
|
// Skip UI?
|
|
//
|
|
|
|
if (!lParam) {
|
|
return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
|
|
}
|
|
|
|
//
|
|
//
|
|
// Inform user of password mismatch, and don't allow next page
|
|
// to be activated.
|
|
//
|
|
if (Unattended) {
|
|
UnattendErrorDlg(hdlg, IDD_COMPUTERNAME);
|
|
}
|
|
MessageBoxFromMessage(hdlg,MSG_PW_MISMATCH,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
|
|
SetDlgItemText(hdlg,IDT_EDIT2,L"");
|
|
SetDlgItemText(hdlg,IDT_EDIT3,L"");
|
|
SetFocus(GetDlgItem(hdlg,IDT_EDIT2));
|
|
|
|
return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
|
|
|
|
} else {
|
|
|
|
WCHAR adminName[MAX_USERNAME+1];
|
|
|
|
GetAdminAccountName( adminName );
|
|
|
|
|
|
//
|
|
// Process the encrypted password if
|
|
// 1) We are unattended and
|
|
// 2) The EncryptedAdminPassword key is "Yes" in the unatttend file and
|
|
// 3) We are not back here after setting it - i.e. via the back button etc.
|
|
// 4) We are not back here after failing to set it once.
|
|
|
|
|
|
if( Unattended && IsEncryptedAdminPasswordPresent() &&
|
|
!DontChangeAdminPassword && !EncryptedAdminPasswordBad){
|
|
|
|
// Logging is done inside the call to ProcessEncryptedAdminPassword
|
|
|
|
if(!(ProcessEncryptedAdminPassword(adminName))){
|
|
|
|
EncryptedAdminPasswordBad = TRUE;
|
|
|
|
// Page becomes active, make page visible.
|
|
SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
|
|
// Inform the user and enable the password fields
|
|
|
|
UnattendErrorDlg(hdlg, IDD_COMPUTERNAME);
|
|
MessageBoxFromMessage(hdlg,MSG_CHANGING_PW_FAIL,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP, adminName );
|
|
SetDlgItemText(hdlg,IDT_EDIT2,L"");
|
|
SetDlgItemText(hdlg,IDT_EDIT3,L"");
|
|
SetFocus(GetDlgItem(hdlg,IDT_EDIT2));
|
|
|
|
return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
|
|
}else{
|
|
EncryptedAdminPasswordSet = TRUE;
|
|
|
|
//
|
|
// Set DontChangeAdminPassword to avoid the user from ever trying to
|
|
// reset the password using the dialog. This is needed in the case where the
|
|
// unattend fails, say, in the next page and the user gets here using the back button.
|
|
//
|
|
|
|
DontChangeAdminPassword = TRUE;
|
|
}
|
|
|
|
|
|
}else{
|
|
|
|
|
|
|
|
//
|
|
// They match; allow next page to be activated.
|
|
//
|
|
if (Unattended && pw1[0] == L'*') {
|
|
pw1[0] = L'\0';
|
|
}
|
|
|
|
|
|
// Set administrator password. We need to do some checking here though.
|
|
// There are 3 scenarios that can occur in mini-setup:
|
|
// 1. The OEM doesn't want to have the admin password changed.
|
|
// In this case, he's set OEMAdminPassword = "NoChange". If that's
|
|
// what we find, we don't assign the password. Remember that this
|
|
// system has already been installed, so there's already an admin
|
|
// password.
|
|
// 2. The OEM wants to set the admin password to a specific string.
|
|
// In this case, he's set OEMAdminPassword = <some quoted word>.
|
|
// If this is the case, we've already caught this string in the
|
|
// wizard page.
|
|
// 3. The OEM wants to let the user set the admin password. In this
|
|
// case, there's no OEMAdminpassword in the answer file. If this
|
|
// is the case, we've already caught this and gotten a password
|
|
// from the user in the wizard page.
|
|
//
|
|
// The good news is that the unattend engine has already looked
|
|
// for a password in the unattend file called "NoChange" and has
|
|
// set a global called "DontChangeAdminPassword" to indicate.
|
|
|
|
|
|
|
|
if(!DontChangeAdminPassword) {
|
|
|
|
lstrcpy(AdminPassword,pw1);
|
|
|
|
//
|
|
// The user may have changed the name of the Administrator
|
|
// account. We'll call some special code to retrieve the
|
|
// name on the account. This is really only needed in the
|
|
// case of a sysprep run, but it can't hurt to do it always.
|
|
//
|
|
// In the Win9x case their code in winnt32 generates a random
|
|
// password and passes it to us through the unattend file and
|
|
// so we set it here and do the right thing.
|
|
|
|
// For Minisetup the behavior for now is to silently fail setting
|
|
// the admin password if there was an existing Password on the system.
|
|
// WE only allow setting the admin password from NULL i.e. one time change.
|
|
// In any other case we log the error and move on.
|
|
//
|
|
|
|
|
|
|
|
if(!SetLocalUserPassword(adminName,CurrentAdminPassword,AdminPassword) && !MiniSetup) {
|
|
|
|
SetupDebugPrint( L"SETUP: SetLocalUserPassword failed" );
|
|
// Page becomes active, make page visible.
|
|
SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
|
|
|
|
MessageBoxFromMessage(hdlg,MSG_CHANGING_PW_FAIL,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP, adminName );
|
|
SetDlgItemText(hdlg,IDT_EDIT2,L"");
|
|
SetDlgItemText(hdlg,IDT_EDIT3,L"");
|
|
SetFocus(GetDlgItem(hdlg,IDT_EDIT2));
|
|
|
|
return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
|
|
|
|
}
|
|
//
|
|
// Now store this so that we work fine when the user comes to this page by hitting "Back".
|
|
//
|
|
lstrcpy( CurrentAdminPassword, AdminPassword );
|
|
|
|
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// Skip UI?
|
|
//
|
|
|
|
if (!lParam) {
|
|
return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
|
|
}
|
|
|
|
//
|
|
// Inform user of bogus computer name, and don't allow next page
|
|
// to be activated.
|
|
//
|
|
if (Unattended) {
|
|
UnattendErrorDlg(hdlg, IDD_COMPUTERNAME);
|
|
}
|
|
MessageBoxFromMessage(
|
|
hdlg,
|
|
ComputerName[0] ? MSG_BAD_COMPUTER_NAME1 : MSG_BAD_COMPUTER_NAME2,
|
|
NULL,
|
|
IDS_ERROR,MB_OK|MB_ICONSTOP
|
|
);
|
|
SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
|
|
SendDlgItemMessage(hdlg,IDT_EDIT1,EM_SETSEL,0,-1);
|
|
|
|
return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
|
|
}
|
|
|
|
return ReturnDlgResult (hdlg, VALIDATE_DATA_OK);
|
|
|
|
case WM_NOTIFY:
|
|
|
|
NotifyParams = (NMHDR *)lParam;
|
|
|
|
switch(NotifyParams->code) {
|
|
|
|
case PSN_SETACTIVE:
|
|
TESTHOOK(504);
|
|
|
|
BEGIN_SECTION(L"Computer Name Page");
|
|
SetWizardButtons(hdlg,WizPageComputerName);
|
|
|
|
//
|
|
// Load ComputerName because it may have been set when the user
|
|
// entered the organization name.
|
|
//
|
|
SetDlgItemText(hdlg,IDT_EDIT1,ComputerName);
|
|
|
|
if(Unattended && !UnattendSetActiveDlg(hdlg,IDD_COMPUTERNAME)) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Post ourselves a message we'll get once displayed.
|
|
//
|
|
PostMessage(hdlg,WM_USER,0,0);
|
|
break;
|
|
|
|
case PSN_WIZBACK:
|
|
//
|
|
// Save ComputerName because we're going to load it into the dialog
|
|
// again when we come back.
|
|
//
|
|
GetDlgItemText(hdlg,IDT_EDIT1,ComputerName,DNS_MAX_LABEL_LENGTH+1);
|
|
break;
|
|
|
|
case PSN_WIZNEXT:
|
|
case PSN_WIZFINISH:
|
|
UnattendAdvanceIfValid (hdlg); // see WMX_VALIDATE
|
|
break;
|
|
|
|
case PSN_KILLACTIVE:
|
|
WizardKillHelp(hdlg);
|
|
SetWindowLongPtr(hdlg, DWLP_MSGRESULT, FALSE);
|
|
END_SECTION(L"Computer Name Page");
|
|
break;
|
|
|
|
case PSN_HELP:
|
|
WizardBringUpHelp(hdlg,WizPageComputerName);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case WM_USER:
|
|
// Page becomes active, make page visible.
|
|
SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
|
|
//
|
|
// Select the computer name string and set focus to it.
|
|
//
|
|
SendDlgItemMessage(hdlg,IDT_EDIT1,EM_SETSEL,0,-1);
|
|
SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
#ifdef DOLOCALUSER
|
|
BOOL
|
|
CheckUserAccountData(
|
|
IN HWND hdlg,
|
|
OUT BOOL ValidateOnly
|
|
)
|
|
{
|
|
WCHAR userName[MAX_USERNAME+1];
|
|
WCHAR pw1[MAX_PASSWORD+1];
|
|
WCHAR pw2[MAX_PASSWORD+1];
|
|
WCHAR adminName[MAX_USERNAME+1];
|
|
WCHAR guestName[MAX_USERNAME+1];
|
|
UINT MessageId;
|
|
|
|
FocusId = 0;
|
|
|
|
//
|
|
// Load names of built-in accounts.
|
|
//
|
|
LoadString(MyModuleHandle,IDS_ADMINISTRATOR,adminName,MAX_USERNAME+1);
|
|
LoadString(MyModuleHandle,IDS_GUEST,guestName,MAX_USERNAME+1);
|
|
|
|
//
|
|
// Fetch data user typed in for username and password.
|
|
//
|
|
GetDlgItemText(hdlg,IDT_EDIT1,userName,MAX_USERNAME+1);
|
|
GetDlgItemText(hdlg,IDT_EDIT2,pw1,MAX_PASSWORD+1);
|
|
GetDlgItemText(hdlg,IDT_EDIT3,pw2,MAX_PASSWORD+1);
|
|
|
|
if(lstrcmpi(userName,adminName) && lstrcmpi(userName,guestName)) {
|
|
if(userName[0]) {
|
|
if(IsNetNameValid(userName,FALSE)) {
|
|
if(lstrcmp(pw1,pw2)) {
|
|
//
|
|
// Passwords don't match.
|
|
//
|
|
MessageId = MSG_PW_MISMATCH;
|
|
SetDlgItemText(hdlg,IDT_EDIT2,L"");
|
|
SetDlgItemText(hdlg,IDT_EDIT3,L"");
|
|
SetFocus(GetDlgItem(hdlg,IDT_EDIT2));
|
|
} else {
|
|
//
|
|
// Name is non-empty, is not a built-in, is valid,
|
|
// and the passwords match.
|
|
//
|
|
MessageId = 0;
|
|
}
|
|
} else {
|
|
//
|
|
// Name is not valid.
|
|
//
|
|
MessageId = MSG_BAD_USER_NAME1;
|
|
SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
|
|
}
|
|
} else {
|
|
//
|
|
// Don't allow empty name.
|
|
//
|
|
MessageId = MSG_BAD_USER_NAME2;
|
|
SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
|
|
}
|
|
} else {
|
|
//
|
|
// User entered name of a built-in account.
|
|
//
|
|
MessageId = MSG_BAD_USER_NAME3;
|
|
SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
|
|
}
|
|
|
|
if(MessageId && !ValidateOnly) {
|
|
MessageBoxFromMessage(hdlg,MessageId,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
|
|
}
|
|
|
|
return(MessageId == 0);
|
|
}
|
|
|
|
BOOL
|
|
CALLBACK
|
|
UserAccountDlgProc(
|
|
IN HWND hdlg,
|
|
IN UINT msg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
NMHDR *NotifyParams;
|
|
|
|
switch(msg) {
|
|
|
|
case WM_INITDIALOG:
|
|
//
|
|
// Limit text to maximum length of a user account name,
|
|
// and limit password text to max langth of a password.
|
|
// Also set initial text.
|
|
//
|
|
SendDlgItemMessage(hdlg,IDT_EDIT1,EM_LIMITTEXT,MAX_USERNAME,0);
|
|
SendDlgItemMessage(hdlg,IDT_EDIT2,EM_LIMITTEXT,MAX_PASSWORD,0);
|
|
SendDlgItemMessage(hdlg,IDT_EDIT3,EM_LIMITTEXT,MAX_PASSWORD,0);
|
|
SetDlgItemText(hdlg,IDT_EDIT1,UserName);
|
|
SetDlgItemText(hdlg,IDT_EDIT2,UserPassword);
|
|
SetDlgItemText(hdlg,IDT_EDIT3,UserPassword);
|
|
break;
|
|
|
|
case WM_SIMULATENEXT:
|
|
// Simulate the next button somehow
|
|
PropSheet_PressButton( GetParent(hdlg), PSBTN_NEXT);
|
|
break;
|
|
|
|
case WMX_VALIDATE:
|
|
//
|
|
// lParam == 0 for no UI, or 1 for UI
|
|
// Return 1 for success, -1 for error.
|
|
//
|
|
|
|
//
|
|
// Check name.
|
|
//
|
|
if(CheckUserAccountData(hdlg, lParam == 0)) {
|
|
//
|
|
// Data is valid. Move on to next page.
|
|
//
|
|
GetDlgItemText(hdlg,IDT_EDIT1,UserName,MAX_USERNAME+1);
|
|
GetDlgItemText(hdlg,IDT_EDIT2,UserPassword,MAX_PASSWORD+1);
|
|
CreateUserAccount = TRUE;
|
|
} else if (Unattended) {
|
|
//
|
|
// Data is invalid but we're unattended, so just don't create
|
|
// the account.
|
|
//
|
|
CreateUserAccount = FALSE;
|
|
GetDlgItemText(hdlg,IDT_EDIT1,UserName,MAX_USERNAME+1);
|
|
SetDlgItemText(hdlg,IDT_EDIT2,L"");
|
|
SetDlgItemText(hdlg,IDT_EDIT3,L"");
|
|
UserPassword[0] = 0;
|
|
|
|
return ReturnDlgResult (hdlg, VALIDATE_DATA_OK);
|
|
}
|
|
|
|
//
|
|
// Don't allow next page to be activated.
|
|
//
|
|
return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
|
|
|
|
case WM_NOTIFY:
|
|
|
|
NotifyParams = (NMHDR *)lParam;
|
|
|
|
switch(NotifyParams->code) {
|
|
|
|
case PSN_SETACTIVE:
|
|
TESTHOOK(505);
|
|
BEGIN_SECTION(L"User Name and Password Page");
|
|
SetWizardButtons(hdlg,WizPageUserAccount);
|
|
|
|
//
|
|
// Load ComputerName because it may have been set when the user
|
|
// entered the user name.
|
|
//
|
|
SetDlgItemText(hdlg,IDT_EDIT1,UserName);
|
|
|
|
//
|
|
// Always activate in ui test mode
|
|
//
|
|
if(!UiTest) {
|
|
//
|
|
// Don't activate if this is a dc server or Win9x upgrade.
|
|
//
|
|
if(ISDC(ProductType) || Win95Upgrade) {
|
|
SetWindowLongPtr(hdlg,DWLP_MSGRESULT,-1);
|
|
break;
|
|
}
|
|
}
|
|
if (Unattended) {
|
|
if (!UnattendSetActiveDlg(hdlg,IDD_USERACCOUNT)) {
|
|
break;
|
|
}
|
|
}
|
|
// Page becomes active, make page visible.
|
|
SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
|
|
|
|
break;
|
|
|
|
case PSN_WIZBACK:
|
|
//
|
|
// Save UserName because we're going to load it into the dialog
|
|
// again when we come back.
|
|
//
|
|
GetDlgItemText(hdlg,IDT_EDIT1,UserName,MAX_USERNAME+1);
|
|
break;
|
|
|
|
case PSN_WIZNEXT:
|
|
case PSN_WIZFINISH:
|
|
UnattendAdvanceIfValid (hdlg); // see WMX_VALIDATE
|
|
break;
|
|
|
|
case PSN_KILLACTIVE:
|
|
WizardKillHelp(hdlg);
|
|
SetWindowLongPtr( hdlg, DWLP_MSGRESULT, FALSE );
|
|
END_SECTION(L"User Name and Password Page");
|
|
break;
|
|
|
|
case PSN_HELP:
|
|
WizardBringUpHelp(hdlg,WizPageUserAccount);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
#endif //def DOLOCALUSER
|
|
|
|
|