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
230# One subclass of AuditEvent per audit record...
231EOF
232
233    # generate java final int classes to line up with string/enums
234
235    foreach my $listName (sort keys %msg_list) {
236        my $shortName = uc $listName;
237        $shortName =~ s/_TEXT//;
238        my ($listRef, $headref) = @{$msg_list{$listName}};
239        my @listValue =  @$listRef;
240        my ($header, $enumValue, $public, $deprecated) = @$headref;
241        my $listValue;
242
243        print Jfile "\n\t// adt_$listName" . "\n\n";
244        print Jfile "\tpublic static final int ADT_$shortName",
245    		" = $enumValue;\n" if $enumValue;
246
247        next unless ($#listValue >= 0);
248        print Jfile "\t// Deprecated message list\n" if $deprecated;
249        foreach $listValue (@listValue) {
250            my ($id, $text) = split(/\s*::\s*/, $listValue);
251    	    print Jfile "\t// $text\n";
252    	    print Jfile "\tpublic static final int ADT_$shortName";
253	    print Jfile "_$id = $enumValue;\n";
254    	    $enumValue++;
255        }
256    }
257
258    # generate event creation and access functions and event
259    # generation for both Java and JNI
260    # com.sun.audit.AuditEvent_xxx.java
261    foreach my $eventId (sort keys %jniEventTable) {
262	my ($ref1, $eventType, $allowedIds, $header) = @{$jniEventTable{$eventId}};
263	$eventCode{$eventId} = -1 if ($eventType eq 'generic');
264	my @entries = @$ref1;
265	my $entries = $#entries;
266	my $root = $eventId;
267	$root =~ s/AUE_//;
268	my $javaPutEvent = 'putEvent';
269	my $putMethod = "_$root";
270	$putMethod =~ s/_/_1/g;
271
272	my $jniPutEvent = "Java_com_sun_audit_AuditEvent$putMethod" . "_$javaPutEvent";
273
274	# the subclass file template isn't used; it may be needed to get
275	# the right file header stuff in place.  The subclassPath is
276	# the directory that contains 'em.
277
278	my $validSfile = 1;
279	unless (open(Sfile, ">$subclassPath/AuditEvent_$root.java")) {
280	    print STDERR "can't open class file AuditEvent_$root.java: $!\n";
281	    $validSfile = 0;
282	}
283	if ($eventCode{"AUE_$root"}) {
284	    if ($validSfile) {
285		print Sfile <<EOF;
286/*
287 * $notice
288 */
289
290package com.sun.audit;
291
292// audit event:  $eventId = $eventCode{"AUE_$root"}
293
294public class AuditEvent_$root extends AuditEvent {
295
296EOF
297	    }
298	} else {
299	    print STDERR "no event code for $eventId.  Is audit_event current?\n";
300	}
301	my $nativeParameterList = '';
302	my $jniParameterList = '';
303	my $specParameterList = '';
304	my $jniStorageList = '';
305	my $needCleanupTarget = 0;
306	my $jniFreeList = '';
307
308	my $haveStringDef = 0;
309	my $haveCDef = 0;
310	my $haveLengthDef = 0;
311	my $haveStringArrayDef = 0;
312	my $cntTermidDef = 0;
313	my $jniDefine;
314	my $needLocaleDefined = 0;
315	my $jniADTalloc;
316	if (defined $header && ($header > 0) ) {
317	    $jniDefine = "union union_of_events	*event;\n" .
318		"\tadt_session_data_t	*session;\n";
319	    $jniADTalloc = '(union union_of_events *)adt_alloc_event';
320	} else {
321	    $jniDefine = "adt_event_data_t	*event;\n" .
322		"\tadt_session_data_t	*session;\n";
323	    $jniADTalloc = 'adt_alloc_event';
324	}
325	my $ref2;
326	foreach $ref2 (@entries) {
327	    my ($id, $type) = @$ref2;
328	    my $jniRoot = $root . $id;
329	    $jniRoot =~ s/_/_1/g;  # escape unicode "_"
330
331	    my $p_event;
332	    if (defined $header && ($header > 0) ) {
333		$p_event = "event->d$header.adt_$root.$id";
334	    } else {
335		$p_event = "event->adt_$root.$id";
336	    }
337
338	    if ($type eq 'ADT_UINT32STAR') { # int array
339	        $needLocaleDefined = 1;
340
341
342	        $jniStorageList .= <<EOF;
343	/* $id */
344	length = (*env)->GetArrayLength(env, $id);
345	$p_event =
346	    (int *)malloc(length * sizeof (int));
347	if ($p_event == NULL) {
348		locale = I18N_SETUP;
349		local_throw(env, except_class,
350		    $noMemory);
351		(void) setlocale(LC_MESSAGES, locale);
352		goto cleanup;
353	}
354	(*env)->GetIntArrayRegion(env, $id, 0, length,
355	    (int *)$p_event);
356EOF
357
358
359		$jniFreeList .= "\n\tif ($p_event != NULL)\n" .
360		    "\t\tfree($p_event);\n";
361		unless ($haveLengthDef) {
362		    $haveLengthDef = 1;
363		    $jniDefine .= "\tint\t\t\tlength;\n";
364		}
365		$nativeParameterList .= ",\n\t    int[]\t$id";
366		$jniParameterList .= ",\n    jintArray\t$id";
367		$specParameterList .= ", jintArray";
368		$needCleanupTarget = 1;
369	    } elsif (($type eq 'ADT_UIDSTAR') ||
370		     ($type eq 'ADT_GIDSTAR')) { # gid_t array
371		my $cType = 'uid_t';
372		$cType = 'gid_t' if ($type eq 'ADT_GIDSTAR');
373		$needLocaleDefined = 1;
374
375
376		$jniStorageList .= <<EOF;
377	/* $id */
378	length = (*env)->GetArrayLength(env, $id);
379	$p_event =
380	    ($cType *)malloc(length * sizeof ($cType));
381	if ($p_event == NULL) {
382		locale = I18N_SETUP;
383		local_throw(env, except_class,
384		    $noMemory);
385		(void) setlocale(LC_MESSAGES, locale);
386		goto cleanup;
387	}
388	(*env)->GetIntArrayRegion(env, $id, 0, length,
389	    (int *)$p_event);
390EOF
391
392
393		$jniFreeList .=
394		    "\n\tif ($p_event != NULL)\n" .
395		    "\t\tfree($p_event);\n";
396		unless ($haveLengthDef) {
397		    $haveLengthDef = 1;
398		    $jniDefine .= "\tint\t\t\tlength;\n";
399		}
400		$nativeParameterList .= ",\n\t    int[]\t$id";
401		$jniParameterList .= ",\n    jintArray\t$id";
402		$specParameterList .= ", jintArray";
403		$needCleanupTarget = 1;
404	    } elsif ($type eq 'ADT_UINT64STAR') { # long array
405	        $needLocaleDefined = 1;
406	        $jniStorageList .= <<EOF;
407	/* $id */
408	length = (*env)->GetArrayLength(env, $id);
409	$p_event =
410	    (long *)malloc(length * sizeof (long long));
411	if ($p_event == NULL) {
412		locale = I18N_SETUP;
413		local_throw(env, except_class,
414		    $noMemory);
415		(void) setlocale(LC_MESSAGES, locale);
416		goto cleanup;
417	}
418	(*env)->GetLongArrayRegion(env, $id, 0, length,
419	    $p_event);
420EOF
421		$jniFreeList .= "\n\tif ($p_event != NULL)\n" .
422		    "\t\tfree($p_event);\n";
423		unless ($haveLengthDef) {
424		    $haveLengthDef = 1;
425		    $jniDefine .= "\tint\t\t\tlength;\n";
426		}
427		$nativeParameterList .= ",\n\t    long[]\t$id";
428		$jniParameterList .= ",\n    jlongArray\t$id";
429		$specParameterList .= ", jlongArray";
430		$needCleanupTarget = 1;
431	    } elsif ($type eq 'ADT_CHAR') { # string in Java, char in C
432		$jniStorageList .= <<EOF;
433
434	/* $id */
435	c = (char *)(*env)->GetStringUTFChars(env, $id, NULL);
436	if (c == NULL)
437		goto cleanup; /* exception thrown */
438	$p_event = *c;
439	(*env)->ReleaseStringUTFChars(env, $id, c);
440EOF
441		# no need to free anything
442		unless ($haveCDef) {
443		    $haveCDef = 1;
444		    $jniDefine .= "\tchar\t\t\t*c\n";
445		}
446		$nativeParameterList .= ",\n\t    String\t$id";
447		$jniParameterList .= ",\n    jstring\t$id";
448		$specParameterList .= ", jstring";
449	    } elsif ($type eq 'ADT_CHARSTAR') {
450	        $needLocaleDefined = 1;
451		$jniStorageList .= <<EOF;
452	/* $id */
453	if ($id != NULL) {
454		string = (char *)(*env)->GetStringUTFChars(
455		    env, $id, NULL);
456		if (string == NULL)
457			goto cleanup; /* exception thrown */
458		$p_event = strdup(string);
459		(*env)->ReleaseStringUTFChars(env, $id, string);
460		if ($p_event == NULL) {
461			locale = I18N_SETUP;
462			local_throw(env, except_class,
463			    $noMemory);
464			(void) setlocale(LC_MESSAGES, locale);
465			goto cleanup;
466		}
467	}
468EOF
469		$jniFreeList .= "\n\tif ($p_event != NULL)\n" .
470		    "\t\tfree($p_event);\n";
471		unless ($haveStringDef) {
472		    $haveStringDef = 1;
473		    $jniDefine .= "\tchar\t\t\t*string;\n";
474		}
475		$nativeParameterList .= ",\n\t    String\t$id";
476		$jniParameterList .= ",\n    jstring\t$id";
477		$specParameterList .= ", jstring";
478		$needCleanupTarget = 1;
479	    } elsif ($type eq 'ADT_CHAR2STAR') { # array of string
480	        $needLocaleDefined = 1;
481		$jniStorageList .= <<EOF;
482	/* $id */
483	length = (*env)->GetArrayLength(env, $id);
484	$p_event = (char **)malloc(length
485	    * sizeof (char *));
486	if ($p_event == NULL) {
487		locale = I18N_SETUP;
488		local_throw(env, except_class,
489		    $noMemory);
490		(void) setlocale(LC_MESSAGES, locale);
491		goto cleanup;
492	}
493	p = $p_event;
494	for (i = 0; i < length; i++) {
495		jString = (*env)->GetObjectArrayElement(env, $id, i);
496		string = (char *)(*env)->GetStringUTFChars(
497		    env, jString, NULL);
498		if (string == NULL)
499			goto cleanup; /* exception thrown */
500		*p = strdup(string);
501		(*env)->ReleaseStringUTFChars(env, jString, string);
502		if (*p == NULL) {
503			locale = I18N_SETUP;
504			local_throw(env, except_class,
505			    $noMemory);
506			(void) setlocale(LC_MESSAGES, locale);
507			while (p >= $p_event)
508				free(*p--);
509			goto cleanup;
510		}
511		p++;
512	}
513EOF
514		$jniFreeList .=
515		    "\n\tif ($p_event != NULL)\n" .
516		    "\t\tfree($p_event);\n";
517		unless ($haveStringArrayDef) {
518		    unless ($haveStringDef) {
519			$haveStringDef = 1;
520			$jniDefine .= <<EOF;
521	char			*string;
522EOF
523		    }
524		    unless ($haveLengthDef) {
525			$haveLengthDef = 1;
526			$jniDefine .= <<EOF;
527	int			length;
528EOF
529		    }
530		    $haveStringArrayDef = 1;
531		    $jniDefine .= <<EOF;
532	int			i;
533	char			**p;
534	jstring			jString;
535EOF
536		}
537		$nativeParameterList .= ",\n\t    String[]\t$id";
538		$jniParameterList .= ",\n    jstring\t$id";
539		$specParameterList .= ", jstring";
540		$needCleanupTarget = 1;
541	      } elsif ($type eq 'ADT_TERMIDSTAR') {
542	        $needLocaleDefined = 1;
543
544	        $jniStorageList .= <<EOF;
545	/* $id */
546	hostname$cntTermidDef = (char *)(*env)->GetStringUTFChars(env, $id, NULL);
547
548	if (adt_load_hostname((const char *)hostname$cntTermidDef, &termid$cntTermidDef)) {
549		local_throw(env, except_class,
550			gettext("hostname lookup failed"));
551	}
552	$p_event = termid$cntTermidDef;
553
554	(*env)->ReleaseStringUTFChars(env, $id, hostname$cntTermidDef);
555EOF
556
557		$jniFreeList .= "\n\tif (hostname$cntTermidDef != NULL)\n" .
558		    "\t\tfree(hostname$cntTermidDef);\n";
559		$jniFreeList .= "\n\tif (termid$cntTermidDef != NULL)\n" .
560		    "\t\tfree(termid$cntTermidDef);\n";
561
562		$jniDefine .= "\tchar\t\t\t*hostname$cntTermidDef;\n";
563		$jniDefine .= "\tadt_termid_t\t\t*termid$cntTermidDef;\n"; #djdj
564
565		$cntTermidDef++;
566
567		my ($nativeParameter, $jniParameter) = @{$java_jni{$type}};
568		$nativeParameterList .= ",\n\t    $nativeParameter\t$id";
569		$jniParameterList .= ",\n    $jniParameter\t$id";
570		$specParameterList .= ", $jniParameter";
571		$needCleanupTarget = 1;
572	    } else {  # all others are primitive types
573		$jniStorageList .= "\n\t$p_event = $id;\n";
574		my ($nativeParameter, $jniParameter) = @{$java_jni{$type}};
575		$nativeParameter = "$nativeParameter\t"
576		    if length $nativeParameter < 4;  # why?
577		$nativeParameterList .= ",\n\t    $nativeParameter\t$id";
578		$jniParameterList .= ",\n    $jniParameter\t$id";
579		$specParameterList .= ", $jniParameter";
580	    }
581	}
582	if ($needLocaleDefined) {
583		$jniDefine .= <<EOF
584	char			*locale;
585EOF
586	}
587	my $genericOverride = '';
588	my $idParameter = $eventId;
589	$idParameter =~ s/AUE_/ADT_/;
590	if ($eventType eq 'generic') {
591	    $genericOverride = ', jint eventId';
592	    $idParameter = 'eventId';
593	}
594	$jniFreeList = "\tcleanup:\n" . $jniFreeList if $needCleanupTarget;
595
596	print Cfile qq{/* ARGSUSED */
597JNIEXPORT void JNICALL
598$jniPutEvent(
599    JNIEnv	*env,
600    jobject	self,
601    jbyteArray	jsession$genericOverride,
602    jint	status,
603    jint	ret_val$jniParameterList)
604{
605	$jniDefine
606	(void) j2c_pointer(env, jsession, (char **)&session);
607
608	event = $jniADTalloc(session, $idParameter);
609
610$jniStorageList
611	(void) adt_put_event((adt_event_data_t *)event, status, ret_val);
612
613$jniFreeList
614	adt_free_event((adt_event_data_t *)event);
615}
616};
617	print MapFile qq{
618	$jniPutEvent; };
619	my $overrideParameter = '';
620	if ($eventType eq 'generic') {
621	    $overrideParameter = 'int eventId,';
622	    my @allowed = @$allowedIds;
623	    if (@allowed) {
624		my $i;
625		if ($validSfile) {
626		    print Sfile "\t// Allowed values for eventId in putEvent:\n";
627		    for ($i = 0; $i <= $#allowed; $i++) {
628			my $idNo = $externalIdNo{$allowed[$i]};
629			$allowed[$i] =~ s/AUE_/ADT_/;
630			print Sfile "\tstatic final int $allowed[$i] = ",
631			     "$idNo;\n";
632		    }
633		    print Sfile "\n";
634		}
635	    } else {
636		print STDERR "Generic event with no allowed instances: $eventId\n";
637	    }
638	}
639	if ($validSfile) {
640	    print Sfile <<EOF;
641	private native void $javaPutEvent(byte[]session, $overrideParameter
642	    int status, int ret_val$nativeParameterList);
643
644	public AuditEvent_$root(AuditSession session)
645		throws Exception
646	{
647		super(session);
648	}
649
650EOF
651	    my $javaParameterList = '';
652	    foreach $ref2 (@entries) {
653		my ($id, $type, $format, $jComment, $required) = @$ref2;
654
655		# generate java native method prototypes
656		# and the corresponding C method implementation
657
658		my $javaMethodName = "$id";
659		my $javaStorageName = $javaMethodName . '_val';
660		my $jniMethodName = $root . $id;
661		my $storage;
662		my $enumUsage = '';
663		my $jParam = @{$java_jni{$type}}[0];
664		my $comment = '';
665		if ($required) {
666		    if ($format ne 'NULL') {
667			$comment = "\t// (required) formatted:  $format";
668		    } else {
669			$comment = "\t// required";
670		    }
671		} else {
672		    if ($format ne 'NULL') {
673			$comment = "\t// (optional) formatted:  $format";
674		    } else {
675			$comment = "\t// optional";
676		    }
677		}
678		if (($type eq 'ADT_UINT32STAR') ||
679		    ($type eq 'ADT_UIDSTAR') ||
680		    ($type eq 'ADT_GIDSTAR')) { # int array
681		    $storage = "int[] $javaStorageName" . ($required ?
682							   ' = {}' : '');
683		    $javaParameterList .= ",\n\t\t\t    $javaStorageName";
684		} elsif ($type eq 'ADT_UINT64STAR') { # long array
685		    $storage = "long[] $javaStorageName" . ($required ?
686							    ' = {}' : '');
687		    $javaParameterList .= ",\n\t\t\t    $javaStorageName";
688		} elsif (($type eq 'ADT_CHARSTAR') ||
689			 ($type eq 'ADT_CHAR')) { # string
690		    $storage = "String $javaStorageName" . ($required ?
691							    ' = ""' : '');
692		    $javaParameterList .= ",\n\t\t\t    $javaStorageName";
693		} elsif ($type eq 'ADT_CHAR2STAR') { # array of string
694		    $storage = "String[] $javaStorageName" . ($required ?
695							      ' = {}' : '');
696		    $javaParameterList .= ",\n\t\t\t    $javaStorageName";
697		} elsif ($type eq 'ADT_TERMIDSTAR') { # array of string
698		    $storage = "String $javaStorageName" . ($required ?
699							    ' = ""' : '');
700		    $javaParameterList .= ",\n\t\t\t    $javaStorageName";
701		} else {  # all others are primitive types
702		    $storage = "$jParam $javaStorageName = 0";
703		    $javaParameterList .= ",\n\t\t\t    $javaStorageName";
704		    $enumUsage = "\n\t// See $jComment in AuditEvent.java for valid values"
705			if $jComment;
706		}
707		print Sfile <<EOF;
708$enumUsage
709	private $storage;$comment
710	public void $javaMethodName($jParam setTo)
711	{
712		$javaStorageName = setTo;
713	}
714EOF
715	    }	# end foreach (@entries)
716	    if ($eventType eq 'generic') {
717		print Sfile <<EOF;
718
719	public void putEvent(int status, int ret_val, int eventId)
720	{
721		byte[]	session = super.sh.getSession();
722
723		if ((super.sh.AuditIsOn) && (super.sh.ValidSession))
724			$javaPutEvent(session, eventId,
725			    status, ret_val$javaParameterList);
726	}
727}
728EOF
729	    } else {
730		print Sfile <<EOF;
731
732	public void putEvent(int status, int ret_val)
733	{
734		byte[]	session = super.sh.getSession();
735
736		if ((super.sh.AuditIsOn) && (super.sh.ValidSession))
737			$javaPutEvent(session, status, ret_val$javaParameterList);
738	}
739}
740EOF
741	    }
742	    close Sfile;
743	}	# end if ($validSfile);
744    }
745
746    # write trailers
747    print Jfile <<EOF;
748
749}
750EOF
751    print MapFile <<EOF;
752
753    local:
754	*;
755};
756EOF
757    close Cfile;
758    close Jfile;
759    close MapFile;
760}
761
762sub generateTableC {
763    my $event = shift;
764    my $eventId = shift;
765    my $eventType = shift;
766    my $eventHeader = shift;
767    my $omit = shift;
768
769    my %tokenType = (
770		  'acl'			=> 'AUT_ACL',
771		  'arbitrary'		=> 'AUT_ARBITRARY',
772		  'arg'			=> 'AUT_ARG',
773		  'attr'		=> 'AUT_ATTR',
774		  'command'		=> 'AUT_CMD',
775		  'command_1'		=> 'ADT_CMD_ALT',	# dummy token id
776		  'date'		=> 'AUT_TEXT',
777		  'exec_args'   	=> 'AUT_EXEC_ARGS',
778		  'exec_env'    	=> 'AUT_EXEC_ENV',
779		  'exit'        	=> 'AUT_EXIT',
780		  'file'        	=> 'AUT_FILE',
781		  'fmri'        	=> 'AUT_FMRI',
782		  'groups'      	=> 'AUT_GROUPS',
783	#	  'header'      	=> 'AUT_HEADER',	# not used
784		  'in_addr'     	=> 'AUT_IN_ADDR',
785		  'tid'          	=> 'AUT_TID',
786		  'ipc'         	=> 'AUT_IPC',
787		  'ipc_perm'    	=> 'AUT_IPC_PERM',
788		  'iport'		=> 'AUT_IPORT',
789		  'label'		=> 'AUT_LABEL',
790		  'newgroups'   	=> 'AUT_NEWGROUPS',
791		  'opaque'      	=> 'AUT_OPAQUE',
792		  'path'        	=> 'AUT_PATH',
793		  'path_list'		=> '-AUT_PATH',		# dummy token id
794		  'process'     	=> 'AUT_PROCESS',
795		  'priv_effective'	=> 'ADT_AUT_PRIV_E',	# dummy token id
796		  'priv_limit'		=> 'ADT_AUT_PRIV_L', 	# dummy token id
797		  'priv_inherit'	=> 'ADT_AUT_PRIV_I',	# dummy token id
798		  'return'      	=> 'AUT_RETURN',
799		  'seq'         	=> 'AUT_SEQ',
800		  'socket'      	=> 'AUT_SOCKET',
801		  'socket-inet' 	=> 'AUT_SOCKET_INET',
802		  'subject'     	=> 'AUT_SUBJECT',
803		  'text'        	=> 'AUT_TEXT',
804	#	  'trailer'     	=> 'AUT_TRAILER',	# not used
805		  'uauth'		=> 'AUT_UAUTH',
806		  'zonename'		=> 'AUT_ZONENAME'
807		 );
808
809    my @xlateEntryList = ();
810    my @jniEntryList = ();
811
812    my $external = $event->getExternal();
813    my $internal = $event->getInternal();
814
815    unless ($external) {
816	print STDERR "No external object captured for event $eventId\n";
817	return;
818    }
819    unless ($internal) {
820	print STDERR "No internal object captured for event $eventId\n";
821	return;
822    }
823    my @entryRef = $internal->getEntries();
824    my $entryRef;
825    my @tokenOrder = ();
826    my $firstTokenIndex = 0; # djdj not used yet, djdj BUG!
827    			     # needs to be used by translate table
828
829    if ($internal->isReorder()) { # prescan the entry list to get the token order
830      my @inputOrder;
831      foreach $entryRef (@entryRef) {
832	my ($intEntry, $entry) = @$entryRef;
833	push (@inputOrder, $intEntry->getAttr('order'));
834      }
835
836      my $i; # walk down the inputOrder list once
837      my $k = 1; # discover next in line
838      my $l = 0; # who should point to next in line
839      for ($i = 0; $i <= $#inputOrder; $i++) {
840	my $j;
841	for ($j = 0; $j <= $#inputOrder; $j++) {
842	  if ($k == $inputOrder[$j]) {
843	    if ($k == 1) {
844	        $firstTokenIndex = $j;
845	    } else {
846	        $tokenOrder[$l] = "&(selfReference[$j])";
847	    }
848	    $l = $j;
849	    last;
850	  }
851	}
852	$k++;
853      }
854      $tokenOrder[$l] = 'NULL';
855    }
856    else { # default order -- input order same as output
857      my $i;
858      my $j;
859      for ($i = 0; $i < $#entryRef; $i++) {
860	my $j = $i + 1;
861	$tokenOrder[$i] = "&(selfReference[$j])";
862      }
863      $tokenOrder[$#entryRef] = 'NULL';
864    }
865
866    my $sequence = 0;
867    foreach $entryRef (@entryRef) {
868      my ($intEntry, $entry) = @$entryRef;
869      my $entryId = $entry->getAttr('id');
870
871      my ($extEntry, $unusedEntry, $tokenId) =
872	$external->getEntry($entryId);
873      my $opt = $extEntry->getAttr('opt');
874
875      if ($opt eq 'none') {
876	if (defined ($doc->getToken($tokenId))) {
877	  if (defined ($tokenType{$tokenId})) {
878	    $tokenId = $tokenType{$tokenId};
879	  }
880	  else {
881	    print STDERR "token id $tokenId not implemented\n";
882	  }
883	}
884	else {
885	  print STDERR "token = $tokenId is undefined\n";
886	  $tokenId = 'error';
887	}
888	my ($xlate, $jni) =
889	  formatTableEntry ('', $tokenId, $eventId, '', 0, 0, $tokenOrder[$sequence],
890			    'NULL', '');
891	push (@xlateEntryList, $xlate);
892	push (@jniEntryList, @$jni);
893      }
894      else {
895	my $dataType = $extEntry->getAttr('type');
896	$dataType =~ s/\s+//g;   # remove blanks (char * => char*)
897
898	my $enumGroup = '';
899	if ($dataType =~ /^msg/i) {
900	    $enumGroup = $dataType;
901	    $enumGroup =~ s/^msg\s*//i;
902	    $enumGroup = 'adt_' . $enumGroup;
903	}
904	my $required = ($opt eq 'required') ? 1 : 0;
905	my $tsol = 0;
906	my $tokenId = $intEntry->getAttr('token');
907	my $token;
908	my $tokenName;
909	my $tokenFormat = $intEntry->getAttr('format');
910	if (defined ($tokenFormat)) {
911	  $tokenFormat = "\"$tokenFormat\"";
912	}
913	else {
914	  $tokenFormat = 'NULL';
915	}
916
917	if (defined ($token = $doc->getToken($tokenId))) {
918	  $tsol = (lc $token->getUsage() eq 'tsol') ? 1 : 0;
919	  if (defined ($tokenType{$tokenId})) {
920	    $tokenName = $tokenType{$tokenId};
921	  }
922	  else {
923	    print STDERR "token id $tokenId not implemented\n";
924	  }
925	}
926	else {
927	  print STDERR
928	    "$tokenId is an unimplemented token ($entryId in $eventId)\n";
929	  $tokenName = 'AUT_TEXT';
930	}
931	my ($xlate, $jni) =
932	  formatTableEntry($entryId, $tokenName, $eventId, $dataType, $required,
933			   $tsol, $tokenOrder[$sequence], $tokenFormat,
934			   $enumGroup, (uc $omit eq 'JNI'));
935	push (@xlateEntryList, $xlate);
936	push (@jniEntryList, @$jni);
937      }
938      $sequence++;
939    }
940    $jniEventTable{$eventId} = [\@jniEntryList, $eventType,
941				$external->getAllowedTypes(), $eventHeader]
942	unless (uc $omit eq 'JNI') || ($omit eq 'always');
943}
944
945sub formatTableEntry {
946    my ($id, $token, $eventId, $type, $required, $tsol, $sequence, $format, $enumGroup,
947	$omitJNI) = @_;
948
949
950    # does this map belong in the xml source?  (at least the defaults?)
951    # fill in the default value only if it is other than zero.
952    #		      base type		    adt name,	default value
953    my %entryDef = ( 'au_asid_t'       	=> ['ADT_UINT32',	''],
954		     'uint_t'		=> ['ADT_UINT32',      	''],
955		     'int'		=> ['ADT_INT',		''],
956		     'int32_t'		=> ['ADT_INT32',	''],
957		     'uid_t'		=> ['ADT_UID',		'AU_NOAUDITID'],
958		     'gid_t'		=> ['ADT_GID',		'AU_NOAUDITID'],
959		     'uid_t*'		=> ['ADT_UIDSTAR',	''],
960		     'gid_t*'		=> ['ADT_GIDSTAR',	''],
961		     'char'		=> ['ADT_CHAR',		''],
962		     'char*'		=> ['ADT_CHARSTAR',	''],
963		     'char**'		=> ['ADT_CHAR2STAR',	''],
964		     'long'		=> ['ADT_LONG',		''],
965		     'pid_t'		=> ['ADT_PID',		''],
966		     'priv_set_t*'	=> ['ADT_PRIVSTAR',	''],
967		     'ulong_t'		=> ['ADT_ULONG',	''],
968		     'uint16_t',	=> ['ADT_UINT16',	''],
969		     'uint32_t'		=> ['ADT_UINT32',	''],
970		     'uint32_t*'	=> ['ADT_UINT32STAR',	''],
971		     'uint32_t[]'	=> ['ADT_UINT32ARRAY',  ''],
972		     'uint64_t'		=> ['ADT_UINT64',	''],
973		     'uint64_t*'	=> ['ADT_UINT64STAR',	''],
974		     'm_label_t*'	=> ['ADT_MLABELSTAR',	''],
975		    );
976    my $xlateLabel = $uniLabel.$xlateUniLabelInc;
977    my $xlateLabelInc = 0;
978    my $xlateLine = '';
979    my @jniLine = ();
980
981	# the list handling should be a simple loop with a loop of one
982        # falling out naturally.
983
984    unless ($type =~ /,/) {	# if list, then generate sequence of entries
985      my $dataType;
986      my $dataSize;
987      my $xlateLabelRef = '';
988
989      my $arraySize = '';
990      $arraySize = $1 if ($type =~ s/\[(\d+)\]/[]/);
991
992      my $entryType = ${$entryDef{$type}}[0];
993
994      my @xlateType = ();	# for adt_xlate.c
995      my $typeCount = 1;
996
997      if ($entryType) {
998	$dataType = $entryType;
999	$type =~ s/([^*]+)\s*(\*+)/$1 $2/;
1000	$type =~ s/\[\]//;
1001	$dataSize = "sizeof ($type)";
1002	if ($arraySize) {
1003		$dataSize = "$arraySize * " . $dataSize;
1004	}
1005	$xlateLine = "{{$dataType, $dataSize}}";
1006	push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]);
1007      } elsif ($type eq '') {
1008	  $xlateLabelRef = 'NULL';
1009      } elsif ($type =~ /^msg/i) {
1010	$type =~ s/^msg//i;
1011	$dataType = 'ADT_MSG';
1012	my $dataEnum = 'ADT_LIST_' . uc $type;
1013	$xlateLine = "{{$dataType, $dataEnum}}";
1014	push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]);
1015      } elsif ($type =~ /time_t/i) {
1016	$dataType = 'ADT_DATE';
1017	$dataSize = "sizeof (time_t)";
1018	$xlateLine = "{{$dataType, $dataSize}}";
1019	push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]);
1020      } elsif ($type =~ /termid/i) {
1021	$dataType = 'ADT_TERMIDSTAR';
1022	$dataSize = "sizeof (au_tid_addr_t *)";
1023	$xlateLine = "{{$dataType, $dataSize}}";
1024	push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]);
1025      } elsif ($omitJNI) {
1026	$xlateLabelRef = 'NULL';
1027      } else {
1028	print STDERR "$type is not an implemented data type\n";
1029	$xlateLabelRef = 'NULL';
1030      }
1031      $xlateLabelRef = '&' . $xlateLabel . '[0]'
1032	unless $xlateLabelRef eq 'NULL';
1033
1034      # "EOL" is where a comma should go unless end of list
1035      $xlateLine = "{$token,\t1,\t$xlateLabelRef,\t$sequence,\n" .
1036	  "\t\t0,\t$required,\t$tsol,\t$format}EOL";
1037
1038    } else {	# is a list
1039      my @type = split(/,/, $type);
1040      my @arraySize = ();
1041      my @id   = split(/,/, $id);
1042      my @jniId  = @id;
1043      my $dataType;
1044      my $typeCount = ($#type + 1);
1045      my @xlateType = ();
1046      my @default = ();
1047
1048      foreach my $dtype (@type) {
1049	my $jniId = shift @jniId;
1050	my $id = shift @id;
1051	my $arraySize = '';
1052	$arraySize = $1 if ($dtype =~ s/\[(\d+)\]/[]/);
1053
1054	my $entryType = ${$entryDef{$dtype}}[0];
1055	if ($entryType) {
1056	  my $type = $dtype;
1057	  $type =~ s/([^*]+)\s*(\*+)/$1 $2/;
1058	  $type =~ s/\[\]//;
1059
1060	  my $sizeString = "sizeof";
1061	  $sizeString = "$arraySize * " . $sizeString if $arraySize;
1062	  push (@xlateType, "\{$entryType, $sizeString ($type)\}");
1063	  push (@jniLine, [$jniId, $entryType, $format, $enumGroup, $required]);
1064	} elsif ($type =~ /^msg/i) {
1065	  $type =~ s/^msg//i;
1066	  $dataType = 'ADT_MSG';
1067	  my $dataEnum = 'ADT_LIST_' . uc $type;
1068	  push (@xlateType, "\{$dataType, $dataEnum\}};");
1069	  push (@jniLine, [$jniId, $dataType, $format, $enumGroup, $required]);
1070	} elsif ($type =~ /time_t/i) {
1071	  $dataType = 'ADT_DATE';
1072	  push (@xlateType, "\{$entryType, sizeof ($type)\}");
1073	  push (@jniLine, [$jniId, $entryType, $format, $enumGroup, $required]);
1074	} elsif ($type =~ /termid/i) {
1075	  $dataType = 'ADT_TERMIDSTAR';
1076	  push (@xlateType, "\{$dataType, sizeof (au_tid_addr_t *)\}");
1077	  push (@jniLine, [$jniId, $dataType, $format, $enumGroup, $required]);
1078	} elsif ($omitJNI) {
1079	  # nothing to do.
1080	} else {
1081	  print STDERR "$dtype is not an implemented data type\n";
1082	}
1083	if (${$entryDef{$dtype}}[1]) {
1084	  push (@default, $id, ${$entryDef{$dtype}}[1]);
1085	}
1086      }
1087      my $xlateArray = "\[$typeCount\] =\t{" . join(",\n\t\t\t\t", @xlateType) . "};";
1088
1089      $xlateLine =
1090	"{$token,\t$typeCount,\t&$xlateLabel\[0\],\t$sequence,\n" .
1091        "\t\t0,\t$required,\t$tsol,\t$format}EOL";
1092    }
1093    $xlateUniLabelInc++ if $xlateLabelInc;
1094    return ($xlateLine, \@jniLine);
1095}
1096
1097sub generateMsgLists {
1098    my $textList = shift;
1099
1100    my $textName = $textList->getId();
1101    my $header = $textList->getHeader();
1102    my $start = $textList->getMsgStart();
1103    my $public = $textList->getMsgPublic();
1104    my $deprecated = $textList->getDeprecated();
1105
1106    print "$textName starts at $start\n" if $debug;
1107
1108    my $entry;
1109    my @entry;
1110    while ($entry = $textList->getNextMsg()) {
1111        if ($debug) {
1112	    my ($id, $text) = split(/\s*::\s*/, $entry);
1113	    print "   $id = $text\n";
1114	}
1115	unshift (@entry, $entry);
1116    }
1117    $msg_list{$textName} =
1118	[\@entry, [$header, $start, $public, $deprecated]];
1119}
1120sub readAuditEventFile {
1121    my $eventListFile = shift;
1122
1123  open(Event, $eventListFile)
1124    or die "can't open $eventListFile: $!\n";
1125  while(<Event>) {
1126    next if /^\s*#/;
1127    next if /^\s*$/;
1128    my ($value, $name) = split(/\s*:\s*/);
1129    next if $value < 6000;
1130    $eventCode{$name} = $value;
1131  }
1132  close Event;
1133}
1134
1135