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 };
84
85 package = mkOption {
86 type = types.package;
87 default = pkgs.samba;
88 example = pkgs.samba4;
89 description = ''
90 Defines which package should be used for the samba server.
91 '';
92 };
93
94 syncPasswordsByPam = mkOption {
95 type = types.bool;
96 default = false;
97 description = ''
98 Enabling this will add a line directly after pam_unix.so.
99 Whenever a password is changed the samba password will be updated as well.
100 However you still yave to add the samba password once using smbpasswd -a user
101 If you don't want to maintain an extra pwd database you still can send plain text
102 passwords which is not secure.
103 '';
104 };
105
106 invalidUsers = mkOption {
107 type = types.listOf types.str;
108 default = [ "root" ];
109 description = ''
110 List of users who are denied to login via Samba.
111 '';
112 };
113
114 extraConfig = mkOption {
115 type = types.lines;
116 default = "";
117 description = ''
118 Additional global section and extra section lines go in here.
119 '';
120 };
121
122 configText = mkOption {
123 type = types.nullOr types.lines;
124 default = null;
125 description = ''
126 Verbatim contents of smb.conf. If null (default), use the
127 autogenerated file from NixOS instead.
128 '';
129 };
130
131 securityType = mkOption {
132 type = types.str;
133 default = "user";
134 example = "share";
135 description = "Samba security type";
136 };
137
138 nsswins = mkOption {
139 default = false;
140 type = types.bool;
141 description = ''
142 Whether to enable the WINS NSS (Name Service Switch) plug-in.
143 Enabling it allows applications to resolve WINS/NetBIOS names (a.k.a.
144 Windows machine names) by transparently querying the winbindd daemon.
145 '';
146 };
147
148 shares = mkOption {
149 default = {};
150 description = ''
151 A set describing shared resources.
152 See <command>man smb.conf</command> for options.
153 '';
154 type = types.attrsOf (types.attrsOf types.unspecified);
155 example =
156 { srv =
157 { path = "/srv";
158 "read only" = true;
159 comment = "Public samba share.";
160 };
161 };
162 };
163
164 };
165
166 };
167
168
169 ###### implementation
170
171 config = mkMerge
172 [ { # Always provide a smb.conf to shut up programs like smbclient and smbspool.
173 environment.etc = singleton
174 { source =
175 if cfg.enable then configFile
176 else pkgs.writeText "smb-dummy.conf" "# Samba is disabled.";
177 target = "samba/smb.conf";
178 };
179 }
180
181 (mkIf config.services.samba.enable {
182
183 system.nssModules = optional cfg.nsswins samba;
184
185 systemd = {
186 targets.samba = {
187 description = "Samba Server";
188 requires = [ "samba-setup.service" ];
189 after = [ "samba-setup.service" "network.target" ];
190 wantedBy = [ "multi-user.target" ];
191 };
192
193 services = {
194 "samba-nmbd" = daemonService "nmbd" "-F";
195 "samba-smbd" = daemonService "smbd" "-F";
196 "samba-winbindd" = daemonService "winbindd" "-F";
197 "samba-setup" = {
198 description = "Samba Setup Task";
199 script = setupScript;
200 unitConfig.RequiresMountsFor = "/var/lib/samba";
201 };
202 };
203 };
204
205 security.pam.services.sambda = {};
206
207 })
208 ];
209
210}