Description
The aim of my project is to allow administrators to drop privileges for reasons of self-control. Currently, it works only on MacOS Sierra but the concept should be extensible to any Unix compatible system.
The sudoers mechanism is the workhorse. By adding a file in sudoers.d/
the administrator user (let's call him my-admin
) is given permissions to run the script admin-helper
as root.
The admin-helper
script when run, toggles my-admin
's membership from the admin
group. When the my-admin
is not in the admin
group, the user is only added after the script sleeps for 20 min.
Files
admin-helper
#!/bin/bash
set -e -u
username=$SUDO_USER
delay=$((60*20)) #20 minutes
uGuid=$(dscl . -read /Users/$username/ GeneratedUID | sed -nE 's/GeneratedUID: (.*$)/1円/p')
if groups "$username" | grep -q -w admin; then
dscl . -delete /Groups/admin GroupMembers "$uGuid"
echo "Removed '$username' from admin. You may need to logout for changes to take effect."
else
echo "'$username' is not an admin"
echo "Sleeping for $delay seconds staring from $(date '+%D %T')"
sleep "$delay"
if [[ -z "${1+x}" ]]; then
echo "Adding '$username' to admin group"
dscl . -append /Groups/admin GroupMembers "$uGuid"
else
echo "Executing command as root"
1ドル
fi
fi
admin.sudoers
User_Alias DELAYED_ADMINS = my-admin
Cmnd_Alias ADMIN_HELPERS = /usr/local/bin/admin-helper
DELAYED_ADMINS ALL=(root) ADMIN_HELPERS
Usage
This is the installation process:
sudo mkdir -p /private/etc/sudoers.d/
EDITOR="cp admin.sudoers" sudo visudo -f /private/etc/sudoers.d/admin
sudo cp admin-helper /usr/local/bin/admin-helper
The subsequent usage is:
sudo admin-helper
or
sudo admin-helper "whoami"
Review
Some of the points I want a review for include:
- The way to add/remove user from the
admin
group. Perhaps there is a better cross-platform way of doing this. - Potential security issues. Possibility of locking oneself out from the admin privilages.
- Better/safer way to do implement installation or uninstallation.
EDIT:
The way I use this script is to have my privileges dropped most of the time, and only regain them (by running the script 20min before) when I need to do admin stuff.
Purpose/Example usage
The whole reason behind having the delay before gaining admin privileges is to prevent my-admin
from gaining them at whim. As a concrete example, suppose my-admin
wishes to use MacOS parental control settings on himself. He can do so by dropping admin privileges using admin-helper
, then setting parental controls for my-admin
using another administrator account (and then forgo access to the other admin account). Now suppose my-admin
wants to disable the parental-controls, he must regain privileges by running admin-helper
script again, and only then he can disable parental-controls. For this he has to wait for 20min which is a good thing. Say parental-controls prevented him from viewing Facebook. This means that he can no longer open that Facebook tab on whim while he is still doing important work. He can always decide that, "I will run Facebook after 20min", but that decision too can be changed anytime within 20 minutes by interrupting the admin-helper
script while it is sleeping.
An analogy would be that you have a box of candies that only opens 20min after you tell it to. Will you eat the same amount of candies that you would eat if you could open the box instantly?
2 Answers 2
Usability
The current script works in a dual mode:
- When run without parameters, it toggles group membership
- When run with a parameter, the parameter is executed as root, on the condition that the user is not currently an admin
I find the conditional execution in the second mode a bit confusing. That is, when a parameter is given, but the user is admin, the command won't be executed. Instead the script will drop membership. If you really want to execute the command you have to re-run the same command line, which could be annoying.
I suggest to change the behavior so that when a parameter is given, execute it always, after the delay, regardless of the membership status. I think this won't conflict with your main purpose, but it would improve the usability of the script.
Cross-platform way to add/remove users
As a first step to making the script more portable, it would be good to separate the platform dependent parts from the platform independents ones, for example:
add_to_admin() {
dscl . -append /Groups/admin GroupMembers "$uGuid"
}
remove_from_admin() {
dscl . -delete /Groups/admin GroupMembers "$uGuid"
}
You could have the platform-specific implementations in separate files, and then source the appropriate flavors as needed.
Minor technical improvements
Instead of sed -nE 's/GeneratedUID: (.*$)/1円/p'
to get the UID part,
it would be simpler to use cut -f2 -d' '
or awk '{ print 2ドル }'
.
This seems to check if 1ドル
empty:
if [[ -z "${1+x}" ]]; then
Unless I'm missing something, this is equivalent but simpler:
if [ -z "1ドル" ]; then
When 1ドル
appears in the middle or near the end of a script,
it can be hard to remember where it comes from and what it's supposed to be.
It's better to assign command line arguments to a meaningful variable early in the script, and refer to them by that name.
That also makes it easier to find all locations where it is used.
For example, you could put near the top of the file:
cmd=1ドル
-
\$\begingroup\$ Also, I have added the intended purpose and a usage example to the question. That was perhaps not very clear before. \$\endgroup\$Miheer– Miheer2017年05月04日 12:24:09 +00:00Commented May 4, 2017 at 12:24
-
\$\begingroup\$ I think I can still do what you say. I can create a new group (called
delayed-admin
) and add an entry in sudoers file to allow the group to run sudo command with a delay.my-admin
then has to just add himself to thedelayed-admin
group, and remove himself from theadmin
group once. \$\endgroup\$Miheer– Miheer2017年05月04日 20:38:20 +00:00Commented May 4, 2017 at 20:38 -
\$\begingroup\$ @Miheer I think that would make both the concept and the implementation simpler, so it seems a good idea. \$\endgroup\$janos– janos2017年05月05日 11:23:52 +00:00Commented May 5, 2017 at 11:23
-
\$\begingroup\$ @Miheer I added a new Usability section at the top. \$\endgroup\$janos– janos2017年05月05日 11:35:56 +00:00Commented May 5, 2017 at 11:35
Based on @janos's usability suggestions, the following seems to be a better way:
Installation:
Create a new group called delayed-admin
and copy these files to their respective locations.
/usr/local/bin/delayed
This script reads the delay from /etc/delay.conf
, sleeps for those many seconds, and then executes the command passed in the argument (or executes the shell if there are no arguments)
#!/bin/bash
set -e -u
CONFIG_FILE='/etc/delay.conf'
# use integer variable to ensure that delay is always an integer regardless of the contents of the CONFIG_FILE.
declare -i delay=$(cat "$CONFIG_FILE")
CMD=${@:-/bin/bash}
echo "Sleeping for $delay seconds staring from $(date '+%D %T')"
sleep $delay
echo "Running command '$CMD'"
$CMD
/etc/sudoers.d/delayed-admin
Allow everyone in the delayed-admin
group to run /usr/local/bin/delayed
as root.
%delayed-admin ALL = /usr/local/bin/delayed
/etc/delay.conf
The number of seconds that the delayed
script will sleep for, before executing any command.
1200
Usage:
If my-admin
wants to have delayed administrator access, he should be moved form the admin
group to the delayed-admin
group and can then run the commands:
sudo delayed cmd #run "cmd" as root after a delay of 1200 sec
or
sudo delayed #root shell after a delay of 1200 sec
-
\$\begingroup\$ @janos: check this out \$\endgroup\$Miheer– Miheer2017年05月06日 14:45:56 +00:00Commented May 6, 2017 at 14:45
-
\$\begingroup\$
/etc/delay.conf
is not a great idea. It's not great to pollute/etc
with custom stuff, and the name is too generic. A better way would be putting this configuration in the same dir as the script itself. Or, if you don't mind letting users change the default delay, you could put it in the user's home directory, or use an environment variable. \$\endgroup\$janos– janos2017年05月09日 11:38:04 +00:00Commented May 9, 2017 at 11:38 -
\$\begingroup\$ @janos, the delay should only be configurable by root. I can change the name to
delayed-admin.conf
, but is there another way to maintain configuration which can be modified by root only? \$\endgroup\$Miheer– Miheer2017年05月09日 20:06:36 +00:00Commented May 9, 2017 at 20:06