1#!/usr/perl5/bin/perl -w
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License (the "License").
7# You may not use this file except in compliance with the License.
8#
9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10# or http://www.opensolaris.org/os/licensing.
11# See the License for the specific language governing permissions
12# and limitations under the License.
13#
14# When distributing Covered Code, include this CDDL HEADER in each
15# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16# If applicable, add the following below this CDDL HEADER, with the
17# fields enclosed by brackets "[]" replaced with your own identifying
18# information: Portions Copyright [yyyy] [name of copyright owner]
19#
20# CDDL HEADER END
21#
22#
23# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26# ident	"%Z%%M%	%I%	%E% SMI"
27#
28
29# auditxml_jni [-d] <xml input file>
30
31# auditxml takes the audit record description (.xml file) and
32# generates the files needed for the Java
33
34use auditxml;
35use Getopt::Std;
36use vars qw($opt_d);
37use strict;
38
39
40our $debug = 0; # normal use is to set via the file being parsed.
41               # <debug set="on"/> or <debug set="off"/> or <debug/>
42               # if the set attribute is omitted, debug state is toggled
43               # Override with appDebug, but toggle won't do what you
44               # want.
45my $appDebug = 0; # used after return from "new auditxml";
46
47my $genNotice = "
48DO NOT EDIT. This file is auto generated by the Solaris Audit
49system from adt.xml.
50
51See http://opensolaris.org/os/project/audit/
52";
53
54# trim leading/trailing newlines
55$genNotice =~ s/^\n//s;
56$genNotice =~ s/\n$//s;
57my $prog = $0; $prog =~ s|.*/||g;
58my $usage = "usage: $prog [-d] file.xml\n";
59
60getopts('d');
61
62$appDebug = $opt_d;
63
64my $uniLabel = "adr";
65my $xlateUniLabelInc = 0;
66
67die $usage if ($#ARGV < 0);
68
69# where everything comes from and where it goes:
70
71my $templatePath = './';
72my $javaPath     = $templatePath;
73my $bsmBuildPath = "../libbsm";
74
75my $jniBuildPath = "$javaPath";
76
77my $buildPathJ	 = "$jniBuildPath/com/sun/audit";
78my $buildPathJNI = "$jniBuildPath/common";
79
80my $auditEventJ = "$buildPathJ/AuditEvent.java";
81my $jniC = "$buildPathJNI/adt_jni_event.c";
82my $mapFile = "$jniBuildPath/common/mapfile-vers";
83
84my $doc = new auditxml ($ARGV[0]);  # input XML file
85
86$debug = $appDebug;
87
88my %jniEventTable = ();
89my %externalIdNo = ();
90my %msg_list = ();
91my %eventCode = ();
92
93readAuditEventFile("$bsmBuildPath/audit_event.txt");
94
95my $event;
96while ($event = $doc->getNextEvent()) {
97    my $eventId = $event->getId();
98    my $idNo = $event->getIdNo();
99    $externalIdNo{$eventId} = $idNo;
100    my $super;
101    my $omit = $event->getOmit();
102    my $eventType = '';
103    if ($super = $event->getSuperClass()) {
104	$event = $super;
105	$eventType = 'instance';
106    } else {
107	$eventType = $event->getType();
108    }
109
110    # c file table for translation
111    generateTableC($event, $eventId, $eventType, undef, $omit);
112}
113
114while (my $textList = $doc->getNextMsgId()) {
115    generateMsgLists($textList);  # enum -> text mappings
116}
117
118printJavaFiles($jniC, $auditEventJ, $buildPathJ, $mapFile);
119
120exit 0;
121
122
123
124sub printJavaFiles {
125    my $jniFile = shift;
126    my $javaFile = shift;
127    my $subclassPath = shift;
128    my $mapFile = shift;
129
130    # warning: time_t is equated to jlong since there is no
131    # way to use sys/types.h in Java code.
132    # java long is C long long, 64 bits.
133    # java int is 32 bits.
134
135    my %java_jni = ('ADT_DATE'		=> ['long',	'jlong'],
136		    'ADT_UINT'		=> ['int',	'jint'],
137		    'ADT_INT'		=> ['int',	'jint'],
138		    'ADT_INT32'		=> ['int',	'jint'],
139		    'ADT_UID'		=> ['int',	'jint'],
140		    'ADT_GID'		=> ['int',	'jint'],
141		    'ADT_UIDSTAR'	=> ['int[]',	'jintArray'],
142		    'ADT_GIDSTAR'	=> ['int[]',	'jintArray'],
143		    'ADT_CHAR'		=> ['String',	'jchar'],
144		    'ADT_CHARSTAR'	=> ['String',	'jstring'],
145		    'ADT_CHAR2STAR'	=> ['String[]',	'jstring'],
146		    'ADT_MSG'		=> ['int',	'jint'],
147		    'ADT_PID'		=> ['int',	'jint'],
148# ADT_PRIVSTAR omitted -- not implemented and the audit records that
149# use it must be coded to emit no java.  We'll cross that bridge
150# when someone in Java land needs to generate a priv token.
151		    'ADT_LONG'		=> ['int',	'jint'],
152		    'ADT_TERMIDSTAR'	=> ['String',	'jstring'],	# hostname -> termid
153		    'ADT_ULONG'		=> ['int',	'jint'],
154		    'ADT_UINT16'	=> ['int',	'jint'],
155		    'ADT_UINT32'	=> ['int',	'jint'],
156		    'ADT_UINT32STAR'	=> ['int[]',	'jintArray'],
157# ADT_UINT32ARRAY omitted; no Java implementation yet
158		    'ADT_UINT64'	=> ['long',	'jlong'],
159		    'ADT_UINT64STAR'	=> ['long[]',	'jlongArray']
160		   );
161    my $noMemory = 'gettext("Out of memory")';
162
163    # open output files
164    open (Cfile, ">$jniFile") or
165	die "can't open output file ($jniFile): $!\n";
166    open (Jfile, ">$javaFile") or
167	die "can't open output file ($javaFile): $!\n";
168    open (MapFile, ">$mapFile") or
169	die "can't open output file ($mapFile): $!\n";
170
171    # write headers
172    my $notice = $genNotice;
173    $notice =~ s/\n/\n * /gs;
174    $notice =~ s/\s+\n/\n/gs;
175    print Cfile <<EOF;
176/*
177 * $notice
178 */
179
180#include "../../libbsm/common/adt_xlate.h"
181#include <jni.h>
182#include "../com/sun/audit/AuditSession.h"	/* javah output */
183#include "adt_jni.h"
184#include <stdlib.h>
185#include <string.h>
186
187static char *except_class = "java/lang/Exception";
188
189EOF
190    print Jfile <<EOF;
191/*
192 * $notice
193 */
194
195package com.sun.audit;
196
197public class AuditEvent {
198	protected AuditSession sh;	// associated session object
199
200	public AuditEvent(AuditSession auSession)
201	    throws Error
202	{
203
204		sh = auSession;
205	}
206
207	// See the subclasses of AuditEvent for mapping message codes
208	// to events
209EOF
210
211    my $notice_map = $genNotice;
212    $notice_map =~ s/\n/\n# /gs;
213    $notice_map =~ s/\s+\n/\n/gs;
214    print MapFile <<EOF;
215#
216# $notice_map
217#
218
219SUNWprivate_1.1 {
220    global:
221	c2j_pointer;
222	j2c_pointer;
223	Java_com_sun_audit_AuditSession_bsmAuditOn;
224	Java_com_sun_audit_AuditSession_startSession;
225	Java_com_sun_audit_AuditSession_endSession;
226	Java_com_sun_audit_AuditSession_dupSession;
227	Java_com_sun_audit_AuditSession_getSessionId;
228	Java_com_sun_audit_AuditSession_exportSessionData;
229	Java_com_sun_audit_AuditSession_sessionAttr;
230
231# One subclass of AuditEvent per audit record...
232EOF
233
234    # generate java final int classes to line up with string/enums
235
236    foreach my $listName (sort keys %msg_list) {
237        my $shortName = uc $listName;
238        $shortName =~ s/_TEXT//;
239        my ($listRef, $headref) = @{$msg_list{$listName}};
240        my @listValue =  @$listRef;
241        my ($header, $enumValue, $public, $deprecated) = @$headref;
242        my $listValue;
243
244        print Jfile "\n\t// adt_$listName" . "\n\n";
245        print Jfile "\tpublic static final int ADT_$shortName",
246    		" = $enumValue;\n" if $enumValue;
247
248        next unless ($#listValue >= 0);
249        print Jfile "\t// Deprecated message list\n" if $deprecated;
250        foreach $listValue (@listValue) {
251            my ($id, $text) = split(/\s*::\s*/, $listValue);
252    	    print Jfile "\t// $text\n";
253    	    print Jfile "\tpublic static final int ADT_$shortName";
254	    print Jfile "_$id = $enumValue;\n";
255    	    $enumValue++;
256        }
257    }
258
259    # generate event creation and access functions and event
260    # generation for both Java and JNI
261    # com.sun.audit.AuditEvent_xxx.java
262    foreach my $eventId (sort keys %jniEventTable) {
263	my ($ref1, $eventType, $allowedIds, $header) = @{$jniEventTable{$eventId}};
264	$eventCode{$eventId} = -1 if ($eventType eq 'generic');
265	my @entries = @$ref1;
266	my $entries = $#entries;
267	my $root = $eventId;
268	$root =~ s/AUE_//;
269	my $javaPutEvent = 'putEvent';
270	my $putMethod = "_$root";
271	$putMethod =~ s/_/_1/g;
272
273	my $jniPutEvent = "Java_com_sun_audit_AuditEvent$putMethod" . "_$javaPutEvent";
274
275	# the subclass file template isn't used; it may be needed to get
276	# the right file header stuff in place.  The subclassPath is
277	# the directory that contains 'em.
278
279	my $validSfile = 1;
280	unless (open(Sfile, ">$subclassPath/AuditEvent_$root.java")) {
281	    print STDERR "can't open class file AuditEvent_$root.java: $!\n";
282	    $validSfile = 0;
283	}
284	if ($eventCode{"AUE_$root"}) {
285	    if ($validSfile) {
286		print Sfile <<EOF;
287/*
288 * $notice
289 */
290
291package com.sun.audit;
292
293// audit event:  $eventId = $eventCode{"AUE_$root"}
294
295public class AuditEvent_$root extends AuditEvent {
296
297EOF
298	    }
299	} else {
300	    print STDERR "no event code for $eventId.  Is audit_event current?\n";
301	}
302	my $nativeParameterList = '';
303	my $jniParameterList = '';
304	my $specParameterList = '';
305	my $jniStorageList = '';
306	my $needCleanupTarget = 0;
307	my $jniFreeList = '';
308
309	my $haveStringDef = 0;
310	my $haveCDef = 0;
311	my $haveLengthDef = 0;
312	my $haveStringArrayDef = 0;
313	my $cntTermidDef = 0;
314	my $jniDefine;
315	my $needLocaleDefined = 0;
316	my $jniADTalloc;
317	if (defined $header && ($header > 0) ) {
318	    $jniDefine = "union union_of_events	*event;\n" .
319		"\tadt_session_data_t	*session;\n";
320	    $jniADTalloc = '(union union_of_events *)adt_alloc_event';
321	} else {
322	    $jniDefine = "adt_event_data_t	*event;\n" .
323		"\tadt_session_data_t	*session;\n";
324	    $jniADTalloc = 'adt_alloc_event';
325	}
326	my $ref2;
327	foreach $ref2 (@entries) {
328	    my ($id, $type) = @$ref2;
329	    my $jniRoot = $root . $id;
330	    $jniRoot =~ s/_/_1/g;  # escape unicode "_"
331
332	    my $p_event;
333	    if (defined $header && ($header > 0) ) {
334		$p_event = "event->d$header.adt_$root.$id";
335	    } else {
336		$p_event = "event->adt_$root.$id";
337	    }
338
339	    if ($type eq 'ADT_UINT32STAR') { # int array
340	        $needLocaleDefined = 1;
341
342
343	        $jniStorageList .= <<EOF;
344	/* $id */
345	length = (*env)->GetArrayLength(env, $id);
346	$p_event =
347	    (int *)malloc(length * sizeof (int));
348	if ($p_event == NULL) {
349		locale = I18N_SETUP;
350		local_throw(env, except_class,
351		    $noMemory);
352		(void) setlocale(LC_MESSAGES, locale);
353		goto cleanup;
354	}
355	(*env)->GetIntArrayRegion(env, $id, 0, length,
356	    (int *)$p_event);
357EOF
358
359
360		$jniFreeList .= "\n\tif ($p_event != NULL)\n" .
361		    "\t\tfree($p_event);\n";
362		unless ($haveLengthDef) {
363		    $haveLengthDef = 1;
364		    $jniDefine .= "\tint\t\t\tlength;\n";
365		}
366		$nativeParameterList .= ",\n\t    int[]\t$id";
367		$jniParameterList .= ",\n    jintArray\t$id";
368		$specParameterList .= ", jintArray";
369		$needCleanupTarget = 1;
370	    } elsif (($type eq 'ADT_UIDSTAR') ||
371		     ($type eq 'ADT_GIDSTAR')) { # gid_t array
372		my $cType = 'uid_t';
373		$cType = 'gid_t' if ($type eq 'ADT_GIDSTAR');
374		$needLocaleDefined = 1;
375
376
377		$jniStorageList .= <<EOF;
378	/* $id */
379	length = (*env)->GetArrayLength(env, $id);
380	$p_event =
381	    ($cType *)malloc(length * sizeof ($cType));
382	if ($p_event == NULL) {
383		locale = I18N_SETUP;
384		local_throw(env, except_class,
385		    $noMemory);
386		(void) setlocale(LC_MESSAGES, locale);
387		goto cleanup;
388	}
389	(*env)->GetIntArrayRegion(env, $id, 0, length,
390	    (int *)$p_event);
391EOF
392
393
394		$jniFreeList .=
395		    "\n\tif ($p_event != NULL)\n" .
396		    "\t\tfree($p_event);\n";
397		unless ($haveLengthDef) {
398		    $haveLengthDef = 1;
399		    $jniDefine .= "\tint\t\t\tlength;\n";
400		}
401		$nativeParameterList .= ",\n\t    int[]\t$id";
402		$jniParameterList .= ",\n    jintArray\t$id";
403		$specParameterList .= ", jintArray";
404		$needCleanupTarget = 1;
405	    } elsif ($type eq 'ADT_UINT64STAR') { # long array
406	        $needLocaleDefined = 1;
407	        $jniStorageList .= <<EOF;
408	/* $id */
409	length = (*env)->GetArrayLength(env, $id);
410	$p_event =
411	    (long *)malloc(length * sizeof (long long));
412	if ($p_event == NULL) {
413		locale = I18N_SETUP;
414		local_throw(env, except_class,
415		    $noMemory);
416		(void) setlocale(LC_MESSAGES, locale);
417		goto cleanup;
418	}
419	(*env)->GetLongArrayRegion(env, $id, 0, length,
420	    $p_event);
421EOF
422		$jniFreeList .= "\n\tif ($p_event != NULL)\n" .
423		    "\t\tfree($p_event);\n";
424		unless ($haveLengthDef) {
425		    $haveLengthDef = 1;
426		    $jniDefine .= "\tint\t\t\tlength;\n";
427		}
428		$nativeParameterList .= ",\n\t    long[]\t$id";
429		$jniParameterList .= ",\n    jlongArray\t$id";
430		$specParameterList .= ", jlongArray";
431		$needCleanupTarget = 1;
432	    } elsif ($type eq 'ADT_CHAR') { # string in Java, char in C
433		$jniStorageList .= <<EOF;
434
435	/* $id */
436	c = (char *)(*env)->GetStringUTFChars(env, $id, NULL);
437	if (c == NULL)
438		goto cleanup; /* exception thrown */
439	$p_event = *c;
440	(*env)->ReleaseStringUTFChars(env, $id, c);
441EOF
442		# no need to free anything
443		unless ($haveCDef) {
444		    $haveCDef = 1;
445		    $jniDefine .= "\tchar\t\t\t*c\n";
446		}
447		$nativeParameterList .= ",\n\t    String\t$id";
448		$jniParameterList .= ",\n    jstring\t$id";
449		$specParameterList .= ", jstring";
450	    } elsif ($type eq 'ADT_CHARSTAR') {
451	        $needLocaleDefined = 1;
452		$jniStorageList .= <<EOF;
453	/* $id */
454	if ($id != NULL) {
455		string = (char *)(*env)->GetStringUTFChars(
456		    env, $id, NULL);
457		if (string == NULL)
458			goto cleanup; /* exception thrown */
459		$p_event = strdup(string);
460		(*env)->ReleaseStringUTFChars(env, $id, string);
461		if ($p_event == NULL) {
462			locale = I18N_SETUP;
463			local_throw(env, except_class,
464			    $noMemory);
465			(void) setlocale(LC_MESSAGES, locale);
466			goto cleanup;
467		}
468	}
469EOF
470		$jniFreeList .= "\n\tif ($p_event != NULL)\n" .
471		    "\t\tfree($p_event);\n";
472		unless ($haveStringDef) {
473		    $haveStringDef = 1;
474		    $jniDefine .= "\tchar\t\t\t*string;\n";
475		}
476		$nativeParameterList .= ",\n\t    String\t$id";
477		$jniParameterList .= ",\n    jstring\t$id";
478		$specParameterList .= ", jstring";
479		$needCleanupTarget = 1;
480	    } elsif ($type eq 'ADT_CHAR2STAR') { # array of string
481	        $needLocaleDefined = 1;
482		$jniStorageList .= <<EOF;
483	/* $id */
484	length = (*env)->GetArrayLength(env, $id);
485	$p_event = (char **)malloc(length
486	    * sizeof (char *));
487	if ($p_event == NULL) {
488		locale = I18N_SETUP;
489		local_throw(env, except_class,
490		    $noMemory);
491		(void) setlocale(LC_MESSAGES, locale);
492		goto cleanup;
493	}
494	p = $p_event;
495	for (i = 0; i < length; i++) {
496		jString = (*env)->GetObjectArrayElement(env, $id, i);
497		string = (char *)(*env)->GetStringUTFChars(
498		    env, jString, NULL);
499		if (string == NULL)
500			goto cleanup; /* exception thrown */
501		*p = strdup(string);
502		(*env)->ReleaseStringUTFChars(env, jString, string);
503		if (*p == NULL) {
504			locale = I18N_SETUP;
505			local_throw(env, except_class,
506			    $noMemory);
507			(void) setlocale(LC_MESSAGES, locale);
508			while (p >= $p_event)
509				free(*p--);
510			goto cleanup;
511		}
512		p++;
513	}
514EOF
515		$jniFreeList .=
516		    "\n\tif ($p_event != NULL)\n" .
517		    "\t\tfree($p_event);\n";
518		unless ($haveStringArrayDef) {
519		    unless ($haveStringDef) {
520			$haveStringDef = 1;
521			$jniDefine .= <<EOF;
522	char			*string;
523EOF
524		    }
525		    unless ($haveLengthDef) {
526			$haveLengthDef = 1;
527			$jniDefine .= <<EOF;
528	int			length;
529EOF
530		    }
531		    $haveStringArrayDef = 1;
532		    $jniDefine .= <<EOF;
533	int			i;
534	char			**p;
535	jstring			jString;
536EOF
537		}
538		$nativeParameterList .= ",\n\t    String[]\t$id";
539		$jniParameterList .= ",\n    jstring\t$id";
540		$specParameterList .= ", jstring";
541		$needCleanupTarget = 1;
542	      } elsif ($type eq 'ADT_TERMIDSTAR') {
543	        $needLocaleDefined = 1;
544
545	        $jniStorageList .= <<EOF;
546	/* $id */
547	hostname$cntTermidDef = (char *)(*env)->GetStringUTFChars(env, $id, NULL);
548
549	if (adt_load_hostname((const char *)hostname$cntTermidDef, &termid$cntTermidDef)) {
550		local_throw(env, except_class,
551			gettext("hostname lookup failed"));
552	}
553	$p_event = termid$cntTermidDef;
554
555	(*env)->ReleaseStringUTFChars(env, $id, hostname$cntTermidDef);
556EOF
557
558		$jniFreeList .= "\n\tif (hostname$cntTermidDef != NULL)\n" .
559		    "\t\tfree(hostname$cntTermidDef);\n";
560		$jniFreeList .= "\n\tif (termid$cntTermidDef != NULL)\n" .
561		    "\t\tfree(termid$cntTermidDef);\n";
562
563		$jniDefine .= "\tchar\t\t\t*hostname$cntTermidDef;\n";
564		$jniDefine .= "\tadt_termid_t\t\t*termid$cntTermidDef;\n"; #djdj
565
566		$cntTermidDef++;
567
568		my ($nativeParameter, $jniParameter) = @{$java_jni{$type}};
569		$nativeParameterList .= ",\n\t    $nativeParameter\t$id";
570		$jniParameterList .= ",\n    $jniParameter\t$id";
571		$specParameterList .= ", $jniParameter";
572		$needCleanupTarget = 1;
573	    } else {  # all others are primitive types
574		$jniStorageList .= "\n\t$p_event = $id;\n";
575		my ($nativeParameter, $jniParameter) = @{$java_jni{$type}};
576		$nativeParameter = "$nativeParameter\t"
577		    if length $nativeParameter < 4;  # why?
578		$nativeParameterList .= ",\n\t    $nativeParameter\t$id";
579		$jniParameterList .= ",\n    $jniParameter\t$id";
580		$specParameterList .= ", $jniParameter";
581	    }
582	}
583	if ($needLocaleDefined) {
584		$jniDefine .= <<EOF
585	char			*locale;
586EOF
587	}
588	my $genericOverride = '';
589	my $idParameter = $eventId;
590	$idParameter =~ s/AUE_/ADT_/;
591	if ($eventType eq 'generic') {
592	    $genericOverride = ', jint eventId';
593	    $idParameter = 'eventId';
594	}
595	$jniFreeList = "\tcleanup:\n" . $jniFreeList if $needCleanupTarget;
596
597	print Cfile qq{/* ARGSUSED */
598JNIEXPORT void JNICALL
599$jniPutEvent(
600    JNIEnv	*env,
601    jobject	self,
602    jbyteArray	jsession$genericOverride,
603    jint	status,
604    jint	ret_val$jniParameterList)
605{
606	$jniDefine
607	(void) j2c_pointer(env, jsession, (char **)&session);
608
609	event = $jniADTalloc(session, $idParameter);
610
611$jniStorageList
612	(void) adt_put_event((adt_event_data_t *)event, status, ret_val);
613
614$jniFreeList
615	adt_free_event((adt_event_data_t *)event);
616}
617};
618	print MapFile qq{
619	$jniPutEvent; };
620	my $overrideParameter = '';
621	if ($eventType eq 'generic') {
622	    $overrideParameter = 'int eventId,';
623	    my @allowed = @$allowedIds;
624	    if (@allowed) {
625		my $i;
626		if ($validSfile) {
627		    print Sfile "\t// Allowed values for eventId in putEvent:\n";
628		    for ($i = 0; $i <= $#allowed; $i++) {
629			my $idNo = $externalIdNo{$allowed[$i]};
630			$allowed[$i] =~ s/AUE_/ADT_/;
631			print Sfile "\tstatic final int $allowed[$i] = ",
632			     "$idNo;\n";
633		    }
634		    print Sfile "\n";
635		}
636	    } else {
637		print STDERR "Generic event with no allowed instances: $eventId\n";
638	    }
639	}
640	if ($validSfile) {
641	    print Sfile <<EOF;
642	private native void $javaPutEvent(byte[]session, $overrideParameter
643	    int status, int ret_val$nativeParameterList);
644
645	public AuditEvent_$root(AuditSession session)
646		throws Exception
647	{
648		super(session);
649	}
650
651EOF
652	    my $javaParameterList = '';
653	    foreach $ref2 (@entries) {
654		my ($id, $type, $format, $jComment, $required) = @$ref2;
655
656		# generate java native method prototypes
657		# and the corresponding C method implementation
658
659		my $javaMethodName = "$id";
660		my $javaStorageName = $javaMethodName . '_val';
661		my $jniMethodName = $root . $id;
662		my $storage;
663		my $enumUsage = '';
664		my $jParam = @{$java_jni{$type}}[0];
665		my $comment = '';
666		if ($required) {
667		    if ($format ne 'NULL') {
668			$comment = "\t// (required) formatted:  $format";
669		    } else {
670			$comment = "\t// required";
671		    }
672		} else {
673		    if ($format ne 'NULL') {
674			$comment = "\t// (optional) formatted:  $format";
675		    } else {
676			$comment = "\t// optional";
677		    }
678		}
679		if (($type eq 'ADT_UINT32STAR') ||
680		    ($type eq 'ADT_UIDSTAR') ||
681		    ($type eq 'ADT_GIDSTAR')) { # int array
682		    $storage = "int[] $javaStorageName" . ($required ?
683							   ' = {}' : '');
684		    $javaParameterList .= ",\n\t\t\t    $javaStorageName";
685		} elsif ($type eq 'ADT_UINT64STAR') { # long array
686		    $storage = "long[] $javaStorageName" . ($required ?
687							    ' = {}' : '');
688		    $javaParameterList .= ",\n\t\t\t    $javaStorageName";
689		} elsif (($type eq 'ADT_CHARSTAR') ||
690			 ($type eq 'ADT_CHAR')) { # string
691		    $storage = "String $javaStorageName" . ($required ?
692							    ' = ""' : '');
693		    $javaParameterList .= ",\n\t\t\t    $javaStorageName";
694		} elsif ($type eq 'ADT_CHAR2STAR') { # array of string
695		    $storage = "String[] $javaStorageName" . ($required ?
696							      ' = {}' : '');
697		    $javaParameterList .= ",\n\t\t\t    $javaStorageName";
698		} elsif ($type eq 'ADT_TERMIDSTAR') { # array of string
699		    $storage = "String $javaStorageName" . ($required ?
700							    ' = ""' : '');
701		    $javaParameterList .= ",\n\t\t\t    $javaStorageName";
702		} else {  # all others are primitive types
703		    $storage = "$jParam $javaStorageName = 0";
704		    $javaParameterList .= ",\n\t\t\t    $javaStorageName";
705		    $enumUsage = "\n\t// See $jComment in AuditEvent.java for valid values"
706			if $jComment;
707		}
708		print Sfile <<EOF;
709$enumUsage
710	private $storage;$comment
711	public void $javaMethodName($jParam setTo)
712	{
713		$javaStorageName = setTo;
714	}
715EOF
716	    }	# end foreach (@entries)
717	    if ($eventType eq 'generic') {
718		print Sfile <<EOF;
719
720	public void putEvent(int status, int ret_val, int eventId)
721	{
722		byte[]	session = super.sh.getSession();
723
724		if ((super.sh.AuditIsOn) && (super.sh.ValidSession))
725			$javaPutEvent(session, eventId,
726			    status, ret_val$javaParameterList);
727	}
728}
729EOF
730	    } else {
731		print Sfile <<EOF;
732
733	public void putEvent(int status, int ret_val)
734	{
735		byte[]	session = super.sh.getSession();
736
737		if ((super.sh.AuditIsOn) && (super.sh.ValidSession))
738			$javaPutEvent(session, status, ret_val$javaParameterList);
739	}
740}
741EOF
742	    }
743	    close Sfile;
744	}	# end if ($validSfile);
745    }
746
747    # write trailers
748    print Jfile <<EOF;
749
750}
751EOF
752    print MapFile <<EOF;
753
754    local:
755	*;
756};
757EOF
758    close Cfile;
759    close Jfile;
760    close MapFile;
761}
762
763sub generateTableC {
764    my $event = shift;
765    my $eventId = shift;
766    my $eventType = shift;
767    my $eventHeader = shift;
768    my $omit = shift;
769
770    my %tokenType = (
771		  'acl'			=> 'AUT_ACL',
772		  'arbitrary'		=> 'AUT_ARBITRARY',
773		  'arg'			=> 'AUT_ARG',
774		  'attr'		=> 'AUT_ATTR',
775		  'command'		=> 'AUT_CMD',
776		  'command_1'		=> 'ADT_CMD_ALT',	# dummy token id
777		  'date'		=> 'AUT_TEXT',
778		  'exec_args'   	=> 'AUT_EXEC_ARGS',
779		  'exec_env'    	=> 'AUT_EXEC_ENV',
780		  'exit'        	=> 'AUT_EXIT',
781		  'file'        	=> 'AUT_FILE',
782		  'fmri'        	=> 'AUT_FMRI',
783		  'groups'      	=> 'AUT_GROUPS',
784	#	  'header'      	=> 'AUT_HEADER',	# not used
785		  'in_addr'     	=> 'AUT_IN_ADDR',
786		  'tid'          	=> 'AUT_TID',
787		  'ipc'         	=> 'AUT_IPC',
788		  'ipc_perm'    	=> 'AUT_IPC_PERM',
789		  'iport'		=> 'AUT_IPORT',
790		  'label'		=> 'AUT_LABEL',
791		  'newgroups'   	=> 'AUT_NEWGROUPS',
792		  'opaque'      	=> 'AUT_OPAQUE',
793		  'path'        	=> 'AUT_PATH',
794		  'path_list'		=> '-AUT_PATH',		# dummy token id
795		  'process'     	=> 'AUT_PROCESS',
796		  'priv_effective'	=> 'ADT_AUT_PRIV_E',	# dummy token id
797		  'priv_limit'		=> 'ADT_AUT_PRIV_L', 	# dummy token id
798		  'priv_inherit'	=> 'ADT_AUT_PRIV_I',	# dummy token id
799		  'return'      	=> 'AUT_RETURN',
800		  'seq'         	=> 'AUT_SEQ',
801		  'socket'      	=> 'AUT_SOCKET',
802		  'socket-inet' 	=> 'AUT_SOCKET_INET',
803		  'subject'     	=> 'AUT_SUBJECT',
804		  'text'        	=> 'AUT_TEXT',
805	#	  'trailer'     	=> 'AUT_TRAILER',	# not used
806		  'uauth'		=> 'AUT_UAUTH',
807		  'zonename'		=> 'AUT_ZONENAME'
808		 );
809
810    my @xlateEntryList = ();
811    my @jniEntryList = ();
812
813    my $external = $event->getExternal();
814    my $internal = $event->getInternal();
815
816    unless ($external) {
817	print STDERR "No external object captured for event $eventId\n";
818	return;
819    }
820    unless ($internal) {
821	print STDERR "No internal object captured for event $eventId\n";
822	return;
823    }
824    my @entryRef = $internal->getEntries();
825    my $entryRef;
826    my @tokenOrder = ();
827    my $firstTokenIndex = 0; # djdj not used yet, djdj BUG!
828    			     # needs to be used by translate table
829
830    if ($internal->isReorder()) { # prescan the entry list to get the token order
831      my @inputOrder;
832      foreach $entryRef (@entryRef) {
833	my ($intEntry, $entry) = @$entryRef;
834	push (@inputOrder, $intEntry->getAttr('order'));
835      }
836
837      my $i; # walk down the inputOrder list once
838      my $k = 1; # discover next in line
839      my $l = 0; # who should point to next in line
840      for ($i = 0; $i <= $#inputOrder; $i++) {
841	my $j;
842	for ($j = 0; $j <= $#inputOrder; $j++) {
843	  if ($k == $inputOrder[$j]) {
844	    if ($k == 1) {
845	        $firstTokenIndex = $j;
846	    } else {
847	        $tokenOrder[$l] = "&(selfReference[$j])";
848	    }
849	    $l = $j;
850	    last;
851	  }
852	}
853	$k++;
854      }
855      $tokenOrder[$l] = 'NULL';
856    }
857    else { # default order -- input order same as output
858      my $i;
859      my $j;
860      for ($i = 0; $i < $#entryRef; $i++) {
861	my $j = $i + 1;
862	$tokenOrder[$i] = "&(selfReference[$j])";
863      }
864      $tokenOrder[$#entryRef] = 'NULL';
865    }
866
867    my $sequence = 0;
868    foreach $entryRef (@entryRef) {
869      my ($intEntry, $entry) = @$entryRef;
870      my $entryId = $entry->getAttr('id');
871
872      my ($extEntry, $unusedEntry, $tokenId) =
873	$external->getEntry($entryId);
874      my $opt = $extEntry->getAttr('opt');
875
876      if ($opt eq 'none') {
877	if (defined ($doc->getToken($tokenId))) {
878	  if (defined ($tokenType{$tokenId})) {
879	    $tokenId = $tokenType{$tokenId};
880	  }
881	  else {
882	    print STDERR "token id $tokenId not implemented\n";
883	  }
884	}
885	else {
886	  print STDERR "token = $tokenId is undefined\n";
887	  $tokenId = 'error';
888	}
889	my ($xlate, $jni) =
890	  formatTableEntry ('', $tokenId, $eventId, '', 0, 0, $tokenOrder[$sequence],
891			    'NULL', '');
892	push (@xlateEntryList, $xlate);
893	push (@jniEntryList, @$jni);
894      }
895      else {
896	my $dataType = $extEntry->getAttr('type');
897	$dataType =~ s/\s+//g;   # remove blanks (char * => char*)
898
899	my $enumGroup = '';
900	if ($dataType =~ /^msg/i) {
901	    $enumGroup = $dataType;
902	    $enumGroup =~ s/^msg\s*//i;
903	    $enumGroup = 'adt_' . $enumGroup;
904	}
905	my $required = ($opt eq 'required') ? 1 : 0;
906	my $tsol = 0;
907	my $tokenId = $intEntry->getAttr('token');
908	my $token;
909	my $tokenName;
910	my $tokenFormat = $intEntry->getAttr('format');
911	if (defined ($tokenFormat)) {
912	  $tokenFormat = "\"$tokenFormat\"";
913	}
914	else {
915	  $tokenFormat = 'NULL';
916	}
917
918	if (defined ($token = $doc->getToken($tokenId))) {
919	  $tsol = (lc $token->getUsage() eq 'tsol') ? 1 : 0;
920	  if (defined ($tokenType{$tokenId})) {
921	    $tokenName = $tokenType{$tokenId};
922	  }
923	  else {
924	    print STDERR "token id $tokenId not implemented\n";
925	  }
926	}
927	else {
928	  print STDERR
929	    "$tokenId is an unimplemented token ($entryId in $eventId)\n";
930	  $tokenName = 'AUT_TEXT';
931	}
932	my ($xlate, $jni) =
933	  formatTableEntry($entryId, $tokenName, $eventId, $dataType, $required,
934			   $tsol, $tokenOrder[$sequence], $tokenFormat,
935			   $enumGroup, (uc $omit eq 'JNI'));
936	push (@xlateEntryList, $xlate);
937	push (@jniEntryList, @$jni);
938      }
939      $sequence++;
940    }
941    $jniEventTable{$eventId} = [\@jniEntryList, $eventType,
942				$external->getAllowedTypes(), $eventHeader]
943	unless (uc $omit eq 'JNI') || ($omit eq 'always');
944}
945
946sub formatTableEntry {
947    my ($id, $token, $eventId, $type, $required, $tsol, $sequence, $format, $enumGroup,
948	$omitJNI) = @_;
949
950
951    # does this map belong in the xml source?  (at least the defaults?)
952    # fill in the default value only if it is other than zero.
953    #		      base type		    adt name,	default value
954    my %entryDef = ( 'au_asid_t'       	=> ['ADT_UINT32',	''],
955		     'uint_t'		=> ['ADT_UINT32',      	''],
956		     'int'		=> ['ADT_INT',		''],
957		     'int32_t'		=> ['ADT_INT32',	''],
958		     'uid_t'		=> ['ADT_UID',		'AU_NOAUDITID'],
959		     'gid_t'		=> ['ADT_GID',		'AU_NOAUDITID'],
960		     'uid_t*'		=> ['ADT_UIDSTAR',	''],
961		     'gid_t*'		=> ['ADT_GIDSTAR',	''],
962		     'char'		=> ['ADT_CHAR',		''],
963		     'char*'		=> ['ADT_CHARSTAR',	''],
964		     'char**'		=> ['ADT_CHAR2STAR',	''],
965		     'long'		=> ['ADT_LONG',		''],
966		     'pid_t'		=> ['ADT_PID',		''],
967		     'priv_set_t*'	=> ['ADT_PRIVSTAR',	''],
968		     'ulong_t'		=> ['ADT_ULONG',	''],
969		     'uint16_t',	=> ['ADT_UINT16',	''],
970		     'uint32_t'		=> ['ADT_UINT32',	''],
971		     'uint32_t*'	=> ['ADT_UINT32STAR',	''],
972		     'uint32_t[]'	=> ['ADT_UINT32ARRAY',  ''],
973		     'uint64_t'		=> ['ADT_UINT64',	''],
974		     'uint64_t*'	=> ['ADT_UINT64STAR',	''],
975		     'm_label_t*'	=> ['ADT_MLABELSTAR',	''],
976		    );
977    my $xlateLabel = $uniLabel.$xlateUniLabelInc;
978    my $xlateLabelInc = 0;
979    my $xlateLine = '';
980    my @jniLine = ();
981
982	# the list handling should be a simple loop with a loop of one
983        # falling out naturally.
984
985    unless ($type =~ /,/) {	# if list, then generate sequence of entries
986      my $dataType;
987      my $dataSize;
988      my $xlateLabelRef = '';
989
990      my $arraySize = '';
991      $arraySize = $1 if ($type =~ s/\[(\d+)\]/[]/);
992
993      my $entryType = ${$entryDef{$type}}[0];
994
995      my @xlateType = ();	# for adt_xlate.c
996      my $typeCount = 1;
997
998      if ($entryType) {
999	$dataType = $entryType;
1000	$type =~ s/([^*]+)\s*(\*+)/$1 $2/;
1001	$type =~ s/\[\]//;
1002	$dataSize = "sizeof ($type)";
1003	if ($arraySize) {
1004		$dataSize = "$arraySize * " . $dataSize;
1005	}
1006	$xlateLine = "{{$dataType, $dataSize}}";
1007	push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]);
1008      } elsif ($type eq '') {
1009	  $xlateLabelRef = 'NULL';
1010      } elsif ($type =~ /^msg/i) {
1011	$type =~ s/^msg//i;
1012	$dataType = 'ADT_MSG';
1013	my $dataEnum = 'ADT_LIST_' . uc $type;
1014	$xlateLine = "{{$dataType, $dataEnum}}";
1015	push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]);
1016      } elsif ($type =~ /time_t/i) {
1017	$dataType = 'ADT_DATE';
1018	$dataSize = "sizeof (time_t)";
1019	$xlateLine = "{{$dataType, $dataSize}}";
1020	push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]);
1021      } elsif ($type =~ /termid/i) {
1022	$dataType = 'ADT_TERMIDSTAR';
1023	$dataSize = "sizeof (au_tid_addr_t *)";
1024	$xlateLine = "{{$dataType, $dataSize}}";
1025	push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]);
1026      } elsif ($omitJNI) {
1027	$xlateLabelRef = 'NULL';
1028      } else {
1029	print STDERR "$type is not an implemented data type\n";
1030	$xlateLabelRef = 'NULL';
1031      }
1032      $xlateLabelRef = '&' . $xlateLabel . '[0]'
1033	unless $xlateLabelRef eq 'NULL';
1034
1035      # "EOL" is where a comma should go unless end of list
1036      $xlateLine = "{$token,\t1,\t$xlateLabelRef,\t$sequence,\n" .
1037	  "\t\t0,\t$required,\t$tsol,\t$format}EOL";
1038
1039    } else {	# is a list
1040      my @type = split(/,/, $type);
1041      my @arraySize = ();
1042      my @id   = split(/,/, $id);
1043      my @jniId  = @id;
1044      my $dataType;
1045      my $typeCount = ($#type + 1);
1046      my @xlateType = ();
1047      my @default = ();
1048
1049      foreach my $dtype (@type) {
1050	my $jniId = shift @jniId;
1051	my $id = shift @id;
1052	my $arraySize = '';
1053	$arraySize = $1 if ($dtype =~ s/\[(\d+)\]/[]/);
1054
1055	my $entryType = ${$entryDef{$dtype}}[0];
1056	if ($entryType) {
1057	  my $type = $dtype;
1058	  $type =~ s/([^*]+)\s*(\*+)/$1 $2/;
1059	  $type =~ s/\[\]//;
1060
1061	  my $sizeString = "sizeof";
1062	  $sizeString = "$arraySize * " . $sizeString if $arraySize;
1063	  push (@xlateType, "\{$entryType, $sizeString ($type)\}");
1064	  push (@jniLine, [$jniId, $entryType, $format, $enumGroup, $required]);
1065	} elsif ($type =~ /^msg/i) {
1066	  $type =~ s/^msg//i;
1067	  $dataType = 'ADT_MSG';
1068	  my $dataEnum = 'ADT_LIST_' . uc $type;
1069	  push (@xlateType, "\{$dataType, $dataEnum\}};");
1070	  push (@jniLine, [$jniId, $dataType, $format, $enumGroup, $required]);
1071	} elsif ($type =~ /time_t/i) {
1072	  $dataType = 'ADT_DATE';
1073	  push (@xlateType, "\{$entryType, sizeof ($type)\}");
1074	  push (@jniLine, [$jniId, $entryType, $format, $enumGroup, $required]);
1075	} elsif ($type =~ /termid/i) {
1076	  $dataType = 'ADT_TERMIDSTAR';
1077	  push (@xlateType, "\{$dataType, sizeof (au_tid_addr_t *)\}");
1078	  push (@jniLine, [$jniId, $dataType, $format, $enumGroup, $required]);
1079	} elsif ($omitJNI) {
1080	  # nothing to do.
1081	} else {
1082	  print STDERR "$dtype is not an implemented data type\n";
1083	}
1084	if (${$entryDef{$dtype}}[1]) {
1085	  push (@default, $id, ${$entryDef{$dtype}}[1]);
1086	}
1087      }
1088      my $xlateArray = "\[$typeCount\] =\t{" . join(",\n\t\t\t\t", @xlateType) . "};";
1089
1090      $xlateLine =
1091	"{$token,\t$typeCount,\t&$xlateLabel\[0\],\t$sequence,\n" .
1092        "\t\t0,\t$required,\t$tsol,\t$format}EOL";
1093    }
1094    $xlateUniLabelInc++ if $xlateLabelInc;
1095    return ($xlateLine, \@jniLine);
1096}
1097
1098sub generateMsgLists {
1099    my $textList = shift;
1100
1101    my $textName = $textList->getId();
1102    my $header = $textList->getHeader();
1103    my $start = $textList->getMsgStart();
1104    my $public = $textList->getMsgPublic();
1105    my $deprecated = $textList->getDeprecated();
1106
1107    print "$textName starts at $start\n" if $debug;
1108
1109    my $entry;
1110    my @entry;
1111    while ($entry = $textList->getNextMsg()) {
1112        if ($debug) {
1113	    my ($id, $text) = split(/\s*::\s*/, $entry);
1114	    print "   $id = $text\n";
1115	}
1116	unshift (@entry, $entry);
1117    }
1118    $msg_list{$textName} =
1119	[\@entry, [$header, $start, $public, $deprecated]];
1120}
1121sub readAuditEventFile {
1122    my $eventListFile = shift;
1123
1124  open(Event, $eventListFile)
1125    or die "can't open $eventListFile: $!\n";
1126  while(<Event>) {
1127    next if /^\s*#/;
1128    next if /^\s*$/;
1129    my ($value, $name) = split(/\s*:\s*/);
1130    next if $value < 6000;
1131    $eventCode{$name} = $value;
1132  }
1133  close Event;
1134}
1135
1136