1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 smbToString = x: if builtins.typeOf x == "bool" 8 then (if x then "true" else "false") 9 else toString x; 10 11 cfg = config.services.samba; 12 13 samba = cfg.package; 14 15 setupScript = 16 '' 17 mkdir -p /var/lock/samba /var/log/samba /var/cache/samba /var/lib/samba/private 18 ''; 19 20 shareConfig = name: 21 let share = getAttr name cfg.shares; in 22 "[${name}]\n " + (smbToString ( 23 map 24 (key: "${key} = ${smbToString (getAttr key share)}\n") 25 (attrNames share) 26 )); 27 28 configFile = pkgs.writeText "smb.conf" 29 (if cfg.configText != null then cfg.configText else 30 '' 31 [ global ] 32 security = ${cfg.securityType} 33 passwd program = /var/setuid-wrappers/passwd %u 34 pam password change = ${smbToString cfg.syncPasswordsByPam} 35 invalid users = ${smbToString cfg.invalidUsers} 36 37 ${cfg.extraConfig} 38 39 ${smbToString (map shareConfig (attrNames cfg.shares))} 40 ''); 41 42 # This may include nss_ldap, needed for samba if it has to use ldap. 43 nssModulesPath = config.system.nssModules.path; 44 45 daemonService = appName: args: 46 { description = "Samba Service Daemon ${appName}"; 47 48 requiredBy = [ "samba.target" ]; 49 partOf = [ "samba.target" ]; 50 51 environment = { 52 LD_LIBRARY_PATH = nssModulesPath; 53 LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive"; 54 }; 55 56 serviceConfig = { 57 ExecStart = "${samba}/sbin/${appName} ${args}"; 58 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; 59 }; 60 61 restartTriggers = [ configFile ]; 62 }; 63 64in 65 66{ 67 68 ###### interface 69 70 options = { 71 72 # !!! clean up the descriptions. 73 74 services.samba = { 75 76 enable = mkOption { 77 type = types.bool; 78 default = false; 79 description = '' 80 Whether to enable Samba, which provides file and print 81 services to Windows clients through the SMB/CIFS protocol. 82 83 <note> 84 <para>If you use the firewall consider adding the following:</para> 85 <programlisting> 86 networking.firewall.allowedTCPPorts = [ 139 445 ]; 87 networking.firewall.allowedUDPPorts = [ 137 138 ]; 88 </programlisting> 89 </note> 90 ''; 91 }; 92 93 package = mkOption { 94 type = types.package; 95 default = pkgs.samba; 96 defaultText = "pkgs.samba"; 97 example = literalExample "pkgs.samba3"; 98 description = '' 99 Defines which package should be used for the samba server. 100 ''; 101 }; 102 103 syncPasswordsByPam = mkOption { 104 type = types.bool; 105 default = false; 106 description = '' 107 Enabling this will add a line directly after pam_unix.so. 108 Whenever a password is changed the samba password will be updated as well. 109 However, you still have to add the samba password once, using smbpasswd -a user. 110 If you don't want to maintain an extra password database, you still can send plain text 111 passwords which is not secure. 112 ''; 113 }; 114 115 invalidUsers = mkOption { 116 type = types.listOf types.str; 117 default = [ "root" ]; 118 description = '' 119 List of users who are denied to login via Samba. 120 ''; 121 }; 122 123 extraConfig = mkOption { 124 type = types.lines; 125 default = ""; 126 description = '' 127 Additional global section and extra section lines go in here. 128 ''; 129 example = '' 130 guest account = nobody 131 map to guest = bad user 132 ''; 133 }; 134 135 configText = mkOption { 136 type = types.nullOr types.lines; 137 default = null; 138 description = '' 139 Verbatim contents of smb.conf. If null (default), use the 140 autogenerated file from NixOS instead. 141 ''; 142 }; 143 144 securityType = mkOption { 145 type = types.str; 146 default = "user"; 147 example = "share"; 148 description = "Samba security type"; 149 }; 150 151 nsswins = mkOption { 152 default = false; 153 type = types.bool; 154 description = '' 155 Whether to enable the WINS NSS (Name Service Switch) plug-in. 156 Enabling it allows applications to resolve WINS/NetBIOS names (a.k.a. 157 Windows machine names) by transparently querying the winbindd daemon. 158 ''; 159 }; 160 161 shares = mkOption { 162 default = {}; 163 description = '' 164 A set describing shared resources. 165 See <command>man smb.conf</command> for options. 166 ''; 167 type = types.attrsOf (types.attrsOf types.unspecified); 168 example = 169 { public = 170 { path = "/srv/public"; 171 "read only" = true; 172 browseable = "yes"; 173 "guest ok" = "yes"; 174 comment = "Public samba share."; 175 }; 176 }; 177 }; 178 179 }; 180 181 }; 182 183 184 ###### implementation 185 186 config = mkMerge 187 [ { # Always provide a smb.conf to shut up programs like smbclient and smbspool. 188 environment.etc = singleton 189 { source = 190 if cfg.enable then configFile 191 else pkgs.writeText "smb-dummy.conf" "# Samba is disabled."; 192 target = "samba/smb.conf"; 193 }; 194 } 195 196 (mkIf config.services.samba.enable { 197 198 system.nssModules = optional cfg.nsswins samba; 199 200 systemd = { 201 targets.samba = { 202 description = "Samba Server"; 203 requires = [ "samba-setup.service" ]; 204 after = [ "samba-setup.service" "network.target" ]; 205 wantedBy = [ "multi-user.target" ]; 206 }; 207 208 services = { 209 "samba-nmbd" = daemonService "nmbd" "-F"; 210 "samba-smbd" = daemonService "smbd" "-F"; 211 "samba-winbindd" = daemonService "winbindd" "-F"; 212 "samba-setup" = { 213 description = "Samba Setup Task"; 214 script = setupScript; 215 unitConfig.RequiresMountsFor = "/var/lib/samba"; 216 }; 217 }; 218 }; 219 220 security.pam.services.sambda = {}; 221 222 }) 223 ]; 224 225}