SYSVOL Synchronization Fails Between Primary and Backup DC
Summary
In a Univention Corporate Server (UCS) domain, SYSVOL data is required for Windows clients to access Group Policy Objects (GPOs) and logon scripts via the SMB shares:
\\<domain>\SYSVOL\\<domain>\NETLOGON
In this case, SYSVOL synchronization from the Primary Directory Node to a Backup Directory Node was failing. As a result, Windows clients that authenticated against the Backup DC received empty SYSVOL and NETLOGON shares, leading to missing GPOs and unexpected client behavior.
The root cause was identified as incorrect filesystem permissions on the SYSVOL sync cache directory.
Environment
- UCS 5.2
- Samba 4 Active Directory domain
- One Primary Directory Node
- One Backup Directory Node
- Windows clients authenticating dynamically against different DCs
All hostnames and domain names in this article are intentionally anonymized.
Problem Description
Windows clients access SYSVOL and NETLOGON using the domain UNC path:
\\<domain>\SYSVOL
\\<domain>\NETLOGON
Depending on DNS and site awareness, the domain name (\\<domain>) resolves either to the Primary DC or a Backup DC.
Observed Behavior
-
Clients authenticating against the Primary DC received the expected SYSVOL and GPO content.
-
Clients authenticating against the Backup DC saw empty SYSVOL and NETLOGON shares.
-
Direct access showed inconsistent results:
\\<primary-dc>\SYSVOL→ content present\\<backup-dc>\SYSVOL→ empty
This indicated that SYSVOL replication to the Backup DC was not working correctly.
Investigation
Debugging the SYSVOL Sync Script
The UCS SYSVOL synchronization is handled by the script:
/usr/share/univention-samba4/scripts/sysvol-sync.sh
Running the script with Bash debug output revealed where the process failed:
bash -x /usr/share/univention-samba4/scripts/sysvol-sync.sh
Key Error Messages
During execution, the script failed while trying to place a trigger file on the upstream DC:
mkdir: cannot create directory ‘/var/cache/univention-samba4/sysvol-sync’: Permission denied
touch: cannot touch ‘/var/cache/univention-samba4/sysvol-sync/.trigger/<hostname>’: Permission denied
This step uses machine account authentication (<hostname>$) via univention-ssh to create trigger files on the remote DC.
Failure at this stage prevents any subsequent rsync-based SYSVOL synchronization.
Full Error Message
root@ucs5backup.univention.de:/home/admin #bash -x /usr/share/univention-samba4/scripts/sysvol-sync.sh
+ . /usr/share/univention-lib/ucr.sh
++ /usr/sbin/univention-config-registry shell hostname samba4/sysvol/sync/host domainname
+ eval 'domainname=univention.de
hostname=ucs5backup
samba4_sysvol_sync_host=ucs5primary'
++ domainname=univention.de
++ hostname=ucs5backup
++ samba4_sysvol_sync_host=ucs5primary
+ DEBUG=false
+ SYSVOL_PATH=/var/lib/samba/sysvol
+ SYSVOL_SYNCDIR=/var/cache/univention-samba4/sysvol-sync
+ SYSVOL_SYNC_TRIGGERDIR=/var/cache/univention-samba4/sysvol-sync/.trigger
+ PROCESS_LOCKFILE=/var/lock/sysvol-sync-process
+ SYSVOL_LOCKFILE=/var/lock/sysvol-sync-dir
+ LC_ALL=C
+ flock -n 9
+ '[' -d /var/cache/univention-samba4/sysvol-sync/.trigger ']'
+ chgrp 'DC Slave Hosts' /var/cache/univention-samba4/sysvol-sync/.trigger
+ chmod g+w /var/cache/univention-samba4/sysvol-sync/.trigger
+ is_ucr_true samba4/sysvol/sync/debug
+ local value
++ /usr/sbin/univention-config-registry get samba4/sysvol/sync/debug
+ value=
+ case "$(echo -n "$value" | tr '[:upper:]' '[:lower:]')" in
++ echo -n ''
++ tr '[:upper:]' '[:lower:]'
+ return 2
+ is_ucr_true samba4/sysvol/sync/setfacl/AU
+ local value
++ /usr/sbin/univention-config-registry get samba4/sysvol/sync/setfacl/AU
+ value=false
+ case "$(echo -n "$value" | tr '[:upper:]' '[:lower:]')" in
++ echo -n false
++ tr '[:upper:]' '[:lower:]'
+ return 1
+ '[' '!' 1 -eq 1 ']'
+ '[' '' = --overwrite-local ']'
+ default_rsync_options=("-auAX" --filter='-xr! security.NTACL' "--dirs-update")
+ touch /var/lock/sysvol-sync-dir
+ chgrp 'DC Slave Hosts' /var/lock/sysvol-sync-dir
+ chmod g+w /var/lock/sysvol-sync-dir
+ sync_from_active_downstream_DCs
+ is_ucr_false samba4/sysvol/sync/from_downstream
+ local value
++ /usr/sbin/univention-config-registry get samba4/sysvol/sync/from_downstream
+ value=
+ case "$(echo -n "$value" | tr '[:upper:]' '[:lower:]')" in
++ echo -n ''
++ tr '[:upper:]' '[:lower:]'
+ return 2
++ find /var/cache/univention-samba4/sysvol-sync/.trigger -mindepth 1 -maxdepth 1 -type f
+ sync_from_upstream_DC
+ for s4dc in $samba4_sysvol_sync_host
+ '[' ucs5primary = ucs5backup ']'
+ log_prefix=ucs5primary
+ importdir=/var/cache/univention-samba4/sysvol-sync/.ucs5primary
+ remote_login='ucs5backup$@ucs5primary'
+ trigger_upstream_sync 'ucs5backup$@ucs5primary'
+ local 'remote_login=ucs5backup$@ucs5primary'
+ stderr_log_debug '[ucs5primary] placing triggerfile.'
+ false
++ univention-ssh --no-split /etc/machine.secret 'ucs5backup$@ucs5primary' -o ServerAliveInterval=15 'mkdir -p "/var/cache/univention-samba4/sysvol-sync/.trigger"; touch "/var/cache/univention-samba4/sysvol-sync/.trigger/ucs5backup"'
+ out='Could not chdir to home directory /dev/null: Not a directory
mkdir: das Verzeichnis „/var/cache/univention-samba4/sysvol-sync“ kann nicht angelegt werden: Keine Berechtigung
touch: '\''/var/cache/univention-samba4/sysvol-sync/.trigger/ucs5backup'\'' kann nicht berührt werden: Keine Berechtigung'
+ rsync_exitcode=1
+ '[' 1 -ne 0 ']'
+ stderr_log_error '[ucs5primary] placing triggerfile with ssh failed with 1. (Could not chdir to home directory /dev/null: Not a directory
mkdir: das Verzeichnis „/var/cache/univention-samba4/sysvol-sync“ kann nicht angelegt werden: Keine Berechtigung
touch: '\''/var/cache/univention-samba4/sysvol-sync/.trigger/ucs5backup'\'' kann nicht berührt werden: Keine Berechtigung)'
+ log ERROR '[ucs5primary] placing triggerfile with ssh failed with 1. (Could not chdir to home directory /dev/null: Not a directory
mkdir: das Verzeichnis „/var/cache/univention-samba4/sysvol-sync“ kann nicht angelegt werden: Keine Berechtigung
touch: '\''/var/cache/univention-samba4/sysvol-sync/.trigger/ucs5backup'\'' kann nicht berührt werden: Keine Berechtigung)'
+ local 'msg=[ucs5primary] placing triggerfile with ssh failed with 1. (Could not chdir to home directory /dev/null: Not a directory
mkdir: das Verzeichnis „/var/cache/univention-samba4/sysvol-sync“ kann nicht angelegt werden: Keine Berechtigung
touch: '\''/var/cache/univention-samba4/sysvol-sync/.trigger/ucs5backup'\'' kann nicht berührt werden: Keine Berechtigung)'
++ date '+%F %T'
+ builtin echo '2026-01-02 10:17:33 ERROR [ucs5primary] placing triggerfile with ssh failed with 1. (Could not chdir to home directory /dev/null: Not a directorymkdir: das Verzeichnis „/var/cache/univention-samba4/sysvol-sync“ kann nicht angelegt werden: Keine Berechtigungtouch: '\''/var/cache/univention-samba4/sysvol-sync/.trigger/ucs5backup'\'' kann nicht berührt werden: Keine Berechtigung)'
2026-01-02 10:17:33 ERROR [ucs5primary] placing triggerfile with ssh failed with 1. (Could not chdir to home directory /dev/null: Not a directorymkdir: das Verzeichnis „/var/cache/univention-samba4/sysvol-sync“ kann nicht angelegt werden: Keine Berechtigungtouch: '/var/cache/univention-samba4/sysvol-sync/.trigger/ucs5backup' kann nicht berührt werden: Keine Berechtigung)
+ return 1
+ stderr_log_error '[ucs5primary] Placing a trigger file failed.'
+ log ERROR '[ucs5primary] Placing a trigger file failed.'
+ local 'msg=[ucs5primary] Placing a trigger file failed.'
++ date '+%F %T'
+ builtin echo '2026-01-02 10:17:33 ERROR [ucs5primary] Placing a trigger file failed.'
2026-01-02 10:17:33 ERROR [ucs5primary] Placing a trigger file failed.
+ continue
Additional Check
It’s possible to connect with the machine account and the machine secret via ssh, to the Primary Node. Thats exactly what in the sysvol-sync.sh script done.
root@ucs5backup:~# less /etc/machine.secret
6mPa4rofoT0vKbgWUzAx
root@ucs5backup:~# ssh 'ucs5backup$@ucs5primary'
(ucs5backup$@ucs5primary) Password:
Univention Primary Directory Node 5.2-4:
The UCS management system is available at https://ucs5primary.univention.intranet/ (10.200.30.50)
You can log into the Univention Management Console - the main tool to manage
users, groups, etc. - using the "Administrator" account and the password selected
for the root user on the Primary Directory Node.
Last login: Fri Jan 2 16:08:17 2026 from 10.200.30.51
Could not chdir to home directory /dev/null: Not a directory
$
$ whoami
ucs5backup$
$ cd /var/cache/univention-samba4
$ pwd
/var/cache/univention-samba4
$ ls
sysvol-sync sysvol-sync_bak_univention-support
$ ls -la
total 16
drwxr-xr-x 4 root root 4096 Dec 19 16:51 .
drwxr-xr-x 41 root root 4096 Oct 1 13:05 ..
drwx------ 4 root root 4096 Dec 29 09:10 sysvol-sync
drwx------ 4 root root 4096 Dec 19 16:21 sysvol-sync_bak_univention-support
$ cd sysvol-sync
-sh: 6: cd: can't cd to sysvol-sync
$ ls
sysvol-sync sysvol-sync_bak_univention-support
$ cd sysvol-sync/.trigger
-sh: 8: cd: can't cd to sysvol-sync/.trigger
Root Cause
The directory on the Primary Node used for SYSVOL synchronization caching had incorrect permissions.
Affected Directory
/var/cache/univention-samba4/sysvol-sync
Incorrect Permissions
root@ucs5primary:~# ls -lah /var/cache/univention-samba4/
total 12K
drwxr-xr-x 3 root root 4,0K 11. Sep 07:51 .
drwxr-xr-x 29 root root 4,0K 6. Okt 16:43 ..
drwxr----- 4 root root 4,0K 13. Sep 12:36 sysvol-sync
Mode 700 prevented access by the DC Slave Hosts group, which is required for machine account–based synchronization.
Solution
Correct the Directory Permissions
The directory must be readable and executable by other users (mode 755):
chmod 755 /var/cache/univention-samba4/sysvol-sync
Verify Permissions
root@ucs5primary:~# ls -lah /var/cache/univention-samba4/
total 12K
drwxr-xr-x 3 root root 4,0K 11. Sep 07:51 .
drwxr-xr-x 29 root root 4,0K 6. Okt 16:43 ..
drwxr-xr-x 4 root root 4,0K 13. Sep 12:36 sysvol-sync
Verification
After fixing the permissions, rerun the SYSVOL sync script on the Backup DC:
bash -x /usr/share/univention-samba4/scripts/sysvol-sync.sh
root@ucs5backup:~# bash -x /usr/share/univention-samba4/scripts/sysvol-sync.sh
+ . /usr/share/univention-lib/ucr.sh
++ /usr/sbin/univention-config-registry shell hostname samba4/sysvol/sync/host domainname
+ eval 'domainname=univention.intranet
hostname=ucs5backup
samba4_sysvol_sync_host=ucs5primary'
++ domainname=univention.intranet
++ hostname=ucs5backup
++ samba4_sysvol_sync_host=ucs5primary
+ DEBUG=false
+ SYSVOL_PATH=/var/lib/samba/sysvol
+ SYSVOL_SYNCDIR=/var/cache/univention-samba4/sysvol-sync
+ SYSVOL_SYNC_TRIGGERDIR=/var/cache/univention-samba4/sysvol-sync/.trigger
+ PROCESS_LOCKFILE=/var/lock/sysvol-sync-process
+ SYSVOL_LOCKFILE=/var/lock/sysvol-sync-dir
+ LC_ALL=C
+ flock -n 9
+ '[' -d /var/cache/univention-samba4/sysvol-sync/.trigger ']'
+ chgrp 'DC Slave Hosts' /var/cache/univention-samba4/sysvol-sync/.trigger
+ chmod g+w /var/cache/univention-samba4/sysvol-sync/.trigger
+ is_ucr_true samba4/sysvol/sync/debug
+ local value
++ /usr/sbin/univention-config-registry get samba4/sysvol/sync/debug
+ value=
+ case "$(echo -n "$value" | tr '[:upper:]' '[:lower:]')" in
++ echo -n ''
++ tr '[:upper:]' '[:lower:]'
+ return 2
+ is_ucr_true samba4/sysvol/sync/setfacl/AU
+ local value
++ /usr/sbin/univention-config-registry get samba4/sysvol/sync/setfacl/AU
+ value=false
+ case "$(echo -n "$value" | tr '[:upper:]' '[:lower:]')" in
++ tr '[:upper:]' '[:lower:]'
++ echo -n false
+ return 1
+ '[' '!' 1 -eq 1 ']'
+ '[' '' = --overwrite-local ']'
+ default_rsync_options=("-auAX" --filter='-xr! security.NTACL' "--dirs-update")
+ touch /var/lock/sysvol-sync-dir
+ chgrp 'DC Slave Hosts' /var/lock/sysvol-sync-dir
+ chmod g+w /var/lock/sysvol-sync-dir
+ sync_from_active_downstream_DCs
+ is_ucr_false samba4/sysvol/sync/from_downstream
+ local value
++ /usr/sbin/univention-config-registry get samba4/sysvol/sync/from_downstream
+ value=
+ case "$(echo -n "$value" | tr '[:upper:]' '[:lower:]')" in
++ echo -n ''
++ tr '[:upper:]' '[:lower:]'
+ return 2
++ find /var/cache/univention-samba4/sysvol-sync/.trigger -mindepth 1 -maxdepth 1 -type f
+ sync_from_upstream_DC
+ for s4dc in $samba4_sysvol_sync_host
+ '[' ucs5primary = ucs5backup ']'
+ log_prefix=ucs5primary
+ importdir=/var/cache/univention-samba4/sysvol-sync/.ucs5primary
+ remote_login='ucs5backup$@ucs5primary'
+ trigger_upstream_sync 'ucs5backup$@ucs5primary'
+ local 'remote_login=ucs5backup$@ucs5primary'
+ stderr_log_debug '[ucs5primary] placing triggerfile.'
+ false
++ univention-ssh --no-split /etc/machine.secret 'ucs5backup$@ucs5primary' -o ServerAliveInterval=15 'mkdir -p "/var/cache/univention-samba4/sysvol-sync/.trigger"; touch "/var/cache/univention-samba4/sysvol-sync/.trigger/ucs5backup"'
+ out='Could not chdir to home directory /dev/null: Not a directory'
+ rsync_exitcode=0
+ '[' 0 -ne 0 ']'
+ is_ucr_false samba4/sysvol/sync/from_upstream
+ local value
++ /usr/sbin/univention-config-registry get samba4/sysvol/sync/from_upstream
+ value=
+ case "$(echo -n "$value" | tr '[:upper:]' '[:lower:]')" in
++ echo -n ''
++ tr '[:upper:]' '[:lower:]'
+ return 2
+ stderr_log_debug '[ucs5primary] rsync check for changes on upstream DC'
+ false
+ rsync_options=("${default_rsync_options[@]}" --delete)
+ check_if_need_sync 'ucs5backup$@ucs5primary' /var/cache/univention-samba4/sysvol-sync/.ucs5primary -auAX '--filter=-xr! security.NTACL' --dirs-update --delete
+ local 'remote_login=ucs5backup$@ucs5primary'
+ shift
+ local dst=/var/cache/univention-samba4/sysvol-sync/.ucs5primary
+ shift
+ rsync_options=('-auAX' '--filter=-xr! security.NTACL' '--dirs-update' '--delete')
+ local rsync_options
+ local need_sync
+ local 'src=ucs5backup$@ucs5primary:/var/lib/samba/sysvol'
++ univention-ssh-rsync --no-split /etc/machine.secret --dry-run -v -auAX '--filter=-xr! security.NTACL' --dirs-update --delete 'ucs5backup$@ucs5primary:/var/lib/samba/sysvol/' /var/cache/univention-samba4/sysvol-sync/.ucs5primary
++ tail --lines=+2
++ head --lines=-3
+ need_sync=
+ '[' -n '' ']'
+ stderr_log_debug '[ucs5primary] No upstream changes.'
+ false
+ all_files_and_dirs_have_acls /var/cache/univention-samba4/sysvol-sync/.ucs5primary ucs5primary
+ local dir=/var/cache/univention-samba4/sysvol-sync/.ucs5primary/univention.intranet/Policies
+ shift
+ local host=ucs5primary
+ '[' -d /var/cache/univention-samba4/sysvol-sync/.ucs5primary/univention.intranet/Policies ']'
+ stderr_log_debug '[ucs5primary] checking ACL'\''s'
+ false
++ getfacl -span -R /var/cache/univention-samba4/sysvol-sync/.ucs5primary/univention.intranet/Policies
++ sed -ne 's/^# file: //p'
++ sort
++ md5sum
+ a_md5='59cc15e1481132df7e54768c53664d9e -'
++ find /var/cache/univention-samba4/sysvol-sync/.ucs5primary/univention.intranet/Policies -type f -o -type d
++ sort
++ md5sum
+ f_md5='59cc15e1481132df7e54768c53664d9e -'
+ '[' '59cc15e1481132df7e54768c53664d9e -' '!=' '59cc15e1481132df7e54768c53664d9e -' ']'
+ return 0
+ hot_sync_rsync_options=('-auAX' '--filter=-xr! security.NTACL' '--dirs-update')
+ local hot_sync_rsync_options
+ is_ucr_true samba4/sysvol/sync/from_upstream/delete
+ local value
++ /usr/sbin/univention-config-registry get samba4/sysvol/sync/from_upstream/delete
+ value=
+ case "$(echo -n "$value" | tr '[:upper:]' '[:lower:]')" in
++ echo -n ''
++ tr '[:upper:]' '[:lower:]'
+ return 2
+ sync_to_local_sysvol /var/cache/univention-samba4/sysvol-sync/.ucs5primary -auAX '--filter=-xr! security.NTACL' --dirs-update
+ local importdir=/var/cache/univention-samba4/sysvol-sync/.ucs5primary
+ shift
+ rsync_options=('-auAX' '--filter=-xr! security.NTACL' '--dirs-update')
+ local rsync_options
+ is_ucr_true samba4/sysvol/sync/from_upstream/delete
+ local value
++ /usr/sbin/univention-config-registry get samba4/sysvol/sync/from_upstream/delete
+ value=
+ case "$(echo -n "$value" | tr '[:upper:]' '[:lower:]')" in
++ echo -n ''
++ tr '[:upper:]' '[:lower:]'
+ return 2
+ sync_to_local_sysvol /var/cache/univention-samba4/sysvol-sync/.ucs5primary -auAX '--filter=-xr! security.NTACL' --dirs-update
+ local importdir=/var/cache/univention-samba4/sysvol-sync/.ucs5primary
+ shift
+ rsync_options=('-auAX' '--filter=-xr! security.NTACL' '--dirs-update')
+ local rsync_options
+ stderr_log_debug '[ucs5primary] local sync from importdir to sysvol'
+ false
+ stderr_log_debug '[ucs5primary] trying to get exclusive (write) lock on local sysvol'
+ false
+ timeout=60
+ flock --timeout=60 8
++ rsync -auAX '--filter=-xr! security.NTACL' --dirs-update /var/cache/univention-samba4/sysvol-sync/.ucs5primary/ /var/lib/samba/sysvol
+ out=
+ rsync_exitcode=0
+ '[' 0 -ne 0 ']'
+ is_ucr_true samba4/sysvol/sync/fix_gpt_ini
+ local value
++ /usr/sbin/univention-config-registry get samba4/sysvol/sync/fix_gpt_ini
+ value=
+ case "$(echo -n "$value" | tr '[:upper:]' '[:lower:]')" in
++ echo -n ''
++ tr '[:upper:]' '[:lower:]'
+ return 2
Expected Result
-
Trigger files can be created successfully on the upstream DC
-
rsync completes without errors
-
SYSVOL content is replicated to the Backup DC
-
Windows clients logging in via the Backup DC can access:
\\<domain>\SYSVOL\\<domain>\NETLOGON
-
GPOs apply correctly regardless of which DC handles authentication
Conclusion
SYSVOL synchronization in UCS relies on correct filesystem permissions for its internal cache and trigger directories.
If permissions on /var/cache/univention-samba4/sysvol-sync are too restrictive, SYSVOL replication fails silently, resulting in empty SYSVOL shares on Backup DCs.
Ensuring the directory has mode 755 restores proper synchronization and prevents GPO-related issues on Windows clients.
Additional Notes
-
The message
Could not chdir to home directory /dev/null: Not a directorywhen using
univention-sshwith machine accounts is expected and tracked in Bug 23136.