Time to add some variety to the blog, so I’m starting a series of post which I’ll mix in between other more mainstream topics. I want to spend some time testing some hidden or maybe less known gems that will make your life as a macAdmin a bit easier.
And the honour for the first awesome little tool I’d like to discuss goes to: SAP – Privileges. I knew about the existence of this tool but never took the time to check it out…
So, let’s not waste any time and dive right into it!
Note: Little disclaimer from the SAP Github project page.
This project is 'as-is' with no support, no changes being made. You are welcome to make changes to improve it but we are not available for questions or support of any kind.
That said, there is no need to, as it just works as expected. Within the limitations of the design of course. Nevertheless, Rich Trouton was so friendly to point me to his own Privileges scripts and recipes to enhance the deployment! This made it even easier to use! Thanks Rich!
The basic idea behind the app is to ensure that your end users, who need to be Admin for specific tasks, don’t use their Admin account while performing day to day tasks which don’t require Admin privileges at all.
While there might be other solutions available, such as scripting the elevated privileges via Self Service, the SAP privileges app makes it all possible without too much effort, and even when the end User is offline.
While it’s really a beautiful little tool, it does however have some limitations by design. But don’t worry nothing that can’t be fixed or tweaked. First of all, when you run the default app for the first time, it asks for Admin rights to install the “Helper Tools”:

I wanted to add this app to a workflow where I’d make all my end users ‘Standard Accounts’ (demote everyone, change the pre-stage enrolment to Standard Accounts, etc). Bye bye admin rights as per default deployment, and then only give this app to those users who really need it.
But the prompt for the admin rights to install the “Helper Tools” was initially a little blocker, so MacAdmins Slack to the rescue! And before I lost any time trying to script it myself… Rich reminded me of his GitHub collection, which include some options to automate the process!
I grabbed one of the recipes and used autopkg to get a nice pkg to deploy ‘Privileges’ with the automated installation of the ‘Helper Tools’. However, I also found the scripts alongside the recipes, so just to test this options as well, I repackaged ‘Privileges’ myself with composer and added the Post-Install script from Rich’s Github (Script by Marc Thielemann).


Built the pkg, upload it to Jamf Pro and create a Self Service policy… don’t forget to add the Dock item !


Let’s run it! Once installed, hit the icon in the Dock and click on “Request Privileges”…


… no prompt for Admin credentials to install the “Helper Tool” ! And we immediately get the notification that the Privileges have been granted. So let’s confirm it in Users & Groups…

Harry Potter couldn’t do it any better with all his so called magic! Also check out the Dock item! How cool is that! What do you think? For what it’s worth, I love it!
Next, have a look at the Dock item on it’s own, and do a ctrl/right click on it. Apart from locking the screen or going back to the Login Window (without logging out the user) the end user has the possibility to set a timer on his/her admin rights. Instead of clicking the app to request elevated privileges, the ‘Toggle Privileges’ function via the Dock menu can be used to limit the use of Admin rights in time. The timeout can be set in the preferences of the app.


While this really gives us a tool to educate end users not to use admin rights for daily tasks, it will only work if you can assume a level of trust or confidence in the fact that the end user will use the ‘Toggle Privileges’ function, and not abuse the tool to stay Admin all the time.
The fact that the app does not have a built in functionality to force the user to remove the Admin rights automatically may seem as a limitation, but as they mention on the project page you are free to put your dev skills to work and enhance it were needed for your deployment.
I’m however not a developer, so let’s check out some other options. There are probably plenty of different (better) solutions (apart from changing the app itself), but as a proof of concept I just went with a LaunchDaemon and a script.
I could have deployed the script as part of the custom package, together with the LaunchDaemon, but this would mean that I have to repackage it each time I want to make changes to the script. To avoid that I only added the LaunchDaemon to the custom pkg…

… and added a command to the end of the post-install script to immediately load the LaunchDaemon:

Then I made a LaunchDaemon which I set on an interval of 10 minutes for testing (change it to what you want – displayed in seconds). As I am not deploying the script locally, I’m calling a Jamf Policy via a custom trigger ‘checkAdmin’:

Add the LaunchDaemon to the custom package in Composer, build it as pkg, upload it to Jamf Pro and make a Self Service policy scoped to those users who are entitled elevate themselves to Admin.
Next is the script to check the usage of the elevated Admin privileges:
#!/bin/bash
# Travelling Tech Guy - 6th of March 2019
# Proof of concept - use at own risk!
# This script is an attempt to add a little enforcement to return to standard privileges when using the SAP privileges app
# The SAP Privileges project page:
# https://github.com/SAP/macOS-enterprise-privileges
# set time limit (set to 5 minutes for testing)
timeLimit="5"
logFile="/usr/local/bin/.lastAdminCheck.txt"
timeStamp=$(date +%s)
# check if file exists
if [ -f $logFile ]; then
echo "File ${logFile} exists."
else
echo "File ${logFile} does NOT exists"
touch $logFile
echo $timeStamp > $logFile
fi
# grab the logged in user
loggedInUser=$(/usr/bin/python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "\n");')
# check if the user is admin
if [[ $("/usr/sbin/dseditgroup" -o checkmember -m $loggedInUser admin / 2>&1) =~ "yes" ]]; then
echo "User is Admin... keeping an eye on him/her!"
userType="Admin"
else
echo "User is not admin... bye bye"
userType="Standard"
rm $logFile
exit
fi
# process Admin time
if [[ $userType = "Admin" ]]; then
oldTimeStamp=$(head -1 ${logFile})
rm $logFile
touch $logFile
echo $timeStamp > $logFile
adminTime=$(($timeStamp - $oldTimeStamp))
echo "Admin time in seconds: " $adminTime
adminTimeMinutes=$(($adminTime / 60))
echo "Admin time in minutes: " $adminTimeMinutes
fi
echo "Time Limit is: " $timeLimit
# if user is admin for more than the time limit, ask if to confirm need for superpowers
if [[ "$adminTimeMinutes" -ge $timeLimit ]]; then
confirmAdmin=`/usr/bin/osascript <<EOT
tell application "Finder"
activate
set myReply to button returned of (display dialog "Do you still need Admin Super Power?" buttons {"Yes", "No"} default button 2)
end tell
EOT`
fi
# take action
if [[ "$confirmAdmin" == "No" ]]; then
echo "Demoting the user!"
/usr/local/bin/jamf displayMessage -message "OK, Admin rights revoked"
# Demote the user
sudo -u $loggedInUser /Applications/Privileges.app/Contents/Resources/PrivilegesCLI --remove
fi
if [[ "$confirmAdmin" == "Yes" ]]; then
/usr/local/bin/jamf displayMessage -message "OK, but use them wisely you must - Yoda"
fi
Upload the script to Jamf Pro, add it to a policy with a custom trigger (same as the one you put in the LaunchDaemon obviously) and frequency ongoing.
Important: as we are not deploying the script locally, don’t forget to make the policy available offline!

Now, whenever a user installs our custom privileges package, the LaunchDaemon will be deployed as well. Following the interval you set in the Daemon, it will call the script which will check if the user is Admin, write a timestamp in a hidden file and check again on the next run of the Daemon. If the difference between the 2 timestamps is exceeding the time limit you put in the script (see line 14 of the script), it will prompt the user to confirm he/she still needs Admin rights. If the user is not using elevated privileges when the Daemon triggers the script, it will reset the timestamp and silently exit.

If the end users replies Admin privileges are not needed, the script will demote the user back to Standard:

sudo -u $loggedInUser /Applications/Privileges.app/Contents/Resources/PrivilegesCLI –remove
Also, check out the Dock item which reverted back to green – Standard!
But if the user claims to need the Admin privileges, it will just remind him/her not to abuse it:

Just know that the interval at which the LaunchDaemon is triggered, and recording the timestamps, will not correspond with the real time the user was elevated to Admin. This might trigger false positives, as it might ask the user for confirmation while he/she just recently elevated to Admin again. Hence the script might think the user has continually been in Admin mode since the last check. You could potentially change the strategy here and build some lookup into the script to find timestamps in the logs from when the Admin group was added to the user account. For me, this did however feel a little bit too much work for the intended goal here: educate our end users.
You could of course also play the bad IT Admin guy, and just kill the Admin privileges after a certain time… but yeah…
As said, this is just a proof of concept and the idea is to catch people who are staying in Admin mode all day… Depending the Daemon interval and the time limit you set in the script, you can limit it to only a few spot checks a day
Or as as said, re-engineer the app and built this kind of functionality directly inside the Privileges application.
That’s it, let me know what you thing. Happy to hear how you added similar functionality or if you have a custom version of the app for this!
grtz,
TTG

Apple ecosystem enthusiast, geek, tech gadget freak, Belgian living in the Netherlands
Manager Technical Support | Jamf
The one and only hesitation we have with rolling this out is the logging of the escalation requests and what the user does as Admin. Any suggestions? I plan on auditing the sudoers file and group memberships, but it’s more the accountability that’s somewhat missing from this. Unless I missed something in my testing that actually does log all actions and I’m just blind ????(Hoping it’s the latter case).
Actually, not sure, I was thinking of having a look at the same thing but need to find some time to dive into it.
Great work on this.. running into an issue where after the user say they do not need admin powers anymore, the icon changes to standard but permissions are have not been revoked.. any thoughts?
Oh, no did not have that. How did you check the permissions?
Using the checkAdmin script with Jamf Pro policy..
Yes, I understood that, but in that script I used the command “ sudo -u $loggedInUser /Applications/Privileges.app/Contents/Resources/PrivilegesCLI –remove” to demote the admin. This is a build in CLI command for the privileges app. Because you see the DockItem changing back to Standard, it means that it executed that command.
My question was, you say it does not really revoke the admin privileges, where / how did you confirm that this was the case?
I mean, did you check in Terminal? Or in System Preferences.
Reason for my question, if you only checked in System Preferences, and you had System Preferences open when you pressed “NO” to the question for the admin powers…. you need to quit Sys Prefs and open them again.
macOS does not lively update SysPrefs when changes happen while it’s open.
Ahhh.. okay. I checked via system preferences and yes, i did have it open when i clicked “No” to the question for the admin users. When i closed out of system preferences, i can confirm that the user was set back to standard.
I should’ve known that! Thank you for the prompt response on this. Nicely written instructions.
Cool! Thanks for your comment / question! Always better to check because that’s how we share info!
One last question.. Could the user technically modify the preferences option to increase the amount of time administrator rights is active for? If so, any thoughts on how i could disable this or gray it out?
The time in the option is for when you users decide themselves only want admin privs for x amount of time.
That’s a feature SAP built into Privileges for when you are working with nice endusers toggle the privileges to admin via the Dock Menu “toggle priv” action. It does not impact the admin rights when they just click the app and request admin rights…
The script and launchdaemon counters this… in a way… but whatever they put in the settings… it does not matter, it’s the interval you put in the LaunchDaemon that matters if you want to force a demote back to standard.
Ahh.. fantastic.. Understood
Really good work. Will attempt to implement this here for folks.
Running into an odd issue where a user provisioned as an Admin, and then has them revoked via the Permissions app is no longer able to log on to the device. The same U/P will get past FileVault, but then dumps to a blank logon screen that will not accept the U/P until such time that the user is made an Admin via another account in Users & Groups preferences.
Interesting, I actually checked that workflow if I remember well and dit not have any issues. However, to be tested if that was only an isolated issue or if it can be reproduced on other devices. I don’t immediatly why.
I’ve reproduced this behavior on 2 different enterprise devices (MacMini & MBP).
This is the logon screen displayed after authenticating past filevault:
http://tinypic.com/r/293hfzr/9
Note that the password field was pre-filled in, however it would not accept it when providing the username. Clearing both and providing them fresh also did not work for the account. Only another account (which was admin) was able to logon and convert the impacted account back to admin.
Just noticed that if the username has spaces in it, the script doesn’t work. Putting quotes around “$loggedInUser” in lines 38 and 91 seems to do the trick. Account short names don’t usually have spaces, but on this computer it does. Thought I would share.
Hi! Thanks for that! I’ll update the script! Good catch! Thanks for sharing.
Hello,
I’m getting the following error, “30:38: execution error: An error of type -610 has occurred. (-610)”. It only happens on some computers. Not sure why. I think it happens when the script runs the osascript part. The computers I’m testing it with are on macOS 10.14.4. Thoughts?
Interesting. I did not test it on 10.14.4 yet. Might be that something changed. It feels like a “no user interaction” allowed kind of issue. When I wrote the script I had to force my way into getting the popup in the user gui because the LaunchDeamon runs as root and macOS does not like that. It is indeed possible that the tricks to used in the script broke with 10.14.4.
Will have to look into it but if it’s only 10.14.4 you see the issue with… if might indeed be something to do with not being able to show the popup in the user context.
So, below is what I did in the meantime. You might want to look at it and see of other/better ways to get it done. I’ll be interested to see how you go about it.
===
# The UID will be used to run the user interaction as the logged in user.
loggedInUID=$(id -u “$loggedInUser”)
# if user is admin for more than the time limit, ask if to confirm need for superpowers
if [[ “$adminTimeMinutes” -ge $timeLimit ]]; then
confirmAdmin=$(/bin/launchctl asuser “$loggedInUID” /usr/bin/osascript <<EOT
tell application "Finder"
activate
with timeout of 600 seconds
set myReply to button returned of (display dialog "Do you still need Admin Super Power?" buttons {"Yes", "No"} default button 2)
end timeout
end tell
EOT)
Yesterday version 1.0.5 has been released, including new management features like a fixed timeout.
looks like we no longer need the launchdeamon
Awesome! Thanks for commenting! I’ll add a note to the post!
I don’t see where this is implemented. the only timeout I see is still the toggle timeout. If privileges are elevated by opening the app and clicking “Request Privileges”, the timeout does not apply.
If I’m missing something here, please show me
If you want to block the use of running the app to elevate admin rights and only only the dock toggle you can just create a restricted software record for the process “Privileges” in Jamf Pro and tick the match exact process checkbox.
This will not allow the user elevate by launching the app but it still allows the dock toggle as that users privilegesCLI process.
Nice option Tim!
I used ‘Privileges.app’ in the Process Name and checked the ‘Restrict exact process’ and ‘Kill’ boxes
The only thing I’d like to do now is notice the Users to use the Toggle option when they want to launch Privileges, not when they actually use the toggle-option.
When I use the ‘Message’ option, the users get the notification, even if they use the toggle option.
Any suggestions?
If you set the Process Name to “Privileges” rather than “Privileges.app”, the toggle option is still allowed, but the double-click option is restricted. Neat!
Does it work for Big Sur?
I think the closing of the seconds does not enter what you recommend me to do?
I already ran it in Big Sur a thousand thanks, just to confirm you need to use the checkAdmin.sh so that everything works true.
To later restrict it, we can stop the process, true.
Hi, great article, thank you. Any ideas on how to stop users from elevating themselves to admin and then deleting the app, and therefore remaining admin for the next 6 years?!
Thanks for any advice.
Design an HR policy to get them fired if they do, don’t give them admin rights or the app the start with or run a recurrent script or policy to redeploy the app and /or demote them again. If they really want, they will kill all your launchDaemons etc or fiddle around with things in Terminal via Recovery mode. Unless you put a firmware password on the device. It’s a cat and mouse game to be honest.
The first idea would be my preferred one!
Yes, redeploy was my only thought but that still doesn’t demote them again but as you said in your article, there are ways of demoting. Don’t even mention firmware passwords… M1 macs don’t have them. super cheesed off about that one!
True, M1 is another story indeed. Yeah educating users will remain the main things I guess but API script to lock via MDM is an option indeed.
Or if you really want to, recurring policy checking for admin privs and if found an API call to lock the device via MDM
Great post. I seem to get a BigSur popup prompt asking for access to Finder from Jamf when the script has detected the user has had admin access for 10mins. Any ideas why? If accepted it then prompts “Do you still need admin super power”
This is the popup I was referring too: https://ibb.co/D4jhCTZ
The popup is because of the trick in the script doing.
You’ll to put a PPPC profile in place like discussed here: https://www.jamf.com/jamf-nation/discussions/29866/jamfagent-wants-access-to-control-finder
The trick in the script I mentioned does something like “tell Application Finder”…
You don’t really need `tell application Finder` or `activate` in dialog prompts. Strictly speaking it’s supposed to ensure that the popup is on top of other windows, but I’ve never seen that not happen even if I don’t use those commands. And if you don’t use those commands, you don’t need a PPPC profile.
Going to update the script for the getadmin.sh piece? I see it has python code in there. Apple is taking Python out of macOS. May be a future problem.
Ah good call! Thanks for flagging! Will have a look at that!
macOS 12.3 is out. Python 2.7 is gone.
Id suggest changing the loggedInUser variable from a Python2 line to something like…
loggedInUser=$( scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ && ! /loginwindow/ { print $3 }' )
OR
loggedInUser=$(stat -f %Su /dev/console)
Just tried it, after some signing issues I could deploy it
after install i got the request privileges, clicked request, but the user is still a standard user, no admin rights
I just upgraded to macOS 12.4 is it related that you know of, if not what else can be the issue?
thnx
also the icon doesn’t change and ctrl click doesn’t give me any options
Curious if anyone has seen a user ever fail the GUI auth, nothing is logged with the attempt, oddly if the user triggers the cli tool, provides reason and authenticates with no issue. I have 457 devices and so far this is the only user that this doesn’t appear to work on.
I have a problem to implement it now in Ventura everything excellent except CheckAdmin I have an error in line that uses Python. Will they make it work? Any alternative to make it work in Bash.
Have you installed Python? As it was removed from macOS?
The old method of determining the current user using python can be replaced. See https://scriptingosx.com/2020/02/getting-the-current-user-in-macos-update/
Can someone tell me the updated script for Check Admin worked very well for 1.5.2 but for 1.5.4 this script died.