Fixed check of metadata.
Should have approximately the functionality of my rsync-based script, except that it doesn't clean up yet.
This commit is contained in:
parent
6306294038
commit
5049a3a494
101
lib/Simba/CA.pm
101
lib/Simba/CA.pm
|
@ -12,6 +12,7 @@ use Digest::SHA1;
|
||||||
use List::Util qw(min);
|
use List::Util qw(min);
|
||||||
use IO::Handle;
|
use IO::Handle;
|
||||||
use File::stat;
|
use File::stat;
|
||||||
|
use Scalar::Util qw(tainted);
|
||||||
|
|
||||||
Readonly my $BUFSIZE => 128 * 1024;
|
Readonly my $BUFSIZE => 128 * 1024;
|
||||||
|
|
||||||
|
@ -46,6 +47,7 @@ sub backup2disk {
|
||||||
my @dirs = glob($self->{basedir} . '/????-??-??T??.??.??/' . $target->{host} . '/' . $target->{dir});
|
my @dirs = glob($self->{basedir} . '/????-??-??T??.??.??/' . $target->{host} . '/' . $target->{dir});
|
||||||
|
|
||||||
$self->{last_backup} = $dirs[-1];
|
$self->{last_backup} = $dirs[-1];
|
||||||
|
$self->{last_backup} = $1 if $self->{last_backup} =~ /(.*)/; # detaint
|
||||||
|
|
||||||
my $timestamp = $self->{timestamp} || strftime('%Y-%m-%dT%H.%M.%S', localtime);
|
my $timestamp = $self->{timestamp} || strftime('%Y-%m-%dT%H.%M.%S', localtime);
|
||||||
$self->{this_backup} = $self->{basedir} . "/$timestamp/" . $target->{host} . '/' . $target->{dir};
|
$self->{this_backup} = $self->{basedir} . "/$timestamp/" . $target->{host} . '/' . $target->{dir};
|
||||||
|
@ -93,6 +95,7 @@ sub backup2disk {
|
||||||
$size -= length($buffer);
|
$size -= length($buffer);
|
||||||
$sha1->add($buffer);
|
$sha1->add($buffer);
|
||||||
}
|
}
|
||||||
|
close($file_bfd);
|
||||||
my $trailer = <$file_dfd>; # should be empty line
|
my $trailer = <$file_dfd>; # should be empty line
|
||||||
$trailer = <$file_dfd>;
|
$trailer = <$file_dfd>;
|
||||||
if ($trailer =~ /^fail /) {
|
if ($trailer =~ /^fail /) {
|
||||||
|
@ -104,6 +107,7 @@ sub backup2disk {
|
||||||
} else {
|
} else {
|
||||||
print STDERR "unexpected trailer $trailer\n";
|
print STDERR "unexpected trailer $trailer\n";
|
||||||
}
|
}
|
||||||
|
$self->setmeta($f);
|
||||||
} else {
|
} else {
|
||||||
print STDERR "unexpected header $header\n";
|
print STDERR "unexpected header $header\n";
|
||||||
}
|
}
|
||||||
|
@ -111,7 +115,8 @@ sub backup2disk {
|
||||||
} elsif ($f->{t} eq 'd') {
|
} elsif ($f->{t} eq 'd') {
|
||||||
my $d = "$self->{this_backup}/$f->{name}";
|
my $d = "$self->{this_backup}/$f->{name}";
|
||||||
$d =~ s,//+,/,g;
|
$d =~ s,//+,/,g;
|
||||||
mkdir_p($d, 0700) or die "cannot mkdir $d: $!"; # XXX
|
mkdir_p($d) or die "cannot mkdir $d: $!"; # XXX
|
||||||
|
$self->setmeta($f);
|
||||||
} else {
|
} else {
|
||||||
# create local copy (or insert into DB only?)
|
# create local copy (or insert into DB only?)
|
||||||
print STDERR "ignored $_\n";
|
print STDERR "ignored $_\n";
|
||||||
|
@ -135,6 +140,7 @@ sub parse {
|
||||||
$f->{o} = unquote($f->{o});
|
$f->{o} = unquote($f->{o});
|
||||||
$f->{g} = unquote($f->{g});
|
$f->{g} = unquote($f->{g});
|
||||||
$f->{acl} = unquote($f->{acl});
|
$f->{acl} = unquote($f->{acl});
|
||||||
|
$f->{m} = $1 if $f->{m} =~ /^(\d+)$/;
|
||||||
return $f;
|
return $f;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -146,12 +152,9 @@ sub present {
|
||||||
return unless $st;
|
return unless $st;
|
||||||
if ($st->mtime == $f->{m} &&
|
if ($st->mtime == $f->{m} &&
|
||||||
$st->size == $f->{s} &&
|
$st->size == $f->{s} &&
|
||||||
uid2name($st->uid) eq $f->{o} &&
|
$st->uid == name2uid($f->{o}) &&
|
||||||
uid2name($st->gid) eq $f->{g} &&
|
$st->gid == name2gid($f->{g}) &&
|
||||||
mode2acl($st->mode) eq $f->{acl} &&
|
($st->mode & 07777) == $self->acl2mode($f)
|
||||||
(($st->mode & 04000) == ($f->{setuid} || 0) * 04000) &&
|
|
||||||
(($st->mode & 02000) == ($f->{setgid} || 0) * 02000) &&
|
|
||||||
(($st->mode & 01000) == ($f->{sticky} || 0) * 01000)
|
|
||||||
) {
|
) {
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -199,5 +202,89 @@ sub add_target {
|
||||||
return $self->{targets};
|
return $self->{targets};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my %permstrbits = (
|
||||||
|
'---' => 0,
|
||||||
|
'--x' => 1,
|
||||||
|
'-w-' => 2,
|
||||||
|
'-wx' => 3,
|
||||||
|
'r--' => 4,
|
||||||
|
'r-x' => 5,
|
||||||
|
'rw-' => 6,
|
||||||
|
'rwx' => 7,
|
||||||
|
);
|
||||||
|
|
||||||
|
sub setmeta {
|
||||||
|
my ($self, $f) = @_;
|
||||||
|
my $fn = "$self->{this_backup}/$f->{name}";
|
||||||
|
print STDERR "$fn is tainted!" if tainted($fn);
|
||||||
|
my $mode = $self->acl2mode($f);
|
||||||
|
print STDERR "$mode is tainted!" if tainted($mode);
|
||||||
|
chmod($mode, $fn);
|
||||||
|
chown(name2uid($f->{o}), name2gid($f->{g}), $fn);
|
||||||
|
utime(time, $f->{m}, $fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
# computes the mode from the acl (and the set[ug]id and sticky bits)
|
||||||
|
# and returns it. Optional ACL entries are currently ignored but should
|
||||||
|
# eventually be returned as a second value.
|
||||||
|
|
||||||
|
sub acl2mode {
|
||||||
|
my ($self, $f) = @_;
|
||||||
|
|
||||||
|
my $mode = 0;
|
||||||
|
if ($f->{acl}) {
|
||||||
|
for my $ace (split(',', $f->{acl})) {
|
||||||
|
if ($ace =~ /^u::(...)$/) {
|
||||||
|
$mode |= ($permstrbits{$1} << 6);
|
||||||
|
} elsif ($ace =~ /^g::(...)$/) {
|
||||||
|
$mode |= ($permstrbits{$1} << 3);
|
||||||
|
} elsif ($ace =~ /^o:(...)$/) {
|
||||||
|
$mode |= ($permstrbits{$1} << 0);
|
||||||
|
} else {
|
||||||
|
$self->log(5, "warning: unknown ACE $ace ignored");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($f->{setuid}) { $mode |= 04000 }
|
||||||
|
if ($f->{setgid}) { $mode |= 02000 }
|
||||||
|
if ($f->{sticky}) { $mode |= 01000 }
|
||||||
|
|
||||||
|
return $mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
my %ucache;
|
||||||
|
sub name2uid {
|
||||||
|
my ($uname) = @_;
|
||||||
|
$uname = $1 if $uname =~ /(.*)/; # detaint
|
||||||
|
return $ucache{$uname} if (defined $ucache{$uname});
|
||||||
|
if ($uname =~ /^\d+$/) {
|
||||||
|
return $ucache{$uname} = $uname;
|
||||||
|
} else {
|
||||||
|
my $uid = getpwnam($uname);
|
||||||
|
if (defined($uid)) {
|
||||||
|
return $ucache{$uname} = $uid;
|
||||||
|
} else {
|
||||||
|
return $ucache{$uname} = -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my %gcache;
|
||||||
|
sub name2gid {
|
||||||
|
my ($gname) = @_;
|
||||||
|
$gname = $1 if $gname =~ /(.*)/; # detaint
|
||||||
|
return $gcache{$gname} if (defined $gcache{$gname});
|
||||||
|
if ($gname =~ /^\d+$/) {
|
||||||
|
return $gcache{$gname} = $gname;
|
||||||
|
} else {
|
||||||
|
my $gid = getgrnam($gname);
|
||||||
|
if (defined($gid)) {
|
||||||
|
return $gcache{$gname} = $gid;
|
||||||
|
} else {
|
||||||
|
return $gcache{$gname} = -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# vim: tw=0 expandtab
|
# vim: tw=0 expandtab
|
||||||
1;
|
1;
|
||||||
|
|
52
t/01_ca.t
52
t/01_ca.t
|
@ -9,3 +9,55 @@ BEGIN { use_ok( 'Simba::CA' ); }
|
||||||
my $ca = Simba::CA->new();
|
my $ca = Simba::CA->new();
|
||||||
ok($ca, 'new CA');
|
ok($ca, 'new CA');
|
||||||
|
|
||||||
|
my $uid;
|
||||||
|
$uid = Simba::CA::name2uid('root');
|
||||||
|
ok(defined($uid), 'root has uid');
|
||||||
|
cmp_ok($uid, '==', 0, 'root has correct uid');
|
||||||
|
|
||||||
|
$uid = Simba::CA::name2uid('bin');
|
||||||
|
ok(defined($uid), 'bin has uid');
|
||||||
|
my $bin_uid;
|
||||||
|
{
|
||||||
|
open(my $fd, '<', '/etc/passwd');
|
||||||
|
while (<$fd>) {
|
||||||
|
if (/^bin:[^:]*:(\d+):/) {
|
||||||
|
$bin_uid = $1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmp_ok($uid, '==', $bin_uid, 'bin has correct uid');
|
||||||
|
|
||||||
|
$uid = Simba::CA::name2uid('daemon');
|
||||||
|
ok(defined($uid), 'daemon has uid');
|
||||||
|
my $daemon_uid;
|
||||||
|
{
|
||||||
|
open(my $fd, '<', '/etc/passwd');
|
||||||
|
while (<$fd>) {
|
||||||
|
if (/^daemon:[^:]*:(\d+):/) {
|
||||||
|
$daemon_uid = $1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmp_ok($uid, '==', $daemon_uid, 'daemon has correct uid');
|
||||||
|
|
||||||
|
$uid = Simba::CA::name2uid('4711');
|
||||||
|
ok(defined($uid), 'numerical "user name" has uid');
|
||||||
|
cmp_ok($uid, '==', 4711, 'numerical "user name" has correct uid');
|
||||||
|
|
||||||
|
$uid = Simba::CA::name2uid('i.am.quite.sure.that.this.is.not.a.real.username');
|
||||||
|
ok(defined($uid), 'unknown user has uid');
|
||||||
|
cmp_ok($uid, '==', -2, 'unknown user has correct uid');
|
||||||
|
|
||||||
|
my $gid = Simba::CA::name2gid('adm');
|
||||||
|
ok(defined($gid), 'adm has gid');
|
||||||
|
my $adm_gid;
|
||||||
|
{
|
||||||
|
open(my $fd, '<', '/etc/group');
|
||||||
|
while (<$fd>) {
|
||||||
|
if (/^adm:[^:]*:(\d+):/) {
|
||||||
|
$adm_gid = $1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmp_ok($gid, '==', $adm_gid, 'adm has correct gid');
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue