home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / netds / sna / aremote / server.c < prev    next >
C/C++ Source or Header  |  1997-04-09  |  43KB  |  1,459 lines

  1. /*
  2. Copyright (c) 1994, 1993 Microsoft Corporation
  3.  
  4. Module Name:
  5.     Server.c
  6.  
  7. Abstract:
  8.     The server component of Remote. It spawns a child process
  9.     and redirects the stdin/stdout/stderr of child to itself.
  10.     Waits for connections from clients - passing the
  11.     output of child process to client and the input from clients
  12.     to child process.
  13.  
  14. Author:
  15.     Rajivendra Nath (rajnath) 2-Jan-1993
  16.  
  17. Environment:
  18.     Console App. User mode.
  19.  
  20. Revision History:
  21.     Alex Wetmore (t-alexwe) 6-Jun-1994
  22.         - converted remote to use APPC with Windows SNA Server instead of named
  23.           pipes
  24.         - converted to use Unicode
  25. */
  26.  
  27. #include <windows.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <io.h>
  31. #include <string.h>
  32. #include <winappc.h>
  33. #include "appclib.h"
  34. #include "aremote.h"
  35.  
  36. #define COMMANDFORMAT       TEXT("%c%-15s    [%-15s %d:%d]\n%c")
  37. #define RemoteInfo(prt,flg) {if (!(flg&0x80000000)) prt;}
  38.  
  39. #define CMDSTRING(OutBuff,InpBuff,Client,sTime) \
  40.         {                                \
  41.             /* int xxlen; */             \
  42.             wsprintf                      \
  43.             (                            \
  44.                &OutBuff[0],COMMANDFORMAT,\
  45.                BEGINMARK,InpBuff,        \
  46.                Client->Name,sTime.wHour, \
  47.                sTime.wMinute,ENDMARK     \
  48.             );                           \
  49.          }
  50.  
  51. #define BUFFSIZE      1024
  52.  
  53. SESSION_TYPE ClientList[MAX_SESSION];
  54.  
  55. HANDLE  ChildStdInp;     //Server Writes to  it
  56. HANDLE  ChildStdOut;     //Server Reads from it
  57. HANDLE  ChildStdErr;     //Server Reads from it
  58.  
  59. HANDLE  SaveFile;       //File containing all that was
  60.                         //output by child process.
  61.                         //Each connection opens a handle to this file
  62.                         //and is sent through PipeWriteH.
  63.  
  64. TCHAR   SaveFileName[64]; //Name of above file - all new sessions need
  65. HANDLE  ChldProc;         //Handle to the Child Process
  66. HANDLE  ListenThreadH;    //Handle to the thread listening for connections
  67.                           //from Remote Clients.
  68. extern     BOOL AutoStarted;        // true if this is an autostarted service
  69.  
  70. CRITICAL_SECTION    close_crit;    // critical section for closing
  71.  
  72. HANDLE
  73. ForkChildProcess(          // Creates a new process
  74.     TCHAR *cmd,             // Redirects its stdin,stdout
  75.     PHANDLE in,            // and stderr - returns the
  76.     PHANDLE out,           // corresponding pipe ends. Using currently
  77.     PHANDLE err
  78.     );
  79.  
  80. DWORD WINAPI
  81. ListenForSession(          //THREAD:Listens for new connections and
  82.     TCHAR* pipe             //spawns of new seesions - Updates the
  83.     );                     //Status in Client DataStructure. Seperate Thread.
  84.  
  85. //
  86. // threads for dealing with local session (only when non-autostarted)
  87. DWORD WINAPI LocalSession(SESSION_TYPE *cli);
  88. DWORD WINAPI StdoutThread(SESSION_TYPE *cli);
  89. DWORD WINAPI StdinThread(SESSION_TYPE *cli);
  90.  
  91. BOOL
  92. CreateMySecurityDescriptor(                    //
  93.     PSECURITY_DESCRIPTOR pSecurityDescriptor,  // Creates a security descriptor
  94.     TCHAR *Owner                                // with discretionary access for
  95.     );                                         // access for Owner.
  96.  
  97.  
  98. DWORD
  99. NewSession(                //Manages the session with a client.
  100.     SESSION_TYPE* Client
  101.     );
  102.  
  103. DWORD WINAPI               //2 THREAD:Each reads either
  104. GetChldOutput(             //StdOut or StdErr of child and
  105.     HANDLE rhandle         //writes to SaveFile. Seperate Thread.
  106.     );
  107.  
  108. DWORD WINAPI
  109. TransferFileToClient(      //X THREADS:Reads the save
  110.     SESSION_TYPE* Client   //file and sendsoutput to a client. Seperate Thread
  111.     );
  112.  
  113.  
  114. DWORD WINAPI
  115. GetClientInput(            //Times X THREADS:Gets input from Child pipe
  116.     SESSION_TYPE* Client   //and sends to childs StdIn. Seperate Thread.
  117.     );
  118.  
  119.  
  120. BOOL
  121. FilterCommand(             //Filters input from client
  122.     SESSION_TYPE *cl,      //for commands intended for REMOTE
  123.     TCHAR *buff,
  124.     int dread
  125.     );
  126.  
  127. DWORD WINAPI               // Manages the IO with Remote Client.
  128. RemoteSession(
  129.     SESSION_TYPE* Client
  130.     );
  131.  
  132. BOOL                       // Ctrl-C handler
  133. SrvCtrlHand(
  134.     DWORD event
  135.     );
  136.  
  137. VOID                       // @s command to remote
  138. SendStatus(
  139.     tpconvid_t tpconv
  140.     );
  141.  
  142. DWORD WINAPI               // @p command to remote
  143. ShowPopup(
  144.     TCHAR *mssg
  145.     );
  146.  
  147. VOID                       // Removes the command begin and end markers
  148. RemoveInpMark(             // from the save file.
  149.     char* Buff,
  150.     DWORD Size
  151.     );
  152.  
  153. VOID                       // Cleans up the session
  154. CloseClient(               // once it ends.
  155.     SESSION_TYPE *Client
  156.     );
  157.                            // Initialises the Client datastructs
  158. VOID
  159. InitClientList(
  160.     );
  161.  
  162.  
  163. /*************************************************************/
  164. /* The main entry point for the Server End of Remote         */
  165. /*************************************************************/
  166. VOID Server(TCHAR* ChildCmd, TCHAR *tp_name) {
  167.     DWORD  ThreadID ;
  168.     HANDLE WaitH[3], objs[MAX_SESSION];
  169.     DWORD  WaitObj;
  170.     TCHAR  tmpdir[32];
  171.     int    i, active;
  172.  
  173.     WRITEF((VBuff, TEXT("**************************************\n")));
  174.     WRITEF((VBuff, TEXT("***********     REMOTE    ************\n")));
  175.     WRITEF((VBuff, TEXT("***********     SERVER    ************\n")));
  176.     WRITEF((VBuff, TEXT("**************************************\n")));
  177.  
  178.     InitClientList();
  179.  
  180.     appcinit();
  181.  
  182.     //
  183.     // This critical section is used around close so that only one appcclose
  184.     // is happening at a time.
  185.     //
  186.     InitializeCriticalSection(&close_crit);
  187.  
  188.     //
  189.     //Start the command as a child process
  190.     //
  191.  
  192.     ChldProc=ForkChildProcess(ChildCmd,&ChildStdInp,&ChildStdOut,&ChildStdErr);
  193.  
  194.     //
  195.     //Create a tempfile for storing Child process output.
  196.     //
  197.     {
  198.          DWORD size=sizeof(tmpdir);
  199.          if (
  200.              (GetEnvironmentVariable(TEXT("TMP"),tmpdir,size)==0)&&
  201.              (GetEnvironmentVariable(TEXT("TEMP"),tmpdir,size)==0)
  202.             )
  203.          {
  204.             wsprintf(tmpdir,TEXT("%ws"),TEXT("."));
  205.          }
  206.          if (!GetTempFileName(tmpdir,TEXT("REMOTE"),0,SaveFileName))
  207.             GetTempFileName(TEXT("."),TEXT("REMOTE"),0,SaveFileName);
  208.     }
  209.  
  210.  
  211.     if ((SaveFile=CreateFile
  212.                   (
  213.                      (LPCTSTR)SaveFileName,           /* address of name of the file  */
  214.                      GENERIC_READ|GENERIC_WRITE,      /* access (read/write) mode */
  215.                      FILE_SHARE_READ|FILE_SHARE_WRITE,/* share mode   */
  216.                      (LPSECURITY_ATTRIBUTES)NULL,     /* security descriptor  */
  217.                      CREATE_ALWAYS,                   /* how to create    */
  218.                      FILE_ATTRIBUTE_NORMAL,           /* File Attribute */
  219.                      (HANDLE)NULL)
  220.                   )==NULL)
  221.     {
  222.         TerminateProcess(ChldProc,0);
  223.         ErrorExit(TEXT("Could not Create Output File"));
  224.     }
  225.  
  226.  
  227.     //
  228.     //Start 2 threads to save the output from stdout and stderr of cmd to savefile.
  229.     //
  230.  
  231.     if ((WaitH[0]=CreateThread
  232.                   (
  233.                      (LPSECURITY_ATTRIBUTES)NULL,           // No security attributes.
  234.                      (DWORD)0,                              // Use same stack size.
  235.                      (LPTHREAD_START_ROUTINE)GetChldOutput, // Thread procedure.
  236.                      (LPVOID)ChildStdErr,                   // Parameter to pass.
  237.                      (DWORD)0,                              // Run immediately.
  238.                      (LPDWORD)&ThreadID)
  239.                    )==NULL)
  240.     {
  241.  
  242.         TerminateProcess(ChldProc,0);
  243.         ErrorExit(TEXT("Failed to Create GetGhldOutput#1 Thread"));
  244.     }
  245.  
  246.  
  247.     if ((WaitH[1]=CreateThread
  248.                   (
  249.                      (LPSECURITY_ATTRIBUTES)NULL,           // No security attributes.
  250.                      (DWORD)0,                              // Use same stack size.
  251.                      (LPTHREAD_START_ROUTINE)GetChldOutput, // Thread procedure.
  252.                      (LPVOID)ChildStdOut,                   // Parameter to pass.
  253.                      (DWORD)0,                              // Run immediately.
  254.                      (LPDWORD)&ThreadID)
  255.                   )==NULL)
  256.     {
  257.  
  258.         TerminateProcess(ChldProc,0);
  259.         ErrorExit(TEXT("Failed to Create GetGhldOutput#2 Thread"));
  260.     }
  261.  
  262.  
  263.     //
  264.     // Start Thread for local session
  265.     // only run if this is not an autostarted TP
  266.     //
  267.     if (!AutoStarted) {
  268.         ClientList[0].Active = TRUE;
  269.            if ((ClientList[0].hThread = CreateThread(
  270.                       (LPSECURITY_ATTRIBUTES) NULL,       // No security attributes.
  271.                       (DWORD) 0,                          // Use same stack size.
  272.                       (LPTHREAD_START_ROUTINE) LocalSession,     // Thread procedure.
  273.                       (LPVOID) &ClientList[0],            // Parameter to pass.
  274.                       (DWORD) 0,                          // Run immediately.
  275.                       (LPDWORD) &ThreadID))==NULL) {
  276.                TerminateProcess(ChldProc,0);
  277.                ErrorExit(TEXT("Failed To Create LocalSession Thread"));
  278.            }
  279.     }
  280.  
  281.     //
  282.     //Start Thread to listen for new Connections
  283.     //
  284.  
  285.     if ((ListenThreadH=CreateThread
  286.                        (
  287.                          (LPSECURITY_ATTRIBUTES)NULL,        // No security attributes.
  288.                          (DWORD)0,                           // Use same stack size.
  289.                          (LPTHREAD_START_ROUTINE)ListenForSession, // Thread procedure.
  290.                          (LPVOID)tp_name,                    // Parameter to pass.
  291.                          (DWORD)0,                           // Run immediately.
  292.                          (LPDWORD)&ThreadID)
  293.                        )==NULL)
  294.     {
  295.  
  296.         TerminateProcess(ChldProc,0);
  297.         ErrorExit(TEXT("Failed To Create ListenForSession Thread"));
  298.  
  299.     }
  300.  
  301.     SetConsoleCtrlHandler((PHANDLER_ROUTINE)SrvCtrlHand,TRUE);
  302.  
  303.     WaitH[2]=ChldProc;
  304.  
  305.     //
  306.     // Wait until the child process terminates
  307.     // or local IO thread terminates
  308.     // or IO with child process ends
  309.     //
  310.  
  311.     WaitObj=WaitForMultipleObjects(3,WaitH,FALSE,INFINITE);
  312.  
  313.     switch (WaitObj-WAIT_OBJECT_0)
  314.     {
  315.         case 0:      // Error Writing to savefile
  316.         case 1:
  317.             TerminateProcess(ChldProc,0);
  318.             break;
  319.         case 2:      // Child Proc Terminated
  320.             break;
  321.  
  322.         default:     // Out of Some Resource
  323.             WRITEF((VBuff,
  324.                 TEXT("Out of Resource Error %d..Terminating\n"),
  325.                 GetLastError()));
  326.             break;
  327.  
  328.     }
  329.  
  330.     TerminateThread(ListenThreadH,0);
  331.  
  332.     CloseHandle(ChildStdInp);
  333.     CloseHandle(ChildStdOut);
  334.     CloseHandle(ChildStdErr);
  335.  
  336.     WRITEF((VBuff,
  337.         TEXT("\nServer: Child process \"%ws\" died, parent exiting...\n"),
  338.         ChildCmd));
  339.  
  340.     CloseHandle(SaveFile);
  341.  
  342.     // signal all of the client threads to tell them that they should die
  343.     for (i = 0, active = 0; i < MAX_SESSION; i++) {
  344.         if (ClientList[i].Active) {
  345.             SetEvent(ClientList[i].DoClose);
  346.             objs[active++] = ClientList[i].hThread;
  347.         }
  348.     }
  349.  
  350.     // Wait for all of the client to die gracefully
  351.     WaitForMultipleObjects(active, objs, TRUE, INFINITE);
  352.  
  353.     for (i = 0; i < MAX_SESSION; i++) {
  354.         if (ClientList[i].rSaveFile != INVALID_HANDLE_VALUE)
  355.             CloseHandle(ClientList[i].rSaveFile);
  356.  
  357.         if (ClientList[i].MoreData != NULL)
  358.             CloseHandle(ClientList[i].MoreData);
  359.     }
  360.  
  361.     if (!DeleteFile(SaveFileName))
  362.           WRITEF((VBuff,TEXT("Temp File %ws not deleted..\n"),SaveFileName));
  363.  
  364.     appcdestroy();
  365.  
  366.     return;
  367. }
  368.  
  369. /*************************************************************/
  370. /* Creates the child process and redirects its std.IO handles*/
  371. /*************************************************************/
  372. // these handles should be treated as if they send and receive ANSI, not Unicode
  373. HANDLE
  374. ForkChildProcess(          // Creates a new process
  375.     TCHAR *cmd,             // Redirects its stdin,stdout
  376.     PHANDLE inH,           // and stderr - returns the
  377.     PHANDLE outH,          // corresponding pipe ends.
  378.     PHANDLE errH
  379.     )
  380. {
  381.     SECURITY_ATTRIBUTES lsa;
  382.     STARTUPINFO         si;
  383.     PROCESS_INFORMATION pi;
  384.  
  385.     HANDLE ChildIn;
  386.     HANDLE ChildOut;
  387.     HANDLE ChildErr;
  388.  
  389.     lsa.nLength=sizeof(SECURITY_ATTRIBUTES);
  390.     lsa.lpSecurityDescriptor=NULL;
  391.     lsa.bInheritHandle=TRUE;
  392.  
  393.     //
  394.     //Create Parent_Write to ChildStdIn Pipe
  395.     //
  396.  
  397.     if (!CreatePipe(&ChildIn,inH,&lsa,0))
  398.         ErrorExit(TEXT("Could Not Create Parent-->Child Pipe"));
  399.  
  400.     //
  401.     //Create ChildStdOut to Parent_Read pipe
  402.     //
  403.  
  404.     if (!CreatePipe(outH,&ChildOut,&lsa,0))
  405.         ErrorExit(TEXT("Could Not Create Child-->Parent Pipe"));
  406.  
  407.     //
  408.     //Create ChildStdOut to Parent_Read pipe
  409.     //
  410.  
  411.     if (!CreatePipe(errH,&ChildErr,&lsa,0))
  412.         ErrorExit(TEXT("Could Not Create Child-->Parent Pipe"));
  413.  
  414.     //
  415.     // Lets Redirect Console StdHandles - easy enough
  416.     //
  417.  
  418.  
  419.     si.cb=sizeof(STARTUPINFO);
  420.     si.lpReserved=NULL;
  421.     si.lpTitle=NULL;
  422.     si.lpDesktop=NULL;
  423.     si.dwX=si.dwY=si.dwYSize=si.dwXSize=0;
  424.     si.dwFlags=STARTF_USESTDHANDLES;
  425.     si.hStdInput =ChildIn;
  426.     si.hStdOutput=ChildOut;
  427.     si.hStdError =ChildErr;
  428.     si.wShowWindow=SW_SHOW;
  429.     si.lpReserved2=NULL;
  430.     si.cbReserved2=0;
  431.  
  432.     //
  433.     //Create Child Process
  434.     //
  435.  
  436.     if (!CreateProcess
  437.          (
  438.             NULL,
  439.             cmd,
  440.             NULL,
  441.             NULL,
  442.             TRUE,
  443.             NORMAL_PRIORITY_CLASS,
  444.             NULL,
  445.             NULL,
  446.             &si,
  447.             &pi)
  448.          )
  449.     {
  450.         if (GetLastError()==2)
  451.             WRITEF((VBuff,TEXT("Executable %ws not found\n"),cmd));
  452.         ErrorExit(TEXT("Could Not Create Child Process"));
  453.     }
  454.  
  455.     //
  456.     //Close unneccesary Handles and Restore the crt handles
  457.     //
  458.  
  459.     CloseHandle(ChildIn);
  460.     CloseHandle(ChildOut);
  461.     CloseHandle(ChildErr);
  462.  
  463.     return(pi.hProcess);
  464. }
  465.  
  466. /*************************************************************/
  467. /* Listens for sessions from Clients and creates a new thread*/
  468. /* for each client                                           */
  469. /*************************************************************/
  470.  
  471. DWORD WINAPI ListenForSession(TCHAR* tp_name) {
  472.     int    i;
  473.     DWORD  ThreadID;
  474.     tpconvid_t tpconv;
  475.     HANDLE TokenHandle;
  476.     TOKEN_DEFAULT_DACL DefaultDacl;
  477.  
  478.     WRITEF((VBuff, TEXT("\nServer: Waiting for clients on TP: %ws\n\n"), tp_name));
  479.  
  480.     DefaultDacl.DefaultDacl = NULL;
  481.  
  482.     if (OpenProcessToken
  483.         (
  484.             GetCurrentProcess(),
  485.             TOKEN_ADJUST_DEFAULT,
  486.             &TokenHandle
  487.         ))
  488.     {
  489.  
  490.         //
  491.         // Remove the default DACL on the token
  492.         //
  493.  
  494.         SetTokenInformation
  495.         (
  496.             TokenHandle,
  497.             TokenDefaultDacl,
  498.             &DefaultDacl,
  499.             sizeof( TOKEN_DEFAULT_DACL )
  500.         );
  501.  
  502.     }
  503.  
  504.     while(TRUE) {
  505.         tpconv = appclisten(tp_name);
  506.  
  507.         //
  508.         // Look For a Free Slot
  509.         // There is guaranteed to be one or appclisten wouldn't have run.
  510.         //
  511.  
  512.         for (i = 0; i < MAX_SESSION; i++) {
  513.             //
  514.             // Locate a Free Client block
  515.             //
  516.             if (!ClientList[i].Active) break;
  517.         }
  518.  
  519.         // check to see if we couldn't find a free session
  520.         if (i == MAX_SESSION) {
  521.             WRITEF((VBuff, TEXT("\nServer: Client tried to connect with all sessions in use\n")));
  522.             appcclose(tpconv);
  523.             continue;
  524.         } else {
  525.             appcwrite(tpconv, REMOTE_INIT_MSG,
  526.                 lstrlen(REMOTE_INIT_MSG) * sizeof(TCHAR));
  527.         }
  528.  
  529.         //
  530.         // Initialize the Client
  531.         //
  532.         ClientList[i].tpconv = tpconv;
  533.         ClientList[i].Active = TRUE;
  534.         ClientList[i].SendOutput = TRUE;
  535.         ClientList[i].CommandRcvd = FALSE;
  536.  
  537.         //
  538.         //start new thread for this connection
  539.         //
  540.  
  541.         if((ClientList[i].hThread=CreateThread
  542.             (
  543.                  (LPSECURITY_ATTRIBUTES)NULL,        // No security attributes.
  544.                  (DWORD)0,                           // Use same stack size.
  545.                  (LPTHREAD_START_ROUTINE)RemoteSession, // Thread procedure.
  546.                  (LPVOID)&ClientList[i],             // Parameter to pass.
  547.                  (DWORD)0,                           // Run immediately.
  548.                  (LPDWORD)&ThreadID)
  549.             )==NULL)
  550.         {
  551.             CloseClient(&ClientList[i]);
  552.             continue;
  553.         }
  554.  
  555.     }
  556.     return(0);
  557. }
  558.  
  559. /*************************************************************/
  560. /* Creates a security descriptor with the discrtionry access */
  561. /* for the account specified in the /U switch  if any        */
  562. /*************************************************************/
  563.  
  564. BOOL
  565. CreateMySecurityDescriptor(
  566.     PSECURITY_DESCRIPTOR pSecurityDescriptor,
  567.     TCHAR *Owner
  568.     )
  569. {
  570.     PSID pOwnerSid;
  571.     PACL pAcl;
  572.     BOOL Ret=FALSE;
  573.  
  574.     //
  575.     // Initialize the Security Descriptor struct.
  576.     //
  577.  
  578.  
  579.     InitializeSecurityDescriptor
  580.     (
  581.         pSecurityDescriptor,
  582.         SECURITY_DESCRIPTOR_REVISION
  583.     );
  584.  
  585.     if (Owner==NULL)
  586.     {
  587.         //
  588.         // No security required.
  589.         //
  590.  
  591.         SetSecurityDescriptorDacl
  592.         (
  593.                pSecurityDescriptor,
  594.                TRUE,
  595.                NULL,
  596.                FALSE
  597.         );
  598.  
  599.         return TRUE;
  600.     }
  601.  
  602.     {
  603.         //
  604.         // Get the SID for the account/Group
  605.         //
  606.  
  607.         DWORD len1=1024,len2=1024;
  608.         TCHAR RefDomain[1024];
  609.         SID_NAME_USE snu=0;        //don't care
  610.  
  611.         if ((pOwnerSid=(PSID)LocalAlloc(LMEM_FIXED, len1))==NULL)
  612.             return FALSE;
  613.  
  614.  
  615.         Ret=
  616.         LookupAccountName
  617.         (
  618.             NULL,
  619.             Owner,
  620.             pOwnerSid,
  621.             &len1,
  622.             RefDomain,
  623.             &len2,
  624.             &snu
  625.         );
  626.  
  627.         if (!Ret)
  628.         {
  629.             LocalFree(pOwnerSid);
  630.             return FALSE;
  631.         }
  632.  
  633.     }
  634.  
  635.     {
  636.  
  637.         //
  638.         // Create the access control list with access for
  639.         // the SID obtained above.
  640.         //
  641.  
  642.         DWORD aclsize=sizeof(ACL)+
  643.                       sizeof(ACCESS_ALLOWED_ACE)+
  644.                       GetLengthSid(pOwnerSid)-
  645.                       sizeof(DWORD);
  646.  
  647.         if ((pAcl=(PACL)LocalAlloc(LMEM_FIXED,aclsize))==NULL)
  648.         {
  649.             LocalFree(pOwnerSid);
  650.             return FALSE;
  651.         }
  652.  
  653.         //
  654.         // Initialize the acl buffer
  655.         //
  656.  
  657.         Ret=
  658.         InitializeAcl
  659.         (
  660.             pAcl,
  661.             aclsize,
  662.             ACL_REVISION
  663.         );
  664.  
  665.         if (!Ret)
  666.         {
  667.             LocalFree(pOwnerSid);
  668.             LocalFree(pAcl);
  669.             return FALSE;
  670.         }
  671.  
  672.         //
  673.         // Add the sid to the access allowed part in ACL
  674.         //
  675.  
  676.         Ret=
  677.         AddAccessAllowedAce
  678.         (
  679.             pAcl,
  680.             ACL_REVISION,
  681.             GENERIC_ALL,
  682.             pOwnerSid
  683.         );
  684.  
  685.         if (!Ret)
  686.         {
  687.             LocalFree(pOwnerSid);
  688.             LocalFree(pAcl);
  689.             return FALSE;
  690.         }
  691.     }
  692.  
  693.     //
  694.     // Add the created ACL to the discreationary control list
  695.     //
  696.  
  697.     Ret=
  698.     SetSecurityDescriptorDacl
  699.     (
  700.         pSecurityDescriptor,
  701.         TRUE,
  702.         pAcl,
  703.         FALSE
  704.     );
  705.  
  706.     if (!Ret)
  707.     {
  708.         LocalFree(pOwnerSid);
  709.         LocalFree(pAcl);
  710.         return FALSE;
  711.     }
  712.     return TRUE;
  713. }
  714.  
  715. /*************************************************************/
  716. /* Manages the Session with a Client - Creates a thread for  */
  717. /* Inputs from the client and a thread for sending outputs to*/
  718. /* the client. Could have just as easily done with 1 thread  */
  719. /* using Asyn IO.                                            */
  720. /*************************************************************/
  721. DWORD WINAPI RemoteSession(SESSION_TYPE         *MyClient) {
  722.     SESSION_STARTUPINFO  ssi;
  723.     DWORD                tmp;
  724.     SESSION_STARTREPLY   ssr;
  725.     SYSTEMTIME           st;
  726.  
  727.     GetLocalTime(&st);
  728.     memset((TCHAR *)&ssi,0,sizeof(ssi));
  729.  
  730.     //
  731.     // Open a new handle to the save file ...
  732.     // contains the saved output from the child process
  733.     // and the commands already given to it.
  734.     //
  735.  
  736.     if ((MyClient->rSaveFile=CreateFile
  737.         (
  738.             SaveFileName,
  739.             GENERIC_READ|GENERIC_WRITE,
  740.             FILE_SHARE_READ|FILE_SHARE_WRITE,
  741.             NULL,OPEN_EXISTING,
  742.             FILE_ATTRIBUTE_NORMAL,NULL)
  743.         )==NULL)
  744.  
  745.     {
  746.         CloseClient(MyClient);
  747.         return(1);
  748.     }
  749.  
  750.     //
  751.     // Exchange Remote Information with Client.
  752.     //
  753.     appcread(MyClient->tpconv, (void *) &ssi, sizeof(ssi));
  754.     wcscpy(MyClient->Name, ssi.ClientName);
  755.     MyClient->Name[15] = 0;
  756.  
  757.     ssr.FileSize = GetFileSize(MyClient->rSaveFile, &tmp);
  758.     ssr.MagicNumber = MAGICNUMBER;
  759.  
  760.     appcwrite(MyClient->tpconv, (void *) &ssr, sizeof(ssr));
  761.  
  762.     /* Lines  */
  763.     if (ssi.LinesToSend!=-1)
  764.     {
  765.         long  PosFromEnd=ssi.LinesToSend*CHARS_PER_LINE;
  766.         DWORD BytesToSend=MINIMUM((DWORD)PosFromEnd,ssr.FileSize);
  767.         DWORD BytesRead, usize;
  768.         char *abuff=(char *)LocalAlloc(LMEM_FIXED,(BytesToSend+1)*sizeof(char));
  769.         TCHAR *ubuff=(TCHAR *)LocalAlloc(0, (BytesToSend+1)*sizeof(TCHAR));
  770.  
  771.         if (ssr.FileSize > (DWORD)PosFromEnd)
  772.         {
  773.             SetFilePointer(
  774.                             MyClient->rSaveFile,
  775.                             -PosFromEnd,
  776.                             (PLONG)NULL,
  777.                             FILE_END
  778.                           );
  779.         }
  780.  
  781.         if (abuff!=NULL && ubuff!=NULL)
  782.         {
  783.             if (!ReadFile(MyClient->rSaveFile,abuff,BytesToSend,&BytesRead,NULL))
  784.             {
  785.                 CloseClient(MyClient);
  786.                 return(1);
  787.             }
  788.  
  789.             // Don't want the markers to be part of the output display
  790.             // at the client end.
  791.             RemoveInpMark(abuff, BytesRead);
  792.  
  793.             // convert to wbs
  794.             usize = mbstowcs(ubuff, abuff, BytesRead);
  795.  
  796.             appcwrite(MyClient->tpconv, (void *) ubuff, usize * sizeof(TCHAR));
  797.         }
  798.         LocalFree(abuff);
  799.         LocalFree(ubuff);
  800.  
  801.     }
  802.  
  803.     RemoteInfo(WRITEF((VBuff, TEXT("\nServer: Connected To %ws [%02d:%02d]\n"),MyClient->Name,st.wHour,st.wMinute)),ssi.Flag);
  804.  
  805.     //
  806.     // Start off the new session.
  807.     //
  808.     NewSession(MyClient);
  809.  
  810.     RemoteInfo(WRITEF((VBuff, TEXT("\nServer: Disconnected From %ws [%02d:%02d]\n"),MyClient->Name,st.wHour,st.wMinute)),ssi.Flag);
  811.  
  812.     LocalFree(MyClient->tpconv);
  813.  
  814.     return(0);
  815. }
  816.  
  817. //
  818. // LocalSession: creates a session for use by the local terminal
  819. //
  820. // argument is ignored
  821. //
  822. DWORD WINAPI LocalSession(SESSION_TYPE *cli) {
  823.     BOOL        done = FALSE;
  824.     HANDLE        rthread, wthread;
  825.     DWORD        tid;
  826.     SYSTEMTIME  st;
  827.  
  828.     GetLocalTime(&st);
  829.  
  830.     cli->Active = TRUE;
  831.     cli->tpconv = NULL;
  832.     cli->SendOutput = TRUE;
  833.     lstrcpy(cli->Name, TEXT("Local"));
  834.  
  835.     if ((cli->rSaveFile=CreateFile(SaveFileName,
  836.             GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
  837.             NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL))==NULL) {
  838.         cli->Active = FALSE;
  839.         return 0;
  840.     }
  841.  
  842.     cli->MoreData = CreateEvent(
  843.         (LPSECURITY_ATTRIBUTES) NULL, /* address of security attributes    */
  844.         FALSE,                          /* flag for manual-reset event    */
  845.         TRUE,                          /* flag for initial state            */
  846.         NULL                          /* address of event-object name    */
  847.     );
  848.  
  849.     cli->DoClose = CreateEvent(
  850.         (LPSECURITY_ATTRIBUTES) NULL,    // no security on event
  851.         FALSE,                            // auto reset event mode
  852.         FALSE,                            // initially false
  853.         NULL);                            // unnamed object
  854.  
  855.     WRITEF((VBuff, TEXT("\nServer: Connected To %ws [%02d:%02d]\n"),cli->Name,st.wHour,st.wMinute));
  856.  
  857.     if ((wthread = CreateThread(NULL,                // no security attributes
  858.             0,                                        // use same stack size
  859.             (LPTHREAD_START_ROUTINE) StdinThread,    // function to run
  860.             cli,                                    // pass client info
  861.             0,                                        // run now
  862.             &tid)) == NULL) {                        // return thread id
  863.         ExitThread(0);
  864.     }
  865.  
  866.     if ((rthread = CreateThread(NULL,                // no security attributes
  867.             0,                                        // use same stack size
  868.             (LPTHREAD_START_ROUTINE) StdoutThread,    // function to run
  869.             cli,                                    // pass client info
  870.             0,                                        // run now
  871.             &tid)) == NULL) {                        // return thread id
  872.         ExitThread(0);
  873.     }
  874.     
  875.     WaitForSingleObject(cli->DoClose, INFINITE);
  876.  
  877.     TerminateThread(rthread, 0);
  878.     TerminateThread(wthread, 0);
  879.  
  880.     cli->Active = FALSE;
  881.     CloseHandle(cli->DoClose);
  882.     CloseHandle(cli->MoreData);
  883.     CloseHandle(cli->rSaveFile);
  884.     CloseHandle(stdin);
  885.     CloseHandle(stdout);
  886.  
  887.     WRITEF((VBuff, TEXT("\nServer: Disconnected From %ws [%02d:%02d]\n"),cli->Name,st.wHour,st.wMinute));
  888.  
  889.     return 0;
  890. }
  891.  
  892. DWORD WINAPI StdinThread(SESSION_TYPE *cli) {
  893.     HANDLE    Stdin;
  894.     TCHAR    ubuf[BUFFSIZE];
  895.     char    abuf[BUFFSIZE];
  896.     DWORD    tmp, dread, asize;
  897.  
  898.     Stdin = GetStdHandle(STD_INPUT_HANDLE);
  899.     // read a command from the user into a buffer (it will be in Unicode)
  900.     while (ReadConsole(Stdin, ubuf, BUFFSIZE - 1, &dread, NULL)) {
  901.         cli->CommandRcvd = TRUE;
  902.         ubuf[dread] = 0;
  903.         // see if it is a valid command
  904.         if (!FilterCommand(cli, ubuf, dread)) {
  905.             // convert the buffer from Unicode to ANSI
  906.             asize = wcstombs(abuf, ubuf, BUFFSIZE);
  907.  
  908.             // write the buffer to the child's pipe
  909.             if (!WriteFile(ChildStdInp, abuf, asize, &tmp, NULL))
  910.                 ExitThread(0);
  911.         }
  912.     }
  913.     return 0;
  914. }
  915.  
  916. DWORD WINAPI StdoutThread(SESSION_TYPE *cli) {
  917.     HANDLE    Stdout;
  918.     char    abuffin[BUFFSIZE];
  919.     TCHAR   buffin[BUFFSIZE], buffout[BUFFSIZE], cmdbuff[BUFFSIZE];
  920.     DWORD      aread, dread=0, dwrite=0, tmp, cmdP = 0, i;
  921.     BOOL       incmd=FALSE;
  922.     TCHAR   MyEchoStr[30];
  923.  
  924.     wsprintf(MyEchoStr,TEXT("[%-15s"),cli->Name);
  925.  
  926.     Stdout = GetStdHandle(STD_OUTPUT_HANDLE);
  927.  
  928.     // read a buffer from an ansi file (the buffer will be ANSI)
  929.     while (ReadFile(cli->rSaveFile, abuffin, BUFFSIZE-1, &aread, NULL)) {
  930.         if (aread == 0) {
  931.             // wait for more data to arrive and loop again
  932.             WaitForSingleObject(cli->MoreData, INFINITE);
  933.             continue;
  934.         }
  935.  
  936.         abuffin[aread] = 0;
  937.         dread = mbstowcs(buffin, abuffin, BUFFSIZE);
  938.  
  939.         dwrite=0;
  940.  
  941.         //
  942.         // This is all to insure that the commands entered
  943.         // by clients are not echoed back to them.
  944.         // A Beginmark and an Endmark is placed around commands
  945.         // sent to the child process from some client.
  946.         //
  947.  
  948.         for (i = 0; i < dread; i++) {
  949.             if (incmd) {
  950.                 if ((buffin[i] == ENDMARK) || (cmdP == BUFFSIZE - 1)) {
  951.                     incmd = FALSE;
  952.                     cmdbuff[cmdP] = 0;
  953.                     if ((wcsstr(cmdbuff, MyEchoStr) == NULL) ||
  954.                         (!cli->CommandRcvd)) {
  955.                         WriteConsole(Stdout, cmdbuff, dread, &tmp, NULL);
  956.                     }
  957.                     cmdP=0;
  958.                 } else {
  959.                     cmdbuff[cmdP++] = buffin[i];
  960.                 }
  961.             } else {
  962.                 if (buffin[i] == BEGINMARK) {
  963.                     if (dwrite != 0) {
  964.                         WriteConsole(Stdout, buffout, dread, &tmp, NULL);
  965.                         dwrite = 0;
  966.                     }
  967.                     incmd = TRUE;
  968.                     continue;
  969.                 } else {
  970.                     buffout[dwrite++] = buffin[i];
  971.                 }
  972.             }
  973.         }
  974.  
  975.         if (dwrite != 0) {
  976.             WriteConsole(Stdout, buffout, dread, &tmp, NULL);
  977.         }
  978.     }
  979.  
  980.     return 0;
  981. }
  982.  
  983. DWORD NewSession(SESSION_TYPE* MyClient) {
  984.     DWORD     ThreadId;
  985.     HANDLE  rThread, wThread;
  986.  
  987.     MyClient->MoreData = CreateEvent(
  988.         (LPSECURITY_ATTRIBUTES) NULL, /* address of security attributes    */
  989.         FALSE,                          /* flag for manual-reset event    */
  990.         TRUE,                          /* flag for initial state            */
  991.         NULL                          /* address of event-object name    */
  992.     );
  993.  
  994.     MyClient->DoClose = CreateEvent(
  995.         (LPSECURITY_ATTRIBUTES) NULL,    // no security on event
  996.         FALSE,                            // flag for manual-reset event
  997.         FALSE,                            // initially false
  998.         NULL);                            // unnamed object
  999.  
  1000.     if ((rThread = CreateThread(
  1001.             (LPSECURITY_ATTRIBUTES) NULL,         // No security attributes.
  1002.             (DWORD) 0,                            // Use same stack size.
  1003.             (LPTHREAD_START_ROUTINE) GetClientInput,
  1004.             (LPVOID) MyClient,                    // Parameter to pass.
  1005.             (DWORD) 0,                            // Run immediately.
  1006.             (LPDWORD) &ThreadId))==NULL) {
  1007.         return(GetLastError());
  1008.     }
  1009.  
  1010.  
  1011.     if ((wThread=CreateThread(
  1012.             (LPSECURITY_ATTRIBUTES) NULL,        // No security attributes.
  1013.             (DWORD) 0,                           // Use same stack size.
  1014.             (LPTHREAD_START_ROUTINE) TransferFileToClient,
  1015.             (LPVOID) MyClient,                   // Parameter to pass.
  1016.             (DWORD) 0,                           // Run immediately.
  1017.             (LPDWORD) &ThreadId))==NULL) {
  1018.         CloseHandle(rThread);
  1019.         return(GetLastError());
  1020.     }
  1021.  
  1022.     // Wait for the input thread to terminate.  when it does the session is
  1023.     // over.
  1024.     ThreadId = WaitForSingleObject(wThread, INFINITE);
  1025.  
  1026.     CloseClient(MyClient);
  1027.  
  1028.     ThreadId = WaitForSingleObject(rThread, INFINITE);
  1029.  
  1030.     // close the thread handles
  1031.     CloseHandle(rThread);
  1032.     CloseHandle(wThread);
  1033.  
  1034.     return 0;
  1035. }
  1036.  
  1037. /*************************************************************/
  1038. /* Saves the output from the child process into the savefile */
  1039. /* All the remote client thread and local client thread      */
  1040. /* open a seperate handle to this and output its content     */
  1041. /* sequentially.                                             */
  1042. /*************************************************************/
  1043. DWORD WINAPI GetChldOutput(HANDLE readH) {
  1044.     TCHAR      buff[BUFFSIZE];
  1045.     DWORD     dread;
  1046.     DWORD     tmp;
  1047.     int        i;
  1048.  
  1049.  
  1050.     while (ReadFile(readH,buff,BUFFSIZE-1,&dread,NULL)) {
  1051.         buff[dread]=TEXT('\0');
  1052.  
  1053.         if (!WriteFile(SaveFile,buff,dread,&tmp,NULL))
  1054.             return(1);
  1055.  
  1056.         //
  1057.         // Signal Reader Thread that more data is available
  1058.         //
  1059.         for (i=0;i<MAX_SESSION;i++)
  1060.             if (ClientList[i].Active) SetEvent(ClientList[i].MoreData);
  1061.     }
  1062.     return 1;
  1063. }
  1064.  
  1065. /*************************************************************/
  1066. /* A thread for each client connection and one for local IO  */
  1067. /* Reads the contents of Save file and sends it to client for*/
  1068. /* display.                                                  */
  1069. /*************************************************************/
  1070. DWORD WINAPI TransferFileToClient(SESSION_TYPE *MyClient) {
  1071.     TCHAR   buffin[BUFFSIZE], buffout[BUFFSIZE], cmdbuff[BUFFSIZE];
  1072.     char    abuffin[BUFFSIZE];
  1073.     DWORD      dread=0,dwrite=0,aread;
  1074.     BOOL       incmd=FALSE;
  1075.     DWORD      cmdP=0;
  1076.     DWORD      i;
  1077.     TCHAR       MyEchoStr[30];
  1078.     HANDLE    objs[2];
  1079.     DWORD     which;
  1080.  
  1081.     wsprintf(MyEchoStr,TEXT("[%-15s"),MyClient->Name);
  1082.  
  1083.     while (ReadFile(MyClient->rSaveFile, abuffin, BUFFSIZE-1, &aread, NULL)) {
  1084.         if (aread == 0) {
  1085.             //
  1086.             // Event is set by GetChldOutput() func. to signal
  1087.             // More data is available in save file.
  1088.             //
  1089.             objs[0] = MyClient->MoreData;
  1090.             objs[1] = MyClient->DoClose;
  1091.  
  1092.             // wait for moredata or a close request
  1093.             which = WaitForMultipleObjects(2, objs, FALSE, INFINITE);
  1094.             which = which - WAIT_OBJECT_0;
  1095.  
  1096.             if (which == 0) {
  1097.                 // there is more data waiting
  1098.                 continue;
  1099.             } else {
  1100.                 // they want us to close
  1101.                 return 0;
  1102.             }
  1103.         }
  1104.  
  1105.         dread = mbstowcs(buffin, abuffin, aread);
  1106.  
  1107.         dwrite=0;
  1108.  
  1109.         //
  1110.         // This is all to insure that the commands entered
  1111.         // by clients are not echoed back to them.
  1112.         // A Beginmark and an Endmark is placed around commands
  1113.         // sent to the child process from some client.
  1114.         //
  1115.  
  1116.         for (i = 0; i < dread; i++) {
  1117.             if (incmd) {
  1118.                 if ((buffin[i] == ENDMARK) || (cmdP == BUFFSIZE - 1)) {
  1119.                     incmd = FALSE;
  1120.                     cmdbuff[cmdP] = 0;
  1121.                     if ((wcsstr(cmdbuff, MyEchoStr) == NULL) ||
  1122.                         (!MyClient->CommandRcvd)) {
  1123.                         appcwrite(MyClient->tpconv, (void *) cmdbuff,
  1124.                             cmdP * sizeof(TCHAR));
  1125.                     }
  1126.                     cmdP=0;
  1127.                 } else {
  1128.                     cmdbuff[cmdP++] = buffin[i];
  1129.                 }
  1130.             } else {
  1131.                 if (buffin[i] == BEGINMARK) {
  1132.                     if (dwrite != 0) {
  1133.                         appcwrite(MyClient->tpconv, (void *) buffout,
  1134.                             dwrite * sizeof(TCHAR));
  1135.                         dwrite = 0;
  1136.                     }
  1137.                     incmd = TRUE;
  1138.                     continue;
  1139.                 } else {
  1140.                     buffout[dwrite++] = buffin[i];
  1141.                 }
  1142.             }
  1143.         }
  1144.  
  1145.         if (dwrite != 0) {
  1146.             appcwrite(MyClient->tpconv, (void *) buffout,
  1147.                 dwrite * sizeof(TCHAR));
  1148.         }
  1149.     }
  1150.     return 0;
  1151. }
  1152.  
  1153. /*************************************************************/
  1154. /* Commands from the clients are sent to the child process   */
  1155. /* and also saved in the SaveFile with Begin and End markers */
  1156. /* around them to seperate them from the output from child   */
  1157. /* process.                                                  */
  1158. /*************************************************************/
  1159. DWORD WINAPI GetClientInput(SESSION_TYPE *MyClient) {
  1160.     TCHAR ubuff[BUFFSIZE];
  1161.     char  abuff[BUFFSIZE];
  1162.     DWORD tmp,uread,aread;
  1163.  
  1164.     while (TRUE) {
  1165.         uread = appcread(MyClient->tpconv, (void *) ubuff, BUFFSIZE) /
  1166.             sizeof(TCHAR);
  1167.         if (!appcvalid(MyClient->tpconv)) break;
  1168.  
  1169.         MyClient->CommandRcvd = TRUE;
  1170.  
  1171.         if (FilterCommand(MyClient, ubuff, uread)) continue;
  1172.  
  1173.         aread = wcstombs(abuff, ubuff, uread);
  1174.  
  1175.         if (!WriteFile(ChildStdInp, abuff, aread, &tmp, NULL)) ExitThread(0);
  1176.     }
  1177.  
  1178.     return(1);
  1179. }
  1180.  
  1181. /*************************************************************/
  1182. /* If a client command is intended for the Remote server -   */
  1183. /* those beginning with COMMANDCHAR (are not intended        */
  1184. /* for the child process) - they are executed here           */
  1185. /* and the output sent to the client.                        */
  1186. /*************************************************************/
  1187. BOOL FilterCommand(SESSION_TYPE *cl, TCHAR *buff, int dread) {
  1188.     SYSTEMTIME st;
  1189.     TCHAR       inp_buff[4096];
  1190.     TCHAR       tmpchar;
  1191.     TCHAR       ch[3];
  1192.     DWORD      tmp;
  1193.     int        len;
  1194.     DWORD      ThreadID; //Useless
  1195.  
  1196.     if (dread==0)
  1197.         return(FALSE);
  1198.  
  1199.     buff[dread]=0;
  1200.  
  1201.     GetLocalTime(&st);
  1202.  
  1203.     if (buff[0]==COMMANDCHAR) {
  1204.         switch(tolower(buff[1])) {
  1205.             case TEXT('o'):
  1206.                 cl->SendOutput=!cl->SendOutput;
  1207.                 break;
  1208.  
  1209.             case TEXT('k'):
  1210.                 TerminateProcess(ChldProc,1);
  1211.                 break;
  1212.  
  1213.             case TEXT('q'):
  1214.                 SetEvent(cl->DoClose);
  1215.                 break;
  1216.  
  1217.             case TEXT('s'):
  1218.                 SendStatus(cl->tpconv);
  1219.                 break;
  1220.  
  1221.             case TEXT('p'):
  1222.                 if (cl->tpconv == NULL) break;
  1223.                 {
  1224.                      //Free it in called Proc    
  1225.                     TCHAR *mssg=(TCHAR *)LocalAlloc(0, 4096*sizeof(TCHAR));
  1226.                         TCHAR  *ack=TEXT("Server: Popup Shown..\n");
  1227.  
  1228.                     if (mssg==NULL)
  1229.                         break;
  1230.  
  1231.                     wsprintf(mssg,TEXT("From %ws [%d:%d]\n\n%ws\n"),cl->Name,st.wHour,st.wMinute,&buff[2]);
  1232.                     CreateThread(
  1233.                           (LPSECURITY_ATTRIBUTES)NULL,         // No security attributes.
  1234.                           (DWORD)0,              // Use same stack size.
  1235.                           (LPTHREAD_START_ROUTINE)ShowPopup, // Thread procedure.
  1236.                           (LPVOID)mssg,          // Parameter to pass.
  1237.                           (DWORD)0,              // Run immediately.
  1238.                           (LPDWORD)&ThreadID
  1239.                          );
  1240.                     appcwrite(cl->tpconv, (void *) ack, lstrlen(ack) *
  1241.                         sizeof(TCHAR));
  1242.                     break;
  1243.                  }
  1244.  
  1245.             case TEXT('m'):
  1246.                 buff[dread-2]=0;
  1247.                 CMDSTRING(inp_buff,buff,cl,st);
  1248.                 len=lstrlen(inp_buff);
  1249.                 WriteFile(SaveFile,inp_buff,len,&tmp,NULL);
  1250.                 break;
  1251.  
  1252.             case TEXT('@'):
  1253.                 buff[dread-2]=0;
  1254.                 CMDSTRING(inp_buff,&buff[1],cl,st);
  1255.                 len=lstrlen(inp_buff);
  1256.                 WriteFile(SaveFile,inp_buff,len,&tmp,NULL);
  1257.                 //
  1258.                 // Remove the first @ sign
  1259.                 //
  1260.                 MoveMemory(buff,&buff[1],dread-1);
  1261.                 buff[dread-1]=TEXT(' ');
  1262.                 return(FALSE); //Send it it to the chile process
  1263.                 break;
  1264.  
  1265.  
  1266.             default :
  1267.                 if (cl->tpconv == NULL) break;
  1268.                 lstrcpy(inp_buff, TEXT("** Unknown Command **\n"));
  1269.                 appcwrite(cl->tpconv, (void *) inp_buff,
  1270.                     lstrlen(inp_buff) * sizeof(TCHAR));
  1271.  
  1272.             case TEXT('h'):
  1273.                 if (cl->tpconv != NULL) {
  1274.                     wsprintf(inp_buff,TEXT("%cM: To Send Message\n"),COMMANDCHAR);
  1275.                     appcwrite(cl->tpconv, (void *) inp_buff, lstrlen(inp_buff) * sizeof(TCHAR));
  1276.                        wsprintf(inp_buff,TEXT("%cP: To Generate popup\n"),COMMANDCHAR);
  1277.                     appcwrite(cl->tpconv, (void *) inp_buff, lstrlen(inp_buff) * sizeof(TCHAR));
  1278.                        wsprintf(inp_buff,TEXT("%cK: To kill the server\n"),COMMANDCHAR);
  1279.                     appcwrite(cl->tpconv, (void *) inp_buff, lstrlen(inp_buff) * sizeof(TCHAR));
  1280.                        wsprintf(inp_buff,TEXT("%cH: This Help\n"),COMMANDCHAR);
  1281.                     appcwrite(cl->tpconv, (void *) inp_buff, lstrlen(inp_buff) * sizeof(TCHAR));
  1282.                 }
  1283.                 break;
  1284.         }
  1285.         return(TRUE);
  1286.     }
  1287.  
  1288.  
  1289.     if ((buff[0]<26)) {
  1290.         BOOL ret=FALSE;
  1291.  
  1292.         wsprintf(ch,TEXT("^%c"),buff[0]+64);
  1293. //        CMDSTRING(inp_buff,ch,cl,st);
  1294.         len=lstrlen(inp_buff);
  1295.  
  1296.         if (buff[0]==CTRLC)
  1297.         {
  1298.             cl->CommandRcvd=FALSE;
  1299.             GenerateConsoleCtrlEvent(CTRL_C_EVENT,0);
  1300.             ret=TRUE; //Already sent to child
  1301.         }
  1302.  
  1303.         WriteFile(SaveFile,inp_buff,len,&tmp,NULL);
  1304.         return(ret); //FALSE:send it to child StdIn
  1305.     }
  1306.  
  1307.     tmpchar=buff[dread-2]; //must be 13;but just incase
  1308.     buff[dread-2]=0;
  1309. //    CMDSTRING(inp_buff,buff,cl,st);
  1310.     buff[dread-2]=tmpchar;
  1311.     len=lstrlen(inp_buff);
  1312.     WriteFile(SaveFile,inp_buff,len,&tmp,NULL);
  1313.     return(FALSE);
  1314. }
  1315.  
  1316. /*************************************************************/
  1317. VOID SendStatus(tpconvid_t tpconv) {
  1318.     TCHAR  buff[1024];
  1319.     int   i;
  1320.     TCHAR  *env=(TCHAR *)GetEnvironmentStrings();
  1321.     DWORD ver=GetVersion();
  1322.  
  1323.     if (tpconv == NULL) return;
  1324.  
  1325.     wsprintf(buff,TEXT("Command = %ws\n"), ChildCmd);
  1326.     appcwrite(tpconv, (void *) buff, lstrlen(buff) * sizeof(TCHAR));
  1327.  
  1328.     wsprintf(buff,TEXT("Build = %d \n"),((WORD *)&ver)[1]);
  1329.     appcwrite(tpconv, (void *) buff, lstrlen(buff) * sizeof(TCHAR));
  1330.  
  1331.     for (i=1;i<MAX_SESSION;i++)
  1332.     {
  1333.         if (ClientList[i].Active)
  1334.         {
  1335.             wsprintf(buff,TEXT("ACTIVE SESSION=%ws\n"),ClientList[i].Name);
  1336.             appcwrite(tpconv, (void *) buff, lstrlen(buff) * sizeof(TCHAR));
  1337.         }
  1338.     }
  1339.  
  1340.     wsprintf(buff,TEXT("====================\n"));
  1341.     appcwrite(tpconv, (void *) buff, lstrlen(buff) * sizeof(TCHAR));
  1342.  
  1343.     wsprintf(buff,TEXT("ENVIRONMENT VARIABLES\n"));
  1344.     appcwrite(tpconv, (void *) buff, lstrlen(buff) * sizeof(TCHAR));
  1345.  
  1346.     wsprintf(buff,TEXT("====================\n"));
  1347.     appcwrite(tpconv, (void *) buff, lstrlen(buff) * sizeof(TCHAR));
  1348.  
  1349.  
  1350.     __try {
  1351.         while (*env!=0)
  1352.         {
  1353.             wsprintf(buff,TEXT("%ws\n"),env);
  1354.             appcwrite(tpconv, (void *) buff, lstrlen(buff) * sizeof(TCHAR));
  1355.  
  1356.             while(*(env++)!=0);
  1357.         }
  1358.     } __except(EXCEPTION_EXECUTE_HANDLER) {
  1359.         wsprintf(buff,TEXT("Exception Generated Getting Environment Block\n"),env);
  1360.         appcwrite(tpconv, (void *) buff, lstrlen(buff) * sizeof(TCHAR));
  1361.     }
  1362.  
  1363.     wsprintf(buff,TEXT("====================\n"));
  1364.     appcwrite(tpconv, (void *) buff, lstrlen(buff) * sizeof(TCHAR));
  1365.     return;
  1366. }
  1367.  
  1368. /*************************************************************/
  1369. DWORD WINAPI
  1370. ShowPopup(
  1371.     TCHAR *mssg
  1372.     )
  1373. {
  1374.     MessageBox(GetActiveWindow(),mssg,TEXT("***REMOTE***"),MB_OK|MB_SETFOREGROUND);
  1375.     LocalFree(mssg);
  1376.     return(0);
  1377. }
  1378. /*************************************************************/
  1379. BOOL SrvCtrlHand(
  1380.     DWORD event
  1381.     )
  1382. {
  1383.     if (event==CTRL_BREAK_EVENT)
  1384.     {
  1385.         TerminateProcess(ChldProc,1);
  1386.     }
  1387.     return(TRUE);
  1388. }
  1389. /*************************************************************/
  1390.  
  1391. VOID CloseClient(SESSION_TYPE *Client) {
  1392.     EnterCriticalSection(&close_crit);
  1393.  
  1394.     appcclose(Client->tpconv);
  1395.  
  1396.     if (Client->rSaveFile != INVALID_HANDLE_VALUE) {
  1397.         CloseHandle(Client->rSaveFile);
  1398.         Client->rSaveFile = INVALID_HANDLE_VALUE;
  1399.     }
  1400.  
  1401.     if (Client->MoreData != NULL) {
  1402.         CloseHandle(Client->MoreData);
  1403.         Client->MoreData = NULL;
  1404.     }
  1405.  
  1406.     Client->Active=FALSE; //Keep it last else synch problem.
  1407.  
  1408.     LeaveCriticalSection(&close_crit);
  1409.  
  1410.     return;
  1411. }
  1412.  
  1413. VOID InitClientList(VOID) {
  1414.     int i;
  1415.     for (i=0;i<MAX_SESSION;i++)
  1416.     {
  1417.         ZeroMemory(ClientList[i].Name,HOSTNAMELEN);
  1418.         ClientList[i].tpconv = NULL;
  1419.         ClientList[i].rSaveFile = INVALID_HANDLE_VALUE;
  1420.         ClientList[i].MoreData = NULL;
  1421.         ClientList[i].Active = FALSE;
  1422.         ClientList[i].CommandRcvd = FALSE;
  1423.         ClientList[i].SendOutput = FALSE;
  1424.         ClientList[i].hThread = NULL;
  1425.     }
  1426.     return;
  1427. }
  1428.  
  1429.  
  1430.  
  1431. VOID RemoveInpMark(char* Buff, DWORD Size) {
  1432.     DWORD i;
  1433.     for (i=0;i<Size;i++)
  1434.     {
  1435.         switch (Buff[i])
  1436.         {
  1437.         case BEGINMARK:
  1438.             Buff[i]=' ';
  1439.             break;
  1440.  
  1441.         case ENDMARK:
  1442.             if (i<2)
  1443.             {
  1444.                 Buff[i]= ' ';
  1445.             }
  1446.             else
  1447.             {
  1448.                 Buff[i]  =Buff[i-1];
  1449.                 Buff[i-1]=Buff[i-2];
  1450.                 Buff[i-2]=' ';
  1451.             }
  1452.             break;
  1453.  
  1454.         default:
  1455.            break;
  1456.        }
  1457.     }
  1458. }
  1459.