#!/bin/bash # # Author : Perry Driscoll - https://github.com/PezzaD84 # Created : 31/1/2022 # Updated : 26/9/2023 # Version : v2.2.4 # ############################################################################ # Description: # This script is to decode the encoded LAPS password and display this # to the end user/support engineer. # ############################################################################ # Copyright © 2023 Perry Driscoll # # This file is free software and is shared "as is" without any warranty of # any kind. The author gives unlimited permission to copy and/or distribute # it, with or without modifications, as long as this notice is preserved. # All usage is at your own risk and in no event shall the authors or # copyright holders be liable for any claim, damages or other liability. ############################################################################ # # JAMF Script Variables # $4: JSS URL # $5: Encoded API Credentials # $6: Time to trigger password cycle (in minutes) # $7: Slack WebHook URL # $8: Service desk URL # ############################################################################ ############################################################################ # Variables ############################################################################ CURRENT_USER=$(ls -l /dev/console | awk '{ print $3 }') DEVICE=`hostname` LAPSLOG="/Library/.LAPS/Logs/LAPS.log" SERVICEDESK="$8" OS=$(sw_vers --productVersion | awk -F '.' '{print $1}') ############################################################################ # Create Log ############################################################################ if [ -f "$LAPSLOG" ]; then echo "Log already exists. Continuing setup....." else echo "Log does not exist. Creating Log now....." mkdir -p /Library/.LAPS/Logs/ touch "$LAPSLOG" fi echo -e "=================================================================\n================ LAPS Decode `date '+%d/%m/%Y %T'` ================\n=================================================================" | tee -a "$LAPSLOG" ############################################################## # Functions ############################################################## DialogInstall(){ pkgfile="SwiftDialog.pkg" logfile="/Library/Logs/SwiftDialogInstallScript.log" URL="https://github.com$(curl -sfL "$(curl -sfL "https://github.com/bartreardon/swiftDialog/releases/latest" | tr '"' "\n" | grep -i "expanded_assets" | head -1)" | tr '"' "\n" | grep -i "^/.*\/releases\/download\/.*\.pkg" | head -1)" # Start Log entries echo "--" >> ${logfile} echo "`date`: Downloading latest version." >> ${logfile} # Download installer curl -s -L -J -o /tmp/${pkgfile} ${URL} echo "`date`: Installing..." >> ${logfile} # Change to installer directory cd /tmp # Install application sudo installer -pkg ${pkgfile} -target / sleep 5 echo "`date`: Deleting package installer." >> ${logfile} # Remove downloaded installer rm /tmp/"${pkgfile}" } ############################################################## # Check if SwiftDialog is installed (SwiftDialog created by Bart Reardon https://github.com/bartreardon/swiftDialog) ############################################################## if ! command -v dialog &> /dev/null then echo "SwiftDialog is not installed. App will be installed now....." | tee -a "$LAPSLOG" sleep 2 DialogInstall else echo "SwiftDialog is installed. Checking installed version....." | tee -a "$LAPSLOG" installedVersion=$(dialog -v | sed 's/./ /6' | awk '{print $1}') latestVersion=$(curl -sfL "https://github.com/bartreardon/swiftDialog/releases/latest" | tr '"' "\n" | grep -i "expanded_assets" | head -1 | tr '/' ' ' | awk '{print $7}' | tr -d 'v') if [[ $installedVersion != $latestVersion ]]; then echo "Dialog needs updating" | tee -a "$LAPSLOG" DialogInstall else echo "Dialog is up to date. Continuing to assemble...." | tee -a "$LAPSLOG" fi sleep 3 fi ############################################################################ # API Credentials ############################################################################ encryptedcreds="$5" token=$(curl -s -H "Content-Type: application/json" -H "Authorization: Basic ${encryptedcreds}" -X POST "$4/api/v1/auth/token" | grep 'token' | tr -d '"',',' | sed -e 's#token :##' | xargs) ############################################################################ # Pop up for Device name ############################################################################ message=$(dialog \ --bannerimage "/Library/.LAPS/Branding/Wallpapers/GenericLapsBanner.png" \ --title "none" \ --icon "/Library/.LAPS/Branding/Icons/lock icon.png" --iconsize 100 \ --message "Please enter the name of the device you wish to see the LAPS password for. \n\n You must also provide a reason for viewing the LAPS Password for auditing." \ --messagefont "name=Arial,size=17" \ --button1text "Continue" \ --button2text "Quit" \ --textfield "Device name,required" \ --textfield "Reason,required" \ --ontop \ --regular \ --json \ --moveable ) name=$(echo $message | awk -F '"Device name" : "' '{print$2}' | awk -F '"' '{print$1}') reason=$(echo $message | awk -F '"Reason" : "' '{print$2}' | awk -F '"' '{print$1}') # Thanks to ons-mart https://github.com/ons-mart if [[ $name == "" ]] || [[ $reason == "" ]]; then echo "Aborting" exit 1 fi name2=$(echo $name | sed -e 's#’#%E2%80%99#g' -e 's# #%20#g') ############################################################################ # Grab decoder key for password ############################################################################ cryptkey=$(curl -s -X "GET" "$4/JSSResource/computers/name/$name2/subset/extension_attributes" -H "Accept: application/json" -H "Authorization:Bearer ${token}" | tr '{' '\n' | grep -i CryptKey | tr '"' ' ' | awk '{print $16}') ############################################################################ # Grab secret for decoder ############################################################################ secretkey=$(curl -s -X "GET" "$4/JSSResource/computers/name/$name2/subset/extension_attributes" -H "Accept: application/json" -H "Authorization:Bearer ${token}" | tr '{' '\n' | grep -i Secret | tr '"' ' ' | awk '{print $16}') ############################################################################ # Decode password and display ############################################################################ if [[ $cryptkey == "" ]] || [[ $secretkey == "" ]]; then echo "Aborting" dialog \ --bannerimage "/Library/.LAPS/Branding/Wallpapers/GenericLapsBanner.png" \ --title "none" \ --icon "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/AlertStopIcon.icns" \ --message "Device inventory not found. \n\nPlease make sure the device name is correct.\n\n$name2" \ --messagefont "name=Arial,size=17" \ --ontop \ --moveable \ --small exit 1 fi passwd=$(echo $cryptkey | openssl enc -aes-256-cbc -md sha512 -a -d -salt -pass pass:$secretkey) echo "$passwd" | pbcopy dialog \ --bannerimage "/Library/.LAPS/Branding/Wallpapers/GenericLapsBanner.png" \ --title "none" \ --icon "/Library/.LAPS/Branding/Icons/Open Lock Icon.png" --iconsize 100 \ --message "The LAPS Password for $name is: $passwd \n\n This message will close after 10seconds." \ --messagefont "name=Arial,size=17" \ --timer \ --ontop \ --moveable \ --small & echo "The LAPS Password for $name was viewed by $CURRENT_USER on $DEVICE" | tee -a "$LAPSLOG" echo "Reason for viewing password: $reason" | tee -a "$LAPSLOG" ############################################################################ # Slack notification ############################################################################ if [[ $7 == "" ]]; then echo "No slack URL configured" | tee -a "$LAPSLOG" else if [[ $SERVICEDESK == "" ]]; then SERVICEDESK="https://www.slack.com" fi echo "Sending slack Webhook" | tee -a "$LAPSLOG" curl -s -X POST -H 'Content-type: application/json' \ -d \ '{ "blocks": [ { "type": "header", "text": { "type": "plain_text", "text": "LAPS Password Requested:closed_lock_with_key:", } }, { "type": "divider" }, { "type": "section", "fields": [ { "type": "mrkdwn", "text": ">*Device Name:*\n>'"$name"'" }, { "type": "mrkdwn", "text": ">*Requested by:*\n>'"$CURRENT_USER"'" }, { "type": "mrkdwn", "text": ">*Reason for Request:*\n>'"$reason"'" }, ] }, { "type": "actions", "elements": [ { "type": "button", "text": { "type": "plain_text", "text": "Challenge Request", "emoji": true }, "style": "danger", "action_id": "actionId-0", "url": "'"$SERVICEDESK"'" } ] } ] }' \ $7 fi ############################################################################ # Final Decoder checks for password rotation ############################################################################ cycleMins="$6" if [[ $6 == "" ]]; then echo "Password rotation has not been set." | tee -a "$LAPSLOG" else cycleTime=$(date -v "+"$cycleMins"M" "+%m %d %H %M") MONTH=$(echo $cycleTime | awk '{print $1}') if [[ $MONTH == "0"* ]]; then MONTH=$(echo $MONTH | sed -e 's#0##') fi DAY=$(echo $cycleTime | awk '{print $2}') if [[ $DAY == "0"* ]]; then DAY=$(echo $DAY | sed -e 's#0##') fi HOUR=$(echo $cycleTime | awk '{print $3}') MINUTE=$(echo $cycleTime | awk '{print $4}') echo "Password rotation has been set to $6 Minutes. LAPS Password for $name will be reset at $HOUR:$MINUTE." | tee -a "$LAPSLOG" ############################################################################ # Teams notification ############################################################################ if [[ $9 == "" ]]; then echo "No teams Webhook configured" | tee -a "$LAPSLOG" else if [[ $SERVICEDESK == "" ]]; then SERVICEDESK="https://www.microsoft.com/en-us/microsoft-teams/" fi echo "Sending teams Webhook" | tee -a "$LAPSLOG" jsonPayload='{ "@type": "MessageCard", "@context": "http://schema.org/extensions", "themeColor": "0076D7", "summary": "Admin has been used", "sections": [{ "activityTitle": "Admin has been used on:'"$name"'/'"$DEVICE"'", "activitySubtitle": "Reason:'"$reason"'", "activityImage": "https://adaptivecards.io/content/cats/3.png", "facts": [{ "name": "Requested by:", "value": "'"$CURRENT_USER"'" }, { "name": "Reason", "value": "'"$reason"'" }, { "name": "Password will reset at:", "value": "'"$HOUR"':'"$MINUTE"'" }], "markdown": true }], "potentialAction": [{ "@type": "OpenUri", "name": "Report an Issue", "targets": [{ "os": "default", "uri": "'"$SERVICEDESK"'" }] }] }' # Send the JSON payload using curl curl -s -X POST -H "Content-Type: application/json" -d "$jsonPayload" "$9" fi ############################################################################ # Create plist to Cycle Password ############################################################################ plist="/Library/LaunchDaemons/com.LAPS.triggerCycle.plist" # Bootout old Launch Daemon launchctl bootout system $plist #Create the plist defaults write $plist Label -string "com.LAPS.triggerCycle.plist" #Add program argument to have it run the LAPS Policy defaults write $plist ProgramArguments -array -string "/usr/local/bin/jamf" -string "policy" -string "-event" -string "createLAPS" #Set the run inverval to run at specified time defaults write $plist StartCalendarInterval -dict Hour -int $HOUR Minute -int $MINUTE #Set run at load defaults write $plist RunAtLoad -boolean no #Set User to run as defaults write $plist UserName -string root #Set ownership chown root:wheel $plist chmod 644 $plist #Load the daemon if (( $OS > 11 )); then echo "OS version is Newer than OS11" launchctl bootstrap system $plist else echo "OS Version is 11 or older" launchctl load $plist fi sleep 5 fi exit 0