Cocoa: Entitlements for file
Original Reporter info from Mantis: crlab @neurolabusc1
-
Reporter name: Chris Rorden
Original Reporter info from Mantis: crlab @neurolabusc1
- Reporter name: Chris Rorden
Description:
With recent versions of MacOS, by default applications run in a sandbox and operate with limited entitlements. Specifically, they are only able to read and write to files that the user has explicitly selected with this application (e.g. through a file open dialog or dragging and dropping). Attempting to read a file outside this sandbox will fail. This is a nice security feature.
I think the LazFileUtils FileIsReadable function should return whether the file is readable by the invoking application, not whether its file system properties are set to allow a program with appropriate entitlements to read it. The demo program illustrates the problem, where file is readable reports a text file does have its read permission set to true, but the invoking application does not have permission to read it and will subsequently fail. I have found this an issue with my most recently used menu, where a user can select images they viewed the last time they used the application. MacOS is smart enough to remember entitlements between subsequent launches of the program. However, if the user upgrades my software, the software will read the previous preference file, but MacOS sees this as a new application without the same entitlements.
Add(fnm +' FileIsReadable ' + BoolToStr(FileIsReadable(fnm),TRUE));
ns := NSString.alloc.initWithCString(@fnm[1]);
Add(fnm +' NSFileManager isReadableFileAtPath ' + BoolToStr(NSFileManager.defaultManager.isReadableFileAtPath(ns),true));
Steps to reproduce:
- Create a text file named 'notes.txt' on Desktop.
- Run the attached program.
- Note that both FileIsReadable and the NSFileManager isReadableFileAtPath claim that the file can be opened.
- Note that when the program attempts to read the file, it fails.
/Users/chris/src/entitlements/project1.app/Contents/MacOS/project1 : Got 0 command-line parameters:
/Users/chris/Desktop/notes.txt FileExists: True
/Users/chris/Desktop/notes.txt FileSize 13125
/Users/chris/Desktop/notes.txt FileIsReadable True
/Users/chris/Desktop/notes.txt NSFileManager isReadableFileAtPath True
/Users/chris/Desktop/notes.txt IsReadable False
Additional information:
The software includes my own kludge to determine if a file is truly readable by an application: it actually attempts to read the first byte of data. I suspect there are more elegant ways to do this. However, this does work for me:
function IsReadable(fnm: string): boolean;
label 222;
var
f: file;
b: byte;
begin
result := false;
if not fileexists(fnm) then goto 222;
if FileUtil.FileSize(fnm) < 2 then goto 222;
AssignFile(f, fnm);
{$I+}
try
FileMode := fmOpenRead; //Set file access to read only
Reset(f, 1);
if ioresult <> 0 then
exit;
b := 0;
BlockRead(f, b, sizeof(b)); //Byte-order Identifier
CloseFile(f);
result := true;
except
result := false;
end;
222:
if result then exit;
writeln('Unable to read file (not in sandbox?): '+fnm);
end;
Mantis conversion info:
- Mantis ID: 37403
- OS: Darwin
- OS Build: 11.0 Beta
- Build: 63600
- Platform: AArch64
- Version: 2.1 (SVN)
- Monitored by: » @trevoz (Trevor Roydhouse)