378 lines
11 KiB
C++
378 lines
11 KiB
C++
|
#include "stdafx.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
//
|
||
|
// registry information
|
||
|
//
|
||
|
|
||
|
const WCHAR c_szWinLogon[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon";
|
||
|
|
||
|
const WCHAR c_szAutoLogon[] = L"AutoAdminLogon";
|
||
|
const WCHAR c_szDisableCAD[] = L"DisableCAD";
|
||
|
|
||
|
const WCHAR c_szDefUserName[] = L"DefaultUserName";
|
||
|
const WCHAR c_szDefDomain[] = L"DefaultDomainName";
|
||
|
const WCHAR c_szDefPassword[] = L"DefaultPassword";
|
||
|
|
||
|
const WCHAR c_szDefaultPwdKey[] = L"DefaultPassword";
|
||
|
|
||
|
//
|
||
|
// registry helpers
|
||
|
//
|
||
|
|
||
|
BOOL _RegSetSZ(HKEY hk, LPCWSTR pszValueName, LPCWSTR pszValue)
|
||
|
{
|
||
|
DWORD dwSize = lstrlen(pszValue)*SIZEOF(WCHAR);
|
||
|
return ERROR_SUCCESS == RegSetValueEx(hk, pszValueName, 0x0, REG_SZ, (BYTE *)pszValue, dwSize);
|
||
|
}
|
||
|
|
||
|
BOOL _RegSetDWORD(HKEY hk, LPCWSTR pszValueName, DWORD dwValue)
|
||
|
{
|
||
|
DWORD dwSize = SIZEOF(dwValue);
|
||
|
return ERROR_SUCCESS == RegSetValueEx(hk, pszValueName, 0x0, REG_DWORD, (BYTE *)&dwValue, dwSize);
|
||
|
}
|
||
|
|
||
|
BOOL _RegDelValue(HKEY hk, LPCWSTR pszValueName)
|
||
|
{
|
||
|
return ERROR_SUCCESS == RegDeleteValue(hk, pszValueName);
|
||
|
}
|
||
|
|
||
|
|
||
|
INT_PTR CALLBACK _CredDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
|
||
|
LPCREDINFO pci = (LPCREDINFO)GetWindowLongPtr(hwnd, DWLP_USER);
|
||
|
|
||
|
switch ( uMsg )
|
||
|
{
|
||
|
case WM_INITDIALOG:
|
||
|
{
|
||
|
pci = (LPCREDINFO)lParam;
|
||
|
SetWindowLongPtr(hwnd, DWLP_USER, lParam);
|
||
|
|
||
|
SetDlgItemText(hwnd, IDC_USER, pci->pszUser);
|
||
|
Edit_LimitText(GetDlgItem(hwnd, IDC_USER), pci->cchUser - 1);
|
||
|
|
||
|
SetDlgItemText(hwnd, IDC_DOMAIN, pci->pszDomain);
|
||
|
Edit_LimitText(GetDlgItem(hwnd, IDC_DOMAIN), pci->cchDomain - 1);
|
||
|
|
||
|
SetDlgItemText(hwnd, IDC_PASSWORD, pci->pszPassword);
|
||
|
Edit_LimitText(GetDlgItem(hwnd, IDC_PASSWORD), pci->cchPassword - 1);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
case WM_COMMAND:
|
||
|
{
|
||
|
switch ( LOWORD(wParam) )
|
||
|
{
|
||
|
case IDOK:
|
||
|
{
|
||
|
FetchText(hwnd, IDC_DOMAIN, pci->pszDomain, pci->cchDomain);
|
||
|
FetchText(hwnd, IDC_USER, pci->pszUser, pci->cchUser);
|
||
|
|
||
|
if (StrChr(pci->pszUser, TEXT('@')))
|
||
|
{
|
||
|
*(pci->pszDomain) = 0;
|
||
|
}
|
||
|
|
||
|
GetDlgItemText(hwnd, IDC_PASSWORD, pci->pszPassword, pci->cchPassword);
|
||
|
return EndDialog(hwnd, IDOK);
|
||
|
}
|
||
|
|
||
|
case IDCANCEL:
|
||
|
return EndDialog(hwnd, IDCANCEL);
|
||
|
|
||
|
case IDC_USER:
|
||
|
{
|
||
|
if ( HIWORD(wParam) == EN_CHANGE )
|
||
|
{
|
||
|
EnableWindow(GetDlgItem(hwnd, IDOK), FetchTextLength(hwnd, IDC_USER) > 0);
|
||
|
|
||
|
EnableDomainForUPN(GetDlgItem(hwnd, IDC_USER), GetDlgItem(hwnd, IDC_DOMAIN));
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// attempt to join a domain/workgroup using the specified names and OU.
|
||
|
//
|
||
|
|
||
|
HRESULT _AttemptJoin(HWND hwnd, DWORD dwFlags, LPCWSTR pszDomain, LPCWSTR pszUser, LPCWSTR pszUserDomain, LPCWSTR pszPassword)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
#ifndef DONT_JOIN
|
||
|
TCHAR szDomainUser[MAX_DOMAINUSER + 1];
|
||
|
if ( pszUser )
|
||
|
MakeDomainUserString(pszUserDomain, pszUser, szDomainUser, ARRAYSIZE(szDomainUser));
|
||
|
|
||
|
NET_API_STATUS nas = NetJoinDomain(NULL, pszDomain, NULL, szDomainUser, pszPassword, dwFlags);
|
||
|
if ( (nas == ERROR_ACCESS_DENIED) )
|
||
|
{
|
||
|
// perhaps an account exists, but we can't delete it so try and remove
|
||
|
// the account create flag
|
||
|
|
||
|
if ( dwFlags & NETSETUP_ACCT_CREATE )
|
||
|
{
|
||
|
dwFlags &= ~NETSETUP_ACCT_CREATE;
|
||
|
nas = NetJoinDomain(NULL, pszDomain, NULL, szDomainUser, *pszPassword ? pszPassword : NULL, dwFlags);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( (nas != NERR_Success) && (nas != NERR_SetupAlreadyJoined) )
|
||
|
{
|
||
|
TCHAR szMessage[512];
|
||
|
|
||
|
if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, (DWORD) nas, 0, szMessage, ARRAYSIZE(szMessage), NULL))
|
||
|
LoadString(g_hinst, IDS_ERR_UNEXPECTED, szMessage, ARRAYSIZE(szMessage));
|
||
|
|
||
|
::DisplayFormatMessage(hwnd, IDS_ERR_CAPTION, IDS_NAW_JOIN_GENERICERROR, MB_OK|MB_ICONERROR, szMessage);
|
||
|
hr = HRESULT_FROM_WIN32(nas);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
void _ShowDcNotFoundErrorDialog(HWND hwnd, LPCWSTR pszDomain, LPCWSTR pszTitle)
|
||
|
{
|
||
|
typedef void (*pfnShowDcNotFoundErrorDialog)(HWND, PCWSTR, PCWSTR);
|
||
|
static HMODULE hNetID = NULL;
|
||
|
static pfnShowDcNotFoundErrorDialog ShowDcNotFoundErrorDialog = NULL;
|
||
|
|
||
|
if (!hNetID)
|
||
|
{
|
||
|
hNetID = LoadLibrary(L"netid.dll");
|
||
|
}
|
||
|
|
||
|
if (hNetID)
|
||
|
{
|
||
|
ShowDcNotFoundErrorDialog = (pfnShowDcNotFoundErrorDialog) GetProcAddress(hNetID, "ShowDcNotFoundErrorDialog");
|
||
|
if (ShowDcNotFoundErrorDialog)
|
||
|
{
|
||
|
ShowDcNotFoundErrorDialog(hwnd, pszDomain, pszTitle);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Handle moving from to a workgroup or domain. To do this we are passed
|
||
|
// a structure containing all the information we need.
|
||
|
//
|
||
|
HRESULT JoinDomain(HWND hwnd, BOOL fDomain, LPCWSTR pszDomain, CREDINFO* pci, BOOL *pfReboot)
|
||
|
{
|
||
|
HRESULT hres = E_FAIL;
|
||
|
DWORD dwFlags = 0x0;
|
||
|
LPWSTR pszCurrentDomain = NULL;
|
||
|
NET_API_STATUS nas;
|
||
|
BOOL fPassedCredentials = (pci && pci->pszUser && pci->pszUser[0] && pci->pszPassword);
|
||
|
CWaitCursor cur;
|
||
|
|
||
|
//
|
||
|
// lets validate the domain name before we go and use it, therefore avoiding
|
||
|
// orphaning the computer too badly
|
||
|
//
|
||
|
|
||
|
nas = NetValidateName(NULL, pszDomain, NULL, NULL, fDomain ? NetSetupDomain:NetSetupWorkgroup);
|
||
|
|
||
|
if (fDomain && (ERROR_NO_SUCH_DOMAIN == nas))
|
||
|
{
|
||
|
WCHAR szTitle[256];
|
||
|
LoadString(g_hinst, IDS_NETWIZCAPTION, szTitle, ARRAYSIZE(szTitle));
|
||
|
|
||
|
_ShowDcNotFoundErrorDialog(hwnd, pszDomain, szTitle);
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
if ( NERR_Success != nas )
|
||
|
{
|
||
|
ShellMessageBox(g_hinst, hwnd,
|
||
|
fDomain ? MAKEINTRESOURCE(IDS_ERR_BADDOMAIN) : MAKEINTRESOURCE(IDS_ERR_BADWORKGROUP),
|
||
|
MAKEINTRESOURCE(IDS_NETWIZCAPTION),
|
||
|
MB_OK|MB_ICONWARNING,
|
||
|
pszDomain);
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// now attempt to join the domain, prompt for credentails if the ones
|
||
|
// specified are not good enough
|
||
|
//
|
||
|
|
||
|
if ( fDomain )
|
||
|
{
|
||
|
dwFlags |= NETSETUP_JOIN_DOMAIN|NETSETUP_ACCT_CREATE|NETSETUP_DOMAIN_JOIN_IF_JOINED;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
nas = NetUnjoinDomain(NULL, NULL, NULL, NETSETUP_ACCT_DELETE);
|
||
|
if ( (nas != NERR_Success) && (nas != NERR_SetupNotJoined) )
|
||
|
{
|
||
|
nas = NetUnjoinDomain(NULL, NULL, NULL, 0x0);
|
||
|
}
|
||
|
|
||
|
if ( (nas != NERR_Success) && (nas != NERR_SetupNotJoined) )
|
||
|
{
|
||
|
hres = E_UNEXPECTED;
|
||
|
goto exit_gracefully;
|
||
|
}
|
||
|
|
||
|
*pfReboot = TRUE; // we changed the domain
|
||
|
}
|
||
|
|
||
|
if ( !fDomain || fPassedCredentials)
|
||
|
{
|
||
|
if (fPassedCredentials)
|
||
|
{
|
||
|
hres = _AttemptJoin(hwnd, dwFlags, pszDomain, pci->pszUser, pci->pszDomain, pci->pszPassword);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hres = _AttemptJoin(hwnd, dwFlags, pszDomain, NULL, NULL, NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( fDomain && ((FAILED(hres) || (!fPassedCredentials))) )
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
if ( IDCANCEL == DialogBoxParam(g_hinst, MAKEINTRESOURCE(IDD_PSW_JOINCREDENTIALS),
|
||
|
hwnd, _CredDlgProc, (LPARAM)pci) )
|
||
|
{
|
||
|
hres = E_FAIL;
|
||
|
goto exit_gracefully;
|
||
|
}
|
||
|
|
||
|
// The dialog box changed the cursor from a wait cursor to an arrow cursor, so the cursor
|
||
|
// needs to be changed back.. This call could be moved to _AttemptJoin (along with a call to
|
||
|
// reset the cursor). This call is made synchronously from the message loop for this hwnd
|
||
|
cur.WaitCursor();
|
||
|
hres = _AttemptJoin(hwnd, dwFlags, pszDomain, pci->pszUser, pci->pszDomain, pci->pszPassword);
|
||
|
|
||
|
}
|
||
|
while ( FAILED(hres) );
|
||
|
}
|
||
|
|
||
|
exit_gracefully:
|
||
|
|
||
|
if ( SUCCEEDED(hres) )
|
||
|
{
|
||
|
ClearAutoLogon();
|
||
|
*pfReboot = TRUE; // we changed the domain
|
||
|
}
|
||
|
|
||
|
NetApiBufferFree(pszCurrentDomain);
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// set and clear the auto admin logon state.
|
||
|
//
|
||
|
// we set the default user and default domain to the specified strings, we then blow away
|
||
|
// the clear text password stored in the registry to replace it with a password stored
|
||
|
// in the LSA secret space.
|
||
|
//
|
||
|
|
||
|
NTSTATUS _SetDefaultPassword(LPCWSTR PasswordBuffer)
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
|
LSA_HANDLE LsaHandle = NULL;
|
||
|
UNICODE_STRING SecretName;
|
||
|
UNICODE_STRING SecretValue;
|
||
|
|
||
|
InitializeObjectAttributes(&ObjectAttributes, NULL, 0L, (HANDLE)NULL, NULL);
|
||
|
|
||
|
Status = LsaOpenPolicy(NULL, &ObjectAttributes, POLICY_CREATE_SECRET, &LsaHandle);
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
return Status;
|
||
|
|
||
|
RtlInitUnicodeString(&SecretName, c_szDefaultPwdKey);
|
||
|
RtlInitUnicodeString(&SecretValue, PasswordBuffer);
|
||
|
|
||
|
Status = LsaStorePrivateData(LsaHandle, &SecretName, &SecretValue);
|
||
|
LsaClose(LsaHandle);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Set and clear auto logon for a particular
|
||
|
//
|
||
|
|
||
|
void SetAutoLogon(LPCWSTR pszUserName, LPCWSTR pszPassword)
|
||
|
{
|
||
|
#ifndef DONT_JOIN
|
||
|
WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1];
|
||
|
DWORD dwComputerName = ARRAYSIZE(szComputerName);
|
||
|
HKEY hk;
|
||
|
|
||
|
GetComputerName(szComputerName, &dwComputerName);
|
||
|
SetDefAccount(pszUserName, szComputerName); // also clears auto logon
|
||
|
|
||
|
if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szWinLogon, 0x0, KEY_WRITE, &hk) )
|
||
|
{
|
||
|
_RegSetSZ(hk, c_szAutoLogon, L"1"); // auto admin logon
|
||
|
_RegDelValue(hk, c_szDefPassword); // use the LSA secret for the password
|
||
|
RegCloseKey (hk);
|
||
|
}
|
||
|
|
||
|
_SetDefaultPassword(pszPassword);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// clear the auto admin logon
|
||
|
//
|
||
|
|
||
|
STDAPI ClearAutoLogon(VOID)
|
||
|
{
|
||
|
#ifndef DONT_JOIN
|
||
|
HKEY hk;
|
||
|
if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szWinLogon, 0x0, KEY_WRITE, &hk) )
|
||
|
{
|
||
|
_RegSetSZ(hk, c_szAutoLogon, L"0"); // no auto admin logon
|
||
|
_RegDelValue(hk, c_szDefPassword);
|
||
|
|
||
|
RegCloseKey(hk);
|
||
|
}
|
||
|
|
||
|
_SetDefaultPassword(L""); // clear the LSA secret
|
||
|
#endif
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// set the default account
|
||
|
//
|
||
|
|
||
|
void SetDefAccount(LPCWSTR pszUser, LPCWSTR pszDomain)
|
||
|
{
|
||
|
#ifndef DONT_JOIN
|
||
|
ClearAutoLogon();
|
||
|
|
||
|
HKEY hk;
|
||
|
if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szWinLogon, 0x0, KEY_WRITE, &hk) )
|
||
|
{
|
||
|
_RegSetSZ(hk, c_szDefUserName, pszUser);
|
||
|
_RegSetSZ(hk, c_szDefDomain, pszDomain);
|
||
|
RegCloseKey(hk);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
}
|