From 12330f3cf274034ce4c9e917f76dd55d212aad07 Mon Sep 17 00:00:00 2001 From: doktornotor Date: Sat, 21 Jan 2017 00:25:21 +0100 Subject: [PATCH 01/18] pfSense-pkg-tftpd package improvements - Add option to bind to a single IP - Add option to force IPv4 only - Add option to specify the maximum permitted block size - Remove useless custom_add_php_command --- .../files/usr/local/pkg/tftpd.xml | 51 ++++++++++++++++--- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml b/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml index 1db5cdf8d92e..997bde396a3e 100644 --- a/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml +++ b/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml @@ -8,6 +8,7 @@ * tftpd.xml * * part of pfSense (https://www.pfsense.org) + * Copyright (c) 2015-2017 Rubicon Communications, LLC (Netgate) * Copyright (c) 2016 Stefan Seidel * All rights reserved. * @@ -44,15 +45,56 @@ Enable TFTP service tftpd_enable - Enable the TFTP service? + Check to enable the TFTP service. checkbox - Directory for files + Directory for Files datadir - Enter the directory path to the files that the TFTP server should serve. The directory must exist. Default: /tftpboot + + Default: /tftpboot + ]]> + input /tftpboot + + + + TFTP Server Bind IP + tftpd_ip + + + This must be a valid, locally configured IP address. + ]]> + + input + + + IPv4 Only + tftpd_ipv4only + Check to allow clients to connect with IPv4 only. + checkbox + + + Max Block Size + tftpd_blocksize + + The permitted range is from 512 to 65464. +
+ Some embedded clients request large block sizes and yet do not handle fragmented packets + correctly; for these clients, it is recommended to set this value to the smallest MTU + on your network minus 32 bytes (20 bytes for IP, 8 for UDP, and 4 for TFTP; less if you + use IP options on your network.)
+ For example, on a standard Ethernet (MTU 1500) a value of 1468 is reasonable. +
+ ]]> +
+ input
@@ -61,9 +103,6 @@ deinstall_package_tftpd(); - - sync_package_tftpd(); - sync_package_tftpd(); From e9c72f458f646115c4be2ccbd39e3dfade66adcf Mon Sep 17 00:00:00 2001 From: doktornotor Date: Sat, 21 Jan 2017 00:29:14 +0100 Subject: [PATCH 02/18] pfSense-pkg-tftpd package improvements - Add option to bind to a single IP - Add option to force IPv4 only - Add option to specify the maximum permitted block size - Remove unneeded includes - Use a PID file for the service - Remove useless filter_configure() call - Nuke the shipped startup scripts on install --- .../files/usr/local/pkg/tftpd.inc | 59 ++++++++++++++----- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.inc b/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.inc index 18322a8e5381..22a9e99e95d4 100644 --- a/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.inc +++ b/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.inc @@ -3,6 +3,7 @@ * tftpd.inc * * part of pfSense (https://www.pfsense.org) + * Copyright (c) 2015-2017 Rubicon Communications, LLC (Netgate) * Copyright (c) 2016 Stefan Seidel * All rights reserved. * @@ -19,17 +20,14 @@ * limitations under the License. */ -if (!function_exists("filter_configure")) { - require_once("filter.inc"); -} require_once("globals.inc"); -require_once("interfaces.inc"); require_once("pfsense-utils.inc"); require_once("service-utils.inc"); require_once("util.inc"); function install_package_tftpd() { safe_mkdir("/tftpboot"); + unlink_if_exists("/usr/local/etc/rc.d/tftpd"); } function deinstall_package_tftpd() { @@ -37,7 +35,7 @@ function deinstall_package_tftpd() { } function sync_package_tftpd() { - global $config; + global $g, $config; conf_mount_rw(); @@ -56,17 +54,35 @@ function sync_package_tftpd() { unlink_if_exists('/usr/local/etc/rc.d/tftpd.sh'); return; } - + + // Root directory $datadir = $tftpd_conf['datadir']; - - if (!is_dir($datadir)) { - log_error("TFTP files directory {$datadir} does not exist."); - return; - } + + // TFTP Server Bind IP + if (!empty($tftpd_conf['tftpd_ip'])) { + $address = $tftpd_conf['tftpd_ip']; + if (is_ipaddrv6($address)) { + $address = "-a [{$address}]"; + } else { + $address = "-a {$address}"; + } + } + + $pidfile = "{$g['varrun_path']}/tftpd-hpa.pid"; + + // IPv4 Only? + if ($tftpd_conf['tftpd_ipv4only'] == "on") { + $options = "-4"; + } + + // Max Block Size + if (!empty($tftpd_conf['tftpd_blocksize'])) { + $options .= " -B {$tftpd_conf['tftpd_blocksize']}"; + } write_rcfile(array( "file" => "tftpd.sh", - "start" => "/usr/local/libexec/in.tftpd -l -s {$datadir}", + "start" => "/usr/local/libexec/in.tftpd -l -s {$datadir} {$address} -P {$pidfile} {$options}", "stop" => "/usr/bin/killall in.tftpd" ) ); @@ -82,14 +98,29 @@ function sync_package_tftpd() { } conf_mount_ro(); - - filter_configure(); } function validate_form_tftpd($post, &$input_errors) { if ($post['datadir'] && !is_dir($post['datadir'])) { $input_errors[] = 'Directory for files does not exist!'; } + + if ($post['tftpd_ip']) { + if ($post['tftpd_ipv4only'] && !is_ipaddrv4($post['tftpd_ip'])) { + $input_errors[] = 'TFTP Server Bind IP must be a valid IPv4 address!'; + } elseif (!is_ipaddr($post['tftpd_ip'])) { + $input_errors[] = 'TFTP Server Bind IP must be a valid IP address!'; + } + if (!is_ipaddr_configured($post['tftpd_ip'])) { + $input_errors[] = "{$post['tftpd_ip']} TFTP Server Bind IP must be a valid, locally configured IP address!"; + } + } + + if ($post['tftpd_blocksize']) { + if (!is_numericint($post['tftpd_blocksize']) || ($post['tftpd_blocksize'] < 512) || ($post['tftpd_blocksize'] > 65464)) { + $input_errors[] = 'Max Block Size must be an integer with a permitted range from 512 to 65464!'; + } + } } ?> From 9859ff4b009b9287f073ff94fbb003a2e8e4f69d Mon Sep 17 00:00:00 2001 From: doktornotor Date: Sat, 21 Jan 2017 00:29:53 +0100 Subject: [PATCH 03/18] Bump port version --- ftp/pfSense-pkg-tftpd/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ftp/pfSense-pkg-tftpd/Makefile b/ftp/pfSense-pkg-tftpd/Makefile index 813a40703f09..7b72bda94274 100644 --- a/ftp/pfSense-pkg-tftpd/Makefile +++ b/ftp/pfSense-pkg-tftpd/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ PORTNAME= pfSense-pkg-tftpd -PORTVERSION= 0.1.2 +PORTVERSION= 0.1.3 CATEGORIES= ftp MASTER_SITES= # empty DISTFILES= # empty From bc486983ea96ddcc7f67623398c172c94e298eac Mon Sep 17 00:00:00 2001 From: doktornotor Date: Sat, 21 Jan 2017 04:11:32 +0100 Subject: [PATCH 04/18] Change priv name to match the menu section --- ftp/pfSense-pkg-tftpd/files/etc/inc/priv/tftpd.priv.inc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ftp/pfSense-pkg-tftpd/files/etc/inc/priv/tftpd.priv.inc b/ftp/pfSense-pkg-tftpd/files/etc/inc/priv/tftpd.priv.inc index 02c69918a2a1..fdc66a4b8d74 100644 --- a/ftp/pfSense-pkg-tftpd/files/etc/inc/priv/tftpd.priv.inc +++ b/ftp/pfSense-pkg-tftpd/files/etc/inc/priv/tftpd.priv.inc @@ -3,6 +3,7 @@ * tftpd.priv.inc * * part of pfSense (https://www.pfsense.org) + * Copyright (c) 2015-2017 Rubicon Communications, LLC (Netgate) * Copyright (c) 2016 Stefan Seidel * All rights reserved. * @@ -22,7 +23,7 @@ global $priv_list; $priv_list['page-system-tftpd'] = array(); -$priv_list['page-system-tftpd']['name'] = "WebCfg - System: tftpd package"; +$priv_list['page-system-tftpd']['name'] = "WebCfg - Services: tftpd package"; $priv_list['page-system-tftpd']['descr'] = "Allow access to tftpd package GUI"; $priv_list['page-system-tftpd']['match'] = array(); From 57a8304467115d35865209734aee79873b646f52 Mon Sep 17 00:00:00 2001 From: doktornotor Date: Sat, 21 Jan 2017 19:30:03 +0100 Subject: [PATCH 05/18] Re-add backup/restore/upload/delete functionality, fix install/deinstall --- .../files/usr/local/pkg/tftpd.inc | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.inc b/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.inc index 22a9e99e95d4..fd6d2bf258f0 100644 --- a/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.inc +++ b/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.inc @@ -25,13 +25,51 @@ require_once("pfsense-utils.inc"); require_once("service-utils.inc"); require_once("util.inc"); +/* Helper function for files listing */ +function tftp_byte_convert($bytes) { + if ($bytes <= 0) { + return '0 Byte'; + } + $convention = 1000; + $s = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB'); + $e = floor(log($bytes, $convention)); + return round($bytes/pow($convention, $e), 2) . ' ' . $s[$e]; +} + +/* Create backup of the TFTP server directory */ +function tftp_create_backup($trigger_download = false) { + global $backup_dir, $backup_path, $files_dir; + + conf_mount_rw(); + safe_mkdir("{$backup_dir}"); + if (mwexec("/usr/bin/tar -czC / -f {$backup_path} {$files_dir}") || !file_exists("{$backup_path}")) { + header("Location: tftp_files.php?savemsg=Backup+failed.&result=alert-warning"); + } elseif ($trigger_download == false) { + header("Location: tftp_files.php?savemsg=Backup+has+been+created"); + } + conf_mount_ro(); +} + function install_package_tftpd() { - safe_mkdir("/tftpboot"); + if (is_array($config['installedpackages']['tftpd'])) { + $tftpd_conf = &$config['installedpackages']['tftpd']['config'][0]; + } else { + $tftpd_conf = array(); + } + $datadir = ($tftpd_conf['datadir'] ?: '/tftpboot'); + safe_mkdir("{$datadir}"); unlink_if_exists("/usr/local/etc/rc.d/tftpd"); } function deinstall_package_tftpd() { - @rmdir("/tftpboot"); + if (is_array($config['installedpackages']['tftpd'])) { + $tftpd_conf = &$config['installedpackages']['tftpd']['config'][0]; + } else { + $tftpd_conf = array(); + } + $datadir = ($tftpd_conf['datadir'] ?: '/tftpboot'); + // Will only get removed when empty + @rmdir("{$datadir}"); } function sync_package_tftpd() { From 589160cce3fffca5817b4f4b64f3800e599eb56f Mon Sep 17 00:00:00 2001 From: doktornotor Date: Sat, 21 Jan 2017 19:37:31 +0100 Subject: [PATCH 06/18] Re-add backup/restore/upload/delete functionality --- ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml b/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml index 997bde396a3e..734a933ac34a 100644 --- a/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml +++ b/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml @@ -41,6 +41,17 @@ in.tftpd TFTP daemon + + + Settings + /pkg_edit.php?xml=tftpd.xml + + + + Files + /tftp_files.php + + Enable TFTP service From 8ca4fd36839884a1682d105f79ff66cc6d6c0b23 Mon Sep 17 00:00:00 2001 From: doktornotor Date: Sat, 21 Jan 2017 19:39:56 +0100 Subject: [PATCH 07/18] Re-add backup/restore/upload/delete functionality --- .../files/etc/inc/priv/tftpd.priv.inc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ftp/pfSense-pkg-tftpd/files/etc/inc/priv/tftpd.priv.inc b/ftp/pfSense-pkg-tftpd/files/etc/inc/priv/tftpd.priv.inc index fdc66a4b8d74..d731bc8a6a6d 100644 --- a/ftp/pfSense-pkg-tftpd/files/etc/inc/priv/tftpd.priv.inc +++ b/ftp/pfSense-pkg-tftpd/files/etc/inc/priv/tftpd.priv.inc @@ -22,11 +22,12 @@ global $priv_list; -$priv_list['page-system-tftpd'] = array(); -$priv_list['page-system-tftpd']['name'] = "WebCfg - Services: tftpd package"; -$priv_list['page-system-tftpd']['descr'] = "Allow access to tftpd package GUI"; -$priv_list['page-system-tftpd']['match'] = array(); +$priv_list['page-services-tftpd'] = array(); +$priv_list['page-services-tftpd']['name'] = "WebCfg - Services: tftpd package"; +$priv_list['page-services-tftpd']['descr'] = "Allow access to tftpd package GUI"; +$priv_list['page-services-tftpd']['match'] = array(); -$priv_list['page-system-tftpd']['match'][] = "pkg_edit.php?xml=tftpd.xml*"; +$priv_list['page-services-tftpd']['match'][] = "pkg_edit.php?xml=tftpd.xml*"; +$priv_list['page-services-tftpd']['match'][] = "tftp_files.php*"; ?> From 97b210fc9095f8360c16a1276fc108c38c1bc725 Mon Sep 17 00:00:00 2001 From: doktornotor Date: Sat, 21 Jan 2017 19:45:24 +0100 Subject: [PATCH 08/18] Re-add backup/restore/upload/delete functionality --- .../files/usr/local/www/tftp_files.php | 229 ++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 ftp/pfSense-pkg-tftpd/files/usr/local/www/tftp_files.php diff --git a/ftp/pfSense-pkg-tftpd/files/usr/local/www/tftp_files.php b/ftp/pfSense-pkg-tftpd/files/usr/local/www/tftp_files.php new file mode 100644 index 000000000000..912ffda34b76 --- /dev/null +++ b/ftp/pfSense-pkg-tftpd/files/usr/local/www/tftp_files.php @@ -0,0 +1,229 @@ + + +
+

+
+ + +
+ + + + + + + + + + $file): ?> + + + + + + + + + +
File NameLast ModifiedSizeActions
+ + + + + + +
+
+
+ + + +
+ + From d88217a5b474feee6523b9551982d5a45e6a20ce Mon Sep 17 00:00:00 2001 From: doktornotor Date: Sat, 21 Jan 2017 19:49:28 +0100 Subject: [PATCH 09/18] Re-add backup/restore/upload/delete functionality --- ftp/pfSense-pkg-tftpd/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ftp/pfSense-pkg-tftpd/Makefile b/ftp/pfSense-pkg-tftpd/Makefile index 7b72bda94274..b60581d3d3e7 100644 --- a/ftp/pfSense-pkg-tftpd/Makefile +++ b/ftp/pfSense-pkg-tftpd/Makefile @@ -25,12 +25,15 @@ do-extract: do-install: ${MKDIR} ${STAGEDIR}${PREFIX}/pkg + ${MKDIR} ${STAGEDIR}${PREFIX}/www ${MKDIR} ${STAGEDIR}/etc/inc/priv ${MKDIR} ${STAGEDIR}${DATADIR} ${INSTALL_DATA} -m 0644 ${FILESDIR}${PREFIX}/pkg/tftpd.xml \ ${STAGEDIR}${PREFIX}/pkg ${INSTALL_DATA} ${FILESDIR}${PREFIX}/pkg/tftpd.inc \ ${STAGEDIR}${PREFIX}/pkg + ${INSTALL_DATA} -m 0755 ${FILESDIR}${PREFIX}/www/tftp_files.php \ + ${STAGEDIR}${PREFIX}/www ${INSTALL_DATA} ${FILESDIR}/etc/inc/priv/tftpd.priv.inc \ ${STAGEDIR}/etc/inc/priv ${INSTALL_DATA} ${FILESDIR}${DATADIR}/info.xml \ From 74ae3e1f17ec022227c59a070792f5e030895f65 Mon Sep 17 00:00:00 2001 From: doktornotor Date: Sat, 21 Jan 2017 19:51:37 +0100 Subject: [PATCH 10/18] Re-add backup/restore/upload/delete functionality --- ftp/pfSense-pkg-tftpd/pkg-plist | 1 + 1 file changed, 1 insertion(+) diff --git a/ftp/pfSense-pkg-tftpd/pkg-plist b/ftp/pfSense-pkg-tftpd/pkg-plist index a28d1b2bcab5..3678b5b309a9 100644 --- a/ftp/pfSense-pkg-tftpd/pkg-plist +++ b/ftp/pfSense-pkg-tftpd/pkg-plist @@ -1,6 +1,7 @@ /etc/inc/priv/tftpd.priv.inc pkg/tftpd.inc pkg/tftpd.xml +www/tftp_files.php %%DATADIR%%/info.xml @dir /etc/inc/priv @dir /etc/inc From 92edca390a6dc63cfeb37c2bc6f2106558b4195f Mon Sep 17 00:00:00 2001 From: doktornotor Date: Sat, 21 Jan 2017 19:54:25 +0100 Subject: [PATCH 11/18] Rename the menu entry --- ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml b/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml index 734a933ac34a..41518f6fe9ec 100644 --- a/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml +++ b/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml @@ -31,7 +31,7 @@ /usr/local/pkg/tftpd.inc /pkg_edit.php?xml=tftpd.xml - tftpd + TFTP Server
Services
/pkg_edit.php?xml=tftpd.xml
From 8b98d75724e1ceea3344d05e47a5fd7424f21e62 Mon Sep 17 00:00:00 2001 From: doktornotor Date: Sat, 21 Jan 2017 20:06:49 +0100 Subject: [PATCH 12/18] Whitespace fixes --- ftp/pfSense-pkg-tftpd/files/usr/local/www/tftp_files.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ftp/pfSense-pkg-tftpd/files/usr/local/www/tftp_files.php b/ftp/pfSense-pkg-tftpd/files/usr/local/www/tftp_files.php index 912ffda34b76..f9e37ea914fe 100644 --- a/ftp/pfSense-pkg-tftpd/files/usr/local/www/tftp_files.php +++ b/ftp/pfSense-pkg-tftpd/files/usr/local/www/tftp_files.php @@ -141,9 +141,9 @@ ?>
-

-
- +

+
+
@@ -190,7 +190,7 @@
@@ -206,7 +207,7 @@ - From af4dac7876fdec3352857d58b6545795124423e0 Mon Sep 17 00:00:00 2001 From: doktornotor Date: Sun, 22 Jan 2017 01:37:24 +0100 Subject: [PATCH 14/18] Do not allow "/" to be used as files directory --- ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.inc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.inc b/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.inc index fd6d2bf258f0..1f75a1583123 100644 --- a/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.inc +++ b/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.inc @@ -143,6 +143,10 @@ function validate_form_tftpd($post, &$input_errors) { $input_errors[] = 'Directory for files does not exist!'; } + if ($post['datadir'] == '/') { + $input_errors[] = 'Setting "/" as directory for files is not allowed!'; + } + if ($post['tftpd_ip']) { if ($post['tftpd_ipv4only'] && !is_ipaddrv4($post['tftpd_ip'])) { $input_errors[] = 'TFTP Server Bind IP must be a valid IPv4 address!'; From 397fb5a21ef8991b9ad3cedf7799bb887f4b6c3a Mon Sep 17 00:00:00 2001 From: doktornotor Date: Mon, 23 Jan 2017 19:00:07 +0100 Subject: [PATCH 15/18] Code sanitizations and cleanup - Hardcode /tftpboot for security reasons. If custom location is desired, it can be changed by patching the FILES_DIR here. Notify users on upgrade in case they need to relocate their TFTP server files. Remove no longer needed input validation. - Remove pointless tftp_byte_convert() and use format_bytes() from util.inc - Use define() and constants instead of variables for hardcoded locations - Move code for restoring a backup here. - Move code to check whether users are trying to download/delete files that are out of the TFTP directory here. - Add an escapeshellarg() for block size. --- .../files/usr/local/pkg/tftpd.inc | 85 +++++++++++-------- 1 file changed, 51 insertions(+), 34 deletions(-) diff --git a/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.inc b/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.inc index 1f75a1583123..cae4bdd93ef0 100644 --- a/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.inc +++ b/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.inc @@ -21,28 +21,25 @@ */ require_once("globals.inc"); +require_once("notices.inc"); require_once("pfsense-utils.inc"); require_once("service-utils.inc"); require_once("util.inc"); -/* Helper function for files listing */ -function tftp_byte_convert($bytes) { - if ($bytes <= 0) { - return '0 Byte'; - } - $convention = 1000; - $s = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB'); - $e = floor(log($bytes, $convention)); - return round($bytes/pow($convention, $e), 2) . ' ' . $s[$e]; -} +/* Define some locations */ +define('BACKUP_DIR', '/root/backup'); +define('BACKUP_FILENAME', 'tftp.bak.tgz'); +define('BACKUP_PATH', BACKUP_DIR . '/' . BACKUP_FILENAME); +/* Change FILES_DIR below if you really need TFTP files directory elsewhere. + * Note: Such modifications are completely unsupported! + */ +define('FILES_DIR', '/tftpboot'); /* Create backup of the TFTP server directory */ function tftp_create_backup($trigger_download = false) { - global $backup_dir, $backup_path, $files_dir; - conf_mount_rw(); - safe_mkdir("{$backup_dir}"); - if (mwexec("/usr/bin/tar -czC / -f {$backup_path} {$files_dir}") || !file_exists("{$backup_path}")) { + safe_mkdir(BACKUP_DIR); + if (mwexec("/usr/bin/tar -czC / -f " . BACKUP_PATH . " " . FILES_DIR) || !file_exists(BACKUP_PATH)) { header("Location: tftp_files.php?savemsg=Backup+failed.&result=alert-warning"); } elseif ($trigger_download == false) { header("Location: tftp_files.php?savemsg=Backup+has+been+created"); @@ -50,26 +47,52 @@ function tftp_create_backup($trigger_download = false) { conf_mount_ro(); } -function install_package_tftpd() { - if (is_array($config['installedpackages']['tftpd'])) { - $tftpd_conf = &$config['installedpackages']['tftpd']['config'][0]; +/* Restore backup of the TFTP server directory */ +function tftp_restore_backup() { + if (file_exists(BACKUP_PATH)) { + conf_mount_rw(); + mwexec("/usr/bin/tar -xpzC / -f " . BACKUP_PATH); + header("Location: tftp_files.php?savemsg=Backup+has+been+restored."); + conf_mount_ro(); } else { - $tftpd_conf = array(); + header("Location: tftp_files.php?savemsg=Restore+failed.+Backup+file+not+found.&result=alert-warning"); + } +} + +/* Only allow to download files under the FILES_DIR */ +function tftp_filesdir_bounds_check($filename, $error_msg) { + $basedirlength = strlen(FILES_DIR); + if (substr($filename, 0, $basedirlength) !== FILES_DIR) { + log_error("[tftpd] {$error_msg}"); + file_notice("tftpd", "{$error_msg}", "Packages"); + return false; + } else { + return true; } - $datadir = ($tftpd_conf['datadir'] ?: '/tftpboot'); - safe_mkdir("{$datadir}"); +} + +function install_package_tftpd() { + safe_mkdir(FILES_DIR); unlink_if_exists("/usr/local/etc/rc.d/tftpd"); + upgrade_config_tftpd(); } function deinstall_package_tftpd() { + // Will only get removed when empty + @rmdir(FILES_DIR); +} + +function upgrade_config_tftpd() { + // FILES_DIR is not configurable any more if (is_array($config['installedpackages']['tftpd'])) { $tftpd_conf = &$config['installedpackages']['tftpd']['config'][0]; } else { $tftpd_conf = array(); } - $datadir = ($tftpd_conf['datadir'] ?: '/tftpboot'); - // Will only get removed when empty - @rmdir("{$datadir}"); + if (!empty($tftpd_conf['datadir']) && $tftpd_conf['datadir'] !== FILES_DIR) { + file_notice("tftpd", "Please, move your TFTP server files from {$tftpd_conf['datadir']} to /tftpboot", "Packages"); + unset($config['installedpackages']['tftpd']['config'][0]['datadir']); + } } function sync_package_tftpd() { @@ -94,15 +117,17 @@ function sync_package_tftpd() { } // Root directory - $datadir = $tftpd_conf['datadir']; + $datadir = FILES_DIR; // TFTP Server Bind IP if (!empty($tftpd_conf['tftpd_ip'])) { $address = $tftpd_conf['tftpd_ip']; if (is_ipaddrv6($address)) { $address = "-a [{$address}]"; - } else { + } elseif (is_ipaddrv4($address)) { $address = "-a {$address}"; + } else { + $address = ""; } } @@ -115,7 +140,7 @@ function sync_package_tftpd() { // Max Block Size if (!empty($tftpd_conf['tftpd_blocksize'])) { - $options .= " -B {$tftpd_conf['tftpd_blocksize']}"; + $options .= " -B " . escapeshellarg($tftpd_conf['tftpd_blocksize']); } write_rcfile(array( @@ -139,14 +164,6 @@ function sync_package_tftpd() { } function validate_form_tftpd($post, &$input_errors) { - if ($post['datadir'] && !is_dir($post['datadir'])) { - $input_errors[] = 'Directory for files does not exist!'; - } - - if ($post['datadir'] == '/') { - $input_errors[] = 'Setting "/" as directory for files is not allowed!'; - } - if ($post['tftpd_ip']) { if ($post['tftpd_ipv4only'] && !is_ipaddrv4($post['tftpd_ip'])) { $input_errors[] = 'TFTP Server Bind IP must be a valid IPv4 address!'; From fe2af9c1db380f765a63bfc6c01ecde0247b6837 Mon Sep 17 00:00:00 2001 From: doktornotor Date: Mon, 23 Jan 2017 19:01:28 +0100 Subject: [PATCH 16/18] Remove 'Directory for Files' setting; /tftpboot is now hardcoded for security reasons. --- ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml b/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml index 41518f6fe9ec..f321230fd527 100644 --- a/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml +++ b/ftp/pfSense-pkg-tftpd/files/usr/local/pkg/tftpd.xml @@ -59,19 +59,6 @@ Check to enable the TFTP service. checkbox - - Directory for Files - datadir - - Default: /tftpboot - ]]> - - input - /tftpboot - - TFTP Server Bind IP tftpd_ip From a35a2b80c766d9d7aecf213b2aea97a61d290054 Mon Sep 17 00:00:00 2001 From: doktornotor Date: Mon, 23 Jan 2017 19:07:18 +0100 Subject: [PATCH 17/18] Code sanitizations and cleanup - The hardcoded locations are now defined() in tftp.inc - Use format_bytes() from util.inc - Fix the logic for full backup download and rename the button accordingly - Code to code whether users are trying to download/delete files that are out of the TFTP directory here was moved to a function in tftp.inc - Added bunch of htmlspecialchars() protections as requested --- .../files/usr/local/www/tftp_files.php | 94 ++++++++++--------- 1 file changed, 51 insertions(+), 43 deletions(-) diff --git a/ftp/pfSense-pkg-tftpd/files/usr/local/www/tftp_files.php b/ftp/pfSense-pkg-tftpd/files/usr/local/www/tftp_files.php index 80abc5e0c5da..dc301154a2f7 100644 --- a/ftp/pfSense-pkg-tftpd/files/usr/local/www/tftp_files.php +++ b/ftp/pfSense-pkg-tftpd/files/usr/local/www/tftp_files.php @@ -26,14 +26,6 @@ require_once("util.inc"); require_once("/usr/local/pkg/tftpd.inc"); -/* Define some locations */ -$backup_dir = "/root/backup"; -$backup_filename = "tftp.bak.tgz"; -$backup_path = "{$backup_dir}/{$backup_filename}"; -$files_dir = $config['installedpackages']['tftpd']['config'][0]['datadir']; -$filename = htmlspecialchars($_GET['filename']); -$download_dir = $files_dir; - /* Trigger full backup creation */ if ($_GET['a'] == "other" && $_GET['t'] == "backup") { tftp_create_backup(); @@ -42,27 +34,37 @@ /* Download full backup or individual files */ if ($_GET['a'] == "download") { if ($_GET['t'] == "backup") { - // Create backup first if it does not exist yet - if (!file_exists("{$backup_path}")) { - tftp_create_backup(true); - } - // Download full TFTP server backup from $backup_dir - $desc = $backup_path; - $filename = $backup_filename; + // Create backup first + tftp_create_backup(true); + // Download full TFTP server backup from BACKUP_DIR + $desc = BACKUP_PATH; + $filename = BACKUP_FILENAME; } else { - // Download a single file from $files_dir - // Only allow to download files under the $files_dir! - $basedirlength = strlen($files_dir); - if (substr($filename, 0, $basedirlength) !== "{$files_dir}") { + // Download a single file from FILES_DIR + // Only allow to download files under the FILES_DIR + $filename = htmlspecialchars($_GET['filename']); + $error_msg = "Attempt to download files outside of TFTP server directory rejected!"; + if (!tftp_filesdir_bounds_check($filename, $error_msg)) { + header("Location: tftp_files.php"); + return; + } else { + $desc = $filename; + $filename = basename($filename); + } + /* + $basedirlength = strlen(FILES_DIR); + $filename = htmlspecialchars($_GET['filename']); + if (substr($filename, 0, $basedirlength) !== FILES_DIR) { $error_msg = "Attempt to download files outside of TFTP server directory rejected!"; log_error("[tftpd] {$error_msg}"); - file_notice("tftpd", $error_msg, "Packages"); + file_notice("tftpd", "{$error_msg}", "Packages"); header("Location: tftp_files.php"); return; } else { $desc = $filename; $filename = basename($filename); } + */ } session_cache_limiter('public'); @@ -81,15 +83,8 @@ /* Restore TFTP server backup */ if ($_GET['a'] == "other" && $_GET['t'] == "restore") { - if (file_exists($backup_path)) { - conf_mount_rw(); - mwexec("/usr/bin/tar -xpzC / -f {$backup_path}"); - header("Location: tftp_files.php?savemsg=Backup+has+been+restored."); - conf_mount_ro(); - } else { - header("Location: tftp_files.php?savemsg=Restore+failed.+Backup+file+not+found.&result=alert-warning"); - } - exit; + tftp_restore_backup(); + exit; } /* Upload files to TFTP server */ @@ -98,7 +93,7 @@ conf_mount_rw(); $tmp_name = $_FILES["tftpd_fileup"]["tmp_name"]; $name = basename($_FILES["tftpd_fileup"]["name"]); - move_uploaded_file($tmp_name, "{$files_dir}/{$name}"); + move_uploaded_file($tmp_name, FILES_DIR . "/{$name}"); conf_mount_ro(); } else { $input_errors[] = gettext("Failed to upload file {$_FILES["tftpd_fileup"]["name"]}"); @@ -110,9 +105,20 @@ if ($_GET['type'] == 'tftp') { conf_mount_rw(); $filename = htmlspecialchars($_GET['filename']); - // Only delete files under the $files_dir! - $basedirlength = strlen($files_dir); - if (substr($filename, 0, $basedirlength) !== "{$files_dir}") { + $error_msg = "Attempt to delete files outside of TFTP server directory rejected!"; + if (!tftp_filesdir_bounds_check($filename, $error_msg)) { + header("Location: tftp_files.php"); + return; + } else { + unlink_if_exists("{$filename}"); + conf_mount_ro(); + header("Location: tftp_files.php"); + exit; + } + /* + // Only delete files under the FILES_DIR! + $basedirlength = strlen(FILES_DIR); + if (substr($filename, 0, $basedirlength) !== FILES_DIR) { $error_msg = "Attempt to delete files outside of TFTP server directory rejected!"; log_error("[tftpd] {$error_msg}"); file_notice("tftpd", $error_msg, "Packages"); @@ -124,6 +130,7 @@ header("Location: tftp_files.php"); exit; } + */ } } @@ -153,20 +160,20 @@ Actions - + $file): ?> - + - + + href='?type=tftp&act=del&filename=' style="cursor: pointer;" text="delete this"> + href='tftp_files.php?a=download&filename=' style="cursor: pointer;"> @@ -207,18 +214,19 @@ - - + - - - + From ea93c1e5787d2202fc777344307bae431ac6dfa6 Mon Sep 17 00:00:00 2001 From: doktornotor Date: Mon, 23 Jan 2017 19:13:13 +0100 Subject: [PATCH 18/18] Remove commented out code leftovers; moved to tftp.inc --- .../files/usr/local/www/tftp_files.php | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/ftp/pfSense-pkg-tftpd/files/usr/local/www/tftp_files.php b/ftp/pfSense-pkg-tftpd/files/usr/local/www/tftp_files.php index dc301154a2f7..e614ae2697ef 100644 --- a/ftp/pfSense-pkg-tftpd/files/usr/local/www/tftp_files.php +++ b/ftp/pfSense-pkg-tftpd/files/usr/local/www/tftp_files.php @@ -51,20 +51,6 @@ $desc = $filename; $filename = basename($filename); } - /* - $basedirlength = strlen(FILES_DIR); - $filename = htmlspecialchars($_GET['filename']); - if (substr($filename, 0, $basedirlength) !== FILES_DIR) { - $error_msg = "Attempt to download files outside of TFTP server directory rejected!"; - log_error("[tftpd] {$error_msg}"); - file_notice("tftpd", "{$error_msg}", "Packages"); - header("Location: tftp_files.php"); - return; - } else { - $desc = $filename; - $filename = basename($filename); - } - */ } session_cache_limiter('public'); @@ -115,22 +101,6 @@ header("Location: tftp_files.php"); exit; } - /* - // Only delete files under the FILES_DIR! - $basedirlength = strlen(FILES_DIR); - if (substr($filename, 0, $basedirlength) !== FILES_DIR) { - $error_msg = "Attempt to delete files outside of TFTP server directory rejected!"; - log_error("[tftpd] {$error_msg}"); - file_notice("tftpd", $error_msg, "Packages"); - header("Location: tftp_files.php"); - return; - } else { - unlink_if_exists("{$filename}"); - conf_mount_ro(); - header("Location: tftp_files.php"); - exit; - } - */ } }