RASHOST.CPP
/////////////////////////////////////////////////////////////////////////////// 
// 
//  File Name  
//      RASHOST.CPP 
// 
//  Description 
//      This file contains the initialization functions for the DLL library 
//      and for the Security Host protocol. The NT RAS manager will call into 
//      our DLL when a dialing user needs to be validated. 
// 
//  Author 
//      Irving De la Cruz 
// 
//  Revision: 1.1 
// 
// Written for Microsoft Developer Support 
// Copyright 1995 - 1998 Microsoft Corporation. All rights reserved. 
// 
#include "RASHOST.H" 
 
HINSTANCE                       ghLibHandle = NULL; 
RASSECURITYDIALOGSENDPROC       gpfnSendProc = NULL; 
RASSECURITYDIALOGRECEIVEPROC    gpfnReceiveProc = NULL; 
 
/////////////////////////////////////////////////////////////////////////////// 
//    LibMain() 
// 
//    Parameters 
//      { Refer to the Win32 SDK documentation for DLL entry points } 
// 
//    Purpose 
//      Entry point of this DLL 
// 
//    Return Value 
//      TRUE if the DLL should proceed with the dwReason case, FALSE otherwise. 
// 
BOOL APIENTRY LibMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved) 
{ 
    if (DLL_PROCESS_DETACH == dwReason && ghLibHandle) 
    { 
        FreeLibrary (ghLibHandle); 
    } 
    return TRUE; 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
//    RasSecurityDialogBegin() 
// 
//    Parameters 
//      hPort       Handle to the COM port where the user is logging in 
//                  (A RAS handle, not a standard handle) 
//      pSendBuf    Pointer to a buffer where we can copy stuff to be sent 
//                  over the wire 
//      SendBufSize Size of the outgoing buffer 
//      pRecvBuf    Pointer a buffer where stuff is received from the 
//                  remote client machine 
//      RecvBufSize Size of the incoming buffer 
//      RasSecurityDialogComplete   Pointer to a callback function we must 
//                  call after we have completed our validation, indicating 
//                  the RAS manager weather or not we granted access to the 
//                  caller. 
// 
//    Purpose 
//      This is the entry point for our security DLL. When the RAS manager 
//      receives a call from a user, after it does its user validation, it 
//      will call into us at this entry point to allow us to do extra 
//      validation. 
//      NOTE: It is very important that this function does not BLOCK. If 
//            it does, the RAS manager will be block and no other calls 
//            will be accepted. That is why we copy the incoming 
//            parameters into a private structure and then spawn a thread 
//            to do the actual validation work. 
//            The passed parameters will be valid until we call the 
//            ending function. 
// 
//    Return Value 
//      ERROR_SUCCESS is we were able to start the validation. Otherwise 
//      return and error from WINERROR.H or RASERROR.H 
// 
DWORD WINAPI RasSecurityDialogBegin (HPORT hPort, 
                                     PBYTE pSendBuf, 
                                     DWORD SendBufSize, 
                                     PBYTE pRecvBuf, 
                                     DWORD RecvBufSize, 
                                     VOID  (WINAPI *RasSecurityDialogComplete)(SECURITY_MESSAGE*)) 
{ 
    // Initialize the global pointer to the entry points in the RAS manager 
    // DLL. I use these entry points to send and receive data to the remote 
    // client machine. These functions will send and receive RAW buffers of 
    // data to the other machine just before PPP-framing starts. 
    // These functions have not been exported in any publish import library 
    // so we must do a dynamic binding to them. 
    if (NULL == ghLibHandle) 
    { 
        ghLibHandle = LoadLibrary ("RASMAN.DLL"); 
        if (NULL == ghLibHandle) 
        { 
            return ERROR_DLL_NOT_FOUND; 
        } 
    } 
    // Obtain the send and received entry points from the RAS manager DLL. 
    if (NULL == gpfnSendProc) 
    { 
        gpfnSendProc = (RASSECURITYDIALOGSENDPROC)GetProcAddress (ghLibHandle, TEXT("RasSecurityDialogSend")); 
        if (NULL == gpfnSendProc) 
        { 
            return ERROR_PROC_NOT_FOUND; 
        } 
    } 
    if (NULL == gpfnReceiveProc) 
    { 
        gpfnReceiveProc = (RASSECURITYDIALOGRECEIVEPROC)GetProcAddress (ghLibHandle, TEXT("RasSecurityDialogReceive")); 
        if (NULL == gpfnReceiveProc) 
        { 
            return ERROR_PROC_NOT_FOUND; 
        } 
    } 
     
    // Save the parameters passed and give them to the working thread 
    // that will handle the authentication of the caller. The thread 
    // should release this memory. 
    // The parameters passed to use should be valid until we call the 
    // dialog end function or until we get call in the termination 
    // dialog entry point by the RAS system supervisor (the RAS manager) 
    PWORK_THREAD_DATA pCallData = (PWORK_THREAD_DATA)HeapAlloc (GetProcessHeap(), 
                                                                HEAP_ZERO_MEMORY, 
                                                                sizeof(WORK_THREAD_DATA)); 
    if (NULL == pCallData) 
    { 
        return ERROR_OUTOFMEMORY; 
    } 
    // Initialize the members. 
    pCallData->hPort = hPort; 
    pCallData->pSendBuf = pSendBuf; 
    pCallData->SendBufSize = SendBufSize; 
    pCallData->pRecvBuf = pRecvBuf; 
    pCallData->RecvBufSize = RecvBufSize; 
    pCallData->pfnSecurityDialogEnd = RasSecurityDialogComplete; 
 
    // For each call, spawn a working thread that will make the neccesary 
    // authentication of the dial-up caller. We should never block the call 
    // to RasSecurityDialogBegin(). If we do so, RAS will also block and no 
    // more call would be accepted. 
    DWORD dwThreadID; 
    HANDLE hThread = CreateThread (NULL, 
                                   0, 
                                   (LPTHREAD_START_ROUTINE)CallWorkerThread, 
                                   (LPVOID)pCallData, 
                                   0, 
                                   &dwThreadID); 
    if (NULL == hThread) 
    { 
        // Call GetLastError() before calling HeapFree(). 
        DWORD dwError = GetLastError(); 
        HeapFree (GetProcessHeap(), 0, pCallData); 
        return dwError; 
    } 
    return ERROR_SUCCESS; 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
//    RasSecurityDialogEnd() 
// 
//    Parameters 
//      hPort   Handle to the COM port (A RAS handle, not a standard handle) 
// 
//    Purpose 
//      Stub function. Need to export this by the security DLL even if 
//      not needed. We need to return non-zero to indicate RAS we are no 
//      longer responsible for the port connection. It will take care 
//      of the rest. 
// 
//    Return Value 
//      ERROR_PORT_DISCONNECTED always 
// 
DWORD WINAPI RasSecurityDialogEnd (HPORT hPort) 
{ 
    return ERROR_PORT_DISCONNECTED; 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
//    CallWorkerThread() 
// 
//    Parameters 
//      pCallData   Pointer to the data structure with the data for the 
//                  instance we are handling. 
// 
//    Purpose 
//      This is the function for the thread that interacts with a dialing RAS 
//      user. Here we query the user for its identity and based on it we 
//      compute a challenge to for it. Once the response from the client 
//      is received, we validate it and decide wether or not we allow access. 
// 
//    Return Value 
//      None 
// 
void WINAPI CallWorkerThread (PWORK_THREAD_DATA pCallData) 
{ 
    // Initialize the appropiate structures 
    SECURITY_MESSAGE smResult = { 0 }; 
    smResult.hPort = pCallData->hPort; 
    lstrcpy (smResult.UserName, TEXT("(RASHOST - Unknown)")); 
 
    DWORD dwBytes = pCallData->RecvBufSize; 
    ZeroMemory (pCallData->pRecvBuf, dwBytes); 
    dwBytes = sizeof(RASHOST_DATA); 
 
    // Initialize the structure that we'll send to the caller 
    RASHOST_DATA HostData = { 0 }; 
    HostData.dwSize = sizeof(RASHOST_DATA); 
     
    // Create an event to wait for client responses 
    HANDLE hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); 
 
    // We must copy the data from the structure to the buffer RAS 
    // manager uses to transmit the information. This buffer 
    // cannot be larger than 1500 bytes 
    CopyMemory (pCallData->pSendBuf, &HostData, sizeof(RASHOST_DATA)); 
    DWORD dwError = 0; 
 
    gpfnSendProc (pCallData->hPort, 
                  pCallData->pSendBuf, 
                  (WORD)sizeof(RASHOST_DATA)); 
 
    // Wait for an answer from the client responder 
    gpfnReceiveProc (pCallData->hPort, 
                     pCallData->pRecvBuf, 
                     (WORD *)&dwBytes, 
                     0, 
                     hEvent); 
    DWORD dwWait; 
    dwWait = WaitForSingleObject (hEvent, CLIENT_RESPONSE_TIMEOUT); 
    if (WAIT_OBJECT_0 != dwWait) 
    { 
        dwError = ERROR_SMM_TIMEOUT; 
        goto ErrorExit; 
    } 
 
    // Copy the client data from the incoming buffer to the data structure 
    CopyMemory (&HostData, pCallData->pRecvBuf, sizeof(RASHOST_DATA)); 
     
    // Save this information for RAS authentication with the NT RAS manager. 
    // The user name must be the same as the one in the NT account database 
    // on the domain where the user is granted access. 
    lstrcpy (smResult.UserName, HostData.szUserName); 
    lstrcpy (smResult.Domain, HostData.szUserDomain); 
 
    //lstrcpy (smResult.UserName, "IrvingD"); 
 
    BOOL fAccessGranted; // Weather or not access was granted 
    // With the received client response, validate the access for the client 
    dwError = ValidateCallingUser (&HostData, &fAccessGranted); 
    if (dwError) 
    { 
        goto ErrorExit; 
    } 
     
    if (fAccessGranted) 
    { 
        // Access has been granted 
        smResult.dwMsgId = SECURITYMSG_SUCCESS; 
    } 
    else 
    { 
        // The caller did not respond correctly 
        smResult.dwMsgId = SECURITYMSG_FAILURE; 
    } 
 
ErrorExit: 
    if (dwError) 
    { 
        // There was an error, deny access. 
        if (ERROR_SMM_TIMEOUT == dwError) 
        { 
            smResult.dwMsgId = SECURITYMSG_FAILURE; 
        } 
        else 
        { 
            smResult.dwMsgId = SECURITYMSG_ERROR; 
            smResult.dwError = dwError; 
        } 
    } 
    // Release the synchronization objects 
    CloseHandle (hEvent); 
    // Tell the RAS manager we are finished by calling the END dialog funcition. 
    pCallData->pfnSecurityDialogEnd (&smResult); 
    // Free the memory of this call instance before exiting the thread 
    HeapFree (GetProcessHeap(), 0, pCallData); 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
//    ValidateCallingUser() 
// 
//    Parameters 
//      pData               Pointer to the host data structure 
//      pfAccessGranted     We return TRUE here is access is granted. 
//                          FALSE otherwise. 
// 
//    Purpose 
//      Here we validate the answer to the challenge sent to the client. 
// 
//    Return Value 
//      ERROR_SUCCESS if successful. Otherwiser an error code from WINERROR.H 
//      or RASERROR.H 
// 
DWORD WINAPI ValidateCallingUser (PRASHOST_DATA       pData, 
                                  BOOL *              pfAccessGranted) 
{ 
    DWORD dwResult = ERROR_SUCCESS; 
    *pfAccessGranted = FALSE; 
     
    // Do stuff here 
 
    return dwResult; 
} 
 
// End of file for RASHOST.CPP