Samba: Difference between revisions

imported>Maximeborges
Fix AD DC instructions
No edit summary
 
(36 intermediate revisions by 27 users not shown)
Line 1: Line 1:
This guide will help you on how to use samba on nixos.
This guide will help you on how to use samba on nixos.


== Samba Client ==
== Usershares ==
=== cifs mount ===


The following snippets shows how to mount a CIFS (Windows) share in NixOS.
You can allow some users to share via samba a given directory simply via a right click in their file browser (tested with Dolphin). For that, first add this configuration (make sure to add your user in the samba group):
Replace all <code><FIELDS></code> with concrete values:


<syntaxhighlight lang="nix">
{{file|/etc/nixos/configuration.nix|nix|<nowiki>
{
{ pkgs, config, ... }: {
   fileSystems."/mnt/share" = {
   services.samba = {
      device = "//<IP_OR_HOST>/path/to/share";
    # The full package is needed to register mDNS records (for discoverability), see discussion in
      fsType = "cifs";
    # https://gist.github.com/vy-let/a030c1079f09ecae4135aebf1e121ea6
      options = let
    package = pkgs.samba4Full;
        # this line prevents hanging on network split
    usershares.enable = true;
        automount_opts = "x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s";
    enable = true;
 
    openFirewall = true;
      in ["${automount_opts},credentials=/etc/nixos/smb-secrets"];
    };
   };
   };
}
</syntaxhighlight>
Also create /etc/nixos/smb-secrets with the following content (<code>domain=</code> can be optional)
<syntaxhighlight lang="nix">
username=<USERNAME>
domain=<DOMAIN>
password=<PASSWORD>
</syntaxhighlight>
== Firewall ==
Samba discovery of machines and shares may need the firewall to be tuned ([https://wiki.archlinux.org/index.php/Samba#.22Browsing.22_network_fails_with_.22Failed_to_retrieve_share_list_from_server.22 source]):
in <code>/etc/nixos/configuration.nix</code>, add:
<syntaxhighlight lang="nix">
networking.firewall.extraCommands = ''iptables -t raw -A OUTPUT -p udp -m udp --dport 137 -j CT --helper netbios-ns'';
</syntaxhighlight>
== Browsing samba shares with GVFS ==
Many GTK-based file managers like Nautilus, Thunar, and PCManFM can browse samba shares thanks to GVFS.
GVFS is a dbus daemon which must be running for this to work.
If you use Gnome, you have nothing to do as the module already enables it for you, but in less full-featured desktop environments, some further configuration options are needed.
The generic way of enabling GVFS is to add this in <code>/etc/nixos/configuration.nix</code>:
<syntaxhighlight lang="nix">
services.gvfs.enable = true;
</syntaxhighlight>


There are however some special cases.
  # To be discoverable with windows
===== XFCE =====
   services.samba-wsdd = {
[[Xfce]] comes with a slimmed-down version of GVFS by default which comes with samba support compiled out. To have smb:// support in Thunar, we will use GNOME's full-featured version of GVFS:
<syntaxhighlight lang="nix">
   services.gvfs = {
     enable = true;
     enable = true;
     package = lib.mkForce pkgs.gnome3.gvfs;
     openFirewall = true;
   };
   };
</syntaxhighlight>
===== No desktop environment =====
GVFS relies on polkit to gain privileges for some operations. Polkit needs an authentication agent to ask for credentials.
Desktop environments usually provide one but if you have no desktop environment, you may have to install one yourself:
Excerpt of <code>/etc/nixos/configuration.nix</code>:
<syntaxhighlight lang="nix">
environment.systemPackages = with pkgs; [ lxqt.lxqt-policykit ]; # provides a default authentification client for policykit
</syntaxhighlight>


  # Make sure your user is in the samba group
  users.users.YOURUSER = {
    isNormalUser = true;
    extraGroups = [ "samba" ];
  };
}
</nowiki>}}


===== DBUS =====
Then, logout and login (to make sure your group change has been taken into account), open Dolphin, right click on a folder you'd like to share, go to Properties, Tab "Share", and configure it the way you want.
Furthermore, if you happen to start your Window Manager directly, via <code>.xinitrc</code>, or directly invoke a Wayland compositor such as Sway, you should ensure that you launch dbus at startup in your session and export its environment. If you do not have a dbus session in your environment, you will see errors such as "Operation not supported" when attempting to browse the network.
 
For example, if you are using <code>.xinitrc</code>, you could invoke <code>dbus-launch</code>:
<syntaxhighlight lang="bash">
export `dbus-launch` # starts dbus and exports its address
exec xterm # your prefered Window Manager
</syntaxhighlight>
(You need to restart your Window Manager to have the changes in <code>.xinitrc</code> to take place.)


If you are using a Wayland compositor like Sway, you can run it under <code>dbus-run-session</code> for the same effect:
<syntaxhighlight lang="bash">
dbus-run-session sway
</syntaxhighlight>


(Because <code>dbus-run-session</code> exits when the child process exits, it is only appropriate to use <code>dbus-run-session</code> with a process that will be running during the entire session. This is the case for Wayland compositors, but is not necessarily true for all configurations of X11 window managers.)
== Server setup ==


== Samba Server ==
Example setup for creating a public guest share called <code>public</code> and a private share called <code>private</code>.
=== excerpt of /etc/nixos/configuration.nix ===


<syntaxhighlight lang="nix">
{{file|/etc/nixos/configuration.nix|nix|<nowiki>
services.samba = {
services.samba = {
   enable = true;
   enable = true;
   securityType = "user";
   openFirewall = true;
   extraConfig = ''
   settings = {
     workgroup = WORKGROUP
     global = {
    server string = smbnix
      "workgroup" = "WORKGROUP";
    netbios name = smbnix
      "server string" = "smbnix";
    security = user  
      "netbios name" = "smbnix";
    #use sendfile = yes
      "security" = "user";
    #max protocol = smb2
      #"use sendfile" = "yes";
    hosts allow = 192.168.0 localhost
      #"max protocol" = "smb2";
    hosts deny = 0.0.0.0/0
      # note: localhost is the ipv6 localhost ::1
    guest account = nobody
      "hosts allow" = "192.168.0. 127.0.0.1 localhost";
    map to guest = bad user
      "hosts deny" = "0.0.0.0/0";
  '';
      "guest account" = "nobody";
  shares = {
      "map to guest" = "bad user";
     public = {
    };
       path = "/mnt/Shares/Public";
     "public" = {
       browseable = "yes";
       "path" = "/mnt/Shares/Public";
       "browseable" = "yes";
       "read only" = "no";
       "read only" = "no";
       "guest ok" = "yes";
       "guest ok" = "yes";
Line 112: Line 66:
       "force group" = "groupname";
       "force group" = "groupname";
     };
     };
     private = {
     "private" = {
       path = "/mnt/Shares/Private";
       "path" = "/mnt/Shares/Private";
       browseable = "yes";
       "browseable" = "yes";
       "read only" = "no";
       "read only" = "no";
       "guest ok" = "no";
       "guest ok" = "no";
Line 124: Line 78:
   };
   };
};
};
</syntaxhighlight>


If your firewall is enabled, or if you consider enabling it:
services.samba-wsdd = {
<syntaxhighlight lang="nix">
  enable = true;
  openFirewall = true;
};
 
services.avahi = {
  publish.enable = true;
  publish.userServices = true;
  # ^^ Needed to allow samba to automatically register mDNS records (without the need for an `extraServiceFile`
  nssmdns4 = true;
  # ^^ Not one hundred percent sure if this is needed- if it aint broke, don't fix it
  enable = true;
  openFirewall = true;
};
 
networking.firewall.enable = true;
networking.firewall.enable = true;
networking.firewall.allowPing = true;
networking.firewall.allowPing = true;
networking.firewall.allowedTCPPorts = [ 445 139 ];
</nowiki>}}
networking.firewall.allowedUDPPorts = [ 137 138 ];
 
The <code>samba-wsdd</code> service and avahi is used to advertise the shares to Windows hosts.
 
=== User Authentication ===
 
For a user called <code>my_user</code>to be authenticated on the samba server, you can add a password using:
 
<syntaxhighlight lang="bash">
sudo smbpasswd -a my_user
</syntaxhighlight>
</syntaxhighlight>


{{Evaluate}}
To automate creation of the samba user and the required system user, you can use [https://search.nixos.org/options?show=system.activationScripts system.activationScripts]:


Samba should startup afterwards.
<syntaxhighlight lang="nix">
{
  # Make the samba user "my_user" on the system
  users.users.my_user = {
    description = "Write-access to samba media shares";
    # Add this user to a group with permission to access the expected files
    extraGroups = [ "users" ];
    # Password can be set in clear text with a literal string or from a file.
    # Using sops-nix we can use the same file so that the system user and samba
    # user share the same credential (if desired).
    hashedPasswordFile = config.sops.secrets.samba.path;
    isNormalUser = true;
  };
  # Set "my_user" as a valid samba login
  services.samba = {
    enable = true;
    securityType = "user";
    openFirewall = true;
    settings.my_share_directory = {
      # ...
      "valid users" = "my_user";
    };
  };
  # Activation scripts run every time nixos switches build profiles. So if you're
  # pulling the user/samba password from a file then it will be updated during
  # nixos-rebuild. Again, in this example we're using sops-nix with a "samba" entry
  # to avoid cleartext password, but this could be replaced with a static path.
  system.activationScripts = {
    # The "init_smbpasswd" script name is arbitrary, but a useful label for tracking
    # failed scripts in the build output. An absolute path to smbpasswd is necessary
    # as it is not in $PATH in the activation script's environment. The password
    # is repeated twice with newline characters as smbpasswd requires a password
    # confirmation even in non-interactive mode where input is piped in through stdin.
    init_smbpasswd.text = ''
      /run/current-system/sw/bin/printf "$(/run/current-system/sw/bin/cat ${config.sops.secrets.samba.path})\n$(/run/current-system/sw/bin/cat ${config.sops.secrets.samba.path})\n" | /run/current-system/sw/bin/smbpasswd -sa my_user
    '';
  };


If you plan to access a share as a user on the server, you'll need to run <code>smbpasswd -a <user></code> as root to set the password.
}


=== stopping/restarting the services ===
<syntaxhighlight lang="console">
# systemctl stop samba
# systemctl start samba
# systemctl restart samba
</syntaxhighlight>
</syntaxhighlight>


=== Use Cases ===
 
=== Configuration ===
 
==== Apple Time Machine ====
==== Apple Time Machine ====
Example configuration:
 
In addition to the example above, add this to your configuration:
 
<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
services.samba = {
services.samba = {
   shares = {
   settings = {
     tm_share = {
     "tm_share" = {
         path = "/mnt/Shares/tm_share";
         "path" = "/mnt/Shares/tm_share";
         "valid users" = "username";
         "valid users" = "username";
         public = "no";
         "public" = "no";
         writeable = "yes";
         "writeable" = "yes";
         "force user" = "username";
         "force user" = "username";
        # Below are the most imporant for macOS compatibility
        # Change the above to suit your needs
         "fruit:aapl" = "yes";
         "fruit:aapl" = "yes";
         "fruit:time machine" = "yes";
         "fruit:time machine" = "yes";
Line 164: Line 175:
     };
     };
   };
   };
}
};
 
# Ensure Time Machine can discover the share without `tmutil`
services.avahi = {
  extraServiceFiles = {
    timemachine = ''
      <?xml version="1.0" standalone='no'?>
      <!DOCTYPE service-group SYSTEM "avahi-service.dtd">
      <service-group>
        <name replace-wildcards="yes">%h</name>
        <service>
          <type>_smb._tcp</type>
          <port>445</port>
        </service>
          <service>
          <type>_device-info._tcp</type>
          <port>0</port>
          <txt-record>model=TimeCapsule8,119</txt-record>
        </service>
        <service>
          <type>_adisk._tcp</type>
          <!--
            change tm_share to share name, if you changed it.
          -->
          <txt-record>dk0=adVN=tm_share,adVF=0x82</txt-record>
          <txt-record>sys=waMa=0,adVF=0x100</txt-record>
        </service>
      </service-group>
    '';
  };
};
</syntaxhighlight>
</syntaxhighlight>


==== Printer sharing ====
==== Printer sharing ====
The `samba` packages comes without cups support compiled in, however `sambaFull` features printer sharing support.
To use it set the `services.samba.package` option:


<syntaxhighlight lang=nix>
<syntaxhighlight lang=nix>
Line 176: Line 214:
</syntaxhighlight>
</syntaxhighlight>


A printer share that allows all members in the local network printing could look like this:
A printer share that allows printing to all members in the local network


<syntaxhighlight lang=nix>
{{file|/etc/nixos/configuration.nix|nix|<nowiki>
{ pkgs, ... }: {
services.samba = {
  services.samba = {
  enable = true;
    enable = true;
  package = pkgs.sambaFull;
    package = pkgs.sambaFull;
  openFirewall = true;
     extraConfig = ''
  settings = {
       load printers = yes
     "global" = {
       printing = cups
       "load printers" = "yes";
       printcap name = cups
       "printing" = "cups";
     '';
       "printcap name" = "cups";
     shares = {
     };
       printers = {
     "printers" = {
        comment = "All Printers";
       "comment" = "All Printers";
        path = "/var/spool/samba";
      "path" = "/var/spool/samba";
        public = "yes";
      "public" = "yes";
        browseable = "yes";
      "browseable" = "yes";
        # to allow user 'guest account' to print.
      # to allow user 'guest account' to print.
        "guest ok" = "yes";
      "guest ok" = "yes";
        writable = "no";
      "writable" = "no";
        printable = "yes";
      "printable" = "yes";
        "create mode" = 0700;
      "create mode" = 0700;
      };
    };
   };
   };
  systemd.tmpfiles.rules = [
};
    "d /var/spool/samba 1777 root root -"
systemd.tmpfiles.rules = [
  ];
  "d /var/spool/samba 1777 root root -"
}
];
</syntaxhighlight>
</nowiki>}}
 
The `samba` packages comes without [[Printing|CUPS printing]] support compiled in, however `sambaFull` features printer sharing support.


==== Active Directory Domain Controller ====
==== Active Directory Domain Controller ====
Line 220: Line 260:
   samba = cfg.package;
   samba = cfg.package;
   nssModulesPath = config.system.nssModules.path;
   nssModulesPath = config.system.nssModules.path;
   adDomain = 'samdom.example.com';
   adDomain = "samdom.example.com";
   adWorkgroup = 'SAM';
   adWorkgroup = "SAM";
   adNetbiosName = 'SAMDOM';
   adNetbiosName = "SAMDOM";
   staticIp = '10.42.129.160';
   staticIp = "10.42.129.160";
in {
in {
   # Disable resolveconf, we're using Samba internal DNS backend
   # Disable resolveconf, we're using Samba internal DNS backend
Line 238: Line 278:
   # Rebuild Samba with LDAP, MDNS and Domain Controller support
   # Rebuild Samba with LDAP, MDNS and Domain Controller support
   nixpkgs.overlays = [ (self: super: {
   nixpkgs.overlays = [ (self: super: {
     samba = super.samba.override {
     samba = (super.samba.override {
       enableLDAP = true;
       enableLDAP = true;
       enableMDNS = true;
       enableMDNS = true;
       enableDomainController = true;
       enableDomainController = true;
     };
      enableProfiling = true; # Optional for logging
   } ) ];
      # Set pythonpath manually (bellow with overrideAttrs) as it is not set on 22.11 due to bug
     }).overrideAttrs (finalAttrs: previousAttrs: {
        pythonPath = with super; [ python3Packages.dnspython python3Packages.markdown tdb ldb talloc ];
      });
   })];


   # Disable default Samba `smbd` service, we will be using the `samba` server binary
   # Disable default Samba `smbd` service, we will be using the `samba` server binary
Line 301: Line 345:
Then restart the samba service with <code>sudo systemctl restart samba</code>, and you're ready to go!
Then restart the samba service with <code>sudo systemctl restart samba</code>, and you're ready to go!


==Troubleshooting==
== Samba Client ==
 
=== CIFS mount configuration ===
 
The following snippets shows how to mount a CIFS (Windows) share in NixOS.
Replace all <code><FIELDS></code> with concrete values:
 
<syntaxhighlight lang="nix">
{
  # For mount.cifs, required unless domain name resolution is not needed.
  environment.systemPackages = [ pkgs.cifs-utils ];
  fileSystems."/mnt/share" = {
    device = "//<IP_OR_HOST>/path/to/share";
    fsType = "cifs";
    options = let
      # this line prevents hanging on network split
      automount_opts = "x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s";
 
    in ["${automount_opts},credentials=/etc/nixos/smb-secrets"];
  };
}
</syntaxhighlight>
 
Also create /etc/nixos/smb-secrets with the following content (<code>domain=</code> can be optional)
 
<syntaxhighlight lang="nix">
username=<USERNAME>
domain=<DOMAIN>
password=<PASSWORD>
</syntaxhighlight>
 
By default, CIFS shares are mounted as root. If mounting as user is desirable, `uid`, `gid` and usergroup arguments can be provided as part of the filesystem options:
<syntaxhighlight lang="nix">
{
  fileSystems."/mnt/share" = {
    # ... rest of the filesystem config omitted
    options = let
      automount_opts = "x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s,user,users";
 
      in ["${automount_opts},credentials=/etc/nixos/smb-secrets,uid=1000,gid=100"];
    # or if you have specified `uid` and `gid` explicitly through NixOS configuration,
    # you can refer to them rather than hard-coding the values:
    # in ["${automount_opts},credentials=/etc/nixos/smb-secrets,uid=${toString config.users.users.<username>.uid},gid=${toString config.users.groups.<group>.gid}"];
  };
}
</syntaxhighlight>
 
=== Firewall configuration ===
 
Samba discovery of machines and shares may need the firewall to be tuned ([https://wiki.archlinux.org/index.php/Samba#.22Browsing.22_network_fails_with_.22Failed_to_retrieve_share_list_from_server.22 source]):
in <code>/etc/nixos/configuration.nix</code>, add:
<syntaxhighlight lang="nix">
networking.firewall.extraCommands = ''iptables -t raw -A OUTPUT -p udp -m udp --dport 137 -j CT --helper netbios-ns'';
</syntaxhighlight>
 
=== Command line ===
 
List shares
 
<pre>
smbclient --list localhost
</pre>
 
This should print
 
<pre>
$ smbclient --list localhost
Password for [WORKGROUP\user]:
 
Sharename      Type      Comment
---------      ----      -------
public          Disk     
IPC$            IPC      IPC Service (smbnix)
SMB1 disabled -- no workgroup available
</pre>
 
Mount as guest. <code>public</code> is your share name
 
<pre>
nix-shell -p cifs-utils
mkdir mnt
sudo mount.cifs -o sec=none //localhost/public mnt
</pre>
 
mount as user. <code>user</code> is your username
 
<pre>
sudo mount.cifs -o sec=ntlmssp,username=user //localhost/public mnt
</pre>
 
<code>sec=ntlmssp</code> should work.
for more values, see `man mount.cifs` (search for `sec=arg`)
 
=== Browsing samba shares with GVFS ===
 
Many GTK-based file managers like Nautilus, Thunar, and PCManFM can browse samba shares thanks to GVFS.
GVFS is a dbus daemon which must be running for this to work.
If you use Gnome, you have nothing to do as the module already enables it for you, but in less full-featured desktop environments, some further configuration options are needed.
 
The generic way of enabling GVFS is to add this in <code>/etc/nixos/configuration.nix</code>:
<syntaxhighlight lang="nix">
services.gvfs.enable = true;
</syntaxhighlight>
 
There are however some special cases.
 
===== XFCE =====
 
[[Xfce]] comes with a slimmed-down version of GVFS by default which comes with samba support compiled out. To have smb:// support in Thunar, we will use GNOME's full-featured version of GVFS:
<syntaxhighlight lang="nix">
  services.gvfs = {
    enable = true;
    package = lib.mkForce pkgs.gnome.gvfs;
  };
</syntaxhighlight>
 
===== No desktop environment =====
 
GVFS relies on polkit to gain privileges for some operations. Polkit needs an authentication agent to ask for credentials.
Desktop environments usually provide one but if you have no desktop environment, you may have to install one yourself:
 
Excerpt of <code>/etc/nixos/configuration.nix</code>:
<syntaxhighlight lang="nix">
environment.systemPackages = with pkgs; [ lxqt.lxqt-policykit ]; # provides a default authentification client for policykit
</syntaxhighlight>
 
===== DBUS =====
 
Furthermore, if you happen to start your Window Manager directly, via <code>.xinitrc</code>, or directly invoke a Wayland compositor such as Sway, you should ensure that you launch dbus at startup in your session and export its environment. If you do not have a dbus session in your environment, you will see errors such as "Operation not supported" when attempting to browse the network.
 
For example, if you are using <code>.xinitrc</code>, you could invoke <code>dbus-launch</code>:
<syntaxhighlight lang="bash">
export `dbus-launch` # starts dbus and exports its address
exec xterm # your prefered Window Manager
</syntaxhighlight>
(You need to restart your Window Manager to have the changes in <code>.xinitrc</code> to take place.)
 
If you are using a Wayland compositor like Sway, you can run it under <code>dbus-run-session</code> for the same effect:
<syntaxhighlight lang="bash">
dbus-run-session sway
</syntaxhighlight>
 
(Because <code>dbus-run-session</code> exits when the child process exits, it is only appropriate to use <code>dbus-run-session</code> with a process that will be running during the entire session. This is the case for Wayland compositors, but is not necessarily true for all configurations of X11 window managers.)
 
== Troubleshooting ==
 
=== Server log ===
 
<pre>
sudo journalctl -u samba-smbd.service -f
</pre>
 
=== Stale file handle ===
=== Stale file handle ===
Trying to read the contents of a remote file leads to the following error message: "Stale file handle". If you have mounted a share via the method described in "cfis mount", adding the option <code>noserverino</code> might fix this problem. [https://askubuntu.com/questions/1265164/stale-file-handler-when-mounting-cifs-smb-network-drive-from-fritz-router]
Trying to read the contents of a remote file leads to the following error message: "Stale file handle". If you have mounted a share via the method described in "cfis mount", adding the option <code>noserverino</code> might fix this problem. [https://askubuntu.com/questions/1265164/stale-file-handler-when-mounting-cifs-smb-network-drive-from-fritz-router]


== links ==
=== NT_STATUS_INVALID_NETWORK_RESPONSE ===
* [https://search.nixos.org/options/?query=services.samba Samba Options in NixOS]
 
The error
<code>protocol negotiation failed: NT_STATUS_INVALID_NETWORK_RESPONSE</code>
means "access denied".
Probably you must fix your server's <code>hosts allow</code> section.
Note that <code>localhost</code> is the ipv6 localhost <code>::1</code>,
and <code>127.0.0.1</code> is the ipv4 localhost
 
=== Permission denied ===
 
Maybe check the <code>guest account</code> setting in your server config.
The default value is <code>nobody</code>,
but the user <code>nobody</code> has no access to <code>/home/user</code>:
 
<pre>
$ sudo -u nobody ls /home/user
[sudo] password for user:
ls: cannot open directory '/home/user': Permission denied
</pre>
 
As workaround, set <code>guest account = user</code>,
where <code>user</code> is your username
 
== See also ==
 
* [https://search.nixos.org/options?channel=unstable&from=0&size=50&sort=relevance&type=packages&query=services.samba Samba Options in NixOS on unstable]
* [https://wiki.archlinux.org/title/Samba Samba in the Arch Linux Wiki]
* [https://www.samba.org/samba/docs/current/man-html/smb.conf.5.html smb.conf man page]


[[Category:Services]]
[[Category:Server]]
[[Category:Applications]]