Mac OS X: Launching an app using NSWorkspace from a daemon doesn't work if the daemon is run as root - macos

I created a Command Line Tool app using Xcode.
In that app, I used NSWorkspace to launch another application bundle (.app) as suggested here.
MacOsX: How to launch an application (.app) from a "Command Line Tool" type of app
All seem to work fine until I tried to start that Command Line Tool app as a daemon using launchctl.
If the daemon is run as the currently logged in user, then the Command Line Tool app launches the external app just fine.
If the daemon is run as root, then the Command Line Tool app cannot launch the external app.
Using NSWorkspace to open an app doesn't seem to work if the daemon is run as root.
Does anyone know the correct way to open another app from a daemon that's running as root?

This is likely a security restriction within MacOS you're running into.
What I would suggest doing is to create a code-signed "helper tool" that resets itself (via setuid -- which I wouldn't do outside of a code-signed app) to the userid of currently logged in user, and then do the NSWorkspace trick to launch the app in that user context.
Creating helper tools is not trivial though. The grand concepts are described in Apple's Authorization Services Programming Guide.
Take a look at Apple's "SMJobBless" sample code, which shows how to install the helper tool that you could set the user rights on and then modify it's helper tool code to launch your app.

This is too complicated a subject to really address in a StackOverflow answer. The short answer is that daemons can't launch applications reliably. For the long answer, please read Apple's Technical Note TN2083: Daemons and Agents.

I finally got it working by using the code mentioned in this link to get the "console user's" uid and gid:
https://superuser.com/questions/180819/how-can-you-find-out-the-currently-logged-in-user-in-the-os-x-gui.
The link shows an example of how to use SCDynamicStoreCreate() and SCDynamicStoreCopyConsoleUser() to get "console user's" uid and gid.
After getting the uid and gid, just set the uid and gid to those of the console user before using NSWorkspace to open an app and that did the trick for me.

Related

How to run a macOS app as root and use system calls?

I'm trying to run the setpriority command from my macOS app (objective-c). It never works and I'm assuming it is because the app is not being run as the root user.
I'm logged in to the admin account on my computer
I've tried opening the app with sudo
I've tried using chmod on the app
I've tried adding the app to the Accessibility list under Security and Privacy
Xcode version 9.2 (9C40b)
I would appreciate any help, thanks!
You want to run as root, or you want to run with sudo? There's a difference. Running as root is definitely not recommended, you will get strange behaviour from the system.
You wrote:
I've tried opening the app with sudo
That should work. How have you tried? You need to call the binary within the .app bundle. Running open against the bundle won't work.
e.g.
sudo ./Xcode.app/Contents/MacOS/Xcode
It's not recommended to run GUI apps on macOS as root. Instead, you should factor out the part of your application which needs root access into a separate helper tool, launch that tool as root using the SMJobBless() function, and then communicate with the tool using XPC.
Apple provides the EvenBetterAuthorizationSample example code to give a pretty good basic framework to work from.
EDIT: I decided to make my own authorization sample project a while ago that should be a little easier to use than the venerable EvenBetterAuthorizationSample. You can check it out at CSAuthSample.

Application backgrounding in Xamarin.Mac

How do I achieve Application backgrounding in Xamarin.Mac. I want something that work similar as android services:
Android Services - A Service is an application component that can perform long-running operations in the background, and it does not
provide a user interface. Another application component can start a
service, and it continues to run in the background even if the user
switches to another application. Additionally, a component can bind to
a service to interact with it and even perform interprocess
communication (IPC). For example, a service can handle network
transactions, play music, perform file I/O, or interact with a content
provider, all from the background. ~Android.com
Thanks in Advance.
The proper way is to install your application as a LaunchAgent (instance-per-user) or a LaunchDaemon (instance-per-machine) using launchd, and the 'application type' setting (within "Xamarin Studio" or "Visual Studio for Mac" project options dialog) should be set to "Executable" instead of "Executable with a UI" (or similar.)
As a "LaunchAgent" you have the option of interacting with the desktop, and your code runs under the context of each logged in user instead of a system process account. You will not see a tile in the 'dock bar' (unless you allocate an NSApp), and you only see a 'status menu bar' if you explicitly call a Mac API to make it happen. Additionally, launchd will periodically check for and launch your process, ensuring that it is always running.) There is no requirement that you use any Cocoa/Mac APIs to implement an agent/daemon, you could run any console app under launchd and the above would still remain true.
Integration with launchd is non-trivial, but well documented for the macOS platform, and it applies equally to Xamarin.Mac-developed applications as it does any other platform/tool-chain (Java, C++, Obj-C, SWift, ...), if I had to guess learning how to use launchd is a 2-4 hour investment for most devs.
Because Xamarin.Mac does not itself have explicit support for launchd (and IMO should not) you will also be tasked with calling launchctl yourself. As a seasoned .NET developer I find that wrapping all of the 'launchctl ugliness' inside an "installer class" works well (then you only need to run installutil to install/uninstall your agent/service/application.) These installer classes can also be implemented to work on Windows and Linux, meaning cross-platform installs only ever require the use of installutil.
Separately, you can set particular properties in your app bundle Info.plist, but this is not necessary. However, most will find editing the existing plist easier than integrating with launchd. It's worth noting that one behavioral difference is that editing the plist to include either LSBackgroundOnly or LSUIElement doesn't guarantee your application is running, but using launchctl will.
HTH
References
Creating Launch Daemons and Agents Article on Apple.com
How to Create a Background Running Cocoa Application on StackOverflow.com
launchd Article on Wikipedia.org
launchctl Manual Page on Apple.com
LSBackgroundOnly Reference on Apple.com
LSUIElement Reference on Apple.com
installutil Reference on Microsoft.com (applies to Mono/Xamarin Linux/Mac platforms as well, though Windows uses its own 'Service Control Manager (SCM)' APIs instead of launchctl.)

Run a shell command through a Chrome App

I have Crouton on my Chromebook with Spotify inside an Ubuntu chroot.
I can execute Spotify inside an Ubuntu chroot as a single app window via a Crouton command.
I want to create a Chrome OS application that acts as a launcher for Spotify, Skype, etc.
In short:
My Chrome OS app should execute a shell command.
I read about NPAPI, but it says it's getting depreciated (since 2013 o.O).
If there's another way (for example executing a bash script that adds a button to the shelf that just executes another shell script to open Spotify), it would also be great.
Thx in advance :)
EDIT:
With Dart this seems to be possible. It says "access File system, USB Devices, shells and much more" with it
Looks like Native Messaging is just the thing you're looking for! However you may need to create an application that can be registered as a Native Messaging Host. This application will then in turn call the shell command/script you intend to run.

Sandboxed Mac app does not always launch automatically using SMLoginItemSetEnabled()

I have a very strange issue with a sandboxed Mac app I'm developing. One requirement is that the user should have the possibility to launch the app when the system starts. For this, I'm using SMLoginItemSetEnabled() as described on http://blog.timschroeder.net/2012/07/03/the-launch-at-login-sandbox-project/.
When the user starts the app for the first time and enables this option, I can see an entry is being added to launchctl by using launchctl list. When I reboot the system, the app is not being started. More strange is the fact that the entry found using launchctl list has disappeared. However, a similar entry is still available in /private/var/db/launchd.db/com.apple.launchd.peruser.501/overrides.plist with key Disabled being false.
When I start the app manually and again set the option to start automatically, the entry is again available in launchctl list. When I reboot the system the app is being launched automatically. Concluding, for some reason SMLoginItemSetEnabled() only works the second time I run the app. Therefor it looks similar to this issue: https://stackoverflow.com/questions/16354295/sandbox-app-with-loginitems-only-work-after-second-app-launch. However, no solution is provided.
https://stackoverflow.com/questions/16354295/sandbox-app-with-loginitems-only-work-after-second-app-launch
If you're like me, you probably had extra copies (generated by Xcode, etc) laying around that seem to confuse LaunchServices.
I wrote a post about it here: Login Items in macOS 10.11 and newer
But the short version is, use lsregister -dump to find all copies that LaunchServices knows about, remove them, then use lsregister -kill to reset the LaunchServices database when you're done.

Application on Startup Mac

I need to run my application on startup. So when the user boot up his Mac and is about to see his desktop, my application needs to launch. I set my app to run as launchd. I am using the QueuedDirectories flag in the plist of the launchd process. So if I place a file it launches up automatically. I have looked at the question - How do I launch an application on system startup? (Mac OSX, Cocoa). The suggested answer is to use launchd.
I have two questions -
In Macs where more than one accounts are present, the application does not launch for the other user(who has not installed it). In Windows you can install program for everyone. Is a similar thing possible on Mac. If so, I can use the Queued directory approach with launchd.
Is launchd the right way to start an application at startup/login in Lion as well. Or has Apple added any new feature with Lion which will allow this to be done in a smarter way. I looked up and everything does seem to point towards launchd.
I am targeting Snow leopard and Lion.
Yes, you should be using launchd. Have a look at my answer to this question.
Basically, you need to install your launchd configuration file in the root /Library/LaunchAgents/ folder rather than an individual user's ~/Library/LaunchAgents/ folder. That way, it will launch an instance for each user that logs in.

Resources