I'm writing a simple OSX application to write firmware to a USB device. I'm using libusb to perform I/O.
My first pass at this works perfectly, provided I run it with sudo. I'm now creating a GUI version of the tool and I'd like to prompt the user to escalate.
I know the "correct" way to do this is with a privileged helper but I also need to report back progress to the UI, and I don't feel like building out IPC for something this simple.
Is there a simple way to request root or USB write privilege from the user for a GUI app?
I gave up and used the deprecated AuthorizationExecuteWithPrivilege API to re-launch my app if I didn't have root privilege.
It strikes me as a way less than optimal solution, if anyone has a better idea, I'd love to hear it.
Related
The short version: is it possible to delete helper tools which were set up by the app (SMJobBless() etc.) when the app is deleted? If so, how?
The long version:
The Mac app we are developing unfortunately requires admin privileges to perform an occasional operation, and it also requires a background task to be live for other apps' plugins to connect to even when the app itself isn't running (this one can be unprivileged). The app will be signed with a Developer ID certificate, and distributed only outside the App Store.
We'd like the app to be a "good citizen" as far as possible, also on uninstall.
For the background task, we're using a login item, created using SMLoginItemSetEnabled(). This isn't amazing, because XPC messaging doesn't seem to work (we're using CFMessagePort instead - alternative suggestions welcome), but if the user deletes the app, the login item at least doesn't get loaded anymore on next login. I suspect there's still a trace of it somewhere in the system, but the executable inside the .app bundle is used, and when that disappears, the login item no longer runs.
For the occasional operation requiring admin rights, we've got a privileged helper tool which our app installs using SMJobBless(), and which implements a named XPC service, so the task spins up on demand when it receives a message from the main app. This is what Apple recommends and describes in its Even Better Authorization Sample.
The helper executable is copied to /Library/PrivilegedHelperTools/ by SMJobBless(), and the embedded launchd.plist ends up in /Library/LaunchDaemons/. Even though the OS has the information on which app "owns" the helper, it doesn't seem to uninstall it when the user deletes the app. Apple's sample is silent on uninstalling, other than the uninstall.sh script which is apparently intended to be used during development only. We don't need this helper while the app isn't running, so installing it as a full-blown launch daemon is slightly overkill, but we'd also like to avoid repeatedly annoying the user with the password prompt too. Besides, Apple advises against other forms of running code with admin privileges than SMJobBless() these days - for example SMJobSubmit() is marked deprecated.
So how do we clean up after ourselves?
I've found SMJobRemove(), but (a) when would we call that in our case - you can't run code on .app bundle deletion, or can you? and (b) it doesn't actually seem to clean up.
The only 2 things I can think of are not terribly satisfying:
Some kind of uninstaller app or script. But that seems pretty ugly too.
Don't worry about it and just leave a mess behind when the user deletes our app.
Update:
There have been some changes in this area with macOS 13.0 Ventura; there's an introduction to the new mechanism in the WWDC22 session 'What’s new in privacy'. The new SMAppService APIs support automatic cleanup for daemons, agents and login items. Unfortunately you'll of course still have to find a workaround for any older macOS versions you support.
Original answer:
There has been a similar question on the Apple Developer Forums at https://forums.developer.apple.com/thread/66821 - the recommendation by Apple is a manual uninstall mechanism, and consuming as few resources as possible if the user does not do this.
Apple DTS staff further recommended implementing a self-uninstall mechanism in the privileged launch daemon, to be triggered from the app via XPC. This is what we're going with.
I think the only solution you have right now is to use the uninstall shell code that you mentioned in order to physically remove the privileged helper from disk or to build an uninstaller for it. Either way you will have to ask the user to enter his/her password. This what all installers / uninstallers that require privileged access to the system do, and for a very good reason. That's why I avoid like the plague to use privileged helpers, but I understand that sometimes you really have to. I don't think it is good that you leave such a helper in the user's system, because it will reload next time the user starts up the computer.
I just checked ServiceManagement.h header and they state that SMJobRemove will be replaced by an API that will be made available through libxpc in the future. (Sometimes you really need to go to the headers to get extra info that the documentation does not give you.) Hopefully this promised replacement will uninstall it for us. However, I'd file a bug report and ask for that enhancement.
One solution you could consider is to include an uninstaller script or program in your .app bundle.
You can then pass the path of this small tool to your helper tool (via IPC) and have the execute the the uninstaller, thereby deleting itself. You will have to be careful that components are removed in the right order but it can be made to work.
You're correct that Apple does not provide an API to uninstall a helper tool installed with SMJobBless nor do they do so automatically. As for why macOS doesn't automatically do an uninstall, my educated guess is because macOS fundamentally doesn't have a unified concept of "install". While it's convention for apps to be located in /Applications (and a few other locations), it's perfectly valid for apps to be located and run from anywhere on the system including external drives and network drives. For example should macOS uninstall helper tools when apps disappear because the drive they're on is disconnected?
In terms of how to uninstall, doing so requires root permission and so realistically have the helper tool itself do the uninstall is the easiest option. You can have your app via XPC tell the helper to uninstall itself. Here's an example in Swift of how to do this; it's part of SwiftAuthorizationSample. The basic idea is:
Use the launchctl command line tool to unload the helper tool
Delete the helper tool executable
Delete the helper tool launchd plist
But there's a bit of additional complexity involved because launchctl won't let you unload a running process.
#UPDATE:
OK FOR ANYONE ELSE WHO IS SEEKING ADVICE ON THIS ISSUE...
So far, the best thing I have found is to download yourself a copy of pGina and for 2k/XP modify the GINA, and for vista/win7 you will need to create custom login credentials (pGina have the tools/samples to interface with the Vista/Win7 architecture).
to confirm -- it appears that this is what Novell are doing with Vista/Win7 rather than the traditional method of replacing the GINA (like in 2k/XP)
If anyone else comes up with a way to run an application on the logon screen in Win7 please post it.
Ok I'm writing some vb6 software that requires input before the user logs on to the system.
Basically I want to run an application on the Windows logon screen where the user can interact with the program. At present I have the application running as a service allowing to interact with the desktop, but it is still now showing.
I know that "Allow service to interact with desktop" will work in Windows 2000 / XP, I'm running Windows 7 - I am also aware that services cannot directly interact with a user as of Windows Vista - saying this, are there any other methods to get my application running on the logon screen. Novell does it
Does anyone have any other ideas to get this working?
You can only do this if you are authenticating the credentials yourself. Prior to Vista, this was done via GINA, but since Vista, you need to write your own Credential Provider.
The reasons behind this are buried deep in the security principles -- Ctrl-Alt-Del will only ever bring up the window station associated with login (etc), and no other application can get to that window station (so you can't create a fake password box over the top to scrape passwords, for instance).
Without knowing why you think your service needs to interact with that desktop, it's difficult to advise further, but it might mean that your design is broken somehow.
Service isolation will probably prevent you doing this from a service.
Pre-vista Novell and the like would probably have used GINA, which was replaced in vista; http://msdn.microsoft.com/en-gb/magazine/cc163489.aspx
The only way I know of would be to write your own msgina.dll.
It can get dicey during testing though. Any mistakes can mess up your OS so bad that a complete reinstall becomes necessary.
I'm trying to run only the browser in the system - locking access to everything else. Only the supervisor can resume the normal functioning of the system after giving a password.
This kind of activity is usually done by virus. Disabling the registry for Task manager etc. Does anyone know of any source available that does this? I might be able to pull it off in Windows XP. But have anyone tried this in Windows 7 ?
The aim is to to emulate the Chrome OS on Windows. Only the browser. Nothing else.
Sounds like you're after Kiosk Mode. Knowing that, a little searching gives a guide to what to do.
AFAIK, What you are attempting is NOT natively possible on windows.
You best bet would be to write a program that runs in the background and monitors for any processes apart from the browser being launched.
It should immediately terminate the "unauthorised" processes as soon as they are created.
Also using the group-policy manager restrict access to the task-manager to prevent the user from stopping this process.
Contact me if U require help in writing the above program
2.6Kilohertz#gmail.com
GOOD LUCK!!
I am working on some Automation Project where one needs to perform some action related to display resolution.Change the Display resolution , Lock the Desktop and then Unlock Desktop again to check that resolution remained same.
I am able to perform LockWorkstation but unable to have any thing for Unlock Workstation.
Can any body help me regarding unlocking Display with help of C# and in Win 7 ?
I heard of GINA dll which can help ,but I dont know anything about it.Can this be used for Win7 and .NET 3.5?
Thanks
_Prat.
I don't think that doing this is technically feasible. GINAs were deprecated after XP and the new way to provide custom authentication in Vista/Win7 is to use the ICredentialProvider
interface. Even if you get this working you'll still have to somehow send the the secure attention sequence, i.e. ctrl-alt-delete, to initiate the logon. Sending ctrl-alt-delete programmatically is itself something that is difficult to do and not really supported.
This sounds like a lot of work for some automation and probably won't have much ROI. Can you test this by logging the user off completely and then logging back in? If so, then you could set your test machine to auto-logon the user. When you log-off it will shut down the session and then promptly log the user back in and you could check if the resolution is what you expect.
I have a requirement to create a cross platform application that launches a web link to a feedback form when its uninstalled.
This is obviously normal sort of behaviour on windows..., but on a Mac is is proving to be more complicated as applications are not technically installed and uninstalled in a windows sense, aka you just copy the .app file into Applications and delete it when you're finished.
How can I achieve this website launching requirement? (Should I even be trying, is this process too alien to Mac users?)
I tired packing the application with an uninstall shell script that deletes the app and lunches the site, but obviously the script can't delete itself.
I don't think this is the best idea, since the process would be a bit unusual to OS X users. As you noted, most applications are installed simply by dragging a .app file to /Applications (or some other location). Some apps do have an installer, but even apps with an installer only occasionally have an uninstaller; and furthermore, as a Mac user, I'd be immediately suspicious of an app that installed itself and some sort of unknown shell script.
Mac OS applications should not need to be uninstalled in any way other than the user dragging them into the trash.
Also, I would rethink very carefully your plan to make a cross-platform applications. Cross-platform applications that treat Mac OS as an afterthought and try to push foreign paradigms onto Mac OS are really irritating. If you want a Mac client, keep your backend code, but rewrite the front-end from scratch. Don't use something like Qt, no matter how tempting the portability is.
So, long story short, you're right. The process is alien to Mac users (except for things like plugins). So my suggestion is just to go with the normal Mac OS behavior (drag to trash). Best of luck!
I would recommend against it. You could create an uninstaller but nothing is going to stop a user from just deleting it from the application folder or using something like AppZapper. Most people don't even look for an uninstaller application, they just trash the app, so even if you wrote one there would be no guarantee it'll be used.
I'd certainly avoid an uninstaller shell script, no way in the world I'd personally run it.
An uninstaller on a Mac makes no sense and would be awkward to implement, if you could even implement it at all in a way where people would use it.
Consider trying to get user feedback using alternate methods, such as:
Add a menu item that opens the feedback form
Require registration when the software is downloaded, then send an email to the user at some point in the future to ask for feedback
Ask for feedback occasionally on application quit (could be annoying, though)
I don't think that it's a good idea to ask for a feedback when the app is uninstalled. However, here is a good way to provide an uninstaller for a MACOS app in case it needs to do some clean up.