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