/********************************************************************/ /** Copyright(c) 1989 Microsoft Corporation. **/ /********************************************************************/ //*** // // Filename: util.c // // Description: Contains utility routines used by the PPP engine. // // History: // Oct 31,1993. NarenG Created original version. // #define UNICODE // This file is in UNICODE #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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define INCL_RASAUTHATTRIBUTES #include #define PASSWORDMAGIC 0xA5 #define CLASSA_ADDR(a) (( (*((UCHAR *)&(a))) & 0x80) == 0) #define CLASSB_ADDR(a) (( (*((UCHAR *)&(a))) & 0xc0) == 0x80) #define CLASSC_ADDR(a) (( (*((UCHAR *)&(a))) & 0xe0) == 0xc0) #define CLASSE_ADDR(a) ((( (*((UCHAR *)&(a))) & 0xf0) == 0xf0) && \ ((a) != 0xffffffff)) #define CLASSA_MASK 0x000000ff #define CLASSB_MASK 0x0000ffff #define CLASSC_MASK 0x00ffffff #define CLASSD_MASK 0x000000e0 #define CLASSE_MASK 0xffffffff #define GetClassMask(a)\ (CLASSA_ADDR((a)) ? CLASSA_MASK : \ (CLASSB_ADDR((a)) ? CLASSB_MASK : \ (CLASSC_ADDR((a)) ? CLASSC_MASK : CLASSE_MASK))) VOID ReverseString( CHAR* psz ); //** // // Call: InitRestartCounters // // Returns: none. // // Description: Will initialize all the counters for the Control Protocol // to their initial values. // VOID InitRestartCounters( IN PCB * pPcb, IN CPCB * pCpCb ) { pCpCb->ConfigRetryCount = PppConfigInfo.MaxConfigure; pCpCb->TermRetryCount = PppConfigInfo.MaxTerminate; } //** // // Call: GetPCBPointerFromhPort // // Returns: PCB * - Success // NULL - Failure // // Description: Give an HPORT, this function will return a pointer to the // port control block for it. // PCB * GetPCBPointerFromhPort( IN HPORT hPort ) { PCB * pPcbWalker = NULL; DWORD dwIndex = HashPortToBucket( hPort ); for ( pPcbWalker = PcbTable.PcbBuckets[dwIndex].pPorts; pPcbWalker != (PCB *)NULL; pPcbWalker = pPcbWalker->pNext ) { if ( pPcbWalker->hPort == hPort ) return( pPcbWalker ); } return( (PCB *)NULL ); } //** // // Call: GetBCBPointerFromhConnection // // Returns: BCB * - Success // NULL - Failure // // Description: Given an HCONN, this function will return a pointer to the // bundle control block for it. // BCB * GetBCBPointerFromhConnection( IN HCONN hConnection ) { BCB * pBcbWalker = NULL; DWORD dwIndex = HashPortToBucket( hConnection ); for ( pBcbWalker = PcbTable.BcbBuckets[dwIndex].pBundles; pBcbWalker != (BCB *)NULL; pBcbWalker = pBcbWalker->pNext ) { if ( pBcbWalker->hConnection == hConnection ) return( pBcbWalker ); } return( (BCB *)NULL ); } //** // // Call: NumLinksInBundle // // Returns: The number of links whose LCP is in the Opened state in the bundle // represented by pBcb // DWORD NumLinksInBundle( IN BCB * pBcb ) { DWORD dwForIndex; PCB * pPcb; CPCB * pCpCb; DWORD dwNumLinks = 0; PPP_ASSERT( NULL != pBcb ); for (dwForIndex = 0; dwForIndex < pBcb->dwPpcbArraySize; dwForIndex++) { pPcb = pBcb->ppPcb[dwForIndex]; if ( NULL == pPcb ) { continue; } pCpCb = GetPointerToCPCB( pPcb, LCP_INDEX ); PPP_ASSERT( NULL != pCpCb ); if ( FSM_OPENED == pCpCb->State ) { dwNumLinks += 1; } } return( dwNumLinks ); } //** // // Call: GetPCBPointerFromBCB // // Returns: PCB * - Success // NULL - Failure // // Description: Given a BCB*, this function will return a pointer to the // PCB in it with the highest dwSubEntryIndex. // PCB * GetPCBPointerFromBCB( IN BCB * pBcb ) { DWORD dwForIndex; PCB * pPcb = NULL; PCB * pPcbTemp; CPCB * pCpCb; DWORD dwSubEntryIndex = 0; if ( pBcb == NULL ) { return( NULL ); } for (dwForIndex = 0; dwForIndex < pBcb->dwPpcbArraySize; dwForIndex++) { if ( ( pPcbTemp = pBcb->ppPcb[dwForIndex] ) != NULL ) { pCpCb = GetPointerToCPCB( pPcbTemp, LCP_INDEX ); PPP_ASSERT( NULL != pCpCb ); if ( FSM_OPENED == pCpCb->State ) { if ( pPcbTemp->dwSubEntryIndex >= dwSubEntryIndex ) { pPcb = pPcbTemp; dwSubEntryIndex = pPcbTemp->dwSubEntryIndex; } } } } return( pPcb ); } //** // // Call: HashPortToBucket // // Returns: Index into the PcbTable for the HPORT passed in. // // Description: Will hash the HPORT to a bucket index in the PcbTable. // DWORD HashPortToBucket( IN HPORT hPort ) { return( (HandleToUlong(hPort)) % PcbTable.NumPcbBuckets ); } //** // // Call: InsertWorkItemInQ // // Returns: None. // // Description: Inserts a work item in to the work item Q. // VOID InsertWorkItemInQ( IN PCB_WORK_ITEM * pWorkItem ) { // // Take Mutex around work item Q // EnterCriticalSection( &(WorkItemQ.CriticalSection) ); if ( WorkItemQ.pQTail != (PCB_WORK_ITEM *)NULL ) { WorkItemQ.pQTail->pNext = pWorkItem; WorkItemQ.pQTail = pWorkItem; if ( ProcessLineDown == pWorkItem->Process ) { // // If a lot of work items are coming in, the worker thread may get // overwhelmed and the following might happen in the work item Q: // IPCP(port 1)-LineDown(1)-LineUp(1) // We will send the reply to the IPCP packet to the wrong (ie new) // peer. // Proposed solution: Insert a LineDown at the beginning of the // queue, as well as at the end: // LineDown(1)-IPCP(port 1)-LineDown(1)-LineUp(1). // However, this will not take care of the following case: // IPCP(1)-LD(1)-LU(1)-LCP(1)-LD(1)-LU(1)-LCP(1) // We transform the above to: // LD(1)-LD(1)-IPCP(1)-LD(1)-LU(1)-LCP(1)-LD(1)-LU(1)-LCP(1) // However, the frequency of this problem will be a lot less. // PCB_WORK_ITEM * pWorkItem2; pWorkItem2 = (PCB_WORK_ITEM *)LOCAL_ALLOC( LPTR, sizeof(PCB_WORK_ITEM)); if ( NULL != pWorkItem2 ) { pWorkItem2->hPort = pWorkItem->hPort; pWorkItem2->Process = ProcessLineDown; PppLog( 2, "Inserting extra PPPEMSG_LineDown for hPort=%d", pWorkItem2->hPort ); pWorkItem2->pNext = WorkItemQ.pQHead; WorkItemQ.pQHead = pWorkItem2; } } } else { WorkItemQ.pQHead = pWorkItem; WorkItemQ.pQTail = pWorkItem; } SetEvent( WorkItemQ.hEventNonEmpty ); LeaveCriticalSection( &(WorkItemQ.CriticalSection) ); } //** // // Call: NotifyCallerOfFailureOnPort // // Returns: None // // Description: Will notify the caller or initiator of the PPP connection on // the port about a failure event. // VOID NotifyCallerOfFailureOnPort( IN HPORT hPort, IN BOOL fServer, IN DWORD dwRetCode ) { PPP_MESSAGE PppMsg; DWORD dwMsgId = fServer ? PPPDDMMSG_PppFailure : PPPMSG_PppFailure; ZeroMemory( &PppMsg, sizeof( PppMsg ) ); PppMsg.hPort = hPort; PppMsg.dwMsgId = dwMsgId; switch( dwMsgId ) { case PPPDDMMSG_PppFailure: PppMsg.ExtraInfo.DdmFailure.dwError = dwRetCode; PppConfigInfo.SendPPPMessageToDdm( &PppMsg ); break; case PPPMSG_PppFailure: PppMsg.ExtraInfo.Failure.dwError = dwRetCode; PppMsg.ExtraInfo.Failure.dwExtendedError = 0; RasSendPppMessageToRasman( PppMsg.hPort, (LPBYTE) &PppMsg ); break; } } //** // // Call: NotifyCallerOfFailure // // Returns: None // // Description: Will notify the caller or initiator of the PPP connection on // the port about a failure event. // VOID NotifyCallerOfFailure( IN PCB * pPcb, IN DWORD dwRetCode ) { // // Discard all non-LCP packets // pPcb->PppPhase = PPP_LCP; NotifyCaller( pPcb, ( pPcb->fFlags & PCBFLAG_IS_SERVER ) ? PPPDDMMSG_PppFailure : PPPMSG_PppFailure, &dwRetCode ); } //** // // Call: NotifyCaller // // Returns: None. // // Description: Will notify the caller or initiater of the PPP connection // for the port about PPP events on that port. // VOID NotifyCaller( IN PCB * pPcb, IN DWORD dwMsgId, IN PVOID pData ) { DWORD dwRetCode; PPP_MESSAGE PppMsg; ZeroMemory( &PppMsg, sizeof( PppMsg ) ); PppLog( 2, "NotifyCaller(hPort=%d, dwMsgId=%d)", pPcb->hPort, dwMsgId ); PppMsg.hPort = pPcb->hPort; PppMsg.dwMsgId = dwMsgId; switch( dwMsgId ) { case PPPDDMMSG_Stopped: if ( !(pPcb->fFlags & PCBFLAG_IS_SERVER) ) { return; } PppMsg.ExtraInfo.DdmStopped.dwReason = *((DWORD*)pData); PppConfigInfo.SendPPPMessageToDdm( &PppMsg ); break; case PPPDDMMSG_PortCleanedUp: if ( !(pPcb->fFlags & PCBFLAG_IS_SERVER) ) { return; } PppConfigInfo.SendPPPMessageToDdm( &PppMsg ); break; case PPPDDMMSG_PppFailure: if ( !(pPcb->fFlags & PCBFLAG_IS_SERVER) ) { return; } PppMsg.ExtraInfo.DdmFailure.dwError = *((DWORD*)pData); if ( pPcb->pBcb->szRemoteUserName[0] != (CHAR)NULL ) { strcpy(PppMsg.ExtraInfo.DdmFailure.szUserName, pPcb->pBcb->szRemoteUserName); } else { PppMsg.ExtraInfo.DdmFailure.szUserName[0] = (CHAR)NULL; } if ( pPcb->pBcb->szRemoteDomain[0] != (CHAR)NULL ) { strcpy(PppMsg.ExtraInfo.DdmFailure.szLogonDomain, pPcb->pBcb->szRemoteDomain); } else { PppMsg.ExtraInfo.DdmFailure.szLogonDomain[0] = (CHAR)NULL; } PppConfigInfo.SendPPPMessageToDdm( &PppMsg ); break; case PPPDDMMSG_NewBundle: case PPPDDMMSG_NewLink: if ( !(pPcb->fFlags & PCBFLAG_IS_SERVER) ) return; if ( dwMsgId == PPPDDMMSG_NewBundle ) { PppMsg.ExtraInfo.DdmNewBundle.pClientInterface = GetClientInterfaceInfo( pPcb ); } PppConfigInfo.SendPPPMessageToDdm( &PppMsg ); break; case PPPDDMMSG_CallbackRequest: if ( !(pPcb->fFlags & PCBFLAG_IS_SERVER) ) return; { PPPDDM_CALLBACK_REQUEST * pPppDdmCallbackRequest = ( PPPDDM_CALLBACK_REQUEST *)pData; CopyMemory( &(PppMsg.ExtraInfo.CallbackRequest), pPppDdmCallbackRequest, sizeof( PPPDDM_CALLBACK_REQUEST ) ); } PppConfigInfo.SendPPPMessageToDdm( &PppMsg ); break; case PPPDDMMSG_PppDone: if ( !(pPcb->fFlags & PCBFLAG_IS_SERVER) ) return; PppMsg.ExtraInfo.ProjectionResult = *((PPP_PROJECTION_RESULT*)pData); PppConfigInfo.SendPPPMessageToDdm( &PppMsg ); break; case PPPDDMMSG_Authenticated: // // Only server wants to know about authentication results. // if ( !(pPcb->fFlags & PCBFLAG_IS_SERVER) ) return; strcpy( PppMsg.ExtraInfo.AuthResult.szUserName, pPcb->pBcb->szRemoteUserName); strcpy( PppMsg.ExtraInfo.AuthResult.szLogonDomain, pPcb->pBcb->szRemoteDomain ); PppMsg.ExtraInfo.AuthResult.fAdvancedServer = pPcb->fFlags & PCBFLAG_IS_ADVANCED_SERVER; PppConfigInfo.SendPPPMessageToDdm( &PppMsg ); break; case PPPMSG_PppDone: case PPPMSG_AuthRetry: case PPPMSG_Projecting: case PPPMSG_CallbackRequest: case PPPMSG_Callback: case PPPMSG_ChangePwRequest: case PPPMSG_LinkSpeed: case PPPMSG_Progress: if ( pPcb->fFlags & PCBFLAG_IS_SERVER ) return; RasSendPppMessageToRasman( PppMsg.hPort, (LPBYTE) &PppMsg ); break; case PPPMSG_Stopped: if ( pPcb->fFlags & PCBFLAG_IS_SERVER ) return; PppMsg.dwError = *((DWORD*)pData); if(pPcb->fFlags & PCBFLAG_RECVD_TERM_REQ) { PppMsg.ExtraInfo.Stopped.dwFlags = PPP_FAILURE_REMOTE_DISCONNECT; } else { PppMsg.ExtraInfo.Stopped.dwFlags = 0; } RasSendPppMessageToRasman( PppMsg.hPort, (LPBYTE) &PppMsg ); break; case PPPMSG_PppFailure: if ( pPcb->fFlags & PCBFLAG_IS_SERVER ) return; PppMsg.ExtraInfo.Failure.dwError = *((DWORD*)pData); PppMsg.ExtraInfo.Failure.dwExtendedError = 0; RasSendPppMessageToRasman( PppMsg.hPort, (LPBYTE) &PppMsg ); break; case PPPMSG_ProjectionResult: if ( pPcb->fFlags & PCBFLAG_IS_SERVER ) return; PppMsg.ExtraInfo.ProjectionResult = *((PPP_PROJECTION_RESULT*)pData); RasSendPppMessageToRasman( PppMsg.hPort, (LPBYTE) &PppMsg ); break; case PPPMSG_InvokeEapUI: if ( pPcb->fFlags & PCBFLAG_IS_SERVER ) return; PppMsg.ExtraInfo.InvokeEapUI = *((PPP_INVOKE_EAP_UI*)pData); RasSendPppMessageToRasman( PppMsg.hPort, (LPBYTE)&PppMsg ); break; case PPPMSG_SetCustomAuthData: if ( pPcb->fFlags & PCBFLAG_IS_SERVER ) return; PppMsg.ExtraInfo.SetCustomAuthData= *((PPP_SET_CUSTOM_AUTH_DATA*)pData); RasSendPppMessageToRasman( PppMsg.hPort, (LPBYTE)&PppMsg ); break; default: PPP_ASSERT( FALSE ); break; } return; } //** // // Call: LogPPPEvent // // Returns: None // // Description: Will log a PPP event in the eventvwr. // VOID LogPPPEvent( IN DWORD dwEventId, IN DWORD dwData ) { PppLog( 2, "EventLog EventId = %d, error = %d", dwEventId, dwData ); PppLogError( dwEventId, 0, NULL, dwData ); } //** // // Call: GetCpIndexFromProtocol // // Returns: Index of the CP with dwProtocol in the CpTable. // -1 if there is not CP with dwProtocol in CpTable. // // Description: // DWORD GetCpIndexFromProtocol( IN DWORD dwProtocol ) { DWORD dwIndex; for ( dwIndex = 0; dwIndex < ( PppConfigInfo.NumberOfCPs + PppConfigInfo.NumberOfAPs ); dwIndex++ ) { if ( CpTable[dwIndex].CpInfo.Protocol == dwProtocol ) return( dwIndex ); } return( (DWORD)-1 ); } //** // // Call: IsLcpOpened // // Returns: TRUE - LCP is in the OPENED state. // FALSE - Otherwise // // Description: Uses the PppPhase value of the PORT_CONTROL_BLOCK to detect // to see if the LCP layer is in the OPENED state. // BOOL IsLcpOpened( PCB * pPcb ) { if ( pPcb->PppPhase == PPP_LCP ) return( FALSE ); else return( TRUE ); } //** // // Call: GetConfiguredInfo // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: // DWORD GetConfiguredInfo( IN PCB * pPcb, IN DWORD CPIndex, IN OUT PPP_PROJECTION_RESULT * pProjectionResult, OUT BOOL * pfNCPsAreDone ) { DWORD dwIndex; CPCB * pCpCb; DWORD dwRetCode; pProjectionResult->ip.dwError = ERROR_PPP_NO_PROTOCOLS_CONFIGURED; pProjectionResult->at.dwError = ERROR_PPP_NO_PROTOCOLS_CONFIGURED; pProjectionResult->ipx.dwError = ERROR_PPP_NO_PROTOCOLS_CONFIGURED; pProjectionResult->nbf.dwError = ERROR_PPP_NO_PROTOCOLS_CONFIGURED; pProjectionResult->ccp.dwError = ERROR_PPP_NO_PROTOCOLS_CONFIGURED; // // Check to see if we are all done // for (dwIndex = LCP_INDEX+1; dwIndex < PppConfigInfo.NumberOfCPs; dwIndex++) { pCpCb = GetPointerToCPCB( pPcb, dwIndex ); if ( pCpCb->fConfigurable ) { if ( pCpCb->NcpPhase == NCP_CONFIGURING ) { return( NO_ERROR ); } switch( CpTable[dwIndex].CpInfo.Protocol ) { case PPP_IPCP_PROTOCOL: pProjectionResult->ip.dwError = pCpCb->dwError; if ( pProjectionResult->ip.dwError == NO_ERROR ) { /* Assumption is made here that the ** PPP_PROJECTION_RESULT.wszServerAddress field immediately ** follows the PPP_PROJECTION_RESULT.wszAddress field and ** that both fields are 15 + 1 WCHARs long. */ dwRetCode =(CpTable[dwIndex].CpInfo.RasCpGetNegotiatedInfo)( pCpCb->pWorkBuf, &(pProjectionResult->ip)); if ( dwRetCode != NO_ERROR ) { PppLog( 2, "IPCP GetNegotiatedInfo returned %d", dwRetCode ); pCpCb->dwError = dwRetCode; pCpCb->NcpPhase = NCP_CONFIGURING; FsmClose( pPcb, dwIndex ); return( ( dwIndex == CPIndex ) ? dwRetCode : NO_ERROR ); } pPcb->pBcb->nboRemoteAddress = pProjectionResult->ip.dwRemoteAddress; if ( pProjectionResult->ip.fSendVJHCompression && pProjectionResult->ip.fReceiveVJHCompression ) { pPcb->pBcb->fFlags |= BCBFLAG_IPCP_VJ_NEGOTIATED; } } break; case PPP_ATCP_PROTOCOL: pProjectionResult->at.dwError = pCpCb->dwError; if ( pProjectionResult->at.dwError == NO_ERROR ) { dwRetCode=(CpTable[dwIndex].CpInfo.RasCpGetNegotiatedInfo)( pCpCb->pWorkBuf, &(pProjectionResult->at) ); if ( dwRetCode != NO_ERROR ) { pCpCb->dwError = dwRetCode; pCpCb->NcpPhase = NCP_CONFIGURING; FsmClose( pPcb, dwIndex ); return( ( dwIndex == CPIndex ) ? dwRetCode : NO_ERROR ); } } break; case PPP_IPXCP_PROTOCOL: pProjectionResult->ipx.dwError = pCpCb->dwError; if ( pProjectionResult->ipx.dwError == NO_ERROR ) { dwRetCode =(CpTable[dwIndex].CpInfo.RasCpGetNegotiatedInfo)( pCpCb->pWorkBuf, &(pProjectionResult->ipx) ); if ( dwRetCode != NO_ERROR ) { pCpCb->dwError = dwRetCode; pCpCb->NcpPhase = NCP_CONFIGURING; FsmClose( pPcb, dwIndex ); return( ( dwIndex == CPIndex ) ? dwRetCode : NO_ERROR ); } } break; case PPP_CCP_PROTOCOL: pProjectionResult->ccp.dwError = pCpCb->dwError; if ( pProjectionResult->ccp.dwError == NO_ERROR ) { dwRetCode= (CpTable[dwIndex].CpInfo.RasCpGetNegotiatedInfo)( pCpCb->pWorkBuf, &(pProjectionResult->ccp)); if ( dwRetCode != NO_ERROR ) { pCpCb->dwError = dwRetCode; pCpCb->NcpPhase = NCP_CONFIGURING; FsmClose( pPcb, dwIndex ); return( ( dwIndex == CPIndex ) ? dwRetCode : NO_ERROR ); } if ( RAS_DEVICE_TYPE( pPcb->dwDeviceType ) != RDT_Tunnel_L2tp ) { DWORD dwEncryptionType; // // Not L2TP. In the case of L2TP, we are interested in // the IpSec encryption, not MPPE. // dwEncryptionType = pProjectionResult->ccp.dwSendProtocolData & ( MSTYPE_ENCRYPTION_40 | MSTYPE_ENCRYPTION_40F | MSTYPE_ENCRYPTION_56 | MSTYPE_ENCRYPTION_128 ); switch ( dwEncryptionType ) { case MSTYPE_ENCRYPTION_40: case MSTYPE_ENCRYPTION_40F: pPcb->pBcb->fFlags |= BCBFLAG_BASIC_ENCRYPTION; break; case MSTYPE_ENCRYPTION_56: pPcb->pBcb->fFlags |= BCBFLAG_STRONGER_ENCRYPTION; break; case MSTYPE_ENCRYPTION_128: pPcb->pBcb->fFlags |= BCBFLAG_STRONGEST_ENCRYPTION; break; } } } break; case PPP_NBFCP_PROTOCOL: pProjectionResult->nbf.dwError = pCpCb->dwError; // // We call this even if we have an error one the client side // since we need the failure information // if ( ( pProjectionResult->nbf.dwError == NO_ERROR ) || ( !( pPcb->fFlags & PCBFLAG_IS_SERVER ) ) ) { dwRetCode=(CpTable[dwIndex].CpInfo.RasCpGetNegotiatedInfo)( pCpCb->pWorkBuf, &(pProjectionResult->nbf) ); if ( dwRetCode != NO_ERROR ) { pCpCb->dwError = dwRetCode; pCpCb->NcpPhase = NCP_CONFIGURING; FsmClose( pPcb, dwIndex ); return( ( dwIndex == CPIndex ) ? dwRetCode : NO_ERROR ); } } break; default: break; } } else { // // The protocol may have been de-configured because CpBegin failed // if ( pCpCb->dwError != NO_ERROR ) { switch( CpTable[dwIndex].CpInfo.Protocol ) { case PPP_IPCP_PROTOCOL: pProjectionResult->ip.dwError = pCpCb->dwError; break; case PPP_ATCP_PROTOCOL: pProjectionResult->at.dwError = pCpCb->dwError; break; case PPP_IPXCP_PROTOCOL: pProjectionResult->ipx.dwError = pCpCb->dwError; break; case PPP_NBFCP_PROTOCOL: pProjectionResult->nbf.dwError = pCpCb->dwError; break; case PPP_CCP_PROTOCOL: pProjectionResult->ccp.dwError = pCpCb->dwError; break; default: break; } } } } if ( ( pPcb->fFlags & PCBFLAG_IS_SERVER ) && ( pProjectionResult->nbf.dwError != NO_ERROR )) { // // If NBF was not configured copy the computername to the wszWksta // field // if ( *(pPcb->pBcb->szComputerName) == (CHAR)NULL ) { pProjectionResult->nbf.wszWksta[0] = (WCHAR)NULL; } else { CHAR chComputerName[NETBIOS_NAME_LEN+1]; memset( chComputerName, ' ', NETBIOS_NAME_LEN ); chComputerName[NETBIOS_NAME_LEN] = (CHAR)NULL; strcpy( chComputerName, pPcb->pBcb->szComputerName + strlen(MS_RAS_WITH_MESSENGER)); chComputerName[strlen(chComputerName)] = (CHAR)' '; MultiByteToWideChar( CP_ACP, 0, chComputerName, -1, pProjectionResult->nbf.wszWksta, sizeof( pProjectionResult->nbf.wszWksta ) ); if ( !memcmp( MS_RAS_WITH_MESSENGER, pPcb->pBcb->szComputerName, strlen( MS_RAS_WITH_MESSENGER ) ) ) { pProjectionResult->nbf.wszWksta[NETBIOS_NAME_LEN-1] = (WCHAR)3; } } } *pfNCPsAreDone = TRUE; return( NO_ERROR ); } //** // // Call: AreNCPsDone // // Returns: NO_ERROR - Success // anything else - Failure // // Description: If we detect that all configurable NCPs have completed their // negotiation, then the PPP_PROJECTION_RESULT structure is also // filled in. // This is called during the FsmThisLayerFinished or FsmThisLayerUp // calls for a certain CP. The index of this CP is passed in. // If any call to that particular CP fails then an error code is // passed back. If any call to any other CP fails then the error // is stored in the dwError field for that CP but the return is // successful. This is done so that the FsmThisLayerFinshed or // FsmThisLayerUp calls know if they completed successfully for // that CP or not. Depending on this, the FSM changes the state // for that CP or not. // DWORD AreNCPsDone( IN PCB * pPcb, IN DWORD CPIndex, OUT PPP_PROJECTION_RESULT * pProjectionResult, OUT BOOL * pfNCPsAreDone ) { DWORD dwRetCode; *pfNCPsAreDone = FALSE; ZeroMemory( pProjectionResult, sizeof( PPP_PROJECTION_RESULT ) ); dwRetCode = GetConfiguredInfo( pPcb, CPIndex, pProjectionResult, pfNCPsAreDone ); if ( dwRetCode != NO_ERROR ) { return( dwRetCode ); } if ( !(*pfNCPsAreDone ) ) { return( NO_ERROR ); } // // Now get LCP information // pProjectionResult->lcp.hportBundleMember = (HPORT)INVALID_HANDLE_VALUE; pProjectionResult->lcp.szReplyMessage = pPcb->pBcb->szReplyMessage; dwRetCode = (CpTable[LCP_INDEX].CpInfo.RasCpGetNegotiatedInfo)( pPcb->LcpCb.pWorkBuf, &(pProjectionResult->lcp)); if ( RAS_DEVICE_TYPE( pPcb->dwDeviceType ) == RDT_Tunnel_L2tp ) { if ( pPcb->pBcb->fFlags & BCBFLAG_BASIC_ENCRYPTION ) { pProjectionResult->lcp.dwLocalOptions |= PPPLCPO_DES_56; pProjectionResult->lcp.dwRemoteOptions |= PPPLCPO_DES_56; } else if ( pPcb->pBcb->fFlags & BCBFLAG_STRONGEST_ENCRYPTION ) { pProjectionResult->lcp.dwLocalOptions |= PPPLCPO_3_DES; pProjectionResult->lcp.dwRemoteOptions |= PPPLCPO_3_DES; } } pProjectionResult->lcp.dwLocalEapTypeId = pPcb->dwServerEapTypeId; pProjectionResult->lcp.dwRemoteEapTypeId = pPcb->dwClientEapTypeId; return( dwRetCode ); } //** // // Call: GetUid // // Returns: A BYTE value viz. unique with the 0 - 255 range // // Description: // BYTE GetUId( IN PCB * pPcb, IN DWORD CpIndex ) { BYTE UId; // // For NCPs get the UID from the BCB // if ( ( CpIndex != LCP_INDEX ) && ( CpIndex >= PppConfigInfo.NumberOfCPs ) ) { UId = (BYTE)(pPcb->pBcb->UId); (pPcb->pBcb->UId)++; return( UId ); } UId = (BYTE)(pPcb->UId); (pPcb->UId)++; return( UId ); } //** // // Call: AlertableWaitForSingleObject // // Returns: None // // Description: Will wait infintely for a single object in alertable mode. If // the wait completes because of an IO completion it will // wait again. // VOID AlertableWaitForSingleObject( IN HANDLE hObject ) { DWORD dwRetCode; do { dwRetCode = WaitForSingleObjectEx( hObject, INFINITE, TRUE ); PPP_ASSERT( dwRetCode != 0xFFFFFFFF ); PPP_ASSERT( dwRetCode != WAIT_TIMEOUT ); } while ( dwRetCode == WAIT_IO_COMPLETION ); } //** // // Call: NotifyIPCPOfNBFCPProjectiont // // Returns: TRUE - Success // FALSE - Failure // // Description: Will notify IPCPs of all the configuration information, // specifically it is looking for NBFCP information. // Will return FALSE if the IPCP was not notified // successfully. // // BOOL NotifyIPCPOfNBFCPProjection( IN PCB * pPcb, IN DWORD CpIndex ) { CPCB* pCpCb; DWORD dwRetCode; PPP_PROJECTION_RESULT ProjectionResult; PPPCP_NBFCP_RESULT NbfCpResult; DWORD NBFCPIndex; DWORD IPCPIndex; NBFCPIndex = GetCpIndexFromProtocol( PPP_NBFCP_PROTOCOL ); IPCPIndex = GetCpIndexFromProtocol( PPP_IPCP_PROTOCOL ); // // No IPCP installed, we are done // if ( IPCPIndex == (DWORD)-1 ) { return( TRUE ); } if ( CpTable[CpIndex].CpInfo.Protocol == PPP_IPCP_PROTOCOL ) { if ( NBFCPIndex != (DWORD)-1 ) { pCpCb = GetPointerToCPCB( pPcb, NBFCPIndex ); if ( pCpCb == NULL ) { return( FALSE ); } if ( pCpCb->fConfigurable ) { if ( pCpCb->NcpPhase == NCP_CONFIGURING ) { // // NBFCP is still being configured, we need to wait // until it is done // PppLog( 2, "Waiting for NBFCP to complete" ); return( TRUE ); } } } } if ( CpTable[CpIndex].CpInfo.Protocol == PPP_NBFCP_PROTOCOL ) { pCpCb = GetPointerToCPCB( pPcb, IPCPIndex ); if ( pCpCb == NULL ) { return( FALSE ); } if ( pCpCb->fConfigurable ) { if ( pCpCb->NcpPhase == NCP_CONFIGURING ) { // // IPCP is still being configured, we need to wait // until it is done // PppLog( 2, "Waiting for IPCP to complete" ); return( TRUE ); } } else { // // IPCP not configurable, we are done. // return( TRUE ); } } // // If we are here that means we need to notify IPCP of NBFCP projection. // NBF may or may not be configurable, or may or may not have projected // successfully // ZeroMemory( &ProjectionResult, sizeof( PPP_PROJECTION_RESULT ) ); ZeroMemory( &NbfCpResult, sizeof( NbfCpResult ) ); ProjectionResult.nbf.dwError = ERROR_PPP_NO_PROTOCOLS_CONFIGURED; if ( NBFCPIndex != (DWORD)-1 ) { pCpCb = GetPointerToCPCB( pPcb, NBFCPIndex ); if ( pCpCb == NULL ) { return( FALSE ); } if ( pCpCb->fConfigurable ) { if ( ProjectionResult.nbf.dwError == NO_ERROR ) { dwRetCode = (CpTable[NBFCPIndex].CpInfo.RasCpGetNegotiatedInfo)( pCpCb->pWorkBuf, &(ProjectionResult.nbf) ); if ( dwRetCode != NO_ERROR ) { pCpCb->dwError = dwRetCode; pCpCb->NcpPhase = NCP_CONFIGURING; FsmClose( pPcb, NBFCPIndex ); return( FALSE ); } } } } // // Notify IPCP of NBFCP projection // pCpCb = GetPointerToCPCB( pPcb, IPCPIndex ); if ( pCpCb == NULL ) { return( FALSE ); } dwRetCode = (CpTable[IPCPIndex].CpInfo.RasCpProjectionNotification)( pCpCb->pWorkBuf, (PVOID)&ProjectionResult ); PppLog( 2, "Notifying IPCP of projection notification" ); if ( dwRetCode != NO_ERROR ) { PppLog( 2,"RasIPCPProjectionNotification returned %d", dwRetCode ); pCpCb->dwError = dwRetCode; pCpCb->NcpPhase = NCP_CONFIGURING; FsmClose( pPcb, IPCPIndex ); return( FALSE ); } return( TRUE ); } //** // // Call: CalculateRestartTimer // // Returns: The value of the restart timer in seconds based on the link // speed. // // Description: Will get the link speed from rasman and calculate the value // if the restart timer based on it. // DWORD CalculateRestartTimer( IN HPORT hPort ) { RASMAN_INFO RasmanInfo; if ( RasGetInfo( NULL, hPort, &RasmanInfo ) != NO_ERROR ) { return( PppConfigInfo.DefRestartTimer ); } if ( RasmanInfo.RI_LinkSpeed <= 1200 ) { return( 7 ); } if ( RasmanInfo.RI_LinkSpeed <= 2400 ) { return( 5 ); } if ( RasmanInfo.RI_LinkSpeed <= 9600 ) { return( 3 ); } else { return( 1 ); } } //** // // Call: CheckCpsForInactivity // // Returns: None // // Description: Will call each Control protocol to get the time since last // activity. // VOID CheckCpsForInactivity( IN PCB * pPcb, IN DWORD dwEvent //Type of event to check against ) { DWORD dwRetCode; DWORD dwIndex; DWORD dwTimeSinceLastActivity = 0; PppLog( 2, "Time to check Cps for Activity for port %d", pPcb->hPort ); dwRetCode = RasGetTimeSinceLastActivity( pPcb->hPort, &dwTimeSinceLastActivity ); if ( dwRetCode != NO_ERROR ) { PppLog(2, "RasGetTimeSinceLastActivityTime returned %d\r\n", dwRetCode); return; } PppLog(2, "Port %d inactive for %d seconds", pPcb->hPort, dwTimeSinceLastActivity ); // // If all the stacks have been inactive for at least AutoDisconnectTime // then we disconnect. // if ( dwEvent == TIMER_EVENT_AUTODISCONNECT ) { if ( dwTimeSinceLastActivity >= pPcb->dwAutoDisconnectTime) { PppLog(1,"Disconnecting port %d due to inactivity.", pPcb->hPort); if ( !( pPcb->fFlags & PCBFLAG_IS_SERVER ) ) { HANDLE hLogHandle; if( pPcb->pBcb->InterfaceInfo.IfType == ROUTER_IF_TYPE_FULL_ROUTER) { hLogHandle = RouterLogRegisterA( "RemoteAccess" ); } else { hLogHandle = PppConfigInfo.hLogEvents; } if ( hLogHandle != NULL ) { CHAR * pszPortName = pPcb->szPortName; RouterLogInformationA( hLogHandle, ROUTERLOG_CLIENT_AUTODISCONNECT, 1, &pszPortName, NO_ERROR ); if ( hLogHandle != PppConfigInfo.hLogEvents ) { RouterLogDeregisterA( hLogHandle ); } } } // // Terminate the link // pPcb->LcpCb.dwError = ERROR_IDLE_DISCONNECTED; FsmClose( pPcb, LCP_INDEX ); } else { InsertInTimerQ( pPcb->dwPortId, pPcb->hPort, 0, 0, FALSE, TIMER_EVENT_AUTODISCONNECT, pPcb->dwAutoDisconnectTime - dwTimeSinceLastActivity ); } } // // Do the LCP Echo request if its pppoe // else if ( (RDT_PPPoE == RAS_DEVICE_TYPE(pPcb->dwDeviceType)) && (dwEvent == TIMER_EVENT_LCP_ECHO )) { if ( pPcb->fEchoRequestSend ) { // // Because the line was inactive for dwEchoTimeout, we send an echo // request and did not get any response back in 3 seconds after that. // So we have to disconnect the port. // pPcb->dwNumEchoResponseMissed ++; if ( pPcb->dwNumEchoResponseMissed >= pPcb->dwNumMissedEchosBeforeDisconnect ) { PppLog(1,"Missed %d consecutive echo responses. Disconnecting port %d " "due to no echo responses.", pPcb->dwNumMissedEchosBeforeDisconnect, pPcb->hPort); // // Terminate the link // pPcb->LcpCb.dwError = ERROR_IDLE_DISCONNECTED; pPcb->fEchoRequestSend = 0; pPcb->dwNumEchoResponseMissed = 0; FsmClose( pPcb, LCP_INDEX ); } else { //no response yet. So send one more echo request. FsmSendEchoRequest( pPcb, LCP_INDEX); InsertInTimerQ( pPcb->dwPortId, pPcb->hPort, 0, 0, FALSE, TIMER_EVENT_LCP_ECHO, pPcb->dwLCPEchoTimeInterval ); } } else { // //No echo request send or we have got a response for echo already // // // check to see if the the inactivity is more than EchoTimeout // if ( dwTimeSinceLastActivity >= pPcb->dwIdleBeforeEcho ) { // // call the lcp cp to make the echo request // if ( FsmSendEchoRequest( pPcb, LCP_INDEX) ) { // // send the echo requesst and set the flag // pPcb->fEchoRequestSend = 1; //Setup for next echo request here. InsertInTimerQ( pPcb->dwPortId, pPcb->hPort, 0, 0, FALSE, TIMER_EVENT_LCP_ECHO, pPcb->dwLCPEchoTimeInterval ); } else { PppLog (1, "Send EchoRequest Failed..."); } } else { InsertInTimerQ( pPcb->dwPortId, pPcb->hPort, 0, 0, FALSE, TIMER_EVENT_LCP_ECHO, pPcb->dwIdleBeforeEcho - dwTimeSinceLastActivity ); } } } } //These functions are in ppputil.lib. Should be used from there #if 0 //** // // Call: // // Returns: // // Description: // CHAR* DecodePw( IN CHAR chSeed, IN OUT CHAR* pszPassword ) /* Un-obfuscate 'pszPassword' in place. ** ** Returns the address of 'pszPassword'. */ { return EncodePw( chSeed, pszPassword ); } //** // // Call: // // Returns: // // Description: // CHAR* EncodePw( IN CHAR chSeed, IN OUT CHAR* pszPassword ) /* Obfuscate 'pszPassword' in place to foil memory scans for passwords. ** ** Returns the address of 'pszPassword'. */ { if (pszPassword) { CHAR* psz; ReverseString( pszPassword ); for (psz = pszPassword; *psz != '\0'; ++psz) { if (*psz != chSeed) *psz ^= chSeed; /* if (*psz != (CHAR)PASSWORDMAGIC) *psz ^= PASSWORDMAGIC; */ } } return pszPassword; } //** // // Call: ReverseString // // Returns: // // Description: // VOID ReverseString( CHAR* psz ) /* Reverses order of characters in 'psz'. */ { CHAR* pszBegin; CHAR* pszEnd; for (pszBegin = psz, pszEnd = psz + strlen( psz ) - 1; pszBegin < pszEnd; ++pszBegin, --pszEnd) { CHAR ch = *pszBegin; *pszBegin = *pszEnd; *pszEnd = ch; } } #endif //** // // Call: GetLocalComputerName // // Returns: None // // Description: Will get the local computer name. Will also find out if the // the messenger is running and set the appropriate prefix. // VOID GetLocalComputerName( IN OUT LPSTR szComputerName ) { SC_HANDLE ScHandle; SC_HANDLE ScHandleService; SERVICE_STATUS ServiceStatus; CHAR chComputerName[MAX_COMPUTERNAME_LENGTH + 1]; DWORD dwComputerNameLen; *szComputerName = (CHAR)NULL; // // Open the local service control manager // ScHandle = OpenSCManager( NULL, NULL, GENERIC_READ ); if ( ScHandle == (SC_HANDLE)NULL ) { return; } ScHandleService = OpenService( ScHandle, SERVICE_MESSENGER, SERVICE_QUERY_STATUS ); if ( ScHandleService == (SC_HANDLE)NULL ) { CloseServiceHandle( ScHandle ); return; } if ( !QueryServiceStatus( ScHandleService, &ServiceStatus ) ) { CloseServiceHandle( ScHandle ); CloseServiceHandle( ScHandleService ); return; } CloseServiceHandle( ScHandle ); CloseServiceHandle( ScHandleService ); if ( ServiceStatus.dwCurrentState == SERVICE_RUNNING ) { strcpy( szComputerName, MS_RAS_WITH_MESSENGER ); } else { strcpy( szComputerName, MS_RAS_WITHOUT_MESSENGER ); } // // Get the size of the buffer to hold local computer name // dwComputerNameLen = sizeof(chComputerName); if ( !GetComputerNameA( chComputerName, &dwComputerNameLen ) ) { *szComputerName = (CHAR)NULL; return; } strcpy( szComputerName+strlen(szComputerName), chComputerName ); CharToOemA( szComputerName, szComputerName ); PppLog( 2, "Local identification = %s", szComputerName ); return; } //** // // Call: InitEndpointDiscriminator // // Returns: NO_ERROR - Success // non-zero - Failure // // Description: Will obtain a unique end-point discriminator to be used to // negotiate multi-link. This end-point discrimintator has to // globally unique to this machine. // // We first try to use a Class 3 IEEE 802.1 address of any // netcard that is in this local machine. // // If this fails we use the RPC UUID generator to generate a // Class 1 discriminator. // // If this fails we simply use the local computer name as the // Class 1 discriminator. // // Simply use a random number if all else fails. // // NOTE: For now we skip over NwLnkNb because it may return an // address of 1 and not the real MAC address. There is not way // in user mode for now to get the address. // DWORD InitEndpointDiscriminator( IN OUT BYTE EndPointDiscriminator[] ) { DWORD dwRetCode; LPBYTE pBuffer; DWORD EntriesRead; DWORD TotalEntries; PWCHAR pwChar; DWORD dwIndex; UUID Uuid; DWORD dwComputerNameLen; PWKSTA_TRANSPORT_INFO_0 pWkstaTransport; // // Enumerate all the transports used by the local rdr and then get the // address of the first LAN transport card // dwRetCode = NetWkstaTransportEnum( NULL, // Local 0, // Level &pBuffer, // Output buffer (DWORD)-1,// Pref. max len &EntriesRead, &TotalEntries, NULL ); if ( ( dwRetCode == NO_ERROR ) && ( EntriesRead > 0 ) ) { pWkstaTransport = (PWKSTA_TRANSPORT_INFO_0)pBuffer; while ( EntriesRead-- > 0 ) { if ( !pWkstaTransport->wkti0_wan_ish ) { EndPointDiscriminator[0] = 3; // Class 3 pwChar = pWkstaTransport->wkti0_transport_address; for ( dwIndex = 0; dwIndex < 6; dwIndex++ ) { EndPointDiscriminator[dwIndex+1] = ( iswalpha( *pwChar ) ? *pwChar-L'A'+10 : *pwChar-L'0' ) * 0x10 + ( iswalpha( *(pwChar+1) ) ? *(pwChar+1)-L'A'+10 : *(pwChar+1)-L'0' ); pwChar++; pwChar++; } NetApiBufferFree( pBuffer ); return( NO_ERROR ); } pWkstaTransport++; } } if ( dwRetCode == NO_ERROR ) { NetApiBufferFree( pBuffer ); } EndPointDiscriminator[0] = 1; // Class 1 // // We failed to get the mac address so try to use UUIDGEN to get an unique // local id // dwRetCode = UuidCreate( &Uuid ); if ( ( dwRetCode == RPC_S_UUID_NO_ADDRESS ) || ( dwRetCode == RPC_S_OK ) || ( dwRetCode == RPC_S_UUID_LOCAL_ONLY) ) { HostToWireFormat32( Uuid.Data1, EndPointDiscriminator+1 ); HostToWireFormat16( Uuid.Data2, EndPointDiscriminator+5 ); HostToWireFormat16( Uuid.Data3, EndPointDiscriminator+7 ); CopyMemory( EndPointDiscriminator+9, Uuid.Data4, 8 ); return( NO_ERROR ); } // // We failed to get the UUID so simply use the computer name // dwComputerNameLen = 20; if ( !GetComputerNameA( EndPointDiscriminator+1, &dwComputerNameLen ) ) { // // We failed to get the computer name so use a random number // srand( GetCurrentTime() ); HostToWireFormat32( rand(), EndPointDiscriminator+1 ); } return( NO_ERROR ); } //** // // Call: AllocateAndInitBcb // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: Allocates and initializes a Bundle control block // DWORD AllocateAndInitBcb( PCB * pPcb ) { DWORD dwIndex; DWORD dwRetCode; // // Allocate space for NumberOfNcp - LCP - 1 already in the // Bcb structure // pPcb->pBcb = (BCB *)LOCAL_ALLOC( LPTR, sizeof( BCB ) + ( sizeof( CPCB ) * ( PppConfigInfo.NumberOfCPs - 2 ) ) ); if ( pPcb->pBcb == (BCB *)NULL ) { return( GetLastError() ); } pPcb->pBcb->dwBundleId = GetNewPortOrBundleId(); pPcb->pBcb->UId = 0; pPcb->pBcb->dwLinkCount = 1; pPcb->pBcb->dwAcctLinkCount = 1; pPcb->pBcb->dwMaxLinksAllowed = 0xFFFFFFFF; pPcb->pBcb->fFlags = 0; pPcb->pBcb->hLicense = INVALID_HANDLE_VALUE; pPcb->pBcb->BapCb.dwId = 0; pPcb->pBcb->hTokenImpersonateUser = INVALID_HANDLE_VALUE; pPcb->pBcb->chSeed = GEN_RAND_ENCODE_SEED; //random number seed for encode/decode password // // The most common case is to have no more than 2 links in the bundle. // pPcb->pBcb->ppPcb = (PPCB *)LOCAL_ALLOC( LPTR, sizeof( PPCB ) * 2 ); if ( pPcb->pBcb->ppPcb == (PPCB *) NULL ) { LOCAL_FREE( pPcb->pBcb ); pPcb->pBcb = NULL; return( GetLastError() ); } pPcb->pBcb->dwPpcbArraySize = 2; pPcb->pBcb->ppPcb[0] = pPcb; pPcb->pBcb->ppPcb[1] = NULL; for( dwIndex=0; dwIndex < PppConfigInfo.NumberOfCPs-1; dwIndex++ ) { CPCB * pCpCb = &(pPcb->pBcb->CpCb[dwIndex]); pCpCb->NcpPhase = NCP_DEAD; } return( NO_ERROR ); } //** // // Call: DeallocateAndRemoveBcbFromTable // // Returns: None // // Description: Will remove the Bcb from the hash table // VOID DeallocateAndRemoveBcbFromTable( IN BCB * pBcb ) { DWORD dwIndex; BCB * pBcbWalker = (BCB *)NULL; BCB * pBcbTemp = (BCB *)NULL; if ( NULL == pBcb ) { return; } dwIndex = HashPortToBucket( pBcb->hConnection ); pBcbWalker = PcbTable.BcbBuckets[dwIndex].pBundles; pBcbTemp = pBcbWalker; while( pBcbTemp != (BCB *)NULL ) { if ( pBcbTemp->hConnection == pBcb->hConnection ) { if ( pBcbTemp == PcbTable.BcbBuckets[dwIndex].pBundles ) { PcbTable.BcbBuckets[dwIndex].pBundles = pBcbTemp->pNext; } else { pBcbWalker->pNext = pBcbTemp->pNext; } break; } pBcbWalker = pBcbTemp; pBcbTemp = pBcbWalker->pNext; } // // Release the licence if there is one // if ( INVALID_HANDLE_VALUE != pBcb->hLicense ) { NtLSFreeHandle( (LS_HANDLE)(pBcb->hLicense) ); } ZeroMemory( pBcb->szPassword, sizeof( pBcb->szPassword ) ); ZeroMemory( pBcb->szOldPassword, sizeof( pBcb->szOldPassword ) ); // // Close the OpenThreadToken() handle obtained from Rasman // if ( INVALID_HANDLE_VALUE != pBcb->hTokenImpersonateUser ) { CloseHandle( pBcb->hTokenImpersonateUser ); } // // pCustomAuthConnData, pCustomAuthUserData, szPhonebookPath, // szEntryName, and szServerPhoneNumber are allocated by RasMan // and MUST be LocalFree'd, not LOCAL_FREE'd. // LocalFree( pBcb->pCustomAuthConnData ); LocalFree( pBcb->pCustomAuthUserData ); LocalFree( pBcb->EapUIData.pEapUIData ); LocalFree( pBcb->szPhonebookPath ); LocalFree( pBcb->szEntryName ); LocalFree( pBcb->BapCb.szServerPhoneNumber ); LocalFree( pBcb->BapCb.szClientPhoneNumber ); LocalFree( pBcb->szReplyMessage ); if ( NULL != pBcb->szTextualSid ) { LOCAL_FREE( pBcb->szTextualSid ); } if ( NULL != pBcb->szRemoteIdentity ) { LOCAL_FREE( pBcb->szRemoteIdentity ); } if ( NULL != pBcb->ppPcb ) { LOCAL_FREE( pBcb->ppPcb ); } LOCAL_FREE( pBcb ); } //** // // Call: RemovePcbFromTable // // Returns: None // // Description: Will remove the Pcb from the hash table // VOID RemovePcbFromTable( IN PCB * pPcb ) { DWORD dwIndex = HashPortToBucket( pPcb->hPort ); PCB * pPcbWalker = (PCB *)NULL; PCB * pPcbTemp = (PCB *)NULL; pPcbWalker = PcbTable.PcbBuckets[dwIndex].pPorts; pPcbTemp = pPcbWalker; while( pPcbTemp != (PCB *)NULL ) { if ( pPcbTemp->hPort == pPcb->hPort ) { if ( pPcbTemp == PcbTable.PcbBuckets[dwIndex].pPorts ) { PcbTable.PcbBuckets[dwIndex].pPorts = pPcbTemp->pNext; } else { pPcbWalker->pNext = pPcbTemp->pNext; } break; } pPcbWalker = pPcbTemp; pPcbTemp = pPcbWalker->pNext; } } //** // // Call: WillPortBeBundled // // Returns: TRUE - Port will be bundled after authentication // FALSE - Port cannot be bundled // // Description: Will check to see if the usernames and discriminators match // BOOL WillPortBeBundled( IN PCB * pPcb ) { PCB* pPcbWalker; DWORD dwIndex; // // Optimization: Have rasman tell PPP that the port will be bundled. // // // Walk thru the list of PCBs // for ( dwIndex = 0; dwIndex < PcbTable.NumPcbBuckets; dwIndex++ ) { for ( pPcbWalker = PcbTable.PcbBuckets[dwIndex].pPorts; pPcbWalker != NULL; pPcbWalker = pPcbWalker->pNext ) { // // Don't bundle a port with itself. // if ( pPcbWalker->hPort == pPcb->hPort ) { continue; } // // If the current port negotiated MRRU ie multilink. // if ( pPcbWalker->fFlags & PCBFLAG_CAN_BE_BUNDLED ) { LCPCB * pLcpCb1 = (LCPCB*)(pPcbWalker->LcpCb.pWorkBuf); LCPCB * pLcpCb2 = (LCPCB*)(pPcb->LcpCb.pWorkBuf); if ( _stricmp(pPcbWalker->pBcb->szLocalUserName, pPcb->pBcb->szLocalUserName) != 0 ) { // // Authenticator mismatch, not in our bundle // continue; } if ( ( pLcpCb1->Remote.Work.EndpointDiscr[0] != 0 ) && ( memcmp(pLcpCb1->Remote.Work.EndpointDiscr, pLcpCb2->Remote.Work.EndpointDiscr, sizeof(pLcpCb1->Remote.Work.EndpointDiscr))!=0)) { // // Discriminator mismatch, not in our bundle // continue; } return( TRUE ); } } } return( FALSE ); } //** // // Call: CanPortsBeBundled // // Returns: TRUE - Ports can be bundled // FALSE - Ports cannot be bundled // // Description: Will check to see if the usernames and discriminators match // BOOL CanPortsBeBundled( IN PCB * pPcb1, IN PCB * pPcb2, IN BOOL fCheckPolicy ) { CPCB * pCpCb; LCPCB * pLcpCb1 = (LCPCB*)(pPcb1->LcpCb.pWorkBuf); LCPCB * pLcpCb2 = (LCPCB*)(pPcb2->LcpCb.pWorkBuf); if ( fCheckPolicy && ( PppConfigInfo.fFlags & PPPCONFIG_FLAG_WKSTA ) && ( pPcb1->fFlags & PCBFLAG_IS_SERVER ) && ( pPcb2->fFlags & PCBFLAG_IS_SERVER ) ) { // // RAS server policy on workstation. Allow multilinking of devices in // the same device class only, ie all devices are dial-up, or all // devices are VPN, or all devices are DCC (direct) // if ( ( pPcb1->dwDeviceType & RDT_Tunnel ) != ( pPcb2->dwDeviceType & RDT_Tunnel ) ) { return( FALSE ); } if ( ( pPcb1->dwDeviceType & RDT_Direct ) != ( pPcb2->dwDeviceType & RDT_Direct ) ) { return( FALSE ); } } // // If the current port is in PPP_NCP phase meaning that it is post // authentication and callback. // if ( pPcb1->PppPhase == PPP_NCP ) { if ( ( _stricmp(pPcb1->pBcb->szLocalUserName, pPcb2->pBcb->szLocalUserName) != 0 )|| ( _stricmp(pPcb1->pBcb->szRemoteUserName, pPcb2->pBcb->szRemoteUserName) != 0 )) { // // Authenticator mismatch, not in our bundle // return( FALSE ); } if ( ( pLcpCb1->Remote.Work.EndpointDiscr[0] != 0 ) && ( memcmp(pLcpCb1->Remote.Work.EndpointDiscr, pLcpCb2->Remote.Work.EndpointDiscr, sizeof(pLcpCb1->Remote.Work.EndpointDiscr))!=0)) { // // Discriminator mismatch, not in our bundle // return( FALSE ); } if ( ( pLcpCb1->Local.Work.EndpointDiscr[0] != 0 ) && ( memcmp(pLcpCb1->Local.Work.EndpointDiscr, pLcpCb2->Local.Work.EndpointDiscr, sizeof(pLcpCb1->Local.Work.EndpointDiscr))!=0)) { // // Discriminator mismatch, not in our bundle // return( FALSE ); } return( TRUE ); } return( FALSE ); } //** // // Call: TryToBundleWithAnotherLink // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: Will search through all the PCBs for a port that can be bundled. // We follow the criteria specified by RFC 1717. // phPortMulttlink will point to an HPORT that this port was // bundled with if this function returns TRUE. // // If the link is to be bundled, and its link discriminator is not // unique, we return a unique discriminator in pwLinkDiscriminator. // DWORD TryToBundleWithAnotherLink( IN PCB * pPcb ) { DWORD dwIndex; PCB * pPcbWalker; BCB * pBcbOld = NULL; DWORD dwRetCode = NO_ERROR; DWORD dwForIndex; PPCB * ppPcb; DWORD CpIndex; CPCB * pCpCb; pPcb->hportBundleMember = (HPORT)INVALID_HANDLE_VALUE; // // Walk thru the list of PCBs // for ( dwIndex = 0; dwIndex < PcbTable.NumPcbBuckets; dwIndex++ ) { for( pPcbWalker = PcbTable.PcbBuckets[dwIndex].pPorts; pPcbWalker != NULL; pPcbWalker = pPcbWalker->pNext ) { // // Don't bundle a port with itself. // if ( pPcbWalker->hPort == pPcb->hPort ) { continue; } // // If the current port negotiated MRRU ie multilink. // if ( ( pPcbWalker->fFlags & PCBFLAG_CAN_BE_BUNDLED ) && ( CanPortsBeBundled( pPcbWalker, pPcb, TRUE ) ) ) { if ( pPcbWalker->pBcb->dwLinkCount >= pPcbWalker->pBcb->dwMaxLinksAllowed ) { dwRetCode = ERROR_PORT_LIMIT_REACHED; break; } CpIndex = GetCpIndexFromProtocol( PPP_BACP_PROTOCOL ); if (CpIndex != (DWORD)-1) { pCpCb = GetPointerToCPCB( pPcbWalker, CpIndex ); if ( pCpCb->State != FSM_OPENED && ( pPcb->pBcb->fFlags & BCBFLAG_BAP_REQUIRED )) { PppLog( 1, "BAP is required for this user, but BACP " "is not open. hPort = %d", pPcb->hPort ); dwRetCode = ERROR_BAP_REQUIRED; break; } } // // Either there was no authenticator and no discriminator,or // there were both and there was match for both. So join the // bundle in either case. // dwRetCode = RasPortBundle( pPcbWalker->hPort, pPcb->hPort ); if ( dwRetCode == NO_ERROR ) { PppLog( 2, "Bundling this link with hPort = %d", pPcbWalker->hPort ); pPcb->hportBundleMember = pPcbWalker->hPort; break; } } } if ( pPcb->hportBundleMember != (HPORT)INVALID_HANDLE_VALUE ) { break; } } // // Bundle the port // if ( ( dwRetCode == NO_ERROR ) && ( pPcb->hportBundleMember != (HPORT)INVALID_HANDLE_VALUE ) ) { pPcbWalker->fFlags |= PCBFLAG_IS_BUNDLED; pPcb->fFlags |= PCBFLAG_IS_BUNDLED; pBcbOld = pPcb->pBcb; pPcb->pBcb = pPcbWalker->pBcb; pPcbWalker->hportBundleMember = pPcb->hPort; pPcb->pBcb->dwLinkCount++; pPcb->pBcb->dwAcctLinkCount++; for ( dwForIndex = 0; dwForIndex < pPcb->pBcb->dwPpcbArraySize; dwForIndex++ ) { // // If there is a free space in the array of back pointers, use it // if ( pPcb->pBcb->ppPcb[dwForIndex] == NULL ) { PppLog( 2, "Found slot %d for port %d in BCB back pointer array", dwForIndex, pPcb->hPort ); pPcb->pBcb->ppPcb[dwForIndex] = pPcb; break; } } if ( dwForIndex == pPcb->pBcb->dwPpcbArraySize ) { // // The array of back pointers is full. ReAlloc. // ppPcb = (PPCB *) LOCAL_REALLOC( pPcb->pBcb->ppPcb, 2 * pPcb->pBcb->dwPpcbArraySize * sizeof( PPCB * ) ); if (ppPcb == NULL) { // // Can we really assume that pPcb->pBcb->ppPcb will be left // intact? The documentation for HeapReAlloc does not say so. // pPcb->pBcb = pBcbOld; pBcbOld = NULL; pPcbWalker->pBcb->dwLinkCount--; pPcbWalker->pBcb->dwAcctLinkCount--; pPcb->fFlags &= ~PCBFLAG_IS_BUNDLED; PppLog( 1, "Couldn't ReAlloc BCB back pointer array for port %d", pPcb->hPort ); dwRetCode = GetLastError(); goto LDone; } pPcb->pBcb->ppPcb = ppPcb; PppLog( 2, "Found slot %d for port %d in BCB back pointer array after ReAlloc", dwForIndex, pPcb->hPort ); pPcb->pBcb->ppPcb[dwForIndex++] = pPcb; pPcb->pBcb->dwPpcbArraySize *= 2; // // We are assuming that the new memory will be zeroed. // } } LDone: DeallocateAndRemoveBcbFromTable( pBcbOld ); return( dwRetCode ); } //** // // Call: AdjustHTokenImpersonateUser // // Returns: VOID // // Description: Sets hTokenImpersonateUser in pPcb by finding another link that // pPcb is capable of bundling with and stealing its // hTokenImpersonateUser. The original hTokenImpersonateUser may // be INVALID_HANDLE_VALUE if this link came up because BAP called // RasDial. // VOID AdjustHTokenImpersonateUser( IN PCB * pPcb ) { DWORD dwIndex; PCB* pPcbWalker; HANDLE hToken; HANDLE hTokenDuplicate; if ( INVALID_HANDLE_VALUE != pPcb->pBcb->hTokenImpersonateUser ) { return; } for ( dwIndex = 0; dwIndex < PcbTable.NumPcbBuckets; dwIndex++ ) { for( pPcbWalker = PcbTable.PcbBuckets[dwIndex].pPorts; pPcbWalker != NULL; pPcbWalker = pPcbWalker->pNext ) { if ( pPcbWalker->hPort == pPcb->hPort ) { continue; } hToken = pPcbWalker->pBcb->hTokenImpersonateUser; // // If the current port negotiated MRRU ie multilink. // if ( ( pPcbWalker->fFlags & PCBFLAG_CAN_BE_BUNDLED ) && ( CanPortsBeBundled( pPcbWalker, pPcb, FALSE ) ) && ( INVALID_HANDLE_VALUE != hToken ) ) { if (DuplicateHandle( GetCurrentProcess(), hToken, GetCurrentProcess(), &hTokenDuplicate, 0, TRUE, DUPLICATE_SAME_ACCESS)) { pPcb->pBcb->hTokenImpersonateUser = hTokenDuplicate; } return; } } } } //** // // Call: FLinkDiscriminatorIsUnique // // Returns: TRUE - Unique Link Discriminator // FALSE - Non-unique Link Discriminator // // Description: Returns TRUE if the link discriminator of the link in pPcb is // unique with respect to the other links in the same bundle. // Otherwise, it returns FALSE and sets *pdwLinkDisc to a unique // value that can be used as link discrim. // BOOL FLinkDiscriminatorIsUnique( IN PCB * pPcb, OUT DWORD * pdwLinkDisc ) { DWORD dwForIndex; DWORD dwNewDisc; DWORD dwTempDisc; DWORD fDiscIsUnique = TRUE; dwNewDisc = ((LCPCB*) (pPcb->LcpCb.pWorkBuf))->Local.Work.dwLinkDiscriminator; *pdwLinkDisc = 0; // The highest link discriminator seen so far for ( dwForIndex = 0; dwForIndex < pPcb->pBcb->dwPpcbArraySize; dwForIndex++ ) { if ( ( pPcb->pBcb->ppPcb[dwForIndex] != NULL ) && ( pPcb->pBcb->ppPcb[dwForIndex] != pPcb ) ) { dwTempDisc = ((LCPCB *) (pPcb->pBcb->ppPcb[dwForIndex]->LcpCb.pWorkBuf)) ->Local.Work.dwLinkDiscriminator; if ( dwTempDisc > *pdwLinkDisc ) { *pdwLinkDisc = dwTempDisc; } if ( dwTempDisc == dwNewDisc ) { fDiscIsUnique = FALSE; } } } if ( fDiscIsUnique ) { return( TRUE ); } if ( *pdwLinkDisc != 0xFFFF ) { *pdwLinkDisc += 1; return( FALSE ); } // // Find a unique link discriminator // for ( dwTempDisc = 0; // A candidate for unique discriminator dwTempDisc < 0xFFFF; dwTempDisc++ ) { for ( dwForIndex = 0; dwForIndex < pPcb->pBcb->dwPpcbArraySize; dwForIndex++ ) { if ( pPcb->pBcb->ppPcb[dwForIndex] != NULL ) { if ( dwTempDisc == ((LCPCB *) (pPcb->pBcb->ppPcb[dwForIndex]->LcpCb.pWorkBuf)) ->Local.Work.dwLinkDiscriminator ) { break; } } } if ( dwForIndex == pPcb->pBcb->dwPpcbArraySize ) { *pdwLinkDisc = dwTempDisc; break; } } if ( dwTempDisc == 0xFFFF ) { PppLog( 1, "FLinkDiscriminatorIsUnique couldn't find a unique link " "discriminator for port %d", pPcb->hPort ); } return( FALSE ); } //** // // Call: CreateAccountingAttributes // // Returns: VOID // // Description: // VOID CreateAccountingAttributes( IN PCB * pPcb ) { CHAR szAcctSessionId[20]; CHAR szAcctMultiSessionId[20]; DWORD dwIndex = 0; DWORD dwEncryptionType; BYTE abEncryptionType[6]; DWORD dwRetCode; RAS_AUTH_ATTRIBUTE * pAttributes = NULL; RAS_AUTH_ATTRIBUTE * pClassAttribute = NULL; RAS_AUTH_ATTRIBUTE * pFramedRouteAttribute = NULL; RAS_AUTH_ATTRIBUTE * pDomainAttribute = NULL; HANDLE hAttribute; DWORD dwValue; PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pGlobalDomainInfo; LCPCB * pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf); RasAuthAttributeDestroy( pPcb->pAccountingAttributes ); pPcb->pAccountingAttributes = NULL; if ( !( pPcb->fFlags & PCBFLAG_IS_SERVER ) ) { return; } // // Check to see how many class attributes we have to send if any. // if ( pPcb->pAuthProtocolAttributes != NULL ) { pAttributes = pPcb->pAuthProtocolAttributes; } else if ( pPcb->pAuthenticatorAttributes != NULL ) { pAttributes = pPcb->pAuthenticatorAttributes; } pClassAttribute = RasAuthAttributeGetFirst( raatClass, pAttributes, &hAttribute ); while( pClassAttribute != NULL ) { dwIndex++; pClassAttribute = RasAuthAttributeGetNext( &hAttribute, raatClass ); } // // Check to see how many Framed-Route attributes we have to send if any. // pFramedRouteAttribute = RasAuthAttributeGetFirst( raatFramedRoute, pPcb->pAuthenticatorAttributes, &hAttribute ); while( pFramedRouteAttribute != NULL ) { dwIndex++; pFramedRouteAttribute = RasAuthAttributeGetNext( &hAttribute, raatFramedRoute ); } pDomainAttribute = RasAuthAttributeGetVendorSpecific( 311, 10, pAttributes ); ZeroMemory( szAcctSessionId, sizeof( szAcctSessionId ) ); _itoa(PppConfigInfo.GetNextAccountingSessionId(),szAcctSessionId, 10); ZeroMemory( szAcctMultiSessionId, sizeof( szAcctMultiSessionId ) ); _itoa( pPcb->pBcb->dwBundleId, szAcctMultiSessionId, 10 ); // // Allocate max total number of attributes that will be used in the // start and stop accouting messages. // pPcb->pAccountingAttributes = RasAuthAttributeCreate( PPP_NUM_ACCOUNTING_ATTRIBUTES + dwIndex ); if ( pPcb->pAccountingAttributes == NULL ) { return; } do { // // First insert user attributes // for( dwIndex = 0; pPcb->pUserAttributes[dwIndex].raaType != raatMinimum; dwIndex++ ) { dwRetCode = RasAuthAttributeInsert( dwIndex, pPcb->pAccountingAttributes, pPcb->pUserAttributes[dwIndex].raaType, FALSE, pPcb->pUserAttributes[dwIndex].dwLength, pPcb->pUserAttributes[dwIndex].Value ); if ( dwRetCode != NO_ERROR ) { break; } } if ( dwRetCode != NO_ERROR ) { break; } // // Now insert the class attributes if there were any // pClassAttribute = RasAuthAttributeGetFirst( raatClass, pAttributes, &hAttribute ); while( pClassAttribute != NULL ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, pClassAttribute->raaType, FALSE, pClassAttribute->dwLength, pClassAttribute->Value ); if ( dwRetCode != NO_ERROR ) { break; } pClassAttribute = RasAuthAttributeGetNext( &hAttribute, raatClass ); } if ( dwRetCode != NO_ERROR ) { break; } // // Now insert the Framed-Route attributes if there were any // pFramedRouteAttribute = RasAuthAttributeGetFirst( raatFramedRoute, pPcb->pAuthenticatorAttributes, &hAttribute ); while( pFramedRouteAttribute != NULL ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, pFramedRouteAttribute->raaType, FALSE, pFramedRouteAttribute->dwLength, pFramedRouteAttribute->Value ); if ( dwRetCode != NO_ERROR ) { break; } pFramedRouteAttribute = RasAuthAttributeGetNext( &hAttribute, raatFramedRoute ); } if ( dwRetCode != NO_ERROR ) { break; } // // Now insert the domain attribute if there was one // if ( pDomainAttribute != NULL ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, pDomainAttribute->raaType, FALSE, pDomainAttribute->dwLength, pDomainAttribute->Value ); if ( dwRetCode != NO_ERROR ) { break; } } dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatAcctSessionId, FALSE, strlen( szAcctSessionId ), szAcctSessionId ); if ( dwRetCode != NO_ERROR ) { break; } if ( NULL != pPcb->pBcb->szRemoteIdentity ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatUserName, FALSE, strlen( pPcb->pBcb->szRemoteIdentity ), pPcb->pBcb->szRemoteIdentity ); if ( dwRetCode != NO_ERROR ) { break; } } if ( 0 != pPcb->pBcb->nboRemoteAddress ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatFramedIPAddress, FALSE, 4, (LPVOID) LongToPtr(ntohl( pPcb->pBcb->nboRemoteAddress )) ); if ( dwRetCode != NO_ERROR ) { break; } } { ULONG mru = (pLcpCb->Remote.Work.MRU > LCP_DEFAULT_MRU) ? LCP_DEFAULT_MRU : pLcpCb->Remote.Work.MRU; dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatFramedMTU, FALSE, 4, (LPVOID) UlongToPtr(( mru ))); } if ( dwRetCode != NO_ERROR ) { break; } if ( pPcb->pBcb->fFlags & BCBFLAG_IPCP_VJ_NEGOTIATED ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatFramedCompression, FALSE, 4, (LPVOID) 1 ); // VJ TCP/IP header compression if ( dwRetCode != NO_ERROR ) { break; } } if ( pPcb->szCallbackNumber[0] != 0 ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatCallbackNumber, FALSE, strlen(pPcb->szCallbackNumber), (LPVOID)pPcb->szCallbackNumber ); if ( dwRetCode != NO_ERROR ) { break; } } if ( pPcb->dwSessionTimeout > 0 ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatSessionTimeout, FALSE, 4, (LPVOID) ULongToPtr(pPcb->dwSessionTimeout) ); if ( dwRetCode != NO_ERROR ) { break; } } if ( pPcb->dwAutoDisconnectTime > 0 ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatIdleTimeout, FALSE, 4, (LPVOID) ULongToPtr(pPcb->dwAutoDisconnectTime) ); if ( dwRetCode != NO_ERROR ) { break; } } if ( pPcb->pBcb->dwMaxLinksAllowed != 0xFFFFFFFF ) { // // There is a real limit // dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatPortLimit, FALSE, 4, (LPVOID) ULongToPtr(pPcb->pBcb->dwMaxLinksAllowed) ); if ( dwRetCode != NO_ERROR ) { break; } } dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatAcctMultiSessionId, FALSE, strlen(szAcctMultiSessionId), (LPVOID)szAcctMultiSessionId ); if ( dwRetCode != NO_ERROR ) { break; } dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatAcctLinkCount, FALSE, 4, (LPVOID)ULongToPtr(pPcb->pBcb->dwAcctLinkCount) ); if ( dwRetCode != NO_ERROR ) { break; } // // Insert event timestamp attribute // dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatAcctEventTimeStamp, FALSE, 4, (LPVOID)ULongToPtr(GetSecondsSince1970()) ); if ( dwRetCode != NO_ERROR ) { break; } if ( PppConfigInfo.fRadiusAuthenticationUsed ) { dwValue = 1; // RADIUS } else { dwValue = 0; pGlobalDomainInfo = NULL; dwRetCode = DsRoleGetPrimaryDomainInformation( NULL, DsRolePrimaryDomainInfoBasic, (PBYTE *)&pGlobalDomainInfo ); if ( NO_ERROR == dwRetCode ) { if ( ( pGlobalDomainInfo->MachineRole == DsRole_RoleMemberServer ) || ( pGlobalDomainInfo->MachineRole == DsRole_RoleMemberWorkstation ) ) { dwValue = 3; // Remote } else { dwValue = 2; // Local } DsRoleFreeMemory(pGlobalDomainInfo); } else { dwRetCode = NO_ERROR; } } if ( 0 != dwValue ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatAcctAuthentic, FALSE, 4, (LPVOID)ULongToPtr(dwValue) ); if ( dwRetCode != NO_ERROR ) { break; } } // // Insert encryption attribute // dwEncryptionType = 0; if ( pPcb->pBcb->fFlags & BCBFLAG_BASIC_ENCRYPTION ) { dwEncryptionType = 0x00000002; } else if ( pPcb->pBcb->fFlags & BCBFLAG_STRONGER_ENCRYPTION ) { dwEncryptionType = 0x00000008; } else if ( pPcb->pBcb->fFlags & BCBFLAG_STRONGEST_ENCRYPTION ) { dwEncryptionType = 0x00000004; } abEncryptionType[0] = 8; // Vendor-Type = MS_MPPE_EncryptionType abEncryptionType[1] = 6; // Vendor-Length = 6 HostToWireFormat32( dwEncryptionType, abEncryptionType + 2 ); dwRetCode = RasAuthAttributeInsertVSA( dwIndex++, pPcb->pAccountingAttributes, 311, 6, abEncryptionType ); if ( dwRetCode != NO_ERROR ) { break; } } while( FALSE ); // // Do not send accounting start if there was any error // if ( dwRetCode != NO_ERROR ) { RasAuthAttributeDestroy( pPcb->pAccountingAttributes ); pPcb->pAccountingAttributes = NULL; return; } // // NULL terminate // pPcb->pAccountingAttributes[dwIndex].raaType = raatMinimum; pPcb->pAccountingAttributes[dwIndex].dwLength = 0; pPcb->pAccountingAttributes[dwIndex].Value = NULL; } //** // // Call: MakeStartAccountingCall // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: Start backend authentication module accounting // VOID MakeStartAccountingCall( IN PCB * pPcb ) { LCPCB * pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf); RAS_AUTH_ATTRIBUTE * pAcctInterimIntervalAttribute = NULL; RAS_AUTH_ATTRIBUTE * pAttributes = NULL; if ( pPcb->fFlags & PCBFLAG_ACCOUNTING_STARTED ) { // // Already started // return; } pPcb->fFlags |= PCBFLAG_ACCOUNTING_STARTED; if ( pLcpCb->Local.Work.AP == 0 ) { // // If the remote side was not authenticated then do not send an // accounting request as per RADIUS accounting RFC 2139 sec 5.6. // return; } if ( PppConfigInfo.RasAcctProviderStartAccounting != NULL ) { RAS_AUTH_ATTRIBUTE * pAccountingAttributes; CreateAccountingAttributes( pPcb ); pAccountingAttributes = RasAuthAttributeCopy( pPcb->pAccountingAttributes ); if ( NULL == pAccountingAttributes ) { return; } RtlQueueWorkItem( StartAccounting, pAccountingAttributes, WT_EXECUTEDEFAULT ); if ( pPcb->pAuthProtocolAttributes != NULL ) { pAttributes = pPcb->pAuthProtocolAttributes; } else if ( pPcb->pAuthenticatorAttributes != NULL ) { pAttributes = pPcb->pAuthenticatorAttributes; } // // See if we have to do interim accounting // pAcctInterimIntervalAttribute = RasAuthAttributeGet( raatAcctInterimInterval, pAttributes ); if ( pAcctInterimIntervalAttribute != NULL ) { DWORD dwInterimInterval = PtrToUlong(pAcctInterimIntervalAttribute->Value); if ( dwInterimInterval < 60 ) { dwInterimInterval = 60; } InsertInTimerQ( pPcb->dwPortId, pPcb->hPort, 0, 0, FALSE, TIMER_EVENT_INTERIM_ACCOUNTING, dwInterimInterval ); } } return; } //** // // Call: InitializeNCPs // // Returns: NO_ERROR // Non-zero return code. // // Description: Will run through and initialize all the NCPs that are enabled // to run. // DWORD InitializeNCPs( IN PCB * pPcb, IN DWORD dwConfigMask ) { DWORD dwIndex; BOOL fInitSuccess = FALSE; DWORD dwRetCode = NO_ERROR; if ( pPcb->fFlags & PCBFLAG_NCPS_INITIALIZED ) { return( NO_ERROR ); } pPcb->fFlags |= PCBFLAG_NCPS_INITIALIZED; // // Initialize all the CPs for this port // for( dwIndex=LCP_INDEX+1; dwIndex < PppConfigInfo.NumberOfCPs; dwIndex++ ) { CPCB * pCpCb = GetPointerToCPCB( pPcb, dwIndex ); pCpCb->fConfigurable = FALSE; if ( !( CpTable[dwIndex].fFlags & PPPCP_FLAG_AVAILABLE ) ) { PppLog( 2, "Will not initialize CP %x", CpTable[dwIndex].CpInfo.Protocol ); continue; } switch( CpTable[dwIndex].CpInfo.Protocol ) { case PPP_IPCP_PROTOCOL: if ( dwConfigMask & PPPCFG_ProjectIp ) { // // Make sure we have a valid interface handle if we are not // a client dialing out // if ( pPcb->pBcb->InterfaceInfo.IfType != (DWORD)-1 ) { if (pPcb->pBcb->InterfaceInfo.hIPInterface == INVALID_HANDLE_VALUE ) { break; } } pCpCb->fConfigurable = TRUE; if ( FsmInit( pPcb, dwIndex ) ) { fInitSuccess = TRUE; } } break; case PPP_ATCP_PROTOCOL: if ( dwConfigMask & PPPCFG_ProjectAt ) { pCpCb->fConfigurable = TRUE; if ( FsmInit( pPcb, dwIndex ) ) { fInitSuccess = TRUE; } } break; case PPP_IPXCP_PROTOCOL: if ( dwConfigMask & PPPCFG_ProjectIpx ) { // // Make sure we have a valid interface handle if we are not // a client dialing out // if ( pPcb->pBcb->InterfaceInfo.IfType != (DWORD)-1 ) { if ( pPcb->pBcb->InterfaceInfo.hIPXInterface == INVALID_HANDLE_VALUE ) { break; } } pCpCb->fConfigurable = TRUE; if ( FsmInit( pPcb, dwIndex ) ) { fInitSuccess = TRUE; } } break; case PPP_NBFCP_PROTOCOL: if ( dwConfigMask & PPPCFG_ProjectNbf ) { // // If we are not a client dialing in or out do not enable // NBF // if ( ( pPcb->pBcb->InterfaceInfo.IfType != (DWORD)-1 ) && ( pPcb->pBcb->InterfaceInfo.IfType != ROUTER_IF_TYPE_CLIENT )) { break; } pCpCb->fConfigurable = TRUE; if ( FsmInit( pPcb, dwIndex ) ) { fInitSuccess = TRUE; } } break; case PPP_CCP_PROTOCOL: pCpCb->fConfigurable = TRUE; if ( !( FsmInit( pPcb, dwIndex ) ) ) { // // If encryption failed to initialize and we are forcing // encryption, then bring down the link // if ( dwConfigMask & ( PPPCFG_RequireEncryption | PPPCFG_RequireStrongEncryption ) ) { // // We need to send an Accounting Stop if RADIUS sends // an Access Accept but we still drop the line. // pPcb->fFlags |= PCBFLAG_SERVICE_UNAVAILABLE; dwRetCode = ERROR_NO_LOCAL_ENCRYPTION; } } break; case PPP_BACP_PROTOCOL: if ( ( dwConfigMask & PPPCFG_NegotiateBacp ) && ( pPcb->pBcb->fFlags & BCBFLAG_CAN_DO_BAP ) ) { pCpCb->fConfigurable = TRUE; if ( !( FsmInit( pPcb, dwIndex ) ) ) { pPcb->pBcb->fFlags &= ~BCBFLAG_CAN_DO_BAP; } } break; default: break; } if ( dwRetCode != NO_ERROR ) { break; } } // // If we failed to initialize one of the CPs, or CCP failed to // initialize and we require encryption, then we fail. // if ( ( !fInitSuccess ) || ( dwRetCode != NO_ERROR ) ) { if ( dwRetCode == NO_ERROR ) { dwRetCode = ERROR_PPP_NO_PROTOCOLS_CONFIGURED; } for(dwIndex=LCP_INDEX+1;dwIndex < PppConfigInfo.NumberOfCPs;dwIndex++) { CPCB * pCpCb = GetPointerToCPCB( pPcb, dwIndex ); if ( pCpCb->fBeginCalled == TRUE ) { if ( pCpCb->pWorkBuf != NULL ) { (CpTable[dwIndex].CpInfo.RasCpEnd)( pCpCb->pWorkBuf ); pCpCb->pWorkBuf = NULL; } pCpCb->fBeginCalled = FALSE; pCpCb->fConfigurable = FALSE; } } } return( dwRetCode ); } //** // // Call: GetPointerToCPCB // // Returns: Pointer to Control Protocol Control Block // // Description: Returns the appropriate pointer for a give CP, will return the // (first) local side for the AP. // CPCB * GetPointerToCPCB( IN PCB * pPcb, IN DWORD CpIndex ) { // // If the C.P. is LCP or authentication, then return the pointer to the // Pcb's CPCB // if ( CpIndex == (DWORD)-1 ) { return( NULL ); } else if ( CpIndex == LCP_INDEX ) { return( &(pPcb->LcpCb) ); } else if ( CpIndex >= PppConfigInfo.NumberOfCPs ) { if ( CpTable[CpIndex].CpInfo.Protocol == PPP_CBCP_PROTOCOL ) { return( &(pPcb->CallbackCb) ); } if (CpTable[CpIndex].CpInfo.Protocol == pPcb->AuthenticatorCb.Protocol) { return( &(pPcb->AuthenticatorCb) ); } if (CpTable[CpIndex].CpInfo.Protocol == pPcb->AuthenticateeCb.Protocol) { return( &(pPcb->AuthenticateeCb) ); } } else { // // Otherwise for NCPs return the pointer to the Pcb's CPCB in its BCB. // return( &(pPcb->pBcb->CpCb[CpIndex-1]) ); } return( NULL ); } //** // // Call: GetNewPortOrBundleId // // Returns: New Id // // Description: Simply returns a new Id for a new port or bundle. // DWORD GetNewPortOrBundleId( VOID ) { return( PppConfigInfo.PortUIDGenerator++ ); } //** // // Call: QueryBundleNCPSate // // Returns: NCP_DEAD // NCP_CONFIGURING // NCP_UP // NCP_DOWN // // Description: Will check to see if the NCPs for a certain bundle have // completed their negotiation, either successfully or not. // If unsuccessfuly, then the retcode is // ERROR_PPP_NO_PROTOCOLS_CONFIGURED // NCP_PHASE QueryBundleNCPState( IN PCB * pPcb ) { DWORD dwIndex; CPCB * pCpCb; BOOL fOneNcpConfigured = FALSE; BOOL fAllNcpsDead = TRUE; for (dwIndex = LCP_INDEX+1; dwIndex < PppConfigInfo.NumberOfCPs; dwIndex++) { pCpCb = GetPointerToCPCB( pPcb, dwIndex ); if ( pCpCb->fConfigurable ) { if ( pCpCb->NcpPhase == NCP_CONFIGURING ) { return( NCP_CONFIGURING ); } if ( pCpCb->NcpPhase == NCP_UP ) { fOneNcpConfigured = TRUE; } if ( pCpCb->NcpPhase != NCP_DEAD ) { fAllNcpsDead = FALSE; } } } if ( fOneNcpConfigured ) { return( NCP_UP ); } if ( fAllNcpsDead ) { return( NCP_DEAD ); } return( NCP_DOWN ); } //** // // Call: NotifyCallerOfBundledProjection // // Returns: None // // Description: Will notify the caller (i.e. supervisor or rasphone) about // this link being bundled. // // VOID NotifyCallerOfBundledProjection( IN PCB * pPcb ) { DWORD dwRetCode; PPP_PROJECTION_RESULT ProjectionResult; BOOL fNCPsAreDone = FALSE; ZeroMemory( &ProjectionResult, sizeof( ProjectionResult ) ); // // Notify the ras client and the ras server about the // projections // dwRetCode = GetConfiguredInfo( pPcb, 0, // don't care &ProjectionResult, &fNCPsAreDone ); if ( dwRetCode != NO_ERROR ) { return; } if ( !fNCPsAreDone ) { return; } // // Now get LCP information // ProjectionResult.lcp.hportBundleMember = pPcb->hportBundleMember; ProjectionResult.lcp.szReplyMessage = pPcb->pBcb->szReplyMessage; dwRetCode = (CpTable[LCP_INDEX].CpInfo.RasCpGetNegotiatedInfo)( pPcb->LcpCb.pWorkBuf, &(ProjectionResult.lcp)); if ( RAS_DEVICE_TYPE( pPcb->dwDeviceType ) == RDT_Tunnel_L2tp ) { if ( pPcb->pBcb->fFlags & BCBFLAG_BASIC_ENCRYPTION ) { ProjectionResult.lcp.dwLocalOptions |= PPPLCPO_DES_56; ProjectionResult.lcp.dwRemoteOptions |= PPPLCPO_DES_56; } else if ( pPcb->pBcb->fFlags & BCBFLAG_STRONGEST_ENCRYPTION ) { ProjectionResult.lcp.dwLocalOptions |= PPPLCPO_3_DES; ProjectionResult.lcp.dwRemoteOptions |= PPPLCPO_3_DES; } } ProjectionResult.lcp.dwLocalEapTypeId = pPcb->dwServerEapTypeId; ProjectionResult.lcp.dwRemoteEapTypeId = pPcb->dwClientEapTypeId; if ( dwRetCode != NO_ERROR ) { return; } if ( pPcb->fFlags & PCBFLAG_IS_SERVER ) { NotifyCaller( pPcb, PPPDDMMSG_PppDone, &ProjectionResult ); } else { NotifyCaller( pPcb, PPPMSG_ProjectionResult, &ProjectionResult); NotifyCaller( pPcb, PPPMSG_PppDone, NULL ); } } //** // // Call: StartNegotiatingNCPs // // Returns: None // // Description: Will start NCP negogiating for the particular port or bundle // VOID StartNegotiatingNCPs( IN PCB * pPcb ) { DWORD dwIndex; pPcb->PppPhase = PPP_NCP; for (dwIndex = LCP_INDEX+1; dwIndex < PppConfigInfo.NumberOfCPs; dwIndex++) { CPCB * pCpCb = GetPointerToCPCB( pPcb, dwIndex ); if ( pCpCb->fConfigurable ) { pCpCb->NcpPhase = NCP_CONFIGURING; FsmOpen( pPcb, dwIndex ); FsmUp( pPcb, dwIndex ); } } } //** // // Call: StartAutoDisconnectForPort // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: Will insert an auto disconnect and sesison timeout item in the // timer Q // VOID StartAutoDisconnectForPort( IN PCB * pPcb ) { // // Do session timeout if there is any // if ( pPcb->fFlags & PCBFLAG_IS_SERVER ) { RAS_AUTH_ATTRIBUTE * pAttribute; RAS_AUTH_ATTRIBUTE * pUserAttributes = ( pPcb->pAuthProtocolAttributes ) ? pPcb->pAuthProtocolAttributes : pPcb->pAuthenticatorAttributes; pAttribute = RasAuthAttributeGet( raatSessionTimeout, pUserAttributes); if ( pAttribute != NULL ) { pPcb->dwSessionTimeout = PtrToUlong(pAttribute->Value); } else { pPcb->dwSessionTimeout = PppConfigInfo.dwDefaultSessionTimeout; } PppLog( 2, "AuthAttribute SessionTimeout = %d", pPcb->dwSessionTimeout); if ( pPcb->dwSessionTimeout > 0 ) { // // Remove any previous session-disconnect time item from the // queue if there was one. // RemoveFromTimerQ( pPcb->dwPortId, 0, 0, FALSE, TIMER_EVENT_SESSION_TIMEOUT ); InsertInTimerQ( pPcb->dwPortId, pPcb->hPort, 0, 0, FALSE, TIMER_EVENT_SESSION_TIMEOUT, pPcb->dwSessionTimeout ); } } // // Do not start autodisconnect for router interfaces that have // dialed in, the router dialing in will take care of this. // if ( ( pPcb->fFlags & PCBFLAG_IS_SERVER ) && ( pPcb->pBcb->InterfaceInfo.IfType == ROUTER_IF_TYPE_FULL_ROUTER ) ) { return; } // // If the AutoDisconnectTime is not infinte, put a timer // element on the queue that will wake up in AutoDisconnectTime. // if ( pPcb->dwAutoDisconnectTime > 0 ) { PppLog( 2, "Inserting autodisconnect in timer q for port=%d, sec=%d", pPcb->hPort, pPcb->dwAutoDisconnectTime ); // // Remove any previous auto-disconnect time item from the // queue if there was one. // RemoveFromTimerQ( pPcb->dwPortId, 0, 0, FALSE, TIMER_EVENT_AUTODISCONNECT); InsertInTimerQ( pPcb->dwPortId, pPcb->hPort, 0, 0, FALSE, TIMER_EVENT_AUTODISCONNECT, pPcb->dwAutoDisconnectTime ); } } //** // // Call: StartLCPEchoForPort // // Returns: None // // // Description: Will insert an LCPEcho item in the timer Q // VOID StartLCPEchoForPort( IN PCB * pPcb ) { if ( !(pPcb->fFlags & PCBFLAG_IS_SERVER) ) { //if this is a client. //check to see if the connection type is broadband - PPPOE in particular if ( (RAS_DEVICE_TYPE(pPcb->dwDeviceType) == RDT_PPPoE) && pPcb->dwIdleBeforeEcho ) { PppLog( 2, "LCPEchoTimeout = %d", pPcb->dwIdleBeforeEcho); pPcb->fEchoRequestSend = 0; pPcb->dwNumEchoResponseMissed = 0; //No responses missed yet InsertInTimerQ( pPcb->dwPortId, pPcb->hPort, 0, 0, FALSE, TIMER_EVENT_LCP_ECHO, pPcb->dwIdleBeforeEcho ); } } return; } //** // // Call: NotifyCompletionOnBundledPorts // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: Will notify all ports that are bundled with this port and // are waiting to for negotiation to complete on the bundle. // VOID NotifyCompletionOnBundledPorts( IN PCB * pPcb ) { DWORD dwIndex; PCB * pPcbWalker; // // Walk thru the list of PCBs // for ( dwIndex = 0; dwIndex < PcbTable.NumPcbBuckets; dwIndex++ ) { for( pPcbWalker = PcbTable.PcbBuckets[dwIndex].pPorts; pPcbWalker != NULL; pPcbWalker = pPcbWalker->pNext ) { if ( ( pPcbWalker->hPort != pPcb->hPort ) && ( pPcbWalker->fFlags & PCBFLAG_IS_BUNDLED ) && ( CanPortsBeBundled( pPcbWalker, pPcb, TRUE ) ) ) { // // In our bundle so notify the caller of completion on this // port. // RemoveFromTimerQ( pPcbWalker->dwPortId, 0, 0, FALSE, TIMER_EVENT_NEGOTIATETIME ); NotifyCallerOfBundledProjection( pPcbWalker ); StartAutoDisconnectForPort( pPcbWalker ); } } } } //** // // Call: RemoveNonNumerals // // Returns: VOID // // Description: Removes any character that is not an ASCII digit from // the string szString // VOID RemoveNonNumerals( IN CHAR* szString ) { CHAR c; DWORD dwIndexOld; DWORD dwIndexNew; if (NULL == szString) { return; } for (dwIndexOld = 0, dwIndexNew = 0; (c = szString[dwIndexOld]) != 0; dwIndexOld++) { if (isdigit(c)) { szString[dwIndexNew++] = c; } } szString[dwIndexNew] = 0; } //** // // Call: GetTextualSid // // Returns: TRUE - Success // FALSE - Failure // // Description: The GetTextualSid function will convert a binary Sid to a // textual string. Obtained from the Knowledge Base. // Article ID: Q131320 // BOOL GetTextualSid( IN PSID pSid, // binary Sid OUT CHAR* TextualSid, // buffer for Textual representaion of Sid IN LPDWORD dwBufferLen // required/provided TextualSid buffersize ) { PSID_IDENTIFIER_AUTHORITY psia; DWORD dwSubAuthorities; DWORD dwSidRev=SID_REVISION; DWORD dwCounter; DWORD dwSidSize; // // test if Sid passed in is valid // if(!IsValidSid(pSid)) return FALSE; // // obtain SidIdentifierAuthority // psia=GetSidIdentifierAuthority(pSid); // // obtain sidsubauthority count // dwSubAuthorities=*GetSidSubAuthorityCount(pSid); // // compute buffer length // S-SID_REVISION- + identifierauthority- + subauthorities- + NULL // dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR); // // check provided buffer length. // If not large enough, indicate proper size and setlasterror // if (*dwBufferLen < dwSidSize) { *dwBufferLen = dwSidSize; SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } // // prepare S-SID_REVISION- // dwSidSize=wsprintfA(TextualSid, "S-%lu-", dwSidRev ); // // prepare SidIdentifierAuthority // if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) ) { dwSidSize+=wsprintfA(TextualSid + lstrlenA(TextualSid), "0x%02hx%02hx%02hx%02hx%02hx%02hx", (USHORT)psia->Value[0], (USHORT)psia->Value[1], (USHORT)psia->Value[2], (USHORT)psia->Value[3], (USHORT)psia->Value[4], (USHORT)psia->Value[5]); } else { dwSidSize+=wsprintfA(TextualSid + lstrlenA(TextualSid), "%lu", (ULONG)(psia->Value[5] ) + (ULONG)(psia->Value[4] << 8) + (ULONG)(psia->Value[3] << 16) + (ULONG)(psia->Value[2] << 24) ); } // // loop through SidSubAuthorities // for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++) { dwSidSize+=wsprintfA(TextualSid + dwSidSize, "-%lu", *GetSidSubAuthority(pSid, dwCounter) ); } return TRUE; } //** // // Call: TextualSidFromPid // // Returns: NULL - Failure // non-NULL - Success // // Description: Will LOCAL_ALLOC a Textual Sid for a user whose pid is dwPid. // CHAR* TextualSidFromPid( DWORD dwPid ) { #define BUF_SIZE 256 BOOL fFreeTextualSid = FALSE; CHAR* szTextualSid = NULL; HANDLE ProcessHandle = NULL; HANDLE TokenHandle = INVALID_HANDLE_VALUE; TOKEN_USER ptgUser[BUF_SIZE]; DWORD cbBuffer; DWORD cbSid; szTextualSid = LOCAL_ALLOC( LPTR, sizeof( CHAR ) * BUF_SIZE ); if ( NULL == szTextualSid ) { BapTrace( "LOCAL_ALLOC() returned error %d", GetLastError() ); goto LDone; } fFreeTextualSid = TRUE; ProcessHandle = OpenProcess( PROCESS_ALL_ACCESS, FALSE /* bInheritHandle */, dwPid ); if ( NULL == ProcessHandle ) { BapTrace( "OpenProcess() returned error %d", GetLastError() ); goto LDone; } if ( !OpenProcessToken( ProcessHandle, TOKEN_QUERY, &TokenHandle ) ) { BapTrace( "OpenProcessToken() returned error %d", GetLastError() ); goto LDone; } cbBuffer = BUF_SIZE; if ( !GetTokenInformation( TokenHandle, TokenUser, ptgUser, cbBuffer, &cbBuffer ) ) // Look at KB article Q131320 { BapTrace( "GetTokenInformation() returned error %d", GetLastError() ); goto LDone; } cbSid = BUF_SIZE; if ( !GetTextualSid( ptgUser->User.Sid, szTextualSid, &cbSid ) ) { BapTrace( "GetTextualSid() returned error %d", GetLastError() ); goto LDone; } fFreeTextualSid = FALSE; LDone: if ( NULL != ProcessHandle ) { CloseHandle( ProcessHandle ); } if ( INVALID_HANDLE_VALUE != TokenHandle ) { CloseHandle( TokenHandle ); } if ( fFreeTextualSid ) { LOCAL_FREE( szTextualSid ); szTextualSid = NULL; } return( szTextualSid ); } //** // // Call: GetRouterPhoneBook // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: Will LocalAlloc and set pszPhonebookPath to point to the // full path of the router phonebook. // DWORD GetRouterPhoneBook( CHAR** pszPhonebookPath ) { DWORD dwSize; DWORD cchDir = GetWindowsDirectoryA( NULL, 0 ); CHAR* szPhonebookPath; *pszPhonebookPath = NULL; if ( cchDir == 0 ) { return( GetLastError() ); } dwSize=(cchDir+lstrlenA("\\system32\\ras\\router.pbk")+1)*sizeof(CHAR); if ( ( szPhonebookPath = LocalAlloc( LPTR, dwSize ) ) == NULL ) { return( GetLastError() ); } if ( GetWindowsDirectoryA( szPhonebookPath, cchDir ) == 0 ) { LocalFree( szPhonebookPath ); return( GetLastError() ); } if ( szPhonebookPath[cchDir-1] != '\\' ) { lstrcatA( szPhonebookPath, "\\" ); } lstrcatA( szPhonebookPath, "system32\\ras\\router.pbk" ); *pszPhonebookPath = szPhonebookPath; return( NO_ERROR ); } //** // // Call: GetCredentialsFromInterface // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: Get the credentials for the interface called // pPcb->pBcb->szRemoteUserName. // DWORD GetCredentialsFromInterface( PCB * pPcb ) { WCHAR wchUserName[UNLEN+1]; WCHAR wchPassword[PWLEN+1]; WCHAR wchDomainName[DNLEN+1]; WCHAR wchInterfaceName[UNLEN+1]; DWORD dwRetCode; wchUserName[0] = wchPassword[0] = wchDomainName[0] = wchInterfaceName[0] = 0; if ( 0 == MultiByteToWideChar( CP_ACP, 0, pPcb->pBcb->szRemoteUserName, -1, wchInterfaceName, sizeof( wchInterfaceName ) / sizeof( WCHAR ) ) ) { dwRetCode = GetLastError(); return( dwRetCode ); } dwRetCode = MprAdminInterfaceGetCredentialsInternal( NULL, wchInterfaceName, wchUserName, wchPassword, wchDomainName ); if ( NO_ERROR == dwRetCode ) { if ( 0 == WideCharToMultiByte( CP_ACP, 0, wchUserName, -1, pPcb->pBcb->szLocalUserName, sizeof( pPcb->pBcb->szLocalUserName ), NULL, NULL ) ) { dwRetCode = GetLastError(); return( dwRetCode ); } if ( 0 == WideCharToMultiByte( CP_ACP, 0, wchPassword, -1, pPcb->pBcb->szPassword, sizeof( pPcb->pBcb->szPassword ), NULL, NULL ) ) { dwRetCode = GetLastError(); return( dwRetCode ); } if ( 0 == WideCharToMultiByte( CP_ACP, 0, wchDomainName, -1, pPcb->pBcb->szLocalDomain, sizeof( pPcb->pBcb->szLocalDomain ), NULL, NULL ) ) { dwRetCode = GetLastError(); return( dwRetCode ); } // // Null out password buffer // ZeroMemory( wchPassword, sizeof( wchPassword ) ); EncodePw( pPcb->pBcb->chSeed, pPcb->pBcb->szPassword ); EncodePw( pPcb->pBcb->chSeed, pPcb->pBcb->szOldPassword ); } return( dwRetCode ); } //** // // Call: IsCpIndexOfAp // // Returns: TRUE - The CpIndex belongs to an Authentication Protocol // FALSE - Otherwise // // Description: // BOOL IsCpIndexOfAp( IN DWORD CpIndex ) { if ( CpIndex >= PppConfigInfo.NumberOfCPs ) { return( TRUE ); } return( FALSE ); } //** // // Call: StartAccounting // // Returns: None // // Description: Will start accounting if the back-end authentication provider // supports it. // VOID StartAccounting( PVOID pContext ) { DWORD dwRetCode; RAS_AUTH_ATTRIBUTE * pInAttributes = (RAS_AUTH_ATTRIBUTE*)pContext; RAS_AUTH_ATTRIBUTE * pOutAttributes = NULL; dwRetCode = (*PppConfigInfo.RasAcctProviderStartAccounting)( pInAttributes, &pOutAttributes ); if ( pOutAttributes != NULL ) { PppConfigInfo.RasAuthProviderFreeAttributes( pOutAttributes ); } RasAuthAttributeDestroy( pInAttributes ); } //** // // Call: InterimAccounting // // Returns: None // // Description: Will send and interim accounting packet if the back-end // authentication provider supports it. // VOID InterimAccounting( PVOID pContext ) { DWORD dwRetCode; RAS_AUTH_ATTRIBUTE * pInAttributes = (RAS_AUTH_ATTRIBUTE*)pContext; RAS_AUTH_ATTRIBUTE * pOutAttributes = NULL; dwRetCode = (*PppConfigInfo.RasAcctProviderInterimAccounting)( pInAttributes, &pOutAttributes ); if ( pOutAttributes != NULL ) { PppConfigInfo.RasAuthProviderFreeAttributes( pOutAttributes ); } RasAuthAttributeDestroy( pInAttributes ); } //** // // Call: StopAccounting // // Returns: None // // Description: Will stop accounting if the back-end authentication provider // supports it. // VOID StopAccounting( PVOID pContext ) { DWORD dwRetCode; PSTOP_ACCOUNTING_CONTEXT pAcctContext = (PSTOP_ACCOUNTING_CONTEXT)pContext; RAS_AUTH_ATTRIBUTE * pInAttributes = pAcctContext->pAuthAttributes; RAS_AUTH_ATTRIBUTE * pOutAttributes = NULL; PPPE_MESSAGE PppMessage; // // It is possible that StopAccounting will be queued on a worker thread // soon after a StartAccounting (Win2000 bug 376334). We don't want the // StopAccounting to finish before the StartAccounting. Hence the sleep. // The real fix is to make sure that the same thread calls both // StartAccounting and StopAccounting. // PppLog ( 2, "Stopping Accounting for port %d", pAcctContext->pPcb->hPort ); Sleep( 2000 ); dwRetCode = (*PppConfigInfo.RasAcctProviderStopAccounting)( pInAttributes, &pOutAttributes ); if ( pOutAttributes != NULL ) { PppConfigInfo.RasAuthProviderFreeAttributes( pOutAttributes ); } RasAuthAttributeDestroy( pInAttributes ); ZeroMemory ( &PppMessage, sizeof(PppMessage)); PppMessage.hPort = pAcctContext->pPcb->hPort; PppMessage.dwMsgId = PPPEMSG_PostLineDown; PppMessage.ExtraInfo.PostLineDown.pPcb = (VOID *)pAcctContext->pPcb; //Call PostLineDown SendPPPMessageToEngine( &PppMessage ); LocalFree(pAcctContext); } //** // // Call: StripCRLF // // Returns: Strips out CR and LF characters from the string // // Description: // VOID StripCRLF( CHAR* psz ) { DWORD dw1; DWORD dw2; CHAR ch; if ( NULL == psz ) { return; } dw1 = 0; dw2 = 0; while ( ( ch = psz[dw1++] ) != 0 ) { if ( ( ch == 0xD ) || ( ch == 0xA ) ) { // // Don't copy this character // continue; } psz[dw2++] = ch; } psz[dw2] = 0; } //** // // Call: GetUserAttributes // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: // RAS_AUTH_ATTRIBUTE * GetUserAttributes( PCB * pPcb ) { RAS_AUTH_ATTRIBUTE * pAttributes = NULL; DWORD dwRetCode = NO_ERROR; DWORD dwIndex = 0; RAS_CONNECT_INFO * pConnectInfo = NULL; DWORD dwSize = 0; DWORD dwNASPortType = (DWORD)-1; DWORD dwValue; BOOL fTunnel = FALSE; if ( pPcb->pUserAttributes != NULL ) { return( NULL ); } pAttributes = RasAuthAttributeCreate( PPP_NUM_USER_ATTRIBUTES ); if ( pAttributes == NULL ) { return( NULL ); } do { if ( PppConfigInfo.szNASIdentifier[0] != 0 ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pAttributes, raatNASIdentifier, FALSE, strlen( PppConfigInfo.szNASIdentifier ), (LPVOID)PppConfigInfo.szNASIdentifier ); if ( dwRetCode != NO_ERROR ) { break; } } if ( PppConfigInfo.dwNASIpAddress != 0 ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pAttributes, raatNASIPAddress, FALSE, 4, (LPVOID)ULongToPtr(PppConfigInfo.dwNASIpAddress) ); } if ( dwRetCode != NO_ERROR ) { break; } dwRetCode = RasAuthAttributeInsert( dwIndex++, pAttributes, raatServiceType, FALSE, 4, UlongToPtr ( ( pPcb->fFlags & PCBFLAG_THIS_IS_A_CALLBACK ) ? 4 : // Callback Framed 2 ) ); // Framed if ( dwRetCode != NO_ERROR ) { break; } dwRetCode = RasAuthAttributeInsert( dwIndex++, pAttributes, raatFramedProtocol, FALSE, 4, (LPVOID)1 ); //PPP if ( dwRetCode != NO_ERROR ) { break; } dwRetCode = RasAuthAttributeInsert( dwIndex++, pAttributes, raatNASPort, FALSE, 4, (LPVOID)pPcb->hPort ); if ( dwRetCode != NO_ERROR ) { break; } { BYTE MSRASVendor[10]; BYTE MSRASVersion[30]; BYTE bLength; HostToWireFormat32( 311, MSRASVendor ); // Vendor-Id MSRASVendor[4] = 9; // Vendor-Type: MS-RAS-Vendor MSRASVendor[5] = 6; // Vendor-Length HostToWireFormat32( 311, MSRASVendor + 6) ; // Vendor-Id dwRetCode = RasAuthAttributeInsert( dwIndex++, pAttributes, raatVendorSpecific, FALSE, 10, &MSRASVendor ); if ( dwRetCode != NO_ERROR ) { break; } bLength = (BYTE)strlen( MS_RAS_VERSION ); RTASSERT( 30 >= 6 + bLength ); HostToWireFormat32( 311, MSRASVersion ); // Vendor-Id MSRASVersion[4] = 18; // Vendor-Type: MS-RAS-Version MSRASVersion[5] = 2 + bLength; // Vendor-Length CopyMemory( MSRASVersion + 6, MS_RAS_VERSION, bLength ); dwRetCode = RasAuthAttributeInsert( dwIndex++, pAttributes, raatVendorSpecific, FALSE, 6 + bLength, &MSRASVersion ); if ( dwRetCode != NO_ERROR ) { break; } } switch( RAS_DEVICE_TYPE( pPcb->dwDeviceType ) ) { case RDT_Modem: case RDT_Serial: dwNASPortType = 0; break; case RDT_Isdn: dwNASPortType = 2; break; case RDT_Tunnel_Pptp: case RDT_Tunnel_L2tp: dwNASPortType = 5; fTunnel = TRUE; break; default: dwNASPortType = (DWORD)-1; break; } if ( dwNASPortType != (DWORD)-1 ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pAttributes, raatNASPortType, FALSE, 4, (LPVOID)ULongToPtr(dwNASPortType) ); if ( dwRetCode != NO_ERROR ) { break; } } if ( fTunnel ) { dwValue = 0; ((BYTE*)(&dwValue))[0] = ( RAS_DEVICE_TYPE( pPcb->dwDeviceType ) == RDT_Tunnel_Pptp ) ? 1 : 3; dwRetCode = RasAuthAttributeInsert( dwIndex++, pAttributes, raatTunnelType, FALSE, 4, (LPVOID)ULongToPtr(dwValue) ); if ( dwRetCode != NO_ERROR ) { break; } dwRetCode = RasAuthAttributeInsert( dwIndex++, pAttributes, raatTunnelMediumType, FALSE, 4, (LPVOID)1 ); // IP if ( dwRetCode != NO_ERROR ) { break; } } if ( ( pPcb->fFlags & PCBFLAG_IS_SERVER ) && ( pPcb->fFlags & PCBFLAG_THIS_IS_A_CALLBACK ) ) { // // send the calling-station-id attrib with the number dialed // dwRetCode = RasAuthAttributeInsert( dwIndex++, pAttributes, raatCallingStationId, FALSE, strlen( pPcb->szCallbackNumber ), (VOID*) pPcb->szCallbackNumber ); if ( dwRetCode != NO_ERROR ) { break; } } if ( RasGetConnectInfo( pPcb->hPort, &dwSize, NULL ) == ERROR_BUFFER_TOO_SMALL ) { if ( ( pConnectInfo = LOCAL_ALLOC( LPTR, dwSize ) ) != NULL ) { if ( RasGetConnectInfo( pPcb->hPort, &dwSize, pConnectInfo ) == NO_ERROR ) { if ( ( pConnectInfo->dwCalledIdSize > 0 ) && ( pConnectInfo->pszCalledId[0] != 0 ) ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pAttributes, raatCalledStationId, FALSE, strlen(pConnectInfo->pszCalledId), (LPVOID)pConnectInfo->pszCalledId ); if ( dwRetCode != NO_ERROR ) { break; } if ( fTunnel ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pAttributes, raatTunnelServerEndpoint, FALSE, strlen(pConnectInfo->pszCalledId), (LPVOID)pConnectInfo->pszCalledId ); if ( dwRetCode != NO_ERROR ) { break; } } } else if ( ( pConnectInfo->dwAltCalledIdSize > 0 ) && ( pConnectInfo->pszAltCalledId[0] != 0 ) ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pAttributes, raatCalledStationId, FALSE, strlen(pConnectInfo->pszAltCalledId), (LPVOID)pConnectInfo->pszAltCalledId ); if ( dwRetCode != NO_ERROR ) { break; } if ( fTunnel ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pAttributes, raatTunnelServerEndpoint, FALSE, strlen(pConnectInfo->pszAltCalledId), (LPVOID)pConnectInfo->pszAltCalledId ); if ( dwRetCode != NO_ERROR ) { break; } } } if ( ( pConnectInfo->dwCallerIdSize > 0 ) && ( pConnectInfo->pszCallerId[0] != 0 ) ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pAttributes, raatCallingStationId, FALSE, strlen(pConnectInfo->pszCallerId), (LPVOID)pConnectInfo->pszCallerId ); if ( dwRetCode != NO_ERROR ) { break; } if ( fTunnel ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pAttributes, raatTunnelClientEndpoint, FALSE, strlen(pConnectInfo->pszCallerId), (LPVOID)pConnectInfo->pszCallerId ); if ( dwRetCode != NO_ERROR ) { break; } } } StripCRLF( pConnectInfo->pszConnectResponse ); if ( pConnectInfo->dwConnectResponseSize > 0 ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pAttributes, raatConnectInfo, FALSE, strlen( pConnectInfo->pszConnectResponse), (LPVOID)pConnectInfo->pszConnectResponse); if ( dwRetCode != NO_ERROR ) { break; } } } } } pAttributes[dwIndex].raaType = raatMinimum; pAttributes[dwIndex].dwLength = 0; pAttributes[dwIndex].Value = NULL; } while( FALSE ); if ( pConnectInfo != NULL ) { LOCAL_FREE( pConnectInfo ); } if ( dwRetCode != NO_ERROR ) { RasAuthAttributeDestroy( pAttributes ); return( NULL ); } return( pAttributes ); } //** // // Call: MakeStopOrInterimAccountingCall // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: // VOID MakeStopOrInterimAccountingCall( IN PCB * pPcb, IN BOOL fInterimAccounting ) { ULARGE_INTEGER qwCurrentTime; ULARGE_INTEGER qwUpTime; DWORD dwRemainder; DWORD dwActiveTimeInSeconds; DWORD dwRetCode; BYTE buffer[sizeof(RAS_STATISTICS) + (MAX_STATISTICS * sizeof (ULONG))]; RAS_STATISTICS * pStats = (RAS_STATISTICS *)buffer; DWORD dwSize = sizeof (buffer); DWORD dwIndex; RAS_AUTH_ATTRIBUTE * pAttribute; RAS_AUTH_ATTRIBUTE * pAccountingAttributes; LCPCB * pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf); PSTOP_ACCOUNTING_CONTEXT pStopAcctContext = NULL; if ( !pLcpCb ) { return; } if ( pLcpCb->Local.Work.AP == 0 ) { // // If the remote side was not authenticated then do not send an // accounting request as per RADIUS accounting RFC 2139 sec 5.6. // RasAuthAttributeDestroy( pPcb->pAccountingAttributes ); pPcb->pAccountingAttributes = NULL; return; } if ( fInterimAccounting ) { if ( PppConfigInfo.RasAcctProviderInterimAccounting == NULL ) { RasAuthAttributeDestroy( pPcb->pAccountingAttributes ); pPcb->pAccountingAttributes = NULL; return; } } else { if ( PppConfigInfo.RasAcctProviderStopAccounting == NULL ) { RasAuthAttributeDestroy( pPcb->pAccountingAttributes ); pPcb->pAccountingAttributes = NULL; return; } } // // If we have not sent an interim accouting packet then we need to // create attributes // if ( !( pPcb->fFlags & PCBFLAG_INTERIM_ACCT_SENT ) ) { // // Find out where the array is terminated and then insert attributes // for ( dwIndex = 0; pPcb->pAccountingAttributes[dwIndex].raaType != raatMinimum; dwIndex++ ); // // Undo the NULL termination // pPcb->pAccountingAttributes[dwIndex].raaType = raatReserved; pPcb->pAccountingAttributes[dwIndex].dwLength = 0; pPcb->pAccountingAttributes[dwIndex].Value = NULL; do { // // Insert session time // GetSystemTimeAsFileTime( (FILETIME*)&qwCurrentTime ); if ( ( qwCurrentTime.QuadPart > pPcb->qwActiveTime.QuadPart ) && ( pPcb->qwActiveTime.QuadPart > 0 ) ) { qwUpTime.QuadPart = qwCurrentTime.QuadPart - pPcb->qwActiveTime.QuadPart; dwActiveTimeInSeconds = RtlEnlargedUnsignedDivide( qwUpTime,(DWORD)10000000,&dwRemainder); dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatAcctSessionTime, FALSE, 4, (PVOID)ULongToPtr(dwActiveTimeInSeconds) ); if ( dwRetCode != NO_ERROR ) { break; } } // // Insert Input and Output bytes and packets // dwRetCode = RasPortGetStatisticsEx( NULL, pPcb->hPort, (PBYTE)pStats, &dwSize); if ( dwRetCode == NO_ERROR ) { dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatAcctOutputOctets, FALSE, 4, (PVOID)ULongToPtr(pStats->S_Statistics[BYTES_XMITED])); if ( dwRetCode != NO_ERROR ) { break; } dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatAcctInputOctets, FALSE, 4, (PVOID)ULongToPtr(pStats->S_Statistics[BYTES_RCVED])); if ( dwRetCode != NO_ERROR ) { break; } dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatAcctOutputPackets, FALSE, 4, (PVOID)ULongToPtr(pStats->S_Statistics[FRAMES_XMITED])); if ( dwRetCode != NO_ERROR ) { break; } dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatAcctInputPackets, FALSE, 4, (PVOID)ULongToPtr(pStats->S_Statistics[FRAMES_RCVED])); if ( dwRetCode != NO_ERROR ) { break; } } } while (FALSE); if ( dwRetCode != NO_ERROR ) { RasAuthAttributeDestroy( pPcb->pAccountingAttributes ); pPcb->pAccountingAttributes = NULL; return; } // // Null terminate the array // pPcb->pAccountingAttributes[dwIndex].raaType = raatMinimum; pPcb->pAccountingAttributes[dwIndex].dwLength = 0; pPcb->pAccountingAttributes[dwIndex].Value = NULL; pPcb->fFlags |= PCBFLAG_INTERIM_ACCT_SENT; } else { // // Else we need to update session time and other attributes // GetSystemTimeAsFileTime( (FILETIME*)&qwCurrentTime ); if ( ( qwCurrentTime.QuadPart > pPcb->qwActiveTime.QuadPart ) && ( pPcb->qwActiveTime.QuadPart > 0 ) ) { qwUpTime.QuadPart = qwCurrentTime.QuadPart - pPcb->qwActiveTime.QuadPart; dwActiveTimeInSeconds = RtlEnlargedUnsignedDivide( qwUpTime,(DWORD)10000000,&dwRemainder); pAttribute = RasAuthAttributeGet( raatAcctSessionTime, pPcb->pAccountingAttributes ); if ( pAttribute != NULL ) { pAttribute->Value = (PVOID)ULongToPtr(dwActiveTimeInSeconds); } } // // Update Input and Output bytes and packets // dwRetCode = RasPortGetStatisticsEx( NULL, pPcb->hPort, (PBYTE)pStats, &dwSize); if ( dwRetCode == NO_ERROR ) { pAttribute = RasAuthAttributeGet( raatAcctOutputOctets, pPcb->pAccountingAttributes ); if ( pAttribute != NULL ) { pAttribute->Value = (PVOID)(ULongToPtr(pStats->S_Statistics[BYTES_XMITED])); } pAttribute = RasAuthAttributeGet( raatAcctInputOctets, pPcb->pAccountingAttributes ); if ( pAttribute != NULL ) { pAttribute->Value = (PVOID)(ULongToPtr(pStats->S_Statistics[BYTES_RCVED])); } pAttribute = RasAuthAttributeGet( raatAcctOutputPackets, pPcb->pAccountingAttributes ); if ( pAttribute != NULL ) { pAttribute->Value = (PVOID)(ULongToPtr(pStats->S_Statistics[FRAMES_XMITED])); } pAttribute = RasAuthAttributeGet( raatAcctInputPackets, pPcb->pAccountingAttributes ); if ( pAttribute != NULL ) { pAttribute->Value = (PVOID)(ULongToPtr(pStats->S_Statistics[FRAMES_RCVED])); } } } pAttribute = RasAuthAttributeGet( raatAcctLinkCount, pPcb->pAccountingAttributes ); if ( pAttribute != NULL ) { pAttribute->Value = (LPVOID)(ULongToPtr(pPcb->pBcb->dwAcctLinkCount)); } pAttribute = RasAuthAttributeGet( raatAcctEventTimeStamp, pPcb->pAccountingAttributes ); // // Insert event timestamp attribute // if ( pAttribute != NULL ) { pAttribute->Value = (LPVOID)ULongToPtr(GetSecondsSince1970()); } if ( !fInterimAccounting ) { DWORD dwTerminateCause = 9; // // If this is a stop accounting call, then find out where the // array is terminated and then insert stop accounting attributes // for ( dwIndex = 0; pPcb->pAccountingAttributes[dwIndex].raaType != raatMinimum; dwIndex++ ); // // Undo the NULL termination // pPcb->pAccountingAttributes[dwIndex].raaType = raatReserved; pPcb->pAccountingAttributes[dwIndex].dwLength = 0; pPcb->pAccountingAttributes[dwIndex].Value = NULL; // // Insert termination cause attribute // if ( pPcb->LcpCb.dwError == ERROR_IDLE_DISCONNECTED ) { dwTerminateCause = 4; } else if ( pPcb->LcpCb.dwError == ERROR_PPP_SESSION_TIMEOUT ) { dwTerminateCause = 5; } else if ( pPcb->fFlags & PCBFLAG_SERVICE_UNAVAILABLE ) { dwTerminateCause = 15; } else if ( pPcb->fFlags & PCBFLAG_DOING_CALLBACK ) { dwTerminateCause = 16; } else { RASMAN_INFO RasmanInfo; if ( RasGetInfo( NULL, pPcb->hPort, &RasmanInfo ) == NO_ERROR ) { switch( RasmanInfo.RI_DisconnectReason ) { case USER_REQUESTED: dwTerminateCause = 6; if ( pPcb->fFlags & PCBFLAG_RECVD_TERM_REQ ) { // // Even though we brought the line down, it was at the // client's request. // dwTerminateCause = 1; } break; case REMOTE_DISCONNECTION: dwTerminateCause = 1; break; case HARDWARE_FAILURE: dwTerminateCause = 8; break; default: break; } } } dwRetCode = RasAuthAttributeInsert( dwIndex++, pPcb->pAccountingAttributes, raatAcctTerminateCause, FALSE, 4, (LPVOID)ULongToPtr(dwTerminateCause) ); pPcb->pAccountingAttributes[dwIndex].raaType = raatMinimum; pPcb->pAccountingAttributes[dwIndex].dwLength = 0; pPcb->pAccountingAttributes[dwIndex].Value = NULL; } if ( fInterimAccounting ) { pAccountingAttributes = RasAuthAttributeCopy( pPcb->pAccountingAttributes ); if ( NULL == pAccountingAttributes ) { return; } } else { pStopAcctContext = (PSTOP_ACCOUNTING_CONTEXT) LocalAlloc ( LPTR, sizeof(STOP_ACCOUNTING_CONTEXT)); if ( NULL == pStopAcctContext ) { PppLog( 1, "Failed to allocate memory for Stop Accounting Context" ); return; } pStopAcctContext->pPcb= pPcb; //actually there is no need to pass the accounting attributes separately //need to revisit once this is done. pStopAcctContext->pAuthAttributes = pPcb->pAccountingAttributes; pAccountingAttributes = pPcb->pAccountingAttributes; } RtlQueueWorkItem( fInterimAccounting ? InterimAccounting : StopAccounting, fInterimAccounting ? (PVOID)pAccountingAttributes : (PVOID)pStopAcctContext, WT_EXECUTEDEFAULT ); } //** // // Call: GetClientInterfaceInfo // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: // PBYTE GetClientInterfaceInfo( IN PCB * pPcb ) { HANDLE hAttribute; PBYTE pClientInterface = NULL; PBYTE pClientInterface2= NULL; DWORD dwCount = 0; DWORD dwRetCode = NO_ERROR; BYTE * pbValue = NULL; MIB_IPFORWARDROW * pStaticRoute = NULL; MIB_IPFORWARDROW * pStaticRouteSaved= NULL; RAS_AUTH_ATTRIBUTE * pStaticRoutes = RasAuthAttributeGetFirst( raatFramedRoute, pPcb->pAuthenticatorAttributes, &hAttribute ); BYTE * pbFilter = NULL; pbFilter = RasAuthAttributeGetConcatVendorSpecific( 311, 22, pPcb->pAuthenticatorAttributes ); if ( ( pStaticRoutes == NULL ) && ( pbFilter == NULL ) ) { return( NULL ); } if ( pbFilter != NULL ) { dwRetCode = MprInfoDuplicate( pbFilter, &pClientInterface ); LocalFree( pbFilter ); pbFilter = NULL; if ( dwRetCode != NO_ERROR ) { return( NULL ); } } if ( pStaticRoutes != NULL ) { if ( pClientInterface == NULL ) { // // Allocate header // dwRetCode = MprInfoCreate(RTR_INFO_BLOCK_VERSION,&pClientInterface); if ( dwRetCode != NO_ERROR ) { PppLog( 1, "Failed to allocate memory for static routes" ); return( NULL ); } } // // Find out how many routes there are // for ( dwCount = 0; pStaticRoutes != NULL; dwCount++ ) { pStaticRoutes=RasAuthAttributeGetNext(&hAttribute, raatFramedRoute); } pStaticRoute = (MIB_IPFORWARDROW*) LOCAL_ALLOC( LPTR, dwCount * sizeof( MIB_IPFORWARDROW ) ); pStaticRouteSaved = pStaticRoute; if ( pStaticRoute == NULL ) { PppLog( 1, "Failed to allocate memory for static routes" ); MprInfoDelete( pClientInterface ); return( NULL ); } for ( pbValue = NULL, pStaticRoutes = RasAuthAttributeGetFirst( raatFramedRoute, pPcb->pAuthenticatorAttributes, &hAttribute ); pStaticRoutes != NULL; pStaticRoute++, pStaticRoutes = RasAuthAttributeGetNext( &hAttribute, raatFramedRoute ) ) { CHAR * pChar; DWORD dwUniqueDigits = 0; DWORD dwMask = 0; DWORD dwIndex; LocalFree( pbValue ); pbValue = LocalAlloc( LPTR, pStaticRoutes->dwLength + 1 ); if ( NULL == pbValue ) { PppLog( 1, "Failed to allocate memory for static routes" ); continue; } CopyMemory( pbValue, (BYTE *)(pStaticRoutes->Value), pStaticRoutes->dwLength ); pChar = strtok( (CHAR *) pbValue, "/" ); if ( pChar != NULL ) { pStaticRoute->dwForwardDest = inet_addr( pChar ); if ( pStaticRoute->dwForwardDest == INADDR_NONE ) { PppLog(1, "Ignoring invalid static route - no destination IP"); continue; } pChar = strtok( NULL, " " ); if ( pChar == NULL ) { PppLog( 1, "Ignoring invalid static route - no MASK"); continue; } dwUniqueDigits = atoi( pChar ); if ( dwUniqueDigits > 32 ) { PppLog( 1, "Ignoring invalid static route - invalid MASK"); continue; } for ( dwIndex = 0; dwIndex < dwUniqueDigits; dwIndex++ ) { dwMask |= ( 0x80000000 >> dwIndex ); } HostToWireFormat32( dwMask, (PBYTE)&(pStaticRoute->dwForwardMask)); } else { pChar = strtok( (CHAR *) pbValue, " " ); if ( pChar == NULL ) { PppLog(1, "Ignoring invalid static route - no destination IP"); continue; } else { pStaticRoute->dwForwardDest = inet_addr( pChar ); pStaticRoute->dwForwardMask = GetClassMask( pStaticRoute->dwForwardDest ); } } pChar = strtok( NULL, " " ); if ( pChar == NULL ) { PppLog( 1, "Ignoring invalid static route - no next hop IP"); continue; } pStaticRoute->dwForwardNextHop = inet_addr( pChar ); if ( pStaticRoute->dwForwardDest == INADDR_NONE ) { PppLog(1,"Ignoring invalid static route - invalid nexthop IP"); continue; } pChar = strtok( NULL, " " ); if ( pChar != NULL ) { pStaticRoute->dwForwardMetric1 = atoi( pChar ); } pChar = strtok( NULL, " " ); if ( pChar != NULL ) { pStaticRoute->dwForwardMetric2 = atoi( pChar ); } pChar = strtok( NULL, " " ); if ( pChar != NULL ) { pStaticRoute->dwForwardMetric3 = atoi( pChar ); } pChar = strtok( NULL, " " ); if ( pChar != NULL ) { pStaticRoute->dwForwardMetric4 = atoi( pChar ); } pChar = strtok( NULL, " " ); if ( pChar != NULL ) { pStaticRoute->dwForwardMetric5 = atoi( pChar ); } } LocalFree( pbValue ); dwRetCode = MprInfoBlockAdd( pClientInterface, IP_ROUTE_INFO, sizeof( MIB_IPFORWARDROW ), dwCount, (PBYTE)pStaticRouteSaved, &pClientInterface2 ); MprInfoDelete( pClientInterface ); if ( dwRetCode != NO_ERROR ) { PppLog( 1, "MprInfoBlockAdd failed and returned %d", dwRetCode ); LOCAL_FREE( pStaticRouteSaved ); return( NULL ); } else { pClientInterface = pClientInterface2; } LOCAL_FREE( pStaticRouteSaved ); } return( pClientInterface ); } //** // // Call: LoadParserDll // // Returns: VOID // // Description: Loads the parser DLL with the entry points PacketFromPeer, // PacketToPeer, and PacketFree. // VOID LoadParserDll( IN HKEY hKeyPpp ) { LONG lRet; DWORD dwType; DWORD dwSize; CHAR* pszPath = NULL; CHAR* pszExpandedPath = NULL; HINSTANCE hInstance = NULL; FARPROC pPacketFromPeer; FARPROC pPacketToPeer; FARPROC pPacketFree; BOOL fUnloadDLL = TRUE; // // Find how big the path is // dwSize = 0; lRet = RegQueryValueExA( hKeyPpp, RAS_VALUENAME_PARSEDLLPATH, NULL, &dwType, NULL, &dwSize ); if (ERROR_SUCCESS != lRet) { goto LDone; } if ( (REG_EXPAND_SZ != dwType) && (REG_SZ != dwType)) { goto LDone; } pszPath = LOCAL_ALLOC(LPTR, dwSize); if (NULL == pszPath) { goto LDone; } // // Read the path // lRet = RegQueryValueExA( hKeyPpp, RAS_VALUENAME_PARSEDLLPATH, NULL, &dwType, pszPath, &dwSize ); if (ERROR_SUCCESS != lRet) { goto LDone; } // // Replace the %SystemRoot% with the actual path. // dwSize = ExpandEnvironmentStringsA(pszPath, NULL, 0); if (0 == dwSize) { goto LDone; } pszExpandedPath = LOCAL_ALLOC(LPTR, dwSize); if (NULL == pszExpandedPath) { goto LDone; } dwSize = ExpandEnvironmentStringsA( pszPath, pszExpandedPath, dwSize ); if (0 == dwSize) { goto LDone; } if ( (NULL != PppConfigInfo.pszParserDllPath) && (!strcmp(pszExpandedPath, PppConfigInfo.pszParserDllPath))) { // // The DLL is already loaded // fUnloadDLL = FALSE; goto LDone; } hInstance = LoadLibraryA(pszExpandedPath); if (NULL == hInstance) { goto LDone; } fUnloadDLL = FALSE; pPacketFromPeer = GetProcAddress(hInstance, "PacketFromPeer"); pPacketToPeer = GetProcAddress(hInstance, "PacketToPeer"); pPacketFree = GetProcAddress(hInstance, "PacketFree"); FreeLibrary(PppConfigInfo.hInstanceParserDll); PppConfigInfo.hInstanceParserDll = hInstance; hInstance = NULL; if (NULL != PppConfigInfo.pszParserDllPath) { LOCAL_FREE(PppConfigInfo.pszParserDllPath); } PppConfigInfo.pszParserDllPath = pszExpandedPath; pszExpandedPath = NULL; PppConfigInfo.PacketFromPeer = (VOID(*)(HANDLE, BYTE*, DWORD, BYTE**, DWORD*)) pPacketFromPeer; PppConfigInfo.PacketToPeer = (VOID(*)(HANDLE, BYTE*, DWORD, BYTE**, DWORD*)) pPacketToPeer; PppConfigInfo.PacketFree = (VOID(*)(BYTE*)) pPacketFree; LDone: if (NULL != pszPath) { LOCAL_FREE(pszPath); } if (NULL != pszExpandedPath) { LOCAL_FREE(pszExpandedPath); } if (NULL != hInstance) { FreeLibrary(hInstance); } if (fUnloadDLL) { FreeLibrary(PppConfigInfo.hInstanceParserDll); PppConfigInfo.hInstanceParserDll = NULL; if (NULL != PppConfigInfo.pszParserDllPath) { LOCAL_FREE(PppConfigInfo.pszParserDllPath); } PppConfigInfo.pszParserDllPath = NULL; PppConfigInfo.PacketFromPeer = NULL; PppConfigInfo.PacketToPeer = NULL; PppConfigInfo.PacketFree = NULL; } } //** // // Call: PortSendOrDisconnect // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: // DWORD PortSendOrDisconnect( IN PCB * pPcb, IN DWORD cbPacket ) { DWORD dwRetCode; BYTE* pData = NULL; DWORD dwSize = 0; BOOL fBufferReceivedFromParser = FALSE; if ( NULL != PppConfigInfo.PacketToPeer ) { PppConfigInfo.PacketToPeer( pPcb->hPort, (BYTE*)(pPcb->pSendBuf), cbPacket, &pData, &dwSize ); } if ( NULL == pData ) { pData = (BYTE*)(pPcb->pSendBuf); dwSize = cbPacket; } else { fBufferReceivedFromParser = TRUE; } dwRetCode = RasPortSend( pPcb->hPort, pData, dwSize ); if ( NO_ERROR != dwRetCode ) { PppLog( 1, "RasPortSend on port %d failed: %d", pPcb->hPort, dwRetCode ); pPcb->LcpCb.dwError = dwRetCode; pPcb->fFlags |= PCBFLAG_STOPPED_MSG_SENT; NotifyCaller( pPcb, ( pPcb->fFlags & PCBFLAG_IS_SERVER ) ? PPPDDMMSG_Stopped : PPPMSG_Stopped, &(pPcb->LcpCb.dwError) ); } if ( fBufferReceivedFromParser ) { PPP_ASSERT( NULL != PppConfigInfo.PacketFree ); PppConfigInfo.PacketFree( pData ); } return( dwRetCode ); } //** // // Call: ReceiveViaParser // // Returns: VOID // // Description: // VOID ReceiveViaParser( IN PCB * pPcb, IN PPP_PACKET * pPacket, IN DWORD dwPacketLength ) { BYTE* pData = NULL; DWORD dwSize = 0; BOOL fBufferReceivedFromParser = FALSE; if ( NULL != PppConfigInfo.PacketFromPeer ) { PppConfigInfo.PacketFromPeer( pPcb->hPort, (BYTE*)pPacket, dwPacketLength, &pData, &dwSize ); } if ( NULL == pData ) { pData = (BYTE*)pPacket; dwSize = dwPacketLength; } else { fBufferReceivedFromParser = TRUE; } FsmReceive( pPcb, (PPP_PACKET*) pData, dwSize ); if ( fBufferReceivedFromParser ) { PPP_ASSERT( NULL != PppConfigInfo.PacketFree ); PppConfigInfo.PacketFree( pData ); } } //** // // Call: GetSecondsSince1970 // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: // DWORD GetSecondsSince1970( VOID ) { SYSTEMTIME LocalTime; TIME_FIELDS LocalTimeFields; LARGE_INTEGER TempTime; LARGE_INTEGER SystemTime; DWORD RetTime; GetLocalTime( &LocalTime ); LocalTimeFields.Year = LocalTime.wYear; LocalTimeFields.Month = LocalTime.wMonth; LocalTimeFields.Day = LocalTime.wDay; LocalTimeFields.Hour = LocalTime.wHour; LocalTimeFields.Minute = LocalTime.wMinute; LocalTimeFields.Second = LocalTime.wSecond; LocalTimeFields.Milliseconds = LocalTime.wMilliseconds; LocalTimeFields.Weekday = LocalTime.wDayOfWeek; RtlTimeFieldsToTime(&LocalTimeFields, &TempTime); RtlLocalTimeToSystemTime(&TempTime, &SystemTime); RtlTimeToSecondsSince1970(&SystemTime, &RetTime); return( RetTime ); } //** // // Call: IsPschedRunning // // Returns: TRUE iff Psched is running // // Description: // BOOL IsPschedRunning( VOID ) { SC_HANDLE hCont = NULL; SC_HANDLE hSched = NULL; DWORD dwErr = NO_ERROR; SERVICE_STATUS Status; BOOL fRet = FALSE; // // Initialize // ZeroMemory( &Status, sizeof(Status) ); do { hCont = OpenSCManager( NULL, NULL, GENERIC_READ ); if ( hCont == NULL ) { dwErr = GetLastError(); PppLog( 1, "OpenSCManager failed: %d", dwErr ); break; } hSched = OpenService( hCont, TEXT("psched"), SERVICE_QUERY_STATUS ); if ( hSched == NULL ) { dwErr = GetLastError(); PppLog( 1, "OpenService failed: %d", dwErr ); break; } if ( !QueryServiceStatus( hSched, &Status )) { dwErr = GetLastError(); PppLog( 1, "QueryServiceStatus failed: %d", dwErr ); break; } fRet = ( Status.dwCurrentState == SERVICE_RUNNING ); } while ( FALSE ); // // Cleanup // if ( hSched ) { CloseServiceHandle( hSched ); } if ( hCont ) { CloseServiceHandle( hCont ); } return( fRet ); } //** // // Call: LogPPPPacket // // Returns: None // // Description: // VOID LogPPPPacket( IN BOOL fReceived, IN PCB * pPcb, IN PPP_PACKET * pPacket, IN DWORD cbPacket ) { SYSTEMTIME SystemTime; CHAR * pchProtocol; CHAR * pchType; BYTE Id = 0; BYTE bCode; DWORD cbTracePacketSize = cbPacket; DWORD dwUnknownPacketTraceSize; BOOL fPrint = TRUE; dwUnknownPacketTraceSize = PppConfigInfo.dwUnknownPacketTraceSize; GetSystemTime( &SystemTime ); if ( cbPacket > PPP_CONFIG_HDR_LEN ) { bCode = *(((CHAR*)pPacket)+PPP_PACKET_HDR_LEN); if ( ( bCode == 0 ) || ( bCode > TIME_REMAINING ) ) { pchType = "UNKNOWN"; } else { pchType = FsmCodes[ bCode ]; } Id = *(((CHAR*)pPacket)+PPP_PACKET_HDR_LEN+1); } else { pchType = "UNKNOWN"; } if ( cbPacket > PPP_PACKET_HDR_LEN ) { switch( WireToHostFormat16( (CHAR*)pPacket ) ) { case PPP_LCP_PROTOCOL: pchProtocol = "LCP"; break; case PPP_BACP_PROTOCOL: pchProtocol = "BACP"; break; case PPP_BAP_PROTOCOL: pchProtocol = "BAP"; pchType = "Protocol specific"; break; case PPP_PAP_PROTOCOL: pchProtocol = "PAP"; pchType = "Protocol specific"; fPrint = FALSE; break; case PPP_CBCP_PROTOCOL: pchProtocol = "CBCP"; pchType = "Protocol specific"; break; case PPP_CHAP_PROTOCOL: pchProtocol = "CHAP"; pchType = "Protocol specific"; break; case PPP_IPCP_PROTOCOL: pchProtocol = "IPCP"; break; case PPP_ATCP_PROTOCOL: pchProtocol = "ATCP"; break; case PPP_IPXCP_PROTOCOL: pchProtocol = "IPXCP"; break; case PPP_NBFCP_PROTOCOL: pchProtocol = "NBFCP"; break; case PPP_CCP_PROTOCOL: pchProtocol = "CCP"; break; case PPP_EAP_PROTOCOL: pchProtocol = "EAP"; pchType = "Protocol specific"; if ( cbTracePacketSize > dwUnknownPacketTraceSize ) { cbTracePacketSize = dwUnknownPacketTraceSize; } break; case PPP_SPAP_NEW_PROTOCOL: pchProtocol = "SHIVA PAP"; pchType = "Protocol specific"; break; default: pchProtocol = "UNKNOWN"; if ( cbTracePacketSize > dwUnknownPacketTraceSize ) { cbTracePacketSize = dwUnknownPacketTraceSize; } break; } } else { pchProtocol = "UNKNOWN"; } PppLog( 1, "%sPPP packet %s at %0*d/%0*d/%0*d %0*d:%0*d:%0*d:%0*d", fReceived ? ">" : "<", fReceived ? "received" : "sent", 2, SystemTime.wMonth, 2, SystemTime.wDay, 2, SystemTime.wYear, 2, SystemTime.wHour, 2, SystemTime.wMinute, 2, SystemTime.wSecond, 3, SystemTime.wMilliseconds ); PppLog(1, "%sProtocol = %s, Type = %s, Length = 0x%x, Id = 0x%x, Port = %d", fReceived ? ">" : "<", pchProtocol, pchType, cbPacket, Id, pPcb->hPort ); if ( fPrint ) { TraceDumpExA( PppConfigInfo.dwTraceId, TRACE_LEVEL_1 | TRACE_USE_MSEC, (CHAR*)pPacket, cbTracePacketSize, 1, FALSE, fReceived ? ">" : "<" ); } PppLog(1," " ); } //** // // Call: PppLog // // Returns: None // // Description: Will print to the PPP logfile // VOID PppLog( IN DWORD DbgLevel, ... ) { va_list arglist; CHAR *Format; char OutputBuffer[1024]; va_start( arglist, DbgLevel ); Format = va_arg( arglist, CHAR* ); vsprintf( OutputBuffer, Format, arglist ); va_end( arglist ); TracePutsExA( PppConfigInfo.dwTraceId, (( DbgLevel == 1 ) ? TRACE_LEVEL_1 : TRACE_LEVEL_2 ) | TRACE_USE_MSEC, OutputBuffer ); } #ifdef MEM_LEAK_CHECK LPVOID DebugAlloc( DWORD Flags, DWORD dwSize ) { DWORD Index; LPBYTE pMem = (LPBYTE)HeapAlloc( PppConfigInfo.hHeap, HEAP_ZERO_MEMORY,dwSize+8); if ( pMem == NULL ) return( pMem ); for( Index=0; Index < PPP_MEM_TABLE_SIZE; Index++ ) { if ( PppMemTable[Index] == NULL ) { PppMemTable[Index] = pMem; break; } } PPP_ASSERT( Index != PPP_MEM_TABLE_SIZE ); return( (LPVOID)pMem ); } BOOL DebugFree( PVOID pMem ) { DWORD Index; for( Index=0; Index < PPP_MEM_TABLE_SIZE; Index++ ) { if ( PppMemTable[Index] == pMem ) { PppMemTable[Index] = NULL; break; } } ASSERT( Index != PPP_MEM_TABLE_SIZE ); return( HeapFree( PppConfigInfo.hHeap, 0, pMem ) ); } LPVOID DebugReAlloc( PVOID pMem, DWORD dwSize ) { DWORD Index; if ( pMem == NULL ) { PPP_ASSERT(FALSE); } for( Index=0; Index < PPP_MEM_TABLE_SIZE; Index++ ) { if ( PppMemTable[Index] == pMem ) { PppMemTable[Index] = HeapReAlloc( PppConfigInfo.hHeap, HEAP_ZERO_MEMORY, pMem, dwSize ); pMem = PppMemTable[Index]; break; } } PPP_ASSERT( Index != PPP_MEM_TABLE_SIZE ); return( (LPVOID)pMem ); } #endif