1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * adt_jni.c
23 *
24 * JNI wrapper for adt interface within libbsm
25 *
26 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
27 * Use is subject to license terms.
28 *
29 */
30#pragma ident	"%Z%%M%	%I%	%E% SMI"
31
32#include <bsm/adt.h>
33#include "adt_jni.h"
34#include <jni.h>
35#include "../com/sun/audit/AuditSession.h"	/* javah output */
36#include <assert.h>
37#include <stdlib.h>
38#include <string.h>
39#include <netdb.h>
40
41/*
42 * local_throw  -- throw an exception.
43 * "why" string must be i18n'd before calling here.
44 *
45 */
46
47void
48local_throw(JNIEnv *env, const char *exception, const char *why) {
49	jobject jexception;
50	jclass exceptionclass;
51	jmethodID jexceptionnew;
52
53	jbyteArray jbarray;
54
55	jstring jmsg;
56	jclass strclass;
57	jmethodID jstrnew;
58
59	/* Get a String class and "new" method */
60	strclass = (*env)->FindClass(env, "java/lang/String");
61	jstrnew = (*env)->GetMethodID(env, strclass, "<init>", "([B)V");
62
63	/* Create a Byte Array from message "why" */
64	jbarray = (*env)->NewByteArray(env, (jsize)(strlen(why)));
65	(*env)->SetByteArrayRegion(env, jbarray, (jsize)0,
66	    (jsize)(strlen(why)), (jbyte*) why);
67
68	/* Create string from byte array */
69	jmsg = (*env)->NewObject(env, strclass, jstrnew, jbarray);
70	exceptionclass = (*env)->FindClass(env, exception);
71	jexceptionnew = (*env)->GetMethodID(env, exceptionclass,
72	    "<init>", "(Ljava/lang/String;)V");
73
74	jexception = (*env)->NewObject(env, exceptionclass, jexceptionnew,
75	    jmsg);
76	(*env)->Throw(env, jexception);
77}
78
79/*
80 * i18n the strerror return.  Input is errno.
81 *
82 */
83
84static char *
85errno_to_i18n(int error_code) {
86	char	*locale;
87	char	*local_text;
88
89	locale = I18N_SETUP;
90	local_text = strerror(error_code);
91	(void) setlocale(LC_MESSAGES, locale);
92	return (local_text);
93}
94
95/*
96 * j2c_pointer
97 *
98 * convert java byte array into a C pointer
99 */
100int
101j2c_pointer(JNIEnv *env, jbyteArray jpointer, caddr_t *cpointer) {
102	union {
103		caddr_t		ptr;
104		jbyte		buf[sizeof (uint64_t)];
105	} u;
106	size_t			jpointer_length;
107	char	*locale;
108
109	(void) memset(u.buf, 0, sizeof (uint64_t));
110
111	assert(jpointer != NULL);
112
113	jpointer_length = (*env)->GetArrayLength(env, jpointer);
114	if (jpointer_length != sizeof (uint64_t)) {
115		locale = I18N_SETUP;
116		local_throw(env, "java/lang/Error",
117		    gettext("Bad session handle"));
118		(void) setlocale(LC_MESSAGES, locale);
119		return (-1);
120	}
121	(*env)->GetByteArrayRegion(env, jpointer, 0, jpointer_length,
122	    &(u.buf[0]));
123	*cpointer = (caddr_t)u.ptr;
124
125	return (0);
126}
127
128/*
129 * c2j_pointer
130 *
131 * convert a C pointer into a java byte array
132 */
133void
134c2j_pointer(JNIEnv *env, caddr_t cpointer, jbyteArray *jpointer) {
135	union {
136		caddr_t		ptr;
137		jbyte		buf[sizeof (uint64_t)];
138	} u;
139
140	(void) memset(u.buf, 0, sizeof (uint64_t));
141	u.ptr = cpointer;
142
143	*jpointer = (*env)->NewByteArray(env, sizeof (uint64_t));
144
145	(*env)->SetByteArrayRegion(env, *jpointer, 0, sizeof (uint64_t),
146	    &(u.buf[0]));
147}
148
149/*
150 * adt_start_session wrapper
151 *
152 */
153/*ARGSUSED*/
154JNIEXPORT jbyteArray JNICALL
155Java_com_sun_audit_AuditSession_startSession(JNIEnv *env, jobject cls,
156    jbyteArray jimport, jlong flags) {
157	jbyteArray		jstate;
158	adt_session_data_t	*state;
159	jbyte			*import;
160	size_t			import_size;
161	int			rc;
162
163	if (jimport == NULL) {
164		import = NULL;
165	} else {
166		import_size = (*env)->GetArrayLength(env, jimport);
167		import = (jbyte *)malloc(import_size * sizeof (jbyte));
168		if (import == NULL) {
169			local_throw(env, "java/lang/Error",
170			    errno_to_i18n(errno));
171			return (NULL);
172		}
173		(*env)->GetByteArrayRegion(env, jimport, 0, import_size,
174		    import);
175	}
176	rc = adt_start_session(&state, (adt_export_data_t *)import, flags);
177
178	if (import != NULL)
179		free(import);
180
181	if (rc) {
182		local_throw(env, "java/lang/Error", errno_to_i18n(errno));
183		return (NULL);
184	}
185	c2j_pointer(env, (caddr_t)state, &jstate);
186
187	return (jstate);
188}
189
190/*
191 * adt_end_session wrapper
192 */
193
194/* ARGSUSED */
195JNIEXPORT void JNICALL
196Java_com_sun_audit_AuditSession_endSession(JNIEnv *env, jobject cls,
197    jbyteArray jstate) {
198	adt_session_data_t	*state;
199	char	*locale;
200
201	if (j2c_pointer(env, jstate, (caddr_t *)&state))
202		return;
203
204	if (state == NULL)
205		return;  /* invalid session, nothing to free */
206
207	/* presently, no errors defined, but what the heck? */
208	if (adt_end_session(state)) {
209		locale = I18N_SETUP;
210		local_throw(env, "java/lang/Error",
211		    gettext("Bad session handle"));
212		(void) setlocale(LC_MESSAGES, locale);
213	}
214}
215
216/*
217 * adt_dup_session wrapper
218 */
219
220/* ARGSUSED */
221JNIEXPORT jbyteArray JNICALL
222Java_com_sun_audit_AuditSession_dupSession(JNIEnv *env, jobject cls,
223    jbyteArray jsource) {
224	jbyteArray		jdest;
225	adt_session_data_t	*source, *dest;
226	char	*locale;
227
228	if (j2c_pointer(env, jsource, (caddr_t *)&source))
229		return (NULL);
230
231	if (adt_dup_session(source, &dest)) {
232		locale = I18N_SETUP;
233		local_throw(env, "java/lang/Error",
234		    gettext("Out of memory"));
235		(void) setlocale(LC_MESSAGES, locale);
236	}
237
238	c2j_pointer(env, (caddr_t)dest, &jdest);
239
240	return (jdest);
241}
242
243/*
244 * adt_get_session_id wrapper
245 *
246 */
247
248/* ARGSUSED */
249JNIEXPORT jstring JNICALL
250Java_com_sun_audit_AuditSession_getSessionId(JNIEnv *env, jobject cls,
251    jbyteArray jstate) {
252	adt_session_data_t	*state;
253	char			*session_id;
254	jstring			return_val;
255
256	if (j2c_pointer(env, jstate, (caddr_t *)&state))
257		return (NULL);
258
259	if (adt_get_session_id(state, &session_id)) {
260		return_val = (*env)->NewStringUTF(env, session_id);
261		free(session_id);
262		return (return_val);
263	} else
264		return (NULL);
265}
266
267/*
268 * adt_get_session_id wrapper
269 */
270
271/* ARGSUSED */
272JNIEXPORT jbyteArray JNICALL
273Java_com_sun_audit_AuditSession_exportSessionData
274	(JNIEnv *env, jobject cls, jbyteArray jstate) {
275	adt_session_data_t	*state;
276	size_t			length;
277	jbyte			*buffer;
278	jbyteArray		jbuf;
279
280	if (j2c_pointer(env, jstate, (caddr_t *)&state))
281		return (NULL);
282
283	length = adt_export_session_data(state, (adt_export_data_t **)&buffer);
284
285	if ((jbuf = (*env)->NewByteArray(env, length)) == NULL) {
286		free(buffer);
287		return (NULL);
288	}
289	(*env)->SetByteArrayRegion(env, jbuf, 0, length, buffer);
290	free(buffer);
291
292	return (jbuf);
293}
294
295/* ARGSUSED */
296JNIEXPORT void JNICALL
297Java_com_sun_audit_AuditSession_sessionAttr(JNIEnv *env, jobject cls,
298    jbyteArray jstate,
299    jint euid, jint egid, jint ruid, jint rgid,
300    jstring jhostname, jint context) {
301	adt_session_data_t	*state;
302	const char		*hostname;
303	adt_termid_t		*termid;
304
305	if (j2c_pointer(env, jstate, (caddr_t *)&state))
306		return;	/* j2c_pointer threw exception */
307
308	if (state == NULL)
309		return;	/* invalid session */
310
311	hostname = (*env)->GetStringUTFChars(env, jhostname, NULL);
312
313	if (adt_load_hostname(hostname, &termid)) {
314		local_throw(env, "java/lang/Error", errno_to_i18n(errno));
315	} else if (adt_set_user(state, euid, egid, ruid, rgid, termid,
316	    context)) {
317		free(termid);
318		local_throw(env, "java/lang/Error", errno_to_i18n(errno));
319	}
320	(*env)->ReleaseStringUTFChars(env, jhostname, hostname);
321	free(termid);
322}
323
324/* ARGSUSED */
325JNIEXPORT jboolean JNICALL
326Java_com_sun_audit_AuditSession_bsmAuditOn(JNIEnv *env, jobject cls) {
327	int condition;
328
329	if (auditon(A_GETCOND, (caddr_t)&condition, sizeof (condition)))
330		return (0);
331
332	return (1);
333}
334