You cannot impersonate a pipe until you have read from it. Even a write call doesn’t work. So a service has to wait for a dummy client write call until it can check the client’s token.

The following codes shows how multi instance pipe server could look like. Be aware that I wrote this to show how it can be done and not for a simple copy&paste.

  1. //necessary units
  2. uses JwaWindows, …, JwsclToken, JwsclUtils, JwsclComUtils, JwsclLogging, SvcMgr;
  3. {checks ReadFile and WriteFile result but ignores overlapped error result}
  4. function CheckPipe(const Value : Boolean) : Boolean;
  5. begin
  6.   result := (Value )
  7.       or (not Value and (GetLastError() = ERROR_IO_PENDING));
  8. end;
  9.  
  10. var
  11.   ServiceStopEvent : THandle; //define a stop event for the service
  12.   Stopped : Boolean = false;
  13.  
  14. procedureServiceExecute
  15. var
  16.   Log : IJwLogClient;
  17.  
  18.   ProtocolVersion,
  19.   WaitResult : DWORD;
  20.   Msg : TMsg;
  21.   OvLapped : OVERLAPPED;
  22.   PipeToken : TJwSecurityToken;
  23. begin
  24.   //JWSCL logging
  25.   Log := uLogging.LogServer.Connect(etMethod,ClassName,
  26.           ‘ServiceExecute’,‘MainUnit.pas’,);
  27.  
  28.   hPipe := CreateNamedPipe(‘\\.\pipe\PipeName’,
  29.         PIPE_ACCESS_DUPLEX or FILE_FLAG_OVERLAPPED,
  30.         PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 0, 0, 0, nil);
  31.  
  32.   //check hPipe here…TODO for the reader
  33.  
  34.   ZeroMemory(@OvLapped, sizeof(OvLapped));
  35.   OvLapped.hEvent := CreateEvent(nil, false, false, nil);
  36.   //auto CloseHandle
  37.   TJwAutoPointer.Wrap(OvLapped.hEvent);
  38.  
  39.   Stopped := false;
  40.   //for services we use this msg friendly approach
  41.   repeat //1.
  42.      ConnectNamedPipe(Pipe, @OvLapped);
  43.  
  44.      repeat //2.
  45.        ServiceThread.ProcessRequests(False);
  46.        WaitResult := JwMsgWaitForMultipleObjects([ServiceStopEvent, OvLapped.hEvent], false, INFINITE, QS_ALLINPUT);
  47.  
  48.        case WaitResult of
  49.           WAIT_OBJECT_0 + 1 :  ResetEvent(OvLapped.hEvent);
  50.           WAIT_OBJECT_0 + 2 :  PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE); //tag message as read, so waitfor does not return next time
  51.        else
  52.           //another problem
  53.        end;
  54.      until WaitResult <> WAIT_OBJECT_0 + 2; //2.
  55.  
  56.      if WaitResult = WAIT_OBJECT_0 +1 then //connected
  57.      begin
  58.        //read dummy data or e.g. Protocol version of client
  59.        if not CheckPipe(ReadFile(Pipe, @ProtocolVersion, sizeof(ProtocolVersion) ,nil, @OvLapped)) then
  60.          //uhh error
  61.        else
  62.        begin
  63.          //JWSCL JwsclUtils.pas implements this more convenient wait function
  64.          if JwWaitForMultipleObjects([ServiceStopEvent, OvLapped.hEvent], false,
  65.                 TIMEOUT) = WAIT_OBJECT_0 +1 then
  66.          begin
  67.             try
  68.               //now we can get the client’s token - may throw exception if it fails!
  69.               TJwSecurityToken.ImpersonateNamedPipeClient(Pipe);
  70.  
  71.               try
  72.                 PipeToken := TJwSecurityToken.CreateTokenByThread(0, MAXIMUM_ALLOWED, true);
  73.               finally
  74.                 TJwSecurityToken.RevertToSelf;
  75.               end;
  76.               //……. go on with what you want
  77.             on E : Exception do
  78.             begin
  79.               Log.Exception(E);
  80.             end;
  81.          end
  82.          else
  83.            Log.Log(‘Read for protocol version failed.’);
  84.        end;
  85.      end;
  86.  
  87.      DisconnectNamedPipe(Pipe);
  88.   until Stopped; //1. - the one who signales ServiceStopEvent, must also set this boolean value to true
  89.  
  90.   CloseHandle(Pipe);
  91. end;
Send post as PDF to www.pdf24.org
convert this post to pdf.