#include #include "tracing.h" #include "utils.h" //------------------------------------ // Allocates storage for RPC transactions. The RPC stubs will either call // MIDL_user_allocate when it needs to un-marshall data into a buffer // that the user must free. RPC servers will use MIDL_user_allocate to // allocate storage that the RPC server stub will free after marshalling // the data. PVOID MIDL_user_allocate(IN size_t NumBytes) { PVOID pMem; pMem = (NumBytes > 0) ? LocalAlloc(LMEM_ZEROINIT,NumBytes) : NULL; DbgPrint((TRC_MEM, "[MIDL_user_allocate(%d)=0x%p]", NumBytes, pMem)); return pMem; } //------------------------------------ // Frees storage used in RPC transactions. The RPC client can call this // function to free buffer space that was allocated by the RPC client // stub when un-marshalling data that is to be returned to the client. // The Client calls MIDL_user_free when it is finished with the data and // desires to free up the storage. // The RPC server stub calls MIDL_user_free when it has completed // marshalling server data that is to be passed back to the client. VOID MIDL_user_free(IN LPVOID MemPointer) { DbgPrint((TRC_MEM, "[MIDL_user_free(0x%p)]", MemPointer)); if (MemPointer != NULL) LocalFree(MemPointer); } //------------------------------------ // Allocates general usage memory from the process heap PVOID Process_user_allocate(IN size_t NumBytes) { PVOID pMem; pMem = (NumBytes > 0) ? HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, NumBytes) : NULL; DbgPrint((TRC_MEM, "[MemAlloc(%d)=0x%p]", NumBytes, pMem)); return pMem; } //------------------------------------ // Frees general usage memory VOID Process_user_free(IN LPVOID pMem) { DbgPrint((TRC_MEM, "[MemFree(0x%p)]", pMem)); if (pMem != NULL) HeapFree(GetProcessHeap(), 0, (pMem)); } //----------------------------------------------------------- // Searches pwzcConfig in the list pwzcVList. The entries are // matched exclusively based on the matching SSIDs and on // matching Infrastructure Mode. // [in] pwzcVList: Set of WZC_WLAN_CONFIGs to search in // [in] pwzcConfig: WZC_WLAN_CONFIG to look for // [in] nIdx: index in pwzcVList to start searching from // Returns: Pointer to the entry that matches pwzcConfig or NULL // if none matches PWZC_WLAN_CONFIG WzcFindConfig( PWZC_802_11_CONFIG_LIST pwzcList, PWZC_WLAN_CONFIG pwzcConfig, ULONG nIdx) { PWZC_WLAN_CONFIG pMatchingConfig = NULL; // if there is no config in pwzcList, there is no reason in // looking further if (pwzcList != NULL) { ULONG i; // for each of the visible SSIDs, see if it matches the given one for (i = nIdx; i < pwzcList->NumberOfItems; i++) { PWZC_WLAN_CONFIG pCrt; pCrt = &(pwzcList->Config[i]); // the SSIDs match if they have the same InfrastructureMode, their // SSID strings have the same length and are the same if (pCrt->InfrastructureMode == pwzcConfig->InfrastructureMode && pCrt->Ssid.SsidLength == pwzcConfig->Ssid.SsidLength && RtlCompareMemory(pCrt->Ssid.Ssid, pwzcConfig->Ssid.Ssid, pCrt->Ssid.SsidLength) == pCrt->Ssid.SsidLength) { pMatchingConfig = pCrt; break; } } } return pMatchingConfig; } //--------------------------------------------------------------------- // Matches the content of the two configurations one against the other. // [in] pwzcConfigA: | configs to match // [in] pwzcConfigB: | // [in/out] pbWepDiffOnly: TRUE if there is a difference and the difference is exclusively // in the WEP Key index or in WEP Key Material. Otherwise is false. // Returns: TRUE if the configs match, FALSE otherwise; BOOL WzcMatchConfig( PWZC_WLAN_CONFIG pwzcConfigA, PWZC_WLAN_CONFIG pwzcConfigB, PBOOL pbWepDiffOnly) { BOOL bDiff; BOOL bWepDiff; bDiff = (pwzcConfigA->dwCtlFlags & WZCCTL_WEPK_PRESENT) != (pwzcConfigB->dwCtlFlags & WZCCTL_WEPK_PRESENT); bDiff = bDiff || (pwzcConfigA->Privacy != pwzcConfigB->Privacy); bDiff = bDiff || (pwzcConfigA->InfrastructureMode != pwzcConfigB->InfrastructureMode); bDiff = bDiff || (pwzcConfigA->AuthenticationMode != pwzcConfigB->AuthenticationMode); bDiff = bDiff || (memcmp(&pwzcConfigA->Ssid, &pwzcConfigB->Ssid, sizeof(NDIS_802_11_SSID)) != 0); bWepDiff = (pwzcConfigA->KeyIndex != pwzcConfigB->KeyIndex); bWepDiff = bWepDiff || (pwzcConfigA->KeyLength != pwzcConfigB->KeyLength); bWepDiff = bWepDiff || (memcmp(&pwzcConfigA->KeyMaterial, &pwzcConfigB->KeyMaterial, WZCCTL_MAX_WEPK_MATERIAL) != 0); if (pbWepDiffOnly != NULL) *pbWepDiffOnly = (!bDiff && bWepDiff); return !bDiff && !bWepDiff; } //----------------------------------------------------------- // Converts an NDIS_802_11_BSSID_LIST object to an equivalent // (imaged) WZC_802_11_CONFIG_LIST // [in] pndList: NDIS BSSID list to convert // Returns: Pointer to the list of copied WZC configurations PWZC_802_11_CONFIG_LIST WzcNdisToWzc( PNDIS_802_11_BSSID_LIST pndList) { PWZC_802_11_CONFIG_LIST pwzcList = NULL; // if there is no NDIS list, don't do anything if (pndList != NULL) { // allocate space for the WZC image pwzcList = (PWZC_802_11_CONFIG_LIST) MemCAlloc(FIELD_OFFSET(WZC_802_11_CONFIG_LIST, Config) + pndList->NumberOfItems * sizeof(WZC_WLAN_CONFIG)); // in case allocation failed, return NULL, the caller will know it // is an error since he passed down a !NULL pointer. if (pwzcList != NULL) { UINT i; LPBYTE prawList = (LPBYTE)&(pndList->Bssid[0]); pwzcList->NumberOfItems = pndList->NumberOfItems; // for each of the NDIS configs, copy the relevant data into the WZC config for (i = 0; i < pwzcList->NumberOfItems; i++) { PWZC_WLAN_CONFIG pwzcConfig; PNDIS_WLAN_BSSID pndBssid; pwzcConfig = &(pwzcList->Config[i]); pndBssid = (PNDIS_WLAN_BSSID)prawList; prawList += pndBssid->Length; pwzcConfig->Length = sizeof(WZC_WLAN_CONFIG); memcpy(&(pwzcConfig->MacAddress), &(pndBssid->MacAddress), sizeof(NDIS_802_11_MAC_ADDRESS)); memcpy(&(pwzcConfig->Ssid), &(pndBssid->Ssid), sizeof(NDIS_802_11_SSID)); pwzcConfig->Privacy = pndBssid->Privacy; pwzcConfig->Rssi = pndBssid->Rssi; pwzcConfig->NetworkTypeInUse = pndBssid->NetworkTypeInUse; memcpy(&(pwzcConfig->Configuration), &(pndBssid->Configuration), sizeof(NDIS_802_11_CONFIGURATION)); pwzcConfig->InfrastructureMode = pndBssid->InfrastructureMode; memcpy(&(pwzcConfig->SupportedRates), &(pndBssid->SupportedRates), sizeof(NDIS_802_11_RATES)); } } } return pwzcList; } //----------------------------------------------------------- // WzcCleanupWzcList: Cleanup a list of WZC_WLAN_CONFIG objects VOID WzcCleanupWzcList( PWZC_802_11_CONFIG_LIST pwzcList) { if (pwzcList != NULL) { UINT i; for (i=0; iNumberOfItems; i++) MemFree(pwzcList->Config[i].rdUserData.pData); MemFree(pwzcList); } } //----------------------------------------------------------- // RccsInit: Initializes an RCCS structure DWORD RccsInit(PRCCS_SYNC pRccs) { DWORD dwErr = ERROR_SUCCESS; // assume pRccs is not null (it shouldn't be under any // circumstances) __try { InitializeCriticalSection(&(pRccs->csMutex)); } __except(EXCEPTION_EXECUTE_HANDLER) { dwErr = GetExceptionCode(); } // access through this structure will be paired as Enter/Leave calls // Object deletion will bump down the ref counter which will reach 0 // and will trigger the destruction code. pRccs->nRefCount = 1; return dwErr; } //----------------------------------------------------------- // RccsInit: Deletes an RCCS structure DWORD RccsDestroy(PRCCS_SYNC pRccs) { // assume pRccs is not null (it shouldn't be under any // circumstances) DeleteCriticalSection(&(pRccs->csMutex)); return ERROR_SUCCESS; } //----------------------------------------------------------- // WzcCryptBuffer: Randomly generates a nBufLen bytes in the range // [loByte hiByte], all stored in pBuffer (buffer assumed preallocated) // Returns a win32 error code. DWORD WzcRndGenBuffer(LPBYTE pBuffer, UINT nBufLen, BYTE loByte, BYTE hiByte) { DWORD dwErr = ERROR_SUCCESS; HCRYPTPROV hProv = (HCRYPTPROV)NULL; if (loByte >= hiByte) dwErr = ERROR_INVALID_PARAMETER; if (dwErr == ERROR_SUCCESS) { // acquire the crypt context if (!CryptAcquireContext( &hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) dwErr = GetLastError(); DbgAssert((dwErr == ERROR_SUCCESS, "CryptAcquireContext failed with err=%d", dwErr)); } // randomly generate the buffer of bytes if (dwErr == ERROR_SUCCESS) { if (!CryptGenRandom( hProv, nBufLen, pBuffer)) dwErr = GetLastError(); DbgAssert((dwErr == ERROR_SUCCESS, "CryptGenRandom failed with err=%d", dwErr)); } // fix each byte from the buffer within the given range if (dwErr == ERROR_SUCCESS) { while (nBufLen > 0) { *pBuffer = loByte + *pBuffer % (hiByte - loByte + 1); pBuffer++; nBufLen--; } } // release the crypt context if (hProv != (HCRYPTPROV)NULL) CryptReleaseContext(hProv,0); return dwErr; } //----------------------------------------------------------- // WzcIsNullBuffer: Checks whether a buffer of nBufLen characters // is all filled with null characters. BOOL WzcIsNullBuffer(LPBYTE pBuffer, UINT nBufLen) { for (;nBufLen > 0 && *pBuffer == 0; pBuffer++, nBufLen--); return (nBufLen == 0); } //----------------------------------------------------------- // WzcSSKClean: Cleans up the PSEC_SESSION_KEYS object given as parameter VOID WzcSSKClean(PSEC_SESSION_KEYS pSSK) { if (pSSK->dblobSendKey.pbData != NULL) { LocalFree(pSSK->dblobSendKey.pbData); pSSK->dblobSendKey.cbData = 0; pSSK->dblobSendKey.pbData = NULL; } if (pSSK->dblobReceiveKey.pbData != NULL) { LocalFree(pSSK->dblobReceiveKey.pbData); pSSK->dblobReceiveKey.cbData = 0; pSSK->dblobReceiveKey.pbData = NULL; } } //----------------------------------------------------------- // WzcSSKFree: Frees up the memory used by the PSEC_SESSION_KEYS parameter VOID WzcSSKFree(PSEC_SESSION_KEYS pSSK) { if (pSSK != NULL) { WzcSSKClean(pSSK); MemFree(pSSK); } } //----------------------------------------------------------- // WzcSSKEncrypt: Creates/Allocates a SEC_SESSION_KEYS object // by encrypting the SESSION_KEYS object provided as parameter. DWORD WzcSSKEncrypt(PSEC_SESSION_KEYS pSSK, PSESSION_KEYS pSK) { DWORD dwErr = ERROR_SUCCESS; DATA_BLOB blobIn; DATA_BLOB blobSndOut = {0, NULL}; DATA_BLOB blobRcvOut = {0, NULL}; if (pSSK == NULL || pSK == NULL) { dwErr = ERROR_INVALID_PARAMETER; goto exit; } blobIn.cbData = pSK->dwKeyLength; blobIn.pbData = pSK->bSendKey; if (!CryptProtectData( &blobIn, // DATA_BLOB *pDataIn, L"", // LPCWSTR szDataDescr, NULL, // DATA_BLOB *pOptionalEntropy, NULL, // PVOID pvReserved, NULL, // CRYPTPROTECT_PROMPTSTRUCT *pPromptStrct, 0, // DWORD dwFlags, &blobSndOut)) // DATA_BLOB *pDataOut { dwErr = GetLastError(); goto exit; } blobIn.cbData = pSK->dwKeyLength; blobIn.pbData = pSK->bReceiveKey; if (!CryptProtectData( &blobIn, // DATA_BLOB *pDataIn, L"", // LPCWSTR szDataDescr, NULL, // DATA_BLOB *pOptionalEntropy, NULL, // PVOID pvReserved, NULL, // CRYPTPROTECT_PROMPTSTRUCT *pPromptStrct, 0, // DWORD dwFlags, &blobRcvOut)) // DATA_BLOB *pDataOut { dwErr = GetLastError(); goto exit; } pSSK->dblobSendKey = blobSndOut; pSSK->dblobReceiveKey = blobRcvOut; exit: if (dwErr != ERROR_SUCCESS) { if (blobSndOut.pbData != NULL) LocalFree(blobSndOut.pbData); if (blobRcvOut.pbData != NULL) LocalFree(blobRcvOut.pbData); } return dwErr; } //----------------------------------------------------------- // WzcSSKDecrypt: Creates/Allocates a SESSION_KEYS object // by dencrypting the SEC_SESSION_KEYS object provided as parameter. DWORD WzcSSKDecrypt(PSEC_SESSION_KEYS pSSK, PSESSION_KEYS pSK) { DWORD dwErr = ERROR_SUCCESS; DATA_BLOB blobSndOut = {0, NULL}; DATA_BLOB blobRcvOut = {0, NULL}; if (pSSK == NULL || pSK == NULL) { dwErr = ERROR_INVALID_PARAMETER; goto exit; } if (!CryptUnprotectData( &(pSSK->dblobSendKey), NULL, NULL, NULL, NULL, 0, &blobSndOut)) { dwErr = GetLastError(); goto exit; } if (blobSndOut.cbData > MAX_SESSION_KEY_LENGTH) { dwErr = ERROR_INVALID_DATA; goto exit; } if (!CryptUnprotectData( &(pSSK->dblobReceiveKey), NULL, NULL, NULL, NULL, 0, &blobRcvOut)) { dwErr = GetLastError(); goto exit; } if (blobRcvOut.cbData != blobSndOut.cbData) { dwErr = ERROR_INVALID_DATA; goto exit; } pSK->dwKeyLength = blobSndOut.cbData; memcpy(pSK->bSendKey, blobSndOut.pbData, blobSndOut.cbData); memcpy(pSK->bReceiveKey, blobRcvOut.pbData, blobRcvOut.cbData); exit: if (blobSndOut.pbData != NULL) LocalFree(blobSndOut.pbData); if (blobRcvOut.pbData != NULL) LocalFree(blobRcvOut.pbData); return dwErr; }