main.m   [plain text]

//
// main.m
// trustdFileHelper
//
// Copyright © 2020 Apple Inc. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <Foundation/NSError_Private.h>
#import <Foundation/NSXPCConnection_Private.h>
#import <Security/SecTask.h>

#import <xpc/private.h>
#import <xpc/xpc.h>
#import <xpc/activity_private.h>

#import <dirhelper_priv.h>
#include <sandbox.h>
#include <utilities/SecCFWrappers.h>
#include <utilities/SecFileLocations.h>

#include "trust/trustd/trustdFileLocations.h"
#include "trust/trustd/trustdFileHelper/trustdFileHelper.h"

@interface ServiceDelegate : NSObject <NSXPCListenerDelegate>
@end

@implementation ServiceDelegate

- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection
{
if(![[newConnection valueForEntitlement:@"com.apple.private.trustd.FileHelp"] boolValue]) {
SecTaskRef clientTask = SecTaskCreateWithAuditToken(NULL, [newConnection auditToken]);
secerror("rejecting client %@ due to lack of entitlement", clientTask);
CFReleaseNull(clientTask);
return NO;
}

secdebug("ipc", "opening connection for %d", [newConnection processIdentifier]);
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(TrustdFileHelper_protocol)];
TrustdFileHelper *exportedObject = [[TrustdFileHelper alloc] init];
newConnection.exportedObject = exportedObject;
[newConnection resume];
return YES;
}

@end

static void enter_sandbox(void) {
char buf[PATH_MAX] = "";

if (!_set_user_dir_suffix("com.apple.trustd") ||
confstr(_CS_DARWIN_USER_TEMP_DIR, buf, sizeof(buf)) == 0 ||
(mkdir(buf, 0700) && errno != EEXIST)) {
secerror("failed to initialize temporary directory (%d): %s", errno, strerror(errno));
exit(EXIT_FAILURE);
}

char *tempdir = realpath(buf, NULL);
if (tempdir == NULL) {
secerror("failed to resolve temporary directory (%d): %s", errno, strerror(errno));
exit(EXIT_FAILURE);
}

if (confstr(_CS_DARWIN_USER_CACHE_DIR, buf, sizeof(buf)) == 0 ||
(mkdir(buf, 0700) && errno != EEXIST)) {
secerror("failed to initialize cache directory (%d): %s", errno, strerror(errno));
exit(EXIT_FAILURE);
}

char *cachedir = realpath(buf, NULL);
if (cachedir == NULL) {
secerror("failed to resolve cache directory (%d): %s", errno, strerror(errno));
exit(EXIT_FAILURE);
}

const char *parameters[] = {
"_TMPDIR", tempdir,
"_DARWIN_CACHE_DIR", cachedir,
NULL
};

char *sberror = NULL;
if (sandbox_init_with_parameters("com.apple.trustdFileHelper", SANDBOX_NAMED, parameters, &sberror) != 0) {
secerror("Failed to enter trustdFileHelper sandbox: %{public}s", sberror);
exit(EXIT_FAILURE);
}

free(tempdir);
free(cachedir);
}

int
main(int argc, const char *argv[])
{
[NSError _setFileNameLocalizationEnabled:NO];
enter_sandbox();

static NSXPCListener *listener = nil;

ServiceDelegate *delegate = [ServiceDelegate new];
listener = [[NSXPCListener alloc] initWithMachServiceName:@TrustdFileHelperXPCServiceName];
listener.delegate = delegate;

// We're always launched in response to client activity and don't want to sit around idle.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5ull * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
secnotice("lifecycle", "will exit when clean");
xpc_transaction_exit_clean();
});

[listener resume];
secdebug("ipc", "trustdFileHelper accepting work");

dispatch_main();
}