auditxml_jni revision cd3e933325e68e23516a196a8fea7f49b1e497c3
#!/usr/perl5/bin/perl -w
#
# 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
# or http://www.opensolaris.org/os/licensing.
# 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
#
#
# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
#
# auditxml_jni [-d] <xml input file>
# auditxml takes the audit record description (.xml file) and
# generates the files needed for the Java
use auditxml;
use Getopt::Std;
use vars qw($opt_d);
use strict;
our $debug = 0; # normal use is to set via the file being parsed.
# <debug set="on"/> or <debug set="off"/> or <debug/>
# if the set attribute is omitted, debug state is toggled
# Override with appDebug, but toggle won't do what you
# want.
my $appDebug = 0; # used after return from "new auditxml";
my $genNotice = "
DO NOT EDIT. This file is auto generated by the Solaris Audit
system from adt.xml.
See http://opensolaris.org/os/project/audit/
";
# trim leading/trailing newlines
$genNotice =~ s/^\n//s;
$genNotice =~ s/\n$//s;
my $prog = $0; $prog =~ s|.*/||g;
my $usage = "usage: $prog [-d] file.xml\n";
getopts('d');
$appDebug = $opt_d;
my $uniLabel = "adr";
my $xlateUniLabelInc = 0;
die $usage if ($#ARGV < 0);
# where everything comes from and where it goes:
my $templatePath = './';
my $javaPath = $templatePath;
my $bsmBuildPath = "../libbsm";
my $jniBuildPath = "$javaPath";
my $buildPathJ = "$jniBuildPath/com/sun/audit";
my $buildPathJNI = "$jniBuildPath/common";
my $auditEventJ = "$buildPathJ/AuditEvent.java";
my $jniC = "$buildPathJNI/adt_jni_event.c";
my $mapFile = "$jniBuildPath/common/mapfile-vers";
my $doc = new auditxml ($ARGV[0]); # input XML file
$debug = $appDebug;
my %jniEventTable = ();
my %externalIdNo = ();
my %msg_list = ();
my %eventCode = ();
readAuditEventFile("$bsmBuildPath/audit_event.txt");
my $event;
while ($event = $doc->getNextEvent()) {
my $eventId = $event->getId();
my $idNo = $event->getIdNo();
$externalIdNo{$eventId} = $idNo;
my $super;
my $omit = $event->getOmit();
my $eventType = '';
if ($super = $event->getSuperClass()) {
$event = $super;
$eventType = 'instance';
} else {
$eventType = $event->getType();
}
# c file table for translation
generateTableC($event, $eventId, $eventType, undef, $omit);
}
while (my $textList = $doc->getNextMsgId()) {
generateMsgLists($textList); # enum -> text mappings
}
printJavaFiles($jniC, $auditEventJ, $buildPathJ, $mapFile);
exit 0;
sub printJavaFiles {
my $jniFile = shift;
my $javaFile = shift;
my $subclassPath = shift;
my $mapFile = shift;
# warning: time_t is equated to jlong since there is no
# way to use sys/types.h in Java code.
# java long is C long long, 64 bits.
# java int is 32 bits.
my %java_jni = ('ADT_DATE' => ['long', 'jlong'],
'ADT_UINT' => ['int', 'jint'],
'ADT_INT' => ['int', 'jint'],
'ADT_INT32' => ['int', 'jint'],
'ADT_UID' => ['int', 'jint'],
'ADT_GID' => ['int', 'jint'],
'ADT_UIDSTAR' => ['int[]', 'jintArray'],
'ADT_GIDSTAR' => ['int[]', 'jintArray'],
'ADT_CHAR' => ['String', 'jchar'],
'ADT_CHARSTAR' => ['String', 'jstring'],
'ADT_CHAR2STAR' => ['String[]', 'jstring'],
'ADT_MSG' => ['int', 'jint'],
'ADT_PID' => ['int', 'jint'],
# ADT_PRIVSTAR omitted -- not implemented and the audit records that
# use it must be coded to emit no java. We'll cross that bridge
# when someone in Java land needs to generate a priv token.
'ADT_LONG' => ['int', 'jint'],
'ADT_TERMIDSTAR' => ['String', 'jstring'], # hostname -> termid
'ADT_ULONG' => ['int', 'jint'],
'ADT_UINT16' => ['int', 'jint'],
'ADT_UINT32' => ['int', 'jint'],
'ADT_UINT32STAR' => ['int[]', 'jintArray'],
# ADT_UINT32ARRAY omitted; no Java implementation yet
'ADT_UINT64' => ['long', 'jlong'],
'ADT_UINT64STAR' => ['long[]', 'jlongArray']
);
my $noMemory = 'gettext("Out of memory")';
# open output files
open (Cfile, ">$jniFile") or
die "can't open output file ($jniFile): $!\n";
open (Jfile, ">$javaFile") or
die "can't open output file ($javaFile): $!\n";
open (MapFile, ">$mapFile") or
die "can't open output file ($mapFile): $!\n";
# write headers
my $notice = $genNotice;
$notice =~ s/\n/\n * /gs;
$notice =~ s/\s+\n/\n/gs;
print Cfile <<EOF;
/*
* $notice
*/
#include "../../libbsm/common/adt_xlate.h"
#include <jni.h>
#include "../com/sun/audit/AuditSession.h" /* javah output */
#include "adt_jni.h"
#include <stdlib.h>
#include <string.h>
static char *except_class = "java/lang/Exception";
EOF
print Jfile <<EOF;
/*
* $notice
*/
package com.sun.audit;
public class AuditEvent {
protected AuditSession sh; // associated session object
public AuditEvent(AuditSession auSession)
throws Error
{
sh = auSession;
}
// Manifest values: keep them in sync with generated <bsm/adt_event.h>.
// It is generated by \$SRC/lib/libbsm/auditxml
public static final int ADT_SUCCESS = 0; // generated
public static final int ADT_FAILURE = -1; // generated
// See the subclasses of AuditEvent for mapping message codes
// to events
EOF
my $notice_map = $genNotice;
$notice_map =~ s/\n/\n# /gs;
$notice_map =~ s/\s+\n/\n/gs;
print MapFile <<EOF;
#
# $notice_map
#
\$mapfile_version 2
SYMBOL_VERSION SUNWprivate_1.1 {
global:
c2j_pointer;
j2c_pointer;
Java_com_sun_audit_AuditSession_bsmAuditOn;
Java_com_sun_audit_AuditSession_startSession;
Java_com_sun_audit_AuditSession_endSession;
Java_com_sun_audit_AuditSession_dupSession;
Java_com_sun_audit_AuditSession_getSessionId;
Java_com_sun_audit_AuditSession_exportSessionData;
Java_com_sun_audit_AuditSession_sessionAttr;
# One subclass of AuditEvent per audit record...
EOF
# generate java final int classes to line up with string/enums
foreach my $listName (sort keys %msg_list) {
my $shortName = uc $listName;
$shortName =~ s/_TEXT//;
my ($listRef, $headref) = @{$msg_list{$listName}};
my @listValue = @$listRef;
my ($header, $enumValue, $public, $deprecated) = @$headref;
my $listValue;
print Jfile "\n\t// adt_$listName" . "\n\n";
print Jfile "\tpublic static final int ADT_$shortName",
" = $enumValue;\n" if $enumValue;
next unless ($#listValue >= 0);
print Jfile "\t// Deprecated message list\n" if $deprecated;
foreach $listValue (@listValue) {
my ($id, $text) = split(/\s*::\s*/, $listValue);
print Jfile "\t// $text\n";
print Jfile "\tpublic static final int ADT_$shortName";
print Jfile "_$id = $enumValue;\n";
$enumValue++;
}
}
# generate event creation and access functions and event
# generation for both Java and JNI
# com.sun.audit.AuditEvent_xxx.java
foreach my $eventId (sort keys %jniEventTable) {
my ($ref1, $eventType, $allowedIds, $header) = @{$jniEventTable{$eventId}};
$eventCode{$eventId} = -1 if ($eventType eq 'generic');
my @entries = @$ref1;
my $entries = $#entries;
my $root = $eventId;
$root =~ s/AUE_//;
my $javaPutEvent = 'putEvent';
my $putMethod = "_$root";
$putMethod =~ s/_/_1/g;
my $jniPutEvent = "Java_com_sun_audit_AuditEvent$putMethod" . "_$javaPutEvent";
# the subclass file template isn't used; it may be needed to get
# the right file header stuff in place. The subclassPath is
# the directory that contains 'em.
my $validSfile = 1;
unless (open(Sfile, ">$subclassPath/AuditEvent_$root.java")) {
print STDERR "can't open class file AuditEvent_$root.java: $!\n";
$validSfile = 0;
}
if ($eventCode{"AUE_$root"}) {
if ($validSfile) {
print Sfile <<EOF;
/*
* $notice
*/
package com.sun.audit;
// audit event: $eventId = $eventCode{"AUE_$root"}
public class AuditEvent_$root extends AuditEvent {
EOF
}
} else {
print STDERR "no event code for $eventId. Is audit_event current?\n";
}
my $nativeParameterList = '';
my $jniParameterList = '';
my $specParameterList = '';
my $jniStorageList = '';
my $needCleanupTarget = 0;
my $jniFreeList = '';
my $haveStringDef = 0;
my $haveCDef = 0;
my $haveLengthDef = 0;
my $haveStringArrayDef = 0;
my $cntTermidDef = 0;
my $jniDefine;
my $needLocaleDefined = 0;
my $jniADTalloc;
if (defined $header && ($header > 0) ) {
$jniDefine = "union union_of_events *event;\n" .
"\tadt_session_data_t *session;\n";
$jniADTalloc = '(union union_of_events *)adt_alloc_event';
} else {
$jniDefine = "adt_event_data_t *event;\n" .
"\tadt_session_data_t *session;\n";
$jniADTalloc = 'adt_alloc_event';
}
my $ref2;
foreach $ref2 (@entries) {
my ($id, $type) = @$ref2;
my $jniRoot = $root . $id;
$jniRoot =~ s/_/_1/g; # escape unicode "_"
my $p_event;
if (defined $header && ($header > 0) ) {
$p_event = "event->d$header.adt_$root.$id";
} else {
$p_event = "event->adt_$root.$id";
}
if ($type eq 'ADT_UINT32STAR') { # int array
$needLocaleDefined = 1;
$jniStorageList .= <<EOF;
/* $id */
length = (*env)->GetArrayLength(env, $id);
$p_event =
(int *)malloc(length * sizeof (int));
if ($p_event == NULL) {
locale = I18N_SETUP;
local_throw(env, except_class,
$noMemory);
(void) setlocale(LC_MESSAGES, locale);
goto cleanup;
}
(*env)->GetIntArrayRegion(env, $id, 0, length,
(int *)$p_event);
EOF
$jniFreeList .= "\n\tif ($p_event != NULL)\n" .
"\t\tfree($p_event);\n";
unless ($haveLengthDef) {
$haveLengthDef = 1;
$jniDefine .= "\tint\t\t\tlength;\n";
}
$nativeParameterList .= ",\n\t int[]\t$id";
$jniParameterList .= ",\n jintArray\t$id";
$specParameterList .= ", jintArray";
$needCleanupTarget = 1;
} elsif (($type eq 'ADT_UIDSTAR') ||
($type eq 'ADT_GIDSTAR')) { # gid_t array
my $cType = 'uid_t';
$cType = 'gid_t' if ($type eq 'ADT_GIDSTAR');
$needLocaleDefined = 1;
$jniStorageList .= <<EOF;
/* $id */
length = (*env)->GetArrayLength(env, $id);
$p_event =
($cType *)malloc(length * sizeof ($cType));
if ($p_event == NULL) {
locale = I18N_SETUP;
local_throw(env, except_class,
$noMemory);
(void) setlocale(LC_MESSAGES, locale);
goto cleanup;
}
(*env)->GetIntArrayRegion(env, $id, 0, length,
(int *)$p_event);
EOF
$jniFreeList .=
"\n\tif ($p_event != NULL)\n" .
"\t\tfree($p_event);\n";
unless ($haveLengthDef) {
$haveLengthDef = 1;
$jniDefine .= "\tint\t\t\tlength;\n";
}
$nativeParameterList .= ",\n\t int[]\t$id";
$jniParameterList .= ",\n jintArray\t$id";
$specParameterList .= ", jintArray";
$needCleanupTarget = 1;
} elsif ($type eq 'ADT_UINT64STAR') { # long array
$needLocaleDefined = 1;
$jniStorageList .= <<EOF;
/* $id */
length = (*env)->GetArrayLength(env, $id);
$p_event =
(long *)malloc(length * sizeof (long long));
if ($p_event == NULL) {
locale = I18N_SETUP;
local_throw(env, except_class,
$noMemory);
(void) setlocale(LC_MESSAGES, locale);
goto cleanup;
}
(*env)->GetLongArrayRegion(env, $id, 0, length,
$p_event);
EOF
$jniFreeList .= "\n\tif ($p_event != NULL)\n" .
"\t\tfree($p_event);\n";
unless ($haveLengthDef) {
$haveLengthDef = 1;
$jniDefine .= "\tint\t\t\tlength;\n";
}
$nativeParameterList .= ",\n\t long[]\t$id";
$jniParameterList .= ",\n jlongArray\t$id";
$specParameterList .= ", jlongArray";
$needCleanupTarget = 1;
} elsif ($type eq 'ADT_CHAR') { # string in Java, char in C
$jniStorageList .= <<EOF;
/* $id */
c = (char *)(*env)->GetStringUTFChars(env, $id, NULL);
if (c == NULL)
goto cleanup; /* exception thrown */
$p_event = *c;
(*env)->ReleaseStringUTFChars(env, $id, c);
EOF
# no need to free anything
unless ($haveCDef) {
$haveCDef = 1;
$jniDefine .= "\tchar\t\t\t*c\n";
}
$nativeParameterList .= ",\n\t String\t$id";
$jniParameterList .= ",\n jstring\t$id";
$specParameterList .= ", jstring";
} elsif ($type eq 'ADT_CHARSTAR') {
$needLocaleDefined = 1;
$jniStorageList .= <<EOF;
/* $id */
if ($id != NULL) {
string = (char *)(*env)->GetStringUTFChars(
env, $id, NULL);
if (string == NULL)
goto cleanup; /* exception thrown */
$p_event = strdup(string);
(*env)->ReleaseStringUTFChars(env, $id, string);
if ($p_event == NULL) {
locale = I18N_SETUP;
local_throw(env, except_class,
$noMemory);
(void) setlocale(LC_MESSAGES, locale);
goto cleanup;
}
}
EOF
$jniFreeList .= "\n\tif ($p_event != NULL)\n" .
"\t\tfree($p_event);\n";
unless ($haveStringDef) {
$haveStringDef = 1;
$jniDefine .= "\tchar\t\t\t*string;\n";
}
$nativeParameterList .= ",\n\t String\t$id";
$jniParameterList .= ",\n jstring\t$id";
$specParameterList .= ", jstring";
$needCleanupTarget = 1;
} elsif ($type eq 'ADT_CHAR2STAR') { # array of string
$needLocaleDefined = 1;
$jniStorageList .= <<EOF;
/* $id */
length = (*env)->GetArrayLength(env, $id);
$p_event = (char **)malloc(length
* sizeof (char *));
if ($p_event == NULL) {
locale = I18N_SETUP;
local_throw(env, except_class,
$noMemory);
(void) setlocale(LC_MESSAGES, locale);
goto cleanup;
}
p = $p_event;
for (i = 0; i < length; i++) {
jString = (*env)->GetObjectArrayElement(env, $id, i);
string = (char *)(*env)->GetStringUTFChars(
env, jString, NULL);
if (string == NULL)
goto cleanup; /* exception thrown */
*p = strdup(string);
(*env)->ReleaseStringUTFChars(env, jString, string);
if (*p == NULL) {
locale = I18N_SETUP;
local_throw(env, except_class,
$noMemory);
(void) setlocale(LC_MESSAGES, locale);
while (p >= $p_event)
free(*p--);
goto cleanup;
}
p++;
}
EOF
$jniFreeList .=
"\n\tif ($p_event != NULL)\n" .
"\t\tfree($p_event);\n";
unless ($haveStringArrayDef) {
unless ($haveStringDef) {
$haveStringDef = 1;
$jniDefine .= <<EOF;
char *string;
EOF
}
unless ($haveLengthDef) {
$haveLengthDef = 1;
$jniDefine .= <<EOF;
int length;
EOF
}
$haveStringArrayDef = 1;
$jniDefine .= <<EOF;
int i;
char **p;
jstring jString;
EOF
}
$nativeParameterList .= ",\n\t String[]\t$id";
$jniParameterList .= ",\n jstring\t$id";
$specParameterList .= ", jstring";
$needCleanupTarget = 1;
} elsif ($type eq 'ADT_TERMIDSTAR') {
$needLocaleDefined = 1;
$jniStorageList .= <<EOF;
/* $id */
hostname$cntTermidDef = (char *)(*env)->GetStringUTFChars(env, $id, NULL);
if (adt_load_hostname((const char *)hostname$cntTermidDef, &termid$cntTermidDef)) {
local_throw(env, except_class,
gettext("hostname lookup failed"));
}
$p_event = termid$cntTermidDef;
(*env)->ReleaseStringUTFChars(env, $id, hostname$cntTermidDef);
EOF
$jniFreeList .= "\n\tif (hostname$cntTermidDef != NULL)\n" .
"\t\tfree(hostname$cntTermidDef);\n";
$jniFreeList .= "\n\tif (termid$cntTermidDef != NULL)\n" .
"\t\tfree(termid$cntTermidDef);\n";
$jniDefine .= "\tchar\t\t\t*hostname$cntTermidDef;\n";
$jniDefine .= "\tadt_termid_t\t\t*termid$cntTermidDef;\n"; #djdj
$cntTermidDef++;
my ($nativeParameter, $jniParameter) = @{$java_jni{$type}};
$nativeParameterList .= ",\n\t $nativeParameter\t$id";
$jniParameterList .= ",\n $jniParameter\t$id";
$specParameterList .= ", $jniParameter";
$needCleanupTarget = 1;
} else { # all others are primitive types
$jniStorageList .= "\n\t$p_event = $id;\n";
my ($nativeParameter, $jniParameter) = @{$java_jni{$type}};
$nativeParameter = "$nativeParameter\t"
if length $nativeParameter < 4; # why?
$nativeParameterList .= ",\n\t $nativeParameter\t$id";
$jniParameterList .= ",\n $jniParameter\t$id";
$specParameterList .= ", $jniParameter";
}
}
if ($needLocaleDefined) {
$jniDefine .= <<EOF
char *locale;
EOF
}
my $genericOverride = '';
my $idParameter = $eventId;
$idParameter =~ s/AUE_/ADT_/;
if ($eventType eq 'generic') {
$genericOverride = ', jint eventId';
$idParameter = 'eventId';
}
$jniFreeList = "\tcleanup:\n" . $jniFreeList if $needCleanupTarget;
print Cfile qq{/* ARGSUSED */
JNIEXPORT void JNICALL
$jniPutEvent(
JNIEnv *env,
jobject self,
jbyteArray jsession$genericOverride,
jint status,
jint ret_val$jniParameterList)
{
$jniDefine
(void) j2c_pointer(env, jsession, (char **)&session);
event = $jniADTalloc(session, $idParameter);
$jniStorageList
(void) adt_put_event((adt_event_data_t *)event, status, ret_val);
$jniFreeList
adt_free_event((adt_event_data_t *)event);
}
};
print MapFile qq{
$jniPutEvent; };
my $overrideParameter = '';
if ($eventType eq 'generic') {
$overrideParameter = 'int eventId,';
my @allowed = @$allowedIds;
if (@allowed) {
my $i;
if ($validSfile) {
print Sfile "\t// Allowed values for eventId in putEvent:\n";
for ($i = 0; $i <= $#allowed; $i++) {
my $idNo = $externalIdNo{$allowed[$i]};
$allowed[$i] =~ s/AUE_/ADT_/;
print Sfile "\tstatic final int $allowed[$i] = ",
"$idNo;\n";
}
print Sfile "\n";
}
} else {
print STDERR "Generic event with no allowed instances: $eventId\n";
}
}
if ($validSfile) {
print Sfile <<EOF;
private native void $javaPutEvent(byte[]session, $overrideParameter
int status, int ret_val$nativeParameterList);
public AuditEvent_$root(AuditSession session)
throws Exception
{
super(session);
}
EOF
my $javaParameterList = '';
foreach $ref2 (@entries) {
my ($id, $type, $format, $jComment, $required) = @$ref2;
# generate java native method prototypes
# and the corresponding C method implementation
my $javaMethodName = "$id";
my $javaStorageName = $javaMethodName . '_val';
my $jniMethodName = $root . $id;
my $storage;
my $enumUsage = '';
my $jParam = @{$java_jni{$type}}[0];
my $comment = '';
if ($required) {
if ($format ne 'NULL') {
$comment = "\t// (required) formatted: $format";
} else {
$comment = "\t// required";
}
} else {
if ($format ne 'NULL') {
$comment = "\t// (optional) formatted: $format";
} else {
$comment = "\t// optional";
}
}
if (($type eq 'ADT_UINT32STAR') ||
($type eq 'ADT_UIDSTAR') ||
($type eq 'ADT_GIDSTAR')) { # int array
$storage = "int[] $javaStorageName" . ($required ?
' = {}' : '');
$javaParameterList .= ",\n\t\t\t $javaStorageName";
} elsif ($type eq 'ADT_UINT64STAR') { # long array
$storage = "long[] $javaStorageName" . ($required ?
' = {}' : '');
$javaParameterList .= ",\n\t\t\t $javaStorageName";
} elsif (($type eq 'ADT_CHARSTAR') ||
($type eq 'ADT_CHAR')) { # string
$storage = "String $javaStorageName" . ($required ?
' = ""' : '');
$javaParameterList .= ",\n\t\t\t $javaStorageName";
} elsif ($type eq 'ADT_CHAR2STAR') { # array of string
$storage = "String[] $javaStorageName" . ($required ?
' = {}' : '');
$javaParameterList .= ",\n\t\t\t $javaStorageName";
} elsif ($type eq 'ADT_TERMIDSTAR') { # array of string
$storage = "String $javaStorageName" . ($required ?
' = ""' : '');
$javaParameterList .= ",\n\t\t\t $javaStorageName";
} else { # all others are primitive types
$storage = "$jParam $javaStorageName = 0";
$javaParameterList .= ",\n\t\t\t $javaStorageName";
$enumUsage = "\n\t// See $jComment in AuditEvent.java for valid values"
if $jComment;
}
print Sfile <<EOF;
$enumUsage
private $storage;$comment
public void $javaMethodName($jParam setTo)
{
$javaStorageName = setTo;
}
EOF
} # end foreach (@entries)
if ($eventType eq 'generic') {
print Sfile <<EOF;
public void putEvent(int status, int ret_val, int eventId)
{
byte[] session = super.sh.getSession();
if ((super.sh.AuditIsOn) && (super.sh.ValidSession))
$javaPutEvent(session, eventId,
status, ret_val$javaParameterList);
}
}
EOF
} else {
print Sfile <<EOF;
public void putEvent(int status, int ret_val)
{
byte[] session = super.sh.getSession();
if ((super.sh.AuditIsOn) && (super.sh.ValidSession))
$javaPutEvent(session, status, ret_val$javaParameterList);
}
}
EOF
}
close Sfile;
} # end if ($validSfile);
}
# write trailers
print Jfile <<EOF;
}
EOF
print MapFile <<EOF;
local:
*;
};
EOF
close Cfile;
close Jfile;
close MapFile;
}
sub generateTableC {
my $event = shift;
my $eventId = shift;
my $eventType = shift;
my $eventHeader = shift;
my $omit = shift;
my %tokenType = (
'acl' => 'AUT_ACL',
'arbitrary' => 'AUT_ARBITRARY',
'arg' => 'AUT_ARG',
'attr' => 'AUT_ATTR',
'command' => 'AUT_CMD',
'command_1' => 'ADT_CMD_ALT', # dummy token id
'date' => 'AUT_TEXT',
'exec_args' => 'AUT_EXEC_ARGS',
'exec_env' => 'AUT_EXEC_ENV',
'exit' => 'AUT_EXIT',
'file' => 'AUT_FILE',
'fmri' => 'AUT_FMRI',
'groups' => 'AUT_GROUPS',
# 'header' => 'AUT_HEADER', # not used
'in_addr' => 'AUT_IN_ADDR',
'ipc' => 'AUT_IPC',
'ipc_perm' => 'AUT_IPC_PERM',
'iport' => 'AUT_IPORT',
'label' => 'AUT_LABEL',
'newgroups' => 'AUT_NEWGROUPS',
'opaque' => 'AUT_OPAQUE',
'path' => 'AUT_PATH',
'path_list' => '-AUT_PATH', # dummy token id
'process' => 'AUT_PROCESS',
'priv_effective' => 'ADT_AUT_PRIV_E', # dummy token id
'priv_limit' => 'ADT_AUT_PRIV_L', # dummy token id
'priv_inherit' => 'ADT_AUT_PRIV_I', # dummy token id
'return' => 'AUT_RETURN',
'seq' => 'AUT_SEQ',
'socket' => 'AUT_SOCKET',
'socket-inet' => 'AUT_SOCKET_INET',
'subject' => 'AUT_SUBJECT',
'text' => 'AUT_TEXT',
'tid' => 'AUT_TID',
# 'trailer' => 'AUT_TRAILER', # not used
'uauth' => 'AUT_UAUTH',
'user' => 'AUT_USER',
'zonename' => 'AUT_ZONENAME'
);
my @xlateEntryList = ();
my @jniEntryList = ();
my $external = $event->getExternal();
my $internal = $event->getInternal();
unless ($external) {
print STDERR "No external object captured for event $eventId\n";
return;
}
unless ($internal) {
print STDERR "No internal object captured for event $eventId\n";
return;
}
my @entryRef = $internal->getEntries();
my $entryRef;
my @tokenOrder = ();
my $firstTokenIndex = 0; # djdj not used yet, djdj BUG!
# needs to be used by translate table
if ($internal->isReorder()) { # prescan the entry list to get the token order
my @inputOrder;
foreach $entryRef (@entryRef) {
my ($intEntry, $entry) = @$entryRef;
push (@inputOrder, $intEntry->getAttr('order'));
}
my $i; # walk down the inputOrder list once
my $k = 1; # discover next in line
my $l = 0; # who should point to next in line
for ($i = 0; $i <= $#inputOrder; $i++) {
my $j;
for ($j = 0; $j <= $#inputOrder; $j++) {
if ($k == $inputOrder[$j]) {
if ($k == 1) {
$firstTokenIndex = $j;
} else {
$tokenOrder[$l] = "&(selfReference[$j])";
}
$l = $j;
last;
}
}
$k++;
}
$tokenOrder[$l] = 'NULL';
}
else { # default order -- input order same as output
my $i;
my $j;
for ($i = 0; $i < $#entryRef; $i++) {
my $j = $i + 1;
$tokenOrder[$i] = "&(selfReference[$j])";
}
$tokenOrder[$#entryRef] = 'NULL';
}
my $sequence = 0;
foreach $entryRef (@entryRef) {
my ($intEntry, $entry) = @$entryRef;
my $entryId = $entry->getAttr('id');
my ($extEntry, $unusedEntry, $tokenId) =
$external->getEntry($entryId);
my $opt = $extEntry->getAttr('opt');
if ($opt eq 'none') {
if (defined ($doc->getToken($tokenId))) {
if (defined ($tokenType{$tokenId})) {
$tokenId = $tokenType{$tokenId};
}
else {
print STDERR "token id $tokenId not implemented\n";
}
}
else {
print STDERR "token = $tokenId is undefined\n";
$tokenId = 'error';
}
my ($xlate, $jni) =
formatTableEntry ('', $tokenId, $eventId, '', 0, 0, $tokenOrder[$sequence],
'NULL', '');
push (@xlateEntryList, $xlate);
push (@jniEntryList, @$jni);
}
else {
my $dataType = $extEntry->getAttr('type');
$dataType =~ s/\s+//g; # remove blanks (char * => char*)
my $enumGroup = '';
if ($dataType =~ /^msg/i) {
$enumGroup = $dataType;
$enumGroup =~ s/^msg\s*//i;
$enumGroup = 'adt_' . $enumGroup;
}
my $required = ($opt eq 'required') ? 1 : 0;
my $tsol = 0;
my $tokenId = $intEntry->getAttr('token');
my $token;
my $tokenName;
my $tokenFormat = $intEntry->getAttr('format');
if (defined ($tokenFormat)) {
$tokenFormat = "\"$tokenFormat\"";
}
else {
$tokenFormat = 'NULL';
}
if (defined ($token = $doc->getToken($tokenId))) {
$tsol = (lc $token->getUsage() eq 'tsol') ? 1 : 0;
if (defined ($tokenType{$tokenId})) {
$tokenName = $tokenType{$tokenId};
}
else {
print STDERR "token id $tokenId not implemented\n";
}
}
else {
print STDERR
"$tokenId is an unimplemented token ($entryId in $eventId)\n";
$tokenName = 'AUT_TEXT';
}
my ($xlate, $jni) =
formatTableEntry($entryId, $tokenName, $eventId, $dataType, $required,
$tsol, $tokenOrder[$sequence], $tokenFormat,
$enumGroup, (uc $omit eq 'JNI'));
push (@xlateEntryList, $xlate);
push (@jniEntryList, @$jni);
}
$sequence++;
}
$jniEventTable{$eventId} = [\@jniEntryList, $eventType,
$external->getAllowedTypes(), $eventHeader]
unless (uc $omit eq 'JNI') || ($omit eq 'always');
}
sub formatTableEntry {
my ($id, $token, $eventId, $type, $required, $tsol, $sequence, $format, $enumGroup,
$omitJNI) = @_;
# does this map belong in the xml source? (at least the defaults?)
# fill in the default value only if it is other than zero.
# base type adt name, default value
my %entryDef = ( 'au_asid_t' => ['ADT_UINT32', ''],
'uint_t' => ['ADT_UINT32', ''],
'int' => ['ADT_INT', ''],
'int32_t' => ['ADT_INT32', ''],
'uid_t' => ['ADT_UID', 'AU_NOAUDITID'],
'gid_t' => ['ADT_GID', 'AU_NOAUDITID'],
'uid_t*' => ['ADT_UIDSTAR', ''],
'gid_t*' => ['ADT_GIDSTAR', ''],
'char' => ['ADT_CHAR', ''],
'char*' => ['ADT_CHARSTAR', ''],
'char**' => ['ADT_CHAR2STAR', ''],
'long' => ['ADT_LONG', ''],
'pid_t' => ['ADT_PID', ''],
'priv_set_t*' => ['ADT_PRIVSTAR', ''],
'ulong_t' => ['ADT_ULONG', ''],
'uint16_t', => ['ADT_UINT16', ''],
'uint32_t' => ['ADT_UINT32', ''],
'uint32_t*' => ['ADT_UINT32STAR', ''],
'uint32_t[]' => ['ADT_UINT32ARRAY', ''],
'uint64_t' => ['ADT_UINT64', ''],
'uint64_t*' => ['ADT_UINT64STAR', ''],
'm_label_t*' => ['ADT_MLABELSTAR', ''],
);
my $xlateLabel = $uniLabel.$xlateUniLabelInc;
my $xlateLabelInc = 0;
my $xlateLine = '';
my @jniLine = ();
# the list handling should be a simple loop with a loop of one
# falling out naturally.
unless ($type =~ /,/) { # if list, then generate sequence of entries
my $dataType;
my $dataSize;
my $xlateLabelRef = '';
my $arraySize = '';
$arraySize = $1 if ($type =~ s/\[(\d+)\]/[]/);
my $entryType = ${$entryDef{$type}}[0];
my @xlateType = (); # for adt_xlate.c
my $typeCount = 1;
if ($entryType) {
$dataType = $entryType;
$type =~ s/([^*]+)\s*(\*+)/$1 $2/;
$type =~ s/\[\]//;
$dataSize = "sizeof ($type)";
if ($arraySize) {
$dataSize = "$arraySize * " . $dataSize;
}
$xlateLine = "{{$dataType, $dataSize}}";
push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]);
} elsif ($type eq '') {
$xlateLabelRef = 'NULL';
} elsif ($type =~ /^msg/i) {
$type =~ s/^msg//i;
$dataType = 'ADT_MSG';
my $dataEnum = 'ADT_LIST_' . uc $type;
$xlateLine = "{{$dataType, $dataEnum}}";
push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]);
} elsif ($type =~ /time_t/i) {
$dataType = 'ADT_DATE';
$dataSize = "sizeof (time_t)";
$xlateLine = "{{$dataType, $dataSize}}";
push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]);
} elsif ($type =~ /termid/i) {
$dataType = 'ADT_TERMIDSTAR';
$dataSize = "sizeof (au_tid_addr_t *)";
$xlateLine = "{{$dataType, $dataSize}}";
push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]);
} elsif ($omitJNI) {
$xlateLabelRef = 'NULL';
} else {
print STDERR "$type is not an implemented data type\n";
$xlateLabelRef = 'NULL';
}
$xlateLabelRef = '&' . $xlateLabel . '[0]'
unless $xlateLabelRef eq 'NULL';
# "EOL" is where a comma should go unless end of list
$xlateLine = "{$token,\t1,\t$xlateLabelRef,\t$sequence,\n" .
"\t\t0,\t$required,\t$tsol,\t$format}EOL";
} else { # is a list
my @type = split(/,/, $type);
my @arraySize = ();
my @id = split(/,/, $id);
my @jniId = @id;
my $dataType;
my $typeCount = ($#type + 1);
my @xlateType = ();
my @default = ();
foreach my $dtype (@type) {
my $jniId = shift @jniId;
my $id = shift @id;
my $arraySize = '';
$arraySize = $1 if ($dtype =~ s/\[(\d+)\]/[]/);
my $entryType = ${$entryDef{$dtype}}[0];
if ($entryType) {
my $type = $dtype;
$type =~ s/([^*]+)\s*(\*+)/$1 $2/;
$type =~ s/\[\]//;
my $sizeString = "sizeof";
$sizeString = "$arraySize * " . $sizeString if $arraySize;
push (@xlateType, "\{$entryType, $sizeString ($type)\}");
push (@jniLine, [$jniId, $entryType, $format, $enumGroup, $required]);
} elsif ($type =~ /^msg/i) {
$type =~ s/^msg//i;
$dataType = 'ADT_MSG';
my $dataEnum = 'ADT_LIST_' . uc $type;
push (@xlateType, "\{$dataType, $dataEnum\}};");
push (@jniLine, [$jniId, $dataType, $format, $enumGroup, $required]);
} elsif ($type =~ /time_t/i) {
$dataType = 'ADT_DATE';
push (@xlateType, "\{$entryType, sizeof ($type)\}");
push (@jniLine, [$jniId, $entryType, $format, $enumGroup, $required]);
} elsif ($type =~ /termid/i) {
$dataType = 'ADT_TERMIDSTAR';
push (@xlateType, "\{$dataType, sizeof (au_tid_addr_t *)\}");
push (@jniLine, [$jniId, $dataType, $format, $enumGroup, $required]);
} elsif ($omitJNI) {
# nothing to do.
} else {
print STDERR "$dtype is not an implemented data type\n";
}
if (${$entryDef{$dtype}}[1]) {
push (@default, $id, ${$entryDef{$dtype}}[1]);
}
}
my $xlateArray = "\[$typeCount\] =\t{" . join(",\n\t\t\t\t", @xlateType) . "};";
$xlateLine =
"{$token,\t$typeCount,\t&$xlateLabel\[0\],\t$sequence,\n" .
"\t\t0,\t$required,\t$tsol,\t$format}EOL";
}
$xlateUniLabelInc++ if $xlateLabelInc;
return ($xlateLine, \@jniLine);
}
sub generateMsgLists {
my $textList = shift;
my $textName = $textList->getId();
my $header = $textList->getHeader();
my $start = $textList->getMsgStart();
my $public = $textList->getMsgPublic();
my $deprecated = $textList->getDeprecated();
print "$textName starts at $start\n" if $debug;
my $entry;
my @entry;
while ($entry = $textList->getNextMsg()) {
if ($debug) {
my ($id, $text) = split(/\s*::\s*/, $entry);
print " $id = $text\n";
}
unshift (@entry, $entry);
}
$msg_list{$textName} =
[\@entry, [$header, $start, $public, $deprecated]];
}
sub readAuditEventFile {
my $eventListFile = shift;
open(Event, $eventListFile)
or die "can't open $eventListFile: $!\n";
while(<Event>) {
next if /^\s*#/;
next if /^\s*$/;
my ($value, $name) = split(/\s*:\s*/);
next if $value < 6000;
$eventCode{$name} = $value;
}
close Event;
}