Thu, 04 Oct 2012 20:30:05 +0200
Correct out of date build configuration, porting to Solaris 11 network
link infrastructure and new libpcap logic. This additionally allows for
device drivers in subdirectories of /dev. Correct packaged nmap
personalities and signatures to work out of the box. Finally, hack
arpd logic to properly close sockets and quit on TERM by repeating
signaling in the run command script. Sadly, all this fails to correct
the run time behaviour of honeyd which fails to bind to the IP layer.
1 ##
2 ## makeproxy.pl -- OpenPKG Tool Chain
3 ## Copyright (c) 2000-2012 OpenPKG GmbH <http://openpkg.com/>
4 ##
5 ## This software is property of the OpenPKG GmbH, DE MUC HRB 160208.
6 ## All rights reserved. Licenses which grant limited permission to use,
7 ## copy, modify and distribute this software are available from the
8 ## OpenPKG GmbH.
9 ##
10 ## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
11 ## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
12 ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
13 ## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
14 ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
15 ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
16 ## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
17 ## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
18 ## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
19 ## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
20 ## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
21 ## SUCH DAMAGE.
22 ##
24 require 5.003;
26 # OpenPKG instance prefix and RPM
27 my $my_prefix = $ENV{'OPENPKG_PREFIX'};
28 my $my_rpm = "$my_prefix/bin/openpkg rpm";
29 delete $ENV{'OPENPKG_PREFIX'};
31 # program identification
32 my $progname = "makeproxy";
33 my $progvers = "2.1.0";
35 # parameters (defaults)
36 my $help = 0;
37 my $version = 0;
38 my $verbose = 0;
39 my $debug = 0;
40 my $slave_prefix = $my_prefix;
41 my $master_prefix = '';
42 my $tmpdir = ($ENV{TMPDIR} || "/tmp");
43 my $output = '.';
44 my $input = '-';
46 # cleanup support
47 my @cleanup = ();
48 sub cleanup_remember {
49 my ($cmd) = @_;
50 push(@cleanup, $cmd);
51 }
52 sub cleanup_perform {
53 foreach my $cmd (reverse @cleanup) {
54 runcmd($cmd);
55 }
56 }
58 # exception handling support
59 $SIG{__DIE__} = sub {
60 my ($err) = @_;
61 $err =~ s|\s+at\s+.*||s if (not $verbose);
62 $err =~ s/\n+$//s;
63 print STDERR "openpkg:$progname:ERROR: $err\n";
64 cleanup_perform() if (not $verbose);
65 exit(1);
66 };
68 # verbose message printing
69 sub verbose {
70 my ($msg) = @_;
71 print STDERR "$msg\n" if ($verbose);
72 }
74 # execution of external commands
75 sub runcmd {
76 my ($cmd) = @_;
77 if ($cmd =~ m/^(.+)\|$/s) {
78 print STDERR "\$ $1\n" if ($debug);
79 return `$1`;
80 }
81 else {
82 print STDERR "\$ $cmd\n" if ($debug);
83 $cmd = "($cmd) >/dev/null 2>&1" if (not $debug);
84 return (system($cmd) == 0);
85 }
86 }
88 # expand into a full filesystem path
89 sub fullpath {
90 my ($prog) = @_;
91 my $fullprog = '';
92 foreach my $path (split(/:/, $ENV{PATH})) {
93 if (-x "$path/$prog") {
94 $fullprog = "$path/$prog";
95 last;
96 }
97 }
98 return $fullprog;
99 }
101 # convert a subdirectory (a/b/c/)
102 # into a corresponding reverse path (../../../)
103 sub sub2rev {
104 my ($sub) = @_;
105 my $rev = '';
106 $sub =~ s|^/+||s;
107 $sub =~ s|/+$||s;
108 while ($sub =~ s|/[^/]+||) {
109 $rev .= "../";
110 }
111 if ($sub ne '') {
112 $rev .= "../";
113 }
114 $rev =~ s|/$||s;
115 return $rev;
116 }
118 # create a directory (plus its missing parent dirs)
119 sub mkdirp {
120 my ($dir) = @_;
121 my $pdir = $dir;
122 $pdir =~ s|/[^/]*$||s;
123 if (not -d $pdir) {
124 mkdirp($pdir);
125 }
126 if (not -d $dir) {
127 runcmd("mkdir $dir");
128 }
129 }
131 # home-brewn getopt(3) style option parser
132 sub getopts ($) {
133 my ($opts) = @_;
134 my (%optf) = map { m/(\w)/; $1 => $_ } $opts =~ m/(\w:|\w)/g;
135 my (%opts, @argv, $optarg);
137 foreach (@ARGV) {
138 if (@argv) {
139 push @argv, $_;
140 } elsif (defined $optarg) {
141 if (exists $opts{$optarg}) {
142 $opts{$optarg} .= " $_";
143 } else {
144 $opts{$optarg} = $_;
145 }
146 $optarg = undef;
147 } elsif (!/^[-]/) {
148 push @argv, $_;
149 } else {
150 while (/^\-(\w)(.*)/) {
151 if (exists $optf{$1}) {
152 if (length($optf{$1}) > 1) {
153 if ($2 ne '') {
154 if (exists $opts{$1}) {
155 $opts{$1} .= " $2";
156 } else {
157 $opts{$1} = $2;
158 }
159 } else {
160 $optarg = $1;
161 }
162 last;
163 } else {
164 $opts{$1} = 1;
165 }
166 } else {
167 warn "openpkg:makeproxy:WARNING: unknown option $_\n";
168 }
169 $_ = "-$2";
170 }
171 }
172 }
173 if (defined $optarg) {
174 warn "openpkg:makeproxy:WARNING: option $optarg requires an argument\n";
175 }
176 foreach (keys %opts) {
177 eval '$opt_'.$_.' = "'.quotemeta($opts{$_}).'";';
178 }
179 @ARGV = @argv;
180 }
182 # command line parsing
183 getopts("Vhdvm:s:t:o:");
184 $version = $opt_V if (defined $opt_V);
185 $help = $opt_h if (defined $opt_h);
186 $debug = $opt_d if (defined $opt_d);
187 $verbose = $opt_v if (defined $opt_v);
188 $master_prefix = $opt_m if (defined $opt_m);
189 $slave_prefix = $opt_s if (defined $opt_s);
190 $tmpdir = $opt_t if (defined $opt_t);
191 $output = $opt_o if (defined $opt_o);
192 if ($help) {
193 print "Usage: openpkg $progname [options] master-package\n" .
194 " -h,--help print this usage page\n" .
195 " -V,--version print version\n" .
196 " -v,--verbose print verbose run-time information\n" .
197 " -d,--debug print debug information\n" .
198 " -m,--master=DIR filesystem path to master OpenPKG instance\n" .
199 " -s,--slave=DIR filesystem path to slave OpenPKG instance\n" .
200 " -t,--tmpdir=DIR filesystem path to temporary directory\n" .
201 " -o,--output=FILE filesystem path to output proxy OpenPKG RPM package\n";
202 exit(0);
203 }
204 if ($version) {
205 print "OpenPKG $progname $progvers\n";
206 exit(0);
207 }
208 if ($#ARGV == 0) {
209 $input = shift(@ARGV);
210 }
211 if ($#ARGV != -1) {
212 die "invalid number of command line arguments";
213 }
215 # prepare temporary location
216 verbose("++ prepare temporary directory");
217 $tmpdir = "$tmpdir/$progname.$$";
218 if (not -d $tmpdir) {
219 runcmd("umask 077 && mkdir $tmpdir")
220 or die "cannot create temporary directory \"$tmpdir\"";
221 cleanup_remember("rm -rf $tmpdir");
222 }
223 verbose("-- temporary directory: $tmpdir");
225 # determine input and output RPM
226 verbose("++ determining OpenPKG RPM package files");
227 verbose("-- input/master/regular RPM package: $input");
228 verbose("-- output/slave/proxy RPM package: $output");
230 # ensure input RPM package is available on the filesystem
231 if ($input eq '-') {
232 $input = "$tmpdir/input.rpm";
233 runcmd("cat >$input");
234 }
236 # determine master and slave OpenPKG instance and RPM commands
237 if ($master_prefix eq '') {
238 if (not -f $input) {
239 die "input/master/regular RPM package does not exist: \"$input\"";
240 }
241 $master_prefix = runcmd("($my_rpm -qp --qf '%{PREFIXES}' $input 2>/dev/null || true) |");
242 $master_prefix =~ s/\r?\n$//s;
243 if ($master_prefix eq '') {
244 die "unable to determine master OpenPKG instance";
245 }
246 }
247 if ($master_prefix eq $slave_prefix) {
248 die "master and slave OpenPKG instances have to be different";
249 }
250 my $slave_rpm = (-f "$slave_prefix/bin/openpkg" ? "$slave_prefix/bin/openpkg rpm" : $my_rpm);
251 my $master_rpm = (-f "$master_prefix/bin/openpkg" ? "$master_prefix/bin/openpkg rpm" : $my_rpm);
252 verbose("-- tool OpenPKG instance: $my_prefix");
253 verbose("-- tool OpenPKG RPM command: $my_rpm");
254 verbose("-- master OpenPKG instance: $master_prefix");
255 verbose("-- master OpenPKG RPM command: $master_rpm");
256 verbose("-- slave OpenPKG instance: $slave_prefix");
257 verbose("-- slave OpenPKG RPM command: $slave_rpm");
259 # helper function for parsing RPM query outputs
260 sub parseresponse {
261 my ($r, $o) = @_;
262 sub parseline {
263 my ($r, $t, $k, $v) = @_;
264 $v =~ s|^\s+||s;
265 $v =~ s|\s+$||s;
266 if ($t eq 'S') { # single-value results
267 $r->{$k} = $v;
268 }
269 elsif ($t eq 'M') { # multi-value results
270 $r->{$k} = [] if (not defined($r->{$k}));
271 push(@{$r->{$k}}, $v);
272 }
273 }
274 $o =~ s|([SM])-([^:]+):<(.*?)>\n|parseline($r, $1, $2, $3, '')|egs;
275 return $r;
276 }
278 # query master OpenPKG RPM package
279 verbose("++ query information from master OpenPKG RPM package");
280 my $q = '';
281 foreach my $t (qw(
282 NAME SUMMARY URL VENDOR PACKAGER DISTRIBUTION CLASS GROUP LICENSE VERSION RELEASE
283 DESCRIPTION
284 )) {
285 $q .= "S-$t:<%{$t}>\\n";
286 }
287 $q .= '[M-PREREQ:<%{REQUIRENAME} %|REQUIREFLAGS?{%{REQUIREFLAGS:depflags} %{REQUIREVERSION}}:{}|>\n]';
288 $q .= '[M-PROVIDES:<%{PROVIDENAME} %|PROVIDEFLAGS?{%{PROVIDEFLAGS:depflags} %{PROVIDEVERSION}}:{}|>\n]';
289 $q .= '[M-PREFIXES:<%{PREFIXES}>\n]';
290 my $cmd = sprintf("%s -q %s --qf '$q' %s", $master_rpm, (-f $input ? "-p" : ""), $input);
291 my $o = runcmd("$cmd|");
292 if ($o =~ m/package .* is not installed/s) {
293 die "master package \"$input\" not installed in master OpenPKG instance \"$master_prefix\"";
294 }
295 $o =~ s|M-PREREQ:<rpmlib\(.*?\).*?>\n||gs;
296 my $r = {};
297 $r = parseresponse($r, $o);
298 my $BD = '';
299 my $ID = '';
300 my $PR = '';
301 foreach my $d (@{$r->{PREREQ}}) {
302 if ($d =~ m|^OpenPKG|i) {
303 $BD .= ", " if ($BD ne '');
304 $BD .= $d;
305 }
306 $ID .= ", " if ($ID ne '');
307 $ID .= $d;
308 }
309 foreach my $d (@{$r->{PROVIDES}}) {
310 $PR .= ", " if ($PR ne '');
311 $PR .= $d;
312 }
314 # prepare build environment
315 verbose("++ establishing temporary OpenPKG RPM environment");
316 verbose("-- directory: $tmpdir");
317 runcmd("rm -rf $tmpdir/src; mkdir $tmpdir/src");
318 runcmd("rm -rf $tmpdir/bld; mkdir $tmpdir/bld");
319 cleanup_remember("rm -rf $tmpdir/src");
320 cleanup_remember("rm -rf $tmpdir/tmp");
321 cleanup_remember("rm -rf $tmpdir/bld");
322 cleanup_remember("rm -rf $tmpdir/pkg");
323 runcmd("mkdir $tmpdir/src/.openpkg");
324 open(MACRO, ">$tmpdir/src/.openpkg/rpmmacros")
325 or die "unable to write file \"$tmpdir/src/.openpkg/rpmmacros\": $!";
326 print MACRO "\%openpkg_layout macrosfile=\%{macrosfile} layout=local shared=no\n";
327 close(MACRO);
328 $ENV{HOME} = $tmpdir;
330 # generate OpenPKG RPM .spec file for proxy OpenPKG RPM package
331 verbose("++ generating OpenPKG RPM package specification for proxy package");
332 verbose("-- file: $tmpdir/src/".$r->{NAME}.".spec");
333 my $S = '';
334 $S .= "Name: ".$r->{NAME}."\n";
335 $S .= "Summary: ".$r->{SUMMARY}."\n";
336 $S .= "URL: ".$r->{URL}."\n";
337 $S .= "Vendor: ".$r->{VENDOR}."\n";
338 $S .= "Packager: ".$r->{PACKAGER}."\n";
339 $S .= "Distribution: ".$r->{DISTRIBUTION}."\n";
340 $S .= "Class: ".$r->{CLASS}."\n";
341 $S .= "Group: ".$r->{GROUP}."\n";
342 $S .= "License: ".$r->{LICENSE}."\n";
343 $S .= "Version: ".$r->{VERSION}."\n";
344 $S .= "Release: ".$r->{RELEASE}."+PROXY\n";
345 $S .= "\n";
346 $S .= "BuildPreReq: $BD\n" if ($BD ne '');
347 $S .= "PreReq: $ID\n" if ($ID ne '');
348 $S .= "Provides: $PR\n" if ($PR ne '');
349 $S .= "\n";
350 $S .= "\%description\n";
351 $S .= " ".$r->{DESCRIPTION}."\n";
352 $S .= "\n";
353 $S .= "\%install\n";
354 $S .= " \%{l_rpmtool} files -v -ofiles -r\$RPM_BUILD_ROOT \%{l_files_std}\n";
355 $S .= "\n";
356 $S .= "\%files -f files\n";
357 $S .= "\n";
358 open(SPEC, ">$tmpdir/src/".$r->{NAME}.".spec")
359 or die "unable to write file \"$tmpdir/src/".$r->{NAME}."\": $!";
360 print SPEC $S;
361 close(SPEC);
363 # creating shadow tree of original contents
364 verbose("++ creating shadow tree from original package contents");
365 $q = '[%{FILEMODES:perms} %{FILENAMES}\n]';
366 $cmd = sprintf("%s -q %s --qf '$q' '%s'", $master_rpm, (-f $input ? "-p" : ""), $input);
367 my @FL = runcmd("$cmd|");
368 my $FD = [];
369 my $FR = [];
370 foreach my $fl (@FL) {
371 $fl =~ s|\n$||s;
372 if ($fl =~ m|^(d\S+)\s+$master_prefix(.*)$|) {
373 mkdirp("$tmpdir/bld$slave_prefix$2");
374 verbose("-- | PHYS $1 $slave_prefix$2");
375 }
376 elsif ($fl =~ m|^(\S+)\s+$master_prefix(.*?)([^/\s]+)$|) {
377 my ($subdir, $file) = ($2, $3);
378 my $target = sub2rev($subdir)."/.prefix-".$r->{NAME}.$subdir.$file;
379 mkdirp("$tmpdir/bld$slave_prefix$subdir");
380 runcmd("ln -s $target $tmpdir/bld$slave_prefix$subdir$file");
381 verbose("-- | VIRT $1 $slave_prefix$subdir$file");
382 }
383 }
385 # create master-reference symbolic link
386 runcmd("ln -s $master_prefix $tmpdir/bld$slave_prefix/.prefix-".$r->{NAME});
388 # rolling output proxy RPM package
389 verbose("++ rolling output proxy RPM package");
390 runcmd(
391 "cd $tmpdir/src && " .
392 "$slave_rpm -bb " .
393 "--define 'buildroot $tmpdir/bld' " .
394 "--define '__spec_install_pre \%{___build_pre}' " .
395 "--nodeps ".$r->{NAME}.".spec"
396 );
398 # providing output
399 verbose("++ providing output: $output");
400 if ($output eq '-') {
401 runcmd("cat $tmpdir/src/*.rpm");
402 }
403 else {
404 runcmd("cp $tmpdir/src/*.rpm $output");
405 }
407 # die gracefully...
408 verbose("++ cleaning up environment");
409 cleanup_perform();
410 exit(0);