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