Quantcast
Channel: rtrouton – Der Flounder
Viewing all 764 articles
Browse latest View live

Updated Jamf Pro MDM lock script to add reporting feature

$
0
0

Previously, I’d written a script to manage sending device lock commands using the Jamf Pro Classic API. After writing it, I thought that it would be a good idea if the script could also generate a report that could be handed off to others so I forked the script and updated it to generate a report in .tsv format. Since others might prefer the original script without the automatically generated report, I left that one alone and have made the forked copy into its own script. For more details, please see below the jump.

Pre-requisites:

If setting up a specific Jamf Pro user account for this purpose with limited rights, here are the required API privileges for the account on the Jamf Pro server:

Jamf Pro Server Objects:

Computers: Create, Read

Jamf Pro Server Action:

Send Computer Remote Lock Command

This script reads a .csv file formatted as follows:

Jamf Pro ID, PIN Code” as the first line

Subsequent lines:
Column 1: A Mac’s Jamf Pro ID
Column 2: Device Lock PIN code


Jamf Pro ID PIN Code
26 165234
52 197898
1226 201145
view raw
mdmlock.csv
hosted with ❤ by GitHub

For authentication, the script can accept manual input or values stored in a ~/Library/Preferences/com.github.jamfpro-info.plist file.

The plist file can be created by running the following commands and substituting your own values where appropriate:

To store the Jamf Pro URL in the plist file:

defaults write com.github.jamfpro-info jamfpro_url https://jamf.pro.server.goes.here:port_number_goes_here

To store the account username in the plist file:

defaults write com.github.jamfpro-info jamfpro_user account_username_goes_here

To store the account password in the plist file:

defaults write com.github.jamfpro-info jamfpro_password account_password_goes_here

Once you have authentication handled, the script is designed to run as shown below:

/path/to/Jamf_Pro_MDM_Device_Lock.sh /path/to/filename_goes_here.csv

Once executed, the script will then do the following:

Skip the first line of the .csv file (this is the “Jamf Pro ID, PIN Code” line.)
Read each subsequent line of the .csv one at a time and assign the values of column 1
and column 2 to separate variables.

Use the variables in an API POST call to identify a Jamf Pro computer inventory record using the Jamf Pro ID listed in the .csv file and lock the Mac in question using the the PIN code listed in the .csv file.

A successful MDM lock should produce output similar to that shown below:

Attempting to send MDM lock to Jamf Pro ID 2935 with PIN code 348202.
<?xml version="1.0" encoding="UTF-8"?><computer_command><command><name>DeviceLock</name><command_uuid>98d915a4-6132-4535-b474-c8381e48425a</command_uuid><computer_id>2935</computer_id></command></computer_command>
Successfully locked computer with Jamf Pro ID 1925 with PIN code 348202.
view raw
gistfile1.txt
hosted with ❤ by GitHub

Failures should look similar to this:

Attempting to send MDM lock to Jamf Pro ID 1234567890 with PIN code 348201.

ERROR! MDM lock of computer with Jamf Pro ID 1234567890 failed.

 

Attempting to send MDM lock to Jamf Pro ID 29352935 with PIN code 12345.

Invalid PIN code data provided: 12345

 

Attempting to send MDM lock to Jamf Pro ID AA2319 with PIN code 348206.

Invalid Jamf Pro ID data provided: AA2319

 

username@computername ~ % /path/to/Jamf_Pro_MDM_Device_Lock_with_Report.sh /path/to/filename.csv
Please enter your Jamf Pro server URL : https://jamf.pro.server.here
Please enter your Jamf Pro user account : username_goes_here
Please enter the password for the username_goes_here account:
Attempting to send MDM lock to Jamf Pro ID 1234567890 with PIN code 348201.
ERROR! MDM lock of computer with Jamf Pro ID 1234567890 failed.
Attempting to send MDM lock to Jamf Pro ID 2935 with PIN code 348202.
<?xml version="1.0" encoding="UTF-8"?><computer_command><command><name>DeviceLock</name><command_uuid>ee3aa1de-cb8d-482e-84f3-384ad8ce6754</command_uuid><computer_id>2935</computer_id></command></computer_command>
Successfully locked computer with Jamf Pro ID 2935 with PIN code 348202.
Attempting to send MDM lock to Jamf Pro ID 29352935 with PIN code 12345.
Invalid PIN code provided: 12345
Attempting to send MDM lock to Jamf Pro ID 9876543210 with PIN code 348203.
ERROR! MDM lock of computer with Jamf Pro ID 9876543210 failed.
Attempting to send MDM lock to Jamf Pro ID AA2319 with PIN code 348206.
Invalid Jamf Pro ID provided: AA2319
Report on Macs available here: /var/folders/wz/mp27mjl97h505nvff787hh3c0000gn/T/tmp.myASwMzm.tsv
username@computername ~ %
view raw
gistfile1.txt
hosted with ❤ by GitHub

 

This script will also automatically generate a report in .tsv format with information similar to what’s shown below:


Jamf Pro ID Number Make Model Serial Number UDID Jamf Pro URL MDM Lock Successful
10734 Apple MacBook Pro (13-inch, 2018) C02TW0WAHX87 60471C6E-02D6-56C5-91AE-5E73868ADA08 https://jamf.pro.server.here/computers.html?id=30734 Yes
858 Apple MacBook Pro (13-inch, 2018) C027251024N23 209B8A69-CCA1-5F31-B415-A929019673D8 https://jamf.pro.server.here/computers.html?id=31858 No
421 Apple MacBook Pro (13-inch, 2018) Q027251024R23 EFAA3D9C-A53A-551E-B9C5-FAEFD77A4F58 https://jamf.pro.server.here/computers.html?id=32421 Yes
1217 Apple MacBook Pro (13-inch, 2018) C02F0U5WAHX54 C47E3AAC-0D4A-566F-8820-EAC94732739D https://jamf.pro.server.here/computers.html?id=31217 Yes

This script is available below and also from GitHub at the following location:

https://github.com/rtrouton/rtrouton_scripts/tree/main/rtrouton_scripts/Casper_Scripts/Jamf_Pro_MDM_Device_Lock_with_Report

#!/bin/bash
# Sends MDM lock commands using Jamf Pro's Classic API.
# This script reads a .csv file formatted as follows:
#
# "Jamf Pro ID, PIN Code" as the first line
#
# Subsequent lines:
# Column 1: A Mac's Jamf Pro ID
# Column 2: Device Lock PIN code
#
# Example:
#
# Jamf Pro ID, PIN Code
# 26,165234
# 52,197898
# 1226,201145
#
# This script is designed to run as shown below:
#
# /path/to/Jamf_Pro_MDM_Device_Lock_with_Report.sh /path/to/filename_goes_here.csv
#
# Once executed, the script will then do the following:
#
# Skip the first line of the .csv file (this is the "Jamf Pro ID, PIN Code" line.)
# Read each subsequent line of the .csv one at a time and assign the values of column 1
# and column 2 to separate variables.
#
# Use the variables in an API PUT call to identify a Jamf Pro computer inventory record
# using the Jamf Pro ID listed in the .csv file and lock the Mac in question using the
# the PIN code listed in the .csv file.
#
# A successful MDM lock should produce output similar to that shown below:
#
# Attempting to send MDM lock to Jamf Pro ID 2935 with PIN code 348202.
# <?xml version="1.0" encoding="UTF-8"?><computer_command><command><name>DeviceLock</name><command_uuid>98d915a4-6132-4535-b474-c8381e48425a</command_uuid><computer_id>2935</computer_id></command></computer_command>
# Successfully locked computer with Jamf Pro ID 2935 with PIN code 348202.
#
# Failures should look similar to this:
#
# Attempting to send MDM lock to Jamf Pro ID 1234567890 with PIN code 348201.
#
# ERROR! MDM lock of computer with Jamf Pro ID 1234567890 failed.
#
# Attempting to send MDM lock to Jamf Pro ID 29352935 with PIN code 12345.
#
# Invalid PIN code data provided: 12345
#
# Attempting to send MDM lock to Jamf Pro ID AA2319 with PIN code 348206.
#
# Invalid Jamf Pro ID data provided: AA2319
#
# This script will also generate a report in .tsv format with information similar to what's shown below:
#
#
# |Jamf Pro ID Number|Make |Model |Serial Number|UDID |Jamf Pro URL |MDM Lock Successful|
# |——————|—–|—————————|————-|————————————|———————————————————|——————-|
# |10734 |Apple|MacBook Pro (13-inch, 2018)|C02TW0WAHX874|C66B7C82-9CAB-4C89-85BE-7271121592A8|https://jamf.pro.server.here/computers.html?id=10734 |Yes |
# |858 |Apple|MacBook Pro (13-inch, 2018)|C027251024N23|159C6524-5069-41EC-9EDE-81158843F2EC|https://jamf.pro.server.here/computers.html?id=858 |No |
# |421 |Apple|MacBook Pro (13-inch, 2018)|Q027251024R23|A5C73F1F-35BD-4E27-BE63-E5760F886A1A|https://jamf.pro.server.here/computers.html?id=421 |Yes |
# |1217 |Apple|MacBook Pro (13-inch, 2018)|C02F0U5WAHX54|D59F50C3-3559-4B6A-AE04-81FF6BF25349|https://jamf.pro.server.here/computers.html?id=1217 |Yes |
#
# If setting up a specific user account with limited rights, here are the required API privileges
# for the account on the Jamf Pro server:
#
# Jamf Pro Server Objects:
#
# Computers: Create
#
# Jamf Pro Server Action:
#
# Send Computer Remote Lock Command
# If you choose to hardcode API information into the script, set one or more of the following values:
#
# The username for an account on the Jamf Pro server with sufficient API privileges
# The password for the account
# The Jamf Pro URL
# Set the Jamf Pro URL here if you want it hardcoded.
jamfpro_url=""
# Set the username here if you want it hardcoded.
jamfpro_user=""
# Set the password here if you want it hardcoded.
jamfpro_password=""
# If you do not want to hardcode API information into the script, you can also store
# these values in a ~/Library/Preferences/com.github.jamfpro-info.plist file.
#
# To create the file and set the values, run the following commands and substitute
# your own values where appropriate:
#
# To store the Jamf Pro URL in the plist file:
# defaults write com.github.jamfpro-info jamfpro_url https://jamf.pro.server.goes.here:port_number_goes_here
#
# To store the account username in the plist file:
# defaults write com.github.jamfpro-info jamfpro_user account_username_goes_here
#
# To store the account password in the plist file:
# defaults write com.github.jamfpro-info jamfpro_password account_password_goes_here
#
# If the com.github.jamfpro-info.plist file is available, the script will read in the
# relevant information from the plist file.
jamfpro_plist="$HOME/Library/Preferences/com.github.jamfpro-info.plist"
filename="$1"
exitCode=0
report_file="$(mktemp).tsv"
if [[ -r "$jamfpro_plist" ]]; then
if [[ -z "$jamfpro_url" ]]; then
jamfpro_url=$(defaults read "${jamfpro_plist%.*}" jamfpro_url)
fi
if [[ -z "$jamfpro_user" ]]; then
jamfpro_user=$(defaults read "${jamfpro_plist%.*}" jamfpro_user)
fi
if [[ -z "$jamfpro_password" ]]; then
jamfpro_password=$(defaults read "${jamfpro_plist%.*}" jamfpro_password)
fi
fi
# If the Jamf Pro URL, the account username or the account password aren't available
# otherwise, you will be prompted to enter the requested URL or account credentials.
if [[ -z "$jamfpro_url" ]]; then
read -p "Please enter your Jamf Pro server URL : " jamfpro_url
fi
if [[ -z "$jamfpro_user" ]]; then
read -p "Please enter your Jamf Pro user account : " jamfpro_user
fi
if [[ -z "$jamfpro_password" ]]; then
read -p "Please enter the password for the $jamfpro_user account: " -s jamfpro_password
fi
echo
# Remove the trailing slash from the Jamf Pro URL if needed.
jamfpro_url=${jamfpro_url%%/}
# Verify that the file exists and is readable
if [[ -r $filename ]]; then
# Set IFS to read the .csv file by setting commas as the character
# which separates fields in the .csv file
while IFS=, read jamf_pro_id pin_code || [ -n "$jamf_pro_id" ]; do
# Due to IFS redefining field separation, the $pin_code
# value has a carriage return included. The next check
# below trims that off before it can cause problems for both
# curl and the echo message immediately below.
pin_code=$(echo $pin_code | tr -d '\r')
echo "Attempting to send MDM lock to Jamf Pro ID $jamf_pro_id with PIN code $pin_code."
# All Jamf Pro IDs should be positive numbers and
# PIN codes should be all positive numbers that are
# exactly six digits, so we check for those conditions
# before proceeding.
if [[ "$jamf_pro_id" =~ ^[0-9]+$ ]]; then
if [[ "$pin_code" =~ ^[0-9]{6} ]]; then
ComputerRecord=$(curl -sfu "$jamfpro_user:$jamfpro_password" "${jamfpro_url}/JSSResource/computers/id/$jamf_pro_id" -H "Accept: application/xml" 2>/dev/null)
Make=$(echo "$ComputerRecord" | xmllint –xpath '//computer/hardware/make/text()'2>/dev/null)
MachineModel=$(echo "$ComputerRecord" | xmllint –xpath '//computer/hardware/model/text()'2>/dev/null)
SerialNumber=$(echo "$ComputerRecord" | xmllint –xpath '//computer/general/serial_number/text()'2>/dev/null)
UDIDIdentifier=$(echo "$ComputerRecord" | xmllint –xpath '//computer/general/udid/text()'2>/dev/null)
jamfproURL=$(echo "$jamfpro_url"/computers.html?id="$jamf_pro_id")
if [[ ! -f "$report_file" ]]; then
touch "$report_file"
printf "Jamf Pro ID Number\tMake\tModel\tSerial Number\tUDID\tJamf Pro URL\tMDM Lock Successful\n" > "$report_file"
fi
# If the previous checks succeeded, the curl command below
# sends the DeviceLock command, which will then be sent out
# by the Jamf Pro server. The curl command uses the "–fail"
# function to enable curl to send out an exit code, which we
# use to test if the API call was successful.
/usr/bin/curl –fail -su ${jamfpro_user}:${jamfpro_password} "$jamfpro_url/JSSResource/computercommands/command/DeviceLock/passcode/$pin_code/id/$jamf_pro_id" -H "Content-Type: application/xml" -X POST
# curl's exit status is checked below. If curl has an exit status of zero,
# the API call was sent and received successfully. If curl has a non-zero
# exit status, a warning message is displayed which indicates that the API call
# has failed.
if [[ $? -eq 0 ]]; then
echo -e "\nSuccessfully locked computer with Jamf Pro ID $jamf_pro_id with PIN code $pin_code."
if [[ $? -eq 0 ]]; then
printf "$jamf_pro_id\t$Make\t$MachineModel\t$SerialNumber\t$UDIDIdentifier\t${jamfproURL}\tYes\n" >> "$report_file"
else
echo "ERROR! Failed to read computer record with id $jamf_pro_id"
fi
else
echo -e "\nERROR! MDM lock of computer with Jamf Pro ID $jamf_pro_id failed."
printf "$jamf_pro_id\t$Make\t$MachineModel\t$SerialNumber\t$UDIDIdentifier\t${jamfproURL}\tNo\n" >> "$report_file"
fi
# If the PIN code is not all positive numbers
# and exactly six digits, a warning message is
# displayed that an invalid PIN code has been
# provided.
else
echo -e "\nInvalid PIN code provided: $pin_code"
fi
# If the Jamf Pro ID number is not all positive numbers,
# a warning message is displayed that an Jamf Pro ID number
# has been provided.
else
echo -e "\nInvalid Jamf Pro ID provided: $jamf_pro_id"
fi
echo ""
done < <(tail -n +2 "$filename")
else
# If the provided .csv is not readable, a warning message
# is displayed that the file does not exist or is not readable.
echo "Input file does not exist or is not readable"
exitCode=1
fi
if [[ -f "$report_file" ]]; then
echo "Report on Macs available here: $report_file"
fi
exit "$exitCode"

WWDC 2021 notes

$
0
0

This week, like last year, I’m attending Apple’s WWDC 2021 conference from the comforts of home. As part of this, I’m taking notes during the labs and session videos. Due to wanting to stay on the right side of Apple’s NDA, I’ve been posting my notes to Apple’s developer forums rather than to here.

To make it easier for Mac admins to access them, I’ve set up a post in the forums where I’ve linking the various forum posts with my notes. It’s available via the link below:

https://developer.apple.com/forums/thread/681818

Slides from the “Ride on the Release Train” session at MacDevOpsYVR 2021

Session videos from MacDevOps YVR 2021 now available

Jamf Pro deprecating the ability to issue a Tomcat certificate from the Jamf Pro built-in certificate authority

$
0
0

As part of the release of Jamf Pro 10.30, the following entry was added to the Deprecations section of the Jamf Pro Release Notes:

Functionality to issue the Tomcat SSL/TLS certificate from Jamf Pro’s built-in certificate authority — Jamf Pro’s functionality to issue the Tomcat SSL/TLS certificate from the JSS built-in certificate authority (CA) will be discontinued in a future release of Jamf Pro. The release version for this change has not been determined.

Before this change occurs, it is recommended that all on-premise Jamf Pro instances leveraging this functionality switch to a publicly trusted third-party CA to issue the Tomcat SSL/TLS certificate. This will prevent the potential loss of MDM communication from Jamf Pro to enrolled devices.

If needed, a Tomcat SSL/TLS server certificate for Jamf Pro may be issued from an internal certificate authority. The JSS built-in CA will maintain its current ability to manually issue server certificates to other servers.

Screen Shot 2021 06 15 at 3 08 31 PM

For shops which use Jamf Pro’s built-in certificate authority to create the SSL certificate used by the Tomcat web application, this means that at some point in the near(ish) future, you will need to plan to use a certificate for your Jamf Pro server which is no longer being issued by your Jamf Pro server’s built-in certificate authority.

Screen Shot 2021 06 15 at 3 11 52 PM

For more details, please see below the jump.

As part of the deprecation notes, Jamf recommends a switch to a publicly trusted certificate for Tomcat. One way to get those is to use the Let’s Encrypt certificate authority. This is a free service which will issue free publicly trusted certificates that are valid for 90 days before needing to be renewed.

Screen Shot 2021 06 15 at 3 31 06 PM

While Jamf Pro does not natively include functionality for using and renewing Let’s Encrypt-issued certificates, there is at least one script available on GitHub for using Let’s Encrypt certificates with a Jamf Pro server:

https://github.com/sean-rabbitt/letsEncryptJSS

Screen Shot 2021 06 15 at 3 35 19 PM

I’ve been using this script on a development Jamf Pro server myself for over a year and it works pretty well with the host OS (CentOS 7.x.) The script renews the certificate with Let’s Encrypt’s certificate authority on a scheduled basis and automatically updates the Java keystone with the new certificate for Tomcat to detect and use.

Tomcat needs to be started as part of the renewal process because the certificate in the Java keystore is being changed out for the new certificate, but the script handles that as well.

Screen Shot 2021 06 15 at 3 32 50 PM

I’ve also leveraged the same Let’s Encrypt-issued certificate to provide an Apache-hosted HTTPS local distribution point for this server. In this case, Apache has been configured with the filesystem path of the Let’s Encrypt  certificate files and is able to use them without additional importing into Java or other services.

Screen Shot 2021 06 15 at 3 36 50 PM

Backing up Self Service bookmarks for Jamf Pro 10.30.0 and later

$
0
0

A while ago, I wrote a post on how to back up your Jamf Pro Self Service bookmarks. I’ve been using that process to back up my bookmarks and it’s been working fine until after my upgrade to Jamf Pro 10.30.0. At that point, my script stopped working. When I checked into it and talked with some colleagues, it became apparent that Jamf had made a change with how they stored bookmark information for Self Service.

In 10.29.x and earlier, Jamf had stored bookmarks as individual plist files in the following location:

/Library/Application Support/JAMF/Self Service/Managed Plug-ins

Screen Shot 2020 09 27 at 11 31 16 AM

In 10.30.x and later, the /Library/Application Support/JAMF/Self Service/Managed Plug-ins directory has disappeared.

Screen Shot 2021 06 23 at 10 37 24 AM

Jamf now stores bookmark information inside an XML file named CocoaAppCD.storedata in the user’s home folder at the following location:

~/Library/Application Support/com.jamfsoftware.selfservice.mac/CocoaAppCD.storedata

Screen Shot 2021 06 23 at 10 35 51 AM

Inside the CocoaAppCD.storedata file, the bookmarks are stored as XML objects similar to what is shown below:

<object type="SSBOOKMARK" id="z169">
<attribute name="url" type="string">https://www.bananas.com</attribute>
<attribute name="priority" type="int64">5</attribute>
<attribute name="displayinbrowser" type="bool">1</attribute>
<attribute name="name" type="string">Bananas.com</attribute>
<attribute name="jssdescription" type="string">Bananas.com</attribute>
<attribute name="installstatus" type="int64">0</attribute>
<attribute name="id" type="int64">2</attribute>
<attribute name="iconurl" type="string">https://ics.services.jamfcloud.com/icon/hash_95740013589cddd19b2192016788dd9e91e735f8ff5213f92005f4eb92ac16b6</attribute>
<attribute name="compliance" type="bool">0</attribute>
<attribute name="buttontext" type="string">Open</attribute>
</object>
view raw
Bananas.com.xml
hosted with ❤ by GitHub

Screen Shot 2021 06 23 at 4 22 03 PM

Fortunately, I was able to figure out a way to do the following:

  1. Parse the document for the bookmark XML objects.
  2. Split them out into individual XML files.
  3. Name the files using the title of the Self Service bookmark.

For more details, please see below the jump.

To make backups of the Self Service bookmarks, I’ve written a script which performs the following tasks:

  1. If necessary, create a directory for storing backup copies of the Self Service bookmark files.
  2. Make copies of the Self Service bookmark files.
  3. Name the copied files using the title of the Self Service bookmark.
  4. Store the copied bookmarks in the specified directory.

Once the script is run, you should see copies of the Self Service bookmark files appearing in the script-specified location. This location can be manually set or created automatically by the script.

Screen Shot 2021 06 23 at 11 11 08 AM

Screen Shot 2021 06 23 at 11 33 09 AM

When examined, the files should look similar to this:

<?xml version="1.0" encoding="UTF-8"?>
<object type="SSBOOKMARK" id="z169">
<attribute name="url" type="string">https://www.bananas.com</attribute>
<attribute name="priority" type="int64">5</attribute>
<attribute name="displayinbrowser" type="bool">1</attribute>
<attribute name="name" type="string">Bananas.com</attribute>
<attribute name="jssdescription" type="string">Bananas.com</attribute>
<attribute name="installstatus" type="int64">0</attribute>
<attribute name="id" type="int64">2</attribute>
<attribute name="iconurl" type="string">https://ics.services.jamfcloud.com/icon/hash_95740013589cddd19b2192016788dd9e91e735f8ff5213f92005f4eb92ac16b6</attribute>
<attribute name="compliance" type="bool">0</attribute>
<attribute name="buttontext" type="string">Open</attribute>
</object>
view raw
Bananas.com.xml
hosted with ❤ by GitHub

The script is available below, and at the following address on GitHub:

https://github.com/rtrouton/rtrouton_scripts/tree/master/rtrouton_scripts/Casper_Scripts/Jamf_Pro_Self_Service_Bookmark_Backup

Jamf_Pro_Self_Service_Bookmark_Backup.sh:

#!/bin/bash
# This script is designed to do the following:
#
# 1. If necessary, create a directory for storing backup copies of Jamf Pro Self Service bookmark files.
# 2. Make copies of the Self Service bookmark files.
# 3. Name the copied files using the title of the Self Service bookmark.
# 4. Store the copied bookmarks in the specified directory.
#
# If you choose to specify a directory to save the Self Service bookmarks into,
# please enter the complete directory path into the SelfServiceBookmarkBackupDirectory
# variable below.
SelfServiceBookmarkBackupDirectory=""
# If the SelfServiceBookmarkBackupDirectory isn't specified above, a directory will be
# created and the complete directory path displayed by the script.
error=0
if [[ -z "$SelfServiceBookmarkBackupDirectory" ]]; then
SelfServiceBookmarkBackupDirectory=$(mktemp -d)
echo "A location to store downloaded groups has not been specified."
echo "Downloaded groups will be stored in $SelfServiceBookmarkBackupDirectory."
fi
self_service_bookmark_file="$HOME/Library/Application Support/com.jamfsoftware.selfservice.mac/CocoaAppCD.storedata"
if [[ -f "$self_service_bookmark_file" ]]; then
tmp_dir="/private/tmp/bookmark-workdir-$(date +%y%m%d%H%M%S)"
mkdir -p "$tmp_dir"
# For the next command, add a trailing slash for
# the the tmp_dir variable if it's not there.
length=${#tmp_dir}
last_char=${tmp_dir:length-1:1}
[[ $last_char != "/" ]] && tmp_dir="$tmp_dir/";
sed -n '/SSBOOKMARK/,/object/p' "$self_service_bookmark_file" | awk -v a=$tmp_dir '/SSBOOKMARK/{filename=a""++i".xml"}; {print >filename}'
#remove trailing slash if needed from the bookmark and tmp directories
SelfServiceBookmarkBackupDirectory=${SelfServiceBookmarkBackupDirectory%%/}
tmp_dir=${tmp_dir%%/}
for file in "$tmp_dir"/*
do
# Add XML declaration to first line if not already present in the file.
# This will allow xmllint to format the XML in human-readable format.
if [[ -z $(cat $file | grep "<?xml version="1.0" encoding="UTF-8"?>") ]]; then
echo -e "<?xml version="\""1.0"\"" encoding="\""UTF-8"\""?>\n$(cat $file)" > $file
fi
bookmark_name=$(cat $file | awk -F '[<>]' '/"name"/{print $3}')
xmllint –format "$file" > "$file"_formatted.xml
mv "$file"_formatted.xml "$SelfServiceBookmarkBackupDirectory/$bookmark_name".xml
if [[ $? -eq 0 ]]; then
echo "$bookmark_name.xml processed and stored in $SelfServiceBookmarkBackupDirectory."
else
echo "ERROR! Problem occurred when processing $self_service_bookmark_file file!"
error=1
fi
done
rm -rf "$tmp_dir"
fi
exit $error

AutoPkg recipes for OS X Lion and OS X Mountain Lion OS installers now available

$
0
0

Now that Apple has made direct download links available for Lion and Mountain Lion, I’ve written AutoPkg .download and .pkg recipes for the following OS X installers:

These recipes will download the disk images linked to the relevant KBase articles, extract the installer packages stored inside the disk images and rename the disk images and installer packages with the OS name and version number.

One thing to be aware of is that the downloaded installers do not themselves install the relevant version of OS X. Instead, they install the Install.app for that version of OS X into the /Applications directory.

Screen Shot 2021 06 30 at 5 36 49 PM

Another thing to know is that the downloaded installers are signed using Software Update signing certificates which expired in 2019. As of June 30th, 2021, I do not know if Apple is planning to re-sign the installers with the current Software Update signing certificate.

Screen Shot 2021 06 30 at 4 26 25 PM

One of the consequences of this is that I cannot use AutoPkg’s code signature verification as part of the AutoPkg recipes, since AutoPkg’s current code signature verification will error when it hit the expired certificates. If Apple does choose to re-sign these certificate with valid non-expired signing certificates, I’ll add code signature verification to the recipes.

If you do need to use these installers, setting the system clock on your Mac to a date and time before the October 24th 2019 expiration date will allow these certificates to appear as valid again and any expiration-related issues should go away.

The AutoPkg recipes are available via the links below:

OS X Lion: https://github.com/autopkg/rtrouton-recipes/tree/master/OSXLion
OS X Mountain Lion: https://github.com/autopkg/rtrouton-recipes/tree/master/OSXMountainLion

Slides from the “SAP In The Haus” session at Penn State MacAdmins 2021


Monitoring Startup Security settings on Apple Silicon Macs

$
0
0

To help maintain the security of the Apple Silicon Macs in your environment, it’s helpful to be able to monitor what the Startup Security settings are for those Macs.

Screen Shot 2021 07 23 at 10 08 32 AM

For this task, the reporting functions of the bputil tool are available. Normally, Apple wants you to avoid the bputil tool like you would a swarm of bees. As part of that, the following warning is displayed by bputil:

username@computername ~ % bputil -d
This utility is not meant for normal users or even sysadmins.
It provides unabstracted access to capabilities which are normally handled for the user automatically when changing the security policy through GUIs such as the Startup Security Utility in macOS Recovery.
It is possible to make your system security much weaker and therefore easier to compromise using this tool.
This tool is not to be used in production environments.
It is possible to render your system unbootable with this tool.
It should only be used to understand how the security of Apple Silicon Macs works.
Use at your own risk!
The tool requires running as root
username@computername ~ %
view raw
gistfile1.txt
hosted with ❤ by GitHub

However, the bputil -d command is safe to use as it displays the contents of the current security policy’s settings. When the default Full Security security mode is enabled, running the bputil -d command with root privileges should display content similar to what’s shown below:

username@computername ~ % sudo bputil -d
Password:
This utility is not meant for normal users or even sysadmins.
It provides unabstracted access to capabilities which are normally handled for the user automatically when changing the security policy through GUIs such as the Startup Security Utility in macOS Recovery.
It is possible to make your system security much weaker and therefore easier to compromise using this tool.
This tool is not to be used in production environments.
It is possible to render your system unbootable with this tool.
It should only be used to understand how the security of Apple Silicon Macs works.
Use at your own risk!
Current OS environment:
OS Type : macOS
Local Policy Nonce Hash (lpnh): 7E1ED4512B6DF2A284C6343E469C1F1459453E4898E770CF37A8F3B1D9C000E0DA0C5C5F0546AB70984BEC3A9870DD9E
Remote Policy Nonce Hash (rpnh): 88EB8429C516B53BBCA49EC7C0D58C3F27F2890D23E176264B2178EE2A865327CFD06ED94834EE6FF7D145FB39245B59
Recovery OS Policy Nonce Hash (ronh): 6CF5EB6318AF551C5A23B8D3B2E4196AAA372B523E4F412C375CF6B39DCFED28F9B4E9881BF348886F9B9A14E918AA69
Current local policy:
Signature Type : BAA
Unique Chip ID (ECID): 0xD793810C0291E
Board ID (BORD): 0x26
Chip ID (CHIP): 0x8103
Certificate Epoch (CEPO): 0x1
Security Domain (SDOM): 0x1
Production Status (CPRO): 1
Security Mode (CSEC): 1
OS Version (love): 21.1.268.5.8,0
Volume Group UUID (vuid): 2D85CA09-A291-47CA-A68A-66CB2D3BDF70
KEK Group UUID (kuid): AC09E9D5-36DC-10C9-4312-E6DAA3753224
Local Policy Nonce Hash (lpnh): 7E1ED4512B6DF2A284C6343E469C1F1459453E4898E770CF37A8F3B1D9C000E0DA0C5C5F0546AB70984BEC3A9870DD9E
Remote Policy Nonce Hash (rpnh): 88EB8429C516B53BBCA49EC7C0D58C3F27F2890D23E176264B2178EE2A865327CFD06ED94834EE6FF7D145FB39245B59
Next Stage Image4 Hash (nsih): 443560FD2BE056BC9527452729EEC1A1BB22BA2DA456B278624DEF822DE9F7A64F0303B64ED811405B4039475F8A623D
User Authorized Kext List Hash (auxp): absent
Auxiliary Kernel Cache Image4 Hash (auxi): absent
Kext Receipt Hash (auxr): absent
CustomKC or fuOS Image4 Hash (coih): absent
Security Mode: Full (smb0): absent
User-allowed MDM Control: Disabled (smb3): absent
DEP-allowed MDM Control: Disabled (smb4): absent
SIP Status: Enabled (sip0): absent
Signed System Volume Status: Enabled (sip1): absent
Kernel CTRR Status: Enabled (sip2): absent
Boot Args Filtering Status: Enabled (sip3): absent
3rd Party Kexts Status: Disabled (smb2): absent
username@computername ~ %
view raw
gistfile1.txt
hosted with ❤ by GitHub

Here’s what bputil -d will return if the Startup Security settings are configured as follows:

  • Reduced Security: Enabled
  • Allow user management or kernel extensions from identified developers: Enabled
  • Allow remote management of kernel extensions from identified developers: Enabled

Screen Shot 2021 07 23 at 10 13 39 AM

username@computername ~ % sudo bputil -d
Password:
This utility is not meant for normal users or even sysadmins.
It provides unabstracted access to capabilities which are normally handled for the user automatically when changing the security policy through GUIs such as the Startup Security Utility in macOS Recovery.
It is possible to make your system security much weaker and therefore easier to compromise using this tool.
This tool is not to be used in production environments.
It is possible to render your system unbootable with this tool.
It should only be used to understand how the security of Apple Silicon Macs works.
Use at your own risk!
Current OS environment:
OS Type : macOS
Local Policy Nonce Hash (lpnh): 987619CF88732BB0FB0CCC476302DFE84EB1C1F7B92E8CBEC4B124D9F76B3DBACD8787E5DEBB8A3F70576639CE74F727
Remote Policy Nonce Hash (rpnh): 88EB8429C516B53BBCA49EC7C0D58C3F27F2890D23E176264B2178EE2A865327CFD06ED94834EE6FF7D145FB39245B59
Recovery OS Policy Nonce Hash (ronh): 6CF5EB6318AF551C5A23B8D3B2E4196AAA372B523E4F412C375CF6B39DCFED28F9B4E9881BF348886F9B9A14E918AA69
Current local policy:
Signature Type : BAA
Unique Chip ID (ECID): 0xD793810C0291E
Board ID (BORD): 0x26
Chip ID (CHIP): 0x8103
Certificate Epoch (CEPO): 0x1
Security Domain (SDOM): 0x1
Production Status (CPRO): 1
Security Mode (CSEC): 1
OS Version (love): 21.1.284.5.5,0
Volume Group UUID (vuid): 2D85CA09-A291-47CA-A68A-66CB2D3BDF70
KEK Group UUID (kuid): AC09E9D5-36DC-10C9-4312-E6DAA3753224
Local Policy Nonce Hash (lpnh): 987619CF88732BB0FB0CCC476302DFE84EB1C1F7B92E8CBEC4B124D9F76B3DBACD8787E5DEBB8A3F70576639CE74F727
Remote Policy Nonce Hash (rpnh): 88EB8429C516B53BBCA49EC7C0D58C3F27F2890D23E176264B2178EE2A865327CFD06ED94834EE6FF7D145FB39245B59
Next Stage Image4 Hash (nsih): 1FAC4F6723D591DD6FAEC1DDB7D84C0AB28782096F8F2570EDA1F3CC41DECBE883A59BC4C3C962484E283F4E11549CB6
User Authorized Kext List Hash (auxp): absent
Auxiliary Kernel Cache Image4 Hash (auxi): absent
Kext Receipt Hash (auxr): absent
CustomKC or fuOS Image4 Hash (coih): absent
Security Mode: Reduced (smb0): 1
User-allowed MDM Control: Enabled (smb3): 1
DEP-allowed MDM Control: Disabled (smb4): absent
SIP Status: Enabled (sip0): absent
Signed System Volume Status: Enabled (sip1): absent
Kernel CTRR Status: Enabled (sip2): absent
Boot Args Filtering Status: Enabled (sip3): absent
3rd Party Kexts Status: Enabled (smb2): 1
username@computername ~ %
view raw
gistfile1.txt
hosted with ❤ by GitHub

Note: This reporting function does not require macOS Recovery and works while booted from regular macOS.

To check the Startup Security settings, the following status codes should be checked:

  • smb0
  • smb2
  • smb3

Screen Shot 2021-07-23 at 10.58.13 AM

In the Startup Security Utility app in macOS Recovery, the following settings correspond to the status codes listed above:

  • smb0: Full Security / Reduced Security
  • smb2: Allow user management of kernel extensions from identified developers
  • smb3: Allow remote management of kernel extensions from identified developers

For more details, please see below the jump.

If you want to check to see if an Apple Silicon Mac is set for Full Security or Reduced Security, run the command shown below with root privileges:

bputil -d | awk '/smb0/ {print $5}'
view raw
gistfile1.txt
hosted with ❤ by GitHub

If Full Security is set, you should see the following result:

absent

Screen Shot 2021 07 23 at 11 11 39 AM

If Reduced Security is set, you should see the following result:

1

Screen Shot 2021 07 23 at 10 33 43 AM

If you want to check to see if an Apple Silicon Mac is set for Allow user management or kernel extensions from identified developers, run the command shown below with root privileges:

bputil -d | awk '/smb2/ {print $7}'
view raw
gistfile1.txt
hosted with ❤ by GitHub

If Allow user management or kernel extensions from identified developers is not set, you should see the following result:

absent

Screen Shot 2021 07 23 at 11 11 10 AM

If Allow user management or kernel extensions from identified developers is set, you should see the following result:

1

Screen Shot 2021 07 23 at 10 36 30 AM

Note: If this setting is returning a value of 1, this means that Reduced Security is enabled, so the smb0 status code will also return 1.

Screen Shot 2021 07 23 at 10 33 43 AM

If you want to check to see if an Apple Silicon Mac is set for Allow remote management of kernel extensions from identified developers, run the command shown below with root privileges:

bputil -d | awk '/smb3/ {print $6}'
view raw
gistfile1.txt
hosted with ❤ by GitHub

If Allow remote management of kernel extensions from identified developers is not set, you should see the following result:

absent

Screen Shot 2021 07 23 at 11 10 36 AM

If Allow remote management of kernel extensions from identified developers is set, you should see the following result:

1

Screen Shot 2021 07 23 at 10 43 26 AM

Note: If this setting is returning a value of 1, this means that Reduced Security is enabled, so the smb0 status code will also return 1.

Screen Shot 2021 07 23 at 10 33 43 AM

Packaging a SAP GUI installer application for macOS

$
0
0

One of the recent changes for the macOS version of SAP GUI for Java is that both SapMachine Java 11 and OpenJFX 11 are now bundled with SAP GUI, so it is no longer required to have Java installed on your machine in order for SAP GUI to work. This change has also been extended to the SAP GUI installer, which is now available as a notarized installer application as of SAP GUI 7.70.

You can run this installer on a Mac which does not have Java already installed and it will install SAP GUI for Java with SapMachine Java 11 and OpenJFX 11 installations embedded inside the SAP GUI application.

Note: As of SAP GUI 7.70 rev 2, Rosetta 2 is required if installing on an Apple Silicon Mac so Rosetta needs to be installed and running before installing SAP GUI.

The installer application is available for download to customers via a link on the announcement blog post:

https://blogs.sap.com/2021/03/16/ann-sap-gui-for-java-7.70-available-for-download/

When you click the download link, you will see two choices:

  • DMG
  • JAR

Screen Shot 2021 07 26 at 9 52 31 AM

The DMG download will provide the notarized installer application and the JAR download will provide the Java .jar installer that SAP GUI has traditionally used on macOS. I’ve discussed how to package the .jar installer in previous posts, so this post is going to focus on the new installer application contained inside the DMG download.

Screen Shot 2021 07 26 at 9 52 32 AM

For more details, please see below the jump.

If you want to run the SAP GUI installer application without repackaging it as a macOS installer package, use the procedure below:

1. Download the disk image.

Screen Shot 2021 07 26 at 2 00 35 PM

2. Mount the disk image.

Screen Shot 2021 07 22 at 2 16 27 PM

3. Copy the SAP GUI for Java Installer application to a convenient location.

Screen Shot 2021 07 26 at 2 28 16 PM

If you have a templates.jar file, copy the templates.jar file to the same location. As long as both files are in the same directory, the SAP GUI for Java Installer application will detect and use the templates.jar file’s contents to help configure SAP GUI.

Screen Shot 2021 07 26 at 2 02 26 PM

4. Launch the SAP GUI for Java Installer application.

Screen Shot 2021 07 22 at 2 16 55 PM

5. Follow the prompts to install.

Screen Shot 2021 07 22 at 2 17 20 PM

Screen Shot 2021 07 22 at 2 17 32 PM

Screen Shot 2021 07 22 at 2 17 56 PM

To build an installer package for SAP GUI which uses the installer application, use the procedure shown below:

Building the SAP GUI installer

Pre-requisites:

  • Packages
  • SAP GUI for Java Installer application
  • templates.jar file (optional)

1. Set up a new Packages project and select Raw Package.

Screen Shot 2021 07 26 at 10 34 15 AM

2. In this case, I’m naming the project SAP GUI 7.70 rev2.

Screen Shot 2021 07 26 at 10 34 25 AM

3. Once the Packages project opens, click on the Project tab. You’ll want to make sure that the your information is correctly set here (if you don’t know what to put in, check the Help menu for the Packages User Guide. The information you need is in Chapter 4 – Configuring a project.)

Screen Shot 2021 07 26 at 10 35 18 AM

In this example, I’m not changing any of the options from what is set by default.

4. Next, click on the Settings tab. In the case of my project, I want to install with root privileges and not require a logout, restart or shutdown.

To accomplish this, I’m choosing the following options in the Settings section:

In the Tag section:

  • Identifier: set as appropriate (for my installer, I’m using com.sap.pkg.SAPGUI770rev2
  • Version: set as appropriate (for my installer, I’m usings 7.70.02 )

In the Post-installation Behavior section:

  • On Success: should be set to Do Nothing

In the Options section:

  • Require admin password for installation should be checked
  • Relocatable should be unchecked
  • Overwrite directory permissions should be unchecked
  • Follow symbolic links should be unchecked

Screen Shot 2021 07 26 at 10 35 58 AM

7. Select the Payload tab. Nothing here should be changed from the defaults.

Screen Shot 2021 07 26 at 10 36 06 AM

8. Select the Scripts tab.

Under the Additional Resources section, add the following files:

  • The latest SAP GUI for Java installer (this is the SAP GUI for Java Installer application file)

Screen Shot 2021 07 26 at 10 51 17 AM

Screen Shot 2021 07 26 at 10 51 26 AM

  • If you have a templates.jar file, also add that file.

Screen Shot 2021 07 26 at 10 51 46 AM

Screen Shot 2021 07 26 at 2 15 31 PM

The last part is telling the SAP GUI for Java installer to run. For this, you’ll need a postinstall script.

Here’s the postinstall script being used for this installer package:

#!/bin/bash
install_dir=$(/usr/bin/dirname $0)
sap_gui_installer="$install_dir/SAP GUI for Java Installer.app"
sap_gui_install_path="/Applications/SAP Clients"
ERROR=0
if [[ -x "$sap_gui_installer" ]]; then
echo "Attempting to install $sap_gui_install"
"$sap_gui_installer/Contents/MacOS/install" -G –installdir "${sap_gui_install_path}" -J "${install_dir}" –force
if [[ $? -ne 0 ]]; then
echo "ERROR! Installation of $sap_gui_installer failed"
ERROR=1
else
echo "Successfully installed $sap_gui_installer"
fi
else
echo "$sap_gui_installer not found or not executable."
ERROR=1
fi
exit $ERROR
view raw
gistfile1.txt
hosted with ❤ by GitHub

If not already selected, select the postinstall script and add it to the project.

Screen Shot 2021 07 26 at 10 52 18 AM

Screen Shot 2021 07 26 at 10 52 31 AM

9. Build the package. (If you don’t know to build, check the Help menu for the Packages User Guide. The information you need is in Chapter 3 – Creating a raw package project and Chapter 10 – Building a project.)

Screen Shot 2021 07 26 at 10 38 13 AM

Screen Shot 2021 07 26 at 10 38 20 AM

Testing the installer

Once the package has been built, test it by installing it on a test machine which has the following:

  • Does not have the SAP GUI client installed

The end result should be that the SAP GUI client installs into /Applications.

Screen Shot 2021 07 26 at 1 48 42 PM

If a templates.jar file was included with the installer, the SAP GUI configuration files specified by the templates.jar file should also be installed.

Screen Shot 2021 07 26 at 1 47 38 PM

Videos from Penn State MacAdmins Campfire Sessions 2021

Signing AutoPkg-built packages using a .sign recipe

$
0
0

For those that need to sign their AutoPkg-generated installer packages with a signing certificate, the PkgSigner processor is available to assist with this. When I originally started using this processor, I was building the signing part directly into .pkg recipes, but my teammate @jaharmi came up with a better and more modular idea: the .sign recipe.

Screen Shot 2021 07 30 at 2 09 06 PM

The .sign recipe uses the PkgSigner processor and is designed to be placed in the AutoPkg workflow between a .pkg recipe and a.jss recipe for JSSImporter, a .munki recipe for Munki or other recipes used to upload an installer package to a deployment tool. In this case, the .pkg recipe would be a parent recipe for the .sign recipe. In turn, the .sign recipe would be used as the parent recipe for whatever came next in the workflow.

Screen Shot 2021 07 30 at 2 07 10 PM

For those who want to use .sign recipes, there is an example recipe available via the link below:

https://github.com/autopkg/rtrouton-recipes/blob/master/SharedProcessors/Example.sign.recipe

If you want to use the PkgSigner processor hosted from my AutoPkg recipe repo, first verify that AutoPkg is installed on the Mac you’re using. Once verified, run the following command:

autopkg repo-add rtrouton-recipes

Downloading and installing macOS Big Sur via macOS Recovery’s Terminal

$
0
0

Every so often, you may find yourself in a situation where you need to reinstall macOS Big Sur and everything is failing on you. Installing from macOS Recovery? Not working via the usual methods. Building a USB installer? Left the flash drive in your other pants. Using DFU mode and Apple Configurator on an Apple Silicon Mac? You need a second Mac to use this process and you just have the one Mac available.

For those situations, there’s one more option when you’ve exhausted all of the others. For more details, please see below the jump.

This method is referenced in the following Apple KBase article:

https://support.apple.com/HT211983

It involves the following:

  • Wiping the drive that you intend to install macOS Big Sur onto.
  • Creating the proper directory structure manually on the drive.
  • Copying the Install macOS app available in macOS Recovery manually into the proper location on the drive 
  • Using the curl tool to download the needed installer files onto the drive
  • Launching the Install macOS app
  • Using the Install macOS app to install macOS Big Sur

To install macOS Big Sur using the methods described above, use the procedure below:

1. Boot to macOS Recovery.

Screen Shot 2021 08 04 at 12 03 17 PM

2. Erase your Mac’s startup drive using the correct procedure for your Mac model:

Macs with Intel processors: https://support.apple.com/HT208496
Apple Silicon Macs: https://support.apple.com/kb/HT212030

By default, an erased drive is named Untitled. We’ll be using that drive name for the examples shown in this post.

2. Once the drive is erased, open Safari and go to the following URL:

https://support.apple.com/HT211983

Screen Shot 2021 08 04 at 12 03 18 PM

Screen Shot 2021 08 04 at 12 04 29 PM

 

3. Scroll to the bottom of the KBase article and locate the Or use Terminal to reinstall section.

Screen Shot 2021 08 04 at 12 05 46 PM

 

4. Copy the complete command which begins with curl. (This will save a lot of typing later.)

Screen Shot 2021 08 04 at 12 05 47 PM

 

5. Quit Safari.

6. Open Terminal.

Screen Shot 2021 08 04 at 12 13 45 PM

Screen Shot 2021 08 04 at 12 14 04 PM

 

7. Run the following command to change to using the drive named Untitled:

cd "/Volumes/Untitled"

Screen Shot 2021 08 04 at 10 29 27 AM

 

8. Run the following command to create a directory named private on the Untitled drive as well as a sub-directory inside of private which is named tmp:

mkdir -p private/tmp

Screen Shot 2021 08 04 at 10 30 11 AM

 

9. Run the following command to copy the Install macOS Big Sur.app application from macOS Recovery to the /Volumes/Untitled/private/tmp directory.

cp -R "/Install macOS Big Sur.app" private/tmp

Screen Shot 2021 08 04 at 10 31 03 AM

 

10. Run the following command to change to the /Volumes/Untitled/private/tmp/Install macOS Big Sur.app directory:

cd "private/tmp/Install macOS Big Sur.app"

Screen Shot 2021 08 04 at 10 32 00 AM

 

11. Run the following command to create a directory named Contents on the Untitled drive as well as a sub-directory inside of Contents which is named SharedSupport:

mkdir Contents/SharedSupport

Screen Shot 2021 08 04 at 10 33 44 AM

 

12. Paste the copied curl command and hit the enter key on your keyboard to have the macOS Big Sur installer files be downloaded into a file named SharedSupport.dmg. The SharedSupport.dmg will be located in /Volumes/Untitled/private/tmp/Install macOS Big Sur.app directory/Contents/SharedSupport.

curl -L -o Contents/SharedSupport/SharedSupport.dmg https://swcdn.apple.com/content/downloads/01/60/071-72781-A_CZ1D1FENMH/a09fvud3xxgih7qyau9a7lhtspho36mp0l/InstallAssistant.pkg

Screen Shot 2021 08 04 at 10 47 06 AM

Screen Shot 2021 08 04 at 10 47 34 AM

13. Once curl has finished downloading /Volumes/Untitled/private/tmp/Install macOS Big Sur.app directory/Contents/SharedSupport/SharedSupport.dmg, run the following command to launch the macOS Big Sur installer.

./Contents/MacOS/InstallAssistant_springboard

Screen Shot 2021 08 04 at 10 51 29 AM

Screen Shot 2021 08 04 at 10 53 05 AM

Screen Shot 2021 08 04 at 10 55 20 AM

14. Follow the prompts to install macOS Big Sur.

Screen Shot 2021 08 04 at 11 04 32 AM

Screen Shot 2021 08 04 at 11 04 38 AM

Screen Shot 2021 08 04 at 11 04 46 AM

Codesigning, untrusted certificate authorities and why certain apps aren’t launching

$
0
0

A number of folks noticed that certain older applications they use on macOS stopped working as of August 24th, 2021. As of this date, this appears to affect the following applications among others:

Note: This list is not complete, it’s just the ones I’m aware of as of August 24, 2021.

Why this is happening goes back to an episode in 2018, where Symantec had to get out of the PKI certificate issuing business because of a number of issues discovered with how Symantec had been issuing certificates.

As part of these issues, Apple issued an advisory that a number of Symantec Certificate Authority (CA) root certificates were to be distrusted by Apple on a timeline which concluded with the full distrust of Symantec CAs on February 25, 2020.

While this primarily affected website operators, Symantec also issued certificates from the affected Symantec CAs which were used to provide code signing for applications. An example of this is RSA SecurID Software Token 4.2.1.


Update 8-26-2021: RSA has released RSA SecurID Software Token 4.2.2 to resolve the issue with RSA SecurID Software Token 4.2.1. For more details, please see the link below:

https://community.rsa.com/t5/securid-access-product/updated-securid-announces-securid-software-token-4-2-2-for-macos/ta-p/640000?emcs_t=S2h8ZW1haWx8Ym9hcmRfc3Vic2NyaXB0aW9ufEtTUTg5SktCWUQxS1JHfDY0MDAwMHxTVUJTQ1JJUFRJT05TfGhL


In the case of SecureID, this app relies on Qt Core for user interface support and ships copies of the QT Core framework along with the SecureID app. SecurID stores this in the following location:

/Library/Frameworks/stauto32.framework

If you take a look at the installer, you can see where the files are supposed to go.

Screen Shot 2021 08 24 at 6 25 25 PM

However, the actual file which is causing the issue is buried further down in the following location:

/Library/Frameworks/stauto32.framework/Versions/4/QtCore.cire

Screen Shot 2021 08 24 at 6 27 36 PM

This file is important because the QT Core framework is shipped without Apple’s code signing, which is to say that QT is not using an Apple Developer ID signing certificate to sign QT Core. Instead, QT ships a code signing certificate chain and that information is stored in the QtCore.cire file.

One of the certificates in the code signing certificate chain is using VeriSign Class 3 Public Primary Certification Authority – G5 as its root certificate authority (root CA). That root CA is one of the Symantec CAs which is no longer trusted by Apple.

Screen Shot 2021 08 24 at 6 03 58 PM

To summarize: the SecureID app has a component which is signed by a not-trusted certificate. This is causing SecureID to not trust that component, which then prevents the app from launching correctly.

Image

Why is this happening now?

Apple released updates on August 23, 2021 for both XProtect (now version 2150) and Malware Removal Tool (now version 1.82). My assumption is that XProtect’s update included instructions to no longer accept code signing from the distrusted Symantec CAs. XProtect checks executable code on launch, so it would be working with Gatekeeper to detect and block the no-longer-trusted code signing.

What should you do?

See if your vendor has released an updated version of the app which is having problems. If they haven’t yet, I recommend contacting them to make sure they’re aware of the problem.

Hat tip to all the folks working on this issue in the MacAdmins Slack for helping diagnose the issue and why it is happening.

Using the Jamf Pro API to report on which Macs are assigned to a particular person

$
0
0

Every so often, it may be necessary to generate a report from Jamf Pro on which computers are assigned to a particular person. To assist with this task, I’ve written a script which uses the Jamf Pro Classic API to search through the computer inventory records and generate a report in .tsv format.

For more details, please see below the jump.

Pre-requisites:

If setting up a specific Jamf Pro user account for this purpose with limited rights, here are the required API privileges for the account on the Jamf Pro server:

Jamf Pro Server Objects

  • Computers: Read

Computer inventory records

  • In Jamf Pro, the username field must be populated in the User and Location section of the computer inventory record.

Screen Shot 2021 08 26 at 3 43 23 PM

 

For authentication, the script can accept manual input or values stored in a ~/Library/Preferences/com.github.jamfpro-info.plist file.

The plist file can be created by running the following commands and substituting your own values where appropriate:

To store the Jamf Pro URL in the plist file:

defaults write com.github.jamfpro-info jamfpro_url https://jamf.pro.server.goes.here:port_number_goes_here

To store the account username in the plist file:

defaults write com.github.jamfpro-info jamfpro_user account_username_goes_here

To store the account password in the plist file:

defaults write com.github.jamfpro-info jamfpro_password account_password_goes_here

This script imports a list of usernames from a plaintext file and uses that information to generate a report about the computers assigned to that username.

Usage:

./Generate_Assigned_Mac_Report_From_Jamf_Pro_Usernames.sh usernames.txt

Screen Shot 2021 08 26 at 3 34 47 PM

Plaintext file format should look like this:

username
otheruser
view raw
usernames.txt
hosted with ❤ by GitHub

The script can also accept one username as input, if a plaintext file containing usernames
is not available.

Usage:

./Generate_Assigned_Mac_Report_From_Jamf_Pro_Usernames.sh

Screen Shot 2021 08 26 at 3 34 00 PM

 

Once the username(s) are read from in from the plaintext file or from manual input, the script takes the following actions:

1. Uses the Jamf Pro API to download all information about the matching computer inventory record in XML format.
2. Pulls the following information out of the inventory entry:

  • Jamf Pro ID
  • Assigned user’s username
  • Assigned user’s email
  • Manufacturer
  • Model
  • Serial Number
  • Hardware UDID

3. Create a report in tab-separated value (.tsv) format which contains the following information about the deleted Macs

  • Jamf Pro ID
  • Assigned user’s username
  • Assigned user’s email
  • Manufacturer
  • Model
  • Serial Number
  • Hardware UDID
  • Jamf Pro URL for the computer inventory record

This script will generate a report in .tsv format with information similar to what’s shown below:

One user:


Jamf Pro ID Number Assigned User Assigned User Email Make Model Serial Number UDID Jamf Pro URL
13 username username@pretendco.com Apple Mac mini (Mid 2011) C07GM01TDJD0 00BC7701-6791-573D-B461-470B44D16DF6 https://jamfpro.pretendco.com:8443/computers.html?id=13
86 username username@pretendco.com Apple iMac Pro Intel (Retina 5k, 27-inch, Late 2017) VM0N0WRc4EjC 564D33BC-AF4C-86CF-1DFB-AF6EDFC395A3 https://jamfpro.pretendco.com:8443/computers.html?id=86
87 username username@pretendco.com Apple iMac Pro Intel (Retina 5k, 27-inch, Late 2017) VMWmmR2FJqk3 564D4A6F-280F-1EC0-5E66-178DB2D45A8A https://jamfpro.pretendco.com:8443/computers.html?id=87
view raw
tmp.d5KLaAhc.tsv
hosted with ❤ by GitHub

Multiple users:


Jamf Pro ID Number Assigned User Assigned User Email Make Model Serial Number UDID Jamf Pro URL
13 username username@pretendco.com Apple Mac mini (Mid 2011) C07GM01TDJD0 00BC7701-6791-573D-B461-470B44D16DF6 https://jamfpro.pretendco.com:8443/computers.html?id=13
86 username username@pretendco.com Apple iMac Pro Intel (Retina 5k, 27-inch, Late 2017) VM0N0WRc4EjC 564D33BC-AF4C-86CF-1DFB-AF6EDFC395A3 https://jamfpro.pretendco.com:8443/computers.html?id=86
87 username username@pretendco.com Apple iMac Pro Intel (Retina 5k, 27-inch, Late 2017) VMWmmR2FJqk3 564D4A6F-280F-1EC0-5E66-178DB2D45A8A https://jamfpro.pretendco.com:8443/computers.html?id=87
85 otheruser otheruser@pretendco.com Apple VMware Virtual Platform VMD4TkB2CNtn 564D6125-8B99-47F1-9867-F92CD80BF0C9 https://jamfpro.pretendco.com:8443/computers.html?id=85
view raw
tmp.crenHMuh.tsv
hosted with ❤ by GitHub

This script is available below and also from GitHub at the following location:

https://github.com/rtrouton/rtrouton_scripts/tree/main/rtrouton_scripts/Casper_Scripts/Generate_Assigned_Mac_Report_From_Jamf_Pro_Usernames

#!/bin/bash
# This script imports a list of usernames from a plaintext file
# and uses that information to generate a report about the computers
# assigned to that username.
#
# ./Generate_Assigned_Mac_Report_From_Jamf_Pro_Usernames.sh usernames.txt
#
# The script can also accept one username as input, if a plaintext file containing usernames
# is not available.
#
# Usage: ./Generate_Assigned_Mac_Report_From_Jamf_Pro_Usernames.sh
#
# Plaintext file format should look like this:
#
# first_username_goes_here
# second_username_goes_here
# third_username_goes_here
# fourth_username_goes_here
#
# Once the username(s) are read from in from the plaintext file or from manual input, the script takes the following actions:
#
# 1. Uses the Jamf Pro API to download all information about the matching computer inventory record in XML format.
# 2. Pulls the following information out of the inventory entry:
#
# Jamf Pro ID
# Assigned user's username
# Assigned user's email
# Manufacturer
# Model
# Serial Number
# Hardware UDID
#
# 3. Create a report in tab-separated value (.tsv) format which contains the following information
# about the deleted Macs
#
# Jamf Pro ID
# Assigned user's username
# Assigned user's email
# Manufacturer
# Model
# Serial Number
# Hardware UDID
# Jamf Pro URL for the computer inventory record
report_file="$(mktemp).tsv"
# If you choose to hardcode API information into the script, set one or more of the following values:
#
# The username for an account on the Jamf Pro server with sufficient API privileges
# The password for the account
# The Jamf Pro URL
# Set the Jamf Pro URL here if you want it hardcoded.
jamfpro_url=""
# Set the username here if you want it hardcoded.
jamfpro_user=""
# Set the password here if you want it hardcoded.
jamfpro_password=""
# If you do not want to hardcode API information into the script, you can also store
# these values in a ~/Library/Preferences/com.github.jamfpro-info.plist file.
#
# To create the file and set the values, run the following commands and substitute
# your own values where appropriate:
#
# To store the Jamf Pro URL in the plist file:
# defaults write com.githubjamfpro-info jamfpro_url https://jamf.pro.server.goes.here:port_number_goes_here
#
# To store the account username in the plist file:
# defaults write com.githubjamfpro-info jamfpro_user account_username_goes_here
#
# To store the account password in the plist file:
# defaults write com.githubjamfpro-info jamfpro_password account_password_goes_here
#
# If the com.github.jamfpro-info.plist file is available, the script will read in the
# relevant information from the plist file.
jamf_plist="$HOME/Library/Preferences/com.github.jamfpro-info.plist"
if [[ -r "$jamf_plist" ]]; then
if [[ -z "$jamfpro_url" ]]; then
jamfpro_url=$(defaults read "${jamf_plist%.*}" jamfpro_url)
fi
if [[ -z "$jamfpro_user" ]]; then
jamfpro_user=$(defaults read "${jamf_plist%.*}" jamfpro_user)
fi
if [[ -z "$jamfpro_password" ]]; then
jamfpro_password=$(defaults read "${jamf_plist%.*}" jamfpro_password)
fi
fi
# If the Jamf Pro URL, the account username or the account password aren't available
# otherwise, you will be prompted to enter the requested URL or account credentials.
if [[ -z "$jamfpro_url" ]]; then
read -p "Please enter your Jamf Pro server URL : " jamfpro_url
fi
if [[ -z "$jamfpro_user" ]]; then
read -p "Please enter your Jamf Pro user account : " jamfpro_user
fi
if [[ -z "$jamfpro_password" ]]; then
read -p "Please enter the password for the $jamfpro_user account: " -s jamfpro_password
fi
echo ""
# Set initial status for exit
error=0
filename="$1"
# If a text file with usernames has not been provided, the script
# will prompt for a single username.
if [[ -z "$filename" ]]; then
read -p "Please enter the relevant username : " assigned_user
assigned_user_filename=$(mktemp)
/usr/bin/touch "$assigned_user_filename"
echo "$assigned_user" > "$assigned_user_filename"
fi
if [[ -z "$filename" ]] && [[ -r "$assigned_user_filename" ]]; then
filename="$assigned_user_filename"
fi
# Remove the trailing slash from the Jamf Pro URL if needed.
jamfpro_url=${jamfpro_url%%/}
progress_indicator() {
spinner="⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
while :
do
for i in $(seq 0 7)
do
echo -n "${spinner:$i:1}"
echo -en "\010"
/bin/sleep 0.10
done
done
}
echo "Report being generated. File location will appear below once ready."
progress_indicator &
SPIN_PID=$!
trap "kill -9 $SPIN_PID" $(seq 0 15)
# Create temp files for data
idtempfile=$(mktemp)
xmltempfile=$(mktemp)
/usr/bin/touch "$xmltempfile"
# Get all computers that are associated with username
while read -r UserToMatch; do
# Get all computers associated with usernames
/usr/bin/curl -sfu "$jamfpro_user:$jamfpro_password" "${jamfpro_url}/JSSResource/computers/match/${UserToMatch}" -H "Accept: application/xml" | xmllint –format – >> "$xmltempfile"
done < "$filename"
# Extract the Jamf Pro computer IDs
/bin/cat "$xmltempfile" | sed -n 's:.*<id>\(.*\)</id>.*:\1:p' > "$idtempfile"
while read -r ID; do
if [[ "$ID" =~ ^[0-9]+$ ]]; then
ComputerRecord=$(/usr/bin/curl -sfu "$jamfpro_user:$jamfpro_password" "${jamfpro_url}/JSSResource/computers/id/$ID" -H "Accept: application/xml" 2>/dev/null)
if [[ ! -f "$report_file" ]]; then
/usr/bin/touch "$report_file"
printf "Jamf Pro ID Number\tAssigned User\tAssigned User Email\tMake\tModel\tSerial Number\tUDID\tJamf Pro URL\n" > "$report_file"
fi
Make=$(echo "$ComputerRecord" | xmllint –xpath '//computer/hardware/make/text()'2>/dev/null)
AssignedUser=$(echo "$ComputerRecord" | xmllint –xpath '//computer/location/username/text()'2>/dev/null)
AssignedUserEmail=$(echo "$ComputerRecord" | xmllint –xpath '//computer/location/email_address/text()'2>/dev/null)
MachineModel=$(echo "$ComputerRecord" | xmllint –xpath '//computer/hardware/model/text()'2>/dev/null)
SerialNumber=$(echo "$ComputerRecord" | xmllint –xpath '//computer/general/serial_number/text()'2>/dev/null)
JamfProID=$(echo "$ComputerRecord" | xmllint –xpath '//computer/general/id/text()'2>/dev/null)
UDIDIdentifier=$(echo "$ComputerRecord" | xmllint –xpath '//computer/general/udid/text()'2>/dev/null)
JamfProURL=$(echo "$jamfpro_url"/computers.html?id="$JamfProID")
if [[ $? -eq 0 ]]; then
printf "$JamfProID\t$AssignedUser\t$AssignedUserEmail\t$Make\t$MachineModel\t$SerialNumber\t$UDIDIdentifier\t${JamfProURL}\n" >> "$report_file"
else
echo "ERROR! Failed to read computer record with id $JamfProID"
error=1
fi
fi
done < "$idtempfile"
# Clean up temp files
if [[ -f "$assigned_user_filename" ]]; then
rm -rf "$assigned_user_filename"
fi
if [[ -f "$xmltempfile" ]]; then
rm -rf "$xmltempfile"
fi
if [[ -f "$idtempfile" ]]; then
rm -rf "$idtempfile"
fi
kill -9 "$SPIN_PID" 2>/dev/null
if [[ -f "$report_file" ]]; then
echo "Report on Macs available here: $report_file"
fi
exit "$error"

Identifying an AWS RDS-hosted database by its tag information

$
0
0

Recently, I was working on a task where I wanted to set up an automated process to create manual database snapshots for a database hosted in Amazon’s RDS service. Normally this is a straightforward process because you can use the database’s unique identifier when requesting the database snapshot to be created.

However in this case, the database was being created as part of an Elastic Beanstalk configuration. This meant that there was the potential for the database in question to be removed from RDS and a new one set up, which meant a new unique identifier for the database I wanted to create manual database snapshots from.

The Elastic Beanstalk configuration does tag the database, using a Name tag specified in the Elastic Beanstalk configuration, so the answer seemed obvious: Use the tag information to identify the database. That way, even if the database identifier changed (because a new database had been created), the automated process could find the new database on its own and continue to make snapshots.

One hitch: Within the AWS API, RDS lists only the following three API calls to interact with tags.

ListTagsForResource would seem to be the answer, but the hitch there is that you have to have the database’s Amazon Resource Name (ARN) identifier available first and then use that to list the tags associated with the database:

aws rds add-tags-to-resource --resource-name arn:aws:rds:us-east-1:123456789102:db:dev-test-db-instance --tags Key=Name

I was coming at it from the other end – I wanted to use the tag information to find the database. RDS’s API doesn’t support that.

Fortunately, the RDS API is not the only way to read tags from an RDS database. For more details, please see below the jump.

The answer is that outside of RDS, there is also the Resource Groups Tagging API, which is accessible using the resourcegroupstaggingapi command for the AWS CLI tool. Among other things, the resourcegroupstaggingapi command allows you to identify a specified values for a specified key for a specified service.

For example, if you were looking for a RDS-hosted database whose database identifier you didn’t know, but you did know that it is in AWS’s eu-west-1 region and had a Name tag with the value of VIPDatabase, you could run the following query to get that databases’s ARN identifier:

aws –region eu-west-1 resourcegroupstaggingapi get-resources –resource-type-filters rds:db –query "ResourceTagMappingList[?Tags[? Key == 'Name' && Value == 'VIPDatabase']].ResourceARN"
view raw
gistfile1.txt
hosted with ❤ by GitHub

Once you had the ARN identifier, you could then use the following command to get the matching database’s instance identifier. For this example, we’re using arn:aws:rds:eu-west-1:123456789012:db:database_name_here as the ARN identifier:

aws rds --region eu-west-1 describe-db-instances --db-instance-identifier arn:aws:rds:eu-west-1:123456789012:db:database_name_here --query "*[].{DBInstanceIdentifier:DBInstanceIdentifier}"

Assuming you wanted to use this lookup capability in a shell script, the following code should get you started:

#!/bin/bash
TagKey="Tag Key Goes Here"
TagValue="Tag's Value Goes Here"
aws_region=$(/bin/curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed "s/.$//g")
RDSDatabaseARNIdentifier=$(aws –region "$aws_region" resourcegroupstaggingapi get-resources –resource-type-filters rds:db –query "ResourceTagMappingList[?Tags[? Key == '$TagKey' && Value == '$TagValue']].ResourceARN" –output=text)
RDSDatabaseDBIdentifier=$(aws rds –region "$aws_region" describe-db-instances –db-instance-identifier "$RDSDatabaseARNIdentifier" –query "*[].{DBInstanceIdentifier:DBInstanceIdentifier}" –output text)
view raw
gistfile1.txt
hosted with ❤ by GitHub

In the case of our example, where you’re looking for a database with a Name tag where the Name tag’s value is VIPDatabase, it would look like this:

#!/bin/bash
TagKey="Name"
TagValue="VIPDatabase"
aws_region=$(/bin/curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed "s/.$//g")
RDSDatabaseARNIdentifier=$(aws –region "$aws_region" resourcegroupstaggingapi get-resources –resource-type-filters rds:db –query "ResourceTagMappingList[?Tags[? Key == '$TagKey' && Value == '$TagValue']].ResourceARN" –output=text)
RDSDatabaseDBIdentifier=$(aws rds –region "$aws_region" describe-db-instances –db-instance-identifier "$RDSDatabaseARNIdentifier" –query "*[].{DBInstanceIdentifier:DBInstanceIdentifier}" –output text)
view raw
gistfile1.txt
hosted with ❤ by GitHub

Setting up software deployment groups using a Jamf Pro Extension Attribute

$
0
0

When setting up software for deployment, it’s usually a good idea to first send it out to a small percentage of the Macs in your environment. That way, if there’s a problem that wasn’t caught in testing, the amount of cleanup required is also small. If that initial deployment works, the software can then be sent out to greater percentages of the Mac population until all of them are eventually covered by the deployment.

This can be a pain to track manually though. New Macs come in, older ones are retired and keeping all Macs covered can turn into a significant investment of time. Fortunately, this is a task which can be automated and enable the Macs to assign themselves to deployment groups based on their machine UUID identifier. For more details, please see below the jump.

This method uses a Jamf Pro Extension Attribute, which is designed to calculate and set a numerical identifier for individual Macs based on the Mac’s machine UUID. This numerical identifier in turn is designed to be used to determine deployment groups.

Jamf Pro Extension Attribute Setup

Once identified, the value will be written to a plist file located in /Library/Preferences. By default, this file is named as follows:

/Library/Preferences/com.companyname.deploymentgroup.plist

You can change the companyname part by setting a different value for the organizationName variable in the Extension Attribute.

Screen Shot 2021 09 10 at 3 41 23 PM

 

If the plist file is present in /Library/Preferences, the Extension Attribute will read the correct value from the plist file.

If the plist file is not present in /Library/Preferences, the Extension Attribute will calculate the correct value and store in the plist as the value of the deploymentGroupAssignmentValue key.

Screen Shot 2021 09 10 at 8 36 20 PM

By default, this Extension Attribute is designed to assign Macs to seven deployment groups, with the following percentage of Macs assigned to each group.


Deployment Group Percentage of Macs
1 1
2 5
3 10
4 20
5 20
6 20
7 24
view raw
Deployment_Group.csv
hosted with ❤ by GitHub

When all is working correctly, the Extension Attribute will display one of the following values for each Mac:

1
2
3
4
5
6
7
view raw
gistfile1.txt
hosted with ❤ by GitHub

Screen Shot 2021 09 10 at 4 29 58 PM

 

When not working properly, the Extension Attribute will display the following value:

0
view raw
gistfile1.txt
hosted with ❤ by GitHub

The Extension Attribute’s values can then be used as Jamf Pro smart group criteria to create smart groups for software deployment.

This script is available below and also from GitHub at the following location:

https://github.com/rtrouton/rtrouton_scripts/tree/main/rtrouton_scripts/Casper_Extension_Attributes/set_deployment_group

#!/bin/bash
# This Jamf Pro Extension Attribute is designed to calculate and set a
# numerical identifier for individual Macs based on the Mac's machine UUID.
# This numerical identifier in turn is designed to be used to determine deployment
# groups.
#
# By default, this script is designed to set up and assign Macs to seven
# deployment groups, with the following percentage of Macs assigned to
# each group.
#
# Group % of Macs
# ————————-
# 1 1
# 2 5
# 3 10
# 4 20
# 5 20
# 6 20
# 7 24
#
# Put in the name of your company, school, or institution.
# Must all be one word without spaces
#
# Examples:
#
# MyGreatCompany
# TheNewSchool
# BankofGreaterNewtown
# MikesSurfShop
organizationName="companyname"
# Do not edit variables below this line
deploymentGroupFile="/Library/Preferences/com.${organizationName}.deploymentgroup.plist"
exitCode=0
log() {
local errorMsg="$1"
echo "$errorMsg"
/usr/bin/logger "$errorMsg"
}
deploymentGroupAssignment() {
deploymentGroup=7
# Get the machine's uuid
machineUUID=$(/usr/sbin/ioreg -rd1 -c IOPlatformExpertDevice | /usr/bin/awk '/IOPlatformUUID/ { gsub(/"/,"",$3); print $3; }')
# If the UUID is available, generate a hash of the UUID
# then use that hash to assign an index number.
if [[ -n "$machineUUID" ]]; then
uuidHash=$(echo "$machineUUID" | /usr/bin/shasum -a 512 | /usr/bin/sed 's/[^0-9]*//g')
indexNumber=$(echo "${uuidHash:0:12}" | /usr/bin/awk '{ print $1 % 100 }')
if [[ -n "$indexNumber" ]]; then
# Once the index number is assigned, match the index number
# to a deployment group's numerical identifier.
case "$indexNumber" in
1) deploymentGroup=1
;;
2|3|4|5|6) deploymentGroup=2
;;
7|8|9|10|11|12|13|14|15|16) deploymentGroup=3
;;
17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36) deploymentGroup=4
;;
37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56) deploymentGroup=5
;;
57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76) deploymentGroup=6
;;
*) deploymentGroup=7
;;
esac
fi
else
log "ERROR! Unable to get machine's machine UUID"
exitCode=1
fi
}
reportExtensionAttributeValue() {
deploymentGroupAssignmentCheck=$(/usr/bin/defaults read ${deploymentGroupFile} deploymentGroupAssignmentValue)
# The extension attribute should have a numeric value greater than zero.
# If the value is blank or a non-number, the following value is reported:
#
# 0
#
# The 0 value indicates that there was a problem determining the deployment group.
if [[ "$deploymentGroupAssignmentCheck" =~ ^[0-9]+$ ]]; then
echo "<result>$deploymentGroupAssignmentCheck</result>"
else
echo "<result>0</result>"
fi
}
# Check to see if there's an existing plist file in /Library/Preferences which has the
# deployment group's numerical identifier assigned as an integer value to the plist file's
# deploymentGroupAssignmentValue key.
#
# If there is not a plist file, or there is not a deploymentGroupAssignmentValue key with a numerical
# value inside the plist file, the extension attribute generates the deployment group's numerical identifier.
# Once the deployment group's numerical identifier is generated, the identifier is stored as an integer value
# to the plist file's deploymentGroupAssignmentValue key.
if [[ -r ${deploymentGroupFile} ]]; then
reportExtensionAttributeValue
else
/usr/bin/defaults delete ${deploymentGroupFile}
deploymentGroupAssignment
/usr/bin/defaults write ${deploymentGroupFile} deploymentGroupAssignmentValue -int "$deploymentGroup"
reportExtensionAttributeValue
fi
exit $exitCode

Setting up an ad-hoc TCP listener for connection testing using Python’s web service

$
0
0

I recently needed to set up a connection test so that an outside vendor could verify that firewall rules had been set up correctly on both ends and that a connection which originated at a specific IP address on the vendor’s end was able to resolve a DNS address on our end and make a connection.

I remembered that Python has a simple way to set up a web server, so I decided to use this to create a script which creates a connection listener by setting up a web server on the desired port. For more details, please see below the jump.

Pre-requisites:

  • Python 3

The script does the following:

  • Creates a temporary directory
  • Changes location into the temporary directory
  • Creates an index.html file inside the temporary directory
  • Starts Python 3’s web service using the content inside the temporary directory

Once running, you should be able to run connection tests against the port number defined in the script. In this example, port 8080 is being used.

Note: If you need to use a privileged port number between 0 – 1023, be aware that you will need to run this script with root privileges or by using authbind.

When the address being checked is connected to, you should see results similar to what’s shown below:

Note: In this case, localhost is being used as the address to check:

Curl connection test:

username@computername ~ % curl -v localhost:8080
* Trying ::1…
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: SimpleHTTP/0.6 Python/3.8.2
< Date: Tue, 14 Sep 2021 18:02:32 GMT
< Content-type: text/html
< Content-Length: 86
< Last-Modified: Tue, 14 Sep 2021 18:01:59 GMT
<
<html>
<head>
<title>Hello World</title>
</head>
<body>
Hello World
</body>
</html>
* Closing connection 0
username@computername ~ %
view raw
gistfile1.txt
hosted with ❤ by GitHub

Telnet connection test using curl:

username@computername ~ % curl -v telnet://localhost:8080
* Trying ::1…
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
^C
username@computername ~ %
view raw
gistfile1.txt
hosted with ❤ by GitHub

As a web page is also being created by the script, you can also try connecting via a web browser. If successful, you should see a Hello World message as shown below.

Screen Shot 2021 09 14 at 4 25 59 PM

The connection test script is available below:

#!/bin/bash
webdirectory=$(mktemp -d)
# Set port number for web service
port_number="8080"
# Create temporary directory and change directory
# into the temporary directory
cd "$webdirectory"
cat > "$webdirectory"/index.html << 'Index'
<html>
<head>
<title>Hello World</title>
</head>
<body>
Hello World
</body>
</html>
Index
# Run webservice
/usr/bin/python3 -m http.server "$port_number"
view raw
connection_test.sh
hosted with ❤ by GitHub

Enabling full disk access for SSH on macOS Big Sur using a management profile

$
0
0

When connecting via SSH to a remote Mac running macOS Big Sur, Apple’s user-level privacy controls apply. You can access data in the home folder of the account you’re using to connect, but you can’t access or alter protected data in other account’s home folders.

For most use cases, this is fine. However, there may be circumstances when full disk access for SSH connections is desired. To accommodate for this, Apple added an Allow full disk access for remote users checkbox in the Remote Login settings in System Preference’s Sharing preference pane.

EnableFullDiskAccessforSSH

This setting can normally only be enabled by the logged-in user sitting at that Mac. However, there is a way to manage this with a configuration profile. For more details, please see below the jump.

I’ve written a profile to manage full disk access for SSH connections which does the following:

  • Enables the Allow full disk access for remote users checkbox in the Remote Login settings in System Preference’s Sharing preference pane
  • Enables full disk access for /usr/libexec/sshd-keygen-wrapper

The first part is mainly cosmetic. It enables the Allow full disk access for remote users checkbox, but does not actually enable full disk access for SSH. That function is handled by the second part, which are the PPPC settings to allow full disk access for /usr/libexec/sshd-keygen-wrapper.

In order to apply PPPC settings, there are some pre-requisites:

  • User Approved Mobile Device Management (UAMDM) must be enabled on the target Mac.
  • Profile must be installed by an MDM server.

Those pre-requisites also apply to deploying this profile, which is available via the link below:

https://github.com/rtrouton/profiles/tree/main/EnableFullDiskAccessforSSH

When deployed, the profile should appear similar to this in System Preference’s Profiles preference pane.

Screen Shot 2021 09 29 at 5 23 58 PM

Hat tip to poundbangbash for providing the correct PPPC settings for SSH full disk access by allowing full disk access to /usr/libexec/sshd-keygen-wrapper.

Slides and video from the “AutoPkg in the Cloud” session at MacSysAdmin 2021

Viewing all 764 articles
Browse latest View live