1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 smbToString = x: if builtins.typeOf x == "bool" 8 then boolToString x 9 else toString x; 10 11 cfg = config.services.samba; 12 13 samba = cfg.package; 14 15 shareConfig = name: 16 let share = getAttr name cfg.shares; in 17 "[${name}]\n " + (smbToString ( 18 map 19 (key: "${key} = ${smbToString (getAttr key share)}\n") 20 (attrNames share) 21 )); 22 23 configFile = pkgs.writeText "smb.conf" 24 (if cfg.configText != null then cfg.configText else 25 '' 26 [global] 27 security = ${cfg.securityType} 28 passwd program = /run/wrappers/bin/passwd %u 29 invalid users = ${smbToString cfg.invalidUsers} 30 31 ${cfg.extraConfig} 32 33 ${smbToString (map shareConfig (attrNames cfg.shares))} 34 ''); 35 36 # This may include nss_ldap, needed for samba if it has to use ldap. 37 nssModulesPath = config.system.nssModules.path; 38 39 daemonService = appName: args: 40 { description = "Samba Service Daemon ${appName}"; 41 42 after = [ (mkIf (cfg.enableNmbd && "${appName}" == "smbd") "samba-nmbd.service") "network.target" ]; 43 requiredBy = [ "samba.target" ]; 44 partOf = [ "samba.target" ]; 45 46 environment = { 47 LD_LIBRARY_PATH = nssModulesPath; 48 LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive"; 49 }; 50 51 serviceConfig = { 52 ExecStart = "${samba}/sbin/${appName} --foreground --no-process-group ${args}"; 53 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; 54 LimitNOFILE = 16384; 55 PIDFile = "/run/${appName}.pid"; 56 Type = "notify"; 57 NotifyAccess = "all"; #may not do anything... 58 }; 59 unitConfig.RequiresMountsFor = "/var/lib/samba"; 60 61 restartTriggers = [ configFile ]; 62 }; 63 64in 65 66{ 67 imports = [ 68 (mkRemovedOptionModule [ "services" "samba" "defaultShare" ] "") 69 (mkRemovedOptionModule [ "services" "samba" "syncPasswordsByPam" ] "This option has been removed by upstream, see https://bugzilla.samba.org/show_bug.cgi?id=10669#c10") 70 ]; 71 72 ###### interface 73 74 options = { 75 76 # !!! clean up the descriptions. 77 78 services.samba = { 79 80 enable = mkOption { 81 type = types.bool; 82 default = false; 83 description = '' 84 Whether to enable Samba, which provides file and print 85 services to Windows clients through the SMB/CIFS protocol. 86 87 ::: {.note} 88 If you use the firewall consider adding the following: 89 90 services.samba.openFirewall = true; 91 ::: 92 ''; 93 }; 94 95 openFirewall = mkOption { 96 type = types.bool; 97 default = false; 98 description = '' 99 Whether to automatically open the necessary ports in the firewall. 100 ''; 101 }; 102 103 enableNmbd = mkOption { 104 type = types.bool; 105 default = true; 106 description = '' 107 Whether to enable Samba's nmbd, which replies to NetBIOS over IP name 108 service requests. It also participates in the browsing protocols 109 which make up the Windows "Network Neighborhood" view. 110 ''; 111 }; 112 113 enableWinbindd = mkOption { 114 type = types.bool; 115 default = true; 116 description = '' 117 Whether to enable Samba's winbindd, which provides a number of services 118 to the Name Service Switch capability found in most modern C libraries, 119 to arbitrary applications via PAM and ntlm_auth and to Samba itself. 120 ''; 121 }; 122 123 package = mkPackageOption pkgs "samba" { 124 example = "samba4Full"; 125 }; 126 127 invalidUsers = mkOption { 128 type = types.listOf types.str; 129 default = [ "root" ]; 130 description = '' 131 List of users who are denied to login via Samba. 132 ''; 133 }; 134 135 extraConfig = mkOption { 136 type = types.lines; 137 default = ""; 138 description = '' 139 Additional global section and extra section lines go in here. 140 ''; 141 example = '' 142 guest account = nobody 143 map to guest = bad user 144 ''; 145 }; 146 147 configText = mkOption { 148 type = types.nullOr types.lines; 149 default = null; 150 description = '' 151 Verbatim contents of smb.conf. If null (default), use the 152 autogenerated file from NixOS instead. 153 ''; 154 }; 155 156 securityType = mkOption { 157 type = types.enum [ "auto" "user" "domain" "ads" ]; 158 default = "user"; 159 description = "Samba security type"; 160 }; 161 162 nsswins = mkOption { 163 default = false; 164 type = types.bool; 165 description = '' 166 Whether to enable the WINS NSS (Name Service Switch) plug-in. 167 Enabling it allows applications to resolve WINS/NetBIOS names (a.k.a. 168 Windows machine names) by transparently querying the winbindd daemon. 169 ''; 170 }; 171 172 shares = mkOption { 173 default = {}; 174 description = '' 175 A set describing shared resources. 176 See {command}`man smb.conf` for options. 177 ''; 178 type = types.attrsOf (types.attrsOf types.unspecified); 179 example = literalExpression '' 180 { public = 181 { path = "/srv/public"; 182 "read only" = true; 183 browseable = "yes"; 184 "guest ok" = "yes"; 185 comment = "Public samba share."; 186 }; 187 } 188 ''; 189 }; 190 191 }; 192 193 }; 194 195 196 ###### implementation 197 198 config = mkMerge 199 [ { assertions = 200 [ { assertion = cfg.nsswins -> cfg.enableWinbindd; 201 message = "If samba.nsswins is enabled, then samba.enableWinbindd must also be enabled"; 202 } 203 ]; 204 # Always provide a smb.conf to shut up programs like smbclient and smbspool. 205 environment.etc."samba/smb.conf".source = mkOptionDefault ( 206 if cfg.enable then configFile 207 else pkgs.writeText "smb-dummy.conf" "# Samba is disabled." 208 ); 209 } 210 211 (mkIf cfg.enable { 212 213 system.nssModules = optional cfg.nsswins samba; 214 system.nssDatabases.hosts = optional cfg.nsswins "wins"; 215 216 systemd = { 217 targets.samba = { 218 description = "Samba Server"; 219 after = [ "network.target" ]; 220 wants = [ "network-online.target" ]; 221 wantedBy = [ "multi-user.target" ]; 222 }; 223 # Refer to https://github.com/samba-team/samba/tree/master/packaging/systemd 224 # for correct use with systemd 225 services = { 226 samba-smbd = daemonService "smbd" ""; 227 samba-nmbd = mkIf cfg.enableNmbd (daemonService "nmbd" ""); 228 samba-winbindd = mkIf cfg.enableWinbindd (daemonService "winbindd" ""); 229 }; 230 tmpfiles.rules = [ 231 "d /var/lock/samba - - - - -" 232 "d /var/log/samba - - - - -" 233 "d /var/cache/samba - - - - -" 234 "d /var/lib/samba/private - - - - -" 235 ]; 236 }; 237 238 security.pam.services.samba = {}; 239 environment.systemPackages = [ cfg.package ]; 240 241 networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ 139 445 ]; 242 networking.firewall.allowedUDPPorts = mkIf cfg.openFirewall [ 137 138 ]; 243 }) 244 ]; 245 246}