Problem: Users cannot upload files into a write-only directory via samba -> NT_STATUS_ACCESS_DENIED

Problem

A Samba share contains directories that are intended to work as write-only drop boxes.

For example:

drwxrwx--- root  Domain Users /home/Laufwerk-T
drwx-wx--- user1 Domain Users /home/Laufwerk-T/user1

Members of Domain Users should be able to create files inside user1, but they should not be able to list its contents.

The directory permissions therefore provide:

  • Write permission to create files.
  • Execute permission to access known paths inside the directory.
  • No read permission, preventing directory listings.

This works correctly when accessing the directory locally on the file system. However, uploading a file through Samba fails:

smb: \> put test.txt user1/test.txt
NT_STATUS_ACCESS_DENIED opening remote file \user1\test.txt

Adding read permission to the directory makes the upload work, but defeats the intended write-only behavior.

Investigation

The share configuration contained settings similar to:

[share]
path = /home/Laufwerk-T
read only = no
create mask = 0660
directory mask = 0770
force create mode = 0660
force directory mode = 0770
nt acl support = no
vfs objects = acl_xattr

The file system permissions and group memberships were checked first:

getfacl -p /home/Laufwerk-T
getfacl -p /home/Laufwerk-T/user1

id <USERNAME>
wbinfo -r <USERNAME>

A local test executed as the affected user worked as expected:

runuser -u <USERNAME> -- sh -c '
    DIR=/home/Laufwerk-T/user1
    FILE="$DIR/.local-test-$$"

    if printf test > "$FILE"; then
        echo "File creation: successful"
        rm -f "$FILE"
    else
        echo "File creation: failed"
    fi

    echo "Directory listing should fail:"
    ls -la "$DIR"
'

The file was created successfully, while the directory listing failed with Permission denied.

This confirmed that:

  • The user had the required group membership.
  • The POSIX permissions and ACLs were correct.
  • The underlying file system supported the intended behavior.
  • The problem occurred only through Samba.

The Samba debug log was then examined:

/var/log/samba/log.smbd

The log showed that the failure occurred while Samba was resolving the parent directory, before the actual file creation:

smbd_smb2_create_send: name [user1\test.txt]
openat_pathref_fsp_nosymlink: path_in=user1
openat_pathref_fsp_nosymlink: SMB_VFS_OPENAT() failed: Permission denied
filename_convert_dirfsp_nosymlink:
opening directory user1 failed: NT_STATUS_ACCESS_DENIED

To identify the system call causing the failure, the smbd processes belonging to the affected connection were determined:

smbstatus -p | grep '<USERNAME>'

The corresponding processes were traced while reproducing the upload:

strace -ff -tt -s 256 \
    -e trace=openat,openat2 \
    -p <SMBD-PID-1> \
    -p <SMBD-PID-2> \
    -o /root/univention-support/smbd-open

While strace was running, the upload was executed through smbclient:

smb: \> put test.txt user1/test.txt

The trace was stopped with Ctrl+C and reviewed with:

cat /root/univention-support/smbd-open*

The relevant system call was:

openat(AT_FDCWD, "user1", O_RDONLY|O_NONBLOCK) = -1 EACCES

Samba was attempting to open the directory for reading. Because the directory intentionally did not provide read permission to the accessing user, the kernel correctly returned EACCES.

A separate test confirmed that opening the same directory with O_PATH worked:

runuser -u <USERNAME> -- python3 - <<'PY'
import os

path = "/home/Laufwerk-T/user1"

fd = os.open(path, os.O_PATH | os.O_NOFOLLOW)
print(f"O_PATH successful: fd={fd}")
os.close(fd)
PY

This ruled out a kernel, file-system, or general POSIX-permission problem.

Checking Samba’s effective path-handling configuration

The failure occurred inside Samba’s internal path resolution. The next step was therefore to inspect the Samba settings that influence symbolic-link handling and the VFS path-processing chain:

testparm -sv 2>/dev/null |
    grep -iE \
        'wide links|smb1 unix extensions|allow insecure wide links|vfs objects'

These settings were checked for the following reasons:

  • wide links controls whether Samba may follow symbolic links outside the exported share path. If this feature is effectively active, Samba uses different path-handling logic.
  • smb1 unix extensions influences whether Wide Links are actually enabled. When SMB1 Unix Extensions are enabled, Samba normally disables Wide Links for security reasons.
  • allow insecure wide links can override this protection and allow Wide Links to remain active even when SMB1 Unix Extensions are enabled.
  • vfs objects shows the configured VFS module chain. VFS modules can intercept and modify internal openat() operations and their flags.

The affected system showed the following relevant combination:

wide links = yes
smb1 unix extensions = no

The UCS Configuration Registry confirmed that Wide Links had been enabled globally:

ucr get samba/wide_links

Output:

true

The corresponding UCR setting was therefore:

samba/wide_links=true

On the working comparison system, wide links was also set to yes, but the surrounding global configuration differed:

wide links = yes
smb1 unix extensions = yes

In this combination, Samba internally disables Wide Links unless the following additional option is enabled:

allow insecure wide links = yes

Wide Links were therefore not effectively active on the working system, even though testparm displayed:

wide links = yes

Root Cause

The problem was not caused by wide links = yes alone.

The relevant configuration on the affected system was:

wide links = yes
smb1 unix extensions = no

Because SMB1 Unix Extensions were disabled, Samba did not apply the protection that normally disables Wide Links. Wide Links therefore remained effectively active.

When Wide Links are active, Samba uses the corresponding VFS path-handling code. During the internal resolution of the parent directory, this processing removes the O_PATH flag from the directory-open operation.

Under normal path-reference handling, Samba can use O_PATH to obtain a reference to the directory:

openat(..., "user1", O_RDONLY|O_NOFOLLOW|O_PATH)

O_PATH requires execute permission on the directory, but not read permission. This is compatible with a write-only directory using permissions such as 0730.

On the affected system, the effective Wide Links handling changed the operation to:

openat(..., "user1", O_RDONLY|O_NONBLOCK)

A regular O_RDONLY open requires read permission on the directory. Because the group intentionally had only write and execute permissions, the kernel returned:

EACCES (Permission denied)

Samba then aborted path resolution before reaching the actual file-creation operation and returned:

NT_STATUS_ACCESS_DENIED

The effective sequence was:

wide links = yes
smb1 unix extensions = no
        |
        v
Wide Links remain effectively active
        |
        v
The Wide Links VFS path removes O_PATH
        |
        v
Samba opens the parent directory using O_RDONLY
        |
        v
The directory has write and execute permissions, but no read permission
        |
        v
The kernel returns EACCES
        |
        v
Samba returns NT_STATUS_ACCESS_DENIED

On the working comparison system, the configuration behaved differently:

wide links = yes
smb1 unix extensions = yes
allow insecure wide links = no
        |
        v
Samba internally disables Wide Links
        |
        v
O_PATH remains in use
        |
        v
Only execute permission is required
        |
        v
The file can be created successfully

Enabling SMB1 Unix Extensions should not be used as the solution to this issue. The direct and safer solution is to disable Wide Links where they are not required.

Solution

Disable wide links either for the affected share or globally.

Disable Wide Links for a single share

This is the preferred option when Wide Links may still be required by other shares.

Add the following custom Samba setting to the affected UCS share:

wide links = no

For example:

udm shares/share modify \
    --dn '<SHARE-DN>' \
    --append sambaCustomSettings='wide links no'

If a custom wide links setting already exists on the share, modify or remove the existing value instead of adding a duplicate setting.

Check the effective configuration of the affected share:

testparm -sv 2>/dev/null |
    sed -n '/^\[<SHARE-NAME>\]$/,/^\[/p' |
    grep -iE 'path|wide links|vfs objects'

The share should show:

wide links = No

Disable Wide Links globally

If Wide Links are not required by any Samba share on the system, remove the global UCS Configuration Registry setting:

ucr unset samba/wide_links

This change applies to all Samba shares on the system.

Verify that the UCR setting has been removed:

ucr get samba/wide_links

The command should return no value.

The complete effective Samba configuration can then be checked with:

testparm -sv 2>/dev/null |
    grep -iE \
        'wide links|smb1 unix extensions|allow insecure wide links|vfs objects'

Apply the change

Restart Samba:

systemctl restart samba

Existing SMB connections must then be closed and re-established.

After reconnecting, the expected behavior is restored:

  • Users can create files inside the directory.
  • Users cannot list the directory contents.
  • Permissions such as 0730 can be retained.
  • Additional read permission is not required.

This topic was automatically closed after 24 hours. New replies are no longer allowed.