srvutil.c

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