0

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
6
  • 2
    Not sure what you mean with simpler, seems to be rather simple already?
    – nohillside
    Jul 27, 2021 at 12:27
  • You could get rid of the variable by running the commands within the if, but readability would suffer.
    – nohillside
    Jul 27, 2021 at 12:29
  • If I were at you, I would probably just change the shebang.
    – Rakib Fiha
    Jul 27, 2021 at 14:01
  • @Rakib Fiha, RE: "If I were at you, I would probably just change the shebang." -- Why? FYI In a default clean install of macOS Big Sur the default shell is zsh. Jul 27, 2021 at 16:34
  • OP asked specifically what I would do. I just happen to run latest bash as my default shell for personal reasons (like posix compatibility and so on) and I do a lot of scripting in bash for my work to have Linux compatibility. So my shebang in most cases is #!/usr/bin/env bash. But here, clearly OP doesn’t need to bother about those issues.
    – Rakib Fiha
    Jul 27, 2021 at 16:55

2 Answers 2

3

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, enter help 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.

1
  • 1
    getconf PATH might be dangerous if other parts of the script rely on commands stored in /usr/local/bin or similar. In general I wouldn't specify paths for commands which are in the standard paths. If PATH doesn't include them other stuff may not work either.
    – nohillside
    Jul 27, 2021 at 19:10
1

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 not
set, or (defaults only) the property
list 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
8
  • JSYK The output is atypical in that while the prompt returns to a normal position, nonetheless, the message has a trailing space and whatever the prompt character is after it, highlighted, and doesn't look at all normal to standard output. Changing printf '%s ' to echo will eliminate the strange output. Jul 27, 2021 at 17:41
  • @user3439894- Wouldn't printf '%s \n' fix the issue?
    – fd0
    Jul 27, 2021 at 19:00
  • OK, you need to quote the desired output. ...my bad....
    – fd0
    Jul 27, 2021 at 19:07
  • Quoting it as it's currently shown the output would be on two lines and why I originally said... Changing printf '%s ' to echo will eliminate the strange output. Jul 27, 2021 at 19:16
  • CJK, I didn't realize that was fd0 that comment back and I deleted the picture link, so have a look at: i.imgur.com/r7HKU7w.png Jul 27, 2021 at 19:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .