nixpkgs/nixos/modules/services/network-filesystems/samba.nix

343 lines
12 KiB
Nix

{ config, lib, pkgs, ... }:
let
cfg = config.services.samba;
settingsFormat = pkgs.formats.ini {
listToValue = lib.concatMapStringsSep " " (lib.generators.mkValueStringDefault { });
};
# Ensure the global section is always first
globalConfigFile = settingsFormat.generate "smb-global.conf" { global = cfg.settings.global; };
sharesConfigFile = settingsFormat.generate "smb-shares.conf" (lib.removeAttrs cfg.settings [ "global" ]);
configFile = pkgs.concatText "smb.conf" [ globalConfigFile sharesConfigFile ];
in
{
meta = {
doc = ./samba.md;
maintainers = [ lib.maintainers.anthonyroussel ];
};
imports = [
(lib.mkRemovedOptionModule [ "services" "samba" "defaultShare" ] "")
(lib.mkRemovedOptionModule [ "services" "samba" "syncPasswordsByPam" ] "This option has been removed by upstream, see https://bugzilla.samba.org/show_bug.cgi?id=10669#c10")
(lib.mkRemovedOptionModule [ "services" "samba" "configText" ] ''
Use services.samba.settings instead.
This is part of the general move to use structured settings instead of raw
text for config as introduced by RFC0042:
https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md
'')
(lib.mkRemovedOptionModule [ "services" "samba" "extraConfig" ] "Use services.samba.settings instead.")
(lib.mkRenamedOptionModule [ "services" "samba" "invalidUsers" ] [ "services" "samba" "settings" "global" "invalid users" ])
(lib.mkRenamedOptionModule [ "services" "samba" "securityType" ] [ "services" "samba" "settings" "global" "security" ])
(lib.mkRenamedOptionModule [ "services" "samba" "shares" ] [ "services" "samba" "settings" ])
(lib.mkRenamedOptionModule [ "services" "samba" "enableWinbindd" ] [ "services" "samba" "winbindd" "enable" ])
(lib.mkRenamedOptionModule [ "services" "samba" "enableNmbd" ] [ "services" "samba" "nmbd" "enable" ])
];
###### interface
options = {
services.samba = {
enable = lib.mkEnableOption "Samba, the SMB/CIFS protocol";
package = lib.mkPackageOption pkgs "samba" {
example = "samba4Full";
};
openFirewall = lib.mkEnableOption "opening the default ports in the firewall for Samba";
smbd = {
enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to enable Samba's smbd daemon.";
};
extraArgs = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "Extra arguments to pass to the smbd service.";
};
};
nmbd = {
enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Whether to enable Samba's nmbd, which replies to NetBIOS over IP name
service requests. It also participates in the browsing protocols
which make up the Windows "Network Neighborhood" view.
'';
};
extraArgs = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "Extra arguments to pass to the nmbd service.";
};
};
winbindd = {
enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Whether to enable Samba's winbindd, which provides a number of services
to the Name Service Switch capability found in most modern C libraries,
to arbitrary applications via PAM and ntlm_auth and to Samba itself.
'';
};
extraArgs = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "Extra arguments to pass to the winbindd service.";
};
};
usershares = {
enable = lib.mkEnableOption "user-configurable Samba shares";
group = lib.mkOption {
type = lib.types.str;
default = "samba";
description = ''
Name of the group members of which will be allowed to create usershares.
The group will be created automatically.
'';
};
};
nsswins = lib.mkEnableOption ''
WINS NSS (Name Service Switch) plug-in.
Enabling it allows applications to resolve WINS/NetBIOS names (a.k.a.
Windows machine names) by transparently querying the winbindd daemon
'';
settings = lib.mkOption {
type = lib.types.submodule {
freeformType = settingsFormat.type;
options = {
global.security = lib.mkOption {
type = lib.types.enum [ "auto" "user" "domain" "ads" ];
default = "user";
description = "Samba security type.";
};
global."invalid users" = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ "root" ];
description = "List of users who are denied to login via Samba.";
};
global."passwd program" = lib.mkOption {
type = lib.types.str;
default = "/run/wrappers/bin/passwd %u";
description = "Path to a program that can be used to set UNIX user passwords.";
};
};
};
default = {
"global" = {
"security" = "user";
"passwd program" = "/run/wrappers/bin/passwd %u";
"invalid users" = [ "root" ];
};
};
example = {
"global" = {
"security" = "user";
"passwd program" = "/run/wrappers/bin/passwd %u";
"invalid users" = [ "root" ];
};
"public" = {
"path" = "/srv/public";
"read only" = "yes";
"browseable" = "yes";
"guest ok" = "yes";
"comment" = "Public samba share.";
};
};
description = ''
Configuration file for the Samba suite in ini format.
This file is located in /etc/samba/smb.conf
Refer to <https://www.samba.org/samba/docs/current/man-html/smb.conf.5.html>
for all available options.
'';
};
};
};
###### implementation
config = lib.mkMerge
[ { assertions =
[ { assertion = cfg.nsswins -> cfg.winbindd.enable;
message = "If services.samba.nsswins is enabled, then services.samba.winbindd.enable must also be enabled";
}
];
}
(lib.mkIf cfg.enable {
environment.etc."samba/smb.conf".source = configFile;
system.nssModules = lib.optional cfg.nsswins cfg.package;
system.nssDatabases.hosts = lib.optional cfg.nsswins "wins";
systemd = {
slices.system-samba = {
description = "Samba (SMB Networking Protocol) Slice";
};
targets.samba = {
description = "Samba Server";
after = [ "network.target" ];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
};
tmpfiles.rules = [
"d /var/lock/samba - - - - -"
"d /var/log/samba - - - - -"
"d /var/cache/samba - - - - -"
"d /var/lib/samba/private - - - - -"
];
};
security.pam.services.samba = {};
environment.systemPackages = [ cfg.package ];
# Like other mount* related commands that need the setuid bit, this is
# required too.
security.wrappers."mount.cifs" = {
program = "mount.cifs";
source = "${lib.getBin pkgs.cifs-utils}/bin/mount.cifs";
owner = "root";
group = "root";
setuid = true;
};
networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ 139 445 ];
networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall [ 137 138 ];
})
(lib.mkIf (cfg.enable && cfg.nmbd.enable) {
systemd.services.samba-nmbd = {
description = "Samba NMB Daemon";
documentation = [ "man:nmbd(8)" "man:samba(7)" "man:smb.conf(5)" ];
after = [
"network.target"
"network-online.target"
];
partOf = [ "samba.target" ];
wantedBy = [ "samba.target" ];
wants = [ "network-online.target" ];
environment.LD_LIBRARY_PATH = config.system.nssModules.path;
serviceConfig = {
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
ExecStart = "${cfg.package}/sbin/nmbd --foreground --no-process-group ${lib.escapeShellArgs cfg.nmbd.extraArgs}";
LimitCORE = "infinity";
PIDFile = "/run/samba/nmbd.pid";
Slice = "system-samba.slice";
Type = "notify";
};
unitConfig.RequiresMountsFor = "/var/lib/samba";
restartTriggers = [ configFile ];
};
})
(lib.mkIf (cfg.enable && cfg.smbd.enable) {
systemd.services.samba-smbd = {
description = "Samba SMB Daemon";
documentation = [ "man:smbd(8)" "man:samba(7)" "man:smb.conf(5)" ];
after = [
"network.target"
"network-online.target"
] ++ lib.optionals (cfg.nmbd.enable) [
"samba-nmbd.service"
] ++ lib.optionals (cfg.winbindd.enable) [
"samba-winbindd.service"
];
partOf = [ "samba.target" ];
wantedBy = [ "samba.target" ];
wants = [ "network-online.target" ];
environment.LD_LIBRARY_PATH = config.system.nssModules.path;
serviceConfig = {
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
ExecStart = "${cfg.package}/sbin/smbd --foreground --no-process-group ${lib.escapeShellArgs cfg.smbd.extraArgs}";
LimitCORE = "infinity";
LimitNOFILE = 16384;
PIDFile = "/run/samba/smbd.pid";
Slice = "system-samba.slice";
Type = "notify";
};
unitConfig.RequiresMountsFor = "/var/lib/samba";
restartTriggers = [ configFile ];
};
})
(lib.mkIf (cfg.enable && cfg.winbindd.enable) {
systemd.services.samba-winbindd = {
description = "Samba Winbind Daemon";
documentation = [ "man:winbindd(8)" "man:samba(7)" "man:smb.conf(5)" ];
after = [
"network.target"
] ++ lib.optionals (cfg.nmbd.enable) [
"samba-nmbd.service"
];
partOf = [ "samba.target" ];
wantedBy = [ "samba.target" ];
environment.LD_LIBRARY_PATH = config.system.nssModules.path;
serviceConfig = {
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
ExecStart = "${cfg.package}/sbin/winbindd --foreground --no-process-group ${lib.escapeShellArgs cfg.winbindd.extraArgs}";
LimitCORE = "infinity";
PIDFile = "/run/samba/winbindd.pid";
Slice = "system-samba.slice";
Type = "notify";
};
unitConfig.RequiresMountsFor = "/var/lib/samba";
restartTriggers = [ configFile ];
};
})
(lib.mkIf (cfg.enable && cfg.usershares.enable) {
users.groups.${cfg.usershares.group} = {};
systemd.tmpfiles.settings."50-samba-usershares"."/var/lib/samba/usershares".d = {
user = "root";
group = cfg.usershares.group;
mode = "1775"; # sticky so users can't delete others' shares
};
# set some reasonable defaults
services.samba.settings.global = lib.mkDefault {
"usershare path" = "/var/lib/samba/usershares";
"usershare max shares" = 100; # high enough to be considered ~unlimited
"usershare allow guests" = true;
};
})
];
}