Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

6353 lines
173 KiB

/********************************************************************/
/** 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 <nt.h>
#include <ntrtl.h>
#include <nturtl.h> // needed for winbase.h
#include <windows.h> // Win32 base API's
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <rpc.h>
#include <winsock2.h>
#include <rtinfo.h>
#include <iprtrmib.h>
#include <ipinfoid.h>
#include <lmcons.h>
#include <lmwksta.h>
#include <lmapibuf.h>
#include <lmsname.h>
#include <rasman.h>
#include <rtutils.h>
#include <mprapip.h>
#include <mprlog.h>
#include <raserror.h>
#include <mprerror.h>
#include <rasppp.h>
#include <pppcp.h>
#include <ppp.h>
#include <smevents.h>
#include <smaction.h>
#include <timer.h>
#include <util.h>
#include <worker.h>
#include <bap.h>
#include <dsrole.h>
#include <ntlsapi.h>
#define INCL_RASAUTHATTRIBUTES
#define INCL_PWUTIL
#include <ppputil.h>
#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 );
extern PPP_AUTH_ACCT_PROVIDER g_AcctProv;
//**
//
// 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 );
PppMsg.ExtraInfo.DdmNewBundle.pQuarantineIPFilter = NULL;
PppMsg.ExtraInfo.DdmNewBundle.pFilter = NULL;
PppMsg.ExtraInfo.DdmNewBundle.fQuarantinePresent = FALSE;
if(pPcb->pBcb->InterfaceInfo.IfType != ROUTER_IF_TYPE_FULL_ROUTER)
{
PBYTE pQuarantineFilter, pFilter;
pQuarantineFilter = RasAuthAttributeGetConcatVendorSpecific(
311,
MS_VSA_Quarantine_IP_Filter,
pPcb->pAuthenticatorAttributes);
if(NULL != pQuarantineFilter)
{
MprInfoDuplicate(
pQuarantineFilter,
&PppMsg.ExtraInfo.DdmNewBundle.pQuarantineIPFilter);
LocalFree(pQuarantineFilter);
PppMsg.ExtraInfo.DdmNewBundle.fQuarantinePresent = TRUE;
pFilter = RasAuthAttributeGetConcatVendorSpecific(
311,
MS_VSA_Filter,
pPcb->pAuthenticatorAttributes);
if(NULL != pFilter)
{
MprInfoDuplicate(
pFilter,
&PppMsg.ExtraInfo.DdmNewBundle.pFilter);
LocalFree(pFilter);
}
}
}
if(!PppMsg.ExtraInfo.DdmNewBundle.fQuarantinePresent)
{
//
// Check to see if quarantine timeout is present.
//
if(NULL != RasAuthAttributeGetVendorSpecific(
311,
MS_VSA_Quarantine_Session_Timeout,
pPcb->pAuthenticatorAttributes))
{
PppMsg.ExtraInfo.DdmNewBundle.fQuarantinePresent = TRUE;
}
}
}
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 )/sizeof(WCHAR));
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 );
}
}
}
}
//**
//
// 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
//
// 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) );
}
RtlSecureZeroMemory( pBcb->szPassword,
sizeof( pBcb->szPassword ) );
RtlSecureZeroMemory( 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 );
FreePassword(&pBcb->DBPassword);
FreePassword(&pBcb->DBOldPassword);
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 = NULL;
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 ) )
{
//This check is added to please prefast
if ( pPcbWalker )
{
pPcbWalker->fFlags |= PCBFLAG_IS_BUNDLED;
}
pPcb->fFlags |= PCBFLAG_IS_BUNDLED;
pBcbOld = pPcb->pBcb;
if ( pPcbWalker )
{
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 = NO_ERROR;
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,
MS_VSA_CHAP_Domain, //10
pAttributes );
ZeroMemory( szAcctSessionId, sizeof( szAcctSessionId ) );
_itoa(pPcb->dwAccountingSessionId, 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;
}
//
// 8 Vendor-Type = MS_MPPE_EncryptionType
//
abEncryptionType[0] = MS_VSA_MPPE_Encryption_Type;
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;
}
//
// Ref the accounting provider - the ref will be removed
// in StartAccounting code.
//
REF_PROVIDER(g_AcctProv);
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 = NULL;
RAS_AUTH_ATTRIBUTE * pUserAttributes = ( pPcb->pAuthProtocolAttributes )
? pPcb->pAuthProtocolAttributes
: pPcb->pAuthenticatorAttributes;
if((pPcb->pBcb->InterfaceInfo.IfType != ROUTER_IF_TYPE_FULL_ROUTER )&&
(0 == (pPcb->pBcb->fFlags & BCBFLAG_QUARANTINE_TIMEOUT)))
{
//
// Check to see if there is a quarantine-session-timeout
// attribute.
//
pAttribute = RasAuthAttributeGetVendorSpecific(
311,
MS_VSA_Quarantine_Session_Timeout,
pUserAttributes);
if(pAttribute != NULL)
{
pPcb->pBcb->dwQuarantineSessionTimeout =
WireToHostFormat32(((BYTE*)(pAttribute->Value))+6);
pPcb->pBcb->fFlags |= BCBFLAG_QUARANTINE_TIMEOUT;
}
}
if(pPcb->pBcb->fFlags & BCBFLAG_QUARANTINE_TIMEOUT)
{
//
// 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->pBcb->dwQuarantineSessionTimeout );
PppLog(2, "AuthAttribute Quarantine Session Timeout = %d",
pPcb->pBcb->dwQuarantineSessionTimeout);
}
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) &&
( (pPcb->pBcb->fFlags & BCBFLAG_QUARANTINE_TIMEOUT) == 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();
goto done;
}
if ( 0 == WideCharToMultiByte(
CP_ACP,
0,
wchPassword,
-1,
pPcb->pBcb->szPassword,
sizeof( pPcb->pBcb->szPassword ),
NULL,
NULL ) )
{
dwRetCode = GetLastError();
goto done;
}
if ( 0 == WideCharToMultiByte(
CP_ACP,
0,
wchDomainName,
-1,
pPcb->pBcb->szLocalDomain,
sizeof( pPcb->pBcb->szLocalDomain ),
NULL,
NULL ) )
{
dwRetCode = GetLastError();
goto done;
}
// EncodePw( pPcb->pBcb->chSeed, pPcb->pBcb->szPassword );
// EncodePw( pPcb->pBcb->chSeed, pPcb->pBcb->szOldPassword );
dwRetCode = EncodePassword(strlen(pPcb->pBcb->szPassword) + 1,
pPcb->pBcb->szPassword,
&pPcb->pBcb->DBPassword);
if(NO_ERROR != dwRetCode)
{
goto done;
}
}
done:
//
// Null out password buffer
//
RtlSecureZeroMemory( wchPassword,
(PWLEN + 1) * sizeof(WCHAR));
//
// wipe out password field in bcb. DBPassword field
// now has the encrypted password.
//
RtlSecureZeroMemory(pPcb->pBcb->szPassword,
PWLEN + 1);
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 );
DEREF_PROVIDER(g_AcctProv);
}
//**
//
// 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 );
DEREF_PROVIDER(g_AcctProv);
}
//**
//
// 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);
DEREF_PROVIDER(g_AcctProv);
}
//**
//
// 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] = MS_VSA_RAS_Vendor; //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] = MS_VSA_RAS_Version; //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 = TERMINATE_CAUSE_IDLE_TIMEOUT;
}
else if ( pPcb->LcpCb.dwError == ERROR_PPP_SESSION_TIMEOUT )
{
if(pPcb->fFlags & PCBFLAG_QUARANTINE_TIMEOUT)
{
dwTerminateCause = TERMINATE_CAUSE_USER_ERROR;
}
else
{
dwTerminateCause = TERMINATE_CAUSE_SESSION_TIMEOUT;
}
}
else if ( pPcb->fFlags & PCBFLAG_SERVICE_UNAVAILABLE )
{
dwTerminateCause = TERMINATE_CAUSE_SERVICE_UNAVAILABLE;
}
else if ( pPcb->fFlags & PCBFLAG_DOING_CALLBACK )
{
dwTerminateCause = TERMINATE_CAUSE_CALLBACK;
}
else
{
RASMAN_INFO RasmanInfo;
if ( RasGetInfo( NULL, pPcb->hPort, &RasmanInfo ) == NO_ERROR )
{
switch( RasmanInfo.RI_DisconnectReason )
{
case USER_REQUESTED:
dwTerminateCause = TERMINATE_CAUSE_ADMIN_RESET;
if ( pPcb->fFlags & PCBFLAG_RECVD_TERM_REQ )
{
//
// Even though we brought the line down, it was at the
// client's request.
//
dwTerminateCause = TERMINATE_CAUSE_USER_REQUEST;
}
break;
case REMOTE_DISCONNECTION:
dwTerminateCause = TERMINATE_CAUSE_USER_REQUEST;
break;
case HARDWARE_FAILURE:
dwTerminateCause = TERMINATE_CAUSE_PORT_ERROR;
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;
}
REF_PROVIDER(g_AcctProv);
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;
ASSERT(NULL != pPcb->pBcb);
//
// Get quarantine filters for this connection if they
// are available.
//
pbFilter = RasAuthAttributeGetConcatVendorSpecific(
311,
MS_VSA_Quarantine_IP_Filter,
pPcb->pAuthenticatorAttributes);
if(NULL == pbFilter)
{
//
// Get the regular filters for this connection if
// no quarantine filters are specified.
//
pbFilter = RasAuthAttributeGetConcatVendorSpecific(
311,
MS_VSA_Filter, //22
pPcb->pAuthenticatorAttributes );
}
else
{
PppLog(2, "Found Quarantine-filter");
}
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 | TRACE_USE_DATE, 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