Posted on 09-15-2021 03:27 PM
Hello All,
First off, I tried to find another post related to this type of thing and was not able to find on JAMF Nation so sorry if this is a duplicate post. I also scoured the web for this and seem to find things that are older or designed for much more complex needs.
I am trying to come up with a script that, at least to me, should be pretty simple to do. This will be deployed via Self Service for users to run, so not something executed from Terminal.
At bit of back story: I am trying to deploy FileVault in our environment and we have mobile/AD Joined accounts that will be used for enabling Encryption and generating recovery keys. My understanding is that this will require the local admin account (which does have a token verified by: sudo profiles status -type bootstraptoken) created in the Pre-Stage process on our machines to "pass" the Secure Token to these mobile accounts using the sysadminctl command. I would like to script the process out as much as possible and I am trying to find a good/simple solution to create a pop-up box prompt for the currently logged in user to enter their password and click OK.
This is what my script looks like so far. Any suggestions or tips is greatly appreciated!
#!/bin/bash
## Get the logged in user's name
LoggedinUser=$(/usr/bin/stat -f%Su /dev/console)
## Prompt for currently logged in users password
userPass=$ ??????????????????????????
## Enable the logged in user with secure token
sudo sysadminctl -adminUser <ourlocaladminaccount> -adminPassword -<ourlocaladminpassword> -secureTokenOn "$LoggedinUser" -password -$"userPass"
09-15-2021 08:36 PM - edited 09-27-2021 07:33 PM
I use applescript & prompt the end user for password & then write it to a tmp text file, /var/tmp is ideal as its wiped after restart & you can also encode the password using something like ceasar cipher / rot13 but here is a script for passing it in plain text, you will see in the scripts in the github link, the file the applescript writes to is then passed using cat to the shell script for automating filevault within a script.
@Schmidt https://github.com/Hugonauts/Jamf-Filevault
#!/usr/bin/osascript
set myupname to do shell script "echo $USER"
set questionadmin to "*EDITHERE* Account Setup Requires Encryption.
Please enter your Password " & myupname & ""
repeat
try
set init_pass to text returned of (display dialog questionadmin default answer "" buttons {"OK", "Cancel"} default button 1 with hidden answer)
set final_pass to text returned of (display dialog "Please verify and re-type your password" buttons {"OK", "Cancel"} default button 1 default answer "" with hidden answer)
if (final_pass is not equal to init_pass) then
display dialog "Password Incorrect. Please Try Again." with icon stop
else
try
do shell script "ls" user name myupname password init_pass with administrator privileges
set admin_passwd to final_pass
exit repeat
on error err
display dialog "Password Incorrect. Please Try Again."
end try
end if
on error number -128
set canceldialog to display dialog "Cancel was Selected, " & myupname & " is Not Enabled for Filevault 2. You must Enable " & myupname & " for Filevault 2 in Order to Login at Startup." buttons {"OK"} default button 1 with icon stop
try
if button returned of canceldialog is "OK" then
return
end if
end try
end try
end repeat
do shell script "touch /Library/Scripts/TempFVPassword.txt"
do shell script "echo " & init_pass & "> " & "/Library/Scripts/TempFVPassword.txt"
09-16-2021 05:11 AM - edited 09-16-2021 05:15 AM
Unfortunately as with most things involving macOS, nothing is simple. You are on the right path in needing to prompt the users to enter credentials, however I have found the most straight forward commands to use are fdesetup for provisioning access. I can see needing a users authentication to remove filevault access, but granting it should be a much simpler process. Either way this is what we use, it could be cleaned up a bit but it works. I have not finished the end of it to run an if statement to exit correctly (or fail) if FV access was not provisioned, I just noticed that lol.
#!/bin/bash
echo "Begin script"
######################
# Gather and verify local admin account
# Password is salted lines 13-19 can be removed, and the password can be hard coded in line 19
######################
#*------------------------ STRING DECRYPTION ------------------------*#
function DecryptString() {
echo "${1}" | /usr/bin/openssl enc -aes256 -d -a -A -S "${2}" -k "${3}"
}
Pass=""
Salt=""
DecryptString=$(DecryptString "$5" "$Salt" "$Pass")
adminUser="$4"
adminPass="$DecryptString"
osvers=$(sw_vers -productVersion | awk -F. '{print $2}')
check4AD=`/usr/bin/dscl localhost -list . | grep "Active Directory"`
## verify that adminuser and pass variables are both passed to the user
if [[ -z "$adminUser" ]] || [[ -z "$adminPass" ]] ; then
dialog="either Admin User or Password is missing"
echo "$dialog"
cmd="Tell app \"System Events\" to display dialog \"$dialog\""
/usr/bin/osascript -e "$cmd"
exit 1
fi
## check the admin password
adminCheck=$(/usr/bin/dscl /Local/Default -authonly "$adminUser" "$adminPass")
if [[ -z "$adminCheck" ]] ; then
echo "Admin password is verified"
else
echo "Admin Password not working"
exit 1
fi
######################
# Check for domain bind, fails out of not bound
######################
echo "Checking for Domain Bind"
if [ "${check4AD}" != "Active Directory" ]; then
dialog="This machine is not bound to Active Directory.\nPlease bind to AD first. "
echo "$dialog"
cmd="Tell app \"System Events\" to display dialog \"$dialog\""
/usr/bin/osascript -e "$cmd"
exit 2
fi
######################
# Popups asking for user to ender userID and Password
######################
echo "Prompting for userToAdd credentials."
## Prompt for Username
userToAdd=$(/usr/bin/osascript<<END
tell application "System Events"
activate
set the answer to text returned of (display dialog "Enter your userID:" default answer "" buttons {"Continue"} default button 1)
end tell
END
)
## Prompt for Password
userPass=$(/usr/bin/osascript<<END
tell application "System Events"
activate
set the answer to text returned of (display dialog "Enter your Password:" default answer "" with hidden answer buttons {"Continue"} default button 1)
end tell
END
)
loopCount=0
while [ "$loopCount" -lt 3 ]; do
# Refresh Directory Services
if [[ ${osvers} -ge 7 ]]; then
/usr/bin/killall opendirectoryd
else
/usr/bin/killall DirectoryService
fi
sleep 15
## try to auth the user in advance. this seems to increase the success of the ID command.
/usr/bin/dscl /Search -authonly "$userToAdd" "$userPass"
adCheck=`id $userToAdd`
echo "AD Check is: $adCheck"
if [[ -z "$adCheck" ]] ; then
((loopCount++))
else
echo "AD Check successful"
break
fi
done
######################
# Fails script if user account is not found on domain controller
# Commented out as this function is error prone if the domain controller takes too long to respond.
######################
#
#if [[ -z "$adCheck" ]] ; then
# dialog="AD User Not found. Please contact the support center at 205.261.4357"
# echo "$dialog"
# cmd="Tell app \"System Events\" to display dialog \"$dialog\""
# /usr/bin/osascript -e "$cmd"
# exit 3
#fi
#
#sleep 2
#
######################
# Remove FV Access if existing
######################
sleep 2
sudo fdesetup remove -user $userToAdd
######################
# Provision Admin Access
# Comment this function out if admin access is not desired
######################
dscl . -append /groups/admin GroupMembership $userToAdd
echo "Provisioning admin access for $userToAdd."
######################
# Provision FileVault Access
# Filevault encryption status currently commented out as its not needed at this time
######################
## Check to see if the encryption process is complete
#encryptCheck=fdesetup status\
#statusCheck=$(echo "${encryptCheck}" | grep "FileVault is On.")
#expectedStatus="FileVault is On."
# if [ "${statusCheck}" != "${expectedStatus}" ]; then
# echo "The encryption process has not completed, unable to add user at this time." echo "${encryptCheck}" exit 4
# else
# echo "Adding $userToAdd to FileVault 2 list."
# fi
#
#sleep 5
## Get the user to be added to FV
userName=$userToAdd
## This "expect" block will populate answers for the sysadminctl variables.
sysadminctl -adminUser "$adminUser" -adminPassword "$adminPass" -secureTokenOn "$userName" -password "$userPass"
echo "${userName} has been added to the FileVault 2 list."
######################
# Runs JAMF Recon to assign Mac to $userToAdd
######################
jamf recon -endUsername $userToAdd
######################
# Clean up
######################
echo "Script completed"
exit 0
Posted on 09-21-2021 12:45 PM
I was able to create a simple script below using the method you provided. Nothing fancy but at least for initial testing, seems to get the job done. One thing I did tweak was remove the "Tell" potion of the prompt as it removes the need for users to accept the prompt of "JAMF wants access to control system events", which I could not seem to remove using PPPCP, although we already have JAMF PPPCP setup.
#!/bin/bash
## Get the logged in user's name
LoggedinUser=$(/usr/bin/stat -f%Su /dev/console)
## Prompt for Password
userPass=$(/usr/bin/osascript<<END
application "System Events"
activate
set the answer to text returned of (display dialog "IT needs to Activate Encryption, Please Enter your Password:" default answer "" with hidden answer buttons {"Continue"} default button 1)
END
)
## Enable the logged in user with secure token
sudo sysadminctl -adminUser <localmacaccount>-adminPassword -<localmacpassword> -secureTokenOn "$LoggedinUser" -password -$"userPass"
Posted on 09-17-2021 01:18 PM
I had the same problem as you, and this was my resolution, using osascript
CurrentUser=$(stat -f%Su /dev/console)
UIDCurrentUser=$(id -u "$CurrentUser")
adminPASS=""
jamfHELPERbody=""
jamfHELPERHEADER=""
jamfHELPERicon=""
jamfHELPERbody2=""
popup=`/Library/Application\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -description "$jamfHELPERbody" -heading "$jamfHELPERHEADER" -icon "$jamfHELPERicon" -button1 "Continue" -defaultButton 1`
#popup=`/Library/Application\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -description "$description" -heading "{VALUE}" -icon "$logo" -button1 "Update Now" -defaultButton 1 -countdown 1800 -countdown -alignCountdown center`
if [[ "$popup" == "0" ]]; then]
#Ask User Password
userPassword=$(/bin/launchctl asuser "$UIDCurrentUser" sudo -iu "$CurrentUser" /usr/bin/osascript -e 'Tell application "System Events" to display dialog "Password for user: '${CurrentUser}'" default answer "" with title "{VALUE}" with text buttons {"Ok"} default button 1 with hidden answer' -e 'text returned of result')
#Enable SecureToken for the CurrentUser and adminUser
sysadminctl -adminUser {admin account} -adminPassword $adminPASS -secureTokenOn $CurrentUser -password $userPassword
#Notification
/Library/Application\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -description "$jamfHELPERbody2" -button1 "Ok" -icon "$jamfHELPERicon"
fi
exit 0
Posted on 09-18-2021 11:26 AM
Just a heads up, and I totally understand this may be your only option, but prompting a user for their password in any language that doesn't use some sort of secure auth hook/API, or something like say a password vault, that password will be stored in clear text in memory and possibly elsewhere. I am only pointing this out from a security perspective so you are aware, and not really telling anyone how to do their job.
Posted on 09-21-2021 12:36 PM
Hey tlarkin,
Thanks for the advice. I am still new to JAMF/MacOS administration so if you have any tips for how to secure this information, or if you know of ways that using a script like this can exploit and/or extract the users password, I would like to learn more.
Posted on 09-22-2021 09:26 AM
An API Hook is absolutely the way to go. +1
Posted on 09-22-2021 10:03 AM
API hook as in this right?
https://{{url}}/JSSResource/computercommands/command/ScheduleOSUpdate/action/install/id/136,326,332
I run that in postman at night after hours, but not sure if that should be in a script or if you have yours as part of a script @Hugonaut
09-22-2021 10:18 AM - edited 09-27-2021 07:32 PM
@beebooI am referring to an Api call in the sense of scripting the following (all without writing anywhere on the system),
Prompt End user for Password -> Encode Password -> Pass encoded password via api to say Jamf Dashboard via Extension attribute -> Pass Extension Attribute of Encoded Password to script in Jamf Dash as Variable & have another variable that decodes pass & used as the password flag for the startoscommand for M1s to authenticate end user & upgrade OS.
this will all be fixed in Monterey though
Posted on 09-22-2021 10:38 AM
Do you mind sharing the workflow?
I didnt think there was an alternative method til you brought up yours.
And when you say itll be fixed in monterey, what do you? that wont be possible anymore?
Thanks!
Posted on 09-22-2021 10:53 AM
Yeah there is a secure prompt API in macOS (swift or objc) which one can invoke to pop up a dialog box or prompt for touch ID or what not. AFAIK there is no way to do this in scripting languages like the shells or AppleScript. I do know AppleScript will store creds in clear text. I am not here to accept any risks for any other Orgs, but simply pointing this out. It is up to the Org to accept those risks. Sometimes the risk is wroth the acceptance, sometimes it is not, but that highly depends on your threat models
Posted on 09-22-2021 10:44 AM
It was just a thought pertaining to what tlarkin stated, I don't have this built out to share, Monterey will introduce an easier workflow for us