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
  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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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 }