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 ## lint-fsl.pl -- OpenPKG fsl.* File Checker
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 # Perl run-time requirement
25 require 5;
26 BEGIN {
27 eval "use Getopt::Long; use IO;";
28 if ($@) {
29 print STDERR
30 "lint-fsl: ERROR: This command requires a full-size Perl installation!\n" .
31 "lint-fsl: HINT: Install OpenPKG \"perl\" package to use this command.\n";
32 exit(1);
33 }
34 }
36 # OpenPKG instance prefix
37 my $my_prefix = $ENV{'OPENPKG_PREFIX'};
38 delete $ENV{'OPENPKG_PREFIX'};
40 # program information
41 my $progname = "lint-fsl";
42 my $progvers = "1.0.0";
44 # parameters (defaults)
45 my $version = 0;
46 my $verbose = 0;
47 my $help = 0;
48 my $check = 'all';
49 my $tmpdir = ($ENV{TMPDIR} || $ENV{TEMPDIR} || "/tmp") . "/$progname";
50 my $rpm = "$my_prefix/bin/openpkg rpm";
52 # exception handling support
53 $SIG{__DIE__} = sub {
54 my ($err) = @_;
55 $err =~ s|\s+at\s+.*||s if (not $verbose);
56 print STDERR "$progname:ERROR: $err ". ($! ? "($!)" : "") . "\n";
57 exit(1);
58 };
60 # command line parsing
61 Getopt::Long::Configure("bundling");
62 my $result = GetOptions(
63 'V|version' => \$version,
64 'v|verbose' => \$verbose,
65 'h|help' => \$help,
66 'c|check=s' => \$check,
67 't|tmpdir=s' => \$tmpdir,
68 'r|rpm=s' => \$rpm,
69 ) || die "option parsing failed";
70 if ($help) {
71 print "Usage: $progname [options] [RPMFILE ...]\n" .
72 "Available options:\n" .
73 " -v,--verbose enable verbose run-time mode\n" .
74 " -h,--help print out this usage page\n" .
75 " -c,--check=CHECKS select checks to perform (default='all')\n" .
76 " -r,--rpm=FILE filesystem path to RPM program\n" .
77 " -t,--tmpdir=PATH filesystem path to temporary directory\n" .
78 " -V,--version print program version\n";
79 exit(0);
80 }
81 if ($version) {
82 print "OpenPKG $progname $progvers\n";
83 exit(0);
84 }
86 # verbose message printing
87 sub msg_verbose {
88 my ($msg) = @_;
89 print STDERR "$msg\n" if ($verbose);
90 }
92 # warning message printing
93 sub msg_warning {
94 my ($msg) = @_;
95 print STDERR "$progname:WARNING: $msg\n";
96 }
98 # error message printing
99 sub msg_error {
100 my ($msg) = @_;
101 print STDERR "$progname:ERROR: $msg\n";
102 }
104 # determine check list
105 my @check_list = (qw(
106 blank
107 comment
108 ident
109 ));
110 my @checks = ();
111 if ($check eq 'all') {
112 @checks = @check_list;
113 }
114 else {
115 foreach my $c (split(/,/, $check)) {
116 if (not grep(/^$c$/, @check_list)) {
117 die "invalid check \"$c\"";
118 }
119 push(@checks, $c);
120 }
121 }
123 # global return code
124 $main::GRC = 0;
126 # environment preparation
127 system("rm -rf $tmpdir");
128 system("mkdir -p $tmpdir");
130 # iterate over all fsl. files
131 foreach my $filename (@ARGV) {
132 my $io = new IO::File "<$filename"
133 or die "unable to open file \"$filename\" for reading";
134 my $spec; { local $/ = undef; $spec = <$io>; }
135 $io->close;
136 foreach my $check (@checks) {
137 eval "\&check_$check(\$filename, \$spec);";
138 }
139 }
141 # environment cleanup
142 system("rm -rf $tmpdir");
144 # die gracefully
145 exit($main::GRC);
147 ## _________________________________________________________________
148 ##
149 ## COMMON SUBROUTINES
150 ## _________________________________________________________________
151 ##
153 sub lines {
154 my ($txt) = @_;
155 my $l = 0;
156 $txt =~ s|\n|$l++, ''|sge;
157 return $l;
158 }
160 sub lint_message {
161 my ($type, $file, $done, $this, $msg) = @_;
162 if (defined($done) and defined($this)) {
163 my $start = &lines($done) + 1;
164 my $end = $start + &lines($this);
165 my $pos = $start;
166 $pos .= "-". $end if ($end > $start);
167 printf("%s:%s: %s:%s: %s\n", $progname, $type, $file, $pos, $msg);
168 }
169 else {
170 printf("%s:%s: %s: %s\n", $progname, $type, $file, $msg);
171 }
172 }
174 sub lint_warning {
175 my ($file, $done, $this, $msg) = @_;
176 &lint_message("WARNING", $file, $done, $this, $msg);
177 $main::GRC = 1 if ($main::GRC < 1);
178 }
180 sub lint_error {
181 my ($file, $done, $this, $msg) = @_;
182 &lint_message("ERROR", $file, $done, $this, $msg);
183 $main::GRC = 2 if ($main::GRC < 2);
184 }
186 ## _________________________________________________________________
187 ##
188 ## CHECK "blank": whitespace and blank lines
189 ## _________________________________________________________________
190 ##
192 sub check_blank {
193 my ($file, $spec) = @_;
195 # check for CR-LF combination
196 my $done = ''; my $this = ''; my $todo = $spec;
197 while ($todo =~ m/\r\n/s) {
198 $done .= $`; $this = $&; $todo = $';
199 &lint_warning($file, $done, $this, "carriage-return (CR, 0x0d) line-feed (NL, 0x0a) combination (expected just line-feed)");
200 $done .= $this;
201 }
203 # check for multiple blank lines
204 $done = ''; $this = ''; $todo = $spec;
205 while ($todo =~ m/(\r?\n[ \t]*){3,}/s) {
206 $done .= $`; $this = $&; $todo = $';
207 &lint_warning($file, $done, $this, "multiple subsequent blank lines (expected single blank line)");
208 $done .= $this;
209 }
211 # check for trailing whitespaces
212 $done = ''; $this = ''; $todo = $spec;
213 while ($todo =~ m/[ \t]+\r?\n/s) {
214 $done .= $`; $this = $&; $todo = $';
215 if ($done eq '' or $done =~ m|\n$|s) {
216 &lint_warning($file, $done, $this, "whitespace on empty line (expected none)");
217 }
218 else {
219 &lint_warning($file, $done, $this, "trailing whitespace (expected none)");
220 }
221 $done .= $this;
222 }
224 # check for bogus line continuations
225 $done = ''; $this = ''; $todo = $spec;
226 while ($todo =~ m/\\[ \t]*\r?\n(?=[ \t]*\r?\n)/s) {
227 $done .= $`; $this = $&; $todo = $';
228 &lint_warning($file, $done, $this, "bogus line continuation for following empty line (expect no line continuation)");
229 $done .= $this;
230 }
232 # check for leading whitespaces before line continuations
233 $done = ''; $this = ''; $todo = $spec;
234 while ($todo =~ m/[ \t]{2,}\\[ \t]*\r?\n/s) {
235 $done .= $`; $this = $&; $todo = $';
236 &lint_warning($file, $done, $this, "multiple leading whitespace before line continuation (expected just a single space)");
237 $done .= $this;
238 }
240 # check for leading tabs
241 $done = ''; $this = ''; $todo = $spec;
242 while ($todo =~ m/^ *\t+ *[^ \t]/m) {
243 $done .= $`; $this = $&; $todo = $';
244 &lint_warning($file, $done, $this, "leading tabs (expected spaces)");
245 $done .= $this;
246 }
248 # check for mandatory/wished trailing blank line
249 if ($spec !~ m|\n\n$|) {
250 &lint_warning($file, $done, "", "mandatory/wished trailing blank line missing (expected one)");
251 }
252 }
254 ## _________________________________________________________________
255 ##
256 ## CHECK "comment": sharp-comments
257 ## _________________________________________________________________
258 ##
260 sub check_comment {
261 my ($file, $spec) = @_;
262 my ($pkg);
264 # determine package name
265 $pkg = $file;
266 $pkg =~ s|^.+/||;
267 $pkg =~ s|^fsl\.||;
269 # check comment header
270 my $re = "";
271 $re .= "##\\n## fsl.$pkg -- OSSP fsl configuration\\n##\\n\\n";
272 if ($spec !~ m|^$re|os) {
273 &lint_warning($file, "", "", "invalid comment header (expected $re)");
274 }
276 # check for comment indentation
277 my $done .= $`; my $this = $&; my $todo = $';
278 while ($todo =~ m/^([ \t]*)(#+)([ \t]*)(.*?)$/m) {
279 $done .= $`; $this = $&; $todo = $';
280 my ($lead, $sharp, $pad, $text) = ($1, $2, $3, $4);
281 if (length($lead) % 2 != 0) {
282 &lint_warning($file, $done, $this, "incorrect comment indentation (expected a multiple of 2 spaces)");
283 }
284 if (length($lead) > 1 && length($sharp) > 1) {
285 &lint_warning($file, $done, $this, "indented comment has introduced with multiple sharps (expected single sharp character)");
286 }
287 if (length($pad.$text) > 0 && length($sharp.$pad) % 4 != 0) {
288 &lint_warning($file, $done, $this, "incorrect comment text padding (expected a multiple of 4 sharps or spaces)");
289 }
290 if (length($pad) == 0 && length($text) > 0) {
291 &lint_warning($file, $done, $this, "missing leading space before comment text (expected padding spaces)");
292 }
293 if (length($pad) > 0 && length($text) == 0) {
294 &lint_warning($file, $done, $this, "empty comment text (expected a reasonable text)");
295 }
296 $done .= $this;
297 }
298 }
300 ## _________________________________________________________________
301 ##
302 ## CHECK "ident"
303 ## _________________________________________________________________
304 ##
306 sub check_ident {
307 my ($file, $spec) = @_;
308 my ($pkg, $section);
310 # determine package name
311 $pkg = $file;
312 $pkg =~ s|^.+/||;
313 $pkg =~ s|^fsl\.||;
315 # check sections with ident/facility regex
316 my $done .= ""; my $this = ""; my $todo = $spec;
317 while ($todo =~ m:\n(\w+)(\s+)(\S+)/(\S+)(\s+)q\{(.*?)\};:s) {
318 $done .= $`; $this = $&; $todo = $';
319 my ($section, $ws1, $ident, $facility, $ws2, $body) = ($1, $2, $3, $4, $5, $6);
321 if ($pkg eq "fsl") {
322 # enforce default section for fsl
323 if ($section ne "default") {
324 &lint_warning($file, "", "", "section \"$section\" not allowed for package $pkg (expected default)");
325 }
326 }
327 else {
328 # enforce ident section for any package othen than fsl
329 if ($section ne "ident") {
330 &lint_warning($file, "", "", "section \"$section\" not allowed for package $pkg (expected ident)");
331 }
333 # ident and facility wildcard-only would be a catch-all
334 if ($ident =~ m/^[(]?\.[\+\*][)]?$/ and $facility =~ m/^[(]?\.[\+\*][)]?$/) {
335 &lint_warning($file, "", "", "wildcard not allowed for both ident and facility (found $ident/$facility");
336 }
337 }
339 # enforce a single space
340 if (length($ws1) != 1) {
341 &lint_warning($file, "", "", "whitespace count wrong between section ($section) and ident ($ident)");
342 }
344 # enforce a single space
345 if (length($ws2) != 1) {
346 &lint_warning($file, "", "", "whitespace count wrong between facility ($facility) and end of line");
347 }
349 # ident same as facility is likely to be a typo
350 if ($ident eq $facility) {
351 &lint_warning($file, "", "", "unusual constellation ident equal to facility (found $ident/$facility");
352 }
354 # FIXME MTAs hardcoded here for /mail
355 if ($facility eq "mail" and $pkg !~ m/^(sendmail|ssmtp|postfix|exim)$/) {
356 &lint_warning($file, "", "", "only MTAs may match facility mail");
357 }
359 # FIXME inn hardcoded here for /news
360 if ($facility eq "news" and $pkg !~ m/^(inn)$/) {
361 &lint_warning($file, "", "", "only inn may match facility news");
362 }
364 # check prefix channel
365 if ($body =~ m/\n([ ]*)prefix(\s*?)\((.*?)\)/s) {
366 my ($ws1, $ws2, $options) = ($1, $2, $3);
368 # enforce eight spaces
369 if (length($ws1) != 4) {
370 &lint_warning($file, "", "", "prefix channel whitespace count at start of line");
371 }
373 # enforce zero spaces
374 if (length($ws2) != 0) {
375 &lint_warning($file, "", "", "whitespace not allowed between prefix channel and round open bracket");
376 }
378 # enforce prefix options in prefix channel
379 if ($options !~ m/\sprefix="%b %d %H:%M:%S %N (<%L> )?\$1(\[%P\])?: "/) {
380 &lint_warning($file, "", "", "prefix option in prefix channel invalid or missing");
381 }
382 $options = $';
383 $options =~ s/,//;
385 # detect superflous options in prefix channel
386 if ($options =~ m/\S+/s) {
387 $options =~ s/\n/\\n/;
388 &lint_warning($file, "", "", "superflous option in prefix channel unseparated line detected: $options");
389 }
390 }
391 else {
392 &lint_warning($file, "", "", "prefix channel missing");
393 }
395 # check path branch
396 if ($body !~ m/\n([ ]*)->(\s*?)\{(.*)\}\n/s) {
397 &lint_warning($file, "", "", "no path branch found");
398 return;
399 }
400 my ($ws1, $ws2, $body) = ($1, $2, $3); #FIXME check ws1/ws2
402 # check path channel
403 while ($body =~ m/\n([ ]*)(\w+):(\s+?)file(\s*?)\((.*?)\);/s) {
404 my ($ws1, $level, $ws2, $ws3, $options) = ($1, $2, $3, $4, $5);
405 $body = $';
407 # enforce eight spaces
408 if (length($ws1) != 8) {
409 &lint_warning($file, "", "", "path channel whitespace count at start of line");
410 }
412 # enforce spaces
413 if (length($ws2) < 1) {
414 &lint_warning($file, "", "", "whitespace required between level and file");
415 }
417 # enforce zero spaces
418 if (length($ws3) != 0) {
419 &lint_warning($file, "", "", "path channel whitespace not allowed between file channel and round open bracket");
420 }
422 # check for legal l2 level
423 if ($level !~ m/^(panic|critical|error|warning|notice|info|trace|debug)$/) {
424 &lint_warning($file, "", "", "illegal l2 level $level detected");
425 }
427 # enforce file option in file channel
428 if ($options !~ m;path="\@l_prefix\@/var/$pkg/(log\S+|$pkg\.log)";) {
429 &lint_warning($file, "", "", "path option in file channel invalid or missing");
430 }
431 $options = $';
432 $options =~ s/,//;
434 # enforce perm option in file channel
435 if ($options !~ m;perm=0[0-7]{3};) {
436 &lint_warning($file, "", "", "perm option in file channel invalid or missing");
437 }
438 $options = $';
439 $options =~ s/,//;
441 # detect superflous options in file channel
442 if ($options =~ m/\S+/s) {
443 $options =~ s/\n/\\n/;
444 &lint_warning($file, "", "", "superflous option in prefix channel detected: $options");
445 }
446 }
448 # check path channel
449 if ($body =~ m/\n([ ]*)(\w+):(\s*?)file(\s*?)\((.*?)\)/s) {
450 my ($ws1, $level, $ws2, $ws3, $options) = ($1, $2, $3, $4, $5);
452 # enforce eight spaces
453 if (length($ws1) != 8) {
454 &lint_warning($file, "", "", "path channel whitespace count at start of unseparated line");
455 }
457 # enforce spaces
458 if (length($ws2) < 1) {
459 &lint_warning($file, "", "", "path channel whitespace required between level and file of unseparated line");
460 }
462 # enforce zero spaces
463 if (length($ws3) != 0) {
464 &lint_warning($file, "", "", "whitespace not allowed between file channel and round open bracket");
465 }
467 # check for legal l2 level
468 if ($level !~ m/^(panic|critical|error|warning|notice|info|trace|debug)$/) {
469 &lint_warning($file, "", "", "illegal l2 level $level detected on unseparated line");
470 }
472 # enforce file option in file channel
473 if ($options !~ m;path="\@l_prefix\@/var/$pkg/(log\S+|$pkg\.log)";) {
474 &lint_warning($file, "", "", "XXX path option in file channel invalid or missing on unseparated line");
475 }
476 $options = $';
477 $options =~ s/,//;
479 # enforce perm option in file channel
480 if ($options !~ m;perm=0[0-7]{3};) {
481 &lint_warning($file, "", "", "perm option in file channel invalid or missing on unseparated line");
482 }
484 $options = $';
485 $options =~ s/, jitter=[0-9]+//;
486 $options =~ s/, monitor=[0-9]+//;
487 $options =~ s/,//;
489 # detect superflous options in file channel
490 if ($options =~ m/\S+/s) {
491 $options =~ s/\n/\\n/;
492 &lint_warning($file, "", "", "superflous option in file channel unseparated line detected: $options");
493 }
494 }
495 else {
496 &lint_warning($file, "", "", "file channel missing");
497 }
499 $done .= $this;
500 }
501 return;
502 }