Script to Prompt user for password

Schmidt
New Contributor II

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"

 

12 REPLIES 12

Hugonaut
Valued Contributor

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"

 

 

________________
Looking for a Jamf Managed Service Provider? Look no further than Rocketman

AJPinto
Contributor III

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

 

 

 

Schmidt
New Contributor II

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"

 

 

 

beeboo
Contributor

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

tlarkin
Honored Contributor

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.

Schmidt
New Contributor II

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.

Hugonaut
Valued Contributor

An API Hook is absolutely the way to go. +1

________________
Looking for a Jamf Managed Service Provider? Look no further than Rocketman

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 

Hugonaut
Valued Contributor

@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

________________
Looking for a Jamf Managed Service Provider? Look no further than Rocketman

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!

tlarkin
Honored Contributor

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

Hugonaut
Valued Contributor

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

________________
Looking for a Jamf Managed Service Provider? Look no further than Rocketman