DEV Community

Tony Miller
Tony Miller

Posted on

Mounting a Mac's SMB share from Linux without gutting the Mac's security

Lost an evening to this, so you don't have to.

The fix everyone hands you is a single checkbox that quietly downgrades how your Mac stores its password. The clean alternative — Kerberos, the exact thing your iPhone already uses — is "impossible" according to three sources I dug up, one of them Apple's own Heimdal source. They're wrong. What follows is the whole path: why it breaks, why the popular fix is the bad one, and the two setups that actually work (a one-shot command and a hands-off automount).

My Mac mini shares a folder over SMB. My iPhone mounts it fine. My Linux box:

$ smbclient -L 192.168.0.153 -U tmlr%remote
session setup failed: NT_STATUS_LOGON_FAILURE
Enter fullscreen mode Exit fullscreen mode

Same username, same password, rejected. Every "fix" on the internet ends with "turn on Windows File Sharing for that user on the Mac." That works, and it's the wrong answer. Here's why, and what to do instead.

The problem

The credentials are correct — the iPhone's connecting just fine. The handshake even completes; run it with -d3 and you'll see the full NTLMSSP exchange finish before the Mac rejects you. So this isn't networking, isn't the password, isn't the SMB dialect. It's authentication, and only Linux hits it.

Why: two doors, one account

macOS keeps several credentials for a local account, not one. Look:

$ dscl . -read /Users/tmlr AuthenticationAuthority
AuthenticationAuthority: ;ShadowHash;HASHLIST:<SALTED-SHA512-PBKDF2,SRP-RFC5054-4096-SHA512-PBKDF2>
 ;Kerberosv5;;tmlr@LKDC:SHA1.XXXX;LKDC:SHA1.XXXX;
Enter fullscreen mode Exit fullscreen mode

Two things matter in there:

  • HASHLIST is SALTED-SHA512-PBKDF2 (login) and an SRP verifier. There is no NT hash.
  • There's a Kerberosv5 identity in a realm called LKDC:SHA1.<40 hex>.

SMB auth has two doors into this account:

  • NTLMv2 — validates against a stored NT hash. Linux smbclient and mount.cifs knock here.
  • Kerberos — validates against the Mac's built-in Local KDC (LKDC), which every Mac runs. Apple clients knock here.

Your iPhone walks through the Kerberos door and never touches the NT hash. Linux tries the NTLM door, and on a fresh account that door was never built — macOS only mints the NT hash when you tick "Windows File Sharing." So the handshake completes and then fails the credential check: LOGON_FAILURE.

That's the whole mystery. The iPhone succeeding tells you nothing about the NT hash, because the iPhone isn't using it.

The right fix is Kerberos

The popular fix — tick the per-user Windows sharing box — makes macOS store an NT hash. Apple's own docs say that password is then "stored in a less secure manner." You're bolting a weaker credential onto the Mac to satisfy a Linux client. No thanks.

Do what the iPhone does: authenticate over Kerberos to the LKDC. No NT hash, nothing weakened.

Worth noting up front: half the internet (and Apple's Heimdal source) will tell you a non-Apple client can't get a TGT from an LKDC because Apple uses proprietary SRP preauth. On an account that also has a normal Kerberos key — which mine did — MIT kinit just works with plain encrypted-timestamp preauth. Test it before believing the "impossible."

Making smbclient work

1. Find the realm. Apple publishes it as an mDNS _kerberos TXT record. This is exactly how the iPhone discovers it:

IP=$(avahi-resolve -4 -n mini.local | awk '{print $2}')
dig @"$IP" -p 5353 +short -t TXT _kerberos.mini.local
# "LKDC:SHA1.3A0D9D58C5DDED406F63333CFCDE40D414A7949A"
Enter fullscreen mode Exit fullscreen mode

(Use the IPv4. The link-local IPv6 responder breaks dig's unicast query.)

2. Point krb5 at it. No global config needed — use KRB5_CONFIG:

# ~/.config/krb5-mac.conf
[realms]
    LKDC:SHA1.3A0D...949A = {
        kdc = 192.168.0.153
    }
Enter fullscreen mode Exit fullscreen mode

There's no SRV discovery for LKDC realms, so the kdc = line is mandatory. dns_lookup_kdc won't save you.

3. Get a ticket.

export KRB5_CONFIG=~/.config/krb5-mac.conf
kinit tmlr@LKDC:SHA1.3A0D...949A
Enter fullscreen mode Exit fullscreen mode

4. The SPN trap. This is where it gets stupid. smbclient builds its Kerberos service principal from the hostname you give it — cifs/mini.local. The Mac doesn't register that. It registers cifs/LKDC:SHA1.<hash>. Ask for cifs/mini.local and the KDC refers you to a phantom LOCAL realm that has no such principal:

Server not found in Kerberos database while getting credentials for cifs/mini.local@...
Enter fullscreen mode Exit fullscreen mode

Fix: put the LKDC name where the hostname goes, and force the real IP with -I so that colon-riddled "hostname" is never resolved on the network:

smbclient "//LKDC:SHA1.3A0D...949A/Music" -I 192.168.0.153 -U tmlr --use-kerberos=required
Enter fullscreen mode Exit fullscreen mode

The colon in the UNC doesn't faze Samba's parser. You land at smb: \>. Pure Kerberos, no NT hash.

Helper script. Self-discovering, nothing hardcoded but the hostname, config in a temp dir that's wiped on exit:

#!/usr/bin/env bash
set -euo pipefail
HOST=${MINISMB_HOST:-mini.local}
ACCT=${MINISMB_USER:-tmlr}
SHARE=${1:-Music}; shift 2>/dev/null || true

IP=$(avahi-resolve -4 -n "$HOST" | awk '{print $2; exit}')
REALM=$(dig @"$IP" -p 5353 +short -t TXT "_kerberos.$HOST" | tr -d '"')

workdir=$(mktemp -d); trap 'rm -rf "$workdir"' EXIT
export KRB5_CONFIG="$workdir/krb5.conf"
cat > "$KRB5_CONFIG" <<EOF
[realms]
    $REALM = {
        kdc = $IP
    }
EOF

klist -s 2>/dev/null || kinit "$ACCT@$REALM"
smbclient "//$REALM/$SHARE" -I "$IP" -U "$ACCT" --use-kerberos=required "$@"
Enter fullscreen mode Exit fullscreen mode

minismb, minismb Documents, minismb Music -c 'ls'. IP drifts on DHCP? It re-discovers every run.

Persistent automount with systemd

For an always-on /mnt/mac, mount.cifs needs a ticket at mount time — as root, no prompt. That means a keytab. The mount ticket is fetched by cifs.upcall, which runs as root and reads /etc/krb5.conf, so the realm has to live there. The interactive path stayed fully user-local; a kernel mount can't.

Keytab. ktutil is interactive and prompts per addent:

$ ktutil
ktutil:  addent -password -p tmlr@LKDC:SHA1.3A0D...949A -k 1 -e aes256-cts-hmac-sha1-96
ktutil:  addent -password -p tmlr@LKDC:SHA1.3A0D...949A -k 1 -e aes128-cts-hmac-sha1-96
ktutil:  wkt /home/tmlr/.config/minismb/mini.keytab
ktutil:  quit
Enter fullscreen mode Exit fullscreen mode

Verify it can pull a TGT with no password:

kinit -kt ~/.config/minismb/mini.keytab tmlr@LKDC:SHA1.3A0D...949A && klist
Enter fullscreen mode Exit fullscreen mode

If that fails with a preauth error, your LKDC uses a non-default salt — read it out of KRB5_TRACE=/dev/stderr kinit ... (etype info ... salt "...") and match it. Mine used the default (realm+principal), so plain addent worked.

Realm for root/etc/krb5.conf.d/lkdc-mini.conf:

[realms]
    LKDC:SHA1.3A0D...949A = {
        kdc = mini.local
    }
Enter fullscreen mode Exit fullscreen mode

kdc = mini.local (not an IP) keeps the KDC side immune to DHCP drift, assuming nss-mdns resolves .local. Make sure /etc/krb5.conf has includedir /etc/krb5.conf.d/.

Keep a TGT alive — user units:

# ~/.config/systemd/user/minismb-tgt.service
[Unit]
Description=Refresh LKDC TGT from keytab
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
Environment=KRB5CCNAME=FILE:/tmp/krb5cc_%U
ExecStart=/usr/bin/kinit -kt %h/.config/minismb/mini.keytab tmlr@LKDC:SHA1.3A0D...949A
Enter fullscreen mode Exit fullscreen mode
# ~/.config/systemd/user/minismb-tgt.timer
[Unit]
Description=Keep the LKDC TGT fresh
[Timer]
OnStartupSec=30s
OnUnitActiveSec=8h
Persistent=true
[Install]
WantedBy=timers.target
Enter fullscreen mode Exit fullscreen mode

Mount + automount — system units:

# /etc/systemd/system/mnt-mac.mount
[Unit]
Description=Mac mini /Music over SMB (LKDC Kerberos)
After=network-online.target minismb-tgt.service
Wants=network-online.target
[Mount]
What=//LKDC:SHA1.3A0D...949A/Music
Where=/mnt/mac
Type=cifs
Options=sec=krb5,cruid=1000,uid=1000,gid=1000,vers=3.0,ip=192.168.0.153,_netdev,nofail
[Install]
WantedBy=multi-user.target
Enter fullscreen mode Exit fullscreen mode
# /etc/systemd/system/mnt-mac.automount
[Unit]
Description=Automount Mac mini /Music
[Automount]
Where=/mnt/mac
TimeoutIdleSec=600
[Install]
WantedBy=multi-user.target
Enter fullscreen mode Exit fullscreen mode

Enable:

systemctl --user daemon-reload
systemctl --user enable --now minismb-tgt.timer
systemctl --user start minismb-tgt.service
sudo systemctl daemon-reload
sudo systemctl enable --now mnt-mac.automount
ls /mnt/mac
Enter fullscreen mode Exit fullscreen mode

Two gotchas that cost me an hour:

  • vers=3.1.1 fails with Dialect not supported by server. Use vers=3.0. smbclient auto-negotiates and dodges this; the kernel client doesn't.
  • ip= is static — the colon UNC isn't DNS-resolvable, so you must pass an IP, and a .mount unit can't run a resolver. Give the Mac a DHCP reservation and this stays put. (Only the SMB ip= cares; the KDC uses mini.local.)

And that's it. On-access mount, keytab-driven, no password ever, and the Mac keeps only its strong credentials. Same door the iPhone uses.

Top comments (0)