/*++ Copyright (c) 2001, Microsoft Corporation Module Name: eloptimize.c Abstract: The module deals with functions related to user identity selection optimization Revision History: sachins, July 26 2001, Created --*/ #include "pcheapol.h" #pragma hdrstop // // ElGetUserIdentityOptimized // // Description: // // Function called to fetch identity of the user // If UI is required then send identity request to user module // // Arguments: // pPCB - Current interface context // // Return values: // ERROR_REQUIRE_INTERACTIVE_WORKSTATION - User interaction required // Other - can send out user identity without user interaction // // DWORD ElGetUserIdentityOptimized ( IN EAPOL_PCB *pPCB ) { DWORD dwIndex = 0; CHAR *pszIdentity = NULL; BYTE *pUserDataOut = NULL; DWORD dwSizeOfUserDataOut = 0; LPWSTR lpwszIdentity = NULL; HWND hwndOwner = NULL; PBYTE pbUserIn = NULL; DWORD cbData = 0; DWORD dwInSize = 0; PBYTE pbAuthData = NULL; HANDLE hLib = NULL; RASEAPFREE pFreeFunc = NULL; RASEAPGETIDENTITY pIdenFunc = NULL; BYTE *pbSSID = NULL; DWORD dwSizeOfSSID = 0; BOOLEAN fVerifyPhase = TRUE; DWORD dwRetCode1 = NO_ERROR; DWORD dwRetCode = NO_ERROR; do { if (pPCB->pSSID) { pbSSID = pPCB->pSSID->Ssid; dwSizeOfSSID = pPCB->pSSID->SsidLength; } // Get the size of the user blob if ((dwRetCode = ElGetEapUserInfo ( pPCB->hUserToken, pPCB->pwszDeviceGUID, pPCB->dwEapTypeToBeUsed, dwSizeOfSSID, pbSSID, NULL, &dwInSize )) != NO_ERROR) { if (dwRetCode == ERROR_BUFFER_TOO_SMALL) { if (dwInSize <= 0) { // No blob stored in the registry // Continue processing TRACE0 (USER, "ElGetUserIdentityOptimized: NULL sized user data"); pbUserIn = NULL; } else { // Allocate memory to hold the blob pbUserIn = MALLOC (dwInSize); if (pbUserIn == NULL) { dwRetCode = ERROR_NOT_ENOUGH_MEMORY; TRACE0 (USER, "ElGetUserIdentityOptimized: Error in memory allocation for User data"); break; } if ((dwRetCode = ElGetEapUserInfo ( pPCB->hUserToken, pPCB->pwszDeviceGUID, pPCB->dwEapTypeToBeUsed, dwSizeOfSSID, pbSSID, pbUserIn, &dwInSize )) != NO_ERROR) { TRACE1 (USER, "ElGetUserIdentityOptimized: ElGetEapUserInfo failed with %ld", dwRetCode); break; } } } else { // User info may not have been created till now // which is valid condition to proceed if (dwRetCode != ERROR_FILE_NOT_FOUND) { TRACE1 (USER, "ElGetUserIdentityOptimized: ElGetEapUserInfo size estimation failed with error %ld", dwRetCode); break; } else { dwRetCode = NO_ERROR; } } } // The EAP dll has already been loaded by the state machine // Retrieve the handle to the dll from the global EAP table if ((dwIndex = ElGetEapTypeIndex (pPCB->dwEapTypeToBeUsed)) == -1) { TRACE1 (USER, "ElGetUserIdentityOptimized: ElGetEapTypeIndex finds no dll for EAP index %ld", pPCB->dwEapTypeToBeUsed); dwRetCode = ERROR_CAN_NOT_COMPLETE; break; } hLib = g_pEapTable[dwIndex].hInstance; pIdenFunc = (RASEAPGETIDENTITY)GetProcAddress(hLib, "RasEapGetIdentity"); pFreeFunc = (RASEAPFREE)GetProcAddress(hLib, "RasEapFreeMemory"); if ((pFreeFunc == NULL) || (pIdenFunc == NULL)) { TRACE0 (USER, "ElGetUserIdentityOptimized: pIdenFunc or pFreeFunc does not exist in the EAP implementation"); dwRetCode = ERROR_CAN_NOT_COMPLETE; break; } // Get the size of the EAP blob if ((dwRetCode = ElGetCustomAuthData ( pPCB->pwszDeviceGUID, pPCB->dwEapTypeToBeUsed, dwSizeOfSSID, pbSSID, NULL, &cbData )) != NO_ERROR) { if (dwRetCode == ERROR_BUFFER_TOO_SMALL) { if (cbData == 0) { // No EAP blob stored in the registry TRACE0 (USER, "ElGetUserIdentityOptimized: NULL sized EAP blob"); pbAuthData = NULL; } else { // Allocate memory to hold the blob pbAuthData = MALLOC (cbData); if (pbAuthData == NULL) { dwRetCode = ERROR_NOT_ENOUGH_MEMORY; TRACE0 (USER, "ElGetUserIdentityOptimized: Error in memory allocation for EAP blob"); break; } if ((dwRetCode = ElGetCustomAuthData ( pPCB->pwszDeviceGUID, pPCB->dwEapTypeToBeUsed, dwSizeOfSSID, pbSSID, pbAuthData, &cbData )) != NO_ERROR) { TRACE1 (USER, "ElGetUserIdentityOptimized: ElGetCustomAuthData failed with %ld", dwRetCode); break; } } } else { // CustomAuthData for "Default" is always created for an // interface when EAPOL starts up TRACE1 (USER, "ElGetUserIdentityOptimized: ElGetCustomAuthData size estimation failed with error %ld", dwRetCode); break; } } if (!ImpersonateLoggedOnUser (pPCB->hUserToken)) { dwRetCode = GetLastError(); TRACE1 (USER, "ElGetUserIdentityOptimized: ImpersonateLoggedOnUser failed with error %ld", dwRetCode); break; } if (pIdenFunc) if ((dwRetCode = (*(pIdenFunc))( pPCB->dwEapTypeToBeUsed, fVerifyPhase?NULL:hwndOwner, // hwndOwner ((fVerifyPhase?RAS_EAP_FLAG_NON_INTERACTIVE:0) | RAS_EAP_FLAG_8021X_AUTH), // dwFlags NULL, // lpszPhonebook pPCB->pwszFriendlyName, // lpszEntry pbAuthData, // Connection data cbData, // Count of pbAuthData pbUserIn, // User data for port dwInSize, // Size of user data &pUserDataOut, &dwSizeOfUserDataOut, &lpwszIdentity )) != NO_ERROR) { TRACE1 (USER, "ElGetUserIdentityOptimized: Error in calling GetIdentity = %ld", dwRetCode); if (!RevertToSelf()) { dwRetCode = GetLastError(); TRACE1 (USER, "ElGetUserIdentity: Error in RevertToSelf = %ld", dwRetCode); dwRetCode = ERROR_BAD_IMPERSONATION_LEVEL; break; } if (fVerifyPhase) { if (dwRetCode == ERROR_NO_EAPTLS_CERTIFICATE) { DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_NO_CERTIFICATE_USER); } if (dwRetCode == ERROR_INTERACTIVE_MODE) { DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_DESKTOP_REQUIRED_IDENTITY); } // If interactive mode is required, return error accordingly if ((dwRetCode == ERROR_INTERACTIVE_MODE) || (dwRetCode == ERROR_NO_EAPTLS_CERTIFICATE) || (dwRetCode == ERROR_NO_SMART_CARD_READER)) { dwRetCode = ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION; break; } DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_ERROR_GET_IDENTITY, EAPOLAuthTypes[EAPOL_USER_AUTHENTICATION], dwRetCode); } break; } if (!RevertToSelf()) { dwRetCode = GetLastError(); TRACE1 (USER, "ElGetUserIdentityOptimized: Error in RevertToSelf = %ld", dwRetCode); dwRetCode = ERROR_BAD_IMPERSONATION_LEVEL; break; } // Fill in the returned information into the PCB fields for // later authentication if (pPCB->pCustomAuthUserData != NULL) { FREE (pPCB->pCustomAuthUserData); pPCB->pCustomAuthUserData = NULL; } pPCB->pCustomAuthUserData = MALLOC (dwSizeOfUserDataOut + sizeof (DWORD)); if (pPCB->pCustomAuthUserData == NULL) { TRACE1 (USER, "ElGetUserIdentityOptimized: Error in allocating memory for UserInfo = %ld", dwRetCode); dwRetCode = ERROR_NOT_ENOUGH_MEMORY; break; } pPCB->pCustomAuthUserData->dwSizeOfCustomAuthData = dwSizeOfUserDataOut; if ((dwSizeOfUserDataOut != 0) && (pUserDataOut != NULL)) { memcpy ((BYTE *)pPCB->pCustomAuthUserData->pbCustomAuthData, (BYTE *)pUserDataOut, dwSizeOfUserDataOut); } if (lpwszIdentity != NULL) { pszIdentity = MALLOC (wcslen(lpwszIdentity)*sizeof(CHAR) + sizeof(CHAR)); if (pszIdentity == NULL) { dwRetCode = ERROR_NOT_ENOUGH_MEMORY; TRACE0 (USER, "ElGetUserIdentityOptimized: MALLOC failed for pszIdentity"); break; } if (0 == WideCharToMultiByte ( CP_ACP, 0, lpwszIdentity, -1, pszIdentity, wcslen(lpwszIdentity)*sizeof(CHAR)+sizeof(CHAR), NULL, NULL )) { dwRetCode = GetLastError(); TRACE2 (USER, "ElGetUserIdentityOptimized: WideCharToMultiByte (%ws) failed: %ld", lpwszIdentity, dwRetCode); break; } TRACE1 (USER, "ElGetUserIdentityOptimized: Got identity = %s", pszIdentity); if (pPCB->pszIdentity != NULL) { FREE (pPCB->pszIdentity); pPCB->pszIdentity = NULL; } pPCB->pszIdentity = MALLOC (strlen(pszIdentity) + sizeof(CHAR)); if (pPCB->pszIdentity == NULL) { dwRetCode = ERROR_NOT_ENOUGH_MEMORY; TRACE0 (USER, "ElGetUserIdentityOptimized: MALLOC failed for pPCB->pszIdentity"); break; } memcpy (pPCB->pszIdentity, pszIdentity, strlen (pszIdentity)); pPCB->pszIdentity[strlen(pszIdentity)] = '\0'; } if (pPCB->pCustomAuthConnData != NULL) { FREE (pPCB->pCustomAuthConnData); pPCB->pCustomAuthConnData = NULL; } pPCB->pCustomAuthConnData = MALLOC (cbData + sizeof (DWORD)); if (pPCB->pCustomAuthConnData == NULL) { TRACE1 (USER, "ElGetUserIdentityOptimized: Error in allocating memory for AuthInfo = %ld", dwRetCode); dwRetCode = ERROR_NOT_ENOUGH_MEMORY; break; } pPCB->pCustomAuthConnData->dwSizeOfCustomAuthData = cbData; if ((cbData != 0) && (pbAuthData != NULL)) { memcpy ((BYTE *)pPCB->pCustomAuthConnData->pbCustomAuthData, (BYTE *)pbAuthData, cbData); } // Mark the identity has been obtained for this PCB pPCB->fGotUserIdentity = TRUE; } while (FALSE); if (dwRetCode != NO_ERROR) { if (pPCB->pCustomAuthUserData != NULL) { FREE (pPCB->pCustomAuthUserData); pPCB->pCustomAuthUserData = NULL; } if (pPCB->pszIdentity != NULL) { FREE (pPCB->pszIdentity); pPCB->pszIdentity = NULL; } } #if 0 if ((dwRetCode != NO_ERROR) && (dwRetCode != ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION)) { // Delete User Data stored in registry since RasEapGetIdentity // is failing if ((dwRetCode = ElDeleteEapUserInfo ( pPCB->hUserToken, pPCB->pwszDeviceGUID, pPCB->dwEapTypeToBeUsed, pPCB->pSSID?pPCB->pSSID->SsidLength:0, pPCB->pSSID?pPCB->pSSID->Ssid:NULL )) != NO_ERROR) { TRACE1 (EAPOL, "ElGetUserIdentityOptimized: ElDeleteEapUserInfo failed with error %ld", dwRetCode); // Mark that identity is not obtained, since it has been cleaned // up now pPCB->fGotUserIdentity = FALSE; dwRetCode = ERROR_INVALID_DATA; } } #endif if (pbUserIn != NULL) { FREE (pbUserIn); } if (pbAuthData != NULL) { FREE (pbAuthData); } if (pszIdentity != NULL) { FREE (pszIdentity); } if (pFreeFunc != NULL) { if (lpwszIdentity != NULL) { if (( dwRetCode1 = (*(pFreeFunc)) ((BYTE *)lpwszIdentity)) != NO_ERROR) { TRACE1 (USER, "ElGetUserIdentityOptimized: Error in pFreeFunc = %ld", dwRetCode1); } } if (pUserDataOut != NULL) { if (( dwRetCode1 = (*(pFreeFunc)) ((BYTE *)pUserDataOut)) != NO_ERROR) { TRACE1 (USER, "ElGetUserIdentityOptimized: Error in pFreeFunc = %ld", dwRetCode1); } } } return dwRetCode; }