Home | History | Annotate | Download | only in native
      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  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 #include <jni.h>
     29 #include <kadm5/admin.h>
     30 #include <adm_err.h>
     31 #include <sys/signal.h>
     32 #include <netdb.h>
     33 #include <iconv.h>
     34 #include <langinfo.h>
     35 #include <clnt/client_internal.h>
     36 #include <etypes.h>
     37 
     38 static int Principal_to_kadmin(JNIEnv *, jobject, int, krb5_principal *,
     39 	kadm5_principal_ent_rec *, long *, char **, char **,
     40 	kadm5_config_params *);
     41 static int kadmin_to_Principal(kadm5_principal_ent_rec *, JNIEnv *, jobject,
     42 	const char *, char *);
     43 static int Policy_to_kadmin(JNIEnv *, jobject, int, kadm5_policy_ent_rec *,
     44 	long *);
     45 static int kadmin_to_Policy(kadm5_policy_ent_rec *, JNIEnv *, jobject);
     46 static int edit_comments(kadm5_principal_ent_rec *, krb5_principal, char *);
     47 static int format_comments(kadm5_principal_ent_rec *, long *, char *);
     48 static int extract_comments(kadm5_principal_ent_rec *, char **);
     49 static int set_password(krb5_principal, char *, kadm5_config_params *);
     50 static void handle_error(JNIEnv *, int);
     51 static char *qualify(char *name);
     52 
     53 static void *server_handle = NULL;
     54 static char *cur_realm = NULL;
     55 
     56 static iconv_t cd = (iconv_t)-1;
     57 
     58 static char *
     59 qualify(char *name)
     60 {
     61 	char *fullname;
     62 	int len;
     63 
     64 	if (strchr(name, '@') != NULL)
     65 		return (strdup(name));
     66 	len = strlen(name) + strlen(cur_realm) + 2;
     67 	fullname = malloc(len);
     68 	if (fullname)
     69 		snprintf(fullname, len, "%s@%s", name, cur_realm);
     70 	return (fullname);
     71 }
     72 
     73 
     74 /*
     75  * Class:     Kadmin
     76  * Method:    sessionInit
     77  * Signature:
     78  * (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
     79  */
     80 /*ARGSUSED*/
     81 JNIEXPORT jboolean JNICALL
     82 Java_Kadmin_sessionInit(JNIEnv *env, jobject obj, jstring name,
     83 	jstring passwd, jstring realm, jstring server, jint port)
     84 {
     85 	const char *cname = NULL, *cpasswd = NULL;
     86 	const char *crealm = NULL, *cserver = NULL;
     87 	int cport = 749;
     88 	kadm5_config_params params;
     89 	kadm5_ret_t ret;
     90 	char *ka_service = NULL;
     91 	char *ka_name = NULL;
     92 	char *codeset;
     93 	int len;
     94 
     95 	if (server_handle != NULL)
     96 		kadm5_destroy(server_handle);
     97 
     98 	if (cd == (iconv_t)-1) {
     99 		codeset = nl_langinfo(CODESET);
    100 		/* fprintf(stderr, "codeset returned %s\n", codeset);  XXX */
    101 		if (strcmp("UTF-8", codeset) != 0)
    102 			cd = iconv_open("UTF-8", codeset);
    103 	}
    104 
    105 	/* Get hold of string arguments */
    106 	cname = (*env)->GetStringUTFChars(env, name, NULL);
    107 	if (!cname) {
    108 		ret = KADM_JNI_STRING;
    109 		goto err;
    110 	}
    111 	cpasswd = (*env)->GetStringUTFChars(env, passwd, NULL);
    112 	if (!cpasswd) {
    113 		ret = KADM_JNI_STRING;
    114 		goto err;
    115 	}
    116 	crealm = (*env)->GetStringUTFChars(env, realm, NULL);
    117 	if (!crealm) {
    118 		ret = KADM_JNI_STRING;
    119 		goto err;
    120 	}
    121 	if (cur_realm)
    122 		free(cur_realm);
    123 	cur_realm = strdup(crealm);
    124 	cserver = (*env)->GetStringUTFChars(env, server, NULL);
    125 	if (!cserver) {
    126 		ret = KADM_JNI_STRING;
    127 		goto err;
    128 	}
    129 	if (port != 0)
    130 		cport = port;
    131 	else {
    132 		/*
    133 		 * Look for a services map entry
    134 		 * Note that this will be in network byte order,
    135 		 * and that the API requires native byte order.
    136 		 */
    137 		struct servent *rec = getservbyname("kerberos-adm", NULL);
    138 		if (rec)
    139 			cport = (int)ntohs((uint16_t)rec->s_port);
    140 	}
    141 
    142 	/*
    143 	 * Build kadm5_config_params with realm name and server name
    144 	 */
    145 	memset((char *)&params, 0, sizeof (params));
    146 	params.realm = (char *)crealm;
    147 	params.admin_server = (char *)cserver;
    148 	params.mask = KADM5_CONFIG_REALM | KADM5_CONFIG_ADMIN_SERVER;
    149 	params.kadmind_port = cport;
    150 	params.mask |= KADM5_CONFIG_KADMIND_PORT;
    151 	len = strlen("kadmin") + strlen(cserver) + 2;
    152 	ka_service = malloc(len);
    153 	if (!ka_service) {
    154 		ret = KADM_ENOMEM;
    155 		goto err;
    156 	}
    157 	snprintf(ka_service, len, "%s@%s", "kadmin", cserver);
    158 	ka_name = qualify((char *)cname);
    159 	if (!ka_name) {
    160 		ret = KADM_ENOMEM;
    161 		goto err;
    162 	}
    163 
    164 	ret = kadm5_init_with_password(ka_name, (char *)cpasswd,
    165 				ka_service, &params, KADM5_STRUCT_VERSION,
    166 				KADM5_API_VERSION_2, NULL, &server_handle);
    167 
    168 	/* Release string arguments and variables */
    169 	if (cname)
    170 		(*env)->ReleaseStringUTFChars(env, name, cname);
    171 	if (cpasswd)
    172 		(*env)->ReleaseStringUTFChars(env, passwd, cpasswd);
    173 	if (crealm)
    174 		(*env)->ReleaseStringUTFChars(env, realm, crealm);
    175 	if (cserver)
    176 		(*env)->ReleaseStringUTFChars(env, server, cserver);
    177 	if (ka_name)
    178 		free(ka_name);
    179 	if (ka_service)
    180 		free(ka_service);
    181 
    182 err:
    183 	if (ret) {
    184 		handle_error(env, ret);
    185 		return (JNI_FALSE);
    186 	}
    187 	return (JNI_TRUE);
    188 }
    189 
    190 /*
    191  * Class:     Kadmin
    192  * Method:    sessionExit
    193  * Signature: ()V
    194  */
    195 /*ARGSUSED*/
    196 JNIEXPORT void JNICALL
    197 Java_Kadmin_sessionExit(JNIEnv *env, jobject obj)
    198 {
    199 	kadm5_ret_t ret;
    200 
    201 	/*
    202 	 * Use persistant handle to close
    203 	 */
    204 	ret = kadm5_destroy(server_handle);
    205 	if (ret)
    206 		handle_error(env, ret);
    207 	server_handle = NULL;
    208 	if (cur_realm) {
    209 		free(cur_realm);
    210 		cur_realm = NULL;
    211 	}
    212 }
    213 
    214 /*
    215  * Class:     Kadmin
    216  * Method:    getPrivs
    217  * Signature: ()I
    218  */
    219 /*ARGSUSED*/
    220 JNIEXPORT jint JNICALL
    221 Java_Kadmin_getPrivs(JNIEnv *env, jobject obj)
    222 {
    223 	long privs = 0;
    224 	kadm5_ret_t ret;
    225 
    226 	/*
    227 	 * Get ACL for this user
    228 	 */
    229 	ret = kadm5_get_privs(server_handle, &privs);
    230 	if (ret)
    231 		handle_error(env, ret);
    232 	return (privs);
    233 }
    234 
    235 static int
    236 charcmp(const void *a, const void *b)
    237 {
    238 	char    **sa = (char **)a;
    239 	char    **sb = (char **)b;
    240 
    241 	return (strcmp(*sa, *sb));
    242 }
    243 
    244 /*
    245  * Class:     Kadmin
    246  * Method:    getEncList
    247  * Signature: ()[Ljava/lang/String;
    248  */
    249 
    250 /*ARGSUSED*/
    251 JNIEXPORT jobjectArray JNICALL
    252 Java_Kadmin_getEncList(JNIEnv *env,
    253 	jobject obj)
    254 {
    255 	jclass stringclass;
    256 	jobjectArray elist;
    257 	jstring s;
    258 	kadm5_ret_t ret;
    259 	int i, j, k, *grp = NULL;
    260 	krb5_int32 num_keysalts;
    261 	krb5_key_salt_tuple *keysalts;
    262 	krb5_enctype e_type;
    263 	kadm5_server_handle_t handle;
    264 	char *e_str, e_buf[BUFSIZ];
    265 	krb5_error_code kret;
    266 	krb5_boolean similar;
    267 	krb5_context context;
    268 
    269 	if (kret = krb5_init_context(&context)) {
    270 		handle_error(env, kret);
    271 		return (NULL);
    272 	}
    273 
    274 	/*
    275 	 * Create and populate a Java String array
    276 	 */
    277 	stringclass = (*env)->FindClass(env, "java/lang/String");
    278 	if (!stringclass) {
    279 		handle_error(env, KADM_JNI_CLASS);
    280 		return (NULL);
    281 	}
    282 
    283 	handle = server_handle;
    284 	num_keysalts = handle->params.num_keysalts;
    285 	keysalts = handle->params.keysalts;
    286 	elist = (*env)->NewObjectArray(env, num_keysalts, stringclass, NULL);
    287 	if (!elist) {
    288 		handle_error(env, KADM_JNI_ARRAY);
    289 		return (NULL);
    290 	}
    291 
    292 	/*
    293 	 * Populate groupings for encryption types that are similar.
    294 	 */
    295 	grp = malloc(sizeof (int) * num_keysalts);
    296 	if (grp == NULL) {
    297 		handle_error(env, errno);
    298 		return (NULL);
    299 	}
    300 	for (i = 0; i < num_keysalts; grp[i] = i++);
    301 	for (i = 0; i < num_keysalts; i++) {
    302 		if (grp[i] != i)
    303 			continue;
    304 		for (j = i + 1; j < num_keysalts; j++) {
    305 			if (kret = krb5_c_enctype_compare(context,
    306 			    keysalts[i].ks_enctype, keysalts[j].ks_enctype,
    307 			    &similar)) {
    308 				free(grp);
    309 				handle_error(env, kret);
    310 				return (NULL);
    311 			}
    312 			if (similar)
    313 				grp[j] = grp[i];
    314 		}
    315 	}
    316 
    317 	/*
    318 	 * Populate from params' supported enc type list from the initial kadmin
    319 	 * session, this is documented default that the client can handle.
    320 	 */
    321 	for (i = 0; i < num_keysalts; i++) {
    322 		e_type = keysalts[i].ks_enctype;
    323 
    324 		for (j = 0; j < krb5_enctypes_length; j++) {
    325 			if (e_type == krb5_enctypes_list[j].etype) {
    326 				e_str = krb5_enctypes_list[j].in_string;
    327 				(void) snprintf(e_buf, sizeof (e_buf),
    328 				    "%d %s:normal", grp[i], e_str);
    329 				s = (*env)->NewStringUTF(env, e_buf);
    330 				if (!s) {
    331 					free(grp);
    332 					handle_error(env, KADM_JNI_NEWSTRING);
    333 					return (NULL);
    334 				}
    335 				(*env)->SetObjectArrayElement(env, elist, i, s);
    336 				break;
    337 			}
    338 		}
    339 	}
    340 
    341 	free(grp);
    342 	return (elist);
    343 }
    344 
    345 /*
    346  * Class:     Kadmin
    347  * Method:    getPrincipalList
    348  * Signature: ()[Ljava/lang/String;
    349  */
    350 /*ARGSUSED*/
    351 JNIEXPORT jobjectArray JNICALL
    352 Java_Kadmin_getPrincipalList(JNIEnv *env,
    353 	jobject obj)
    354 {
    355 	jclass stringclass;
    356 	jobjectArray plist;
    357 	jstring s;
    358 	char **princs;
    359 	int i, count;
    360 	kadm5_ret_t ret;
    361 
    362 	/*
    363 	 * Get the list
    364 	 */
    365 	ret = kadm5_get_principals(server_handle, NULL, &princs, &count);
    366 	if (ret) {
    367 		handle_error(env, ret);
    368 		return (NULL);
    369 	}
    370 	qsort(princs, count, sizeof (princs[0]), charcmp);
    371 
    372 	/*
    373 	 * Create and populate a Java String array
    374 	 */
    375 	stringclass = (*env)->FindClass(env, "java/lang/String");
    376 	if (!stringclass) {
    377 		handle_error(env, KADM_JNI_CLASS);
    378 		return (NULL);
    379 	}
    380 	plist = (*env)->NewObjectArray(env, count, stringclass, NULL);
    381 	if (!plist) {
    382 		handle_error(env, KADM_JNI_ARRAY);
    383 		return (NULL);
    384 	}
    385 	for (i = 0; i < count; i++) {
    386 		s = (*env)->NewStringUTF(env, princs[i]);
    387 		if (!s) {
    388 			handle_error(env, KADM_JNI_NEWSTRING);
    389 			return (NULL);
    390 		}
    391 		(*env)->SetObjectArrayElement(env, plist, i, s);
    392 	}
    393 	kadm5_free_name_list(server_handle, princs, count);
    394 	return (plist);
    395 }
    396 
    397 /*
    398  * Class:     Kadmin
    399  * Method:    getPrincipalList2
    400  * Signature: ()Ljava/lang/String;
    401  */
    402 /*ARGSUSED*/
    403 JNIEXPORT jstring JNICALL
    404 Java_Kadmin_getPrincipalList2(JNIEnv *env, jobject obj)
    405 {
    406 	jstring plist;
    407 	char **princs;
    408 	char *princlist = NULL;
    409 	int i, count, n, used = 0, size = 0;
    410 	kadm5_ret_t ret;
    411 
    412 	/*
    413 	 * Get the list
    414 	 */
    415 	ret = kadm5_get_principals(server_handle, NULL, &princs, &count);
    416 	if (ret) {
    417 		handle_error(env, ret);
    418 		return (NULL);
    419 	}
    420 	qsort(princs, count, sizeof (princs[0]), charcmp);
    421 
    422 	/*
    423 	 * Build one large C string to hold list
    424 	 */
    425 	used = 0;
    426 	princlist = malloc(size += 2048);
    427 	if (!princlist)
    428 		return (NULL);
    429 	for (i = 0; i < count; i++) {
    430 		n = strlen(princs[i]);
    431 		if (used + n + 2 > size) {
    432 			princlist = realloc(princlist, size += 2048);
    433 			if (!princlist)
    434 				return (NULL);
    435 		}
    436 		strncpy(&princlist[used], princs[i], n);
    437 		used += n + 1;
    438 		princlist[used-1] = ' ';
    439 		princlist[used] = '\0';
    440 	}
    441 
    442 	/*
    443 	 * Create a Java String
    444 	 */
    445 	plist = (*env)->NewStringUTF(env, princlist);
    446 	free(princlist);
    447 	kadm5_free_name_list(server_handle, princs, count);
    448 	return (plist);
    449 }
    450 
    451 
    452 /*
    453  * Class:     Kadmin
    454  * Method:    loadPrincipal
    455  * Signature: (Ljava/lang/String;LPrincipal;)Z
    456  */
    457 /*ARGSUSED*/
    458 JNIEXPORT jboolean JNICALL
    459 Java_Kadmin_loadPrincipal(JNIEnv *env, jobject obj, jstring name, jobject prin)
    460 {
    461 	const char *cname;
    462 	char *fullname;
    463 	char *comments = NULL;
    464 	kadm5_principal_ent_rec pr_rec;
    465 	kadm5_ret_t ret;
    466 	long mask = KADM5_PRINCIPAL_NORMAL_MASK | KADM5_TL_DATA |
    467 	    KADM5_KEY_DATA;
    468 	krb5_principal kprin = NULL;
    469 	krb5_context context;
    470 
    471 	cname = (*env)->GetStringUTFChars(env, name, NULL);
    472 	if (!cname) {
    473 		handle_error(env, KADM_JNI_STRING);
    474 		return (JNI_FALSE);
    475 	}
    476 	fullname = qualify((char *)cname);
    477 	if (!fullname) {
    478 		handle_error(env, KADM_JNI_STRING);
    479 		return (JNI_FALSE);
    480 	}
    481 
    482 	/*
    483 	 * Get the principal
    484 	 */
    485 	ret = krb5_init_context(&context);
    486 	if (ret) {
    487 		handle_error(env, ret);
    488 		return (JNI_FALSE);
    489 	}
    490 	ret = krb5_parse_name(context, fullname, &kprin);
    491 	if (ret) {
    492 		handle_error(env, ret);
    493 		return (JNI_FALSE);
    494 	}
    495 	memset((char *)&pr_rec, 0, sizeof (pr_rec));
    496 	ret = kadm5_get_principal(server_handle, kprin, &pr_rec, mask);
    497 	if (ret) {
    498 		handle_error(env, ret);
    499 		return (JNI_FALSE);
    500 	}
    501 
    502 	/*
    503 	 * Pull the comments out of the tl_data array
    504 	 */
    505 	ret = extract_comments(&pr_rec, &comments);
    506 	if (ret) {
    507 		handle_error(env, ret);
    508 		return (JNI_FALSE);
    509 	}
    510 
    511 	/*
    512 	 * Fill in our Principal object
    513 	 */
    514 	ret = kadmin_to_Principal(&pr_rec, env, prin, cname, comments);
    515 	if (ret) {
    516 		handle_error(env, ret);
    517 		return (JNI_FALSE);
    518 	}
    519 
    520 	kadm5_free_principal_ent(server_handle, &pr_rec);
    521 	krb5_free_principal(context, kprin);
    522 	(*env)->ReleaseStringUTFChars(env, name, cname);
    523 	free(fullname);
    524 
    525 	return (JNI_TRUE);
    526 }
    527 
    528 /*
    529  * Class:     Kadmin
    530  * Method:    savePrincipal
    531  * Signature: (LPrincipal;)Z
    532  */
    533 /*ARGSUSED*/
    534 JNIEXPORT jboolean JNICALL
    535 Java_Kadmin_savePrincipal(JNIEnv *env, jobject obj, jobject prin)
    536 {
    537 	kadm5_principal_ent_rec pr_rec;
    538 	long mask;
    539 	char *pw = NULL;
    540 	char *comments = NULL;
    541 	kadm5_ret_t ret;
    542 	krb5_principal kprin = NULL;
    543 	kadm5_config_params params;
    544 
    545 	/*
    546 	 * Convert principal object to the kadmin API structure
    547 	 */
    548 	memset((char *)&pr_rec, 0, sizeof (pr_rec));
    549 	memset((char *)&params, 0, sizeof (params));
    550 	ret = Principal_to_kadmin(env, prin, 0, &kprin, &pr_rec, &mask,
    551 					&pw, &comments, &params);
    552 	if (ret) {
    553 		handle_error(env, ret);
    554 		return (JNI_FALSE);
    555 	}
    556 
    557 	/*
    558 	 * Save the principal
    559 	 */
    560 	ret = kadm5_modify_principal(server_handle, &pr_rec, mask);
    561 	if (ret) {
    562 		handle_error(env, ret);
    563 		ret = JNI_FALSE;
    564 		goto out;
    565 	}
    566 
    567 	/*
    568 	 * Handle any comments with read-modify-write
    569 	 */
    570 	ret = edit_comments(&pr_rec, kprin, comments);
    571 	if (ret) {
    572 		handle_error(env, ret);
    573 		ret = JNI_FALSE;
    574 		goto out;
    575 	}
    576 
    577 	/*
    578 	 * Set the password if changed
    579 	 */
    580 	ret = set_password(kprin, pw, &params);
    581 	if (params.keysalts != NULL)
    582 		free(params.keysalts);
    583 	if (ret) {
    584 		handle_error(env, ret);
    585 		ret = JNI_FALSE;
    586 		goto out;
    587 	}
    588 	ret = JNI_TRUE;
    589 
    590 out:
    591 	kadm5_free_principal_ent(server_handle, &pr_rec);
    592 	return (ret);
    593 }
    594 
    595 /*
    596  * Class:     Kadmin
    597  * Method:    createPrincipal
    598  * Signature: (LPrincipal;)Z
    599  */
    600 /*ARGSUSED*/
    601 JNIEXPORT jboolean JNICALL
    602 Java_Kadmin_createPrincipal(JNIEnv *env, jobject obj, jobject prin)
    603 {
    604 	kadm5_principal_ent_rec pr_rec;
    605 	long mask;
    606 	char *pw = NULL;
    607 	char *comments = NULL;
    608 	kadm5_ret_t ret;
    609 	krb5_principal kprin = NULL;
    610 	kadm5_config_params params;
    611 
    612 	/*
    613 	 * Convert principal object to the kadmin API structure
    614 	 */
    615 	memset((char *)&pr_rec, 0, sizeof (pr_rec));
    616 	memset((char *)&params, 0, sizeof (params));
    617 	ret = Principal_to_kadmin(env, prin, 1, &kprin, &pr_rec, &mask,
    618 					&pw, &comments, &params);
    619 	if (ret) {
    620 		handle_error(env, ret);
    621 		return (JNI_FALSE);
    622 	}
    623 
    624 	/*
    625 	 * Create the new principal
    626 	 */
    627 	if (params.mask & KADM5_CONFIG_ENCTYPES) {
    628 		ret = kadm5_create_principal_3(server_handle, &pr_rec, mask,
    629 			params.num_keysalts, params.keysalts, pw);
    630 		if (params.keysalts != NULL)
    631 			free(params.keysalts);
    632 	} else
    633 		ret = kadm5_create_principal(server_handle, &pr_rec, mask, pw);
    634 	if (ret) {
    635 		handle_error(env, ret);
    636 		ret = JNI_FALSE;
    637 		goto out;
    638 	}
    639 
    640 	/*
    641 	 * Handle any comments with read-modify-write
    642 	 */
    643 	ret = edit_comments(&pr_rec, kprin, comments);
    644 	if (ret) {
    645 		handle_error(env, ret);
    646 		ret = JNI_FALSE;
    647 		goto out;
    648 	}
    649 
    650 	ret = JNI_TRUE;
    651 out:
    652 	kadm5_free_principal_ent(server_handle, &pr_rec);
    653 	return (ret);
    654 }
    655 
    656 /*
    657  * Class:     Kadmin
    658  * Method:    deletePrincipal
    659  * Signature: (Ljava/lang/String;)Z
    660  */
    661 /*ARGSUSED*/
    662 JNIEXPORT jboolean JNICALL
    663 Java_Kadmin_deletePrincipal(JNIEnv *env, jobject obj, jstring name)
    664 {
    665 	kadm5_ret_t ret;
    666 	const char *cname;
    667 	char *fullname;
    668 	krb5_principal kprin = NULL;
    669 	krb5_context context;
    670 
    671 	/*
    672 	 * Get name and call the delete function
    673 	 */
    674 	cname = (*env)->GetStringUTFChars(env, name, NULL);
    675 	if (!cname) {
    676 		handle_error(env, KADM_JNI_STRING);
    677 		return (JNI_FALSE);
    678 	}
    679 	fullname = qualify((char *)cname);
    680 	if (!fullname) {
    681 		handle_error(env, KADM_JNI_STRING);
    682 		return (JNI_FALSE);
    683 	}
    684 
    685 	ret = krb5_init_context(&context);
    686 	if (ret) {
    687 		handle_error(env, ret);
    688 		return (JNI_FALSE);
    689 	}
    690 	ret = krb5_parse_name(context, fullname, &kprin);
    691 	if (ret) {
    692 		handle_error(env, ret);
    693 		return (JNI_FALSE);
    694 	}
    695 	ret = kadm5_delete_principal(server_handle, kprin);
    696 	if (ret) {
    697 		handle_error(env, ret);
    698 		return (JNI_FALSE);
    699 	}
    700 
    701 	krb5_free_principal(context, kprin);
    702 	(*env)->ReleaseStringUTFChars(env, name, cname);
    703 	free(fullname);
    704 
    705 	return (JNI_TRUE);
    706 }
    707 
    708 /*
    709  * Class:     Kadmin
    710  * Method:    getPolicyList
    711  * Signature: ()[Ljava/lang/String;
    712  */
    713 /*ARGSUSED*/
    714 JNIEXPORT jobjectArray JNICALL
    715 Java_Kadmin_getPolicyList(JNIEnv *env, jobject obj)
    716 {
    717 	jclass stringclass;
    718 	jobjectArray plist;
    719 	jstring s;
    720 	char **pols;
    721 	int i, count;
    722 	kadm5_ret_t ret;
    723 
    724 	/*
    725 	 * Get the list
    726 	 */
    727 	ret = kadm5_get_policies(server_handle, NULL, &pols, &count);
    728 	if (ret) {
    729 		handle_error(env, ret);
    730 		return (NULL);
    731 	}
    732 	qsort(pols, count, sizeof (pols[0]), charcmp);
    733 
    734 	/*
    735 	 * Create and populate a Java String array
    736 	 */
    737 	stringclass = (*env)->FindClass(env, "java/lang/String");
    738 	if (!stringclass) {
    739 		handle_error(env, KADM_JNI_CLASS);
    740 		return (NULL);
    741 	}
    742 	plist = (*env)->NewObjectArray(env, count, stringclass, NULL);
    743 	if (!plist) {
    744 		handle_error(env, KADM_JNI_ARRAY);
    745 		return (NULL);
    746 	}
    747 	for (i = 0; i < count; i++) {
    748 		s = (*env)->NewStringUTF(env, pols[i]);
    749 		if (!s) {
    750 			handle_error(env, KADM_JNI_NEWSTRING);
    751 			return (NULL);
    752 		}
    753 		(*env)->SetObjectArrayElement(env, plist, i, s);
    754 	}
    755 	kadm5_free_name_list(server_handle, pols, count);
    756 	return (plist);
    757 }
    758 
    759 /*
    760  * Class:     Kadmin
    761  * Method:    loadPolicy
    762  * Signature: (Ljava/lang/String;LPolicy;)Z
    763  */
    764 /*ARGSUSED*/
    765 JNIEXPORT jboolean JNICALL
    766 Java_Kadmin_loadPolicy(JNIEnv *env, jobject obj, jstring name, jobject pol)
    767 {
    768 	const char *cname;
    769 	kadm5_policy_ent_rec po_rec;
    770 	kadm5_ret_t ret;
    771 
    772 	cname = (*env)->GetStringUTFChars(env, name, NULL);
    773 	if (!cname) {
    774 		handle_error(env, KADM_JNI_STRING);
    775 		return (JNI_FALSE);
    776 	}
    777 
    778 	ret = kadm5_get_policy(server_handle, (char *)cname, &po_rec);
    779 	if (ret) {
    780 		handle_error(env, ret);
    781 		return (JNI_FALSE);
    782 	}
    783 
    784 	ret = kadmin_to_Policy(&po_rec, env, pol);
    785 	if (ret) {
    786 		handle_error(env, ret);
    787 		return (JNI_FALSE);
    788 	}
    789 
    790 	kadm5_free_policy_ent(server_handle, &po_rec);
    791 	(*env)->ReleaseStringUTFChars(env, name, cname);
    792 
    793 	return (JNI_TRUE);
    794 }
    795 
    796 /*
    797  * Class:     Kadmin
    798  * Method:    savePolicy
    799  * Signature: (LPolicy;)Z
    800  */
    801 /*ARGSUSED*/
    802 JNIEXPORT jboolean JNICALL
    803 Java_Kadmin_savePolicy(JNIEnv *env, jobject obj, jobject pol)
    804 {
    805 	kadm5_policy_ent_rec po_rec;
    806 	kadm5_ret_t ret;
    807 	long mask;
    808 
    809 	ret = Policy_to_kadmin(env, pol, 0, &po_rec, &mask);
    810 	if (ret) {
    811 		handle_error(env, ret);
    812 		return (JNI_FALSE);
    813 	}
    814 
    815 	ret = kadm5_modify_policy(server_handle, &po_rec, mask);
    816 	if (ret) {
    817 		handle_error(env, ret);
    818 		return (JNI_FALSE);
    819 	}
    820 
    821 	return (JNI_TRUE);
    822 }
    823 
    824 /*
    825  * Class:     Kadmin
    826  * Method:    createPolicy
    827  * Signature: (LPolicy;)Z
    828  */
    829 /*ARGSUSED*/
    830 JNIEXPORT jboolean JNICALL
    831 Java_Kadmin_createPolicy(JNIEnv * env, jobject obj, jobject pol)
    832 {
    833 	kadm5_policy_ent_rec po_rec;
    834 	kadm5_ret_t ret;
    835 	long mask;
    836 
    837 	ret = Policy_to_kadmin(env, pol, 1, &po_rec, &mask);
    838 	if (ret) {
    839 		handle_error(env, ret);
    840 		return (JNI_FALSE);
    841 	}
    842 
    843 	ret = kadm5_create_policy(server_handle, &po_rec, mask);
    844 	if (ret) {
    845 		handle_error(env, ret);
    846 		return (JNI_FALSE);
    847 	}
    848 
    849 	return (JNI_TRUE);
    850 }
    851 
    852 /*
    853  * Class:     Kadmin
    854  * Method:    deletePolicy
    855  * Signature: (Ljava/lang/String;)Z
    856  */
    857 /*ARGSUSED*/
    858 JNIEXPORT jboolean JNICALL
    859 Java_Kadmin_deletePolicy(JNIEnv * env, jobject obj, jstring name)
    860 {
    861 	const char *cname;
    862 	kadm5_ret_t ret;
    863 
    864 	cname = (*env)->GetStringUTFChars(env, name, NULL);
    865 	if (!cname) {
    866 		handle_error(env, KADM_JNI_STRING);
    867 		return (JNI_FALSE);
    868 	}
    869 
    870 	ret = kadm5_delete_policy(server_handle, (char *)cname);
    871 	if (ret) {
    872 		handle_error(env, ret);
    873 		return (JNI_FALSE);
    874 	}
    875 	return (JNI_TRUE);
    876 }
    877 
    878 #ifdef needtoknowmore
    879 /*
    880  * Class:     Kadmin
    881  * Method:    loadDefaults
    882  * Signature: (LConfig;)Z
    883  */
    884 /*ARGSUSED*/
    885 JNIEXPORT jboolean JNICALL
    886 Java_Kadmin_loadDefaults(JNIEnv *env, jobject obj, jobject config)
    887 {
    888 	/*
    889 	 *
    890 	 */
    891 	return (JNI_TRUE);
    892 }
    893 
    894 /*
    895  * Class:     Kadmin
    896  * Method:    saveDefaults
    897  * Signature: (LConfig;)Z
    898  */
    899 /*ARGSUSED*/
    900 JNIEXPORT jboolean JNICALL
    901 Java_Kadmin_saveDefaults(JNIEnv *env, jobject obj, jobject config)
    902 {
    903 	/*
    904 	 *
    905 	 */
    906 	return (JNI_TRUE);
    907 }
    908 #endif
    909 
    910 static int
    911 Principal_to_kadmin(JNIEnv *env, jobject prin, int new, krb5_principal *kprin,
    912 	kadm5_principal_ent_rec *p, long *mask, char **pw, char **comments,
    913 	kadm5_config_params *pparams)
    914 {
    915 	jstring s;
    916 	jclass prcl, dateclass, intclass;
    917 	jfieldID f;
    918 	jmethodID mid;
    919 	jobject obj;
    920 	const char *str;
    921 	jlong l;
    922 	jint i;
    923 	jboolean b;
    924 	kadm5_ret_t ret;
    925 	krb5_context context;
    926 	jfieldID flagsID;
    927 	jobject flagsObj;
    928 	jclass flagsClass;
    929 	char *fullname;
    930 
    931 	*mask = 0;
    932 
    933 	prcl = (*env)->GetObjectClass(env, prin);
    934 	if (!prcl)
    935 		return (KADM_JNI_CLASS);
    936 	dateclass = (*env)->FindClass(env, "java/util/Date");
    937 	if (!dateclass)
    938 		return (KADM_JNI_CLASS);
    939 	intclass = (*env)->FindClass(env, "java/lang/Integer");
    940 	if (!intclass)
    941 		return (KADM_JNI_CLASS);
    942 
    943 	f = (*env)->GetFieldID(env, prcl, "PrName", "Ljava/lang/String;");
    944 	if (!f)
    945 		return (KADM_JNI_FIELD);
    946 	obj = (*env)->GetObjectField(env, prin, f);
    947 	if (!obj)
    948 		return (KADM_JNI_OFIELD);
    949 	s = (jstring)obj;
    950 	str = (*env)->GetStringUTFChars(env, s, NULL);
    951 	if (!str)
    952 		return (KADM_JNI_STRING);
    953 	fullname = qualify((char *)str);
    954 	if (!fullname)
    955 		return (KADM_ENOMEM);
    956 	ret = krb5_init_context(&context);
    957 	if (ret)
    958 		return (ret);
    959 	ret = krb5_parse_name(context, fullname, kprin);
    960 	if (ret)
    961 		return (ret);
    962 	p->principal = *kprin;
    963 	(*env)->ReleaseStringUTFChars(env, s, str);
    964 	if (new)
    965 		*mask |= KADM5_PRINCIPAL;
    966 
    967 	f = (*env)->GetFieldID(env, prcl, "PrExpireTime", "Ljava/util/Date;");
    968 	if (!f)
    969 		return (KADM_JNI_FIELD);
    970 	obj = (*env)->GetObjectField(env, prin, f);
    971 	if (!obj)
    972 		return (KADM_JNI_OFIELD);
    973 	mid = (*env)->GetMethodID(env, dateclass, "getTime", "()J");
    974 	if (!mid)
    975 		return (KADM_JNI_METHOD);
    976 	l = (*env)->CallLongMethod(env, obj, mid);
    977 	p->princ_expire_time = (long)(l / 1000LL);
    978 	*mask |= KADM5_PRINC_EXPIRE_TIME;
    979 
    980 	f = (*env)->GetFieldID(env, prcl, "EncTypes", "Ljava/lang/String;");
    981 	if (!f)
    982 		return (KADM_JNI_FIELD);
    983 	obj = (*env)->GetObjectField(env, prin, f);
    984 	if (!obj)
    985 		return (KADM_JNI_OFIELD);
    986 	s = (jstring)obj;
    987 	str = (*env)->GetStringUTFChars(env, s, NULL);
    988 	if (!str)
    989 		return (KADM_JNI_STRING);
    990 	if (strlen(str)) {
    991 		ret = krb5_string_to_keysalts((char *)str, ", \t", ":.-", 0,
    992 		    &(pparams->keysalts), &(pparams->num_keysalts));
    993 		if (ret) {
    994 			(*env)->ReleaseStringUTFChars(env, s, str);
    995 			return (ret);
    996 		}
    997 		pparams->mask |= KADM5_CONFIG_ENCTYPES;
    998 	}
    999 	(*env)->ReleaseStringUTFChars(env, s, str);
   1000 
   1001 	f = (*env)->GetFieldID(env, prcl, "Policy", "Ljava/lang/String;");
   1002 	if (!f)
   1003 		return (KADM_JNI_FIELD);
   1004 	obj = (*env)->GetObjectField(env, prin, f);
   1005 	if (!obj)
   1006 		return (KADM_JNI_OFIELD);
   1007 	s = (jstring)obj;
   1008 	str = (*env)->GetStringUTFChars(env, s, NULL);
   1009 	if (!str)
   1010 		return (KADM_JNI_STRING);
   1011 	p->policy = strdup(str);
   1012 	if (!p->policy)
   1013 		return (KADM_ENOMEM);
   1014 	(*env)->ReleaseStringUTFChars(env, s, str);
   1015 	if (strlen(p->policy))
   1016 		*mask |= KADM5_POLICY;
   1017 	else if (!new)
   1018 		*mask |= KADM5_POLICY_CLR;
   1019 
   1020 	f = (*env)->GetFieldID(env, prcl, "PwExpireTime", "Ljava/util/Date;");
   1021 	if (!f)
   1022 		return (KADM_JNI_FIELD);
   1023 	obj = (*env)->GetObjectField(env, prin, f);
   1024 	if (obj) {
   1025 		mid = (*env)->GetMethodID(env, dateclass, "getTime", "()J");
   1026 		if (!mid)
   1027 			return (KADM_JNI_METHOD);
   1028 		l = (*env)->CallLongMethod(env, obj, mid);
   1029 		p->pw_expiration = (long)(l / 1000LL);
   1030 		*mask |= KADM5_PW_EXPIRATION;
   1031 	}
   1032 
   1033 	f = (*env)->GetFieldID(env, prcl, "MaxLife", "Ljava/lang/Integer;");
   1034 	if (!f)
   1035 		return (KADM_JNI_FIELD);
   1036 	obj = (*env)->GetObjectField(env, prin, f);
   1037 	if (!obj)
   1038 		return (KADM_JNI_OFIELD);
   1039 	mid = (*env)->GetMethodID(env, intclass, "intValue", "()I");
   1040 	if (!mid)
   1041 		return (KADM_JNI_METHOD);
   1042 	i = (*env)->CallIntMethod(env, obj, mid);
   1043 	p->max_life = i;
   1044 	*mask |= KADM5_MAX_LIFE;
   1045 
   1046 	f = (*env)->GetFieldID(env, prcl, "MaxRenew", "Ljava/lang/Integer;");
   1047 	if (!f)
   1048 		return (KADM_JNI_FIELD);
   1049 	obj = (*env)->GetObjectField(env, prin, f);
   1050 	if (!obj)
   1051 		return (KADM_JNI_OFIELD);
   1052 	mid = (*env)->GetMethodID(env, intclass, "intValue", "()I");
   1053 	if (!mid)
   1054 		return (KADM_JNI_METHOD);
   1055 	i = (*env)->CallIntMethod(env, obj, mid);
   1056 	p->max_renewable_life = i;
   1057 	*mask |= KADM5_MAX_RLIFE;
   1058 
   1059 	/*
   1060 	 * Comments: because of API rules on the TL_DATA entries,
   1061 	 * which say that a load-modify-write is always necessary,
   1062 	 * we will only deal with comments if they are newly changed.
   1063 	 */
   1064 	f = (*env)->GetFieldID(env, prcl, "newComments", "Z");
   1065 	if (!f)
   1066 		return (KADM_JNI_FIELD);
   1067 	b = (*env)->GetBooleanField(env, prin, f);
   1068 	if (b == JNI_TRUE) {
   1069 
   1070 		f = (*env)->GetFieldID(env, prcl, "Comments",
   1071 				"Ljava/lang/String;");
   1072 		if (!f)
   1073 			return (KADM_JNI_FIELD);
   1074 		obj = (*env)->GetObjectField(env, prin, f);
   1075 		if (!obj)
   1076 			return (KADM_JNI_OFIELD);
   1077 		s = (jstring)obj;
   1078 		str = (*env)->GetStringUTFChars(env, s, NULL);
   1079 		if (!str)
   1080 			return (KADM_JNI_STRING);
   1081 		*comments = strdup(str);
   1082 		if (!*comments)
   1083 			return (KADM_ENOMEM);
   1084 		(*env)->ReleaseStringUTFChars(env, s, str);
   1085 	}
   1086 
   1087 	f = (*env)->GetFieldID(env, prcl, "Kvno", "Ljava/lang/Integer;");
   1088 	if (!f)
   1089 		return (KADM_JNI_FIELD);
   1090 	obj = (*env)->GetObjectField(env, prin, f);
   1091 	if (!obj)
   1092 		return (KADM_JNI_OFIELD);
   1093 	mid = (*env)->GetMethodID(env, intclass, "intValue", "()I");
   1094 	if (!mid)
   1095 		return (KADM_JNI_METHOD);
   1096 	i = (*env)->CallIntMethod(env, obj, mid);
   1097 	p->kvno = i;
   1098 	*mask |= KADM5_KVNO;
   1099 
   1100 	/*
   1101 	 * Get the Principal.flags field id
   1102 	 */
   1103 	flagsID = (*env)->GetFieldID(env, prcl, "flags",
   1104 				    "LFlags;");
   1105 	if (!f)
   1106 		return (KADM_JNI_FIELD);
   1107 
   1108 	/*
   1109 	 * Get the Principal.Flags object
   1110 	 */
   1111 	flagsObj = (*env)->GetObjectField(env, prin, flagsID);
   1112 	if (!obj)
   1113 		return (KADM_JNI_OFIELD);
   1114 
   1115 	/*
   1116 	 * Get the Flags object's class
   1117 	 */
   1118 	flagsClass = (*env)->GetObjectClass(env, flagsObj);
   1119 	if (!flagsClass)
   1120 		return (KADM_JNI_CLASS);
   1121 
   1122 	/*
   1123 	 * Now get the Flags.flags field's value
   1124 	 */
   1125 	f = (*env)->GetFieldID(env, flagsClass, "flags", "I");
   1126 	if (!f)
   1127 		return (KADM_JNI_FIELD);
   1128 
   1129 	i = (*env)->GetIntField(env, flagsObj, f);
   1130 	p->attributes = i & ~65536;
   1131 
   1132 	*mask |= KADM5_ATTRIBUTES;
   1133 
   1134 	f = (*env)->GetFieldID(env, prcl, "PrPasswd", "Ljava/lang/String;");
   1135 	if (!f)
   1136 		return (KADM_JNI_FIELD);
   1137 	obj = (*env)->GetObjectField(env, prin, f);
   1138 	if (!obj)
   1139 		return (KADM_JNI_OFIELD);
   1140 	s = (jstring)obj;
   1141 	str = (*env)->GetStringUTFChars(env, s, NULL);
   1142 	if (!str)
   1143 		return (KADM_JNI_STRING);
   1144 	*pw = strdup(str);
   1145 	if (!*pw)
   1146 		return (KADM_ENOMEM);
   1147 	(*env)->ReleaseStringUTFChars(env, s, str);
   1148 
   1149 	free(fullname);
   1150 	return (0);
   1151 }
   1152 
   1153 static int
   1154 kadmin_to_Principal(kadm5_principal_ent_rec *p, JNIEnv *env, jobject prin,
   1155 		const char *prname, char *comments)
   1156 {
   1157 	jstring s;
   1158 	jclass prcl, dateclass, intclass;
   1159 	jfieldID f;
   1160 	jmethodID mid;
   1161 	jobject obj;
   1162 	int i, j, n, used = 0, size = 0;
   1163 	kadm5_ret_t ret;
   1164 	krb5_context context;
   1165 	char *ptr, *enclist = NULL, *e_str = NULL, *i_str;
   1166 	char *cstr;
   1167 
   1168 	jfieldID flagsID;
   1169 	jobject flagsObj;
   1170 	jclass flagsClass;
   1171 
   1172 	prcl = (*env)->GetObjectClass(env, prin);
   1173 	if (!prcl)
   1174 		return (KADM_JNI_CLASS);
   1175 	dateclass = (*env)->FindClass(env, "java/util/Date");
   1176 	if (!dateclass)
   1177 		return (KADM_JNI_CLASS);
   1178 	intclass = (*env)->FindClass(env, "java/lang/Integer");
   1179 	if (!intclass)
   1180 		return (KADM_JNI_CLASS);
   1181 
   1182 	f = (*env)->GetFieldID(env, prcl, "PrName", "Ljava/lang/String;");
   1183 	if (!f)
   1184 		return (KADM_JNI_FIELD);
   1185 	s = (*env)->NewStringUTF(env, prname);
   1186 	if (!s)
   1187 		return (KADM_JNI_NEWSTRING);
   1188 	(*env)->SetObjectField(env, prin, f, s);
   1189 
   1190 	f = (*env)->GetFieldID(env, prcl, "PrExpireTime", "Ljava/util/Date;");
   1191 	if (!f)
   1192 		return (KADM_JNI_FIELD);
   1193 	mid = (*env)->GetMethodID(env, dateclass, "setTime", "(J)V");
   1194 	if (!mid)
   1195 		return (KADM_JNI_METHOD);
   1196 	obj = (*env)->GetObjectField(env, prin, f);
   1197 	if (!obj)
   1198 		return (KADM_JNI_OFIELD);
   1199 	(*env)->CallVoidMethod(env, obj, mid,
   1200 			(jlong) (p->princ_expire_time * 1000LL));
   1201 
   1202 	f = (*env)->GetFieldID(env, prcl, "EncTypes", "Ljava/lang/String;");
   1203 	if (!f)
   1204 		return (KADM_JNI_FIELD);
   1205 	used = 0;
   1206 	enclist = malloc(size += 2048);
   1207 	if (enclist == NULL)
   1208 		return (errno);
   1209 	for (i = 0; i < p->n_key_data; i++) {
   1210 		krb5_key_data *key_data = &p->key_data[i];
   1211 		for (j = 0; j < krb5_enctypes_length; j++) {
   1212 			if (key_data->key_data_type[0] ==
   1213 			    krb5_enctypes_list[j].etype) {
   1214 				i_str = krb5_enctypes_list[j].in_string;
   1215 				n = strlen(i_str) + strlen(":normal");
   1216 				e_str = malloc(n);
   1217 				if (e_str == NULL) {
   1218 					free(enclist);
   1219 					return (errno);
   1220 				}
   1221 				(void) snprintf(e_str, n + 1, "%s:normal",
   1222 				    i_str);
   1223 				/*
   1224 				 * We reallocate if existing + what we need +
   1225 				 * 2 (the null byte and a space for the list).
   1226 				 */
   1227 				if (used + n + 2 > size) {
   1228 					enclist = realloc(enclist,
   1229 					    size += 2048);
   1230 					if (enclist == NULL) {
   1231 						free(e_str);
   1232 						return (errno);
   1233 					}
   1234 				}
   1235 				(void) strncpy(&enclist[used], e_str, n);
   1236 				free(e_str);
   1237 				e_str = NULL;
   1238 				used += n + 1;
   1239 				enclist[used-1] = ' ';
   1240 				enclist[used] = '\0';
   1241 				break;
   1242 			}
   1243 		}
   1244 	}
   1245 	s = (*env)->NewStringUTF(env, enclist);
   1246 	free(enclist);
   1247 	if (!s)
   1248 		return (KADM_JNI_NEWSTRING);
   1249 	(*env)->SetObjectField(env, prin, f, s);
   1250 
   1251 	f = (*env)->GetFieldID(env, prcl, "Policy", "Ljava/lang/String;");
   1252 	if (!f)
   1253 		return (KADM_JNI_FIELD);
   1254 	cstr = strdup(p->policy ? p->policy : "");
   1255 	if (!cstr)
   1256 		return (KADM_ENOMEM);
   1257 	s = (*env)->NewStringUTF(env, cstr);
   1258 	if (!s)
   1259 		return (KADM_JNI_NEWSTRING);
   1260 	(*env)->SetObjectField(env, prin, f, s);
   1261 	free(cstr);
   1262 
   1263 	f = (*env)->GetFieldID(env, prcl, "LastPwChange", "Ljava/util/Date;");
   1264 	if (!f)
   1265 		return (KADM_JNI_FIELD);
   1266 	mid = (*env)->GetMethodID(env, dateclass, "setTime", "(J)V");
   1267 	if (!mid)
   1268 		return (KADM_JNI_METHOD);
   1269 	obj = (*env)->GetObjectField(env, prin, f);
   1270 	if (!obj)
   1271 		return (KADM_JNI_OFIELD);
   1272 	(*env)->CallVoidMethod(env, obj, mid,
   1273 			(jlong) (p->last_pwd_change * 1000LL));
   1274 
   1275 	f = (*env)->GetFieldID(env, prcl, "PwExpireTime", "Ljava/util/Date;");
   1276 	if (!f)
   1277 		return (KADM_JNI_FIELD);
   1278 	mid = (*env)->GetMethodID(env, dateclass, "setTime", "(J)V");
   1279 	if (!mid)
   1280 		return (KADM_JNI_METHOD);
   1281 	obj = (*env)->GetObjectField(env, prin, f);
   1282 	if (!obj)
   1283 		return (KADM_JNI_OFIELD);
   1284 	(*env)->CallVoidMethod(env, obj, mid,
   1285 			(jlong) (p->pw_expiration * 1000LL));
   1286 
   1287 	f = (*env)->GetFieldID(env, prcl, "MaxLife", "Ljava/lang/Integer;");
   1288 	if (!f)
   1289 		return (KADM_JNI_FIELD);
   1290 	mid = (*env)->GetMethodID(env, intclass, "<init>", "(I)V");
   1291 	if (!mid)
   1292 		return (KADM_JNI_METHOD);
   1293 	obj = (*env)->NewObject(env, intclass, mid, (jint) p->max_life);
   1294 	if (!obj)
   1295 		return (KADM_JNI_OBJECT);
   1296 	(*env)->SetObjectField(env, prin, f, obj);
   1297 
   1298 	f = (*env)->GetFieldID(env, prcl, "MaxRenew", "Ljava/lang/Integer;");
   1299 	if (!f)
   1300 		return (KADM_JNI_FIELD);
   1301 	mid = (*env)->GetMethodID(env, intclass, "<init>", "(I)V");
   1302 	if (!mid)
   1303 		return (KADM_JNI_METHOD);
   1304 	obj = (*env)->NewObject(env, intclass, mid,
   1305 			(jint) p->max_renewable_life);
   1306 	if (!obj)
   1307 		return (KADM_JNI_OBJECT);
   1308 	(*env)->SetObjectField(env, prin, f, obj);
   1309 
   1310 	f = (*env)->GetFieldID(env, prcl, "ModTime", "Ljava/util/Date;");
   1311 	if (!f)
   1312 		return (KADM_JNI_FIELD);
   1313 	mid = (*env)->GetMethodID(env, dateclass, "setTime", "(J)V");
   1314 	if (!mid)
   1315 		return (KADM_JNI_METHOD);
   1316 	obj = (*env)->GetObjectField(env, prin, f);
   1317 	if (!obj)
   1318 		return (KADM_JNI_OFIELD);
   1319 	(*env)->CallVoidMethod(env, obj, mid,
   1320 			(jlong) (p->mod_date * 1000LL));
   1321 
   1322 	ret = krb5_init_context(&context);
   1323 	if (ret)
   1324 		return (ret);
   1325 	ret = krb5_unparse_name(context, p->mod_name, &ptr);
   1326 	if (ret)
   1327 		return (ret);
   1328 	f = (*env)->GetFieldID(env, prcl, "ModName", "Ljava/lang/String;");
   1329 	if (!f)
   1330 		return (KADM_JNI_FIELD);
   1331 	s = (*env)->NewStringUTF(env, ptr);
   1332 	if (!s)
   1333 		return (KADM_JNI_NEWSTRING);
   1334 	(*env)->SetObjectField(env, prin, f, s);
   1335 	krb5_xfree(ptr);
   1336 
   1337 	f = (*env)->GetFieldID(env, prcl, "LastSuccess", "Ljava/util/Date;");
   1338 	if (!f)
   1339 		return (KADM_JNI_FIELD);
   1340 	mid = (*env)->GetMethodID(env, dateclass, "setTime", "(J)V");
   1341 	if (!mid)
   1342 		return (KADM_JNI_METHOD);
   1343 	obj = (*env)->GetObjectField(env, prin, f);
   1344 	if (!obj)
   1345 		return (KADM_JNI_OFIELD);
   1346 	(*env)->CallVoidMethod(env, obj, mid,
   1347 			(jlong) (p->last_success * 1000LL));
   1348 
   1349 	f = (*env)->GetFieldID(env, prcl, "LastFailure", "Ljava/util/Date;");
   1350 	if (!f)
   1351 		return (KADM_JNI_FIELD);
   1352 	mid = (*env)->GetMethodID(env, dateclass, "setTime", "(J)V");
   1353 	if (!mid)
   1354 		return (KADM_JNI_METHOD);
   1355 	obj = (*env)->GetObjectField(env, prin, f);
   1356 	if (!obj)
   1357 		return (KADM_JNI_OFIELD);
   1358 	(*env)->CallVoidMethod(env, obj, mid,
   1359 			(jlong) (p->last_failed * 1000LL));
   1360 
   1361 	f = (*env)->GetFieldID(env, prcl, "NumFailures", "Ljava/lang/Integer;");
   1362 	if (!f)
   1363 		return (KADM_JNI_FIELD);
   1364 	mid = (*env)->GetMethodID(env, intclass, "<init>", "(I)V");
   1365 	if (!mid)
   1366 		return (KADM_JNI_METHOD);
   1367 	obj = (*env)->NewObject(env, intclass, mid,
   1368 			(jint) p->fail_auth_count);
   1369 	if (!obj)
   1370 		return (KADM_JNI_OBJECT);
   1371 	(*env)->SetObjectField(env, prin, f, obj);
   1372 
   1373 	f = (*env)->GetFieldID(env, prcl, "Comments", "Ljava/lang/String;");
   1374 	if (!f)
   1375 		return (KADM_JNI_FIELD);
   1376 	cstr = strdup(comments ? comments : "");
   1377 	if (!cstr)
   1378 		return (KADM_ENOMEM);
   1379 	s = (*env)->NewStringUTF(env, cstr);
   1380 	if (!s)
   1381 		return (KADM_JNI_NEWSTRING);
   1382 	(*env)->SetObjectField(env, prin, f, s);
   1383 	free(cstr);
   1384 
   1385 	f = (*env)->GetFieldID(env, prcl, "Kvno", "Ljava/lang/Integer;");
   1386 	if (!f)
   1387 		return (KADM_JNI_FIELD);
   1388 	mid = (*env)->GetMethodID(env, intclass, "<init>", "(I)V");
   1389 	if (!mid)
   1390 		return (KADM_JNI_METHOD);
   1391 	obj = (*env)->NewObject(env, intclass, mid, p->kvno);
   1392 	if (!obj)
   1393 		return (KADM_JNI_OBJECT);
   1394 	(*env)->SetObjectField(env, prin, f, obj);
   1395 
   1396 	f = (*env)->GetFieldID(env, prcl, "Mkvno", "Ljava/lang/Integer;");
   1397 	if (!f)
   1398 		return (KADM_JNI_FIELD);
   1399 	mid = (*env)->GetMethodID(env, intclass, "<init>", "(I)V");
   1400 	if (!mid)
   1401 		return (KADM_JNI_METHOD);
   1402 	obj = (*env)->NewObject(env, intclass, mid, p->mkvno);
   1403 	if (!obj)
   1404 		return (KADM_JNI_OBJECT);
   1405 	(*env)->SetObjectField(env, prin, f, obj);
   1406 
   1407 	i = p->attributes;
   1408 
   1409 	/*
   1410 	 * Get the Principal.flags field id
   1411 	 */
   1412 	flagsID = (*env)->GetFieldID(env, prcl, "flags",
   1413 				    "LFlags;");
   1414 	if (!f)
   1415 		return (KADM_JNI_FIELD);
   1416 
   1417 	/*
   1418 	 * Get the Principal.Flags object
   1419 	 */
   1420 	flagsObj = (*env)->GetObjectField(env, prin, flagsID);
   1421 	if (!obj)
   1422 		return (KADM_JNI_OFIELD);
   1423 
   1424 	/*
   1425 	 * Get the Flags object's class
   1426 	 */
   1427 	flagsClass = (*env)->GetObjectClass(env, flagsObj);
   1428 
   1429 	/*
   1430 	 * Now set the Flags.flags field's value
   1431 	 */
   1432 	f = (*env)->GetFieldID(env, flagsClass, "flags", "I");
   1433 	if (!f)
   1434 		return (KADM_JNI_FIELD);
   1435 	(*env)->SetIntField(env, flagsObj, f, i);
   1436 
   1437 	return (0);
   1438 }
   1439 
   1440 static int
   1441 Policy_to_kadmin(JNIEnv *env, jobject pol, int new,
   1442 	kadm5_policy_ent_rec *p, long *mask)
   1443 {
   1444 	jstring s;
   1445 	jclass pocl, intclass;
   1446 	jfieldID f;
   1447 	jmethodID mid;
   1448 	jobject obj;
   1449 	const char *str;
   1450 	int i;
   1451 
   1452 	*mask = 0;
   1453 
   1454 	pocl = (*env)->GetObjectClass(env, pol);
   1455 	if (!pocl)
   1456 		return (KADM_JNI_CLASS);
   1457 	intclass = (*env)->FindClass(env, "java/lang/Integer");
   1458 	if (!intclass)
   1459 		return (KADM_JNI_CLASS);
   1460 
   1461 	f = (*env)->GetFieldID(env, pocl, "PolicyName", "Ljava/lang/String;");
   1462 	if (!f)
   1463 		return (KADM_JNI_FIELD);
   1464 	obj = (*env)->GetObjectField(env, pol, f);
   1465 	if (!obj)
   1466 		return (KADM_JNI_OFIELD);
   1467 	s = (jstring)obj;
   1468 	str = (*env)->GetStringUTFChars(env, s, NULL);
   1469 	if (!str)
   1470 		return (KADM_JNI_STRING);
   1471 	p->policy = strdup(str);
   1472 	if (!p->policy)
   1473 		return (KADM_ENOMEM);
   1474 	if (new)
   1475 		*mask |= KADM5_POLICY;
   1476 	(*env)->ReleaseStringUTFChars(env, s, str);
   1477 
   1478 	f = (*env)->GetFieldID(env, pocl, "PwMinLife", "Ljava/lang/Integer;");
   1479 	if (!f)
   1480 		return (KADM_JNI_FIELD);
   1481 	obj = (*env)->GetObjectField(env, pol, f);
   1482 	if (!obj)
   1483 		return (KADM_JNI_OFIELD);
   1484 	mid = (*env)->GetMethodID(env, intclass, "intValue", "()I");
   1485 	if (!mid)
   1486 		return (KADM_JNI_METHOD);
   1487 	i = (*env)->CallIntMethod(env, obj, mid);
   1488 	p->pw_min_life = i;
   1489 	*mask |= KADM5_PW_MIN_LIFE;
   1490 
   1491 	f = (*env)->GetFieldID(env, pocl, "PwMaxLife", "Ljava/lang/Integer;");
   1492 	if (!f)
   1493 		return (KADM_JNI_FIELD);
   1494 	obj = (*env)->GetObjectField(env, pol, f);
   1495 	if (!obj)
   1496 		return (KADM_JNI_OFIELD);
   1497 	mid = (*env)->GetMethodID(env, intclass, "intValue", "()I");
   1498 	if (!mid)
   1499 		return (KADM_JNI_METHOD);
   1500 	i = (*env)->CallIntMethod(env, obj, mid);
   1501 	p->pw_max_life = i;
   1502 	*mask |= KADM5_PW_MAX_LIFE;
   1503 
   1504 	f = (*env)->GetFieldID(env, pocl, "PwMinLength", "Ljava/lang/Integer;");
   1505 	if (!f)
   1506 		return (KADM_JNI_FIELD);
   1507 	obj = (*env)->GetObjectField(env, pol, f);
   1508 	if (!obj)
   1509 		return (KADM_JNI_OFIELD);
   1510 	mid = (*env)->GetMethodID(env, intclass, "intValue", "()I");
   1511 	if (!mid)
   1512 		return (KADM_JNI_METHOD);
   1513 	i = (*env)->CallIntMethod(env, obj, mid);
   1514 	p->pw_min_length = i;
   1515 	*mask |= KADM5_PW_MIN_LENGTH;
   1516 
   1517 	f = (*env)->GetFieldID(env, pocl, "PwMinClasses",
   1518 				"Ljava/lang/Integer;");
   1519 	if (!f)
   1520 		return (KADM_JNI_FIELD);
   1521 	obj = (*env)->GetObjectField(env, pol, f);
   1522 	if (!obj)
   1523 		return (KADM_JNI_OFIELD);
   1524 	mid = (*env)->GetMethodID(env, intclass, "intValue", "()I");
   1525 	if (!mid)
   1526 		return (KADM_JNI_METHOD);
   1527 	i = (*env)->CallIntMethod(env, obj, mid);
   1528 	p->pw_min_classes = i;
   1529 	*mask |= KADM5_PW_MIN_CLASSES;
   1530 
   1531 	f = (*env)->GetFieldID(env, pocl, "PwSaveCount", "Ljava/lang/Integer;");
   1532 	if (!f)
   1533 		return (KADM_JNI_FIELD);
   1534 	obj = (*env)->GetObjectField(env, pol, f);
   1535 	if (!obj)
   1536 		return (KADM_JNI_OFIELD);
   1537 	mid = (*env)->GetMethodID(env, intclass, "intValue", "()I");
   1538 	if (!mid)
   1539 		return (KADM_JNI_METHOD);
   1540 	i = (*env)->CallIntMethod(env, obj, mid);
   1541 	p->pw_history_num = i;
   1542 	*mask |= KADM5_PW_HISTORY_NUM;
   1543 
   1544 	return (0);
   1545 }
   1546 
   1547 static int
   1548 kadmin_to_Policy(kadm5_policy_ent_rec *p, JNIEnv *env, jobject pol)
   1549 {
   1550 	jstring s;
   1551 	jclass pocl, intclass;
   1552 	jfieldID f;
   1553 	jmethodID mid;
   1554 	jobject obj;
   1555 
   1556 	pocl = (*env)->GetObjectClass(env, pol);
   1557 	if (!pocl)
   1558 		return (KADM_JNI_CLASS);
   1559 	intclass = (*env)->FindClass(env, "java/lang/Integer");
   1560 	if (!intclass)
   1561 		return (KADM_JNI_CLASS);
   1562 
   1563 	f = (*env)->GetFieldID(env, pocl, "PolicyName", "Ljava/lang/String;");
   1564 	if (!f)
   1565 		return (KADM_JNI_FIELD);
   1566 	s = (*env)->NewStringUTF(env, p->policy);
   1567 	if (!s)
   1568 		return (KADM_JNI_NEWSTRING);
   1569 	(*env)->SetObjectField(env, pol, f, s);
   1570 
   1571 	f = (*env)->GetFieldID(env, pocl, "PwMinLife", "Ljava/lang/Integer;");
   1572 	if (!f)
   1573 		return (KADM_JNI_FIELD);
   1574 	mid = (*env)->GetMethodID(env, intclass, "<init>", "(I)V");
   1575 	if (!mid)
   1576 		return (KADM_JNI_METHOD);
   1577 	obj = (*env)->NewObject(env, intclass, mid, p->pw_min_life);
   1578 	if (!obj)
   1579 		return (KADM_JNI_OBJECT);
   1580 	(*env)->SetObjectField(env, pol, f, obj);
   1581 
   1582 	f = (*env)->GetFieldID(env, pocl, "PwMaxLife", "Ljava/lang/Integer;");
   1583 	if (!f)
   1584 		return (KADM_JNI_FIELD);
   1585 	mid = (*env)->GetMethodID(env, intclass, "<init>", "(I)V");
   1586 	if (!mid)
   1587 		return (KADM_JNI_METHOD);
   1588 	obj = (*env)->NewObject(env, intclass, mid, p->pw_max_life);
   1589 	if (!obj)
   1590 		return (KADM_JNI_OBJECT);
   1591 	(*env)->SetObjectField(env, pol, f, obj);
   1592 
   1593 	f = (*env)->GetFieldID(env, pocl, "PwMinLength", "Ljava/lang/Integer;");
   1594 	if (!f)
   1595 		return (KADM_JNI_FIELD);
   1596 	mid = (*env)->GetMethodID(env, intclass, "<init>", "(I)V");
   1597 	if (!mid)
   1598 		return (KADM_JNI_METHOD);
   1599 	obj = (*env)->NewObject(env, intclass, mid, p->pw_min_length);
   1600 	if (!obj)
   1601 		return (KADM_JNI_OBJECT);
   1602 	(*env)->SetObjectField(env, pol, f, obj);
   1603 
   1604 	f = (*env)->GetFieldID(env, pocl, "PwMinClasses",
   1605 				"Ljava/lang/Integer;");
   1606 	if (!f)
   1607 		return (KADM_JNI_FIELD);
   1608 	mid = (*env)->GetMethodID(env, intclass, "<init>", "(I)V");
   1609 	if (!mid)
   1610 		return (KADM_JNI_METHOD);
   1611 	obj = (*env)->NewObject(env, intclass, mid, p->pw_min_classes);
   1612 	if (!obj)
   1613 		return (KADM_JNI_OBJECT);
   1614 	(*env)->SetObjectField(env, pol, f, obj);
   1615 
   1616 	f = (*env)->GetFieldID(env, pocl, "PwSaveCount", "Ljava/lang/Integer;");
   1617 	if (!f)
   1618 		return (KADM_JNI_FIELD);
   1619 	mid = (*env)->GetMethodID(env, intclass, "<init>", "(I)V");
   1620 	if (!mid)
   1621 		return (KADM_JNI_METHOD);
   1622 	obj = (*env)->NewObject(env, intclass, mid, p->pw_history_num);
   1623 	if (!obj)
   1624 		return (KADM_JNI_OBJECT);
   1625 	(*env)->SetObjectField(env, pol, f, obj);
   1626 
   1627 	f = (*env)->GetFieldID(env, pocl, "RefCount", "Ljava/lang/Integer;");
   1628 	if (!f)
   1629 		return (KADM_JNI_FIELD);
   1630 	mid = (*env)->GetMethodID(env, intclass, "<init>", "(I)V");
   1631 	if (!mid)
   1632 		return (KADM_JNI_METHOD);
   1633 	obj = (*env)->NewObject(env, intclass, mid, p->policy_refcnt);
   1634 	if (!obj)
   1635 		return (KADM_JNI_OBJECT);
   1636 	(*env)->SetObjectField(env, pol, f, obj);
   1637 
   1638 	return (0);
   1639 }
   1640 
   1641 #define	SUNSOFT_COMMENTS	256
   1642 
   1643 /*
   1644  * The new principal has been saved; now we do a load-modify-store
   1645  * to get the comments into the TL_DATA array.
   1646  */
   1647 static int
   1648 edit_comments(kadm5_principal_ent_rec *p, krb5_principal kprin, char *comments)
   1649 {
   1650 	long mask = KADM5_PRINCIPAL | KADM5_TL_DATA;
   1651 	kadm5_ret_t ret;
   1652 
   1653 	if (!comments || !strlen(comments))
   1654 		return (0);
   1655 
   1656 	ret = kadm5_get_principal(server_handle, kprin, p, mask);
   1657 	if (ret)
   1658 		return (ret);
   1659 
   1660 	mask = 0;
   1661 	ret = format_comments(p, &mask, comments);
   1662 	if (ret)
   1663 		return (ret);
   1664 
   1665 	if (mask) {
   1666 		ret = kadm5_modify_principal(server_handle, p, mask);
   1667 		if (ret)
   1668 			return (ret);
   1669 	}
   1670 
   1671 	return (0);
   1672 }
   1673 
   1674 /*
   1675  * Put the comments into TL_DATA.
   1676  */
   1677 static int
   1678 format_comments(kadm5_principal_ent_rec *p, long *mask, char *comments)
   1679 {
   1680 	krb5_tl_data *t, *t1, *tdp;
   1681 	char *s;
   1682 
   1683 	if (!comments || !strlen(comments))
   1684 		return (0);
   1685 	tdp = malloc(sizeof (krb5_tl_data));
   1686 	if (!tdp)
   1687 		return (KADM_ENOMEM);
   1688 	s = strdup(comments);
   1689 	if (!s)
   1690 		return (KADM_ENOMEM);
   1691 
   1692 	/*
   1693 	 * Search for existing comments field, or find next-to-last
   1694 	 */
   1695 	for (t = t1 = p->tl_data; t; t1 = t, t = t->tl_data_next)
   1696 		if (t->tl_data_type == SUNSOFT_COMMENTS)
   1697 			break;
   1698 	if (t) {
   1699 		t->tl_data_length = strlen(comments);
   1700 		free(t->tl_data_contents);
   1701 		t->tl_data_contents = (krb5_octet *)s;
   1702 	} else {
   1703 		tdp->tl_data_next = NULL;
   1704 		tdp->tl_data_type = SUNSOFT_COMMENTS;
   1705 		tdp->tl_data_length = strlen(comments)+1;
   1706 		tdp->tl_data_contents = (krb5_octet *)s;
   1707 		if (t1)
   1708 			t1->tl_data_next = tdp;
   1709 		else
   1710 			p->tl_data = tdp;
   1711 		p->n_tl_data++;
   1712 	}
   1713 	*mask |= KADM5_TL_DATA;
   1714 	return (0);
   1715 }
   1716 
   1717 /*
   1718  * The principal has been loaded, so we pluck the comments out of TL_DATA.
   1719  */
   1720 static int
   1721 extract_comments(kadm5_principal_ent_rec *p, char **comments)
   1722 {
   1723 	krb5_tl_data *t;
   1724 	char *s;
   1725 
   1726 	/*
   1727 	 * Search for existing comments field, or find next-to-last
   1728 	 */
   1729 	if (!p->n_tl_data)
   1730 		return (0);
   1731 	for (t = p->tl_data; t; t = t->tl_data_next)
   1732 		if (t->tl_data_type == SUNSOFT_COMMENTS)
   1733 			break;
   1734 	if (t && t->tl_data_length) {
   1735 		s = strdup((char *)t->tl_data_contents);
   1736 		if (!s)
   1737 			return (KADM_ENOMEM);
   1738 		s[t->tl_data_length] = 0;
   1739 		*comments = s;
   1740 	}
   1741 	return (0);
   1742 }
   1743 
   1744 /*
   1745  * Set password for the modified principal
   1746  */
   1747 static int
   1748 set_password(krb5_principal kprin, char *pw, kadm5_config_params *pparams)
   1749 {
   1750 	kadm5_ret_t ret;
   1751 	int keepold = 0;
   1752 
   1753 	if (!pw || !strlen(pw))
   1754 		return (0);
   1755 
   1756 	if (pparams->mask & KADM5_CONFIG_ENCTYPES)
   1757 		ret = kadm5_chpass_principal_3(server_handle, kprin, keepold,
   1758 		    pparams->num_keysalts, pparams->keysalts, pw);
   1759 	else
   1760 		ret = kadm5_chpass_principal(server_handle, kprin, pw);
   1761 
   1762 	if (ret)
   1763 		return (ret);
   1764 	return (0);
   1765 }
   1766 
   1767 static void
   1768 handle_error(JNIEnv *env, int error)
   1769 {
   1770 	char *s;
   1771 	char    from[BUFSIZ], to[BUFSIZ];
   1772 	char    *tptr;
   1773 	const char  *fptr;
   1774 	size_t  ileft, oleft, ret;
   1775 
   1776 	s = (char *)error_message(error);
   1777 	/* fprintf(stderr, "Kadmin: %s (%d)\n", s, error); XXX */
   1778 	if (cd != (iconv_t)-1) {
   1779 		ileft = strlen(s);
   1780 		strncpy(from, s, ileft);
   1781 		fptr = from;
   1782 		oleft = BUFSIZ;
   1783 		tptr = to;
   1784 		ret = iconv(cd, &fptr, &ileft, &tptr, &oleft);
   1785 		if (ret != (size_t)-1) {
   1786 			to[BUFSIZ-oleft] = '\0';
   1787 			s = to;
   1788 		/* fprintf(stderr, "Kadmin: %s (%d)\n", s, error); XXX */
   1789 		}
   1790 	}
   1791 	(*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/Exception"),
   1792 			(const char *)s);
   1793 }
   1794