aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2012-05-29 17:47:46 +1200
committerTom Ryder <tom@sanctum.geek.nz>2012-05-29 17:47:46 +1200
commite0176ca7c974e7bb9867f491ad28f08e4531fde2 (patch)
tree21d7b726eea0ebbc28fca809a7e9123fa7b96ce2
parentUpdate README with requirements and better paths (diff)
downloadclubber-e0176ca7c974e7bb9867f491ad28f08e4531fde2.tar.gz
clubber-e0176ca7c974e7bb9867f491ad28f08e4531fde2.zip
Add actual script, seems to work nicely
-rwxr-xr-xclubber186
1 files changed, 185 insertions, 1 deletions
diff --git a/clubber b/clubber
index f017cfc..e40ac54 100755
--- a/clubber
+++ b/clubber
@@ -2,7 +2,8 @@
#
# Clubber -- Less painful chroot environment building and verification. Please
-# see README.markdown for documentation.
+# see README.markdown for documentation. Be sure you trust your binaries! This
+# script won't protect you from ldd exploits.
#
# @author Tom Ryder <tom@sanctum.geek.nz>
# @copyright 2012 Sanctum
@@ -10,4 +11,187 @@
use strict;
use warnings;
+use Cwd qw(abs_path);
+use File::Basename;
+use Getopt::Long;
+
+#
+# Bail if we're not root.
+#
+if ($< != 0 || $> != 0) {
+ error("You must have root permissions to use this script.");
+}
+
+#
+# Check ldd is available.
+#
+chomp(my $ldd = `which ldd`);
+if (!$ldd) {
+ error("Couldn't find ldd in your \$PATH.");
+}
+
+#
+# Check md5sum is available.
+#
+chomp(my $md5sum = `which md5sum`);
+if (!$md5sum) {
+ error("Couldn't find md5sum in your \$PATH.");
+}
+
+#
+# Check options.
+#
+my ($chroot, $dry, $verify) = ("", 0, 0, 0);
+my $config = GetOptions("chroot=s" => \$chroot,
+ "dry" => \$dry);
+if ($chroot) {
+ $chroot = abs_path($chroot);
+ if (!-d $chroot) {
+ error("Nominated chroot %s doesn't seem to be a directory.", $chroot);
+ }
+} elsif ($dry) {
+ error("Doesn't make sense to specify --dry without --chroot.");
+}
+
+#
+# Check we were passed at least one parameter, otherwise print a helpful
+# message.
+#
+if (!@ARGV) {
+ printf STDOUT "USAGE: ${0} [--chroot] [--verify] [--dry] binary1 binary2 ... \n";
+ exit 0;
+}
+
+#
+# Check that all our parameters are real files, or point to one.
+#
+my $binaries = [];
+foreach my $argument (@ARGV) {
+ $argument = abs_path($argument);
+ if (-f $argument) {
+ push @$binaries, $argument;
+ } else {
+ error("File %s doesn't seem to exist.", $argument);
+ }
+}
+
+#
+# Run ldd on all the files and slurp all the absolute paths; put them into a
+# hash to keep things unique.
+#
+my $libraries = {};
+foreach my $binary (@$binaries) {
+ my $output = [qx/${ldd} ${binary}/];
+ foreach my $line (@$output) {
+ if ($line =~ m#(/\S*lib\S+)#) {
+ $libraries->{$1} = 1;
+ }
+ }
+}
+
+#
+# If we have a chroot, we need to figure out what libraries require importing
+# and which directories require creating.
+#
+if ($chroot) {
+ my ($directories, $imports) = ({}, {});
+
+ #
+ # First we'll recurse through the list of libraries and flag any
+ # directories that require creation. We won't complicate things by
+ # reproducing any symbolic link structures.
+ #
+ # If the directory does exist, we'll make sure the library is in place
+ # too, and if it is that its md5sum is the same as our root system
+ # library. If it doesn't exist or if it's different, we'll flag it for
+ # overwriting.
+ #
+ foreach my $library (keys(%$libraries)) {
+ my $directory = dirname($library);
+ if (!-d "${chroot}${directory}") {
+ $directories->{$directory} = 1;
+ }
+ if (-f "${chroot}{$library}") {
+ if (qx/${md5sum} ${library}/ ne qx/${md5sum} ${chroot}${library}/) {
+ $imports->{$library} = 1;
+ }
+ } else {
+ $imports->{$library} = 1;
+ }
+ }
+
+ #
+ # Check there's something for us to do.
+ #
+ if (keys %$directories || keys %$imports) {
+
+ #
+ # If we're just supposed to print what we do, all the better, do
+ # that and then quit.
+ #
+ if ($dry) {
+ if (keys %$directories) {
+ printf STDOUT "Create directories:\n";
+ foreach my $directory (keys(%$directories)) {
+ printf STDOUT " %s\n", "${chroot}${directory}";
+ }
+ }
+ if (keys %$imports) {
+ printf STDOUT "Copy libraries:\n";
+ foreach my $import (keys(%$imports)) {
+ printf STDOUT " %s -> %s\n", $import, "${chroot}${import}";
+ }
+ }
+
+ #
+ # Otherwise, we'd best get started.
+ #
+ } else {
+ foreach my $directory (keys(%$directories)) {
+ system("mkdir -pv ${chroot}${directory}");
+ }
+ foreach my $import (keys(%$imports)) {
+ system("cp -pv ${import} ${chroot}${import}");
+ }
+ }
+
+ #
+ # If there's nothing we need to do, say so.
+ #
+ } else {
+ printf STDOUT "Nothing to do.\n";
+ }
+
+#
+# If we don't have a chroot, we can just print the list of libraries, and we're
+# done.
+#
+} else {
+ foreach my $library (keys(%$libraries)) {
+ printf "%s\n", $library;
+ }
+}
+
+#
+# And one way or another, we're done.
+#
+exit 0;
+
+#
+# Print a usage message and exit with non-zero.
+#
+sub usage {
+ my $message = shift @_;
+ printf STDERR "USAGE: ${message}\n", @_;
+ exit 1;
+}
+
+#
+# Print a usage message and exit with non-zero.
+#
+sub error {
+ my $message = shift @_;
+ printf STDERR "ERROR: ${message}\n", @_;
+ exit 1;
+}