Das Problem

Du hast einen UCS Domain Controller erfolgreich demoted. Samba ist gestoppt, der neue DC läuft, FSMO-Rollen sind übertragen. Alles gut, oder?

Dann rufst du auf deinem Member Server wbinfo -i administrator auf:

failed to call wbcGetpwnam: WBC_ERR_DOMAIN_NOT_FOUND
Could not get info for user administrator

SMB-Freigaben sind nicht erreichbar. /etc/ldap/ldap.conf zeigt auf den alten, toten DC:

URI ldap://dc-vader.darkside.lan:7389 ldap://dc-obiwan.darkside.lan:7389

Logisch. dc-vader ist der demoted DC, dc-obiwan der neue Primary. Also schnell fixen:

ucr set ldap/server/name='dc-obiwan.darkside.lan'

Und dann das:

W: ldap/server/name is overridden by scope "ldap"

ucr get ldap/server/name gibt immer noch dc-vader.darkside.lan zurück. Facepalm.


Die Diagnose

Schritt 1: UCR scope “ldap” verstehen

Der Scope-Override bedeutet: Eine LDAP-Policy vom DC überschreibt den lokalen UCR-Wert. Also Policy prüfen:

# Auf dem Primary DC (dc-obiwan):
udm policies/ldapserver list
DN: cn=default-settings,cn=ldap,cn=policies,dc=darkside,dc=lan
  ldapServer: dc-vader.darkside.lan    ← da ist er!
  ldapServer: dc-obiwan.darkside.lan

Policy fixen — dc-vader entfernen:

udm policies/ldapserver modify \
  --dn "cn=default-settings,cn=ldap,cn=policies,dc=darkside,dc=lan" \
  --remove ldapServer="dc-vader.darkside.lan"

Listener auf dem Member Server neu starten… und ldap/server/name zeigt immer noch auf dc-vader.

Hä?

Schritt 2: Den echten Täter finden — ldap_server.py

Zeit, tiefer zu graben. Was setzt ldap/server/name überhaupt?

cat /usr/lib/univention-directory-listener/system/ldap_server.py

Der relevante Teil:

filter = '(&(objectClass=univentionDomainController)(|(univentionServerRole=master)(univentionServerRole=backup)))'

def add_ldap_server(ucr, name, domain, role):
    if role == 'master':
        old_master = ucr.get('ldap/master')
        changes = ['ldap/master=%s' % server_name]
        if ucr.get('ldap/server/name') == old_master:
            changes.append('ldap/server/name=%s' % server_name)
        univention.config_registry.handler_set(changes)

Der Listener liest beim Start alle DC-Objekte mit univentionServerRole=master oder backup aus dem LDAP — und setzt ldap/server/name daraus. Nicht aus der Policy, nicht aus UCR: aus den DC-Objekten.

Schritt 3: Das DC-Objekt des alten DC prüfen

# Auf dc-obiwan:
ldapsearch -x -H ldap://localhost:7389 \
  -D "cn=admin,dc=darkside,dc=lan" -w "$(cat /etc/ldap.secret)" \
  -b "cn=dc,cn=computers,dc=darkside,dc=lan" \
  "(|(univentionServerRole=master)(univentionServerRole=backup))" \
  dn univentionServerRole cn
dn: cn=dc-vader,cn=dc,cn=computers,dc=darkside,dc=lan
univentionServerRole: master          ← da ist der echte Täter!

dn: cn=dc-obiwan,cn=dc,cn=computers,dc=darkside,dc=lan
univentionServerRole: backup

dc-vader hat noch univentionServerRole=master im OpenLDAP — obwohl er seit Wochen demoted ist.

samba-tool domain demote entfernt das Samba-AD-Objekt. Das UCS-OpenLDAP-Objekt unter cn=dc,cn=computers bleibt unberührt. Und solange dc-vader als master im LDAP steht, setzt der Listener auf allen Member Servern beim Start ldap/server/name=dc-vader.darkside.lan.


Die Ursache

UCS hat zwei getrennte Verzeichnisse:

VerzeichnisPortInhaltGeändert durch
Samba4 AD389AD-Objekte, Kerberos, GPOssamba-tool domain demote
OpenLDAP (UCS)7389UCS-Computer-Objekte, Policies, UCRudm computers/...

samba-tool domain demote bereinigt das Samba-AD. Das UCS-OpenLDAP-Objekt (cn=dc-vader,cn=dc,cn=computers,... mit univentionServerRole=master) bleibt stehen. Das ist der blinde Fleck.

Der ldap_server.py Listener-Filter:

'(&(objectClass=univentionDomainController)(|(univentionServerRole=master)(univentionServerRole=backup)))'

…trifft weiterhin auf dc-vader zu. Beim Listener-Start auf dem Member Server wird ldap/server/name erneut auf dc-vader gesetzt — Policy-Cleanup hin oder her.


Die Lösung

1. Backup (immer!)

# Auf dc-obiwan:
ldapsearch -x -H ldap://localhost:7389 \
  -D "cn=admin,dc=darkside,dc=lan" -w "$(cat /etc/ldap.secret)" \
  -b "dc=darkside,dc=lan" \
  "(|(cn=dc-vader)(univentionServerRole=master))" \
  -LLL > /root/dc-vader-ldap-backup-$(date +%Y%m%d).ldif

2. UDM DC-Objekt entfernen

udm computers/domaincontroller_master remove \
  --dn "cn=dc-vader,cn=dc,cn=computers,dc=darkside,dc=lan"
Object removed: cn=dc-vader,cn=dc,cn=computers,dc=darkside,dc=lan

3. Verifizieren: Nur noch aktive DCs

ldapsearch -x -H ldap://localhost:7389 \
  -D "cn=admin,dc=darkside,dc=lan" -w "$(cat /etc/ldap.secret)" \
  -b "cn=dc,cn=computers,dc=darkside,dc=lan" \
  "(univentionServerRole=*)" dn univentionServerRole -LLL

Erwartung: Nur noch dc-obiwan (und eventuelle Replica DCs).

4. Listener auf dem Member Server neu starten

# Auf dem Member Server (z.B. srv-r2d2):
systemctl restart univention-directory-listener
sleep 15
ucr get ldap/server/name
# Erwartung: dc-obiwan.darkside.lan

5. Dienste neu starten und testen

ucr commit /etc/ldap/ldap.conf /etc/samba/smb.conf /etc/krb5.conf
systemctl restart winbind nmbd smbd

# Tests:
net ads testjoin          # Join is OK
wbinfo -t                 # trust succeeded
wbinfo -i 'DARKSIDE+administrator'  # Achtung: Winbind separator ist +, nicht \!

Lessons Learned

Checkliste nach einem UCS DC-Demote

Nach samba-tool domain demote IMMER prüfen:

[ ] UDM DC-Objekt des alten DC entfernen:
    udm computers/domaincontroller_master remove --dn "cn=<alter-dc>,..."

[ ] LDAP-Policy prüfen und bereinigen:
    udm policies/ldapserver list
    → Alle Referenzen auf den alten DC entfernen

[ ] Listener auf allen Member Servern neu starten:
    systemctl restart univention-directory-listener

[ ] DNS-Bereinigung (SRV-Records!):
    samba_dnsupdate --all-names
    → srvdc01-Einträge manuell aus _ldap._tcp, _kerberos._tcp entfernen
    → _domaincontroller_master._tcp für neuen DC anlegen

[ ] ucr get ldap/server/name auf Member Servern prüfen

Warum ucr set nicht hilft

ucr set ldap/server/name=... mit der Warnung W: overridden by scope "ldap" ist ein Symptom, kein Problem. Den UCR-Wert zu forcen würde beim nächsten Listener-Restart wieder überschrieben. Die Ursache (DC-Objekt im LDAP) muss behoben werden.

Winbind separator = +

In UCS-Member-Setups ist der Winbind-Separator standardmäßig +, nicht \. Also:

wbinfo -i 'DARKSIDE+administrator'   # ✅ funktioniert
wbinfo -i 'DARKSIDE\administrator'   # ❌ WBC_ERR_DOMAIN_NOT_FOUND

Das ist verwirrend, wenn man von reinen Windows-Umgebungen kommt.


Referenzen