I have a global daemon managed by launchd, whose .plist is installed in /Library/LaunchDaemons).
To be correctly entitled and code-signed so it can communicate with EndpointSecurity framework, its executable resides in a normal Mac App bundle (main() will run as minimal UI when launched from UI, and as a daemon when launched by launchd).
This means that the ProgramArguments.0 in its .plist looks something like
/Library/PrivilegedHelperTools/MyDaemonApp.app/Contents/MacOS/MyDaemonApp
Now I need this daemon to publish an XPC Service (with few control commands) so that other components of our system (UI app, a user-context launchd-daemon and another launchd global-daemon) will be able to connect to The XPC Service and control it via the published protocol.
I read some answers here, and also found a working order sample code that does just this here - https://github.com/jdspoone/SampleOSXLaunchDaemon
But when I apply its content to my global daemon, word for word - it doesn't work - meaning, clients cannot create a connection to The XPC Service.
The daemon is up and running, and functional. its .plist is quite simple and looks like this:
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.mycompany.itm.service</string>
<key>KeepAlive</key>
<true/>
<key>RunAtLoad</key>
<true/>
<key>MachServices</key>
<dict>
<key>com.mycompany.itm.service</key>
<true/>
</dict>
<key>ProgramArguments</key>
<array>
<string>/Library/PrivilegedHelperTools/IMyDaemonApp.app/Contents/MacOS/MyDaemonApp</string>
<string>-monitor</string>
<string>-protectDeviceProtocol</string>
<string>USB</string>
</array>
</dict>
</plist>
It creates and starts an XPC listener in MYXPCListener.h like thus:
#import <Foundation/Foundation.h>
#import "MYXPCProtocol.h"
NS_ASSUME_NONNULL_BEGIN
@interface OITPreventionXPCService : NSObject (instancetype) init;
(void) start; /* Begin listening for incoming XPC connections */
(void) stop; /* Stop listening for incoming XPC connections */
@end
NS_ASSUME_NONNULL_END
and the implementation is:
/* AppDelegate.m */
@interface MYXPCService () <NSXPCListenerDelegate, OITPreventionXPCProtocol>
@property (nonatomic, strong, readwrite) NSXPCListener *listener;
@property (nonatomic, readwrite) BOOL started;
@end
@implementation OITPreventionXPCService (instancetype) init {
if ((self = [super init]) != nil) {
_listener = [[NSXPCListener alloc] initWithMachServiceName:@"com.mycompany.itm.service"];
_listener.delegate = self;
if (_listener == nil) {
os_log_error(myLog, "XPCListener failed to initialize");
}
_started = NO;
}
return self;
} (void) start {
assert(_started == NO);
[_listener resume];
os_log_info(myLog, "XPCListener resumed");
_started = YES;
} (void) stop {
assert(_started == YES);
[_listener suspend];
os_log_info(myLog, "XPCListener suspended");
_started = NO;
}
/* NSXPCListenerDelegate implementation */
(BOOL) listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
os_log_info(myLog, "Prevention XPCListener is bequsted a new connection");
assert(listener == _listener);
assert(newConnection != nil);
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MYXPCProtocol)];
newConnection.exportedObject = self;
		[newConnection resume];
return YES;
}
/* Further down this implementation, I have implementations to all the methods in MYXPCProtocol. */
@end
Now the client code (and I tried EVERY kind of client, signed unsigned, daemon, UI, root privileged, or user-scoped - whatever). For example, in the AppDelegate of a UI app:
#import "AppDelegate.h"
#import "MYXPCProtocol.h"
@interface AppDelegate ()
@property (strong) IBOutlet NSWindow *window;
@property (nonatomic, strong, readwrite) NSXPCConnection *connection; /* lazy initialized */
@end
@implementation AppDelegate (NSXPCConnection *) connection
{
if (_connection == nil) {
_connection = [[NSXPCConnection alloc] initWithMachServiceName:daemonLabel options:NSXPCConnectionPrivileged];
_connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MYXPCProtocol)];
_connection.invalidationHandler = ^{
self->_connection = nil;
NSLog(@"connection has been invalidated");
};
[_connection resume]; /* New connections always start suspended */
}
return _connection;
}
(IBAction) getServiceStatus:(id)sender
{
[self.connection.remoteObjectProxy getStatus:^(NSString * _Nonnull status) {
NSLog(@"MY XPC Service status is: %@", status);
}];
}
@end
but no matter what I do - I always get the "connection invalidated".
The sample launchDaemon that works - is not code-signed at all!!! but mine, which is both signed and checking of which yields
$ spctl --assess --verbose IMyDaemonApp.app
IMyDaemonApp.app: accepted
source=Notarized Developer ID
I'm at a loss - and would like to get any advice, or any helpful documentation (I've been reading TN2083, and man launchctl and man launchd.plist and many other pages - to no avail. There seems to be no real "programming guide" for XPC and no reasonable sample code on Apple developer site to fit my needs.
Last - this is MacOS 10.15.7, and latest Xcode 12.3
Post
Replies
Boosts
Views
Activity
My new EndpointSecurity client code receives event messages of type esmessaget. These contain 3 time values.
struct timespec time;
uint64_t mach_time;
uint64_t deadline;
To interpret the deadline I refer to the mach_time. However, when I wish to log/formet/otherwise-consider the "wall time" where the event was created - I need to translate the timespec into NSDate (hmm... NSTimeInterval?) and I fail to find any documentation or hint about the right way to do so.
What I tried so far looks like this:
NSDate * timestamp = [NSDate dateWithTimeIntervalSince1970:(double)(message->time.tv_sec) + (double)(message->time.tv_sec) / 1E9 ];
which at least mathematically seems reasonable, but I'm not sure this is the right answer, and I don't know anything about the behaviour of timespec, its origin and accuracy, and whether or not it is consistent.
Can anyone shed a little light on the relation between these two time formats?
Thanks!
Hi. I watched the short "Optimize the Core Image pipeline for your video app" session several times, all excited, because it is at least 5 years that CI code-samples for MacOS are nonfunctional, and failed to make them work.
My application (for Microscopy) needs to apply (mostly built-in) CI filters onto live video coming from an external IIDC/DCam camera. My current code is AVFoundation based, but I never managed to apply filters onto the video, and as I said Documentation and code-samples deteriorated to the point of no use.
This beautiful session shows how to create an AVPlayerView and set it up for displaying CI-filtered video - but only for an "asset" (meaning - dead video from disk). How to do it for live "Preview" video?
Also, is it too much to ask for a simple working order modern MacOS sample of CoreImage use?
Thanks!
(BTW I would be glad to move to MTKView instead- have I known how to tie the camera input to it. Again - Docs are unusable, and no reasonable sample exists for MacOS. Not even for the simplest of tasks.
My agent/service relies on Accessibility APIs. Being installed by IT on all corporate Macs, it receives its permission to use these APIs via a configuration profile installed on the Mac, and not via the System-Preferences Security & Privacy panel (Privacy tab, Accessibility item).
Problem is - if that profile is removed, or changed to remove this permission - The agent currently has no way to know it, and will hang on the next call to some AX API.
our code calls
@result Returns TRUE if the current process is a trusted accessibility client, FALSE if it is not.
*/
extern Boolean AXIsProcessTrustedWithOptions (CFDictionaryRef __nullable options) CF_AVAILABLE_MAC(10_9);
before using other AX APIs, but sadly - the method returns true even when accessibility has been denied by removing the profile.
By contrast - if If user manually un-checks the Accessibility for this agent in the System-Preferences panel - the function returns false immediately.
If after removing the profile, I kill my agent (launchd then relaunches it) - then calling AXIsProcessTrustedWithOptions returns false as expected.
This seems to be a bug of some kind or incomplete behaviour, but I need a workaround as soon as possible.
My first "wish" would be to be able to register for and receive some system-wide NSNotification about "configuration profile changes", at which time, I could decide to exit my agent, and relaunch with accessibility permissions synchronised.
Or is there any AX internal notification I could register for? haven't found any.
Any clue would be greatly appreciated.