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 2006 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 
47 void
48 local_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 
84 static char *
85 errno_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  */
100 int
101 j2c_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  */
133 void
134 c2j_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*/
154 JNIEXPORT jbyteArray JNICALL
155 Java_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 */
195 JNIEXPORT void JNICALL
196 Java_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 */
221 JNIEXPORT jbyteArray JNICALL
222 Java_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 */
249 JNIEXPORT jstring JNICALL
250 Java_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 */
272 JNIEXPORT jbyteArray JNICALL
273 Java_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 */
296 JNIEXPORT void JNICALL
297 Java_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,
316 	    termid, context))
317 		local_throw(env, "java/lang/Error", errno_to_i18n(errno));
318 
319 	(*env)->ReleaseStringUTFChars(env, jhostname, hostname);
320 }
321 
322 /* ARGSUSED */
323 JNIEXPORT jboolean JNICALL
324 Java_com_sun_audit_AuditSession_bsmAuditOn(JNIEnv *env, jobject cls) {
325 	int condition;
326 
327 	if (auditon(A_GETCOND, (caddr_t)&condition, sizeof (condition)))
328 		return (0);
329 
330 	return (1);
331 }
332