BackupPC-users

[BackupPC-users] Code to allow auto-dumping and backup of SElinux attributes

2010-01-11 12:07:00
Subject: [BackupPC-users] Code to allow auto-dumping and backup of SElinux attributes
From: "Jeffrey J. Kosowsky" <backuppc AT kosowsky DOT org>
To: General list for user discussion <backuppc-users AT lists.sourceforge DOT net>
Date: Mon, 11 Jan 2010 12:03:06 -0500
Given that my shadowmountrsync procedure allows backing up of full
Windows acl's, I figured it was only fair to write something that
would allow for full backing up of SElinux attributes.

Hopefully this routine will become obsolete in BackupPC 4.0 since Craig is
talking about adding extended attribute support.

But meanwhile feel free to use this routine. Note almost all the
complexity is due to the following three elements:
1. I want to only include SElinux attributes for the actual files
   being backed up 
   (i.e., include the included paths and exclude the excluded ones)
2. But unfortunately, BackupPC does not allow you to pass the
   corresponding BackupPC %Conf hashes to DumpPreShareCmd, so I have
   to encode and push them myself using perl code in the config.pl
   file.
   [NB: it would *really* be nice if future versions of backuppc allowed
   the Dump/Restore/Archive Pre/Post commands to access the full %Conf
   hash]
3. I want to be able to run the script as suidperl so I don't have to
   ssh as root or allow separately via /etc/sudoers

So, here is the code in 2 parts:
1. First some perl code to add to your config.pl file:
   Don't forget to make sure that BackupPC_Dumplinux.pl is in your
   path. Note I have set it up to ssh as user 'root' but if running as
   suidperl, this is not necessary.
   
-----------------------------------------------------------------------------
# Code to generate listing of SELinux attributes for each share
my ($includepaths, $excludepaths); #Generate include/exclude paths
foreach (@{$Conf{RsyncShareName}}) {
        my @includearr = defined($Conf{BackupFilesOnly}{$_}) 
                ? @{$Conf{BackupFilesOnly}{$_}} : ();
        $includepaths .= " -i $_  " . join(" ", @includearr)
                if @includearr > 0;
        my @excludearr = defined($Conf{BackupFilesExclude}{$_}) 
                ? @{$Conf{BackupFilesExclude}{$_}} : ();
        $excludepaths .= " -e $_ " . join(" ", @excludearr)
                if @excludearr > 0;
}
$includepaths =~ s#//+#/#g; #Remove redundant slashes
$excludepaths =~ s#//+#/#g;

$Conf{DumpPreShareCmd}    = '$sshPath -q -x -l root $hostIP  
BackupPC_DumpSElinux.pl $share/SElinuxDump.gz $share' . $includepaths  . 
$excludepaths;
---------------------------------------------------------------------------- 
---------------------------------------------------------------------------- 

2. The shell script called to dump the SElinux attributes:
   Note I run it as suidperl (and note that I bypass tainting) using:
                chown root.backuppc BackupPC_DumpSElinux.pl
        chmod 4754 BackupPC_DumplSEinux.pl
   This allows me to run BackupPC as user backuppc without full root
   privileges. 


---------------------------------------------------------------------------
#! /usr/bin/suidperl -w
#
## BackupPC_DumpSElinux.pl - suid perl script to dump SElinux context for input
#                   share to output file for use by $Conf{DumpPreShareCmd}
#
#             If not running as root, this script can be set suidperl
#             as follows:
#                  chown root.backuppc BackupPC_DumpSElinux.pl
#                  chmod 4754 BackupPC_DumpSElinux.pl
#  
# Usage: BackupPC_DumpSElinux.pl <outfile> <share> 
#                                 [ -i <share1> <path1a> <path1b>...]
#                                 [ -e <share1> <path1a> <path1b>...]
#                                 [ -i <share2> <path2a> <path2b>...]
#                                 [ -e <share2> <path2a> <path2b>...]
#
# where:
#    <outfile>   = Place to store the (compressed) output 
#                   (prior to adding the .gz suffix
#    <share>     = Root of the share
#    -i|-e       = Include|Exclude paths
#    <pathNx>    = path relative to <shareN>
#    <includes>  = One or more arguments representing paths to *include*
#    <excludes>  = One or more optional arguments representating  paths to 
*exclude*
#    Searches only include on includes/excludes whose <shareN> matches <share>
#    Note: this is necessary so we can pre-evaluate variables and pass 
#    everything to $Conf{DumpPreShareCmd}
#
# Jeffrey J. Kosowsky
# Copyright December 2009
# Version 0.5
#

$ENV{'PATH'} = '';      # This script is entirely internal, so needs no
$ENV{'SHELL'} = '';     # shell or path
$ENV{'IFS'} = '';

use File::Basename;
use Fcntl;
use strict;
use warnings;

map ({ /(.*)/, $_=$1 } @ARGV); #Untaint args

my ($outfile, $share, @args) = @ARGV;
my (@includelist, @excludelist, $path);

die "Wrong number of arguments...\n" if $#ARGV < 1;

my $flag = 0;
$share = "/" . $share; #Add initial slash
$share =~ s#/$##; #Remove trailing slash
$share =~ s#//+#/#; #Remove double slashes
die "Share '$share' doesn't exist...\n" unless -e $share;

while (@args) {
        $_= shift(@args);
        $_ = "/" . $_; #Add initial slash
        if  (m#^/-(i|e)$#) { #include or exclude flag
                $flag = $1;
                $_ = shift @args;
                $_ = "/" . $_; #Add initial slash
                s#//+#/#g; #Remove double slashes
                $flag  = 0 unless m#^$share/?$#;
                next;
        }
        $path = $share . "/" . $_;
        $path =~ s#//+#/#g; #Remove double slashes
        if( $flag eq 'i' ) { #Include list
                push @includelist, $path; #Add to include
        } elsif( $flag eq 'e' ) {
                push @excludelist, "-path", "$path";  #Add to exclude
                push @excludelist, "-o";
        }
}

push @includelist, $share unless @includelist;
# If no includes, then just search the whole share

if (@excludelist > 0) {
        pop  @excludelist; #Pop trailing -o
        unshift @excludelist, "\(";
        push @excludelist, "\)", "-prune", "-o";
}
my @findstring = ("/usr/bin/find", @includelist, "-xdev",  @excludelist, 
"-printf",  "%p %Z\\n");

$outfile =~ s#//+#/#g; #Remove redundant slashes
unless ((-f $outfile && -w $outfile ) ||
        ( ! -e $outfile && -w dirname($outfile))) {
        $!=10;
        die "Error: '$outfile' is not writable\n";
}
#Note following three lines are necessary since we need to make sure file 
#is writable by the UID (and not just the EUID)
die "Couldn't open $outfile for writing\n"  unless
        sysopen STDOUT, $outfile, O_CREAT | O_TRUNC, 0600;  #Note clobbers 
before opening
close($outfile);
chown($<,$>,$outfile); # chown $UID.$EUID where $EUID=0 (root) if suidperl
die "Couldn't gzip onto $outfile\n" unless
        open STDOUT, "| /bin/gzip >> $outfile";
die "cannot dup STDERR to STDOUT: $!\n" unless
        open STDERR, ">&STDOUT";
select STDERR; $| = 1;
select STDOUT; $| = 1;


system(@findstring);
close($outfile);
#chown(0,0,$outfile);
chown($>,$>,$outfile); # chown $EUID.$EUID where $EUID=0 (root) if suidperl
exit 0;

---------------------------------------------------------------------------- 

------------------------------------------------------------------------------
This SF.Net email is sponsored by the Verizon Developer Community
Take advantage of Verizon's best-in-class app development support
A streamlined, 14 day to market process makes app distribution fast and easy
Join now and get one step closer to millions of Verizon customers
http://p.sf.net/sfu/verizon-dev2dev 
_______________________________________________
BackupPC-users mailing list
BackupPC-users AT lists.sourceforge DOT net
List:    https://lists.sourceforge.net/lists/listinfo/backuppc-users
Wiki:    http://backuppc.wiki.sourceforge.net
Project: http://backuppc.sourceforge.net/

<Prev in Thread] Current Thread [Next in Thread>