Dutch MacAdmins Meeting: 8 June

The (ir)regular meeting of Dutch MacAdmins will happen again! We will meet on June 8, 14:00-17:00 at SAP Netherlands in ‘s-Hertogenbosch. Main topics will be:

  • WWDC news and how it affects MacAdmins
  • Mac management at SAP
  • anything else you may want to bring up

Join #thenetherlands channel on MacAdmins Slack for questions, feedback and great discussions or if you want to volunteer to present.

Registration (Eventbrite, free)

Demystifying `root` on macOS, Part 4 —The Authorization Database

Beyond the Shell

sudo allows you to gain super user privileges from the interactive shell. launchd, installer Packages, management systems and other tools will run scripts as root when required. This covers many cases where administrators need to influence the system on macOS.

However, for most users, macOS is exclusively the graphical interface. Users can authorize to perform certain tasks when they are administrators, like unlocking a Preference Pane or running an installer package.

These tasks are not controlled by sudo but by a separate mechanism. The data for that mechanism is stored in the authorization database.

Here there be Dragons!

As mentioned in earlier parts of this series, many pieces of macOS assume users have administrator accounts. This might not be a possible or useful configuration in your environment. But you still need to provide access to some privileges without giving a user full administrator accounts and access.

However, if you find yourself frequently editing the authorization database, you should re-evaluate your approach. Future macOS updates might change privileges or rules and then your heaviliy modified setup will need to be adpated. Small modifications or granting users admin privileges will be the the least fragile configuration going forward with future macOS releases.

What is it?

The active authorization database lives in sqlite3 database files in /var/db/auth.db.

You can use the sqlite3 command or another tool to read the database directly.

$ sudo sqlite3 /var/db/auth.db .dump

You can use this database access to change the settings directly. However, this is not recommended. The only way sanctioned by Apple to access and change the authorization database is through the security authorization command.

This layer of abstraction allows Apple to change the underlying data store, while keeping tools and frameworks that access the data same.

The authorization database is intialized from the property list file /System/Library/Security/authorization.plist. In older versions of macOS administrators could replace this file with a modified version and delete the database files to have the modified property list initialize the database with the new settings. However, in current versions of macOS this file is protected by SIP, so this strategy is no longer useful.

However, the authorization.plist file is still useful to look at the default values and get an idea of how the authorization database is configured and works. Since there is quite a lot of data in this file, it is best to open it in a graphical property list editor such as Xcode or PlistEdit Pro.

The authorization property list consists of two main dictionaries: rights and rules. There are also comment fields distributed all through the file, which provide some context to what the individual elements are for.

rights designate a certain context that permits a certain action, group of actions or access to configure some part of the os. The names of the rights follow a hierarchy and are denoted in reverse DNS notation.

This website has an overview of all the rights and rules from the authorization.plist. More importantly it shows which rights and rules are available in which version of macOS.

How it works

Within the dictionary for a given right you can find the requirements that a user needs to fulfill to gain the right. There are two main classes: user and rule.

(There is also a third possible value for the class: evaluate-mechanisms will test multiple mechanisms in order. This is used for more complex processes such as the login window.)

The user class will verify whether the user asking to gain the right is in a particular user group. Usually this is the admin group. for example you can inspect the configuration of the system.preferences.datetime right with:

$ security authorizationdb read system.preferences.datetime
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>allow-root</key>
    <true/>
    <key>authenticate-user</key>
    <true/>
    <key>class</key>
    <string>user</string>
    <key>comment</key>
    <string>Checked by the Admin framework when making changes to the Date &amp; Time preference pane.</string>
    <key>created</key>
    <real>522083506.22018802</real>
    <key>group</key>
    <string>admin</string>
    <key>modified</key>
    <real>522083506.22018802</real>
    <key>session-owner</key>
    <false/>
    <key>shared</key>
    <false/>
    <key>timeout</key>
    <integer>2147483647</integer>
    <key>tries</key>
    <integer>10000</integer>
    <key>version</key>
    <integer>1</integer>
</dict>
</plist>
YES (0)

(The YES (0) at the end of the command’s output means that retrieving the data was successful.)

You can also look for the system.preferences.datetime entry in the authorization.plist. This tells us that when a user clicks on the lock in the ‘Date & Time’ preference pane the system will ask for authentication (authenticate-user is true) to check if the user a member of the admin group.

Read the com.apple.configurationprofiles.userprofile.trustcert right to see an example for a rule based right:

$ security authorizationdb read com.apple.configurationprofiles.userprofile.trustcert
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>class</key>
    <string>rule</string>
    <key>comment</key>
    <string>Install user configuration profile with certificate requiring trust change.</string>
    <key>created</key>
    <real>529239529.937994</real>
    <key>modified</key>
    <real>529239529.937994</real>
    <key>rule</key>
    <array>
        <string>authenticate-session-owner-or-admin</string>
    </array>
    <key>version</key>
    <integer>0</integer>
</dict>
</plist>
YES (0)

Rather than defining the approving criteria in the right itself, this right references the authenticate-session-owner-or-admin rule. This name is already quite self-explanatory. However, we can also read the definition of the rule:

$ security authorizationdb read authenticate-session-owner-or-admin
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>allow-root</key>
    <false/>
    <key>authenticate-user</key>
    <true/>
    <key>class</key>
    <string>user</string>
    <key>comment</key>
    <string>Authenticate either as the owner or as an administrator.</string>
    <key>created</key>
    <real>522083506.22018802</real>
    <key>group</key>
    <string>admin</string>
    <key>modified</key>
    <real>522083506.22018802</real>
    <key>session-owner</key>
    <true/>
    <key>shared</key>
    <false/>
    <key>timeout</key>
    <integer>2147483647</integer>
    <key>tries</key>
    <integer>10000</integer>
    <key>version</key>
    <integer>0</integer>
</dict>
</plist>
YES (0)

Requests to grant a right are logged. When you are unsure what the name of right is you can perform/unlock the right or task in the interface and then read the log with:

$ sudo log show --style syslog --predicate 'subsystem == "com.apple.Authorization" && eventMessage CONTAINS[c] "validating credential"' --last 1h

This will list the rights (and rules) that were requested in the last hour.

(Thanks to Erik Berglund on the MacAdmins Slack for showing me how to do this.)

Changing Behavior

You can use the security authorizationdb command to change rights and rules in the authorization database.

WARNING: you can really mess up your system and make it unusable with the wrong settings in the authorization database. You should not test these commands on your (or anybody else’s) work machine. You should do your experimentation and testing on a virtual machine, where you can quickly revert the system to a known working state. You should only use these commands on production Macs when they have been thoroughly tested.

You need super user privileges to change the authorization db. I will use sudo for the interactive examples.

The easiest way to change behavior is to change the right to a different preset rule. The most permissive rule is allow which allow any user the right and not even prompt for authorization.

When you change the ‘Date & Time’ right with:

$ sudo security authorizationdb write system.preferences.datetime allow
Password:
YES (0)

And then open the ‘Date & Time’ preference pane with any user. You will see the pane is unlocked by default.

This may be just a bit too permissive. A more useful rule to use is the authenticate-session-owner-or-admin rule, which will prompt for authentication, and accept the currently logged in user (session-owner) or any admin. This provides for some security so that other people cannot walk up and change the current user’s settings.

$ sudo security authorizationdb write system.preferences.datetime authenticate-session-owner-or-admin
YES (0)

This will allow the any user to unlock the preference pane in their own session. Note that the dialog to unlock does not prefill the user’s name and the text in the dialog still asks for an ‘administrator’s name and password’. So this may be confusing for users. Proper documentation for the user’s affected will help.

Another use case for this rule is to allow administrator account to unlock a locked screen in another user’s session (particularly useful in lab or classroom settings).

$ sudo security authorizationdb write system.login.screensaver authenticate-session-owner-or-admin
Password:
YES (0)

Now, any admin user can unlock any other user’s locked screen. This will of course drop them in that user’s login session so the admin’s have to be responsible with this privilege.

When you take a look through the rules, you will notice that some start with authenticate- and other with is-. The difference is that the authenticate- rules will prompt for user name and password, while the is- rules will grant the privilege when the user satisfies the rule with out a prompt.

There are also some rules whose names end in -nonshared. These have the shared key set to false. This means that these rules will not share credentials with other requests for authentication. Shared credentials will not prompt multiple times for the same credentials in a certain time (the timeout, usually 300 seconds/5 minutes). More sensitive settings are usually not shared.

Exporting and importing privileges

Changing the rule is a straightforward and fairly safe way to change a right’s behavior. When a rule fits your requirements, you should probably use a rule.

However, sometimes you need more fine-grained control of a right. For this you can export a right to a property list file, modify this and re-import it.

For example, say you do not want to grant every user access to a certain right but just a certain group of users even though they are not administrators. Common examples for this would be developers, teachers or lab techs. So, in our example, we create a group named techs:

$ sudo dseditgroup -o create -n . -r "Lab Techs" techs

to be safe we will nest the admin group in the techs group so that members of admin also gain all the rights of techs:

$ sudo dseditgroup -o edit -a admin -t group techs

and add the example user beth

$ sudo dseditgroup -o edit -a beth techs

You can verify that everything worked with:

$ sudo dseditgroup -o read techs
dsAttrTypeStandard:GeneratedUID -
        F9EBB33D-8A71-45EE-A65D-4DBBFF421B49
dsAttrTypeStandard:RecordName -
        techs
dsAttrTypeStandard:AppleMetaNodeLocation -
        /Local/Default
dsAttrTypeStandard:GroupMembers -
        87EE7744-5872-47C1-9574-D247D3DD4D5C
dsAttrTypeStandard:PrimaryGroupID -
        501
dsAttrTypeStandard:NestedGroups -
        ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000050
dsAttrTypeStandard:RealName -
        Lab Techs
dsAttrTypeStandard:GroupMembership -
        beth
dsAttrTypeStandard:RecordType -
        dsRecTypeStandard:Groups

Now we can assign this group to a right. Our example will be the system.preferences.energysaver right. First export it to a property list file:

$ security authorizationdb read system.preferences.energysaver > energysaver.plist
YES (0)

Then change the value of the group key in the property list file to techs:

$ /usr/libexec/PlistBuddy -c "set group techs" energysaver.plist

If you want to learn more about working with property list files, I have written a book on it: ‘Property Lists, Preferences and Profiles for Apple Administrators’

And re-import the modified property list to the authorization database:

$ sudo security authorizationdb write system.preferences.energysaver < energysaver.plist

This alone is not sufficient to unlock the Energy Saver preference pane. When you look at the log with command from above, you can see that unlocking the energy saver pane requires the system.preferences right as well. You can modify this the same way:

$ security authorizationdb read system.preferences > system.preferences.plist
YES (0)
$ /usr/libexec/PlistBuddy -c "set group techs" system.preferences.plist
$ security authorizationdb write system.preferences < system.preferences.plist

Scripting

When scripting this setup you do not have to go through the export/import cycle but can directly import a prepared property list file or here doc:

Summary

There are many levels of access privileges in macOS. Most of them are controlled by different users and groups.

The super userroot exists on macOS like any other unix, but logging in as root is disabled by default as a security measure. The sudo command allows for interactive super user privileges in a shell. There are other ways administration scripts can be launched with super user privileges, such as LaunchDaemons, management systems etc.

The authorization database controls access to elevated rights in the macOS UI. You can modify it as an admin, but should do so with care.

Demystifying root on macOS: Conclusion

This ends my series on the super user in macOS. I hope it clarifies some confusing terms and configurations. As admins we have to use these privileges regularly. But, as the saying goes: “With great power comes great responsibility.”

Understanding how things work and how they affect the system will help you understand what to do when and how to avoid unexpected consequences.

Weekly News Summary for Admins — 2018-05-04

The conference registration season has begun! Three conferences started their registrations this week. There should be one for you. (The one for me is MacSysAdmin, where I will be presenting among many other great speakers this year.)

We got quite a few security related posts this week. Most important is a note from Twitter that they may have left your password unencrypted on their servers. So go change that right now, if you have not already.

In happier news, the iMac turns 20 this week!

Also in last week’s email I forgot set the subject and the email was sent out with tinyletter’s default subject line. My apologies for the confusion both for you, the readers and any email rules/filters you may have set up.

If you would rather get the weekly newsletter by email, you can subscribe to the Scripting OS X Weekly Newsletter here!! (Same content, delivered to your Inbox once a week.)

#! On Scripting OS X

🎤Conferences

📰News and Opinion

🐦MacAdmins on Twitter

🐞Bugs and Security

🔨Support and HowTos

🤖Scripting and Automation

♻️Updates and Releases

📺To Watch

🎧To Listen

📚Support

I do not have any ads on my webpage or this newsletter. However, if you want to support me and this website, then please consider buying one (or both) of my books. (Imagine it’s like a subscription fee, but you also get one or two useful books on top!)

If you have already bought and read the books, please leave a review on the iBooks Store. Reviews are important to help new potential readers make the purchase decision. Thank you (again)!

Demystifying `root` on macOS, Part 3 — `root` and Scripting

sudo is very useful when working interactively in the shell. However, when you are scripting workflows then you don’t want to encounter the interactive prompt for authentication.

sudo in Scripts

You will write scripts that require root privileges to perform their tasks. Many novice scripters will simply add the sudo command to their scripts. For example:

#!/bin/bash

timeserver="time.apple.com"

echo "Setting Time Server to: $timeserver"

# note: sudo is superfluous
sudo systemsetup -setnetworktimeserver "$timeserver"
sudo systemsetup -setusingnetworktime on

When you invoke this script from the command line, it will actually work as expected, since the first sudo will prompt the password and the second sudo will use the cached credentials.

In many cases where the script already has root privileges, it will work also, because sudo when run as root will not prompt for authorization again.

However, when this script is sent with Remote Desktop or run in a different context without user interaction to authorize sudo, the script will stall and eventually fail.

In most contexts, the scripts should already be running with root privileges so sudo in the script is not necessary.

#!/bin/bash

timeserver="time.apple.com"

echo "Setting Time Server to: $timeserver"

systemsetup -setnetworktimeserver "$timeserver"
systemsetup -setusingnetworktime on

You should not use sudo in your management scripts. When commands inside a script require root privileges, you should invoke the entire script with sudo:

$ sudo ./settimeserver.sh

or you deploy and execute the script through other methods that provide root privileges. (Remote Desktop: run as user root, installation scripts, LaunchDaemons, management systems, etc.)

Testing for root Privileges in Scripts

When you write scripts that require root privileges, you may want to test whether it is actually running as root early in the script or exit gracefully with an error or warning. As usual with Unix, there are many ways to achieve this, but the recommended one is to check the EUID (effective user id) environment variable. For the root user the EUID is 0.

#!/bin/bash

# test if root
if [[ $EUID -ne 0 ]]; then
    >&2 echo "script requires super user privileges, exiting..."
    exit 1
fi

# continue with important things here
echo "I am root"

Running a Process as Another User

Most administrator scripts are run in a context where they run with super user privileges. Often they require root privileges.

On the other hand, when you need to affect settings or processes in a user’s context or login session, you may need to run commands as a specific user from a script running as root. It’s the opposite problem of gaining root privileges.

Update: 2020-08-25 macOS has changed and I had a few things to add. Rather than keep modifying this post, I decided to make a new post with some updated code.

You can use sudo -u user command or su user -c command to run a command as a different user. However, the launchd man page warns us:

On Darwin platforms, a user environment includes a specific Mach boot strap subset, audit session and other characteristics not recognized by POSIX. Therefore, making the appropriate setuid(2) and setgid(2) system calls is not sufficient to completely assume the identity for a given user. Running a service as a launchd agent or a per-user XPC service is the only way to run a process with a complete identity of that user.

So it is safest use the Darwin/macOS native mechanism to launch a process as another user. Enter launchctl. You can use the the launchctl asuser verb to execute a script or command as a different user.

uid=$(id -u "$username")
launchctl asuser "$uid" /path/to/command arguments

The launchctl command takes a user’s numerical ID or UID rather than the short name as an argument. You can get a user’s UID with the id -u username command.

Note that launchctl asuser does not launch the command in the context of a new shell environment. You cannot rely on environment variables being set in that context. This is especially relevant for the PATH.

Note also that the asuser verb of launchctl is listed among the deprecated functions of launchctl. However, there is no replacement for the functionality yet.

Getting the Current User

Most of the time you will not know which user you need to run as, when you write a script, but need to run as the ‘currently logged in user’. There are many unix-y ways of determining the current user. However, once again there are edge cases in macOS where some of the traditional methods fail. (Mainly concerning Fast User Switching)

Update 2019-09-04: I have changed the command to get the current user from the python based solution to the scutil based solution. You can get more details why I now recommend scutil in this post.

The ‘official’ method is to use the SystemConfiguration framework, and from a script this is easiest with scutil:

loggedInUser=$( echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ && ! /loginwindow/ { print $3 }' )

This will return the currently active user, even when multiple users are logged in with Fast User Switching. When no user is logged and the system is logging in the value returned will be "". Your scripts have to cover this case as well.

You can use this code snippet as a template:

# get the current user
loggedInUser=$( echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ && ! /loginwindow/ { print $3 }' )

# test if a user is logged in
if [ -n "$loggedInUser" ]; then
    # get the uid
    uid=$(id -u "$loggedInUser")
    # do what you need to do
    launchctl asuser "$uid" /path/to/command arguments
fi

AppleScript

AppleScript has a special function when invoking shell commands for gaining super user privileges. When you run a shell command from AppleScript with the do shell script command you can add with administrator privileges to have the script prompt for admin user authentication and run the command as root:

do shell script "whoami"
do shell script "whoami" with administrator privileges

Will run like this:

    do shell script "whoami"
       --> "armin"
    do shell script "whoami" with administrator privileges
     --> "root"

Like with sudo the credentials for the first command run with administrator privileges will also be cached, so you will not get mulitple prompts, unless the script runs for a long time.

This is useful for providing tools and workflows from within AppleScript for interactive use. However, as with sudo you have to keep in mind that some contexts in which a script may be run does not allow for user interaction and then you have to find other means of elevating privileges.

AppleScript is often used to communicate with other applications and/or the user interface. However, when run with root privileges AppleScripts are often prohibited from connecting to other process or present user interface, such as dialogs. When you really need to do this, you have to use launchctl asuser to change the user the script is run as:

launchctl asuser "$uid" /usr/bin/osascript -e 'display dialog "Do you really want to do this?"

Beyond the Shell

sudo allows you to gain super user privileges from the interactive shell. LaunchDaemons, installer Packages, management systems and other tools will run scripts as root when required. This covers many cases where administrators need to influence the system on macOS.

However, for most users, macOS is exclusively the graphical interface. Users can authorize to perform certain tasks when they are administrator users, like unlocking a Preference Pane or running an installer package.

These tasks are not controlled by sudo but by a separate mechanism. The data for that mechanism is stored in the authorization database, which we will cover in the next post.

Weekly News Summary for Admins — 2018-04-27

Today is Koningsdag (King’s Day) here in the Netherlands. So, because of the holiday, just a quick summary! Have a great week-end, everyone!

If you would rather get the weekly newsletter by email, you can subscribe to the Scripting OS X Weekly Newsletter here!! (Same content, delivered to your Inbox once a week.)

#! On Scripting OS X

📰News and Opinion

🐞Bugs and Security

🔨Support and HowTos

MacAdmins on Twitter

🤖Scripting and Automation

🍏Apple Support

♻Updates and Releases

📚Support

I do not have any ads on my webpage or this newsletter. However, if you want to support me and this website, then please consider buying one (or both) of my books. (Imagine it’s like a subscription fee, but you also get one or two useful books on top!)

If you have already bought and read the books, please leave a review on the iBooks Store. Reviews are important to help new potential readers make the purchase decision. Thank you (again)!

Demystifying `root` on macOS, Part 2 — The `sudo` Command

As mentioned before, the recommended way of gaining super user privileges from the command line in macOS is the sudo command. The name means ‘super user do’ and will perform the following command with root privileges after verifying the user running sudo has the permission to do so.

How sudo works

sudo allows a user to execute a command with super user privileges, without needing to authenticate as the super user. The user has to authenticate as themself, however, and the sudo will check whether the user is authorized to use sudo.

For example, you want to run a command that requires super user privileges:

$ systemsetup -getremotelogin
You need administrator access to run this tool... exiting!

You can then repeat the command with sudo to run it with temporary super user privileges.

$ sudo systemsetup -getremotelogin
Password:
Remote Login: On

On macOS, administator users are allowed to use sudo.

A few notes on sudo:

  • you can type sudo !! as a short cut for ‘repeat the last command with sudo’. More details on this in my post “On Bash History Substitution”.
  • the first time you run sudo with an account on a Mac it will show a longer dialog with a warning or ‘lecture’. (You can change the lecture.)
  • the system will prompt for your password when executing a command with sudo. However, there is a 5 minute (300 seconds) ‘grace period’ where the sudo system caches your credentials and you do not have to re-enter the password. This grace period is limited to a given shell session, so if you open a new Terminal window, you will have to re-enter the password.
  • on macOS sudo will not work if your administrator account’s password is empty: Using the sudo command in Terminal requires an administrator password
  • use of sudo is logged. You can find the log entries in the Console.app by searching for process:sudo:
armin : TTY=ttys000 ; PWD=/Users/armin ; USER=root ; COMMAND=/bin/echo "#iamroot"

sudo and the Environment

sudo runs the command in the current shell environment. The user (or effective user ID) the command is run as switches to root:

$ whoami
armin
$ sudo whoami
root

The sudo environment changes some of the variables, while some will be passed through from your shell. To show this, create a short script:

#!/bin/bash

echo $USER
echo $HOME
echo $EUID

and run it as yourself and then with sudo:

$ chmod +x printenvs.sh
$ ./printenvs.sh 
armin
/Users/armin
501
$ sudo ./printenvs.sh 
Password:
root
/Users/armin
0

Some tools might not read environment variables and determine the user environment through different means. This may lead to some tools writing data to root’s home directory instead of the current users when running with sudo.

The defaults command is one example:

$ sudo defaults write com.apple.loginwindow LoginHook /path/to/script
~ $ defaults read com.apple.loginwindow LoginHook
2018-04-16 15:09:00.378 defaults[69217:3291382] 
The domain/default pair of (com.apple.loginwindow, LoginHook) does not exist
~ $ sudo !!
sudo defaults read com.apple.loginwindow LoginHook
/path/to/script
~ $ sudo plutil -p /var/root/Library/Preferences/com.apple.loginwindow.plist
{
  "LoginHook" => "/path/to/script"
}

Note: This form of customizing login behavior in macOS is deprecated (but still works as of 10.13). LaunchAgents are the preferred method to run scripts or processes at login. (More info here.) If you find yourself building custom LaunchAgents and LaunchDaemons frequently, you need to check out outset.

You have to be aware that running commands with sudo results in a different environment than when you run them directly.

root Shells

In most cases running a single command with sudo is sufficient. However, sometimes it can be convenient to have an interactive shell that runs with super user privileges.

There are two ways of achieving this withsudo:

When you run sudo -s it will invoke a new shell, running as root. The shell that is run is the default shell of your account. So when you have bash set as your shell (the default on macOS) you will get a bash shell running as root. Most other environment settings will remain the same:

$ sudo -s
Password:
# whoami
root
# echo $HOME
/Users/armin
# echo $SHELL
/bin/bash
# exit
$ 

Usually, the Terminal prompt is set up to change from the $ prompt to # when you are running with super user privileges, to remind you of the power you have right now and the danger you are in.

Note: learn how to configure your shell prompt.

To leave the root shell, just type exit.

Alternatively you can use sudo -i to invoke a root shell. With the -i option, the shell will be chosen from the default shell set for root user (/bin/sh on macOS) and will be set up as if the root user were logging in, ignoring your settings, like profile files etc.

$ sudo -i
Mac:~ root# whoami
root
Mac:~ root# echo $HOME
/var/root
Mac:~ root# echo $SHELL
/bin/sh

Note that my custom minimal shell prompt changes when I switch to root with sudo -i since it creates the root shell with the root user’s environment.

In most cases sudo -s should serve well. However, when you want to avoid any customization you might have set in your user environment and work in more pristine environment then it is good to know sudo -i exists.

sudo vs su

There is a different command which allows you to change the user: su (short for ‘switch user’). The main difference between these tools is how they verify if you are authorized to switch.

su will ask for credentials of the user you are switching to. So if you run su bob you need to have Bob’s credentials.

When you run su without a username, it assumes root. But since logging in as root is disabled by default on macOS, it will fail.

$ su
Password:
su: Sorry

sudo, on the other hand, will check its configuration files to see if your account is authorized to run the command as the given user. It asks for your credentials to verify you. You do not need the credentials of the other user, whether it is root or a different user.

Since the root account login is usually disabled on macOS, you cannot use su root - or su - to get a root shell. Use sudo -s or sudo -i instead.

sudo and Scripting

sudo is very useful when working interactively in the shell. However, when you are scripting workflows then you don’t want to encounter the interactive prompt for authentication.

We will look at strategies for privilege escalation (and the opposite) in scripts in the next post.

Weekly News Summary for Admins — 2018-04-20

Still more articles (and bugs) from the 10.13.4 release coming in. Otherwise this has been a quieter week.

If you would rather get the weekly newsletter by email, you can subscribe to the Scripting OS X Weekly Newsletter here!! (Same content, delivered to your Inbox once a week.)

#! On Scripting OS X

📰News and Opinion

🐞Bugs and Security

🔨Support and HowTos

🤖Scripting and Automation

♻️Updates and Releases

🎧To Listen

📚Support

I do not have any ads on my webpage or this newsletter. However, if you want to support me and this website, then please consider buying one (or both) of my books. (Imagine it’s like a subscription fee, but you also get one or two useful books on top!)

If you have already bought and read the books, please leave a review on the iBooks Store. Reviews are important to help new potential readers make the purchase decision. Thank you (again)!

Converting Composer dmg ‘installers’ to pkg

Jamf Composer has always had two formats to build installers. The standard pkg and the seemlingly standard (but not) dmg. The pkg option will build a standard pkg installer file, which will install with any system that can install pkg files.

The dmg option will build a standard dmg disk image file, with the payload of the installer as contents. On its own, however, this dmg cannot do anything. The Jamf Pro management system how ever will understand what to do and how to install the files from the dmg to a system. There are certain features in Jamf Pro which can install and distribute files to user directories and templates (called ‘Fill User Templates’ FUT and ‘Fill Every User’ FEU) which only work with dmg installers in Jamf Pro.

However, Jamf themselves have been recommending to use the standard pkg format in favor of their proprietary use of dmg. Also the Composer application is 32-bit and its future is uncertain.

Luckily there are plenty of great other third-party tools to build installer packages. I cover many of them in my book: Packaging for Apple Administrators

In general, it is probably preferable to re-visit your imaging process and rebuild any installer you still may have in dmg format from scratch. However, in some cases that might not be possible or necessary.

Since the Composer generated dmgs contain all the files for the payload in the proper folder structure you can just use the entire mounted volume as your payload root for pkgbuild. You can easily convert a Composer generated installer dmg to a standard pkg with these commands:

1) mount the dmg:

$ hdiutil attach /path/to/Sample.dmg

this will output a bunch of info, the very last bit is the mount point of the dmg /Volumes/Sample (the name will depend on the dmg)

2) build a pkg with the contents of the mounted dmg as a payload:

$ pkgbuild --root /Volumes/Sample --version 1.0 --identifier com.example.sample --install-location / Sample-1.0.pkg

This will create Sample-1.0.pkg in your current working directory. (I like to include the version in the pkg file name, but that is entirely optional.)

3) cleanup: unmount the dmg

$ hdiutil detach /Volumes/Sample

Obviously this will not work well with other dmgs, such as Full System dmgs, or dmgs downloaded from the web, which contain an app that should be dragged to /Applications to install (use quickpkg for those dmgs).

Demystifying `root` on macOS, Part 1

As Mac Adminstrators, we often have to deal with user privileges for files and processes. While doing that we will use administrator privileges and sudo without as much as a second thought.

However, a proper understanding of what these privileges and processes actually do and mean, can help prevent many problems when managing Macs.

Some History

macOS is based on BSD Unix, which stems back to a time where large mainframes were so expensive they had to be shared among many users. Users and their access privileges control what any user can read, write, or change in the system. These rules prevent conflicts and data loss or theft. When managing these users and their access privileges, there had to be a first, ‘top’, or ‘super user’ which has access to anything.

In Unix and Unix-like systems this user account is traditionally called root. In macOS this user is often also called ‘System Administrator’.

Classic Mac OS, in contrast, had no concept of multiple users built-in to the system. Any person sitting down at a Mac (and any process launched on that Mac) could access and change anything on that system. There were some attempts at adding multi-user functionality to classic Mac OS, but they were ‘added on, not built-in’ and fairly easy to circumvent when a user knew what to do.

User and process management was one of the main benefits Apple touted for the various ‘next generation’ systems Apple introduced in the 90s to succeed classic Mac OS. When Apple bought NeXT and with it the NeXTStep operating system it inherited the unix model of doing so.

Even though the concept of sharing your computer is now relegated to some classroom labs and supercomputer clusters, this model still is present in every macOS and iOS device today. On iOS it is completly invisible to the user, unless a jailbreak is applied. On macOS, however, users and especially admins have to deal with it every day.

Users on macOS

To create a new user on macOS you have go to the ‘Users & Groups’ Preference Pane in System Preferences. Before you can add a new user, you have to unlock the preference pane by clicking the lock icon in the lower left corner. Then the system will prompt for an username and password with adminstrative privileges.

When the account you are logged in as has admin privileges, its name will be pre-filled. When the account is a standard user the username field will be empty and you can enter another user’s name and password.

Once the pane is unlocked, you can hit the ‘+’ icon under the user and will be offered four choices for a new user (from the popup menu next to ‘New Account’:

  • Administrator
  • Standard (the default)
  • Managed with Parental Controls
  • Sharing Only

There are three types of users not present in the popup list

  • Guest
  • System Administrator
  • system services users

The difference between Administrator and Standard accounts is that Administrator accounts are members of the ‘Administrators’ or admin group. This sound simple, but membership in this group bestows many additional benefits.

In day-to-day use Administrator accounts and Standard accounts behave the same. However, there are many situations and workflows on macOS which require authenticating as an Administrator account. As a general rule, a user can affect all the files (and applications) in their home directory and in /Users/Shared, but as soon as you want to change another user, another user’s files or settings that affect all users on a system you need to authenticate as an Administrator account.

The first user created on an unmanaged Mac out of the box will always be an Adminstrator user. Most Mac users use an Administrator account. Many of the workflows built-in to macOS assume an adminstrator account. One example is setting up a new printer.

With an Administrator account you can install third party software. You can also install malicious software. Often malicious software will trick users into installing by masquerading as or hiding in an installer for something useful.

Many consider it a ‘best practice’ to run your everyday work on your Mac with a standard account and only use an administrative account when you have to. However, since you get prompted to authenticate even with an administrative account, the better advice is to take these prompts very seriously and consider what confirming this prompt will really do or install.

The only difference you get when using a standard account is that you need to enter a different username and password in an authentication box instead of just the password. If this helps you pause and consider what you are actually doing, then great! Then this is the proper workflow for you.

However, I suspect that most users would be just as non-considerate of this dialog with a separate username and password as they would otherwise.

macOS Administrator Accounts

The only difference between Adminstrator accounts and Standard accounts is the membership of the admins group.

You can check whether a given user is a member of the admin group with the dseditgroup tool:

$ dseditgroup -o checkmember -u armin admin
yes armin is a member of admin

You can also use this tool to add or remove a user from the admin group:

$ dseditgroup -o edit -n . -a username -t user admin    # add username
$ dseditgroup -o edit -n . -d username -t user admin    # delete username

This membership comes with many privileges. Admin users can (after authentication):

  • unlock System Preferences and change system settings
  • install Apple and third party software and installer packages
  • create, change, and delete files owned by other users
  • change access privileges and ownership of files of folders in Finder
  • run and stop (kill) processes owned by other users
  • use sudo in Terminal

and many things more.

On macOS these privileges are controlled mainly by two mechanisms:

  • sudo and the sudoers file
  • the authorization database

sudo is used to gain root privileges in the shell (Terminal). The authorization database controls access privileges everywhere else.

What root can do

The ‘System Administrator’ or the root account controls the system. Mainly the root account can read, update, delete all local user accounts. It can control file and folder privileges and ownership. It can start system services running in the background and assign system network ports (with a port number lower than 1000). Most of this is managed by a process called launchd which is the first process to run on macOS.

Many commands require to be run as root or with elevated root privileges.

What root cannot do: System Integrity Protection (SIP)

On macOS, however, there are limits to what the root account can do. System Integrity Protection is a mechanism which protects important parts of the OS from mnodification, even with root permissions.

Only certain processes signed by Apple are allowed to modify these protected files and directories. Usually this means Apple signed installer pkgs for software and security updates.

Apple Support: About System Integrity Protection on your Mac

Apple lists a set of top-level directories that are protected. However, the list is a bit more detailed. You can use the -O (capital letter ‘O’, not a zero) to see if a file or directory is protected by SIP:

$ ls -lO /usr/
total 0
drwxr-xr-x  978 root  wheel  restricted 31296 Mar 30 18:21 bin
drwxr-xr-x  294 root  wheel  restricted  9408 Mar 30 18:21 lib
drwxr-xr-x  238 root  wheel  restricted  7616 Mar 30 18:21 libexec
drwxr-xr-x    8 root  wheel  sunlnk       256 Dec 28 13:48 local
drwxr-xr-x  248 root  wheel  restricted  7936 Mar 30 18:21 sbin
drwxr-xr-x   46 root  wheel  restricted  1472 Mar 30 18:21 share
drwxr-xr-x    5 root  wheel  restricted   160 Oct  3  2017 standalone

Files and Folders marked with restricted are protected by SIP. Sometimes folders inside a protected folder may not be protected, as the /usr/local/ directory in this example is.

SIP provides more protection than just certain parts of the file system, it also protects changing the boot volume and some other aspects of the OS.

While these limitations on even the root account can be annoying, they provide a level of security that parts of the OS have not been tampered with or changed by other software.

Enabling (and Disabling) root

On macOS the root account exists with a UID of ‘0’. However, it is set up so you cannot log in to a Mac as ‘System Administrator’ or root. (A terrible bug in early 10.13 provided a brief exeception to that rule.)

Note: login as root is disabled for security purposes. It is highly recommended that you leave the root account disabled on macOS and rely on sudo to gain temporary super user privileges when necessary.

If, for some reason, you do need to log in as root, then you can enable the root and provide it with a password. You can do so in either the ‘Directory Utility’ application. After unlocking with your administrator password, you choose ‘Enable Root User’ from the ‘Edit’ menu. You can also change the root account’s password here or disable it again later.

Apple Support: How to enable the root user on your Mac or change your root password

From the command line, you can also use the dsenableroot command:

$ dsenableroot

will enable and/or update the root account. It will interactively ask for admin credentials and for a new password for the root account. Read the command’s man page for details.

$ dsenableroot -d

will interactively disable the root account again.

Becoming root

Different environments and tools have different means of gaining super user or root privileges. While the sudo command should be the preferred means of gaining temporary super user privileges, it is important to know and understand the other options.

LaunchDaemons

Scripts and tools executed from LaunchDaemons run as root unless a different user is specified in the UserName key in launchd property list.

LaunchAgents on the other hand will be executed as the user logging in.

You can get details on how to set up and use LaunchDaemons here.

Run as root in ARD

When you prepare a ‘UNIX command’ to be sent to remote computers in Apple Remote Desktop, you have the option of running the command as the currently logged in user or as a specific user. When you specify root as the user, the script will execute with super user privileges. Since the ARD agent process runs as root on the client, no extra authentication or enabled root account is necessary.

Management Systems

The agent software of most management systems (Jamf, Munki, etc.) is installed to run with root privileges. Therefore, scripts executed by management systems run with root privileges as well.

Installation Scripts

Installation packages also perform their task with root privileges. They also require administrator authentication to start. Any installation scripts (pre-/postinstall scripts) will also run with root privileges.

set-UID bits

There is a special bit you can set on an executable’s mode (or privileges) which tells the system to run this script as the file owner, no matter who actually runs the executable. If the executable file is owned by root it will run with root privileges.

This flag is the “set-user-ID-on-execution bit”, also called the “Set-User-ID”-bit or just “s-bit”.

In the long ls format or with the stat command the set-user-ID bit is shown as an ‘s’ in place of the user’s x bit. One example is the ps command:

$ stat -l /bin/ps
-rwsr-xr-x 1 root wheel 51200 00:57 /bin/ps

Use chmod's u+s to set the set-user-ID bit and u-s to remove it:

$ chmod +x importantcommand [rwxr-xr-x]
$ chmod u+s importantcommand    [rwsr-xr-x]
$ chmod u-s importantcommand    [rwxr-xr-x]

Warning: Obviously it is very important that this executable is not modifiable by other users. They would be able to replace the command with their own code and execute anything with root privileges. Most system commands that have the s-bit set on macOS are protected with SIP.

The sudo command

As mentioned before, the recommended way of gaining super user privileges from the command line in macOS is the sudo command. The name means ‘super user do’ and will perform the following command with root privileges after verifying the user running sudo has the permission to do so.

We will look at the sudo command in detail in the next post.

Weekly News Summary for Admins — 2018-04-13

More ‘Spring Update Fallout’ this week. Users will now get warning when they launch a 32-bit app. Apple is updating older versions of OS X to install the High Sierra Installer app.

If you would rather get the weekly newsletter by email, you can subscribe to the Scripting OS X Weekly Newsletter here!! (Same content, delivered to your Inbox once a week.)

🎂Anniversary

I published the first “Weekly News Summary for Admins” a year ago on this blog. The email newsletter came later in June.

The summary now has a few hundred readers every week. They are split fairly evenly across the weblog and the email newsletter. I have gotten lots of friendly and grateful feedback both from reader and authors.

So, thank you, readers, for your attention, and thank you all the MacAdmin authors who are documenting and sharing their opinions and solutions for everyone!

If you enjoy the news summary, then you can do me a favor by recommending it to another Mac Admin, retweeting it on Twitter or sharing it on your favorite social media. Thank you!

(Now back to the normal program.)

📰News and Opinion

🐞Bugs and Security

🔨Support and HowTos

Krypted Server Migration Posts

Charles Edge is continuing his epic series of posts on how to replace macOS Server.

🤖Scripting and Automation

🍏Apple Support

♻️Updates and Releases

🎧To Listen

📚Support

I do not have any ads on my webpage or this newsletter. However, if you want to support me and this website, then please consider buying one (or both) of my books. (Imagine it’s like a subscription fee, but you also get one or two useful books on top!)

If you have already bought and read the books, please leave a review on the iBooks Store. Reviews are important to help new potential readers make the purchase decision. Thank you (again)!