#include #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; cRulecRules; 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; cClausergRules[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; }