home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / winnt / remote / srvutil.c < prev   
C/C++ Source or Header  |  1997-10-12  |  32KB  |  1,150 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples. 
  4. *       Copyright 1995 - 1997 Microsoft Corporation.
  5. *       All rights reserved. 
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. /*++
  13.  
  14. Copyright (c) 1997  Microsoft Corporation
  15.  
  16. Module Name:
  17.  
  18.     SrvUtil.c
  19.  
  20. Abstract:
  21.  
  22.     The server component of Remote. It spawns a child process
  23.     and redirects the stdin/stdout/stderr of child to itself.
  24.     Waits for connections from clients - passing the
  25.     output of child process to client and the input from clients
  26.     to child process.
  27.  
  28. Author:
  29.  
  30.     Rajivendra Nath  2-Jan-1992
  31.     Dave Hart  30 May 1997 split from Server.c
  32.  
  33. Environment:
  34.  
  35.     Console App. User mode.
  36.  
  37. Revision History:
  38.  
  39. --*/
  40.  
  41. #include <windows.h>
  42. #include <stdio.h>
  43. #include <stdlib.h>
  44. #include <process.h>
  45. #include <io.h>
  46. #include <string.h>
  47. #include "Remote.h"
  48. #include "Server.h"
  49.  
  50.  
  51. #define COMMANDFORMAT     "%c%-20s    [%-12s %s]\n%08x%c"
  52. #define CMDSTRING(OutBuff,OutSize,InpBuff,Client,szTime,ForceShow) \
  53. {                                                                  \
  54.     char *pch;                                                     \
  55.                                                                    \
  56.     for (pch = InpBuff;                                            \
  57.          *pch;                                                     \
  58.          pch++) {                                                  \
  59.                                                                    \
  60.         if (ENDMARK == *pch ||                                     \
  61.             BEGINMARK == *pch) {                                   \
  62.                                                                    \
  63.             *pch = '`';                                            \
  64.         }                                                          \
  65.     }                                                              \
  66.                                                                    \
  67.     OutSize =                                                      \
  68.         sprintf(                                                   \
  69.             (OutBuff),                                             \
  70.             COMMANDFORMAT,                                         \
  71.             BEGINMARK,                                             \
  72.             (InpBuff),                                             \
  73.             (Client)->Name,                                        \
  74.             (szTime),                                              \
  75.             (ForceShow) ? 0 : (Client)->dwID,                      \
  76.             ENDMARK                                                \
  77.             );                                                     \
  78. }
  79.  
  80.  
  81. /*************************************************************/
  82. // GetFormattedTime -- returns pointer to formatted time
  83. //
  84. // returns pointer to static buffer, only the main thread
  85. // should use this.
  86. //
  87.  
  88. PCHAR
  89. GetFormattedTime(
  90.     BOOL bDateToo
  91.     )
  92. {
  93.     static char szTime[64];
  94.     int cch = 0;
  95.  
  96.     if (bDateToo) {
  97.  
  98.         cch =
  99.             GetDateFormat(
  100.                 LOCALE_USER_DEFAULT,
  101.                 0,
  102.                 NULL,    // current date
  103.                 "ddd",   // short day of week
  104.                 szTime,
  105.                 sizeof szTime
  106.                 );
  107.  
  108.         // cch includes null terminator, change it to
  109.         // a space to separate from time.
  110.  
  111.         szTime[ cch - 1 ] = ' ';
  112.     }
  113.  
  114.     //
  115.     // Get time and format to characters
  116.     //
  117.  
  118.     GetTimeFormat(
  119.         LOCALE_USER_DEFAULT,
  120.         TIME_NOSECONDS,
  121.         NULL,   // use current time
  122.         NULL,   // use default format
  123.         szTime + cch,
  124.         (sizeof szTime) - cch );
  125.  
  126.     return szTime;
  127. }
  128.  
  129. /*************************************************************/
  130.  
  131. BOOL
  132. FilterCommand(
  133.     REMOTE_CLIENT *cl,
  134.     char *buff,
  135.     int dread
  136.     )
  137. {
  138.     char       tmpchar;
  139.     DWORD      tmp;
  140.     int        len;
  141.     DWORD      ThreadID;
  142.     char       inp_buff[2048];
  143.     char       ch[3];
  144.  
  145.     if (dread==0)
  146.         return(FALSE);
  147.  
  148.     buff[dread]=0;
  149.  
  150.     if (buff[0]==COMMANDCHAR)
  151.     {
  152.  
  153.         switch(buff[1])
  154.         {
  155.         case 'k':
  156.         case 'K':
  157.  
  158.                 if (INVALID_HANDLE_VALUE != hWriteChildStdIn) {
  159.  
  160.                     printf("Remote: killing child softly, @K again to be more convincing.\n");
  161.  
  162.                     CANCELIO( hWriteChildStdIn );
  163.                     CloseHandle( hWriteChildStdIn );
  164.                     hWriteChildStdIn = INVALID_HANDLE_VALUE;
  165.  
  166.                     GenerateConsoleCtrlEvent(CTRL_CLOSE_EVENT, 0);
  167.                     SleepEx(200, TRUE);
  168.                     cPendingCtrlCEvents++;
  169.                     GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
  170.                     SleepEx(20, TRUE);
  171.                     GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0);
  172.  
  173.                 } else {
  174.  
  175.                     printf("Remote: Resorting to TerminateProcess.\n");
  176.  
  177.                     TerminateProcess(ChldProc, ERROR_PROCESS_ABORTED);
  178.                 }
  179.  
  180.  
  181.                  break;
  182.         case 's':
  183.         case 'S':
  184.                 CloseHandle( (HANDLE)
  185.                     _beginthreadex(
  186.                         NULL,             // security
  187.                         0,                // default stack size
  188.                         SendStatus,
  189.                         (void *) cl->PipeWriteH,
  190.                         0,                // not suspended
  191.                         &ThreadID
  192.                         ));
  193.                 break;
  194.  
  195.         case 'p':
  196.         case 'P':
  197.             {
  198.                 char  *msg;
  199.  
  200.                 msg = HeapAlloc(                    // freed by ShowPopup
  201.                           hHeap,
  202.                           HEAP_ZERO_MEMORY,
  203.                           4096
  204.                           );
  205.  
  206.  
  207.                 if ( ! msg) {
  208.                     break;
  209.                 }
  210.  
  211.                 sprintf(msg,"From %s %s [%s]\n\n%s\n",cl->Name,cl->UserName,GetFormattedTime(TRUE),&buff[2]);
  212.  
  213.                 if (WriteFileSynch(hWriteTempFile,msg,strlen(msg),&tmp,dwWriteFilePointer,&olMainThread)) {
  214.                     dwWriteFilePointer += tmp;
  215.                     StartServerToClientFlow();
  216.                 }
  217.  
  218.                 CloseHandle( (HANDLE)
  219.                     CreateThread(                              // no CRT for ShowPopup
  220.                         NULL,             // security
  221.                         0,                // default stack size
  222.                         ShowPopup,
  223.                         (void *) msg,
  224.                         0,                // not suspended
  225.                         &ThreadID
  226.                         ));
  227.  
  228.                 break;
  229.              }
  230.  
  231.         case 'm':
  232.         case 'M':
  233.                 buff[dread-2]=0;
  234.                 CMDSTRING(inp_buff,len,buff,cl,GetFormattedTime(TRUE),TRUE);
  235.  
  236.                 if (WriteFileSynch(hWriteTempFile,inp_buff,len,&tmp,dwWriteFilePointer,&olMainThread)) {
  237.                     dwWriteFilePointer += tmp;
  238.                     StartServerToClientFlow();
  239.                 }
  240.                 break;
  241.  
  242.         case '@':
  243.                 buff[dread-2]=0;
  244.                 CMDSTRING(inp_buff,len,&buff[1],cl,GetFormattedTime(FALSE),FALSE);
  245.                 if (WriteFileSynch(hWriteTempFile,inp_buff,len,&tmp,dwWriteFilePointer,&olMainThread)) {
  246.                     dwWriteFilePointer += tmp;
  247.                     StartServerToClientFlow();
  248.                 }
  249.                 //
  250.                 // Remove the first @ sign
  251.                 //
  252.                 MoveMemory(buff,&buff[1],dread-1);
  253.                 buff[dread-1]=' ';
  254.                 return(FALSE); //Send it it to the chile process
  255.  
  256.  
  257.         default :
  258.                 sprintf(inp_buff,"%s","** Unknown Command **\n");
  259.                 if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) {
  260.                     dwWriteFilePointer += tmp;
  261.                     // we do this below // StartServerToClientFlow();
  262.                 }
  263.         case 'h':
  264.         case 'H':
  265.                 sprintf(inp_buff,"%cM: To Send Message\n",COMMANDCHAR);
  266.                 if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) {
  267.                     dwWriteFilePointer += tmp;
  268.                 }
  269.                 sprintf(inp_buff,"%cP: To Generate popup\n",COMMANDCHAR);
  270.                 if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) {
  271.                     dwWriteFilePointer += tmp;
  272.                 }
  273.                 sprintf(inp_buff,"%cK: To kill the server\n",COMMANDCHAR);
  274.                 if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) {
  275.                     dwWriteFilePointer += tmp;
  276.                 }
  277.                 sprintf(inp_buff,"%cH: This Help\n",COMMANDCHAR);
  278.                 if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) {
  279.                     dwWriteFilePointer += tmp;
  280.                 }
  281.                 StartServerToClientFlow();
  282.                 break;
  283.         }
  284.         return(TRUE);
  285.     }
  286.  
  287.  
  288.     if ((buff[0]<26))
  289.     {
  290.         BOOL ret=FALSE;
  291.  
  292.         sprintf(ch, "^%c", buff[0] + 'A' - 1);
  293.  
  294.  
  295.         if (buff[0]==CTRLC)
  296.         {
  297.             // show this even to this client
  298.             CMDSTRING(inp_buff,len,ch,cl,GetFormattedTime(FALSE),TRUE);
  299.  
  300.             cPendingCtrlCEvents++;
  301.             GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
  302.             ret = TRUE;  // Already sent to child
  303.  
  304.         } else {
  305.  
  306.             CMDSTRING(inp_buff,len,ch,cl,GetFormattedTime(FALSE),FALSE);
  307.         }
  308.  
  309.         if (WriteFileSynch(hWriteTempFile,inp_buff,len,&tmp,dwWriteFilePointer,&olMainThread)) {
  310.             dwWriteFilePointer += tmp;
  311.             StartServerToClientFlow();
  312.         }
  313.         return(ret); //FALSE:send it to child StdIn
  314.     }
  315.  
  316.  
  317.     tmpchar=buff[dread-2]; //must be 13;but just incase
  318.     buff[dread-2]=0;
  319.     CMDSTRING(inp_buff,len,buff,cl,GetFormattedTime(FALSE),FALSE);
  320.     buff[dread-2]=tmpchar;
  321.     if (WriteFileSynch(hWriteTempFile,inp_buff,len,&tmp,dwWriteFilePointer,&olMainThread)) {
  322.         dwWriteFilePointer += tmp;
  323.         StartServerToClientFlow();
  324.     }
  325.     return(FALSE);
  326. }
  327.  
  328. /*************************************************************/
  329. HANDLE
  330. ForkChildProcess(           // Creates a new process
  331.     char *cmd,              // Redirects its stdin,stdout
  332.     PHANDLE inH,            // and stderr - returns the
  333.     PHANDLE outH            // corresponding pipe ends.
  334.     )
  335.  
  336. {
  337.     SECURITY_ATTRIBUTES lsa;
  338.     STARTUPINFO         si;
  339.     PROCESS_INFORMATION pi;
  340.     HANDLE ChildIn;
  341.     HANDLE ChildOut, ChildOutDup;
  342.     HANDLE hWriteChild;
  343.     HANDLE hReadChild;
  344.     BOOL Success;
  345.  
  346.     BOOL                                     // pipeex.c
  347.     APIENTRY
  348.     MyCreatePipeEx(
  349.         OUT LPHANDLE lpReadPipe,
  350.         OUT LPHANDLE lpWritePipe,
  351.         IN LPSECURITY_ATTRIBUTES lpPipeAttributes,
  352.         IN DWORD nSize,
  353.         DWORD dwReadMode,
  354.         DWORD dwWriteMode
  355.         );
  356.  
  357.  
  358.  
  359.     lsa.nLength=sizeof(SECURITY_ATTRIBUTES);
  360.     lsa.lpSecurityDescriptor=NULL;
  361.     lsa.bInheritHandle=TRUE;
  362.  
  363.     //
  364.     // Create Parent_Write to ChildStdIn Pipe.  Then
  365.     // duplicate the parent copy to a noninheritable
  366.     // handle and close the inheritable one so that
  367.     // the child won't be holding open a handle to
  368.     // the server end of its stdin pipe when we try
  369.     // to nuke that pipe to close the child.
  370.     //
  371.  
  372.     Success = MyCreatePipeEx(
  373.                   &ChildIn,
  374.                   &hWriteChild,
  375.                   &lsa,
  376.                   0,
  377.                   0,
  378.                   FILE_FLAG_OVERLAPPED) &&
  379.  
  380.               DuplicateHandle(
  381.                   GetCurrentProcess(),
  382.                   hWriteChild,
  383.                   GetCurrentProcess(),
  384.                   inH,
  385.                   0,                       // ignored b/c SAME_ACCESS
  386.                   FALSE,                   // not inheritable
  387.                   DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE
  388.                   );
  389.  
  390.     if (!Success) {
  391.         ErrorExit("Could Not Create Parent-->Child Pipe");
  392.     }
  393.  
  394.     //
  395.     //Create ChildStdOut/stderr to Parent_Read pipe
  396.     //
  397.  
  398.     Success = MyCreatePipeEx(
  399.                   &hReadChild,
  400.                   &ChildOut,
  401.                   &lsa,
  402.                   0,
  403.                   FILE_FLAG_OVERLAPPED,
  404.                   0) &&
  405.  
  406.               DuplicateHandle(
  407.                   GetCurrentProcess(),
  408.                   hReadChild,
  409.                   GetCurrentProcess(),
  410.                   outH,
  411.                   0,                       // ignored b/c SAME_ACCESS
  412.                   FALSE,                   // not inheritable
  413.                   DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE
  414.                   ) &&
  415.  
  416.               DuplicateHandle(
  417.                   GetCurrentProcess(),
  418.                   ChildOut,
  419.                   GetCurrentProcess(),
  420.                   &ChildOutDup,
  421.                   0,                       // ignored b/c SAME_ACCESS
  422.                   TRUE,                    // inheritable
  423.                   DUPLICATE_SAME_ACCESS
  424.                   );
  425.  
  426.     if (!Success) {
  427.         ErrorExit("Could Not Create Child-->Parent Pipe");
  428.     }
  429.  
  430.     ZeroMemory(&si, sizeof(si));
  431.     si.cb            = sizeof(STARTUPINFO);
  432.     si.dwFlags       = STARTF_USESTDHANDLES;
  433.     si.hStdInput     = ChildIn;
  434.     si.hStdOutput    = ChildOut;
  435.     si.hStdError     = ChildOutDup;
  436.     si.wShowWindow   = SW_SHOW;
  437.  
  438.     //
  439.     // Create Child Process
  440.     //
  441.  
  442.     if ( ! CreateProcess(
  443.                NULL,
  444.                cmd,
  445.                NULL,
  446.                NULL,
  447.                TRUE,
  448.                GetPriorityClass( GetCurrentProcess() ),
  449.                NULL,
  450.                NULL,
  451.                &si,
  452.                &pi)) {
  453.  
  454.         if (GetLastError()==2) {
  455.             printf("Executable %s not found\n",cmd);
  456.         } else {
  457.             printf("CreateProcess(%s) failed, error %d.\n", cmd, GetLastError());
  458.         }
  459.         ErrorExit("Could Not Create Child Process");
  460.     }
  461.  
  462.     //
  463.     // Close unneccesary Handles
  464.     //
  465.  
  466.     CloseHandle(ChildIn);
  467.     CloseHandle(ChildOut);
  468.     CloseHandle(ChildOutDup);
  469.     CloseHandle(pi.hThread);
  470.  
  471.     pidChild = pi.dwProcessId;
  472.  
  473.     return(pi.hProcess);
  474. }
  475.  
  476. //
  477. // SendStatus runs as its own thread, with C runtime available.
  478. //
  479.  
  480. DWORD
  481. WINAPI
  482. SendStatus(
  483.     LPVOID   lpSendStatusParm
  484.     )
  485. {
  486.     HANDLE hClientPipe = (HANDLE) lpSendStatusParm;
  487.     char *pch;
  488.     DWORD tmp;
  489.     PREMOTE_CLIENT pClient;
  490.     OVERLAPPED ol;
  491.     char  buff[2048];
  492.     char szSep[] = " ------------------------------\n";
  493.  
  494.     //
  495.     // Since we're in our own thread we need our own
  496.     // overlapped structure for our client pipe writes.
  497.     //
  498.  
  499.     ZeroMemory(&ol, sizeof(ol));
  500.  
  501.     ol.hEvent =
  502.         CreateEvent(
  503.             NULL,      // security
  504.             TRUE,      // auto-reset
  505.             FALSE,     // initially nonsignaled
  506.             NULL       // unnamed
  507.             );
  508.  
  509.  
  510.     //
  511.     // Dump the closing client list
  512.     //
  513.  
  514.     pch = buff;
  515.  
  516.     EnterCriticalSection(&csClosingClientList);
  517.  
  518.     for (pClient = (PREMOTE_CLIENT) ClosingClientListHead.Flink;
  519.          pClient != (PREMOTE_CLIENT) &ClosingClientListHead;
  520.          pClient = (PREMOTE_CLIENT) pClient->Links.Flink ) {
  521.  
  522.          if (pch + 60 > buff + sizeof(buff)) {
  523.  
  524.             break;
  525.          }
  526.  
  527.          pch += sprintf(pch, "%d: %s %s (Disconnected)\n", pClient->dwID, pClient->Name, pClient->UserName);
  528.     }
  529.  
  530.     LeaveCriticalSection(&csClosingClientList);
  531.  
  532.     WriteFileSynch(hClientPipe, buff, pch - buff, &tmp, 0, &ol);
  533.  
  534.     WriteFileSynch(hClientPipe, szSep, sizeof(szSep) - 1, &tmp, 0, &ol);
  535.  
  536.  
  537.     //
  538.     // Dump the normal client list
  539.     //
  540.  
  541.     pch = buff;
  542.  
  543.     EnterCriticalSection(&csClientList);
  544.  
  545.     for (pClient = (PREMOTE_CLIENT) ClientListHead.Flink;
  546.          pClient != (PREMOTE_CLIENT) &ClientListHead;
  547.          pClient = (PREMOTE_CLIENT) pClient->Links.Flink ) {
  548.  
  549.          if (pch + 60 > buff + sizeof(buff)) {
  550.  
  551.             break;
  552.          }
  553.  
  554.          pch += sprintf(pch, "%d: %s %s\n", pClient->dwID, pClient->Name, pClient->UserName);
  555.     }
  556.  
  557.     LeaveCriticalSection(&csClientList);
  558.  
  559.     WriteFileSynch(hClientPipe, buff, pch - buff, &tmp, 0, &ol);
  560.  
  561.     WriteFileSynch(hClientPipe, szSep, sizeof(szSep) - 1, &tmp, 0, &ol);
  562.  
  563.  
  564.  
  565.     //
  566.     // Dump the handshaking client list
  567.     //
  568.  
  569.     pch = buff;
  570.  
  571.     EnterCriticalSection(&csHandshakingList);
  572.  
  573.     for (pClient = (PREMOTE_CLIENT) HandshakingListHead.Flink;
  574.          pClient != (PREMOTE_CLIENT) &HandshakingListHead;
  575.          pClient = (PREMOTE_CLIENT) pClient->Links.Flink ) {
  576.  
  577.          if (pch + 60 > buff + sizeof(buff)) {
  578.  
  579.             break;
  580.          }
  581.  
  582.          pch += sprintf(pch, "%d: %s %s (Connecting)\n", pClient->dwID, pClient->Name, pClient->UserName);
  583.     }
  584.  
  585.     LeaveCriticalSection(&csHandshakingList);
  586.  
  587.     WriteFileSynch(hClientPipe, buff, pch - buff, &tmp, 0, &ol);
  588.  
  589.     WriteFileSynch(hClientPipe, szSep, sizeof(szSep) - 1, &tmp, 0, &ol);
  590.  
  591.  
  592.     //
  593.     // Dump summary information.
  594.     //
  595.  
  596.     pch = buff;
  597.  
  598.     pch += sprintf(pch, "REMOTE /C %s %s\n", HostName, PipeName);
  599.     pch += sprintf(pch, "Command: %s\n", ChildCmd);
  600.     pch += sprintf(pch, "Windows NT %d.%d build %d \n",
  601.                    OsVersionInfo.dwMajorVersion,
  602.                    OsVersionInfo.dwMinorVersion,
  603.                    OsVersionInfo.dwBuildNumber);
  604.  
  605.     WriteFileSynch(hClientPipe, buff, pch - buff, &tmp, 0, &ol);
  606.  
  607.     WriteFileSynch(hClientPipe, szSep, sizeof(szSep) - 1, &tmp, 0, &ol);
  608.  
  609.     CloseHandle(ol.hEvent);
  610.  
  611.     return 0;
  612. }
  613.  
  614. /*************************************************************/
  615.  
  616. DWORD                // NO CRT for ShowPopup
  617. WINAPI
  618. ShowPopup(
  619.     void *vpArg
  620.     )
  621. {
  622.     char *msg = (char *) vpArg;
  623.  
  624.     MessageBox(GetActiveWindow(),msg,"** REMOTE.EXE **",MB_OK|MB_SETFOREGROUND);
  625.     HeapFree(hHeap, 0, msg);
  626.     return(0);
  627.  
  628. }
  629.  
  630. /*************************************************************/
  631.  
  632. //
  633. // SrvCtrlHand is the console event handler for the server side
  634. // of remote.  If our stdin is a console handle, we've disabled
  635. // generation of ^C events by the console code.  Therefore
  636. // any we see are either generated by us for the benefit of
  637. // our child processes sharing the console, or generated by
  638. // some other process.  We want to ignore the ones we generate
  639. // (since we're already done with everything that needs to be
  640. // done at that point), and also ignore ^C's generated by
  641. // other processes since we don't need to do anything with those.
  642. // For example if someone runs:
  643. //
  644. // remote /s "remote /s cmd inner" outer
  645. //
  646. // Then local keyboard ^C's will be read by the outer remote.exe
  647. // from its stdin handle, then it will generate a CTRL_C_EVENT that
  648. // all processes in the console will see, including both remote.exe's
  649. // and the child cmd.exe.  So the handler needs do nothing but indicate
  650. // the event was handled by returning TRUE so the default handler
  651. // won't kill us.  For ^BREAK we want to specifically kill our child
  652. // process so that cmd.exe and others that ignore ^BREAK will go away.
  653. // Of course this won't kill our grandchildren and so on.  Oh well.
  654. //
  655. // For all other events we return FALSE and let the default handler
  656. // have it.
  657. //
  658.  
  659. BOOL
  660. WINAPI
  661. SrvCtrlHand(
  662.     DWORD event
  663.     )
  664. {
  665.     BOOL bRet = FALSE;
  666.     DWORD cb;
  667.     DWORD dwTempFileOffset;
  668.     OVERLAPPED ol;
  669.     char szTime[64];
  670.     char szCmd[128];
  671.  
  672.     if (event == CTRL_BREAK_EVENT) {
  673.  
  674.         TerminateProcess(ChldProc, 3);
  675.         bRet = TRUE;
  676.  
  677.     } else if (event == CTRL_C_EVENT) {
  678.  
  679.         if ( ! cPendingCtrlCEvents ) {
  680.  
  681.             //
  682.             // This came from the local keyboard or
  683.             // was generated by another process in
  684.             // this console.  Echo it as a local
  685.             // command.  We have use GetTimeFormat
  686.             // here not our GetFormattedTime since
  687.             // the latter is for the use of the
  688.             // main thread only.
  689.             //
  690.  
  691.             GetTimeFormat(
  692.                 LOCALE_USER_DEFAULT,
  693.                 TIME_NOSECONDS,
  694.                 NULL,   // use current time
  695.                 NULL,   // use default format
  696.                 szTime,
  697.                 sizeof(szTime)
  698.                 );
  699.  
  700.             CMDSTRING(szCmd, cb, "^C", pLocalClient, szTime, TRUE);
  701.  
  702.             ZeroMemory(&ol, sizeof(ol));
  703.             ol.hEvent =
  704.                 CreateEvent(
  705.                     NULL,      // security
  706.                     TRUE,      // auto-reset
  707.                     FALSE,     // initially nonsignaled
  708.                     NULL       // unnamed
  709.                     );
  710.  
  711.             //
  712.             // Practically all writes to the tempfile are happening on
  713.             // the primary server thread.  We're on a Ctrl-C thread.
  714.             // We can't start the server to client I/O going after
  715.             // writing because we're on the wrong thread, so we
  716.             // punt.  To fix this we need an event we can signal
  717.             // that causes the main thread to call StartServerToClientFlow.
  718.             //
  719.  
  720.             dwTempFileOffset = dwWriteFilePointer;
  721.             dwWriteFilePointer += cb;
  722.             WriteFileSynch(hWriteTempFile, szCmd, cb, &cb, dwTempFileOffset, &ol);
  723.             // wrong thread // StartServerToClientFlow();
  724.  
  725.             CloseHandle(ol.hEvent);
  726.  
  727.         } else {
  728.  
  729.             //
  730.             // We generated this event in response to a ^C received from
  731.             // a client, it's already been displayed to all clients.
  732.             //
  733.  
  734.             cPendingCtrlCEvents--;
  735.         }
  736.  
  737.         bRet = TRUE;
  738.  
  739.     }
  740.  
  741.     return bRet;
  742. }
  743.  
  744.  
  745. /*************************************************************/
  746.  
  747. PSECURITY_DESCRIPTOR
  748. FormatSecurityDescriptor(
  749.     CHAR * * DenyNames,
  750.     DWORD    DenyCount,
  751.     CHAR * * Names,
  752.     DWORD    Count)
  753. {
  754.     PSECURITY_DESCRIPTOR    Sd;
  755.     PACL    Acl;
  756.     DWORD   i;
  757.     PSID    Sids;
  758.     DWORD   SidLength ;
  759.     CHAR    ReferencedDomain[ MAX_PATH ];
  760.     UCHAR   SidBuffer[ 8 * sizeof(DWORD) + 8 ];
  761.     DWORD   DomainLen ;
  762.     SID_NAME_USE    Use;
  763.     DWORD   SdLen;
  764.  
  765.  
  766.     SdLen = sizeof(SECURITY_DESCRIPTOR) +
  767.                         DenyCount * (sizeof( ACCESS_DENIED_ACE ) ) +
  768.                         DenyCount * GetSidLengthRequired( 8 ) +
  769.                         Count * (sizeof( ACCESS_ALLOWED_ACE ) ) + sizeof(ACL) +
  770.                         (Count * GetSidLengthRequired( 8 ) );
  771.  
  772.     Sd = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, SdLen );
  773.  
  774.     if ( !Sd )
  775.     {
  776.         ErrorExit("Could not allocate SD");
  777.     }
  778.  
  779.     InitializeSecurityDescriptor( Sd, SECURITY_DESCRIPTOR_REVISION );
  780.  
  781.     Acl = (PACL)( (PUCHAR) Sd + sizeof( SECURITY_DESCRIPTOR) );
  782.  
  783.     InitializeAcl( Acl, SdLen - sizeof( SECURITY_DESCRIPTOR) ,
  784.                     ACL_REVISION );
  785.  
  786.     Sids = SidBuffer;
  787.     for (i = 0 ; i < DenyCount ; i ++ )
  788.     {
  789.         SidLength = sizeof( SidBuffer );
  790.  
  791.         DomainLen = MAX_PATH ;
  792.  
  793.         if (! LookupAccountName(NULL,
  794.                                 DenyNames[ i ],
  795.                                 Sids,
  796.                                 &SidLength,
  797.                                 ReferencedDomain,
  798.                                 &DomainLen,
  799.                                 &Use ) )
  800.         {
  801.             _snprintf( ReferencedDomain, MAX_PATH, "Unable to find account %s", DenyNames[ i ]);
  802.             ErrorExit( ReferencedDomain );
  803.         }
  804.  
  805.         //
  806.         // Got the sid.  Now, add it as an access denied ace:
  807.         //
  808.  
  809.         AddAccessDeniedAce( Acl,
  810.                             ACL_REVISION,
  811.                             FILE_GENERIC_READ |
  812.                                 FILE_GENERIC_WRITE |
  813.                                 FILE_CREATE_PIPE_INSTANCE,
  814.                             Sids );
  815.  
  816.  
  817.     }
  818.  
  819.     for (i = 0 ; i < Count ; i ++ )
  820.     {
  821.         SidLength = sizeof( SidBuffer );
  822.  
  823.         DomainLen = MAX_PATH ;
  824.  
  825.         if (! LookupAccountName(NULL,
  826.                                 Names[ i ],
  827.                                 Sids,
  828.                                 &SidLength,
  829.                                 ReferencedDomain,
  830.                                 &DomainLen,
  831.                                 &Use ) )
  832.         {
  833.             _snprintf( ReferencedDomain, MAX_PATH, "Unable to find account %s", Names[ i ]);
  834.             ErrorExit( ReferencedDomain );
  835.         }
  836.  
  837.         //
  838.         // Got the sid.  Now, add it as an access allowed ace:
  839.         //
  840.  
  841.         AddAccessAllowedAce(Acl,
  842.                             ACL_REVISION,
  843.                             FILE_GENERIC_READ |
  844.                                 FILE_GENERIC_WRITE |
  845.                                 FILE_CREATE_PIPE_INSTANCE,
  846.                             Sids );
  847.  
  848.  
  849.     }
  850.  
  851.     //
  852.     // Now the ACL should be complete, so set it into the SD and return:
  853.     //
  854.  
  855.     SetSecurityDescriptorDacl( Sd, TRUE, Acl, FALSE );
  856.  
  857.     return Sd ;
  858.  
  859. }
  860.  
  861.  
  862. /*************************************************************/
  863.  
  864. VOID
  865. CloseClient(
  866.     REMOTE_CLIENT *pClient
  867.     )
  868. {
  869.     DWORD tmp;
  870.     char  Buf[200];
  871.  
  872.     #if DBG
  873.         if (pClient->ServerFlags & ~SFLG_VALID) {
  874.  
  875.             printf("pClient %x looks nasty in CloseClient.\n", pClient);
  876.             ErrorExit("REMOTE_CLIENT structure corrupt.");
  877.         }
  878.     #endif
  879.  
  880.  
  881.     //
  882.     // If we're still active (on the normal client list)
  883.     // start tearing things down and move to the closing
  884.     // list.
  885.     //
  886.  
  887.     if (pClient->ServerFlags & SFLG_CLOSING) {
  888.  
  889.         return;
  890.     }
  891.  
  892.  
  893.     if (pClient->ServerFlags & SFLG_HANDSHAKING) {
  894.  
  895.         MoveClientToNormalList(pClient);
  896.     }
  897.  
  898.     MoveClientToClosingList(pClient);
  899.  
  900.     pClient->ServerFlags |= SFLG_CLOSING;
  901.  
  902.  
  903.     if (pClient->PipeWriteH != INVALID_HANDLE_VALUE) {
  904.  
  905.         TRACE(CONNECT, ("Disconnecting %d PipeWriteH (%x).\n", pClient->dwID, pClient->PipeWriteH));
  906.         CANCELIO(pClient->PipeWriteH);
  907.         DisconnectNamedPipe(pClient->PipeWriteH);
  908.         CloseHandle(pClient->PipeWriteH);
  909.     }
  910.  
  911.  
  912.     if (pClient->PipeReadH != INVALID_HANDLE_VALUE &&
  913.         pClient->PipeReadH != pClient->PipeWriteH) {
  914.  
  915.         TRACE(CONNECT, ("Disconnecting %d PipeReadH (%x).\n", pClient->dwID, pClient->PipeReadH));
  916.         CANCELIO(pClient->PipeReadH);
  917.         DisconnectNamedPipe(pClient->PipeReadH);
  918.         CloseHandle(pClient->PipeReadH);
  919.     }
  920.  
  921.  
  922.     if (pClient->rSaveFile != INVALID_HANDLE_VALUE) {
  923.  
  924.         CANCELIO(pClient->rSaveFile);
  925.         CloseHandle(pClient->rSaveFile);
  926.     }
  927.  
  928.     pClient->rSaveFile =
  929.         pClient->PipeWriteH =
  930.             pClient->PipeReadH =
  931.                 INVALID_HANDLE_VALUE;
  932.  
  933.  
  934.     if ( ! bShuttingDownServer ) {
  935.  
  936.         sprintf(Buf, "\n**Remote: Disconnected from %s %s [%s]\n", pClient->Name, pClient->UserName, GetFormattedTime(TRUE));
  937.  
  938.         if (WriteFileSynch(hWriteTempFile,Buf,strlen(Buf),&tmp,dwWriteFilePointer,&olMainThread)) {
  939.             dwWriteFilePointer += tmp;
  940.             StartServerToClientFlow();
  941.         }
  942.     }
  943.  
  944.     return;
  945. }
  946.  
  947. BOOL
  948. FASTCALL
  949. HandleSessionError(
  950.     PREMOTE_CLIENT pClient,
  951.     DWORD         dwError
  952.     )
  953. {
  954.  
  955.     if (pClient->ServerFlags & SFLG_CLOSING) {
  956.  
  957.         return TRUE;
  958.     }
  959.  
  960.     if (dwError) {
  961.  
  962.         if (ERROR_BROKEN_PIPE == dwError ||
  963.             ERROR_OPERATION_ABORTED == dwError ||
  964.             ERROR_NO_DATA == dwError ) {
  965.  
  966.             CloseClient(pClient);
  967.             return TRUE;
  968.         }
  969.  
  970.         SetLastError(dwError);
  971.         ErrorExit("Unhandled session error.");
  972.     }
  973.  
  974.     return FALSE;
  975. }
  976.  
  977.  
  978. VOID
  979. FASTCALL
  980. CleanupTempFiles(
  981.     PSZ pszTempDir
  982.     )
  983. {
  984.     HANDLE          hSearch;
  985.     WIN32_FIND_DATA FindData;
  986.     char            szPath[MAX_PATH + 1];
  987.     char            szFile[MAX_PATH + 1];
  988.  
  989.     //
  990.     // pszTempDir, from GetTempPath, has a trailing backslash.
  991.     //
  992.  
  993.     sprintf(szPath, "%sREM*.tmp", pszTempDir);
  994.  
  995.     hSearch = FindFirstFile(
  996.                   szPath,
  997.                   &FindData
  998.                   );
  999.  
  1000.     if (INVALID_HANDLE_VALUE != hSearch) {
  1001.  
  1002.         do {
  1003.  
  1004.             sprintf(szFile, "%s%s", pszTempDir, FindData.cFileName);
  1005.  
  1006.             DeleteFile(szFile);
  1007.  
  1008.         } while (FindNextFile(hSearch, &FindData));
  1009.  
  1010.         FindClose(hSearch);
  1011.     }
  1012.  
  1013. }
  1014.  
  1015.  
  1016. VOID
  1017. FASTCALL
  1018. SetupSecurityDescriptors(
  1019.     VOID
  1020.     )
  1021. {
  1022.     int i;
  1023.  
  1024.     //
  1025.     // Initialize the wide-open security descriptor.
  1026.     //
  1027.  
  1028.     InitializeSecurityDescriptor(
  1029.         &sdPublic,
  1030.         SECURITY_DESCRIPTOR_REVISION
  1031.         );
  1032.  
  1033.     SetSecurityDescriptorDacl(
  1034.         &sdPublic,
  1035.         TRUE,
  1036.         NULL,
  1037.         FALSE
  1038.         );
  1039.  
  1040.     saPublic.nLength = sizeof(saPublic);
  1041.     saPublic.lpSecurityDescriptor = &sdPublic;
  1042.  
  1043.  
  1044.     //
  1045.     // if /u was specified once or more, build the security descriptor to
  1046.     // enforce it.
  1047.     //
  1048.  
  1049.     saPipe.nLength = sizeof(saPipe);
  1050.  
  1051.     if ( DaclNameCount  || DaclDenyNameCount ) {
  1052.  
  1053.         saPipe.lpSecurityDescriptor =
  1054.             FormatSecurityDescriptor(
  1055.                 DaclDenyNames,
  1056.                 DaclDenyNameCount,
  1057.                 DaclNames,
  1058.                 DaclNameCount
  1059.                 );
  1060.  
  1061.         if (DaclNameCount) {
  1062.  
  1063.             printf( "\nProtected Server!  Only the following users or groups can connect:\n" );
  1064.  
  1065.             for (i = 0 ; i < (int) DaclNameCount ; i++) {
  1066.  
  1067.                 printf( "    %s\n", DaclNames[i] );
  1068.             }
  1069.         }
  1070.  
  1071.         if (DaclDenyNameCount) {
  1072.  
  1073.             printf( "The following users or groups explicitly cannot connect:\n" );
  1074.  
  1075.             for (i = 0 ; i < (int) DaclDenyNameCount ; i++) {
  1076.  
  1077.                 printf("    %s\n", DaclDenyNames[i] );
  1078.             }
  1079.         }
  1080.  
  1081.  
  1082.     } else {
  1083.  
  1084.         saPipe.lpSecurityDescriptor = &sdPublic;
  1085.     }
  1086. }
  1087.  
  1088.  
  1089. VOID
  1090. FASTCALL
  1091. RuntimeLinkAPIs(
  1092.     VOID
  1093.     )
  1094. {
  1095.     HANDLE hmodKernel32;
  1096.     HANDLE hmodNetApi32;
  1097.  
  1098.  
  1099.     hmodKernel32 = LoadLibrary("kernel32");
  1100.     hmodNetApi32 = LoadLibrary("netapi32");
  1101.  
  1102.     pfnCreateWaitableTimer = (void *)
  1103.         GetProcAddress(
  1104.             hmodKernel32,
  1105.             "CreateWaitableTimerA"
  1106.             );
  1107.  
  1108.     pfnSetWaitableTimer = (void *)
  1109.         GetProcAddress(
  1110.             hmodKernel32,
  1111.             "SetWaitableTimer"
  1112.             );
  1113.  
  1114.     pfnCancelWaitableTimer = (void *)
  1115.         GetProcAddress(
  1116.             hmodKernel32,
  1117.             "CancelWaitableTimer"
  1118.             );
  1119.  
  1120.     pfnCancelIo = (void *)
  1121.         GetProcAddress(
  1122.             hmodKernel32,
  1123.             "CancelIo"
  1124.             );
  1125.  
  1126.     pfnNetWkstaGetInfo = (void *)
  1127.         GetProcAddress(
  1128.             hmodNetApi32,
  1129.             "NetWkstaGetInfo"
  1130.             );
  1131.  
  1132.     pfnNetApiBufferFree = (void *)
  1133.         GetProcAddress(
  1134.             hmodNetApi32,
  1135.             "NetApiBufferFree"
  1136.             );
  1137.  
  1138.     //
  1139.     // We do without Waitable Timers and CancelIo on 3.51
  1140.     //
  1141.  
  1142.     if (!pfnNetWkstaGetInfo ||
  1143.         !pfnNetApiBufferFree) {
  1144.  
  1145.         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  1146.         ErrorExit("Remote server requires Windows NT.");
  1147.     }
  1148.  
  1149. }
  1150.