How to edit specific files in /Library folder on Mac with Apple Sandbox? - cocoa

From Apple's documentation, I didn't understand if there's any way to get pre-approved entitlements to edit files in a specific folder located in the system /Library folder, without asking the user to choose this specific location via NSOpenPanel or similar.
I don't mind, and would actually like, to ask for the user's credentials to make such a change, at specific points in the application's lifetime; but letting the user choose which folder to modify just doesn't make sense in my case.

Found it - the application needs a File Access Temporary Exception entitlement.

Related

How to Trash items that are not owned by the current user, the same way the Finder does?

I am writing a tool that offers the option to trash selected items (files, folders). Usually, I'd call -[NSFileManager trashItemAtURL:...] for each of those items, as it's also explained in this and in this SO question.
However, these do not work when trying to delete files from a directory owned by a different user, such as root. My tool shall offer the same option as the Finder in this case, i.e. ask the user to authorize the operation by providing the credentials of an Admin user, and then my app would move the items to the Trash like the Finder does.
I've tried solving this by using a privileged helper, as outline by the EvenBetterAuthorizationSample example code, using launchd, SMJobBless and XPC Services.
The problem with that is, however, that the privileged helper runs as the root user, without knowledge of the current user my app runs under. The result is that, when it trashes a file, it ends up in the root user's Trash folder and not, as the Finder would do it, in the user's Trash folder.
How do I solve this, i.e. how do I move items not owned by the user to the current user's trash instead of the root user's Trash?
Is there some trick I can use that would let me keep using one of the existing trash oder recycle functions?
Doing the move myself is not going to work properly because for Put Back to work, the Trash's .DS_Store file would need to be updated, and there's no API for that, AFAIK.
I have almost found a solution:
Analysis
When the helper is run, e.g. from launchd, or via AuthorizationExecuteWithPrivileges (under macOS 10.15), it may be running as root, with no knowledge of the logged-in user, hence it cannot determine the user's Trash folder.
Oddly, the Environment variables (see man env) may even show the current user's name and home dir, yet the real user id, which one can query with getuid(), will return 0 (root), which also results in NSUserName()and NSHomeDirectory() returning the root user's information. And it appears that trashItemAtURL and related functions rely on NSHomeDirectory() to determine the Trash folder location.
Half-working solution
Fortunately, there is a way to change the real user id, with setreuid.
Therefore, in my testing, when I call setreuid (501, 0) (501 being the uid of the currently logged-in user), then trashItemAtURL does move the file to the user's Trash folder, indeed, along with automatic renaming where necessary.
However, this does not make the Put Back work, the way it would when trashing the same file using the Finder.
Making Put Back work
Looks like the reason for Put Back not working comes from a deeper issue: It appears to be a long-standing bug in the macOS framework, see this bug report.
Which basically means: This is the best we can get out of it until Apple fixes the underlying bug.
The only working alternative to make Put Back work is to ask the Finder to trash the items using AppleEvents / AppleScript.

Distinguish things like .app/.xcodeproj and actual folders in Cocoa

I am trying to build an alternative file manager that works similar to the default Finder in Cocoa.
As you can imagine, the app needs to show a list of files/subfolders in certain directory, and when the user click on an item, it checks whether it's a folder or a file that a user has clicked. If it's a folder, the app simply shows the content of the folder. If it's a file, it will be opened with the default application.
I used NSFileManager.file​Exists(at​Path:​is​Directory:​) to determine if an item at certain path is a folder. This works well in most cases, but for things like something.app or project.xcodeproj, they are also considered as directories according to the method.
I know it's true that technically they are just folders, but is there a way in Cocoa to distinguish them from actual folders?
Use (NS)URL.
Get the values for resource keys isDirectoryKey and isPackageKey via resourceValues(forKeys.
In case of bundles isPackage is true.

Is it possible to access file system in Mac App without file browser dialogue

In our Mac App we have following credential to entitlement.plist which enables us to read/write to user's file system followed by file browser dialogue:
com.apple.security.files.user-selected.read-write
That does mean we able to read/write a file/folder if once accessed by file browser dialogue. We never able to read/write to files/folder if not accessed by file browser dialogue at least once in an application life cycle.
I didn't found any other possible credential too to entitlement.plist which can enable us read/write to files/folder by completely removing any use of file browser dialogue. Is there any way we can achieve this?
I assume your app is Sandboxed and if so, it's only possible to access the filesystem as defined here:
Powerbox and File System Access Outside of Your Container Your
sandboxed app can access file system locations outside of its
container in the following three ways:
At the specific direction of the user
By using entitlements for
specific file-system locations (described in Entitlements and System
Resource Access)
When the file system location is in certain
directories that are world readable
The OS X security technology that interacts with the user to expand your sandbox is called Powerbox. Powerbox has no API. Your app uses Powerbox transparently when you use the NSOpenPanel and NSSavePanel classes.
Well, the whole point of Sandboxing is to actually don't allow you to access user's files without their knowledge.
The only thing you can probably do is to use com.apple.security.temporary-exception.files.absolute-path.* entitlements to access some specific (read hard-coded) file system locations. You can learn more about temporary exceptions here: App Sandbox Temporary Exception Entitlements.
But keep in mind that you'll have to explain to the Apple Review Team why you need those exceptions in the first place.

Mac App Sandbox testing - how remove existing folder access permissions

I'm currently adding Sandboxing support to my app.
Having give permission to my app to access a folder (by dragging it onto my Window) and I would now like to revoke that permission so that I can retest what happens before that permission is given.
How can I do that?
I'm not yet using URL bookmarks, and yet the permission persists across restarts of the application. I don't know if this is because it's a folder rather than a file?
Before you change the permissions of file or folder, you must store the current one for later use. I have never seen a method or system-call to restore previous permissions after a change.

NSSavePanel for saving a file after sandboxing

I have a mac AVRecording app, which records a video and save it to a location selected via NSSavePanel. It was working fine till I sandboxed the app.
For sandboxing I have added the following entitlements
com.apple.security.files.user-selected.read-write
com.apple.security.assets.movies.read-write
com.apple.security.files.downloads.read-write
This enables saving to Downloads and movies folder only.
How is it possible to save my file to any desired location, Desktop, Documents etc ?
It's not clear from your question whether you are referring to saving a particular file (in which case you can use the NSSavePanel and manually copy the file using NSFileManager to write the file into the user-specified new file), or whether you are referring to having the user choose a location for all future downloads.
If you want to prompt the user for a location to use for future downloads, you'll need to use the secure bookmark entitlement and secure bookmarks to retain access to the folder.
There's another stackoverflow answer about sandboxing which covers the process of saving and using the secure bookmark.

Resources