main.m
 1  #import <Foundation/Foundation.h>
 2  #import <Foundation/NSXPCConnection_Private.h>
 3  #import <unistd.h>
 4  #import <xpc/private.h>
 5  #import <sandbox.h>
 6  
 7  #import <Security/SecEntitlements.h>
 8  #import <utilities/debugging.h>
 9  #import <utilities/SecFileLocations.h>
10  
11  #import "KeychainStasher.h"
12  
13  NSString* const KeychainStasherMachServiceName = @"com.apple.security.KeychainStasher";
14  
15  @interface ServiceDelegate : NSObject <NSXPCListenerDelegate>
16  @end
17  
18  @implementation ServiceDelegate
19  
20  - (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
21      // We should encounter no more than 1 transaction per boot in normal conditions, so get out of everyone's way ASAP
22      xpc_transaction_exit_clean();
23  
24      NSNumber* value = [newConnection valueForEntitlement:kSecEntitlementPrivateStashService];
25      if (value == nil || ![value boolValue]) {
26          secerror("KeychainStasher: client not entitled, rejecting connection");
27          [newConnection invalidate];
28          return NO;
29      }
30  
31      newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(KeychainStasherProtocol)];
32      newConnection.exportedObject = [KeychainStasher new];
33      [newConnection resume];
34      return YES;
35  }
36  
37  @end
38  
39  int main(int argc, const char *argv[])
40  {
41      if (geteuid() == 0) {
42          secerror("KeychainStasher invoked as root, do not want.");
43          return 1;
44      } else {
45          secnotice("KeychainStasher", "Invoked with uid %d", geteuid());
46      }
47  
48      NSString* analyticsdir = [[(__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory(nil) URLByAppendingPathComponent:@"Analytics/"] path];
49      if (analyticsdir) {
50          const char* sandbox_parameters[] = {"ANALYTICSDIR", analyticsdir.UTF8String, NULL};
51          char* sandbox_error = NULL;
52          if (0 != sandbox_init_with_parameters("com.apple.security.KeychainStasher", SANDBOX_NAMED, sandbox_parameters, &sandbox_error)) {
53              secerror("unable to enter sandbox with parameter: %s", sandbox_error);
54              sandbox_free_error(sandbox_error);
55              abort();
56          }
57      } else {    // If this fails somehow we will go ahead without analytics
58          char* sandbox_error = NULL;
59          if (0 != sandbox_init("com.apple.security.KeychainStasher", SANDBOX_NAMED, &sandbox_error)) {
60              secerror("unable to enter sandbox: %s", sandbox_error);
61              sandbox_free_error(sandbox_error);
62              abort();
63          }
64      }
65  
66      ServiceDelegate *delegate = [ServiceDelegate new];
67      NSXPCListener *listener = [[NSXPCListener alloc] initWithMachServiceName:KeychainStasherMachServiceName];
68      listener.delegate = delegate;
69      [listener resume];
70      [[NSRunLoop currentRunLoop] run];
71      return 0;
72  }