vuls: init at 0.27.0
[NixPkgs.git] / nixos / modules / services / networking / vsftpd.nix
blob07b93e92a750998b74cf77212028c2e7eb56b7f9
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
7   /* minimal secure setup:
9    enable = true;
10    forceLocalLoginsSSL = true;
11    forceLocalDataSSL = true;
12    userlistDeny = false;
13    localUsers = true;
14    userlist = ["non-root-user" "other-non-root-user"];
15    rsaCertFile = "/var/vsftpd/vsftpd.pem";
17   */
19   cfg = config.services.vsftpd;
21   inherit (pkgs) vsftpd;
23   yesNoOption = nixosName: vsftpdName: default: description: {
24     cfgText = "${vsftpdName}=${if getAttr nixosName cfg then "YES" else "NO"}";
26     nixosOption = {
27       type = types.bool;
28       name = nixosName;
29       value = mkOption {
30         description = description;
31         inherit default;
32         type = types.bool;
33       };
34     };
35   };
37   optionDescription = [
38     (yesNoOption "allowWriteableChroot" "allow_writeable_chroot" false ''
39       Allow the use of writeable root inside chroot().
40     '')
41     (yesNoOption "virtualUseLocalPrivs" "virtual_use_local_privs" false ''
42       If enabled, virtual users will use the same privileges as local
43       users. By default, virtual users will use the same privileges as
44       anonymous users, which tends to be more restrictive (especially
45       in terms of write access).
46     '')
47     (yesNoOption "anonymousUser" "anonymous_enable" false ''
48       Whether to enable the anonymous FTP user.
49     '')
50     (yesNoOption "anonymousUserNoPassword" "no_anon_password" false ''
51       Whether to disable the password for the anonymous FTP user.
52     '')
53     (yesNoOption "localUsers" "local_enable" false ''
54       Whether to enable FTP for local users.
55     '')
56     (yesNoOption "writeEnable" "write_enable" false ''
57       Whether any write activity is permitted to users.
58     '')
59     (yesNoOption "anonymousUploadEnable" "anon_upload_enable" false ''
60       Whether any uploads are permitted to anonymous users.
61     '')
62     (yesNoOption "anonymousMkdirEnable" "anon_mkdir_write_enable" false ''
63       Whether any uploads are permitted to anonymous users.
64     '')
65     (yesNoOption "chrootlocalUser" "chroot_local_user" false ''
66       Whether local users are confined to their home directory.
67     '')
68     (yesNoOption "userlistEnable" "userlist_enable" false ''
69       Whether users are included.
70     '')
71     (yesNoOption "userlistDeny" "userlist_deny" false ''
72       Specifies whether {option}`userlistFile` is a list of user
73       names to allow or deny access.
74       The default `false` means whitelist/allow.
75     '')
76     (yesNoOption "forceLocalLoginsSSL" "force_local_logins_ssl" false ''
77       Only applies if {option}`sslEnable` is true. Non anonymous (local) users
78       must use a secure SSL connection to send a password.
79     '')
80     (yesNoOption "forceLocalDataSSL" "force_local_data_ssl" false ''
81       Only applies if {option}`sslEnable` is true. Non anonymous (local) users
82       must use a secure SSL connection for sending/receiving data on data connection.
83     '')
84     (yesNoOption "portPromiscuous" "port_promiscuous" false ''
85       Set to YES if you want to disable the PORT security check that ensures that
86       outgoing data connections can only connect to the client. Only enable if you
87       know what you are doing!
88     '')
89     (yesNoOption "ssl_tlsv1" "ssl_tlsv1" true  ''
90       Only applies if {option}`ssl_enable` is activated. If
91       enabled, this option will permit TLS v1 protocol connections.
92       TLS v1 connections are preferred.
93     '')
94     (yesNoOption "ssl_sslv2" "ssl_sslv2" false ''
95       Only applies if {option}`ssl_enable` is activated. If
96       enabled, this option will permit SSL v2 protocol connections.
97       TLS v1 connections are preferred.
98     '')
99     (yesNoOption "ssl_sslv3" "ssl_sslv3" false ''
100       Only applies if {option}`ssl_enable` is activated. If
101       enabled, this option will permit SSL v3 protocol connections.
102       TLS v1 connections are preferred.
103     '')
104   ];
106   configFile = pkgs.writeText "vsftpd.conf"
107     ''
108       ${concatMapStrings (x: "${x.cfgText}\n") optionDescription}
109       ${optionalString (cfg.rsaCertFile != null) ''
110         ssl_enable=YES
111         rsa_cert_file=${cfg.rsaCertFile}
112       ''}
113       ${optionalString (cfg.rsaKeyFile != null) ''
114         rsa_private_key_file=${cfg.rsaKeyFile}
115       ''}
116       ${optionalString (cfg.userlistFile != null) ''
117         userlist_file=${cfg.userlistFile}
118       ''}
119       background=YES
120       listen=NO
121       listen_ipv6=YES
122       nopriv_user=vsftpd
123       secure_chroot_dir=/var/empty
124       ${optionalString (cfg.localRoot != null) ''
125         local_root=${cfg.localRoot}
126       ''}
127       syslog_enable=YES
128       ${optionalString (pkgs.stdenv.hostPlatform.system == "x86_64-linux") ''
129         seccomp_sandbox=NO
130       ''}
131       anon_umask=${cfg.anonymousUmask}
132       ${optionalString cfg.anonymousUser ''
133         anon_root=${cfg.anonymousUserHome}
134       ''}
135       ${optionalString cfg.enableVirtualUsers ''
136         guest_enable=YES
137         guest_username=vsftpd
138       ''}
139       pam_service_name=vsftpd
140       ${cfg.extraConfig}
141     '';
147   ###### interface
149   options = {
151     services.vsftpd = {
153       enable = mkEnableOption "vsftpd";
155       userlist = mkOption {
156         default = [];
157         type = types.listOf types.str;
158         description = "See {option}`userlistFile`.";
159       };
161       userlistFile = mkOption {
162         type = types.path;
163         default = pkgs.writeText "userlist" (concatMapStrings (x: "${x}\n") cfg.userlist);
164         defaultText = literalExpression ''pkgs.writeText "userlist" (concatMapStrings (x: "''${x}\n") cfg.userlist)'';
165         description = ''
166           Newline separated list of names to be allowed/denied if {option}`userlistEnable`
167           is `true`. Meaning see {option}`userlistDeny`.
169           The default is a file containing the users from {option}`userlist`.
171           If explicitly set to null userlist_file will not be set in vsftpd's config file.
172         '';
173       };
175       enableVirtualUsers = mkOption {
176         type = types.bool;
177         default = false;
178         description = ''
179           Whether to enable the `pam_userdb`-based
180           virtual user system
181         '';
182       };
184       userDbPath = mkOption {
185         type = types.nullOr types.str;
186         example = "/etc/vsftpd/userDb";
187         default = null;
188         description = ''
189           Only applies if {option}`enableVirtualUsers` is true.
190           Path pointing to the `pam_userdb` user
191           database used by vsftpd to authenticate the virtual users.
193           This user list should be stored in the Berkeley DB database
194           format.
196           To generate a new user database, create a text file, add
197           your users using the following format:
198           ```
199           user1
200           password1
201           user2
202           password2
203           ```
205           You can then install `pkgs.db` to generate
206           the Berkeley DB using
207           ```
208           db_load -T -t hash -f logins.txt userDb.db
209           ```
211           Caution: `pam_userdb` will automatically
212           append a `.db` suffix to the filename you
213           provide though this option. This option shouldn't include
214           this filetype suffix.
215         '';
216       };
218       localRoot = mkOption {
219         type = types.nullOr types.str;
220         default = null;
221         example = "/var/www/$USER";
222         description = ''
223           This option represents a directory which vsftpd will try to
224           change into after a local (i.e. non- anonymous) login.
226           Failure is silently ignored.
227         '';
228       };
230       anonymousUserHome = mkOption {
231         type = types.path;
232         default = "/home/ftp/";
233         description = ''
234           Directory to consider the HOME of the anonymous user.
235         '';
236       };
238       rsaCertFile = mkOption {
239         type = types.nullOr types.path;
240         default = null;
241         description = "RSA certificate file.";
242       };
244       rsaKeyFile = mkOption {
245         type = types.nullOr types.path;
246         default = null;
247         description = "RSA private key file.";
248       };
250       anonymousUmask = mkOption {
251         type = types.str;
252         default = "077";
253         example = "002";
254         description = "Anonymous write umask.";
255       };
257       extraConfig = mkOption {
258         type = types.lines;
259         default = "";
260         example = "ftpd_banner=Hello";
261         description = "Extra configuration to add at the bottom of the generated configuration file.";
262       };
264     } // (listToAttrs (catAttrs "nixosOption" optionDescription));
266   };
269   ###### implementation
271   config = mkIf cfg.enable {
273     assertions = [
274       { assertion =
275               (cfg.forceLocalLoginsSSL -> cfg.rsaCertFile != null)
276           &&  (cfg.forceLocalDataSSL -> cfg.rsaCertFile != null);
277         message = "vsftpd: If forceLocalLoginsSSL or forceLocalDataSSL is true then a rsaCertFile must be provided!";
278       }
279       {
280         assertion = (cfg.enableVirtualUsers -> cfg.userDbPath != null)
281                  && (cfg.enableVirtualUsers -> cfg.localUsers);
282         message = "vsftpd: If enableVirtualUsers is true, you need to setup both the userDbPath and localUsers options.";
283       }];
285     users.users = {
286       "vsftpd" = {
287         group = "vsftpd";
288         isSystemUser = true;
289         description = "VSFTPD user";
290         home = if cfg.localRoot != null
291                then cfg.localRoot # <= Necessary for virtual users.
292                else "/homeless-shelter";
293       };
294     } // optionalAttrs cfg.anonymousUser {
295       "ftp" = { name = "ftp";
296           uid = config.ids.uids.ftp;
297           group = "ftp";
298           description = "Anonymous FTP user";
299           home = cfg.anonymousUserHome;
300         };
301     };
303     users.groups.vsftpd = {};
304     users.groups.ftp.gid = config.ids.gids.ftp;
306     # If you really have to access root via FTP use mkOverride or userlistDeny
307     # = false and whitelist root
308     services.vsftpd.userlist = optional cfg.userlistDeny "root";
310     systemd = {
311       tmpfiles.rules = optional cfg.anonymousUser
312         #Type Path                       Mode User   Gr    Age Arg
313         "d    '${builtins.toString cfg.anonymousUserHome}' 0555 'ftp'  'ftp' -   -";
314       services.vsftpd = {
315         description = "Vsftpd Server";
317         wantedBy = [ "multi-user.target" ];
319         serviceConfig.ExecStart = "@${vsftpd}/sbin/vsftpd vsftpd ${configFile}";
320         serviceConfig.Restart = "always";
321         serviceConfig.Type = "forking";
322       };
323     };
325     security.pam.services.vsftpd.text = mkIf (cfg.enableVirtualUsers && cfg.userDbPath != null)''
326       auth required pam_userdb.so db=${cfg.userDbPath}
327       account required pam_userdb.so db=${cfg.userDbPath}
328     '';
329   };