Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Named Pipes zwischen Service und eingeschränktem Programm (https://www.delphipraxis.net/119717-named-pipes-zwischen-service-und-eingeschraenktem-programm.html)

Fridolin Walther 30. Aug 2008 14:13

Re: Named Pipes zwischen Service und eingeschränktem Program
 
Delphi-Quellcode:
program pipeserver;

{$APPTYPE CONSOLE}

uses
  jwawinbase, jwawintype, jwawinnt, jwaaccctrl, jwaaclapi, jwawinerror, sysutils;

function InstanceThread(PipeHandle : dword) : dword; stdcall;
var
  Value : dword;
  tmp  : dword;
begin
  result := 0;

  ReadFile(PipeHandle, @Value, 4, @tmp, nil);
  WriteFile(PipeHandle, @Value, 4, @tmp, nil);

  FlushFileBuffers(PipeHandle);
  DisconnectNamedPipe(PipeHandle);
  CloseHandle(PipeHandle);
end;

function ServerThread(unused : dword) : dword; stdcall;
const
  BUFSIZE = 4;
var
  PipeHandle : dword;
  Connected : boolean;
  SA        : LPSECURITY_ATTRIBUTES;
  ACL       : PACL;
  Group     : TRUSTEE;
  EA        : PEXPLICIT_ACCESS;
  SD        : PSECURITY_DESCRIPTOR;
  ACL_SIZE  : ACL_SIZE_INFORMATION;
  tmp       : dword;
begin
  Group.MultipleTrusteeOperation := NO_MULTIPLE_TRUSTEE;
  Group.pMultipleTrustee := nil;
  Group.ptstrName := 'Jeder';
  Group.TrusteeForm := TRUSTEE_IS_NAME;
  Group.TrusteeType := TRUSTEE_IS_GROUP;

  new(EA);
  EA^.grfAccessMode := GRANT_ACCESS;
  EA^.grfAccessPermissions := GENERIC_READ or GENERIC_WRITE;
  EA^.grfInheritance := NO_INHERITANCE;
  EA^.Trustee := group;

  SetEntriesInAcl(1, EA, nil, ACL);
  GetAclInformation(ACL, @ACL_SIZE, sizeof(ACL_SIZE), AclSizeInformation);
  getmem(SD, SECURITY_DESCRIPTOR_MIN_LENGTH + ACL_SIZE.AclBytesFree + ACL_SIZE.AclBytesInUse);
  InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
  SetSecurityDescriptorDacl(sd, TRUE, ACL, FALSE);

  new(SA);
  sa^.bInheritHandle := FALSE;
  sa^.lpSecurityDescriptor := sd;
  sa^.nLength := sizeof(sa);

  while true do
    begin
      PipeHandle := CreateNamedPipeW('\\.\pipe\demopipe', PIPE_ACCESS_DUPLEX,
                                     PIPE_TYPE_MESSAGE or PIPE_READMODE_MESSAGE or
                                     PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, BUFSIZE,
                                     BUFSIZE, INFINITE, SA);

      if PipeHandle = INVALID_HANDLE_VALUE then
        begin
          sleep(100);
          continue;
        end;

      Connected := ConnectNamedPipe(PipeHandle, nil)
                   or (GetLastError = ERROR_PIPE_CONNECTED);

      if Connected then
        begin
          tmp := CreateThread(nil, 0, @InstanceThread,
                                       Pointer(PipeHandle), 0, nil);
          if tmp = 0 then
            begin
              DisconnectNamedPipe(PipeHandle);
              CloseHandle(PipeHandle);
              continue;
            end else
              CloseHandle(tmp);
        end else
          CloseHandle(PipeHandle);
  end;

  LocalFree(cardinal(ACL));
  freemem(SD);
  dispose(EA);
end;

var
  tmp : dword;
begin
  write('Starting ServerThread: ');
  tmp := CreateThread(nil, 0, @ServerThread, nil, 0, nil);
  writeln(tmp <> 0);
  CloseHandle(tmp);
  readln;
end.
Ist ein kleiner Pipe Server, der eine Pipe mit einer DACL die Jedem im System explizit Lese und Schreibrechte erlaubt erstellt.

CodeX 30. Aug 2008 14:21

Re: Named Pipes zwischen Service und eingeschränktem Program
 
Danke!
Sieht recht kompliziert aus. Ich habe parallel hier im Forum noch nach dem Stichwort gesucht und diesen Thread hier gefunden.
Tun es die paar Zeilen, um FSA zu bestimmen, auch? Oder gibt es irgendwelche Bedenken?

Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var
   FSA : SECURITY_ATTRIBUTES;
   FSD : SECURITY_DESCRIPTOR;
   pch1: shortstring;
begin
   InitializeSecurityDescriptor(@FSD, SECURITY_DESCRIPTOR_REVISION);
   SetSecurityDescriptorDacl(@FSD, True, nil, False);
   FSA.lpSecurityDescriptor := @FSD;
   FSA.nLength := sizeof(SECURITY_ATTRIBUTES);
   FSA.bInheritHandle := True;

   Pipe:= CreateNamedPipe(PChar('\\.\pipe\<test>'),
                          PIPE_ACCESS_DUPLEX or FILE_FLAG_WRITE_THROUGH,
                          PIPE_TYPE_MESSAGE or PIPE_READMODE_MESSAGE or PIPE_NOWAIT,
                          PIPE_UNLIMITED_INSTANCES,
                          1024,
                          1024,
                          50,
                          @FSA);
end;

Fridolin Walther 30. Aug 2008 14:27

Re: Named Pipes zwischen Service und eingeschränktem Program
 
Funktioniert genauso. Allerdings solltest Du Dir bewusst sein, das alles und jeder dann auf die Pipe zugreifen kann - auch übers Netzwerk und ohne Authentifizierung!

CodeX 30. Aug 2008 15:05

Re: Named Pipes zwischen Service und eingeschränktem Program
 
Hm, also mein Service prüft den Sender der Nachricht auf seine Signatur und agiert nur dann, wenn es sich um meine Signatur handelt.
Dennoch wäre es wahrscheinlich nicht verkehrt, die beiden Punkte Netzwerk und Authentifizierung in den Code einzubeziehen.

Ich habe Deinen Code nun genauer angeschaut. Ich verstehe zwar nicht alles davon, aber die Zeile Group.ptstrName := 'Jeder'; macht mich stutzig. Die starre Angabe, würde dann doch nur auf deutschen Betriebssystemen funktionieren, oder? Ich nehme an, dass es nicht einfach einen Flag-Wert gibt, der nur lokal angemeldete Benutzer zulässt? :gruebel:

Apollonius 30. Aug 2008 15:09

Re: Named Pipes zwischen Service und eingeschränktem Program
 
Mit der TRUSTEE-Struktur kann man Gruppen oder Benutzer nicht nur per Name, sondern auch per SID angeben. *klick* Die SID der eingebauten Gruppen ist unabhängig von der Sprache.

Fridolin Walther 30. Aug 2008 15:19

Re: Named Pipes zwischen Service und eingeschränktem Program
 
Nunja, das war Code aus einem kleinen Beispiel von mir, wie man eine Pipe erstellt auf die nur Mitglieder einer bestimmten Gruppe Zugriff haben. Für Deine Zwecke wäre es wahrscheinlich besser den Zugriff an einen Well Known SID zu koppeln. Der Code würde dann so aussehen:

Delphi-Quellcode:
program pipeserver;

{$APPTYPE CONSOLE}

uses
  jwawinbase, jwawintype, jwawinnt, jwaaccctrl, jwaaclapi, jwawinerror, sysutils;

function InstanceThread(PipeHandle : dword) : dword; stdcall;
var
  Value : dword;
  tmp  : dword;
begin
  result := 0;

  ReadFile(PipeHandle, @Value, 4, @tmp, nil);
  WriteFile(PipeHandle, @Value, 4, @tmp, nil);

  FlushFileBuffers(PipeHandle);
  DisconnectNamedPipe(PipeHandle);
  CloseHandle(PipeHandle);
end;

function ServerThread(unused : dword) : dword; stdcall;
const
  BUFSIZE = 4;
var
  PipeHandle  : dword;
  Connected   : boolean;
  SA          : LPSECURITY_ATTRIBUTES;
  ACL         : PACL;
  Group       : TRUSTEE;
  EA          : PEXPLICIT_ACCESS;
  SD          : PSECURITY_DESCRIPTOR;
  ACL_SIZE    : ACL_SIZE_INFORMATION;
  WellKnownSID : PSID;
  tmp         : dword;
begin
  tmp := SECURITY_MAX_SID_SIZE;
  GetMem(WellKnownSID, tmp);
  CreateWellKnownSid(WinWorldSid, nil, WellKnownSID, tmp);

  Group.MultipleTrusteeOperation := NO_MULTIPLE_TRUSTEE;
  Group.pMultipleTrustee := nil;
  Group.ptstrName := Pointer(WellKnownSID);
  Group.TrusteeForm := TRUSTEE_IS_SID;
  Group.TrusteeType := TRUSTEE_IS_WELL_KNOWN_GROUP;

  new(EA);
  EA^.grfAccessMode := GRANT_ACCESS;
  EA^.grfAccessPermissions := GENERIC_READ or GENERIC_WRITE;
  EA^.grfInheritance := NO_INHERITANCE;
  EA^.Trustee := group;

  SetEntriesInAcl(1, EA, nil, ACL);
  GetAclInformation(ACL, @ACL_SIZE, sizeof(ACL_SIZE), AclSizeInformation);
  getmem(SD, SECURITY_DESCRIPTOR_MIN_LENGTH + ACL_SIZE.AclBytesFree + ACL_SIZE.AclBytesInUse);
  InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
  SetSecurityDescriptorDacl(sd, TRUE, ACL, FALSE);

  new(SA);
  sa^.bInheritHandle := FALSE;
  sa^.lpSecurityDescriptor := sd;
  sa^.nLength := sizeof(sa);

  while true do
    begin
      PipeHandle := CreateNamedPipeW('\\.\pipe\demopipe', PIPE_ACCESS_DUPLEX,
                                     PIPE_TYPE_MESSAGE or PIPE_READMODE_MESSAGE or
                                     PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, BUFSIZE,
                                     BUFSIZE, INFINITE, SA);

      if PipeHandle = INVALID_HANDLE_VALUE then
        begin
          sleep(100);
          continue;
        end;

      Connected := ConnectNamedPipe(PipeHandle, nil)
                   or (GetLastError = ERROR_PIPE_CONNECTED);

      if Connected then
        begin
          tmp := CreateThread(nil, 0, @InstanceThread,
                                       Pointer(PipeHandle), 0, nil);
          if tmp = 0 then
            begin
              DisconnectNamedPipe(PipeHandle);
              CloseHandle(PipeHandle);
              continue;
            end else
              CloseHandle(tmp);
        end else
          CloseHandle(PipeHandle);
  end;

  LocalFree(cardinal(ACL));
  freemem(SD);
  freemem(WellKnownSID);
  dispose(EA);
end;

var
  tmp : dword;
begin
  write('Starting ServerThread: ');
  tmp := CreateThread(nil, 0, @ServerThread, nil, 0, nil);
  writeln(tmp <> 0);
  CloseHandle(tmp);
  readln;
end.
Eine Liste der Well Known SIDs gibts hier: http://msdn.microsoft.com/en-us/library/aa379650(VS.85).aspx
In Deinem Falle wäre wohl WinLocalSid nützlich.

Man kann den Code übrigens noch stark vereinfachen indem man die JWSCL benutzt. Allerdings ist mir die JWSCL für meinen Geschmack zu viel Overhead.

Apollonius 30. Aug 2008 15:23

Re: Named Pipes zwischen Service und eingeschränktem Program
 
Wäre es hier nicht klüger, den Speicher für WellKnownSID auf dem Stack zu reservieren?

Fridolin Walther 30. Aug 2008 15:25

Re: Named Pipes zwischen Service und eingeschränktem Program
 
Welchen Vorteil erhoffst Du Dir dadurch?

CodeX 30. Aug 2008 15:26

Re: Named Pipes zwischen Service und eingeschränktem Program
 
Zitat:

Zitat von 0xF30FC7
Man kann den Code übrigens noch stark vereinfachen indem man die JWSCL benutzt.

Ich bin ganz Ohr! :-D
Da ich die JWSCL so oder so bereits eingebunden habe, würd ich auch gern den vereinfachten Code nehmen.

Zitat:

Zitat von 0xF30FC7
Allerdings ist mir die JWSCL für meinen Geschmack zu viel Overhead.

Ja, stimmt leider. Hat mich auch Überwindung gekostet, mich letztlich darauf festzulegen. Aber gut, die Arbeitsersparnis wars dann doch Wert.

Apollonius 30. Aug 2008 15:40

Re: Named Pipes zwischen Service und eingeschränktem Program
 
@0xF30FC7: Ich finde einfach, dass man den Memory Manager nicht bemühen sollte, wenn der Stack es genauso tut, denn er ist in jedem Fall langsamer und hat einen nicht zu vernachlässigenden Speicher-Overhead.
Das gleiche gilt für EA. Bei SD würde ich allerdings auch den MM nehmen, da du die Größe nicht im Voraus weißt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:33 Uhr.
Seite 2 von 3     12 3      

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz