Einzelnen Beitrag anzeigen

Alter Mann

Registriert seit: 15. Nov 2003
Ort: Berlin
934 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#1

Berechtigungen einer Datei setzen (jwscl)

  Alt 22. Aug 2008, 17:22
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 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
  Mit Zitat antworten Zitat