|
|
80b5f20 |
--- contrib/mod_copy.c
|
|
|
80b5f20 |
+++ contrib/mod_copy.c
|
|
|
80b5f20 |
@@ -31,7 +31,7 @@
|
|
|
80b5f20 |
|
|
|
80b5f20 |
#include "conf.h"
|
|
|
80b5f20 |
|
|
|
80b5f20 |
-#define MOD_COPY_VERSION "mod_copy/0.4"
|
|
|
80b5f20 |
+#define MOD_COPY_VERSION "mod_copy/0.5"
|
|
|
80b5f20 |
|
|
|
80b5f20 |
/* Make sure the version of proftpd is as necessary. */
|
|
|
80b5f20 |
#if PROFTPD_VERSION_NUMBER < 0x0001030401
|
|
|
80b5f20 |
@@ -40,6 +40,8 @@
|
|
|
80b5f20 |
|
|
|
80b5f20 |
extern pr_response_t *resp_list, *resp_err_list;
|
|
|
80b5f20 |
|
|
|
80b5f20 |
+static int copy_engine = TRUE;
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
static const char *trace_channel = "copy";
|
|
|
80b5f20 |
|
|
|
80b5f20 |
/* These are copied largely from src/mkhome.c */
|
|
|
80b5f20 |
@@ -471,10 +473,37 @@ static int copy_paths(pool *p, const cha
|
|
|
80b5f20 |
return 0;
|
|
|
80b5f20 |
}
|
|
|
80b5f20 |
|
|
|
80b5f20 |
+/* Configuration handlers
|
|
|
80b5f20 |
+ */
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+/* usage: CopyEngine on|off */
|
|
|
80b5f20 |
+MODRET set_copyengine(cmd_rec *cmd) {
|
|
|
80b5f20 |
+ int engine = -1;
|
|
|
80b5f20 |
+ config_rec *c;
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ CHECK_ARGS(cmd, 1);
|
|
|
80b5f20 |
+ CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ engine = get_boolean(cmd, 1);
|
|
|
80b5f20 |
+ if (engine == -1) {
|
|
|
80b5f20 |
+ CONF_ERROR(cmd, "expected Boolean parameter");
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ c = add_config_param(cmd->argv[0], 1, NULL);
|
|
|
80b5f20 |
+ c->argv[0] = palloc(c->pool, sizeof(int));
|
|
|
80b5f20 |
+ *((int *) c->argv[0]) = engine;
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ return PR_HANDLED(cmd);
|
|
|
80b5f20 |
+}
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
/* Command handlers
|
|
|
80b5f20 |
*/
|
|
|
80b5f20 |
|
|
|
80b5f20 |
MODRET copy_copy(cmd_rec *cmd) {
|
|
|
80b5f20 |
+ if (copy_engine == FALSE) {
|
|
|
80b5f20 |
+ return PR_DECLINED(cmd);
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
if (cmd->argc < 2) {
|
|
|
80b5f20 |
return PR_DECLINED(cmd);
|
|
|
80b5f20 |
}
|
|
|
80b5f20 |
@@ -539,12 +568,26 @@ MODRET copy_cpfr(cmd_rec *cmd) {
|
|
|
80b5f20 |
register unsigned int i;
|
|
|
80b5f20 |
int res;
|
|
|
80b5f20 |
char *path = "";
|
|
|
80b5f20 |
+ unsigned char *authenticated = NULL;
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ if (copy_engine == FALSE) {
|
|
|
80b5f20 |
+ return PR_DECLINED(cmd);
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
|
|
|
80b5f20 |
if (cmd->argc < 3 ||
|
|
|
80b5f20 |
strncasecmp(cmd->argv[1], "CPFR", 5) != 0) {
|
|
|
80b5f20 |
return PR_DECLINED(cmd);
|
|
|
80b5f20 |
}
|
|
|
80b5f20 |
|
|
|
80b5f20 |
+ authenticated = get_param_ptr(cmd->server->conf, "authenticated", FALSE);
|
|
|
80b5f20 |
+ if (authenticated == NULL ||
|
|
|
80b5f20 |
+ *authenticated == FALSE) {
|
|
|
80b5f20 |
+ pr_response_add_err(R_530, _("Please login with USER and PASS"));
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ errno = EPERM;
|
|
|
80b5f20 |
+ return PR_ERROR(cmd);
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
CHECK_CMD_MIN_ARGS(cmd, 3);
|
|
|
80b5f20 |
|
|
|
80b5f20 |
/* Construct the target file name by concatenating all the parameters after
|
|
|
80b5f20 |
@@ -594,12 +637,26 @@ MODRET copy_cpfr(cmd_rec *cmd) {
|
|
|
80b5f20 |
MODRET copy_cpto(cmd_rec *cmd) {
|
|
|
80b5f20 |
register unsigned int i;
|
|
|
80b5f20 |
char *from, *to = "";
|
|
|
80b5f20 |
+ unsigned char *authenticated = NULL;
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ if (copy_engine == FALSE) {
|
|
|
80b5f20 |
+ return PR_DECLINED(cmd);
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
|
|
|
80b5f20 |
if (cmd->argc < 3 ||
|
|
|
80b5f20 |
strncasecmp(cmd->argv[1], "CPTO", 5) != 0) {
|
|
|
80b5f20 |
return PR_DECLINED(cmd);
|
|
|
80b5f20 |
}
|
|
|
80b5f20 |
|
|
|
80b5f20 |
+ authenticated = get_param_ptr(cmd->server->conf, "authenticated", FALSE);
|
|
|
80b5f20 |
+ if (authenticated == NULL ||
|
|
|
80b5f20 |
+ *authenticated == FALSE) {
|
|
|
80b5f20 |
+ pr_response_add_err(R_530, _("Please login with USER and PASS"));
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ errno = EPERM;
|
|
|
80b5f20 |
+ return PR_ERROR(cmd);
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
CHECK_CMD_MIN_ARGS(cmd, 3);
|
|
|
80b5f20 |
|
|
|
80b5f20 |
from = pr_table_get(session.notes, "mod_copy.cpfr-path", NULL);
|
|
|
80b5f20 |
@@ -632,6 +689,10 @@ MODRET copy_cpto(cmd_rec *cmd) {
|
|
|
80b5f20 |
}
|
|
|
80b5f20 |
|
|
|
80b5f20 |
MODRET copy_log_site(cmd_rec *cmd) {
|
|
|
80b5f20 |
+ if (copy_engine == FALSE) {
|
|
|
80b5f20 |
+ return PR_DECLINED(cmd);
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
if (cmd->argc < 3 ||
|
|
|
80b5f20 |
strncasecmp(cmd->argv[1], "CPTO", 5) != 0) {
|
|
|
80b5f20 |
return PR_DECLINED(cmd);
|
|
|
80b5f20 |
@@ -643,23 +704,58 @@ MODRET copy_log_site(cmd_rec *cmd) {
|
|
|
80b5f20 |
return PR_DECLINED(cmd);
|
|
|
80b5f20 |
}
|
|
|
80b5f20 |
|
|
|
80b5f20 |
+MODRET copy_post_pass(cmd_rec *cmd) {
|
|
|
80b5f20 |
+ config_rec *c;
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ if (copy_engine == FALSE) {
|
|
|
80b5f20 |
+ return PR_DECLINED(cmd);
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ /* The CopyEngine directive may have been changed for this user by
|
|
|
80b5f20 |
+ * e.g. mod_ifsession, thus we check again.
|
|
|
80b5f20 |
+ */
|
|
|
80b5f20 |
+ c = find_config(main_server->conf, CONF_PARAM, "CopyEngine", FALSE);
|
|
|
80b5f20 |
+ if (c != NULL) {
|
|
|
80b5f20 |
+ copy_engine = *((int *) c->argv[0]);
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ return PR_DECLINED(cmd);
|
|
|
80b5f20 |
+}
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
/* Initialization functions
|
|
|
80b5f20 |
*/
|
|
|
80b5f20 |
|
|
|
80b5f20 |
static int copy_sess_init(void) {
|
|
|
80b5f20 |
+ config_rec *c;
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ c = find_config(main_server->conf, CONF_PARAM, "CopyEngine", FALSE);
|
|
|
80b5f20 |
+ if (c != NULL) {
|
|
|
80b5f20 |
+ copy_engine = *((int *) c->argv[0]);
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ if (copy_engine == FALSE) {
|
|
|
80b5f20 |
+ return 0;
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
/* Advertise support for the SITE command */
|
|
|
80b5f20 |
pr_feat_add("SITE COPY");
|
|
|
80b5f20 |
-
|
|
|
80b5f20 |
return 0;
|
|
|
80b5f20 |
}
|
|
|
80b5f20 |
|
|
|
80b5f20 |
/* Module API tables
|
|
|
80b5f20 |
*/
|
|
|
80b5f20 |
|
|
|
80b5f20 |
+static conftable copy_conftab[] = {
|
|
|
80b5f20 |
+ { "CopyEngine", set_copyengine, NULL },
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ { NULL }
|
|
|
80b5f20 |
+};
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
static cmdtable copy_cmdtab[] = {
|
|
|
80b5f20 |
{ CMD, C_SITE, G_WRITE, copy_copy, FALSE, FALSE, CL_MISC },
|
|
|
80b5f20 |
{ CMD, C_SITE, G_DIRS, copy_cpfr, FALSE, FALSE, CL_MISC },
|
|
|
80b5f20 |
{ CMD, C_SITE, G_WRITE, copy_cpto, FALSE, FALSE, CL_MISC },
|
|
|
80b5f20 |
+ { POST_CMD, C_PASS, G_NONE, copy_post_pass, FALSE, FALSE },
|
|
|
80b5f20 |
{ LOG_CMD, C_SITE, G_NONE, copy_log_site, FALSE, FALSE },
|
|
|
80b5f20 |
{ LOG_CMD_ERR, C_SITE, G_NONE, copy_log_site, FALSE, FALSE },
|
|
|
80b5f20 |
|
|
|
80b5f20 |
@@ -676,7 +772,7 @@ module copy_module = {
|
|
|
80b5f20 |
"copy",
|
|
|
80b5f20 |
|
|
|
80b5f20 |
/* Module configuration handler table */
|
|
|
80b5f20 |
- NULL,
|
|
|
80b5f20 |
+ copy_conftab,
|
|
|
80b5f20 |
|
|
|
80b5f20 |
/* Module command handler table */
|
|
|
80b5f20 |
copy_cmdtab,
|
|
|
80b5f20 |
--- doc/contrib/mod_copy.html
|
|
|
80b5f20 |
+++ doc/contrib/mod_copy.html
|
|
|
80b5f20 |
@@ -27,22 +27,40 @@ ProFTPD 1.3.x, and is not compile
|
|
|
80b5f20 |
instructions are discussed here.
|
|
|
80b5f20 |
|
|
|
80b5f20 |
|
|
|
80b5f20 |
-The most current version of mod_copy can be found at:
|
|
|
80b5f20 |
-
|
|
|
80b5f20 |
- http://www.castaglia.org/proftpd/
|
|
|
80b5f20 |
-
|
|
|
80b5f20 |
+The most current version of mod_copy is distributed with the
|
|
|
80b5f20 |
+ProFTPD source code.
|
|
|
80b5f20 |
|
|
|
80b5f20 |
Author
|
|
|
80b5f20 |
|
|
|
80b5f20 |
Please contact TJ Saunders <tj at castaglia.org> with any
|
|
|
80b5f20 |
questions, concerns, or suggestions regarding this module.
|
|
|
80b5f20 |
|
|
|
80b5f20 |
+Directives
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ CopyEngine
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
SITE Commands
|
|
|
80b5f20 |
|
|
|
80b5f20 |
SITE CPFR
|
|
|
80b5f20 |
SITE CPTO
|
|
|
80b5f20 |
|
|
|
80b5f20 |
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+Syntax: CopyEngine on|off
|
|
|
80b5f20 |
+Default: CopyEngine on
|
|
|
80b5f20 |
+Context: server config, <VirtualHost> , <Global>
|
|
|
80b5f20 |
+Module: mod_radius
|
|
|
80b5f20 |
+Compatibility: 1.3.6rc1 and later
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+The CopyEngine directive enables or disables the module's
|
|
|
80b5f20 |
+handling of SITE COPY et al commands. If it is set to
|
|
|
80b5f20 |
+off this module ignores these commands.
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
|
|
|
80b5f20 |
|
|
|
80b5f20 |
This SITE command specifies the source file/directory to use
|
|
|
80b5f20 |
@@ -118,13 +136,8 @@ your existing server:
|
|
|
80b5f20 |
|
|
|
80b5f20 |
|
|
|
80b5f20 |
|
|
|
80b5f20 |
-Author: $Author: castaglia $
|
|
|
80b5f20 |
-Last Updated: $Date: 2010/03/10 19:20:43 $
|
|
|
80b5f20 |
-
|
|
|
80b5f20 |
-
|
|
|
80b5f20 |
-
|
|
|
80b5f20 |
<font size=2>
|
|
|
80b5f20 |
-© Copyright 2009-2010 TJ Saunders
|
|
|
80b5f20 |
+© Copyright 2009-2015 TJ Saunders
|
|
|
80b5f20 |
All Rights Reserved
|
|
|
80b5f20 |
</font>
|
|
|
80b5f20 |
|
|
|
80b5f20 |
--- RELEASE_NOTES
|
|
|
80b5f20 |
+++ RELEASE_NOTES
|
|
|
80b5f20 |
@@ -6,6 +6,14 @@ This file contains a description of the
|
|
|
80b5f20 |
releases. More information on these changes can be found in the NEWS and
|
|
|
80b5f20 |
ChangeLog files.
|
|
|
80b5f20 |
|
|
|
80b5f20 |
+Upcoming 1.3.5a
|
|
|
80b5f20 |
+---------------
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ + New Configuration Directives
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ CopyEngine (Bug#4169)
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
1.3.5
|
|
|
80b5f20 |
---------
|
|
|
80b5f20 |
|
|
|
80b5f20 |
--- tests/t/lib/ProFTPD/Tests/Modules/mod_copy.pm
|
|
|
80b5f20 |
+++ tests/t/lib/ProFTPD/Tests/Modules/mod_copy.pm
|
|
|
80b5f20 |
@@ -21,6 +21,11 @@ my $TESTS = {
|
|
|
80b5f20 |
test_class => [qw(forking)],
|
|
|
80b5f20 |
},
|
|
|
80b5f20 |
|
|
|
80b5f20 |
+ copy_file_no_login => {
|
|
|
80b5f20 |
+ order => ++$order,
|
|
|
80b5f20 |
+ test_class => [qw(bug forking)],
|
|
|
80b5f20 |
+ },
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
copy_dir => {
|
|
|
80b5f20 |
order => ++$order,
|
|
|
80b5f20 |
test_class => [qw(forking)],
|
|
|
80b5f20 |
@@ -86,6 +91,11 @@ my $TESTS = {
|
|
|
80b5f20 |
test_class => [qw(forking)],
|
|
|
80b5f20 |
},
|
|
|
80b5f20 |
|
|
|
80b5f20 |
+ copy_cpfr_cpto_no_login => {
|
|
|
80b5f20 |
+ order => ++$order,
|
|
|
80b5f20 |
+ test_class => [qw(bug forking)],
|
|
|
80b5f20 |
+ },
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
copy_cpto_no_cpfr => {
|
|
|
80b5f20 |
order => ++$order,
|
|
|
80b5f20 |
test_class => [qw(forking)],
|
|
|
80b5f20 |
@@ -263,6 +273,137 @@ sub copy_file {
|
|
|
80b5f20 |
unlink($log_file);
|
|
|
80b5f20 |
}
|
|
|
80b5f20 |
|
|
|
80b5f20 |
+sub copy_file_no_login {
|
|
|
80b5f20 |
+ my $self = shift;
|
|
|
80b5f20 |
+ my $tmpdir = $self->{tmpdir};
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $config_file = "$tmpdir/copy.conf";
|
|
|
80b5f20 |
+ my $pid_file = File::Spec->rel2abs("$tmpdir/copy.pid");
|
|
|
80b5f20 |
+ my $scoreboard_file = File::Spec->rel2abs("$tmpdir/copy.scoreboard");
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $log_file = File::Spec->rel2abs('tests.log');
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $auth_user_file = File::Spec->rel2abs("$tmpdir/copy.passwd");
|
|
|
80b5f20 |
+ my $auth_group_file = File::Spec->rel2abs("$tmpdir/copy.group");
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $user = 'proftpd';
|
|
|
80b5f20 |
+ my $passwd = 'test';
|
|
|
80b5f20 |
+ my $group = 'ftpd';
|
|
|
80b5f20 |
+ my $home_dir = File::Spec->rel2abs($tmpdir);
|
|
|
80b5f20 |
+ my $uid = 500;
|
|
|
80b5f20 |
+ my $gid = 500;
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ # Make sure that, if we're running as root, that the home directory has
|
|
|
80b5f20 |
+ # permissions/privs set for the account we create
|
|
|
80b5f20 |
+ if ($< == 0) {
|
|
|
80b5f20 |
+ unless (chmod(0755, $home_dir)) {
|
|
|
80b5f20 |
+ die("Can't set perms on $home_dir to 0755: $!");
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ unless (chown($uid, $gid, $home_dir)) {
|
|
|
80b5f20 |
+ die("Can't set owner of $home_dir to $uid/$gid: $!");
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
|
|
|
80b5f20 |
+ '/bin/bash');
|
|
|
80b5f20 |
+ auth_group_write($auth_group_file, $group, $gid, $user);
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $src_file = File::Spec->rel2abs("$home_dir/foo.txt");
|
|
|
80b5f20 |
+ if (open(my $fh, "> $src_file")) {
|
|
|
80b5f20 |
+ print $fh "Hello, World!\n";
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ unless (close($fh)) {
|
|
|
80b5f20 |
+ die("Can't write $src_file: $!");
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ } else {
|
|
|
80b5f20 |
+ die("Can't open $src_file: $!");
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $dst_file = File::Spec->rel2abs("$home_dir/bar.txt");
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $config = {
|
|
|
80b5f20 |
+ PidFile => $pid_file,
|
|
|
80b5f20 |
+ ScoreboardFile => $scoreboard_file,
|
|
|
80b5f20 |
+ SystemLog => $log_file,
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ AuthUserFile => $auth_user_file,
|
|
|
80b5f20 |
+ AuthGroupFile => $auth_group_file,
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ IfModules => {
|
|
|
80b5f20 |
+ 'mod_delay.c' => {
|
|
|
80b5f20 |
+ DelayEngine => 'off',
|
|
|
80b5f20 |
+ },
|
|
|
80b5f20 |
+ },
|
|
|
80b5f20 |
+ };
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my ($port, $config_user, $config_group) = config_write($config_file, $config);
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ # Open pipes, for use between the parent and child processes. Specifically,
|
|
|
80b5f20 |
+ # the child will indicate when it's done with its test by writing a message
|
|
|
80b5f20 |
+ # to the parent.
|
|
|
80b5f20 |
+ my ($rfh, $wfh);
|
|
|
80b5f20 |
+ unless (pipe($rfh, $wfh)) {
|
|
|
80b5f20 |
+ die("Can't open pipe: $!");
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $ex;
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ # Fork child
|
|
|
80b5f20 |
+ $self->handle_sigchld();
|
|
|
80b5f20 |
+ defined(my $pid = fork()) or die("Can't fork: $!");
|
|
|
80b5f20 |
+ if ($pid) {
|
|
|
80b5f20 |
+ eval {
|
|
|
80b5f20 |
+ my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ eval { $client->site('COPY', 'foo.txt', 'bar.txt') };
|
|
|
80b5f20 |
+ unless ($@) {
|
|
|
80b5f20 |
+ die("SITE COPY succeeded unexpectedly");
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $resp_code = $client->response_code();
|
|
|
80b5f20 |
+ my $resp_msg = $client->response_msg();
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $expected;
|
|
|
80b5f20 |
+ $expected = 530;
|
|
|
80b5f20 |
+ $self->assert($expected == $resp_code,
|
|
|
80b5f20 |
+ test_msg("Expected response code $expected, got $resp_code"));
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ $expected = "Please login with USER and PASS";
|
|
|
80b5f20 |
+ $self->assert($expected eq $resp_msg,
|
|
|
80b5f20 |
+ test_msg("Expected response message '$expected', got '$resp_msg'"));
|
|
|
80b5f20 |
+ };
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ if ($@) {
|
|
|
80b5f20 |
+ $ex = $@;
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ $wfh->print("done\n");
|
|
|
80b5f20 |
+ $wfh->flush();
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ } else {
|
|
|
80b5f20 |
+ eval { server_wait($config_file, $rfh) };
|
|
|
80b5f20 |
+ if ($@) {
|
|
|
80b5f20 |
+ warn($@);
|
|
|
80b5f20 |
+ exit 1;
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ exit 0;
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ # Stop server
|
|
|
80b5f20 |
+ server_stop($pid_file);
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ $self->assert_child_ok($pid);
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ if ($ex) {
|
|
|
80b5f20 |
+ die($ex);
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ unlink($log_file);
|
|
|
80b5f20 |
+}
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
sub copy_dir {
|
|
|
80b5f20 |
my $self = shift;
|
|
|
80b5f20 |
my $tmpdir = $self->{tmpdir};
|
|
|
80b5f20 |
@@ -2578,6 +2719,153 @@ sub copy_cpfr_cpto {
|
|
|
80b5f20 |
};
|
|
|
80b5f20 |
|
|
|
80b5f20 |
if ($@) {
|
|
|
80b5f20 |
+ $ex = $@;
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ $wfh->print("done\n");
|
|
|
80b5f20 |
+ $wfh->flush();
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ } else {
|
|
|
80b5f20 |
+ eval { server_wait($config_file, $rfh) };
|
|
|
80b5f20 |
+ if ($@) {
|
|
|
80b5f20 |
+ warn($@);
|
|
|
80b5f20 |
+ exit 1;
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ exit 0;
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ # Stop server
|
|
|
80b5f20 |
+ server_stop($pid_file);
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ $self->assert_child_ok($pid);
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ if ($ex) {
|
|
|
80b5f20 |
+ die($ex);
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ unlink($log_file);
|
|
|
80b5f20 |
+}
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+sub copy_cpfr_cpto_no_login {
|
|
|
80b5f20 |
+ my $self = shift;
|
|
|
80b5f20 |
+ my $tmpdir = $self->{tmpdir};
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $config_file = "$tmpdir/copy.conf";
|
|
|
80b5f20 |
+ my $pid_file = File::Spec->rel2abs("$tmpdir/copy.pid");
|
|
|
80b5f20 |
+ my $scoreboard_file = File::Spec->rel2abs("$tmpdir/copy.scoreboard");
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $log_file = File::Spec->rel2abs('tests.log');
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $auth_user_file = File::Spec->rel2abs("$tmpdir/copy.passwd");
|
|
|
80b5f20 |
+ my $auth_group_file = File::Spec->rel2abs("$tmpdir/copy.group");
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $user = 'proftpd';
|
|
|
80b5f20 |
+ my $passwd = 'test';
|
|
|
80b5f20 |
+ my $group = 'ftpd';
|
|
|
80b5f20 |
+ my $home_dir = File::Spec->rel2abs($tmpdir);
|
|
|
80b5f20 |
+ my $uid = 500;
|
|
|
80b5f20 |
+ my $gid = 500;
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ # Make sure that, if we're running as root, that the home directory has
|
|
|
80b5f20 |
+ # permissions/privs set for the account we create
|
|
|
80b5f20 |
+ if ($< == 0) {
|
|
|
80b5f20 |
+ unless (chmod(0755, $home_dir)) {
|
|
|
80b5f20 |
+ die("Can't set perms on $home_dir to 0755: $!");
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ unless (chown($uid, $gid, $home_dir)) {
|
|
|
80b5f20 |
+ die("Can't set owner of $home_dir to $uid/$gid: $!");
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
|
|
|
80b5f20 |
+ '/bin/bash');
|
|
|
80b5f20 |
+ auth_group_write($auth_group_file, $group, $gid, $user);
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $src_file = File::Spec->rel2abs("$home_dir/foo.txt");
|
|
|
80b5f20 |
+ if (open(my $fh, "> $src_file")) {
|
|
|
80b5f20 |
+ print $fh "Hello, World!\n";
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ unless (close($fh)) {
|
|
|
80b5f20 |
+ die("Can't write $src_file: $!");
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ } else {
|
|
|
80b5f20 |
+ die("Can't open $src_file: $!");
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $dst_file = File::Spec->rel2abs("$home_dir/bar.txt");
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $config = {
|
|
|
80b5f20 |
+ PidFile => $pid_file,
|
|
|
80b5f20 |
+ ScoreboardFile => $scoreboard_file,
|
|
|
80b5f20 |
+ SystemLog => $log_file,
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ AuthUserFile => $auth_user_file,
|
|
|
80b5f20 |
+ AuthGroupFile => $auth_group_file,
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ IfModules => {
|
|
|
80b5f20 |
+ 'mod_delay.c' => {
|
|
|
80b5f20 |
+ DelayEngine => 'off',
|
|
|
80b5f20 |
+ },
|
|
|
80b5f20 |
+ },
|
|
|
80b5f20 |
+ };
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my ($port, $config_user, $config_group) = config_write($config_file, $config);
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ # Open pipes, for use between the parent and child processes. Specifically,
|
|
|
80b5f20 |
+ # the child will indicate when it's done with its test by writing a message
|
|
|
80b5f20 |
+ # to the parent.
|
|
|
80b5f20 |
+ my ($rfh, $wfh);
|
|
|
80b5f20 |
+ unless (pipe($rfh, $wfh)) {
|
|
|
80b5f20 |
+ die("Can't open pipe: $!");
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $ex;
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ # Fork child
|
|
|
80b5f20 |
+ $self->handle_sigchld();
|
|
|
80b5f20 |
+ defined(my $pid = fork()) or die("Can't fork: $!");
|
|
|
80b5f20 |
+ if ($pid) {
|
|
|
80b5f20 |
+ eval {
|
|
|
80b5f20 |
+ my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ eval { $client->site('CPFR', 'foo.txt') };
|
|
|
80b5f20 |
+ unless ($@) {
|
|
|
80b5f20 |
+ die("SITE CPFR succeeded unexpectedly");
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $resp_code = $client->response_code();
|
|
|
80b5f20 |
+ my $resp_msg = $client->response_msg();
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ my $expected;
|
|
|
80b5f20 |
+ $expected = 530;
|
|
|
80b5f20 |
+ $self->assert($expected == $resp_code,
|
|
|
80b5f20 |
+ test_msg("Expected response code $expected, got $resp_code"));
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ $expected = "Please login with USER and PASS";
|
|
|
80b5f20 |
+ $self->assert($expected eq $resp_msg,
|
|
|
80b5f20 |
+ test_msg("Expected response message '$expected', got '$resp_msg'"));
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ eval { $client->site('CPTO', 'bar.txt') };
|
|
|
80b5f20 |
+ unless ($@) {
|
|
|
80b5f20 |
+ die("SITE CPTO succeeded unexpectedly");
|
|
|
80b5f20 |
+ }
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ $resp_code = $client->response_code();
|
|
|
80b5f20 |
+ $resp_msg = $client->response_msg();
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ $expected = 530;
|
|
|
80b5f20 |
+ $self->assert($expected == $resp_code,
|
|
|
80b5f20 |
+ test_msg("Expected response code $expected, got $resp_code"));
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ $expected = "Please login with USER and PASS";
|
|
|
80b5f20 |
+ $self->assert($expected eq $resp_msg,
|
|
|
80b5f20 |
+ test_msg("Expected response message '$expected', got '$resp_msg'"));
|
|
|
80b5f20 |
+ };
|
|
|
80b5f20 |
+
|
|
|
80b5f20 |
+ if ($@) {
|
|
|
80b5f20 |
$ex = $@;
|
|
|
80b5f20 |
}
|
|
|
80b5f20 |
|