xref: /titanic_41/usr/src/cmd/krb5/kadmin/gui/native/Kadmin.c (revision 2b24ab6b3865caeede9eeb9db6b83e1d89dcd1ea)
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