2

We're working towards a zero trust security model in our office, with servers secured behind a WireGuard VPN. We already use WireGuard for remote access, so this is the simplest way to ensure encryption for all network traffic. WireGuard guarantees a specific IP address for each user.

We would like to authenticate file server access with both username and IP address, to prevent lateral movement in the event of a breach. We're using Samba 4.13 with the simple default passdb backend = tdbsam (no domain controller).

I was hoping for a simple solution with PAM, but although the default configuration file still includes auth, I've read that it isn't supported (Samba uses challenge-response authentication, which isn't the PAM way). When I added auth required pam_rhosts.so to /etc/pam.d/samba, there was no change in my ability to authenticate. Adding it to the account or session sections caused authentication to fail, even from the authorized IP address.

Other solutions I can see are to modify the source code or run an Active Directory Domain Controller, but those seem like a much bigger job to implement and maintain. An application firewall might also work, but I'm not aware of anything that can inspect Samba traffic.

Is there a simple way to add this user-host pair restriction (or MFA in general) to Samba 4?

-- Edit --

The /etc/pam.d/samba configuration clearly has some effect, because adding a 'debug' option to any of the lines in the auth section gives debug logging as follows, though additional required lines make no difference to the outcome of authentication:

[2022/11/10 15:56:56.258835,  3] ../../auth/ntlmssp/ntlmssp_server.c:509(ntlmssp_server_preauth)
  Got user=[username] domain=[FILESERVER] workstation=[COMPUTER-NAME] len1=24 len2=190
[2022/11/10 15:56:56.258932,  3] ../../source3/auth/auth.c:200(auth_check_ntlm_password)
  check_ntlm_password:  Checking password for unmapped user [FILESERVER]\[username]@[COMPUTER-NAME] with the new password interface
[2022/11/10 15:56:56.258959,  3] ../../source3/auth/auth.c:203(auth_check_ntlm_password)
  check_ntlm_password:  mapped user is: [FILESERVER]\[username]@[COMPUTER-NAME]
[2022/11/10 15:56:56.259651,  4] ../../source3/auth/check_samsec.c:183(sam_account_ok)
  sam_account_ok: Checking SMB password for user username
[2022/11/10 15:56:56.262124,  3] ../../source3/auth/auth.c:267(auth_check_ntlm_password)
  auth_check_ntlm_password: sam_ignoredomain authentication for user [username] succeeded
[2022/11/10 15:56:56.262230,  4] ../../source3/auth/pampass.c:485(smb_pam_start)
  smb_pam_start: PAM: Init user: username
[2022/11/10 15:56:56.267184,  4] ../../source3/auth/pampass.c:494(smb_pam_start)
  smb_pam_start: PAM: setting rhost to: 10.1.2.3
[2022/11/10 15:56:56.267246,  4] ../../source3/auth/pampass.c:503(smb_pam_start)
  smb_pam_start: PAM: setting tty
[2022/11/10 15:56:56.267285,  4] ../../source3/auth/pampass.c:511(smb_pam_start)
  smb_pam_start: PAM: Init passed for user: username
[2022/11/10 15:56:56.267323,  4] ../../source3/auth/pampass.c:569(smb_pam_account)
  smb_pam_account: PAM: Account Management for User: username
[2022/11/10 15:56:56.267907,  4] ../../source3/auth/pampass.c:588(smb_pam_account)
  smb_pam_account: PAM: Account OK for User: username
[2022/11/10 15:56:56.268550,  4] ../../source3/auth/pampass.c:467(smb_pam_end)
  smb_pam_end: PAM: PAM_END OK.
[2022/11/10 15:56:56.268641,  2] ../../source3/auth/auth.c:323(auth_check_ntlm_password)
  check_ntlm_password:  authentication for user [username] -> [username] -> [username] succeeded

3 Answers 3

2

I'm not keen on this particular topic, but after adding auth required pam_rhosts.so, you did create the respective ~/.rhosts files right?

This link says the rhosts files need to specify the hostname [username] pair(s) that will be permitted, I'm assuming ip addresses would work just as well in place of hostname.

Are there any specific log messages you can share (redacted if needs be of course) that might give more insight?


EDIT - No idea if this will work, but you could maybe try with netgroups.

I'm not sure of the requirements or procedure for setting these up or if it's as simple as just creating & populating the /etc/netgroup file.

Then based on the example in the manpage for pam_succeed_if, it seems like you could make netgroups for the (host,user) pairs, which I imagine could look something like this:

sambang (alicepc, alice) (bobpc, bob) (charliepc, charlie)

and add this module to your samba auth to make pam auth succeed if the (host,user) pair is in the netgroup, something like:

auth required pam_succeed_if.so audit user innetgr netgroup sambang

I'd probably replace audit with debug until you get it working (assuming it can work).

4
  • Yes, I did create ~/.rhosts, and it connects just as before, even from hosts not listed in ~/.rhosts. No significant error messages, just 2 lines in /var/log/syslog: Nov 10 14:45:12 fileserver smbd[443420]: [2022/11/10 14:45:12.693848, 0] ../../source3/rpc_server/mdssvc/mdssvc_es.c:272(mds_es_http_connect_done) \nNov 10 14:45:12 fileserver smbd[443420]: mds_es_http_connect_done: HTTP connect failed, retrying... Nov 10, 2022 at 21:46
  • Got an idea but it's basically a shot in the dark, will update my original post just to make it easier to read. Nov 10, 2022 at 22:03
  • Adding the pam_succeed_if module made no difference. It does seem that the auth directives in /etc/pam.d/samba are ignored in Samba 4. I did find something interesting in /var/log/samba/<userLogFile>: check_ntlm_password: Checking password for unmapped user [FILESERVER]\[username]@[COMPUTER-NAME] with the new password interface. Maybe there's a way to modify how check_ntml_password works. Nov 10, 2022 at 23:11
  • Seems like it could be good to look into considering its seeing the [username]@[COMPUTER-NAME], not much support I can provide though, I was already out of my depth here & I'm caught up in something else now. Good luck. Nov 10, 2022 at 23:41
1

Wouldn't samba's ACL per IP/subnet files /etc/hosts.allow & /etc/hosts.deny be enough to restrict shared mounts to users?

See this article describing how to set up samba's authorisations.

EDIT: Also, here is an answer for PAM modules for roaming home folders. Maybe it's the same use-case as yours?

FWIW, I'd give a try on Hashicorp's Boundary for a 0-trust solution.

7
  • 1
    I think what he's going for here is he wants individual users to only be able to log in from a specific IP which is dictated by WireGuard. I believe those files would just specify a general blanket of which remote addresses can access a share. Nov 10, 2022 at 4:15
  • From OP's question: "we would like to authenticate file server access". That's how you do it with TCP wrappers to allow only specific subnets, the users are already authorised into the server through Wireguard, no? In any case, maybe the simplest solution is already enough? Why don't we let the OP first test the TCP wrappers, instead of Pluggable Authentication Modules, instead of trying to interpret his question or rather my answer ;) ?
    – Marcel
    Nov 10, 2022 at 9:41
  • @A.Trevelyan is correct. /etc/hosts.allow won't help, because access is already limited to the WireGuard subnet via iptables firewall. What I want to do is require that user bob can only connect from 10.1.2.3, user sally can only connect from 10.1.2.4, etc. So if Sally's computer is compromised, the attacker cannot access Bob's account - lateral movement is restricted. I assume that cracking Samba passwords is much easier than cracking a WireGuard connection. Would HCP Boundary solve this problem, or just add another layer before Samba's regular password auth? Nov 10, 2022 at 16:14
  • I'm sorry if I don't understand you correctly, but from what I understood you ALREADY have people connected to your network via Wireguard and now you want to restrict access to the File Server, it is now irrelevant that they come via a distinct subnet, as they are already in, or what else am I missing?
    – Marcel
    Nov 10, 2022 at 16:33
  • 1
    From a zero-trust perspective it makes sense to me. The people connected to wireguard (distinct subnet) can all access the file server, say Alice, Bob, Charlie -- They all have shares on the File server. If Bob's machine is compromised, that machine could potentially be used to gain access to all 3 shares on the file server. What he wants is to restrict it such that in that scenario, only Bob's share will be at risk -- ie. Bob@BobPC can only access //Bob, Alice@AlicePC can only access //Alice. Alice@BobPC cannot access //Alice Nov 10, 2022 at 19:17
0

I decided to monitor user sessions with smbstatus. This doesn't happen immediately at login, so it won't prevent someone from logging in, but it will terminate an invalid session within a few seconds. Not a perfect solution, but it should be adequate in our case.

Here's how I implemented it in PHP:

#!/usr/bin/php
<?php
/**
@file blockInvalidSambaUserHosts.php
Block invalid user-host pairs from using Samba.
Run as a root service.
Configure valid pairs in /etc/samba/validUserHosts.conf with lines like:
alice 10.1.0.100
bob 10.1.0.101,10.2.0.88
**/

$STATUS_COMMAND = <<< 'END'
smbstatus -p | awk '/SMB3/{print $1" "$2" "$4}'
END;

$configFile = '/etc/samba/validUserHosts.conf';
if (!file_exists($configFile)) file_put_contents($configFile,'');

list($configTime,$validUserHosts) = getConfig($configFile);

while (true) {
    $connections = explode("\n",trim(shell_exec($STATUS_COMMAND)));
    foreach ($connections as $c) {
        if (!$c) continue;
        list($pid,$uname,$ip) = explode(' ',$c);

        if (!isset($validUserHosts[$uname])) $msg = "Invalid user $uname.";
        elseif (!in_array($ip,$validUserHosts[$uname])) $msg = "Invalid address $ip for user $uname.";
        else continue;

        error_log($msg);
        killProcess($ip);
        blockIPAddress($ip,$uname);
        //notify($ip,$uname);
    }

    sleep(10);

    // Reload config if it has been modified
    if (filemtime($configFile) > $configTime) {
        list($configTime,$validUserHosts) = getConfig($configFile);
    }
}

// Immediately stop any operations in progress
function killProcess(string $ip): void {
    shell_exec("kill -9 $ip");
    error_log("Killed smbd process for $ip.");
}

// Immediately block further traffic
function blockIPAddress(string $ip, string $uname): void {
    shell_exec("iptables -I INPUT -s $ip -j DROP -m comment --comment '$uname@$ip not valid for Samba'");
    error_log("All traffic from $ip is now blocked.");
}

function getConfig($configFile) {
    $utime = filemtime($configFile);
    $lines = file($configFile);
    $validUserHosts = [];
    foreach ($lines as $line) {
        list($uname,$hosts) = explode(' ',rtrim($line));
        $validUserHosts[$uname] = explode(',',$hosts);
    }

    return [$utime,$validUserHosts];
}

with a systemd configuration like the following:

# @file blockInvalidSambaUserHosts.service
# @version 1.0.0
[Unit]
Description=Block invalid user-host pairs from using Samba
After=smbd.service

[Service]
Type=simple
ExecStart=/root/blockInvalidSambaUserHosts.php
StandardOutput=append:/var/log/sambaUserHostBlocks.log
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.