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.
531 lines
14 KiB
531 lines
14 KiB
#include <pch.cpp>
|
|
#pragma hdrstop
|
|
|
|
|
|
#define MAX_PW_LEN 160
|
|
#define MAX_STRING_RSC_SIZE 512
|
|
|
|
#define WSZ_NULLSTRING L""
|
|
|
|
extern HINSTANCE g_hInst;
|
|
|
|
extern "C" {
|
|
|
|
typedef DWORD (WINAPI *WNETGETUSERA)(
|
|
LPCSTR lpName,
|
|
LPSTR lpUserName,
|
|
LPDWORD lpnLength
|
|
);
|
|
|
|
extern WNETGETUSERA _WNetGetUserA;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct _GETWINPW_DIALOGARGS
|
|
{
|
|
LPWSTR* ppszPW;
|
|
PST_PROVIDER_HANDLE *phPSTProv;
|
|
|
|
} GETWINPW_DIALOGARGS, *PGETWINPW_DIALOGARGS;
|
|
|
|
|
|
INT_PTR CALLBACK DialogGetWindowsPassword(
|
|
HWND hDlg, // handle to dialog box
|
|
UINT message, // message
|
|
WPARAM wParam, // first message parameter
|
|
LPARAM lParam // second message parameter
|
|
)
|
|
{
|
|
int iRet = IDCANCEL; // assume cancel
|
|
BOOL bSuccess = FALSE; // assume error
|
|
|
|
WCHAR szMessage[MAX_STRING_RSC_SIZE];
|
|
WCHAR szDlgTitle[MAX_STRING_RSC_SIZE];
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
UINT uResString;
|
|
|
|
SetLastError( 0 ); // as per win32 documentation
|
|
if(SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)lParam) == 0) {
|
|
if(GetLastError() != ERROR_SUCCESS) {
|
|
EndDialog(hDlg, IDCANCEL);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if(FIsWinNT()) {
|
|
uResString = IDS_GET_WINDOWS_PASSWORD_NT;
|
|
} else {
|
|
uResString = IDS_GET_WINDOWS_PASSWORD_95;
|
|
}
|
|
|
|
LoadStringU(
|
|
g_hInst,
|
|
uResString,
|
|
szMessage,
|
|
MAX_STRING_RSC_SIZE);
|
|
|
|
SetWindowTextU(GetDlgItem(hDlg, IDC_MESSAGE), szMessage);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
if (LOWORD(wParam) == IDOK)
|
|
{
|
|
PGETWINPW_DIALOGARGS pDlgArgs;
|
|
LPWSTR* ppszPW;
|
|
WCHAR sz1[MAX_PW_LEN];
|
|
|
|
DWORD cch1 = 0;
|
|
BOOL bPasswordVerified;
|
|
|
|
pDlgArgs = (PGETWINPW_DIALOGARGS)GetWindowLongPtr(hDlg, GWLP_USERDATA);
|
|
if(pDlgArgs == 0) break; // TODO: bail out
|
|
|
|
ppszPW = pDlgArgs->ppszPW;
|
|
*ppszPW = NULL;
|
|
|
|
// must impersonate client. If it fails, bail.
|
|
if(!FImpersonateClient(pDlgArgs->phPSTProv))
|
|
break;
|
|
|
|
cch1 = GetDlgItemTextU(
|
|
hDlg,
|
|
IDC_EDIT1,
|
|
sz1,
|
|
MAX_PW_LEN);
|
|
|
|
// push an hourglass to the screen
|
|
HCURSOR curOld;
|
|
curOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
// validate password
|
|
bPasswordVerified = VerifyWindowsPassword(sz1);
|
|
|
|
// put old cursor back
|
|
SetCursor(curOld);
|
|
|
|
FRevertToSelf(pDlgArgs->phPSTProv);
|
|
|
|
// Clear any queued user keyboard entry turds before returning
|
|
MSG sMsg;
|
|
while (PeekMessage(&sMsg, hDlg, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
|
|
;
|
|
|
|
if(!bPasswordVerified)
|
|
{
|
|
szMessage[0] = L'\0';
|
|
LoadStringU(
|
|
g_hInst,
|
|
IDS_PASSWORD_NOVERIFY,
|
|
szMessage,
|
|
MAX_STRING_RSC_SIZE);
|
|
|
|
szDlgTitle[0] = L'\0';
|
|
LoadStringU(
|
|
g_hInst,
|
|
IDS_PASSWORD_ERROR_DLGTITLE,
|
|
szDlgTitle,
|
|
MAX_STRING_RSC_SIZE);
|
|
|
|
// this W implemented in both Win95 & NT!
|
|
MessageBoxW(
|
|
NULL, // hDlg,
|
|
szMessage,
|
|
szDlgTitle,
|
|
MB_OK|MB_ICONEXCLAMATION|MB_SERVICE_NOTIFICATION);
|
|
|
|
SetWindowTextU(GetDlgItem(hDlg, IDC_EDIT1), WSZ_NULLSTRING);
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
// now bite it: save
|
|
|
|
SS_ASSERT(ppszPW != NULL);
|
|
*ppszPW = (LPWSTR)SSAlloc( (cch1+1) * sizeof(WCHAR) );
|
|
if(*ppszPW == NULL) goto cleanup;
|
|
|
|
//
|
|
// sfield: defer copying strings until we know everything succeeded.
|
|
// this way, we don't have to zero these buffers if some
|
|
// allocs + copies succeed, and others fail.
|
|
//
|
|
wcscpy(*ppszPW, sz1);
|
|
|
|
iRet = IDOK;
|
|
bSuccess = TRUE;
|
|
|
|
cleanup:
|
|
|
|
if(cch1) RtlSecureZeroMemory(sz1, cch1 * sizeof(WCHAR));
|
|
|
|
if(!bSuccess)
|
|
{
|
|
if(*ppszPW)
|
|
{
|
|
SSFree(*ppszPW);
|
|
*ppszPW = NULL;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
break; // things went OK, just bail to EndDialog
|
|
|
|
} // IDOK
|
|
|
|
if( LOWORD(wParam) == IDCANCEL )
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
EndDialog(hDlg, iRet);
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
BOOL
|
|
FGetWindowsPassword(
|
|
IN PST_PROVIDER_HANDLE *hPSTProv,
|
|
IN BYTE rgbPasswordDerivedBytes[],
|
|
IN DWORD cbPasswordDerivedBytes
|
|
)
|
|
{
|
|
BOOL fRet;
|
|
LPWSTR pszPW = NULL;
|
|
|
|
|
|
if ((rgbPasswordDerivedBytes == NULL) || (cbPasswordDerivedBytes < A_SHA_DIGEST_LEN))
|
|
return FALSE;
|
|
|
|
|
|
//
|
|
// the general event flow for this routine:
|
|
//
|
|
// 1. Search cache for credentials. WinNT requires impersonating around search.
|
|
// 2. If search fails on Win95, try to get the password directly from MPR
|
|
// 3. If search fails on WinNT, check for special cases like LocalSystem and NETWORK
|
|
// Allow Local System by building fixed credential.
|
|
// Disallow NETWORK because no credentials exist (return FAILURE).
|
|
// 4. If we still don't have credentials, prompt user via UI.
|
|
//
|
|
|
|
|
|
//
|
|
// we must be impersonating around this call !!!
|
|
//
|
|
|
|
if(!FImpersonateClient(hPSTProv))
|
|
return FALSE;
|
|
|
|
fRet = GetPasswordNT(rgbPasswordDerivedBytes);
|
|
|
|
FRevertToSelf(hPSTProv);
|
|
|
|
|
|
// if either GetPassword routine fails
|
|
if (!fRet)
|
|
{
|
|
INT_PTR iRet;
|
|
DWORD cbPassword;
|
|
BOOL fCachePassword = TRUE; // cache the results by default
|
|
BOOL fSpecialCase;
|
|
|
|
if(!FImpersonateClient(hPSTProv))
|
|
goto Ret;
|
|
|
|
//
|
|
// WinNT: check for some special cases, namely, if we are runninng
|
|
// under Local System or Network credentials.
|
|
//
|
|
|
|
fRet = GetSpecialCasePasswordNT(
|
|
rgbPasswordDerivedBytes, // derived bits when fSpecialCase == TRUE
|
|
&fSpecialCase // legal special case encountered?
|
|
);
|
|
|
|
FRevertToSelf(hPSTProv);
|
|
|
|
//
|
|
// if the query failed bail out, since we encountered an illegal
|
|
// or inapproriate condition.
|
|
//
|
|
|
|
if(!fRet)
|
|
goto Ret;
|
|
|
|
//
|
|
// now, set fRet to the result of the special case test.
|
|
// so, if we encountered an allowed special case, we have an
|
|
// validly filled rgbPasswordDerivedBytes buffer. If we didn't
|
|
// encounter a legal special case, we continue on our quest for
|
|
// a password.
|
|
//
|
|
|
|
fRet = fSpecialCase;
|
|
|
|
|
|
//
|
|
// re-evaluate fRet for the special hack for Win95 above.
|
|
//
|
|
|
|
if(!fRet) {
|
|
|
|
// return a validated password
|
|
GETWINPW_DIALOGARGS DialogArgs = {&pszPW, hPSTProv};
|
|
iRet = DialogBoxParam(
|
|
g_hInst,
|
|
MAKEINTRESOURCE(IDD_GET_WINDOWS_PASSWORD),
|
|
NULL,
|
|
DialogGetWindowsPassword,
|
|
(LPARAM)&DialogArgs);
|
|
|
|
if(iRet != IDOK) goto Ret;
|
|
|
|
if (pszPW == NULL)
|
|
goto Ret;
|
|
|
|
//
|
|
// everything went fine, now derive the password bits!
|
|
//
|
|
|
|
cbPassword = WSZ_BYTECOUNT(pszPW) - sizeof(WCHAR) ;
|
|
|
|
// hash pwd, copy out
|
|
A_SHA_CTX sSHAHash;
|
|
A_SHAInit(&sSHAHash);
|
|
A_SHAUpdate(&sSHAHash, (BYTE *) pszPW, cbPassword);
|
|
RtlSecureZeroMemory(pszPW, cbPassword); // sfield: zero the password
|
|
|
|
// Finish off the hash
|
|
A_SHAFinal(&sSHAHash, rgbPasswordDerivedBytes);
|
|
}
|
|
|
|
//
|
|
// now, update the password cache
|
|
//
|
|
if(fCachePassword)
|
|
{
|
|
LUID AuthenticationId;
|
|
|
|
// get user LUID
|
|
|
|
//
|
|
// we must be impersonating around this call !!!
|
|
//
|
|
|
|
if(!FImpersonateClient(hPSTProv))
|
|
goto Ret;
|
|
|
|
if(!GetThreadAuthenticationId(
|
|
GetCurrentThread(),
|
|
&AuthenticationId))
|
|
{
|
|
FRevertToSelf(hPSTProv);
|
|
goto Ret;
|
|
}
|
|
|
|
if (!SetPasswordNT(
|
|
&AuthenticationId,
|
|
rgbPasswordDerivedBytes))
|
|
{
|
|
FRevertToSelf(hPSTProv);
|
|
goto Ret;
|
|
}
|
|
|
|
FRevertToSelf(hPSTProv);
|
|
|
|
} // fCachePassword
|
|
}
|
|
|
|
fRet = TRUE;
|
|
Ret:
|
|
if (pszPW)
|
|
SSFree(pszPW);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
FIsACLSatisfied(
|
|
IN PST_PROVIDER_HANDLE *hPSTProv,
|
|
IN PST_ACCESSRULESET *psRules,
|
|
IN DWORD dwAccess,
|
|
IN OUT LPVOID // coming soon: fill a status structure with data about access attempt
|
|
)
|
|
{
|
|
if ((psRules->cRules == 0)||(psRules->rgRules == NULL))
|
|
return TRUE;
|
|
|
|
//
|
|
// parent exe name. cached through loop
|
|
//
|
|
|
|
LPWSTR pszParentExeName = NULL;
|
|
|
|
//
|
|
// direct caller image. cached through loop
|
|
//
|
|
|
|
LPWSTR pszDirectCaller = NULL;
|
|
|
|
//
|
|
// base address of direct call module
|
|
//
|
|
|
|
DWORD_PTR BaseAddressDirect;
|
|
|
|
//
|
|
// module that is the subject of analysis
|
|
//
|
|
|
|
LPWSTR szHashTarget;
|
|
|
|
|
|
//
|
|
// search for a list of terms that are completely satisfied
|
|
//
|
|
|
|
for(DWORD cRule=0; cRule<psRules->cRules; cRule++)
|
|
{
|
|
// check only those rules that govern the right access
|
|
//
|
|
// loop while we still have dwAccess modes to check
|
|
//
|
|
if (0 == (psRules->rgRules[cRule].AccessModeFlags & dwAccess))
|
|
continue;
|
|
|
|
// evaluate the ith term
|
|
PPST_ACCESSCLAUSE pClause;
|
|
|
|
// walk down list
|
|
for(DWORD cClause=0; cClause<psRules->rgRules[cRule].cClauses; cClause++)
|
|
{
|
|
pClause = &psRules->rgRules[cRule].rgClauses[cClause];
|
|
|
|
// for each term, make sure ALL ENTRIES are satisfied
|
|
|
|
// TODO: what to do if clause data not self relative?
|
|
// not possible at this point in time, but it may come up later
|
|
//
|
|
|
|
switch(pClause->ClauseType & ~PST_SELF_RELATIVE_CLAUSE)
|
|
{
|
|
// for each type, may use the pClause->pbClauseData
|
|
case PST_SECURITY_DESCRIPTOR:
|
|
{
|
|
// passed test
|
|
continue; // next clause
|
|
}
|
|
case PST_AUTHENTICODE:
|
|
{
|
|
// passed test
|
|
continue; // next clause
|
|
}
|
|
case PST_BINARY_CHECK:
|
|
{
|
|
// passed test
|
|
continue; // next clause
|
|
}
|
|
|
|
default:
|
|
// unknown type in ACL: this chain failed, goto next chain
|
|
goto NextRule; // next rule
|
|
}
|
|
}
|
|
|
|
// YES! ALL clauses evaluated and OK
|
|
|
|
// turn off the bits that got us into this clause chain
|
|
dwAccess &= ~ psRules->rgRules[cRule].AccessModeFlags;
|
|
|
|
NextRule:
|
|
|
|
continue;
|
|
}
|
|
|
|
//Cleanup:
|
|
|
|
// cleanup
|
|
if (pszParentExeName)
|
|
SSFree(pszParentExeName);
|
|
|
|
if(pszDirectCaller)
|
|
SSFree(pszDirectCaller);
|
|
|
|
return (dwAccess == 0);
|
|
}
|
|
|
|
|
|
BOOL FGetUser(
|
|
PST_PROVIDER_HANDLE *hPSTProv,
|
|
LPWSTR* ppszUser)
|
|
{
|
|
return FGetUserName(hPSTProv, ppszUser);
|
|
}
|
|
|
|
BOOL
|
|
FGetCallerName(
|
|
IN PST_PROVIDER_HANDLE *hPSTProv,
|
|
OUT LPWSTR* ppszCallerName,
|
|
OUT DWORD_PTR *lpdwBaseAddress
|
|
)
|
|
{
|
|
return FGetParentFileName(hPSTProv, ppszCallerName, lpdwBaseAddress);
|
|
}
|
|
|
|
BOOL
|
|
FGetServerParam(
|
|
IN PST_PROVIDER_HANDLE *hPSTProv,
|
|
IN DWORD dwParam,
|
|
IN LPVOID pData,
|
|
IN OUT DWORD *pcbData
|
|
)
|
|
{
|
|
//
|
|
// check for the server get param that asks for private dispatch interfaces
|
|
//
|
|
|
|
if( dwParam == SS_SERVERPARAM_CALLBACKS &&
|
|
*pcbData >= sizeof( PRIVATE_CALLBACKS )) {
|
|
|
|
PRIVATE_CALLBACKS *PrivateCallbacks = (PRIVATE_CALLBACKS *)pData;
|
|
|
|
PrivateCallbacks->cbSize = sizeof( PRIVATE_CALLBACKS );
|
|
PrivateCallbacks->pfnFGetWindowsPassword = FGetWindowsPassword;
|
|
PrivateCallbacks->pfnAuthenticodeInitPolicy = NULL;
|
|
PrivateCallbacks->pfnAuthenticodeFinalPolicy = NULL;
|
|
|
|
*pcbData = sizeof( PRIVATE_CALLBACKS );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
FSetServerParam(
|
|
IN PST_PROVIDER_HANDLE *hPSTProv,
|
|
IN DWORD dwParam,
|
|
IN LPVOID pData,
|
|
IN DWORD pcbData
|
|
)
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|