Is there any way to give my sandboxed Mac app read only access to files in ~/Library?
Asked Answered
H

1

14

I'm a little confused with the sandbox. Is this possible?

Thanks!

Hagridden answered 8/6, 2012 at 15:58 Comment(2)
Is it possible to get a write permission to my app with "com.apple.security.temporary-exception.files.absolute-path.read-write Enables read/write access to the specified files or directories at specified absolute paths."Sweetandsour
Why would 10 users favorite this but only 8 upvote it...?Dedication
D
37

Yes, but it requires a "temporary exception" entitlement. "Temporary" means that it may go away in some future version of the OS, but that's not much of a risk. The bigger problem is that word "exception": It means you will have to justify your use of the entitlement, or the App Store reviewers will probably reject you.

File a bug report explaining exactly what it is you think you ought to be able to do, but can't do today without access to ~/Library, and ideally also start a forum thread on the topic. They may suggest a workaround to use instead of accessing ~/Library (maybe even using private APIs), in which case, do what they say. Or they may say to use the temporary exception for now, in which case, do that. Or they may not respond, in which case you use the temporary exception and cross your fingers. In any case, make sure your App Store submission review notes have a link to the bug report and/or forum thread.

You will have to edit your project's entitlements plist manually to do this, but it's not very hard. Create a com.apple.security.temporary-exception.files.home-relative-path.read-only array, with one string, "/Library/". Like this:

<key>com.apple.security.temporary-exception.files.home-relative-path.read-only</key>
<array>
    <string>/Library/</string>
</array>

The extra / at the end is how the sandbox knows you want to access a directory, rather than a file. If you leave it off, you will get access to all files in ~/Library, which is what you asked for, but not to files in (recursive) subdirectories of ~/Library, like, say, ~/Library/LaunchAgents/com.mycompany.myapp.myoldagent.12345678-ABCD-EF00-1234-567890ABCDEF.plist, which is what you probably want. See File Access Temporary Extensions in the Entitlement Key Reference documentation.

Also, notice that you already have access "for free" to certain things under ~/Library, either because they get copied into your container, or indirectly when you use the appropriate APIs instead of using paths. So, there may be a better way to accomplish what you're doing—e.g., to read files left by a previous non-sandboxed version of your app, you might be able to migrate them into the container and read them there.

One more thing: Just having access to ~/Library doesn't change what NSHomeDirectory(), URLsForDirectory:inDomains:, etc. will return--you'll still get ~/Containers/com.mycompany.myproduct/Data/Library instead. Apple's semi-official recommendation for dealing with this is to use BSD APIs to get the user's real home directory, and the simplest way is this:

const char *home = getpwuid(getuid())->pw_dir;
NSString *path = [[NSFileManager defaultManager] 
                  stringWithFileSystemRepresentation:home
                  length:strlen(home)];
NSURL *url = [NSURL fileURLWithPath:path isDirectory:YES];

A few notes:

  • It's generally not a good idea to call getpwuid too frequently. The best solution is to call this code once early, and then cache the resulting NSURL.
  • This can obviously also be used to get other users' home (and therefore Library) directories, but the App Store almost certainly won't allow any software that actually tries that.
  • The fact that the library is at ~/Library is considered an "implementation detail" that could change one day, which is another reason (on top of the entitlement) that this has to be considered a temporary workaround until Apple provides a real solution to your higher-level problem, and it might be worth mentioning in your review notes.
Delayedaction answered 8/6, 2012 at 21:1 Comment(7)
Upvoted, although your proposed solution of using getpwent()->pw_dir returns /var/virusmails for me.Grissel
This has worked for me: getpwnam([NSUserName() UTF8String])->pw_dirGrissel
Sorry; the "right" way is getpwuid(getuid()), not getpwent() (which returns the first entry). The original solution endorsed by one of Apple's sandbox engineers on the forums had the same mistake, and was later corrected, and somehow the wrong version stuck in my head. I've updated my answer. Anyway, getpwnam is just as good as getpwuid, so you can stick with what's already working for you.Delayedaction
I think you need to add a slash to the end of the path like <string>/Library/</string> due to the documentation at developer.apple.com/library/ios/documentation/Miscellaneous/… otherwise you can only address files not directories.Paronychia
@anka: Well, he asked for "files in ~/Library", but you're right, he almost certainly wants files under some subdirectory of ~/Library.Delayedaction
Does this still work on 10.12+? I've got an app extension that is trying to use this and failing. The relevant part of the entitlements file: <dict> <key>com.apple.security.app-sandbox</key> <true/> <key>com.apple.security.files.user-selected.read-only</key> <true/> <key>com.apple.security.temporary-exception.files.home-relative-path.read-write</key> <array> <string>/Library/Application Support/{COMPANY}/</string> <string>/Library/Application Support/{COMPANY}/ipc_socket</string> <string>/Library/Logs/{COMPANY}/</string> </array> </dict> but it can't see the socket.Weiler
Is there a way to grant access to the whole home directory?Hiatt

© 2022 - 2024 — McMap. All rights reserved.