Add vsftpd service
This commit is contained in:
parent
465225cc62
commit
fc920c4556
|
@ -197,4 +197,14 @@ in
|
|||
inherit createManagedProcess runtimeDir tmpDir libDir forceDisableUserChange callingUser;
|
||||
inherit (pkgs) lib xinetd writeTextFile;
|
||||
};
|
||||
|
||||
vsftpd = import ./vsftpd {
|
||||
inherit createManagedProcess;
|
||||
inherit (pkgs) vsftpd;
|
||||
};
|
||||
|
||||
simpleVsftpd = import ./vsftpd/simple.nix {
|
||||
inherit createManagedProcess forceDisableUserChange logDir libDir callingUser callingGroup;
|
||||
inherit (pkgs) stdenv vsftpd writeTextFile lib;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
{createManagedProcess, vsftpd}:
|
||||
{instanceSuffix ? "", instanceName ? "vsftpd${instanceSuffix}", initialize ? "", configFile}:
|
||||
|
||||
let
|
||||
user = instanceName;
|
||||
group = instanceName;
|
||||
in
|
||||
createManagedProcess {
|
||||
inherit instanceName initialize;
|
||||
|
||||
foregroundProcess = "${vsftpd}/bin/vsftpd";
|
||||
args = [ configFile ];
|
||||
|
||||
credentials = {
|
||||
groups = {
|
||||
"${group}" = {};
|
||||
};
|
||||
users = {
|
||||
"${user}" = {
|
||||
inherit group;
|
||||
description = "vsftpd user";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
overrides = {
|
||||
sysvinit = {
|
||||
runlevels = [ 3 4 5 ];
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
{createManagedProcess, stdenv, vsftpd, writeTextFile, lib, logDir, libDir, forceDisableUserChange, callingUser, callingGroup}:
|
||||
|
||||
{ instanceSuffix ? ""
|
||||
, instanceName ? "vsftpd${instanceSuffix}"
|
||||
, dataPort ? 20
|
||||
, listenPort ? dataPort + 1
|
||||
, options ? {}
|
||||
, enableAnonymousUser ? false
|
||||
, anonymousUsername ? "ftp"
|
||||
, anonymousRoot ? if forceDisableUserChange then "/home/${callingUser}" else "/home/${anonymousUsername}"
|
||||
}:
|
||||
|
||||
let
|
||||
user = instanceName;
|
||||
group = instanceName;
|
||||
|
||||
vsftpdLogDir = "${logDir}/${instanceName}";
|
||||
|
||||
configFile = writeTextFile {
|
||||
name = "vsftpd.conf";
|
||||
text =
|
||||
lib.optionalString (stdenv.isLinux) ''
|
||||
seccomp_sandbox=NO
|
||||
''
|
||||
+
|
||||
''
|
||||
vsftpd_log_file=${vsftpdLogDir}/vsftpd.log
|
||||
xferlog_file=${vsftpdLogDir}/xferlog
|
||||
'' +
|
||||
(if forceDisableUserChange then ''
|
||||
run_as_launching_user=YES
|
||||
ftp_username=${callingUser}
|
||||
'' else ''
|
||||
nopriv_user=${user}
|
||||
ftp_username=${if enableAnonymousUser then anonymousUsername else "nobody"}
|
||||
pam_service_name=vsftpd
|
||||
secure_chroot_dir=/var/empty
|
||||
'')
|
||||
+ ''
|
||||
ftp_data_port=${toString dataPort}
|
||||
listen_port=${toString listenPort}
|
||||
''
|
||||
+ lib.optionalString enableAnonymousUser ''
|
||||
anon_root=${anonymousRoot}
|
||||
''
|
||||
+ lib.concatMapStrings (name:
|
||||
let
|
||||
value = builtins.getAttr name options;
|
||||
in
|
||||
"${name}=${toString value}\n"
|
||||
) (builtins.attrNames options);
|
||||
};
|
||||
in
|
||||
import ./default.nix {
|
||||
inherit createManagedProcess vsftpd;
|
||||
} {
|
||||
inherit instanceSuffix instanceName;
|
||||
|
||||
# When running as unprivileged user, we need to make a copy of the config file and make the calling user the owner
|
||||
configFile = if forceDisableUserChange then "${libDir}/${instanceName}/vsftpd.conf" else configFile;
|
||||
|
||||
initialize =
|
||||
''
|
||||
mkdir -p ${vsftpdLogDir}
|
||||
''
|
||||
+
|
||||
# Make the unprivileged user the owner of the config file
|
||||
lib.optionalString forceDisableUserChange
|
||||
(let
|
||||
dynamicConfigFile = "${libDir}/${instanceName}/vsftpd.conf";
|
||||
in
|
||||
''
|
||||
mkdir -p ${libDir}/${instanceName}
|
||||
cp ${configFile} ${dynamicConfigFile}
|
||||
chmod u+w ${dynamicConfigFile}
|
||||
chown ${callingUser}:${callingGroup} ${dynamicConfigFile}
|
||||
'');
|
||||
}
|
|
@ -104,4 +104,8 @@ in
|
|||
xinetd-extendable = import ./xinetd/extendable {
|
||||
inherit pkgs processManagers profiles testService nix-processmgmt;
|
||||
};
|
||||
|
||||
vsftpd = import ./vsftpd {
|
||||
inherit pkgs processManagers profiles testService nix-processmgmt;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
{ pkgs, testService, processManagers, profiles, nix-processmgmt }:
|
||||
|
||||
testService {
|
||||
exprFile = ./processes.nix;
|
||||
extraParams = {
|
||||
inherit nix-processmgmt;
|
||||
};
|
||||
|
||||
nixosConfig = {
|
||||
users.users.ftp = {
|
||||
description = "Anonymous FTP user";
|
||||
isNormalUser = true;
|
||||
createHome = true;
|
||||
password = "secret";
|
||||
};
|
||||
};
|
||||
|
||||
systemPackages = [ pkgs.inetutils ];
|
||||
|
||||
readiness = {instanceName, instance, ...}:
|
||||
''
|
||||
machine.wait_for_open_port(${toString instance.listenPort})
|
||||
'';
|
||||
|
||||
tests = {instanceName, instance, forceDisableUserChange, ...}:
|
||||
if forceDisableUserChange then ''
|
||||
machine.succeed("echo test > /home/unprivileged/test.txt")
|
||||
machine.succeed("chown unprivileged:users /home/unprivileged/test.txt")
|
||||
machine.succeed('(echo "user anonymous foobar"; echo "ls") | ftp -n 127.0.0.1 ${toString instance.listenPort} >&2')
|
||||
machine.succeed("curl --fail ftp://anonymous@localhost:${toString instance.listenPort}/test.txt -o test.txt")
|
||||
machine.succeed("grep test test.txt")
|
||||
machine.succeed("rm test.txt")
|
||||
'' else ''
|
||||
machine.succeed("echo test > /home/ftp/test.txt")
|
||||
machine.succeed("chown ftp:users /home/ftp/test.txt")
|
||||
machine.succeed("chmod a-w /home/ftp")
|
||||
machine.succeed('(echo "user anonymous foobar"; echo "ls") | ftp -n 127.0.0.1 ${pkgs.lib.optionalString (instance.listenPort != 21) (toString instance.listenPort)} >&2')
|
||||
machine.succeed("curl -v --fail ftp://anonymous@localhost${pkgs.lib.optionalString (instance.listenPort != 21) ":${toString instance.listenPort}"}/test.txt -o test.txt 2>&1")
|
||||
machine.succeed("grep test test.txt")
|
||||
machine.succeed("rm test.txt")
|
||||
'';
|
||||
|
||||
inherit processManagers profiles;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
{ pkgs ? import <nixpkgs> { inherit system; }
|
||||
, system ? builtins.currentSystem
|
||||
, stateDir ? "/var"
|
||||
, runtimeDir ? "${stateDir}/run"
|
||||
, logDir ? "${stateDir}/log"
|
||||
, spoolDir ? "${stateDir}/spool"
|
||||
, cacheDir ? "${stateDir}/cache"
|
||||
, libDir ? "${stateDir}/lib"
|
||||
, tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
|
||||
, forceDisableUserChange ? false
|
||||
, callingUser ? null
|
||||
, callingGroup ? null
|
||||
, processManager
|
||||
, nix-processmgmt ? ../../../nix-processmgmt
|
||||
}:
|
||||
|
||||
let
|
||||
constructors = import ../../services-agnostic/constructors.nix {
|
||||
inherit pkgs stateDir runtimeDir logDir tmpDir cacheDir libDir spoolDir forceDisableUserChange callingUser callingGroup processManager nix-processmgmt;
|
||||
};
|
||||
in
|
||||
{
|
||||
vsftpd = rec {
|
||||
dataPort = if forceDisableUserChange then 2000 else 20;
|
||||
listenPort = if forceDisableUserChange then 2001 else 21;
|
||||
|
||||
pkg = constructors.simpleVsftpd {
|
||||
inherit dataPort listenPort;
|
||||
enableAnonymousUser = true;
|
||||
options = {
|
||||
dual_log_enable = "YES";
|
||||
local_enable = "YES";
|
||||
anon_world_readable_only = "NO";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
vsftpd-secondary = rec {
|
||||
dataPort = if forceDisableUserChange then 2010 else 30;
|
||||
listenPort = if forceDisableUserChange then 2011 else 31;
|
||||
|
||||
pkg = constructors.simpleVsftpd {
|
||||
inherit dataPort listenPort;
|
||||
enableAnonymousUser = true;
|
||||
|
||||
instanceSuffix = "-secondary";
|
||||
options = {
|
||||
dual_log_enable = "YES";
|
||||
local_enable = "YES";
|
||||
anon_world_readable_only = "NO";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue