Service Management

RSS for tag

The Service Management framework provides facilities to load and unload launched services and read and modify launched dictionaries from within an application.

Posts under Service Management tag

84 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Changes in behaviour of [SMAppService registerAndReturnError:] after Sonoma 14.4
I am using [SMAppService registerAndReturnError:] to register a launch agent from a plist bundled in the app (before the registration call a matching unregister is done via unregisterWithCompletionHandler as suggested by the docs). The non standard thing is that I am doing that in a root gui login with sudo to bootstrap my launch agent into gui/0 domain. This worked well until Sonoma 14.4 - now the call fails with: Error Domain=SMAppServiceErrorDomain Code=125 "Domain does not support specified action" UserInfo={NSLocalizedFailureReason=Domain does not support specified action} which is not really helpful. For now, i've switche to just using launchctl bootout and launchctl bootstrap to get around this, but could anyone elaborate on what has changed? My feeling is that something has changed in the logic that determines the domain - could it be that even with sudo the target domain is gui/ not gui/0 ? As far as I can see there are no ways to specify the domain from the SMAppService APIs right? Also a weird thing is that if run the code in a raw terminal in root gui it works as previously (but out of security, no thing really runs as root, everything is a launch agent under some less privileged user, and before Sonoma 14.4 sudoing with that less privileged user did work for [SMAppService registerAndReturn], now it does not, and what is also strange, doing sudo - and then sudo su also shows the same error code 125.
1
0
179
2w
Python Backend alongside MacOS Swift application
Context/Project Idea: I'm currently developing a project that consists of a macOS application using Swift and a local Python backend that executes specific tasks such as processing data. The Python backend is the core of this project, while the Swift application is a mere interface to interact with it. These two project parts should be decoupled so the user can theoretically run their own backend and connect the Swift application to it. Likewise, the user should be able to connect to the shipped backend using, e.g. curl. Current plan: My main idea is to use launchctl to launch a launchd agent which runs the Python backend. The script launching the backend will generate an API key stored in a keychain access group. The Swift application can then get that key and access the backend. The user can always get that API key from the keychain if they want to connect to it programmatically. Here are the main questions I have currently: Python Interpreter Consistency: I'm exploring options such as cx_Freeze or PyInstaller to create a standalone Python executable for better system stability. Does anyone have experience with these tools in a macOS environment, or are there other reliable alternatives worth considering? Adding a Launchd Agent to Xcode: How can I add a launchd agent to my Xcode project to manage a Python executable built with cx_Freeze or PyInstaller? What steps should I follow to ensure it functions properly? Keychain Access for Launchd Agent: Is it feasible for a launchd agent to access a Keychain access group? What configurations or permissions are necessary to implement this? Thanks in advance!
3
0
188
2w
How to correctly deploy bundled launchdaemons/launchagents?
I'm working on an enterprise product that's mainly a daemon (with Endpoint Security) without any GUI component. I'm looking into the update process for daemons/agents that was introduced with Ventura (Link), but I have to say that the entire process is just deeply unfun. Really can't stress this enough how unfun. Anyway... The product bundle now contains a dedicated Swift executable that calls SMAppService.register for both the daemon and agent. It registers the app in the system preferences login items menu, but I also get an error. Error registering daemon: Error Domain=SMAppServiceErrorDomain Code=1 "Operation not permitted" UserInfo={NSLocalizedFailureReason=Operation not permitted} What could be the reason? I wouldn't need to activate the items, I just need them to be added to the list, so that I can control them via launchctl. Which leads me to my next question, how can I control bundled daemons/agents via launchctl? I tried to use launchctl enable and bootstrap, just like I do with daemons under /Library/LaunchDaemons, but all I get is sudo launchctl enable system/com.identifier.daemon sudo launchctl bootstrap /Path/to/daemon/launchdplist/inside/bundle/Library/LaunchDaemons/com.blub.plist Bootstrap failed: 5: Input/output error (not super helpful error message) I'm really frustrated by the complexity of this process and all of its pitfalls.
3
0
188
3w
SMAppService fails to register agent with MDM
btm_launchagent.txt I have a menu bar app which should be triggered to start when a system extension is successfully installed. The menu bar app is configured as a agent which should be started by SMAppServer. SMAppService register/unregister the agent successfully when the program is running locally. When doing the program installation through JamfNow, which is a MDM system, it fails with following error. I think the problem here is that the backgroundtaskmanagementd trys to register the agent with an invalid uid=-1 or uid: 4294967295(0xFFFFFFFF). 2024-10-02 10:45:33.100537+0200 0x156d4 Activity 0x1b927 88 0 smd: (BackgroundTaskManagement) BTMManager.getEffectiveDisposition 2024-10-02 10:45:33.103478+0200 0x156dd Default 0x1b927 282 0 backgroundtaskmanagementd: [com.apple.backgroundtaskmanagement:main] effectiveItemDisposition: appURL=file:///Applications/Company%20Agent.app/, type=agent, url=Contents/Library/LaunchAgents/com.Company.agent.notifier.plist -- file:///, config={ BTMConfigArguments = ( ); BTMConfigBundleIdentifiers = ( ); BTMConfigExecutablePath = "Contents/Resources/CompanyNotifier.app/Contents/MacOS/CompanyNotifier"; BTMConfigLabel = "com.Company.agent.notifier"; } 2024-10-02 10:45:33.103544+0200 0x156dd Info 0x1b927 282 0 backgroundtaskmanagementd: [com.apple.backgroundtaskmanagement:main] effectiveItemDisposition: result=[disabled, allowed, visible, not notified] 2024-10-02 10:45:33.105120+0200 0x156d4 Default 0x1b927 88 0 smd: (BackgroundTaskManagement) [com.apple.backgroundtaskmanagement:main] getEffectiveDisposition: disposition=[disabled, allowed, visible, not notified], have LWCR=true 2024-10-02 10:45:33.105181+0200 0x156d4 Default 0x0 88 0 smd: [com.apple.xpc.smd:all] Found status: 0 for <private> 2024-10-02 10:45:33.240190+0200 0x154da Default 0x0 88 0 smd: [com.apple.xpc.smd:SMAppServiceFactory] Setting up BundleProgram keys for <private> 2024-10-02 10:45:33.240250+0200 0x154da Default 0x0 88 0 smd: [com.apple.xpc.smd:SMAppServiceFactory] Setting up BundleProgram keys for <private> 2024-10-02 10:45:33.240388+0200 0x154da Activity 0x1b92a 88 0 smd: (BackgroundTaskManagement) BTMManager.registerLaunchItemWithAuditToken 2024-10-02 10:45:33.243990+0200 0x156dd Default 0x1b92a 282 0 backgroundtaskmanagementd: [com.apple.backgroundtaskmanagement:main] registerLaunchItem: pid=3626, uid=-1, type=agent, parentURL=<private>, url=<private>, config=<private> 2024-10-02 10:45:33.244917+0200 0x156dd Default 0x1b92a 282 0 backgroundtaskmanagementd: [com.apple.backgroundtaskmanagement:main] registerLaunchItem: found existing item: uuid=AC0DBC9B-7A16-443E-ABFC-05DF0F534C08, name=CompanyNotifier, type=managed agent, disposition=[disabled, allowed, visible, notified], identifier=com.Company.agent.notifier, url=Contents/Library/LaunchAgents/com.Company.agent.notifier.plist -- file:/// 2024-10-02 10:45:33.245238+0200 0x156dd Debug 0x1b92a 282 0 backgroundtaskmanagementd: [com.apple.backgroundtaskmanagement:main] BTMStore: save scheduled. 2024-10-02 10:45:33.245281+0200 0x156dd Debug 0x1b92a 282 0 backgroundtaskmanagementd: [com.apple.backgroundtaskmanagement:main] RecordSet notification scheduled for uid -1 .... 2024-10-02 10:45:33.252358+0200 0x154da Error 0x0 88 0 smd: [com.apple.xpc.smd:SMAppService] Unable to submit job: <private> error: Error Domain=OSLaunchdErrorDomain Code=112 UserInfo={NSLocalizedFailureReason=<private>} 2024-10-02 10:45:33.252707+0200 0x156d4 Default 0x1b92a 88 0 smd: [com.apple.xpc.smd:all] Update request for identifier: <private> uid: 4294967295 2024-10-02 10:45:33.253190+0200 0x156dd Default 0x1b92a 282 0 backgroundtaskmanagementd: [com.apple.backgroundtaskmanagement:main] getItemWithIdentifier: identifier=com.Company.agent.notifier, uid=-1 2024-10-02 10:45:33.253759+0200 0x156d4 Error 0x1b92a 88 0 smd: [com.apple.xpc.smd:btm] Error getting BTMItem with Identifier: <private> uid: 4294967295 error: (null) 2024-10-02 10:45:33.253803+0200 0x156d4 Error 0x1b92a 88 0 smd: [com.apple.xpc.smd:all] Unable to find BTMItem for <private> in 4294967295 2024-10-02 10:45:33.253835+0200 0x156d4 Error 0x1b92a 88 0 smd: [com.apple.xpc.smd:all] Update operation returned error: 3, but no reply expected so error will be silent 2024-10-02 10:45:33.661537+0200 0x156dd Debug 0x0 282 0 backgroundtaskmanagementd: [com.apple.backgroundtaskmanagement:main] sending notification for uid -1, type 131080 2024-10-02 10:45:33.665159+0200 0x154fa Info 0x1b853 282 0 backgroundtaskmanagementd: [com.apple.backgroundtaskmanagement:main] fetchSFLItemsMatching: type=managed user item app 2024-10-02 10:45:33.665374+0200 0x154fa Activity 0x15dd3 282 0 backgroundtaskmanagementd: (BackgroundTaskManagement) BTMManager.userDataDidChange 2024-10-02 10:45:33.666041+0200 0x154da Activity 0x1b92d 88 0 smd: (BackgroundTaskManagement) BTMManager.userDataDidChange 2024-10-02 10:45:33.666651+0200 0x154fa Debug 0x15dd3 282 0 backgroundtaskmanagementd: (BackgroundTaskManagement) [com.apple.backgroundtaskmanagement:main] -[BTMManager handleUserDataDidChangeNotification:]: uid=-1, type=131080 2024-10-02 10:45:33.666085+0200 0x154da Debug 0x1b92d 88 0 smd: (BackgroundTaskManagement) [com.apple.backgroundtaskmanagement:main] -[BTMManager handleUserDataDidChangeNotification:]: uid=-1, type=131080 2024-10-02 10:45:36.218160+0200 0x154fa Debug 0x0 282 0 backgroundtaskmanagementd: [com.apple.backgroundtaskmanagement:main] -[BTMStore handleWriteTimer] entered 2024-10-02 10:45:36.218254+0200 0x154fa Debug 0x0 282 0 backgroundtaskmanagementd: [com.apple.backgroundtaskmanagement:main] -[BTMStore _save] entered 2024-10-02 10:45:36.224738+0200 0x154fa Default 0x0 282 0 backgroundtaskmanagementd: [com.apple.backgroundtaskmanagement:main] BTMStore: store saved to /var/db/com.apple.backgroundtaskmanagement/BackgroundItems-v9.btm Could it be a problem from the MDM system JamfNow or somewhere else? The whole logs is as attached. Thanks!
4
0
537
3w
Install non-sandboxed Helper app from sandboxed Main app
Hi, I developed a utility app that allows monitoring system activity and usage. It is a sandboxed app distributed via the Mac App Store. Because in the sandbox I cannot fetch enough data about system activity (like processor temperature, fans, etc.), I developed a little Helper app (non-sandboxed), which currently is distributed via my website, and to enable extra features it provides, the user is asked to download and install it manually (it installs itself as a daemon). I'm looking for ways to improve the user experience. Ideally, it would be a button inside the main app, which would download and install the helper app, without asking the user to do more than pressing a button. As far as I understand, in the previous versions of macOS, it would be possible with privileged helpers and SMJobBless, but those are deprecated APIs now. Another way I tried, is simply downloading the installer app from the website, but opening it programmatically from the main app is tricky since it cannot remove it from the quarantine, in other words, it fails with "operation not permitted". Any advice is appreciated!
4
0
320
Sep ’24
How to make my daemon run only in pre login mode.
Hi, I'd like to be able to run my daemon process only in pre-logon mode that can be reach by either reboot the machine prior to provide user credentials, or by log out from current user. So far I couldn't find any useful configuration in the plist file under /Library/LaunchDaemon. Perhaps there's a way to get notification programmatically for when the system enter/exit pre-login mode ? Thanks
1
0
237
Sep ’24
Daemon needs to get user name
Years ago my daemon was since then using SCDynamicStoreCopyConsoleUser() function and now it longer works. Basically the daemon needs to know the user name of who is using the system. If I restart the daemon,after the login, it gets the user name. I tried run a shell command via my daemon ("id -F") and look likes it still picks the root as user name. So, is there a way to get the current user name using Swift? ProcessInfo.userName fails too
1
0
279
Sep ’24
Session, Desktops and login screen
Coming from windows development, I'm trying to understand macOS architecture and how to do certain things. I've already read the Root and Login Sessions AND Service and Daemons AND User Switch Notifications documentation so will frame the questions accordingly. On Windows, there's a concept of User Sessions, each of which contain One or more WindowStations, each of which contain One or more Desktops. Each user gets at least 3 desktops (e.g. Login/Lock/UAC, Screensaver, and default desktop). From what I understand about macOS, it only has Sessions and then a single Desktop. Is that correct? i.e. same display surface is used to display user's desktop, screensaver, sudo prompt and lock screen? What about login screen? Does each user get its own login screen process/window running in their session? or is there a common login screen for all users running in one particular session (root?). How does Fast User switching effect login screen? In a daemon, is it possible to get active console session ID? console meaning the session being displayed on the monitor, whether its login screen, lock screen, user's desktop etc. In a daemon, is it possible to get session switch notifications? E.g. user logged-in and now their desktop is being displayed, user logged-out and now we're back on login screen, or user switched to another user (Fast User switching). How do I get notification of such events in daemon? If no user is logged in which session is pre-login agent running in? and after login does the session ID assigned to pre-login agent stay the same and user's session is assigned a new session ID? Is there always one and only one pre-login agent running? Is it possible to launch pre-login agent and user agents on-demand with custom commandline arguments from a daemon?
7
0
454
Sep ’24
Startup Items Cache Issue: New Items from the Same Team Fail
Our team has two products. The first product adds two /Library/LaunchDaemon startup items and one /Library/LaunchAgents startup item, which run normally after installation. A few months later, our team developed another product, which adds two /Library/LaunchDaemon startup items and one /Library/LaunchAgents startup item. However, we found that on some customers' systems, these startup items for the second product do not load correctly, and the processes do not start. Restarting the system does not resolve the issue. This occurs across systems running versions 14.5 to 14.6.1. The app's signatures, notarization, and Gatekeeper validations all pass. Eventually, we discovered that by disabling and then re-enabling our team's startup items in the System Settings - Login Items, all the startup items from our team load correctly. Could this be a caching bug related to new startup items from the same team?
2
0
259
Sep ’24
SMAppService.daemon initial pkg install
What I did. Started with the example at https://developer.apple.com/documentation/servicemanagement/updating-your-app-package-installer-to-use-the-new-service-management-api Changed it to configure a system daemon instead let service = SMAppService.daemon(plistName: "com.xpc.example.daemon.plist") Disabled automatic register in the package postinstall script (or else pkg install fails) Built/Installed the package, it just places files in the disk Validated install files Ran the test|register commands by hand sudo ../SMAppServiceSampleCode.app/Contents/MacOS/SMAppServiceSampleCode" register Dealt with System Settings user interaction to do this Validated that com.xpc.example.daemon is installed and ready to work sudo launchctl list | grep example sudo launchctl print system/com.xpc.example.daemon Got it to successfully do some work, YAY sudo ../SMAppServiceSampleCode.app/Contents/MacOS/SMAppServiceSampleCode" test Expectations My users would obviously download and install this pkg, so to make it easy for them. I would expect that I could call SMAppService.daemon(plistName: "...") .register() during the package postinstall installation step and the system daemon would be configured. Observations After getting all my teeth pulled why can't I just do that? Why so many hurdles for the dev and the end user, asking them to code sign this and that, notarize this and that, click here and there, accepting this and that? I understand the job of a developer but for the end user this should be relatively easy. Questions Do I need to start a DTS ticket to get this simple flow to work? It could be I'm missing step 42 in my endeavor :-)
0
0
289
Aug ’24
Daemon has reduced permissions after migrating from SMJobBless to SMAppService
Hello, I am working on updating an app to see if we can remove deprecated API usage, and am running into an issue after migrating from SMJobBless to SMAppService. If there is no current solution, I know that SMJobBless still works, but I wish to move to non-deprecated APIs whenever possible. The app is a text editor that installs a privileged helper for when users need to edit text files with root privileges. The example I'll use here is /etc/ssh/sshd_config. When using SMJobBless, the privileged helper was able to write to this location. When using SMAppService.daemon, the daemon is not able to write to this location. Neither the app nor the daemon are sandboxed. Both use the hardened runtime, and the daemon does not have any hardened runtime exceptions. I'm not sure how to attach a debugger to the daemon, but I was able to add logging to the daemon to confirm that getuid() and geteuid() are both 0, so the daemon appears to be running as root. However, the daemon is returning permission errors when attempting to replace the file. {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"} I've tried both atomic saving and writing directly to the file. When this code is run by the privileged helper installed with SMJobBless, it works without permissions problems. Here is some simplified code I tried for atomic saving. do { let fileManager = FileManager.default try? fileManager.createDirectory(at: originalItemURL.deletingLastPathComponent(), withIntermediateDirectories: true) _ = try fileManager.replaceItemAt(originalItemURL, withItemAt: newItemURL, options: options) completionHandler(nil) } catch { completionHandler(error) } And the code for writing directly to the file do { try data.write(to: url) completionHandler(nil) } catch { completionHandler(error) } One thing I should note is that the privileged helper tool had a launchd plist embedded in the binary. When moving to SMAppService, I removed it from the build settings and added BundleProgram to it. It gets placed in my app bundle in Contents/Library/LaunchDaemons, while the daemon itself gets put in Contents/MacOS. The plist only contains the following keys: BundleProgram, Label, MachServices, and AssociatedBundleIdentifiers. is there anything additional I can do to give my daemon permission to edit these files, or do I need to stick with SMJobBless for the time being?
2
0
305
Aug ’24
Operation not permitted error when sandboxed daemon tries to write System Keychain
Hi, I'm writing a sandboxed Daemon that I register from my sandboxed application via SMAppService. The registration is successful, and the daemon is called based on logs. However when I'm trying to save a keychain item into the keychain, I see entries like this in the logs: (Security) SecItemAdd [com.apple.securityd:atomicfile] create /Library/Keychains/System.keychain.sb-1c133873-RPL9wo: Operation not permitted [com.apple.securityd:security_exception] UNIX error exception: 1 [com.apple.securityd:security_exception] CSSM Exception: 100001 UNIX[Operation not permitted] [com.apple.securityd:security_exception] CSSM Exception: 100001 UNIX[Operation not permitted] I'm attempting to create the item with the regular SecItemAdd function call: var query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrLabel as String: "[redacted string]", kSecAttrAccount as String: "[redacted string]", kSecAttrService as String: "[redacted string]", kSecValueData as String: secretData ] SecItemAdd(query as CFDictionary, nil) I'm guessing this is because the System keychain is outside of the sandbox for the daemon. Is there a way to create items for the System Keychain from a sandboxed daemon?
1
0
417
Aug ’24
Spawn Constraint example
I downloaded the sample code given in: https://developer.apple.com/documentation/servicemanagement/updating-your-app-package-installer-to-use-the-new-service-management-api?language=objc Made necessary changes and I was able to install and test successfully. Next, I watched: https://developer.apple.com/videos/play/wwdc2023/10266/ I noted the example given at: 14:52 Example launchd plist constraint. Applied the KeepAlive, RunAtLoad and SpawnConstraints parameters to the sample code downloaded earlier. I got the log in the console and agent was not allowed: default 11:35:26.885483+0300 kernel AMFI: Launch Constraint Violation (enforcing), error info: c[5]p[1]m[1]e[0], (Constraint not matched) launching proc[vc: 10 pid: 19439]: /Library/Application Support/X/SMAppServiceSampleCode.app/Contents/Resources/SampleLaunchAgent, launch type 0, failure proc [vc: 10 pid: 19439]: /Library/Application Support/X/SMAppServiceSampleCode.app/Contents/Resources/SampleLaunchAgent Is SpawnConstraint not applicable for launch agents? Since launchd is the only parent process that can spawn the launch agent based on the plist, is the example given at 14:52 still valid?
4
1
455
Aug ’24
Service Management how to register handle_checkbox_toggle?
Hi, I noticed in this page, there is no explanation about who/when/how the method handle_checkbox_toggle is called. Page: https://developer.apple.com/documentation/servicemanagement/updating-helper-executables-from-earlier-versions-of-macos?language=objc Ultimately, how should the app come to know when a app service is allowed or disallowed in System Settings > Login Items ?
1
0
516
Aug ’24
Track system event(shutdown/restart) via launchagent
Hi There, I have to achieve following scenario Track system event on macosx for shutdown and restart and update one plist with same event via launchAgent I have tried following code on launchAgent class MyAgent { init() { let notificationCenter = NSWorkspace.shared.notificationCenter // Register for system shutdown notification notificationCenter.addObserver(self, selector: #selector(handleNotification(_:)), name: NSWorkspace.willPowerOffNotification, object: nil) RunLoop.current.run() } @objc func handleNotification(_ notification: Notification) { var logMessage = "" switch notification.name { case NSWorkspace.willPowerOffNotification: os_log("System is going to shut down at", log: log, type: .default) updatePlistFile(event: "shut down") let fileName = "example.txt" let content = "shut down" createAndWriteFile(fileName: fileName, content: content) logMessage = "System is going to shut down at \(Date())\n" } } } loaded the agent, and tried to restart device, I can't see as it is coming to handleNotification Same code is working fine from sample application but not from launchAgent Is there any restriction is there for NSWorkspace, if is that so, how to track shutdown/restart event from launchAgent or LaunchDaemon Any help will be appreciate
3
0
515
Sep ’24
How to authorize LaunchDaemons
I referred this(https://developer.apple.com/forums/thread/721737?answerId=739716022#739716022) example, this works for agent, but I am not able to Launch a daemon As documentation says "If your app uses launch daemons, it needs to register those first. Launch daemons require authentication by the user", how do I get user authorizes the LaunchDaemon. In Smjobbless we used AuthorizationRef, but how do i use it with SMAppservice?
6
0
492
Aug ’24
PreLogin Agent and login screen UI
I'm working on a screen sharing app and need to capture Pre-login screen and also foward remote input to login window/screen so remote user can login. Researching online, it looks like I need to use Pre-Login Agent to do that. However, I found these two threads: https://forums.developer.apple.com/forums/thread/45536 https://developer.apple.com/forums/thread/726470 Apparently, there is an unpublished workaround related to (r. 5636091). Can anyone provide details about that?
2
0
358
Aug ’24
get image icon of running applications in daemon
I need to get image icon of running applications in daemon. I have found the method iconForFile. [[NSWorkspace sharedWorkspace] iconForFile: bundlePath]; However, as far as I know, the framework AppKit is not daemon-safe. https://developer.apple.com/library/archive/technotes/tn2083/_index.html So, the only way which I see is to get icon file path via parsing Info.plist. However, the icon is not defined for some system app, e.g.: /System/Applications/Calendar.app /System/Applications/System Settings.app Are there any way to get icons of system application in daemon code? Is it safe to use NSBundle in daemon code? Thank you in advance.
2
0
446
Aug ’24
Do CloudKit subscriptions work from command line tool application?
I am able to fetch CloudKit records from my MacOS command line tool/daemon. However, I would like CloudKit to notify my daemon whenever CKRecords were altered so I would not have to poll periodically. In CloudKit console I see that my app successfully created CloudKit subscription, but the part that confuses me is where in my app do I define callback function that gets called whenever CloudKit attempted to notify my app of CloudKit changes? My first question - do I need to define callback in my implementation of UNUserNotificationCenterDelegate? NSApplicationDelegate? Something else? My second question, would CKSyncEngine work from command line application?
1
0
372
Aug ’24