14

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

Thanks!

dot
  • 2,823
  • 7
  • 38
  • 52
  • 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." – Govind Jan 19 '16 at 07:43
  • 1
    Why would 10 users favorite this but only 8 upvote it...? – Ky - Apr 17 '19 at 19:57

1 Answers1

36

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.
abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Upvoted, although your proposed solution of using `getpwent()->pw_dir` returns `/var/virusmails` for me. – Ivan Vučica Jun 28 '12 at 09:18
  • 2
    This has worked for me: `getpwnam([NSUserName() UTF8String])->pw_dir` – Ivan Vučica Jun 28 '12 at 09:27
  • 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. – abarnert Jun 28 '12 at 20:15
  • 3
    I think you need to add a slash to the end of the path like `/Library/` due to the documentation at http://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/AppSandboxTemporaryExceptionEntitlements.html#//apple_ref/doc/uid/TP40011195-CH5-SW7 otherwise you can only address files not directories. – anka Jan 02 '13 at 14:10
  • @anka: Well, he asked for "files in ~/Library", but you're right, he almost certainly wants files _under some subdirectory_ of ~/Library. – abarnert Jan 02 '13 at 19:04
  • 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: ` com.apple.security.app-sandbox com.apple.security.files.user-selected.read-only com.apple.security.temporary-exception.files.home-relative-path.read-write /Library/Application Support/{COMPANY}/ /Library/Application Support/{COMPANY}/ipc_socket /Library/Logs/{COMPANY}/ ` but it can't see the socket. – CBHacking Jul 21 '17 at 16:55
  • Is there a way to grant access to the whole home directory? – Violet Giraffe Nov 06 '19 at 14:26