17c478bd9Sstevel@tonic-gate#
2*32a06bbaSJan Friedel# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate# Use is subject to license terms.
47c478bd9Sstevel@tonic-gate#
57c478bd9Sstevel@tonic-gate# CDDL HEADER START
67c478bd9Sstevel@tonic-gate#
77c478bd9Sstevel@tonic-gate# The contents of this file are subject to the terms of the
887e895dbStz# Common Development and Distribution License (the "License").
987e895dbStz# You may not use this file except in compliance with the License.
107c478bd9Sstevel@tonic-gate#
117c478bd9Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
127c478bd9Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing.
137c478bd9Sstevel@tonic-gate# See the License for the specific language governing permissions
147c478bd9Sstevel@tonic-gate# and limitations under the License.
157c478bd9Sstevel@tonic-gate#
167c478bd9Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each
177c478bd9Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
187c478bd9Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the
197c478bd9Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying
207c478bd9Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner]
217c478bd9Sstevel@tonic-gate#
227c478bd9Sstevel@tonic-gate# CDDL HEADER END
237c478bd9Sstevel@tonic-gate#
247c478bd9Sstevel@tonic-gate
257c478bd9Sstevel@tonic-gate# WARNING -- this package implements a Sun private interface; it may
267c478bd9Sstevel@tonic-gate# change without notice.
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gatepackage Sun::Solaris::BSM::_BSMparse;
297c478bd9Sstevel@tonic-gaterequire 5.005;
307c478bd9Sstevel@tonic-gateuse strict;
317c478bd9Sstevel@tonic-gateuse Exporter;
327c478bd9Sstevel@tonic-gateuse Sun::Solaris::Utils qw(gettext);
337c478bd9Sstevel@tonic-gate
347c478bd9Sstevel@tonic-gateuse vars qw($VERSION $failedOpen
357c478bd9Sstevel@tonic-gate    %EXPORT_TAGS @ISA @EXPORT_OK @EXPORT_FAIL);
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate$VERSION = '1.01';
387c478bd9Sstevel@tonic-gate
397c478bd9Sstevel@tonic-gate@ISA = qw(Exporter);
407c478bd9Sstevel@tonic-gatemy @constants = qw();
417c478bd9Sstevel@tonic-gate@EXPORT_OK = qw(readAttr readEvent readClass filterLabel filterCallName
427c478bd9Sstevel@tonic-gate		readControl getPathList readUser ckAttrEvent);
437c478bd9Sstevel@tonic-gate@EXPORT_FAIL = qw($failedOpen);
447c478bd9Sstevel@tonic-gate%EXPORT_TAGS = (ALL => \@EXPORT_OK);
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate$failedOpen = gettext("failed to open %s: %s");
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gatesub new {
497c478bd9Sstevel@tonic-gate	my $obj = shift;
507c478bd9Sstevel@tonic-gate	my $debug = shift;	# bool
517c478bd9Sstevel@tonic-gate	my $filters = shift;	# options for filtering
527c478bd9Sstevel@tonic-gate
537c478bd9Sstevel@tonic-gate	my $dir = '/etc/security';
541b5f7228Stz	my $attrDir = '/usr/lib/audit';
557c478bd9Sstevel@tonic-gate        my $configDir = $dir;
567c478bd9Sstevel@tonic-gate	$attrDir = shift if (@_);	# override for test
577c478bd9Sstevel@tonic-gate	$configDir = shift if (@_);	# ditto
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate	my $suffix = '';
607c478bd9Sstevel@tonic-gate	$suffix = shift if (@_);	# test, again
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate	$obj = ref($obj) || $obj;
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate	my ($recordf, $classf, $controlf, $eventf, $userf) =
657c478bd9Sstevel@tonic-gate	   ("$attrDir/audit_record_attr$suffix",
667c478bd9Sstevel@tonic-gate	    "$configDir/audit_class$suffix",
677c478bd9Sstevel@tonic-gate	    "$configDir/audit_control$suffix",
687c478bd9Sstevel@tonic-gate	    "$configDir/audit_event$suffix",
697c478bd9Sstevel@tonic-gate	    "$configDir/audit_user$suffix");
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate	return (bless {
727c478bd9Sstevel@tonic-gate		'attrFile'	=> $recordf,
737c478bd9Sstevel@tonic-gate		'classFile'	=> $classf,
747c478bd9Sstevel@tonic-gate		'classFilter'	=> $filters->{'classFilter'},
757c478bd9Sstevel@tonic-gate		'controlFile'	=> $controlf,
767c478bd9Sstevel@tonic-gate		'debug'		=> $debug,
777c478bd9Sstevel@tonic-gate		'eventFile'	=> $eventf,
787c478bd9Sstevel@tonic-gate		'eventFilter'	=> $filters->{'eventFilter'},
797c478bd9Sstevel@tonic-gate		'idFilter'	=> $filters->{'idFilter'},
807c478bd9Sstevel@tonic-gate		'havePath'	=> 0,
817c478bd9Sstevel@tonic-gate		'kernelDefault'	=> '',
827c478bd9Sstevel@tonic-gate		'userDefault'	=> '',
837c478bd9Sstevel@tonic-gate		'userFile'	=> $userf}, $obj);
847c478bd9Sstevel@tonic-gate}
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate# readAttr
877c478bd9Sstevel@tonic-gate# read the hand edited attrFile file
887c478bd9Sstevel@tonic-gate#
897c478bd9Sstevel@tonic-gate# return a hash reference
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gatesub readAttr {
927c478bd9Sstevel@tonic-gate	my $obj = shift;
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate	my $file = $obj->{'attrFile'};
957c478bd9Sstevel@tonic-gate	my $fileHandle = do {local *FileHandle; *FileHandle};
967c478bd9Sstevel@tonic-gate	open($fileHandle, $file) or die sprintf("$failedOpen\n", $file, $!);
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate	my $count = 0;
99*32a06bbaSJan Friedel	my $lastAttr = '';
100*32a06bbaSJan Friedel	my $lastMacro = '';
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate	my $attrState = -1;
1037c478bd9Sstevel@tonic-gate	my $caseState = 0;
1047c478bd9Sstevel@tonic-gate	my $label;
1057c478bd9Sstevel@tonic-gate	my $callName = '';
1067c478bd9Sstevel@tonic-gate	my $skip = '';
1077c478bd9Sstevel@tonic-gate	my $description = 'none';
1087c478bd9Sstevel@tonic-gate	my $format = 'none';
1097c478bd9Sstevel@tonic-gate	my $comment = '';
1107c478bd9Sstevel@tonic-gate	my $title = 'none';
1117c478bd9Sstevel@tonic-gate	my $note = '';
1127c478bd9Sstevel@tonic-gate	my $case = '';
1137c478bd9Sstevel@tonic-gate	my @case = ();
1147c478bd9Sstevel@tonic-gate	my %skipClass;
1157c478bd9Sstevel@tonic-gate	my %attr = ();
1167c478bd9Sstevel@tonic-gate	my %token = ();
1177c478bd9Sstevel@tonic-gate	my $classFilter = $obj->{'classFilter'};
1187c478bd9Sstevel@tonic-gate	$classFilter = '' unless (defined ($classFilter));
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate	my %noteAlias = ();
1217c478bd9Sstevel@tonic-gate	while (<$fileHandle>) {
1227c478bd9Sstevel@tonic-gate		chomp;
1237c478bd9Sstevel@tonic-gate		s/#.*//;	 # remove comment
1247c478bd9Sstevel@tonic-gate		next if (/^\s*$/);
1257c478bd9Sstevel@tonic-gate
1267c478bd9Sstevel@tonic-gate		if ($attrState < 0) {  # initial state:  header info
127*32a06bbaSJan Friedel			# continue assigning lines to multiline macros
128*32a06bbaSJan Friedel			# type: message
129*32a06bbaSJan Friedel			if ( $lastMacro ne '' ) {
130*32a06bbaSJan Friedel				my ($mcr, $attr) = split(/\s*:\s*/, $lastMacro);
131*32a06bbaSJan Friedel
132*32a06bbaSJan Friedel				if ($mcr eq "message") {
133*32a06bbaSJan Friedel					chomp($noteAlias{$attr});
134*32a06bbaSJan Friedel					chop($noteAlias{$attr});
135*32a06bbaSJan Friedel
136*32a06bbaSJan Friedel					$_ =~ /^\s*(.*)/i;
137*32a06bbaSJan Friedel					$noteAlias{$attr} .= $1;
138*32a06bbaSJan Friedel
139*32a06bbaSJan Friedel					$lastMacro = chkBslash($lastMacro, \$1);
140*32a06bbaSJan Friedel				}
141*32a06bbaSJan Friedel				next;
142*32a06bbaSJan Friedel			}
143*32a06bbaSJan Friedel
144*32a06bbaSJan Friedel			$lastMacro = '';
1457c478bd9Sstevel@tonic-gate			if (/^\s*skipClass\s*=\s*(.*)/i) {
1467c478bd9Sstevel@tonic-gate				my $class = $1;
1477c478bd9Sstevel@tonic-gate				# don't skip what you're searching for
14887e895dbStz				next if (index(lc($classFilter),lc($class)) > -1);
1497c478bd9Sstevel@tonic-gate				$skipClass{$1} = 1;
1507c478bd9Sstevel@tonic-gate				next;
1517c478bd9Sstevel@tonic-gate			}
1527c478bd9Sstevel@tonic-gate			elsif (/^\s*token\s*=\s*(.*)/i) {
1537c478bd9Sstevel@tonic-gate				my ($attr, $value) = split(/\s*:\s*/, $1);
1547c478bd9Sstevel@tonic-gate				$token{$attr} = $value;
1557c478bd9Sstevel@tonic-gate				next;
1567c478bd9Sstevel@tonic-gate			}
1577c478bd9Sstevel@tonic-gate			elsif (/^\s*message\s*=\s*(.*)/i) {
1587c478bd9Sstevel@tonic-gate				my ($attr, $value) = split(/\s*:\s*/, $1);
1597c478bd9Sstevel@tonic-gate				$noteAlias{$attr} = $value;
160*32a06bbaSJan Friedel				$lastMacro = chkBslash("message:$attr", \$1);
1617c478bd9Sstevel@tonic-gate				next;
1627c478bd9Sstevel@tonic-gate			}
1637c478bd9Sstevel@tonic-gate			elsif (/^\s*kernel\s*=\s*(.*)/i) {
1647c478bd9Sstevel@tonic-gate				my ($attr, $value) = split(/\s*:\s*/, $1);
1657c478bd9Sstevel@tonic-gate				$obj->{'kernelDefault'} = $1;
1667c478bd9Sstevel@tonic-gate				next;
1677c478bd9Sstevel@tonic-gate			}
1687c478bd9Sstevel@tonic-gate			elsif (/^\s*user\s*=\s*(.*)/i) {
1697c478bd9Sstevel@tonic-gate				my ($attr, $value) = split(/\s*:\s*/, $1);
1707c478bd9Sstevel@tonic-gate				$obj->{'userDefault'} = $1;
1717c478bd9Sstevel@tonic-gate				next;
1727c478bd9Sstevel@tonic-gate			}
1737c478bd9Sstevel@tonic-gate		}
174*32a06bbaSJan Friedel
175*32a06bbaSJan Friedel		# continue assigning lines to multiline attributes
176*32a06bbaSJan Friedel		# type: case, comment, note, format
177*32a06bbaSJan Friedel		if ( $lastAttr ne '' ) {
178*32a06bbaSJan Friedel			my $curAttrVal = '';
179*32a06bbaSJan Friedel
180*32a06bbaSJan Friedel			eval "\$curAttrVal = \$$lastAttr";
181*32a06bbaSJan Friedel			chomp($curAttrVal);
182*32a06bbaSJan Friedel			chop($curAttrVal);
183*32a06bbaSJan Friedel
184*32a06bbaSJan Friedel			$_ =~ /^\s*(.*)/i;
185*32a06bbaSJan Friedel			$curAttrVal .= $1;
186*32a06bbaSJan Friedel
187*32a06bbaSJan Friedel			eval "\$$lastAttr = \$curAttrVal";
188*32a06bbaSJan Friedel
189*32a06bbaSJan Friedel			$lastAttr = chkBslash($lastAttr, \$1);
190*32a06bbaSJan Friedel			next;
191*32a06bbaSJan Friedel		}
192*32a06bbaSJan Friedel
193*32a06bbaSJan Friedel		$lastAttr = '';
1947c478bd9Sstevel@tonic-gate		if (/^\s*label\s*=\s*(.*)/i) {
1957c478bd9Sstevel@tonic-gate			$attrState = 0 if ($attrState < 0);
1967c478bd9Sstevel@tonic-gate			my $newLabel = $1;
1977c478bd9Sstevel@tonic-gate
1987c478bd9Sstevel@tonic-gate			if ($obj->{'debug'}) {
1997c478bd9Sstevel@tonic-gate				print STDERR qq{
2007c478bd9Sstevel@tonic-gate$newLabel is duplicated in the attribute file (line $.)
2017c478bd9Sstevel@tonic-gate				} if ($attr{$newLabel});
2027c478bd9Sstevel@tonic-gate			}
2037c478bd9Sstevel@tonic-gate			# if $attrState not zero, an unwritten record exists
2047c478bd9Sstevel@tonic-gate			if ($attrState) {
2057c478bd9Sstevel@tonic-gate				$callName = $obj->filterCallName($label,
2067c478bd9Sstevel@tonic-gate				    $callName);
2077c478bd9Sstevel@tonic-gate				push(@case, [$case, $format, $comment, $note]);
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate				if ($obj->filterLabel($label)) {
2107c478bd9Sstevel@tonic-gate					$attr{$label} =
2117c478bd9Sstevel@tonic-gate					    [$callName, $description, $title,
2127c478bd9Sstevel@tonic-gate					    $skip, @case];
2137c478bd9Sstevel@tonic-gate					$count++;
2147c478bd9Sstevel@tonic-gate				}
2157c478bd9Sstevel@tonic-gate				$format = $description = $title = 'none';
2167c478bd9Sstevel@tonic-gate				$case = $note = $comment = $skip = $callName
2177c478bd9Sstevel@tonic-gate				    = '';
2187c478bd9Sstevel@tonic-gate				@case = ();
2197c478bd9Sstevel@tonic-gate				$caseState = 0;
2207c478bd9Sstevel@tonic-gate			}
2217c478bd9Sstevel@tonic-gate			$label = $newLabel;
2227c478bd9Sstevel@tonic-gate			$attrState = 1;
2237c478bd9Sstevel@tonic-gate		}
2247c478bd9Sstevel@tonic-gate		elsif (/^\s*skip\s*=\s*(.*)/i) {
2257c478bd9Sstevel@tonic-gate			$skip = $1;
2267c478bd9Sstevel@tonic-gate		}
2277c478bd9Sstevel@tonic-gate		elsif (/^\s*syscall\s*=\s*(.*)/i) {
2287c478bd9Sstevel@tonic-gate			$callName = $1;
2297c478bd9Sstevel@tonic-gate		}
2307c478bd9Sstevel@tonic-gate		elsif (/^\s*program\s*=\s*(.*)/i) {
2317c478bd9Sstevel@tonic-gate			$callName = $1;
2327c478bd9Sstevel@tonic-gate		}
2337c478bd9Sstevel@tonic-gate		elsif (/^\s*title\s*=\s*(.*)/i) {
2347c478bd9Sstevel@tonic-gate			$title = $1;
2357c478bd9Sstevel@tonic-gate		}
2367c478bd9Sstevel@tonic-gate		elsif (/^\s*see\s*=\s*(.*)/i) {
2377c478bd9Sstevel@tonic-gate			$description = $1;
2387c478bd9Sstevel@tonic-gate		}
2397c478bd9Sstevel@tonic-gate		elsif (/^\s*format\s*=\s*(.*)/i) {
2407c478bd9Sstevel@tonic-gate			$format = $1;
241*32a06bbaSJan Friedel			$lastAttr = chkBslash("format", \$1);
2427c478bd9Sstevel@tonic-gate		}
2437c478bd9Sstevel@tonic-gate		elsif (/^\s*comment\s*=\s*(.*)/i) {
2447c478bd9Sstevel@tonic-gate			$comment .= $1;
245*32a06bbaSJan Friedel			$lastAttr = chkBslash("comment", \$1);
2467c478bd9Sstevel@tonic-gate		}
2477c478bd9Sstevel@tonic-gate		elsif (/^\s*note\s*=\s*(.*)/i) {
2487c478bd9Sstevel@tonic-gate			$note .= $1;
249*32a06bbaSJan Friedel			$lastAttr = chkBslash("note", \$1);
2507c478bd9Sstevel@tonic-gate		}
2517c478bd9Sstevel@tonic-gate		elsif (/^\s*case\s*=\s*(.*)/i) {
2527c478bd9Sstevel@tonic-gate			if ($caseState) {
2537c478bd9Sstevel@tonic-gate				push(@case, [$case, $format, $comment, $note]);
2547c478bd9Sstevel@tonic-gate				$format = 'none';
2557c478bd9Sstevel@tonic-gate				$comment = $note = '';
2567c478bd9Sstevel@tonic-gate			}
2577c478bd9Sstevel@tonic-gate			$case = $1;
258*32a06bbaSJan Friedel			$lastAttr = chkBslash("case", \$1);
2597c478bd9Sstevel@tonic-gate			$caseState = 1;
2607c478bd9Sstevel@tonic-gate		}
2617c478bd9Sstevel@tonic-gate	}
2627c478bd9Sstevel@tonic-gate	if ($attrState) {
2637c478bd9Sstevel@tonic-gate		$callName = $obj->filterCallName($label, $callName);
2647c478bd9Sstevel@tonic-gate		push(@case, [$case, $format, $comment, $note]);
2657c478bd9Sstevel@tonic-gate		if ($obj->filterLabel($label)) {
2667c478bd9Sstevel@tonic-gate			$attr{$label} = [$callName, $description, $title, $skip,
2677c478bd9Sstevel@tonic-gate			    @case];
2687c478bd9Sstevel@tonic-gate			$count++;
2697c478bd9Sstevel@tonic-gate		}
2707c478bd9Sstevel@tonic-gate	}
2717c478bd9Sstevel@tonic-gate	close $fileHandle;
2727c478bd9Sstevel@tonic-gate	print STDERR "found $count audit attribute entries\n" if ($obj->{'debug'});
2737c478bd9Sstevel@tonic-gate
2747c478bd9Sstevel@tonic-gate	return ($obj->{'attr'} = \%attr, \%token, \%skipClass, \%noteAlias);
2757c478bd9Sstevel@tonic-gate}
2767c478bd9Sstevel@tonic-gate
2777c478bd9Sstevel@tonic-gate# readEvent
2787c478bd9Sstevel@tonic-gate# read eventFile and extract audit event information, including
2797c478bd9Sstevel@tonic-gate# which classes are associated with each event and what call is
2807c478bd9Sstevel@tonic-gate# related.
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gatesub readEvent {
2837c478bd9Sstevel@tonic-gate	my $obj = shift;
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate	my %event = ();
2867c478bd9Sstevel@tonic-gate	my $file = $obj->{'eventFile'};
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate	my $fileHandle = do {local *FileHandle; *FileHandle};
2897c478bd9Sstevel@tonic-gate	open($fileHandle, $file) or die sprintf("$failedOpen\n", $file, $!);
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gate	my $count = 0;
2927c478bd9Sstevel@tonic-gate
29387e895dbStz	unless (defined $obj->{'class'} && (scalar keys %{$obj->{'class'}} > 1)) {
29487e895dbStz		$obj->readClass();
29587e895dbStz	}
29687e895dbStz
29787e895dbStz	my @classFilterMasks = ();
2987c478bd9Sstevel@tonic-gate	my $classFilter = $obj->{'classFilter'};
2997c478bd9Sstevel@tonic-gate	if ($classFilter) {
30087e895dbStz		foreach (split(',', $classFilter)) {
30187e895dbStz			push @classFilterMasks, $obj->{'class'}{$_};
30287e895dbStz		}
3037c478bd9Sstevel@tonic-gate	}
3047c478bd9Sstevel@tonic-gate	# ignore customer-supplied audit events (id > 32767)
3057c478bd9Sstevel@tonic-gate
3067c478bd9Sstevel@tonic-gate	while (<$fileHandle>) {
3077c478bd9Sstevel@tonic-gate		chomp;
3087c478bd9Sstevel@tonic-gate		s/#.*//;	# remove comment
3097c478bd9Sstevel@tonic-gate		next if (/^\s*$/);
3107c478bd9Sstevel@tonic-gate		if (/^\s*(\d+):(\w+):([^:]+):(.*)/) {
3117c478bd9Sstevel@tonic-gate			my $id = $1;
3127c478bd9Sstevel@tonic-gate			my $label = $2;
3137c478bd9Sstevel@tonic-gate			my $description = $3;
3147c478bd9Sstevel@tonic-gate			my $class = $4;
3157c478bd9Sstevel@tonic-gate
3167c478bd9Sstevel@tonic-gate			if ($id !~ /\d+/) {
3177c478bd9Sstevel@tonic-gate				print STDERR "$id is not numeric (line $.)\n";
3187c478bd9Sstevel@tonic-gate				next;
3197c478bd9Sstevel@tonic-gate			}
3207c478bd9Sstevel@tonic-gate			next if ($id > 32767);
3217c478bd9Sstevel@tonic-gate
3227c478bd9Sstevel@tonic-gate			$class =~ s/\s*$//;
3237c478bd9Sstevel@tonic-gate
3247c478bd9Sstevel@tonic-gate			if ($obj->{'debug'}) {
3257c478bd9Sstevel@tonic-gate				print STDERR qq{
3267c478bd9Sstevel@tonic-gate$label is duplicated in the event file (line $.)
3277c478bd9Sstevel@tonic-gate				} if ($event{$label});
3287c478bd9Sstevel@tonic-gate			}
3297c478bd9Sstevel@tonic-gate			next unless ($obj->filterLabel($label));
33087e895dbStz			my $mask = 0;
3317c478bd9Sstevel@tonic-gate			if ($classFilter) {
33287e895dbStz				foreach (split(/\s*,\s*/, $class)) {
33387e895dbStz					$mask |= $obj->{'class'}{$_};
33487e895dbStz				}
33587e895dbStz				my $skip = 0;
33687e895dbStz				foreach my $filterMask (@classFilterMasks) {
33787e895dbStz					unless ($mask & $filterMask) {
33887e895dbStz						$skip = 1;
33987e895dbStz						last;
34087e895dbStz					}
34187e895dbStz				}
34287e895dbStz				next if $skip;
3437c478bd9Sstevel@tonic-gate			}
3447c478bd9Sstevel@tonic-gate			if ($obj->{'idFilter'}) {
3457c478bd9Sstevel@tonic-gate				next unless ($obj->{'idFilter'} == $id);
3467c478bd9Sstevel@tonic-gate			}
3477c478bd9Sstevel@tonic-gate			$event{$label} = [$id, $class, $description];
3487c478bd9Sstevel@tonic-gate
3497c478bd9Sstevel@tonic-gate			$count++;
3507c478bd9Sstevel@tonic-gate		}
3517c478bd9Sstevel@tonic-gate	}
3527c478bd9Sstevel@tonic-gate	close $fileHandle;
3537c478bd9Sstevel@tonic-gate	print STDERR "found $count audit events\n" if ($obj->{'debug'});
3547c478bd9Sstevel@tonic-gate
3557c478bd9Sstevel@tonic-gate	return ($obj->{'event'} = \%event);
3567c478bd9Sstevel@tonic-gate}
3577c478bd9Sstevel@tonic-gate
3587c478bd9Sstevel@tonic-gate# readClass
3597c478bd9Sstevel@tonic-gate# read classFile and extract audit class information
3607c478bd9Sstevel@tonic-gate
3617c478bd9Sstevel@tonic-gatesub readClass {
3627c478bd9Sstevel@tonic-gate	my $obj = shift;
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate	my %class = ();
3657c478bd9Sstevel@tonic-gate	my $file = $obj->{'classFile'};
3667c478bd9Sstevel@tonic-gate
3677c478bd9Sstevel@tonic-gate	my $fileHandle = do {local *FileHandle; *FileHandle};
3687c478bd9Sstevel@tonic-gate	open($fileHandle, $file) or die sprintf("$failedOpen\n", $file, $!);
3697c478bd9Sstevel@tonic-gate
3707c478bd9Sstevel@tonic-gate	my $count = 0;
3717c478bd9Sstevel@tonic-gate
3727c478bd9Sstevel@tonic-gate	while (<$fileHandle>) {
3737c478bd9Sstevel@tonic-gate		chomp;
3747c478bd9Sstevel@tonic-gate		s/#.*//;	# remove comment
3757c478bd9Sstevel@tonic-gate		next if (/^\s*$/);
3767c478bd9Sstevel@tonic-gate		my ($mask1, $class) = split(/:/);  # third field not used
3777c478bd9Sstevel@tonic-gate		my $mask2 = hex($mask1);  # integer
3787c478bd9Sstevel@tonic-gate		$class{$class} = $mask2;
3797c478bd9Sstevel@tonic-gate		$count++;
3807c478bd9Sstevel@tonic-gate	}
3817c478bd9Sstevel@tonic-gate	close $fileHandle;
3827c478bd9Sstevel@tonic-gate	print STDERR "found $count audit classes\n" if ($obj->{'debug'});
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate	return ($obj->{'class'} = \%class);
3857c478bd9Sstevel@tonic-gate}
3867c478bd9Sstevel@tonic-gate
3877c478bd9Sstevel@tonic-gatesub filterLabel {
3887c478bd9Sstevel@tonic-gate	my $obj = shift;
3897c478bd9Sstevel@tonic-gate	my $label = shift;
3907c478bd9Sstevel@tonic-gate
3917c478bd9Sstevel@tonic-gate	my $eventFilter = $obj->{'eventFilter'};
3927c478bd9Sstevel@tonic-gate	my $keepIt = 1;
3937c478bd9Sstevel@tonic-gate
3947c478bd9Sstevel@tonic-gate	$keepIt = 0 if ($eventFilter && ($label !~ /$eventFilter/i));
3957c478bd9Sstevel@tonic-gate
3967c478bd9Sstevel@tonic-gate	return ($keepIt);
3977c478bd9Sstevel@tonic-gate}
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate# Normally, the root of the event label is the system call.  The
4007c478bd9Sstevel@tonic-gate# attrFile attribute syscall or program overrides this.
4017c478bd9Sstevel@tonic-gate
4027c478bd9Sstevel@tonic-gatesub filterCallName {
4037c478bd9Sstevel@tonic-gate	my $obj = shift;
4047c478bd9Sstevel@tonic-gate	my $label = shift;
4057c478bd9Sstevel@tonic-gate	my $callName = shift;
4067c478bd9Sstevel@tonic-gate
4077c478bd9Sstevel@tonic-gate	return ($callName) if ($callName);
4087c478bd9Sstevel@tonic-gate
4097c478bd9Sstevel@tonic-gate	$label =~ /AUE_(.*)/;
4107c478bd9Sstevel@tonic-gate
4117c478bd9Sstevel@tonic-gate	my $name = $1;
4127c478bd9Sstevel@tonic-gate
4137c478bd9Sstevel@tonic-gate	return (lc ($name));
4147c478bd9Sstevel@tonic-gate}
4157c478bd9Sstevel@tonic-gate
4167c478bd9Sstevel@tonic-gate# readControl
4177c478bd9Sstevel@tonic-gate# read controlFile and extract flags and naflags information
4187c478bd9Sstevel@tonic-gate# at present, minfree, maxfree and the audit partitions are not
4197c478bd9Sstevel@tonic-gate# checked.
4207c478bd9Sstevel@tonic-gate
4217c478bd9Sstevel@tonic-gatesub readControl {
4227c478bd9Sstevel@tonic-gate	my $obj = shift;
4237c478bd9Sstevel@tonic-gate	my $failMode = shift;
4247c478bd9Sstevel@tonic-gate
4257c478bd9Sstevel@tonic-gate	my $cError = 0;
4267c478bd9Sstevel@tonic-gate	my $errors = '';
4277c478bd9Sstevel@tonic-gate	my $file = $obj->{'controlFile'};
4287c478bd9Sstevel@tonic-gate	my $invalidClass = gettext('invalid class, %s, in audit_control: %s');
4297c478bd9Sstevel@tonic-gate
4307c478bd9Sstevel@tonic-gate	my $fileHandle = do {local *FileHandle; *FileHandle};
4317c478bd9Sstevel@tonic-gate	unless (open($fileHandle, $file)) {
4327c478bd9Sstevel@tonic-gate		die sprintf("$failedOpen\n", $file, $!)
4337c478bd9Sstevel@tonic-gate			unless ($failMode eq 'ignore');
4347c478bd9Sstevel@tonic-gate		return (0, '');
4357c478bd9Sstevel@tonic-gate	}
4367c478bd9Sstevel@tonic-gate	my %class = $obj->{'class'};
4377c478bd9Sstevel@tonic-gate	my @paths = $obj->{'paths'};
4387c478bd9Sstevel@tonic-gate	while (<$fileHandle>) {
4397c478bd9Sstevel@tonic-gate		chomp;
4407c478bd9Sstevel@tonic-gate		s/#.*//;	# remove comment
4417c478bd9Sstevel@tonic-gate		next if (/^\s*$/);
4427c478bd9Sstevel@tonic-gate		if ((/^\s*flags:/i) || (/^\s*naflags:/i)) {
4437c478bd9Sstevel@tonic-gate			my ($class) = /flags:\s*(.*)/;
4447c478bd9Sstevel@tonic-gate			my @class = split(/\s*,\s*/, $class);
4457c478bd9Sstevel@tonic-gate
4467c478bd9Sstevel@tonic-gate			foreach $class (@class) {
44787e895dbStz				$class =~ s/^[-+^]+//;
4487c478bd9Sstevel@tonic-gate				unless (defined ($class{$class})) {
4497c478bd9Sstevel@tonic-gate					$errors .=
4507c478bd9Sstevel@tonic-gate					    sprintf("$invalidClass\n",
4517c478bd9Sstevel@tonic-gate					    $class, $_);
4527c478bd9Sstevel@tonic-gate					$cError++;
4537c478bd9Sstevel@tonic-gate				}
4547c478bd9Sstevel@tonic-gate			}
4557c478bd9Sstevel@tonic-gate		}
4567c478bd9Sstevel@tonic-gate		elsif (/^\s*dir:\s*(.*)/) {
4577c478bd9Sstevel@tonic-gate			push (@paths, $1);
4587c478bd9Sstevel@tonic-gate			$obj->{'havePath'} = 1;
4597c478bd9Sstevel@tonic-gate		}
4607c478bd9Sstevel@tonic-gate	}
4617c478bd9Sstevel@tonic-gate	close $fileHandle;
4627c478bd9Sstevel@tonic-gate	return ($cError, $errors);
4637c478bd9Sstevel@tonic-gate}
4647c478bd9Sstevel@tonic-gate
4657c478bd9Sstevel@tonic-gatesub getPathList {
4667c478bd9Sstevel@tonic-gate	my $obj = shift;
4677c478bd9Sstevel@tonic-gate
4687c478bd9Sstevel@tonic-gate	$obj->readControl() unless ($obj->{'havePath'});
4697c478bd9Sstevel@tonic-gate
4707c478bd9Sstevel@tonic-gate	return ($obj->{'paths'});
4717c478bd9Sstevel@tonic-gate}
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate# readUser
4747c478bd9Sstevel@tonic-gate# read userFile and extract audit information for validation
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gatesub readUser {
4777c478bd9Sstevel@tonic-gate	my $obj = shift;
4787c478bd9Sstevel@tonic-gate	my $failMode = shift;
4797c478bd9Sstevel@tonic-gate
4807c478bd9Sstevel@tonic-gate	my $cError = 0;
4817c478bd9Sstevel@tonic-gate	my $error = '';
4827c478bd9Sstevel@tonic-gate	my $file = $obj->{'userFile'};
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate	my $fileHandle = do {local *FileHandle; *FileHandle};
4857c478bd9Sstevel@tonic-gate	unless (open($fileHandle, $file)) {
4867c478bd9Sstevel@tonic-gate		die sprintf("$failedOpen\n", $file, $!)
4877c478bd9Sstevel@tonic-gate			unless ($failMode eq 'ignore');
4887c478bd9Sstevel@tonic-gate		return (0, '');
4897c478bd9Sstevel@tonic-gate	}
4907c478bd9Sstevel@tonic-gate	# these strings are defined here mostly to avoid indentation problems
4917c478bd9Sstevel@tonic-gate	my $emptyErr   = gettext('empty audit mask in audit_user: %s');
4927c478bd9Sstevel@tonic-gate	my $syntaxErr1 = gettext(
4937c478bd9Sstevel@tonic-gate	    'incorrect syntax (exactly two colons req\'d) in audit_user: %s');
4947c478bd9Sstevel@tonic-gate	my $syntaxErr2 = gettext('incorrect syntax in audit_user: %s');
4957c478bd9Sstevel@tonic-gate	my $invalidErr = gettext('invalid class, %s, in audit_user: %s');
4967c478bd9Sstevel@tonic-gate	my $undefined  = gettext('undefined user name in audit_user: %s');
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate	my %class = $obj->{'class'};
4997c478bd9Sstevel@tonic-gate	while (<$fileHandle>) {
5007c478bd9Sstevel@tonic-gate		chomp;
5017c478bd9Sstevel@tonic-gate		s/#.*//;        # remove comment
5027c478bd9Sstevel@tonic-gate		next if (/^\s*$/);
5037c478bd9Sstevel@tonic-gate		my $colonCount = tr/:/:/;
5047c478bd9Sstevel@tonic-gate
5057c478bd9Sstevel@tonic-gate		if ($colonCount != 2) {
5067c478bd9Sstevel@tonic-gate			$error .= sprintf("$syntaxErr1\n", $_);
5077c478bd9Sstevel@tonic-gate			$cError++;
5087c478bd9Sstevel@tonic-gate		}
5097c478bd9Sstevel@tonic-gate		my ($user, $always, $never) = split(/\s*:\s*/);
5107c478bd9Sstevel@tonic-gate		unless (defined($user)) {
5117c478bd9Sstevel@tonic-gate			$error .= sprintf("$syntaxErr2\n", $_);
5127c478bd9Sstevel@tonic-gate			$cError++;
5137c478bd9Sstevel@tonic-gate			next;
5147c478bd9Sstevel@tonic-gate		}
5157c478bd9Sstevel@tonic-gate		$error .= sprintf("$emptyErr\n", $_) unless ($always);
5167c478bd9Sstevel@tonic-gate
5177c478bd9Sstevel@tonic-gate		my ($name) = getpwnam($user);
5187c478bd9Sstevel@tonic-gate		unless (defined($name)) {
5197c478bd9Sstevel@tonic-gate			$error .= sprintf("$undefined\n", $user);
5207c478bd9Sstevel@tonic-gate			$cError++;
5217c478bd9Sstevel@tonic-gate		}
5227c478bd9Sstevel@tonic-gate		unless (defined($always) && defined($never)) {
5237c478bd9Sstevel@tonic-gate			$error .= sprintf("$emptyErr\n", $_);
5247c478bd9Sstevel@tonic-gate			$cError++;
5257c478bd9Sstevel@tonic-gate			next;
5267c478bd9Sstevel@tonic-gate		}
5277c478bd9Sstevel@tonic-gate		my $verify = $always . ',' . $never;
5287c478bd9Sstevel@tonic-gate		my @class = split(/\s*,\s*/, $verify);
5297c478bd9Sstevel@tonic-gate		my $thisClass;
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate		foreach $thisClass (@class) {
53287e895dbStz			$thisClass =~ s/^[-+^]+//;
5337c478bd9Sstevel@tonic-gate			unless (defined $class{$thisClass}) {
5347c478bd9Sstevel@tonic-gate				$error .= sprintf("$invalidErr\n", $thisClass,
5357c478bd9Sstevel@tonic-gate				    $_);
5367c478bd9Sstevel@tonic-gate				$cError++;
5377c478bd9Sstevel@tonic-gate			}
5387c478bd9Sstevel@tonic-gate		}
5397c478bd9Sstevel@tonic-gate	}
5407c478bd9Sstevel@tonic-gate	close $fileHandle;
5417c478bd9Sstevel@tonic-gate	return ($cError, $error);
5427c478bd9Sstevel@tonic-gate}
5437c478bd9Sstevel@tonic-gate
5447c478bd9Sstevel@tonic-gate# ckAttrEvent complains if controlFile and attrFile don''t contain the
5457c478bd9Sstevel@tonic-gate# same list of events.
5467c478bd9Sstevel@tonic-gate
5477c478bd9Sstevel@tonic-gatesub ckAttrEvent {
5487c478bd9Sstevel@tonic-gate	my $obj = shift;
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate	my $cError = 0;
5517c478bd9Sstevel@tonic-gate	my $error = '';
5527c478bd9Sstevel@tonic-gate	my $cAttr = 0;
5537c478bd9Sstevel@tonic-gate	my $label;
5547c478bd9Sstevel@tonic-gate	my $attrErr  = gettext(
5557c478bd9Sstevel@tonic-gate	    '%s entry in attribute file but not in event file');
5567c478bd9Sstevel@tonic-gate	my $eventErr = gettext(
5577c478bd9Sstevel@tonic-gate	    '%s entry in event file but not in attribute file');
5587c478bd9Sstevel@tonic-gate
5597c478bd9Sstevel@tonic-gate	my %attr = %{$obj->{'attr'}};
5607c478bd9Sstevel@tonic-gate	my %event = %{$obj->{'event'}};
5617c478bd9Sstevel@tonic-gate	foreach $label (keys %attr) {
5627c478bd9Sstevel@tonic-gate		$cAttr++;
5637c478bd9Sstevel@tonic-gate		unless ($event{$label}) {
5647c478bd9Sstevel@tonic-gate			$error .= sprintf("$attrErr\n", $label);
5657c478bd9Sstevel@tonic-gate			$cError++;
5667c478bd9Sstevel@tonic-gate		}
5677c478bd9Sstevel@tonic-gate	}
5687c478bd9Sstevel@tonic-gate	my $cEvent = 0;
5697c478bd9Sstevel@tonic-gate	foreach $label (keys %event) {
5707c478bd9Sstevel@tonic-gate		$cEvent++;
5717c478bd9Sstevel@tonic-gate		unless ($attr{$label}) {
5727c478bd9Sstevel@tonic-gate			$error .= sprintf("$eventErr\n", $label);
5737c478bd9Sstevel@tonic-gate			$cError++;
5747c478bd9Sstevel@tonic-gate		}
5757c478bd9Sstevel@tonic-gate	}
5767c478bd9Sstevel@tonic-gate	# debug only; not I18N'd
5777c478bd9Sstevel@tonic-gate	print STDERR
5787c478bd9Sstevel@tonic-gate	    "$cAttr audit_record_attr entries and $cEvent audit_event entries\n"
5797c478bd9Sstevel@tonic-gate		if ($obj->{'debug'});
5807c478bd9Sstevel@tonic-gate	return ($cError, $error);
5817c478bd9Sstevel@tonic-gate}
5827c478bd9Sstevel@tonic-gate
583*32a06bbaSJan Friedel# chkBslash (helper)
584*32a06bbaSJan Friedel# check the given string for backslash character at the end; if found
585*32a06bbaSJan Friedel# return the string sent as a first argument, otherwise return empty
586*32a06bbaSJan Friedel# string.
587*32a06bbaSJan Friedelsub chkBslash ($$) {
588*32a06bbaSJan Friedel	my $retStr = shift;
589*32a06bbaSJan Friedel	my $strPtr = shift;
590*32a06bbaSJan Friedel
591*32a06bbaSJan Friedel	if ( $$strPtr !~ /\\$/ ) {
592*32a06bbaSJan Friedel		 $retStr = '';
593*32a06bbaSJan Friedel	}
594*32a06bbaSJan Friedel
595*32a06bbaSJan Friedel	return $retStr;
596*32a06bbaSJan Friedel}
597*32a06bbaSJan Friedel
5987c478bd9Sstevel@tonic-gate1;
599