Created
March 11, 2025 22:09
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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