at 17.09-beta 7.2 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 /* minimal secure setup: 8 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"; 16 17 */ 18 19 cfg = config.services.vsftpd; 20 21 inherit (pkgs) vsftpd; 22 23 yesNoOption = nixosName: vsftpdName: default: description: { 24 cfgText = "${vsftpdName}=${if getAttr nixosName cfg then "YES" else "NO"}"; 25 26 nixosOption = { 27 type = types.bool; 28 name = nixosName; 29 value = mkOption { 30 inherit description default; 31 type = types.bool; 32 }; 33 }; 34 }; 35 36 optionDescription = [ 37 (yesNoOption "anonymousUser" "anonymous_enable" false '' 38 Whether to enable the anonymous FTP user. 39 '') 40 (yesNoOption "anonymousUserNoPassword" "no_anon_password" false '' 41 Whether to disable the password for the anonymous FTP user. 42 '') 43 (yesNoOption "localUsers" "local_enable" false '' 44 Whether to enable FTP for local users. 45 '') 46 (yesNoOption "writeEnable" "write_enable" false '' 47 Whether any write activity is permitted to users. 48 '') 49 (yesNoOption "anonymousUploadEnable" "anon_upload_enable" false '' 50 Whether any uploads are permitted to anonymous users. 51 '') 52 (yesNoOption "anonymousMkdirEnable" "anon_mkdir_write_enable" false '' 53 Whether any uploads are permitted to anonymous users. 54 '') 55 (yesNoOption "chrootlocalUser" "chroot_local_user" false '' 56 Whether local users are confined to their home directory. 57 '') 58 (yesNoOption "userlistEnable" "userlist_enable" false '' 59 Whether users are included. 60 '') 61 (yesNoOption "userlistDeny" "userlist_deny" false '' 62 Specifies whether <option>userlistFile</option> is a list of user 63 names to allow or deny access. 64 The default <literal>false</literal> means whitelist/allow. 65 '') 66 (yesNoOption "forceLocalLoginsSSL" "force_local_logins_ssl" false '' 67 Only applies if <option>sslEnable</option> is true. Non anonymous (local) users 68 must use a secure SSL connection to send a password. 69 '') 70 (yesNoOption "forceLocalDataSSL" "force_local_data_ssl" false '' 71 Only applies if <option>sslEnable</option> is true. Non anonymous (local) users 72 must use a secure SSL connection for sending/receiving data on data connection. 73 '') 74 (yesNoOption "portPromiscuous" "port_promiscuous" false '' 75 Set to YES if you want to disable the PORT security check that ensures that 76 outgoing data connections can only connect to the client. Only enable if you 77 know what you are doing! 78 '') 79 (yesNoOption "ssl_tlsv1" "ssl_tlsv1" true '' '') 80 (yesNoOption "ssl_sslv2" "ssl_sslv2" false '' '') 81 (yesNoOption "ssl_sslv3" "ssl_sslv3" false '' '') 82 ]; 83 84 configFile = pkgs.writeText "vsftpd.conf" 85 '' 86 ${concatMapStrings (x: "${x.cfgText}\n") optionDescription} 87 ${optionalString (cfg.rsaCertFile != null) '' 88 ssl_enable=YES 89 rsa_cert_file=${cfg.rsaCertFile} 90 ''} 91 ${optionalString (cfg.rsaKeyFile != null) '' 92 rsa_private_key_file=${cfg.rsaKeyFile} 93 ''} 94 ${optionalString (cfg.userlistFile != null) '' 95 userlist_file=${cfg.userlistFile} 96 ''} 97 background=YES 98 listen=YES 99 nopriv_user=vsftpd 100 secure_chroot_dir=/var/empty 101 syslog_enable=YES 102 ${optionalString (pkgs.stdenv.system == "x86_64-linux") '' 103 seccomp_sandbox=NO 104 ''} 105 anon_umask=${cfg.anonymousUmask} 106 ${optionalString cfg.anonymousUser '' 107 anon_root=${cfg.anonymousUserHome} 108 ''} 109 ${cfg.extraConfig} 110 ''; 111 112in 113 114{ 115 116 ###### interface 117 118 options = { 119 120 services.vsftpd = { 121 122 enable = mkOption { 123 default = false; 124 description = "Whether to enable the vsftpd FTP server."; 125 }; 126 127 userlist = mkOption { 128 default = []; 129 description = "See <option>userlistFile</option>."; 130 }; 131 132 userlistFile = mkOption { 133 type = types.path; 134 default = pkgs.writeText "userlist" (concatMapStrings (x: "${x}\n") cfg.userlist); 135 defaultText = "pkgs.writeText \"userlist\" (concatMapStrings (x: \"\${x}\n\") cfg.userlist)"; 136 description = '' 137 Newline separated list of names to be allowed/denied if <option>userlistEnable</option> 138 is <literal>true</literal>. Meaning see <option>userlistDeny</option>. 139 140 The default is a file containing the users from <option>userlist</option>. 141 142 If explicitely set to null userlist_file will not be set in vsftpd's config file. 143 ''; 144 }; 145 146 anonymousUserHome = mkOption { 147 type = types.path; 148 default = "/home/ftp/"; 149 description = '' 150 Directory to consider the HOME of the anonymous user. 151 ''; 152 }; 153 154 rsaCertFile = mkOption { 155 type = types.nullOr types.path; 156 default = null; 157 description = "RSA certificate file."; 158 }; 159 160 rsaKeyFile = mkOption { 161 type = types.nullOr types.path; 162 default = null; 163 description = "RSA private key file."; 164 }; 165 166 anonymousUmask = mkOption { 167 type = types.string; 168 default = "077"; 169 example = "002"; 170 description = "Anonymous write umask."; 171 }; 172 173 extraConfig = mkOption { 174 type = types.lines; 175 default = ""; 176 example = "ftpd_banner=Hello"; 177 description = "Extra configuration to add at the bottom of the generated configuration file."; 178 }; 179 180 } // (listToAttrs (catAttrs "nixosOption" optionDescription)); 181 182 }; 183 184 185 ###### implementation 186 187 config = mkIf cfg.enable { 188 189 assertions = singleton 190 { assertion = 191 (cfg.forceLocalLoginsSSL -> cfg.rsaCertFile != null) 192 && (cfg.forceLocalDataSSL -> cfg.rsaCertFile != null); 193 message = "vsftpd: If forceLocalLoginsSSL or forceLocalDataSSL is true then a rsaCertFile must be provided!"; 194 }; 195 196 users.extraUsers = 197 [ { name = "vsftpd"; 198 uid = config.ids.uids.vsftpd; 199 description = "VSFTPD user"; 200 home = "/homeless-shelter"; 201 } 202 ] ++ optional cfg.anonymousUser 203 { name = "ftp"; 204 uid = config.ids.uids.ftp; 205 group = "ftp"; 206 description = "Anonymous FTP user"; 207 home = cfg.anonymousUserHome; 208 }; 209 210 users.extraGroups.ftp.gid = config.ids.gids.ftp; 211 212 # If you really have to access root via FTP use mkOverride or userlistDeny 213 # = false and whitelist root 214 services.vsftpd.userlist = if cfg.userlistDeny then ["root"] else []; 215 216 systemd.services.vsftpd = 217 { description = "Vsftpd Server"; 218 219 wantedBy = [ "multi-user.target" ]; 220 221 preStart = 222 optionalString cfg.anonymousUser 223 '' 224 mkdir -p -m 555 ${cfg.anonymousUserHome} 225 chown -R ftp:ftp ${cfg.anonymousUserHome} 226 ''; 227 228 serviceConfig.ExecStart = "@${vsftpd}/sbin/vsftpd vsftpd ${configFile}"; 229 serviceConfig.Restart = "always"; 230 serviceConfig.Type = "forking"; 231 }; 232 233 }; 234 235}