[Git][debian-proftpd-team/proftpd][1.3.5b] ..and now the patch
Hilmar Preuße
gitlab at salsa.debian.org
Sat Aug 3 10:26:57 BST 2019
Hilmar Preuße pushed to branch 1.3.5b at Debian ProFTPD Team / proftpd
Commits:
774b745c by Hilmar Preusse at 2019-08-03T09:25:38Z
..and now the patch
- - - - -
1 changed file:
- + debian/patches/proftpd-1.3.5e-CVE-2019-12815.patch
Changes:
=====================================
debian/patches/proftpd-1.3.5e-CVE-2019-12815.patch
=====================================
@@ -0,0 +1,363 @@
+Index: proftpd-dfsg-1.3.5b/contrib/mod_copy.c
+===================================================================
+--- proftpd-dfsg-1.3.5b.orig/contrib/mod_copy.c 2016-03-11 02:04:32.000000000 +0100
++++ proftpd-dfsg-1.3.5b/contrib/mod_copy.c 2019-08-01 11:54:43.000000000 +0200
+@@ -2,7 +2,7 @@
+ * ProFTPD: mod_copy -- a module supporting copying of files on the server
+ * without transferring the data to the client and back
+ *
+- * Copyright (c) 2009-2015 TJ Saunders
++ * Copyright (c) 2009-2019 TJ Saunders
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+@@ -565,7 +565,7 @@
+ MODRET copy_cpfr(cmd_rec *cmd) {
+ register unsigned int i;
+ int res;
+- char *path = "";
++ char *cmd_name, *path = "";
+ unsigned char *authenticated = NULL;
+
+ if (copy_engine == FALSE) {
+@@ -596,6 +596,20 @@
+ pr_fs_decode_path(cmd->tmp_pool, cmd->argv[i]), NULL);
+ }
+
++ cmd_name = cmd->argv[0];
++ pr_cmd_set_name(cmd, "SITE_CPFR");
++ if (!dir_check(cmd->tmp_pool, cmd, G_READ, path, NULL)) {
++ int xerrno = EPERM;
++
++ pr_cmd_set_name(cmd, cmd_name);
++ pr_response_add_err(R_550, "%s: %s", (char *) cmd->argv[3],
++ strerror(xerrno));
++
++ errno = xerrno;
++ return PR_ERROR(cmd);
++ }
++ pr_cmd_set_name(cmd, cmd_name);
++
+ res = pr_filter_allow_path(CURRENT_CONF, path);
+ switch (res) {
+ case 0:
+@@ -635,6 +649,7 @@
+ MODRET copy_cpto(cmd_rec *cmd) {
+ register unsigned int i;
+ char *from, *to = "";
++ char *cmd_name;
+ unsigned char *authenticated = NULL;
+
+ if (copy_engine == FALSE) {
+@@ -673,6 +688,19 @@
+
+ to = dir_canonical_vpath(cmd->tmp_pool, to);
+
++ cmd_name = cmd->argv[0];
++ pr_cmd_set_name(cmd, "SITE_CPTO");
++ if (!dir_check(cmd->tmp_pool, cmd, G_WRITE, to, NULL)) {
++ int xerrno = EPERM;
++
++ pr_cmd_set_name(cmd, cmd_name);
++ pr_response_add_err(R_550, "%s: %s", to, strerror(xerrno));
++
++ errno = xerrno;
++ return PR_ERROR(cmd);
++ }
++ pr_cmd_set_name(cmd, cmd_name);
++
+ if (copy_paths(cmd->tmp_pool, from, to) < 0) {
+ int xerrno = errno;
+
+@@ -751,7 +779,7 @@
+
+ static cmdtable copy_cmdtab[] = {
+ { CMD, C_SITE, G_WRITE, copy_copy, FALSE, FALSE, CL_MISC },
+- { CMD, C_SITE, G_DIRS, copy_cpfr, FALSE, FALSE, CL_MISC },
++ { CMD, C_SITE, G_READ, copy_cpfr, FALSE, FALSE, CL_MISC },
+ { CMD, C_SITE, G_WRITE, copy_cpto, FALSE, FALSE, CL_MISC },
+ { POST_CMD, C_PASS, G_NONE, copy_post_pass, FALSE, FALSE },
+ { LOG_CMD, C_SITE, G_NONE, copy_log_site, FALSE, FALSE },
+Index: proftpd-dfsg-1.3.5b/tests/t/lib/ProFTPD/Tests/Modules/mod_copy.pm
+===================================================================
+--- proftpd-dfsg-1.3.5b.orig/tests/t/lib/ProFTPD/Tests/Modules/mod_copy.pm 2016-03-11 02:04:32.000000000 +0100
++++ proftpd-dfsg-1.3.5b/tests/t/lib/ProFTPD/Tests/Modules/mod_copy.pm 2019-08-01 11:54:56.426883780 +0200
+@@ -111,6 +111,15 @@
+ test_class => [qw(forking rootprivs)],
+ },
+
++ copy_cpfr_config_limit_read_bug4372 => {
++ order => ++$order,
++ test_class => [qw(bug forking)],
++ },
++
++ copy_cpto_config_limit_write_bug4372 => {
++ order => ++$order,
++ test_class => [qw(bug forking)],
++ },
+ };
+
+ sub new {
+@@ -3238,6 +3247,12 @@
+
+ my ($port, $config_user, $config_group) = config_write($config_file, $config);
+
++ my $config_subdir = $sub_dir;
++ if ($^O eq 'darwin') {
++ # MacOSX hack
++ $config_subdir = '/private' . $sub_dir;
++ }
++
+ if (open(my $fh, ">> $config_file")) {
+ print $fh <<EOC;
+ <Directory />
+@@ -3246,7 +3261,7 @@
+ </Limit>
+ </Directory>
+
+-<Directory $sub_dir>
++<Directory $config_subdir>
+ <Limit WRITE>
+ AllowAll
+ </Limit>
+@@ -3326,4 +3341,240 @@
+ unlink($log_file);
+ }
+
++sub copy_cpfr_config_limit_read_bug4372 {
++ my $self = shift;
++ my $tmpdir = $self->{tmpdir};
++ my $setup = test_setup($tmpdir, 'copy');
++
++ my $src_file = File::Spec->rel2abs("$tmpdir/foo.dat");
++ if (open(my $fh, "> $src_file")) {
++ unless (close($fh)) {
++ die("Can't write $src_file: $!");
++ }
++
++ } else {
++ die("Can't open $src_file: $!");
++ }
++
++ my $config = {
++ PidFile => $setup->{pid_file},
++ ScoreboardFile => $setup->{scoreboard_file},
++ SystemLog => $setup->{log_file},
++ TraceLog => $setup->{log_file},
++ Trace => 'copy:20 timer:20',
++
++ AuthUserFile => $setup->{auth_user_file},
++ AuthGroupFile => $setup->{auth_group_file},
++ TimeoutIdle => 3,
++
++ IfModules => {
++ 'mod_delay.c' => {
++ DelayEngine => 'off',
++ },
++ },
++ };
++
++ my ($port, $config_user, $config_group) = config_write($setup->{config_file},
++ $config);
++
++ if (open(my $fh, ">> $setup->{config_file}")) {
++ print $fh <<EOC;
++<Directory />
++ <Limit READ>
++ DenyAll
++ </Limit>
++</Directory>
++EOC
++ unless (close($fh)) {
++ die("Can't write $setup->{config_file}: $!");
++ }
++
++ } else {
++ die("Can't open $setup->{config_file}: $!");
++ }
++
++ # Open pipes, for use between the parent and child processes. Specifically,
++ # the child will indicate when it's done with its test by writing a message
++ # to the parent.
++ my ($rfh, $wfh);
++ unless (pipe($rfh, $wfh)) {
++ die("Can't open pipe: $!");
++ }
++
++ my $ex;
++
++ # Fork child
++ $self->handle_sigchld();
++ defined(my $pid = fork()) or die("Can't fork: $!");
++ if ($pid) {
++ eval {
++ my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1);
++ $client->login($setup->{user}, $setup->{passwd});
++
++ eval { $client->site('CPFR', 'foo.dat') };
++ unless ($@) {
++ die("SITE CPFR succeeded unexpectedly");
++ }
++
++ my $resp_code = $client->response_code();
++ my $resp_msg = $client->response_msg();
++
++ my $expected = 550;
++ $self->assert($expected == $resp_code,
++ test_msg("Expected response code $expected, got $resp_code"));
++
++ $expected = 'Operation not permitted';
++ $self->assert(qr/$expected/, $resp_msg,
++ test_msg("Expected response message '$expected', got '$resp_msg'"));
++
++ $client->quit();
++ };
++ if ($@) {
++ $ex = $@;
++ }
++
++ $wfh->print("done\n");
++ $wfh->flush();
++
++ } else {
++ eval { server_wait($setup->{config_file}, $rfh, 30) };
++ if ($@) {
++ warn($@);
++ exit 1;
++ }
++
++ exit 0;
++ }
++
++ # Stop server
++ server_stop($setup->{pid_file});
++ $self->assert_child_ok($pid);
++
++ test_cleanup($setup->{log_file}, $ex);
++}
++
++sub copy_cpto_config_limit_write_bug4372 {
++ my $self = shift;
++ my $tmpdir = $self->{tmpdir};
++ my $setup = test_setup($tmpdir, 'copy');
++
++ my $src_file = File::Spec->rel2abs("$tmpdir/foo.dat");
++ if (open(my $fh, "> $src_file")) {
++ unless (close($fh)) {
++ die("Can't write $src_file: $!");
++ }
++
++ } else {
++ die("Can't open $src_file: $!");
++ }
++
++ my $dst_file = File::Spec->rel2abs("$tmpdir/bar.dat");
++
++ my $config = {
++ PidFile => $setup->{pid_file},
++ ScoreboardFile => $setup->{scoreboard_file},
++ SystemLog => $setup->{log_file},
++ TraceLog => $setup->{log_file},
++ Trace => 'copy:20 timer:20',
++
++ AuthUserFile => $setup->{auth_user_file},
++ AuthGroupFile => $setup->{auth_group_file},
++ TimeoutIdle => 3,
++
++ IfModules => {
++ 'mod_delay.c' => {
++ DelayEngine => 'off',
++ },
++ },
++ };
++
++ my ($port, $config_user, $config_group) = config_write($setup->{config_file},
++ $config);
++
++ if (open(my $fh, ">> $setup->{config_file}")) {
++ print $fh <<EOC;
++<Directory />
++ <Limit WRITE>
++ DenyAll
++ </Limit>
++</Directory>
++EOC
++ unless (close($fh)) {
++ die("Can't write $setup->{config_file}: $!");
++ }
++
++ } else {
++ die("Can't open $setup->{config_file}: $!");
++ }
++
++ # Open pipes, for use between the parent and child processes. Specifically,
++ # the child will indicate when it's done with its test by writing a message
++ # to the parent.
++ my ($rfh, $wfh);
++ unless (pipe($rfh, $wfh)) {
++ die("Can't open pipe: $!");
++ }
++
++ my $ex;
++
++ # Fork child
++ $self->handle_sigchld();
++ defined(my $pid = fork()) or die("Can't fork: $!");
++ if ($pid) {
++ eval {
++ my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1);
++ $client->login($setup->{user}, $setup->{passwd});
++
++ my ($resp_code, $resp_msg) = $client->site('CPFR', 'foo.dat');
++
++ my $expected = 350;
++ $self->assert($expected == $resp_code,
++ test_msg("Expected response code $expected, got $resp_code"));
++
++ $expected = 'File or directory exists, ready for destination name';
++ $self->assert($expected eq $resp_msg,
++ test_msg("Expected response message '$expected', got '$resp_msg'"));
++
++ eval { $client->site('CPTO', 'bar.dat') };
++ unless ($@) {
++ die('SITE CPTO succeeded unexpectedly');
++ }
++
++ my $resp_code = $client->response_code();
++ my $resp_msg = $client->response_msg();
++
++ my $expected = 550;
++ $self->assert($expected == $resp_code,
++ test_msg("Expected response code $expected, got $resp_code"));
++
++ $expected = 'Operation not permitted';
++ $self->assert(qr/$expected/, $resp_msg,
++ test_msg("Expected response message '$expected', got '$resp_msg'"));
++
++ $client->quit();
++ };
++ if ($@) {
++ $ex = $@;
++ }
++
++ $wfh->print("done\n");
++ $wfh->flush();
++
++ } else {
++ eval { server_wait($setup->{config_file}, $rfh, 30) };
++ if ($@) {
++ warn($@);
++ exit 1;
++ }
++
++ exit 0;
++ }
++
++ # Stop server
++ server_stop($setup->{pid_file});
++ $self->assert_child_ok($pid);
++
++ test_cleanup($setup->{log_file}, $ex);
++}
++
+ 1;
View it on GitLab: https://salsa.debian.org/debian-proftpd-team/proftpd/commit/774b745c73c7b12ffd0fb9bb7f57d41c16d4e05d
--
View it on GitLab: https://salsa.debian.org/debian-proftpd-team/proftpd/commit/774b745c73c7b12ffd0fb9bb7f57d41c16d4e05d
You're receiving this email because of your account on salsa.debian.org.
More information about the Pkg-proftpd-maintainers
mailing list