macOS shell script check. A better way to execute the if statement and check for a condition
I need to write a very simple shell script that will check if the system is configured to enforce multi-factor authentication.
To verify that the system is configured to enforce multi-factor authentication, run the following commands:
/usr/sbin/system_profiler SPConfigurationProfileDataType | /usr/bin/grep enforceSmartCard
If the results do not show "enforceSmartCard=1", this is a finding.
I created this very simple script, but I am pretty sure there is a more effective, elegant and efficient way to achieve the same result.
Basically if it was you, what kind of modifications would you apply to the script below to achieve the same results?
Thank you so much in advance for your help.
#!/bin/zsh
myVAR=`/usr/sbin/system_profiler SPConfigurationProfileDataType | /usr/bin/grep enforceSmartCard`
if [ $myVAR = "enforceSmartCard=1" ]
then
echo "The system is configured to enforce multi-factor authentication"
else
echo "The system is not configured to enforce multi-factor authentication"
fi
Solution 1:
This might be a little more elegant, not necessarily simpler: I'm wrapping the parts of the pipeline in their own functions
profile () { /usr/sbin/system_profiler SPConfigurationProfileDataType; }
enforces2fa () { /usr/bin/grep -F -q 'enforceSmartCard=1'; }
if profile | enforces2fa; then
echo "The system is configured to enforce multi-factor authentication"
else
echo "The system is not configured to enforce multi-factor authentication"
fi
Some notes
- prefer
$(...)
over`...`
for command substitution: it's easier to read. -
if
takes a command and branches based on the command's exit status. At a bash prompt, enterhelp if
for more details.-
[
is a bash builtin command, not just syntax.
-
- if "enforceSmartCard=1" is the only text on the line, add
-x
to the grep options.
Additionally, you can modify the PATH in your script to streamline the functions
PATH=$(getconf PATH) # /usr/bin:/bin:/usr/sbin:/sbin
profile () { system_profiler SPConfigurationProfileDataType; }
enforces2fa () { grep -F -q 'enforceSmartCard=1'; }
This is only in effect for the duration of the running script, and will not affect your interactive shell.
Solution 2:
I'd be inclined to read the value of the enforceSmartCard
key directly from the com.apple.security.smartcard.plist
file located in the /Library/Preferences
folder.
This can be done using the defaults
command-line tool, which will be significantly faster than the system_profiler
, and you won't need to grep
its output:
defaults read /Library/Preferences/com.apple.security.smartcard enforceSmartCard
Here are the possible outputs for the system_profiler | grep
and defaults
commands, together with their meaning:
system_profiler | grep |
defaults |
|
---|---|---|
enforceSmartCard=0 |
0 | The enforceSmartCard key is set,and its value is false
|
enforceSmartCard=1 |
1 | The enforceSmartCard key is set,and its value is true
|
non-zero exit status |
Error message and non-zero exit status |
The enforceSmartCard key is notset, or ( defaults only) the propertylist does not exist |
The default value for enforceSmartCard
is false
, therefore a non-zero exit status is essentially equivalent in meaning—for our purposes—to enforceSmartCard=0
. In the case of the defaults
command, an error message is also printed that looks something like this:
The domain/default pair of (/Library/Preferences/com.apple.security.smartcard, enforceSmartCard) does not exist
so, provided there isn't a typographical error when you issue the command, then either the file /Library/Preferences/com.apple.security.smartcard.plist does not exist, or it does and the enforceSmartCard
key is not set. Either way, the error message is of little value, so this can be suppressed by redirecting stderr
into the void:
defaults read /Library/Preferences/com.apple.security.smartcard enforceSmartCard 2>/dev/null
Thus, the predicate we discriminate upon will be whether or not this command outputs "1"
(without quotes): if it does, then a user must authenticate using their smart card (in addition to whatever other form of authentication would be required); any other result (either an output of "0"
, or a non-zero exit status with no output) infers that a user may authenticate without using a smart card.
Here's the final script that should be equivalent to yours:
#!/usr/bin/env zsh
plist=/Library/Preferences/com.apple.security.smartcard
(( $( defaults read "$plist" \
enforceSmartCard 2>/dev/null )
)) && i=1 _not= ||
i=2 _not=not
printf '%s ' The system is ${_not} configured to \
enforce multi-factor authentication \
>/dev/fd/$i