This question is really about transferring file permissions from a parent macOS application that is not sandboxed, to a child XPC service that is sandboxed.
This question, App sandbox: how to allow XPC service to read file that user opened in parent app?, is almost identical in purpose, but differs in implementation. (An accepted answer on that question involves sending a security-scoped bookmark across, which works, but is really slow.)
The lower-level implementation that Apple seems to recommend is to send a file descriptor over to the XPC service. Apple's Secure Coding Guide talks about this very issue under "Inheriting File Descriptors".
Using the C-based XPC framework, I can successfully send a file descriptor from the main application to the XPC service and read data using that file descriptor:
In the main app:
NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:@"..."];
xpc_dictionary_set_fd(dict, "fd", handle.fileDescriptor);
In the XPC service:
int fd = xpc_dictionary_dup_fd(dict, "fd");
NSFileHandle *handle = [[NSFileHandle alloc] initWithFileDescriptor:fd
closeOnDealloc:YES];
NSData *data = [handle readDataOfLength:1000];
NSLog(@"Read data of length: %@", @(data.length));
The XPC service is able to read that data. However, any attempts to now create an NSURL using a file path (NSString
) that points to the same file will fail. This is problematic because the APIs that I want to use in the XPC service all require an NSURL
.
I can't see anyway to create an NSURL
from a file descriptor nor convert a file descriptor into an NSURL
, but perhaps I've overlooked something.
Is there a way to create an NSURL from a file descriptor, or have a newly created NSURL inherit the read-only permissions of the file descriptor?
Alternatively, is there another way to transfer file permissions from a parent process to a child XPC process that doesn't involve having to create an security scoped bookmark, archiving it and then unarchiving it on the other end?
macOS 10.12/10.13
Edit 1
Apple's SandboxedFetch sample code uses the file descriptor technique perfectly, but the functions it uses in the XPC service are able to take file descriptors. Namely, it just uses read()
, fdopen()
and curl
.