5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
23 # Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 # Use is subject to license terms.
27 # auditrecord - display one or more audit records
33 our (%opt, $parse, $callFilter, $debug,
34 %attr, %event, %class, %skipClass, %token, %noteAlias,
35 $title, $note, $name, $col1, $col2, $col3, $skip);
39 use POSIX
qw(locale_h);
40 use Sun
::Solaris
::Utils
qw(gettext textdomain);
41 use Sun
::Solaris
::BSM
::_BSMparse
;
43 setlocale
(LC_ALL
, "");
44 textdomain
(TEXT_DOMAIN
);
46 if (!getopts
('adhe:c:i:p:s:', \
%opt) || @ARGV) {
48 gettext
("$0 takes no arguments other than switches.\n");
49 print STDERR
$errString if (@ARGV);
54 unless ($opt{a
} || $opt{c
} || $opt{e
} || $opt{h
} || $opt{i
} ||
61 $options{'classFilter'} = $opt{c
}; # filter on this class
62 $debug = $opt{d
}; # debug mode on
63 $options{'eventFilter'} = $opt{e
}; # filter on this event
64 my $html = $opt{h
}; # output in html format
65 $options{'idFilter'} = $opt{i
}; # filter on this id
66 $callFilter = $opt{p
}; # filter on this program name
67 $callFilter = $opt{s
} if ($opt{s
}); # filter on this system call
69 if (defined($callFilter)) {
70 $callFilter = qr/\b$callFilter\b/;
74 $parse = new Sun
::Solaris
::BSM
::_BSMparse
($debug, \
%options);
76 my ($attr, $token, $skipClass, $noteAlias) = $parse->readAttr();
79 %noteAlias = %$noteAlias;
80 %skipClass = %$skipClass;
82 %class = %{$parse->readClass()};
83 %event = %{$parse->readEvent()};
85 # the calls to readControl and readUser are for debug; they are not
86 # needed for generation of record formats. 'ignore' means if there
87 # is no permission to read the file, don't die, just soldier on.
89 # $error is L10N'd by $parse
94 # verify audit_control content
95 ($cnt, $error) = $parse->readControl('ignore');
96 print STDERR
$error if ($cnt);
98 # verify audit_user content
99 ($cnt, $error) = $parse->readUser('ignore');
100 print STDERR
$error if ($cnt);
102 # check audit_event, audit_display_attr
103 ($cnt, $error) = $parse->ckAttrEvent();
104 print STDERR
$error if ($cnt);
107 # check for invalid class to -c option if supplied
108 if (defined $options{'classFilter'}) {
109 my $invalidClass = gettext
('Invalid class %s supplied.');
110 my $isInvalidClass = 0;
111 foreach (split(/\s*,\s*/, $options{'classFilter'})) {
112 unless (exists $class{$_}) {
113 printf STDERR
"$invalidClass\n", $_;
117 exit (1) if $isInvalidClass;
128 # writeASCII -- collect what's been read from various sources and
129 # output the formatted audit records
136 foreach $label (sort(keys(%event))) {
140 my ($id, $class, $eventDescription) = @
{$event{$label}};
142 our ($title, $note, $name, $col1, $col2, $col3);
144 my ($skipThisClass, $mask) = classToMask
($class, $label);
146 next if ($skipThisClass);
148 $mask = sprintf("0x%08X", $mask);
150 ($name, $description, $title, $skip, @case) =
151 getAttributes
($label, $eventDescription);
153 next if ($name eq 'undefined');
155 next unless $description =~ $callFilter;
168 ($col1, $col2, $col3) = getCallInfo
($id, $name, $description);
169 my @col1 = split(/\s*;\s*/, $col1);
170 my @col2 = split(/\s*;\s*/, $col2);
171 my @col3 = split(/\s*;\s*/, $col3);
173 $rows = $#col2 if ($#col2 > $rows);
174 $rows = $#col3 if ($#col3 > $rows);
175 for (my $i = 0; $i <= $rows; $i++) {
176 $col1 = defined ($col1[$i]) ?
$col1[$i] : '';
177 $col2 = defined ($col2[$i]) ?
$col2[$i] : '';
178 $col3 = defined ($col3[$i]) ?
'See ' . $col3[$i] : '';
194 foreach $caseElement (@case) {
195 # $note1 is the "case" description
197 my ($note1, $format, $comment, $note2) = @
$caseElement;
204 unless (defined($format)) {
205 $errString = gettext
(
206 "missing format field: %s");
207 printf STDERR
("$errString\n", $label);
210 unless ($format eq 'none') {
213 my $list = getFormatList
($format, $id);
215 my @format = split(/\s*:\s*/, $list);
216 my @comment = split(/\s*:\s*/, $comment);
220 foreach $item (@format) {
223 getFormatLine
($item, $label,
232 $note2 = $noteAlias{$note2} if ($noteAlias{$note2});
243 unless ($haveFormat) {
245 $note = gettext
('No format information available');
251 # writeHTML -- collect what's been read from various sources
252 # and output the formatted audit records
261 my $docTitle = gettext
("Audit Record Formats");
264 <!doctype html PUBLIC
"-//IETF//DTD HTML//EN">
267 <title
>$docTitle</title
>
268 <META http
-equiv
="Content-Style-Type" content
="text/css">
271 <body TEXT
="#000000" BGCOLOR
="#F0F0F0">
274 my $tableRows = 0; # work around Netscape large table bug
275 startTable
(); # by generating multiple tables
277 foreach $label (sort(keys(%event))) {
278 my ($id, $class, $eventDescription) = @
{$event{$label}};
280 our ($title, $name, $note, $col1, $col2, $col3);
282 my ($skipThisClass, $mask) = classToMask
($class, $label);
284 next if ($skipThisClass);
286 $mask = sprintf("0x%08X", $mask);
290 ($name, $description, $title, $skip, @case) =
291 getAttributes
($label, $eventDescription);
293 next if ($name eq 'undefined');
295 next unless $description =~ $callFilter;
298 if ($tableRows > 50) {
304 my ($callType, $callName);
305 ($callType, $callName, $description) =
306 getCallInfo
($id, $name, $description);
307 $description =~ s/\s*;\s*/<br>/g;
309 my $titleName = $title;
311 $titleName = $callName;
313 $titleName =~ s/\s*;\s*/<br>/g;
314 $titleName = ' ' if ($titleName eq $title);
317 <tr bgcolor
="#C0C0C0">
324 <td colspan
=2>$titleName</td
>
325 <td colspan
=2>$description</td
>
342 foreach $caseElement (@case) {
343 my ($note1, $format, $comment, $note2) = @
$caseElement;
350 unless (defined($format)) {
351 my $errString = gettext
(
352 "Missing format field: %s\n");
353 printf STDERR
($errString, $label);
356 unless ($format eq 'none') {
359 my $list = getFormatList
($format, $id);
361 my @format = split(/\s*:\s*/, $list);
362 my @comment = split(/\s*:\s*/, $comment);
366 foreach $item (@format) {
368 getFormatLine
($item, $label,
374 $note2 = $noteAlias{$note2} if ($noteAlias{$note2});
384 unless ($haveFormat) {
386 $note = 'No format information available';
402 <tr bgcolor="#C0C0C0">
409 <th colspan=2>Call Name</th>
410 <th colspan=2>Reference</th>
413 <th colspan=4>Format</th>
427 # classToMask: One, given a class list, it calculates the mask; Two,
428 # it checks to see if every item on the class list is marked for
429 # skipping, and if so, sets a flag.
432 my $classList = shift;
436 my @classes = split(/\s*,\s*/, $classList);
437 my $skipThisClass = 0;
440 foreach $thisClass (@classes) {
441 unless (defined($class{$thisClass})) {
442 my $errString = gettext
(
443 "%s not found in audit_class. Omitting %s\n");
444 $errString = sprintf($errString, $thisClass,
446 print STDERR
$errString if ($debug);
449 $skipThisClass = 1 if ($skipClass{$thisClass});
450 $mask |= $class{$thisClass};
452 return ($skipThisClass, $mask);
455 # getAttributes: Combine fields from %event and %attr; a description
456 # in the attribute file overrides a description from audit_event
460 my $desc = shift; # description from audit_event
462 my ($description, $title, $skip, @case);
464 my $errString = gettext
("%s not found in attribute file.");
465 my $name = gettext
("undefined");
467 if (defined($attr{$label})) {
468 ($name, $description, $title, $skip, @case) = @
{$attr{$label}};
469 if ($description eq 'none') {
470 if ($desc eq 'blank') {
473 $description = $desc;
476 $name = '' if ($name eq 'none');
477 $title = $name if (($title eq 'none') || (!defined($title)));
479 printf STDERR
("$errString\n", $label) if ($debug);
481 return ($name, $description, $title, $skip, @case);
484 # getCallInfo: the system call or program name for an audit record can
485 # usually be derived from the event name; %attr provides exceptions to
499 $callType = 'system call';
501 $callType = 'program';
503 ($callName) = split(/\s*:\s*/, $name);
509 $description = "$desc" if ($desc);
511 return ($callType, $callName, $description);
514 # getFormatList: determine the order and details of kernel vs user
515 # audit records. If the first token is "head" then the token list
516 # is explicit, otherwise the header, subject and return are implied.
524 if ($format =~ /^head:/) {
527 elsif ($format eq 'kernel') {
528 $list = $parse->{'kernelDefault'};
529 $list =~ s/insert://;
530 } elsif ($format eq 'user') {
531 $list = $parse->{'userDefault'};
532 $list =~ s/insert://;
533 } elsif ($id < 6000) {
534 $list = $parse->{'kernelDefault'};
535 $list =~ s/insert/$format/;
537 $list = $parse->{'userDefault'};
538 $list =~ s/insert/$format/;
543 # getFormatLine: the arguments from the attribute 'format' are
544 # expanded to their printable form and also paired with a comment if
554 my ($token, $comment);
557 if ($arg =~ s/(\D*)(\d+)$/$1/) { # trailing digits select a comment
560 $isOption = 1 if ($arg =~ s/^\[(.+)\]$/$1/);
562 if (defined($token{$arg})) { # expand abbreviated name to token
563 $token = $token{$arg};
565 $token = $arg; # no abbreviation found
567 $token = '['.$token.']' if ($isOption);
570 unless(defined($comment[$cmt])) {
571 my $errString = gettext
(
572 "missing comment for %s %s token %d\n");
573 printf STDERR
($errString, $label, $token,
575 $comment = gettext
('missing comment field');
577 $comment = $comment[$cmt];
578 $comment =~ s/:/:/g; #':' is a delimiter
583 unless (defined($token) && defined($comment)) {
584 my $errString = gettext
("attribute format/comment error for %s\n");
585 printf STDERR
($errString, $label);
587 return ($token, $comment);
591 print "$0 [ -d ] [ -h ] {[ -a ] | [ -e event ] |\n";
592 print "\t[ -c class ] | [-i id ] | [ -p program ] |\n";
593 print "\t[ -s syscall ]}\n";
598 @
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
602 format threeColumns
=
603 @
<<<<<<<<<< @
<<<<<<<<<<<<<<<<<<< @
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
608 @
<<<<<<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
612 ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
621 ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
626 ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<