windows-nt/Source/XPSP1/NT/shell/ext/ratings/mslocusr/mslunp.cpp
2020-09-26 16:20:57 +08:00

619 lines
17 KiB
C++

#include "mslocusr.h"
#include "msluglob.h"
#include "resource.h"
#include <winnetwk.h>
#include <netspi.h>
#pragma data_seg(".shared")
char szDefaultLogonUsername[MAX_PATH] = "";
char szDefaultLogonPassword[MAX_PATH] = "";
BOOL fDoDefaultLogon = FALSE;
#pragma data_seg()
struct LogonData
{
LPLOGONINFO lpAuthentInfo;
DWORD dwFlags;
IUser **ppOut;
HBITMAP hbmTransparent;
};
void ObfuscateString(LPSTR pszBuffer)
{
DWORD dwMask = 0xa95e633b; /* nice random collection of bits */
unsigned char ch;
do {
ch = *pszBuffer;
*(pszBuffer++) = ch ^ (unsigned char)(dwMask & 0xff);
dwMask = (dwMask >> 8) | (dwMask << 24);
} while (ch);
}
void DeObfuscateString(LPSTR pszBuffer)
{
DWORD dwMask = 0xa95e633b; /* nice random collection of bits */
unsigned char ch;
do {
ch = *pszBuffer ^ (unsigned char)(dwMask & 0xff);
*(pszBuffer++) = ch;
dwMask = (dwMask >> 8) | (dwMask << 24);
} while (ch);
}
void CacheLogonCredentials(LPCSTR pszUsername, LPCSTR pszPassword)
{
lstrcpy(szDefaultLogonUsername, pszUsername);
lstrcpy(szDefaultLogonPassword, pszPassword);
fDoDefaultLogon = TRUE;
ObfuscateString(szDefaultLogonUsername);
ObfuscateString(szDefaultLogonPassword);
}
SPIENTRY NPGetCaps(
DWORD nIndex
)
{
switch (nIndex) {
case WNNC_SPEC_VERSION:
return 0x00040001; /* spec version 4.1 */
case WNNC_NET_TYPE:
return WNNC_NET_MSNET;
case WNNC_DRIVER_VERSION:
return 0x00010000; /* driver version 1.0 */
case WNNC_USER:
return
// WNNC_USR_GETUSER |
0;
case WNNC_CONNECTION:
return
0;
case WNNC_DIALOG:
return
0;
case WNNC_ENUMERATION:
return
0;
case WNNC_START:
return 0x1; /* started */
case WNNC_RESOURCE:
return
0;
case WNNC_AUTHENTICATION:
return
WNNC_AUTH_LOGON |
WNNC_AUTH_LOGOFF |
// WNNC_AUTH_GETHOMEDIRECTORY |
// WNNC_AUTH_GETPOLICYPATH |
0;
}
return 0;
}
// FEATURE not multimonitor friendly
VOID PlaceDialog(HWND hDlg, BOOL fTopThird)
{
RECT rc;
int dyScreen = GetSystemMetrics(SM_CYSCREEN);
int yDialog;
GetWindowRect(hDlg,&rc);
if (fTopThird)
yDialog = (dyScreen / 3) - ((rc.bottom-rc.top) / 2);
else
yDialog = (dyScreen - (rc.bottom - rc.top)) / 2;
SetWindowPos(hDlg,NULL,
(GetSystemMetrics(SM_CXSCREEN) - (rc.right - rc.left)) / 2,
yDialog, 0, 0, SWP_NOSIZE);
}
void UserSelected(HWND hwndLB, int iItem)
{
BOOL fNeedPassword;
BOOL fEnableOK;
if (iItem == LB_ERR) {
fNeedPassword = FALSE;
fEnableOK = FALSE;
}
else {
IUser *pUser = (IUser *)::SendMessage(hwndLB, LB_GETITEMDATA, iItem, 0);
fNeedPassword = FAILED(pUser->Authenticate(""));
fEnableOK = TRUE;
}
HWND hDlg = GetParent(hwndLB);
EnableWindow(GetDlgItem(hDlg, IDC_PASSWORD_LABEL), fNeedPassword);
EnableWindow(GetDlgItem(hDlg, IDC_PASSWORD), fNeedPassword);
EnableWindow(GetDlgItem(hDlg, IDOK), fEnableOK);
}
HRESULT FillUserList(HWND hwndLB, IUserDatabase *pDB, LPCSTR pszDefaultSelection,
BOOL fIncludeGuest, PFNSELNOTIFY pfnSelNotify)
{
IEnumUnknown *pEnum;
BOOL fSelectionSet = FALSE;
if (fIncludeGuest) {
NLS_STR nlsTemp(MAX_RES_STR_LEN);
if (nlsTemp.LoadString(IDS_GUEST_USERNAME) == ERROR_SUCCESS) {
UINT iItem = (UINT)::SendMessage(hwndLB, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)nlsTemp.QueryPch());
if (iItem != LB_ERR && iItem != LB_ERRSPACE) {
::SendMessage(hwndLB, LB_SETITEMDATA, iItem, 0);
}
}
}
HRESULT hres = pDB->EnumUsers(&pEnum);
if (SUCCEEDED(hres)) {
IUnknown *pUnk;
while (pEnum->Next(1, &pUnk, NULL) == S_OK) {
IUser *pUser;
if (SUCCEEDED(pUnk->QueryInterface(IID_IUser, (void **)&pUser))) {
char szBuf[cchMaxUsername+1];
DWORD cbBuffer = sizeof(szBuf);
if (SUCCEEDED(pUser->GetName(szBuf, &cbBuffer))) {
UINT iItem = (UINT)::SendMessage(hwndLB, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)szBuf);
if (iItem != LB_ERR && iItem != LB_ERRSPACE) {
if (::SendMessage(hwndLB, LB_SETITEMDATA, iItem, (LPARAM)pUser) == LB_ERR)
::SendMessage(hwndLB, LB_SETITEMDATA, iItem, 0);
if (!fSelectionSet) {
if (pszDefaultSelection != NULL && !::stricmpf(szBuf, pszDefaultSelection)) {
fSelectionSet = TRUE;
::SendMessage(hwndLB, LB_SETCURSEL, iItem, 0);
if (pfnSelNotify != NULL)
(*pfnSelNotify)(hwndLB, iItem);
}
}
}
}
/* Note that pUser is not Release()d here, since the
* listbox has a pointer to it.
*/
}
pUnk->Release();
}
if (!fSelectionSet) {
if (pfnSelNotify)
(*pfnSelNotify)(hwndLB, LB_ERR);
}
else {
/* If we select the default item above, then insert more names
* above it, the focus rect and the selection will be different,
* which is confusing if the user tabs to the listbox. Work
* around this by setting the caret index manually.
*/
LRESULT iItem = ::SendMessage(hwndLB, LB_GETCURSEL, 0, 0);
if (iItem != LB_ERR)
::SendMessage(hwndLB, LB_SETCURSEL, iItem, 0);
}
pEnum->Release();
}
if (FAILED(hres))
return hres;
return fSelectionSet ? NOERROR : S_FALSE;
}
BOOL IsMemphis(void)
{
OSVERSIONINFOA osvi;
osvi.dwOSVersionInfoSize = sizeof(osvi);
GetVersionExA(&osvi);
return (VER_PLATFORM_WIN32_WINDOWS == osvi.dwPlatformId &&
(osvi.dwMajorVersion > 4 ||
(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion >= 10)));
}
DWORD InitLogonDialog(HWND hwndDialog, LogonData *pld)
{
DWORD err = WN_NO_NETWORK;
BOOL fSelectionSet = FALSE;
::SetWindowLongPtr(hwndDialog, DWLP_USER, (LONG_PTR)pld);
PlaceDialog(hwndDialog, FALSE);
int idBitmap;
DWORD dwFlags;
if (IsMemphis())
idBitmap = IDB_IMAGE_WIN98_LOGON;
else
idBitmap = IDB_IMAGE_LOGON;
/* The bitmap we show at the top of the logon dialog has black text on a
* transparent background. If the dialog background is very dark, the
* text will be unreadable. In that case we use a static bitmap with
* a white background. For more common background colors, though, we use
* LoadImage to load a transparent image and replace the bitmap in the
* dialog.
*
* CODEWORK: Could try a variant of COLORISLIGHT macro from shell32,
* defview.cpp; it seems pretty aggressive about declaring blues in
* particular as "dark". Maybe we could have the alternate bitmap be
* 3D-mapped as well, but have white text and maybe a white box around
* the Windows flag, then we could always be transparent and just choose
* one or the other at an arbitrary cutoff point.
*/
DWORD clrBtnFace = GetSysColor(COLOR_3DFACE);
if ((LOBYTE(clrBtnFace) >= 128) ||
(LOBYTE(clrBtnFace >> 8) >= 128) ||
(LOBYTE(clrBtnFace >> 16) >= 128)) {
dwFlags = LR_LOADMAP3DCOLORS; /* we'll use a transparent bitmap */
}
else {
idBitmap++; /* advance to static bitmap ID */
dwFlags = LR_DEFAULTCOLOR;
}
pld->hbmTransparent = (HBITMAP)LoadImage(::hInstance,
MAKEINTRESOURCE(idBitmap),
IMAGE_BITMAP, 0, 0,
dwFlags);
if (pld->hbmTransparent != NULL) {
HBITMAP hbmOld = (HBITMAP)SendDlgItemMessage(hwndDialog,
IDC_MAIN_CAPTION,
STM_SETIMAGE,
(WPARAM)IMAGE_BITMAP,
(LPARAM)pld->hbmTransparent);
/* If we set the new bitmap into the control, we got the old one
* back. Delete the old one. We will also have to delete the
* new one when the dialog is dismissed.
*/
if (hbmOld != NULL)
DeleteObject(hbmOld);
}
IUserDatabase *pDB;
if (SUCCEEDED(::CreateUserDatabase(IID_IUserDatabase, (void **)&pDB))) {
HRESULT hres = FillUserList(GetDlgItem(hwndDialog, IDC_USERNAME),
pDB, pld->lpAuthentInfo ? pld->lpAuthentInfo->lpUsername : NULL,
FALSE, UserSelected);
if (SUCCEEDED(hres)) {
err = ERROR_SUCCESS;
::SetFocus(::GetDlgItem(hwndDialog, hres == NOERROR ? IDC_PASSWORD : IDC_USERNAME));
}
pDB->Release();
}
return err;
}
BOOL ValidateLogonDialog(HWND hwndDialog)
{
LRESULT iItem = ::SendDlgItemMessage(hwndDialog, IDC_USERNAME, LB_GETCURSEL, 0, 0);
if (iItem == LB_ERR)
return FALSE;
IUser *pUser = (IUser *)::SendDlgItemMessage(hwndDialog, IDC_USERNAME, LB_GETITEMDATA, iItem, 0);
if (pUser != NULL) {
NLS_STR nlsUsername(cchMaxUsername+1);
if (nlsUsername.QueryError())
return FALSE;
DWORD cbBuffer = nlsUsername.QueryAllocSize();
pUser->GetName(nlsUsername.Party(), &cbBuffer);
nlsUsername.DonePartying();
HWND hwndPassword = ::GetDlgItem(hwndDialog, IDC_PASSWORD);
NLS_STR nlsPassword(::GetWindowTextLength(hwndPassword)+2);
if (nlsPassword.QueryError())
return FALSE;
::GetWindowText(hwndPassword, nlsPassword.Party(), nlsPassword.QueryAllocSize()-1);
nlsPassword.DonePartying();
if (SUCCEEDED(pUser->Authenticate(nlsPassword.QueryPch()))) {
LogonData *pld = (LogonData *)::GetWindowLongPtr(hwndDialog, DWLP_USER);
if (pld->lpAuthentInfo) {
DWORD cbUsername = pld->lpAuthentInfo->cbUsername;
DWORD cbPassword = pld->lpAuthentInfo->cbPassword;
NPSCopyNLS(&nlsUsername, pld->lpAuthentInfo->lpUsername, &cbUsername);
NPSCopyNLS(&nlsPassword, pld->lpAuthentInfo->lpPassword, &cbPassword);
}
if (pld->ppOut) {
*pld->ppOut = pUser;
pUser->AddRef();
}
if (pld->dwFlags & LUA_FORNEXTLOGON) {
CacheLogonCredentials(nlsUsername.QueryPch(), nlsPassword.QueryPch());
}
return TRUE;
}
NLS_STR nlsTitle(MAX_RES_STR_LEN);
NLS_STR nlsMessage(MAX_RES_STR_LEN);
if (!nlsTitle.QueryError() && !nlsMessage.QueryError()) {
nlsTitle.LoadString(IDS_LOGONTITLE);
nlsMessage.LoadString(IDS_BADPASSWORD);
::MessageBox(hwndDialog, nlsMessage.QueryPch(), nlsTitle.QueryPch(), MB_ICONSTOP | MB_OK);
}
::SetFocus(hwndPassword);
::SendMessage(hwndPassword, EM_SETSEL, (WPARAM)(INT)0, (WPARAM)(INT)-1);
}
return FALSE;
}
void DestroyUserList(HWND hwndLB)
{
LRESULT cItems = ::SendMessage(hwndLB, LB_GETCOUNT, 0, 0);
for (LRESULT iItem = 0; iItem < cItems; iItem++) {
IUser *pUser = (IUser *)::SendMessage(hwndLB, LB_GETITEMDATA, iItem, 0);
if (pUser != NULL) {
pUser->Release();
}
}
}
void ExitLogonDialog(HWND hwndDialog, DWORD err)
{
DestroyUserList(GetDlgItem(hwndDialog, IDC_USERNAME));
LogonData *pld = (LogonData *)::GetWindowLongPtr(hwndDialog, DWLP_USER);
if (pld->hbmTransparent != NULL)
DeleteObject(pld->hbmTransparent);
::EndDialog(hwndDialog, err);
}
extern "C" {
INT_PTR LogonDlgProc(
HWND hwndDlg,
UINT msg,
WPARAM wParam,
LPARAM lParam
)
{
#if 0 /*** no help for now ***/
// Help text array
static DWORD aIds[] = {
IDC_DUMMY1, IDH_NET_LOG_USERNAME,
IDD_LOG_USERNAME, IDH_NET_LOG_USERNAME,
IDC_DUMMY2, IDH_NET_LOG_PASSWORD,
IDD_LOG_PASSWORD, IDH_NET_LOG_PASSWORD,
IDC_LOGOFRAME, NO_HELP,
IDC_DUMMY3, NO_HELP,
0,0
};
#endif
switch (msg) {
case WM_INITDIALOG:
{
DWORD err = ::InitLogonDialog(hwndDlg, (LogonData *)lParam);
if (err != ERROR_SUCCESS) {
::ExitLogonDialog(hwndDlg, err);
}
}
return FALSE; /* we set the focus */
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDCANCEL:
::ExitLogonDialog(hwndDlg, WN_CANCEL);
return TRUE; /* we processed a message */
case IDOK:
if (::ValidateLogonDialog(hwndDlg))
::ExitLogonDialog(hwndDlg, WN_SUCCESS);
return TRUE; /* we processed a message */
case IDC_USERNAME:
if (HIWORD(wParam) == LBN_SELCHANGE) {
int iItem = (int)::SendDlgItemMessage(hwndDlg, IDC_USERNAME, LB_GETCURSEL, 0, 0);
UserSelected((HWND)lParam, iItem);
}
}
break;
#if 0 /*** no help for now ***/
case WM_HELP:
WinHelp( ((LPHELPINFO)lParam)->hItemHandle, szHelpFile,
HELP_WM_HELP, (DWORD)(LPVOID)aIds );
return TRUE;
case WM_CONTEXTMENU:
WinHelp( (HWND)wParam, szHelpFile, HELP_CONTEXTMENU,
(DWORD)(LPVOID)aIds );
return TRUE;
#endif
}
return FALSE; /* we didn't process the message */
}
}; /* extern "C" */
DWORD DoLogonDialog(HWND hwndOwner, LPLOGONINFO lpAuthentInfo)
{
LogonData ld;
ld.lpAuthentInfo = lpAuthentInfo;
ld.dwFlags = 0;
ld.ppOut = NULL;
ld.hbmTransparent = NULL;
INT_PTR nRet = ::DialogBoxParam(::hInstance, MAKEINTRESOURCE(IDD_LOGON),
hwndOwner, LogonDlgProc, (LPARAM)&ld);
if (nRet == -1)
return WN_OUT_OF_MEMORY;
else
return (DWORD)nRet;
}
HRESULT DoUserDialog(HWND hwndOwner, DWORD dwFlags, IUser **ppOut)
{
LogonData ld;
ld.lpAuthentInfo = NULL;
ld.dwFlags = dwFlags;
ld.ppOut = ppOut;
if (ppOut != NULL)
*ppOut = NULL;
INT_PTR nRet = ::DialogBoxParam(::hInstance, MAKEINTRESOURCE(IDD_LOGON),
hwndOwner, LogonDlgProc, (LPARAM)&ld);
if (nRet == -1)
return E_OUTOFMEMORY;
else
return (nRet == WN_SUCCESS) ? S_OK : E_ABORT;
}
DWORD TryDefaultLogon(LPCSTR pszUsername, LPCSTR pszPassword, LPLOGONINFO lpAuthentInfo)
{
IUserDatabase *pDB = NULL;
if (FAILED(::CreateUserDatabase(IID_IUserDatabase, (void **)&pDB))) {
return WN_OUT_OF_MEMORY;
}
DWORD err;
IUser *pUser;
if (SUCCEEDED(pDB->GetUser(pszUsername, &pUser))) {
if (SUCCEEDED(pUser->Authenticate(pszPassword)))
err = WN_SUCCESS;
else
err = WN_BAD_PASSWORD;
pUser->Release();
}
else {
err = WN_BAD_USER;
}
pDB->Release();
if (err == WN_SUCCESS) {
DWORD cbUsername = lpAuthentInfo->cbUsername;
DWORD cbPassword = lpAuthentInfo->cbPassword;
NPSCopyString(pszUsername, lpAuthentInfo->lpUsername, &cbUsername);
NPSCopyString(pszPassword, lpAuthentInfo->lpPassword, &cbPassword);
}
return err;
}
SPIENTRY NPLogon(
HWND hwndOwner,
LPLOGONINFO lpAuthentInfo,
LPLOGONINFO lpPreviousAuthentInfo,
LPTSTR lpLogonScript,
DWORD dwBufferSize,
DWORD dwFlags
)
{
/* ignore logon done notification, we only act on logon starting */
if (dwFlags & LOGON_DONE) {
return WN_SUCCESS;
}
/* we have nothing to do if we're not the primary logon provider */
if (!(dwFlags & LOGON_PRIMARY)) {
return WN_SUCCESS;
}
/* make sure profiles are enabled, fall back to windows logon if not */
HKEY hkeyLogon;
DWORD err;
DWORD fProfilesEnabled = FALSE;
DWORD cbData = sizeof(fProfilesEnabled);
err = ::RegOpenKey(HKEY_LOCAL_MACHINE, ::szLogonKey, &hkeyLogon);
if (err != ERROR_SUCCESS)
return WN_NO_NETWORK;
err = ::RegQueryValueEx(hkeyLogon, ::szUserProfiles, NULL, NULL,
(LPBYTE)&fProfilesEnabled, &cbData);
::RegCloseKey(hkeyLogon);
if (err != ERROR_SUCCESS || !fProfilesEnabled)
return WN_NO_NETWORK;
/* If we have cached logon credentials, attempt to use them. */
if (fDoDefaultLogon) {
DeObfuscateString(szDefaultLogonUsername);
DeObfuscateString(szDefaultLogonPassword);
DWORD err = TryDefaultLogon(szDefaultLogonUsername, szDefaultLogonPassword, lpAuthentInfo);
::memsetf(szDefaultLogonUsername, '\0', sizeof(szDefaultLogonUsername));
::memsetf(szDefaultLogonPassword, '\0', sizeof(szDefaultLogonPassword));
fDoDefaultLogon = FALSE;
if (err == WN_SUCCESS)
return WN_SUCCESS;
}
return DoLogonDialog(hwndOwner, lpAuthentInfo);
}
SPIENTRY NPLogoff(
HWND hwndOwner,
LPLOGONINFO lpAuthentInfo,
DWORD dwReason
)
{
return WN_SUCCESS;
}
SPIENTRY NPGetPolicyPath(
LPTSTR lpPath,
LPDWORD lpBufferSize,
DWORD dwFlags
)
{
return WN_NOT_SUPPORTED;
}