[proftpd-mod-vroot] 04/05: New upstream version 0.9.4

Francesco Lovergine frankie at moszumanska.debian.org
Sat Dec 24 19:12:43 UTC 2016


This is an automated email from the git hooks/post-receive script.

frankie pushed a commit to branch master
in repository proftpd-mod-vroot.

commit 807dd9d48ac3ae9d8026ab83f1e7c00083a8f821
Author: Francesco Paolo Lovergine <frankie at debian.org>
Date:   Sat Dec 24 20:03:26 2016 +0100

    New upstream version 0.9.4
---
 mod_vroot.c                              |  55 +--
 mod_vroot.html                           |  15 +
 t/lib/ProFTPD/Tests/Modules/mod_vroot.pm | 789 ++++++++++++++++++++++++++++++-
 3 files changed, 820 insertions(+), 39 deletions(-)

diff --git a/mod_vroot.c b/mod_vroot.c
index 3c27be5..b0ce59a 100644
--- a/mod_vroot.c
+++ b/mod_vroot.c
@@ -2,7 +2,7 @@
  * ProFTPD: mod_vroot -- a module implementing a virtual chroot capability
  *                       via the FSIO API
  *
- * Copyright (c) 2002-2013 TJ Saunders
+ * Copyright (c) 2002-2014 TJ Saunders
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -32,7 +32,7 @@
 #include "conf.h"
 #include "privs.h"
 
-#define MOD_VROOT_VERSION 	"mod_vroot/0.9.3"
+#define MOD_VROOT_VERSION 	"mod_vroot/0.9.4"
 
 /* Make sure the version of proftpd is as necessary. */
 #if PROFTPD_VERSION_NUMBER < 0x0001030406
@@ -344,7 +344,6 @@ loop:
        * aliases are found.
        */
       bufp = buf;
-
       start_ptr = path;
 
       while (start_ptr != NULL) {
@@ -430,8 +429,7 @@ static int handle_vroot_alias(void) {
 
   c = find_config(main_server->conf, CONF_PARAM, "VRootAlias", FALSE);
   while (c) {
-    char src_path[PR_TUNABLE_PATH_MAX+1], dst_path[PR_TUNABLE_PATH_MAX+1],
-      vpath[PR_TUNABLE_PATH_MAX+1], *ptr;
+    char src_path[PR_TUNABLE_PATH_MAX+1], dst_path[PR_TUNABLE_PATH_MAX+1], *ptr;
 
     pr_signals_handle();
 
@@ -458,21 +456,6 @@ static int handle_vroot_alias(void) {
     vroot_lookup_path(NULL, dst_path, sizeof(dst_path)-1, ptr,
       VROOT_LOOKUP_FL_NO_ALIASES, NULL);
 
-    /* If the vroot of the source path matches the vroot of the destination
-     * path, then we have a badly configured VRootAlias, one which is trying
-     * to override itself.  Need to check for, and reject, such cases.
-     */
-    vroot_lookup_path(NULL, vpath, sizeof(vpath)-1, src_path,
-      VROOT_LOOKUP_FL_NO_ALIASES, NULL);
-    if (strcmp(dst_path, vpath) == 0) {
-      (void) pr_log_writefile(vroot_logfd, MOD_VROOT_VERSION,
-        "alias '%s' maps to its real path '%s' inside the vroot, "
-        "ignoring bad alias", dst_path, src_path);
-
-      c = find_config_next(c, c->next, CONF_PARAM, "VRootAlias", FALSE);
-      continue;
-    }
-
     if (vroot_alias_pool == NULL) {
       vroot_alias_pool = make_sub_pool(session.pool);
       pr_pool_tag(vroot_alias_pool, "VRoot Alias Pool");
@@ -1089,6 +1072,7 @@ static int vroot_alias_dirscan(const void *key_data, size_t key_datasz,
     void *value_data, size_t value_datasz, void *user_data) {
   const char *alias_path = NULL, *dir_path = NULL, *real_path = NULL;
   char *ptr = NULL;
+  size_t dir_pathlen;
 
   alias_path = key_data;
   real_path = value_data;
@@ -1109,15 +1093,12 @@ static int vroot_alias_dirscan(const void *key_data, size_t key_datasz,
     return 0;
   }
 
-  /* If the length from the start of the alias path to the last occurring
-   * slash is longer than the length of the directory path, then this
-   * alias obviously does not occur in this directory.
-   */
-  if ((ptr - alias_path) > strlen(dir_path)) {
-    return 0;
-  }
+  dir_pathlen = strlen(dir_path);
 
-  if (strncmp(dir_path, alias_path, (ptr - alias_path)) == 0) {
+  if (strncmp(dir_path, alias_path, dir_pathlen) == 0) {
+    pr_trace_msg(trace_channel, 17,
+      "adding VRootAlias '%s' to list of aliases contained in '%s'",
+      alias_path, dir_path);
     *((char **) push_array(vroot_dir_aliases)) = pstrdup(vroot_dir_pool,
       ptr + 1);
   }
@@ -1127,7 +1108,7 @@ static int vroot_alias_dirscan(const void *key_data, size_t key_datasz,
 
 static int vroot_dirtab_keycmp_cb(const void *key1, size_t keysz1,
     const void *key2, size_t keysz2) {
-  unsigned int k1, k2;
+  unsigned long k1, k2;
 
   memcpy(&k1, key1, sizeof(k1));
   memcpy(&k2, key2, sizeof(k2));
@@ -1136,7 +1117,7 @@ static int vroot_dirtab_keycmp_cb(const void *key1, size_t keysz1,
 }
 
 static unsigned int vroot_dirtab_hash_cb(const void *key, size_t keysz) {
-  unsigned int h;
+  unsigned long h;
 
   memcpy(&h, key, sizeof(h));
   return h;
@@ -1217,7 +1198,7 @@ static void *vroot_opendir(pr_fs_t *fs, const char *orig_path) {
   }
 
   if (vroot_aliastab != NULL) {
-    unsigned int *cache_dirh;
+    unsigned long *cache_dirh = NULL;
 
     if (vroot_dirtab == NULL) {
       vroot_dir_pool = make_sub_pool(session.pool);
@@ -1235,10 +1216,10 @@ static void *vroot_opendir(pr_fs_t *fs, const char *orig_path) {
         vroot_dirtab_keycmp_cb);
     }
 
-    cache_dirh = palloc(vroot_dir_pool, sizeof(unsigned int));
-    *cache_dirh = (unsigned int) dirh;
+    cache_dirh = palloc(vroot_dir_pool, sizeof(unsigned long));
+    *cache_dirh = (unsigned long) dirh;
 
-    if (pr_table_kadd(vroot_dirtab, cache_dirh, sizeof(unsigned int),
+    if (pr_table_kadd(vroot_dirtab, cache_dirh, sizeof(unsigned long),
         pstrdup(vroot_dir_pool, vpath), strlen(vpath) + 1) < 0) {
       (void) pr_log_writefile(vroot_logfd, MOD_VROOT_VERSION,
         "error stashing path '%s' (key %p) in directory table: %s", vpath,
@@ -1339,11 +1320,11 @@ static int vroot_closedir(pr_fs_t *fs, void *dirh) {
   res = closedir((DIR *) dirh);
 
   if (vroot_dirtab != NULL) {
-    unsigned int lookup_dirh;
+    unsigned long lookup_dirh;
     int count;
 
-    lookup_dirh = (unsigned int) dirh;
-    (void) pr_table_kremove(vroot_dirtab, &lookup_dirh, sizeof(unsigned int),
+    lookup_dirh = (unsigned long) dirh;
+    (void) pr_table_kremove(vroot_dirtab, &lookup_dirh, sizeof(unsigned long),
       NULL);
 
     /* If the dirtab table is empty, destroy the table. */
diff --git a/mod_vroot.html b/mod_vroot.html
index f980f89..c5f03df 100644
--- a/mod_vroot.html
+++ b/mod_vroot.html
@@ -196,11 +196,26 @@ the <code>mod_vroot.c</code> file into:
 Then follow the normal steps for using third-party modules in proftpd:
 <pre>
   ./configure --with-modules=mod_vroot
+</pre>
+To build <code>mod_vroot</code> as a DSO module:
+<pre>
+  ./configure --enable-dso --with-shared=mod_vroot
+</pre>
+Then follow the usual steps:
+<pre>
   make
   make install
 </pre>
 
 <p>
+For those with an existing ProFTPD installation, you can use the
+<code>prxs</code> tool to add <code>mod_vroot</code>, as a DSO module, to
+your existing server:
+<pre>
+  # prxs -c -i -d mod_vroot.c
+</pre>
+
+<p>
 <hr>
 Author: <i>$Author: tj $</i><br>
 Last Updated: <i>$Date: 2009/10/19 16:30:18 $</i><br>
diff --git a/t/lib/ProFTPD/Tests/Modules/mod_vroot.pm b/t/lib/ProFTPD/Tests/Modules/mod_vroot.pm
index 010070b..9c542db 100644
--- a/t/lib/ProFTPD/Tests/Modules/mod_vroot.pm
+++ b/t/lib/ProFTPD/Tests/Modules/mod_vroot.pm
@@ -29,6 +29,11 @@ my $TESTS = {
     test_class => [qw(forking)],
   },
 
+  vroot_anon_limit_write_allow_stor => {
+    order => ++$order,
+    test_class => [qw(forking)],
+  },
+
   vroot_symlink => {
     order => ++$order,
     test_class => [qw(forking)],
@@ -328,12 +333,37 @@ my $TESTS = {
     test_class => [qw(forking)],
   },
 
+  # See:
+  #  https://github.com/Castaglia/proftpd-mod_vroot/issues/4
+  vroot_alias_bad_src_dst_check_bug4 => {
+    order => ++$order,
+    test_class => [qw(bug forking)],
+  },
+
+  # See:
+  #  https://github.com/Castaglia/proftpd-mod_vroot/issues/5
+  vroot_alias_bad_alias_dirscan_bug5 => {
+    order => ++$order,
+    test_class => [qw(bug forking)],
+  },
+
+  # See:
+  #  https://github.com/proftpd/proftpd/issues/59
+  vroot_alias_enametoolong_bug59 => {
+    order => ++$order,
+    test_class => [qw(bug forking)],
+  },
+
 };
 
 sub new {
   return shift()->SUPER::new(@_);
 }
 
+sub tear_down {
+  rmtree('/tmp/vroot.d');
+}
+
 sub list_tests {
   return testsuite_get_runnable_tests($TESTS);
 
@@ -964,6 +994,185 @@ EOC
   unlink($log_file);
 }
 
+sub vroot_anon_limit_write_allow_stor {
+  my $self = shift;
+  my $tmpdir = $self->{tmpdir};
+
+  my $config_file = "$tmpdir/vroot.conf";
+  my $pid_file = File::Spec->rel2abs("$tmpdir/vroot.pid");
+  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/vroot.scoreboard");
+
+  my $log_file = test_get_logfile();
+
+  my $auth_user_file = File::Spec->rel2abs("$tmpdir/vroot.passwd");
+  my $auth_group_file = File::Spec->rel2abs("$tmpdir/vroot.group");
+
+  my ($user, $group) = config_get_identity();
+  my $passwd = 'test';
+  my $anon_dir = File::Spec->rel2abs($tmpdir);
+  my $uid = $<;
+  my $gid = $(;
+
+  my $uploads_dir = File::Spec->rel2abs("$anon_dir/uploads");
+  mkpath($uploads_dir);
+
+  my $test_file = File::Spec->rel2abs("$uploads_dir/test.txt");
+
+  # Make sure that, if we're running as root, that the home directory has
+  # permissions/privs set for the account we create
+  if ($< == 0) {
+    unless (chmod(0755, $anon_dir, $uploads_dir)) {
+      die("Can't set perms on $anon_dir to 0755: $!");
+    }
+
+    unless (chown($uid, $gid, $anon_dir, $uploads_dir)) {
+      die("Can't set owner of $anon_dir to $uid/$gid: $!");
+    }
+  }
+
+  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, '/tmp',
+    '/bin/bash');
+  auth_group_write($auth_group_file, $group, $gid, $user);
+
+  # Test this config:
+  #
+  #  <Anonymous>
+  #    <Limit WRITE SITE_CHMOD>
+  #      DenyAll
+  #    </Limit>
+  #
+  #    <Directory uploads/*>
+  #      <Limit STOR>
+  #        AllowAll
+  #      </Limit>
+  #    </Directory>
+  #  </Anonymous>
+
+  my $config = {
+    PidFile => $pid_file,
+    ScoreboardFile => $scoreboard_file,
+    SystemLog => $log_file,
+
+    AuthUserFile => $auth_user_file,
+    AuthGroupFile => $auth_group_file,
+
+    IfModules => {
+      'mod_vroot.c' => {
+        VRootEngine => 'on',
+        VRootLog => $log_file,
+      },
+
+      'mod_delay.c' => {
+        DelayEngine => 'off',
+      },
+    },
+  };
+
+  my ($port, $config_user, $config_group) = config_write($config_file, $config);
+
+  if (open(my $fh, ">> $config_file")) {
+    print $fh <<EOC;
+<Anonymous $anon_dir>
+  User $user
+  Group $group
+
+  RequireValidShell off
+
+  <Limit WRITE SITE_CHMOD>
+    DenyAll
+  </Limit>
+
+  # Ideally there would be no leading slash here, but because of how
+  # mod_vroot alters things (see Issue #1), the leading slash makes
+  # the test succeed.
+  <Directory /uploads/*>
+    <Limit STOR>
+      AllowAll
+    </Limit>
+  </Directory>
+
+</Anonymous>
+
+EOC
+    unless (close($fh)) {
+      die("Can't write $config_file: $!");
+    }
+
+  } else {
+    die("Can't open $config_file: $!");
+  }
+
+  # Open pipes, for use between the parent and child processes.  Specifically,
+  # the child will indicate when it's done with its test by writing a message
+  # to the parent.
+  my ($rfh, $wfh);
+  unless (pipe($rfh, $wfh)) {
+    die("Can't open pipe: $!");
+  }
+
+  my $ex;
+
+  # Fork child
+  $self->handle_sigchld();
+  defined(my $pid = fork()) or die("Can't fork: $!");
+  if ($pid) {
+    eval {
+      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
+      $client->login($user, $passwd);
+
+      my $conn = $client->stor_raw('uploads/test.txt');
+      unless ($conn) {
+        die("STOR uploads/test.txt failed:" . $client->response_code() . " " .
+          $client->response_msg());
+      }
+
+      my $buf = "Hello, World!\n";
+      $conn->write($buf, length($buf), 15);
+      eval { $conn->close() };
+
+      my $resp_code = $client->response_code();
+      my $resp_msg = $client->response_msg();
+
+      $self->assert_transfer_ok($resp_code, $resp_msg);
+
+      $client->quit();
+
+      $self->assert(-f $test_file,
+        test_msg("File $test_file does not exist as expected"));
+    };
+
+    if ($@) {
+      $ex = $@;
+    }
+
+    $wfh->print("done\n");
+    $wfh->flush();
+
+  } else {
+    eval { server_wait($config_file, $rfh) };
+    if ($@) {
+      warn($@);
+      exit 1;
+    }
+
+    exit 0;
+  }
+
+  # Stop server
+  server_stop($pid_file);
+
+  $self->assert_child_ok($pid);
+
+  if ($ex) {
+    test_append_logfile($log_file, $ex);
+    unlink($log_file);
+
+    die($ex);
+  }
+
+  unlink($log_file);
+}
+
 sub vroot_symlink {
   my $self = shift;
   my $tmpdir = $self->{tmpdir};
@@ -1033,7 +1242,7 @@ sub vroot_symlink {
     ScoreboardFile => $scoreboard_file,
     SystemLog => $log_file,
     TraceLog => $log_file,
-    Trace => 'fsio:10',
+    Trace => 'fsio:10 vroot:20',
 
     AuthUserFile => $auth_user_file,
     AuthGroupFile => $auth_group_file,
@@ -1068,6 +1277,8 @@ sub vroot_symlink {
   defined(my $pid = fork()) or die("Can't fork: $!");
   if ($pid) {
     eval {
+      sleep(1);
+
       my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
       $client->login($user, $passwd);
 
@@ -1123,7 +1334,7 @@ sub vroot_symlink {
     $wfh->flush();
 
   } else {
-    eval { server_wait($config_file, $rfh) };
+    eval { server_wait($config_file, $rfh, 15) };
     if ($@) {
       warn($@);
       exit 1;
@@ -11862,4 +12073,578 @@ sub vroot_alias_var_u_symlink_dir {
   unlink($log_file);
 }
 
+sub vroot_alias_bad_src_dst_check_bug4 {
+  my $self = shift;
+  my $tmpdir = $self->{tmpdir};
+
+  my $config_file = "$tmpdir/vroot.conf";
+  my $pid_file = File::Spec->rel2abs("$tmpdir/vroot.pid");
+  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/vroot.scoreboard");
+
+  my $log_file = test_get_logfile();
+
+  my $auth_user_file = File::Spec->rel2abs("$tmpdir/vroot.passwd");
+  my $auth_group_file = File::Spec->rel2abs("$tmpdir/vroot.group");
+
+  my $user = 'proftpd';
+  my $passwd = 'test';
+  my $group = 'ftpd';
+  my $home_dir = File::Spec->rel2abs("$tmpdir/$user");
+  mkpath($home_dir);
+  my $uid = 500;
+  my $gid = 500;
+
+  # In order for the real /tmp/vroot.d directory to be visible, via
+  # VRootAlias, within the vroot, the leading /tmp directory needs to
+  # actually exist with the vroot.  In other words, the path needs to be
+  # real, even if the leaf is virtual.
+  my $user_tmpdir = File::Spec->rel2abs("$home_dir/tmp");
+  mkpath($user_tmpdir);
+
+  my $test_dir = File::Spec->rel2abs("/tmp/vroot.d");
+  mkpath($test_dir);
+
+  my $test_file = File::Spec->rel2abs("$test_dir/test.txt");
+  if (open(my $fh, "> $test_file")) {
+    close($fh);
+
+  } else {
+    die("Can't open $test_file: $!");
+  }
+
+  # Make sure that, if we're running as root, that the home directory has
+  # permissions/privs set for the account we create
+  if ($< == 0) {
+    unless (chmod(0755, $home_dir, $user_tmpdir, $test_dir)) {
+      die("Can't set perms on $home_dir to 0755: $!");
+    }
+
+    unless (chown($uid, $gid, $home_dir, $user_tmpdir, $test_dir)) {
+      die("Can't set owner of $home_dir to $uid/$gid: $!");
+    }
+  }
+
+  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
+    '/bin/bash');
+  auth_group_write($auth_group_file, $group, $gid, $user);
+
+  my $config = {
+    PidFile => $pid_file,
+    ScoreboardFile => $scoreboard_file,
+    SystemLog => $log_file,
+    TraceLog => $log_file,
+    Trace => 'fsio:20 vroot:20',
+
+    AuthUserFile => $auth_user_file,
+    AuthGroupFile => $auth_group_file,
+    ShowSymlinks => 'off',
+
+    IfModules => {
+      'mod_vroot.c' => {
+        VRootEngine => 'on',
+        VRootLog => $log_file,
+        DefaultRoot => '~',
+
+        VRootAlias => "$test_dir ~/tmp/vroot.d",
+      },
+
+      'mod_delay.c' => {
+        DelayEngine => 'off',
+      },
+    },
+  };
+
+  my ($port, $config_user, $config_group) = config_write($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 {
+      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
+      $client->login($user, $passwd);
+
+      my ($resp_code, $resp_msg) = $client->pwd();
+
+      my $expected;
+
+      $expected = 257;
+      $self->assert($expected == $resp_code,
+        test_msg("Expected $expected, got $resp_code"));
+
+      $expected = "\"/\" is the current directory";
+      $self->assert($expected eq $resp_msg,
+        test_msg("Expected '$expected', got '$resp_msg'"));
+
+      $client->cwd('/tmp/vroot.d');
+
+      my $conn = $client->list_raw();
+      unless ($conn) {
+        die("Failed to LIST: " . $client->response_code() . " " .
+          $client->response_msg());
+      }
+
+      my $buf;
+      $conn->read($buf, 8192, 5);
+      eval { $conn->close() };
+
+      # We have to be careful of the fact that readdir returns directory
+      # entries in an unordered fashion.
+      my $res = {};
+      my $lines = [split(/\n/, $buf)];
+      foreach my $line (@$lines) {
+        if ($line =~ /^(\S+)\s+\d+\s+\S+\s+\S+\s+.*?\s+(\S+)$/) {
+          $res->{$2} = $1;
+        }
+      }
+
+      unless (scalar(keys(%$res)) > 0) {
+        die("LIST data unexpectedly empty");
+      }
+
+      $expected = {
+        'test.txt' => 1,
+      };
+
+      my $ok = 1;
+      my $mismatch;
+      foreach my $name (keys(%$res)) {
+        unless (defined($expected->{$name})) {
+          $mismatch = $name;
+          $ok = 0;
+          last;
+        }
+      }
+
+      unless ($ok) {
+        die("Unexpected name '$mismatch' appeared in LIST data")
+      }
+
+      my $mode = '-rw-r--r--';
+      $self->assert($mode eq $res->{'test.txt'},
+        test_msg("Expected '$mode' for 'test.txt', got '$res->{'test.txt'}'"));
+
+      $client->quit();
+    };
+
+    if ($@) {
+      $ex = $@;
+    }
+
+    $wfh->print("done\n");
+    $wfh->flush();
+
+  } else {
+    eval { server_wait($config_file, $rfh) };
+    if ($@) { warn($@);
+      exit 1;
+    }
+
+    exit 0;
+  }
+
+  # Stop server
+  server_stop($pid_file);
+
+  $self->assert_child_ok($pid);
+
+  if ($ex) {
+    test_append_logfile($log_file, $ex);
+    unlink($log_file);
+
+    die($ex);
+  }
+
+  unlink($log_file);
+}
+
+sub vroot_alias_bad_alias_dirscan_bug5 {
+  my $self = shift;
+  my $tmpdir = $self->{tmpdir};
+
+  my $config_file = "$tmpdir/vroot.conf";
+  my $pid_file = File::Spec->rel2abs("$tmpdir/vroot.pid");
+  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/vroot.scoreboard");
+
+  my $log_file = test_get_logfile();
+
+  my $auth_user_file = File::Spec->rel2abs("$tmpdir/vroot.passwd");
+  my $auth_group_file = File::Spec->rel2abs("$tmpdir/vroot.group");
+
+  my $user = 'proftpd';
+  my $passwd = 'test';
+  my $group = 'ftpd';
+  my $home_dir = File::Spec->rel2abs("$tmpdir/$user");
+  mkpath($home_dir);
+  my $uid = 500;
+  my $gid = 500;
+
+  # In order for the real /tmp/vroot.d directory to be visible, via
+  # VRootAlias, within the vroot, the leading /tmp directory needs to
+  # actually exist with the vroot.  In other words, the path needs to be
+  # real, even if the leaf is virtual.
+  my $user_tmpdir = File::Spec->rel2abs("$home_dir/tmp");
+  mkpath($user_tmpdir);
+
+  my $test_dir = File::Spec->rel2abs("/tmp/vroot.d");
+  mkpath($test_dir);
+
+  my $test_file = File::Spec->rel2abs("$test_dir/test.txt");
+  if (open(my $fh, "> $test_file")) {
+    close($fh);
+
+  } else {
+    die("Can't open $test_file: $!");
+  }
+
+  # Make sure that, if we're running as root, that the home directory has
+  # permissions/privs set for the account we create
+  if ($< == 0) {
+    unless (chmod(0755, $home_dir, $user_tmpdir, $test_dir)) {
+      die("Can't set perms on $home_dir to 0755: $!");
+    }
+
+    unless (chown($uid, $gid, $home_dir, $user_tmpdir, $test_dir)) {
+      die("Can't set owner of $home_dir to $uid/$gid: $!");
+    }
+  }
+
+  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
+    '/bin/bash');
+  auth_group_write($auth_group_file, $group, $gid, $user);
+
+  my $config = {
+    PidFile => $pid_file,
+    ScoreboardFile => $scoreboard_file,
+    SystemLog => $log_file,
+    TraceLog => $log_file,
+    Trace => 'fsio:20 vroot:20',
+
+    AuthUserFile => $auth_user_file,
+    AuthGroupFile => $auth_group_file,
+    ShowSymlinks => 'off',
+
+    IfModules => {
+      'mod_vroot.c' => [
+        'VRootEngine on',
+        "VRootLog $log_file",
+        'DefaultRoot ~',
+        "VRootAlias $test_dir ~/vroot.d",
+        "VRootAlias $test_dir ~/tmp/vroot.d",
+      ],
+
+      'mod_delay.c' => {
+        DelayEngine => 'off',
+      },
+    },
+  };
+
+  my ($port, $config_user, $config_group) = config_write($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 {
+      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
+      $client->login($user, $passwd);
+
+      my ($resp_code, $resp_msg) = $client->pwd();
+
+      my $expected;
+
+      $expected = 257;
+      $self->assert($expected == $resp_code,
+        test_msg("Expected $expected, got $resp_code"));
+
+      $expected = "\"/\" is the current directory";
+      $self->assert($expected eq $resp_msg,
+        test_msg("Expected '$expected', got '$resp_msg'"));
+
+      $client->cwd('/tmp');
+
+      my $conn = $client->list_raw();
+      unless ($conn) {
+        die("Failed to LIST: " . $client->response_code() . " " .
+          $client->response_msg());
+      }
+
+      my $buf;
+      $conn->read($buf, 8192, 5);
+      eval { $conn->close() };
+
+      # We have to be careful of the fact that readdir returns directory
+      # entries in an unordered fashion.
+      my $res = {};
+      my $lines = [split(/\n/, $buf)];
+      foreach my $line (@$lines) {
+        if ($line =~ /^(\S+)\s+\d+\s+\S+\s+\S+\s+.*?\s+(\S+)$/) {
+          $res->{$2} = $1;
+        }
+      }
+
+      unless (scalar(keys(%$res)) > 0) {
+        die("LIST data unexpectedly empty");
+      }
+
+      $expected = {
+        'vroot.d' => 1,
+      };
+
+      my $ok = 1;
+      my $mismatch;
+      foreach my $name (keys(%$res)) {
+        unless (defined($expected->{$name})) {
+          $mismatch = $name;
+          $ok = 0;
+          last;
+        }
+      }
+
+      unless ($ok) {
+        die("Unexpected name '$mismatch' appeared in LIST data")
+      }
+
+      my $mode = 'drwxr-xr-x';
+      $self->assert($mode eq $res->{'vroot.d'},
+        test_msg("Expected '$mode' for 'vroot.d', got '$res->{'vroot.d'}'"));
+
+      $client->quit();
+    };
+
+    if ($@) {
+      $ex = $@;
+    }
+
+    $wfh->print("done\n");
+    $wfh->flush();
+
+  } else {
+    eval { server_wait($config_file, $rfh) };
+    if ($@) { warn($@);
+      exit 1;
+    }
+
+    exit 0;
+  }
+
+  # Stop server
+  server_stop($pid_file);
+
+  $self->assert_child_ok($pid);
+
+  if ($ex) {
+    test_append_logfile($log_file, $ex);
+    unlink($log_file);
+
+    die($ex);
+  }
+
+  unlink($log_file);
+}
+
+sub vroot_alias_enametoolong_bug59 {
+  my $self = shift;
+  my $tmpdir = $self->{tmpdir};
+
+  my $config_file = "$tmpdir/vroot.conf";
+  my $pid_file = File::Spec->rel2abs("$tmpdir/vroot.pid");
+  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/vroot.scoreboard");
+
+  my $log_file = test_get_logfile();
+
+  my $auth_user_file = File::Spec->rel2abs("$tmpdir/vroot.passwd");
+  my $auth_group_file = File::Spec->rel2abs("$tmpdir/vroot.group");
+
+  my $user = 'proftpd';
+  my $passwd = 'test';
+  my $group = 'ftpd';
+  my $home_dir = File::Spec->rel2abs("$tmpdir/$user");
+  mkpath($home_dir);
+  my $uid = 500;
+  my $gid = 500;
+
+  my $test_dir = File::Spec->rel2abs("/tmp/vroot.d/0001a/10001a/encoding/input");
+  mkpath($test_dir);
+
+  my $test_file = File::Spec->rel2abs("$test_dir/asgard");
+  if (open(my $fh, "> $test_file")) {
+    close($fh);
+
+  } else {
+    die("Can't open $test_file: $!");
+  }
+
+  # Make sure that, if we're running as root, that the home directory has
+  # permissions/privs set for the account we create
+  if ($< == 0) {
+    unless (chmod(0755, $home_dir, $test_dir)) {
+      die("Can't set perms on $home_dir to 0755: $!");
+    }
+
+    unless (chown($uid, $gid, $home_dir, $test_dir)) {
+      die("Can't set owner of $home_dir to $uid/$gid: $!");
+    }
+  }
+
+  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
+    '/bin/bash');
+  auth_group_write($auth_group_file, $group, $gid, $user);
+
+  my $config = {
+    PidFile => $pid_file,
+    ScoreboardFile => $scoreboard_file,
+    SystemLog => $log_file,
+    TraceLog => $log_file,
+    Trace => 'fsio:20 vroot:20',
+
+    AuthUserFile => $auth_user_file,
+    AuthGroupFile => $auth_group_file,
+    ShowSymlinks => 'off',
+
+    IfModules => {
+      'mod_vroot.c' => [
+        'VRootEngine on',
+        "VRootLog $log_file",
+        'DefaultRoot ~',
+        "VRootAlias /tmp ~/tmp-vroot-alias",
+        "VRootAlias $test_dir ~/0001a-input",
+      ],
+
+      'mod_delay.c' => {
+        DelayEngine => 'off',
+      },
+    },
+  };
+
+  my ($port, $config_user, $config_group) = config_write($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 {
+      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
+      $client->login($user, $passwd);
+
+      my ($resp_code, $resp_msg) = $client->pwd();
+
+      my $expected;
+
+      $expected = 257;
+      $self->assert($expected == $resp_code,
+        test_msg("Expected $expected, got $resp_code"));
+
+      $expected = "\"/\" is the current directory";
+      $self->assert($expected eq $resp_msg,
+        test_msg("Expected '$expected', got '$resp_msg'"));
+
+      my $conn = $client->mlsd_raw('0001a-input');
+      unless ($conn) {
+        die("Failed to MLSD: " . $client->response_code() . " " .
+          $client->response_msg());
+      }
+
+      my $buf;
+      $conn->read($buf, 8192, 30);
+      eval { $conn->close() };
+
+      # We have to be careful of the fact that readdir returns directory
+      # entries in an unordered fashion.
+      my $res = {};
+      my $lines = [split(/\n/, $buf)];
+      foreach my $line (@$lines) {
+        if ($line =~ /^modify=\S+;perm=\S+;type=\S+;unique=\S+;UNIX\.group=\d+;UNIX\.mode=\d+;UNIX.owner=\d+; (.*?)$/) {
+          $res->{$1} = 1;
+        }
+      }
+
+      unless (scalar(keys(%$res)) > 0) {
+        die("MLSD data unexpectedly empty");
+      }
+
+      $expected = {
+        '.' => 1,
+        '..' => 1,
+        'asgard' => 1,
+      };
+
+      my $ok = 1;
+      my $mismatch;
+      foreach my $name (keys(%$res)) {
+        unless (defined($expected->{$name})) {
+          $mismatch = $name;
+          $ok = 0;
+          last;
+        }
+      }
+
+      unless ($ok) {
+        die("Unexpected name '$mismatch' appeared in MLSD data")
+      }
+
+      $client->quit();
+    };
+
+    if ($@) {
+      $ex = $@;
+    }
+
+    $wfh->print("done\n");
+    $wfh->flush();
+
+  } else {
+    eval { server_wait($config_file, $rfh) };
+    if ($@) { warn($@);
+      exit 1;
+    }
+
+    exit 0;
+  }
+
+  # Stop server
+  server_stop($pid_file);
+
+  $self->assert_child_ok($pid);
+
+  if ($ex) {
+    test_append_logfile($log_file, $ex);
+    unlink($log_file);
+
+    die($ex);
+  }
+
+  unlink($log_file);
+}
+
 1;

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-proftpd/proftpd-mod-vroot.git



More information about the Pkg-proftpd-maintainers mailing list