(mod_copy)
*/
if (strcmp(cmd->argv[1], "CHGRP") == 0 ||
strcmp(cmd->argv[1], "CHMOD") == 0 ||
strcmp(cmd->argv[1], "UTIME") == 0) {
register unsigned int i;
char *arg = "";
if (cmd->argc < 4) {
return PR_DECLINED(cmd);
}
/* Construct the path by concatenating all of the parameter after the
* operational data, separating them with spaces.
*/
for (i = 3; i < cmd->argc; i++) {
arg = pstrcat(cmd->tmp_pool, arg, *arg ? " " : "", cmd->argv[i], NULL);
}
cmd_name = pstrcat(cmd->tmp_pool, cmd->argv[0], " ", cmd->argv[1], NULL);
path = arg;
return handle_path(cmd, cmd_name, path);
} else if (strcmp(cmd->argv[1], "CPFR") == 0 ||
strcmp(cmd->argv[1], "CPTO") == 0 ||
strcmp(cmd->argv[1], "MKDIR") == 0 ||
strcmp(cmd->argv[1], "RMDIR") == 0) {
cmd_name = pstrcat(cmd->tmp_pool, cmd->argv[0], " ", cmd->argv[1], NULL);
path = cmd->argv[2];
return handle_path(cmd, cmd_name, path);
} else if (strcmp(cmd->argv[1], "COPY") == 0 ||
strcmp(cmd->argv[1], "SYMLINK") == 0) {
char *from, *to;
modret_t *mr;
if (cmd->argc < 4) {
return PR_DECLINED(cmd);
}
cmd_name = pstrcat(cmd->tmp_pool, cmd->argv[0], " ", cmd->argv[1], NULL);
from = cmd->argv[2];
to = cmd->argv[3];
mr = handle_path(cmd, cmd_name, from);
if (MODRET_ISERROR(mr)) {
return mr;
}
return handle_path(cmd, cmd_name, to);
} else {
pr_trace_msg(trace_channel, 7,
"unknown/unsupported SITE '%s' command, ignoring", (char *) cmd->argv[1]);
}
return PR_DECLINED(cmd);
}
MODRET procfs_sftp_pre_path(cmd_rec *cmd) {
const char *path, *proto;
if (procfs_engine == FALSE) {
return PR_DECLINED(cmd);
}
proto = pr_session_get_protocol(0);
if (strcmp(proto, "sftp") != 0) {
return PR_DECLINED(cmd);
}
path = cmd->argv[1];
return handle_path(cmd, cmd->argv[0], path);
}
MODRET procfs_sftp_pre_hardlink(cmd_rec *cmd) {
const char *src_path, *dst_path, *proto;
char *ptr;
modret_t *mr;
if (procfs_engine == FALSE) {
return PR_DECLINED(cmd);
}
proto = pr_session_get_protocol(0);
if (strcmp(proto, "sftp") != 0) {
return PR_DECLINED(cmd);
}
/* Unfortunately, mod_sftp currently does NOT break the two paths into
* the cmd->argv array; it only populates cmd->arg.
*
* In the future, if/when mod_sftp behavior changes, we can look at the
* cmd->argc to determine which style is being used by mod_sftp.
*/
ptr = strchr(cmd->arg, ' ');
if (ptr == NULL) {
return PR_DECLINED(cmd);
}
src_path = pstrndup(cmd->tmp_pool, cmd->arg, ptr - cmd->arg);
dst_path = pstrdup(cmd->tmp_pool, ptr + 1);
mr = handle_path(cmd, cmd->argv[0], src_path);
if (MODRET_ISERROR(mr)) {
return mr;
}
return handle_path(cmd, cmd->argv[0], dst_path);
}
MODRET procfs_sftp_pre_symlink(cmd_rec *cmd) {
const char *src_path, *dst_path, *proto;
char *ptr;
modret_t *mr;
if (procfs_engine == FALSE) {
return PR_DECLINED(cmd);
}
proto = pr_session_get_protocol(0);
if (strcmp(proto, "sftp") != 0) {
return PR_DECLINED(cmd);
}
/* Unfortunately, mod_sftp currently does NOT break the two paths into
* the cmd->argv array; it only populates cmd->arg.
*
* In the future, if/when mod_sftp behavior changes, we can look at the
* cmd->argc to determine which style is being used by mod_sftp.
*/
ptr = strchr(cmd->arg, '\t');
if (ptr == NULL) {
return PR_DECLINED(cmd);
}
src_path = pstrndup(cmd->tmp_pool, cmd->arg, ptr - cmd->arg);
dst_path = pstrdup(cmd->tmp_pool, ptr + 1);
mr = handle_path(cmd, cmd->argv[0], src_path);
if (MODRET_ISERROR(mr)) {
return mr;
}
return handle_path(cmd, cmd->argv[0], dst_path);
}
MODRET procfs_post_pass(cmd_rec *cmd) {
config_rec *c;
if (procfs_mounts == NULL) {
procfs_engine = FALSE;
return PR_DECLINED(cmd);
}
c = find_config(main_server->conf, CONF_PARAM, "ProcfsEngine", FALSE);
if (c != NULL) {
procfs_engine = *((int *) c->argv[0]);
}
if (procfs_engine == FALSE) {
return PR_DECLINED(cmd);
}
/* Check whether we are chrooted. If so, then we need not do anything. */
if (session.chroot_path != NULL) {
if (strcmp(session.chroot_path, "/") != 0) {
pr_trace_msg(trace_channel, 3,
"session is chrooted to '%s', disabling mod_procfs",
session.chroot_path);
procfs_engine = FALSE;
}
}
return PR_DECLINED(cmd);
}
/* Event Listeners
*/
#if defined(PR_SHARED_MODULE)
static void procfs_mod_unload_ev(const void *event_data, void *user_data) {
if (strcmp("mod_procfs.c", (const char *) event_data) != 0) {
return;
}
pr_event_unregister(&procfs_module, NULL, NULL);
(void) close(procfs_logfd);
procfs_logfd = -1;
if (procfs_pool != NULL) {
destroy_pool(procfs_pool);
procfs_pool = NULL;
procfs_mounts = NULL;
}
procfs_engine = FALSE;
}
#endif /* PR_SHARED_MODULE */
static void procfs_restart_ev(const void *event_data, void *user_data) {
(void) close(procfs_logfd);
procfs_logfd = -1;
if (procfs_pool != NULL) {
destroy_pool(procfs_pool);
}
procfs_pool = make_sub_pool(permanent_pool);
pr_pool_tag(procfs_pool, MOD_PROCFS_VERSION);
}
static void procfs_shutdown_ev(const void *event_data, void *user_data) {
(void) close(procfs_logfd);
procfs_logfd = -1;
if (procfs_pool != NULL) {
destroy_pool(procfs_pool);
procfs_pool = NULL;
procfs_mounts = NULL;
}
}
/* Initialization functions
*/
static int procfs_init(void) {
if (procfs_pool != NULL) {
destroy_pool(procfs_pool);
}
procfs_pool = make_sub_pool(permanent_pool);
pr_pool_tag(procfs_pool, MOD_PROCFS_VERSION);
#if defined(PR_SHARED_MODULE)
pr_event_register(&procfs_module, "core.module-unload", procfs_mod_unload_ev,
NULL);
#endif /* PR_SHARED_MODULE */
pr_event_register(&procfs_module, "core.restart", procfs_restart_ev, NULL);
pr_event_register(&procfs_module, "core.shutdown", procfs_shutdown_ev, NULL);
if (get_procfs_mounts(procfs_pool) < 0) {
pr_trace_msg(trace_channel, 1, "unable to discover procfs mounts: %s",
strerror(errno));
}
return 0;
}
static int procfs_sess_init(void) {
config_rec *c;
const char *path;
int res, xerrno;
c = find_config(main_server->conf, CONF_PARAM, "ProcfsLog", FALSE);
if (c == NULL) {
return 0;
}
path = c->argv[0];
if (strcasecmp(path, "none") == 0) {
return 0;
}
PRIVS_ROOT
res = pr_log_openfile(path, &procfs_logfd, 0660);
xerrno = errno;
PRIVS_RELINQUISH
switch (res) {
case 0:
break;
case -1:
pr_log_debug(DEBUG1, MOD_PROCFS_VERSION
": unable to open ProcfsLog '%s': %s", path, strerror(xerrno));
break;
case PR_LOG_SYMLINK:
pr_log_debug(DEBUG1, MOD_PROCFS_VERSION
": unable to open ProcfsLog '%s': %s", path, "is a symlink");
break;
case PR_LOG_WRITABLE_DIR:
pr_log_debug(DEBUG1, MOD_PROCFS_VERSION
": unable to open ProcfsLog '%s': %s", path,
"parent directory is world-writable");
break;
}
return 0;
}
/* Module API tables
*/
static conftable procfs_conftab[] = {
{ "ProcfsEngine", set_procfsengine, NULL },
{ "ProcfsLog", set_procfslog, NULL },
{ NULL }
};
static cmdtable procfs_cmdtab[] = {
/* FTP */
{ PRE_CMD, C_APPE, G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, C_CWD, G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, C_XCWD, G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, C_DELE, G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, C_LIST, G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, C_MDTM, G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, C_MFF, G_NONE, procfs_pre_mfmt, FALSE, FALSE },
{ PRE_CMD, C_MFMT, G_NONE, procfs_pre_mfmt, FALSE, FALSE },
{ PRE_CMD, C_MKD, G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, C_XMKD, G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, C_MLSD, G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, C_MLST, G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, C_NLST, G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, C_RETR, G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, C_RMD, G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, C_XRMD, G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, C_RNFR, G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, C_RNTO, G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, C_SITE, G_NONE, procfs_pre_site, FALSE, FALSE },
{ PRE_CMD, C_SIZE, G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, C_STAT, G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, C_STOR, G_NONE, procfs_pre_path, FALSE, FALSE },
/* mod_digest FTP commands */
{ PRE_CMD, "HASH", G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, "MD5", G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, "XCRC", G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, "XMD5", G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, "XSHA", G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, "XSHA1", G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, "XSHA256", G_NONE, procfs_pre_path, FALSE, FALSE },
{ PRE_CMD, "XSHA512", G_NONE, procfs_pre_path, FALSE, FALSE },
/* SFTP */
{ PRE_CMD, "HARDLINK", G_NONE, procfs_sftp_pre_hardlink, FALSE, FALSE },
{ PRE_CMD, "LINK", G_NONE, procfs_sftp_pre_hardlink, FALSE, FALSE },
{ PRE_CMD, "LSTAT", G_NONE, procfs_sftp_pre_path, FALSE, FALSE },
{ PRE_CMD, "OPENDIR", G_NONE, procfs_sftp_pre_path, FALSE, FALSE },
{ PRE_CMD, "READLINK", G_NONE, procfs_sftp_pre_path, FALSE, FALSE },
{ PRE_CMD, "REALPATH", G_NONE, procfs_sftp_pre_path, FALSE, FALSE },
{ PRE_CMD, "SETSTAT", G_NONE, procfs_sftp_pre_path, FALSE, FALSE },
{ PRE_CMD, "SYMLINK", G_NONE, procfs_sftp_pre_symlink, FALSE, FALSE },
{ POST_CMD, C_PASS, G_NONE, procfs_post_pass, FALSE, FALSE },
{ 0, NULL }
};
module procfs_module = {
NULL, NULL,
/* Module API version 2.0 */
0x20,
/* Module name */
"procfs",
/* Module configuration handler table */
procfs_conftab,
/* Module command handler table */
procfs_cmdtab,
/* Module authentication handler table */
NULL,
/* Module initialization function */
procfs_init,
/* Session initialization function */
procfs_sess_init,
/* Module version */
MOD_PROCFS_VERSION
};
proftpd-mod_procfs-0.3/mod_procfs.html 0000664 0000000 0000000 00000012447 15232172151 0020213 0 ustar 00root root 0000000 0000000
ProFTPD module mod_procfs
ProFTPD module mod_procfs
The mod_procfs module affects the visibility and usage of the
/proc and /sys pseudo-filesystem directories.
This module is contained in the mod_procfs file for
ProFTPD 1.3.x, and is not compiled by default. Installation
instructions are discussed here. More examples
of mod_procfs usage can be found here.
The most current version of mod_procfs can be found at:
https://github.com/Castaglia/proftpd-mod_procfs
Author
Please contact TJ Saunders <tj at castaglia.org> with any
questions, concerns, or suggestions regarding this module.
Directives
Syntax: ProcfsEngine on|off
Default: on
Context: "server config", <VirtualHost>, <Global>
Module: mod_procfs
Compatibility: 1.3.1rc1 and later
The ProcfsEngine directive enables or disables the module's
hiding of the /proc and /sys filesystems. When
enabled, mod_procfs works to prevent access to the
/proc and /sys pseudo-filesystems, returning
"No such file or directory" errors for such access attempts.
Note that ProcfsEngine is automatically enabled
if the module detects, on startup, that the /proc or
/sys filesystems are present. If the /proc and
/sys filesystems are not present on startup, then
ProcfsEngine is automatically disabled. Explicitly setting this
directive overrides the automatic behavior.
Syntax: ProcfsLog file
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_procfs
Compatibility: 1.3.1rc1 and later
The ProcfsLog directive is used to a specify a log file for
mod_procfs reporting and debugging, and can be done a per-server
basis. The file parameter must be the full path to the file to use for
logging. Note that this path must not be to a world-writeable
directory and, unless AllowLogSymlinks is explicitly set to
on (generally a bad idea), the path must not be a symbolic
link.
If file is "none", no logging will be done at all; this
setting can be used to override a ProcfsLog setting inherited from
a <Global> context.
To install mod_procfs, copy the mod_procfs.c file
into:
proftpd-dir/contrib/
after unpacking the latest proftpd-1.3.x source code. For including
mod_procfs as a statically linked module:
./configure --with-modules=mod_procfs
To build mod_procfs as a DSO module:
./configure --enable-dso --with-shared=mod_procfs
Then follow the usual steps:
make
make install
For those with an existing ProFTPD installation, you can use the
prxs tool to add mod_procfs, as a DSO module, to
your existing server:
# prxs -c -i -d mod_procfs.c
The mod_procfs module works by using the ProFTPD command dispatch
system to intercept all commands/requests that use paths; if the paths
being used reference the /proc or /sys filesystems,
those commands will fail with a "No such file or directory" error.
Example configuration:
<IfModule mod_procfs.c>
# This is not required; the module automatically determines when it is
# needed.
ProcfsEngine on
ProcfsLog /var/log/proftpd/procfs.log
</IfModule>
Logging
The mod_procfs module supports different forms of logging. The
main module logging is done via the
ProcfsLog directive. For debugging
purposes, the module also uses
trace logging, via
the module-specific channels:
Thus for trace logging, to aid in debugging, you would use the following in
your proftpd.conf:
TraceLog /path/to/proftpd-trace.log
Trace command:10 response:10 procfs:20
This trace logging can generate large files; it is intended for debugging
use only, and should be removed from any production configuration.
© Copyright 2026 TJ Saunders
All Rights Reserved
proftpd-mod_procfs-0.3/t/ 0000775 0000000 0000000 00000000000 15232172151 0015425 5 ustar 00root root 0000000 0000000 proftpd-mod_procfs-0.3/t/lib/ 0000775 0000000 0000000 00000000000 15232172151 0016173 5 ustar 00root root 0000000 0000000 proftpd-mod_procfs-0.3/t/lib/ProFTPD/ 0000775 0000000 0000000 00000000000 15232172151 0017411 5 ustar 00root root 0000000 0000000 proftpd-mod_procfs-0.3/t/lib/ProFTPD/Tests/ 0000775 0000000 0000000 00000000000 15232172151 0020513 5 ustar 00root root 0000000 0000000 proftpd-mod_procfs-0.3/t/lib/ProFTPD/Tests/Modules/ 0000775 0000000 0000000 00000000000 15232172151 0022123 5 ustar 00root root 0000000 0000000 proftpd-mod_procfs-0.3/t/lib/ProFTPD/Tests/Modules/mod_procfs.pm 0000664 0000000 0000000 00000241477 15232172151 0024633 0 ustar 00root root 0000000 0000000 package ProFTPD::Tests::Modules::mod_procfs;
use lib qw(t/lib);
use base qw(ProFTPD::TestSuite::Child);
use strict;
use Cwd;
use File::Copy;
use File::Path qw(mkpath);
use File::Spec;
use IO::Handle;
use ProFTPD::TestSuite::FTP;
use ProFTPD::TestSuite::Utils qw(:auth :config :running :test :testsuite);
$| = 1;
my $order = 0;
my $TESTS = {
procfs_engine_off => {
order => ++$order,
test_class => [qw(bug forking)],
},
procfs_chrooted_nonrootfs => {
order => ++$order,
test_class => [qw(bug forking rootprivs)],
},
procfs_chrooted_rootfs => {
order => ++$order,
test_class => [qw(bug forking rootprivs)],
},
procfs_rename_issue2170 => {
order => ++$order,
test_class => [qw(bug forking)],
},
procfs_appe_rejected => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_cwd_rejected => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_dele_rejected => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_list_rejected => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_mdtm_rejected => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_mkd_rejected => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_mlsd_rejected => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_mlst_rejected => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_nlst_rejected => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_retr_procfs_rejected => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_retr_sysfs_rejected => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_rmd_rejected => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_rnto_rejected => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_size_rejected => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_stat_rejected => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_stor_rejected => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_site_chgrp_rejected => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_site_chmod_rejected => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_site_mkdir_rejected => {
order => ++$order,
test_class => [qw(forking mod_site_misc)],
},
procfs_site_rmdir_rejected => {
order => ++$order,
test_class => [qw(forking mod_site_misc)],
},
procfs_site_symlink_rejected => {
order => ++$order,
test_class => [qw(forking mod_site_misc)],
},
procfs_site_utime_rejected => {
order => ++$order,
test_class => [qw(forking mod_site_misc)],
},
procfs_site_cpfr_rejected => {
order => ++$order,
test_class => [qw(forking mod_copy)],
},
procfs_site_cpto_rejected => {
order => ++$order,
test_class => [qw(forking mod_copy)],
},
procfs_site_copy_rejected => {
order => ++$order,
test_class => [qw(forking mod_copy)],
},
};
sub new {
return shift()->SUPER::new(@_);
}
sub list_tests {
return testsuite_get_runnable_tests($TESTS);
}
sub procfs_engine_off {
my $self = shift;
unless (-d '/proc/') {
print STDERR "# /proc/ filesystem does not exist, skipping\n";
return;
}
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'off',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
$client->list('/proc');
sleep(0.25);
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$self->assert_transfer_ok($resp_code, $resp_msg);
$client->list('/proc/');
sleep(0.25);
$resp_code = $client->response_code();
$resp_msg = $client->response_msg();
$self->assert_transfer_ok($resp_code, $resp_msg);
$client->quit();
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_chrooted_nonrootfs {
my $self = shift;
unless (-d '/proc/') {
print STDERR "# /proc/ filesystem does not exist, skipping\n";
return;
}
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
DefaultRoot => '~',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->list('/proc') };
unless ($@) {
die("LIST /proc succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
my $expected = 450;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
eval { $client->list('/proc/') };
unless ($@) {
die("LIST succeeded unexpectedly");
}
$resp_code = $client->response_code();
$resp_msg = $client->response_msg();
$expected = 450;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/: No such file or directory";
$self->assert($expected eq $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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_chrooted_rootfs {
my $self = shift;
unless (-d '/proc/') {
print STDERR "# /proc/ filesystem does not exist, skipping\n";
return;
}
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
DefaultRoot => '/',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->list('/proc') };
unless ($@) {
die("LIST /proc succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
my $expected = 450;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
eval { $client->list('/proc/') };
unless ($@) {
die("LIST succeeded unexpectedly");
}
$resp_code = $client->response_code();
$resp_msg = $client->response_msg();
$expected = 450;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/: No such file or directory";
$self->assert($expected eq $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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_rename_issue2170 {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $test_dir = File::Spec->rel2abs("$setup->{home_dir}/private");
mkpath($test_dir);
my $test_file = File::Spec->rel2abs("$test_dir/test.txt");
if (open(my $fh, "> $test_file")) {
print $fh "Hello, World!\n";
unless (close($fh)) {
die("Can't write $test_file: $!");
}
# Make sure that, if we're running as root, that the test file has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $test_dir)) {
die("Can't set perms on $test_dir: $!");
}
unless (chown($setup->{uid}, $setup->{gid}, $test_dir, $test_file)) {
die("Can't set owner of $test_dir to $setup->{uid}/$setup->{gid}: $!");
}
}
} else {
die("Can't open $test_file: $!");
}
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
if (open(my $fh, ">> $setup->{config_file}")) {
print $fh <
DenyAll
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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->rnfr("/proc/self/root/$test_file") };
unless ($@) {
die("RNFR succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/self/root/$test_file: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_appe_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
my $conn = $client->appe_raw('/proc/test.txt');
if ($conn) {
die("APPE succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/test.txt: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_cwd_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->cwd('/proc/') };
unless ($@) {
die("CWD 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 = "/proc/: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
eval { $client->cwd('/proc') };
unless ($@) {
die("CWD succeeded unexpectedly");
}
$resp_code = $client->response_code();
$resp_msg = $client->response_msg();
$expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
eval { $client->xcwd('/proc/') };
unless ($@) {
die("XCWD succeeded unexpectedly");
}
$resp_code = $client->response_code();
$resp_msg = $client->response_msg();
$expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
eval { $client->xcwd('/proc') };
unless ($@) {
die("XCWD succeeded unexpectedly");
}
$resp_code = $client->response_code();
$resp_msg = $client->response_msg();
$expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc: No such file or directory";
$self->assert($expected eq $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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_dele_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->dele('/proc/test.txt') };
unless ($@) {
die("DELE succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/test.txt: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_list_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->list('/proc') };
unless ($@) {
die("LIST succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
my $expected = 450;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
eval { $client->list('/proc/') };
unless ($@) {
die("LIST succeeded unexpectedly");
}
$resp_code = $client->response_code();
$resp_msg = $client->response_msg();
$expected = 450;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/: No such file or directory";
$self->assert($expected eq $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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_mdtm_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->mdtm('/proc/test.txt') };
unless ($@) {
die("MDTM succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/test.txt: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_mff_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->mff('modify=20020717210715;', '/proc/test.txt') };
unless ($@) {
die("MFF succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/test.txt: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_mfmt_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->mfmt('20020717210715', '/proc/test.txt') };
unless ($@) {
die("MFMT succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/test.txt: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_mkd_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->mkd('/proc/test.d') };
unless ($@) {
die("MKD 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 = "/proc/test.d: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
eval { $client->xmkd('/proc/test.d') };
unless ($@) {
die("XMKD succeeded unexpectedly");
}
$resp_code = $client->response_code();
$resp_msg = $client->response_msg();
$expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/test.d: No such file or directory";
$self->assert($expected eq $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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_mlsd_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->mlsd('/proc') };
unless ($@) {
die("MLSD 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 = "/proc: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
eval { $client->mlsd('/proc/') };
unless ($@) {
die("MLSD succeeded unexpectedly");
}
$resp_code = $client->response_code();
$resp_msg = $client->response_msg();
$expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/: No such file or directory";
$self->assert($expected eq $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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_mlst_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->mlst('/proc') };
unless ($@) {
die("MLST 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 = '(No such file or directory|cannot be listed)';
$self->assert(qr/$expected/, $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
eval { $client->mlst('/proc/') };
unless ($@) {
die("MLST succeeded unexpectedly");
}
$resp_code = $client->response_code();
$resp_msg = $client->response_msg();
$expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = '(No such file or directory|cannot be listed)';
$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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_nlst_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->nlst('/proc') };
unless ($@) {
die("NLST succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
my $expected = 450;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
eval { $client->nlst('/proc/') };
unless ($@) {
die("NLST succeeded unexpectedly");
}
$resp_code = $client->response_code();
$resp_msg = $client->response_msg();
$expected = 450;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = '/proc(\/)?: No such file or directory';
$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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_retr_procfs_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
my $conn = $client->retr_raw('/proc/test.txt');
if ($conn) {
die("RETR succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/test.txt: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_retr_sysfs_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $test_file = '/sys/test.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
my $conn = $client->retr_raw($test_file);
if ($conn) {
die("RETR succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "$test_file: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /RETR $test_file denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_rmd_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->rmd('/proc/') };
unless ($@) {
die("RMD 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 = "/proc/: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
eval { $client->xrmd('/proc') };
unless ($@) {
die("XRMD succeeded unexpectedly");
}
$resp_code = $client->response_code();
$resp_msg = $client->response_msg();
$expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc: No such file or directory";
$self->assert($expected eq $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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_rnto_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $src_file = File::Spec->rel2abs("$tmpdir/src.txt");
if (open(my $fh, "> $src_file")) {
print $fh "Hello, World!\n";
unless (close($fh)) {
die("Can't write $src_file: $!");
}
} else {
die("Can't open $src_file: $!");
}
if ($< == 0) {
unless (chown($setup->{uid}, $setup->{gid}, $src_file)) {
die("Can't set owner of $src_file to $setup->{uid}/$setup->{gid}: $!");
}
}
my $dst_file = File::Spec->rel2abs("/proc/test.txt");
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
$client->rnfr($src_file);
eval { $client->rnto($dst_file) };
unless ($@) {
die("RNTO succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "$dst_file: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_size_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
$client->type('binary');
eval { $client->size('/proc/test.txt') };
unless ($@) {
die("SIZE succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/test.txt: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_stat_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->stat('/proc/test.txt') };
unless ($@) {
die("STAT succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 450;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/test.txt: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_stor_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
my $conn = $client->stor_raw('/proc/test.txt');
if ($conn) {
die("STOR succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/test.txt: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_site_chgrp_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->site('CHGRP', $setup->{group}, '/proc/test.txt') };
unless ($@) {
die("SITE CHGRP succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/test.txt: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_site_chmod_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->site('CHMOD', '777', '/proc/test.txt') };
unless ($@) {
die("SITE CHMOD succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/test.txt: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_site_mkdir_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->site('MKDIR', '/proc/test.d') };
unless ($@) {
die("SITE MKDIR succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = '(No such file or directory|Read-only file system)';
$self->assert(qr/$expected/, $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_site_rmdir_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->site('RMDIR', '/proc') };
unless ($@) {
die("SITE RMDIR succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = 'No such file or directory';
$self->assert(qr/$expected/, $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_site_symlink_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->site('SYMLINK', '/proc/from.txt', 'to.txt') };
unless ($@) {
die("SITE SYMLINK 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 = 'No such file or directory';
$self->assert(qr/$expected/, $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
eval { $client->site('SYMLINK', 'from.txt', '/proc/to.txt') };
unless ($@) {
die("SITE SYMLINK succeeded unexpectedly");
}
$resp_code = $client->response_code();
$resp_msg = $client->response_msg();
$expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = 'No such file or directory';
$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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_site_utime_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->site('UTIME', '200002240826', '/proc/test.txt') };
unless ($@) {
die("SITE UTIME succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = 'No such file or directory';
$self->assert(qr/$expected/, $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_site_cpfr_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->site('CPFR', '/proc/test.txt') };
unless ($@) {
die("SITE CPFR succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "/proc/test.txt: No such file or directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_site_cpto_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $src_file = File::Spec->rel2abs("$tmpdir/src.txt");
if (open(my $fh, "> $src_file")) {
print $fh "Hello, World!\n";
unless (close($fh)) {
die("Can't write $src_file: $!");
}
} else {
die("Can't open $src_file: $!");
}
if ($< == 0) {
unless (chown($setup->{uid}, $setup->{gid}, $src_file)) {
die("Can't set owner of $src_file to $setup->{uid}/$setup->{gid}: $!");
}
}
my $dst_file = '/proc/test.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
$client->site('CPFR', $src_file);
eval { $client->site('CPTO', $dst_file) };
unless ($@) {
die("SITE CPTO succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
$client->quit();
my $expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = 'No such file or directory';
$self->assert(qr/$expected/, $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
sub procfs_site_copy_rejected {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'command:10 response:10 procfs:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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 {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->site('COPY', '/proc/from.txt', 'to.txt') };
unless ($@) {
die("SITE COPY 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 = 'No such file or directory';
$self->assert(qr/$expected/, $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
eval { $client->site('COPY', 'from.txt', '/proc/to.txt') };
unless ($@) {
die("SITE COPY succeeded unexpectedly");
}
$resp_code = $client->response_code();
$resp_msg = $client->response_msg();
$expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = 'No such file or directory';
$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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
test_cleanup($setup, $ex);
}
1;
proftpd-mod_procfs-0.3/t/lib/ProFTPD/Tests/Modules/mod_procfs/ 0000775 0000000 0000000 00000000000 15232172151 0024256 5 ustar 00root root 0000000 0000000 proftpd-mod_procfs-0.3/t/lib/ProFTPD/Tests/Modules/mod_procfs/digest.pm 0000664 0000000 0000000 00000061637 15232172151 0026110 0 ustar 00root root 0000000 0000000 package ProFTPD::Tests::Modules::mod_procfs::digest;
use lib qw(t/lib);
use base qw(ProFTPD::TestSuite::Child);
use strict;
use Cwd;
use File::Copy;
use File::Path qw(mkpath);
use File::Spec;
use IO::Handle;
use IPC::Open3;
use Socket;
use ProFTPD::TestSuite::FTP;
use ProFTPD::TestSuite::Utils qw(:auth :config :running :test :testsuite);
$| = 1;
my $order = 0;
my $TESTS = {
procfs_digest_hash => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_digest_md5 => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_digest_xmd5 => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_digest_xcrc => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_digest_xsha => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_digest_xsha1 => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_digest_xsha256 => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_digest_xsha512 => {
order => ++$order,
test_class => [qw(forking)],
},
};
sub new {
return shift()->SUPER::new(@_);
}
sub list_tests {
return testsuite_get_runnable_tests($TESTS);
# procfs_digest_xsha
# procfs_digest_xsha1
# procfs_digest_xsha256
}
sub procfs_digest_hash {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $test_file = '/proc/test.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 digest:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_digest.c' => {
DigestEngine => 'on',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
my $algo = 'CRC32';
my ($resp_code, $resp_msg) = $client->opts('HASH', $algo);
my $expected = 200;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = $algo;
$self->assert($expected eq $resp_msg,
test_msg("Expected response message '$expected', got '$resp_msg'"));
eval { $client->quote('HASH', $test_file) };
unless ($@) {
die("HASH command succeeded unexpectedly");
}
$resp_code = $client->response_code();
$resp_msg = $client->response_msg();
$expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected response code $expected, got $resp_code"));
$expected = "$test_file: No such file or directory";
$self->assert($expected eq $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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /HASH $test_file denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_digest_md5 {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $test_file = '/proc/test.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 digest:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_digest.c' => {
DigestEngine => 'on',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->quote('MD5', $test_file) };
unless ($@) {
die("MD5 command 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 = "$test_file: No such file or directory";
$self->assert($expected eq $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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /MD5 $test_file denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_digest_xmd5 {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $test_file = '/proc/test.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 digest:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_digest.c' => {
DigestEngine => 'on',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->quote('XMD5', $test_file) };
unless ($@) {
die("XMD5 command 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 = "$test_file: No such file or directory";
$self->assert($expected eq $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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /XMD5 $test_file denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_digest_xcrc {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $test_file = '/proc/test.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 digest:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_digest.c' => {
DigestEngine => 'on',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->quote('XCRC', $test_file) };
unless ($@) {
die("XCRC command 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 = "$test_file: No such file or directory";
$self->assert($expected eq $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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /XCRC $test_file denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_digest_xsha {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $test_file = '/proc/test.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 digest:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_digest.c' => {
DigestEngine => 'on',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->quote('XSHA', $test_file) };
unless ($@) {
die("XSHA command 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 = "$test_file: No such file or directory";
$self->assert($expected eq $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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /XSHA $test_file denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_digest_xsha1 {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $test_file = '/proc/test.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 digest:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_digest.c' => {
DigestEngine => 'on',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->quote('XSHA1', $test_file) };
unless ($@) {
die("XSHA1 command 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 = "$test_file: No such file or directory";
$self->assert($expected eq $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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /XSHA1 $test_file denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_digest_xsha256 {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $test_file = '/proc/test.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 digest:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_digest.c' => {
DigestEngine => 'on',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->quote('XSHA256', $test_file) };
unless ($@) {
die("XSHA256 command 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 = "$test_file: No such file or directory";
$self->assert($expected eq $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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /XSHA256 $test_file denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_digest_xsha512 {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $test_file = '/proc/test.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 digest:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_digest.c' => {
DigestEngine => 'on',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($setup->{user}, $setup->{passwd});
eval { $client->quote('XSHA512', $test_file) };
unless ($@) {
die("XSHA512 command 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 = "$test_file: No such file or directory";
$self->assert($expected eq $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) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /XSHA512 $test_file denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
1;
proftpd-mod_procfs-0.3/t/lib/ProFTPD/Tests/Modules/mod_procfs/sftp.pm 0000664 0000000 0000000 00000163115 15232172151 0025577 0 ustar 00root root 0000000 0000000 package ProFTPD::Tests::Modules::mod_procfs::sftp;
use lib qw(t/lib);
use base qw(ProFTPD::TestSuite::Child);
use strict;
use Cwd;
use File::Copy;
use File::Path qw(mkpath);
use File::Spec;
use IO::Handle;
use IPC::Open3;
use POSIX qw(:fcntl_h);
use Socket;
use ProFTPD::TestSuite::Utils qw(:auth :config :running :test :testsuite);
$| = 1;
my $order = 0;
my $TESTS = {
procfs_sftp_open_readonly => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_sftp_open_readwrite => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_sftp_lstat => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_sftp_mkdir => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_sftp_opendir => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_sftp_readlink => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_sftp_realpath => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_sftp_remove => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_sftp_rename => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_sftp_rmdir => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_sftp_setstat => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_sftp_stat => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_sftp_symlink => {
order => ++$order,
test_class => [qw(forking)],
},
procfs_sftp_ext_hardlink => {
order => ++$order,
test_class => [qw(forking)],
},
# TODO
# procfs_sftp_link
};
sub new {
return shift()->SUPER::new(@_);
}
sub list_tests {
# Check for the required Perl modules:
#
# Net-SSH2
# Net-SSH2-SFTP
my $required = [qw(
Net::SSH2
Net::SSH2::SFTP
)];
foreach my $req (@$required) {
eval "use $req";
if ($@) {
print STDERR "\nWARNING:\n + Module '$req' not found, skipping all tests\n";
if ($ENV{TEST_VERBOSE}) {
print STDERR "Unable to load $req: $@\n";
}
return qw(testsuite_empty_test);
}
}
return testsuite_get_runnable_tests($TESTS);
}
sub set_up {
my $self = shift;
$self->SUPER::set_up(@_);
# Make sure that mod_sftp does not complain about permissions on the hostkey
# files.
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
unless (chmod(0400, $rsa_host_key, $dsa_host_key)) {
die("Can't set perms on $rsa_host_key, $dsa_host_key: $!");
}
}
sub procfs_sftp_open_readonly {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_file = '/proc/test.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 sftp:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
'mod_sftp.c' => [
'SFTPEngine on',
"SFTPLog $setup->{log_file}",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $ssh2 = Net::SSH2->new();
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($setup->{user}, $setup->{passwd})) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $fh = $sftp->open($test_file, O_RDONLY);
if ($fh) {
die("OPEN $test_file succeeded unexpectedly");
}
my ($err_code, $err_name) = $sftp->error();
my $expected = 'SSH_FX_NO_SUCH_FILE';
$self->assert($expected eq $err_name,
test_msg("Expected error name '$expected', got '$err_name'"));
$expected = 2;
$self->assert($expected == $err_code,
test_msg("Expected error code $expected, got $err_code"));
$sftp = undef;
$ssh2->disconnect();
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /RETR $test_file denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_sftp_open_readwrite {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_file = '/proc/test.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 sftp:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
'mod_sftp.c' => [
'SFTPEngine on',
"SFTPLog $setup->{log_file}",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $ssh2 = Net::SSH2->new();
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($setup->{user}, $setup->{passwd})) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $fh = $sftp->open($test_file, O_RDWR|O_CREAT);
if ($fh) {
die("OPEN $test_file succeeded unexpectedly");
}
my ($err_code, $err_name) = $sftp->error();
my $expected = 'SSH_FX_NO_SUCH_FILE';
$self->assert($expected eq $err_name,
test_msg("Expected error name '$expected', got '$err_name'"));
$expected = 2;
$self->assert($expected == $err_code,
test_msg("Expected error code $expected, got $err_code"));
$sftp = undef;
$ssh2->disconnect();
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /STOR $test_file denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_sftp_lstat {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_file = '/proc/test.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 sftp:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
'mod_sftp.c' => [
'SFTPEngine on',
"SFTPLog $setup->{log_file}",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $ssh2 = Net::SSH2->new();
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($setup->{user}, $setup->{passwd})) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $st = $sftp->stat($test_file, 0);
if ($st) {
die("LSTAT $test_file succeeded unexpectedly");
}
my ($err_code, $err_name) = $sftp->error();
my $expected = 'SSH_FX_PERMISSION_DENIED';
$self->assert($expected eq $err_name,
test_msg("Expected error name '$expected', got '$err_name'"));
$expected = 3;
$self->assert($expected == $err_code,
test_msg("Expected error code $expected, got $err_code"));
$sftp = undef;
$ssh2->disconnect();
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /LSTAT $test_file denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_sftp_mkdir {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_path = '/proc/test.d';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 sftp:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
'mod_sftp.c' => [
'SFTPEngine on',
"SFTPLog $setup->{log_file}",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $ssh2 = Net::SSH2->new();
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($setup->{user}, $setup->{passwd})) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $res = $sftp->mkdir($test_path);
if ($res) {
die("MKDIR $test_path succeeded unexpectedly");
}
my ($err_code, $err_name) = $sftp->error();
my $expected = 'SSH_FX_PERMISSION_DENIED';
$self->assert($expected eq $err_name,
test_msg("Expected error name '$expected', got '$err_name'"));
$expected = 3;
$self->assert($expected == $err_code,
test_msg("Expected error code $expected, got $err_code"));
$sftp = undef;
$ssh2->disconnect();
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /MKD $test_path denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_sftp_opendir {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_path = '/proc/test.d';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 sftp:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
'mod_sftp.c' => [
'SFTPEngine on',
"SFTPLog $setup->{log_file}",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $ssh2 = Net::SSH2->new();
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($setup->{user}, $setup->{passwd})) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $dir = $sftp->opendir($test_path);
if ($dir) {
die("OPENDIR $test_path succeeded unexpectedly");
}
my ($err_code, $err_name) = $sftp->error();
my $expected = 'SSH_FX_PERMISSION_DENIED';
$self->assert($expected eq $err_name,
test_msg("Expected error name '$expected', got '$err_name'"));
$expected = 3;
$self->assert($expected == $err_code,
test_msg("Expected error code $expected, got $err_code"));
$sftp = undef;
$ssh2->disconnect();
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /OPENDIR $test_path denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_sftp_readlink {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_file = '/proc/test.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 sftp:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
'mod_sftp.c' => [
'SFTPEngine on',
"SFTPLog $setup->{log_file}",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $ssh2 = Net::SSH2->new();
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($setup->{user}, $setup->{passwd})) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $res = $sftp->readlink($test_file);
if ($res) {
die("READLINK $test_file succeeded unexpectedly");
}
my ($err_code, $err_name) = $sftp->error();
my $expected = 'SSH_FX_PERMISSION_DENIED';
$self->assert($expected eq $err_name,
test_msg("Expected error name '$expected', got '$err_name'"));
$expected = 3;
$self->assert($expected == $err_code,
test_msg("Expected error code $expected, got $err_code"));
$sftp = undef;
$ssh2->disconnect();
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /READLINK $test_file denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_sftp_realpath {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_file = '/proc/test.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 sftp:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
'mod_sftp.c' => [
'SFTPEngine on',
"SFTPLog $setup->{log_file}",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $ssh2 = Net::SSH2->new();
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($setup->{user}, $setup->{passwd})) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $res = $sftp->realpath($test_file);
if ($res) {
die("REALPATH $test_file succeeded unexpectedly");
}
my ($err_code, $err_name) = $sftp->error();
my $expected = 'SSH_FX_PERMISSION_DENIED';
$self->assert($expected eq $err_name,
test_msg("Expected error name '$expected', got '$err_name'"));
$expected = 3;
$self->assert($expected == $err_code,
test_msg("Expected error code $expected, got $err_code"));
$sftp = undef;
$ssh2->disconnect();
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /REALPATH $test_file denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_sftp_remove {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_file = '/proc/test.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 sftp:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
'mod_sftp.c' => [
'SFTPEngine on',
"SFTPLog $setup->{log_file}",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $ssh2 = Net::SSH2->new();
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($setup->{user}, $setup->{passwd})) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $res = $sftp->unlink($test_file);
if ($res) {
die("REMOVE $test_file succeeded unexpectedly");
}
my ($err_code, $err_name) = $sftp->error();
my $expected = 'SSH_FX_PERMISSION_DENIED';
$self->assert($expected eq $err_name,
test_msg("Expected error name '$expected', got '$err_name'"));
$expected = 3;
$self->assert($expected == $err_code,
test_msg("Expected error code $expected, got $err_code"));
$sftp = undef;
$ssh2->disconnect();
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /DELE $test_file denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_sftp_rename {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $from_file = '/proc/src.txt';
my $to_file = '/proc/dst.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 sftp:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
'mod_sftp.c' => [
'SFTPEngine on',
"SFTPLog $setup->{log_file}",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $ssh2 = Net::SSH2->new();
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($setup->{user}, $setup->{passwd})) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $res = $sftp->rename($from_file, 'dst.txt');
if ($res) {
die("RENAME $from_file succeeded unexpectedly");
}
my ($err_code, $err_name) = $sftp->error();
my $expected = 'SSH_FX_PERMISSION_DENIED';
$self->assert($expected eq $err_name,
test_msg("Expected error name '$expected', got '$err_name'"));
$expected = 3;
$self->assert($expected == $err_code,
test_msg("Expected error code $expected, got $err_code"));
$res = $sftp->rename('src.txt', $to_file);
if ($res) {
die("RENAME $to_file succeeded unexpectedly");
}
($err_code, $err_name) = $sftp->error();
$expected = 'SSH_FX_PERMISSION_DENIED';
$self->assert($expected eq $err_name,
test_msg("Expected error name '$expected', got '$err_name'"));
$expected = 3;
$self->assert($expected == $err_code,
test_msg("Expected error code $expected, got $err_code"));
$sftp = undef;
$ssh2->disconnect();
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $from_ok = 0;
my $to_ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /RNFR $from_file denied by mod_procfs/) {
$from_ok = 1;
}
if ($line =~ /RNTO $to_file denied by mod_procfs/) {
$to_ok = 1;
}
if ($from_ok && $to_ok) {
last;
}
}
close($fh);
$self->assert($from_ok && $to_ok,
test_msg("Did not see expected ProcfsLog messages"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_sftp_rmdir {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_path = '/proc/test.d';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 sftp:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
'mod_sftp.c' => [
'SFTPEngine on',
"SFTPLog $setup->{log_file}",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $ssh2 = Net::SSH2->new();
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($setup->{user}, $setup->{passwd})) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $res = $sftp->rmdir($test_path);
if ($res) {
die("RMDIR $test_path succeeded unexpectedly");
}
my ($err_code, $err_name) = $sftp->error();
my $expected = 'SSH_FX_PERMISSION_DENIED';
$self->assert($expected eq $err_name,
test_msg("Expected error name '$expected', got '$err_name'"));
$expected = 3;
$self->assert($expected == $err_code,
test_msg("Expected error code $expected, got $err_code"));
$sftp = undef;
$ssh2->disconnect();
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /RMD $test_path denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_sftp_setstat {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_file = '/proc/test.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 sftp:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
'mod_sftp.c' => [
'SFTPEngine on',
"SFTPLog $setup->{log_file}",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $ssh2 = Net::SSH2->new();
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($setup->{user}, $setup->{passwd})) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $res = $sftp->setstat($test_file,
atime => 0,
mtime => 0
);
if ($res) {
die("SETSTAT $test_file succeeded unexpectedly");
}
my ($err_code, $err_name) = $sftp->error();
my $expected = 'SSH_FX_PERMISSION_DENIED';
$self->assert($expected eq $err_name,
test_msg("Expected error name '$expected', got '$err_name'"));
$expected = 3;
$self->assert($expected == $err_code,
test_msg("Expected error code $expected, got $err_code"));
$sftp = undef;
$ssh2->disconnect();
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /SETSTAT $test_file denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_sftp_stat {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_file = '/proc/test.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 sftp:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
'mod_sftp.c' => [
'SFTPEngine on',
"SFTPLog $setup->{log_file}",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $ssh2 = Net::SSH2->new();
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($setup->{user}, $setup->{passwd})) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $st = $sftp->stat($test_file, 1);
if ($st) {
die("STAT $test_file succeeded unexpectedly");
}
my ($err_code, $err_name) = $sftp->error();
my $expected = 'SSH_FX_PERMISSION_DENIED';
$self->assert($expected eq $err_name,
test_msg("Expected error name '$expected', got '$err_name'"));
$expected = 3;
$self->assert($expected == $err_code,
test_msg("Expected error code $expected, got $err_code"));
$sftp = undef;
$ssh2->disconnect();
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /STAT $test_file denied by mod_procfs/) {
$ok = 1;
last;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog message"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_sftp_symlink {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $from_file = '/proc/src.txt';
my $to_file = '/proc/dst.txt';
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 sftp:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
'mod_sftp.c' => [
'SFTPEngine on',
"SFTPLog $setup->{log_file}",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $ssh2 = Net::SSH2->new();
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($setup->{user}, $setup->{passwd})) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $res = $sftp->symlink($from_file, 'dst.txt');
if ($res) {
die("SYMLINK $from_file succeeded unexpectedly");
}
my ($err_code, $err_name) = $sftp->error();
my $expected = 'SSH_FX_PERMISSION_DENIED';
$self->assert($expected eq $err_name,
test_msg("Expected error name '$expected', got '$err_name'"));
$expected = 3;
$self->assert($expected == $err_code,
test_msg("Expected error code $expected, got $err_code"));
$res = $sftp->symlink('src.txt', $to_file);
if ($res) {
die("SYMLINK $to_file succeeded unexpectedly");
}
($err_code, $err_name) = $sftp->error();
$expected = 'SSH_FX_PERMISSION_DENIED';
$self->assert($expected eq $err_name,
test_msg("Expected error name '$expected', got '$err_name'"));
$expected = 3;
$self->assert($expected == $err_code,
test_msg("Expected error code $expected, got $err_code"));
$sftp = undef;
$ssh2->disconnect();
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $from_ok = 0;
my $to_ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /SYMLINK $from_file denied by mod_procfs/) {
$from_ok = 1;
}
if ($line =~ /SYMLINK $to_file denied by mod_procfs/) {
$to_ok = 1;
}
if ($from_ok && $to_ok) {
last;
}
}
close($fh);
$self->assert($from_ok && $to_ok,
test_msg("Did not see expected ProcfsLog messages"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
sub procfs_sftp_ext_hardlink {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $setup = test_setup($tmpdir, 'procfs');
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $rsa_priv_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/test_rsa_key");
my $rsa_pub_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/test_rsa_key.pub");
my $rsa_rfc4716_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/authorized_rsa_keys");
my $authorized_keys = File::Spec->rel2abs("$tmpdir/.authorized_keys");
unless (copy($rsa_rfc4716_key, $authorized_keys)) {
die("Can't copy $rsa_rfc4716_key to $authorized_keys: $!");
}
my $from_file = '/proc/src.txt';
my $to_file = '/proc/dst.txt';
# As Net::SSH2::SFTP (via libssh2) does not implement LINK, we'll use
# OpenSSH's sftp(1) and its "hardlink@openssh.com" extension.
my $batch_file = File::Spec->rel2abs("$tmpdir/sftp-batch.conf");
if (open(my $fh, "> $batch_file")) {
print $fh "ln $from_file $to_file\n";
unless (close($fh)) {
die("Can't write $batch_file: $!");
}
} else {
die("Can't open $batch_file: $!");
}
my $config = {
PidFile => $setup->{pid_file},
ScoreboardFile => $setup->{scoreboard_file},
SystemLog => $setup->{log_file},
TraceLog => $setup->{log_file},
Trace => 'procfs:20 sftp:20',
AuthUserFile => $setup->{auth_user_file},
AuthGroupFile => $setup->{auth_group_file},
AuthOrder => 'mod_auth_file.c',
IfModules => {
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_procfs.c' => {
ProcfsEngine => 'on',
ProcfsLog => $setup->{log_file},
},
'mod_sftp.c' => [
'SFTPEngine on',
"SFTPLog $setup->{log_file}",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
"SFTPAuthorizedUserKeys file:~/.authorized_keys",
],
},
};
my ($port, $config_user, $config_group) = config_write($setup->{config_file},
$config);
# 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: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
# Allow for server startup
sleep(1);
my $sftp = 'sftp';
my @cmd = (
$sftp,
'-oBatchMode=yes',
'-oCheckHostIP=no',
'-oCompression=yes',
"-oPort=$port",
"-oIdentityFile=$rsa_priv_key",
'-oIdentitiesOnly=yes',
'-oPubkeyAuthentication=yes',
'-oStrictHostKeyChecking=no',
'-oUserKnownHostsFile=/dev/null',
'-vvv',
'-b',
$batch_file,
"$setup->{user}\@127.0.0.1",
);
my $sftp_rh = IO::Handle->new();
my $sftp_wh = IO::Handle->new();
my $sftp_eh = IO::Handle->new();
$sftp_wh->autoflush(1);
sleep(1);
local $SIG{CHLD} = 'DEFAULT';
# Make sure that the perms on the priv key are what OpenSSH wants
unless (chmod(0400, $rsa_priv_key)) {
die("Can't set perms on $rsa_priv_key to 0400: $!");
}
if ($ENV{TEST_VERBOSE}) {
print STDERR "Executing: ", join(' ', @cmd), "\n";
}
my $sftp_pid = open3($sftp_wh, $sftp_rh, $sftp_eh, @cmd);
waitpid($sftp_pid, 0);
my $exit_status = $?;
# Restore the perms on the priv key
unless (chmod(0644, $rsa_priv_key)) {
die("Can't set perms on $rsa_priv_key to 0644: $!");
}
my ($res, $errstr);
if ($exit_status >> 8 == 0) {
$errstr = join('', <$sftp_eh>);
$res = 0;
} else {
$errstr = join('', <$sftp_eh>);
if ($ENV{TEST_VERBOSE}) {
print STDERR "Stderr: $errstr\n";
}
$res = 1;
}
if ($res == 0) {
die("Hardlink $from_file on server succeeded unexpectedly");
}
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($setup->{config_file}, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($setup->{pid_file});
$self->assert_child_ok($pid);
eval {
if (open(my $fh, "< $setup->{log_file}")) {
my $ok = 0;
while (my $line = <$fh>) {
chomp($line);
next unless $line =~ /mod_procfs\//;
if ($ENV{TEST_VERBOSE}) {
print STDERR "# $line\n";
}
if ($line =~ /HARDLINK $from_file denied by mod_procfs/) {
$ok = 1;
}
}
close($fh);
$self->assert($ok, test_msg("Did not see expected ProcfsLog messages"));
} else {
die("Can't read $setup->{log_file}: $!");
}
};
if ($@) {
$ex = $@;
}
test_cleanup($setup, $ex);
}
1;
proftpd-mod_procfs-0.3/t/modules/ 0000775 0000000 0000000 00000000000 15232172151 0017075 5 ustar 00root root 0000000 0000000 proftpd-mod_procfs-0.3/t/modules/mod_procfs.t 0000664 0000000 0000000 00000000266 15232172151 0021421 0 ustar 00root root 0000000 0000000 #!/usr/bin/env perl
use lib qw(t/lib);
use strict;
use Test::Unit::HarnessUnit;
$| = 1;
my $r = Test::Unit::HarnessUnit->new();
$r->start("ProFTPD::Tests::Modules::mod_procfs");
proftpd-mod_procfs-0.3/t/modules/mod_procfs/ 0000775 0000000 0000000 00000000000 15232172151 0021230 5 ustar 00root root 0000000 0000000 proftpd-mod_procfs-0.3/t/modules/mod_procfs/digest.t 0000664 0000000 0000000 00000000276 15232172151 0022701 0 ustar 00root root 0000000 0000000 #!/usr/bin/env perl
use lib qw(t/lib);
use strict;
use Test::Unit::HarnessUnit;
$| = 1;
my $r = Test::Unit::HarnessUnit->new();
$r->start("ProFTPD::Tests::Modules::mod_procfs::digest");
proftpd-mod_procfs-0.3/t/modules/mod_procfs/sftp.t 0000664 0000000 0000000 00000000274 15232172151 0022374 0 ustar 00root root 0000000 0000000 #!/usr/bin/env perl
use lib qw(t/lib);
use strict;
use Test::Unit::HarnessUnit;
$| = 1;
my $r = Test::Unit::HarnessUnit->new();
$r->start("ProFTPD::Tests::Modules::mod_procfs::sftp");
proftpd-mod_procfs-0.3/tests.pl 0000664 0000000 0000000 00000005240 15232172151 0016662 0 ustar 00root root 0000000 0000000 #!/usr/bin/env perl
use strict;
use Cwd qw(abs_path);
use File::Spec;
use Getopt::Long;
use Test::Harness qw(&runtests $verbose);
my $opts = {};
GetOptions($opts, 'h|help', 'C|class=s@', 'K|keep-tmpfiles', 'F|file-pattern=s',
'V|verbose');
if ($opts->{h}) {
usage();
}
if ($opts->{K}) {
$ENV{KEEP_TMPFILES} = 1;
}
$verbose = 1;
if ($opts->{V}) {
$ENV{TEST_VERBOSE} = 1;
}
# We use this, rather than use(), since use() is equivalent to a BEGIN
# block, and we want the module to be loaded at run-time.
if ($ENV{PROFTPD_TEST_DIR}) {
push(@INC, "$ENV{PROFTPD_TEST_DIR}/t/lib");
}
my $test_dir = (File::Spec->splitpath(abs_path(__FILE__)))[1];
push(@INC, "$test_dir/t/lib");
require ProFTPD::TestSuite::Utils;
import ProFTPD::TestSuite::Utils qw(:testsuite);
# This is to handle the case where this tests.pl script might be
# being used to run test files other than those that ship with proftpd,
# e.g. to run the tests that come with third-party modules.
unless (defined($ENV{PROFTPD_TEST_BIN})) {
$ENV{PROFTPD_TEST_BIN} = File::Spec->catfile($test_dir, '..', 'proftpd');
}
$| = 1;
my $test_files;
if (scalar(@ARGV) > 0) {
$test_files = [@ARGV];
} else {
$test_files = [qw(
t/modules/mod_procfs.t
)];
# Now interrogate the build to see which module/feature-specific test files
# should be added to the list.
my $order = 0;
my $FEATURE_TESTS = {
't/modules/mod_procfs/digest.t' => {
order => ++$order,
test_class => [qw(mod_digest)],
},
't/modules/mod_procfs/sftp.t' => {
order => ++$order,
test_class => [qw(mod_sftp)],
},
};
my @feature_tests = testsuite_get_runnable_tests($FEATURE_TESTS);
my $feature_ntests = scalar(@feature_tests);
if ($feature_ntests > 1 ||
($feature_ntests == 1 && $feature_tests[0] ne 'testsuite_empty_test')) {
push(@$test_files, @feature_tests);
}
}
$ENV{PROFTPD_TEST} = 1;
if (defined($opts->{C})) {
$ENV{PROFTPD_TEST_ENABLE_CLASS} = join(':', @{ $opts->{C} });
} else {
# Disable all 'inprogress' and 'slow' tests by default
$ENV{PROFTPD_TEST_DISABLE_CLASS} = 'inprogress:slow';
}
if (defined($opts->{F})) {
# Using the provided string as a regex, and run only the tests whose
# files match the pattern
my $file_pattern = $opts->{F};
my $filtered_files = [];
foreach my $test_file (@$test_files) {
if ($test_file =~ /$file_pattern/) {
push(@$filtered_files, $test_file);
}
}
$test_files = $filtered_files;
}
runtests(@$test_files) if scalar(@$test_files) > 0;
exit 0;
sub usage {
print STDOUT <