Einzelnen Beitrag anzeigen

berens

Registriert seit: 3. Sep 2004
434 Beiträge
 
Delphi 10.4 Sydney
 
#1

[JwSCL] Exception bei TJwSecurityDescriptorDialog.SetSecurity

  Alt 19. Okt 2015, 11:41
Hallo zusammen,
obwohl ja die JwSCL insgesamt einfach bedienbar ist -wenn man mal den Einstieg geschafft hat- bin ich hier an der Stelle ein wenig festgefahren und weiß nicht, ob es an mangelndem Wissen scheitert, oder ein Fehler in der JwSCL Unit an sich vorhanden ist.

Folgender Sachverhalt:
Wenn ich mit dem ACL-Editor einen neuen SecurityDescriptor bearbeite, habe ich kein Problem.
Wenn ich mit dem ACL-Editor einen SecurityDescriptor ("SD") bearbeite, der geladen wurde (also ein neuer SD, der als Parameter einen Plain-Text-Wert übergeben bekommt) kommt eine Exception, sobald ich den ACL-Editor mit "Ok" beende.

Dazu muss man wissen:
-Der "geladene" SD ist generell gültig; man kann damit arbeiten und im ACL-Editor werden die geladenen Benutzer & Rechte auch korrekt angezeigt; daran sollte es also nicht liegen.
-Im folgenden Beispiel wird der SD mit dem Text "" geladen (also leerer Text, für dieses Beispiel hier). Dies ist meines Wissens ebenfalls gültig und sollte somit nicht die Ursache für das Problem sein.
-In der angehängten Funktion "TJwSecurityDescriptorDialog.SetSecurity" gibt es an der Stelle "MergeSD.Free" die Exception
Zitat:
---------------------------
Benachrichtigung über Debugger-Exception
---------------------------
Im Projekt Beispiel.exe ist eine Exception der Klasse EInvalidPointer mit der Meldung 'Ungültige Zeigeroperation' aufgetreten.
---------------------------
Anhalten Fortsetzen Hilfe
---------------------------
Das Programm ist nun richtig hart abgestürzt und lässt sich auch nicht mehr fortsetzen, da nach jedem "F9" nur noch kommt:
Zitat:
---------------------------
Benachrichtigung über Debugger-Problem
---------------------------
In Projekt ...\Beispiel.exe trat ein Problem mit folgender Meldung auf: 'access violation at 0x00000000: read of address 0x00000000'. Prozess angehalten. Mit Einzelne Anweisung oder Start fortsetzen.
---------------------------
OK
---------------------------
Als Laie vermute ich nun mal, dass es sich hier um ein "Multi-Free"-Problem handelt. Nachdem der Editor mit "Ok" geschlossen werden soll, werden ja alle GUI-Einstellungen auf die Variable übertragen, und die "Erlauben" und "Verweigern"-Listen zu einer kombiniert. Hier scheint das Problem zu sein, dass die Variablen "SD" und "MergeSD" auf die selbe (nicht die gleiche!) DACL im Arbeitsspeicher zugreifen. Wird nun die SD-Variable freigegeben, wird die DACL im RAM gelöscht, und kann nicht nochmal gelöscht werden, wenn die MergeSD freigegeben wird.

Zitat:
In der JwSCL-Unit, direkt vor "SD.Free":
Wert SD:
(nil, nil, nil, True, (JwsclDescriptor.TJwSecurityDescriptor.hashCode,$5 301D4), True, True, False, False, False, True, False, False, [sdcDaclPresent,sdcDaclAutoInheritReq], $9B14FD0, $9E3CE10, True, aclpUnprotected, aclpUnprotected, 0)

Wert MergedSD
(nil, $2B2BDA0, $2B2BE60, True, (JwsclDescriptor.TJwSecurityDescriptor.hashCode,$5 301D4), True, True, False, False, False, False, False, False, [sdcDaclAutoInheritReq], $9B14FD0, $9E3D108, True, aclpUnprotected, aclpUnprotected, 0)
Hier sieht man, dass zumindest $9B14FD0 in beiden Objekten verwendet wird, was die DACL (fDACL: TJwDAccessControlList) ist. Wer jetzt hier der eigentliche Owner ist oder sein sollte, kann ich nicht sagen. Hat das seine Richtigkeit?

-Wenn ich übrigens bei "SD.Free; MergedSD.Free;" try..except drum mache, kann ich das Programm zumindest fortsetzen.
-Der ACLEditor schaltet mit dem bearbeiten bei dem SD immer die Variablen "OwnOwner" und "OwnPrimaryGroup" selbständig auf True. Ich kann nicht einschätzen in wie weit das mit dem Problem zusammenhängt, und was man dagegen tun kann/soll. Die Variablen werden ja auch mit dem "neu erzeugtem" SD auf True gesetzt, und dort gibt es das Problem nicht.

-Ist das schlimm, wenn ich als behelf einfach die try..except Lösung verwende? Klar, das ist keine saubere Lösung, aber bevor mein Programm gar nicht geht und ich hier nicht weiterkomme ...?

Code:
"Neuer" SD, keine Probleme:
SD-Variable vor dem ACL Editor:
(nil, $2A3ABA0, $2A3ABA0, False, (JwsclDescriptor.TJwSecurityDescriptor.hashCode,$5301D4), False, False, False, False, False, False, False, False, [], $2A8AD60, $9B98B70, True, aclpUnprotected, aclpUnprotected, 0)

SD-Variable nach dem ACL-Editor:
(nil, $2A3C3A0, $2A3E410, False, (JwsclDescriptor.TJwSecurityDescriptor.hashCode,$5301D4), True, True, False, False, False, False, False, False, [], $2A8AD60, $9B98B70, True, aclpUnprotected, aclpUnprotected, 0)


"Geladener" SD, Problem:
SD-Variable vor dem ACL Editor:
 (nil, $27ABB30, $27ABB90, False, (JwsclDescriptor.TJwSecurityDescriptor.hashCode,$5301D4), False, False, False, False, False, False, False, False, [], nil, $9918B70, True, aclpUnprotected, aclpUnprotected, 0)

SD-Variable nach dem ACL-Editor:
 (nil, $27AAE70, $27AC400, False, (JwsclDescriptor.TJwSecurityDescriptor.hashCode,$5301D4), True, True, False, False, False, False, False, False, [], $99A6698, $9918B70, True, aclpUnprotected, aclpUnprotected, 0)
Delphi-Quellcode:
procedure TfrmZugriffsrechte.Button1Click(Sender: TObject);
var
  sd: TjwSecurityDescriptor;
  ACLEditor : TJwSecurityDescriptorDialog;
begin

  // Funktioniert ohne Probleme
  sd := TjwSecurityDescriptor.Create;

  // Problem mit ACLEditor
  sd := TjwSecurityDescriptor.Create('');
  with sd do begin
  PrimaryGroup := JwNullSID;
  Owner := JwNullSID;
  OwnDACL := False;
  OwnOwner := False;
  OwnPrimaryGroup := False;
  DACLInherited := False;
  AuditInherited := False;
  Control := [];
  end;

  // Editor erzeugen
  ACLEditor := TJwSecurityDescriptorDialog.Create(GetActiveWindow);

  // Zum testen in dieser Demo erstmal Alles freischalten (Erweitert-Button, alle Karteikarten, etc.)
  ACLEditor.Flags := [sdfEditOwner];
  // sdfAdvanced, sdfEditDacl, sdfEditEffective, sdfNoAdditionalPermission, sdfEditSacl
  // Caption des Dialogs, bzw. der "Objektes", für das gerade die Sicherheit verändert wird. Nehmt zur Not euren Programmnamen oder so...
  ACLEditor.ObjectName := Caption;
  ACLEditor.ServerName := '';


  try
    try
    ACLEditor.Mapping := TMyMapping;
    ACLEditor.SecurityDescriptor.Assign(sd);
    ACLEditor.OnSetSecurity := OnSetSecurity;

    // Editor anzeigen. Das Programm pausiert, bis der Dialog geschlossen wird.
    // Wenn der Dialog mit "Ok" beendet wurde:
    if ACLEditor.ShowModal then
    begin
      Sleep(0); // wenn wir hier ankommen, alles Ok!
      // Den kompletten SD wieder in unsere Variable zurückkopieren
      sd.Assign(ACLEditor.SecurityDescriptor);
    end;
    except
      sleep(0); // Keine Chance, das Problem hierüber zu behandeln!
    end;
  finally
    try
      ACLEditor.Free;
    except
      sleep(0); // Keine Chance, das Problem hierüber zu behandeln!
    end;
  end;

end;

procedure TfrmZugriffsrechte.OnSetSecurity(Sender: TJwSecurityDescriptorDialog;
  SecurityType: TJwSecurityInformationFlagSet;
  SecurityDialogFlags: TJwSecurityDialogFlags;
  SecurityResetType: TJwSecurityResetTypes;
  Settings: TJwSecurityDescriptorControlSet; NewSecurityDescriptor,
  MergedSecurityDescriptor: TJwSecurityDescriptor; var bSuccess: boolean);
begin
  bSuccess := true;
end;

Delphi-Quellcode:
function TJwSecurityDescriptorDialog.SetSecurity(
  SecurityInformation: SECURITY_INFORMATION;
  pSecurityDescriptor: PSECURITY_DESCRIPTOR): HRESULT;
var
  secInfo: TJwSecurityInformationFlagSet;
  secControl: TJwSecurityDescriptorControlSet;

  MergedSD, SD: TJwSecurityDescriptor;
  SecurityResetTypes: TJwSecurityResetTypes;
  secInfoEx: TJwSecurityDialogFlags;
  bSuccess: boolean;

begin
  secInfo := TJwEnumMap.ConvertSecurityInformation(
    SecurityInformation);
  secControl := TJwEnumMap.ConvertSecurityControl(
    pSecurityDescriptor.Control);
  secInfoEx := TJwEnumMap.ConvertFlags(SecurityInformation);


  //create new SD that contains the changed security information
  SD := TJwSecurityDescriptor.Create(pSecurityDescriptor);

  //create new SD that contains the default SD and will receive the new one
  MergedSD := TJwSecurityDescriptor.Create(fSD);

  //replace Owner
  if siOwnerSecurityInformation in secInfo then
  begin
    MergedSD.OwnOwner := True;
    MergedSD.Owner := SD.Owner; //simply copy owner
  end;

  //replace group
  if siGroupSecurityInformation in secInfo then
  begin
    MergedSD.OwnPrimaryGroup := True;
    MergedSD.PrimaryGroup := SD.PrimaryGroup; //simply copy group
  end;

  //replace DACL
  if siDaclSecurityInformation in secInfo then
  begin
    MergedSD.OwnDACL := True;
    MergedSD.DACL := SD.DACL; //simply copy DACL
  end;

  //replace SACL
  if siSaclSecurityInformation in secInfo then
  begin
    MergedSD.SACL := SD.SACL; //simply copy SACL
  end;


  if siDaclSecurityInformation in secInfo then
  begin
    //protect DACL from inheritance
    if sdcDaclProtected in SD.Control then
    begin
      Include(secInfo, siProtectedDaclSecurityInformation);
      MergedSD.Control := MergedSD.Control + [sdcDaclProtected];
    end;

    //unprotect DACL so inheritance can flow
    if sdcDaclAutoInheritReq in SD.Control then
    begin
      Include(secInfo, siUnprotectedDaclSecurityInformation);
      MergedSD.Control := MergedSD.Control + [sdcDaclAutoInheritReq];
    end;
  end;

  if siSaclSecurityInformation in secInfo then
  begin
    //protect SACL from inheritance
    if sdcSaclProtected in SD.Control then
    begin
      Include(secInfo, siProtectedSaclSecurityInformation);
      MergedSD.Control := MergedSD.Control + [sdcSaclProtected];
    end;

    //unprotect SACL so inheritance can flow
    if sdcSaclAutoInheritReq in SD.Control then
    begin
      Include(secInfo, siUnprotectedSaclSecurityInformation);
      MergedSD.Control := MergedSD.Control + [sdcSaclAutoInheritReq];
    end;
  end;

  //set reset state, so user can easily see whether he must reset all children
  SecurityResetTypes := [];
  if (SecurityInformation and SI_OWNER_RECURSE = SI_OWNER_RECURSE) then
    Include(SecurityResetTypes, srtOwner);

  if (SecurityInformation and SI_RESET_DACL_TREE = SI_RESET_DACL_TREE) then
    Include(SecurityResetTypes, srtDacl);

  if (SecurityInformation and SI_RESET_SACL_TREE = SI_RESET_SACL_TREE) then
    Include(SecurityResetTypes, srtSacl);


  bSuccess := False;
  try
    if Assigned(fOnSetSecurity) then
      fOnSetSecurity(Self, secInfo, secInfoEx,
        SecurityResetTypes,
        SD.Control, SD, MergedSD, bSuccess);
    if bSuccess then
      fSD.Assign(MergedSD);
  finally
// try
      SD.Free;
      MergedSD.Free; // <-- hier gibt es die eigentliche Exception
// except end;
  end;

  if bSuccess then
    Result := S_OK
  else
    Result := S_FALSE;
end;
  Mit Zitat antworten Zitat