Skip to content

Instantly share code, notes, and snippets.

@macsimom
Created March 11, 2025 22:09
Show Gist options
  • Save macsimom/1ea6d54aa4a96e977f9c2ab2955ef422 to your computer and use it in GitHub Desktop.
Save macsimom/1ea6d54aa4a96e977f9c2ab2955ef422 to your computer and use it in GitHub Desktop.
An attempt at a bandaid for AD bound Macs that lose their bind due to corrupted credentials
#!/bin/bash
# version 1.4 - Simon Andersen
# set -x
export PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
DSCONFIGADOUTPUT="$(dsconfigad -show -xml)"
COMPUTERACCOUNT="$(/usr/libexec/PlistBuddy -c "Print ':General Info:Computer Account'" /dev/stdin <<<"$DSCONFIGADOUTPUT")"
if [[ -z "$COMPUTERACCOUNT" ]]; then
echo "Fatal error - No computer account name found"
exit 1
fi
DOMAIN="$(/usr/libexec/PlistBuddy -c "Print ':General Info:Active Directory Domain'" /dev/stdin <<<"$DSCONFIGADOUTPUT")"
DIGOUTPUT="$(dig -t SRV "_kerberos._tcp.$DOMAIN" +short)"
KERBEROSSERVER="$(sed -Ene 's/.+ .+ .+ (.+)\./\1/p' <<<"$DIGOUTPUT" | head -n1)"
KERBEROSSERVERPORT="$(sed -Ene 's/.+ .+ (.+) .+\./\1/p' <<<"$DIGOUTPUT" | head -n1)"
if [[ -z "$KERBEROSSERVER" ]] ; then
echo "Warning - No kerberos server found"
exit 0
fi
# 88 is the standard kerberos tcp port
if /usr/bin/nc -dvz -G 2 "$KERBEROSSERVER" "$KERBEROSSERVERPORT" &>/dev/null ; then
:
else
echo "Warning - Failed to reach $KERBEROSSERVER:$KERBEROSSERVERPORT"
exit 0
fi
ODSUBNODE="$(dscl localhost read /Active\ Directory SubNodes | sed -Ene 's/^SubNodes: (.*)/\1/p')"
ADNODE="/Active Directory/$ODSUBNODE"
REALM="$(tr '[:lower:]' '[:upper:]' <<<"$DOMAIN")"
function RETRIEVE_AD_CREDENTIALS() {
_ACCOUNT="$1"
_SERVICE="$2"
_LABEL="$3"
security find-generic-password -a "$_ACCOUNT" -s "$_SERVICE" -l "$_LABEL" -w /Library/Keychains/System.keychain 2>/dev/null
}
function STORE_AD_CREDENTIALS() {
_ACCOUNT="$1"
_SERVICE="$2"
_LABEL="$3"
_PASSWORD="$4"
while security delete-generic-password -a "$_ACCOUNT" -s "$_SERVICE" -l "$_LABEL" /Library/Keychains/System.keychain &>/dev/null ; do
:
done
security add-generic-password -a "$_ACCOUNT" -s "$_SERVICE" -l "$_LABEL" -A -w "$_PASSWORD" /Library/Keychains/System.keychain
}
function VERIFY_AD_CREDENTIALS() {
_PRINCIPAL="$1"
_PASSWORD="$2"
local RESULT
RESULT=1
if [[ -z "$_PASSWORD" ]]; then
return $RESULT
fi
KCACHE="$(uuidgen)"
kinit --cache="API:$KCACHE" --password-file=STDIN "$_PRINCIPAL" <<<"$_PASSWORD"
RESULT=$?
#echo "kinit: $RESULT"
#klist --cache="API:$KCACHE"
#echo "klist: $?"
kdestroy --cache="API:$KCACHE"
#echo "kdestroy: $?"
if [[ $RESULT -eq 0 ]]
then
PLIST="/Library/Preferences/ActiveDirectory.plist"
defaults write "$PLIST" LastLogonTimestamp -int "$(date -j +%s)" &>/dev/null
fi
return $RESULT
}
function RESET_OPENDIRECTORY() {
echo "Info - Killing opendirectoryd and flushing ds cache"
pkill -9 -x opendirectoryd
dscacheutil -flushcache
local i
local delay
local threshold
i=0
threshold=90
delay=3
while [[ $i -lt $threshold ]]
do
if dscl localhost read "${ADNODE}/All Domains/Computers/${COMPUTERACCOUNT}" RecordName &>/dev/null
then
break
else
sleep $delay
printf "."
i=$((i + delay))
fi
done
printf "\n"
if [[ $i -ge $threshold ]]
then
echo "Info - Timeout threshold for OD lookup exceeded"
else
echo "Info - Waited $i seconds for Active Directory plug-in to start responding"
fi
}
ADPASS="$(RETRIEVE_AD_CREDENTIALS "$COMPUTERACCOUNT" "$ADNODE" "$ADNODE")"
BACKUPADPASS="$(RETRIEVE_AD_CREDENTIALS "$COMPUTERACCOUNT - Backup" "$ADNODE - Backup" "$ADNODE - Backup")"
if VERIFY_AD_CREDENTIALS "$COMPUTERACCOUNT@$REALM" "$ADPASS" ; then
if [[ "$ADPASS" != "$BACKUPADPASS" ]]; then
echo "Info - Storing credentials backup"
STORE_AD_CREDENTIALS "$COMPUTERACCOUNT - Backup" "$ADNODE - Backup" "$ADNODE - Backup" "$ADPASS"
else
:
fi
else
if VERIFY_AD_CREDENTIALS "$COMPUTERACCOUNT@$REALM" "$BACKUPADPASS" ; then
echo "Info - Replacing stored AD credentials with backup"
STORE_AD_CREDENTIALS "$COMPUTERACCOUNT" "$ADNODE" "$ADNODE" "$BACKUPADPASS"
RESET_OPENDIRECTORY
else
if [[ -z "$ADPASS" && -z "$BACKUPADPASS" ]]; then
echo "Fatal error - No stored credentials found what so ever"
exit 2
else
echo "Fatal error - unable to verify backup credentials"
exit 1
fi
fi
fi
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment