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.
354 lines
11 KiB
354 lines
11 KiB
/*++
|
|
|
|
Copyright (c) 2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ItgRasXp
|
|
|
|
File Name:
|
|
|
|
ItgRasXp.cpp
|
|
|
|
Abstract:
|
|
|
|
This is the entry point file for the ITG RAS Smartcard Support Applet. This app
|
|
prompts the user for his domain\username and password credentials, and uses
|
|
these to create a *Session credential that is used for NTLM authentication for
|
|
servers on the network which do not use Kerberos.
|
|
|
|
Author:
|
|
|
|
|
|
Environment:
|
|
|
|
Win32, C++
|
|
|
|
Revision History:
|
|
|
|
none
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <windows.h>
|
|
#include <commdlg.h>
|
|
#include <commctrl.h>
|
|
#include <ole2.h>
|
|
#include <stdio.h>
|
|
|
|
#include <lmcons.h>
|
|
#include <wincred.h>
|
|
#include <wincrui.h>
|
|
|
|
#define SECURITY_WIN32
|
|
#include <security.h>
|
|
#include "testaudit.h"
|
|
|
|
#include "res.h"
|
|
|
|
BOOL gfSuccess = FALSE;
|
|
HINSTANCE ghInstance = NULL;
|
|
|
|
#if 0
|
|
|
|
#define TESTKEY L"Environment"
|
|
|
|
#else
|
|
|
|
#define TESTKEY L"Software\\Microsoft\\Connection Manager\\Worldwide Dial-Up RAS to MS Corp"
|
|
|
|
#endif
|
|
|
|
|
|
// see if name valid - check for common mistakes. At the moment, we merely insist that
|
|
// the user fill in both username and password, and that the username contains the '\'
|
|
// character, making it more likely that it is an approved domain\usernaem form.
|
|
BOOL CheckUsername(WCHAR *pszUsername,WCHAR *pszPassword)
|
|
{
|
|
ASSERT(pszUsername);
|
|
ASSERT(pszPassword);
|
|
if ((0 == wcslen(pszUsername)) || (0 == wcslen(pszPassword)))
|
|
{
|
|
CHECKPOINT(2,"Username and password not both filled in.");
|
|
MessageBox(NULL,L"Both username and password must be specified.",L"Error",MB_ICONHAND);
|
|
return FALSE;
|
|
}
|
|
if (NULL == wcschr(pszUsername,L'\\'))
|
|
{
|
|
CHECKPOINT(3,"Username not domain\\username.");
|
|
MessageBox(NULL,L"The username format must be \"domain\\username\".",L"Error",MB_ICONHAND);
|
|
return FALSE;
|
|
}
|
|
else return TRUE;
|
|
}
|
|
|
|
// Attempt to use the credentials that the user entered and return FALSE if they do not
|
|
// appear to be valid on the net. Show the user any errors that arise from trying to validate
|
|
// his credentials. In the event that validation is impossible owing to a network error or some
|
|
// other error not the fault of his credentials, save them anyway, though with a warning.
|
|
|
|
#define DEFAULTSERVER L"\\\\products\\public"
|
|
|
|
BOOL IsCredentialOK(WCHAR *pszUsername,WCHAR *pszPassword)
|
|
{
|
|
ASSERT(pszUsername);
|
|
ASSERT(pszPassword);
|
|
NETRESOURCE stNetResource;
|
|
WCHAR szServer[MAX_PATH + 1]; // to hold test host string from registry
|
|
BOOL fKeyFound = FALSE;
|
|
DWORD dwErr = 0;
|
|
DWORD dwSize = 0; // for return from open connection
|
|
DWORD dwResult = 0; // for return from open connection
|
|
HKEY hKey= NULL; // reg key rread
|
|
DWORD dwType; // reg key read return
|
|
DWORD dwDataSize = 0; // reg key read in/out
|
|
|
|
memset(&stNetResource,0,sizeof(NETRESOURCE));
|
|
|
|
// prepare the servername preset to the default
|
|
wcsncpy(szServer,DEFAULTSERVER,MAX_PATH);
|
|
|
|
// Look for server in registry HKCU. If found, use it to overwrite the default server
|
|
if ((!fKeyFound) && (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER,TESTKEY,0,KEY_READ,&hKey)))
|
|
{
|
|
if ((hKey) && (ERROR_SUCCESS == RegQueryValueEx(hKey,L"RAS Test Host",0,&dwType,(LPBYTE) NULL,&dwDataSize)))
|
|
{
|
|
// key value exists and is of size dwDataSize
|
|
WCHAR *pString = (WCHAR *) LocalAlloc(LMEM_FIXED,dwDataSize);
|
|
ASSERT(pString);
|
|
ASSERT(dwType == REG_SZ);
|
|
if (pString)
|
|
{
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hKey,L"RAS Test Host",0,&dwType,(LPBYTE) pString,&dwDataSize))
|
|
{
|
|
CHECKPOINT(9,"Override server found in registry in HKCU");
|
|
wcsncpy(szServer,pString,dwDataSize / sizeof(WCHAR));
|
|
fKeyFound = TRUE;
|
|
}
|
|
LocalFree(pString);
|
|
}
|
|
}
|
|
RegCloseKey(hKey);
|
|
hKey = NULL;
|
|
}
|
|
|
|
// Look for server in registry HKLM.
|
|
if ((!fKeyFound) && (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,TESTKEY,0,KEY_READ,&hKey)))
|
|
{
|
|
if ((hKey) && (ERROR_SUCCESS == RegQueryValueEx(hKey,L"RAS Test Host",0,&dwType,(LPBYTE) NULL,&dwDataSize)))
|
|
{
|
|
// key value exists and is of size dwDataSize
|
|
WCHAR *pString = (WCHAR *) LocalAlloc(LMEM_FIXED,dwDataSize);
|
|
ASSERT(pString);
|
|
ASSERT(dwType == REG_SZ);
|
|
if (pString)
|
|
{
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hKey,L"RAS Test Host",0,&dwType,(LPBYTE) pString,&dwDataSize))
|
|
{
|
|
CHECKPOINT(8,"Override server found in registry in HKLM");
|
|
wcsncpy(szServer,pString,dwDataSize / sizeof(WCHAR));
|
|
fKeyFound = TRUE;
|
|
}
|
|
LocalFree(pString);
|
|
}
|
|
}
|
|
RegCloseKey(hKey);
|
|
hKey = NULL;
|
|
}
|
|
|
|
#if TESTAUDIT
|
|
if (!fKeyFound) CHECKPOINT(10,"No override server found in registry");
|
|
#endif
|
|
|
|
stNetResource.dwType = RESOURCETYPE_DISK;
|
|
stNetResource.lpLocalName = NULL;
|
|
stNetResource.lpRemoteName = szServer;
|
|
stNetResource.lpProvider = NULL;
|
|
|
|
dwErr = WNetUseConnection( NULL,
|
|
&stNetResource,
|
|
pszPassword,
|
|
pszUsername,
|
|
0,
|
|
NULL, // lpAccessName
|
|
&dwSize, // size of lpAccessName buffer
|
|
&dwResult);
|
|
|
|
if (dwErr == S_OK)
|
|
{
|
|
// On successful connection, tear down the connection and return success
|
|
WNetCancelConnection2(szServer, 0, TRUE);
|
|
return TRUE;
|
|
}
|
|
|
|
// Errors are handled by presenting a message box. If the server was found and rejected
|
|
// the creds, don't save them - give the user a chance to correct. If the server was
|
|
// unavailable, save the creds anyway, but warn the user that they were unvalidated.
|
|
switch (dwErr)
|
|
{
|
|
case ERROR_ACCESS_DENIED:
|
|
case ERROR_INVALID_PASSWORD:
|
|
// announce that the password is no good
|
|
CHECKPOINT(7,"Reached the server, but the creds were no good");
|
|
MessageBox(NULL,L"The entered username and password are not correct",L"Error",MB_ICONHAND);
|
|
break;
|
|
|
|
case ERROR_NO_NET_OR_BAD_PATH:
|
|
case ERROR_NO_NETWORK:
|
|
case ERROR_EXTENDED_ERROR:
|
|
case ERROR_BAD_NET_NAME:
|
|
case ERROR_BAD_PROVIDER:
|
|
default:
|
|
CHECKPOINT(6,"Not able to validate - server unreachable");
|
|
MessageBox(NULL,L"Your username and password will be saved for this session, though they could not be verified. They may be incorrect.",L"Error",MB_ICONHAND);
|
|
return TRUE; // permit them to be saved anyway
|
|
// announce that we cannot validate, and let them save it anyway
|
|
break;
|
|
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// Store the user's entered credentials on the keyring as a session persisted *Session cred.
|
|
// Call IsCredentialOK() before storing. If the credentials don't appear correct, present
|
|
// a message box describing the error and leave the dialog up.
|
|
|
|
BOOL WriteDomainCreds(WCHAR *pszUsername,WCHAR *pszPassword)
|
|
{
|
|
CREDENTIAL cred;
|
|
|
|
if (!CheckUsername(pszUsername,pszPassword))
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (!IsCredentialOK(pszUsername,pszPassword))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
memset(&cred,0,sizeof(CREDENTIAL));
|
|
cred.TargetName = CRED_SESSION_WILDCARD_NAME_W;
|
|
cred.UserName = pszUsername;
|
|
cred.CredentialBlob = (LPBYTE) pszPassword;
|
|
cred.CredentialBlobSize = (wcslen(pszPassword) * sizeof(WCHAR));
|
|
cred.Type = CRED_TYPE_DOMAIN_PASSWORD;
|
|
cred.Persist = CRED_PERSIST_SESSION;
|
|
return CredWrite(&cred,0);
|
|
}
|
|
|
|
INT_PTR CALLBACK DialogProc(
|
|
HWND hwnd,
|
|
UINT msg,
|
|
WPARAM wparam,
|
|
LPARAM lparam)
|
|
{
|
|
INT_PTR ret;
|
|
HWND hwndCred = NULL;
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_COMMAND:
|
|
// Button clicks.
|
|
switch(LOWORD(wparam))
|
|
{
|
|
case IDOK:
|
|
if (HIWORD(wparam) == BN_CLICKED)
|
|
{
|
|
WCHAR szUser[UNLEN + 1];
|
|
WCHAR szPass[PWLEN + 1];
|
|
szUser[0] = 0;
|
|
szPass[0] = 0;
|
|
HWND hCc = GetDlgItem(hwnd,IDC_CRED);
|
|
ASSERT(hCc);
|
|
Credential_GetUserName(hCc,szUser,UNLEN);
|
|
Credential_GetPassword(hCc,szPass,PWLEN);
|
|
// Get contents of the cred control controls and write the session cred
|
|
gfSuccess = WriteDomainCreds(szUser,szPass);
|
|
SecureZeroMemory(szPass,sizeof(szPass));
|
|
if (gfSuccess)
|
|
{
|
|
EndDialog(hwnd,IDOK);
|
|
}
|
|
}
|
|
break;
|
|
case IDCANCEL:
|
|
if (HIWORD(wparam) == BN_CLICKED)
|
|
{
|
|
CHECKPOINT(5,"Leave the dialog by cancel.");
|
|
// Exit doing nothing
|
|
EndDialog(hwnd,IDCANCEL);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
//return DefWindowProc(hwnd, msg, wparam, lparam);
|
|
return FALSE;
|
|
}
|
|
|
|
int WINAPI WinMain (
|
|
HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
LPSTR lpszCmdParam,
|
|
int nCmdShow)
|
|
{
|
|
CHECKPOINTINIT;
|
|
ghInstance = hInstance;
|
|
//OleInitialize(NULL);
|
|
|
|
INITCOMMONCONTROLSEX stICC;
|
|
BOOL fICC;
|
|
stICC.dwSize = sizeof(INITCOMMONCONTROLSEX);
|
|
stICC.dwICC = ICC_WIN95_CLASSES | ICC_STANDARD_CLASSES;
|
|
fICC = InitCommonControlsEx(&stICC);
|
|
|
|
// Silent fail if there is no preexisting cert credential.
|
|
CREDENTIAL *pCred = NULL;
|
|
BOOL fOK = CredRead(L"*Session",CRED_TYPE_DOMAIN_CERTIFICATE,0,&pCred);
|
|
CredFree(pCred);
|
|
if (!fOK)
|
|
{
|
|
CHECKPOINT(1,"No preexisting certificate cred for *Session");
|
|
CHECKPOINTFINISH;
|
|
return 1;
|
|
}
|
|
|
|
// Gen up credui
|
|
if (!CredUIInitControls())
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
// show the ui
|
|
INT_PTR iErr = DialogBoxParam(
|
|
hInstance,
|
|
MAKEINTRESOURCE(IDD_MAINDIALOG),
|
|
GetForegroundWindow(),
|
|
DialogProc,
|
|
NULL);
|
|
|
|
if (iErr != IDOK && iErr != IDCANCEL)
|
|
{
|
|
MessageBox(NULL,L"An error occurred saving credential information.",L"Error",MB_OK);
|
|
CHECKPOINTFINISH;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
CHECKPOINT(4,"Sucessfully saved a cred.");
|
|
CHECKPOINTFINISH;
|
|
return 1;
|
|
}
|
|
}
|
|
|