Merge pull request #234 from jaredj/writeable-dir
Add perms test to Qpsmtpd::DB::File::DBM::dir()
This commit is contained in:
commit
11a9154552
@ -180,12 +180,47 @@ sub flush {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub dir {
|
sub dir {
|
||||||
my ( $self, @arg ) = @_;
|
my ( $self, $dir ) = @_;
|
||||||
return $self->{dir} if $self->{dir} and ! @arg;
|
if ( $dir ) {
|
||||||
for my $d ( $self->candidate_dirs(@arg) ) {
|
$self->validate_dir($dir);
|
||||||
next if ! $self->validate_dir($d);
|
return $self->{dir} = $dir;
|
||||||
return $self->{dir} = $d; # first match wins
|
|
||||||
}
|
}
|
||||||
|
return $self->{dir} if $self->{dir};
|
||||||
|
my @err;
|
||||||
|
for my $d ( $self->candidate_dirs ) {
|
||||||
|
# Ignore invalid directories for static default directories
|
||||||
|
my $is_valid;
|
||||||
|
eval { $is_valid = $self->validate_dir($d); };
|
||||||
|
if ($@) {
|
||||||
|
push @err, $@;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$self->{dir} = $d; # first match wins
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( !$self->{dir} ) {
|
||||||
|
my $err = join "\n",
|
||||||
|
"Unable to find a useable database directory!",
|
||||||
|
"",
|
||||||
|
@err;
|
||||||
|
die $err;
|
||||||
|
}
|
||||||
|
if (@err) {
|
||||||
|
my $err = join "\n",
|
||||||
|
"Encountered errors while selecting database directory:",
|
||||||
|
"",
|
||||||
|
@err,
|
||||||
|
"Selected database directory: $self->{dir}. Data is now stored in:",
|
||||||
|
"",
|
||||||
|
$self->path,
|
||||||
|
"",
|
||||||
|
"It is recommended to manually specify a useable database directory",
|
||||||
|
"and move any important data into this directory.\n";
|
||||||
|
warn $err;
|
||||||
|
}
|
||||||
|
return $self->{dir};
|
||||||
}
|
}
|
||||||
|
|
||||||
sub candidate_dirs {
|
sub candidate_dirs {
|
||||||
@ -199,8 +234,9 @@ sub candidate_dirs {
|
|||||||
|
|
||||||
sub validate_dir {
|
sub validate_dir {
|
||||||
my ( $self, $d ) = @_;
|
my ( $self, $d ) = @_;
|
||||||
return 0 if ! $d;
|
die "Empty DB directory supplied\n" if ! $d;
|
||||||
return 0 if ! -d $d;
|
die "DB directory '$d' does not exist\n" if ! -d $d;
|
||||||
|
die "DB directory '$d' is not writeable\n" if ! -w $d;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,12 +266,17 @@ sub init_dbm {
|
|||||||
name => 'greylist',
|
name => 'greylist',
|
||||||
class => 'Qpsmtpd::DB::File::DBM'
|
class => 'Qpsmtpd::DB::File::DBM'
|
||||||
);
|
);
|
||||||
my $cdir = $self->{_args}{db_dir};
|
|
||||||
$cdir = $1 if $cdir and $cdir =~ m{^([-a-zA-Z0-9./_]+)$};
|
|
||||||
# greylisting-specific hints for where to store the greylist DB
|
|
||||||
my $db_dir = $self->db->dir( $cdir, '/var/lib/qpsmtpd/greylisting' );
|
|
||||||
$self->db->nfs_locking( $self->{_args}{nfslock} );
|
$self->db->nfs_locking( $self->{_args}{nfslock} );
|
||||||
|
|
||||||
|
# Add to the default list of possible DB directories
|
||||||
|
$self->db->candidate_dirs('/var/lib/qpsmtpd/greylisting');
|
||||||
|
if ( my $dir_arg = $self->{_args}{db_dir} ) {
|
||||||
|
# user-supplied db dir
|
||||||
|
$dir_arg = $1 if $dir_arg =~ m{^([-a-zA-Z0-9./_]+)$};
|
||||||
|
$self->db->dir($dir_arg);
|
||||||
|
}
|
||||||
|
my $db_dir = $self->db->dir;
|
||||||
|
|
||||||
# Work around old DBM filename
|
# Work around old DBM filename
|
||||||
my $oldname = 'denysoft_greylist';
|
my $oldname = 'denysoft_greylist';
|
||||||
if ( ! -f "$db_dir/greylist.dbm" && -f "$db_dir/$oldname.dbm" ) {
|
if ( ! -f "$db_dir/greylist.dbm" && -f "$db_dir/$oldname.dbm" ) {
|
||||||
|
@ -358,9 +358,10 @@ sub test_init_dbm {
|
|||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
delete $self->{db};
|
delete $self->{db};
|
||||||
delete $self->{_args}{redis};
|
delete $self->{_args}{redis};
|
||||||
|
$self->{_args}{db_dir} = 't/tmp';
|
||||||
$self->init_db;
|
$self->init_db;
|
||||||
is( $self->db->name, 'greylist', 'init_dbm() sets correct db name' );
|
is( $self->db->name, 'greylist', 'init_dbm() sets correct db name' );
|
||||||
is( $self->db->path, 't/config/greylist.dbm', 'init_dbm() sets correct path' );
|
is( $self->db->path, 't/tmp/greylist.dbm', 'init_dbm() sets correct path' );
|
||||||
is( ref $self->db, 'Qpsmtpd::DB::File::DBM', 'init_dbm() gives DBM object' );
|
is( ref $self->db, 'Qpsmtpd::DB::File::DBM', 'init_dbm() gives DBM object' );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,22 +119,79 @@ sub __candidate_dirs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub __validate_dir {
|
sub __validate_dir {
|
||||||
is( $db->validate_dir(), 0, 'validate_dir(): false on no input' );
|
eval { $db->validate_dir(); };
|
||||||
is( $db->validate_dir(undef), 0, 'validate_dir(): false on undef' );
|
is( $@, "Empty DB directory supplied\n",
|
||||||
is( $db->validate_dir('invalid'), 0,
|
'validate_dir(): die on no input' );
|
||||||
'validate_dir(): false for non-existent directory' );
|
eval { $db->validate_dir(undef); };
|
||||||
|
is( $@, "Empty DB directory supplied\n",
|
||||||
|
'validate_dir(): die on undef' );
|
||||||
|
eval { $db->validate_dir(''); };
|
||||||
|
is( $@, "Empty DB directory supplied\n",
|
||||||
|
'validate_dir(): die on empty string' );
|
||||||
|
eval { $db->validate_dir('invalid'); };
|
||||||
|
is( $@, "DB directory 'invalid' does not exist\n",
|
||||||
|
'validate_dir(): die on non-existent directory' );
|
||||||
is( $db->validate_dir('t/tmp'), 1,
|
is( $db->validate_dir('t/tmp'), 1,
|
||||||
'validate_dir(): true for real directory' );
|
'validate_dir(): true for real directory' );
|
||||||
|
mkdir 't/tmp/wtest', 0555;
|
||||||
|
eval { $db->validate_dir('t/tmp/wtest') };
|
||||||
|
is( $@, "DB directory 't/tmp/wtest' is not writeable\n",
|
||||||
|
'validate_dir(): die on non-writeable directory' );
|
||||||
|
chmod 0777, 't/tmp/wtest';
|
||||||
|
is( $db->validate_dir('t/tmp/wtest'), 1,
|
||||||
|
'validate_dir(): true for writeable directory' );
|
||||||
|
rmdir 't/tmp/wtest';
|
||||||
}
|
}
|
||||||
|
|
||||||
sub __dir {
|
sub __dir {
|
||||||
my $db2 = Qpsmtpd::DB::File::DBM->new( name => 'dirtest' );
|
my $db2 = Qpsmtpd::DB::File::DBM->new( name => 'dirtest' );
|
||||||
is( $db2->dir(), 't/config', 'default directory' );
|
{
|
||||||
is( $db2->dir('_invalid','t/Test'), 't/Test', 'skip invalid candidate dirs' );
|
local $SIG{__WARN__} = sub {
|
||||||
$db2->{dir} = '_cached';
|
warn @_ if $_[0] !~ /selecting database directory/;
|
||||||
is( $db2->dir(), '_cached', 'cached directory' );
|
};
|
||||||
is( $db2->dir('t/Test'), 't/Test', 'passing candidate dirs resets cache' );
|
is( $db2->dir(), 't/config', 'default directory' );
|
||||||
is( $db2->dir('_invalid'), 't/config', 'invalid candidate dirs reverts to default' );
|
delete $db2->{dir};
|
||||||
|
$db2->candidate_dirs('_invalid','t/Test');
|
||||||
|
is( $db2->dir, 't/Test', 'skip invalid candidate dirs' );
|
||||||
|
$db2->{dir} = '_cached';
|
||||||
|
is( $db2->dir(), '_cached', 'cached directory' );
|
||||||
|
is( $db2->dir('t/Test'), 't/Test', 'passing candidate dirs resets cache' );
|
||||||
|
delete $db2->{dir};
|
||||||
|
$db2->candidate_dirs('_invalid');
|
||||||
|
is( $db2->dir, 't/config', 'invalid candidate dirs reverts to default' );
|
||||||
|
eval { $db2->dir('_invalid'); };
|
||||||
|
is( $@, "DB directory '_invalid' does not exist\n", 'die on invalid dir' );
|
||||||
|
}
|
||||||
|
{
|
||||||
|
delete $db2->{dir};
|
||||||
|
my $warned;
|
||||||
|
local $SIG{__WARN__} = sub {
|
||||||
|
warn @_ if $_[0] !~ /selecting database directory/;
|
||||||
|
$warned .= join '', @_;
|
||||||
|
};
|
||||||
|
$db2->candidate_dirs('_invalid2','t/Test');
|
||||||
|
is( $db2->dir(), 't/Test', 'default directory' );
|
||||||
|
my $expected_warning =
|
||||||
|
"Encountered errors while selecting database directory:
|
||||||
|
|
||||||
|
DB directory '_invalid2' does not exist
|
||||||
|
|
||||||
|
Selected database directory: t/Test. Data is now stored in:
|
||||||
|
|
||||||
|
t/Test/dirtest.dbm
|
||||||
|
|
||||||
|
It is recommended to manually specify a useable database directory
|
||||||
|
and move any important data into this directory.\n";
|
||||||
|
is( $warned, $expected_warning, 'Emit warning on bad directories' );
|
||||||
|
delete $db2->{dir};
|
||||||
|
$db2->{candidate_dirs} = ['/___invalid___'];
|
||||||
|
my $expected_err =
|
||||||
|
"Unable to find a useable database directory!
|
||||||
|
|
||||||
|
DB directory '/___invalid___' does not exist\n";
|
||||||
|
eval { $db2->dir() };
|
||||||
|
is( $@, $expected_err, 'Die on no valid directories' );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub __untie_gotcha {
|
sub __untie_gotcha {
|
||||||
|
Loading…
Reference in New Issue
Block a user