I have a command line util the is running in root context (in macOS). This uses CoreLocation to determine the device's location. When this process is launched in High Sierra (in root context), the prompt requesting for user's permission doesn't come up. Also, the process isn't listed in System Preferences -> Privacy pane. Please note that the Command Line Util is signed. However, when the same util is run in user context, it works as expected.
Also, I tried manually editing the clients.plist. When I add the process to the plist, it lists up in System preferences. However, the CoreLocation delegates are not invoked. I see the following error in logs: "Registration timer expired, but client is still registering"
Has apple blocked root processes from collecting location data?
P.S: The code is in objective C
It's generally not safe to run Objective-c code as root, code-injection is very easy due to the dynamic nature of the language.
The permission for location access is given by the user, and root has no login account, so the prompt can't appear. You'll either have to enable root login (but see above) or run the location portions of you code in user space and communicate with a system daemon.
Related
I am building a command line tool using only command line tools (mainly clang) in ObjC++ using AudioUnit v2(C) API. Output to speakers works fine but the input from microphone callback is never invoked. The iTerm or Terminal hosts have access according to Settings. The executable also has an embedded info.plist although I do not think this is relevant.
The precise security model is not clear to me, it looks like a major security hole if it worked (anything run from terminal would have access): my guess is that the process launched by an "App" has permissions which then propagate to any child process. However this view is confused by another case where an executable I generate does network access (as it happens only to localhost because it is a regression test) and in this case the executable is asking for network access, not the terminal.
The source code is actually written in Felix which is translated to C++ and then compiled and linked by clang with the -ObjC option so embedded Objective C is supported. The translator is mature enough to have reasonable confidence in its correctness in this kind of simple application. The AudioUnit configuration for the microphone input is:
// configure
var outputElement = 0u32;
var inputElement = 1u32;
// establish callback
status = AudioUnitSetProperty(
outputAudioUnit,
kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Global,
inputElement,
(&inputCallback).address,
C_hack::sizeof[AURenderCallbackStruct].uint32
);
assert noErr == status;
and the inputElement is enabled and outputElement disabled. A second audio unit is constructed later with similar technology which pumps a sine wave to the speakers and that works fine. The actual callback just prints a diagnostic and exits, but the diagnostic is never seen. Originally, the terminal had no permissions, and we guessed the code was correct but failed due to lack of permission to access the microphone. The executable still has no permission but the terminal does now (if I try to run the executable from file manager a terminal pops up).
No errors are reported at any stage. The callback simply isn't invoked.
To get a callback, you need to
enable IO
set the audio unit input device
Number 2. trips people up because it's not necessary for output [which sensibly defaults to the default output device], nor is it necessary on iOS, probably because there is no concept of Audio Device there, at least not in the AudioUnit API.
Surprisingly, both these requirements are actually documented! Technote 2091 covers the steps needed to record audio using AudioUnits and code listings 3. and 4. have sample code that enables IO and sets the input device. Listing 4. sets the audio unit input device to whatever the default input device was, but any input device will do.
Since macOS Mojave (10.14), you need an NSMicrophoneUsageDescription string in your Info.plist. Without this, your app is aborted with an exception. With this, the user is shown a prompt requesting permission to access input devices. You can control when this happens using code found here.
For a command line tool, you can embed an Info.plist file during the link stage.
On Catalina you also seem to need to opt into audio-input enabled sandboxing or the hardened runtime (or both!). Without one of these your callback is called, but with silence! Both of these runtime environments are enabled using "entitlements" which are metadata that is embedded in your app via codesigning, so you will need some form of codesigning. I don't think this necessarily means you will need a certificate from Apple, there is "local/ad-hoc" code signing, which seems to embed entitlements without a certificate, although I'm not sure how distributable the resulting binaries will be.
My custom Cocoa-based setup.app on Mac OSX that I made in Objective C needs to install a LaunchDaemon for doing elevated privilege tasks such as an antivirus program that needs to scan the entire hard drive and therefore needs root privileges. How can I make my setup application prompt the customer for their admin login and then install that LaunchDaemon into /Library/LaunchDaemons (and note I don't mean ~/Library/LaunchDaemons)?
The way I'm currently handling it is by using AppleScript with the admin privilege. It prompts for this login and then the AppleScript does the copying into this folder without the OS complaining. However, I assume that's not the proper technique -- that I should be doing this entirely in Objective C somehow?
Note that I can't use SMBlessJob in this case because it is for this reason that I'm creating the Launch Daemon in the first place.
BACKGROUND INFORMATION
I have a special need to create a custom setup.app -- just like the fact that Norton's AV application uses a custom setup.app. This is because the Apple PKG and DMG installers do not permit downloading of very large files (like virus definitions) from a server during install with some kind of friendly feedback. I mean, I can make a PKG file download a file from the server when running a Perl script or Bash script, but then the installer just hangs the progress bar for the amount of minutes it takes to download, not giving any other feedback to the user except that hung progress bar, and so the user thinks the installer is broke, when it's not. That's why I had to make my own custom setup.app, just like Norton did for their AV application.
Normally, SMJobBless would be the technique to do this. It's the one Apple recommends now as of 2016. Here's the readme.txt for Apple's sample project:
https://developer.apple.com/library/mac/samplecode/SMJobBless/Listings/ReadMe_txt.html
However, that's not the only way to do it. Another route would be to have your installer use AppleScript to prompt and run a Bash or Perl script with elevated privileges to install the LaunchDaemon, as well. (That's actually easier than SMJobBless.)
Basically, either technique installs a LaunchDaemon (e.g., "service") into a special folder, and that daemon can be set with elevated privileges, which can then run anything you want -- even command line commands. A super fantastic explanation of LaunchDaemons and LaunchAgents is here:
http://launchd.info/
Now, the problem is how to communicate with it from your application, once installed. They leave that up to you, and there are various techniques. However, they also leave it up to you to secure this so that it's not an attack vector.
A fantastic article on how to do IPC (Inter Process Communication between your application and this service) is here:
http://nshipster.com/inter-process-communication/
One IPC protocol on OSX is Distributed Objects, which is quite smooth from an architecture perspective -- you'll feel more like it's "coding" instead of "sending messages back and forth" like other IPC protocols. I've written a Stack Overflow post on this because the docs are shoddy and the existing examples on the Apple site and others are stale (won't compile on XCode7.1 with OSX 10.10+).
On communication protocol between your application and daemon/service, you can probably get away with key/value, XML, or JSON messages that are encrypted with AES256 with a long password and converted to Base64 encoding, and then use one of the various IPC mechanisms. However, that's another topic entirely.
I am deciding between using a login item and launch agent.
In this respect I have few questions:
Is it possible for a non root user to quit a login item helper if it is launched with service management framework using SMLoginItemSetEnabled? Will the helper app be reloaded by launchD if it is killed by user or in some cases OS?
Why does apple not recommend presenting a UI with an app that can be executed via a LaunchAgent? Is there a problem if we present a minimal UI?
A login item as a helper application requires the main application to call SMLoginItemSetEnabled. This implies that the main app must be called at least once to enable the login item. This differentiates it from a launch agent which can be loaded as soon as the plist is installed on the system. Can we execute the helper login item irrespective if the user has opened the main app or not?
Any help would be appreciable
LaunchAgents that are configured using SMJobBless are intended to be non-gui services. They run without UI in the background, and don't run as the logged in user.
If you want a gui, you're going to have to use SMLoginItemSetEnabled, or manually install a user LaunchAgent via a .plist with the "LimitLoadToSessionType" = "Aqua" property.
Helpers launched by SMLoginItemSetEnabled run as the current user, so they can be terminated by that user. The process will get relaunched if launchd detects that the agent went away because of a signal or due to an abnormal termination. If it terminates due to a clean termination it will not be restarted until the next login of the user (by clean termination we mean terminating with an exit code of 0, which will not happen if the program is killed e.g. via the activity monitor. If the helper has an option to quit, and that option causes it to exit with a 0 return code, then it will not be restarted, which would be considered good form by the application.
It's a stylistic thing - a user cannot disable the agent without interacting with the command line which would be considered poor standing. There is no issue displaying a UI from a LaunchAgent. As long as it's registered with the appropriate keys, it will be launched in the user's gui login context which means that it can be fully interactive. I have several applications which act like that - TunnelBlick, 1Password (this is via the LaunchAgent plist) and they only put up a menu bar item on startup.
If you're just shipping an application - e.g. via the app store, then there's no way to have anything automatically start without some interaction by the user - you have to launch the main app to get the helper to be enabled. The helper login item can be launched manually without ever launching the main application; but it won't have the 'launch at startup' magic enabled. If you can register a LaunchAgent plist, then you can get the launch at startup & starting it up immediately behaviour.
For uninstallation, however, LaunchAgents require the removal of the .plist, and interacting with launchd to disable it, items registered with the Service Mangement framework will naturally vanish once the app is dragged to the trash.
IMHO, (bit soapboxy, bit opinionated) If you're shipping a standard app with a helper, then rely on first launch before configuring such things as helper start on login; primarily because it keeps the user in control. Autoinstalling startup items is one of my pet peeves with windows applications (so many status bar items...).
The docs for SMLoginItemSetEnabled state the login item will be "kept running", which seems to indicate it will be relaunched if it is killed:
The Boolean enabled state of the helper application. This value is effective only for the currently logged in user. If true, the helper application will be started immediately (and upon subsequent logins) and kept running. If false, the helper application will no longer be kept running.
https://developer.apple.com/documentation/servicemanagement/1501557-smloginitemsetenabled
I have a desktop application that attempts to limit the user to one instance per session (so each user/remote desktop connection can run a copy)
I do this by creating an EventWaitHandle with a "Local\..." prefix on the event name, and if isn't created, I exit the program.
The warning from the verifier tool looks like this:
WARNING
Multi user session test
• Warning: The multi user session test detected the following errors:◦An error occurred while performing the testing process.
• Impact if not fixed: Multiple users might not be able to launch the app in concurrent sessions.
• How to fix: Make sure that the app doesn’t block multiple concurrent sessions, either locally or remotely. The app must not depend on global mutexes or other named-objects to check for or block multiple concurrent sessions. If the app can’t allow multiple concurrent sessions per user, use per-user or per-session namespaces for mutexes or other named-objects. See link below for more information:
Remote Desktop Services programming guidelines
http://msdn.microsoft.com/library/windows/desktop/aa383490(v=vs.85).aspx
Any idea on what this error means, and how to get rid of it?
I've tested the program while logged into multiple accounts, and it correctly detects that the program is not running on the new session, despite running on a previous one.
Is there a way to get more detailed descriptions of the failures?
this link suggests that there is a bug in Windows Application Certification Kit (WACK) 2.2 and it is resolved in WACK 3.0 available for Windows 8.1 Preview. I chose to ignore this particular warning for now.
Set for user (choice user or machine) when you run Windows App Cert
I'm looking to sandbox an app to comply with the March 1st sandboxing requirement of the Mac App Store. My app includes a built-in terminal emulator which utilizes a forkpty() call to launch processes in a pseudo-tty environment. Unfortunately, this call fails under the sandbox with the error "Operation not permitted", although the fork() call works just fine. Presumably the forkpty() call requires read/write access to the /dev/ directory to create a pseudo-tty (according to the man page). I've tried adding a temporary sandboxing entitlement (com.apple.security.temporary-exception.files.absolute-path.read-write) with read/write access to /, and I now can indeed read and write files anywhere on the file system, but the forkpty() call still fails with the same error. Does anyone know how I might get forkpty() to work under the sandbox?
My app is a programming text editor with a built-in terminal emulator and file browser, so it essentially needs to have access to the entire file system. Apart from the forkpty() problem, this temporary entitlement seems to do what I need. But will Apple accept an app with such a loosely defined temporary exception entitlement?
Thanks in advance guys. I really hope I can get this sandboxing up and running so I continue to distribute my app through the App Store.
It is impossible to implement a useful terminal emulator in a sandboxed application -- even after you add entitlements for the PTY devices, the shell ends up in the same sandbox as the app, preventing it from doing very much.