Samba: Difference between revisions

Klinger (talk | contribs)
User Authentication: add robust automated authentication example that provides full context and aims to give a basic, typical password-protected folder share
(12 intermediate revisions by 9 users not shown)
Line 8: Line 8:
services.samba = {
services.samba = {
   enable = true;
   enable = true;
  securityType = "user";
   openFirewall = true;
   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";
    # note: localhost is the ipv6 localhost ::1
      #"max protocol" = "smb2";
    hosts allow = 192.168.0. 127.0.0.1 localhost
      # note: localhost is the ipv6 localhost ::1
    hosts deny = 0.0.0.0/0
      "hosts allow" = "192.168.0. 127.0.0.1 localhost";
    guest account = nobody
      "hosts deny" = "0.0.0.0/0";
    map to guest = bad user
      "guest account" = "nobody";
  '';
      "map to guest" = "bad user";
  shares = {
    };
     public = {
     "public" = {
       path = "/mnt/Shares/Public";
       "path" = "/mnt/Shares/Public";
       browseable = "yes";
       "browseable" = "yes";
       "read only" = "no";
       "read only" = "no";
       "guest ok" = "yes";
       "guest ok" = "yes";
Line 34: Line 33:
       "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 48: Line 47:


services.samba-wsdd = {
services.samba-wsdd = {
  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;
   enable = true;
   openFirewall = true;
   openFirewall = true;
Line 56: Line 65:
</nowiki>}}
</nowiki>}}


The <code>samba-wsdd</code> service is used to advertise the shares to Windows hosts.
The <code>samba-wsdd</code> service and avahi is used to advertise the shares to Windows hosts.


=== User Authentication ===
=== User Authentication ===


For a user called <code>my_user</code>to be authenticated on the samba server, you must add their password using
For a user called <code>my_user</code>to be authenticated on the samba server, you can add a password using:


<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
smbpasswd -a my_user
sudo smbpasswd -a my_user
</syntaxhighlight>
 
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]:
 
<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
    '';
  };
 
}
 
</syntaxhighlight>
</syntaxhighlight>


=== Configuration ===
=== Configuration ===
Line 70: Line 124:
==== 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 86: Line 142:
     };
     };
   };
   };
}
};
 
# 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>


Line 102: Line 188:
   package = pkgs.sambaFull;
   package = pkgs.sambaFull;
   openFirewall = true;
   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;
     };
     };
Line 166: Line 252:
       # Set pythonpath manually (bellow with overrideAttrs) as it is not set on 22.11 due to bug
       # Set pythonpath manually (bellow with overrideAttrs) as it is not set on 22.11 due to bug
     }).overrideAttrs (finalAttrs: previousAttrs: {
     }).overrideAttrs (finalAttrs: previousAttrs: {
         pythonPath = with super; [ python3Packages.dnspython tdb ldb talloc ];
         pythonPath = with super; [ python3Packages.dnspython python3Packages.markdown tdb ldb talloc ];
       });
       });
   })];
   })];
Line 268: Line 354:
     # or if you have specified `uid` and `gid` explicitly through NixOS configuration,
     # or if you have specified `uid` and `gid` explicitly through NixOS configuration,
     # you can refer to them rather than hard-coding the values:
     # you can refer to them rather than hard-coding the values:
     # in ["${automount_opts},credentials=/etc/nixos/smb-secrets,${config.users.users.<username>.uid},gid=${config.users.groups.<group>.gid}"];
     # in ["${automount_opts},credentials=/etc/nixos/smb-secrets,uid=${toString config.users.users.<username>.uid},gid=${toString config.users.groups.<group>.gid}"];
   };
   };
}
}
Line 338: Line 424:
   services.gvfs = {
   services.gvfs = {
     enable = true;
     enable = true;
     package = lib.mkForce pkgs.gnome3.gvfs;
     package = lib.mkForce pkgs.gnome.gvfs;
   };
   };
</syntaxhighlight>
</syntaxhighlight>