17c478bd9Sstevel@tonic-gate#!/usr/perl5/bin/perl
27c478bd9Sstevel@tonic-gate#
37c478bd9Sstevel@tonic-gate# CDDL HEADER START
47c478bd9Sstevel@tonic-gate#
57c478bd9Sstevel@tonic-gate# The contents of this file are subject to the terms of the
687e895dbStz# Common Development and Distribution License (the "License").
787e895dbStz# You may not use this file except in compliance with the License.
87c478bd9Sstevel@tonic-gate#
97c478bd9Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate# See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate# and limitations under the License.
137c478bd9Sstevel@tonic-gate#
147c478bd9Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate#
207c478bd9Sstevel@tonic-gate# CDDL HEADER END
217c478bd9Sstevel@tonic-gate#
227c478bd9Sstevel@tonic-gate#
23*cf9691b9Sgww# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate# Use is subject to license terms.
257c478bd9Sstevel@tonic-gate#
267c478bd9Sstevel@tonic-gate
27*cf9691b9Sgww# auditrecord - display one or more audit records
287c478bd9Sstevel@tonic-gate
29df0345f7SJohn Sonnenscheinrequire 5.8.4;
307c478bd9Sstevel@tonic-gateuse strict;
317c478bd9Sstevel@tonic-gateuse warnings;
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gateour (%opt, $parse, $callFilter, $debug,
347c478bd9Sstevel@tonic-gate    %attr, %event, %class, %skipClass, %token, %noteAlias,
357c478bd9Sstevel@tonic-gate    $title, $note, $name, $col1, $col2, $col3, $skip);
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gateuse Getopt::Std;
387c478bd9Sstevel@tonic-gateuse locale;
397c478bd9Sstevel@tonic-gateuse POSIX qw(locale_h);
407c478bd9Sstevel@tonic-gateuse Sun::Solaris::Utils qw(gettext textdomain);
417c478bd9Sstevel@tonic-gateuse Sun::Solaris::BSM::_BSMparse;
427c478bd9Sstevel@tonic-gate
437c478bd9Sstevel@tonic-gatesetlocale(LC_ALL, "");
447c478bd9Sstevel@tonic-gatetextdomain(TEXT_DOMAIN);
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gateif (!getopts('adhe:c:i:p:s:', \%opt) || @ARGV) {
477c478bd9Sstevel@tonic-gate	my $errString =
487c478bd9Sstevel@tonic-gate	    gettext("$0 takes no arguments other than switches.\n");
497c478bd9Sstevel@tonic-gate	print STDERR $errString if (@ARGV);
507c478bd9Sstevel@tonic-gate	usage();
517c478bd9Sstevel@tonic-gate	exit (1);
527c478bd9Sstevel@tonic-gate}
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gateunless ($opt{a} || $opt{c} || $opt{e} || $opt{h} || $opt{i} ||
557c478bd9Sstevel@tonic-gate	$opt{p} || $opt{s}) {
567c478bd9Sstevel@tonic-gate	usage();
577c478bd9Sstevel@tonic-gate	exit (1);
587c478bd9Sstevel@tonic-gate}
597c478bd9Sstevel@tonic-gate
607c478bd9Sstevel@tonic-gatemy %options;
617c478bd9Sstevel@tonic-gate$options{'classFilter'} = $opt{c};   # filter on this class
627c478bd9Sstevel@tonic-gate$debug			= $opt{d};   # debug mode on
637c478bd9Sstevel@tonic-gate$options{'eventFilter'} = $opt{e};   # filter on this event
647c478bd9Sstevel@tonic-gatemy $html		= $opt{h};   # output in html format
657c478bd9Sstevel@tonic-gate$options{'idFilter'}	= $opt{i};   # filter on this id
667c478bd9Sstevel@tonic-gate$callFilter		= $opt{p};   # filter on this program name
677c478bd9Sstevel@tonic-gate$callFilter		= $opt{s} if ($opt{s}); # filter on this system call
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gateif (defined($callFilter)) {
707c478bd9Sstevel@tonic-gate	$callFilter = qr/\b$callFilter\b/;
717c478bd9Sstevel@tonic-gate} else {
727c478bd9Sstevel@tonic-gate	$callFilter = qr//;
737c478bd9Sstevel@tonic-gate}
747c478bd9Sstevel@tonic-gate$parse = new Sun::Solaris::BSM::_BSMparse($debug, \%options);
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gatemy ($attr, $token, $skipClass, $noteAlias) = $parse->readAttr();
777c478bd9Sstevel@tonic-gate%attr  = %$attr;
787c478bd9Sstevel@tonic-gate%token = %$token;
797c478bd9Sstevel@tonic-gate%noteAlias = %$noteAlias;
807c478bd9Sstevel@tonic-gate%skipClass = %$skipClass;
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gate%class = %{$parse->readClass()};
837c478bd9Sstevel@tonic-gate%event = %{$parse->readEvent()};
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate# the calls to readControl and readUser are for debug; they are not
867c478bd9Sstevel@tonic-gate# needed for generation of record formats.  'ignore' means if there
877c478bd9Sstevel@tonic-gate# is no permission to read the file, don't die, just soldier on.
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate# $error is L10N'd by $parse
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gateif ($debug) {
927c478bd9Sstevel@tonic-gate	my ($cnt, $error);
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate	# verify audit_control content
957c478bd9Sstevel@tonic-gate	($cnt, $error) = $parse->readControl('ignore');
967c478bd9Sstevel@tonic-gate	print STDERR $error if ($cnt);
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate	# verify audit_user content
997c478bd9Sstevel@tonic-gate	($cnt, $error) = $parse->readUser('ignore');
1007c478bd9Sstevel@tonic-gate	print STDERR $error if ($cnt);
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate	# check audit_event, audit_display_attr
1037c478bd9Sstevel@tonic-gate	($cnt, $error) = $parse->ckAttrEvent();
1047c478bd9Sstevel@tonic-gate	print STDERR $error if ($cnt);
1057c478bd9Sstevel@tonic-gate}
1067c478bd9Sstevel@tonic-gate
10787e895dbStz# check for invalid class to -c option if supplied
10887e895dbStzif (defined $options{'classFilter'}) {
10987e895dbStz	my $invalidClass = gettext('Invalid class %s supplied.');
11087e895dbStz	my $isInvalidClass = 0;
11187e895dbStz	foreach (split(/\s*,\s*/, $options{'classFilter'})) {
11287e895dbStz		unless (exists $class{$_}) {
11387e895dbStz			printf STDERR "$invalidClass\n", $_;
11487e895dbStz			$isInvalidClass = 1;
11587e895dbStz		}
11687e895dbStz	}
11787e895dbStz	exit (1) if $isInvalidClass;
11887e895dbStz}
11987e895dbStz
1207c478bd9Sstevel@tonic-gateif ($html) {
1217c478bd9Sstevel@tonic-gate	writeHTML();
1227c478bd9Sstevel@tonic-gate} else {
1237c478bd9Sstevel@tonic-gate	writeASCII();
1247c478bd9Sstevel@tonic-gate}
1257c478bd9Sstevel@tonic-gate
1267c478bd9Sstevel@tonic-gateexit (0);
1277c478bd9Sstevel@tonic-gate
1287c478bd9Sstevel@tonic-gate# writeASCII -- collect what's been read from various sources and
1297c478bd9Sstevel@tonic-gate# output the formatted audit records
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gatesub writeASCII {
1327c478bd9Sstevel@tonic-gate	my $label;
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate	my $errString;
1357c478bd9Sstevel@tonic-gate
1367c478bd9Sstevel@tonic-gate	foreach $label (sort(keys(%event))) {
1377c478bd9Sstevel@tonic-gate		my $description;
1387c478bd9Sstevel@tonic-gate		my @case;
1397c478bd9Sstevel@tonic-gate
1407c478bd9Sstevel@tonic-gate		my ($id, $class, $eventDescription) = @{$event{$label}};
1417c478bd9Sstevel@tonic-gate
1427c478bd9Sstevel@tonic-gate		our ($title, $note, $name, $col1, $col2, $col3);
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate		my ($skipThisClass, $mask) = classToMask($class, $label);
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate		next if ($skipThisClass);
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate		$mask = sprintf("0x%08X", $mask);
1497c478bd9Sstevel@tonic-gate
1507c478bd9Sstevel@tonic-gate		($name, $description, $title, $skip, @case) =
1517c478bd9Sstevel@tonic-gate			getAttributes($label, $eventDescription);
1527c478bd9Sstevel@tonic-gate
1537c478bd9Sstevel@tonic-gate		next if ($name eq 'undefined');
1547c478bd9Sstevel@tonic-gate
1557c478bd9Sstevel@tonic-gate		next unless $description =~ $callFilter;
1567c478bd9Sstevel@tonic-gate
1577c478bd9Sstevel@tonic-gate		$~ = 'nameLine';
1587c478bd9Sstevel@tonic-gate		write;
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate		$note = $skip;
1617c478bd9Sstevel@tonic-gate		$~ = 'wrapped1';
1627c478bd9Sstevel@tonic-gate		while ($note) {
1637c478bd9Sstevel@tonic-gate			write;
1647c478bd9Sstevel@tonic-gate		}
1657c478bd9Sstevel@tonic-gate		next if ($skip);
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate		$~ = 'threeColumns';
1687c478bd9Sstevel@tonic-gate		($col1, $col2, $col3) = getCallInfo($id, $name, $description);
1697c478bd9Sstevel@tonic-gate		my @col1 = split(/\s*;\s*/, $col1);
1707c478bd9Sstevel@tonic-gate		my @col2 = split(/\s*;\s*/, $col2);
1717c478bd9Sstevel@tonic-gate		my @col3 = split(/\s*;\s*/, $col3);
1727c478bd9Sstevel@tonic-gate		my $rows = $#col1;
1737c478bd9Sstevel@tonic-gate		$rows = $#col2 if ($#col2 > $rows);
1747c478bd9Sstevel@tonic-gate		$rows = $#col3 if ($#col3 > $rows);
1757c478bd9Sstevel@tonic-gate		for (my $i = 0; $i <= $rows; $i++) {
1767c478bd9Sstevel@tonic-gate			$col1 = defined ($col1[$i]) ? $col1[$i] : '';
1777c478bd9Sstevel@tonic-gate			$col2 = defined ($col2[$i]) ? $col2[$i] : '';
1787c478bd9Sstevel@tonic-gate			$col3 = defined ($col3[$i]) ? 'See ' . $col3[$i] : '';
1797c478bd9Sstevel@tonic-gate			write;
1807c478bd9Sstevel@tonic-gate		}
1817c478bd9Sstevel@tonic-gate		$col1 = 'event ID';
1827c478bd9Sstevel@tonic-gate		$col2 = $id;
1837c478bd9Sstevel@tonic-gate		$col3 = $label;
1847c478bd9Sstevel@tonic-gate		write;
1857c478bd9Sstevel@tonic-gate
1867c478bd9Sstevel@tonic-gate		$col1 = 'class';
1877c478bd9Sstevel@tonic-gate		$col2 = $class;
1887c478bd9Sstevel@tonic-gate		$col3 = "($mask)";
1897c478bd9Sstevel@tonic-gate		write;
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate		my $haveFormat = 0;
1927c478bd9Sstevel@tonic-gate		my $caseElement;
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate		foreach $caseElement (@case) {
1957c478bd9Sstevel@tonic-gate			# $note1 is the "case" description
1967c478bd9Sstevel@tonic-gate			# $note2 is a "note"
1977c478bd9Sstevel@tonic-gate			my ($note1, $format, $comment, $note2) = @$caseElement;
1987c478bd9Sstevel@tonic-gate
1997c478bd9Sstevel@tonic-gate			$note = $note1;
2007c478bd9Sstevel@tonic-gate			$~ = 'wrapped1';
2017c478bd9Sstevel@tonic-gate			while ($note) {
2027c478bd9Sstevel@tonic-gate				write;
2037c478bd9Sstevel@tonic-gate			}
2047c478bd9Sstevel@tonic-gate			unless (defined($format)) {
2057c478bd9Sstevel@tonic-gate				$errString = gettext(
2067c478bd9Sstevel@tonic-gate				    "missing format field: %s");
2077c478bd9Sstevel@tonic-gate				printf STDERR ("$errString\n", $label);
2087c478bd9Sstevel@tonic-gate				next;
2097c478bd9Sstevel@tonic-gate			}
2107c478bd9Sstevel@tonic-gate			unless ($format eq 'none') {
2117c478bd9Sstevel@tonic-gate				$haveFormat = 1;
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate				my $list = getFormatList($format, $id);
2147c478bd9Sstevel@tonic-gate
2157c478bd9Sstevel@tonic-gate				my @format  = split(/\s*:\s*/, $list);
2167c478bd9Sstevel@tonic-gate				my @comment = split(/\s*:\s*/, $comment);
2177c478bd9Sstevel@tonic-gate
2187c478bd9Sstevel@tonic-gate				my $item;
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate				foreach $item (@format) {
2217c478bd9Sstevel@tonic-gate					$~ = 'twoColumns';
2227c478bd9Sstevel@tonic-gate					($col1, $col2) =
2237c478bd9Sstevel@tonic-gate					    getFormatLine($item, $label,
2247c478bd9Sstevel@tonic-gate					    @comment);
2257c478bd9Sstevel@tonic-gate					write;
2267c478bd9Sstevel@tonic-gate					$~ = "col2Wrapped";
2277c478bd9Sstevel@tonic-gate					while ($col2) {
2287c478bd9Sstevel@tonic-gate						write;
2297c478bd9Sstevel@tonic-gate					}
2307c478bd9Sstevel@tonic-gate				}
2317c478bd9Sstevel@tonic-gate			}
2327c478bd9Sstevel@tonic-gate			$note2 = $noteAlias{$note2} if ($noteAlias{$note2});
2337c478bd9Sstevel@tonic-gate			if ($note2) {
2347c478bd9Sstevel@tonic-gate				$note = $note2;
2357c478bd9Sstevel@tonic-gate				$~ = 'space';
2367c478bd9Sstevel@tonic-gate				write;
2377c478bd9Sstevel@tonic-gate				$~ = 'wrapped1';
2387c478bd9Sstevel@tonic-gate				while ($note) {
2397c478bd9Sstevel@tonic-gate					write;
2407c478bd9Sstevel@tonic-gate				}
2417c478bd9Sstevel@tonic-gate			}
2427c478bd9Sstevel@tonic-gate		}
2437c478bd9Sstevel@tonic-gate		unless ($haveFormat) {
2447c478bd9Sstevel@tonic-gate			$~ = 'wrapped1';
2457c478bd9Sstevel@tonic-gate			$note = gettext('No format information available');
2467c478bd9Sstevel@tonic-gate			write;
2477c478bd9Sstevel@tonic-gate		}
2487c478bd9Sstevel@tonic-gate	}
2497c478bd9Sstevel@tonic-gate}
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gate# writeHTML -- collect what's been read from various sources
2527c478bd9Sstevel@tonic-gate# and output the formatted audit records
2537c478bd9Sstevel@tonic-gate#
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gatesub writeHTML {
2567c478bd9Sstevel@tonic-gate	my $label;
2577c478bd9Sstevel@tonic-gate
2587c478bd9Sstevel@tonic-gate	my $description;
2597c478bd9Sstevel@tonic-gate	my @case;
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gate	my $docTitle = gettext("Audit Record Formats");
2627c478bd9Sstevel@tonic-gate
2637c478bd9Sstevel@tonic-gate	print qq{
2647c478bd9Sstevel@tonic-gate<!doctype html PUBLIC "-//IETF//DTD HTML//EN">
2657c478bd9Sstevel@tonic-gate<html>
2667c478bd9Sstevel@tonic-gate<head>
2677c478bd9Sstevel@tonic-gate  <title>$docTitle</title>
2687c478bd9Sstevel@tonic-gate  <META http-equiv="Content-Style-Type" content="text/css">
2697c478bd9Sstevel@tonic-gate</head>
2707c478bd9Sstevel@tonic-gate
2717c478bd9Sstevel@tonic-gate<body TEXT="#000000" BGCOLOR="#F0F0F0">
2727c478bd9Sstevel@tonic-gate	};
2737c478bd9Sstevel@tonic-gate
2747c478bd9Sstevel@tonic-gate	my $tableRows = 0;	# work around Netscape large table bug
2757c478bd9Sstevel@tonic-gate	startTable();		# by generating multiple tables
2767c478bd9Sstevel@tonic-gate
2777c478bd9Sstevel@tonic-gate	foreach $label (sort(keys(%event))) {
2787c478bd9Sstevel@tonic-gate		my ($id, $class, $eventDescription) = @{$event{$label}};
2797c478bd9Sstevel@tonic-gate
2807c478bd9Sstevel@tonic-gate		our ($title, $name, $note, $col1, $col2, $col3);
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate		my ($skipThisClass, $mask) = classToMask($class, $label);
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate		next if ($skipThisClass);
2857c478bd9Sstevel@tonic-gate
2867c478bd9Sstevel@tonic-gate		$mask = sprintf("0x%08X", $mask);
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate		my $description;
2897c478bd9Sstevel@tonic-gate
2907c478bd9Sstevel@tonic-gate		($name, $description, $title, $skip, @case) =
2917c478bd9Sstevel@tonic-gate			getAttributes($label, $eventDescription);
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate		next if ($name eq 'undefined');
2947c478bd9Sstevel@tonic-gate
2957c478bd9Sstevel@tonic-gate		next unless $description =~ $callFilter;
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate		$tableRows++;
2987c478bd9Sstevel@tonic-gate		if ($tableRows > 50) {
2997c478bd9Sstevel@tonic-gate			endTable();
3007c478bd9Sstevel@tonic-gate			startTable();
3017c478bd9Sstevel@tonic-gate			$tableRows = 0;
3027c478bd9Sstevel@tonic-gate		}
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate		my ($callType, $callName);
3057c478bd9Sstevel@tonic-gate		($callType, $callName, $description) =
3067c478bd9Sstevel@tonic-gate			getCallInfo($id, $name, $description);
3077c478bd9Sstevel@tonic-gate		$description =~ s/\s*;\s*/<br>/g;
3087c478bd9Sstevel@tonic-gate
3097c478bd9Sstevel@tonic-gate		my $titleName = $title;
3107c478bd9Sstevel@tonic-gate		if ($callName) {
3117c478bd9Sstevel@tonic-gate			$titleName = $callName;
3127c478bd9Sstevel@tonic-gate		}
3137c478bd9Sstevel@tonic-gate		$titleName =~ s/\s*;\s*/<br>/g;
3147c478bd9Sstevel@tonic-gate		$titleName = '&nbsp;' if ($titleName eq $title);
3157c478bd9Sstevel@tonic-gate
3167c478bd9Sstevel@tonic-gate		print qq{
3177c478bd9Sstevel@tonic-gate  <tr bgcolor="#C0C0C0">
3187c478bd9Sstevel@tonic-gate    <td>$label</td>
3197c478bd9Sstevel@tonic-gate    <td>$id</td>
3207c478bd9Sstevel@tonic-gate    <td>$class</td>
3217c478bd9Sstevel@tonic-gate    <td>$mask</td>
3227c478bd9Sstevel@tonic-gate  </tr>
3237c478bd9Sstevel@tonic-gate  <tr>
3247c478bd9Sstevel@tonic-gate    <td colspan=2>$titleName</td>
3257c478bd9Sstevel@tonic-gate    <td colspan=2>$description</td>
3267c478bd9Sstevel@tonic-gate  </tr>
3277c478bd9Sstevel@tonic-gate  <tr>
3287c478bd9Sstevel@tonic-gate    <td colspan=4>
3297c478bd9Sstevel@tonic-gate      <pre>
3307c478bd9Sstevel@tonic-gate};
3317c478bd9Sstevel@tonic-gate
3327c478bd9Sstevel@tonic-gate		$note = $skip;
3337c478bd9Sstevel@tonic-gate		$~ = 'wrapped2';
3347c478bd9Sstevel@tonic-gate		while ($note) {
3357c478bd9Sstevel@tonic-gate			write;
3367c478bd9Sstevel@tonic-gate		}
3377c478bd9Sstevel@tonic-gate		next if ($skip);
3387c478bd9Sstevel@tonic-gate
3397c478bd9Sstevel@tonic-gate		my $haveFormat = 0;
3407c478bd9Sstevel@tonic-gate		my $caseElement;
3417c478bd9Sstevel@tonic-gate
3427c478bd9Sstevel@tonic-gate		foreach $caseElement (@case) {
3437c478bd9Sstevel@tonic-gate			my ($note1, $format, $comment, $note2) = @$caseElement;
3447c478bd9Sstevel@tonic-gate
3457c478bd9Sstevel@tonic-gate			$note = $note1;
3467c478bd9Sstevel@tonic-gate			$~ = 'wrapped2';
3477c478bd9Sstevel@tonic-gate			while ($note) {
3487c478bd9Sstevel@tonic-gate				write;
3497c478bd9Sstevel@tonic-gate			}
3507c478bd9Sstevel@tonic-gate			unless (defined($format)) {
3517c478bd9Sstevel@tonic-gate				my $errString = gettext(
3527c478bd9Sstevel@tonic-gate				    "Missing format field: %s\n");
3537c478bd9Sstevel@tonic-gate				printf STDERR ($errString, $label);
3547c478bd9Sstevel@tonic-gate				next;
3557c478bd9Sstevel@tonic-gate			}
3567c478bd9Sstevel@tonic-gate			unless ($format eq 'none') {
3577c478bd9Sstevel@tonic-gate				$haveFormat = 1;
3587c478bd9Sstevel@tonic-gate
3597c478bd9Sstevel@tonic-gate				my $list = getFormatList($format, $id);
3607c478bd9Sstevel@tonic-gate
3617c478bd9Sstevel@tonic-gate				my @format  = split(/\s*:\s*/, $list);
3627c478bd9Sstevel@tonic-gate				my @comment = split(/\s*:\s*/, $comment);
3637c478bd9Sstevel@tonic-gate				my $item;
3647c478bd9Sstevel@tonic-gate
3657c478bd9Sstevel@tonic-gate				$~ = 'twoColumns';
3667c478bd9Sstevel@tonic-gate				foreach $item (@format) {
3677c478bd9Sstevel@tonic-gate					($col1, $col2) =
3687c478bd9Sstevel@tonic-gate					    getFormatLine($item, $label,
3697c478bd9Sstevel@tonic-gate					    @comment);
3707c478bd9Sstevel@tonic-gate					write;
3717c478bd9Sstevel@tonic-gate				}
3727c478bd9Sstevel@tonic-gate			}
3737c478bd9Sstevel@tonic-gate			if ($note2) {
3747c478bd9Sstevel@tonic-gate				$note2 = $noteAlias{$note2} if ($noteAlias{$note2});
3757c478bd9Sstevel@tonic-gate				$note = $note2;
3767c478bd9Sstevel@tonic-gate				$~ = 'space';
3777c478bd9Sstevel@tonic-gate				write;
3787c478bd9Sstevel@tonic-gate				$~ = 'wrapped2';
3797c478bd9Sstevel@tonic-gate				while ($note) {
3807c478bd9Sstevel@tonic-gate					write;
3817c478bd9Sstevel@tonic-gate				}
3827c478bd9Sstevel@tonic-gate			}
3837c478bd9Sstevel@tonic-gate		}
3847c478bd9Sstevel@tonic-gate		unless ($haveFormat) {
3857c478bd9Sstevel@tonic-gate			$~ = 'wrapped2';
3867c478bd9Sstevel@tonic-gate			$note = 'No format information available';
3877c478bd9Sstevel@tonic-gate			write;
3887c478bd9Sstevel@tonic-gate		}
3897c478bd9Sstevel@tonic-gate		print q{
3907c478bd9Sstevel@tonic-gate      </pre>
3917c478bd9Sstevel@tonic-gate    </td/>
3927c478bd9Sstevel@tonic-gate  </tr>
3937c478bd9Sstevel@tonic-gate		};
3947c478bd9Sstevel@tonic-gate	}
3957c478bd9Sstevel@tonic-gate	endTable();
3967c478bd9Sstevel@tonic-gate}
3977c478bd9Sstevel@tonic-gate
3987c478bd9Sstevel@tonic-gatesub startTable {
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate	print q{
4017c478bd9Sstevel@tonic-gate<table border=1>
4027c478bd9Sstevel@tonic-gate  <tr bgcolor="#C0C0C0">
4037c478bd9Sstevel@tonic-gate    <th>Event Name</th>
4047c478bd9Sstevel@tonic-gate    <th>Event ID</th>
4057c478bd9Sstevel@tonic-gate    <th>Event Class</th>
4067c478bd9Sstevel@tonic-gate    <th>Mask</th>
4077c478bd9Sstevel@tonic-gate  </tr>
4087c478bd9Sstevel@tonic-gate  <tr>
4097c478bd9Sstevel@tonic-gate    <th colspan=2>Call Name</th>
4107c478bd9Sstevel@tonic-gate    <th colspan=2>Reference</th>
4117c478bd9Sstevel@tonic-gate  <tr>
4127c478bd9Sstevel@tonic-gate  <tr>
4137c478bd9Sstevel@tonic-gate    <th colspan=4>Format</th>
4147c478bd9Sstevel@tonic-gate  </tr>
4157c478bd9Sstevel@tonic-gate	};
4167c478bd9Sstevel@tonic-gate}
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gatesub endTable {
4197c478bd9Sstevel@tonic-gate
4207c478bd9Sstevel@tonic-gate	print q{
4217c478bd9Sstevel@tonic-gate</table>
4227c478bd9Sstevel@tonic-gate</body>
4237c478bd9Sstevel@tonic-gate</html>
4247c478bd9Sstevel@tonic-gate	};
4257c478bd9Sstevel@tonic-gate}
4267c478bd9Sstevel@tonic-gate
4277c478bd9Sstevel@tonic-gate# classToMask: One, given a class list, it calculates the mask; Two,
4287c478bd9Sstevel@tonic-gate# it checks to see if every item on the class list is marked for
4297c478bd9Sstevel@tonic-gate# skipping, and if so, sets a flag.
4307c478bd9Sstevel@tonic-gate
4317c478bd9Sstevel@tonic-gatesub classToMask {
4327c478bd9Sstevel@tonic-gate	my $classList = shift;
4337c478bd9Sstevel@tonic-gate	my $label = shift;
4347c478bd9Sstevel@tonic-gate	my $mask = 0;
4357c478bd9Sstevel@tonic-gate
4367c478bd9Sstevel@tonic-gate	my @classes = split(/\s*,\s*/, $classList);
4377c478bd9Sstevel@tonic-gate	my $skipThisClass = 0;
4387c478bd9Sstevel@tonic-gate
4397c478bd9Sstevel@tonic-gate	my $thisClass;
4407c478bd9Sstevel@tonic-gate	foreach $thisClass (@classes) {
4417c478bd9Sstevel@tonic-gate		unless (defined($class{$thisClass})) {
4427c478bd9Sstevel@tonic-gate			my $errString = gettext(
4437c478bd9Sstevel@tonic-gate			    "%s not found in audit_class.  Omitting %s\n");
4447c478bd9Sstevel@tonic-gate			$errString = sprintf($errString, $thisClass,
4457c478bd9Sstevel@tonic-gate			    $label);
4467c478bd9Sstevel@tonic-gate			print STDERR $errString if ($debug);
4477c478bd9Sstevel@tonic-gate			next;
4487c478bd9Sstevel@tonic-gate		}
4497c478bd9Sstevel@tonic-gate		$skipThisClass = 1 if ($skipClass{$thisClass});
45087e895dbStz		$mask |=  $class{$thisClass};
4517c478bd9Sstevel@tonic-gate	}
4527c478bd9Sstevel@tonic-gate	return ($skipThisClass, $mask);
4537c478bd9Sstevel@tonic-gate}
4547c478bd9Sstevel@tonic-gate
4557c478bd9Sstevel@tonic-gate# getAttributes: Combine fields from %event and %attr; a description
4567c478bd9Sstevel@tonic-gate# in the attribute file overrides a description from audit_event
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gatesub getAttributes {
4597c478bd9Sstevel@tonic-gate	my $label = shift;
4607c478bd9Sstevel@tonic-gate	my $desc = shift;	# description from audit_event
4617c478bd9Sstevel@tonic-gate
4627c478bd9Sstevel@tonic-gate	my ($description, $title, $skip, @case);
4637c478bd9Sstevel@tonic-gate
4647c478bd9Sstevel@tonic-gate	my $errString = gettext("%s not found in attribute file.");
4657c478bd9Sstevel@tonic-gate	my $name = gettext("undefined");
4667c478bd9Sstevel@tonic-gate
4677c478bd9Sstevel@tonic-gate	if (defined($attr{$label})) {
4687c478bd9Sstevel@tonic-gate		($name, $description, $title, $skip, @case) = @{$attr{$label}};
4697c478bd9Sstevel@tonic-gate		if ($description eq 'none') {
4707c478bd9Sstevel@tonic-gate			if ($desc eq 'blank') {
4717c478bd9Sstevel@tonic-gate				$description = '';
4727c478bd9Sstevel@tonic-gate			} else {
4737c478bd9Sstevel@tonic-gate				$description = $desc;
4747c478bd9Sstevel@tonic-gate			}
4757c478bd9Sstevel@tonic-gate		}
4767c478bd9Sstevel@tonic-gate		$name = '' if ($name eq 'none');
4777c478bd9Sstevel@tonic-gate		$title = $name if (($title eq 'none') || (!defined($title)));
4787c478bd9Sstevel@tonic-gate	} else {
4797c478bd9Sstevel@tonic-gate		printf STDERR ("$errString\n", $label) if ($debug);
4807c478bd9Sstevel@tonic-gate	}
4817c478bd9Sstevel@tonic-gate	return ($name, $description, $title, $skip, @case);
4827c478bd9Sstevel@tonic-gate}
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate# getCallInfo: the system call or program name for an audit record can
4857c478bd9Sstevel@tonic-gate# usually be derived from the event name; %attr provides exceptions to
4867c478bd9Sstevel@tonic-gate# this rule
4877c478bd9Sstevel@tonic-gate
4887c478bd9Sstevel@tonic-gatesub getCallInfo {
4897c478bd9Sstevel@tonic-gate	my $id = shift;
4907c478bd9Sstevel@tonic-gate	my $name = shift;
4917c478bd9Sstevel@tonic-gate	my $desc = shift;
4927c478bd9Sstevel@tonic-gate
4937c478bd9Sstevel@tonic-gate	my $callType;
4947c478bd9Sstevel@tonic-gate	my $callName;
4957c478bd9Sstevel@tonic-gate	my $description;
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate	if ($name) {
4987c478bd9Sstevel@tonic-gate		if ($id < 6000) {
4997c478bd9Sstevel@tonic-gate			$callType = 'system call';
5007c478bd9Sstevel@tonic-gate		} else {
5017c478bd9Sstevel@tonic-gate			$callType = 'program';
5027c478bd9Sstevel@tonic-gate		}
5037c478bd9Sstevel@tonic-gate		($callName) = split(/\s*:\s*/, $name);
5047c478bd9Sstevel@tonic-gate	} else {
5057c478bd9Sstevel@tonic-gate		$callType = '';
5067c478bd9Sstevel@tonic-gate		$callName = '';
5077c478bd9Sstevel@tonic-gate	}
5087c478bd9Sstevel@tonic-gate	$description = '';
5097c478bd9Sstevel@tonic-gate	$description = "$desc" if ($desc);
5107c478bd9Sstevel@tonic-gate
5117c478bd9Sstevel@tonic-gate	return ($callType, $callName, $description);
5127c478bd9Sstevel@tonic-gate}
5137c478bd9Sstevel@tonic-gate
5147c478bd9Sstevel@tonic-gate# getFormatList: determine the order and details of kernel vs user
5157c478bd9Sstevel@tonic-gate# audit records.  If the first token is "head" then the token list
5167c478bd9Sstevel@tonic-gate# is explicit, otherwise the header, subject and return are implied.
5177c478bd9Sstevel@tonic-gate
5187c478bd9Sstevel@tonic-gatesub getFormatList {
5197c478bd9Sstevel@tonic-gate	my $format = shift;
5207c478bd9Sstevel@tonic-gate	my $id = shift;
5217c478bd9Sstevel@tonic-gate
5227c478bd9Sstevel@tonic-gate	my $list;
5237c478bd9Sstevel@tonic-gate
5247c478bd9Sstevel@tonic-gate	if ($format =~ /^head:/) {
5257c478bd9Sstevel@tonic-gate		$list = $format;
5267c478bd9Sstevel@tonic-gate	}
5277c478bd9Sstevel@tonic-gate	elsif ($format eq 'kernel') {
5287c478bd9Sstevel@tonic-gate		$list = $parse->{'kernelDefault'};
5297c478bd9Sstevel@tonic-gate		$list =~ s/insert://;
5307c478bd9Sstevel@tonic-gate	} elsif ($format eq 'user') {
5317c478bd9Sstevel@tonic-gate		$list = $parse->{'userDefault'};
5327c478bd9Sstevel@tonic-gate		$list =~ s/insert://;
5337c478bd9Sstevel@tonic-gate	} elsif ($id < 6000) {
5347c478bd9Sstevel@tonic-gate		$list = $parse->{'kernelDefault'};
5357c478bd9Sstevel@tonic-gate		$list =~ s/insert/$format/;
5367c478bd9Sstevel@tonic-gate	} else {
5377c478bd9Sstevel@tonic-gate		$list = $parse->{'userDefault'};
5387c478bd9Sstevel@tonic-gate		$list =~ s/insert/$format/;
5397c478bd9Sstevel@tonic-gate	}
5407c478bd9Sstevel@tonic-gate	return ($list);
5417c478bd9Sstevel@tonic-gate}
5427c478bd9Sstevel@tonic-gate
5437c478bd9Sstevel@tonic-gate# getFormatLine: the arguments from the attribute 'format' are
5447c478bd9Sstevel@tonic-gate# expanded to their printable form and also paired with a comment if
5457c478bd9Sstevel@tonic-gate# one exists
5467c478bd9Sstevel@tonic-gate
5477c478bd9Sstevel@tonic-gatesub getFormatLine {
5487c478bd9Sstevel@tonic-gate	my $arg = shift;
5497c478bd9Sstevel@tonic-gate	my $label = shift;
5507c478bd9Sstevel@tonic-gate	my @comment = @_;
5517c478bd9Sstevel@tonic-gate
5527c478bd9Sstevel@tonic-gate	my $isOption = 0;
5537c478bd9Sstevel@tonic-gate
5547c478bd9Sstevel@tonic-gate	my ($token, $comment);
5557c478bd9Sstevel@tonic-gate
5567c478bd9Sstevel@tonic-gate	my $cmt = -1;
5577c478bd9Sstevel@tonic-gate	if ($arg =~ s/(\D*)(\d+)$/$1/) {  # trailing digits select a comment
5587c478bd9Sstevel@tonic-gate		$cmt = $2 - 1;
5597c478bd9Sstevel@tonic-gate	}
5607c478bd9Sstevel@tonic-gate	$isOption = 1 if ($arg =~ s/^\[(.+)\]$/$1/);
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate	if (defined($token{$arg})) {	# expand abbreviated name to token
5637c478bd9Sstevel@tonic-gate		$token = $token{$arg};
5647c478bd9Sstevel@tonic-gate	} else {
5657c478bd9Sstevel@tonic-gate		$token = $arg;		# no abbreviation found
5667c478bd9Sstevel@tonic-gate	}
5677c478bd9Sstevel@tonic-gate	$token = '['.$token.']' if ($isOption);
5687c478bd9Sstevel@tonic-gate
5697c478bd9Sstevel@tonic-gate	if ($cmt > -1) {
5707c478bd9Sstevel@tonic-gate		unless(defined($comment[$cmt])) {
5717c478bd9Sstevel@tonic-gate			my $errString = gettext(
5727c478bd9Sstevel@tonic-gate			    "missing comment for %s %s token %d\n");
5737c478bd9Sstevel@tonic-gate			printf STDERR ($errString, $label, $token,
5747c478bd9Sstevel@tonic-gate			    $cmt);
5757c478bd9Sstevel@tonic-gate			$comment = gettext('missing comment field');
5767c478bd9Sstevel@tonic-gate		} else {
5777c478bd9Sstevel@tonic-gate			$comment = $comment[$cmt];
5787c478bd9Sstevel@tonic-gate			$comment =~ s/&colon;/:/g;	#':' is a delimiter
5797c478bd9Sstevel@tonic-gate		}
5807c478bd9Sstevel@tonic-gate	} else {
5817c478bd9Sstevel@tonic-gate		$comment = '';
5827c478bd9Sstevel@tonic-gate	}
5837c478bd9Sstevel@tonic-gate	unless (defined($token) && defined($comment)) {
5847c478bd9Sstevel@tonic-gate		my $errString = gettext("attribute format/comment error for %s\n");
5857c478bd9Sstevel@tonic-gate		printf STDERR ($errString, $label);
5867c478bd9Sstevel@tonic-gate	}
5877c478bd9Sstevel@tonic-gate	return ($token, $comment);
5887c478bd9Sstevel@tonic-gate}
5897c478bd9Sstevel@tonic-gate
5907c478bd9Sstevel@tonic-gatesub usage {
5917c478bd9Sstevel@tonic-gate	print "$0 [ -d ] [ -h ] {[ -a ] | [ -e event ] |\n";
5927c478bd9Sstevel@tonic-gate	print "\t[ -c class ] | [-i id ] | [ -p program ] |\n";
5937c478bd9Sstevel@tonic-gate	print "\t[ -s syscall ]}\n";
5947c478bd9Sstevel@tonic-gate}
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gateformat nameLine =
5977c478bd9Sstevel@tonic-gate
5987c478bd9Sstevel@tonic-gate@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
5997c478bd9Sstevel@tonic-gate$title
6007c478bd9Sstevel@tonic-gate.
6017c478bd9Sstevel@tonic-gate
6027c478bd9Sstevel@tonic-gateformat threeColumns =
6037c478bd9Sstevel@tonic-gate  @<<<<<<<<<< @<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
6047c478bd9Sstevel@tonic-gate$col1, $col2, $col3
6057c478bd9Sstevel@tonic-gate.
6067c478bd9Sstevel@tonic-gate
6077c478bd9Sstevel@tonic-gateformat twoColumns =
6087c478bd9Sstevel@tonic-gate      @<<<<<<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
6097c478bd9Sstevel@tonic-gate$col1, $col2
6107c478bd9Sstevel@tonic-gate.
6117c478bd9Sstevel@tonic-gateformat col2Wrapped =
6127c478bd9Sstevel@tonic-gate				   ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
6137c478bd9Sstevel@tonic-gate$col2
6147c478bd9Sstevel@tonic-gate.
6157c478bd9Sstevel@tonic-gate
6167c478bd9Sstevel@tonic-gateformat space =
6177c478bd9Sstevel@tonic-gate
6187c478bd9Sstevel@tonic-gate.
6197c478bd9Sstevel@tonic-gate
6207c478bd9Sstevel@tonic-gateformat wrapped1 =
6217c478bd9Sstevel@tonic-gate    ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
6227c478bd9Sstevel@tonic-gate$note
6237c478bd9Sstevel@tonic-gate.
6247c478bd9Sstevel@tonic-gate
6257c478bd9Sstevel@tonic-gateformat wrapped2 =
6267c478bd9Sstevel@tonic-gate^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
6277c478bd9Sstevel@tonic-gate$note
6287c478bd9Sstevel@tonic-gate.
629