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.
5407 lines
168 KiB
5407 lines
168 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1993.
|
|
//
|
|
// File: mslogon.c
|
|
//
|
|
// Contents: Microsoft Logon GUI DLL
|
|
//
|
|
// History: 7-14-94 RichardW Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "msgina.h"
|
|
#include "shtdnp.h"
|
|
#include "authmon.h"
|
|
#include <stdio.h>
|
|
#include <wchar.h>
|
|
#include <wincrypt.h>
|
|
#include <sclogon.h>
|
|
#include "shlwapi.h"
|
|
#include "shlwapip.h"
|
|
|
|
#include "winsta.h"
|
|
#include "wtsapi32.h"
|
|
#include <keymgr.h>
|
|
#include <passrec.h>
|
|
|
|
typedef void (WINAPI *RUNDLLPROC)(HWND hWndStub,HINSTANCE hInstance,LPWSTR szCommandLine,int nShow);
|
|
|
|
typedef struct _MSGINA_LOGON_PARAMETERS {
|
|
PGLOBALS pGlobals;
|
|
DWORD SasType;
|
|
} MSGINA_LOGON_PARAMETERS, * PMSGINA_LOGON_PARAMETERS ;
|
|
|
|
#define WINSTATIONS_DISABLED TEXT("WinStationsDisabled")
|
|
|
|
//
|
|
// Number of seconds we will display the legal notices
|
|
// before timing out.
|
|
//
|
|
|
|
#define LEGAL_NOTICE_TIMEOUT 120
|
|
|
|
#define LOGON_SLEEP_PERIOD 750
|
|
|
|
#define WM_LOGONPROMPT WM_USER + 257
|
|
#define WM_LOGONCOMPLETE WM_USER + 258
|
|
|
|
#define WM_HANDLEFAILEDLOGON WM_USER + 259
|
|
#define WM_DCACHE_COMPLETE WM_USER + 260
|
|
|
|
#define MAX_CAPTION_LENGTH 256
|
|
|
|
// Maximum size of a UPN name we allow at present
|
|
#define MAX_UPN_NAME_SIZE 520
|
|
|
|
typedef struct FAILEDLOGONINFO_t
|
|
{
|
|
PGLOBALS pGlobals;
|
|
NTSTATUS Status;
|
|
NTSTATUS SubStatus;
|
|
TCHAR UserName[UNLEN + DNLEN + 2];
|
|
TCHAR Domain[DNLEN + 1];
|
|
} FAILEDLOGONINFO, *PFAILEDLOGONINFO;
|
|
|
|
|
|
typedef struct _LEGALINFO
|
|
{
|
|
LPTSTR NoticeText;
|
|
LPTSTR CaptionText;
|
|
} LEGALINFO, *PLEGALINFO;
|
|
|
|
|
|
// Also defined in wstrpc.c
|
|
#define INET_CONNECTOR_EVENT_NAME L"Global\\TermSrvInetConnectorEvent"
|
|
|
|
#define TERMSERV_EVENTSOURCE L"TermService"
|
|
|
|
// Also defined in icaevent.mc
|
|
#define EVENT_BAD_TSINTERNET_USER 1007
|
|
|
|
//
|
|
// Globals:
|
|
//
|
|
static WNDPROC OldCBWndProc;
|
|
|
|
HICON hSteadyFlag;
|
|
HICON hWavingFlag;
|
|
HICON hAuditFull;
|
|
|
|
extern HICON hLockedIcon;
|
|
BOOL IsPswBackupAvailable;
|
|
BOOL s_fAttemptedAutoLogon;
|
|
|
|
BOOL g_fHelpAssistantLogon = FALSE;
|
|
BOOL g_FirstTime = TRUE;
|
|
|
|
|
|
//
|
|
// Prototypes:
|
|
//
|
|
|
|
|
|
INT_PTR
|
|
DisplayLegalNotices(
|
|
PGLOBALS pGlobals
|
|
);
|
|
|
|
BOOL
|
|
GetLegalNotices(
|
|
LPTSTR lpSubKey,
|
|
LPTSTR *NoticeText,
|
|
LPTSTR *CaptionText
|
|
);
|
|
|
|
INT_PTR WINAPI
|
|
LogonDlgCBProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
);
|
|
|
|
INT_PTR WINAPI
|
|
LogonDlgUsernameProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
);
|
|
|
|
INT_PTR WINAPI
|
|
LogonDlgProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
);
|
|
|
|
BOOL
|
|
LogonDlgInit(
|
|
HWND hDlg,
|
|
BOOL bAutoLogon,
|
|
DWORD SasType
|
|
);
|
|
|
|
NTSTATUS
|
|
UpnFromCert(
|
|
IN PCCERT_CONTEXT pCert,
|
|
IN OUT DWORD *pcUpn,
|
|
IN OUT LPWSTR pUPN
|
|
);
|
|
|
|
BOOL
|
|
WINAPI
|
|
QuerySwitchConsoleCredentials(
|
|
PGLOBALS pGlobals,
|
|
HANDLE * phUserToken,
|
|
PLUID pLogonId);
|
|
|
|
|
|
// Global structure for a failed logon filled in by the worker thread to be consumed
|
|
// by the ui thread.
|
|
FAILEDLOGONINFO g_failinfo;
|
|
|
|
void PostFailedLogonMessage(HWND hDlg,
|
|
PGLOBALS pGlobals,
|
|
NTSTATUS Status,
|
|
NTSTATUS SubStatus,
|
|
PWCHAR UserName,
|
|
PWCHAR Domain
|
|
);
|
|
|
|
INT_PTR
|
|
HandleFailedLogon(
|
|
HWND hDlg
|
|
);
|
|
|
|
VOID
|
|
ReportBootGood(
|
|
PGLOBALS pGlobals
|
|
);
|
|
|
|
VOID LogonShowOptions(
|
|
PGLOBALS pGlobals,
|
|
HWND hDlg,
|
|
BOOL fShow,
|
|
BOOL fSticky);
|
|
|
|
VOID AttemptLogonSetControls(
|
|
PGLOBALS pGlobals,
|
|
HWND hDlg
|
|
);
|
|
|
|
INT_PTR
|
|
AttemptLogon(
|
|
HWND hDlg
|
|
);
|
|
|
|
DWORD
|
|
AttemptLogonThread(
|
|
PGLOBALS pGlobals
|
|
);
|
|
|
|
BOOL
|
|
GetAndAllocateLogonSid(
|
|
HANDLE hToken,
|
|
PSID *pLogonSid
|
|
);
|
|
|
|
BOOL GetSessionZeroUser(LPTSTR szUser, int nUserMax);
|
|
BOOL FastUserSwitchingEnabled();
|
|
|
|
|
|
//
|
|
// control tables for showing/hiding options
|
|
//
|
|
|
|
static UINT ctrlNoShutdown[] =
|
|
{
|
|
IDOK,
|
|
IDCANCEL,
|
|
};
|
|
|
|
static UINT ctrlNoCancel[] =
|
|
{
|
|
IDOK,
|
|
};
|
|
|
|
static UINT ctrlNoDomain[] =
|
|
{
|
|
IDOK,
|
|
IDCANCEL,
|
|
IDD_LOGON_SHUTDOWN,
|
|
IDD_LOGON_OPTIONS,
|
|
IDD_LOGON_RASBOX,
|
|
IDD_KBLAYOUT_ICON,
|
|
};
|
|
|
|
static UINT ctrlNoRAS[] =
|
|
{
|
|
IDOK,
|
|
IDCANCEL,
|
|
IDD_LOGON_SHUTDOWN,
|
|
IDD_LOGON_OPTIONS,
|
|
IDD_KBLAYOUT_ICON,
|
|
};
|
|
|
|
static UINT ctrlNoOptions[] =
|
|
{
|
|
IDOK,
|
|
IDCANCEL,
|
|
IDD_LOGON_SHUTDOWN,
|
|
IDD_KBLAYOUT_ICON,
|
|
};
|
|
|
|
static UINT ctrlNoLegalBanner[] =
|
|
{
|
|
IDD_LOGON_NAME_LABEL,
|
|
IDD_LOGON_NAME,
|
|
IDD_LOGON_PASSWORD_LABEL,
|
|
IDD_LOGON_PASSWORD,
|
|
IDD_LOGON_DOMAIN_LABEL,
|
|
IDD_LOGON_DOMAIN,
|
|
IDD_LOGON_RASBOX,
|
|
IDD_KBLAYOUT_ICON,
|
|
IDOK,
|
|
IDCANCEL,
|
|
IDD_LOGON_SHUTDOWN,
|
|
IDD_LOGON_OPTIONS,
|
|
};
|
|
|
|
static UINT ctrlNoUserName[] =
|
|
{
|
|
IDD_LOGON_PASSWORD_LABEL,
|
|
IDD_LOGON_PASSWORD,
|
|
IDD_LOGON_DOMAIN_LABEL,
|
|
IDD_LOGON_DOMAIN,
|
|
IDD_LOGON_RASBOX,
|
|
IDD_KBLAYOUT_ICON,
|
|
IDOK,
|
|
IDCANCEL,
|
|
IDD_LOGON_SHUTDOWN,
|
|
IDD_LOGON_OPTIONS,
|
|
};
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
// ::DisableEditSubClassProc
|
|
//
|
|
// Arguments: hwnd = See the platform SDK under WindowProc.
|
|
// uMsg = See the platform SDK under WindowProc.
|
|
// wParam = See the platform SDK under WindowProc.
|
|
// lParam = See the platform SDK under WindowProc.
|
|
// uiID = ID assigned at subclass time.
|
|
// dwRefData = reference data assigned at subclass time.
|
|
//
|
|
// Returns: LRESULT
|
|
//
|
|
// Purpose: comctl32 subclass callback function. This allows us to not
|
|
// process WM_CUT/WM_COPY/WM_PASTE/WM_CLEAR/WM_UNDO and any
|
|
// other messages to be discarded.
|
|
//
|
|
// History: 2001-02-18 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
LRESULT CALLBACK DisableEditSubClassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uiID, DWORD_PTR dwRefData)
|
|
|
|
{
|
|
LRESULT lResult;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_CUT:
|
|
case WM_COPY:
|
|
case WM_PASTE:
|
|
case WM_CLEAR:
|
|
case WM_UNDO:
|
|
case WM_CONTEXTMENU:
|
|
lResult = FALSE;
|
|
break;
|
|
default:
|
|
lResult = DefSubclassProc(hwnd, uMsg, wParam, lParam);
|
|
break;
|
|
}
|
|
return(lResult);
|
|
}
|
|
|
|
|
|
INT_PTR WINAPI
|
|
LegalDlgProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
PLEGALINFO pLegalInfo;
|
|
|
|
pLegalInfo = (PLEGALINFO) lParam;
|
|
|
|
SetWindowText (hDlg, pLegalInfo->CaptionText);
|
|
SetWindowText (GetDlgItem(hDlg, IDD_LEGALTEXT), pLegalInfo->NoticeText);
|
|
|
|
CentreWindow(hDlg);
|
|
|
|
// Ensure the window is topmost so it's not obscured by the welcome screen.
|
|
SetWindowPos(hDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
{
|
|
if (LOWORD(wParam) == IDOK)
|
|
{
|
|
EndDialog(hDlg, IDOK);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: DisplayLegalNotices
|
|
*
|
|
* PURPOSE: Puts up a dialog box containing legal notices, if any.
|
|
*
|
|
* RETURNS: MSGINA_DLG_SUCCESS - the dialog was shown and dismissed successfully.
|
|
* MSGINA_DLG_FAILURE - the dialog could not be shown
|
|
* DLG_INTERRUPTED() - a set defined in winlogon.h
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* Robertre 6-30-93 Created
|
|
*
|
|
\***************************************************************************/
|
|
|
|
INT_PTR
|
|
DisplayLegalNotices(
|
|
PGLOBALS pGlobals
|
|
)
|
|
{
|
|
INT_PTR Result = MSGINA_DLG_SUCCESS;
|
|
LPTSTR NoticeText;
|
|
LPTSTR CaptionText;
|
|
LEGALINFO LegalInfo;
|
|
|
|
if (GetLegalNotices( WINLOGON_POLICY_KEY, &NoticeText, &CaptionText ))
|
|
{
|
|
|
|
LegalInfo.NoticeText = NoticeText;
|
|
LegalInfo.CaptionText = CaptionText;
|
|
|
|
_Shell_LogonStatus_Hide();
|
|
|
|
pWlxFuncs->WlxSetTimeout(pGlobals->hGlobalWlx, LEGAL_NOTICE_TIMEOUT);
|
|
|
|
Result = pWlxFuncs->WlxDialogBoxParam( pGlobals->hGlobalWlx,
|
|
hDllInstance,
|
|
(LPTSTR) IDD_LEGALMSG,
|
|
NULL,
|
|
LegalDlgProc,
|
|
(LPARAM) &LegalInfo );
|
|
|
|
_Shell_LogonStatus_Show();
|
|
|
|
Free( NoticeText );
|
|
Free( CaptionText );
|
|
}
|
|
else if (GetLegalNotices( WINLOGON_KEY, &NoticeText, &CaptionText ))
|
|
{
|
|
|
|
LegalInfo.NoticeText = NoticeText;
|
|
LegalInfo.CaptionText = CaptionText;
|
|
|
|
_Shell_LogonStatus_Hide();
|
|
|
|
pWlxFuncs->WlxSetTimeout(pGlobals->hGlobalWlx, LEGAL_NOTICE_TIMEOUT);
|
|
|
|
Result = pWlxFuncs->WlxDialogBoxParam( pGlobals->hGlobalWlx,
|
|
hDllInstance,
|
|
(LPTSTR) IDD_LEGALMSG,
|
|
NULL,
|
|
LegalDlgProc,
|
|
(LPARAM) &LegalInfo );
|
|
|
|
_Shell_LogonStatus_Show();
|
|
|
|
Free( NoticeText );
|
|
Free( CaptionText );
|
|
}
|
|
|
|
return( Result );
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: GetLegalNotices
|
|
*
|
|
* PURPOSE: Get legal notice information out of the registry.
|
|
*
|
|
* RETURNS: TRUE - Output parameters contain valid data
|
|
* FALSE - No data returned.
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* Robertre 6-30-93 Created
|
|
*
|
|
\***************************************************************************/
|
|
BOOL
|
|
GetLegalNotices(
|
|
LPTSTR lpSubKey,
|
|
LPTSTR *NoticeText,
|
|
LPTSTR *CaptionText
|
|
)
|
|
{
|
|
LPTSTR lpCaption, lpText;
|
|
HKEY hKey;
|
|
DWORD dwSize, dwType, dwMaxSize = 0;
|
|
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpSubKey,
|
|
0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
|
|
RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL,
|
|
NULL, NULL, NULL, NULL, &dwMaxSize,
|
|
NULL, NULL);
|
|
|
|
lpCaption = Alloc (dwMaxSize);
|
|
|
|
if (!lpCaption) {
|
|
RegCloseKey(hKey);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
lpText = Alloc (dwMaxSize);
|
|
|
|
if (!lpText) {
|
|
Free(lpCaption);
|
|
RegCloseKey(hKey);
|
|
return FALSE;
|
|
}
|
|
|
|
dwSize = dwMaxSize;
|
|
if ((ERROR_SUCCESS != RegQueryValueEx(hKey, LEGAL_NOTICE_CAPTION_KEY,
|
|
0, &dwType, (LPBYTE)lpCaption, &dwSize)) ||
|
|
(dwType != REG_SZ))
|
|
{
|
|
lpCaption[0] = 0;
|
|
}
|
|
|
|
dwSize = dwMaxSize;
|
|
if ((ERROR_SUCCESS != RegQueryValueEx(hKey, LEGAL_NOTICE_TEXT_KEY,
|
|
0, &dwType, (LPBYTE)lpText, &dwSize)) ||
|
|
(dwType != REG_SZ))
|
|
{
|
|
lpText[0] = 0;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
|
|
if (*lpCaption && *lpText) {
|
|
*CaptionText = lpCaption;
|
|
*NoticeText = lpText;
|
|
return TRUE;
|
|
}
|
|
|
|
Free(lpCaption);
|
|
Free(lpText);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: Logon
|
|
*
|
|
* PURPOSE: Display the logon UI depending on the SAS type.
|
|
*
|
|
* RETURNS: -
|
|
*
|
|
* NOTES: If the logon is successful, the global structure is filled in
|
|
* with the logon information.
|
|
*
|
|
* HISTORY:
|
|
* 12-09-91 daviddv Comments.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
INT_PTR
|
|
Logon(
|
|
PGLOBALS pGlobals,
|
|
DWORD SasType
|
|
)
|
|
{
|
|
INT_PTR Result;
|
|
MSGINA_LOGON_PARAMETERS Parm ;
|
|
|
|
if ( SasType == WLX_SAS_TYPE_SC_REMOVE )
|
|
{
|
|
return WLX_SAS_ACTION_NONE ;
|
|
}
|
|
|
|
if( !g_Console )
|
|
{
|
|
//
|
|
// Check if current session is HelpAssistant Session, HelpAssisant
|
|
// session can not be console session.
|
|
//
|
|
g_fHelpAssistantLogon = WinStationIsHelpAssistantSession(
|
|
SERVERNAME_CURRENT,
|
|
LOGONID_CURRENT
|
|
);
|
|
}
|
|
|
|
if ( SasType == WLX_SAS_TYPE_SC_INSERT )
|
|
{
|
|
PWLX_SC_NOTIFICATION_INFO ScInfo = NULL ;
|
|
|
|
pWlxFuncs->WlxGetOption( pGlobals->hGlobalWlx,
|
|
WLX_OPTION_SMART_CARD_INFO,
|
|
(ULONG_PTR *) &ScInfo );
|
|
|
|
//
|
|
// Validate the SC info against some common user
|
|
// errors before the PIN dialog appears
|
|
//
|
|
|
|
if ( ScInfo )
|
|
{
|
|
if ( ( ScInfo->pszReader ) &&
|
|
( ScInfo->pszCard == NULL ) )
|
|
{
|
|
//
|
|
// The card could not be read. Might not be
|
|
// inserted correctly.
|
|
//
|
|
|
|
LocalFree(ScInfo);
|
|
|
|
TimeoutMessageBox( NULL, pGlobals, IDS_CARD_NOT_RECOGNIZED,
|
|
IDS_LOGON_MESSAGE,
|
|
MB_OK | MB_ICONEXCLAMATION,
|
|
LOGON_TIMEOUT );
|
|
|
|
return WLX_SAS_ACTION_NONE;
|
|
}
|
|
|
|
if ( ( ScInfo->pszReader ) &&
|
|
( ScInfo->pszCryptoProvider == NULL ) )
|
|
{
|
|
//
|
|
// Got a card, but the CSP for it could not be
|
|
// found.
|
|
//
|
|
|
|
LocalFree(ScInfo);
|
|
|
|
TimeoutMessageBox( NULL, pGlobals, IDS_CARD_CSP_NOT_RECOGNIZED,
|
|
IDS_LOGON_MESSAGE,
|
|
MB_OK | MB_ICONEXCLAMATION,
|
|
LOGON_TIMEOUT );
|
|
|
|
return WLX_SAS_ACTION_NONE;
|
|
}
|
|
|
|
LocalFree(ScInfo);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Asynchronously update domain cache if necessary.
|
|
// We won't ask to wait so this routine will do no UI.
|
|
// i.e. we can ignore the result.
|
|
//
|
|
// Result = UpdateDomainCache(pGlobals, NULL, FALSE);
|
|
// ASSERT(!DLG_INTERRUPTED(Result));
|
|
|
|
if( !g_fHelpAssistantLogon ) {
|
|
//
|
|
// See if there are legal notices in the registry.
|
|
// If so, put them up in a message box
|
|
//
|
|
Result = DisplayLegalNotices( pGlobals );
|
|
if ( Result != MSGINA_DLG_SUCCESS ) {
|
|
return(WLX_SAS_ACTION_NONE);
|
|
}
|
|
|
|
//
|
|
// Get the latest audit log status and store in our globals
|
|
// If the audit log is full we show a different logon dialog.
|
|
//
|
|
GetAuditLogStatus(pGlobals);
|
|
} else {
|
|
|
|
//
|
|
// fake it so audit log is not full, setting is from GetAuditLogStatus()
|
|
//
|
|
pGlobals->AuditLogFull = FALSE;
|
|
pGlobals->AuditLogNearFull = FALSE;
|
|
}
|
|
|
|
Parm.pGlobals = pGlobals ;
|
|
Parm.SasType = SasType ;
|
|
|
|
//
|
|
// Take their username and password and try to log them on
|
|
//
|
|
pWlxFuncs->WlxSetTimeout(pGlobals->hGlobalWlx,
|
|
( (GetDisableCad(pGlobals) && IsActiveConsoleSession()) ? TIMEOUT_NONE : LOGON_TIMEOUT));
|
|
|
|
Result = pWlxFuncs->WlxDialogBoxParam(pGlobals->hGlobalWlx,
|
|
hDllInstance,
|
|
MAKEINTRESOURCE(IDD_LOGON_DIALOG),
|
|
NULL,
|
|
LogonDlgProc,
|
|
(LPARAM) &Parm );
|
|
|
|
return(Result);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: LogonDlgCBProc
|
|
*
|
|
* PURPOSE: Processes messages for Logon dialog combo box
|
|
*
|
|
* RETURNS: Return value depends on message being sent.
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 05-21-93 RobertRe Created.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
INT_PTR WINAPI
|
|
LogonDlgCBProc(
|
|
HWND hwnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
TCHAR KeyPressed;
|
|
|
|
// DbgPrint("message = %X\n",message);
|
|
|
|
switch (message) {
|
|
case WM_CHAR:
|
|
{
|
|
KeyPressed = (TCHAR) wParam;
|
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG)KeyPressed);
|
|
|
|
//
|
|
// This fake CBN_SELCHANGE message will cause the
|
|
// "Please wait..." dialog box to appear even if
|
|
// the character pressed doesn't exist in the combobox yet.
|
|
//
|
|
|
|
PostMessage (GetParent(hwnd), WM_COMMAND,
|
|
MAKELONG(0, CBN_SELCHANGE), 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return CallWindowProc(OldCBWndProc,hwnd,message,wParam,lParam);
|
|
}
|
|
|
|
INT_PTR
|
|
CALLBACK
|
|
DomainCacheDlgProc(
|
|
HWND hDlg,
|
|
UINT Message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
PGLOBALS pGlobals ;
|
|
|
|
DebugLog(( DEB_TRACE_DOMAIN, "DomainCacheDlgProc( %p, %x, %p, %p )\n",
|
|
hDlg, Message, wParam, lParam ));
|
|
|
|
switch ( Message )
|
|
{
|
|
case WM_INITDIALOG:
|
|
|
|
pGlobals = (PGLOBALS) lParam ;
|
|
|
|
if ( DCacheSetNotifyWindowIfNotReady(
|
|
pGlobals->Cache,
|
|
hDlg,
|
|
WM_DCACHE_COMPLETE ) )
|
|
{
|
|
EndDialog( hDlg, TRUE );
|
|
}
|
|
|
|
return TRUE ;
|
|
|
|
case WM_DCACHE_COMPLETE:
|
|
|
|
EndDialog( hDlg, TRUE );
|
|
|
|
return TRUE ;
|
|
|
|
default:
|
|
|
|
return FALSE ;
|
|
}
|
|
}
|
|
|
|
#ifdef ANNOY_AUTOLOGON_REGISTRY
|
|
|
|
#define TIMER_COUNTDOWN 0
|
|
|
|
INT_PTR
|
|
CALLBACK
|
|
AnnoyAutologonDlgProc(
|
|
HWND hDlg,
|
|
UINT Message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
PGLOBALS pGlobals = (PGLOBALS)GetWindowLongPtr(hDlg, GWLP_USERDATA);
|
|
LARGE_INTEGER Now;
|
|
WCHAR szBuild[10]; // Build number or countdown
|
|
|
|
switch ( Message )
|
|
{
|
|
case WM_INITDIALOG:
|
|
|
|
pGlobals = (PGLOBALS) lParam ;
|
|
SetWindowLongPtr(hDlg, GWLP_USERDATA, (LPARAM)pGlobals);
|
|
|
|
SetTimer(hDlg, TIMER_COUNTDOWN, 1000, NULL); // 1 sec
|
|
|
|
{
|
|
DWORD cbBuild;
|
|
HKEY hKey;
|
|
|
|
DWORD dwStatus = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
L"Software\\Microsoft\\Windows NT\\CurrentVersion",
|
|
0,
|
|
KEY_READ,
|
|
&hKey
|
|
);
|
|
|
|
cbBuild = sizeof(szBuild);
|
|
wcscpy(szBuild, L""); // OK
|
|
|
|
if (dwStatus == ERROR_SUCCESS)
|
|
{
|
|
DWORD dwType = REG_SZ;
|
|
|
|
dwStatus = RegQueryValueEx(
|
|
hKey,
|
|
L"CurrentBuildNumber",
|
|
0,
|
|
&dwType,
|
|
(LPBYTE) szBuild,
|
|
&cbBuild
|
|
);
|
|
|
|
if ((dwStatus != ERROR_SUCCESS) || (dwType != REG_SZ))
|
|
{
|
|
szBuild[0] = 0;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
// 10 sec per build penalty, up to 15 minutes
|
|
cbBuild = _wtol(szBuild);
|
|
if ((0 == cbBuild) || (cbBuild <= 3590))
|
|
{
|
|
cbBuild = 3591;
|
|
}
|
|
if (cbBuild - 3590 > 15 * 6)
|
|
{
|
|
cbBuild = 3590 + 15 * 6;
|
|
}
|
|
|
|
GetSystemTimeAsFileTime((FILETIME*) &Now);
|
|
Now.QuadPart += (cbBuild - 3590) * 10 * 10000000I64;
|
|
|
|
pGlobals->LastNotification.dwHighDateTime = Now.HighPart;
|
|
pGlobals->LastNotification.dwLowDateTime = Now.LowPart;
|
|
|
|
cbBuild = (cbBuild - 3590) * 10;
|
|
|
|
// SAFE: "00:XX:YY" is 8+1 characters (fits in 10)
|
|
swprintf(szBuild, L"00:%02d:%02d", (cbBuild/60)%100, cbBuild%60);
|
|
|
|
SetDlgItemText(hDlg, IDC_COUNTDOWN_STATIC, szBuild);
|
|
|
|
}
|
|
|
|
return TRUE ;
|
|
|
|
case WM_TIMER:
|
|
|
|
if (wParam == TIMER_COUNTDOWN)
|
|
{
|
|
LARGE_INTEGER End;
|
|
|
|
End.HighPart = pGlobals->LastNotification.dwHighDateTime;
|
|
End.LowPart = pGlobals->LastNotification.dwLowDateTime;
|
|
|
|
GetSystemTimeAsFileTime((FILETIME*) &Now);
|
|
|
|
if (Now.QuadPart >= End.QuadPart)
|
|
{
|
|
EndDialog(hDlg, MSGINA_DLG_SUCCESS);
|
|
}
|
|
else
|
|
{
|
|
DWORD dwMins, dwSecs;
|
|
|
|
End.QuadPart -= Now.QuadPart;
|
|
End.QuadPart = End.QuadPart / 10000000I64; // secs
|
|
|
|
dwMins = ((DWORD)End.QuadPart) / 60 % 100;
|
|
dwSecs = ((DWORD)End.QuadPart) % 60;
|
|
|
|
// SAFE: "00:XX:YY" is 8+1 characters (fits in 10)
|
|
swprintf(szBuild, L"00:%02d:%02d", dwMins, dwSecs);
|
|
|
|
SetDlgItemText(hDlg, IDC_COUNTDOWN_STATIC, szBuild);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
KillTimer(hDlg, TIMER_COUNTDOWN);
|
|
pGlobals->LastNotification.dwHighDateTime = 0;
|
|
pGlobals->LastNotification.dwLowDateTime = 0;
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDCANCEL:
|
|
// EndDialog(hDlg, MSGINA_DLG_FAILURE);
|
|
return(TRUE);
|
|
}
|
|
break;
|
|
|
|
case WLX_WM_SAS:
|
|
// Swallow SAS
|
|
return(TRUE);
|
|
|
|
|
|
}
|
|
return FALSE ;
|
|
}
|
|
#endif
|
|
|
|
BOOL IsAutoLogonUserInteractiveLogonRestricted (HWND hDlg)
|
|
|
|
{
|
|
WCHAR szUsername[UNLEN + 1]; // sizeof('\0')
|
|
|
|
return((GetDlgItemText(hDlg, IDD_LOGON_NAME, szUsername, ARRAYSIZE(szUsername)) != 0) &&
|
|
!ShellIsUserInteractiveLogonAllowed(szUsername));
|
|
}
|
|
|
|
BOOL HasDefaultPassword (TCHAR *pszPassword, int cchPassword)
|
|
|
|
{
|
|
DWORD dwType, dwPasswordSize;
|
|
|
|
dwType = REG_NONE;
|
|
dwPasswordSize = cchPassword * sizeof(TCHAR);
|
|
return(ERROR_SUCCESS == RegQueryValueEx(WinlogonKey,
|
|
DEFAULT_PASSWORD_KEY,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)pszPassword,
|
|
&dwPasswordSize) &&
|
|
(REG_SZ == dwType));
|
|
|
|
}
|
|
|
|
NTSTATUS RetrieveStoredSecret(LPCWSTR pswSecretName, WCHAR *PasswordBuffer, int nBufferSize)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
LSA_HANDLE LsaHandle = NULL;
|
|
UNICODE_STRING SecretName;
|
|
PUNICODE_STRING SecretValue = NULL;
|
|
|
|
//
|
|
// Set up the object attributes to open the Lsa policy object
|
|
//
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
NULL,
|
|
0L,
|
|
(HANDLE)NULL,
|
|
NULL);
|
|
|
|
//
|
|
// Open the local LSA policy object
|
|
//
|
|
|
|
Status = LsaOpenPolicy( NULL,
|
|
&ObjectAttributes,
|
|
POLICY_VIEW_LOCAL_INFORMATION,
|
|
&LsaHandle
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
RtlInitUnicodeString(
|
|
&SecretName,
|
|
pswSecretName
|
|
);
|
|
|
|
Status = LsaRetrievePrivateData(
|
|
LsaHandle,
|
|
&SecretName,
|
|
&SecretValue
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
if ( SecretValue->Length > 0 ) {
|
|
|
|
//
|
|
// If the password fits in the buffer, copy it there
|
|
// and null terminate
|
|
//
|
|
|
|
if (SecretValue->Length < (nBufferSize - 1) * sizeof(WCHAR)) {
|
|
|
|
RtlCopyMemory(
|
|
PasswordBuffer,
|
|
SecretValue->Buffer,
|
|
SecretValue->Length
|
|
);
|
|
PasswordBuffer[SecretValue->Length/sizeof(WCHAR)] = L'\0';
|
|
|
|
} else {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
ZeroMemory(SecretValue->Buffer, SecretValue->Length);
|
|
}
|
|
else
|
|
{
|
|
PasswordBuffer[0] = L'\0';
|
|
}
|
|
|
|
LsaFreeMemory(SecretValue);
|
|
}
|
|
LsaClose(LsaHandle);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
// ==========================================================================================
|
|
// Logon dialog has 2 formats, one that looks like logon dialog box, another that looks like
|
|
// unlock desktop dialogbox. When user connects to session 0 from remote (tsclient) the
|
|
// dialog that appears at console // need to change to unlock computer. so if session 0 is in
|
|
// use, and if this session is created at active console. we change logon dialog to look like
|
|
// "unlock computer" dialog.
|
|
// This function SwitchLogonLocked does most of the stuff related to switching these
|
|
// dialog controls.
|
|
// Parameters:
|
|
// HWND hDlg - dialog window handle,
|
|
// BOOL bShowLocked - if true show locked dialog, if false show normal logon dialog.
|
|
// BOOL bInit - TRUE when this function is called for the first time.
|
|
// ==========================================================================================
|
|
|
|
static bLocked = TRUE;
|
|
BOOL IsthisUnlockWindowsDialog ()
|
|
{
|
|
return bLocked;
|
|
}
|
|
|
|
BOOL SwitchLogonLocked(HWND hDlg, BOOL bShowLocked, BOOL bInit)
|
|
{
|
|
UINT rgidLockControls[] = {IDC_GROUP_UNLOCK, IDD_UNLOCK_ICON, IDD_UNLOCK_MESSAGE, IDD_UNLOCK_NAME_INFO};
|
|
static LockedControlHeight = 0;
|
|
BOOL bShutdownWithoutLogon;
|
|
|
|
|
|
int i;
|
|
|
|
if (bShowLocked == bLocked && !bInit)
|
|
{
|
|
// nothing to do.
|
|
return TRUE;
|
|
}
|
|
|
|
if (bInit)
|
|
{
|
|
|
|
{
|
|
//
|
|
// remember the reference rectangle height (groupbox) for control movements.
|
|
//
|
|
RECT rectLockedControls;
|
|
HWND hWnd = GetDlgItem(hDlg, rgidLockControls[0]);
|
|
GetWindowRect(hWnd, &rectLockedControls);
|
|
LockedControlHeight = rectLockedControls.bottom - rectLockedControls.top;
|
|
|
|
//
|
|
// this group box was only for reference, now hide it forever.
|
|
//
|
|
ShowWindow(hWnd, SW_HIDE);
|
|
|
|
}
|
|
|
|
bLocked = TRUE;
|
|
|
|
if ( !hLockedIcon )
|
|
{
|
|
hLockedIcon = LoadImage( hDllInstance,
|
|
MAKEINTRESOURCE( IDI_LOCKED),
|
|
IMAGE_ICON,
|
|
0, 0,
|
|
LR_DEFAULTCOLOR );
|
|
}
|
|
|
|
SendMessage( GetDlgItem( hDlg, IDD_UNLOCK_ICON),
|
|
STM_SETICON,
|
|
(WPARAM)hLockedIcon,
|
|
0 );
|
|
|
|
}
|
|
|
|
|
|
// lets move controls arround, depending upon if lock controls are to be shown or not.
|
|
if (bLocked != bShowLocked)
|
|
{
|
|
if (bShowLocked)
|
|
{
|
|
MoveChildren(hDlg, 0, LockedControlHeight);
|
|
for ( i = 1; i < sizeof(rgidLockControls)/sizeof(rgidLockControls[0]); i++)
|
|
{
|
|
HWND hWnd = GetDlgItem(hDlg, rgidLockControls[i]);
|
|
ASSERT(hWnd);
|
|
EnableWindow(hWnd, TRUE);
|
|
ShowWindow(hWnd, SW_SHOW);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
for ( i = 1; i < sizeof(rgidLockControls)/sizeof(rgidLockControls[0]); i++)
|
|
{
|
|
HWND hWnd = GetDlgItem(hDlg, rgidLockControls[i]);
|
|
ASSERT(hWnd);
|
|
ShowWindow(hWnd, SW_HIDE);
|
|
EnableWindow(hWnd, FALSE);
|
|
}
|
|
MoveChildren(hDlg, 0, -LockedControlHeight);
|
|
}
|
|
}
|
|
|
|
// some more processing
|
|
|
|
{
|
|
if (bShowLocked)
|
|
{
|
|
TCHAR szUser[USERNAME_LENGTH + DOMAIN_LENGTH + 2];
|
|
TCHAR szMessage[MAX_STRING_BYTES] = TEXT("");
|
|
TCHAR szFinalMessage[MAX_STRING_BYTES] = TEXT("");
|
|
if (GetSessionZeroUser(szUser, USERNAME_LENGTH + DOMAIN_LENGTH + 2))
|
|
{
|
|
LoadString(hDllInstance, IDS_LOCKED_EMAIL_NFN_MESSAGE, szMessage, MAX_STRING_BYTES);
|
|
_snwprintf(szFinalMessage, sizeof(szFinalMessage)/sizeof(TCHAR), szMessage, szUser );
|
|
szFinalMessage[sizeof(szFinalMessage)/sizeof(TCHAR) - 1] = 0; // NULL terminate
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// for some reason we could not get the current session zero user.
|
|
//
|
|
LoadString(hDllInstance, IDS_LOCKED_NO_USER_MESSAGE, szFinalMessage, MAX_STRING_BYTES);
|
|
}
|
|
|
|
SetDlgItemText(hDlg, IDD_UNLOCK_NAME_INFO, szFinalMessage);
|
|
}
|
|
|
|
//
|
|
// update the dialog box caption, accordingly
|
|
//
|
|
{
|
|
TCHAR szCaption[MAX_CAPTION_LENGTH] = TEXT("");
|
|
LoadString(hDllInstance, bShowLocked ? IDS_CAPTION_UNLOCK_DIALOG : IDS_CAPTION_LOGON_DIALOG, szCaption, ARRAYSIZE(szCaption));
|
|
if ( szCaption[0] != TEXT('\0') )
|
|
SetWindowText( hDlg, szCaption );
|
|
}
|
|
}
|
|
|
|
bLocked = bShowLocked;
|
|
|
|
|
|
if ( SafeBootMode == SAFEBOOT_MINIMAL )
|
|
{
|
|
bShutdownWithoutLogon = TRUE ;
|
|
}
|
|
else if (IsthisUnlockWindowsDialog() || !IsActiveConsoleSession())
|
|
{
|
|
bShutdownWithoutLogon = FALSE ;
|
|
}
|
|
else
|
|
{
|
|
bShutdownWithoutLogon = ReadWinlogonBoolValue(SHUTDOWN_WITHOUT_LOGON_KEY, TRUE);
|
|
}
|
|
|
|
EnableDlgItem(hDlg, IDD_LOGON_SHUTDOWN, bShutdownWithoutLogon);
|
|
|
|
InvalidateRect(hDlg, NULL, TRUE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: LogonDlgProc
|
|
*
|
|
* PURPOSE: Processes messages for Logon dialog
|
|
*
|
|
* RETURNS: MSGINA_DLG_SUCCESS - the user was logged on successfully
|
|
* MSGINA_DLG_FAILURE - the logon failed,
|
|
* DLG_INTERRUPTED() - a set defined in winlogon.h
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 12-09-91 Davidc Created.
|
|
*
|
|
\***************************************************************************/
|
|
void MyZeroMemory(PVOID lpv, SIZE_T size);
|
|
#define WM_HIDEOURSELVES (WM_USER + 1000)
|
|
|
|
INT_PTR WINAPI
|
|
LogonDlgProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
|
|
PGLOBALS pGlobals = (PGLOBALS)GetWindowLongPtr(hDlg, GWLP_USERDATA);
|
|
INT_PTR Result;
|
|
HWND CBHandle;
|
|
BOOL fDisconnectOnTsAutoLogonFailure = FALSE;
|
|
static BOOL bSessionZeroInUse = FALSE;
|
|
static int iSessionRegistrationCount = 0;
|
|
static BOOL bSmartCardInserted = FALSE;
|
|
|
|
switch (message)
|
|
{
|
|
|
|
case WM_INITDIALOG:
|
|
{
|
|
TCHAR PasswordBuffer[127];
|
|
BOOL bAutoLogon;
|
|
PMSGINA_LOGON_PARAMETERS pParam ;
|
|
|
|
pParam = (PMSGINA_LOGON_PARAMETERS) lParam ;
|
|
pGlobals = pParam->pGlobals ;
|
|
|
|
SetWindowLongPtr(hDlg, GWLP_USERDATA, (LPARAM)pGlobals);
|
|
|
|
// Hide the keyboard accelerator keys to start
|
|
SendMessage(hDlg, WM_CHANGEUISTATE, MAKELONG(UIS_SET, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0);
|
|
|
|
// Limit the maximum password length to 127
|
|
|
|
SendDlgItemMessage(hDlg, IDD_LOGON_PASSWORD, EM_SETLIMITTEXT, (WPARAM) 127, 0);
|
|
|
|
s_fAttemptedAutoLogon = FALSE;
|
|
|
|
//
|
|
// Check if auto logon is enabled.
|
|
//
|
|
|
|
pGlobals->AutoAdminLogon = GetProfileInt( APPLICATION_NAME, AUTO_ADMIN_LOGON_KEY, 0 ) != 0;
|
|
bAutoLogon = !pGlobals->IgnoreAutoAdminLogon;
|
|
|
|
if ( !pGlobals->AutoAdminLogon || (!g_Console) ||
|
|
((GetAsyncKeyState(VK_SHIFT) < 0) && (GetProfileInt( APPLICATION_NAME, IGNORE_SHIFT_OVERRIDE_KEY, 0 ) == 0)) )
|
|
{
|
|
bAutoLogon = FALSE;
|
|
}
|
|
|
|
KdPrint(("AutoAdminLogon = %d, IgnoreAutoAdminLogon = %d, bAutoLogon = %d\n",
|
|
pGlobals->AutoAdminLogon,
|
|
pGlobals->IgnoreAutoAdminLogon,
|
|
bAutoLogon ));
|
|
|
|
|
|
//
|
|
// Subclass the domain list control so we can filter messages
|
|
//
|
|
|
|
CBHandle = GetDlgItem(hDlg,IDD_LOGON_DOMAIN);
|
|
SetWindowLongPtr(CBHandle, GWLP_USERDATA, 0);
|
|
OldCBWndProc = (WNDPROC) SetWindowLongPtr(CBHandle, GWLP_WNDPROC, (LONG_PTR)LogonDlgCBProc);
|
|
|
|
//
|
|
// Subclass the user name and password edit also so we can disable edits
|
|
//
|
|
|
|
SetWindowSubclass(GetDlgItem(hDlg, IDD_LOGON_NAME) , DisableEditSubClassProc, IDD_LOGON_NAME , 0);
|
|
SetWindowSubclass(GetDlgItem(hDlg, IDD_LOGON_PASSWORD), DisableEditSubClassProc, IDD_LOGON_PASSWORD, 0);
|
|
|
|
ShellReleaseLogonMutex(FALSE);
|
|
|
|
if (!LogonDlgInit(hDlg, bAutoLogon, pParam->SasType ))
|
|
{
|
|
bSmartCardInserted = FALSE;
|
|
EndDialog(hDlg, MSGINA_DLG_FAILURE);
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
//
|
|
// If the default user for auto logon is present and the user is
|
|
// restricted (interactive logon denied) then disable auto logon.
|
|
//
|
|
|
|
if (bAutoLogon && IsAutoLogonUserInteractiveLogonRestricted(hDlg))
|
|
{
|
|
bAutoLogon = FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// If CAD is disabled, then gray out the Cancel button
|
|
// if we are going to the PIN dialog we will need a cancel button
|
|
//
|
|
if (GetDisableCad(pGlobals) &&
|
|
IsActiveConsoleSession() &&
|
|
(pParam->SasType != WLX_SAS_TYPE_SC_INSERT))
|
|
{
|
|
EnableDlgItem(hDlg, IDCANCEL, FALSE);
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// this dialog has 2 formats, one that looks like logon dialog box,
|
|
// another that looks like unlock desktop dialogbox.
|
|
// we choose locked one, if session 0 is in use, and if this session is created at
|
|
// active console.
|
|
//
|
|
if (g_IsTerminalServer &&
|
|
IsActiveConsoleSession() &&
|
|
NtCurrentPeb()->SessionId != 0 &&
|
|
!FastUserSwitchingEnabled() &&
|
|
!_ShellIsFriendlyUIActive())
|
|
{
|
|
TCHAR szUser[USERNAME_LENGTH + DOMAIN_LENGTH + 2];
|
|
//
|
|
// we are at temporary session created at console...
|
|
//
|
|
|
|
// check if a user is logged on at console session
|
|
bSessionZeroInUse = GetSessionZeroUser(szUser, USERNAME_LENGTH + DOMAIN_LENGTH + 2);
|
|
if (WinStationRegisterConsoleNotification(SERVERNAME_CURRENT, hDlg, NOTIFY_FOR_ALL_SESSIONS))
|
|
{
|
|
iSessionRegistrationCount++;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// this is not active console nonzero session.
|
|
//
|
|
bSessionZeroInUse = FALSE;
|
|
}
|
|
|
|
//
|
|
//
|
|
// now switch the control, accordigly to show logon or unlock dialog
|
|
//
|
|
SwitchLogonLocked(hDlg, bSessionZeroInUse, TRUE);
|
|
|
|
if (g_IsTerminalServer) {
|
|
BOOL fForceUPN;
|
|
BOOL fPopulateFields = TRUE;
|
|
BOOL fResult = FALSE;
|
|
BOOL fNoAutologon = FALSE;
|
|
PWLX_CLIENT_CREDENTIALS_INFO_V2_0 pAutoLogon;
|
|
|
|
//
|
|
// Query network WinStation client credentials for
|
|
// auto logon
|
|
//
|
|
|
|
pGlobals->MuGlobals.pAutoLogon =
|
|
LocalAlloc( LPTR, sizeof(WLX_CLIENT_CREDENTIALS_INFO_V2_0) );
|
|
|
|
if (pGlobals->MuGlobals.pAutoLogon) {
|
|
|
|
pGlobals->MuGlobals.pAutoLogon->dwType = WLX_CREDENTIAL_TYPE_V2_0;
|
|
|
|
if (NtCurrentPeb()->SessionId != 0) {
|
|
fResult = pWlxFuncs->WlxQueryTsLogonCredentials(
|
|
pGlobals->MuGlobals.pAutoLogon
|
|
);
|
|
}
|
|
|
|
// Query TermSrv if this was a Session directory redirected SmartCard autoLogon
|
|
|
|
if (fResult && !pGlobals->MuGlobals.pAutoLogon->fPromptForPassword && g_FirstTime) {
|
|
BOOL fSessionDirectoryRedirectedAutoLogon = FALSE;
|
|
DWORD Length;
|
|
|
|
if (WinStationQueryInformation(
|
|
SERVERNAME_CURRENT,
|
|
LOGONID_CURRENT,
|
|
WinStationSDRedirectedSmartCardLogon,
|
|
&fSessionDirectoryRedirectedAutoLogon,
|
|
sizeof(BOOL),
|
|
&Length)) {
|
|
|
|
if ( fSessionDirectoryRedirectedAutoLogon ) {
|
|
|
|
//
|
|
// This is a TS Session directory redirected Smartcard autologon
|
|
// We should not proceed with normal Autologon for this special case
|
|
// This is so that Winlogon detects the SmartCard and takes the SmartCard route
|
|
//
|
|
fNoAutologon = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (FALSE == g_FirstTime)
|
|
{
|
|
// We have tried this password once, no need to retry forever...
|
|
pGlobals->MuGlobals.pAutoLogon->fPromptForPassword = TRUE;
|
|
}
|
|
|
|
g_FirstTime = FALSE ;
|
|
|
|
if ( fResult && !fNoAutologon &&
|
|
(pGlobals->MuGlobals.pAutoLogon->pszUserName[0] || pGlobals->MuGlobals.pAutoLogon->pszDomain[0] )) {
|
|
|
|
pAutoLogon = pGlobals->MuGlobals.pAutoLogon;
|
|
fDisconnectOnTsAutoLogonFailure = pAutoLogon->fDisconnectOnLogonFailure;
|
|
|
|
SetupCursor(TRUE); // hourglass cursor
|
|
|
|
fForceUPN = GetProfileInt( APPLICATION_NAME, TEXT("TSForceUPN"), FALSE );
|
|
if (fForceUPN)
|
|
{
|
|
fPopulateFields = FALSE; // never show old SAM style is UPN is forced
|
|
}
|
|
|
|
if (pAutoLogon->pszDomain[0] == TEXT('\0') && fForceUPN)
|
|
{
|
|
fForceUPN = FALSE; // domain name not provided, can't apply policy
|
|
}
|
|
|
|
if (fForceUPN && pGlobals->MuGlobals.pAutoLogon->pszUserName[0] )
|
|
{
|
|
LRESULT iDomain;
|
|
HWND hwndDomain;
|
|
PDOMAIN_CACHE_ENTRY Entry ;
|
|
ULONG nSize;
|
|
|
|
// Performance issue. We don't want to perform a UPN conversion
|
|
// for local machine accounts (or unknown domains). When this
|
|
// happens, the lookup will take a LONG time.
|
|
|
|
hwndDomain = GetDlgItem( hDlg, IDD_LOGON_DOMAIN );
|
|
iDomain = SendMessage( hwndDomain,
|
|
CB_FINDSTRING,
|
|
(WPARAM) -1,
|
|
(LPARAM) pAutoLogon->pszDomain );
|
|
fForceUPN = FALSE; // don't do the conversion
|
|
if (iDomain != CB_ERR)
|
|
{
|
|
Entry = (PDOMAIN_CACHE_ENTRY) SendMessage( hwndDomain, CB_GETITEMDATA, (WPARAM)iDomain, 0);
|
|
if ( Entry != (PDOMAIN_CACHE_ENTRY) CB_ERR && Entry != NULL)
|
|
{
|
|
switch (Entry->Type)
|
|
{
|
|
case DomainNt5:
|
|
fForceUPN = TRUE; // Attempt the conversion
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Convert the domain\username into UPN format.
|
|
// and make sure the dialog is in UPN form.
|
|
|
|
// 2000/10/09 vtan: this function used to have two stack variables
|
|
// szOldStyle and szUPNName that were TCHARs of MAX_UPN_NAME_SIZE size. The
|
|
// fix for this makes these dynamically allocated to save stack space
|
|
|
|
{
|
|
TCHAR *pszOldStyle;
|
|
TCHAR *pszUPNName;
|
|
|
|
pszOldStyle = (TCHAR*)LocalAlloc(LMEM_FIXED, MAX_UPN_NAME_SIZE * sizeof(TCHAR));
|
|
pszUPNName = (TCHAR*)LocalAlloc(LMEM_FIXED, MAX_UPN_NAME_SIZE * sizeof(TCHAR));
|
|
if ((pszOldStyle != NULL) && (pszUPNName != NULL))
|
|
{
|
|
_snwprintf(pszOldStyle, MAX_UPN_NAME_SIZE, TEXT("%s\\%s"), pAutoLogon->pszDomain, pAutoLogon->pszUserName);
|
|
pszOldStyle[MAX_UPN_NAME_SIZE - 1] = 0;
|
|
nSize = MAX_UPN_NAME_SIZE;
|
|
fResult = TranslateName(
|
|
pszOldStyle,
|
|
NameSamCompatible,
|
|
NameUserPrincipal,
|
|
pszUPNName,
|
|
&nSize
|
|
);
|
|
if (fResult)
|
|
{
|
|
// We now have the UPN form of the user account.
|
|
SetDlgItemText( hDlg, IDD_LOGON_NAME, pszUPNName);
|
|
}
|
|
}
|
|
if (pszOldStyle != NULL)
|
|
{
|
|
LocalFree(pszOldStyle);
|
|
}
|
|
if (pszUPNName != NULL)
|
|
{
|
|
LocalFree(pszUPNName);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fPopulateFields)
|
|
{
|
|
// display the old SAM style
|
|
SetDlgItemText( hDlg, IDD_LOGON_NAME, pAutoLogon->pszUserName );
|
|
SendMessage( GetDlgItem( hDlg, IDD_LOGON_DOMAIN ),
|
|
CB_SELECTSTRING,
|
|
(WPARAM) -1,
|
|
(LPARAM) pAutoLogon->pszDomain );
|
|
}
|
|
else
|
|
{
|
|
// Enable or disable the domain box depending on whether a UPN name has been typed
|
|
EnableDomainForUPN(GetDlgItem(hDlg, IDD_LOGON_NAME), GetDlgItem(hDlg, IDD_LOGON_DOMAIN));
|
|
|
|
// Since we're forcing UPN, hide the options dialog, but don't make it sticky
|
|
LogonShowOptions(pGlobals, hDlg, FALSE, FALSE);
|
|
}
|
|
|
|
// See if the administrator always wants password prompting
|
|
|
|
if ( TRUE == g_fHelpAssistantLogon || !pAutoLogon->fPromptForPassword ) {
|
|
SetDlgItemText( hDlg, IDD_LOGON_PASSWORD, pAutoLogon->pszPassword );
|
|
}
|
|
|
|
DCacheSetDefaultEntry(
|
|
pGlobals->Cache,
|
|
pAutoLogon->pszDomain,
|
|
NULL );
|
|
|
|
if( TRUE == g_fHelpAssistantLogon || !pGlobals->MuGlobals.pAutoLogon->fPromptForPassword )
|
|
{
|
|
FreeAutoLogonInfo( pGlobals );
|
|
|
|
// Drop through as if Enter had been pressed...
|
|
wParam = IDOK;
|
|
|
|
goto go_logon;
|
|
}
|
|
else
|
|
{
|
|
FreeAutoLogonInfo( pGlobals );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FreeAutoLogonInfo( pGlobals );
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pGlobals->SmartCardLogon) {
|
|
|
|
bAutoLogon = FALSE;
|
|
pGlobals->AutoAdminLogon = FALSE;
|
|
|
|
if ( RetrieveStoredSecret( TEXT("DefaultPIN"), PasswordBuffer, ARRAYSIZE(PasswordBuffer)) == STATUS_SUCCESS )
|
|
{
|
|
// Ensure we never write more than 127 chars into the password box
|
|
PasswordBuffer[126] = 0;
|
|
SetDlgItemText(hDlg, IDD_LOGON_PASSWORD, PasswordBuffer);
|
|
goto go_logon;
|
|
}
|
|
}
|
|
|
|
// save off the auto logon attempt.
|
|
|
|
s_fAttemptedAutoLogon = (bAutoLogon != FALSE);
|
|
|
|
if (bAutoLogon)
|
|
{
|
|
if (_Shell_LogonDialog_UIHostActive())
|
|
{
|
|
GetWindowRect(hDlg, &pGlobals->rcDialog);
|
|
SetWindowPos(hDlg, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
|
|
PostMessage(hDlg, WM_HIDEOURSELVES, 0, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (_Shell_LogonDialog_Init(hDlg, SHELL_LOGONDIALOG_LOGGEDOFF))
|
|
{
|
|
case SHELL_LOGONDIALOG_NONE:
|
|
default:
|
|
{
|
|
//
|
|
// If auto logon isn't enabled, set the focus to the
|
|
// password edit control and leave.
|
|
//
|
|
|
|
return(SetPasswordFocus(hDlg));
|
|
}
|
|
case SHELL_LOGONDIALOG_LOGON:
|
|
{
|
|
GetWindowRect(hDlg, &pGlobals->rcDialog);
|
|
SetWindowPos(hDlg, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
|
|
PostMessage(hDlg, WM_HIDEOURSELVES, 0, 0);
|
|
goto go_logon;
|
|
}
|
|
case SHELL_LOGONDIALOG_EXTERNALHOST:
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Attempt to auto logon. If no default password
|
|
// specified, then this is a one shot attempt, which handles
|
|
// the case when auto logging on as Administrator.
|
|
//
|
|
|
|
if (HasDefaultPassword(PasswordBuffer, ARRAYSIZE(PasswordBuffer)) != FALSE)
|
|
{
|
|
// Ensure we never write more than 127 chars into the password box
|
|
PasswordBuffer[126] = 0;
|
|
SetDlgItemText(hDlg, IDD_LOGON_PASSWORD, PasswordBuffer);
|
|
|
|
#ifdef ANNOY_AUTOLOGON_REGISTRY
|
|
pWlxFuncs->WlxDialogBoxParam(
|
|
pGlobals->hGlobalWlx,
|
|
hDllInstance,
|
|
(LPTSTR) IDD_ANNOYAUTOLOGON_DIALOG,
|
|
hDlg,
|
|
AnnoyAutologonDlgProc,
|
|
(LPARAM) pGlobals );
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
Status = RetrieveStoredSecret( DEFAULT_PASSWORD_KEY, PasswordBuffer, ARRAYSIZE(PasswordBuffer) );
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
SetDlgItemText(hDlg, IDD_LOGON_PASSWORD, PasswordBuffer);
|
|
}
|
|
else
|
|
{
|
|
WriteProfileString( APPLICATION_NAME, AUTO_ADMIN_LOGON_KEY, TEXT("0") );
|
|
}
|
|
|
|
}
|
|
|
|
go_logon:
|
|
// Zeroize this buffer for obvious security reasons
|
|
// Need to call this stub, otherwise the compiler optimizes this out!
|
|
MyZeroMemory(PasswordBuffer, sizeof(PasswordBuffer));
|
|
|
|
// Drop through as if Enter had been pressed...
|
|
wParam = IDOK;
|
|
}
|
|
|
|
// nb: deliberate drop through from above
|
|
|
|
case WM_COMMAND:
|
|
switch (HIWORD(wParam))
|
|
{
|
|
|
|
case CBN_DROPDOWN:
|
|
case CBN_SELCHANGE:
|
|
|
|
DebugLog((DEB_TRACE, "Got CBN_DROPDOWN\n"));
|
|
|
|
if ( !pGlobals->ListPopulated )
|
|
{
|
|
WCHAR Buffer[ 2 ];
|
|
|
|
if ( DCacheGetCacheState( pGlobals->Cache ) < DomainCacheRegistryCache )
|
|
{
|
|
pWlxFuncs->WlxDialogBoxParam(
|
|
pGlobals->hGlobalWlx,
|
|
hDllInstance,
|
|
(LPTSTR) IDD_WAITDOMAINCACHEVALID_DIALOG,
|
|
hDlg,
|
|
DomainCacheDlgProc,
|
|
(LPARAM) pGlobals );
|
|
|
|
|
|
|
|
}
|
|
|
|
if ( DCacheGetCacheState( pGlobals->Cache ) == DomainCacheReady )
|
|
{
|
|
PDOMAIN_CACHE_ARRAY ActiveArrayBackup ;
|
|
|
|
ActiveArrayBackup = pGlobals->ActiveArray;
|
|
|
|
pGlobals->ActiveArray = DCacheCopyCacheArray( pGlobals->Cache );
|
|
|
|
if ( pGlobals->ActiveArray )
|
|
{
|
|
DCacheFreeArray( ActiveArrayBackup ); // Not needed anymore
|
|
|
|
Buffer[ 0 ] = (WCHAR) GetWindowLongPtr( GetDlgItem( hDlg, IDD_LOGON_DOMAIN ),
|
|
GWLP_USERDATA );
|
|
Buffer[ 1 ] = L'\0';
|
|
|
|
DCachePopulateListBoxFromArray(
|
|
pGlobals->ActiveArray,
|
|
GetDlgItem( hDlg, IDD_LOGON_DOMAIN ),
|
|
Buffer );
|
|
|
|
pGlobals->ListPopulated = TRUE ;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Restore the old array, otherwise the pointers in the
|
|
// combo items will point to freed memory
|
|
//
|
|
pGlobals->ActiveArray = ActiveArrayBackup ;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
switch (LOWORD(wParam))
|
|
{
|
|
|
|
case IDD_LOGON_NAME:
|
|
{
|
|
switch(HIWORD(wParam))
|
|
{
|
|
case EN_CHANGE:
|
|
{
|
|
EnableDomainForUPN((HWND) lParam, GetDlgItem(hDlg, IDD_LOGON_DOMAIN));
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case IDOK:
|
|
|
|
//
|
|
// Deal with combo-box UI requirements
|
|
//
|
|
|
|
if (HandleComboBoxOK(hDlg, IDD_LOGON_DOMAIN))
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
Result = AttemptLogon( hDlg );
|
|
|
|
if (Result == MSGINA_DLG_FAILURE)
|
|
{
|
|
if (!fDisconnectOnTsAutoLogonFailure &&
|
|
!g_fHelpAssistantLogon ) {
|
|
// Let the user try again
|
|
|
|
// Clear the password field and set focus to it
|
|
SetDlgItemText(hDlg, IDD_LOGON_PASSWORD, NULL);
|
|
SetPasswordFocus(hDlg);
|
|
} else {
|
|
bSmartCardInserted = FALSE;
|
|
EndDialog(hDlg, MSGINA_DLG_USER_LOGOFF);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
case IDCANCEL:
|
|
{
|
|
if (!_Shell_LogonDialog_Cancel())
|
|
{
|
|
// If this is TS and the user hit ESC at the smart card pin prompt
|
|
// we want to switch to the password dialog
|
|
if (/*!g_Console && !IsActiveConsoleSession() && */pGlobals->SmartCardLogon) {
|
|
|
|
EndDialog(hDlg, bSmartCardInserted ? MSGINA_DLG_SMARTCARD_REMOVED : MSGINA_DLG_FAILURE);
|
|
bSmartCardInserted = FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Allow logon screen to go away if not at console
|
|
//
|
|
|
|
bSmartCardInserted = FALSE;
|
|
EndDialog(hDlg, !g_Console ? MSGINA_DLG_USER_LOGOFF
|
|
: MSGINA_DLG_FAILURE);
|
|
|
|
if (g_Console && !IsActiveConsoleSession()) {
|
|
|
|
pWlxFuncs->WlxDisconnect();
|
|
}
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
case IDD_LOGON_SHUTDOWN:
|
|
//
|
|
// This is a normal shutdown request
|
|
//
|
|
// Check they know what they're doing and find
|
|
// out if they want to reboot too.
|
|
//
|
|
|
|
// Note that we definitely don't want disconnect or logofff
|
|
// here since no one is logged on
|
|
Result = WinlogonShutdownDialog(hDlg, pGlobals, (SHTDN_DISCONNECT | SHTDN_LOGOFF));
|
|
|
|
if (DLG_SHUTDOWN(Result))
|
|
{
|
|
_Shell_LogonDialog_ShuttingDown();
|
|
bSmartCardInserted = FALSE;
|
|
EndDialog(hDlg, Result);
|
|
}
|
|
return(TRUE);
|
|
|
|
case IDD_LOGON_OPTIONS:
|
|
LogonShowOptions(pGlobals, hDlg, !pGlobals->LogonOptionsShown, TRUE);
|
|
return(TRUE);
|
|
|
|
}
|
|
break;
|
|
|
|
}
|
|
break;
|
|
|
|
case WM_TIMER:
|
|
{
|
|
switch (wParam)
|
|
{
|
|
case 0:
|
|
{
|
|
HDC hDC;
|
|
|
|
RtlEnterCriticalSection(&pGlobals->csGlobals);
|
|
|
|
if ( pGlobals->LogonInProgress )
|
|
{
|
|
if (pGlobals->cxBand != 0)
|
|
{
|
|
pGlobals->xBandOffset = (pGlobals->xBandOffset+5) % pGlobals->cxBand;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pGlobals->xBandOffset = 0;
|
|
KillTimer(hDlg, 0);
|
|
}
|
|
|
|
RtlLeaveCriticalSection(&pGlobals->csGlobals);
|
|
|
|
hDC = GetDC(hDlg);
|
|
if ( hDC )
|
|
{
|
|
PaintBranding(hDlg, hDC, pGlobals->xBandOffset, TRUE, TRUE, COLOR_BTNFACE);
|
|
ReleaseDC(hDlg, hDC);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
case TIMER_MYLANGUAGECHECK:
|
|
{
|
|
LayoutCheckHandler(hDlg, LAYOUT_DEF_USER);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_ERASEBKGND:
|
|
return PaintBranding(hDlg, (HDC)wParam, 0, FALSE, TRUE, COLOR_BTNFACE);
|
|
|
|
case WM_QUERYNEWPALETTE:
|
|
return BrandingQueryNewPalete(hDlg);
|
|
|
|
case WM_PALETTECHANGED:
|
|
return BrandingPaletteChanged(hDlg, (HWND)wParam);
|
|
|
|
case WM_LOGONCOMPLETE:
|
|
{
|
|
_Shell_LogonDialog_LogonCompleted(lParam, pGlobals->UserName, pGlobals->Domain);
|
|
Result = lParam;
|
|
|
|
//
|
|
// Discard the logon in progress dialog if one is displayed
|
|
//
|
|
|
|
RtlEnterCriticalSection(&pGlobals->csGlobals);
|
|
pGlobals->LogonInProgress = FALSE;
|
|
RtlLeaveCriticalSection(&pGlobals->csGlobals);
|
|
|
|
AttemptLogonSetControls(pGlobals, hDlg);
|
|
|
|
if (Result == MSGINA_DLG_FAILURE)
|
|
{
|
|
//
|
|
// reset autoadmin logon flag (Bug 532161)
|
|
//
|
|
pGlobals->AutoAdminLogon = FALSE;
|
|
|
|
//
|
|
// erase the stored password, that otherwise (on success)
|
|
// would get erased after the dialog finishes with
|
|
// MSGINA_DLG_SUCCESS in WlxLoggedOutSAS after Logon
|
|
//
|
|
if (!pGlobals->TransderedCredentials)
|
|
{
|
|
ErasePassword( &pGlobals->PasswordString );
|
|
}
|
|
|
|
if (fDisconnectOnTsAutoLogonFailure || g_fHelpAssistantLogon)
|
|
{
|
|
//
|
|
// If TermSrv Internet Connector is on
|
|
// don't allow a second chance at the logon dialog
|
|
//
|
|
|
|
bSmartCardInserted = FALSE;
|
|
EndDialog(hDlg, MSGINA_DLG_USER_LOGOFF);
|
|
break;
|
|
}
|
|
|
|
if (s_fAttemptedAutoLogon != FALSE)
|
|
{
|
|
s_fAttemptedAutoLogon = FALSE;
|
|
switch (_Shell_LogonDialog_Init(hDlg, SHELL_LOGONDIALOG_LOGGEDOFF))
|
|
{
|
|
case SHELL_LOGONDIALOG_LOGON:
|
|
goto go_logon;
|
|
break;
|
|
case SHELL_LOGONDIALOG_EXTERNALHOST:
|
|
break;
|
|
case SHELL_LOGONDIALOG_NONE:
|
|
default:
|
|
if (!IsWindowVisible(hDlg))
|
|
{
|
|
//
|
|
// The dialog was hidden for automatic logon. An error occurred.
|
|
// Show the dialog so the error can be seen and the problem corrected.
|
|
//
|
|
SetWindowPos(hDlg, NULL, 0, 0, pGlobals->rcDialog.right - pGlobals->rcDialog.left, pGlobals->rcDialog.bottom - pGlobals->rcDialog.top, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
|
|
ShowWindow(hDlg, SW_SHOW);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!_Shell_LogonDialog_UIHostActive())
|
|
{
|
|
// Let the user try again - clear the password
|
|
SetDlgItemText(hDlg, IDD_LOGON_PASSWORD, NULL);
|
|
SetPasswordFocus(hDlg);
|
|
|
|
// the logon failed, so lets ensure we show the options pane so they can update
|
|
// their domain selection if needed.
|
|
|
|
if ( !pGlobals->LogonOptionsShown )
|
|
LogonShowOptions(pGlobals, hDlg, TRUE, FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
bSmartCardInserted = FALSE;
|
|
EndDialog( hDlg, Result );
|
|
break;
|
|
}
|
|
|
|
case WM_HANDLEFAILEDLOGON:
|
|
{
|
|
if (_Shell_LogonDialog_LogonDisplayError(g_failinfo.Status, g_failinfo.SubStatus))
|
|
{
|
|
if (!IsWindowVisible(hDlg))
|
|
{
|
|
//
|
|
// The dialog was hidden for automatic logon. An error occurred.
|
|
// Show the dialog so the error can be seen and the problem corrected.
|
|
//
|
|
SetWindowPos(hDlg, NULL, 0, 0, pGlobals->rcDialog.right - pGlobals->rcDialog.left, pGlobals->rcDialog.bottom - pGlobals->rcDialog.top, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
|
|
ShowWindow(hDlg, SW_SHOW);
|
|
}
|
|
Result = HandleFailedLogon(hDlg);
|
|
}
|
|
else
|
|
{
|
|
Result = MSGINA_DLG_FAILURE;
|
|
}
|
|
SendMessage(hDlg, WM_LOGONCOMPLETE, 0, (LPARAM) Result);
|
|
return TRUE;
|
|
}
|
|
case WLX_WM_SAS:
|
|
|
|
// Give the consumer logon part a chance to handle the SAS
|
|
// or to key off the fact that a SAS has occurred.
|
|
(BOOL)_Shell_LogonDialog_DlgProc(hDlg, message, wParam, lParam);
|
|
|
|
if ((wParam == WLX_SAS_TYPE_TIMEOUT) ||
|
|
(wParam == WLX_SAS_TYPE_SCRNSVR_TIMEOUT) )
|
|
{
|
|
//
|
|
// If this was a timeout, return false, and let winlogon
|
|
// kill us later
|
|
//
|
|
|
|
bSmartCardInserted = FALSE;
|
|
return(FALSE);
|
|
}
|
|
if ( wParam == WLX_SAS_TYPE_SC_INSERT ) {
|
|
|
|
//
|
|
// If a password logon is already taking place then ignore this sas
|
|
//
|
|
if (pGlobals->LogonInProgress && !pGlobals->SmartCardLogon)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
bSmartCardInserted = TRUE;
|
|
EndDialog( hDlg, MSGINA_DLG_SMARTCARD_INSERTED );
|
|
|
|
} else if ( wParam == WLX_SAS_TYPE_SC_REMOVE ) {
|
|
|
|
//
|
|
// If a password logon is already taking place then ignore this sas
|
|
//
|
|
if (pGlobals->LogonInProgress && !pGlobals->SmartCardLogon)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
if ( bSmartCardInserted ) {
|
|
|
|
bSmartCardInserted = FALSE;
|
|
EndDialog( hDlg, MSGINA_DLG_SMARTCARD_REMOVED );
|
|
|
|
} else if ( pGlobals->SmartCardLogon ) {
|
|
|
|
// If this was a s/c initiated logon, then cancel
|
|
// the dialog. Otherwise, ignore it.
|
|
bSmartCardInserted = FALSE;
|
|
EndDialog( hDlg, MSGINA_DLG_FAILURE );
|
|
}
|
|
|
|
} else if ( wParam == WLX_SAS_TYPE_AUTHENTICATED )
|
|
{
|
|
bSmartCardInserted = FALSE;
|
|
_Shell_LogonDialog_LogonCompleted(MSGINA_DLG_SWITCH_CONSOLE, pGlobals->UserName, pGlobals->Domain);
|
|
EndDialog( hDlg, MSGINA_DLG_SWITCH_CONSOLE );
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
case WM_WTSSESSION_CHANGE:
|
|
ASSERT(iSessionRegistrationCount < 2);
|
|
|
|
//
|
|
// its possible, that we unregister for notification in wm_destroy and still receive this notification,
|
|
// as the notification may already have been sent.
|
|
//
|
|
if (iSessionRegistrationCount == 1)
|
|
{
|
|
if (lParam == 0)
|
|
{
|
|
//
|
|
// we are interested only in logon/logoff messages from session 0.
|
|
//
|
|
|
|
if (wParam == WTS_SESSION_LOGON || wParam == WTS_SESSION_LOGOFF)
|
|
{
|
|
bSessionZeroInUse = (wParam == WTS_SESSION_LOGON);
|
|
SwitchLogonLocked(hDlg, bSessionZeroInUse, FALSE);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case WM_DESTROY:
|
|
|
|
// if registered for notification unregister now.
|
|
if (iSessionRegistrationCount)
|
|
{
|
|
WinStationUnRegisterConsoleNotification (SERVERNAME_CURRENT, hDlg);
|
|
iSessionRegistrationCount--;
|
|
ASSERT(iSessionRegistrationCount == 0);
|
|
}
|
|
_Shell_LogonDialog_Destroy();
|
|
|
|
FreeLayoutInfo(LAYOUT_DEF_USER);
|
|
if ( pGlobals->ActiveArray )
|
|
{
|
|
DCacheFreeArray( pGlobals->ActiveArray );
|
|
pGlobals->ActiveArray = NULL ;
|
|
}
|
|
|
|
RemoveWindowSubclass(GetDlgItem(hDlg, IDD_LOGON_NAME), DisableEditSubClassProc, IDD_LOGON_NAME);
|
|
RemoveWindowSubclass(GetDlgItem(hDlg, IDD_LOGON_PASSWORD), DisableEditSubClassProc, IDD_LOGON_PASSWORD);
|
|
|
|
break;
|
|
|
|
case WM_HIDEOURSELVES:
|
|
ShowWindow(hDlg, SW_HIDE);
|
|
break;
|
|
|
|
default:
|
|
if (_Shell_LogonDialog_DlgProc(hDlg, message, wParam, lParam) != FALSE)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
SECURITY_STATUS PopulateSecPackageList(
|
|
PGLOBALS pGlobals
|
|
)
|
|
{
|
|
static UCHAR s_bDoneThat = 0;
|
|
|
|
STRING Narrow;
|
|
SECURITY_STATUS Status;
|
|
|
|
//
|
|
// Populate Security Package List:
|
|
//
|
|
|
|
if ( ( s_bDoneThat & 1) == 0)
|
|
{
|
|
RtlInitString( &Narrow, MICROSOFT_KERBEROS_NAME_A );
|
|
|
|
Status = LsaLookupAuthenticationPackage(
|
|
pGlobals->LsaHandle,
|
|
&Narrow,
|
|
&pGlobals->SmartCardLogonPackage );
|
|
|
|
if ( NT_SUCCESS( Status ) )
|
|
{
|
|
s_bDoneThat |= 1;
|
|
}
|
|
|
|
//
|
|
// this (potential) failure is not critical. If it fails, then s/c logons later
|
|
// will fail.
|
|
//
|
|
}
|
|
|
|
Status = 0;
|
|
|
|
if ( ( s_bDoneThat & 2) == 0)
|
|
{
|
|
RtlInitString( &Narrow, NEGOSSP_NAME_A );
|
|
|
|
Status = LsaLookupAuthenticationPackage(
|
|
pGlobals->LsaHandle,
|
|
&Narrow,
|
|
&pGlobals->PasswordLogonPackage );
|
|
|
|
if ( NT_SUCCESS( Status ) )
|
|
{
|
|
s_bDoneThat |= 2;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: LogonDlgInit
|
|
*
|
|
* PURPOSE: Handles initialization of logon dialog
|
|
*
|
|
* RETURNS: TRUE on success, FALSE on failure
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 12-09-91 Davidc Created.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL
|
|
LogonDlgInit(
|
|
HWND hDlg,
|
|
BOOL bAutoLogon,
|
|
DWORD SasType
|
|
)
|
|
{
|
|
PGLOBALS pGlobals = (PGLOBALS)GetWindowLongPtr(hDlg, GWLP_USERDATA);
|
|
LPTSTR String = NULL;
|
|
TCHAR LogonMsg[MAX_PATH];
|
|
BOOL RemoveLegalBanner;
|
|
BOOL ShowOptions = FALSE;
|
|
HKEY hKey;
|
|
int err;
|
|
DWORD RasDisable;
|
|
DWORD RasForce;
|
|
SECURITY_STATUS Status;
|
|
RECT rc, rc2;
|
|
BOOL bHasLangIcon = FALSE;
|
|
ULONG CacheFlags ;
|
|
|
|
//
|
|
// Populate Security Package List:
|
|
//
|
|
|
|
Status = PopulateSecPackageList(
|
|
pGlobals );
|
|
|
|
if ( !NT_SUCCESS( Status ) )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
|
|
//
|
|
// Update the caption for certain banks
|
|
//
|
|
|
|
SetWelcomeCaption(hDlg);
|
|
|
|
|
|
//
|
|
// Get username and domain last used to login
|
|
//
|
|
|
|
//
|
|
// Ignore the default user name unless on the active console
|
|
//
|
|
if (IsActiveConsoleSession())
|
|
{
|
|
String = NULL;
|
|
|
|
if ( pGlobals->AutoAdminLogon && pGlobals->IgnoreAutoAdminLogon)
|
|
{
|
|
String = AllocAndGetProfileString(APPLICATION_NAME, TEMP_DEFAULT_USER_NAME_KEY, TEXT(""));
|
|
}
|
|
|
|
if ( (!String) || (!String[0]) )
|
|
{
|
|
if ( String )
|
|
{
|
|
Free(String);
|
|
}
|
|
|
|
String = AllocAndGetProfileString(APPLICATION_NAME, DEFAULT_USER_NAME_KEY, TEXT(""));
|
|
}
|
|
|
|
if ( String )
|
|
{
|
|
if (!bAutoLogon && (ReadWinlogonBoolValue(DONT_DISPLAY_LAST_USER_KEY, FALSE) == TRUE))
|
|
{
|
|
String[0] = 0;
|
|
}
|
|
|
|
SetDlgItemText(hDlg, IDD_LOGON_NAME, String);
|
|
Free(String);
|
|
}
|
|
}
|
|
|
|
GetProfileString( APPLICATION_NAME,
|
|
DEFAULT_DOMAIN_NAME_KEY,
|
|
TEXT(""),
|
|
pGlobals->Domain,
|
|
MAX_STRING_BYTES );
|
|
|
|
if ( !DCacheValidateCache( pGlobals->Cache ) )
|
|
{
|
|
ASSERT( pGlobals->ActiveArray == NULL );
|
|
|
|
DCacheUpdateMinimal( pGlobals->Cache, pGlobals->Domain, FALSE );
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Set the current default:
|
|
//
|
|
|
|
DCacheSetDefaultEntry( pGlobals->Cache,
|
|
pGlobals->Domain,
|
|
NULL );
|
|
}
|
|
|
|
CacheFlags = DCacheGetFlags( pGlobals->Cache );
|
|
|
|
if ( ( CacheFlags & DCACHE_NO_CACHE ) &&
|
|
( SafeBootMode != SAFEBOOT_MINIMAL ) &&
|
|
( ( pGlobals->AutoAdminLogon ) ||
|
|
( CacheFlags & DCACHE_DEF_UNKNOWN ) ) )
|
|
{
|
|
//
|
|
// Must wait for the cache to be populated
|
|
//
|
|
|
|
DCacheUpdateFull( pGlobals->Cache,
|
|
pGlobals->Domain );
|
|
|
|
CacheFlags = DCacheGetFlags( pGlobals->Cache );
|
|
}
|
|
else
|
|
{
|
|
if ( DCacheGetCacheState( pGlobals->Cache ) != DomainCacheReady )
|
|
{
|
|
DCacheUpdateFullAsync( pGlobals->Cache );
|
|
}
|
|
}
|
|
|
|
|
|
pGlobals->ListPopulated = FALSE ;
|
|
|
|
pGlobals->ActiveArray = DCacheCopyCacheArray( pGlobals->Cache );
|
|
|
|
if ( pGlobals->ActiveArray )
|
|
{
|
|
DCachePopulateListBoxFromArray( pGlobals->ActiveArray,
|
|
GetDlgItem( hDlg, IDD_LOGON_DOMAIN ),
|
|
NULL );
|
|
}
|
|
else
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
pGlobals->ShowRasBox = FALSE;
|
|
|
|
if (g_Console) {
|
|
|
|
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
TEXT("Software\\Microsoft\\RAS"),
|
|
0,
|
|
KEY_READ,
|
|
& hKey );
|
|
|
|
|
|
if ( err == 0 )
|
|
{
|
|
RegCloseKey( hKey );
|
|
|
|
if ( GetRasDialOutProtocols() )
|
|
{
|
|
if ( ( CacheFlags & DCACHE_MEMBER ) != 0 )
|
|
{
|
|
pGlobals->ShowRasBox = TRUE;
|
|
}
|
|
else
|
|
{
|
|
UNICODE_STRING DnsDomain = { 0 } ;
|
|
|
|
if ( GetPrimaryDomainEx( NULL, &DnsDomain, NULL, NULL ) &&
|
|
( DnsDomain.Buffer != NULL) )
|
|
{ // We are "joined" to a MIT realm
|
|
pGlobals->ShowRasBox = TRUE;
|
|
LocalFree( DnsDomain.Buffer );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// If the audit log is full then display the banner, otherwise
|
|
// load the text from the resource if that gives us a string
|
|
// then set the control.
|
|
//
|
|
// Should neither of these apply then remove the control.
|
|
// The log full info is only displayed at the console so we
|
|
// don't disclose too much info in TS sessions.
|
|
//
|
|
|
|
RemoveLegalBanner = FALSE;
|
|
|
|
if ( pGlobals->AuditLogFull && !GetSystemMetrics(SM_REMOTESESSION))
|
|
{
|
|
if ( LoadString( hDllInstance, IDS_LOGON_LOG_FULL, LogonMsg, MAX_PATH ) )
|
|
{
|
|
SetDlgItemText( hDlg, IDD_LOGON_ANNOUNCE, LogonMsg );
|
|
}
|
|
else
|
|
{
|
|
RemoveLegalBanner = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
String = AllocAndGetProfileString( APPLICATION_NAME,
|
|
LOGON_MSG_KEY, TEXT("") );
|
|
if ( String )
|
|
{
|
|
if ( *String )
|
|
{
|
|
SetDlgItemText( hDlg, IDD_LOGON_ANNOUNCE, String );
|
|
}
|
|
else
|
|
{
|
|
RemoveLegalBanner = TRUE;
|
|
}
|
|
|
|
Free( String );
|
|
}
|
|
else
|
|
{
|
|
RemoveLegalBanner = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( RemoveLegalBanner )
|
|
{
|
|
GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_ANNOUNCE), &rc);
|
|
MoveControls(hDlg, ctrlNoLegalBanner,
|
|
sizeof(ctrlNoLegalBanner)/sizeof(ctrlNoLegalBanner[0]),
|
|
0, rc.top-rc.bottom,
|
|
TRUE);
|
|
|
|
ShowDlgItem(hDlg, IDD_LOGON_ANNOUNCE, FALSE);
|
|
}
|
|
|
|
//
|
|
// Smart Card Specific Stuff:
|
|
//
|
|
|
|
if ( SasType == WLX_SAS_TYPE_SC_INSERT )
|
|
{
|
|
//
|
|
// remove the user name fields
|
|
//
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_NAME), &rc);
|
|
GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_PASSWORD), &rc2);
|
|
|
|
MoveControls(hDlg, ctrlNoUserName,
|
|
sizeof(ctrlNoUserName)/sizeof(ctrlNoUserName[0]),
|
|
0, -(rc2.top-rc.top),
|
|
TRUE);
|
|
|
|
ShowDlgItem(hDlg, IDD_LOGON_NAME_LABEL, FALSE);
|
|
EnableDlgItem(hDlg, IDD_LOGON_NAME_LABEL, FALSE);
|
|
|
|
ShowDlgItem(hDlg, IDD_LOGON_NAME, FALSE);
|
|
EnableDlgItem(hDlg, IDD_LOGON_NAME, FALSE);
|
|
SetDlgItemText( hDlg, IDD_LOGON_NAME, TEXT(""));
|
|
|
|
LogonMsg[0] = 0;
|
|
LoadString(hDllInstance, IDS_PIN, LogonMsg, MAX_PATH);
|
|
SetDlgItemText( hDlg, IDD_LOGON_PASSWORD_LABEL, LogonMsg );
|
|
|
|
pGlobals->SmartCardLogon = TRUE;
|
|
|
|
}
|
|
else
|
|
{
|
|
pGlobals->SmartCardLogon = FALSE;
|
|
}
|
|
|
|
//
|
|
// If this is safe boot and/or we are not part of a domain then lets
|
|
// remove the domain and nix out the RAS box.
|
|
//
|
|
|
|
if ((SafeBootMode == SAFEBOOT_MINIMAL)
|
|
|| (!IsMachineDomainMember())
|
|
|| (SasType == WLX_SAS_TYPE_SC_INSERT)
|
|
|| (ForceNoDomainUI()))
|
|
{
|
|
ShowDlgItem(hDlg, IDD_LOGON_DOMAIN_LABEL, FALSE);
|
|
EnableDlgItem(hDlg, IDD_LOGON_DOMAIN_LABEL, FALSE);
|
|
ShowDlgItem(hDlg, IDD_LOGON_DOMAIN, FALSE);
|
|
EnableDlgItem(hDlg, IDD_LOGON_DOMAIN, FALSE);
|
|
|
|
pGlobals->ShowDomainBox = FALSE;
|
|
|
|
// Shorten the window since the domain box isn't used
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_PASSWORD), &rc);
|
|
GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_DOMAIN), &rc2);
|
|
|
|
MoveControls(hDlg, ctrlNoDomain,
|
|
ARRAYSIZE(ctrlNoDomain),
|
|
0, -(rc2.bottom-rc.bottom),
|
|
TRUE);
|
|
}
|
|
else
|
|
{
|
|
pGlobals->ShowDomainBox = TRUE;
|
|
}
|
|
|
|
|
|
bHasLangIcon = DisplayLanguageIcon(hDlg, LAYOUT_DEF_USER, GetKeyboardLayout(0));
|
|
|
|
//
|
|
// Handle showing the RAS box if needed
|
|
//
|
|
|
|
if ( pGlobals->ShowRasBox )
|
|
{
|
|
RasDisable = GetProfileInt( APPLICATION_NAME, RAS_DISABLE, 0 );
|
|
RasForce = GetProfileInt( APPLICATION_NAME, RAS_FORCE, 0 );
|
|
|
|
if (RasForce)
|
|
{
|
|
CheckDlgButton( hDlg, IDD_LOGON_RASBOX, 1 );
|
|
}
|
|
else
|
|
{
|
|
CheckDlgButton( hDlg, IDD_LOGON_RASBOX, 0 );
|
|
}
|
|
|
|
// SM_CLEANBOOT tells us we are in safe mode. In this case, disable since tapisrv isn't started
|
|
if (RasDisable || RasForce || GetSystemMetrics(SM_CLEANBOOT))
|
|
{
|
|
EnableDlgItem(hDlg, IDD_LOGON_RASBOX, FALSE);
|
|
}
|
|
else
|
|
{
|
|
EnableDlgItem(hDlg, IDD_LOGON_RASBOX, TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If the domain box is hidden, then we'll have to shorten the dialog by the distance
|
|
// between the RAS box and the password box instead of the distance between the
|
|
// RAS box and the domain box since the RAS and Domain boxes will be on top of each other
|
|
BOOL fUsePassword = !pGlobals->ShowDomainBox;
|
|
|
|
CheckDlgButton( hDlg, IDD_LOGON_RASBOX, 0 );
|
|
EnableDlgItem(hDlg, IDD_LOGON_RASBOX, FALSE);
|
|
ShowDlgItem(hDlg, IDD_LOGON_RASBOX, FALSE);
|
|
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, fUsePassword ? IDD_LOGON_PASSWORD : IDD_LOGON_DOMAIN), &rc);
|
|
GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_RASBOX), &rc2);
|
|
if (!bHasLangIcon)
|
|
{
|
|
MoveControls(hDlg, ctrlNoRAS,
|
|
sizeof(ctrlNoRAS)/sizeof(ctrlNoRAS[0]),
|
|
0, -(rc2.bottom-rc.bottom),
|
|
TRUE);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Centre the window on the screen and bring it to the front
|
|
|
|
pGlobals->xBandOffset = 0; // band is not animated yet
|
|
|
|
SizeForBranding(hDlg, TRUE);
|
|
|
|
// Position the window at the same coords as the welcome window
|
|
if ((pGlobals->rcWelcome.right - pGlobals->rcWelcome.left) != 0)
|
|
{
|
|
SetWindowPos(hDlg, NULL, pGlobals->rcWelcome.left, pGlobals->rcWelcome.top,
|
|
0, 0, SWP_NOZORDER | SWP_NOSIZE);
|
|
}
|
|
else
|
|
{
|
|
CentreWindow(hDlg);
|
|
}
|
|
|
|
|
|
//
|
|
// Handle showing and hiding the logon bits
|
|
//
|
|
|
|
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_READ,
|
|
&hKey) == ERROR_SUCCESS)
|
|
{
|
|
DWORD dwType, dwSize = sizeof(ShowOptions);
|
|
|
|
if ((ERROR_SUCCESS != RegQueryValueEx (hKey, SHOW_LOGON_OPTIONS, NULL, &dwType,
|
|
(LPBYTE)&ShowOptions, &dwSize)) ||
|
|
(REG_DWORD != dwType))
|
|
{
|
|
ShowOptions = FALSE; // restore default
|
|
}
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
pGlobals->LogonOptionsShown = TRUE;
|
|
|
|
LogonShowOptions(pGlobals, hDlg, ShowOptions, TRUE);
|
|
|
|
// Success
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************\
|
|
*
|
|
* FUNCTION: LogonShowOptions
|
|
*
|
|
* PURPOSE: Hide the options part of the logon dialog
|
|
*
|
|
* RETURNS: Nothing
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 15-dec-97 daviddv - Created
|
|
*
|
|
\****************************************************************************/
|
|
VOID LogonShowOptions(PGLOBALS pGlobals, HWND hDlg, BOOL fShow, BOOL fSticky)
|
|
{
|
|
HKEY hKey;
|
|
RECT rc, rc2;
|
|
INT dy = 0;
|
|
INT dx = 0;
|
|
TCHAR szBuffer[32] = TEXT("");
|
|
BOOL bHasLangIcon = TRUE;
|
|
DWORD RasDisable;
|
|
DWORD RasForce;
|
|
|
|
if ( pGlobals->LogonOptionsShown != fShow )
|
|
{
|
|
BOOL bShutdownWithoutLogon;
|
|
|
|
//
|
|
// Show/hide domain if it is present in the dialog
|
|
//
|
|
if (pGlobals->ShowDomainBox)
|
|
{
|
|
GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_PASSWORD), &rc);
|
|
GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_DOMAIN), &rc2);
|
|
dy += rc2.bottom-rc.bottom;
|
|
}
|
|
|
|
//
|
|
// If RAS is present then lets ensure that we remove that.
|
|
//
|
|
|
|
if (GetKeyboardLayoutList(0,NULL) < 2)
|
|
{
|
|
bHasLangIcon = FALSE;
|
|
}
|
|
|
|
if ( pGlobals->ShowRasBox || bHasLangIcon)
|
|
{
|
|
// Since the domain box may be hidden with the RAS box directly over
|
|
// top of it, we may need to use the space between the RAS box and the password
|
|
// box
|
|
BOOL fUsePassword = !pGlobals->ShowDomainBox;
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, fUsePassword ? IDD_LOGON_PASSWORD : IDD_LOGON_DOMAIN), &rc);
|
|
GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_RASBOX), &rc2);
|
|
dy += rc2.bottom-rc.bottom;
|
|
}
|
|
|
|
MoveControls(hDlg, ctrlNoRAS,
|
|
sizeof(ctrlNoRAS)/sizeof(ctrlNoRAS[0]),
|
|
0, fShow ? dy:-dy,
|
|
TRUE);
|
|
|
|
|
|
// Handle showing or hiding the shutdown button
|
|
// and moving other controls.
|
|
ShowDlgItem(hDlg, IDD_KBLAYOUT_ICON, fShow);
|
|
EnableWindow(GetDlgItem(hDlg, IDD_KBLAYOUT_ICON), fShow);
|
|
ShowDlgItem(hDlg, IDD_LOGON_SHUTDOWN, fShow);
|
|
|
|
// Move the OK and Cancel buttons over if we are hiding shutdown
|
|
// ..Calculate one "button space". Assumes shutdown will always be on the left of options
|
|
GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_SHUTDOWN), &rc);
|
|
GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_OPTIONS), &rc2);
|
|
|
|
dx = rc2.left - rc.left;
|
|
|
|
// Move OK and Cancel left or right 1 button space
|
|
MoveControls(hDlg, ctrlNoShutdown,
|
|
sizeof(ctrlNoShutdown)/sizeof(ctrlNoShutdown[0]),
|
|
fShow ? -dx:dx, 0,
|
|
FALSE);
|
|
|
|
//
|
|
// if ShutdownWithoutLogon, use the proper 3 buttons: OK, Shutdown and Cancel
|
|
// instead of the 2 buttons OK and Cancel
|
|
//
|
|
|
|
|
|
|
|
if ( SafeBootMode == SAFEBOOT_MINIMAL )
|
|
{
|
|
bShutdownWithoutLogon = TRUE ;
|
|
}
|
|
else if (IsthisUnlockWindowsDialog() || !IsActiveConsoleSession())
|
|
{
|
|
bShutdownWithoutLogon = FALSE ;
|
|
}
|
|
else
|
|
{
|
|
bShutdownWithoutLogon = ReadWinlogonBoolValue(SHUTDOWN_WITHOUT_LOGON_KEY, TRUE);
|
|
}
|
|
|
|
|
|
EnableDlgItem(hDlg, IDD_LOGON_SHUTDOWN, (fShow) &&
|
|
(bShutdownWithoutLogon));
|
|
|
|
|
|
if ( pGlobals->ShowRasBox )
|
|
{
|
|
ShowDlgItem(hDlg, IDD_LOGON_RASBOX, fShow);
|
|
RasDisable = GetProfileInt(APPLICATION_NAME, RAS_DISABLE,0);
|
|
RasForce = GetProfileInt(APPLICATION_NAME, RAS_FORCE, 0);
|
|
|
|
// Never enable RAS for cleanboot
|
|
if (!GetSystemMetrics(SM_CLEANBOOT) && !RasForce && !RasDisable)
|
|
{
|
|
EnableWindow(GetDlgItem(hDlg, IDD_LOGON_RASBOX), fShow);
|
|
}
|
|
}
|
|
|
|
if ( pGlobals->ShowDomainBox )
|
|
{
|
|
ShowDlgItem(hDlg, IDD_LOGON_DOMAIN_LABEL, fShow);
|
|
EnableWindow(GetDlgItem(hDlg, IDD_LOGON_DOMAIN_LABEL), fShow);
|
|
ShowDlgItem(hDlg, IDD_LOGON_DOMAIN, fShow);
|
|
EnableWindow(GetDlgItem(hDlg, IDD_LOGON_DOMAIN), fShow);
|
|
}
|
|
|
|
if ( fSticky )
|
|
{
|
|
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
RegSetValueEx(hKey, SHOW_LOGON_OPTIONS, 0, REG_DWORD,
|
|
(LPBYTE)&fShow, sizeof(fShow));
|
|
RegCloseKey (hKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Change the options button to reflect the open/close state
|
|
//
|
|
|
|
LoadString(hDllInstance, fShow ? IDS_LESSOPTIONS:IDS_MOREOPTIONS,
|
|
szBuffer, sizeof(szBuffer)/sizeof(szBuffer[0]));
|
|
|
|
SetDlgItemText(hDlg, IDD_LOGON_OPTIONS, szBuffer);
|
|
|
|
pGlobals->LogonOptionsShown = fShow;
|
|
|
|
// Enable or disable the domain box depending on whether a UPN name has been typed
|
|
EnableDomainForUPN(GetDlgItem(hDlg, IDD_LOGON_NAME), GetDlgItem(hDlg, IDD_LOGON_DOMAIN));
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: AttemptLogonSetControls
|
|
*
|
|
* PURPOSE: Sets up the logon UI to animating and controls to the
|
|
* correct state.
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 02-05-98 diz Created
|
|
*
|
|
\***************************************************************************/
|
|
|
|
VOID AttemptLogonSetControls(
|
|
PGLOBALS pGlobals,
|
|
HWND hDlg
|
|
)
|
|
{
|
|
DWORD RasDisable;
|
|
static BOOL sbRasBoxOriginalyEnabled;
|
|
static BOOL sbShutDownOriginallyEnabled;
|
|
|
|
RtlEnterCriticalSection( &pGlobals->csGlobals );
|
|
|
|
EnableDlgItem(hDlg, IDD_LOGON_NAME_LABEL, !pGlobals->LogonInProgress);
|
|
EnableDlgItem(hDlg, IDD_LOGON_NAME, !pGlobals->LogonInProgress);
|
|
EnableDlgItem(hDlg, IDD_LOGON_PASSWORD_LABEL, !pGlobals->LogonInProgress);
|
|
EnableDlgItem(hDlg, IDD_LOGON_PASSWORD, !pGlobals->LogonInProgress);
|
|
EnableDlgItem(hDlg, IDD_LOGON_DOMAIN_LABEL, !pGlobals->LogonInProgress);
|
|
|
|
EnableDlgItem(hDlg, IDD_LOGON_DOMAIN, !pGlobals->LogonInProgress);
|
|
|
|
// If no logon is in progress, we want to enable domain box based on whether
|
|
// a UPN has been typed
|
|
if (!pGlobals->LogonInProgress)
|
|
{
|
|
EnableDomainForUPN(GetDlgItem(hDlg, IDD_LOGON_NAME), GetDlgItem(hDlg, IDD_LOGON_DOMAIN));
|
|
}
|
|
|
|
//
|
|
// MakarP: we should not enable all these control when !pGlobals->LogonInProgress, they should really be reverted back to their original state.
|
|
// but for now I am just looking after IDD_LOGON_RASBOX in remote connection cases to fix bug #267270
|
|
//
|
|
if (pGlobals->LogonInProgress)
|
|
{
|
|
sbRasBoxOriginalyEnabled = IsWindowEnabled(GetDlgItem(hDlg, IDD_LOGON_RASBOX));
|
|
RasDisable = GetProfileInt(APPLICATION_NAME, RAS_DISABLE, 0);
|
|
EnableDlgItem(hDlg, IDD_LOGON_RASBOX, !RasDisable && !pGlobals->LogonInProgress);
|
|
|
|
sbShutDownOriginallyEnabled = IsWindowEnabled(GetDlgItem(hDlg, IDD_LOGON_SHUTDOWN));
|
|
EnableDlgItem(hDlg, IDD_LOGON_SHUTDOWN, !pGlobals->LogonInProgress);
|
|
}
|
|
else
|
|
{
|
|
EnableDlgItem(hDlg, IDD_LOGON_RASBOX, sbRasBoxOriginalyEnabled);
|
|
EnableDlgItem(hDlg, IDD_LOGON_SHUTDOWN, sbShutDownOriginallyEnabled);
|
|
}
|
|
|
|
|
|
|
|
EnableDlgItem(hDlg, IDD_KBLAYOUT_ICON, !pGlobals->LogonInProgress);
|
|
EnableDlgItem(hDlg, IDD_LOGON_OPTIONS, !pGlobals->LogonInProgress);
|
|
|
|
//
|
|
// if ShutdownWithoutLogon, use the proper 3 buttons: OK, Shutdown and Cancel
|
|
// instead of the 2 buttons OK and Cancel
|
|
//
|
|
|
|
|
|
EnableDlgItem(hDlg, IDOK, !pGlobals->LogonInProgress);
|
|
|
|
//
|
|
// the logic of enabling the CANCEL button is as follows
|
|
// - if a logon is in progress always disable it (not allowed to cancel)
|
|
// - else if a SC logon always enable it (always allow to get to CAD)
|
|
// - else gray it only when DisableCAD and is set and we're in
|
|
// the active session (i.e. TS always allows Cancel)
|
|
//
|
|
if( pGlobals->LogonInProgress )
|
|
{
|
|
EnableDlgItem(hDlg, IDCANCEL, FALSE);
|
|
}
|
|
else
|
|
{
|
|
if( pGlobals->SmartCardLogon )
|
|
{
|
|
EnableDlgItem(hDlg, IDCANCEL, TRUE);
|
|
}
|
|
else
|
|
{
|
|
EnableDlgItem(hDlg, IDCANCEL,
|
|
!(GetDisableCad(pGlobals) &&
|
|
IsActiveConsoleSession()) );
|
|
}
|
|
}
|
|
|
|
RtlLeaveCriticalSection( &pGlobals->csGlobals );
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: AttemptLogon
|
|
*
|
|
* PURPOSE: Tries to the log the user on using the current values in the
|
|
* logon dialog controls
|
|
*
|
|
* RETURNS: MSGINA_DLG_SUCCESS - the user was logged on successfully
|
|
* MSGINA_DLG_FAILURE - the logon failed,
|
|
* DLG_INTERRUPTED() - a set defined in winlogon.h
|
|
*
|
|
* NOTES: If the logon is successful, the global structure is filled in
|
|
* with the logon information.
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 12-09-91 Davidc Created.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
INT_PTR
|
|
AttemptLogon(
|
|
HWND hDlg
|
|
)
|
|
{
|
|
PGLOBALS pGlobals = (PGLOBALS)GetWindowLongPtr(hDlg, GWLP_USERDATA);
|
|
PWCHAR UserName = pGlobals->UserName;
|
|
PWCHAR Domain = pGlobals->Domain;
|
|
PWCHAR Password = pGlobals->Password;
|
|
PDOMAIN_CACHE_ENTRY Entry ;
|
|
RECT rc;
|
|
HANDLE hThread;
|
|
DWORD tid;
|
|
BOOL timeout;
|
|
PUCHAR Dummy;
|
|
BOOL RasBox;
|
|
DWORD dwAnimationTimeSlice;
|
|
|
|
UserName[0] = TEXT('\0');
|
|
Domain[0] = TEXT('\0');
|
|
Password[0] = TEXT('\0');
|
|
|
|
//
|
|
// Hide the password so it doesn't make it to the pagefile in
|
|
// cleartext. Do this before getting the username and password
|
|
// so that it can't easily be identified (by association with
|
|
// the username and password) if we should crash or be rebooted
|
|
// before getting a chance to encode it.
|
|
//
|
|
|
|
GetDlgItemText(hDlg, IDD_LOGON_PASSWORD, Password, MAX_STRING_BYTES);
|
|
RtlInitUnicodeString(&pGlobals->PasswordString, Password);
|
|
pGlobals->Seed = 0; // Causes the encode routine to assign a seed
|
|
HidePassword( &pGlobals->Seed, &pGlobals->PasswordString );
|
|
|
|
|
|
//
|
|
// Now get the username and domain
|
|
//
|
|
|
|
if ( pGlobals->SmartCardLogon == FALSE )
|
|
{
|
|
HWND hwndDomain = GetDlgItem(hDlg, IDD_LOGON_DOMAIN);
|
|
|
|
if (hwndDomain != NULL)
|
|
{
|
|
INT iDomainSel = (INT)SendMessage(hwndDomain, CB_GETCURSEL, 0, 0);
|
|
|
|
GetDlgItemText(hDlg, IDD_LOGON_NAME, UserName, MAX_STRING_BYTES);
|
|
|
|
//
|
|
// is this the magical "this computer" entry???
|
|
// If so, set local domain flag used by password UI to show/notshow password restore
|
|
//
|
|
|
|
pGlobals->fLocalDomain = FALSE;
|
|
Entry = (PDOMAIN_CACHE_ENTRY) SendMessage( hwndDomain, CB_GETITEMDATA, (WPARAM)iDomainSel, 0);
|
|
if (CB_ERR != (ULONG_PTR) Entry)
|
|
{
|
|
if (NULL != Entry)
|
|
{
|
|
if (Entry->Type == DomainMachine)
|
|
{
|
|
pGlobals->fLocalDomain = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Entry = (PDOMAIN_CACHE_ENTRY) CB_ERR;
|
|
}
|
|
if ( (Entry != (PDOMAIN_CACHE_ENTRY) CB_ERR) && (NULL != Entry))
|
|
{
|
|
// MAX_STRING_BYTES is the size of pGlobals->Domain (WlxInitialize)
|
|
// Truncation should never occur
|
|
lstrcpyn( Domain, Entry->FlatName.Buffer, MAX_STRING_BYTES );
|
|
}
|
|
else
|
|
{
|
|
Domain[0] = L'\0';
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
UserName[0] = TEXT('\0');
|
|
Domain[0] = TEXT('\0') ;
|
|
}
|
|
|
|
// If we are forcing a NoDomainUI, populate the domain with the local machine name now
|
|
if (ForceNoDomainUI())
|
|
{
|
|
DWORD chSize = MAX_STRING_BYTES;
|
|
pGlobals->fLocalDomain = TRUE;
|
|
|
|
if (GetComputerName(Domain, &chSize))
|
|
{
|
|
NOTHING;
|
|
}
|
|
else
|
|
{
|
|
*Domain = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If there is a at-sign in the name, assume that means that a UPN logon
|
|
// attempt is being made. Set the domain to NULL.
|
|
//
|
|
|
|
if ( wcspbrk( UserName, L"@\\" ) )
|
|
{
|
|
Domain[0] = TEXT('\0');
|
|
}
|
|
|
|
RtlInitUnicodeString(&pGlobals->UserNameString, UserName);
|
|
RtlInitUnicodeString(&pGlobals->DomainString, Domain);
|
|
|
|
//
|
|
// Ok, is the RASbox checked?
|
|
//
|
|
|
|
RasBox = IsDlgButtonChecked( hDlg, IDD_LOGON_RASBOX );
|
|
pGlobals->RasUsed = FALSE;
|
|
|
|
if ( RasBox == BST_CHECKED )
|
|
{
|
|
//
|
|
// Reset the current timeout so that they neatly clean up before
|
|
// winlogon up and blows them away.
|
|
//
|
|
|
|
pWlxFuncs->WlxSetTimeout( pGlobals->hGlobalWlx, 5 * 60 );
|
|
|
|
if ( !PopupRasPhonebookDlg( hDlg, pGlobals, &timeout) )
|
|
{
|
|
return( MSGINA_DLG_FAILURE );
|
|
}
|
|
|
|
pGlobals->RasUsed = TRUE;
|
|
|
|
//
|
|
// Reinitialize strings in case they've changed
|
|
//
|
|
|
|
RtlInitUnicodeString( &pGlobals->UserNameString, UserName );
|
|
|
|
//
|
|
// Ping Netlogon to allow us to go out on the net again...
|
|
//
|
|
|
|
I_NetLogonControl2(NULL,
|
|
NETLOGON_CONTROL_TRANSPORT_NOTIFY,
|
|
1, (LPBYTE) &Dummy, &Dummy );
|
|
|
|
Sleep ((DWORD) ReadWinlogonBoolValue(TEXT("RASSleepTime"), 3000));
|
|
RefreshPolicy(TRUE);
|
|
}
|
|
|
|
//
|
|
// Process arguments before kicking off the thread
|
|
//
|
|
pGlobals->hwndLogon = hDlg;
|
|
|
|
RtlEnterCriticalSection( &pGlobals->csGlobals );
|
|
pGlobals->LogonInProgress = TRUE ;
|
|
RtlLeaveCriticalSection( &pGlobals->csGlobals );
|
|
|
|
GetClientRect(hDlg, &rc);
|
|
pGlobals->cxBand = rc.right-rc.left;
|
|
|
|
dwAnimationTimeSlice = GetAnimationTimeInterval(pGlobals);
|
|
|
|
// setup the progress timer
|
|
SetTimer(hDlg, 0, dwAnimationTimeSlice, NULL);
|
|
|
|
//
|
|
// Kick off real logon thread
|
|
//
|
|
|
|
// Set timeout to infinite while attempting to logon
|
|
pWlxFuncs->WlxSetTimeout( pGlobals->hGlobalWlx, TIMEOUT_NONE );
|
|
|
|
hThread = CreateThread( NULL, 0,
|
|
AttemptLogonThread,
|
|
pGlobals,
|
|
0, &tid );
|
|
|
|
if (hThread)
|
|
{
|
|
CloseHandle( hThread );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// CreateThread failed, likely because of low memory.
|
|
// Inform the user.
|
|
//
|
|
|
|
PostFailedLogonMessage(pGlobals->hwndLogon,
|
|
pGlobals,
|
|
GetLastError(),
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
RtlEnterCriticalSection( &pGlobals->csGlobals );
|
|
pGlobals->LogonInProgress = FALSE ;
|
|
RtlLeaveCriticalSection( &pGlobals->csGlobals );
|
|
return MSGINA_DLG_FAILURE ;
|
|
}
|
|
|
|
AttemptLogonSetControls(pGlobals, hDlg);
|
|
|
|
return MSGINA_DLG_SUCCESS;
|
|
}
|
|
|
|
BOOL ReplacedPossibleDisplayName (WCHAR *pszUsername, int nUserMax)
|
|
|
|
{
|
|
BOOL fReplaced;
|
|
DWORD dwIndex, dwReturnedEntryCount;
|
|
NET_API_STATUS nasCode;
|
|
NET_DISPLAY_USER *pNDU;
|
|
|
|
fReplaced = FALSE;
|
|
if (*pszUsername) // Name is not empty (Admin has empty full name by default...)
|
|
{
|
|
dwIndex = 0;
|
|
nasCode = NetQueryDisplayInformation(NULL,
|
|
1,
|
|
dwIndex,
|
|
1,
|
|
sizeof(NET_DISPLAY_USER),
|
|
&dwReturnedEntryCount,
|
|
(void**)&pNDU);
|
|
while (!fReplaced &&
|
|
(dwReturnedEntryCount > 0) &&
|
|
(NERR_Success == nasCode) || (ERROR_MORE_DATA == nasCode))
|
|
{
|
|
fReplaced = (lstrcmpiW(pNDU->usri1_full_name, pszUsername) == 0);
|
|
if (fReplaced)
|
|
{
|
|
lstrcpyn(pszUsername, pNDU->usri1_name, nUserMax); // Zero terminated
|
|
}
|
|
nasCode = NetApiBufferFree(pNDU);
|
|
if (!fReplaced)
|
|
{
|
|
nasCode = NetQueryDisplayInformation(NULL,
|
|
1,
|
|
++dwIndex,
|
|
1,
|
|
sizeof(NET_DISPLAY_USER),
|
|
&dwReturnedEntryCount,
|
|
(void**)&pNDU);
|
|
}
|
|
}
|
|
}
|
|
return(fReplaced);
|
|
}
|
|
|
|
BOOL ReplacedLogonName (PGLOBALS pGlobals)
|
|
|
|
{
|
|
BOOL fReplaced;
|
|
|
|
// MAX_STRING_BYTES is the size of pGlobals->UserName (WlxInitialize)
|
|
fReplaced = ReplacedPossibleDisplayName(pGlobals->UserName, MAX_STRING_BYTES);
|
|
if (fReplaced)
|
|
{
|
|
RtlInitUnicodeString(&pGlobals->UserNameString, pGlobals->UserName);
|
|
}
|
|
return(fReplaced);
|
|
}
|
|
|
|
DWORD
|
|
AttemptLogonThread(
|
|
PGLOBALS pGlobals
|
|
)
|
|
{
|
|
STRING PackageName;
|
|
PSID LogonSid;
|
|
PSID DuplicatedLogonSID;
|
|
LUID LogonId = { 0, 0 };
|
|
HANDLE UserToken = NULL;
|
|
HANDLE RestrictedToken;
|
|
BOOL PasswordExpired, ChangedLogonName;
|
|
NTSTATUS FinalStatus;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
NTSTATUS SubStatus = STATUS_SUCCESS;
|
|
INT_PTR Result = MSGINA_DLG_FAILURE;
|
|
ULONG LogonPackage;
|
|
BYTE GroupsBuffer[sizeof(TOKEN_GROUPS)+sizeof(SID_AND_ATTRIBUTES)];
|
|
PTOKEN_GROUPS TokenGroups = (PTOKEN_GROUPS) GroupsBuffer;
|
|
PVOID AuthInfo ;
|
|
ULONG AuthInfoSize ;
|
|
UCHAR UserBuffer[ SID_MAX_SUB_AUTHORITIES * sizeof( DWORD ) + 8 + sizeof( TOKEN_USER ) ];
|
|
PTOKEN_USER pTokenUser ;
|
|
ULONG TokenInfoSize ;
|
|
PUCHAR SmartCardInfo ;
|
|
SECURITY_LOGON_TYPE logonType;
|
|
PWLX_SC_NOTIFICATION_INFO ScInfo = NULL ;
|
|
|
|
#ifdef SMARTCARD_DOGFOOD
|
|
DWORD StartTime = 0, EndTime = 0;
|
|
#endif
|
|
|
|
//
|
|
// Store the logon time
|
|
// Do this before calling Lsa so we know if logon is successful that
|
|
// the password-must-change time will be greater than this time.
|
|
// If we grabbed this time after calling the lsa, this might not be true.
|
|
//
|
|
|
|
|
|
if ( IsActiveConsoleSession() )
|
|
{
|
|
// this is the console logon;
|
|
logonType = Interactive;
|
|
}
|
|
else
|
|
{
|
|
// remote sessions user must have the SeRemoteInteractiveLogonRight right which
|
|
// is granted to a user due to their membership in the new Remote-Desktop Users group.
|
|
logonType = RemoteInteractive;
|
|
}
|
|
|
|
GetSystemTimeAsFileTime( (LPFILETIME) &pGlobals->LogonTime );
|
|
|
|
DebugLog((DEB_TRACE, "In Attempt Logon!\n"));
|
|
|
|
if ( pGlobals->RasUsed )
|
|
{
|
|
if ( DCacheGetCacheState( pGlobals->Cache ) < DomainCacheRegistryCache )
|
|
{
|
|
//
|
|
// We are using really stale data. Poke the cache to get it to use the
|
|
// now made RAS connection
|
|
//
|
|
|
|
DCacheUpdateMinimal( pGlobals->Cache, NULL, TRUE );
|
|
}
|
|
}
|
|
|
|
SetupCursor( TRUE );
|
|
|
|
FinalStatus = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Generate a unique sid for this logon.
|
|
// Duplicate the SID. It is possible that the function that called
|
|
// the thread (and created the SID originally) may return causing
|
|
// the SID to be freed while this thread is still running.
|
|
// (see bug# 478186).
|
|
// the solution was to duplicate the SID here and free it at the end
|
|
// This still leaves a "small" window between starting the thread
|
|
// and duplicating the token where freeing may potentially cause the
|
|
// same problem (if the pGlobal->LogonSID is freed but not NULL'ed in
|
|
// which case duplication will fail)
|
|
// Notes:
|
|
// - if the duplication fails abort this
|
|
// - there is no need to actually verify the SID on free time
|
|
// at this point.
|
|
//
|
|
LogonSid = DuplicatedLogonSID = DuplicateSID(pGlobals->LogonSid);
|
|
if( NULL == LogonSid )
|
|
{
|
|
FinalStatus = STATUS_NO_MEMORY ;
|
|
Status = FinalStatus ;
|
|
}
|
|
else
|
|
{
|
|
if ( !wcspbrk( pGlobals->UserName, L"@\\" ) &&
|
|
wcschr( pGlobals->UserName, L'/' ))
|
|
{
|
|
FinalStatus = STATUS_LOGON_FAILURE ;
|
|
Status = FinalStatus ;
|
|
}
|
|
}
|
|
|
|
// clear card and reader name
|
|
pGlobals->Smartcard[0] = TEXT('\0');
|
|
pGlobals->SmartcardReader[0] = TEXT('\0');
|
|
|
|
if ( NT_SUCCESS( FinalStatus ) )
|
|
{
|
|
if ( pGlobals->SmartCardLogon )
|
|
{
|
|
pGlobals->AuthenticationPackage = pGlobals->SmartCardLogonPackage ;
|
|
}
|
|
else
|
|
{
|
|
pGlobals->AuthenticationPackage = pGlobals->PasswordLogonPackage ;
|
|
|
|
}
|
|
|
|
if ( pGlobals->SmartCardLogon )
|
|
{
|
|
pWlxFuncs->WlxGetOption( pGlobals->hGlobalWlx,
|
|
WLX_OPTION_SMART_CARD_INFO,
|
|
(ULONG_PTR *) &ScInfo );
|
|
|
|
if ( !ScInfo )
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
|
|
SmartCardInfo = ScBuildLogonInfo(
|
|
ScInfo->pszCard,
|
|
ScInfo->pszReader,
|
|
ScInfo->pszContainer,
|
|
ScInfo->pszCryptoProvider );
|
|
|
|
if(ScInfo->pszCard && ScInfo->pszReader) {
|
|
|
|
lstrcpyn(
|
|
pGlobals->Smartcard,
|
|
ScInfo->pszCard,
|
|
sizeof(pGlobals->Smartcard) / sizeof(TCHAR)
|
|
);
|
|
|
|
lstrcpyn(
|
|
pGlobals->SmartcardReader,
|
|
ScInfo->pszReader,
|
|
sizeof(pGlobals->SmartcardReader) / sizeof(TCHAR)
|
|
);
|
|
|
|
}
|
|
|
|
#ifndef SMARTCARD_DOGFOOD
|
|
LocalFree( ScInfo );
|
|
#endif
|
|
|
|
AuthInfo = FormatSmartCardCredentials(
|
|
&pGlobals->PasswordString,
|
|
SmartCardInfo,
|
|
FALSE,
|
|
NULL,
|
|
&AuthInfoSize );
|
|
|
|
LocalFree( SmartCardInfo );
|
|
|
|
}
|
|
else
|
|
{
|
|
AuthInfo = FormatPasswordCredentials(
|
|
&pGlobals->UserNameString,
|
|
&pGlobals->DomainString,
|
|
&pGlobals->PasswordString,
|
|
FALSE,
|
|
NULL,
|
|
&AuthInfoSize );
|
|
|
|
}
|
|
|
|
//
|
|
// Actually try to logon the user
|
|
//
|
|
|
|
#ifdef SMARTCARD_DOGFOOD
|
|
StartTime = GetTickCount();
|
|
#endif
|
|
|
|
FinalStatus = WinLogonUser(
|
|
pGlobals->LsaHandle,
|
|
pGlobals->AuthenticationPackage,
|
|
logonType,
|
|
AuthInfo,
|
|
AuthInfoSize,
|
|
LogonSid,
|
|
&LogonId,
|
|
&UserToken,
|
|
&pGlobals->UserProcessData.Quotas,
|
|
(PVOID *)&pGlobals->Profile,
|
|
&pGlobals->ProfileLength,
|
|
&SubStatus,
|
|
&pGlobals->OptimizedLogonStatus);
|
|
|
|
#ifdef SMARTCARD_DOGFOOD
|
|
EndTime = GetTickCount();
|
|
#endif
|
|
|
|
Status = FinalStatus;
|
|
}
|
|
|
|
SetupCursor( FALSE );
|
|
|
|
RtlEnterCriticalSection( &pGlobals->csGlobals );
|
|
pGlobals->LogonInProgress = FALSE;
|
|
RtlLeaveCriticalSection( &pGlobals->csGlobals );
|
|
|
|
DebugLog((DEB_TRACE, "WinLogonUser returned %#x\n", Status));
|
|
|
|
PasswordExpired = (((Status == STATUS_ACCOUNT_RESTRICTION) && (SubStatus == STATUS_PASSWORD_EXPIRED)) ||
|
|
(Status == STATUS_PASSWORD_MUST_CHANGE));
|
|
|
|
//
|
|
// If the account has expired we let them change their password and
|
|
// automatically retry the logon with the new password.
|
|
//
|
|
|
|
if (PasswordExpired)
|
|
{
|
|
_Shell_LogonDialog_HideUIHost();
|
|
|
|
if( pGlobals->SmartCardLogon )
|
|
{
|
|
//
|
|
// this was a SC logon that failed because the account had
|
|
// a password that expired. Put an error message and exit
|
|
//
|
|
TimeoutMessageBox(pGlobals->hwndLogon, pGlobals,
|
|
IDS_LOGON_SMARTCARD_PWD_CHANGE,
|
|
IDS_LOGON_MESSAGE,
|
|
MB_OK | MB_ICONSTOP | MB_SETFOREGROUND,
|
|
LOGON_TIMEOUT);
|
|
Result = MSGINA_DLG_FAILURE;
|
|
goto exit;
|
|
}
|
|
|
|
if (Status == STATUS_PASSWORD_MUST_CHANGE)
|
|
{
|
|
|
|
Result = TimeoutMessageBox(pGlobals->hwndLogon, pGlobals, IDS_PASSWORD_MUST_CHANGE,
|
|
IDS_LOGON_MESSAGE,
|
|
MB_OK | MB_ICONSTOP | MB_SETFOREGROUND,
|
|
LOGON_TIMEOUT);
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
Result = TimeoutMessageBox(pGlobals->hwndLogon, pGlobals, IDS_PASSWORD_EXPIRED,
|
|
IDS_LOGON_MESSAGE,
|
|
MB_OK | MB_ICONSTOP | MB_SETFOREGROUND,
|
|
LOGON_TIMEOUT);
|
|
|
|
}
|
|
|
|
if (DLG_INTERRUPTED(Result) || (WLX_DLG_INPUT_TIMEOUT == Result))
|
|
goto exit;
|
|
|
|
//
|
|
// Copy the old password for mpr notification later
|
|
//
|
|
|
|
RevealPassword( &pGlobals->PasswordString );
|
|
// pGlobals->Password has the same size as pGlobals->OldPassword (WlxInitialize)
|
|
// so no need to zero terminate
|
|
wcsncpy(pGlobals->OldPassword, pGlobals->Password, MAX_STRING_BYTES);
|
|
pGlobals->OldSeed = 0;
|
|
RtlInitUnicodeString(&pGlobals->OldPasswordString, pGlobals->OldPassword);
|
|
HidePassword( &pGlobals->OldSeed, &pGlobals->OldPasswordString);
|
|
pGlobals->OldPasswordPresent = 1;
|
|
|
|
//
|
|
// Let the user change their password
|
|
//
|
|
|
|
LogonPackage = pGlobals->AuthenticationPackage ;
|
|
|
|
RtlInitString(&PackageName, MSV1_0_PACKAGE_NAME );
|
|
Status = LsaLookupAuthenticationPackage (
|
|
pGlobals->LsaHandle,
|
|
&PackageName,
|
|
&pGlobals->AuthenticationPackage
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
DebugLog((DEB_ERROR, "Failed to find %s authentication package, status = 0x%lx",
|
|
MSV1_0_PACKAGE_NAME, Status));
|
|
|
|
Result = MSGINA_DLG_FAILURE;
|
|
goto exit;
|
|
}
|
|
|
|
|
|
Result = ChangePasswordLogon(pGlobals->hwndLogon, pGlobals,
|
|
pGlobals->UserName,
|
|
pGlobals->Domain,
|
|
pGlobals->Password);
|
|
|
|
pGlobals->AuthenticationPackage = LogonPackage ;
|
|
|
|
if (DLG_INTERRUPTED(Result))
|
|
goto exit;
|
|
|
|
if (Result == MSGINA_DLG_FAILURE)
|
|
{
|
|
// The user doesn't want to, or failed to change their password.
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Special handling for failed logon on personal or professional
|
|
// machines that are NOT joined to a domain. In this case it's
|
|
// probably a user who disabled friendly UI and only knows of
|
|
// their "display name" not their real "logon name". This
|
|
// transparently maps one to the other to allow logons using
|
|
// the "display name".
|
|
|
|
ChangedLogonName = ((FinalStatus == STATUS_LOGON_FAILURE) &&
|
|
(IsOS(OS_PERSONAL) || IsOS(OS_PROFESSIONAL)) &&
|
|
!IsMachineDomainMember() &&
|
|
ReplacedLogonName(pGlobals));
|
|
|
|
if (PasswordExpired || ChangedLogonName)
|
|
{
|
|
|
|
//
|
|
// Retry the logon with the changed password
|
|
//
|
|
|
|
//
|
|
// Generate a unique sid for this logon
|
|
//
|
|
LogonSid = DuplicatedLogonSID;
|
|
|
|
AuthInfo = FormatPasswordCredentials(
|
|
&pGlobals->UserNameString,
|
|
&pGlobals->DomainString,
|
|
&pGlobals->PasswordString,
|
|
FALSE,
|
|
NULL,
|
|
&AuthInfoSize );
|
|
|
|
|
|
Status = WinLogonUser(
|
|
pGlobals->LsaHandle,
|
|
pGlobals->AuthenticationPackage,
|
|
logonType,
|
|
AuthInfo,
|
|
AuthInfoSize,
|
|
LogonSid,
|
|
&LogonId,
|
|
&UserToken,
|
|
&pGlobals->UserProcessData.Quotas,
|
|
(PVOID *)&pGlobals->Profile,
|
|
&pGlobals->ProfileLength,
|
|
&SubStatus,
|
|
&pGlobals->OptimizedLogonStatus);
|
|
|
|
}
|
|
|
|
//
|
|
// Deal with a terminally failed logon attempt
|
|
//
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// Do lockout processing
|
|
//
|
|
|
|
LockoutHandleFailedLogon(pGlobals);
|
|
|
|
Result = MSGINA_DLG_FAILEDMSGSENT;
|
|
|
|
PostFailedLogonMessage(pGlobals->hwndLogon, pGlobals, Status, SubStatus, pGlobals->UserName, pGlobals->Domain);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
|
|
//
|
|
// The user logged on successfully
|
|
//
|
|
|
|
|
|
//
|
|
// Do lockout processing
|
|
//
|
|
|
|
LockoutHandleSuccessfulLogon(pGlobals);
|
|
|
|
|
|
|
|
//
|
|
// If the audit log is full, check they're an admin
|
|
//
|
|
|
|
if (pGlobals->AuditLogFull)
|
|
{
|
|
|
|
//
|
|
// The audit log is full, so only administrators are allowed to logon.
|
|
//
|
|
|
|
if (!UserToken || !TestTokenForAdmin(UserToken))
|
|
{
|
|
|
|
//
|
|
// The user is not an administrator, boot 'em.
|
|
//
|
|
|
|
LsaFreeReturnBuffer(pGlobals->Profile);
|
|
pGlobals->Profile = NULL;
|
|
NtClose(UserToken);
|
|
|
|
Result = MSGINA_DLG_FAILEDMSGSENT;
|
|
|
|
// Post a specific substatus so we can display a meaningful error message
|
|
PostFailedLogonMessage(pGlobals->hwndLogon, pGlobals, STATUS_LOGON_FAILURE, IDS_LOGON_LOG_FULL, pGlobals->UserName, pGlobals->Domain);
|
|
|
|
goto exit;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If we are in a session, we didn't display the log full onfo on the welcome
|
|
// screen, so tell the admin
|
|
//
|
|
|
|
if (GetSystemMetrics(SM_REMOTESESSION))
|
|
{
|
|
TimeoutMessageBox(
|
|
pGlobals->hwndLogon,
|
|
pGlobals,
|
|
IDS_LOGON_LOG_FULL_ADMIN,
|
|
IDS_LOGON_MESSAGE,
|
|
MB_OK | MB_ICONSTOP | MB_SETFOREGROUND,
|
|
TIMEOUT_CURRENT);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Force smart card logon for normal boot
|
|
//
|
|
if(!pGlobals->SmartCardLogon &&
|
|
(SafeBootMode != SAFEBOOT_MINIMAL) && (SafeBootMode != SAFEBOOT_DSREPAIR) &&
|
|
GetSCForceOption() )
|
|
{
|
|
//
|
|
// not a safe boot - boot 'em.
|
|
//
|
|
LsaFreeReturnBuffer(pGlobals->Profile);
|
|
pGlobals->Profile = NULL;
|
|
NtClose(UserToken);
|
|
|
|
Result = MSGINA_DLG_FAILEDMSGSENT;
|
|
|
|
// Post a specific substatus so we can display a meaningful error message
|
|
PostFailedLogonMessage(pGlobals->hwndLogon, pGlobals,
|
|
STATUS_LOGON_FAILURE, IDS_LOGON_SC_REQUIRED,
|
|
pGlobals->UserName, pGlobals->Domain);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Hide ourselves before letting other credential managers put
|
|
// up dialogs
|
|
//
|
|
|
|
#if 0
|
|
ShowWindow(hDlg, SW_HIDE);
|
|
#endif
|
|
|
|
//
|
|
// Create a filtered version of the token for running normal applications
|
|
// if so indicated by a registry setting
|
|
//
|
|
|
|
|
|
if (GetProfileInt( APPLICATION_NAME, RESTRICT_SHELL, 0) != 0) {
|
|
|
|
TokenGroups->Groups[0].Attributes = 0;
|
|
TokenGroups->Groups[0].Sid = gAdminSid;
|
|
TokenGroups->GroupCount = 1;
|
|
|
|
Status = NtFilterToken(
|
|
UserToken,
|
|
DISABLE_MAX_PRIVILEGE,
|
|
TokenGroups, // disable the administrators sid
|
|
NULL, // no privileges
|
|
NULL,
|
|
&RestrictedToken
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DebugLog((DEB_ERROR, "Failed to filter token: 0x%%x\n", Status));
|
|
RestrictedToken = NULL;
|
|
}
|
|
|
|
//
|
|
// Now set the default dacl for the token
|
|
//
|
|
|
|
{
|
|
PACL Dacl = NULL;
|
|
ULONG DaclLength = 0;
|
|
TOKEN_DEFAULT_DACL DefaultDacl;
|
|
|
|
DaclLength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(LogonSid);
|
|
Dacl = Alloc(DaclLength);
|
|
Status = RtlCreateAcl(Dacl,DaclLength, ACL_REVISION);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
Status = RtlAddAccessAllowedAce(
|
|
Dacl,
|
|
ACL_REVISION,
|
|
GENERIC_ALL,
|
|
LogonSid
|
|
);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
DefaultDacl.DefaultDacl = Dacl;
|
|
Status = NtSetInformationToken(
|
|
RestrictedToken,
|
|
TokenDefaultDacl,
|
|
&DefaultDacl,
|
|
sizeof(TOKEN_DEFAULT_DACL)
|
|
);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Free(Dacl);
|
|
}
|
|
|
|
|
|
} else {
|
|
RestrictedToken = NULL;
|
|
}
|
|
|
|
//
|
|
// Notify credential managers of the successful logon
|
|
//
|
|
|
|
pTokenUser = (PTOKEN_USER) UserBuffer ;
|
|
Status = NtQueryInformationToken( UserToken,
|
|
TokenUser,
|
|
pTokenUser,
|
|
sizeof( UserBuffer ),
|
|
&TokenInfoSize );
|
|
|
|
if ( NT_SUCCESS( Status ) )
|
|
{
|
|
pGlobals->UserProcessData.UserSid = LocalAlloc( LMEM_FIXED,
|
|
RtlLengthSid( pTokenUser->User.Sid ) );
|
|
|
|
if ( pGlobals->UserProcessData.UserSid )
|
|
{
|
|
RtlCopyMemory( pGlobals->UserProcessData.UserSid,
|
|
pTokenUser->User.Sid,
|
|
RtlLengthSid( pTokenUser->User.Sid ) );
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_NO_MEMORY ;
|
|
}
|
|
}
|
|
|
|
if ( !NT_SUCCESS( Status ) )
|
|
{
|
|
|
|
if (pGlobals->Profile)
|
|
{
|
|
LsaFreeReturnBuffer(pGlobals->Profile);
|
|
pGlobals->Profile = NULL;
|
|
}
|
|
NtClose(UserToken);
|
|
|
|
Result = MSGINA_DLG_FAILEDMSGSENT;
|
|
|
|
PostFailedLogonMessage(pGlobals->hwndLogon, pGlobals, Status, 0, pGlobals->UserName, pGlobals->Domain);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
pGlobals->UserProcessData.NewThreadTokenSD = CreateUserThreadTokenSD(LogonSid, pWinlogonSid);
|
|
if ( NULL == pGlobals->UserProcessData.NewThreadTokenSD )
|
|
{
|
|
if (pGlobals->Profile)
|
|
{
|
|
LsaFreeReturnBuffer(pGlobals->Profile);
|
|
pGlobals->Profile = NULL;
|
|
}
|
|
NtClose(UserToken);
|
|
|
|
Result = MSGINA_DLG_FAILEDMSGSENT;
|
|
Status = STATUS_NO_MEMORY;
|
|
|
|
PostFailedLogonMessage(pGlobals->hwndLogon, pGlobals, Status, 0, pGlobals->UserName, pGlobals->Domain);
|
|
|
|
goto exit;
|
|
}
|
|
pGlobals->UserProcessData.RestrictedToken = RestrictedToken;
|
|
pGlobals->UserProcessData.UserToken = UserToken;
|
|
|
|
pGlobals->MprLogonScripts = NULL;
|
|
|
|
// Run the dirty dialog box.
|
|
if ( WinlogonDirtyDialog( NULL, pGlobals ) == WLX_SAS_ACTION_LOGOFF )
|
|
{
|
|
//
|
|
// If this returns logoff, it means that the dialog timed out and
|
|
// we need to force the user back off. Not the best user experience,
|
|
// but that's what the PMs want.
|
|
//
|
|
FreeSecurityDescriptor( pGlobals->UserProcessData.NewThreadTokenSD );
|
|
|
|
LsaFreeReturnBuffer(pGlobals->Profile);
|
|
pGlobals->Profile = NULL;
|
|
NtClose(UserToken);
|
|
|
|
Result = MSGINA_DLG_FAILEDMSGSENT;
|
|
|
|
// Post a specific substatus so we can display a meaningful error message
|
|
PostFailedLogonMessage(pGlobals->hwndLogon, pGlobals, STATUS_LOGON_FAILURE, IDS_SET_DIRTY_UI_TIMEOUT, pGlobals->UserName, pGlobals->Domain);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// If we get here, the system works well enough for the user to have
|
|
// actually logged on. Profile failures aren't fixable by last known
|
|
// good anyway. Therefore, declare the boot good.
|
|
//
|
|
|
|
ReportBootGood(pGlobals);
|
|
|
|
//
|
|
// Set up the system for the new user
|
|
//
|
|
|
|
pGlobals->LogonId = LogonId;
|
|
if ((pGlobals->Profile != NULL) && (pGlobals->Profile->FullName.Length > 0)) {
|
|
DWORD cb = pGlobals->Profile->FullName.Length;
|
|
if (cb + sizeof(WCHAR) > MAX_STRING_LENGTH * sizeof(WCHAR))
|
|
cb = MAX_STRING_LENGTH * sizeof(WCHAR) - sizeof(WCHAR);
|
|
|
|
memcpy(pGlobals->UserFullName, pGlobals->Profile->FullName.Buffer, cb);
|
|
pGlobals->UserFullName[cb / sizeof(WCHAR)] = UNICODE_NULL;
|
|
|
|
} else {
|
|
|
|
//
|
|
// No profile - set full name = NULL
|
|
|
|
pGlobals->UserFullName[0] = 0;
|
|
ASSERT( lstrlen(pGlobals->UserFullName) == 0);
|
|
}
|
|
|
|
if ( pGlobals->SmartCardLogon )
|
|
{
|
|
PCCERT_CONTEXT Cert ;
|
|
PKERB_SMART_CARD_PROFILE ScProfile ;
|
|
|
|
//
|
|
// Need to fix up the user name with the name (UPN) from the
|
|
// certificate, so that unlock, etc. work correctly.
|
|
//
|
|
|
|
ScProfile = (PKERB_SMART_CARD_PROFILE) pGlobals->Profile ;
|
|
|
|
pGlobals->UserName[0] = 0 ;
|
|
|
|
try
|
|
{
|
|
Cert = CertCreateCertificateContext( X509_ASN_ENCODING,
|
|
ScProfile->CertificateData,
|
|
ScProfile->CertificateSize );
|
|
|
|
if ( Cert )
|
|
{
|
|
// Even though the name is MAX_STRING_BYTES, the way it is used
|
|
// throughout the code, it is used as a character counter
|
|
// (Grrr, crappy gina code)
|
|
//
|
|
DWORD dwLen = MAX_STRING_BYTES;
|
|
if(STATUS_SUCCESS == UpnFromCert(Cert, &dwLen, pGlobals->UserName))
|
|
{
|
|
RtlInitUnicodeString( &pGlobals->UserNameString,
|
|
pGlobals->UserName );
|
|
}
|
|
|
|
CertFreeCertificateContext( Cert );
|
|
}
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
pGlobals->UserName[0] = L'\0';
|
|
}
|
|
|
|
//
|
|
// If this is still 0 on exit, the code that sets up the flat name
|
|
// will copy the flat name into UserName, so the failure case is
|
|
// easy.
|
|
//
|
|
|
|
}
|
|
|
|
pGlobals->SmartCardOption = GetProfileInt( APPLICATION_NAME, SC_REMOVE_OPTION, 0 );
|
|
|
|
//
|
|
// WE SHOULD NOT WRITE INTO THE REGISTRY.
|
|
// CLupu
|
|
//
|
|
|
|
//
|
|
// Update our default username and domain ready for the next logon
|
|
//
|
|
|
|
//
|
|
// Update the default username & domain only if on the console. Otherwise
|
|
// we'll break AutoAdminLogon by changing the user name.
|
|
//
|
|
if ( g_Console )
|
|
{
|
|
if ( (!pGlobals->AutoAdminLogon) &&
|
|
(SafeBootMode != SAFEBOOT_MINIMAL ) )
|
|
{
|
|
WriteProfileString(APPLICATION_NAME, DEFAULT_USER_NAME_KEY, pGlobals->UserName);
|
|
WriteProfileString(APPLICATION_NAME, DEFAULT_DOMAIN_NAME_KEY, pGlobals->Domain);
|
|
}
|
|
|
|
WriteProfileString(APPLICATION_NAME, TEMP_DEFAULT_USER_NAME_KEY, pGlobals->UserName);
|
|
WriteProfileString(APPLICATION_NAME, TEMP_DEFAULT_DOMAIN_NAME_KEY, pGlobals->Domain);
|
|
|
|
}
|
|
|
|
if ( pGlobals->Domain[0] )
|
|
{
|
|
DCacheSetDefaultEntry( pGlobals->Cache,
|
|
pGlobals->Domain,
|
|
NULL );
|
|
}
|
|
|
|
Result = MSGINA_DLG_SUCCESS;
|
|
|
|
exit:
|
|
|
|
#ifdef SMARTCARD_DOGFOOD
|
|
|
|
if (pGlobals->SmartCardLogon) {
|
|
|
|
switch (SubStatus)
|
|
{
|
|
case STATUS_SMARTCARD_WRONG_PIN:
|
|
case STATUS_SMARTCARD_CARD_BLOCKED:
|
|
case STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED:
|
|
case STATUS_SMARTCARD_NO_CARD:
|
|
case STATUS_SMARTCARD_NO_KEY_CONTAINER:
|
|
case STATUS_SMARTCARD_NO_CERTIFICATE:
|
|
case STATUS_SMARTCARD_NO_KEYSET:
|
|
case STATUS_SMARTCARD_IO_ERROR:
|
|
case STATUS_SMARTCARD_SUBSYSTEM_FAILURE:
|
|
case STATUS_SMARTCARD_CERT_EXPIRED:
|
|
case STATUS_SMARTCARD_CERT_REVOKED:
|
|
case STATUS_ISSUING_CA_UNTRUSTED:
|
|
case STATUS_REVOCATION_OFFLINE_C:
|
|
case STATUS_PKINIT_CLIENT_FAILURE:
|
|
FinalStatus = SubStatus;
|
|
break;
|
|
|
|
default:
|
|
break; // do NOTHING
|
|
}
|
|
|
|
// write logon data to database
|
|
AuthMonitor(
|
|
AuthOperLogon,
|
|
g_Console,
|
|
&pGlobals->UserNameString,
|
|
&pGlobals->DomainString,
|
|
(ScInfo ? ScInfo->pszCard : NULL),
|
|
(ScInfo ? ScInfo->pszReader : NULL),
|
|
(PKERB_SMART_CARD_PROFILE) pGlobals->Profile,
|
|
EndTime - StartTime,
|
|
FinalStatus
|
|
);
|
|
}
|
|
|
|
if (ScInfo)
|
|
{
|
|
LocalFree( ScInfo );
|
|
}
|
|
#endif
|
|
// Only send a logon complete message if we haven't sent a failed
|
|
// message. The failed message will send a logon complete message
|
|
// when its done.
|
|
if (Result != MSGINA_DLG_FAILEDMSGSENT)
|
|
{
|
|
if (WLX_DLG_INPUT_TIMEOUT == Result)
|
|
{
|
|
//
|
|
// this came from a timeout when:
|
|
// - we want to go back to CAD screen w/out an extra error dialog
|
|
// - we want this to look like a logon failure code
|
|
// the solution is to send WM_LOGONCOMPLETE / MSGINA_DLG_FAILURE
|
|
//
|
|
//
|
|
Result = MSGINA_DLG_FAILURE;
|
|
}
|
|
PostMessage(pGlobals->hwndLogon, WM_LOGONCOMPLETE, 0, Result);
|
|
}
|
|
|
|
//
|
|
// free the duplicated SID
|
|
//
|
|
if( DuplicatedLogonSID && RtlValidSid(DuplicatedLogonSID) )
|
|
{
|
|
Free(DuplicatedLogonSID);
|
|
}
|
|
|
|
return 0L;
|
|
}
|
|
|
|
|
|
/****************************************************************************\
|
|
*
|
|
* FUNCTION: PostFailedLogonMessage
|
|
*
|
|
* PURPOSE: Posts a message to the UI thread telling it to display a dialog that
|
|
* tells the user why their logon attempt failed.
|
|
*
|
|
* The window on the UI thread must correctly handle WM_HANDLEFAILEDLOGON
|
|
* by calling HandleFailedLogon and the Free'ing the structure
|
|
*
|
|
* RETURNS: void
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 12-09-91 Davidc Created.
|
|
*
|
|
\****************************************************************************/
|
|
void PostFailedLogonMessage(HWND hDlg,
|
|
PGLOBALS pGlobals,
|
|
NTSTATUS Status,
|
|
NTSTATUS SubStatus,
|
|
PWCHAR UserName,
|
|
PWCHAR Domain
|
|
)
|
|
|
|
{
|
|
g_failinfo.pGlobals = pGlobals;
|
|
g_failinfo.Status = Status;
|
|
g_failinfo.SubStatus = SubStatus;
|
|
if ( UserName )
|
|
{
|
|
lstrcpyn(g_failinfo.UserName, UserName, ARRAYSIZE(g_failinfo.UserName));
|
|
}
|
|
else
|
|
{
|
|
g_failinfo.UserName[0] = L'\0';
|
|
}
|
|
|
|
if ( Domain )
|
|
{
|
|
lstrcpyn(g_failinfo.Domain, Domain, ARRAYSIZE(g_failinfo.Domain));
|
|
}
|
|
else
|
|
{
|
|
g_failinfo.Domain[0] = L'\0' ;
|
|
}
|
|
|
|
|
|
PostMessage(hDlg, WM_HANDLEFAILEDLOGON, 0 , 0);
|
|
}
|
|
|
|
INT_PTR
|
|
CALLBACK
|
|
FailDlgProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
RUNDLLPROC fptr;
|
|
HMODULE hDll;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
CentreWindow(hDlg);
|
|
return( TRUE );
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
{
|
|
if (LOWORD(wParam) == IDOK)
|
|
{
|
|
EndDialog(hDlg, IDOK);
|
|
}
|
|
if (LOWORD(wParam) == IDC_RECOVER)
|
|
{
|
|
// Will eventually supply username to the recover wizard
|
|
// We use a single export from KEYMGR.DLL for this operation. When this operation completes,
|
|
// we don't use the DLL again without unlikely user intervention. We could DELAYLOAD keymgr.dll,
|
|
// but explicitly loading and unloading this DLL permits us to minimize the memory footprint of msgina.
|
|
hDll = LoadLibraryW(L"keymgr.dll");
|
|
if (hDll)
|
|
{
|
|
fptr = (RUNDLLPROC) GetProcAddress(hDll,(LPCSTR)"PRShowRestoreFromMsginaW");
|
|
// next stmt will be removed eventually when we pass the username
|
|
if (fptr)
|
|
{
|
|
fptr(hDlg,NULL,g_failinfo.UserName,0);
|
|
}
|
|
FreeLibrary(hDll);
|
|
EndDialog(hDlg,IDOK);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/****************************************************************************\
|
|
*
|
|
* FUNCTION: HandleFailedLogon
|
|
*
|
|
* PURPOSE: Tells the user why their logon attempt failed.
|
|
*
|
|
* RETURNS: MSGINA_DLG_FAILURE - we told them what the problem was successfully.
|
|
* DLG_INTERRUPTED() - a set of return values - see winlogon.h
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 12-09-91 Davidc Created.
|
|
*
|
|
\****************************************************************************/
|
|
|
|
INT_PTR
|
|
HandleFailedLogon(
|
|
HWND hDlg
|
|
)
|
|
{
|
|
INT_PTR Result = 0xffffffff;
|
|
DWORD Win32Error ;
|
|
TCHAR *Buffer1 = NULL;
|
|
TCHAR *Buffer2 = NULL;
|
|
TCHAR *Buffer3 = NULL;
|
|
PGLOBALS pGlobals = g_failinfo.pGlobals;
|
|
NTSTATUS Status = g_failinfo.Status;
|
|
NTSTATUS SubStatus = g_failinfo.SubStatus;
|
|
PWCHAR Domain = g_failinfo.Domain;
|
|
DWORD BUStatus = 0xffffffff;
|
|
|
|
UINT uiMsgId = 0xabab; // abab is out of range value for default handler at the bottom of this
|
|
// routine. 0 indicates that the user has a psw reset disk
|
|
// -1 means that Buffer1 & 2 contain the message
|
|
// otherwise there is a corresponding resource message
|
|
|
|
|
|
//
|
|
// for remote sessions, we must set finite timeout value for messagebox.
|
|
// so that the session does not remain there forever
|
|
//
|
|
DWORD TimeOut = IsActiveConsoleSession() ? TIMEOUT_CURRENT : 20;
|
|
|
|
switch (Status)
|
|
{
|
|
|
|
case STATUS_LOGON_FAILURE:
|
|
case STATUS_NAME_TOO_LONG: // Returned if username is too long
|
|
|
|
if (SubStatus == IDS_LOGON_LOG_FULL)
|
|
{
|
|
uiMsgId = IDS_LOGON_LOG_FULL;
|
|
}
|
|
else if( SubStatus == IDS_LOGON_SC_REQUIRED )
|
|
{
|
|
uiMsgId = IDS_LOGON_SC_REQUIRED;
|
|
}
|
|
else if ( SubStatus == IDS_SET_DIRTY_UI_TIMEOUT )
|
|
{
|
|
uiMsgId = IDS_SET_DIRTY_UI_TIMEOUT;
|
|
}
|
|
else if (pGlobals->SmartCardLogon)
|
|
{
|
|
switch(SubStatus)
|
|
{
|
|
case STATUS_SMARTCARD_WRONG_PIN:
|
|
uiMsgId = IDS_STATUS_SMARTCARD_WRONG_PIN;
|
|
break;
|
|
case STATUS_SMARTCARD_CARD_BLOCKED:
|
|
uiMsgId = IDS_STATUS_SMARTCARD_CARD_BLOCKED;
|
|
break;
|
|
case STATUS_SMARTCARD_NO_CARD:
|
|
uiMsgId = IDS_STATUS_SMARTCARD_NO_CARD;
|
|
break;
|
|
case STATUS_SMARTCARD_NO_KEY_CONTAINER:
|
|
uiMsgId = IDS_STATUS_SMARTCARD_NO_KEY_CONTAINER;
|
|
break;
|
|
case STATUS_SMARTCARD_NO_CERTIFICATE:
|
|
uiMsgId = IDS_STATUS_SMARTCARD_NO_CERTIFICATE;
|
|
break;
|
|
case STATUS_SMARTCARD_NO_KEYSET:
|
|
uiMsgId = IDS_STATUS_SMARTCARD_NO_KEYSET;
|
|
break;
|
|
case STATUS_SMARTCARD_IO_ERROR:
|
|
uiMsgId = IDS_STATUS_SMARTCARD_IO_ERROR;
|
|
break;
|
|
case STATUS_SMARTCARD_SUBSYSTEM_FAILURE:
|
|
uiMsgId = IDS_STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
|
|
break;
|
|
case STATUS_SMARTCARD_CERT_REVOKED:
|
|
uiMsgId = IDS_STATUS_SMARTCARD_CERT_REVOKED;
|
|
break;
|
|
case STATUS_ISSUING_CA_UNTRUSTED:
|
|
uiMsgId = IDS_STATUS_ISSUING_CA_UNTRUSTED;
|
|
break;
|
|
case STATUS_REVOCATION_OFFLINE_C:
|
|
uiMsgId = IDS_STATUS_REVOCATION_OFFLINE_C;
|
|
break;
|
|
case STATUS_PKINIT_CLIENT_FAILURE:
|
|
uiMsgId = IDS_STATUS_PKINIT_CLIENT_FAILURE;
|
|
break;
|
|
case STATUS_SMARTCARD_CERT_EXPIRED:
|
|
uiMsgId = IDS_STATUS_SMARTCARD_CERT_EXPIRED;
|
|
break;
|
|
default:
|
|
uiMsgId = IDS_INCORRECT_NAME_OR_PWD_SC;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// Non-smartcard logon case:
|
|
// Find out if the user who attempted logon has a password backup disk
|
|
// that could be used to reset the password. If so, present a dialog that
|
|
// offers that possibility. Else simple message box. (see passrec.h)
|
|
if (pGlobals->fLocalDomain)
|
|
{
|
|
if ((0 == PRQueryStatus(NULL,g_failinfo.UserName,&BUStatus)) && (0 == GetSystemMetrics(SM_REMOTESESSION)))
|
|
{
|
|
if (BUStatus == 0)
|
|
{
|
|
uiMsgId = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// Else UI message is generic one
|
|
uiMsgId = IDS_INCORRECT_NAME_OR_PWD;
|
|
}
|
|
break;
|
|
|
|
case STATUS_NOT_SUPPORTED:
|
|
case STATUS_PKINIT_NAME_MISMATCH:
|
|
case STATUS_PKINIT_FAILURE:
|
|
|
|
Buffer1 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR));
|
|
Buffer2 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR));
|
|
|
|
if ((Buffer1 == NULL) || (Buffer2 == NULL))
|
|
{
|
|
uiMsgId = IDS_STATUS_SERVER_SIDE_ERROR_NOINSERT;
|
|
}
|
|
else
|
|
{
|
|
// Buffer1[0] = 0; unnecessary since LPTR was used
|
|
LoadString(hDllInstance,
|
|
IDS_STATUS_SERVER_SIDE_ERROR,
|
|
Buffer1,
|
|
MAX_STRING_BYTES);
|
|
|
|
_snwprintf(Buffer2, MAX_STRING_BYTES, Buffer1, Status );
|
|
Buffer2[MAX_STRING_BYTES - 1] = 0; // zero terminate
|
|
|
|
Buffer1[0] = 0;
|
|
LoadString(hDllInstance,
|
|
IDS_LOGON_MESSAGE,
|
|
Buffer1,
|
|
MAX_STRING_BYTES);
|
|
|
|
uiMsgId = (DWORD)-1;
|
|
}
|
|
|
|
break;
|
|
|
|
case STATUS_ACCOUNT_RESTRICTION:
|
|
|
|
switch (SubStatus)
|
|
{
|
|
case STATUS_INVALID_LOGON_HOURS:
|
|
uiMsgId = IDS_INVALID_LOGON_HOURS;
|
|
break;
|
|
|
|
case STATUS_INVALID_WORKSTATION:
|
|
uiMsgId = IDS_INVALID_WORKSTATION;
|
|
break;
|
|
|
|
case STATUS_ACCOUNT_DISABLED:
|
|
uiMsgId = IDS_ACCOUNT_DISABLED;
|
|
break;
|
|
|
|
case STATUS_ACCOUNT_EXPIRED:
|
|
uiMsgId = IDS_ACCOUNT_EXPIRED2;
|
|
break;
|
|
|
|
case STATUS_SMARTCARD_LOGON_REQUIRED:
|
|
uiMsgId = IDS_SMARTCARD_REQUIRED;
|
|
break;
|
|
|
|
default:
|
|
uiMsgId = IDS_ACCOUNT_RESTRICTION;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STATUS_NO_LOGON_SERVERS:
|
|
|
|
Buffer1 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR));
|
|
Buffer2 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR));
|
|
|
|
if ((Buffer1 == NULL) || (Buffer2 == NULL))
|
|
{
|
|
uiMsgId = IDS_LOGON_NO_DOMAIN_NOINSERT;
|
|
}
|
|
else
|
|
{
|
|
// Buffer1[0] = 0; unnecessary since LPTR was used
|
|
LoadString(hDllInstance, IDS_LOGON_NO_DOMAIN, Buffer1, MAX_STRING_BYTES);
|
|
_snwprintf(Buffer2, MAX_STRING_BYTES, Buffer1, Domain);
|
|
Buffer2[MAX_STRING_BYTES - 1] = 0; // zero terminate
|
|
|
|
Buffer1[0] = 0;
|
|
LoadString(hDllInstance, IDS_LOGON_MESSAGE, Buffer1, MAX_STRING_BYTES);
|
|
|
|
uiMsgId = (DWORD)-1;
|
|
}
|
|
break;
|
|
|
|
case STATUS_LOGON_TYPE_NOT_GRANTED:
|
|
uiMsgId = IDS_LOGON_TYPE_NOT_GRANTED;
|
|
break;
|
|
|
|
case STATUS_NO_TRUST_LSA_SECRET:
|
|
uiMsgId = IDS_NO_TRUST_LSA_SECRET;
|
|
break;
|
|
|
|
case STATUS_TRUSTED_DOMAIN_FAILURE:
|
|
uiMsgId = IDS_TRUSTED_DOMAIN_FAILURE;
|
|
break;
|
|
|
|
case STATUS_TRUSTED_RELATIONSHIP_FAILURE:
|
|
uiMsgId = IDS_TRUSTED_RELATIONSHIP_FAILURE;
|
|
break;
|
|
|
|
case STATUS_ACCOUNT_EXPIRED:
|
|
uiMsgId = IDS_ACCOUNT_EXPIRED;
|
|
break;
|
|
|
|
case STATUS_NETLOGON_NOT_STARTED:
|
|
uiMsgId = IDS_NETLOGON_NOT_STARTED;
|
|
break;
|
|
|
|
case STATUS_ACCOUNT_LOCKED_OUT:
|
|
uiMsgId = IDS_ACCOUNT_LOCKED;
|
|
break;
|
|
|
|
case ERROR_CTX_LOGON_DISABLED:
|
|
uiMsgId = IDS_MULTIUSER_LOGON_DISABLED;
|
|
break;
|
|
|
|
case ERROR_CTX_WINSTATION_ACCESS_DENIED:
|
|
uiMsgId = IDS_MULTIUSER_WINSTATION_ACCESS_DENIED;
|
|
break;
|
|
|
|
case SCARD_E_NO_SMARTCARD:
|
|
case SCARD_E_UNKNOWN_CARD:
|
|
//
|
|
// Card not recognized (although we should never get this far)
|
|
//
|
|
uiMsgId = IDS_CARD_NOT_RECOGNIZED;
|
|
break;
|
|
|
|
|
|
case NTE_PROV_DLL_NOT_FOUND:
|
|
//
|
|
// Card's CSP not found (although we should never get this far)
|
|
//
|
|
uiMsgId = IDS_CARD_CSP_NOT_RECOGNIZED;
|
|
break;
|
|
|
|
case STATUS_TIME_DIFFERENCE_AT_DC:
|
|
uiMsgId = IDS_TIME_DIFFERENCE_AT_DC;
|
|
break;
|
|
|
|
default:
|
|
|
|
WLPrint(("Logon failure status = 0x%lx, sub-status = 0x%lx", Status, SubStatus));
|
|
|
|
Buffer1 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR));
|
|
Buffer2 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR));
|
|
Buffer3 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR));
|
|
|
|
if ((Buffer1 == NULL) || (Buffer2 == NULL) || (Buffer3 == NULL))
|
|
{
|
|
uiMsgId = IDS_UNKNOWN_LOGON_FAILURE_NOINSERT;
|
|
}
|
|
else
|
|
{
|
|
// Buffer1[0] = 0; unnecessary since LPTR was used
|
|
LoadString(hDllInstance,
|
|
IDS_UNKNOWN_LOGON_FAILURE,
|
|
Buffer1,
|
|
MAX_STRING_BYTES);
|
|
|
|
if ( NT_ERROR( Status ) )
|
|
{
|
|
Win32Error = RtlNtStatusToDosError( Status );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Probably an HRESULT:
|
|
//
|
|
|
|
Win32Error = Status ;
|
|
}
|
|
|
|
// Buffer3[0] = 0; unnecessary since LPTR was used
|
|
GetErrorDescription( Win32Error, Buffer3, MAX_STRING_BYTES);
|
|
|
|
_snwprintf(Buffer2, MAX_STRING_BYTES, Buffer1, Buffer3 );
|
|
Buffer2[MAX_STRING_BYTES - 1] = 0; // zero terminate
|
|
|
|
Buffer1[0] = 0;
|
|
LoadString(hDllInstance,
|
|
IDS_LOGON_MESSAGE,
|
|
Buffer1,
|
|
MAX_STRING_BYTES);
|
|
|
|
uiMsgId = (DWORD)-1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
_Shell_LogonDialog_HideUIHost();
|
|
|
|
switch (uiMsgId)
|
|
{
|
|
case 0:
|
|
// User has a password reset disk - present the option to use it along with the usual
|
|
// help message
|
|
pWlxFuncs->WlxSetTimeout(pGlobals->hGlobalWlx,LOGON_TIMEOUT);
|
|
Result = pWlxFuncs->WlxDialogBoxParam(pGlobals->hGlobalWlx,
|
|
hDllInstance,
|
|
(LPTSTR) IDD_FAILLOGONHELP_DIALOG,
|
|
hDlg,
|
|
FailDlgProc,
|
|
0);
|
|
break;
|
|
|
|
case (DWORD)-1:
|
|
Result = TimeoutMessageBoxlpstr(hDlg, pGlobals,
|
|
Buffer2,
|
|
Buffer1,
|
|
MB_OK | MB_ICONEXCLAMATION,
|
|
TimeOut);
|
|
break;
|
|
|
|
default:
|
|
Result = TimeoutMessageBox(hDlg, pGlobals,
|
|
uiMsgId,
|
|
IDS_LOGON_MESSAGE,
|
|
MB_OK | MB_ICONEXCLAMATION,
|
|
TimeOut);
|
|
}
|
|
|
|
if (Buffer1 != NULL)
|
|
LocalFree(Buffer1);
|
|
if (Buffer2 != NULL)
|
|
LocalFree(Buffer2);
|
|
if (Buffer3 != NULL)
|
|
LocalFree(Buffer3);
|
|
|
|
if (!DLG_INTERRUPTED(Result))
|
|
{
|
|
Result = MSGINA_DLG_FAILURE;
|
|
}
|
|
|
|
return(Result);
|
|
}
|
|
|
|
VOID
|
|
ReportBootGoodThread (LPVOID lpDummy)
|
|
{
|
|
HANDLE hInstDll;
|
|
// PGLOBALS pGlobals = (PGLOBALS)lpDummy;
|
|
|
|
// SetThreadDesktop(pGlobals->hdeskParent);
|
|
|
|
hInstDll = LoadLibrary (TEXT("msgina.dll"));
|
|
|
|
NotifyBootConfigStatus(TRUE);
|
|
|
|
if (hInstDll) {
|
|
FreeLibraryAndExitThread(hInstDll, TRUE);
|
|
} else {
|
|
ExitThread (TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************************************************\
|
|
*
|
|
* FUNCTION: ReportBootGood
|
|
*
|
|
* PURPOSE: Discover if reporting boot success is responsibility of
|
|
* winlogon or not.
|
|
* If it is, report boot success.
|
|
* Otherwise, do nothing.
|
|
*
|
|
* RETURNS: Nothing
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 02-Feb-1993 bryanwi - created
|
|
*
|
|
\****************************************************************************/
|
|
VOID
|
|
ReportBootGood(PGLOBALS pGlobals)
|
|
{
|
|
static DWORD fDoIt = (DWORD) -1; // -1 == uninited
|
|
// 0 == don't do it, or done
|
|
// 1 == do it
|
|
PWCH pchData;
|
|
DWORD cb, cbCopied;
|
|
HANDLE hThread;
|
|
DWORD dwThreadID;
|
|
|
|
|
|
if (fDoIt == -1) {
|
|
|
|
if ((pchData = Alloc(cb = sizeof(TCHAR)*128)) == NULL) {
|
|
return;
|
|
}
|
|
|
|
pchData[0] = TEXT('0');
|
|
cbCopied = GetProfileString(APPLICATION_NAME, REPORT_BOOT_OK_KEY, TEXT("0"),
|
|
(LPTSTR)pchData, 128);
|
|
|
|
fDoIt = 0;
|
|
if (pchData[0] != TEXT('0')) {
|
|
|
|
//
|
|
// "ReportBootGood" is present, and has some value other than
|
|
// '0', so report success.
|
|
//
|
|
fDoIt = 1;
|
|
}
|
|
|
|
Free((TCHAR *)pchData);
|
|
}
|
|
|
|
if (fDoIt == 1) {
|
|
|
|
hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)ReportBootGoodThread,
|
|
pGlobals, CREATE_SUSPENDED, &dwThreadID);
|
|
|
|
if (hThread) {
|
|
SetThreadPriority (hThread, THREAD_PRIORITY_LOWEST);
|
|
ResumeThread (hThread);
|
|
CloseHandle (hThread);
|
|
|
|
} else {
|
|
NotifyBootConfigStatus(TRUE);
|
|
}
|
|
fDoIt = 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: UpnFromCert
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
UpnFromCert(
|
|
IN PCCERT_CONTEXT pCert,
|
|
IN OUT DWORD *pcUpn,
|
|
IN OUT LPWSTR pUPN
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ULONG ExtensionIndex = 0;
|
|
PCERT_ALT_NAME_INFO AltName=NULL;
|
|
PCERT_NAME_VALUE PrincipalNameBlob = NULL;
|
|
|
|
//
|
|
// Get the client name from the cert
|
|
//
|
|
|
|
// See if cert has UPN in AltSubjectName->otherName
|
|
for(ExtensionIndex = 0;
|
|
ExtensionIndex < pCert->pCertInfo->cExtension;
|
|
ExtensionIndex++)
|
|
{
|
|
if(strcmp(pCert->pCertInfo->rgExtension[ExtensionIndex].pszObjId,
|
|
szOID_SUBJECT_ALT_NAME2) == 0)
|
|
{
|
|
DWORD AltNameStructSize = 0;
|
|
ULONG CertAltNameIndex = 0;
|
|
if(CryptDecodeObjectEx(pCert->dwCertEncodingType,
|
|
X509_ALTERNATE_NAME,
|
|
pCert->pCertInfo->rgExtension[ExtensionIndex].Value.pbData,
|
|
pCert->pCertInfo->rgExtension[ExtensionIndex].Value.cbData,
|
|
CRYPT_DECODE_ALLOC_FLAG,
|
|
NULL,
|
|
(PVOID)&AltName,
|
|
&AltNameStructSize))
|
|
{
|
|
|
|
for(CertAltNameIndex = 0; CertAltNameIndex < AltName->cAltEntry; CertAltNameIndex++)
|
|
{
|
|
PCERT_ALT_NAME_ENTRY AltNameEntry = &AltName->rgAltEntry[CertAltNameIndex];
|
|
if((CERT_ALT_NAME_OTHER_NAME == AltNameEntry->dwAltNameChoice) &&
|
|
(NULL != AltNameEntry->pOtherName) &&
|
|
(0 == strcmp(szOID_NT_PRINCIPAL_NAME, AltNameEntry->pOtherName->pszObjId)))
|
|
{
|
|
DWORD PrincipalNameBlobSize = 0;
|
|
|
|
// We found a UPN!
|
|
if(CryptDecodeObjectEx(pCert->dwCertEncodingType,
|
|
X509_UNICODE_ANY_STRING,
|
|
AltNameEntry->pOtherName->Value.pbData,
|
|
AltNameEntry->pOtherName->Value.cbData,
|
|
CRYPT_DECODE_ALLOC_FLAG,
|
|
NULL,
|
|
(PVOID)&PrincipalNameBlob,
|
|
&PrincipalNameBlobSize))
|
|
{
|
|
if(PrincipalNameBlob->Value.cbData + sizeof(WCHAR) > *pcUpn)
|
|
{
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
else
|
|
{
|
|
*pcUpn = PrincipalNameBlob->Value.cbData + sizeof(WCHAR);
|
|
|
|
CopyMemory(pUPN, PrincipalNameBlob->Value.pbData, PrincipalNameBlob->Value.cbData);
|
|
*(WCHAR *)((PBYTE)pUPN+PrincipalNameBlob->Value.cbData) = 0;
|
|
}
|
|
|
|
LocalFree(PrincipalNameBlob);
|
|
PrincipalNameBlob = NULL;
|
|
LocalFree(AltName);
|
|
AltName = NULL;
|
|
|
|
goto Finished;
|
|
}
|
|
}
|
|
}
|
|
LocalFree(AltName);
|
|
AltName = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the name was not found in the UPN, then
|
|
// we grab it the old way.
|
|
|
|
if ( !CertGetNameString( pCert,
|
|
CERT_NAME_ATTR_TYPE,
|
|
0,
|
|
szOID_COMMON_NAME,
|
|
pUPN,
|
|
*pcUpn ) )
|
|
{
|
|
Status = GetLastError();
|
|
}
|
|
|
|
Finished:
|
|
|
|
|
|
return Status ;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function:TSAuthenticatedLogon
|
|
//
|
|
// Notes: This routine gets called in response to WLX_SAS_TYPE_AUTHENTICATED
|
|
// in the context of the console session (sessionid 0) winlogon.
|
|
// This type of logon is for Single Session Terminal Server. When a user
|
|
// logs on from a remote TS session, we pass the credentials from the remote session
|
|
// to the console session and do an auto-logon. This routine queries the credentials
|
|
// logs on the user on the console sesion
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
INT_PTR TSAuthenticatedLogon(PGLOBALS pGlobals)
|
|
{
|
|
PSID LogonSid;
|
|
LUID LogonId;
|
|
HANDLE UserToken;
|
|
HANDLE RestrictedToken;
|
|
INT_PTR Result = MSGINA_DLG_SUCCESS;
|
|
UCHAR UserBuffer[ SID_MAX_SUB_AUTHORITIES * sizeof( DWORD ) + 8 + sizeof( TOKEN_USER ) ];
|
|
PTOKEN_USER pTokenUser ;
|
|
ULONG TokenInfoSize ;
|
|
NTSTATUS Status;
|
|
BYTE GroupsBuffer[sizeof(TOKEN_GROUPS)+sizeof(SID_AND_ATTRIBUTES)];
|
|
PTOKEN_GROUPS TokenGroups = (PTOKEN_GROUPS) GroupsBuffer;
|
|
PACL Dacl = NULL;
|
|
|
|
|
|
if (!QuerySwitchConsoleCredentials(pGlobals,&UserToken,&LogonId)) {
|
|
Result = MSGINA_DLG_FAILEDMSGSENT;
|
|
goto exit;
|
|
}
|
|
|
|
if (pGlobals->SmartCardLogon) {
|
|
|
|
wcscpy(pGlobals->Password,L"");
|
|
wcscpy(pGlobals->OldPassword,L"");
|
|
|
|
{
|
|
KERB_REFRESH_SCCRED_REQUEST PurgeRequest = {0};
|
|
PVOID Response = NULL;
|
|
ULONG ResponseSize;
|
|
NTSTATUS SubStatus;
|
|
|
|
PopulateSecPackageList(
|
|
pGlobals );
|
|
|
|
PurgeRequest.LogonId = LogonId;
|
|
PurgeRequest.MessageType = KerbRefreshSmartcardCredentialsMessage;
|
|
PurgeRequest.Flags = KERB_REFRESH_SCCRED_RELEASE;
|
|
|
|
Status = LsaCallAuthenticationPackage(
|
|
pGlobals->LsaHandle,
|
|
pGlobals->SmartCardLogonPackage,
|
|
&PurgeRequest,
|
|
sizeof(KERB_REFRESH_SCCRED_REQUEST),
|
|
&Response,
|
|
&ResponseSize,
|
|
&SubStatus
|
|
);
|
|
|
|
if (NT_SUCCESS(Status) && NT_SUCCESS(SubStatus))
|
|
{
|
|
if (Response)
|
|
{
|
|
LsaFreeReturnBuffer(Response);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugLog((DEB_ERROR, "KerbRefreshSmartcardCredentials failed: (0x%x - 0x%x)\n", Status, SubStatus));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wcscpy(pGlobals->Password,L"");
|
|
RtlInitUnicodeString(&pGlobals->PasswordString,pGlobals->Password);
|
|
wcscpy(pGlobals->OldPassword,L"");
|
|
RtlInitUnicodeString(&pGlobals->OldPasswordString,pGlobals->OldPassword);
|
|
}
|
|
|
|
RtlInitUnicodeString(&pGlobals->UserNameString, pGlobals->UserName);
|
|
RtlInitUnicodeString(&pGlobals->DomainString, pGlobals->Domain);
|
|
|
|
pGlobals->RasUsed = FALSE;
|
|
|
|
pGlobals->hwndLogon = NULL;
|
|
|
|
//
|
|
// Generate a unique sid for this logon
|
|
//
|
|
if (!GetAndAllocateLogonSid(UserToken,&(pGlobals->LogonSid))) {
|
|
|
|
goto error_exit;
|
|
}
|
|
|
|
LogonSid = pGlobals->LogonSid;
|
|
|
|
|
|
//
|
|
// The user logged on successfully
|
|
//
|
|
|
|
|
|
//
|
|
// Create a filtered version of the token for running normal applications
|
|
// if so indicated by a registry setting
|
|
//
|
|
|
|
|
|
if (GetProfileInt( APPLICATION_NAME, RESTRICT_SHELL, 0) != 0) {
|
|
|
|
TokenGroups->Groups[0].Attributes = 0;
|
|
TokenGroups->Groups[0].Sid = gAdminSid;
|
|
TokenGroups->GroupCount = 1;
|
|
|
|
Status = NtFilterToken(
|
|
UserToken,
|
|
DISABLE_MAX_PRIVILEGE,
|
|
TokenGroups, // disable the administrators sid
|
|
NULL, // no privileges
|
|
NULL,
|
|
&RestrictedToken
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DebugLog((DEB_ERROR, "Failed to filter token: 0x%%x\n", Status));
|
|
RestrictedToken = NULL;
|
|
}
|
|
|
|
//
|
|
// Now set the default dacl for the token
|
|
//
|
|
|
|
{
|
|
ULONG DaclLength = 0;
|
|
TOKEN_DEFAULT_DACL DefaultDacl;
|
|
|
|
DaclLength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(LogonSid);
|
|
Dacl = Alloc(DaclLength);
|
|
|
|
// Check for memory allocation failure
|
|
if (Dacl == NULL) {
|
|
goto error_exit ;
|
|
}
|
|
|
|
Status = RtlCreateAcl(Dacl,DaclLength, ACL_REVISION);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
goto error_exit;
|
|
}
|
|
|
|
Status = RtlAddAccessAllowedAce(
|
|
Dacl,
|
|
ACL_REVISION,
|
|
GENERIC_ALL,
|
|
LogonSid
|
|
);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
goto error_exit;
|
|
}
|
|
|
|
|
|
DefaultDacl.DefaultDacl = Dacl;
|
|
Status = NtSetInformationToken(
|
|
RestrictedToken,
|
|
TokenDefaultDacl,
|
|
&DefaultDacl,
|
|
sizeof(TOKEN_DEFAULT_DACL)
|
|
);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
goto error_exit;
|
|
}
|
|
|
|
Free(Dacl);
|
|
Dacl = NULL;
|
|
}
|
|
|
|
|
|
} else {
|
|
RestrictedToken = NULL;
|
|
}
|
|
//
|
|
// Notify credential managers of the successful logon
|
|
//
|
|
|
|
pTokenUser = (PTOKEN_USER) UserBuffer ;
|
|
Status = NtQueryInformationToken( UserToken,
|
|
TokenUser,
|
|
pTokenUser,
|
|
sizeof( UserBuffer ),
|
|
&TokenInfoSize );
|
|
|
|
if ( NT_SUCCESS( Status ) )
|
|
{
|
|
pGlobals->UserProcessData.UserSid = LocalAlloc( LMEM_FIXED,
|
|
RtlLengthSid( pTokenUser->User.Sid ) );
|
|
|
|
if ( pGlobals->UserProcessData.UserSid )
|
|
{
|
|
RtlCopyMemory( pGlobals->UserProcessData.UserSid,
|
|
pTokenUser->User.Sid,
|
|
RtlLengthSid( pTokenUser->User.Sid ) );
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_NO_MEMORY ;
|
|
}
|
|
}
|
|
|
|
if ( !NT_SUCCESS( Status ) )
|
|
{
|
|
NtClose(UserToken);
|
|
goto error_exit;
|
|
}
|
|
|
|
pGlobals->UserProcessData.NewThreadTokenSD = CreateUserThreadTokenSD(LogonSid, pWinlogonSid);
|
|
if ( NULL == pGlobals->UserProcessData.NewThreadTokenSD )
|
|
{
|
|
if (pGlobals->Profile)
|
|
{
|
|
VirtualFree(pGlobals->Profile, 0, MEM_RELEASE);
|
|
pGlobals->Profile = NULL;
|
|
pGlobals->ProfileLength = 0;
|
|
}
|
|
NtClose(UserToken);
|
|
|
|
Result = MSGINA_DLG_FAILEDMSGSENT;
|
|
Status = STATUS_NO_MEMORY;
|
|
|
|
goto exit;
|
|
}
|
|
pGlobals->UserProcessData.RestrictedToken = RestrictedToken;
|
|
pGlobals->UserProcessData.UserToken = UserToken;
|
|
|
|
|
|
pGlobals->MprLogonScripts = NULL;
|
|
|
|
//
|
|
// If we get here, the system works well enough for the user to have
|
|
// actually logged on. Profile failures aren't fixable by last known
|
|
// good anyway. Therefore, declare the boot good.
|
|
//
|
|
|
|
ReportBootGood(pGlobals);
|
|
|
|
//
|
|
// Set up the system for the new user
|
|
//
|
|
|
|
pGlobals->LogonId = LogonId;
|
|
if ((pGlobals->Profile != NULL) && (pGlobals->Profile->FullName.Length > 0)) {
|
|
|
|
DWORD cb = pGlobals->Profile->FullName.Length;
|
|
if (cb + sizeof(WCHAR) > MAX_STRING_LENGTH * sizeof(WCHAR))
|
|
cb = MAX_STRING_LENGTH * sizeof(WCHAR) - sizeof(WCHAR);
|
|
|
|
memcpy(pGlobals->UserFullName, pGlobals->Profile->FullName.Buffer, cb);
|
|
pGlobals->UserFullName[cb / sizeof(WCHAR)] = UNICODE_NULL;
|
|
|
|
} else {
|
|
|
|
//
|
|
// No profile - set full name = NULL
|
|
|
|
pGlobals->UserFullName[0] = 0;
|
|
ASSERT( lstrlen(pGlobals->UserFullName) == 0);
|
|
}
|
|
|
|
|
|
//
|
|
// Update our default username and domain ready for the next logon
|
|
//
|
|
|
|
//
|
|
// Update the default username & domain only if on the console. Otherwise
|
|
// we'll break AutoAdminLogon by changing the user name.
|
|
//
|
|
if ( g_Console )
|
|
{
|
|
if ( (!pGlobals->AutoAdminLogon) &&
|
|
(SafeBootMode != SAFEBOOT_MINIMAL ) )
|
|
{
|
|
WriteProfileString(APPLICATION_NAME, DEFAULT_USER_NAME_KEY, pGlobals->UserName);
|
|
WriteProfileString(APPLICATION_NAME, DEFAULT_DOMAIN_NAME_KEY, pGlobals->Domain);
|
|
}
|
|
|
|
WriteProfileString(APPLICATION_NAME, TEMP_DEFAULT_USER_NAME_KEY, pGlobals->UserName);
|
|
WriteProfileString(APPLICATION_NAME, TEMP_DEFAULT_DOMAIN_NAME_KEY, pGlobals->Domain);
|
|
|
|
}
|
|
|
|
if ( pGlobals->Domain[0] == '\0' )
|
|
{
|
|
|
|
GetProfileString( APPLICATION_NAME,
|
|
DEFAULT_DOMAIN_NAME_KEY,
|
|
TEXT(""),
|
|
pGlobals->Domain,
|
|
MAX_STRING_BYTES );
|
|
}
|
|
|
|
|
|
if ( !DCacheValidateCache( pGlobals->Cache ) )
|
|
{
|
|
ASSERT( pGlobals->ActiveArray == NULL );
|
|
|
|
DCacheUpdateMinimal( pGlobals->Cache, pGlobals->Domain, TRUE );
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Set the current default:
|
|
//
|
|
|
|
DCacheSetDefaultEntry( pGlobals->Cache,
|
|
pGlobals->Domain,
|
|
NULL );
|
|
}
|
|
|
|
Result = MSGINA_DLG_SUCCESS;
|
|
|
|
exit:
|
|
|
|
return Result;
|
|
|
|
error_exit:
|
|
|
|
Result = MSGINA_DLG_FAILEDMSGSENT;
|
|
|
|
if (pGlobals->Profile) {
|
|
VirtualFree(pGlobals->Profile, 0, MEM_RELEASE);
|
|
pGlobals->Profile = NULL;
|
|
pGlobals->ProfileLength = 0;
|
|
}
|
|
|
|
if (Dacl != NULL) {
|
|
Free(Dacl);
|
|
Dacl = NULL;
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
PWSTR
|
|
AllocAndDuplicateString(
|
|
PWSTR pszString,
|
|
int len)
|
|
{
|
|
PWSTR pszNewString;
|
|
|
|
if (!pszString || !len)
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
pszNewString = LocalAlloc(LMEM_FIXED, (len + 2)*sizeof(WCHAR));
|
|
if (pszNewString)
|
|
{
|
|
wcsncpy(pszNewString, pszString, len);
|
|
pszNewString[len] = UNICODE_NULL;
|
|
}
|
|
|
|
return(pszNewString);
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
WlxGetConsoleSwitchCredentials (
|
|
PVOID pWlxContext,
|
|
PVOID pInfo
|
|
)
|
|
{
|
|
PGLOBALS pGlobals = (PGLOBALS) pWlxContext;
|
|
PWLX_CONSOLESWITCH_CREDENTIALS_INFO_V1_0 pReq = (PWLX_CONSOLESWITCH_CREDENTIALS_INFO_V1_0)pInfo;
|
|
BOOL bReturn = FALSE;
|
|
|
|
|
|
if (pReq->dwType != WLX_CONSOLESWITCHCREDENTIAL_TYPE_V1_0) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Initialize allocated pointers.
|
|
//
|
|
|
|
pReq->UserName = NULL;
|
|
pReq->Domain = NULL;
|
|
pReq->LogonScript = NULL;
|
|
pReq->HomeDirectory = NULL;
|
|
pReq->FullName = NULL;
|
|
pReq->ProfilePath = NULL;
|
|
pReq->HomeDirectoryDrive = NULL;
|
|
pReq->LogonServer = NULL;
|
|
pReq->PrivateData = NULL;
|
|
|
|
|
|
|
|
pReq->LogonId = pGlobals->LogonId;
|
|
pReq->UserToken = pGlobals->UserProcessData.UserToken;
|
|
pReq->LogonTime = pGlobals->LogonTime;
|
|
pReq->SmartCardLogon = pGlobals->SmartCardLogon;
|
|
|
|
pReq->UserName = AllocAndDuplicateString(pGlobals->UserName,
|
|
(DWORD) wcslen(pGlobals->UserName));
|
|
|
|
pReq->Domain = AllocAndDuplicateString(pGlobals->Domain,
|
|
(DWORD) wcslen(pGlobals->Domain));
|
|
|
|
//
|
|
// Quota Information
|
|
//
|
|
pReq->Quotas.PagedPoolLimit = pGlobals->UserProcessData.Quotas.PagedPoolLimit;
|
|
pReq->Quotas.NonPagedPoolLimit = pGlobals->UserProcessData.Quotas.NonPagedPoolLimit;
|
|
pReq->Quotas.MinimumWorkingSetSize = pGlobals->UserProcessData.Quotas.MinimumWorkingSetSize;
|
|
pReq->Quotas.MaximumWorkingSetSize = pGlobals->UserProcessData.Quotas.MaximumWorkingSetSize;
|
|
pReq->Quotas.PagefileLimit = pGlobals->UserProcessData.Quotas.PagefileLimit;
|
|
pReq->Quotas.TimeLimit = pGlobals->UserProcessData.Quotas.TimeLimit;
|
|
|
|
//
|
|
// Profile Information
|
|
//
|
|
pReq->ProfileLength = pGlobals->ProfileLength;
|
|
pReq->UserFlags = pGlobals->Profile->UserFlags;
|
|
pReq->MessageType = pGlobals->Profile->MessageType;
|
|
pReq->LogonCount = pGlobals->Profile->LogonCount;
|
|
pReq->BadPasswordCount = pGlobals->Profile->BadPasswordCount;
|
|
pReq->ProfileLogonTime = pGlobals->Profile->LogonTime;
|
|
pReq->LogoffTime = pGlobals->Profile->LogoffTime;
|
|
pReq->KickOffTime = pGlobals->Profile->KickOffTime;
|
|
pReq->PasswordLastSet = pGlobals->Profile->PasswordLastSet;
|
|
pReq->PasswordCanChange = pGlobals->Profile->PasswordCanChange;
|
|
pReq->PasswordMustChange = pGlobals->Profile->PasswordMustChange;
|
|
|
|
pReq->LogonScript = AllocAndDuplicateString(pGlobals->Profile->LogonScript.Buffer, pGlobals->Profile->LogonScript.Length/sizeof(WCHAR));
|
|
pReq->HomeDirectory = AllocAndDuplicateString(pGlobals->Profile->HomeDirectory.Buffer, pGlobals->Profile->HomeDirectory.Length/sizeof(WCHAR));
|
|
pReq->FullName = AllocAndDuplicateString(pGlobals->Profile->FullName.Buffer, pGlobals->Profile->FullName.Length/sizeof(WCHAR));
|
|
|
|
pReq->ProfilePath = AllocAndDuplicateString(pGlobals->Profile->ProfilePath.Buffer, pGlobals->Profile->ProfilePath.Length/sizeof(WCHAR));
|
|
|
|
pReq->HomeDirectoryDrive = AllocAndDuplicateString(pGlobals->Profile->HomeDirectoryDrive.Buffer, pGlobals->Profile->HomeDirectoryDrive.Length/sizeof(WCHAR));
|
|
pReq->LogonServer = AllocAndDuplicateString(pGlobals->Profile->LogonServer.Buffer, pGlobals->Profile->LogonServer.Length/sizeof(WCHAR));
|
|
pReq->PrivateDataLen = PASSWORD_HASH_SIZE;
|
|
pReq->PrivateData = LocalAlloc(LMEM_FIXED, PASSWORD_HASH_SIZE );
|
|
if (pReq->PrivateData == NULL) {
|
|
goto done;
|
|
}
|
|
|
|
memcpy(pReq->PrivateData, pGlobals->PasswordHash, PASSWORD_HASH_SIZE );
|
|
|
|
bReturn = TRUE;
|
|
|
|
done:
|
|
if (!bReturn) {
|
|
if (pReq->UserName != NULL) {
|
|
LocalFree(pReq->UserName);
|
|
}
|
|
if (pReq->Domain != NULL) {
|
|
LocalFree(pReq->Domain);
|
|
}
|
|
if (pReq->LogonScript != NULL) {
|
|
LocalFree(pReq->LogonScript);
|
|
}
|
|
if (pReq->HomeDirectory != NULL) {
|
|
LocalFree(pReq->HomeDirectory);
|
|
}
|
|
if (pReq->FullName != NULL) {
|
|
LocalFree(pReq->FullName);
|
|
}
|
|
if (pReq->ProfilePath != NULL) {
|
|
LocalFree(pReq->ProfilePath);
|
|
}
|
|
if (pReq->HomeDirectoryDrive != NULL) {
|
|
LocalFree(pReq->HomeDirectoryDrive);
|
|
}
|
|
if (pReq->LogonServer != NULL) {
|
|
LocalFree(pReq->LogonServer);
|
|
}
|
|
if (pReq->PrivateData != NULL) {
|
|
LocalFree(pReq->PrivateData);
|
|
}
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: QuerySwitchConsoleCredentials
|
|
//
|
|
// Notes:
|
|
//
|
|
// Query credentials from session connecting to console to do switch console
|
|
// This routine gets called in response to WLX_SAS_TYPE_AUTHENTICATED
|
|
// in the context of the console session (sessionid 0) winlogon.
|
|
// This type of logon is for Single Session Terminal Server. When a user
|
|
// logs on from a remote TS session, we pass the credentials from the remote session
|
|
// to the console session and do an auto-logon. This routine queries the credentials,
|
|
// logs on the user on the console sesion
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
WINAPI
|
|
QuerySwitchConsoleCredentials(PGLOBALS pGlobals, HANDLE * phUserToken, PLUID pLogonId)
|
|
{
|
|
WLX_CONSOLESWITCH_CREDENTIALS_INFO_V1_0 CredInfo;
|
|
|
|
RtlZeroMemory(&CredInfo,sizeof(CredInfo));
|
|
|
|
CredInfo.dwType = WLX_CONSOLESWITCHCREDENTIAL_TYPE_V1_0;
|
|
|
|
if (!pWlxFuncs->WlxQueryConsoleSwitchCredentials(&CredInfo)){
|
|
return FALSE;
|
|
}
|
|
|
|
if (!CredInfo.UserToken || !CredInfo.UserName) {
|
|
//return false if any of the critical information is missing
|
|
return FALSE;
|
|
}
|
|
|
|
pGlobals->Profile = (PMSV1_0_INTERACTIVE_PROFILE) VirtualAlloc(NULL,
|
|
sizeof(MSV1_0_INTERACTIVE_PROFILE),
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
|
|
|
|
if (pGlobals->Profile == NULL) {
|
|
goto returnerror;
|
|
}
|
|
|
|
//
|
|
// Token, LUID
|
|
//
|
|
*pLogonId = CredInfo.LogonId;
|
|
*phUserToken = CredInfo.UserToken;
|
|
pGlobals->LogonTime = CredInfo.LogonTime;
|
|
pGlobals->SmartCardLogon = CredInfo.SmartCardLogon;
|
|
|
|
pGlobals->SmartCardOption = GetProfileInt( APPLICATION_NAME, SC_REMOVE_OPTION, 0 );
|
|
|
|
//
|
|
// Quota Information
|
|
//
|
|
pGlobals->UserProcessData.Quotas.PagedPoolLimit = CredInfo.Quotas.PagedPoolLimit ;
|
|
pGlobals->UserProcessData.Quotas.NonPagedPoolLimit = CredInfo.Quotas.NonPagedPoolLimit;
|
|
pGlobals->UserProcessData.Quotas.MinimumWorkingSetSize = CredInfo.Quotas.MinimumWorkingSetSize;
|
|
pGlobals->UserProcessData.Quotas.MaximumWorkingSetSize = CredInfo.Quotas.MaximumWorkingSetSize;
|
|
pGlobals->UserProcessData.Quotas.PagefileLimit = CredInfo.Quotas.PagefileLimit;
|
|
pGlobals->UserProcessData.Quotas.TimeLimit = CredInfo.Quotas.TimeLimit;
|
|
|
|
//
|
|
// Profile Information
|
|
//
|
|
pGlobals->ProfileLength = CredInfo.ProfileLength;
|
|
pGlobals->Profile->UserFlags = CredInfo.UserFlags;
|
|
pGlobals->Profile->MessageType = CredInfo.MessageType;
|
|
pGlobals->Profile->LogonCount = CredInfo.LogonCount;
|
|
pGlobals->Profile->BadPasswordCount = CredInfo.BadPasswordCount;
|
|
pGlobals->Profile->LogonTime = CredInfo.ProfileLogonTime;
|
|
pGlobals->Profile->LogoffTime = CredInfo.LogoffTime;
|
|
pGlobals->Profile->KickOffTime = CredInfo.KickOffTime;
|
|
pGlobals->Profile->PasswordLastSet = CredInfo.PasswordLastSet;
|
|
pGlobals->Profile->PasswordCanChange = CredInfo.PasswordCanChange;
|
|
pGlobals->Profile->PasswordMustChange = CredInfo.PasswordMustChange;
|
|
|
|
|
|
RtlInitUnicodeString(&pGlobals->Profile->LogonScript, CredInfo.LogonScript);
|
|
RtlInitUnicodeString(&pGlobals->Profile->HomeDirectory, CredInfo.HomeDirectory);
|
|
RtlInitUnicodeString(&pGlobals->Profile->FullName, CredInfo.FullName);
|
|
RtlInitUnicodeString(&pGlobals->Profile->ProfilePath, CredInfo.ProfilePath);
|
|
RtlInitUnicodeString(&pGlobals->Profile->HomeDirectoryDrive, CredInfo.HomeDirectoryDrive);
|
|
RtlInitUnicodeString(&pGlobals->Profile->LogonServer, CredInfo.LogonServer);
|
|
|
|
|
|
if (CredInfo.UserName) {
|
|
// CredInfo.UserName is a copy of pGlobals->UserName in another session (OK)
|
|
wcscpy(pGlobals->UserName,CredInfo.UserName);
|
|
LocalFree(CredInfo.UserName);
|
|
} else {
|
|
wcscpy(pGlobals->UserName,L"");
|
|
}
|
|
|
|
if (CredInfo.Domain) {
|
|
// CredInfo.Domain is a copy of pGlobals->Domain in another session (OK)
|
|
wcscpy(pGlobals->Domain,CredInfo.Domain);
|
|
LocalFree(CredInfo.Domain);
|
|
} else {
|
|
wcscpy(pGlobals->Domain,L"");
|
|
}
|
|
|
|
if (CredInfo.PrivateDataLen) {
|
|
RtlCopyMemory(pGlobals->PasswordHash,CredInfo.PrivateData, CredInfo.PrivateDataLen );
|
|
LocalFree(CredInfo.PrivateData);
|
|
} else {
|
|
|
|
RtlZeroMemory(pGlobals->PasswordHash,PASSWORD_HASH_SIZE);
|
|
}
|
|
pGlobals->TransderedCredentials = TRUE;
|
|
|
|
|
|
return TRUE;
|
|
|
|
returnerror:
|
|
|
|
if (CredInfo.UserName) {
|
|
LocalFree(CredInfo.UserName);
|
|
}
|
|
|
|
if (CredInfo.Domain) {
|
|
LocalFree(CredInfo.Domain);
|
|
}
|
|
|
|
if (CredInfo.LogonScript) {
|
|
LocalFree(CredInfo.LogonScript);
|
|
}
|
|
|
|
if (CredInfo.HomeDirectory) {
|
|
LocalFree(CredInfo.HomeDirectory);
|
|
}
|
|
|
|
if (CredInfo.FullName) {
|
|
LocalFree(CredInfo.FullName);
|
|
}
|
|
|
|
if (CredInfo.ProfilePath) {
|
|
LocalFree(CredInfo.ProfilePath);
|
|
}
|
|
|
|
if (CredInfo.HomeDirectoryDrive) {
|
|
LocalFree(CredInfo.HomeDirectoryDrive);
|
|
}
|
|
|
|
if (CredInfo.LogonServer) {
|
|
LocalFree(CredInfo.LogonServer);
|
|
}
|
|
|
|
if (CredInfo.UserToken) {
|
|
CloseHandle(CredInfo.UserToken);
|
|
}
|
|
if (pGlobals->Profile) {
|
|
VirtualFree(pGlobals->Profile, 0, MEM_RELEASE);
|
|
pGlobals->Profile = NULL;
|
|
pGlobals->ProfileLength = 0;
|
|
}
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetAndAllocateLogonSid(
|
|
HANDLE hToken,
|
|
PSID *pLogonSid
|
|
)
|
|
{
|
|
PTOKEN_GROUPS ptgGroups = NULL;
|
|
PTOKEN_GROUPS ptgOldGroups = NULL;
|
|
DWORD cbBuffer = 512; // allocation size
|
|
DWORD dwSidLength; // required size to hold Sid
|
|
UINT i; // Sid index counter
|
|
BOOL bSuccess = FALSE; // assume this function will fail
|
|
|
|
*pLogonSid = NULL; // invalidate pointer
|
|
|
|
//
|
|
// initial allocation attempts
|
|
//
|
|
ptgGroups=(PTOKEN_GROUPS)Alloc(cbBuffer);
|
|
if(ptgGroups == NULL) return FALSE;
|
|
|
|
__try {
|
|
|
|
//
|
|
// obtain token information. reallocate memory if necessary
|
|
//
|
|
while(!GetTokenInformation(
|
|
hToken, TokenGroups, ptgGroups, cbBuffer, &cbBuffer)) {
|
|
|
|
//
|
|
// if appropriate, reallocate memory, otherwise bail
|
|
//
|
|
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
|
//
|
|
// attempt to reallocate buffer
|
|
//
|
|
ptgOldGroups = ptgGroups;
|
|
#pragma prefast(suppress: 308, "PREfast noise: LocalRealloc use is valid since old pointer was saved")
|
|
if((ptgGroups=(PTOKEN_GROUPS)ReAlloc(
|
|
ptgGroups, cbBuffer)) == NULL)
|
|
{
|
|
Free(ptgOldGroups);
|
|
__leave;
|
|
}
|
|
}
|
|
else __leave;
|
|
}
|
|
|
|
//
|
|
// Get the logon Sid by looping through the Sids in the token
|
|
//
|
|
for(i = 0 ; i < ptgGroups->GroupCount ; i++) {
|
|
if(ptgGroups->Groups[i].Attributes & SE_GROUP_LOGON_ID) {
|
|
|
|
//
|
|
// insure we are dealing with a valid Sid
|
|
//
|
|
if(!IsValidSid(ptgGroups->Groups[i].Sid)) __leave;
|
|
|
|
//
|
|
// get required allocation size to copy the Sid
|
|
//
|
|
dwSidLength=GetLengthSid(ptgGroups->Groups[i].Sid);
|
|
|
|
//
|
|
// allocate storage for the Logon Sid
|
|
//
|
|
if((*pLogonSid=(PSID *)Alloc(
|
|
dwSidLength)) == NULL) __leave;
|
|
|
|
//
|
|
// copy the Logon Sid to the storage we just allocated
|
|
//
|
|
if(!CopySid(dwSidLength, *pLogonSid, ptgGroups->Groups[i].Sid)) __leave;
|
|
|
|
bSuccess=TRUE; // indicate success...
|
|
break; // ...and get out
|
|
}
|
|
}
|
|
|
|
} // try
|
|
__finally {
|
|
|
|
//
|
|
// free allocated resources
|
|
//
|
|
if(ptgGroups != NULL) Free(ptgGroups);
|
|
|
|
if(!bSuccess) {
|
|
if(*pLogonSid != NULL) {
|
|
Free(*pLogonSid);
|
|
*pLogonSid = NULL;
|
|
}
|
|
}
|
|
|
|
} // finally
|
|
|
|
return bSuccess;
|
|
}
|