#
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
# WARNING -- this package implements a Sun private interface; it may
# change without notice.
require 5.005;
use strict;
use Exporter;
use vars qw($VERSION $failedOpen
$VERSION = '1.01';
my @constants = qw();
@EXPORT_FAIL = qw($failedOpen);
sub new {
my $obj = shift;
my $debug = shift; # bool
my $filters = shift; # options for filtering
$attrDir = shift if (@_); # override for test
$configDir = shift if (@_); # ditto
my $suffix = '';
$suffix = shift if (@_); # test, again
("$attrDir/audit_record_attr$suffix",
"$configDir/audit_class$suffix",
"$configDir/audit_control$suffix",
"$configDir/audit_event$suffix",
"$configDir/audit_user$suffix");
return (bless {
'attrFile' => $recordf,
'classFile' => $classf,
'controlFile' => $controlf,
'debug' => $debug,
'eventFile' => $eventf,
'havePath' => 0,
'kernelDefault' => '',
'userDefault' => '',
}
# readAttr
# read the hand edited attrFile file
#
# return a hash reference
sub readAttr {
my $obj = shift;
my $count = 0;
my $lastAttr = '';
my $lastMacro = '';
my $attrState = -1;
my $caseState = 0;
my $label;
my $callName = '';
my $skip = '';
my $description = 'none';
my $format = 'none';
my $comment = '';
my $title = 'none';
my $note = '';
my $case = '';
my @case = ();
my %skipClass;
my %attr = ();
my %token = ();
my %noteAlias = ();
while (<$fileHandle>) {
chomp;
s/#.*//; # remove comment
next if (/^\s*$/);
# continue assigning lines to multiline macros
# type: message
if ( $lastMacro ne '' ) {
if ($mcr eq "message") {
$_ =~ /^\s*(.*)/i;
}
next;
}
$lastMacro = '';
if (/^\s*skipClass\s*=\s*(.*)/i) {
my $class = $1;
# don't skip what you're searching for
next;
}
elsif (/^\s*token\s*=\s*(.*)/i) {
next;
}
elsif (/^\s*message\s*=\s*(.*)/i) {
next;
}
elsif (/^\s*kernel\s*=\s*(.*)/i) {
next;
}
elsif (/^\s*user\s*=\s*(.*)/i) {
next;
}
}
# continue assigning lines to multiline attributes
# type: case, comment, note, format
if ( $lastAttr ne '' ) {
my $curAttrVal = '';
eval "\$curAttrVal = \$$lastAttr";
chomp($curAttrVal);
chop($curAttrVal);
$_ =~ /^\s*(.*)/i;
$curAttrVal .= $1;
eval "\$$lastAttr = \$curAttrVal";
next;
}
$lastAttr = '';
if (/^\s*label\s*=\s*(.*)/i) {
my $newLabel = $1;
if ($obj->{'debug'}) {
print STDERR qq{
}
# if $attrState not zero, an unwritten record exists
if ($attrState) {
$callName);
$count++;
}
= '';
@case = ();
$caseState = 0;
}
$attrState = 1;
}
elsif (/^\s*skip\s*=\s*(.*)/i) {
$skip = $1;
}
elsif (/^\s*syscall\s*=\s*(.*)/i) {
$callName = $1;
}
elsif (/^\s*program\s*=\s*(.*)/i) {
$callName = $1;
}
elsif (/^\s*title\s*=\s*(.*)/i) {
$title = $1;
}
elsif (/^\s*see\s*=\s*(.*)/i) {
$description = $1;
}
elsif (/^\s*format\s*=\s*(.*)/i) {
$format = $1;
}
elsif (/^\s*comment\s*=\s*(.*)/i) {
$comment .= $1;
}
elsif (/^\s*note\s*=\s*(.*)/i) {
$note .= $1;
}
elsif (/^\s*case\s*=\s*(.*)/i) {
if ($caseState) {
$format = 'none';
}
$case = $1;
$caseState = 1;
}
}
if ($attrState) {
@case];
$count++;
}
}
close $fileHandle;
}
# readEvent
# read eventFile and extract audit event information, including
# which classes are associated with each event and what call is
# related.
sub readEvent {
my $obj = shift;
my %event = ();
my $count = 0;
}
my @classFilterMasks = ();
if ($classFilter) {
foreach (split(',', $classFilter)) {
}
}
# ignore customer-supplied audit events (id > 32767)
while (<$fileHandle>) {
chomp;
s/#.*//; # remove comment
next if (/^\s*$/);
if (/^\s*(\d+):(\w+):([^:]+):(.*)/) {
my $id = $1;
my $label = $2;
my $description = $3;
my $class = $4;
if ($id !~ /\d+/) {
print STDERR "$id is not numeric (line $.)\n";
next;
}
next if ($id > 32767);
$class =~ s/\s*$//;
if ($obj->{'debug'}) {
print STDERR qq{
}
my $mask = 0;
if ($classFilter) {
foreach (split(/\s*,\s*/, $class)) {
}
my $skip = 0;
foreach my $filterMask (@classFilterMasks) {
unless ($mask & $filterMask) {
$skip = 1;
last;
}
}
next if $skip;
}
if ($obj->{'idFilter'}) {
}
$count++;
}
}
close $fileHandle;
}
# readClass
# read classFile and extract audit class information
sub readClass {
my $obj = shift;
my %class = ();
my $count = 0;
while (<$fileHandle>) {
chomp;
s/#.*//; # remove comment
next if (/^\s*$/);
$count++;
}
close $fileHandle;
}
sub filterLabel {
my $obj = shift;
my $label = shift;
my $keepIt = 1;
return ($keepIt);
}
# Normally, the root of the event label is the system call. The
# attrFile attribute syscall or program overrides this.
sub filterCallName {
my $obj = shift;
my $label = shift;
my $callName = shift;
my $name = $1;
return (lc ($name));
}
# readControl
# read controlFile and extract flags and naflags information
# at present, minfree, maxfree and the audit partitions are not
# checked.
sub readControl {
my $obj = shift;
my $failMode = shift;
my $cError = 0;
my $errors = '';
unless (open($fileHandle, $file)) {
die sprintf("$failedOpen\n", $file, $!)
unless ($failMode eq 'ignore');
return (0, '');
}
while (<$fileHandle>) {
chomp;
s/#.*//; # remove comment
next if (/^\s*$/);
$class =~ s/^[-+^]+//;
$errors .=
sprintf("$invalidClass\n",
$class, $_);
$cError++;
}
}
}
elsif (/^\s*dir:\s*(.*)/) {
push (@paths, $1);
}
}
close $fileHandle;
}
sub getPathList {
my $obj = shift;
return ($obj->{'paths'});
}
# readUser
# read userFile and extract audit information for validation
sub readUser {
my $obj = shift;
my $failMode = shift;
my $cError = 0;
my $error = '';
unless (open($fileHandle, $file)) {
die sprintf("$failedOpen\n", $file, $!)
unless ($failMode eq 'ignore');
return (0, '');
}
# these strings are defined here mostly to avoid indentation problems
my $syntaxErr1 = gettext(
'incorrect syntax (exactly two colons req\'d) in audit_user: %s');
while (<$fileHandle>) {
chomp;
s/#.*//; # remove comment
next if (/^\s*$/);
my $colonCount = tr/:/:/;
if ($colonCount != 2) {
$error .= sprintf("$syntaxErr1\n", $_);
$cError++;
}
unless (defined($user)) {
$error .= sprintf("$syntaxErr2\n", $_);
$cError++;
next;
}
unless (defined($name)) {
$cError++;
}
$error .= sprintf("$emptyErr\n", $_);
$cError++;
next;
}
my $thisClass;
$thisClass =~ s/^[-+^]+//;
$_);
$cError++;
}
}
}
close $fileHandle;
}
# ckAttrEvent complains if controlFile and attrFile don''t contain the
# same list of events.
sub ckAttrEvent {
my $obj = shift;
my $cError = 0;
my $error = '';
my $cAttr = 0;
my $label;
'%s entry in attribute file but not in event file');
'%s entry in event file but not in attribute file');
$cAttr++;
$cError++;
}
}
my $cEvent = 0;
$cEvent++;
$cError++;
}
}
# debug only; not I18N'd
print STDERR
"$cAttr audit_record_attr entries and $cEvent audit_event entries\n"
if ($obj->{'debug'});
}
# chkBslash (helper)
# check the given string for backslash character at the end; if found
# return the string sent as a first argument, otherwise return empty
# string.
sub chkBslash ($$) {
my $retStr = shift;
my $strPtr = shift;
if ( $$strPtr !~ /\\$/ ) {
$retStr = '';
}
return $retStr;
}
1;