Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Berechtigungen einer Datei setzen (jwscl) (https://www.delphipraxis.net/119230-berechtigungen-einer-datei-setzen-jwscl.html)

Alter Mann 22. Aug 2008 17:22


Berechtigungen einer Datei setzen (jwscl)
 
Hallo

Ich habe das 'kleine' Problem nach einem 'Zwischenfall' Dateien
wiederherstellen zu müssen.

Ausgangslage:
Die Dateien und Verzeichnisse befinden sich alle in einem Verzeichnis(ca. 15600 Dateien und ca. 1500 Verzeichnisse mit weiteren Dateien von ca. 300 Usern).
Die Berechtigungen sind alle vorhanden, nur die Namen sind geändert(kein Problem).

Lösungsansatz:
Quell- und Zielverzeichnis festlegen.
Mittels FindFirst/FindNext alle Dateien und Verzeichnisse aus dem Quellverzeichnis in eine Liste eintragen
und dabei die Berechtigungen(AccessControlEntry) erfassen.
Im Zielverzeichnis entsprechend des dem User zu gewiesenen Wertes ein Verzeichnis erstellen und
die Berechtigungen zuweisen(Problem).
Dateien und Verzeichnisse in das Zielverzeichnis kopieren.

Damit man auch etwas sieht gibt es dafür eine Form und die Informationen werden in einer ListView
dargestellt.

Um das ganze praktisch zu umzusetzen, habe ich zum Zwischenspeichern
der Informationen eine Klasse erstellt:
Delphi-Quellcode:
type
  PFileEntry = ^TFileEntry;
  TFileEntry = class(TObject)
  private
    FFilePath          : WideString;
    FFileName          : WideString;
    FOwnerName         : WideString;
    FType              : WideString;
    FAttr              : Integer;
    FAccessControlEntry : TJwSecurityAccessControlEntry;
    FSecurityDescriptor : TJwSecurityDescriptor;
    function   GetFullFileName : WideString;
    procedure  SetOwnerName(Value : WideString);
    procedure  SetAccessControlEntry(Value : TJwSecurityAccessControlEntry);
    procedure  SetSecurityDescriptor(Value : TJwSecurityDescriptor);
  protected
    procedure  CheckFile;
  public
    constructor Create(FullFileName : WideString);
    function   HasSecurityData : Boolean;
    property FullFileName : WideString read GetFullFileName;
    property FilePath    : WideString read FFilePath;
    property FileName    : WideString read FFileName;
    property FileTyp     : WideString read FType;
    property FileAttr    : Integer   read FAttr;
    property OwnerName   : WideString read FOwnerName write SetOwnerName;
    property AccessControlEntry : TJwSecurityAccessControlEntry read FAccessControlEntry write SetAccessControlEntry;
    property SecurityDescriptor : TJwSecurityDescriptor read FSecurityDescriptor write SetSecurityDescriptor;
  end;
Zu Testzwecken besteht die Möglichkeit einzelne Dateien einzulesen und zu kopieren.

Delphi-Quellcode:
procedure TMainForm.aSingleFileExecute(Sender: TObject);
var
  LI     : TListItem;
  FEntry : TFileEntry;
begin
  OpenDlg.InitialDir := FSourceDir;
  if OpenDlg.Execute then
  begin
    FEntry := TFileEntry.Create(OpenDlg.FileName);
    lvData.Items.BeginUpdate;
    lvData.Items.Clear;
    LI := lvData.Items.Add;
    LI.Caption := FEntry.FileName;
    LI.SubItems.Add(FEntry.FileTyp);
    GetAccessRights(FEntry);
    LI.SubItems.Add(FEntry.OwnerName);
    LI.Data := FEntry;
    lvData.Items.EndUpdate;
  end;
end;
Die Ermittlung der Berechtigungen erfolgt auf diese Art(habe ich mir aus den Beispielen der jwcsl zusammen 'gebastelt')
Delphi-Quellcode:
procedure TMainForm.GetSelectedPermissions(out mapping : TJwSecurityGenericMappingClass;
                                           out bAuditAccess : Boolean;
                                           var FileEntry : TFileEntry);
var
  Flags : TJwSecurityInformationFlagSet;
  cExDesiredAccessMask : TJwAccessMask;
  FileObject : TJwSecureFileObject;
begin
  bAuditAccess := JwIsPrivilegeSet(SE_SECURITY_NAME, pqt_Available);

  cExDesiredAccessMask := 0;
  Flags := [siDaclSecurityInformation, siOwnerSecurityInformation];
  if bAuditAccess then
  begin
    Include(Flags, siSaclSecurityInformation);
    JwEnablePrivilege(SE_SECURITY_NAME,pst_Enable); //enable access to SACL generally
    cExDesiredAccessMask := ACCESS_SYSTEM_SECURITY; //add SACL access to handle
  end;
  if (FileEntry.FileAttr and faDirectory) = faDirectory then mapping := TJwSecurityFileFolderMapping
                                                        else mapping := TJwSecurityFileMapping;
  try
    FileObject := TJwSecureFileObject.Create(FileEntry.FullFileName);
    try
       FileEntry.SecurityDescriptor := FileObject.GetSecurityDescriptor(Flags);
    finally
      FreeAndNil(FileObject);
    end;
  finally
    if bAuditAccess then
      JwEnablePrivilege(SE_SECURITY_NAME, pst_Disable);
  end;
end;
Das mit dem 'mapping' habe ich nicht verstanden, da letztlich nur der 'SecurityDescriptor'
gebraucht wird, sollte auch dies reichen(ungetestet)
Delphi-Quellcode:
procedure TMainForm.GetSelectedPermissions(var FileEntry : TFileEntry);
var
   FileObject : TJwSecureFileObject;
begin
  FileObject := TJwSecureFileObject.Create(FileEntry.FullFileName);
  try
     FileEntry.SecurityDescriptor := FileObject.GetSecurityDescriptor(Flags);
  finally
     FreeAndNil(FileObject);
  end;
end;
Das eigentliche auslesen der Berechtigungen erfolgt so
Delphi-Quellcode:
procedure TMainPESForm.GetAccessRights(var FileEntry : TFileEntry);
var
  SD           : TJwSecurityDescriptor;
  mapping      : TJwSecurityGenericMappingClass;
  ACLEntry     : TJwSecurityAccessControlEntry;
  bAuditAccess : Boolean;
  sText        : String;
  I            : Integer;
begin
    GetSelectedPermissions(mapping, bAuditAccess, FileEntry);

    if Assigned(FileEntry.SecurityDescriptor) then
    try
      if Assigned(FileEntry.SecurityDescriptor.Owner) then
      begin
        if Assigned(FileEntry.SecurityDescriptor.DACL) then
        begin
          for I := 0 to FileEntry.SecurityDescriptor.DACL.Count -1 do
          begin
            ACLEntry := FileEntry.SecurityDescriptor.DACL.Items[I];
            sText   := ACLEntry.SID.GetText(true);
            if (POS('@', sText) = 4) then
            begin
              sText := Trim(Copy(sText, POS('@', sText) +1, POS('(', sText)-(POS('@', sText) +1)));
              if IsValue(sText) then
              begin
                FileEntry.OwnerName := sText;
                FileEntry.AccessControlEntry := ACLEntry;
                Break;
              end
              else sText := '';
            end;
          end;
        end;
      end;
    finally
      FreeAndNil(SD);
    end;
end;
Nachdem auswählen des Eintrages im ListView kann und soll
1. Das Zielverzeichnis anlegt und die Berechtigungen hinzufügt werden

Delphi-Quellcode:
procedure TMainForm.aCopyUserExecute(Sender: TObject);
begin
  if lvData.Selected = nil then Exit
  else
  begin
    if CreateFolder(FDestDir, TFileEntry(lvData.Selected.Data)) then
     CopyFile(FDestDir, TFileEntry(lvData.Selected.Data));
  end;
end;

function CreateFolder(DestPath : WideString; FileEntry : TFileEntry) : Boolean;
var
  FileObject : TJwSecureFileObject;
  Flags      : TJwSecurityInformationFlagSet;
  ODACL      : TJwDAccessControlList;
begin
  Result := false;
  if FileEntry.HasSecurityData then
  begin
    if not DirectoryExists(DestPath + FileEntry.OwnerName) then
    ForceDirectories(DestPath + FileEntry.OwnerName);
    FileObject := TJwSecureFileObject.Create(DestPath + FileEntry.OwnerName);
    try
      ODACL := FileObject.GetDACL;
      if ODACL <> nil then
      begin
        try
          if ODACL.IndexOf(FileEntry.AccessControlEntry) = -1 then
          begin
            ODACL.Add(FileEntry.AccessControlEntry);
            FileObject.SetDACL(ODACL);
          end;
        except
        end;
      end;
    finally
      FileObject.Free;
      FreeAndNil(ODACL);
    end;
    Result := true;
  end;
end;
2. Kopieren der Dateien mittels CopyFile

Damit die einfache Zuweisung von
Delphi-Quellcode:
ODACL.Add(FileEntry.AccessControlEntry);
funktioniert sieht TFileEntry.SetAccessControlEntry so aus
Delphi-Quellcode:
procedure  TFileEntry.SetAccessControlEntry(Value : TJwSecurityAccessControlEntry);
begin
  if FAccessControlEntry <> Value then
    FAccessControlEntry := TJwDiscretionaryAccessControlEntryAllow.Create(nil,
                                                                Value.Flags,
                                                                Value.AccessMask,
                                                                Value.SID);
end;
Das Problem:
Die Routinen laufen alle ohne Fehler durch, nur werden die Berechtigungen des
Zielverzeichnisses nicht gesetzt.
Liegt es an der falsch verstandenen Umsetzung von TFileEntry.SetAccessControlEntry, oder
ist der Fehler in CreateFolder, oder ganz wo anders?

Für Tipps und Anregungen wie immer Dankbar

Alter Mann

Dezipaitor 22. Aug 2008 19:43

Re: Berechtigungen einer Datei setzen (jwscl)
 
Nur ein Schuss ins Blaue:
In SetAccessControlEntry kopierst du die Flags der anderen ACE. Meiner Meinung nach wird da das Flag afInheritedAce, welches definiert, dass ein ACE vererbt ist, angegeben und dann von Windows ignoriert, da es ungültig ist.


Ein Mapping ist nur notwendig, wenn du generische Rechte verwendest (GENERIC_ALL, GENERIC_READ, usw). Dann wird, wenn ein solches Recht irgendwo in den ACEs gefunden wird, in die explizite Rechte umgewandelt.
z.B. GenericRead -> STANDARD_RIGHTS_READ or READ_CONTROL or SYNCHRONIZE or FILE_READ_EA or FILE_READ_DATA or FILE_READ_EA

p80286 22. Aug 2008 22:07

Re: Berechtigungen einer Datei setzen (jwscl)
 
Hallo Alter Mann,

Zitat:

nur werden die Berechtigungen des
Zielverzeichnisses nicht gesetzt.
verstehe ich so, daß zwar ein Verzeichnis erstellt wird, aber nicht die von Dir gewünschten Berechtigungen vergeben werden, sondern "nur Standardberechtigungen". Die Berechtigungen der einzelnen Dateien stimmen hingegen.

Da ich (zu meiner Schande) nicht ganz durch Deinen Code durchsteige, erteile ich Dir den (wohl überflüssigen) Rat eine Musterberechtigung für ein Verzeichnis zu erstellen, die einmalig beim Erstellen des Verzeichnisses vergeben wird.

Gruß
K-H

Alter Mann 23. Aug 2008 09:31

Re: Berechtigungen einer Datei setzen (jwscl)
 
Hi

die Standardberechtigungen werden auf dem Root des Laufwerkes gesetzt, sodass diese auch für das Zielverzeichnis
gelten. Hinzugefügt werden soll nur die Berechtigung für den User. Die Berechtigungen für die Dateien und den weiteren
Verzeichnissen im Zielverzeichnis ergeben sich dadurch automatisch, da sie ohne weitere Berechtigungen kopiert werden.

Gruß

Dezipaitor 23. Aug 2008 10:12

Re: Berechtigungen einer Datei setzen (jwscl)
 
Wenn du einen neuen User in die ACL einfügst, dann muss dessen ACE angepasst werden. Und wenn Unterordner und -dateien diese Berechtigung auch bekommen sollen, muss einfach nur noch das Container (afContainerInheritAce) und Objekte (afObjectInheritAce) gesetzt werden, denn dann haben alle es andere.

Alter Mann 23. Aug 2008 14:41

Re: Berechtigungen einer Datei setzen (jwscl)
 
Hi

@Dezipaitor
Das ist schon klar, das Problem ist, dass die Berechtigungen des hinzugefügten Users überhaupt nicht gesetzt werden.

Dezipaitor 23. Aug 2008 14:48

Re: Berechtigungen einer Datei setzen (jwscl)
 
Wie sind denn die Flags?D.h. sind sie so wie gedacht?

Was ich gerade bemerkt habe ist, dass du SID einfach übergibst. Da Create
jedoch keine Kopie anlegt und du keinen 5 Parameter (ownSid = true) verwendest,
könnte es zu Problemem kommen (doppelt freigegebenes Objekt).
Nutze den Kopierkonstruktor:

Delphi-Quellcode:
procedure  TFileEntry.SetAccessControlEntry(Value : TJwSecurityAccessControlEntry);
begin
  if FAccessControlEntry <> Value then
  begin
    FAccessControlEntry := TJwDiscretionaryAccessControlEntryAllow.Create(Value);
    FAccessControlEntry.Flags := [afObjectInheritAce, afContainerInheritAce];  
    //dieses ACE ist in keiner Liste!
  end;
end;
Versuch das einfach mal.

Alter Mann 23. Aug 2008 17:25

Re: Berechtigungen einer Datei setzen (jwscl)
 
Hi,

Habe die Ausführung übernommen und folgende Meldung erhalten:

"Es gibt keine Überladene Version von 'Create', die man mit diesen Argumenten aufrufen kann."

Komisch, in der 'jwsclAcl' steht:
Delphi-Quellcode:
TJwDiscretionaryAccessControlEntry = class(TJwSecurityAccessControlEntry);
TJwDiscretionaryAccessControlEntryAllow = class(TJwDiscretionaryAccessControlEntry);
es sollte also gehen :gruebel:

Gruß

Dezipaitor 23. Aug 2008 17:34

Re: Berechtigungen einer Datei setzen (jwscl)
 
Ja der Parametertype muss auch TJwDiscretionaryAccessControlEntryAllow sein.

Alter Mann 23. Aug 2008 18:38

Re: Berechtigungen einer Datei setzen (jwscl)
 
Hi,

Ich habe es hin bekommen.

SetAccessControlEntry sieht jetzt so aus:
Delphi-Quellcode:
procedure  TFileEntry.SetAccessControlEntry(Value : TJwSecurityAccessControlEntry);
begin
  if FAccessControlEntry <> Value then
  begin
    FAccessControlEntry := TJwDiscretionaryAccessControlEntryAllow.Create(nil,
                           [afObjectInheritAce, afContainerInheritAce],
                           Value.AccessMask,
                           Value.SID,
                           false);
  end;
end;

@Dezipaitor
Das mit den Flags hat den erwünschten Effekt gehabt. Danke!!!

Gruß


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:10 Uhr.
Seite 1 von 2  1 2      

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