Posted on 03-11-2019 06:21 PM
I searched all over for this specific problem and I can't seem to find anything close. Feel free to redirect me
I've got a LaunchD that calls a script to do a bunch of checks before calling a JAMF policy that grants the logged in user a secure token for filevault.
The problem I'm having is that I need to update preboot as part of the JAMF policy, but when the script gets there I get this
I'm not quite sure why this is happening. JAMF essentially runs as root. I've even tested running the command:
diskutil apfs updatePreboot /
As root just to check if the same prompt would happen, and it still happens.
I'm trying to get an alpha version of what we will be running soon in testers hands but that system prompt is killing me. Here's all the code, please excuse the ugly code, its still pre-alpha for right now.
For reference here's the launchD that calls the first script:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>com.spi.GrantUserToken</string>
<key>ProgramArguments</key>
<array>
<string>sh</string>
<string>/usr/local/spi/bin/GrantUserToken</string>
</array>
<key>UserName</key>
<string>root</string>
<key>RunAtLoad</key>
<false/>
<key>StartInterval</key>
<integer>30</integer>
<key>ExitTimeOut</key>
<integer>120</integer>
<key>Debug</key>
<true/>
</dict>
</plist>
Here's the script that the LaunchD calls:
#!/bin/bash
CurrentUser=`/bin/ls -l /dev/console | /usr/bin/awk '{ print $3 }'`
chkLocal=$(id -u ${CurrentUser})
tStamp=$(date +%x_%H:%M:%S)
sName=$(basename "$0")
logStamp="${sName} | ${tStamp}"
tokenAddDate=/usr/local/spi/etc/$CurrentUser.txt
lsgutLog=/usr/local/spi/log/LocalScriptGrantUserToken.log
pDelta='false'
# Adding the log file if it doesn't exist
# wish I didn't do this outside of a function
if [[ ! -f $lsgutLog ]]
then
if [[ ! -d /usr/local/spi/log ]]
then
echo "${logStamp} | Creating a log path"
mkdir /usr/local/spi/log
fi
echo "${logStamp} | Creating a log"
touch $lsgutLog
fi
# Checking for /spi/etc path
if [[ ! -d /usr/local/spi/etc/ ]]
then
echo "${logStamp} | Creating a etc path"
mkdir /usr/local/spi/etc
fi
chkJAMFStatus(){
# not called by any other function - nneds to be in main
# make sure we can connect to JAMF
echo "Running chk JAMF Status"
if [[ $(/usr/local/jamf/bin/jamf checkJSSConnection | grep 'available') =~ "The JSS is available." ]]
then
jamfStatus='true'
echo "${logStamp} | JAMF connection OK"
echo "${logStamp} | Check FDE Status on this machine"
chkFVStatus
else
jamfStatus='false'
echo "${logStamp} | Cannot connect to JAMF"
echo "${logStamp} | Exiting Now"
exit 0
fi
}
chkFVStatus(){
# Called by checkJAMFStatus
# Check if FileVault is Enabled
echo "${logStamp} | Running chk FV Status"
if [[ $("/usr/bin/fdesetup" status 2>&1) =~ "FileVault is On." ]]
then
fvStatus='true'
echo "${logStamp} | FileVault is On"
echo "${logStamp} | Check for console user"
chKLoginStatus
else
fvStatus='false'
echo "${logStamp} | FileVault is Off"
echo "${logStamp} | Exiting Now"
exit 0
fi
}
chKLoginStatus(){
# Called by chkFVStatus
# Check if someone is logged in
chkFinder=$(pgrep -x "Finder")
chkDock=$(pgrep -x "Dock")
if [ "$chkFinder" != "" ] && [ "$chkDock" != "" ] && [ "$CurrentUser" != "_mbsetupuser" ]
then
if [[ "$CurrentUser" == "" ]]
then
loginStatus='false'
echo "${logStamp} | Nobody is logged in"
echo "${logStamp} | Exiting Now"
exit 0
else
loginStatus='true'
echo "${logStamp} | ${CurrentUser} is logged in"
echo "${logStamp} | Check ${CurrentUser} netowrk status"
chkLocalUsers
fi
fi
}
chkLocalUsers(){
# Called by chKLoginStatus
# see if the current user is a local user
if [[ $chkLocal -lt 900 ]]
then
localUsr='true'
echo "${logStamp} | ${CurrentUser} is not a network user, UID is ${chkLocal}"
echo "${logStamp} | Exiting Now"
exit 0
else
localUsr='false'
echo "${logStamp} | User is a netowrk user"
echo "${logStamp} | Check ${CurrentUser} Token"
chkUserToken
fi
}
chkUserToken(){
# Called by chkLocalUsers
if [[ $("/usr/sbin/sysadminctl" -secureTokenStatus "$CurrentUser" 2>&1) =~ "ENABLED" ]]; then
userToken='true'
echo "${logStamp} | ${CurrentUser} already has a token"
echo "${logStamp} | Check ${CurrentUser} password delta"
chkUserPassDelta
else
userToken='false'
echo "${logStamp} | ${CurrentUser} needs a token"
echo "${logStamp} | ${CurrentUser} Call for JAMF"
callJAMFPolicy
fi
}
chkUserPassDelta(){
# Called by chkUserToken
if [[ -f $tokenAddDate ]]
then
# get Last Password change from DSCL
MSLastPWD=`dscl "/Active Directory/SOMEPLACE/All Domains" -read /Users/${CurrentUser} | grep -i SMBPasswordLastSet | cut -d ' ' -f 2 | sed q`
# get today's date in Unix time
todayUnix=`date "+%s"`
# Convert Last Password Change date into Unix Time
lastPWDUnix=`expr $MSLastPWD / 10000000 - 11644473600`
# Calculate Difference between Today's Date and Last Changed Date
diffUnix=`expr $todayUnix - $lastPWDUnix`
# Get the Unix Date when the user last got a token from tokenAddDate
tokenDay=$( tail -n 1 $tokenAddDate | awk -F'on ' '{print $2}' )
# Get the difference between todays date and when the current user last got a token
diffTokenTime=`expr $todayUnix - $tokenDay`
# check if the user has changed their password in the last 86400 seconds
# and they last got issued a token more than 86400 seconds ago
# Have to do it in seconds cause bash doesn't do floats at all
if [[ $diffUnix -lt 86400 ]] && [[ $diffTokenTime -gt 86400 ]]
then
pDelta='true'
echo "${logStamp} | ${CurrentUser} needs a token or a sync"
echo "${logStamp} | ${CurrentUser} Call for JAMF"
callJAMFPolicy
else
pDelta='false'
echo "${logStamp} | ${CurrentUser} is good to go."
echo "${logStamp} | Exiting now"
exit 0
fi
else
pDelta='true'
echo "${logStamp} | ${CurrentUser} has no TokenAdd File"
echo "${logStamp} | ${CurrentUser} Call for JAMF"
callJAMFPolicy
fi
}
callJAMFPolicy(){
# check if any of the checks failed, if any one did then exit, otherwise phone home
if [[ $jamfStatus == 'true' ]] && [[ $fvStatus=='true' ]] && [[ $localUsr == 'false' ]] && [[ $loginStatus == 'true' ]] && [[ $pDelta == 'true' ]]
then
#Go for JAMF policy event call grantToken
echo "${logStamp} | All checks passed"
echo "${logStamp} | Caliing JAMF"
/usr/local/jamf/bin/jamf policy -event "grantToken"
else
echo "${logStamp} | JAMF Status is ${jamfStatus}"
echo "${logStamp} | FileVault is on ${fvStatus}"
echo "${logStamp} | User has a Token ${userToken}"
echo "${logStamp} | User is local ${localUsr}"
echo "${logStamp} | Login status is ${loginStatus}"
echo "${logStamp} | User Toekn is in sync ${pDelta}"
echo "${logStamp} | Failed one or more checks"
exit 0
fi
}
main(){
chkJAMFStatus
sleep 5
}
main > $lsgutLog 2>&1
And here's the script that the JAMF policy runs if it gets called:
#!/bin/bash
# JAMF VARS ONLY
AdminUser=$4
AdminPass=$5
# START MY VARIABLES
CurrentUser=$(/bin/ls -l /dev/console | /usr/bin/awk '{ print $3 }')
todayUnix=`date "+%s"`
tokenAddDate=/usr/local/spi/etc/$CurrentUser.txt
tokenLog=/usr/local/spi/log/$CurrentUser.log
tStamp=$(date +%x_%H:%M:%S)
sName=$(basename "$0")
logStamp="${sName} | ${tStamp}"
pDelta='false'
# END MY VARIABLES
# Adding the log file if it doesn't exist
if [[ ! -f $tokenLog ]]
then
if [[ ! -d /usr/local/spi/log ]]
then
echo "${logStamp} | Creating a log path"
mkdir /usr/local/spi/log
fi
echo "${logStamp} | Creating a log"
touch $tokenLog
fi
# Checking for /spi/etc path
if [[ ! -d /usr/local/spi/etc/ ]]
then
echo "${logStamp} | Creating a etc path"
mkdir /usr/local/spi/etc
fi
chkAdminCred(){
# Check if we passed the parameters in at all
echo "${logStamp} | Running chk Admin Cred"
if [[ "${AdminUser}" == "" ]] || [[ "${AdminPass}" == "" ]]
then
echo "${logStamp} | Admin User or Pass undefined, go back and set up in parameters 4 and 5."
exit 1
fi
if [[ "${AdminUser}" == "${CurrentUser}" ]]
then
echo "${logStamp} | Admin user cannot be the same as the current user"
exit 2
fi
}
thatThing(){
while :; do # Loop until valid input is entered or Cancel is pressed.
CurrentUserPass="$(sudo -u $CurrentUser /usr/bin/osascript -e 'tell application "System Events" to display dialog "Please enter your current password" default answer "" with title "FileVault Configuration" with text buttons {"Submit"} default button 1 with hidden answer' -e 'text returned of result')"
if (( $? )); then exit 50; fi # Abort, if user pressed Cancel.
if [[ -z "$CurrentUserPass" ]]; then
# The user left the project name blank.
sudo -u $CurrentUser osascript -e 'Tell application "System Events" to display alert "You must enter a password; please try again." as warning' >/dev/null
# Continue loop to prompt again.
else
# Valid input: exit loop and continue.
break
fi
done
}
JRRToken(){
echo "${logStamp} | Running JRR Token"
# Prompt for password
echo "${logStamp} | Promting for password"
thatThing
#Checking to see if user has changed their password in less than a day
if [[ ${pDelta} == "true" ]]
then
# Remove user from FV Token Holders redirect ALL output to null
echo "${logStamp} | Removing user Token"
sysadminctl -adminUser $AdminUser -adminPassword $AdminPass -secureTokenOff $CurrentUser -password $CurrentUserPass > /dev/null 2>&1
sleep 1
fi
# Add (or re-add) user to FV Token Holders redirect ALL output to null
echo "${logStamp} | Adding user Token"
sysadminctl -adminUser $AdminUser -adminPassword $AdminPass -secureTokenOn $CurrentUser -password $CurrentUserPass > /dev/null 2>&1
# Mark the data in Unix time when this users token was added
# Always adding the latest change to the end of the text file
if [[ ! -f ${tokenAddDate} ]]
then
echo "${logStamp} | creating file ${tokenAddDate}"
touch $tokenAddDate
chown root:wheel $tokenAddDate
chmod 755 $tokenAddDate
echo "${logStamp} | adding UNIX time to ${tokenAddDate}"
echo "${CurrentUser} on ${todayUnix}" >> $tokenAddDate
else
echo "${logStamp} | adding UNIX time to ${tokenAddDate}"
echo "${CurrentUser} on ${todayUnix}" >> $tokenAddDate
fi
# Update preboot
# This could be long I may want to add a loop or something
echo "${logStamp} | Updating preboot"
diskutil apfs updatepreBoot /
sleep 5
echo "${logStamp} | End JRR Token"
}
chkUserPassDelta(){
# Called by chkUserToken
if [[ -f $tokenAddDate ]]
then
# get Last Password change from DSCL
MSLastPWD=`dscl "/Active Directory/SOMEPLACE/All Domains" -read /Users/${CurrentUser} | grep -i SMBPasswordLastSet | cut -d ' ' -f 2 | sed q`
# get today's date in Unix time
todayUnix=`date "+%s"`
# Convert Last Password Change date into Unix Time
lastPWDUnix=`expr $MSLastPWD / 10000000 - 11644473600`
# Calculate Difference between Today's Date and Last Changed Date
diffUnix=`expr $todayUnix - $lastPWDUnix`
# Get the Unix Date when the user last got a token from tokenAddDate
tokenDay=$( tail -n 1 $tokenAddDate | awk -F'on ' '{print $2}' )
# Get the difference between todays date and when the current user last got a token
diffTokenTime=`expr $todayUnix - $tokenDay`
# check if the user has changed their password in the last 86400 seconds
# and they last got issued a token more than 86400 seconds ago
if [[ $diffUnix -lt 86400 ]] && [[ $diffTokenTime -gt 86400 ]]
then
pDelta='true'
echo "${logStamp} | ${CurrentUser} needs a token or a sync"
echo "${logStamp} | ${CurrentUser} lets sync that token"
JRRToken
else
pDelta='false'
echo "${logStamp} | ${CurrentUser} is good to go."
echo "${logStamp} | Exiting now"
exit 0
fi
else
pDelta='true'
echo "${logStamp} | ${CurrentUser} has no TokenAdd File"
echo "${logStamp} | ${CurrentUser} time to make one"
JRRToken
fi
}
chkUserToken(){
if [[ $("/usr/sbin/sysadminctl" -secureTokenStatus "$CurrentUser" 2>&1) =~ "ENABLED" ]]; then
userToken="true"
echo "${logStamp} | ${CurrentUser} already has a token."
echo "${logStamp} | Check ${CurrentUser} password delta"
chkUserPassDelta
else
userToken="false"
echo "${logStamp} | ${CurrentUser} needs a token."
JRRToken
fi
}
main(){
chkAdminCred > $tokenLog 2>&1
wait $!
sleep 5
chkUserToken > $tokenLog 2>&1
wait $!
sleep 5
}
main
Also, calling sometimes this:
sudo -u $CurrentUser /usr/bin/osascript -e 'tell application "System Events" to display dialog blah blah'
Can result in an odd error, and I'm not 100% sure on how to fix that. If I remove the 'sudo -u' I get a 610 error, and if I have it I get a 54 error. Sometimes that happens, but not all the time for some reason.
It's all a bit of a hot mess right now, so please excuse the ugly scripts.
If anyone has any ideas that would be great.
Posted on 03-11-2019 07:47 PM
I'm dumb.
I figured out that there was a media restriction on the internal drive that was causing the issue with updatepreBoot.
I can't figure out how to delete this post so...
I am still seeing some weirdness with returning the text from an applescript prompt.
Here's the full line from the needless vomit of code above:
CurrentUserPass="$(sudo -u $CurrentUser /usr/bin/osascript -e 'tell application "System Events" to display dialog "Please enter your current password" default answer "" with title "FileVault Configuration" with text buttons {"Submit"} default button 1 with hidden answer' -e 'text returned of result')"
Should I be using EOF for this? Does that fix the 610 error about interaction as root, or the 54 error that is a weird file permission error that makes little to no sense in this context. Gotta love applescript.
Anyhoo, if someone has an answer for that or knows how to delete this post, i'd be much obliged for your troubles.
Posted on 03-12-2019 06:36 AM
I had similar problems with my osascript in my token script..I ended up putting a jamf helper before the password input and getting rid of the while/do and replacing it with until/done with a counter. When it ran on my end users it popped up like 20 windows and they did not input user info. I limited the user password attempts to 5 tries.
# Prompt for password
jamfHelper="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"
LOGO="/Library/Application Support/JAMF/Jamf.app/Contents/Resources/AppIcon.icns"
LOGO_POSIX="$(/usr/bin/osascript -e 'tell application "System Events" to return POSIX file "'"$LOGO"'" as text')"
PROMPT_TITLE="Enabling SecureToken for FileVault"
PROMPT_MESSAGE="Enabling SecureToken for FileVault. Please enter your Mac Login password on the following prompt."
FINISHED_MESSAGE="Secure Token has successfully been enabled for FileVault"
FORGOT_PW_MESSAGE="You made five incorrect password attempts. SecureToken was not enabled."
USER_ID=$(/usr/bin/id -u "$userName")
L_ID=$USER_ID
L_METHOD="asuser"
# Display a branded prompt explaining the password prompt.
echo "Alerting user $userName about incoming password prompt..."
"$jamfHelper" -windowType "utility" -icon "$LOGO" -title "$PROMPT_TITLE" -description "$PROMPT_MESSAGE" -button1 "Next" -defaultButton 1 -startlaunchd &>/dev/null
# Get the logged in user's password via a prompt.
echo "Prompting $userName for their Mac password..."
userPass="$(/bin/launchctl "$L_METHOD" "$L_ID" /usr/bin/osascript -e 'display dialog "Please enter the password you use to log in to your Mac:" default answer "" with title "'"${PROMPT_TITLE//"/\"}"'" giving up after 86400 with text buttons {"OK"} default button 1 with hidden answer with icon file "'"${LOGO_POSIX//"/\"}"'"' -e 'return text returned of result')"
# Validate the user's password
TRY=1
until /usr/bin/dscl /Search -authonly "$userName" "$userPass" &>/dev/null; do
(( TRY++ ))
echo "Prompting $userName for their Mac password (attempt $TRY)..."
userPass="$(/bin/launchctl "$L_METHOD" "$L_ID" /usr/bin/osascript -e 'display dialog "Sorry, that password was incorrect. Please try again:" default answer "" with title "'"${PROMPT_TITLE//"/\"}"'" giving up after 86400 with text buttons {"OK"} default button 1 with hidden answer with icon file "'"${LOGO_POSIX//"/\"}"'"' -e 'return text returned of result')"
if (( TRY >= 5 )); then
echo "[ERROR] Password prompt unsuccessful after 5 attempts. Displaying "forgot password" message..."
/bin/launchctl "$L_METHOD" "$L_ID" "$jamfHelper" -windowType "utility" -icon "$LOGO" -title "$PROMPT_TITLE" -description "$FORGOT_PW_MESSAGE" -button1 'OK' -defaultButton 1 -startlaunchd &>/dev/null &
exit 1
fi
done
echo "Successfully validated the correct password."
Posted on 03-12-2019 10:31 AM
Thanks @daniel.hayden
That's a unique way to handle the prompt. Haven't seen it before, and I've tried to google all of em.
I tried:
launchctl asuser someusername /usr/bin/osascript -e 'display dialog [password prompt stuff here]'
To call the prompt, and gotten odd errors, sometimes. Using 'sudo -u' seems to be the most reliable so far.
I will try that 'until do' loop instead of 'while do', that may be the trick that leads me to the promise land.
Thanks for the help.