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.
var
ServiceStopEvent : THandle; //define a stop event for the service
Stopped : Boolean = false;
procedure …ServiceExecute
var
Log : IJwLogClient;
ProtocolVersion,
WaitResult : DWORD;
Msg : TMsg;
OvLapped : OVERLAPPED;
PipeToken : TJwSecurityToken;
begin
//JWSCL logging
Log := uLogging.LogServer.Connect(etMethod,ClassName,
‘ServiceExecute’,‘MainUnit.pas’,”);
hPipe := CreateNamedPipe(‘\\.\pipe\PipeName’,
PIPE_ACCESS_DUPLEX or FILE_FLAG_OVERLAPPED,
PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 0, 0, 0, nil);
//check hPipe here…TODO for the reader
ZeroMemory(@OvLapped, sizeof(OvLapped));
OvLapped.hEvent := CreateEvent(nil, false, false, nil);
//auto CloseHandle
TJwAutoPointer.Wrap(OvLapped.hEvent);
Stopped := false;
//for services we use this msg friendly approach
repeat //1.
ConnectNamedPipe(Pipe, @OvLapped);
repeat //2.
ServiceThread.ProcessRequests(False);
WaitResult := JwMsgWaitForMultipleObjects([ServiceStopEvent, OvLapped.hEvent], false, INFINITE, QS_ALLINPUT);
case WaitResult of
WAIT_OBJECT_0 + 1 : ResetEvent(OvLapped.hEvent);
WAIT_OBJECT_0 + 2 : PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE); //tag message as read, so waitfor does not return next time
else
//another problem
end;
until WaitResult <> WAIT_OBJECT_0 + 2; //2.
if WaitResult = WAIT_OBJECT_0 +1 then //connected
begin
//read dummy data or e.g. Protocol version of client
if not CheckPipe(ReadFile(Pipe, @ProtocolVersion, sizeof(ProtocolVersion) ,nil, @OvLapped)) then
//uhh error
else
begin
//JWSCL JwsclUtils.pas implements this more convenient wait function
if JwWaitForMultipleObjects([ServiceStopEvent, OvLapped.hEvent], false,
TIMEOUT) = WAIT_OBJECT_0 +1 then
begin
try
//now we can get the client’s token – may throw exception if it fails!
TJwSecurityToken.ImpersonateNamedPipeClient(Pipe);
try
PipeToken := TJwSecurityToken.CreateTokenByThread(0, MAXIMUM_ALLOWED, true);
finally
TJwSecurityToken.RevertToSelf;
end;
//……. go on with what you want
on E : Exception do
begin
Log.Exception(E);
end;
end
else
Log.Log(‘Read for protocol version failed.’);
end;
end;
DisconnectNamedPipe(Pipe);
until Stopped; //1. – the one who signales ServiceStopEvent, must also set this boolean value to true
CloseHandle(Pipe);
end;
Leave a reply
You must be logged in to post a comment.