/********************************************************************/ /** Copyright(c) 1989 Microsoft Corporation. **/ /********************************************************************/ //*** // // Filename: auth.c // // Description: Contains FSM code to handle and authentication protocols. // // History: // Nov 11,1993. NarenG Created original version. // Jan 09,1995 RamC Save Lsa hToken in the PCB structure // This will be closed // in ProcessLineDownWorker() routine // to release the RAS license. #include #include #include // needed for winbase.h #include // Win32 base API's #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define INCL_RASAUTHATTRIBUTES #define INCL_MISC #define INCL_PWUTIL #include extern PPP_AUTH_ACCT_PROVIDER g_AuthProv; DWORD EapGetCredentials( VOID * pWorkBuf, VOID ** ppCredentials); //** // // Call: SetMsChapMppeKeys // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: Set the MS-CHAP-MPPE-Keys with NDISWAN // DWORD SetMsChapMppeKeys( IN HPORT hPort, IN RAS_AUTH_ATTRIBUTE * pAttribute, IN BYTE * pChallenge, IN BYTE * pResponse, IN DWORD AP, IN DWORD APData ) { RAS_COMPRESSION_INFO rciSend; RAS_COMPRESSION_INFO rciReceive; DWORD dwRetCode = NO_ERROR; ASSERT( 8 == sizeof( rciSend.RCI_LMSessionKey ) ); ASSERT( 16 == sizeof( rciSend.RCI_UserSessionKey ) ); // // Length of key is 8 (LM key) + 16 (NT key) // if ( pAttribute->dwLength < ( 6 + 8 + 16 ) ) { return( ERROR_INVALID_PARAMETER ); } ZeroMemory( &rciSend, sizeof( rciSend ) ); rciSend.RCI_MacCompressionType = 0xFF; CopyMemory( rciSend.RCI_LMSessionKey, ((PBYTE)(pAttribute->Value))+6, 8 ); CopyMemory( rciSend.RCI_UserSessionKey, ((PBYTE)(pAttribute->Value))+6+8, 16 ); CopyMemory( rciSend.RCI_Challenge, pChallenge, 8 ); CopyMemory( rciSend.RCI_NTResponse, pResponse, 24 ); rciSend.RCI_Flags = CCP_SET_KEYS; ZeroMemory( &rciReceive, sizeof( rciReceive ) ); rciReceive.RCI_MacCompressionType = 0xFF; CopyMemory( rciReceive.RCI_LMSessionKey, ((PBYTE)(pAttribute->Value))+6, 8 ); CopyMemory( rciReceive.RCI_UserSessionKey, ((PBYTE)(pAttribute->Value))+6+8, 16 ); CopyMemory( rciReceive.RCI_Challenge, pChallenge, 8 ); CopyMemory( rciReceive.RCI_NTResponse, pResponse, 24 ); rciReceive.RCI_Flags = CCP_SET_KEYS; rciSend.RCI_AuthType = AUTH_USE_MSCHAPV2; rciReceive.RCI_AuthType = AUTH_USE_MSCHAPV2; if ( ( AP == PPP_CHAP_PROTOCOL ) && ( APData == PPP_CHAP_DIGEST_MSEXT )) { rciSend.RCI_AuthType = AUTH_USE_MSCHAPV1; rciReceive.RCI_AuthType = AUTH_USE_MSCHAPV1; } dwRetCode = RasCompressionSetInfo(hPort,&rciSend,&rciReceive); if ( dwRetCode != NO_ERROR ) { PppLog( 1,"RasCompressionSetInfo failed, Error=%d", dwRetCode ); } return( dwRetCode ); } //** // // Call: SetMsMppeSendRecvKeys // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: Set the MS-MPPE-Send-Key and MS-MPPE-Recv-Key with NDISWAN // DWORD SetMsMppeSendRecvKeys( IN HPORT hPort, IN RAS_AUTH_ATTRIBUTE * pAttributeSendKey, IN RAS_AUTH_ATTRIBUTE * pAttributeRecvKey ) { RAS_COMPRESSION_INFO rciSend; RAS_COMPRESSION_INFO rciRecv; DWORD dwRetCode = NO_ERROR; // // 4: for Vendor-Id. // // The Microsoft Vendor-specific RADIUS Attributes draft says that // Vendor-Length should be > 4. // if ( pAttributeSendKey->dwLength <= ( 4 + 4 ) ) { return( ERROR_INVALID_PARAMETER ); } ZeroMemory( &rciSend, sizeof( rciSend ) ); rciSend.RCI_MacCompressionType = 0xFF; rciSend.RCI_EapKeyLength = *(((BYTE*)(pAttributeSendKey->Value))+8); CopyMemory( rciSend.RCI_EapKey, ((BYTE*)(pAttributeSendKey->Value))+9, rciSend.RCI_EapKeyLength ); rciSend.RCI_Flags = CCP_SET_KEYS; rciSend.RCI_AuthType = AUTH_USE_EAP; if ( pAttributeRecvKey->dwLength <= ( 4 + 4 ) ) { return( ERROR_INVALID_PARAMETER ); } ZeroMemory( &rciRecv, sizeof( rciRecv ) ); rciRecv.RCI_MacCompressionType = 0xFF; rciRecv.RCI_EapKeyLength = *(((BYTE*)(pAttributeRecvKey->Value))+8); CopyMemory( rciRecv.RCI_EapKey, ((BYTE*)(pAttributeRecvKey->Value))+9, rciRecv.RCI_EapKeyLength ); rciRecv.RCI_Flags = CCP_SET_KEYS; rciRecv.RCI_AuthType = AUTH_USE_EAP; dwRetCode = RasCompressionSetInfo(hPort,&rciSend,&rciRecv); if ( dwRetCode != NO_ERROR ) { PppLog( 1,"RasCompressionSetInfo failed, Error=%d", dwRetCode ); } return( dwRetCode ); } //** // // Call: SetUserAuthorizedAttributes // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: // DWORD SetUserAuthorizedAttributes( IN PCB * pPcb, IN RAS_AUTH_ATTRIBUTE * pUserAttributes, IN BOOL fAuthenticator, IN BYTE * pChallenge, IN BYTE * pResponse ) { RAS_AUTH_ATTRIBUTE * pAttribute; RAS_AUTH_ATTRIBUTE * pAttributeSendKey; RAS_AUTH_ATTRIBUTE * pAttributeRecvKey; DWORD dwRetCode; DWORD dwEncryptionPolicy = 0; DWORD dwEncryptionTypes = 0; BOOL fL2tp = FALSE; BOOL fPptp = FALSE; CreateAccountingAttributes( pPcb ); if ( RAS_DEVICE_TYPE( pPcb->dwDeviceType ) == RDT_Tunnel_L2tp ) { fL2tp = TRUE; } if ( RAS_DEVICE_TYPE( pPcb->dwDeviceType ) == RDT_Tunnel_Pptp ) { fPptp = TRUE; } // // Find out if we are to require encrypted data using MPPE // pAttribute = RasAuthAttributeGetVendorSpecific( 311, MS_VSA_MPPE_Encryption_Policy, pUserAttributes ); if ( pAttribute != NULL ) { dwEncryptionPolicy = WireToHostFormat32(((BYTE*)(pAttribute->Value))+6); pAttribute = RasAuthAttributeGetVendorSpecific( 311, MS_VSA_MPPE_Encryption_Type, pUserAttributes ); if ( pAttribute != NULL ) { dwEncryptionTypes = WireToHostFormat32(((BYTE*)(pAttribute->Value))+6); if ( dwEncryptionPolicy == 2 ) { if (!fL2tp) { // // Find out what types of encryption are to be required // if ( ( dwEncryptionTypes & 0x00000002 ) || ( dwEncryptionTypes & 0x00000008 ) ) { pPcb->ConfigInfo.dwConfigMask |= PPPCFG_RequireEncryption; PppLog( 1,"Encryption" ); } if ( dwEncryptionTypes & 0x00000004 ) { pPcb->ConfigInfo.dwConfigMask |= PPPCFG_RequireStrongEncryption; PppLog( 1,"Strong encryption" ); } if ( dwEncryptionTypes == 0 ) { pPcb->ConfigInfo.dwConfigMask |= PPPCFG_DisableEncryption; PppLog( 1,"Encryption is not allowed" ); } } } else if ( dwEncryptionPolicy == 1 ) { // // Find out what types of encryption are to be allowed // if ( !fL2tp && !dwEncryptionTypes ) { pPcb->ConfigInfo.dwConfigMask |= PPPCFG_DisableEncryption; PppLog( 1,"Encryption is not allowed" ); } } } } // // Set encryption keys if we got them, provided we have not already done so // if ( !( pPcb->fFlags & PCBFLAG_MPPE_KEYS_SET ) ) { pAttribute = RasAuthAttributeGetVendorSpecific( 311, MS_VSA_CHAP_MPPE_Keys, pUserAttributes); if ( pAttribute != NULL ) { // // Set the MS-CHAP-MPPE-Keys with NDISWAN // LCPCB * pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf); DWORD AP; DWORD APData = 0; AP = ( fAuthenticator ? pLcpCb->Local.Work.AP : pLcpCb->Remote.Work.AP ); if ( AP == PPP_CHAP_PROTOCOL ) { APData = ( fAuthenticator ? *(pLcpCb->Local.Work.pAPData) : *(pLcpCb->Remote.Work.pAPData) ); } dwRetCode = SetMsChapMppeKeys( pPcb->hPort, pAttribute, pChallenge, pResponse, AP, APData ); if ( NO_ERROR != dwRetCode ) { return( dwRetCode ); } PppLog( 1,"MS-CHAP-MPPE-Keys set" ); pPcb->fFlags |= PCBFLAG_MPPE_KEYS_SET; } pAttributeSendKey = RasAuthAttributeGetVendorSpecific( 311, MS_VSA_MPPE_Send_Key, pUserAttributes ); pAttributeRecvKey = RasAuthAttributeGetVendorSpecific( 311, MS_VSA_MPPE_Recv_Key, pUserAttributes ); if ( ( pAttributeSendKey != NULL ) && ( pAttributeRecvKey != NULL ) ) { // // Set the MS-MPPE-Send-Key and MS-MPPE-Recv-Key with NDISWAN // dwRetCode = SetMsMppeSendRecvKeys( pPcb->hPort, pAttributeSendKey, pAttributeRecvKey ); if ( NO_ERROR != dwRetCode ) { return( dwRetCode ); } PppLog( 1,"MPPE-Send/Recv-Keys set" ); pPcb->fFlags |= PCBFLAG_MPPE_KEYS_SET; } } // // Check if L2tp is being used // if ( fL2tp ) { DWORD dwMask = 0; DWORD dwSize = sizeof(DWORD); DWORD dwConfigMask; dwRetCode = RasGetPortUserData( pPcb->hPort, PORT_IPSEC_INFO_INDEX, (BYTE*) &dwMask, &dwSize ); if ( NO_ERROR != dwRetCode ) { PppLog( 1, "RasGetPortUserData failed: 0x%x", dwRetCode ); dwRetCode = NO_ERROR; } PppLog( 1, "Checking encryption. Policy=0x%x,Types=0x%x,Mask=0x%x", dwEncryptionPolicy, dwEncryptionTypes, dwMask ); if ( dwMask == RASMAN_IPSEC_ESP_DES ) { pPcb->pBcb->fFlags |= BCBFLAG_BASIC_ENCRYPTION; } else if ( dwMask == RASMAN_IPSEC_ESP_3_DES ) { pPcb->pBcb->fFlags |= BCBFLAG_STRONGEST_ENCRYPTION; } if ( !fAuthenticator ) { // // If the user requires maximum encryption (3DES), but we // negotiated weaker encryption (56-bit DES), then return an error. // dwConfigMask = pPcb->ConfigInfo.dwConfigMask; if ( ( dwConfigMask & PPPCFG_RequireStrongEncryption ) && !( dwConfigMask & PPPCFG_RequireEncryption ) && !( dwConfigMask & PPPCFG_DisableEncryption ) && ( dwMask != RASMAN_IPSEC_ESP_3_DES ) ) { return( ERROR_NO_REMOTE_ENCRYPTION ); } // // We are done with the PPPCFG_Require*Encryption flags. Let us now // turn them off because we don't care what kind of encryption CCP // negotiates. // pPcb->ConfigInfo.dwConfigMask &= ~PPPCFG_RequireStrongEncryption; pPcb->ConfigInfo.dwConfigMask &= ~PPPCFG_RequireEncryption; } else if ( dwEncryptionPolicy != 0 ) { BOOL fPolicyError = FALSE; // // There is an encryption policy // switch ( dwMask ) { case 0: if ( ( dwEncryptionPolicy == 2 ) && ( dwEncryptionTypes != 0 ) ) { fPolicyError = TRUE; break; } break; case RASMAN_IPSEC_ESP_DES: if ( !( dwEncryptionTypes & 0x00000002 ) && !( dwEncryptionTypes & 0x00000008 ) ) { fPolicyError = TRUE; break; } break; case RASMAN_IPSEC_ESP_3_DES: if (!( dwEncryptionTypes & 0x00000004 ) ) { fPolicyError = TRUE; break; } break; } if ( fPolicyError ) { // // We need to send an Accounting Stop if RADIUS sends an Access // Accept but we still drop the line. // pPcb->fFlags |= PCBFLAG_SERVICE_UNAVAILABLE; return( ERROR_NO_REMOTE_ENCRYPTION ); } } } // // If we require encryption make sure we have the keys and that CCP is // loaded. // if ( pPcb->ConfigInfo.dwConfigMask & ( PPPCFG_RequireEncryption | PPPCFG_RequireStrongEncryption ) ) { if ( !( pPcb->fFlags & PCBFLAG_MPPE_KEYS_SET ) || ( GetCpIndexFromProtocol( PPP_CCP_PROTOCOL ) == -1 ) ) { // // We need to send an Accounting Stop if RADIUS sends an Access // Accept but we still drop the line. // pPcb->fFlags |= PCBFLAG_SERVICE_UNAVAILABLE; return( ERROR_NO_LOCAL_ENCRYPTION ); } } // // If we are not the authenticator then there is nothing more to set // if ( !fAuthenticator ) { return( NO_ERROR ); } // // Check framed protocol attribute. It must be PPP. // pAttribute = RasAuthAttributeGet( raatFramedProtocol, pUserAttributes ); if ( pAttribute != NULL ) { if ( PtrToUlong(pAttribute->Value) != 1 ) { // // We need to send an Accounting Stop if RADIUS sends an Access // Accept but we still drop the line. // pPcb->fFlags |= PCBFLAG_SERVICE_UNAVAILABLE; return( ERROR_UNKNOWN_FRAMED_PROTOCOL ); } } // // Check tunnel type attribute. It must be correct. // pAttribute = RasAuthAttributeGet( raatTunnelType, pUserAttributes ); if ( pAttribute != NULL ) { DWORD dwTunnelType = PtrToUlong(pAttribute->Value); if ( ( fL2tp && ( dwTunnelType != 3 ) ) || ( fPptp && ( dwTunnelType != 1 ) ) ) { // // We need to send an Accounting Stop if RADIUS sends an Access // Accept but we still drop the line. // pPcb->fFlags |= PCBFLAG_SERVICE_UNAVAILABLE; return( ERROR_WRONG_TUNNEL_TYPE ); } } // // Get the logon domain attribute // pAttribute = RasAuthAttributeGetVendorSpecific( 311, MS_VSA_CHAP_Domain, pUserAttributes ); if ( pAttribute != NULL ) { DWORD cbDomain = sizeof( pPcb->pBcb->szRemoteDomain ) - 1; if ( ( pAttribute->dwLength - 7 ) < cbDomain ) { cbDomain = pAttribute->dwLength - 7; } ZeroMemory( pPcb->pBcb->szRemoteDomain, sizeof( pPcb->pBcb->szRemoteDomain ) ); CopyMemory( pPcb->pBcb->szRemoteDomain, (LPSTR)((PBYTE)(pAttribute->Value)+7), cbDomain ); PppLog( 2, "Auth Attribute Domain = %s", pPcb->pBcb->szRemoteDomain); } // // Setup callback information, default is no callback // pPcb->fCallbackPrivilege = RASPRIV_NoCallback; pPcb->szCallbackNumber[0] = (CHAR)NULL; pAttribute = RasAuthAttributeGet( raatServiceType, pUserAttributes ); if ( pAttribute != NULL ) { if ( PtrToUlong(pAttribute->Value) == 4 ) { // // If service type is callback framed // pAttribute=RasAuthAttributeGet(raatCallbackNumber,pUserAttributes); if ( ( pAttribute == NULL ) || ( pAttribute->dwLength == 0 ) ) { pPcb->fCallbackPrivilege = RASPRIV_NoCallback | RASPRIV_CallerSetCallback; pPcb->szCallbackNumber[0] = (CHAR)NULL; PppLog(2,"Auth Attribute Caller Specifiable callback"); } else { pPcb->fCallbackPrivilege = RASPRIV_AdminSetCallback; ZeroMemory(pPcb->szCallbackNumber, sizeof(pPcb->szCallbackNumber)); CopyMemory( pPcb->szCallbackNumber, pAttribute->Value, pAttribute->dwLength ); PppLog( 2, "Auth Attribute Forced callback to %s", pPcb->szCallbackNumber ); // // Don't accept BAP Call-Requests. Otherwise, when the client // calls us, we will drop the line and callback. The first call // would be a waste. // pPcb->pBcb->fFlags &= ~BCBFLAG_CAN_ACCEPT_CALLS; } } else if ( PtrToUlong(pAttribute->Value) != 2 ) { PppLog( 2, "Service Type %d is not of type Framed", PtrToUlong(pAttribute->Value) ); // // We need to send an Accounting Stop if RADIUS sends an Access // Accept but we still drop the line. // pPcb->fFlags |= PCBFLAG_SERVICE_UNAVAILABLE; return( ERROR_UNKNOWN_SERVICE_TYPE ); } } if ( ( pPcb->fCallbackPrivilege & RASPRIV_CallerSetCallback ) || ( pPcb->fCallbackPrivilege & RASPRIV_AdminSetCallback ) ) { pPcb->pBcb->fFlags |= BCBFLAG_CAN_CALL; } // // Use idle-timeout value if we got one. // pAttribute = RasAuthAttributeGet( raatIdleTimeout, pUserAttributes ); if ( pAttribute != NULL ) { pPcb->dwAutoDisconnectTime = PtrToUlong(pAttribute->Value); } else { pPcb->dwAutoDisconnectTime = PppConfigInfo.dwDefaulIdleTimeout; } PppLog( 2, "Auth Attribute Idle Timeout Seconds = %d", pPcb->dwAutoDisconnectTime ); // // Use MaxChannels value if we got one. // pAttribute = RasAuthAttributeGet( raatPortLimit, pUserAttributes ); if ( pAttribute != NULL ) { if ( PtrToUlong(pAttribute->Value) > 0 ) { pPcb->pBcb->dwMaxLinksAllowed = PtrToUlong(pAttribute->Value); } else { pPcb->pBcb->dwMaxLinksAllowed = PppConfigInfo.dwDefaultPortLimit; } } else { pPcb->pBcb->dwMaxLinksAllowed = PppConfigInfo.dwDefaultPortLimit; } PppLog( 2, "AuthAttribute MaxChannelsAllowed = %d", pPcb->pBcb->dwMaxLinksAllowed ); // // See if BAP is required // pAttribute = RasAuthAttributeGetVendorSpecific( 311, MS_VSA_BAP_Usage, pUserAttributes ); if ( pAttribute != NULL ) { if ( WireToHostFormat32( (PBYTE)(pAttribute->Value)+6 ) == 2 ) { PppLog( 2, "AuthAttribute BAPRequired" ); pPcb->pBcb->fFlags |= BCBFLAG_BAP_REQUIRED; } } // // For the server never send a request bring up the line // pPcb->pBcb->BapParams.dwDialExtraPercent = 100; pPcb->pBcb->BapParams.dwDialExtraSampleSeconds = 100; pAttribute = RasAuthAttributeGetVendorSpecific( 311, MS_VSA_Link_Utilization_Threshold, pUserAttributes ); if ( ( pAttribute != NULL ) && ( pAttribute->dwLength == 10 ) ) { pPcb->pBcb->BapParams.dwHangUpExtraPercent = WireToHostFormat32( ((BYTE *)(pAttribute->Value))+6 ); PppLog( 2, "AuthAttribute BAPLineDownLimit = %d", pPcb->pBcb->BapParams.dwHangUpExtraPercent ); } else { pPcb->pBcb->BapParams.dwHangUpExtraPercent = PppConfigInfo.dwHangupExtraPercent; } pAttribute = RasAuthAttributeGetVendorSpecific( 311, MS_VSA_Link_Drop_Time_Limit, pUserAttributes ); if ( ( pAttribute != NULL ) && ( pAttribute->dwLength == 10 ) ) { pPcb->pBcb->BapParams.dwHangUpExtraSampleSeconds = WireToHostFormat32( ((BYTE *)(pAttribute->Value))+6 ); PppLog( 2, "AuthAttribute BAPLineDownTime = %d", pPcb->pBcb->BapParams.dwHangUpExtraSampleSeconds ); } else { pPcb->pBcb->BapParams.dwHangUpExtraSampleSeconds = PppConfigInfo.dwHangUpExtraSampleSeconds; } return( NO_ERROR ); } //** // // Call: RasAuthenticateUserWorker // // Returns: None. // // Description: // VOID RasAuthenticateUserWorker( PVOID pContext ) { PCB_WORK_ITEM * pWorkItem = (PCB_WORK_ITEM *)pContext; pWorkItem->PppMsg.AuthInfo.dwError = (*PppConfigInfo.RasAuthProviderAuthenticateUser)( pWorkItem->PppMsg.AuthInfo.pInAttributes, &(pWorkItem->PppMsg.AuthInfo.pOutAttributes), &(pWorkItem->PppMsg.AuthInfo.dwResultCode) ); RasAuthAttributeDestroy( pWorkItem->PppMsg.AuthInfo.pInAttributes ); // // Deref the ref applied in RasAuthenticateClient // DEREF_PROVIDER(g_AuthProv); InsertWorkItemInQ( pWorkItem ); } //** // // Call: RasAuthenticateClient // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: // DWORD RasAuthenticateClient( IN HPORT hPort, IN RAS_AUTH_ATTRIBUTE * pInAttributes ) { PCB * pPcb = GetPCBPointerFromhPort( hPort ); LCPCB * pLcpCb = NULL; PCB_WORK_ITEM * pWorkItem = NULL; DWORD dwRetCode = NO_ERROR; if ( pPcb == NULL ) { RasAuthAttributeDestroy( pInAttributes ); return( ERROR_INVALID_PORT_HANDLE ); } pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf); pWorkItem = (PCB_WORK_ITEM *)LOCAL_ALLOC( LPTR, sizeof(PCB_WORK_ITEM) ); if ( pWorkItem == (PCB_WORK_ITEM *)NULL ) { LogPPPEvent( ROUTERLOG_NOT_ENOUGH_MEMORY, GetLastError() ); RasAuthAttributeDestroy( pInAttributes ); return( GetLastError() ); } pWorkItem->hPort = hPort; pWorkItem->dwPortId = pPcb->dwPortId; pWorkItem->Protocol = pLcpCb->Local.Work.AP; pWorkItem->PppMsg.AuthInfo.pInAttributes = pInAttributes; pWorkItem->PppMsg.AuthInfo.dwId = GetUId( pPcb, LCP_INDEX ); pWorkItem->Process = ProcessAuthInfo; pPcb->dwOutstandingAuthRequestId = pWorkItem->PppMsg.AuthInfo.dwId; REF_PROVIDER(g_AuthProv); dwRetCode = RtlNtStatusToDosError( RtlQueueWorkItem( RasAuthenticateUserWorker, pWorkItem, WT_EXECUTEDEFAULT ) ); if ( dwRetCode != NO_ERROR ) { RasAuthAttributeDestroy( pInAttributes ); DEREF_PROVIDER(g_AuthProv); LOCAL_FREE( pWorkItem ); } return( dwRetCode ); } //** // // Call: RemoteError // // Returns: DWORD - Remote version of this error // // Description: Called by a client authenticating the server. // DWORD RemoteError( IN DWORD dwError ) { switch( dwError ) { case ERROR_NO_DIALIN_PERMISSION: return( ERROR_REMOTE_NO_DIALIN_PERMISSION ); case ERROR_PASSWD_EXPIRED: return( ERROR_REMOTE_PASSWD_EXPIRED ); case ERROR_ACCT_DISABLED: return( ERROR_REMOTE_ACCT_DISABLED ); case ERROR_RESTRICTED_LOGON_HOURS: return( ERROR_REMOTE_RESTRICTED_LOGON_HOURS ); case ERROR_AUTHENTICATION_FAILURE: return( ERROR_REMOTE_AUTHENTICATION_FAILURE ); case ERROR_REQ_NOT_ACCEP: return( ERROR_LICENSE_QUOTA_EXCEEDED ); default: return( dwError ); } } //** // // Call: ApIsAuthenticatorPacket // // Returns: TRUE - Packet belongs to authenticator // FALSE - Otherwise // // Description: Called to figure out whether to send the auth packet to the // authenticator or authenticatee. // BOOL ApIsAuthenticatorPacket( IN DWORD CpIndex, IN BYTE bConfigCode ) { switch( CpTable[CpIndex].CpInfo.Protocol ) { case PPP_PAP_PROTOCOL: switch( bConfigCode ) { case 1: return( TRUE ); default: return( FALSE ); } break; case PPP_CHAP_PROTOCOL: switch( bConfigCode ) { case 2: case 5: case 6: case 7: return( TRUE ); default: return( FALSE ); } break; case PPP_SPAP_NEW_PROTOCOL: switch( bConfigCode ) { case 1: case 6: return( TRUE ); default: return( FALSE ); } break; case PPP_EAP_PROTOCOL: switch( bConfigCode ) { case 2: return( TRUE ); default: return( FALSE ); } break; default: PPP_ASSERT( FALSE ); } PPP_ASSERT( FALSE ); return( FALSE ); } //** // // Call: ApStart // // Returns: TRUE - Success // FALSE - Otherwise // // Description: Called to initiatialze the authetication protocol and to // initiate to authentication. // BOOL ApStart( IN PCB * pPcb, IN DWORD CpIndex, IN BOOL fAuthenticator ) { DWORD dwRetCode; PPPAP_INPUT PppApInput; LCPCB * pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf); CPCB * pCpCb = ( fAuthenticator ) ? &(pPcb->AuthenticatorCb) : &(pPcb->AuthenticateeCb); DWORD cbPassword, cbOldPassword; PBYTE pbPassword = NULL, pbOldPassword = NULL; DWORD dwErr = NO_ERROR; pCpCb->fConfigurable = TRUE; pCpCb->State = FSM_INITIAL; pCpCb->Protocol = CpTable[CpIndex].CpInfo.Protocol; pCpCb->LastId = (DWORD)-1; InitRestartCounters( pPcb, pCpCb ); ZeroMemory( &PppApInput, sizeof( PppApInput ) ); PppApInput.hPort = pPcb->hPort; PppApInput.fServer = fAuthenticator; PppApInput.fRouter = ( ROUTER_IF_TYPE_FULL_ROUTER == pPcb->pBcb->InterfaceInfo.IfType ); PppApInput.Luid = pPcb->Luid; PppApInput.dwEapTypeToBeUsed = pPcb->dwEapTypeToBeUsed; PppApInput.hTokenImpersonateUser = pPcb->pBcb->hTokenImpersonateUser; PppApInput.pCustomAuthConnData = pPcb->pBcb->pCustomAuthConnData; PppApInput.pCustomAuthUserData = pPcb->pBcb->pCustomAuthUserData; PppApInput.EapUIData = pPcb->pBcb->EapUIData; PppApInput.fLogon = ( pPcb->pBcb->fFlags & BCBFLAG_LOGON_USER_DATA ); PppApInput.fNonInteractive = ( pPcb->fFlags & PCBFLAG_NON_INTERACTIVE ); PppApInput.fConfigInfo = pPcb->ConfigInfo.dwConfigMask; if ( fAuthenticator ) { PppApInput.dwRetries = pPcb->dwAuthRetries; PppApInput.pAPData = pLcpCb->Local.Work.pAPData; PppApInput.APDataSize = pLcpCb->Local.Work.APDataSize; PppApInput.pUserAttributes = pPcb->pUserAttributes; ZeroMemory( &pPcb->pBcb->szRemoteUserName, sizeof( pPcb->pBcb->szRemoteUserName ) ); } else { // // If we are a server and we do not know who is dialing in and therefore // do not have credentials to use for being authenticated by the // remote peer, then we wait till we do. // if ( pPcb->fFlags & PCBFLAG_IS_SERVER ) { if ( strlen( pPcb->pBcb->szRemoteUserName ) == 0 ) { PppLog(1,"Remote user not identifiable at this time, waiting"); return( FALSE ); } // // Ok we know who is dialed in so get credentials to used for this // connection. // dwRetCode = GetCredentialsFromInterface( pPcb ); if ( dwRetCode != NO_ERROR ) { // // We do not have credentials to use for this user so we // renegotiate LCP and do not accept the authentication option // PppLog( 1, "No credentials available to use for user=%s", pPcb->pBcb->szRemoteUserName ); FsmDown( pPcb, LCP_INDEX ); pLcpCb->Remote.WillNegotiate &= (~LCP_N_AUTHENT); FsmUp( pPcb, LCP_INDEX ); return( FALSE ); } } // // Decode the password // // DecodePw( pPcb->pBcb->chSeed, pPcb->pBcb->szPassword ); // DecodePw( pPcb->pBcb->chSeed, pPcb->pBcb->szOldPassword ); dwErr = DecodePassword(&pPcb->pBcb->DBPassword, &cbPassword, &pbPassword); if(NO_ERROR != dwErr) { PppLog(1, "DecodePassword failed. 0x%x", dwErr); return FALSE; } dwErr = DecodePassword(&pPcb->pBcb->DBOldPassword, &cbOldPassword, &pbOldPassword); if(NO_ERROR != dwErr) { PppLog(1, "DecodePassword failed. 0x%x", dwErr); return FALSE; } PppApInput.pszUserName = pPcb->pBcb->szLocalUserName; PppApInput.pszPassword = (pbPassword) ? pbPassword : "\0"; PppApInput.pszDomain = pPcb->pBcb->szLocalDomain; PppApInput.pszOldPassword = (pbOldPassword) ? pbOldPassword : "\0"; PppApInput.pAPData = pLcpCb->Remote.Work.pAPData; PppApInput.APDataSize = pLcpCb->Remote.Work.APDataSize; PppApInput.dwInitialPacketId = (DWORD)GetUId( pPcb, CpIndex ); if ( CpTable[CpIndex].CpInfo.Protocol == PPP_EAP_PROTOCOL ) { PppApInput.fPortWillBeBundled = WillPortBeBundled( pPcb ); PppApInput.fThisIsACallback = ( pPcb->fFlags & PCBFLAG_THIS_IS_A_CALLBACK ); // // Check to see if this is a resume from hibernate. If so // set the bit that notifies eap of the resume. // if(PppConfigInfo.fFlags & PPPCONFIG_FLAG_RESUME) { PppApInput.fConfigInfo |= PPPCFG_ResumeFromHibernate; PppConfigInfo.fFlags &= ~(PPPCONFIG_FLAG_RESUME); } } } dwRetCode = (CpTable[CpIndex].CpInfo.RasCpBegin)(&(pCpCb->pWorkBuf), &PppApInput ); if ( !fAuthenticator ) { // // Encode the password back // // EncodePw( pPcb->pBcb->chSeed, pPcb->pBcb->szPassword ); // EncodePw( pPcb->pBcb->chSeed, pPcb->pBcb->szOldPassword ); RtlSecureZeroMemory(pbPassword, cbPassword); RtlSecureZeroMemory(pbOldPassword, cbOldPassword); LocalFree(pbPassword); LocalFree(pbOldPassword); } if ( dwRetCode != NO_ERROR ) { pPcb->LcpCb.dwError = dwRetCode; NotifyCallerOfFailure( pPcb, dwRetCode ); return( FALSE ); } PppLog(1,"Calling APWork in APStart"); ApWork( pPcb, CpIndex, NULL, NULL, fAuthenticator ); return( TRUE ); } //** // // Call: ApStop // // Returns: none // // Description: Called to stop the authentication machine. // VOID ApStop( IN PCB * pPcb, IN DWORD CpIndex, IN BOOL fAuthenticator ) { CPCB * pCpCb = ( fAuthenticator ) ? &(pPcb->AuthenticatorCb) : &(pPcb->AuthenticateeCb); if ( pCpCb->pWorkBuf == NULL ) { return; } pCpCb->Protocol = 0; pCpCb->fConfigurable = FALSE; if ( pCpCb->LastId != (DWORD)-1 ) { RemoveFromTimerQ( pPcb->dwPortId, pCpCb->LastId, CpTable[CpIndex].CpInfo.Protocol, fAuthenticator, TIMER_EVENT_TIMEOUT ); } (CpTable[CpIndex].CpInfo.RasCpEnd)( pCpCb->pWorkBuf ); pCpCb->pWorkBuf = NULL; } //** // // Call: ApWork // // Returns: none // // Description: Called when and authentication packet was received or // a timeout occurred or to initiate authentication. // VOID ApWork( IN PCB * pPcb, IN DWORD CpIndex, IN PPP_CONFIG * pRecvConfig, IN PPPAP_INPUT * pApInput, IN BOOL fAuthenticator ) { DWORD dwRetCode; DWORD dwLength; PPPAP_RESULT ApResult; PPP_CONFIG * pSendConfig = (PPP_CONFIG*)(pPcb->pSendBuf->Information); LCPCB * pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf); CPCB * pCpCb = ( fAuthenticator ) ? &(pPcb->AuthenticatorCb) : &(pPcb->AuthenticateeCb); // // If the protocol has not been started yet, call ApStart // if ( pCpCb->pWorkBuf == NULL ) { if ( !ApStart( pPcb, CpIndex, fAuthenticator ) ) { return; } } ZeroMemory( &ApResult, sizeof(ApResult) ); dwRetCode = (CpTable[CpIndex].CpInfo.RasApMakeMessage)( pCpCb->pWorkBuf, pRecvConfig, pSendConfig, ((pLcpCb->Remote.Work.MRU > LCP_DEFAULT_MRU) ? LCP_DEFAULT_MRU : pLcpCb->Remote.Work.MRU) - PPP_PACKET_HDR_LEN, &ApResult, pApInput ); if ( NULL != ApResult.szReplyMessage ) { LocalFree( pPcb->pBcb->szReplyMessage ); pPcb->pBcb->szReplyMessage = ApResult.szReplyMessage; } if ( dwRetCode != NO_ERROR ) { switch( dwRetCode ) { case ERROR_PPP_INVALID_PACKET: PppLog( 1, "Silently discarding invalid auth packet on port %d", pPcb->hPort ); break; default: pPcb->LcpCb.dwError = dwRetCode; PppLog( 1, "Auth Protocol %x returned error %d", CpTable[CpIndex].CpInfo.Protocol, dwRetCode ); if ( fAuthenticator ) { // // Get the username from the CP if it supplies one. // if ( strlen( ApResult.szUserName ) > 0 ) { strcpy( pPcb->pBcb->szRemoteUserName, ApResult.szUserName ); } } NotifyCallerOfFailure( pPcb, dwRetCode ); break; } return; } // // Check to see if we have to save any user data // if ( ( !fAuthenticator ) && ( ApResult.fSaveUserData ) ) { dwRetCode = RasSetEapUserDataA( pPcb->pBcb->hTokenImpersonateUser, pPcb->pBcb->szPhonebookPath, pPcb->pBcb->szEntryName, ApResult.pUserData, ApResult.dwSizeOfUserData ); PppLog( 2, "Saved EAP data for user, dwRetCode = %d", dwRetCode ); } // // Check to see if we have to save any connection data // if ( ( !fAuthenticator ) && ( ApResult.fSaveConnectionData ) && ( 0 != ApResult.SetCustomAuthData.dwSizeOfConnectionData ) ) { NotifyCaller( pPcb, PPPMSG_SetCustomAuthData, &(ApResult.SetCustomAuthData) ); PppLog( 2, "Saved EAP data for connection" ); } switch( ApResult.Action ) { case APA_Send: case APA_SendWithTimeout: case APA_SendWithTimeout2: case APA_SendAndDone: HostToWireFormat16( (WORD)CpTable[CpIndex].CpInfo.Protocol, (PBYTE)(pPcb->pSendBuf->Protocol) ); dwLength = WireToHostFormat16( pSendConfig->Length ); LogPPPPacket(FALSE,pPcb,pPcb->pSendBuf,dwLength+PPP_PACKET_HDR_LEN); if ( ( dwRetCode = PortSendOrDisconnect( pPcb, (dwLength + PPP_PACKET_HDR_LEN))) != NO_ERROR ) { return; } pCpCb->LastId = (DWORD)-1; if ( ( ApResult.Action == APA_SendWithTimeout ) || ( ApResult.Action == APA_SendWithTimeout2 ) ) { pCpCb->LastId = ApResult.bIdExpected; InsertInTimerQ( pPcb->dwPortId, pPcb->hPort, pCpCb->LastId, CpTable[CpIndex].CpInfo.Protocol, fAuthenticator, TIMER_EVENT_TIMEOUT, pPcb->RestartTimer ); // // For SendWithTimeout2 we increment the ConfigRetryCount. This // means send with infinite retry count // if ( ApResult.Action == APA_SendWithTimeout2 ) { (pCpCb->ConfigRetryCount)++; } } if ( ApResult.Action != APA_SendAndDone ) { break; } case APA_Done: switch( ApResult.dwError ) { case NO_ERROR: // // If authentication was successful // if ( CpTable[CpIndex].CpInfo.Protocol == PPP_EAP_PROTOCOL ) { if ( fAuthenticator ) { pPcb->dwServerEapTypeId = ApResult.dwEapTypeId; } else { VOID *pCredentials = NULL; pPcb->dwClientEapTypeId = ApResult.dwEapTypeId; // // Call the eap dll to collect credentials here // so that they can be passed to rasman to be // saved in the cred manager. // if( (NO_ERROR == EapGetCredentials(pCpCb->pWorkBuf, &pCredentials)) && (NULL != pCredentials)) { // // Below call is not fatal. // (void) RasSetPortUserData( pPcb->hPort, PORT_CREDENTIALS_INDEX, pCredentials, sizeof(RASMAN_CREDENTIALS)); RtlSecureZeroMemory(pCredentials, sizeof(RASMAN_CREDENTIALS)); LocalFree(pCredentials); } } } if ( fAuthenticator ) { RAS_AUTH_ATTRIBUTE * pAttribute; RAS_AUTH_ATTRIBUTE * pUserAttributes = NULL; if ( NULL != pPcb->pBcb->szRemoteIdentity ) { LOCAL_FREE( pPcb->pBcb->szRemoteIdentity ); pPcb->pBcb->szRemoteIdentity = NULL; } pPcb->pBcb->szRemoteIdentity = LOCAL_ALLOC( LPTR, strlen( ApResult.szUserName ) + 1 ); if ( NULL == pPcb->pBcb->szRemoteIdentity ) { dwRetCode = GetLastError(); pPcb->LcpCb.dwError = dwRetCode; NotifyCallerOfFailure( pPcb, dwRetCode ); return; } strcpy( pPcb->pBcb->szRemoteIdentity, ApResult.szUserName ); dwRetCode = ExtractUsernameAndDomain( ApResult.szUserName, pPcb->pBcb->szRemoteUserName, NULL ); if ( dwRetCode != NO_ERROR ) { pPcb->LcpCb.dwError = dwRetCode; NotifyCallerOfFailure( pPcb, dwRetCode ); return; } if ( 0 == pPcb->pBcb->szLocalUserName[0] ) { if ( NO_ERROR != GetCredentialsFromInterface( pPcb ) ) { pPcb->pBcb->szLocalUserName[0] = pPcb->pBcb->szPassword[0] = pPcb->pBcb->szLocalDomain[0] = 0; } } if ( ApResult.pUserAttributes != NULL ) { pPcb->pAuthProtocolAttributes = ApResult.pUserAttributes; pUserAttributes = ApResult.pUserAttributes; } else { pUserAttributes = pPcb->pAuthenticatorAttributes; } // // Set all the user connection parameters authorized by the // back-end authenticator // dwRetCode = SetUserAuthorizedAttributes( pPcb, pUserAttributes, fAuthenticator, (BYTE*)&(ApResult.abChallenge), (BYTE*)&(ApResult.abResponse)); if ( dwRetCode != NO_ERROR ) { pPcb->LcpCb.dwError = dwRetCode; NotifyCallerOfFailure( pPcb, dwRetCode ); return; } // // If we are a server and we negotiated to be authenticated // by the remote peer we can do so now that we know who // is dialed in. // if ( ( pLcpCb->Remote.Work.AP != 0 ) && ( pPcb->AuthenticateeCb.pWorkBuf == NULL ) && ( pPcb->AuthenticateeCb.fConfigurable ) && ( pPcb->fFlags & PCBFLAG_IS_SERVER ) ) { CpIndex = GetCpIndexFromProtocol( pLcpCb->Remote.Work.AP ); PPP_ASSERT(( CpIndex != (DWORD)-1 )); if ( !ApStart( pPcb, CpIndex, FALSE ) ) { return; } } } else { // // Get the username from the CP if it supplies one. // if ( ( strlen( pPcb->pBcb->szLocalUserName ) == 0 ) && ( strlen( ApResult.szUserName ) > 0 ) ) { strcpy( pPcb->pBcb->szLocalUserName, ApResult.szUserName ); } dwRetCode = SetUserAuthorizedAttributes( pPcb, ApResult.pUserAttributes, fAuthenticator, (BYTE*)&(ApResult.abChallenge), (BYTE*)&(ApResult.abResponse)); if ( dwRetCode != NO_ERROR ) { pPcb->LcpCb.dwError = dwRetCode; NotifyCallerOfFailure( pPcb, dwRetCode ); return; } pPcb->pAuthProtocolAttributes = ApResult.pUserAttributes; } pCpCb->State = FSM_OPENED; FsmThisLayerUp( pPcb, CpIndex ); break; case ERROR_PASSWD_EXPIRED: if ( pPcb->fFlags & PCBFLAG_IS_SERVER ) { // // We are a server and hence in non-interactive mode and // hence we cannot do this. // pPcb->LcpCb.dwError = ApResult.dwError; NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError ); return; } else { // // Password has expired so the user has to change his/her // password. // NotifyCaller( pPcb, PPPMSG_ChangePwRequest, NULL ); } break; default: // // If we can retry with a new password then tell the client to // get a new one from the user. // if ( (!fAuthenticator) && ( ApResult.fRetry )) { if ( pPcb->fFlags & PCBFLAG_IS_SERVER ) { // // We are a server and hence in non-interactive mode and // hence we cannot do this. // pPcb->LcpCb.dwError = ApResult.dwError; NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError ); return; } else { PppLog( 2, "Sending auth retry message to UI" ); NotifyCaller( pPcb, PPPMSG_AuthRetry, &(ApResult.dwError) ); } } else { PppLog( 1, "Auth Protocol %x terminated with error %d", CpTable[CpIndex].CpInfo.Protocol, ApResult.dwError ); if ( ApResult.szUserName[0] != (CHAR)NULL ) { strcpy( pPcb->pBcb->szRemoteUserName, ApResult.szUserName ); } if ( !( pPcb->fFlags & PCBFLAG_IS_SERVER ) && ( fAuthenticator) ) { pPcb->LcpCb.dwError = RemoteError( ApResult.dwError ); } else { pPcb->LcpCb.dwError = ApResult.dwError; } NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError ); return; } break; } break; case APA_Authenticate: if ( fAuthenticator ) { DWORD dwIndex = 0; DWORD dwExtraIndex = 0; DWORD dwExtraAttributes = 0; DWORD dwNumUserAttributes = 0; RAS_AUTH_ATTRIBUTE * pUserAttributes = NULL; DWORD LocalMagicNumber; DWORD RemoteMagicNumber; CHAR szMagicNumber[20]; for ( dwNumUserAttributes = 0; pPcb->pUserAttributes[dwNumUserAttributes].raaType != raatMinimum; dwNumUserAttributes++ ); if ( CpTable[CpIndex].CpInfo.Protocol == PPP_EAP_PROTOCOL ) { // // One more for Framed-MTU // dwExtraAttributes = 1; } // // We now also need to add local and remote magic numbers // and accounting session id to the access request // #if 0 dwExtraAttributes += 2; //For local and remote magic numbers #endif if ( PppConfigInfo.RasAcctProviderStartAccounting != NULL ) { // // We have accounting turned on. So need to create an // accounting session id and send it with access request // dwExtraAttributes ++; pPcb->dwAccountingSessionId = PppConfigInfo.GetNextAccountingSessionId(); } pUserAttributes = RasAuthAttributeCopyWithAlloc( ApResult.pUserAttributes, dwNumUserAttributes + dwExtraAttributes ); if ( pUserAttributes == NULL ) { dwRetCode = GetLastError(); pPcb->LcpCb.dwError = dwRetCode; NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError ); return; } if ( dwExtraAttributes ) { #if 0 if ( pLcpCb->Local.Work.Negotiate & LCP_N_MAGIC ) { LocalMagicNumber = pLcpCb->Local.Work.MagicNumber; } else { //Default value of 0 LocalMagicNumber = 0; } _itoa( LocalMagicNumber, &szMagicNumber[2], 10 ); szMagicNumber[0] = (CHAR)MS_VSA_Local_Magic_Number; szMagicNumber[1] = (CHAR)strlen(&szMagicNumber[2]) +1+1; dwRetCode = RasAuthAttributeInsertVSA( dwExtraIndex, pUserAttributes, 311, (DWORD)szMagicNumber[1], szMagicNumber ); if ( dwRetCode != NO_ERROR ) { RasAuthAttributeDestroy( pUserAttributes ); pPcb->LcpCb.dwError = dwRetCode; NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError ); return; } if ( pLcpCb->Remote.Work.Negotiate & LCP_N_MAGIC ) { RemoteMagicNumber = pLcpCb->Remote.Work.MagicNumber; } else { //Default value of 0 RemoteMagicNumber = 0; } _itoa( RemoteMagicNumber, &szMagicNumber[2], 10 ); szMagicNumber[0] = (CHAR)MS_VSA_Remote_Magic_Number; szMagicNumber[1] = (CHAR)strlen(&szMagicNumber[2]) +1+1; dwExtraIndex++; dwRetCode = RasAuthAttributeInsertVSA( dwExtraIndex, pUserAttributes, 311, (DWORD)szMagicNumber[1], szMagicNumber ); if ( dwRetCode != NO_ERROR ) { RasAuthAttributeDestroy( pUserAttributes ); pPcb->LcpCb.dwError = dwRetCode; NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError ); return; } #endif if ( CpTable[CpIndex].CpInfo.Protocol == PPP_EAP_PROTOCOL ) { ULONG mru = (pLcpCb->Remote.Work.MRU > LCP_DEFAULT_MRU) ? LCP_DEFAULT_MRU : pLcpCb->Remote.Work.MRU; // // Insert the Framed-MTU attribute at the start. // dwRetCode = RasAuthAttributeInsert( dwExtraIndex, pUserAttributes, raatFramedMTU, FALSE, 4, (LPVOID) ( UlongToPtr(mru)) ); if ( dwRetCode != NO_ERROR ) { RasAuthAttributeDestroy( pUserAttributes ); pPcb->LcpCb.dwError = dwRetCode; NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError ); return; } dwExtraIndex++; } if ( PppConfigInfo.RasAcctProviderStartAccounting != NULL ) { CHAR szAcctSessionId[20]; _itoa(pPcb->dwAccountingSessionId, szAcctSessionId, 10); dwRetCode = RasAuthAttributeInsert( dwExtraIndex, pUserAttributes, raatAcctSessionId, FALSE, strlen( szAcctSessionId ), szAcctSessionId ); if ( dwRetCode != NO_ERROR ) { RasAuthAttributeDestroy( pUserAttributes ); pPcb->LcpCb.dwError = dwRetCode; NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError ); return; } dwExtraIndex++; } } // // Insert the extra (user) attributes at the start. Attributes // returned by the auth protocol follow. // for ( dwIndex = 0; dwIndex < dwNumUserAttributes; dwIndex++ ) { dwRetCode = RasAuthAttributeInsert( dwIndex + dwExtraAttributes, pUserAttributes, pPcb->pUserAttributes[dwIndex].raaType, FALSE, pPcb->pUserAttributes[dwIndex].dwLength, pPcb->pUserAttributes[dwIndex].Value ); if ( dwRetCode != NO_ERROR ) { RasAuthAttributeDestroy( pUserAttributes ); pPcb->LcpCb.dwError = dwRetCode; NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError ); return; } } dwRetCode = RasAuthenticateClient( pPcb->hPort, pUserAttributes ); if ( dwRetCode != NO_ERROR ) { pPcb->LcpCb.dwError = dwRetCode; NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError ); return; } } break; case APA_NoAction: break; default: break; } // // Check to see if we have to bring up the UI for EAP // if ( ( !fAuthenticator ) && ( ApResult.fInvokeEapUI ) ) { NotifyCaller(pPcb, PPPMSG_InvokeEapUI, &(ApResult.InvokeEapUIData)); } }