Forked from macsimom/active_directory_plug-in_helper.sh
Created
February 12, 2026 13:38
-
-
Save thimslugga/222ea28c47fdade38505449fc7db2563 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 hidden or 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