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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * 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 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdarg.h>
30 #include <dhcp_svc_private.h>
31 #include <dhcp_symbol.h>
32 #include <libintl.h>
33 #include <jni.h>
34 
35 #include "dd_misc.h"
36 #include "exception.h"
37 
38 /*
39  * Note: These must match exactly with the message ids defined in the
40  * bridge ResourceBundle.properties file.
41  */
42 #define	DSVC_EXISTS_EX			"dsvc_exists_exception"
43 #define	DSVC_ACCESS_EX			"dsvc_access_exception"
44 #define	DSVC_CREDENTIAL_EX		"dsvc_credential_exception"
45 #define	DSVC_NO_ENT_EX			"dsvc_no_ent_exception"
46 #define	DSVC_BUSY_EX			"dsvc_busy_exception"
47 #define	DSVC_INVALID_ARGS_EX		"dsvc_invalid_args_exception"
48 #define	DSVC_INTERNAL_EX		"dsvc_internal_exception"
49 #define	DSVC_UNAVAILABLE_EX		"dsvc_unavailable_exception"
50 #define	DSVC_COLLISION_EX		"dsvc_collision_exception"
51 #define	DSVC_UNSUPPORTED_EX		"dsvc_unsupported_exception"
52 #define	DSVC_NO_MEMORY_EX		"dsvc_no_memory_exception"
53 #define	DSVC_NO_RESOURCES_EX		"dsvc_no_resources_exception"
54 #define	DSVC_BAD_RESOURCE_EX		"dsvc_bad_resource_exception"
55 #define	DSVC_BAD_PATH_EX		"dsvc_bad_path_exception"
56 #define	DSVC_MOD_VERSION_EX		"dsvc_mod_version_exception"
57 #define	DSVC_MOD_ERR_EX			"dsvc_mod_err_exception"
58 #define	DSVC_MOD_LOAD_ERR_EX		"dsvc_mod_load_err_exception"
59 #define	DSVC_MOD_UNLOAD_ERR_EX		"dsvc_mod_unload_err_exception"
60 #define	DSVC_MOD_CFG_ERR_EX		"dsvc_mod_cfg_err_exception"
61 #define	DSVC_SYNCH_ERR_EX		"dsvc_synch_err_exception"
62 #define	DSVC_NO_LOCKMGR_EX		"dsvc_no_lockmgr_exception"
63 #define	DSVC_NO_LOCATION_EX		"dsvc_no_location_exception"
64 #define	DSVC_NO_TABLE_EX		"dsvc_no_table_exception"
65 #define	DSVC_TABLE_EXISTS_EX		"dsvc_table_exists_exception"
66 #define	DSVC_BAD_CONVER_EX		"dsvc_bad_conver_exception"
67 #define	DSVC_INTERNAL_ERROR		"dsvc_internal_error"
68 
69 #define	DSYM_CODE_OUT_OF_RANGE_EX	"dsym_code_out_of_range_exception"
70 #define	DSYM_EXCEEDS_CLASS_SIZE_EX	"dsym_exceeds_class_size_exception"
71 #define	DSYM_EXCEEDS_MAX_CLASS_SIZE_EX	"dsym_exceeds_max_class_size_exception"
72 #define	DSYM_INTERNAL_EX		"dsym_internal_exception"
73 #define	DSYM_INVALID_CAT_EX		"dsym_invalid_cat_exception"
74 #define	DSYM_INVALID_TYPE_EX		"dsym_invalid_type_exception"
75 #define	DSYM_NO_MEMORY_EX		"dsym_no_memory_exception"
76 #define	DSYM_TOO_FEW_FIELDS_EX		"dsym_too_few_fields_exception"
77 #define	DSYM_SYNTAX_EX			"dsym_syntax_exception"
78 #define	DSYM_TOO_MANY_FIELDS_EX		"dsym_too_many_fields_exception"
79 #define	DSYM_VALUE_OUT_OF_RANGE_EX	"dsym_value_out_of_range_exception"
80 
81 static void
throw_exception(JNIEnv * env,const char * name,const char * msgid,int nargs,...)82 throw_exception(JNIEnv *env, const char *name, const char *msgid,
83     int nargs, ...)
84 {
85 	va_list ap;
86 
87 	jclass class;
88 	jmethodID mid;
89 	jstring jmsgid = NULL;
90 	jobjectArray jlist = NULL;
91 	jthrowable throwObj;
92 
93 	va_start(ap, nargs);
94 
95 	class = (*env)->FindClass(env, name);
96 	if (class == NULL) {
97 		/* exception thrown */
98 		va_end(ap);
99 		return;
100 	}
101 
102 	mid = (*env)->GetMethodID(env, class, "<init>",
103 	    "(Ljava/lang/String;[Ljava/lang/Object;)V");
104 	if (mid == NULL) {
105 		/* exception thrown */
106 		va_end(ap);
107 		return;
108 	}
109 
110 	if (msgid != NULL) {
111 		jmsgid = dd_native_to_jstring(env, msgid);
112 		if (jmsgid == NULL) {
113 			/* exception thrown */
114 			va_end(ap);
115 			return;
116 		}
117 	}
118 
119 	/* The arguments (if any) are arguments to the message */
120 	if (nargs != 0) {
121 
122 		jclass strclass;
123 		int i;
124 		strclass = (*env)->FindClass(env, "java/lang/String");
125 		if (strclass == NULL) {
126 			/* exception thrown */
127 			va_end(ap);
128 			return;
129 		}
130 
131 		jlist = (*env)->NewObjectArray(env, nargs, strclass, NULL);
132 		if (jlist == NULL) {
133 			/* exception thrown */
134 			va_end(ap);
135 			return;
136 		}
137 
138 		for (i = 0; i < nargs; i++) {
139 			jstring jarg;
140 			char *arg;
141 
142 			if ((arg = va_arg(ap, char *)) == 0) {
143 				break;
144 			}
145 
146 			jarg = dd_native_to_jstring(env, arg);
147 			if (jarg == NULL) {
148 				/* exception thrown */
149 				break;
150 			}
151 
152 			(*env)->SetObjectArrayElement(env, jlist, i, jarg);
153 			if ((*env)->ExceptionOccurred(env) != NULL) {
154 				break;
155 			}
156 		}
157 
158 	}
159 
160 	if ((*env)->ExceptionOccurred(env) == NULL) {
161 		throwObj = (jthrowable)(*env)->NewObject(env, class, mid,
162 		    jmsgid, jlist);
163 		if (throwObj == NULL) {
164 			/* exception thrown */
165 			va_end(ap);
166 			return;
167 		}
168 
169 		/* finally! */
170 		(*env)->Throw(env, throwObj);
171 	}
172 
173 	va_end(ap);
174 }
175 
176 /* Throw an exception indicating record or file exists */
177 static void
throw_exists_exception(JNIEnv * env,const char * obj)178 throw_exists_exception(JNIEnv *env, const char *obj)
179 {
180 	throw_exception(env,
181 	    "com/sun/dhcpmgr/bridge/ExistsException", NULL, 1, obj);
182 }
183 
184 /* Throw an exception indicating a table already exists */
185 static void
throw_table_exists_exception(JNIEnv * env,const char * obj)186 throw_table_exists_exception(JNIEnv *env, const char *obj)
187 {
188 	throw_exception(env, "com/sun/dhcpmgr/bridge/TableExistsException",
189 	    NULL, 1, obj);
190 }
191 
192 /* Throw an exception indicating a table does not exist */
193 static void
throw_notable_exception(JNIEnv * env,const char * obj)194 throw_notable_exception(JNIEnv *env, const char *obj)
195 {
196 	throw_exception(env,
197 	    "com/sun/dhcpmgr/bridge/NoTableException", NULL, 1, obj);
198 }
199 
200 /* Throw a generic bridge exception with a specified message */
201 void
throw_bridge_exception(JNIEnv * env,const char * msgid)202 throw_bridge_exception(JNIEnv *env, const char *msgid)
203 {
204 	throw_exception(env,
205 	    "com/sun/dhcpmgr/bridge/BridgeException", msgid, 0);
206 }
207 
208 /* Throw an exception as a result of an remove_dd() error */
209 void
throw_remove_dd_exception(JNIEnv * env,int rcode,const char * obj)210 throw_remove_dd_exception(JNIEnv *env, int rcode, const char *obj)
211 {
212 	switch (rcode) {
213 	case DSVC_NO_TABLE:
214 		throw_notable_exception(env, obj);
215 		break;
216 	default:
217 		throw_libdhcpsvc_exception(env, rcode);
218 	}
219 }
220 
221 /* Throw an exception as a result of an open_dd() error */
222 void
throw_open_dd_exception(JNIEnv * env,int rcode,const char * obj)223 throw_open_dd_exception(JNIEnv *env, int rcode, const char *obj)
224 {
225 	switch (rcode) {
226 	case DSVC_TABLE_EXISTS:
227 		throw_table_exists_exception(env, obj);
228 		break;
229 	case DSVC_NO_TABLE:
230 		throw_notable_exception(env, obj);
231 		break;
232 	default:
233 		throw_libdhcpsvc_exception(env, rcode);
234 	}
235 }
236 
237 /* Throw an exception as a result of an add_dd_entry() error */
238 void
throw_add_dd_entry_exception(JNIEnv * env,int rcode,const char * obj)239 throw_add_dd_entry_exception(JNIEnv *env, int rcode, const char *obj)
240 {
241 	switch (rcode) {
242 	case DSVC_EXISTS:
243 		throw_exists_exception(env, obj);
244 		break;
245 	default:
246 		throw_libdhcpsvc_exception(env, rcode);
247 	}
248 }
249 
250 /* Throw an exception as a result of an delete_dd_entry() error */
251 void
throw_delete_dd_entry_exception(JNIEnv * env,int rcode,const char * obj)252 throw_delete_dd_entry_exception(JNIEnv *env, int rcode, const char *obj)
253 {
254 	switch (rcode) {
255 	case DSVC_NOENT:
256 		throw_noent_exception(env, obj);
257 		break;
258 	default:
259 		throw_libdhcpsvc_exception(env, rcode);
260 	}
261 }
262 
263 /* Throw an exception as a result of an modify_dd_entry() error */
264 void
throw_modify_dd_entry_exception(JNIEnv * env,int rcode,const char * orig,const char * new)265 throw_modify_dd_entry_exception(JNIEnv *env, int rcode, const char *orig,
266 	const char *new)
267 {
268 	switch (rcode) {
269 	case DSVC_EXISTS:
270 		throw_exists_exception(env, new);
271 		break;
272 	case DSVC_NOENT:
273 		throw_noent_exception(env, orig);
274 		break;
275 	default:
276 		throw_libdhcpsvc_exception(env, rcode);
277 	}
278 }
279 
280 /* Throw an out of memory exception */
281 void
throw_memory_exception(JNIEnv * env)282 throw_memory_exception(JNIEnv *env)
283 {
284 	throw_libdhcpsvc_exception(env, DSVC_NO_MEMORY);
285 }
286 
287 /* Throw an exception indicating that there is no DHCP config file */
288 void
throw_no_defaults_exception(JNIEnv * env)289 throw_no_defaults_exception(JNIEnv *env)
290 {
291 	throw_exception(env,
292 	    "com/sun/dhcpmgr/bridge/NoDefaultsException", NULL, 0);
293 }
294 
295 /* Throw an exception indicating record or file does not exist */
296 void
throw_noent_exception(JNIEnv * env,const char * obj)297 throw_noent_exception(JNIEnv *env, const char *obj)
298 {
299 	throw_exception(env,
300 	    "com/sun/dhcpmgr/bridge/NoEntryException", NULL, 1, obj);
301 }
302 
303 /* Throw an exception indicating an invalid resource */
304 void
throw_invalid_resource_exception(JNIEnv * env,const char * obj)305 throw_invalid_resource_exception(JNIEnv *env, const char *obj)
306 {
307 	throw_exception(env, "com/sun/dhcpmgr/bridge/InvalidRsrcException",
308 	    NULL, 1, obj);
309 }
310 
311 /* Throw an exception indicating an invalid path */
312 void
throw_invalid_path_exception(JNIEnv * env,const char * obj)313 throw_invalid_path_exception(JNIEnv *env, const char *obj)
314 {
315 	throw_exception(env, "com/sun/dhcpmgr/bridge/InvalidPathException",
316 	    NULL, 1, obj);
317 }
318 
319 /* Throw an exception indicating that the service is not currently running */
320 void
throw_not_running_exception(JNIEnv * env)321 throw_not_running_exception(JNIEnv *env)
322 {
323 	throw_exception(env,
324 	    "com/sun/dhcpmgr/bridge/NotRunningException", NULL, 0);
325 }
326 
327 /* Throw exception for a libdhcpsvc error that requires no special treatment */
328 void
throw_libdhcpsvc_exception(JNIEnv * env,int rcode)329 throw_libdhcpsvc_exception(JNIEnv *env, int rcode)
330 {
331 	const char *msgid;
332 
333 	switch (rcode) {
334 	case DSVC_SUCCESS:
335 		break;
336 	case DSVC_EXISTS:
337 		msgid = DSVC_EXISTS_EX;
338 		break;
339 	case DSVC_ACCESS:
340 		msgid = DSVC_ACCESS_EX;
341 		break;
342 	case DSVC_NO_CRED:
343 		msgid = DSVC_CREDENTIAL_EX;
344 		break;
345 	case DSVC_NOENT:
346 		msgid = DSVC_NO_ENT_EX;
347 		break;
348 	case DSVC_BUSY:
349 		msgid = DSVC_BUSY_EX;
350 		break;
351 	case DSVC_INVAL:
352 		msgid = DSVC_INVALID_ARGS_EX;
353 		break;
354 	case DSVC_INTERNAL:
355 		msgid = DSVC_INTERNAL_EX;
356 		break;
357 	case DSVC_UNAVAILABLE:
358 		msgid = DSVC_UNAVAILABLE_EX;
359 		break;
360 	case DSVC_COLLISION:
361 		msgid = DSVC_COLLISION_EX;
362 		break;
363 	case DSVC_UNSUPPORTED:
364 		msgid = DSVC_UNSUPPORTED_EX;
365 		break;
366 	case DSVC_NO_MEMORY:
367 		msgid = DSVC_NO_MEMORY_EX;
368 		break;
369 	case DSVC_NO_RESOURCES:
370 		msgid = DSVC_NO_RESOURCES_EX;
371 		break;
372 	case DSVC_BAD_RESOURCE:
373 		msgid = DSVC_BAD_RESOURCE_EX;
374 		break;
375 	case DSVC_BAD_PATH:
376 		msgid = DSVC_BAD_PATH_EX;
377 		break;
378 	case DSVC_MODULE_VERSION:
379 		msgid = DSVC_MOD_VERSION_EX;
380 		break;
381 	case DSVC_MODULE_ERR:
382 		msgid = DSVC_MOD_ERR_EX;
383 		break;
384 	case DSVC_MODULE_LOAD_ERR:
385 		msgid = DSVC_MOD_LOAD_ERR_EX;
386 		break;
387 	case DSVC_MODULE_UNLOAD_ERR:
388 		msgid = DSVC_MOD_UNLOAD_ERR_EX;
389 		break;
390 	case DSVC_MODULE_CFG_ERR:
391 		msgid = DSVC_MOD_CFG_ERR_EX;
392 		break;
393 	case DSVC_SYNCH_ERR:
394 		msgid = DSVC_SYNCH_ERR_EX;
395 		break;
396 	case DSVC_NO_LOCKMGR:
397 		msgid = DSVC_NO_LOCKMGR_EX;
398 		break;
399 	case DSVC_NO_LOCATION:
400 		msgid = DSVC_NO_LOCATION_EX;
401 		break;
402 	case DSVC_BAD_CONVER:
403 		msgid = DSVC_BAD_CONVER_EX;
404 		break;
405 	default:
406 		msgid = DSVC_INTERNAL_ERROR;
407 	}
408 
409 	throw_bridge_exception(env, msgid);
410 }
411 
412 /* Determine whether an exception is a defaults file doesn't exist exception */
413 boolean_t
is_no_defaults_exception(JNIEnv * env,jthrowable e)414 is_no_defaults_exception(JNIEnv *env, jthrowable e)
415 {
416 	jclass class;
417 	boolean_t result = B_FALSE;
418 
419 	class = (*env)->FindClass(env,
420 	    "com/sun/dhcpmgr/bridge/NoDefaultsException");
421 	if (class != NULL) {
422 		if ((*env)->IsInstanceOf(env, e, class) == JNI_TRUE &&
423 		    e != NULL) {
424 			result = B_TRUE;
425 		}
426 	}
427 
428 	return (result);
429 }
430 
431 /* Throw a symbol parsing error */
432 /* ARGSUSED [one day we should use the `key' argument in messages] */
433 void
throw_dsym_parser_exception(JNIEnv * env,const char * key,char ** fields,int field,dsym_errcode_t rcode)434 throw_dsym_parser_exception(JNIEnv *env, const char *key, char **fields,
435     int field, dsym_errcode_t rcode)
436 {
437 	const char *dsym_exception  = "com/sun/dhcpmgr/bridge/DsymException";
438 
439 	char ascii_long_1[ULONG_MAX_CHAR + 1];
440 	char ascii_long_2[ULONG_MAX_CHAR + 1];
441 	ushort_t min;
442 	ushort_t max;
443 
444 	switch (rcode) {
445 	case DSYM_SUCCESS:
446 		break;
447 	case DSYM_SYNTAX_ERROR:
448 		throw_exception(env,
449 		    dsym_exception, DSYM_SYNTAX_EX, 1, fields[field]);
450 		break;
451 	case DSYM_CODE_OUT_OF_RANGE:
452 		(void) dsym_get_code_ranges(fields[DSYM_CAT_FIELD],
453 		    &min, &max, B_TRUE);
454 		(void) sprintf(ascii_long_1, "%d", min);
455 		(void) sprintf(ascii_long_2, "%d", max);
456 		throw_exception(env, dsym_exception, DSYM_CODE_OUT_OF_RANGE_EX,
457 		    3, fields[DSYM_CAT_FIELD], ascii_long_1, ascii_long_2);
458 		break;
459 	case DSYM_VALUE_OUT_OF_RANGE:
460 		throw_exception(env, dsym_exception,
461 		    DSYM_VALUE_OUT_OF_RANGE_EX, 1, fields[field]);
462 		break;
463 	case DSYM_INVALID_CAT:
464 		throw_exception(env, dsym_exception,
465 		    DSYM_INVALID_CAT_EX, 1, fields[DSYM_CAT_FIELD]);
466 		break;
467 	case DSYM_INVALID_TYPE:
468 		throw_exception(env, dsym_exception,
469 		    DSYM_INVALID_TYPE_EX, 1, fields[DSYM_TYPE_FIELD]);
470 		break;
471 	case DSYM_EXCEEDS_CLASS_SIZE:
472 		(void) sprintf(ascii_long_1, "%d", DSYM_CLASS_SIZE);
473 		throw_exception(env, dsym_exception,
474 		    DSYM_EXCEEDS_CLASS_SIZE_EX, 1, ascii_long_1);
475 		break;
476 	case DSYM_EXCEEDS_MAX_CLASS_SIZE:
477 		(void) sprintf(ascii_long_1, "%d", DSYM_MAX_CLASS_SIZE);
478 		throw_exception(env, dsym_exception,
479 		    DSYM_EXCEEDS_MAX_CLASS_SIZE_EX, 1, ascii_long_1);
480 		break;
481 	case DSYM_NO_MEMORY:
482 		throw_exception(env, dsym_exception, DSYM_NO_MEMORY_EX, 0);
483 		break;
484 	default:
485 		throw_exception(env, dsym_exception, DSYM_INTERNAL_EX, 0);
486 	}
487 }
488 
489 /* Throw a symbol init parsing error */
490 void
throw_dsym_parser_init_exception(JNIEnv * env,const char * key,dsym_errcode_t rcode)491 throw_dsym_parser_init_exception(JNIEnv *env, const char *key,
492     dsym_errcode_t rcode)
493 {
494 	const char *dsym_exception  = "com/sun/dhcpmgr/bridge/DsymException";
495 
496 	switch (rcode) {
497 	case DSYM_SUCCESS:
498 		break;
499 	case DSYM_NULL_FIELD:
500 		throw_exception(env,
501 		    dsym_exception, DSYM_TOO_FEW_FIELDS_EX, 1, key);
502 		break;
503 	case DSYM_TOO_MANY_FIELDS:
504 		throw_exception(env,
505 		    dsym_exception, DSYM_TOO_MANY_FIELDS_EX, 1, key);
506 		break;
507 	case DSYM_NO_MEMORY:
508 		throw_exception(env, dsym_exception, DSYM_NO_MEMORY_EX, 0);
509 		break;
510 	default:
511 		throw_exception(env, dsym_exception, DSYM_INTERNAL_EX, 0);
512 	}
513 }
514 
515 /* Throw an exception indicating an error in wordexp */
516 void
throw_wordexp_exception(JNIEnv * env,int code)517 throw_wordexp_exception(JNIEnv *env, int code)
518 {
519 	char buf[UINT64_MAX_CHAR + 1];
520 
521 	(void) snprintf(buf, sizeof (buf), "%d", code);
522 	throw_exception(env, "com/sun/dhcpmgr/bridge/WordexpException",
523 	    NULL, 1, buf);
524 }
525