home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / netds / ras / winnt / rashost / rashost.cpp < prev    next >
C/C++ Source or Header  |  1997-10-05  |  12KB  |  318 lines

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. //  File Name 
  4. //      RASHOST.CPP
  5. //
  6. //  Description
  7. //      This file contains the initialization functions for the DLL library
  8. //      and for the Security Host protocol. The NT RAS manager will call into
  9. //      our DLL when a dialing user needs to be validated.
  10. //
  11. //  Author
  12. //      Irving De la Cruz
  13. //
  14. //  Revision: 1.1
  15. //
  16. // Written for Microsoft Developer Support
  17. // Copyright (c) 1995-1997 Microsoft Corporation. All rights reserved.
  18. //
  19. #include "RASHOST.H"
  20.  
  21. HINSTANCE                       ghLibHandle = NULL;
  22. RASSECURITYDIALOGSENDPROC       gpfnSendProc = NULL;
  23. RASSECURITYDIALOGRECEIVEPROC    gpfnReceiveProc = NULL;
  24.  
  25. ///////////////////////////////////////////////////////////////////////////////
  26. //    LibMain()
  27. //
  28. //    Parameters
  29. //      { Refer to the Win32 SDK documentation for DLL entry points }
  30. //
  31. //    Purpose
  32. //      Entry point of this DLL
  33. //
  34. //    Return Value
  35. //      TRUE if the DLL should proceed with the dwReason case, FALSE otherwise.
  36. //
  37. BOOL APIENTRY LibMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved)
  38. {
  39.     if (DLL_PROCESS_DETACH == dwReason && ghLibHandle)
  40.     {
  41.         FreeLibrary (ghLibHandle);
  42.     }
  43.     return TRUE;
  44. }
  45.  
  46. ///////////////////////////////////////////////////////////////////////////////
  47. //    RasSecurityDialogBegin()
  48. //
  49. //    Parameters
  50. //      hPort       Handle to the COM port where the user is logging in
  51. //                  (A RAS handle, not a standard handle)
  52. //      pSendBuf    Pointer to a buffer where we can copy stuff to be sent
  53. //                  over the wire
  54. //      SendBufSize Size of the outgoing buffer
  55. //      pRecvBuf    Pointer a buffer where stuff is received from the
  56. //                  remote client machine
  57. //      RecvBufSize Size of the incoming buffer
  58. //      RasSecurityDialogComplete   Pointer to a callback function we must
  59. //                  call after we have completed our validation, indicating
  60. //                  the RAS manager weather or not we granted access to the
  61. //                  caller.
  62. //
  63. //    Purpose
  64. //      This is the entry point for our security DLL. When the RAS manager
  65. //      receives a call from a user, after it does its user validation, it
  66. //      will call into us at this entry point to allow us to do extra
  67. //      validation.
  68. //      NOTE: It is very important that this function does not BLOCK. If
  69. //            it does, the RAS manager will be block and no other calls
  70. //            will be accepted. That is why we copy the incoming
  71. //            parameters into a private structure and then spawn a thread
  72. //            to do the actual validation work.
  73. //            The passed parameters will be valid until we call the
  74. //            ending function.
  75. //
  76. //    Return Value
  77. //      ERROR_SUCCESS is we were able to start the validation. Otherwise
  78. //      return and error from WINERROR.H or RASERROR.H
  79. //
  80. DWORD WINAPI RasSecurityDialogBegin (HPORT hPort,
  81.                                      PBYTE pSendBuf,
  82.                                      DWORD SendBufSize,
  83.                                      PBYTE pRecvBuf,
  84.                                      DWORD RecvBufSize,
  85.                                      VOID  (WINAPI *RasSecurityDialogComplete)(SECURITY_MESSAGE*))
  86. {
  87.     // Initialize the global pointer to the entry points in the RAS manager
  88.     // DLL. I use these entry points to send and receive data to the remote
  89.     // client machine. These functions will send and receive RAW buffers of
  90.     // data to the other machine just before PPP-framing starts.
  91.     // These functions have not been exported in any publish import library
  92.     // so we must do a dynamic binding to them.
  93.     if (NULL == ghLibHandle)
  94.     {
  95.         ghLibHandle = LoadLibrary ("RASMAN.DLL");
  96.         if (NULL == ghLibHandle)
  97.         {
  98.             return ERROR_DLL_NOT_FOUND;
  99.         }
  100.     }
  101.     // Obtain the send and received entry points from the RAS manager DLL.
  102.     if (NULL == gpfnSendProc)
  103.     {
  104.         gpfnSendProc = (RASSECURITYDIALOGSENDPROC)GetProcAddress (ghLibHandle, TEXT("RasSecurityDialogSend"));
  105.         if (NULL == gpfnSendProc)
  106.         {
  107.             return ERROR_PROC_NOT_FOUND;
  108.         }
  109.     }
  110.     if (NULL == gpfnReceiveProc)
  111.     {
  112.         gpfnReceiveProc = (RASSECURITYDIALOGRECEIVEPROC)GetProcAddress (ghLibHandle, TEXT("RasSecurityDialogReceive"));
  113.         if (NULL == gpfnReceiveProc)
  114.         {
  115.             return ERROR_PROC_NOT_FOUND;
  116.         }
  117.     }
  118.     
  119.     // Save the parameters passed and give them to the working thread
  120.     // that will handle the authentication of the caller. The thread
  121.     // should release this memory.
  122.     // The parameters passed to use should be valid until we call the
  123.     // dialog end function or until we get call in the termination
  124.     // dialog entry point by the RAS system supervisor (the RAS manager)
  125.     PWORK_THREAD_DATA pCallData = (PWORK_THREAD_DATA)HeapAlloc (GetProcessHeap(),
  126.                                                                 HEAP_ZERO_MEMORY,
  127.                                                                 sizeof(WORK_THREAD_DATA));
  128.     if (NULL == pCallData)
  129.     {
  130.         return ERROR_OUTOFMEMORY;
  131.     }
  132.     // Initialize the members.
  133.     pCallData->hPort = hPort;
  134.     pCallData->pSendBuf = pSendBuf;
  135.     pCallData->SendBufSize = SendBufSize;
  136.     pCallData->pRecvBuf = pRecvBuf;
  137.     pCallData->RecvBufSize = RecvBufSize;
  138.     pCallData->pfnSecurityDialogEnd = RasSecurityDialogComplete;
  139.  
  140.     // For each call, spawn a working thread that will make the neccesary
  141.     // authentication of the dial-up caller. We should never block the call
  142.     // to RasSecurityDialogBegin(). If we do so, RAS will also block and no
  143.     // more call would be accepted.
  144.     DWORD dwThreadID;
  145.     HANDLE hThread = CreateThread (NULL,
  146.                                    0,
  147.                                    (LPTHREAD_START_ROUTINE)CallWorkerThread,
  148.                                    (LPVOID)pCallData,
  149.                                    0,
  150.                                    &dwThreadID);
  151.     if (NULL == hThread)
  152.     {
  153.         // Call GetLastError() before calling HeapFree().
  154.         DWORD dwError = GetLastError();
  155.         HeapFree (GetProcessHeap(), 0, pCallData);
  156.         return dwError;
  157.     }
  158.     return ERROR_SUCCESS;
  159. }
  160.  
  161. ///////////////////////////////////////////////////////////////////////////////
  162. //    RasSecurityDialogEnd()
  163. //
  164. //    Parameters
  165. //      hPort   Handle to the COM port (A RAS handle, not a standard handle)
  166. //
  167. //    Purpose
  168. //      Stub function. Need to export this by the security DLL even if
  169. //      not needed. We need to return non-zero to indicate RAS we are no
  170. //      longer responsible for the port connection. It will take care
  171. //      of the rest.
  172. //
  173. //    Return Value
  174. //      ERROR_PORT_DISCONNECTED always
  175. //
  176. DWORD WINAPI RasSecurityDialogEnd (HPORT hPort)
  177. {
  178.     return ERROR_PORT_DISCONNECTED;
  179. }
  180.  
  181. ///////////////////////////////////////////////////////////////////////////////
  182. //    CallWorkerThread()
  183. //
  184. //    Parameters
  185. //      pCallData   Pointer to the data structure with the data for the
  186. //                  instance we are handling.
  187. //
  188. //    Purpose
  189. //      This is the function for the thread that interacts with a dialing RAS
  190. //      user. Here we query the user for its identity and based on it we
  191. //      compute a challenge to for it. Once the response from the client
  192. //      is received, we validate it and decide wether or not we allow access.
  193. //
  194. //    Return Value
  195. //      None
  196. //
  197. void WINAPI CallWorkerThread (PWORK_THREAD_DATA pCallData)
  198. {
  199.     // Initialize the appropiate structures
  200.     SECURITY_MESSAGE smResult = { 0 };
  201.     smResult.hPort = pCallData->hPort;
  202.     lstrcpy (smResult.UserName, TEXT("(RASHOST - Unknown)"));
  203.  
  204.     DWORD dwBytes = pCallData->RecvBufSize;
  205.     ZeroMemory (pCallData->pRecvBuf, dwBytes);
  206.     dwBytes = sizeof(RASHOST_DATA);
  207.  
  208.     // Initialize the structure that we'll send to the caller
  209.     RASHOST_DATA HostData = { 0 };
  210.     HostData.dwSize = sizeof(RASHOST_DATA);
  211.     
  212.     // Create an event to wait for client responses
  213.     HANDLE hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
  214.  
  215.     // We must copy the data from the structure to the buffer RAS
  216.     // manager uses to transmit the information. This buffer
  217.     // cannot be larger than 1500 bytes
  218.     CopyMemory (pCallData->pSendBuf, &HostData, sizeof(RASHOST_DATA));
  219.     DWORD dwError = 0;
  220.  
  221.     gpfnSendProc (pCallData->hPort,
  222.                   pCallData->pSendBuf,
  223.                   (WORD)sizeof(RASHOST_DATA));
  224.  
  225.     // Wait for an answer from the client responder
  226.     gpfnReceiveProc (pCallData->hPort,
  227.                      pCallData->pRecvBuf,
  228.                      (WORD *)&dwBytes,
  229.                      0,
  230.                      hEvent);
  231.     DWORD dwWait;
  232.     dwWait = WaitForSingleObject (hEvent, CLIENT_RESPONSE_TIMEOUT);
  233.     if (WAIT_OBJECT_0 != dwWait)
  234.     {
  235.         dwError = ERROR_SMM_TIMEOUT;
  236.         goto ErrorExit;
  237.     }
  238.  
  239.     // Copy the client data from the incoming buffer to the data structure
  240.     CopyMemory (&HostData, pCallData->pRecvBuf, sizeof(RASHOST_DATA));
  241.     
  242.     // Save this information for RAS authentication with the NT RAS manager.
  243.     // The user name must be the same as the one in the NT account database
  244.     // on the domain where the user is granted access.
  245.     lstrcpy (smResult.UserName, HostData.szUserName);
  246.     lstrcpy (smResult.Domain, HostData.szUserDomain);
  247.  
  248.     //lstrcpy (smResult.UserName, "IrvingD");
  249.  
  250.     BOOL fAccessGranted; // Weather or not access was granted
  251.     // With the received client response, validate the access for the client
  252.     dwError = ValidateCallingUser (&HostData, &fAccessGranted);
  253.     if (dwError)
  254.     {
  255.         goto ErrorExit;
  256.     }
  257.     
  258.     if (fAccessGranted)
  259.     {
  260.         // Access has been granted
  261.         smResult.dwMsgId = SECURITYMSG_SUCCESS;
  262.     }
  263.     else
  264.     {
  265.         // The caller did not respond correctly
  266.         smResult.dwMsgId = SECURITYMSG_FAILURE;
  267.     }
  268.  
  269. ErrorExit:
  270.     if (dwError)
  271.     {
  272.         // There was an error, deny access.
  273.         if (ERROR_SMM_TIMEOUT == dwError)
  274.         {
  275.             smResult.dwMsgId = SECURITYMSG_FAILURE;
  276.         }
  277.         else
  278.         {
  279.             smResult.dwMsgId = SECURITYMSG_ERROR;
  280.             smResult.dwError = dwError;
  281.         }
  282.     }
  283.     // Release the synchronization objects
  284.     CloseHandle (hEvent);
  285.     // Tell the RAS manager we are finished by calling the END dialog funcition.
  286.     pCallData->pfnSecurityDialogEnd (&smResult);
  287.     // Free the memory of this call instance before exiting the thread
  288.     HeapFree (GetProcessHeap(), 0, pCallData);
  289. }
  290.  
  291. ///////////////////////////////////////////////////////////////////////////////
  292. //    ValidateCallingUser()
  293. //
  294. //    Parameters
  295. //      pData               Pointer to the host data structure
  296. //      pfAccessGranted     We return TRUE here is access is granted.
  297. //                          FALSE otherwise.
  298. //
  299. //    Purpose
  300. //      Here we validate the answer to the challenge sent to the client.
  301. //
  302. //    Return Value
  303. //      ERROR_SUCCESS if successful. Otherwiser an error code from WINERROR.H
  304. //      or RASERROR.H
  305. //
  306. DWORD WINAPI ValidateCallingUser (PRASHOST_DATA       pData,
  307.                                   BOOL *              pfAccessGranted)
  308. {
  309.     DWORD dwResult = ERROR_SUCCESS;
  310.     *pfAccessGranted = FALSE;
  311.     
  312.     // Do stuff here
  313.  
  314.     return dwResult;
  315. }
  316.  
  317. // End of file for RASHOST.CPP
  318.