/*******************************************************************/ /* Copyright(c) 1996 Microsoft Corporation */ /*******************************************************************/ //*** // // Filename: arapif.c // // Description: This module contains the procedures for the // DDM-Arap interface // // Author: Shirish Koti Sep 9, 1996 // // Revision History: // //*** #include "ddm.h" #include "util.h" #include "isdn.h" #include "objects.h" #include "rasmanif.h" #include "handlers.h" #include #include "arapif.h" #include #include #include #include // // prototypes for functions used in this file // VOID ArapDDMAuthenticated( IN PDEVICE_OBJECT pDeviceObj, IN ARAPDDM_AUTH_RESULT * pAuthResult ); VOID ArapDDMCallbackRequest( IN PDEVICE_OBJECT pDeviceObj, IN ARAPDDM_CALLBACK_REQUEST *pCbReq ); VOID ArapDDMDone( IN PDEVICE_OBJECT pDeviceObj, IN DWORD NetAddress, IN DWORD SessTimeOut ); VOID ArapDDMFailure( IN PDEVICE_OBJECT pDeviceObj, IN ARAPDDM_DISCONNECT *pFailInfo ); VOID ArapDDMTimeOut( IN HANDLE hObject ); //*** // // Function: ArapEventHandler // Waits for a message from Arap and depending on the message // type, executes the appropriate routine Loads Arap.dll and // gets all the entry points // // Parameters: None // // Return: Nothing // // //***$ VOID ArapEventHandler( IN VOID ) { ARAP_MESSAGE ArapMsg; PDEVICE_OBJECT pDevObj; LPWSTR portnamep; // // loop to get all messages // while( ServerReceiveMessage( MESSAGEQ_ID_ARAP, (BYTE *)&ArapMsg) ) { EnterCriticalSection( &(gblDeviceTable.CriticalSection) ); // // identify the message recipient // if ( ( pDevObj = DeviceObjGetPointer( ArapMsg.hPort ) ) == NULL ) { LeaveCriticalSection( &(gblDeviceTable.CriticalSection) ); return; } // // action on the message type // switch( ArapMsg.dwMsgId ) { case ARAPDDMMSG_Authenticated: ArapDDMAuthenticated( pDevObj, &ArapMsg.ExtraInfo.AuthResult); break; case ARAPDDMMSG_CallbackRequest: ArapDDMCallbackRequest( pDevObj, &ArapMsg.ExtraInfo.CallbackRequest); break; case ARAPDDMMSG_Done: pDevObj->fFlags &= (~DEV_OBJ_AUTH_ACTIVE); ArapDDMDone(pDevObj, ArapMsg.ExtraInfo.Done.NetAddress, ArapMsg.ExtraInfo.Done.SessTimeOut); break; case ARAPDDMMSG_Inactive: // // Client has been inactive on all protocols for time // specified in the registry. We disconnect the client. // portnamep = pDevObj->wchPortName; DDMLogInformation( ROUTERLOG_AUTODISCONNECT, 1, &portnamep ); // break intentionally omitted here case ARAPDDMMSG_Disconnected: // in case we had this puppy sitting in the timer queue TimerQRemove( (HANDLE)pDevObj->hPort, ArapDDMTimeOut); DevStartClosing(pDevObj); break; case ARAPDDMMSG_Failure: pDevObj->fFlags &= (~DEV_OBJ_AUTH_ACTIVE); ArapDDMFailure(pDevObj, &ArapMsg.ExtraInfo.FailureInfo); break; default: RTASSERT(FALSE); break; } LeaveCriticalSection( &(gblDeviceTable.CriticalSection) ); } } //*** // // Function: ArapDDMAuthenticated // Retrieves username and domain from the message and stores it // in the dcb. // // Parameters: pDeviceObj - the dcb for this connection // pAuthResult - info for the user who is authenticated // // Return: Nothing // // //***$ VOID ArapDDMAuthenticated( IN PDEVICE_OBJECT pDeviceObj, IN ARAPDDM_AUTH_RESULT * pAuthResult ) { DWORD dwRetCode; WCHAR wchUserName[UNLEN+1]; PCONNECTION_OBJECT pConnObj; DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, "ArapDDMAuthenticated: Entered, hPort=%d", pDeviceObj->hPort); if ( pDeviceObj->DeviceState != DEV_OBJ_AUTH_IS_ACTIVE ) { return; } pConnObj = ConnObjGetPointer( pDeviceObj->hConnection ); RTASSERT( pConnObj != NULL ); // this shouldn't happen, but if it does, just ignore this call if (pConnObj == NULL) { return; } // // Stop authentication timer // TimerQRemove( (HANDLE)pDeviceObj->hPort, SvAuthTimeout ); // // devObj: copy the user name, domain name // if ( wcslen( pAuthResult->wchUserName ) > 0 ) { wcscpy(wchUserName, pAuthResult->wchUserName); } else { wcscpy( wchUserName, gblpszUnknown ); } wcscpy( pDeviceObj->wchUserName, wchUserName ); wcscpy( pDeviceObj->wchDomainName, pAuthResult->wchLogonDomain ); // // connObj: copy the user name, domain name, etc. // wcscpy( pConnObj->wchUserName, wchUserName ); wcscpy( pConnObj->wchDomainName, pAuthResult->wchLogonDomain ); wcscpy( pConnObj->wchInterfaceName, pDeviceObj->wchUserName ); pConnObj->hPort = pDeviceObj->hPort; } //*** // // Function: ArapDDMCallbackRequest // Disconnects the connection, setting it up for a callback // // Parameters: pDeviceObj - the dcb for this connection // pCbReq - call back info // // Return: Nothing // // //***$ VOID ArapDDMCallbackRequest( IN PDEVICE_OBJECT pDeviceObj, IN ARAPDDM_CALLBACK_REQUEST *pCbReq ) { DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, "ArapDDMCallbackRequest: Entered, hPort = %d\n", pDeviceObj->hPort); // // check the state // if (pDeviceObj->DeviceState != DEV_OBJ_AUTH_IS_ACTIVE) { return; } TimerQRemove( (HANDLE)pDeviceObj->hPort, SvAuthTimeout ); // // copy relevant fields in our dcb // if (pCbReq->fUseCallbackDelay) { pDeviceObj->dwCallbackDelay = pCbReq->dwCallbackDelay; } else { pDeviceObj->dwCallbackDelay = gblDDMConfigInfo.dwCallbackTime; } mbstowcs(pDeviceObj->wchCallbackNumber, pCbReq->szCallbackNumber, MAX_PHONE_NUMBER_LEN + 1 ); // // Disconnect the line and change the state // pDeviceObj->DeviceState = DEV_OBJ_CALLBACK_DISCONNECTING; // // Wait to enable the client to get the message // TimerQRemove( (HANDLE)pDeviceObj->hPort, SvDiscTimeout ); TimerQInsert( (HANDLE)pDeviceObj->hPort, DISC_TIMEOUT_CALLBACK, SvDiscTimeout ); } //*** // // Function: ArapDDMDone // Logs an event, marks the state // // Parameters: pDeviceObj - the dcb for this connection // // Return: Nothing // // //***$ VOID ArapDDMDone( IN PDEVICE_OBJECT pDeviceObj, IN DWORD NetAddress, IN DWORD SessTimeOut ) { LPWSTR lpstrAudit[2]; PCONNECTION_OBJECT pConnObj; WCHAR wchFullUserName[UNLEN+DNLEN+2]; ROUTER_INTERFACE_OBJECT * pIfObject; DWORD dwRetCode; DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, "ArapDDMDone: Entered, hPort=%d", pDeviceObj->hPort); if ( pDeviceObj->DeviceState != DEV_OBJ_AUTH_IS_ACTIVE ) { return; } // // Get connection object for this connection // pConnObj = ConnObjGetPointer( pDeviceObj->hConnection ); RTASSERT( pConnObj != NULL ); // this shouldn't happen, but if it does, just ignore this call if (pConnObj == NULL) { return; } pConnObj->PppProjectionResult.at.dwError = NO_ERROR; pConnObj->PppProjectionResult.at.dwRemoteAddress = NetAddress; // // Create client interface object for this connection // pIfObject = IfObjectAllocateAndInit( pConnObj->wchUserName, RISTATE_CONNECTED, ROUTER_IF_TYPE_CLIENT, pConnObj->hConnection, TRUE, 0, 0, NULL ); if ( pIfObject == (ROUTER_INTERFACE_OBJECT *)NULL ) { // // Error log this and stop the connection. // DDMLogError( ROUTERLOG_NOT_ENOUGH_MEMORY, 1, NULL, GetLastError() ); DevStartClosing( pDeviceObj ); return; } // // Insert in table now // dwRetCode = IfObjectInsertInTable( pIfObject ); if ( dwRetCode != NO_ERROR ) { LOCAL_FREE( pIfObject ); DDMLogError( ROUTERLOG_NOT_ENOUGH_MEMORY, 1, NULL, dwRetCode ); DevStartClosing( pDeviceObj ); return; } pConnObj->hDIMInterface = pIfObject->hDIMInterface; // // Reduce the media count for this device // if ( !(pDeviceObj->fFlags & DEV_OBJ_MARKED_AS_INUSE) ) { if ( pDeviceObj->fFlags & DEV_OBJ_ALLOW_ROUTERS ) { MediaObjRemoveFromTable( pDeviceObj->wchDeviceType ); } pDeviceObj->fFlags |= DEV_OBJ_MARKED_AS_INUSE; gblDeviceTable.NumDevicesInUse++; // // Possibly need to notify the router managers of unreachability // EnterCriticalSection( &(gblpInterfaceTable->CriticalSection) ); IfObjectNotifyAllOfReachabilityChange( FALSE, INTERFACE_OUT_OF_RESOURCES ); LeaveCriticalSection( &(gblpInterfaceTable->CriticalSection) ); } // // Stop authentication timer (this will be running in case of callback) // TimerQRemove( (HANDLE)pDeviceObj->hPort, SvAuthTimeout ); // // if a session timeout is specified in the policy, put this connection on // the timer queue so the user gets kicked off after the session timeout // if (SessTimeOut != (DWORD)-1) { TimerQInsert( (HANDLE)pDeviceObj->hPort, SessTimeOut, ArapDDMTimeOut); } // // log authentication success // if ( pDeviceObj->wchDomainName[0] != TEXT('\0') ) { wcscpy( wchFullUserName, pDeviceObj->wchDomainName ); wcscat( wchFullUserName, TEXT("\\") ); wcscat( wchFullUserName, pDeviceObj->wchUserName ); } else { wcscpy( wchFullUserName, pDeviceObj->wchUserName ); } lpstrAudit[0] = wchFullUserName; lpstrAudit[1] = pDeviceObj->wchPortName; DDMLogInformation( ROUTERLOG_AUTH_SUCCESS, 2, lpstrAudit); // // and finaly go to ACTIVE state // pDeviceObj->DeviceState = DEV_OBJ_ACTIVE; pDeviceObj->dwTotalNumberOfCalls++; // // and initialize the active time // GetSystemTimeAsFileTime( (FILETIME*)&(pConnObj->qwActiveTime) ); GetSystemTimeAsFileTime( (FILETIME*)&(pDeviceObj->qwActiveTime) ); return; } //*** // // Function: ArapDDMFailure // Closes the dcb, and logs an event depending on why connection failed // // Parameters: pDeviceObj - the dcb for this connection // pFailInfo - info about who disconnected and how (or why) // // Return: Nothing // // //***$ VOID ArapDDMFailure( IN PDEVICE_OBJECT pDeviceObj, IN ARAPDDM_DISCONNECT *pFailInfo ) { LPWSTR auditstrp[3]; WCHAR wchErrorString[256+1]; WCHAR wchUserName[UNLEN+1]; WCHAR wchDomainName[DNLEN+1]; DWORD dwRetCode; DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, "ArapDDMFailure: Entered, hPort=%d\n", pDeviceObj->hPort); // // ignore the DeviceState here: disconnect can happen at any time during // the connection // switch( pFailInfo->dwError ) { case ERROR_AUTHENTICATION_FAILURE: wcscpy( wchUserName, pFailInfo->wchUserName ); auditstrp[0] = wchUserName; auditstrp[1] = pDeviceObj->wchPortName; DDMLogWarning(ROUTERLOG_AUTH_FAILURE,2,auditstrp ); break; case ERROR_PASSWD_EXPIRED: wcscpy( wchUserName, pFailInfo->wchUserName ); wcscpy( wchDomainName, pFailInfo->wchLogonDomain ); auditstrp[0] = wchDomainName; auditstrp[1] = wchUserName; auditstrp[2] = pDeviceObj->wchPortName; DDMLogWarning( ROUTERLOG_PASSWORD_EXPIRED,3,auditstrp ); break; case ERROR_ACCT_EXPIRED: wcscpy( wchUserName, pFailInfo->wchUserName ); wcscpy( wchDomainName, pFailInfo->wchLogonDomain ); auditstrp[0] = wchDomainName; auditstrp[1] = wchUserName; auditstrp[2] = pDeviceObj->wchPortName; DDMLogWarning( ROUTERLOG_ACCT_EXPIRED, 3, auditstrp ); break; case ERROR_NO_DIALIN_PERMISSION: wcscpy( wchUserName, pFailInfo->wchUserName ); wcscpy( wchDomainName, pFailInfo->wchLogonDomain ); auditstrp[0] = wchDomainName; auditstrp[1] = wchUserName; auditstrp[2] = pDeviceObj->wchPortName; DDMLogWarning( ROUTERLOG_NO_DIALIN_PRIVILEGE,3,auditstrp ); break; default: auditstrp[0] = pDeviceObj->wchPortName; auditstrp[1] = wchErrorString; DDMLogErrorString( ROUTERLOG_ARAP_FAILURE, 2, auditstrp, pFailInfo->dwError, 2 ); break; } DevStartClosing( pDeviceObj ); } //*** // // Function: ArapDDMTimeOut // Closes the connection when the timeout specified in policy elapses // // Parameters: hPort // // Return: Nothing // // //***$ VOID ArapDDMTimeOut( IN HANDLE hPort ) { PDEVICE_OBJECT pDeviceObj; EnterCriticalSection( &(gblDeviceTable.CriticalSection) ); pDeviceObj = DeviceObjGetPointer( (HPORT)hPort ); if ( pDeviceObj == NULL ) { LeaveCriticalSection( &(gblDeviceTable.CriticalSection) ); return; } ArapDisconnect((HPORT)pDeviceObj->hPort); LeaveCriticalSection( &(gblDeviceTable.CriticalSection) ); } // // The following two structures (and the RasSetDevConfig call) copied from // ras\ui\common\nouiutil\rasman.c, courtesy SteveC // /* These types are described in MSDN and appear in Win95's unimdm.h private ** header (complete with typo) but not in any SDK headers. */ typedef struct tagDEVCFGGDR { DWORD dwSize; DWORD dwVersion; WORD fwOptions; WORD wWaitBong; }DEVCFGHDR; typedef struct tagDEVCFG { DEVCFGHDR dfgHdr; COMMCONFIG commconfig; } DEVCFG; VOID ArapSetModemParms( IN PVOID pDevObjPtr, IN BOOLEAN TurnItOff ) { DWORD dwErr; DWORD dwBlobSize=0; RAS_DEVCONFIG *pRasDevCfg; PDEVICE_OBJECT pDeviceObj; MODEMSETTINGS *pModemSettings; DEVCFG *pDevCfg; pDeviceObj = (PDEVICE_OBJECT)pDevObjPtr; // // if this was not a callback case, we never messed with modem settings: // don't do anything here // if (pDeviceObj->wchCallbackNumber[0] == 0) { return; } dwErr = RasGetDevConfig(NULL, pDeviceObj->hPort,"modem",NULL,&dwBlobSize); if (dwErr != ERROR_BUFFER_TOO_SMALL) { // what else can we do here? callback will faile, that's about it DbgPrint("ArapSetModemParms: RasGetDevConfig failed with %ld\n",dwErr); return; } pRasDevCfg = (RAS_DEVCONFIG *)LOCAL_ALLOC(LPTR,dwBlobSize); if (pRasDevCfg == NULL) { // what else can we do here? callback will faile, that's about it DbgPrint("ArapSetModemParms: alloc failed\n"); return; } dwErr = RasGetDevConfig(NULL, pDeviceObj->hPort,"modem",(PBYTE)pRasDevCfg,&dwBlobSize); if (dwErr != 0) { // what else can we do here? callback will faile, that's about it DbgPrint("ArapSetModemParms: RasGetDevConfig failed with %ld\n",dwErr); LOCAL_FREE((PBYTE)pRasDevCfg); return; } pDevCfg = (DEVCFG *) ((PBYTE) pRasDevCfg + pRasDevCfg->dwOffsetofModemSettings); pModemSettings = (MODEMSETTINGS* )(((PBYTE)&pDevCfg->commconfig) + pDevCfg->commconfig.dwProviderOffset); // // is this routine called to turn the compression and errorcontrol off? // if (TurnItOff) { // // turn error-control and compression off if it's on // pModemSettings->dwPreferredModemOptions &= ~(MDM_COMPRESSION | MDM_ERROR_CONTROL); } // // no, it's called to turn it back on: just do it // else { pModemSettings->dwPreferredModemOptions |= (MDM_COMPRESSION | MDM_ERROR_CONTROL); } RasSetDevConfig(pDeviceObj->hPort,"modem",(PBYTE)pRasDevCfg,dwBlobSize); LOCAL_FREE((PBYTE)pRasDevCfg); }