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