1 /*
2  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 /*
9  * kadmin/ldap_util/kdb5_ldap_realm.c
10  *
11  * Copyright 1990,1991,2001, 2002 by the Massachusetts Institute of Technology.
12  * All Rights Reserved.
13  *
14  * Export of this software from the United States of America may
15  *   require a specific license from the United States Government.
16  *   It is the responsibility of any person or organization contemplating
17  *   export to obtain such a license before exporting.
18  *
19  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
20  * distribute this software and its documentation for any purpose and
21  * without fee is hereby granted, provided that the above copyright
22  * notice appear in all copies and that both that copyright notice and
23  * this permission notice appear in supporting documentation, and that
24  * the name of M.I.T. not be used in advertising or publicity pertaining
25  * to distribution of the software without specific, written prior
26  * permission.  Furthermore if you modify this software you must label
27  * your software as modified software and not distribute it in such a
28  * fashion that it might be confused with the original M.I.T. software.
29  * M.I.T. makes no representations about the suitability of
30  * this software for any purpose.  It is provided "as is" without express
31  * or implied warranty.
32  */
33 
34 /*
35  * Copyright (C) 1998 by the FundsXpress, INC.
36  *
37  * All rights reserved.
38  *
39  * Export of this software from the United States of America may require
40  * a specific license from the United States Government.  It is the
41  * responsibility of any person or organization contemplating export to
42  * obtain such a license before exporting.
43  *
44  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
45  * distribute this software and its documentation for any purpose and
46  * without fee is hereby granted, provided that the above copyright
47  * notice appear in all copies and that both that copyright notice and
48  * this permission notice appear in supporting documentation, and that
49  * the name of FundsXpress. not be used in advertising or publicity pertaining
50  * to distribution of the software without specific, written prior
51  * permission.  FundsXpress makes no representations about the suitability of
52  * this software for any purpose.  It is provided "as is" without express
53  * or implied warranty.
54  *
55  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
56  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
57  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
58  */
59 
60 /* Copyright (c) 2004-2005, Novell, Inc.
61  * All rights reserved.
62  *
63  * Redistribution and use in source and binary forms, with or without
64  * modification, are permitted provided that the following conditions are met:
65  *
66  *   * Redistributions of source code must retain the above copyright notice,
67  *       this list of conditions and the following disclaimer.
68  *   * Redistributions in binary form must reproduce the above copyright
69  *       notice, this list of conditions and the following disclaimer in the
70  *       documentation and/or other materials provided with the distribution.
71  *   * The copyright holder's name is not used to endorse or promote products
72  *       derived from this software without specific prior written permission.
73  *
74  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
75  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
76  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
77  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
78  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
79  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
80  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
81  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
82  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
83  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
84  * POSSIBILITY OF SUCH DAMAGE.
85  */
86 
87 /*
88  * Create / Modify / Destroy / View / List realm(s)
89  */
90 
91 /* Needed for getting the definition of KRB5_TL_DB_ARGS */
92 #define SECURID
93 
94 #include <stdio.h>
95 #include <k5-int.h>
96 #include <kadm5/admin.h>
97 #include <libintl.h>
98 #include <locale.h>
99 #include "kdb5_ldap_util.h"
100 #include "kdb5_ldap_list.h"
101 #include <ldap_principal.h>
102 #include <ldap_krbcontainer.h>
103 extern time_t get_date(char *); /* kadmin/cli/getdate.o */
104 
105 char *yes = "yes\n"; /* \n to compare against result of fgets */
106 krb5_key_salt_tuple def_kslist = {ENCTYPE_DES_CBC_CRC, KRB5_KDB_SALTTYPE_NORMAL};
107 
108 struct realm_info rblock = {
109     KRB5_KDB_MAX_LIFE,
110     KRB5_KDB_MAX_RLIFE,
111     KRB5_KDB_EXPIRATION,
112     KRB5_KDB_DEF_FLAGS,
113     (krb5_keyblock *) NULL,
114     1,
115     &def_kslist
116 };
117 
118 krb5_data tgt_princ_entries[] = {
119     {0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME},
120     {0, 0, 0} };
121 
122 krb5_data db_creator_entries[] = {
123     {0, sizeof("db_creation")-1, "db_creation"} };
124 
125 
126 static krb5_principal_data db_create_princ = {
127     0,					/* magic number */
128     {0, 0, 0},				/* krb5_data realm */
129     db_creator_entries,			/* krb5_data *data */
130     1,					/* int length */
131     KRB5_NT_SRV_INST			/* int type */
132 };
133 
134 extern char *mkey_password;
135 extern char *progname;
136 extern kadm5_config_params global_params;
137 
138 static void print_realm_params(krb5_ldap_realm_params *rparams, int mask);
139 static int kdb_ldap_create_principal (krb5_context context, krb5_principal
140 				      princ, enum ap_op op, struct realm_info *pblock);
141 
142 
143 static char *strdur(time_t duration);
144 static int get_ticket_policy(krb5_ldap_realm_params *rparams, int *i, char *argv[],int argc);
145 static krb5_error_code krb5_dbe_update_mod_princ_data_new (krb5_context context, krb5_db_entry *entry, krb5_timestamp mod_date, krb5_const_principal mod_princ);
146 static krb5_error_code krb5_dbe_update_tl_data_new ( krb5_context context, krb5_db_entry *entry, krb5_tl_data *new_tl_data);
147 
148 #define ADMIN_LIFETIME 60*60*3 /* 3 hours */
149 #define CHANGEPW_LIFETIME 60*5 /* 5 minutes */
150 
151 static int get_ticket_policy(rparams,i,argv,argc)
152     krb5_ldap_realm_params *rparams;
153     int *i;
154     char *argv[];
155     int argc;
156 {
157     time_t date;
158     time_t now;
159     int mask = 0;
160     krb5_error_code retval = 0;
161     krb5_boolean no_msg = FALSE;
162 
163     krb5_boolean print_usage = FALSE;
164     char *me = argv[0];
165 
166     time(&now);
167     if (!strcmp(argv[*i], "-maxtktlife")) {
168 	if (++(*i) > argc-1)
169 	    goto err_usage;
170 	date = get_date(argv[*i]);
171 	if (date == (time_t)(-1)) {
172 	    retval = EINVAL;
173 	    com_err (me, retval, gettext("while providing time specification"));
174 	    goto err_nomsg;
175 	}
176 	rparams->max_life = date-now;
177 	mask |= LDAP_REALM_MAXTICKETLIFE;
178     }
179 
180 
181     else if (!strcmp(argv[*i], "-maxrenewlife")) {
182 	if (++(*i) > argc-1)
183 	    goto err_usage;
184 
185 	date = get_date(argv[*i]);
186 	if (date == (time_t)(-1)) {
187 	    retval = EINVAL;
188 	    com_err (me, retval, gettext("while providing time specification"));
189 	    goto err_nomsg;
190 	}
191 	rparams->max_renewable_life = date-now;
192 	mask |= LDAP_REALM_MAXRENEWLIFE;
193     } else if (!strcmp((argv[*i] + 1), "allow_postdated")) {
194 	if (*(argv[*i]) == '+')
195 	    rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_POSTDATED);
196 	else if (*(argv[*i]) == '-')
197 	    rparams->tktflags |= KRB5_KDB_DISALLOW_POSTDATED;
198 	else
199 	    goto err_usage;
200 
201 	mask |= LDAP_REALM_KRBTICKETFLAGS;
202     } else if (!strcmp((argv[*i] + 1), "allow_forwardable")) {
203 	if (*(argv[*i]) == '+')
204 	    rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_FORWARDABLE);
205 
206 	else if (*(argv[*i]) == '-')
207 	    rparams->tktflags |= KRB5_KDB_DISALLOW_FORWARDABLE;
208 	else
209 	    goto err_usage;
210 
211 	mask |= LDAP_REALM_KRBTICKETFLAGS;
212     } else if (!strcmp((argv[*i] + 1), "allow_renewable")) {
213 	if (*(argv[*i]) == '+')
214 	    rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_RENEWABLE);
215 	else if (*(argv[*i]) == '-')
216 	    rparams->tktflags |= KRB5_KDB_DISALLOW_RENEWABLE;
217 	else
218 	    goto err_usage;
219 
220 	mask |= LDAP_REALM_KRBTICKETFLAGS;
221     } else if (!strcmp((argv[*i] + 1), "allow_proxiable")) {
222 	if (*(argv[*i]) == '+')
223 	    rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_PROXIABLE);
224 	else if (*(argv[*i]) == '-')
225 	    rparams->tktflags |= KRB5_KDB_DISALLOW_PROXIABLE;
226 	else
227 	    goto err_usage;
228 
229 	mask |= LDAP_REALM_KRBTICKETFLAGS;
230     } else if (!strcmp((argv[*i] + 1), "allow_dup_skey")) {
231 	if (*(argv[*i]) == '+')
232 	    rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_DUP_SKEY);
233 	else if (*(argv[*i]) == '-')
234 	    rparams->tktflags |= KRB5_KDB_DISALLOW_DUP_SKEY;
235 	else
236 	    goto err_usage;
237 
238 	mask |= LDAP_REALM_KRBTICKETFLAGS;
239     }
240 
241     else if (!strcmp((argv[*i] + 1), "requires_preauth")) {
242 	if (*(argv[*i]) == '+')
243 	    rparams->tktflags |= KRB5_KDB_REQUIRES_PRE_AUTH;
244 	else if (*(argv[*i]) == '-')
245 	    rparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_PRE_AUTH);
246 	else
247 	    goto err_usage;
248 
249 	mask |= LDAP_REALM_KRBTICKETFLAGS;
250     } else if (!strcmp((argv[*i] + 1), "requires_hwauth")) {
251 	if (*(argv[*i]) == '+')
252 	    rparams->tktflags |= KRB5_KDB_REQUIRES_HW_AUTH;
253 	else if (*(argv[*i]) == '-')
254 	    rparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_HW_AUTH);
255 	else
256 	    goto err_usage;
257 
258 	mask |= LDAP_REALM_KRBTICKETFLAGS;
259     } else if (!strcmp((argv[*i] + 1), "allow_svr")) {
260 	if (*(argv[*i]) == '+')
261 	    rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_SVR);
262 	else if (*(argv[*i]) == '-')
263 	    rparams->tktflags |= KRB5_KDB_DISALLOW_SVR;
264 	else
265 	    goto err_usage;
266 
267 	mask |= LDAP_REALM_KRBTICKETFLAGS;
268     } else if (!strcmp((argv[*i] + 1), "allow_tgs_req")) {
269 	if (*(argv[*i]) == '+')
270 	    rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_TGT_BASED);
271 	else if (*(argv[*i]) == '-')
272 	    rparams->tktflags |= KRB5_KDB_DISALLOW_TGT_BASED;
273 	else
274 	    goto err_usage;
275 
276 	mask |= LDAP_REALM_KRBTICKETFLAGS;
277     } else if (!strcmp((argv[*i] + 1), "allow_tix")) {
278 	if (*(argv[*i]) == '+')
279 	    rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_ALL_TIX);
280 	else if (*(argv[*i]) == '-')
281 	    rparams->tktflags |= KRB5_KDB_DISALLOW_ALL_TIX;
282 	else
283 	    goto err_usage;
284 
285 	mask |= LDAP_REALM_KRBTICKETFLAGS;
286     } else if (!strcmp((argv[*i] + 1), "needchange")) {
287 	if (*(argv[*i]) == '+')
288 	    rparams->tktflags |= KRB5_KDB_REQUIRES_PWCHANGE;
289 	else if (*(argv[*i]) == '-')
290 	    rparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_PWCHANGE);
291 	else
292 	    goto err_usage;
293 
294 	mask |= LDAP_REALM_KRBTICKETFLAGS;
295     } else if (!strcmp((argv[*i] + 1), "password_changing_service")) {
296 	if (*(argv[*i]) == '+')
297 	    rparams->tktflags |= KRB5_KDB_PWCHANGE_SERVICE;
298 	else if (*(argv[*i]) == '-')
299 	    rparams->tktflags &= (int)(~KRB5_KDB_PWCHANGE_SERVICE);
300 	else
301 	    goto err_usage;
302 
303 	mask |=LDAP_REALM_KRBTICKETFLAGS;
304     }
305 err_usage:
306     print_usage = TRUE;
307 
308 err_nomsg:
309     no_msg = TRUE;
310 
311     return mask;
312 }
313 
314 /*
315  * This function will create a realm on the LDAP Server, with
316  * the specified attributes.
317  */
318 void kdb5_ldap_create(argc, argv)
319     int argc;
320     char *argv[];
321 {
322     krb5_error_code retval = 0;
323     krb5_keyblock master_keyblock;
324     krb5_ldap_realm_params *rparams = NULL;
325     krb5_principal master_princ = NULL;
326     kdb5_dal_handle *dal_handle = NULL;
327     krb5_ldap_context *ldap_context=NULL;
328     krb5_boolean realm_obj_created = FALSE;
329     krb5_boolean create_complete = FALSE;
330     krb5_boolean print_usage = FALSE;
331     krb5_boolean no_msg = FALSE;
332     char *oldcontainerref=NULL;
333     char pw_str[1024];
334     int do_stash = 0;
335     int i = 0;
336     int mask = 0, ret_mask = 0;
337     char **list = NULL;
338 #ifdef HAVE_EDIRECTORY
339     int rightsmask = 0;
340 #endif
341 
342     memset(&master_keyblock, 0, sizeof(master_keyblock));
343 
344     rparams = (krb5_ldap_realm_params *)malloc(
345 	sizeof(krb5_ldap_realm_params));
346     if (rparams == NULL) {
347 	retval = ENOMEM;
348 	goto cleanup;
349     }
350     memset(rparams, 0, sizeof(krb5_ldap_realm_params));
351 
352     /* Parse the arguments */
353     for (i = 1; i < argc; i++) {
354 	if (!strcmp(argv[i], "-subtrees")) {
355 	    if (++i > argc-1)
356 		goto err_usage;
357 
358 	    if(strncmp(argv[i], "", strlen(argv[i]))!=0) {
359 		list = (char **) calloc(MAX_LIST_ENTRIES, sizeof(char *));
360 		if (list == NULL) {
361 		    retval = ENOMEM;
362 		    goto cleanup;
363 		}
364 		if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) {
365 		    free(list);
366 		    list = NULL;
367 		    goto cleanup;
368 		}
369 
370 		rparams->subtreecount=0;
371 		while(list[rparams->subtreecount]!=NULL)
372 		    (rparams->subtreecount)++;
373 		rparams->subtree = list;
374 	    } else if(strncmp(argv[i], "", strlen(argv[i]))==0) {
375 		 /* dont allow subtree value to be set at the root(NULL, "") of the tree */
376 		 com_err(argv[0], EINVAL,
377 			  gettext("for subtree while creating realm '%s'"),
378 			   global_params.realm);
379 		 goto err_nomsg;
380 	    }
381 	    rparams->subtree[rparams->subtreecount] = NULL;
382 	    mask |= LDAP_REALM_SUBTREE;
383 	} else if (!strcmp(argv[i], "-containerref")) {
384 	    if (++i > argc-1)
385 		goto err_usage;
386 	    if(strncmp(argv[i], "", strlen(argv[i]))==0) {
387 		 /* dont allow containerref value to be set at the root(NULL, "") of the tree */
388 		 com_err(argv[0], EINVAL,
389 			  gettext("for container reference while creating realm '%s'"),
390 			   global_params.realm);
391 		 goto err_nomsg;
392 	    }
393 	    rparams->containerref = strdup(argv[i]);
394 	    if (rparams->containerref == NULL) {
395 		retval = ENOMEM;
396 		goto cleanup;
397 	    }
398 	    mask |= LDAP_REALM_CONTREF;
399 	} else if (!strcmp(argv[i], "-sscope")) {
400 	    if (++i > argc-1)
401 		goto err_usage;
402 	    /* Possible values for search scope are
403 	     * one (or 1) and sub (or 2)
404 	     */
405 	    if (!strcasecmp(argv[i], "one")) {
406 		rparams->search_scope = 1;
407 	    } else if (!strcasecmp(argv[i], "sub")) {
408 		rparams->search_scope = 2;
409 	    } else {
410 		rparams->search_scope = atoi(argv[i]);
411 		if ((rparams->search_scope != 1) &&
412 		    (rparams->search_scope != 2)) {
413 		    com_err(argv[0], EINVAL,
414 			    gettext("invalid search scope while creating realm '%s'"),
415 			    global_params.realm);
416 		    goto err_nomsg;
417 		}
418 	    }
419 	    mask |= LDAP_REALM_SEARCHSCOPE;
420 	}
421 #ifdef HAVE_EDIRECTORY
422 	else if (!strcmp(argv[i], "-kdcdn")) {
423 	    if (++i > argc-1)
424 		goto err_usage;
425 	    rparams->kdcservers = (char **)malloc(
426 		sizeof(char *) * MAX_LIST_ENTRIES);
427 	    if (rparams->kdcservers == NULL) {
428 		retval = ENOMEM;
429 		goto cleanup;
430 	    }
431 	    memset(rparams->kdcservers, 0, sizeof(char*)*MAX_LIST_ENTRIES);
432 	    if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
433 					  rparams->kdcservers))) {
434 		goto cleanup;
435 	    }
436 	    mask |= LDAP_REALM_KDCSERVERS;
437 	} else if (!strcmp(argv[i], "-admindn")) {
438 	    if (++i > argc-1)
439 		goto err_usage;
440 	    rparams->adminservers = (char **)malloc(
441 		sizeof(char *) * MAX_LIST_ENTRIES);
442 	    if (rparams->adminservers == NULL) {
443 		retval = ENOMEM;
444 		goto cleanup;
445 	    }
446 	    memset(rparams->adminservers, 0, sizeof(char*)*MAX_LIST_ENTRIES);
447 	    if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
448 					  rparams->adminservers))) {
449 		goto cleanup;
450 	    }
451 	    mask |= LDAP_REALM_ADMINSERVERS;
452 	} else if (!strcmp(argv[i], "-pwddn")) {
453 	    if (++i > argc-1)
454 		goto err_usage;
455 	    rparams->passwdservers = (char **)malloc(
456 		sizeof(char *) * MAX_LIST_ENTRIES);
457 	    if (rparams->passwdservers == NULL) {
458 		retval = ENOMEM;
459 		goto cleanup;
460 	    }
461 	    memset(rparams->passwdservers, 0, sizeof(char*)*MAX_LIST_ENTRIES);
462 	    if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
463 					  rparams->passwdservers))) {
464 		goto cleanup;
465 	    }
466 	    mask |= LDAP_REALM_PASSWDSERVERS;
467 	}
468 #endif
469 	else if (!strcmp(argv[i], "-s")) {
470 	    do_stash = 1;
471 	} else if ((ret_mask= get_ticket_policy(rparams,&i,argv,argc)) !=0) {
472 	    mask|=ret_mask;
473 	}
474 
475 	else {
476 	    printf(gettext("'%s' is an invalid option\n"), argv[i]);
477 	    goto err_usage;
478 	}
479     }
480 
481     /* If the default enctype/salttype is not provided, use the
482      * default values and also add to the list of supported
483      * enctypes/salttype
484      */
485 
486     rblock.max_life = global_params.max_life;
487     rblock.max_rlife = global_params.max_rlife;
488     rblock.expiration = global_params.expiration;
489     rblock.flags = global_params.flags;
490     rblock.nkslist = global_params.num_keysalts;
491     rblock.kslist = global_params.keysalts;
492 
493     krb5_princ_set_realm_data(util_context, &db_create_princ, global_params.realm);
494     krb5_princ_set_realm_length(util_context, &db_create_princ, strlen(global_params.realm));
495 
496     printf(gettext("Initializing database for realm '%s'\n"), global_params.realm);
497 
498     if (!mkey_password) {
499 	unsigned int pw_size;
500 	printf(gettext("You will be prompted for the database Master Password.\n"));
501 	printf(gettext("It is important that you NOT FORGET this password.\n"));
502 	fflush(stdout);
503 
504 	pw_size = sizeof (pw_str);
505 	memset(pw_str, 0, pw_size);
506 
507 	retval = krb5_read_password(util_context, KRB5_KDC_MKEY_1, KRB5_KDC_MKEY_2,
508 				    pw_str, &pw_size);
509 	if (retval) {
510 	    com_err(argv[0], retval, gettext("while reading master key from keyboard"));
511 	    goto err_nomsg;
512 	}
513 	mkey_password = pw_str;
514     }
515 
516     rparams->mkey.enctype = global_params.enctype;
517     /* We are sure that 'mkey_password' is a regular string ... */
518     rparams->mkey.length = strlen(mkey_password) + 1;
519     rparams->mkey.contents = (krb5_octet *)strdup(mkey_password);
520     if (rparams->mkey.contents == NULL) {
521 	retval = ENOMEM;
522 	goto cleanup;
523     }
524 
525     rparams->realm_name = strdup(global_params.realm);
526     if (rparams->realm_name == NULL) {
527 	retval = ENOMEM;
528 	com_err(argv[0], ENOMEM, gettext("while creating realm '%s'"),
529 		global_params.realm);
530 	goto err_nomsg;
531     }
532 
533     dal_handle = (kdb5_dal_handle *) util_context->db_context;
534     ldap_context = (krb5_ldap_context *) dal_handle->db_context;
535     if (!ldap_context) {
536 	retval = EINVAL;
537 	goto cleanup;
538     }
539 
540     /* read the kerberos container */
541     if ((retval=krb5_ldap_read_krbcontainer_params (util_context,
542 						    &(ldap_context->krbcontainer))) == KRB5_KDB_NOENTRY) {
543 	/* Prompt the user for entering the DN of Kerberos container */
544 	char krb_location[MAX_KRB_CONTAINER_LEN];
545 	krb5_ldap_krbcontainer_params kparams;
546 	int krb_location_len = 0;
547 	memset(&kparams, 0, sizeof(kparams));
548 
549 	/* Read the kerberos container location from configuration file */
550 	if (ldap_context->conf_section) {
551 	    if ((retval=profile_get_string(util_context->profile,
552 					   KDB_MODULE_SECTION, ldap_context->conf_section,
553 					   "ldap_kerberos_container_dn", NULL,
554 					   &kparams.DN)) != 0) {
555 		goto cleanup;
556 	    }
557 	}
558 	if (kparams.DN == NULL) {
559 	    if ((retval=profile_get_string(util_context->profile,
560 					   KDB_MODULE_DEF_SECTION,
561 					   "ldap_kerberos_container_dn", NULL,
562 					   NULL, &kparams.DN)) != 0) {
563 		goto cleanup;
564 	    }
565 	}
566 
567 	printf(gettext("\nKerberos container is missing. Creating now...\n"));
568 	if (kparams.DN == NULL) {
569 #ifdef HAVE_EDIRECTORY
570 	    printf(gettext("Enter DN of Kerberos container [cn=Kerberos,cn=Security]: "));
571 #else
572 	    printf(gettext("Enter DN of Kerberos container: "));
573 #endif
574 	    if (fgets(krb_location, MAX_KRB_CONTAINER_LEN, stdin) != NULL) {
575 		/* Remove the newline character at the end */
576 		krb_location_len = strlen(krb_location);
577 		if ((krb_location[krb_location_len - 1] == '\n') ||
578 		    (krb_location[krb_location_len - 1] == '\r')) {
579 		    krb_location[krb_location_len - 1] = '\0';
580 		    krb_location_len--;
581 		}
582 		/* If the user has not given any input, take the default location */
583 		else if (krb_location[0] == '\0')
584 		    kparams.DN = NULL;
585 		else
586 		    kparams.DN = krb_location;
587 	    } else
588 		kparams.DN = NULL;
589 	}
590 
591 	/* create the kerberos container */
592 	retval = krb5_ldap_create_krbcontainer(util_context,
593 					       ((kparams.DN != NULL) ? &kparams : NULL));
594 	if (retval)
595 	    goto cleanup;
596 
597 	retval = krb5_ldap_read_krbcontainer_params(util_context,
598 						    &(ldap_context->krbcontainer));
599 	if (retval) {
600 	    com_err(argv[0], retval, gettext("while reading kerberos container information"));
601 	    goto cleanup;
602 	}
603     } else if (retval) {
604 	com_err(argv[0], retval, gettext("while reading kerberos container information"));
605 	goto cleanup;
606     }
607 
608     if ((retval = krb5_ldap_create_realm(util_context,
609 					 /* global_params.realm, */ rparams, mask))) {
610 	goto cleanup;
611     }
612 
613     /* We just created the Realm container. Here starts our transaction tracking */
614     realm_obj_created = TRUE;
615 
616     if ((retval = krb5_ldap_read_realm_params(util_context,
617 					      global_params.realm,
618 					      &(ldap_context->lrparams),
619 					      &mask))) {
620 	com_err(argv[0], retval, gettext("while reading information of realm '%s'"),
621 		global_params.realm);
622 	goto err_nomsg;
623     }
624     ldap_context->lrparams->realm_name = strdup(global_params.realm);
625     if (ldap_context->lrparams->realm_name == NULL) {
626 	retval = ENOMEM;
627 	goto cleanup;
628     }
629 
630     /* assemble & parse the master key name */
631     if ((retval = krb5_db_setup_mkey_name(util_context,
632 					  global_params.mkey_name,
633 					  global_params.realm,
634 					  0, &master_princ))) {
635 	com_err(argv[0], retval, gettext("while setting up master key name"));
636 	goto err_nomsg;
637     }
638 
639     /* Obtain master key from master password */
640     {
641 	krb5_data master_salt, pwd;
642 
643 	pwd.data = mkey_password;
644 	pwd.length = strlen(mkey_password);
645 	retval = krb5_principal2salt(util_context, master_princ, &master_salt);
646 	if (retval) {
647 	    com_err(argv[0], retval, gettext("while calculating master key salt"));
648 	    goto err_nomsg;
649 	}
650 
651 	retval = krb5_c_string_to_key(util_context, rparams->mkey.enctype,
652 				      &pwd, &master_salt, &master_keyblock);
653 
654 	if (master_salt.data)
655 	    free(master_salt.data);
656 
657 	if (retval) {
658 	    com_err(argv[0], retval, gettext("while transforming master key from password"));
659 	    goto err_nomsg;
660 	}
661 
662     }
663 
664     rblock.key = &master_keyblock;
665     ldap_context->lrparams->mkey = master_keyblock;
666     ldap_context->lrparams->mkey.contents = (krb5_octet *) malloc
667 	(master_keyblock.length);
668     if (ldap_context->lrparams->mkey.contents == NULL) {
669 	retval = ENOMEM;
670 	goto cleanup;
671     }
672     memcpy (ldap_context->lrparams->mkey.contents, master_keyblock.contents,
673 	    master_keyblock.length);
674 
675     /* Create special principals inside the realm subtree */
676     {
677 	char princ_name[MAX_PRINC_SIZE];
678 	krb5_principal_data tgt_princ = {
679 	    0,					/* magic number */
680 	    {0, 0, 0},				/* krb5_data realm */
681 	    tgt_princ_entries,			/* krb5_data *data */
682 	    2,					/* int length */
683 	    KRB5_NT_SRV_INST			/* int type */
684 	};
685 	krb5_principal p, temp_p=NULL;
686 
687 	krb5_princ_set_realm_data(util_context, &tgt_princ, global_params.realm);
688 	krb5_princ_set_realm_length(util_context, &tgt_princ, strlen(global_params.realm));
689 	krb5_princ_component(util_context, &tgt_princ,1)->data = global_params.realm;
690 	krb5_princ_component(util_context, &tgt_princ,1)->length = strlen(global_params.realm);
691 	/* The container reference value is set to NULL, to avoid service principals
692 	 * getting created within the container reference at realm creation */
693 	if (ldap_context->lrparams->containerref != NULL) {
694 	    oldcontainerref = ldap_context->lrparams->containerref;
695 	    ldap_context->lrparams->containerref = NULL;
696 	}
697 
698 	/* Create 'K/M' ... */
699 	rblock.flags |= KRB5_KDB_DISALLOW_ALL_TIX;
700 	if ((retval = kdb_ldap_create_principal(util_context, master_princ, MASTER_KEY, &rblock))) {
701 	    com_err(argv[0], retval, gettext("while adding entries to the database"));
702 	    goto err_nomsg;
703 	}
704 
705 	/* Create 'krbtgt' ... */
706 	rblock.flags = 0; /* reset the flags */
707 	if ((retval = kdb_ldap_create_principal(util_context, &tgt_princ, TGT_KEY, &rblock))) {
708 	    com_err(argv[0], retval, gettext("while adding entries to the database"));
709 	    goto err_nomsg;
710 	}
711 	/*
712 	 * Solaris Kerberos:
713 	 * The kadmin/admin principal is unused on Solaris. This principal is used
714 	 * in AUTH_GSSAPI but Solaris doesn't support AUTH_GSSAPI. RPCSEC_GSS can only
715 	 * be used with host-based principals.
716 	 *
717 	 */
718 #if 0 /* ************ Begin IFDEF'ed OUT ***************************** */
719 	/* Create 'kadmin/admin' ... */
720 	snprintf(princ_name, sizeof(princ_name), "%s@%s", KADM5_ADMIN_SERVICE, global_params.realm);
721 	if ((retval = krb5_parse_name(util_context, princ_name, &p))) {
722 	    com_err(argv[0], retval, gettext("while adding entries to the database"));
723 	    goto err_nomsg;
724 	}
725 	rblock.max_life = ADMIN_LIFETIME;
726 	rblock.flags = KRB5_KDB_DISALLOW_TGT_BASED;
727 	if ((retval = kdb_ldap_create_principal(util_context, p, TGT_KEY, &rblock))) {
728 	    krb5_free_principal(util_context, p);
729 	    com_err(argv[0], retval, gettext("while adding entries to the database"));
730 	    goto err_nomsg;
731 	}
732 	krb5_free_principal(util_context, p);
733 #endif /* ************** END IFDEF'ed OUT ***************************** */
734 
735 	/* Create 'kadmin/changepw' ... */
736 	snprintf(princ_name, sizeof(princ_name), "%s@%s", KADM5_CHANGEPW_SERVICE, global_params.realm);
737 	if ((retval = krb5_parse_name(util_context, princ_name, &p))) {
738 	    com_err(argv[0], retval, gettext("while adding entries to the database"));
739 	    goto err_nomsg;
740 	}
741 	rblock.max_life = CHANGEPW_LIFETIME;
742 	rblock.flags = KRB5_KDB_DISALLOW_TGT_BASED | KRB5_KDB_PWCHANGE_SERVICE;
743 	if ((retval = kdb_ldap_create_principal(util_context, p, TGT_KEY, &rblock))) {
744 	    krb5_free_principal(util_context, p);
745 	    com_err(argv[0], retval, gettext("while adding entries to the database"));
746 	    goto err_nomsg;
747 	}
748 	krb5_free_principal(util_context, p);
749 
750 	/* Create 'kadmin/history' ... */
751 	snprintf(princ_name, sizeof(princ_name), "%s@%s", KADM5_HIST_PRINCIPAL, global_params.realm);
752 	if ((retval = krb5_parse_name(util_context, princ_name, &p))) {
753 	    com_err(argv[0], retval, gettext("while adding entries to the database"));
754 	    goto err_nomsg;
755 	}
756 	rblock.max_life = global_params.max_life;
757 	rblock.flags = 0;
758 	if ((retval = kdb_ldap_create_principal(util_context, p, TGT_KEY, &rblock))) {
759 	    krb5_free_principal(util_context, p);
760 	    com_err(argv[0], retval, gettext("while adding entries to the database"));
761 	    goto err_nomsg;
762 	}
763 	krb5_free_principal(util_context, p);
764 
765 	/* Create 'kadmin/<hostname>' ... */
766 	if ((retval=krb5_sname_to_principal(util_context, NULL, KADM5_ADMIN_HOST_SERVICE, KRB5_NT_SRV_HST, &p))) {
767 	    com_err(argv[0], retval, gettext("krb5_sname_to_principal, while adding entries to the database"));
768 	    goto err_nomsg;
769 	}
770 
771 	if ((retval=krb5_copy_principal(util_context, p, &temp_p))) {
772 	    com_err(argv[0], retval, gettext("krb5_copy_principal, while adding entries to the database"));
773 	    goto err_nomsg;
774 	}
775 
776 	/* change the realm portion to the default realm */
777 	free(temp_p->realm.data);
778 	temp_p->realm.length = strlen(util_context->default_realm);
779 	temp_p->realm.data = strdup(util_context->default_realm);
780 	if (temp_p->realm.data == NULL) {
781 	    com_err(argv[0], ENOMEM, gettext("while adding entries to the database"));
782 	    goto err_nomsg;
783 	}
784 
785 	rblock.max_life = ADMIN_LIFETIME;
786 	rblock.flags = KRB5_KDB_DISALLOW_TGT_BASED;
787 	if ((retval = kdb_ldap_create_principal(util_context, temp_p, TGT_KEY, &rblock))) {
788 	    krb5_free_principal(util_context, p);
789 	    com_err(argv[0], retval, gettext("while adding entries to the database"));
790 	    goto err_nomsg;
791 	}
792 	krb5_free_principal(util_context, temp_p);
793 	krb5_free_principal(util_context, p);
794 
795 	/* Solaris Kerberos: Create 'changepw/<hostname>' ... */
796 	if ((retval=krb5_sname_to_principal(util_context, NULL, KADM5_CHANGEPW_HOST_SERVICE, KRB5_NT_SRV_HST, &p))) {
797 	    com_err(argv[0], retval, gettext("krb5_sname_to_principal, while adding entries to the database"));
798 	    goto err_nomsg;
799 	}
800 
801 	if ((retval=krb5_copy_principal(util_context, p, &temp_p))) {
802 	    com_err(argv[0], retval, gettext("krb5_copy_principal, while adding entries to the database"));
803 	    goto err_nomsg;
804 	}
805 
806 	/* change the realm portion to the default realm */
807 	free(temp_p->realm.data);
808 	temp_p->realm.length = strlen(util_context->default_realm);
809 	temp_p->realm.data = strdup(util_context->default_realm);
810 	if (temp_p->realm.data == NULL) {
811 	    com_err(argv[0], ENOMEM, gettext("while adding entries to the database"));
812 	    goto err_nomsg;
813 	}
814 
815 	rblock.max_life = ADMIN_LIFETIME;
816 	rblock.flags = KRB5_KDB_DISALLOW_TGT_BASED | KRB5_KDB_PWCHANGE_SERVICE;
817 	if ((retval = kdb_ldap_create_principal(util_context, temp_p, TGT_KEY, &rblock))) {
818 	    krb5_free_principal(util_context, p);
819 	    com_err(argv[0], retval, gettext("while adding entries to the database"));
820 	    goto err_nomsg;
821 	}
822 	krb5_free_principal(util_context, temp_p);
823 	krb5_free_principal(util_context, p);
824 
825 	if (oldcontainerref != NULL) {
826 	    ldap_context->lrparams->containerref = oldcontainerref;
827 	    oldcontainerref=NULL;
828 	}
829     }
830 
831 #ifdef HAVE_EDIRECTORY
832     if ((mask & LDAP_REALM_KDCSERVERS) || (mask & LDAP_REALM_ADMINSERVERS) ||
833 	(mask & LDAP_REALM_PASSWDSERVERS)) {
834 
835 	printf(gettext("Changing rights for the service object. Please wait ... "));
836 	fflush(stdout);
837 
838 	rightsmask =0;
839 	rightsmask |= LDAP_REALM_RIGHTS;
840 	rightsmask |= LDAP_SUBTREE_RIGHTS;
841 	if ((rparams != NULL) && (rparams->kdcservers != NULL)) {
842 	    for (i=0; (rparams->kdcservers[i] != NULL); i++) {
843 		if ((retval=krb5_ldap_add_service_rights(util_context,
844 							 LDAP_KDC_SERVICE, rparams->kdcservers[i],
845 							 rparams->realm_name, rparams->subtree, rightsmask)) != 0) {
846 		    printf(gettext("failed\n"));
847 		    com_err(argv[0], retval, gettext("while assigning rights to '%s'"),
848 			    rparams->realm_name);
849 		    goto err_nomsg;
850 		}
851 	    }
852 	}
853 
854 	rightsmask = 0;
855 	rightsmask |= LDAP_REALM_RIGHTS;
856 	rightsmask |= LDAP_SUBTREE_RIGHTS;
857 	if ((rparams != NULL) && (rparams->adminservers != NULL)) {
858 	    for (i=0; (rparams->adminservers[i] != NULL); i++) {
859 		if ((retval=krb5_ldap_add_service_rights(util_context,
860 							 LDAP_ADMIN_SERVICE, rparams->adminservers[i],
861 							 rparams->realm_name, rparams->subtree, rightsmask)) != 0) {
862 		    printf(gettext("failed\n"));
863 		    com_err(argv[0], retval, gettext("while assigning rights to '%s'"),
864 			    rparams->realm_name);
865 		    goto err_nomsg;
866 		}
867 	    }
868 	}
869 
870 	rightsmask = 0;
871 	rightsmask |= LDAP_REALM_RIGHTS;
872 	rightsmask |= LDAP_SUBTREE_RIGHTS;
873 	if ((rparams != NULL) && (rparams->passwdservers != NULL)) {
874 	    for (i=0; (rparams->passwdservers[i] != NULL); i++) {
875 		if ((retval=krb5_ldap_add_service_rights(util_context,
876 							 LDAP_PASSWD_SERVICE, rparams->passwdservers[i],
877 							 rparams->realm_name, rparams->subtree, rightsmask)) != 0) {
878 		    printf(gettext("failed\n"));
879 		    com_err(argv[0], retval, gettext("while assigning rights to '%s'"),
880 			    rparams->realm_name);
881 		    goto err_nomsg;
882 		}
883 	    }
884 	}
885 
886 	printf(gettext("done\n"));
887     }
888 #endif
889     /* The Realm creation is completed. Here is the end of transaction */
890     create_complete = TRUE;
891 
892     /* Stash the master key only if '-s' option is specified */
893     if (do_stash || global_params.mask & KADM5_CONFIG_STASH_FILE) {
894 	retval = krb5_def_store_mkey(util_context,
895 				     global_params.stash_file,
896 				     master_princ,
897 				     &master_keyblock, NULL);
898 	if (retval) {
899 	    com_err(argv[0], errno, gettext("while storing key"));
900 	    printf(gettext("Warning: couldn't stash master key.\n"));
901 	}
902     }
903 
904     goto cleanup;
905 
906 
907 err_usage:
908     print_usage = TRUE;
909 
910 err_nomsg:
911     no_msg = TRUE;
912 
913 cleanup:
914     /* If the Realm creation is not complete, do the roll-back here */
915     if ((realm_obj_created) && (!create_complete))
916 	krb5_ldap_delete_realm(util_context, global_params.realm);
917 
918     if (rparams)
919 	krb5_ldap_free_realm_params(rparams);
920 
921     memset (pw_str, 0, sizeof (pw_str));
922 
923     if (print_usage)
924 	db_usage(CREATE_REALM);
925 
926     if (retval) {
927 	if (!no_msg) {
928 	    com_err(argv[0], retval, gettext("while creating realm '%s'"),
929 		    global_params.realm);
930 	}
931 	exit_status++;
932     }
933 
934     return;
935 }
936 
937 
938 /*
939  * This function will modify the attributes of a given realm object
940  */
941 void kdb5_ldap_modify(argc, argv)
942     int argc;
943     char *argv[];
944 {
945     krb5_error_code retval = 0;
946     krb5_ldap_realm_params *rparams = NULL;
947     krb5_boolean print_usage = FALSE;
948     krb5_boolean no_msg = FALSE;
949     kdb5_dal_handle *dal_handle = NULL;
950     krb5_ldap_context *ldap_context=NULL;
951     int i = 0;
952     int mask = 0, rmask = 0, ret_mask = 0;
953     char **slist = {NULL};
954 #ifdef HAVE_EDIRECTORY
955     int j = 0;
956     char *list[MAX_LIST_ENTRIES];
957     int existing_entries = 0, list_entries = 0;
958     int newkdcdn = 0, newadmindn = 0, newpwddn = 0;
959     char **tempstr = NULL;
960     char **oldkdcdns = NULL;
961     char **oldadmindns = NULL;
962     char **oldpwddns = NULL;
963     char **newkdcdns = NULL;
964     char **newsubtrees = NULL;
965     char **newadmindns = NULL;
966     char **newpwddns = NULL;
967     char **oldsubtrees = {NULL};
968     int rightsmask = 0;
969     int subtree_changed = 0;
970 #endif
971 
972     dal_handle = (kdb5_dal_handle *) util_context->db_context;
973     ldap_context = (krb5_ldap_context *) dal_handle->db_context;
974     if (!(ldap_context)) {
975 	retval = EINVAL;
976 	goto cleanup;
977     }
978 
979     if ((retval = krb5_ldap_read_krbcontainer_params(util_context,
980 						     &(ldap_context->krbcontainer)))) {
981 	com_err(argv[0], retval, gettext("while reading Kerberos container information"));
982 	goto err_nomsg;
983     }
984 
985     retval = krb5_ldap_read_realm_params(util_context,
986 					 global_params.realm, &rparams, &rmask);
987     if (retval)
988 	goto cleanup;
989     /* Parse the arguments */
990     for (i = 1; i < argc; i++) {
991 	int k = 0;
992 	if (!strcmp(argv[i], "-subtrees")) {
993 	    if (++i > argc-1)
994 		goto err_usage;
995 
996 	    if (rmask & LDAP_REALM_SUBTREE) {
997 		if (rparams->subtree) {
998 #ifdef HAVE_EDIRECTORY
999 		    oldsubtrees =  (char **) calloc(rparams->subtreecount+1, sizeof(char *));
1000 		    if (oldsubtrees == NULL) {
1001 			retval = ENOMEM;
1002 			goto cleanup;
1003 		    }
1004 		    for(k=0; rparams->subtree[k]!=NULL && rparams->subtreecount; k++) {
1005 			oldsubtrees[k] = strdup(rparams->subtree[k]);
1006 			if( oldsubtrees[k] == NULL ) {
1007 			    retval = ENOMEM;
1008 			    goto cleanup;
1009 			}
1010 		    }
1011 #endif
1012 		    for(k=0; k<rparams->subtreecount && rparams->subtree[k]; k++)
1013 			free(rparams->subtree[k]);
1014 		    rparams->subtreecount=0;
1015 		}
1016 	    }
1017 	    if (strncmp(argv[i] ,"", strlen(argv[i]))!=0) {
1018 		slist =  (char **) calloc(MAX_LIST_ENTRIES, sizeof(char *));
1019 		if (slist == NULL) {
1020 		    retval = ENOMEM;
1021 		    goto cleanup;
1022 		}
1023 		if (( retval = krb5_parse_list(argv[i], LIST_DELIMITER, slist))) {
1024 		    free(slist);
1025 		    slist = NULL;
1026 		    goto cleanup;
1027 		}
1028 
1029 		rparams->subtreecount=0;
1030 		while(slist[rparams->subtreecount]!=NULL)
1031 		    (rparams->subtreecount)++;
1032 		rparams->subtree =  slist;
1033 	    } else if(strncmp(argv[i], "", strlen(argv[i]))==0) {
1034 		 /* dont allow subtree value to be set at the root(NULL, "") of the tree */
1035 		    com_err(argv[0], EINVAL,
1036 			    gettext("for subtree while modifying realm '%s'"),
1037 			    global_params.realm);
1038 		    goto err_nomsg;
1039 	    }
1040 	    rparams->subtree[rparams->subtreecount] = NULL;
1041 	    mask |= LDAP_REALM_SUBTREE;
1042 	} else if (!strncmp(argv[i], "-containerref", strlen(argv[i]))) {
1043 	    if (++i > argc-1)
1044 		goto err_usage;
1045 	    if(strncmp(argv[i], "", strlen(argv[i]))==0) {
1046 		 /* dont allow containerref value to be set at the root(NULL, "") of the tree */
1047 		 com_err(argv[0], EINVAL,
1048 			  gettext("for container reference while modifying realm '%s'"),
1049 			   global_params.realm);
1050 		 goto err_nomsg;
1051 	    }
1052 	    rparams->containerref = strdup(argv[i]);
1053 	    if (rparams->containerref == NULL) {
1054 		retval = ENOMEM;
1055 		goto cleanup;
1056 	    }
1057 	    mask |= LDAP_REALM_CONTREF;
1058 	} else if (!strcmp(argv[i], "-sscope")) {
1059 	    if (++i > argc-1)
1060 		goto err_usage;
1061 	    /* Possible values for search scope are
1062 	     * one (or 1) and sub (or 2)
1063 	     */
1064 	    if (strcasecmp(argv[i], "one") == 0) {
1065 		rparams->search_scope = 1;
1066 	    } else if (strcasecmp(argv[i], "sub") == 0) {
1067 		rparams->search_scope = 2;
1068 	    } else {
1069 		rparams->search_scope = atoi(argv[i]);
1070 		if ((rparams->search_scope != 1) &&
1071 		    (rparams->search_scope != 2)) {
1072 		    retval = EINVAL;
1073 		    com_err(argv[0], retval,
1074 			    gettext("specified for search scope while modifying information of realm '%s'"),
1075 			    global_params.realm);
1076 		    goto err_nomsg;
1077 		}
1078 	    }
1079 	    mask |= LDAP_REALM_SEARCHSCOPE;
1080 	}
1081 #ifdef HAVE_EDIRECTORY
1082 	else if (!strcmp(argv[i], "-kdcdn")) {
1083 	    if (++i > argc-1)
1084 		goto err_usage;
1085 
1086 	    if ((rmask & LDAP_REALM_KDCSERVERS) && (rparams->kdcservers)) {
1087 		if (!oldkdcdns) {
1088 		    /* Store the old kdc dns list for removing rights */
1089 		    oldkdcdns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
1090 		    if (oldkdcdns == NULL) {
1091 			retval = ENOMEM;
1092 			goto cleanup;
1093 		    }
1094 
1095 		    for (j=0; rparams->kdcservers[j] != NULL; j++) {
1096 			oldkdcdns[j] = strdup(rparams->kdcservers[j]);
1097 			if (oldkdcdns[j] == NULL) {
1098 			    retval = ENOMEM;
1099 			    goto cleanup;
1100 			}
1101 		    }
1102 		    oldkdcdns[j] = NULL;
1103 		}
1104 
1105 		krb5_free_list_entries(rparams->kdcservers);
1106 		free(rparams->kdcservers);
1107 	    }
1108 
1109 	    rparams->kdcservers = (char **)malloc(
1110 		sizeof(char *) * MAX_LIST_ENTRIES);
1111 	    if (rparams->kdcservers == NULL) {
1112 		retval = ENOMEM;
1113 		goto cleanup;
1114 	    }
1115 	    memset(rparams->kdcservers, 0, sizeof(char *)*MAX_LIST_ENTRIES);
1116 	    if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
1117 					  rparams->kdcservers))) {
1118 		goto cleanup;
1119 	    }
1120 	    mask |= LDAP_REALM_KDCSERVERS;
1121 	    /* Going to replace the existing value by this new value. Hence
1122 	     * setting flag indicating that add or clear options will be ignored
1123 	     */
1124 	    newkdcdn = 1;
1125 	} else if (!strcmp(argv[i], "-clearkdcdn")) {
1126 	    if (++i > argc-1)
1127 		goto err_usage;
1128 	    if ((!newkdcdn) && (rmask & LDAP_REALM_KDCSERVERS) && (rparams->kdcservers)) {
1129 		if (!oldkdcdns) {
1130 		    /* Store the old kdc dns list for removing rights */
1131 		    oldkdcdns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
1132 		    if (oldkdcdns == NULL) {
1133 			retval = ENOMEM;
1134 			goto cleanup;
1135 		    }
1136 
1137 		    for (j=0; rparams->kdcservers[j] != NULL; j++) {
1138 			oldkdcdns[j] = strdup(rparams->kdcservers[j]);
1139 			if (oldkdcdns[j] == NULL) {
1140 			    retval = ENOMEM;
1141 			    goto cleanup;
1142 			}
1143 		    }
1144 		    oldkdcdns[j] = NULL;
1145 		}
1146 
1147 		memset(list, 0, sizeof(char *) * MAX_LIST_ENTRIES);
1148 		if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) {
1149 		    goto cleanup;
1150 		}
1151 		list_modify_str_array(&rparams->kdcservers, (const char **)list,
1152 				      LIST_MODE_DELETE);
1153 		mask |= LDAP_REALM_KDCSERVERS;
1154 		krb5_free_list_entries(list);
1155 	    }
1156 	} else if (!strcmp(argv[i], "-addkdcdn")) {
1157 	    if (++i > argc-1)
1158 		goto err_usage;
1159 	    if (!newkdcdn) {
1160 		if ((rmask & LDAP_REALM_KDCSERVERS) && (rparams->kdcservers) && (!oldkdcdns)) {
1161 		    /* Store the old kdc dns list for removing rights */
1162 		    oldkdcdns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
1163 		    if (oldkdcdns == NULL) {
1164 			retval = ENOMEM;
1165 			goto cleanup;
1166 		    }
1167 
1168 		    for (j = 0; rparams->kdcservers[j] != NULL; j++) {
1169 			oldkdcdns[j] = strdup(rparams->kdcservers[j]);
1170 			if (oldkdcdns[j] == NULL) {
1171 			    retval = ENOMEM;
1172 			    goto cleanup;
1173 			}
1174 		    }
1175 		    oldkdcdns[j] = NULL;
1176 		}
1177 
1178 		memset(list, 0, sizeof(char *) * MAX_LIST_ENTRIES);
1179 		if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) {
1180 		    goto cleanup;
1181 		}
1182 		existing_entries = list_count_str_array(rparams->kdcservers);
1183 		list_entries = list_count_str_array(list);
1184 		if (rmask & LDAP_REALM_KDCSERVERS) {
1185 		    tempstr = (char **)realloc(
1186 			rparams->kdcservers,
1187 			sizeof(char *) * (existing_entries+list_entries+1));
1188 		    if (tempstr == NULL) {
1189 			retval = ENOMEM;
1190 			goto cleanup;
1191 		    }
1192 		    rparams->kdcservers = tempstr;
1193 		} else {
1194 		    rparams->kdcservers = (char **)malloc(sizeof(char *) * (list_entries+1));
1195 		    if (rparams->kdcservers == NULL) {
1196 			retval = ENOMEM;
1197 			goto cleanup;
1198 		    }
1199 		    memset(rparams->kdcservers, 0, sizeof(char *) * (list_entries+1));
1200 		}
1201 		list_modify_str_array(&rparams->kdcservers, (const char **)list,
1202 				      LIST_MODE_ADD);
1203 		mask |= LDAP_REALM_KDCSERVERS;
1204 	    }
1205 	} else if (!strcmp(argv[i], "-admindn")) {
1206 	    if (++i > argc-1)
1207 		goto err_usage;
1208 
1209 	    if ((rmask & LDAP_REALM_ADMINSERVERS) && (rparams->adminservers)) {
1210 		if (!oldadmindns) {
1211 		    /* Store the old admin dns list for removing rights */
1212 		    oldadmindns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
1213 		    if (oldadmindns == NULL) {
1214 			retval = ENOMEM;
1215 			goto cleanup;
1216 		    }
1217 
1218 		    for (j=0; rparams->adminservers[j] != NULL; j++) {
1219 			oldadmindns[j] = strdup(rparams->adminservers[j]);
1220 			if (oldadmindns[j] == NULL) {
1221 			    retval = ENOMEM;
1222 			    goto cleanup;
1223 			}
1224 		    }
1225 		    oldadmindns[j] = NULL;
1226 		}
1227 
1228 		krb5_free_list_entries(rparams->adminservers);
1229 		free(rparams->adminservers);
1230 	    }
1231 
1232 	    rparams->adminservers = (char **)malloc(
1233 		sizeof(char *) * MAX_LIST_ENTRIES);
1234 	    if (rparams->adminservers == NULL) {
1235 		retval = ENOMEM;
1236 		goto cleanup;
1237 	    }
1238 	    memset(rparams->adminservers, 0, sizeof(char *)*MAX_LIST_ENTRIES);
1239 	    if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
1240 					  rparams->adminservers))) {
1241 		goto cleanup;
1242 	    }
1243 	    mask |= LDAP_REALM_ADMINSERVERS;
1244 	    /* Going to replace the existing value by this new value. Hence
1245 	     * setting flag indicating that add or clear options will be ignored
1246 	     */
1247 	    newadmindn = 1;
1248 	} else if (!strcmp(argv[i], "-clearadmindn")) {
1249 	    if (++i > argc-1)
1250 		goto err_usage;
1251 
1252 	    if ((!newadmindn) && (rmask & LDAP_REALM_ADMINSERVERS) && (rparams->adminservers)) {
1253 		if (!oldadmindns) {
1254 		    /* Store the old admin dns list for removing rights */
1255 		    oldadmindns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
1256 		    if (oldadmindns == NULL) {
1257 			retval = ENOMEM;
1258 			goto cleanup;
1259 		    }
1260 
1261 		    for (j=0; rparams->adminservers[j] != NULL; j++) {
1262 			oldadmindns[j] = strdup(rparams->adminservers[j]);
1263 			if (oldadmindns[j] == NULL) {
1264 			    retval = ENOMEM;
1265 			    goto cleanup;
1266 			}
1267 		    }
1268 		    oldadmindns[j] = NULL;
1269 		}
1270 
1271 		memset(list, 0, sizeof(char *) * MAX_LIST_ENTRIES);
1272 		if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) {
1273 		    goto cleanup;
1274 		}
1275 		list_modify_str_array(&rparams->adminservers, (const char **)list,
1276 				      LIST_MODE_DELETE);
1277 		mask |= LDAP_REALM_ADMINSERVERS;
1278 		krb5_free_list_entries(list);
1279 	    }
1280 	} else if (!strcmp(argv[i], "-addadmindn")) {
1281 	    if (++i > argc-1)
1282 		goto err_usage;
1283 	    if (!newadmindn) {
1284 		if ((rmask & LDAP_REALM_ADMINSERVERS) && (rparams->adminservers) && (!oldadmindns)) {
1285 		    /* Store the old admin dns list for removing rights */
1286 		    oldadmindns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
1287 		    if (oldadmindns == NULL) {
1288 			retval = ENOMEM;
1289 			goto cleanup;
1290 		    }
1291 
1292 		    for (j=0; rparams->adminservers[j] != NULL; j++) {
1293 			oldadmindns[j] = strdup(rparams->adminservers[j]);
1294 			if (oldadmindns[j] == NULL) {
1295 			    retval = ENOMEM;
1296 			    goto cleanup;
1297 			}
1298 		    }
1299 		    oldadmindns[j] = NULL;
1300 		}
1301 
1302 		memset(list, 0, sizeof(char *) * MAX_LIST_ENTRIES);
1303 		if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) {
1304 		    goto cleanup;
1305 		}
1306 		existing_entries = list_count_str_array(rparams->adminservers);
1307 		list_entries = list_count_str_array(list);
1308 		if (rmask & LDAP_REALM_ADMINSERVERS) {
1309 		    tempstr = (char **)realloc(
1310 			rparams->adminservers,
1311 			sizeof(char *) * (existing_entries+list_entries+1));
1312 		    if (tempstr == NULL) {
1313 			retval = ENOMEM;
1314 			goto cleanup;
1315 		    }
1316 		    rparams->adminservers = tempstr;
1317 		} else {
1318 		    rparams->adminservers = (char **)malloc(sizeof(char *) * (list_entries+1));
1319 		    if (rparams->adminservers == NULL) {
1320 			retval = ENOMEM;
1321 			goto cleanup;
1322 		    }
1323 		    memset(rparams->adminservers, 0, sizeof(char *) * (list_entries+1));
1324 		}
1325 		list_modify_str_array(&rparams->adminservers, (const char **)list,
1326 				      LIST_MODE_ADD);
1327 		mask |= LDAP_REALM_ADMINSERVERS;
1328 	    }
1329 	} else if (!strcmp(argv[i], "-pwddn")) {
1330 	    if (++i > argc-1)
1331 		goto err_usage;
1332 
1333 	    if ((rmask & LDAP_REALM_PASSWDSERVERS) && (rparams->passwdservers)) {
1334 		if (!oldpwddns) {
1335 		    /* Store the old pwd dns list for removing rights */
1336 		    oldpwddns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
1337 		    if (oldpwddns == NULL) {
1338 			retval = ENOMEM;
1339 			goto cleanup;
1340 		    }
1341 
1342 		    for (j=0; rparams->passwdservers[j] != NULL; j++) {
1343 			oldpwddns[j] = strdup(rparams->passwdservers[j]);
1344 			if (oldpwddns[j] == NULL) {
1345 			    retval = ENOMEM;
1346 			    goto cleanup;
1347 			}
1348 		    }
1349 		    oldpwddns[j] = NULL;
1350 		}
1351 
1352 		krb5_free_list_entries(rparams->passwdservers);
1353 		free(rparams->passwdservers);
1354 	    }
1355 
1356 	    rparams->passwdservers = (char **)malloc(
1357 		sizeof(char *) * MAX_LIST_ENTRIES);
1358 	    if (rparams->passwdservers == NULL) {
1359 		retval = ENOMEM;
1360 		goto cleanup;
1361 	    }
1362 	    memset(rparams->passwdservers, 0, sizeof(char *)*MAX_LIST_ENTRIES);
1363 	    if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
1364 					  rparams->passwdservers))) {
1365 		goto cleanup;
1366 	    }
1367 	    mask |= LDAP_REALM_PASSWDSERVERS;
1368 	    /* Going to replace the existing value by this new value. Hence
1369 	     * setting flag indicating that add or clear options will be ignored
1370 	     */
1371 	    newpwddn = 1;
1372 	} else if (!strcmp(argv[i], "-clearpwddn")) {
1373 	    if (++i > argc-1)
1374 		goto err_usage;
1375 
1376 	    if ((!newpwddn) && (rmask & LDAP_REALM_PASSWDSERVERS) && (rparams->passwdservers)) {
1377 		if (!oldpwddns) {
1378 		    /* Store the old pwd dns list for removing rights */
1379 		    oldpwddns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
1380 		    if (oldpwddns == NULL) {
1381 			retval = ENOMEM;
1382 			goto cleanup;
1383 		    }
1384 
1385 		    for (j=0; rparams->passwdservers[j] != NULL; j++) {
1386 			oldpwddns[j] = strdup(rparams->passwdservers[j]);
1387 			if (oldpwddns[j] == NULL) {
1388 			    retval = ENOMEM;
1389 			    goto cleanup;
1390 			}
1391 		    }
1392 		    oldpwddns[j] = NULL;
1393 		}
1394 
1395 		memset(list, 0, sizeof(char *) * MAX_LIST_ENTRIES);
1396 		if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) {
1397 		    goto cleanup;
1398 		}
1399 		list_modify_str_array(&rparams->passwdservers, (const char**)list,
1400 				      LIST_MODE_DELETE);
1401 		mask |= LDAP_REALM_PASSWDSERVERS;
1402 		krb5_free_list_entries(list);
1403 	    }
1404 	} else if (!strcmp(argv[i], "-addpwddn")) {
1405 	    if (++i > argc-1)
1406 		goto err_usage;
1407 	    if (!newpwddn) {
1408 		if ((rmask & LDAP_REALM_PASSWDSERVERS) && (rparams->passwdservers) && (!oldpwddns)) {
1409 		    /* Store the old pwd dns list for removing rights */
1410 		    oldpwddns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
1411 		    if (oldpwddns == NULL) {
1412 			retval = ENOMEM;
1413 			goto cleanup;
1414 		    }
1415 
1416 		    for (j=0; rparams->passwdservers[j] != NULL; j++) {
1417 			oldpwddns[j] = strdup(rparams->passwdservers[j]);
1418 			if (oldpwddns[j] == NULL) {
1419 			    retval = ENOMEM;
1420 			    goto cleanup;
1421 			}
1422 		    }
1423 		    oldpwddns[j] = NULL;
1424 		}
1425 
1426 		memset(list, 0, sizeof(char *) * MAX_LIST_ENTRIES);
1427 		if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) {
1428 		    goto cleanup;
1429 		}
1430 		existing_entries = list_count_str_array(rparams->passwdservers);
1431 		list_entries = list_count_str_array(list);
1432 		if (rmask & LDAP_REALM_PASSWDSERVERS) {
1433 		    tempstr = (char **)realloc(
1434 			rparams->passwdservers,
1435 			sizeof(char *) * (existing_entries+list_entries+1));
1436 		    if (tempstr == NULL) {
1437 			retval = ENOMEM;
1438 			goto cleanup;
1439 		    }
1440 		    rparams->passwdservers = tempstr;
1441 		} else {
1442 		    rparams->passwdservers = (char **)malloc(sizeof(char *) * (list_entries+1));
1443 		    if (rparams->passwdservers == NULL) {
1444 			retval = ENOMEM;
1445 			goto cleanup;
1446 		    }
1447 		    memset(rparams->passwdservers, 0, sizeof(char *) * (list_entries+1));
1448 		}
1449 		list_modify_str_array(&rparams->passwdservers, (const char**)list,
1450 				      LIST_MODE_ADD);
1451 		mask |= LDAP_REALM_PASSWDSERVERS;
1452 	    }
1453 	}
1454 #endif
1455 	else if ((ret_mask= get_ticket_policy(rparams,&i,argv,argc)) !=0) {
1456 	    mask|=ret_mask;
1457 	} else {
1458 	    printf(gettext("'%s' is an invalid option\n"), argv[i]);
1459 	    goto err_usage;
1460 	}
1461     }
1462 
1463     if ((retval = krb5_ldap_modify_realm(util_context,
1464 					 /* global_params.realm, */ rparams, mask))) {
1465 	goto cleanup;
1466     }
1467 
1468 #ifdef HAVE_EDIRECTORY
1469     if ((mask & LDAP_REALM_SUBTREE) || (mask & LDAP_REALM_KDCSERVERS) ||
1470 	(mask & LDAP_REALM_ADMINSERVERS) || (mask & LDAP_REALM_PASSWDSERVERS)) {
1471 
1472 	printf(gettext("Changing rights for the service object. Please wait ... "));
1473 	fflush(stdout);
1474 
1475 	if (!(mask & LDAP_REALM_SUBTREE)) {
1476 	    if (rparams->subtree != NULL) {
1477 		for(i=0; rparams->subtree[i]!=NULL;i++) {
1478 		    oldsubtrees[i] = strdup(rparams->subtree[i]);
1479 		    if( oldsubtrees[i] == NULL ) {
1480 			retval = ENOMEM;
1481 			goto cleanup;
1482 		    }
1483 		}
1484 	    }
1485 	}
1486 
1487 	if ((mask & LDAP_REALM_SUBTREE)) {
1488 	    int check_subtree = 1;
1489 
1490 	    newsubtrees = (char**) calloc(rparams->subtreecount, sizeof(char*));
1491 
1492 	    if (newsubtrees == NULL) {
1493 		retval = ENOMEM;
1494 		goto cleanup;
1495 	    }
1496 
1497 	    if ( (rparams != NULL) && (rparams->subtree != NULL) ) {
1498 		for (j=0; j<rparams->subtreecount && rparams->subtree[j]!= NULL; j++) {
1499 		    newsubtrees[j] = strdup(rparams->subtree[j]);
1500 		    if (newsubtrees[j] == NULL) {
1501 			retval = ENOMEM;
1502 			goto cleanup;
1503 		    }
1504 		}
1505 		newsubtrees[j] = NULL;
1506 	    }
1507 	    for(j=0;oldsubtrees[j]!=NULL;j++) {
1508 		check_subtree = 1;
1509 		for(i=0; ( (oldsubtrees[j] && !rparams->subtree[i]) ||
1510 			(!oldsubtrees[j] && rparams->subtree[i])); i++) {
1511 		    if(strcasecmp( oldsubtrees[j], rparams->subtree[i]) == 0) {
1512 			check_subtree = 0;
1513 			continue;
1514 		    }
1515 		}
1516 		if (check_subtree != 0) {
1517 		    subtree_changed=1;
1518 		    break;
1519 		}
1520 	    }
1521 	    /* this will return list of the disjoint members */
1522 	    disjoint_members( oldsubtrees, newsubtrees);
1523 	}
1524 
1525 	if ((mask & LDAP_REALM_SUBTREE) || (mask & LDAP_REALM_KDCSERVERS)) {
1526 
1527 	    newkdcdns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
1528 	    if (newkdcdns == NULL) {
1529 		retval = ENOMEM;
1530 		goto cleanup;
1531 	    }
1532 
1533 	    if ((rparams != NULL) && (rparams->kdcservers != NULL)) {
1534 		for (j=0;  rparams->kdcservers[j]!= NULL; j++) {
1535 		    newkdcdns[j] = strdup(rparams->kdcservers[j]);
1536 		    if (newkdcdns[j] == NULL) {
1537 			retval = ENOMEM;
1538 			goto cleanup;
1539 		    }
1540 		}
1541 		newkdcdns[j] = NULL;
1542 	    }
1543 
1544 	    if (!subtree_changed) {
1545 		disjoint_members(oldkdcdns, newkdcdns);
1546 	    } else { /* Only the subtrees was changed. Remove the rights on the old subtrees. */
1547 		if (!(mask & LDAP_REALM_KDCSERVERS)) {
1548 
1549 		    oldkdcdns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
1550 		    if (oldkdcdns == NULL) {
1551 			retval = ENOMEM;
1552 			goto cleanup;
1553 		    }
1554 
1555 		    if ((rparams != NULL) && (rparams->kdcservers != NULL)) {
1556 			for (j=0;  rparams->kdcservers[j]!= NULL; j++) {
1557 			    oldkdcdns[j] = strdup(rparams->kdcservers[j]);
1558 			    if (oldkdcdns[j] == NULL) {
1559 				retval = ENOMEM;
1560 				goto cleanup;
1561 			    }
1562 			}
1563 			oldkdcdns[j] = NULL;
1564 		    }
1565 		}
1566 	    }
1567 
1568 	    rightsmask =0;
1569 	    rightsmask |= LDAP_REALM_RIGHTS;
1570 	    rightsmask |= LDAP_SUBTREE_RIGHTS;
1571 	    /* Remove the rights on the old subtrees */
1572 	    if (oldkdcdns) {
1573 		for (i=0; (oldkdcdns[i] != NULL); i++) {
1574 		    if ((retval=krb5_ldap_delete_service_rights(util_context,
1575 								LDAP_KDC_SERVICE, oldkdcdns[i],
1576 								rparams->realm_name, oldsubtrees, rightsmask)) != 0) {
1577 			printf(gettext("failed\n"));
1578 			com_err(argv[0], retval, gettext("while assigning rights '%s'"),
1579 				rparams->realm_name);
1580 			goto err_nomsg;
1581 		    }
1582 		}
1583 	    }
1584 
1585 	    rightsmask =0;
1586 	    rightsmask |= LDAP_REALM_RIGHTS;
1587 	    rightsmask |= LDAP_SUBTREE_RIGHTS;
1588 	    if (newkdcdns) {
1589 		for (i=0; (newkdcdns[i] != NULL); i++) {
1590 
1591 		    if ((retval=krb5_ldap_add_service_rights(util_context,
1592 							     LDAP_KDC_SERVICE, newkdcdns[i], rparams->realm_name,
1593 							     rparams->subtree, rightsmask)) != 0) {
1594 			printf(gettext("failed\n"));
1595 			com_err(argv[0], retval, gettext("while assigning rights to '%s'"),
1596 				rparams->realm_name);
1597 			goto err_nomsg;
1598 		    }
1599 		}
1600 	    }
1601 	}
1602 
1603 	if ((mask & LDAP_REALM_SUBTREE) || (mask & LDAP_REALM_ADMINSERVERS)) {
1604 
1605 	    newadmindns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
1606 	    if (newadmindns == NULL) {
1607 		retval = ENOMEM;
1608 		goto cleanup;
1609 	    }
1610 
1611 	    if ((rparams != NULL) && (rparams->adminservers != NULL)) {
1612 		for (j=0;  rparams->adminservers[j]!= NULL; j++) {
1613 		    newadmindns[j] = strdup(rparams->adminservers[j]);
1614 		    if (newadmindns[j] == NULL) {
1615 			retval = ENOMEM;
1616 			goto cleanup;
1617 		    }
1618 		}
1619 		newadmindns[j] = NULL;
1620 	    }
1621 
1622 	    if (!subtree_changed) {
1623 		disjoint_members(oldadmindns, newadmindns);
1624 	    } else { /* Only the subtrees was changed. Remove the rights on the old subtrees. */
1625 		if (!(mask & LDAP_REALM_ADMINSERVERS)) {
1626 
1627 		    oldadmindns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
1628 		    if (oldadmindns == NULL) {
1629 			retval = ENOMEM;
1630 			goto cleanup;
1631 		    }
1632 
1633 		    if ((rparams != NULL) && (rparams->adminservers != NULL)) {
1634 			for (j=0;  rparams->adminservers[j]!= NULL; j++) {
1635 			    oldadmindns[j] = strdup(rparams->adminservers[j]);
1636 			    if (oldadmindns[j] == NULL) {
1637 				retval = ENOMEM;
1638 				goto cleanup;
1639 			    }
1640 			}
1641 			oldadmindns[j] = NULL;
1642 		    }
1643 		}
1644 	    }
1645 
1646 	    rightsmask = 0;
1647 	    rightsmask |= LDAP_REALM_RIGHTS;
1648 	    rightsmask |= LDAP_SUBTREE_RIGHTS;
1649 	    /* Remove the rights on the old subtrees */
1650 	    if (oldadmindns) {
1651 		for (i=0; (oldadmindns[i] != NULL); i++) {
1652 
1653 		    if ((retval=krb5_ldap_delete_service_rights(util_context,
1654 								LDAP_ADMIN_SERVICE, oldadmindns[i],
1655 								rparams->realm_name, oldsubtrees, rightsmask)) != 0) {
1656 			printf(gettext("failed\n"));
1657 			com_err(argv[0], retval, gettext("while assigning rights '%s'"),
1658 				rparams->realm_name);
1659 			goto err_nomsg;
1660 		    }
1661 		}
1662 	    }
1663 
1664 	    rightsmask = 0;
1665 	    rightsmask |= LDAP_REALM_RIGHTS;
1666 	    rightsmask |= LDAP_SUBTREE_RIGHTS;
1667 	    /* Add rights on the new subtree for all the kdc dns */
1668 	    if (newadmindns) {
1669 		for (i=0; (newadmindns[i] != NULL); i++) {
1670 
1671 		    if ((retval=krb5_ldap_add_service_rights(util_context,
1672 							     LDAP_ADMIN_SERVICE, newadmindns[i],
1673 							     rparams->realm_name, rparams->subtree, rightsmask)) != 0) {
1674 			printf(gettext("failed\n"));
1675 			com_err(argv[0], retval, gettext("while assigning rights to '%s'"),
1676 				rparams->realm_name);
1677 			goto err_nomsg;
1678 		    }
1679 		}
1680 	    }
1681 	}
1682 
1683 
1684 	if ((mask & LDAP_REALM_SUBTREE) || (mask & LDAP_REALM_PASSWDSERVERS)) {
1685 
1686 	    newpwddns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
1687 	    if (newpwddns == NULL) {
1688 		retval = ENOMEM;
1689 		goto cleanup;
1690 	    }
1691 
1692 	    if ((rparams != NULL) && (rparams->passwdservers != NULL)) {
1693 		for (j=0;  rparams->passwdservers[j]!= NULL; j++) {
1694 		    newpwddns[j] = strdup(rparams->passwdservers[j]);
1695 		    if (newpwddns[j] == NULL) {
1696 			retval = ENOMEM;
1697 			goto cleanup;
1698 		    }
1699 		}
1700 		newpwddns[j] = NULL;
1701 	    }
1702 
1703 	    if (!subtree_changed) {
1704 		disjoint_members(oldpwddns, newpwddns);
1705 	    } else { /* Only the subtrees was changed. Remove the rights on the old subtrees. */
1706 		if (!(mask & LDAP_REALM_ADMINSERVERS)) {
1707 
1708 		    oldpwddns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
1709 		    if (oldpwddns == NULL) {
1710 			retval = ENOMEM;
1711 			goto cleanup;
1712 		    }
1713 
1714 		    if ((rparams != NULL) && (rparams->passwdservers != NULL)) {
1715 			for (j=0;  rparams->passwdservers[j]!= NULL; j++) {
1716 			    oldpwddns[j] = strdup(rparams->passwdservers[j]);
1717 			    if (oldpwddns[j] == NULL) {
1718 				retval = ENOMEM;
1719 				goto cleanup;
1720 			    }
1721 			}
1722 			oldpwddns[j] = NULL;
1723 		    }
1724 		}
1725 	    }
1726 
1727 	    rightsmask =0;
1728 	    rightsmask |= LDAP_REALM_RIGHTS;
1729 	    rightsmask |= LDAP_SUBTREE_RIGHTS;
1730 	    /* Remove the rights on the old subtrees */
1731 	    if (oldpwddns) {
1732 		for (i=0; (oldpwddns[i] != NULL); i++) {
1733 		    if ((retval = krb5_ldap_delete_service_rights(util_context,
1734 								  LDAP_PASSWD_SERVICE, oldpwddns[i],
1735 								  rparams->realm_name, oldsubtrees, rightsmask))) {
1736 			printf(gettext("failed\n"));
1737 			com_err(argv[0], retval, gettext("while assigning rights '%s'"),
1738 				rparams->realm_name);
1739 			goto err_nomsg;
1740 		    }
1741 		}
1742 	    }
1743 
1744 	    rightsmask =0;
1745 	    rightsmask |= LDAP_REALM_RIGHTS;
1746 	    rightsmask |= LDAP_SUBTREE_RIGHTS;
1747 	    /* Add rights on the new subtree for all the kdc dns */
1748 	    if (newpwddns) {
1749 		for (i=0; (newpwddns[i] != NULL); i++) {
1750 		    if ((retval = krb5_ldap_add_service_rights(util_context,
1751 							       LDAP_PASSWD_SERVICE, newpwddns[i],
1752 							       rparams->realm_name, rparams->subtree, rightsmask))) {
1753 			printf(gettext("failed\n"));
1754 			com_err(argv[0], retval, gettext("while assigning rights to '%s'"),
1755 				rparams->realm_name);
1756 			goto err_nomsg;
1757 		    }
1758 		}
1759 	    }
1760 	}
1761 
1762 	printf(gettext("done\n"));
1763     }
1764 #endif
1765 
1766     goto cleanup;
1767 
1768 err_usage:
1769     print_usage = TRUE;
1770 
1771 err_nomsg:
1772     no_msg = TRUE;
1773 
1774 cleanup:
1775     krb5_ldap_free_realm_params(rparams);
1776 
1777 
1778 #ifdef HAVE_EDIRECTORY
1779     if (oldkdcdns) {
1780 	for (i=0; oldkdcdns[i] != NULL; i++)
1781 	    free(oldkdcdns[i]);
1782 	free(oldkdcdns);
1783     }
1784     if (oldpwddns) {
1785 	for (i=0; oldpwddns[i] != NULL; i++)
1786 	    free(oldpwddns[i]);
1787 	free(oldpwddns);
1788     }
1789     if (oldadmindns) {
1790 	for (i=0; oldadmindns[i] != NULL; i++)
1791 	    free(oldadmindns[i]);
1792 	free(oldadmindns);
1793     }
1794     if (newkdcdns) {
1795 	for (i=0; newkdcdns[i] != NULL; i++)
1796 	    free(newkdcdns[i]);
1797 	free(newkdcdns);
1798     }
1799     if (newpwddns) {
1800 	for (i=0; newpwddns[i] != NULL; i++)
1801 	    free(newpwddns[i]);
1802 	free(newpwddns);
1803     }
1804     if (newadmindns) {
1805 	for (i=0; newadmindns[i] != NULL; i++)
1806 	    free(newadmindns[i]);
1807 	free(newadmindns);
1808     }
1809     if (oldsubtrees) {
1810 	for (i=0;oldsubtrees[i]!=NULL; i++)
1811 	    free(oldsubtrees[i]);
1812 	free(oldsubtrees);
1813     }
1814     if (newsubtrees) {
1815 	for (i=0;newsubtrees[i]!=NULL; i++)
1816 	    free(newsubtrees[i]);
1817 	free(oldsubtrees);
1818     }
1819 #endif
1820     if (print_usage) {
1821 	db_usage(MODIFY_REALM);
1822     }
1823 
1824     if (retval) {
1825 	if (!no_msg)
1826 	    com_err(argv[0], retval, gettext("while modifying information of realm '%s'"),
1827 		    global_params.realm);
1828 	exit_status++;
1829     }
1830 
1831     return;
1832 }
1833 
1834 
1835 
1836 /*
1837  * This function displays the attributes of a Realm
1838  */
1839 void kdb5_ldap_view(argc, argv)
1840     int argc;
1841     char *argv[];
1842 {
1843     krb5_ldap_realm_params *rparams = NULL;
1844     krb5_error_code retval = 0;
1845     kdb5_dal_handle *dal_handle=NULL;
1846     krb5_ldap_context *ldap_context=NULL;
1847     int mask = 0;
1848 
1849     dal_handle = (kdb5_dal_handle *) util_context->db_context;
1850     ldap_context = (krb5_ldap_context *) dal_handle->db_context;
1851     if (!(ldap_context)) {
1852 	retval = EINVAL;
1853 	com_err(argv[0], retval, gettext("while initializing database"));
1854 	exit_status++;
1855 	return;
1856     }
1857 
1858     /* Read the kerberos container information */
1859     if ((retval = krb5_ldap_read_krbcontainer_params(util_context,
1860 						     &(ldap_context->krbcontainer))) != 0) {
1861 	com_err(argv[0], retval, gettext("while reading kerberos container information"));
1862 	exit_status++;
1863 	return;
1864     }
1865 
1866     if ((retval = krb5_ldap_read_realm_params(util_context,
1867 					      global_params.realm, &rparams, &mask)) || (!rparams)) {
1868 	com_err(argv[0], retval, gettext("while reading information of realm '%s'"),
1869 		global_params.realm);
1870 	exit_status++;
1871 	return;
1872     }
1873     print_realm_params(rparams, mask);
1874     krb5_ldap_free_realm_params(rparams);
1875 
1876     return;
1877 }
1878 
1879 static char *strdur(duration)
1880     time_t duration;
1881 {
1882     static char out[50];
1883     int neg, days, hours, minutes, seconds;
1884 
1885     if (duration < 0) {
1886 	duration *= -1;
1887 	neg = 1;
1888     } else
1889 	neg = 0;
1890     days = duration / (24 * 3600);
1891     duration %= 24 * 3600;
1892     hours = duration / 3600;
1893     duration %= 3600;
1894     minutes = duration / 60;
1895     duration %= 60;
1896     seconds = duration;
1897     snprintf(out, sizeof(out), "%s%d %s %02d:%02d:%02d", neg ? "-" : "",
1898 	    days, days == 1 ? gettext("day") : gettext("days"),
1899 	    hours, minutes, seconds);
1900     return out;
1901 }
1902 
1903 /*
1904  * This function prints the attributes of a given realm to the
1905  * standard output.
1906  */
1907 static void print_realm_params(krb5_ldap_realm_params *rparams, int mask)
1908 {
1909     char **slist = NULL;
1910     int num_entry_printed = 0, i = 0;
1911 
1912     /* Print the Realm Attributes on the standard output */
1913     printf("%25s: %-50s\n", gettext("Realm Name"), global_params.realm);
1914     if (mask & LDAP_REALM_SUBTREE) {
1915 	for (i=0; rparams->subtree[i]!=NULL; i++)
1916 	    printf("%25s: %-50s\n", gettext("Subtree"), rparams->subtree[i]);
1917     }
1918     if (mask & LDAP_REALM_CONTREF)
1919 	printf("%25s: %-50s\n", gettext("Principal Container Reference"), rparams->containerref);
1920     if (mask & LDAP_REALM_SEARCHSCOPE) {
1921 	if ((rparams->search_scope != 1) &&
1922 	    (rparams->search_scope != 2)) {
1923 	    printf("%25s: %-50s\n", gettext("SearchScope"), gettext("Invalid !"));
1924 	} else {
1925 	    printf("%25s: %-50s\n", gettext("SearchScope"),
1926 		   (rparams->search_scope == 1) ? gettext("ONE") : gettext("SUB"));
1927 	}
1928     }
1929     if (mask & LDAP_REALM_KDCSERVERS) {
1930 	printf("%25s:", gettext("KDC Services"));
1931 	if (rparams->kdcservers != NULL) {
1932 	    num_entry_printed = 0;
1933 	    for (slist = rparams->kdcservers; *slist != NULL; slist++) {
1934 		if (num_entry_printed)
1935 		    printf(" %25s %-50s\n", " ", *slist);
1936 		else
1937 		    printf(" %-50s\n", *slist);
1938 		num_entry_printed++;
1939 	    }
1940 	}
1941 	if (num_entry_printed == 0)
1942 	    printf("\n");
1943     }
1944     if (mask & LDAP_REALM_ADMINSERVERS) {
1945 	printf("%25s:", gettext("Admin Services"));
1946 	if (rparams->adminservers != NULL) {
1947 	    num_entry_printed = 0;
1948 	    for (slist = rparams->adminservers; *slist != NULL; slist++) {
1949 		if (num_entry_printed)
1950 		    printf(" %25s %-50s\n", " ", *slist);
1951 		else
1952 		    printf(" %-50s\n", *slist);
1953 		num_entry_printed++;
1954 	    }
1955 	}
1956 	if (num_entry_printed == 0)
1957 	    printf("\n");
1958     }
1959     if (mask & LDAP_REALM_PASSWDSERVERS) {
1960 	printf("%25s:", gettext("Passwd Services"));
1961 	if (rparams->passwdservers != NULL) {
1962 	    num_entry_printed = 0;
1963 	    for (slist = rparams->passwdservers; *slist != NULL; slist++) {
1964 		if (num_entry_printed)
1965 		    printf(" %25s %-50s\n", " ", *slist);
1966 		else
1967 		    printf(" %-50s\n", *slist);
1968 		num_entry_printed++;
1969 	    }
1970 	}
1971 	if (num_entry_printed == 0)
1972 	    printf("\n");
1973     }
1974     if (mask & LDAP_REALM_MAXTICKETLIFE) {
1975 	printf("%25s:", gettext("Maximum Ticket Life"));
1976 	printf(" %s \n", strdur(rparams->max_life));
1977     }
1978 
1979     if (mask & LDAP_REALM_MAXRENEWLIFE) {
1980 	printf("%25s:", gettext("Maximum Renewable Life"));
1981 	printf(" %s \n", strdur(rparams->max_renewable_life));
1982     }
1983 
1984     if (mask & LDAP_REALM_KRBTICKETFLAGS) {
1985 	int ticketflags = rparams->tktflags;
1986 
1987 	printf("%25s: ", gettext("Ticket flags"));
1988 	if (ticketflags & KRB5_KDB_DISALLOW_POSTDATED)
1989 	    printf("%s ","DISALLOW_POSTDATED");
1990 
1991 	if (ticketflags & KRB5_KDB_DISALLOW_FORWARDABLE)
1992 	    printf("%s ","DISALLOW_FORWARDABLE");
1993 
1994 	if (ticketflags & KRB5_KDB_DISALLOW_RENEWABLE)
1995 	    printf("%s ","DISALLOW_RENEWABLE");
1996 
1997 	if (ticketflags & KRB5_KDB_DISALLOW_PROXIABLE)
1998 	    printf("%s ","DISALLOW_PROXIABLE");
1999 
2000 	if (ticketflags & KRB5_KDB_DISALLOW_DUP_SKEY)
2001 	    printf("%s ","DISALLOW_DUP_SKEY");
2002 
2003 	if (ticketflags & KRB5_KDB_REQUIRES_PRE_AUTH)
2004 	    printf("%s ","REQUIRES_PRE_AUTH");
2005 
2006 	if (ticketflags & KRB5_KDB_REQUIRES_HW_AUTH)
2007 	    printf("%s ","REQUIRES_HW_AUTH");
2008 
2009 	if (ticketflags & KRB5_KDB_DISALLOW_SVR)
2010 	    printf("%s ","DISALLOW_SVR");
2011 
2012 	if (ticketflags & KRB5_KDB_DISALLOW_TGT_BASED)
2013 	    printf("%s ","DISALLOW_TGT_BASED");
2014 
2015 	if (ticketflags & KRB5_KDB_DISALLOW_ALL_TIX)
2016 	    printf("%s ","DISALLOW_ALL_TIX");
2017 
2018 	if (ticketflags & KRB5_KDB_REQUIRES_PWCHANGE)
2019 	    printf("%s ","REQUIRES_PWCHANGE");
2020 
2021 	if (ticketflags & KRB5_KDB_PWCHANGE_SERVICE)
2022 	    printf("%s ","PWCHANGE_SERVICE");
2023 
2024 	printf("\n");
2025     }
2026 
2027 
2028     return;
2029 }
2030 
2031 
2032 
2033 /*
2034  * This function lists the Realm(s) present under the Kerberos container
2035  * on the LDAP Server.
2036  */
2037 void kdb5_ldap_list(argc, argv)
2038     int argc;
2039     char *argv[];
2040 {
2041     char **list = NULL;
2042     char **plist = NULL;
2043     krb5_error_code retval = 0;
2044     kdb5_dal_handle *dal_handle=NULL;
2045     krb5_ldap_context *ldap_context=NULL;
2046 
2047     dal_handle = (kdb5_dal_handle *)util_context->db_context;
2048     ldap_context = (krb5_ldap_context *) dal_handle->db_context;
2049     if (!(ldap_context)) {
2050 	retval = EINVAL;
2051 	exit_status++;
2052 	return;
2053     }
2054 
2055     /* Read the kerberos container information */
2056     if ((retval = krb5_ldap_read_krbcontainer_params(util_context,
2057 						     &(ldap_context->krbcontainer))) != 0) {
2058 	com_err(argv[0], retval, gettext("while reading kerberos container information"));
2059 	exit_status++;
2060 	return;
2061     }
2062 
2063     retval = krb5_ldap_list_realm(util_context, &list);
2064     if (retval != 0) {
2065 	krb5_ldap_free_krbcontainer_params(ldap_context->krbcontainer);
2066 	ldap_context->krbcontainer = NULL;
2067 	com_err (argv[0], retval, gettext("while listing realms"));
2068 	exit_status++;
2069 	return;
2070     }
2071     /* This is to handle the case of realm not present */
2072     if (list == NULL) {
2073 	krb5_ldap_free_krbcontainer_params(ldap_context->krbcontainer);
2074 	ldap_context->krbcontainer = NULL;
2075 	return;
2076     }
2077 
2078     for (plist = list; *plist != NULL; plist++) {
2079 	printf("%s\n", *plist);
2080     }
2081     krb5_ldap_free_krbcontainer_params(ldap_context->krbcontainer);
2082     ldap_context->krbcontainer = NULL;
2083     krb5_free_list_entries(list);
2084     free(list);
2085 
2086     return;
2087 }
2088 
2089 /*
2090  * Duplicating the following two functions here because
2091  * 'krb5_dbe_update_tl_data' uses backend specific memory allocation. The catch
2092  * here is that the backend is not initialized - kdb5_ldap_util doesn't go
2093  * through DAL.
2094  * 1. krb5_dbe_update_tl_data
2095  * 2. krb5_dbe_update_mod_princ_data
2096  */
2097 
2098 /* Start duplicate code ... */
2099 
2100 static krb5_error_code
2101 krb5_dbe_update_tl_data_new(context, entry, new_tl_data)
2102     krb5_context context;
2103     krb5_db_entry *entry;
2104     krb5_tl_data *new_tl_data;
2105 {
2106     krb5_tl_data *tl_data = NULL;
2107     krb5_octet *tmp;
2108 
2109     /* copy the new data first, so we can fail cleanly if malloc()
2110      * fails */
2111 /*
2112     if ((tmp =
2113 	 (krb5_octet *) krb5_db_alloc(context, NULL,
2114 				      new_tl_data->tl_data_length)) == NULL)
2115 */
2116     if ((tmp = (krb5_octet *) malloc (new_tl_data->tl_data_length)) == NULL)
2117 	return (ENOMEM);
2118 
2119     /* Find an existing entry of the specified type and point at
2120      * it, or NULL if not found */
2121 
2122     if (new_tl_data->tl_data_type != KRB5_TL_DB_ARGS) {	/* db_args can be multiple */
2123 	for (tl_data = entry->tl_data; tl_data;
2124 	     tl_data = tl_data->tl_data_next)
2125 	    if (tl_data->tl_data_type == new_tl_data->tl_data_type)
2126 		break;
2127     }
2128 
2129     /* if necessary, chain a new record in the beginning and point at it */
2130 
2131     if (!tl_data) {
2132 /*
2133 	if ((tl_data =
2134 	     (krb5_tl_data *) krb5_db_alloc(context, NULL,
2135 					    sizeof(krb5_tl_data)))
2136 	    == NULL) {
2137 */
2138 	if ((tl_data = (krb5_tl_data *) malloc (sizeof(krb5_tl_data))) == NULL) {
2139 	    free(tmp);
2140 	    return (ENOMEM);
2141 	}
2142 	memset(tl_data, 0, sizeof(krb5_tl_data));
2143 	tl_data->tl_data_next = entry->tl_data;
2144 	entry->tl_data = tl_data;
2145 	entry->n_tl_data++;
2146     }
2147 
2148     /* fill in the record */
2149 
2150     if (tl_data->tl_data_contents)
2151 	krb5_db_free(context, tl_data->tl_data_contents);
2152 
2153     tl_data->tl_data_type = new_tl_data->tl_data_type;
2154     tl_data->tl_data_length = new_tl_data->tl_data_length;
2155     tl_data->tl_data_contents = tmp;
2156     memcpy(tmp, new_tl_data->tl_data_contents, tl_data->tl_data_length);
2157 
2158     return (0);
2159 }
2160 
2161 static krb5_error_code
2162 krb5_dbe_update_mod_princ_data_new(context, entry, mod_date, mod_princ)
2163     krb5_context	  context;
2164     krb5_db_entry	* entry;
2165     krb5_timestamp	  mod_date;
2166     krb5_const_principal  mod_princ;
2167 {
2168     krb5_tl_data          tl_data;
2169 
2170     krb5_error_code 	  retval = 0;
2171     krb5_octet		* nextloc = 0;
2172     char		* unparse_mod_princ = 0;
2173     unsigned int	unparse_mod_princ_size;
2174 
2175     if ((retval = krb5_unparse_name(context, mod_princ,
2176 				    &unparse_mod_princ)))
2177 	return(retval);
2178 
2179     unparse_mod_princ_size = strlen(unparse_mod_princ) + 1;
2180 
2181     if ((nextloc = (krb5_octet *) malloc(unparse_mod_princ_size + 4))
2182 	== NULL) {
2183 	free(unparse_mod_princ);
2184 	return(ENOMEM);
2185     }
2186 
2187     tl_data.tl_data_type = KRB5_TL_MOD_PRINC;
2188     tl_data.tl_data_length = unparse_mod_princ_size + 4;
2189     tl_data.tl_data_contents = nextloc;
2190 
2191     /* Mod Date */
2192     krb5_kdb_encode_int32(mod_date, nextloc);
2193 
2194     /* Mod Princ */
2195     memcpy(nextloc+4, unparse_mod_princ, unparse_mod_princ_size);
2196 
2197     retval = krb5_dbe_update_tl_data_new(context, entry, &tl_data);
2198 
2199     free(unparse_mod_princ);
2200     free(nextloc);
2201 
2202     return(retval);
2203 }
2204 
2205 static krb5_error_code
2206 kdb_ldap_tgt_keysalt_iterate(ksent, ptr)
2207     krb5_key_salt_tuple *ksent;
2208     krb5_pointer        ptr;
2209 {
2210     krb5_context        context;
2211     krb5_error_code     kret;
2212     struct iterate_args *iargs;
2213     krb5_keyblock       key;
2214     krb5_int32          ind;
2215     krb5_data   pwd;
2216     krb5_db_entry       *entry;
2217 
2218     iargs = (struct iterate_args *) ptr;
2219     kret = 0;
2220 
2221     context = iargs->ctx;
2222     entry = iargs->dbentp;
2223 
2224     /*
2225      * Convert the master key password into a key for this particular
2226      * encryption system.
2227      */
2228     pwd.data = mkey_password;
2229     pwd.length = strlen(mkey_password);
2230     kret = krb5_c_random_seed(context, &pwd);
2231     if (kret)
2232 	return kret;
2233 
2234     /*if (!(kret = krb5_dbe_create_key_data(iargs->ctx, iargs->dbentp))) {*/
2235     if ((entry->key_data =
2236 	     (krb5_key_data *) realloc(entry->key_data,
2237 					    (sizeof(krb5_key_data) *
2238 					    (entry->n_key_data + 1)))) == NULL)
2239 	return (ENOMEM);
2240 
2241     memset(entry->key_data + entry->n_key_data, 0, sizeof(krb5_key_data));
2242     ind = entry->n_key_data++;
2243 
2244     if (!(kret = krb5_c_make_random_key(context, ksent->ks_enctype,
2245 					&key))) {
2246 	kret = krb5_dbekd_encrypt_key_data(context,
2247 					   iargs->rblock->key,
2248 					   &key,
2249 					   NULL,
2250 					   1,
2251 					   &entry->key_data[ind]);
2252 	krb5_free_keyblock_contents(context, &key);
2253     }
2254     /*}*/
2255 
2256     return(kret);
2257 }
2258 /* End duplicate code */
2259 
2260 /*
2261  * This function creates service principals when
2262  * creating the realm object.
2263  */
2264 static int
2265 kdb_ldap_create_principal (context, princ, op, pblock)
2266     krb5_context context;
2267     krb5_principal princ;
2268     enum ap_op op;
2269     struct realm_info *pblock;
2270 {
2271     int              retval=0, currlen=0, princtype = 2 /* Service Principal */;
2272     unsigned char    *curr=NULL;
2273     krb5_tl_data     *tl_data=NULL;
2274     krb5_db_entry    entry;
2275     int              nentry=1;
2276     long             mask = 0;
2277     krb5_keyblock    key;
2278     int              kvno = 0;
2279     kdb5_dal_handle *dal_handle = NULL;
2280     krb5_ldap_context *ldap_context=NULL;
2281     struct iterate_args   iargs;
2282     krb5_data       *pdata;
2283 
2284     if ((pblock == NULL) || (context == NULL)) {
2285 	retval = EINVAL;
2286 	goto cleanup;
2287     }
2288     dal_handle = (kdb5_dal_handle *) context->db_context;
2289     ldap_context = (krb5_ldap_context *) dal_handle->db_context;
2290     if (!(ldap_context)) {
2291 	retval = EINVAL;
2292 	goto cleanup;
2293     }
2294 
2295     memset(&entry, 0, sizeof(entry));
2296 
2297     tl_data = malloc(sizeof(*tl_data));
2298     if (tl_data == NULL) {
2299 	retval = ENOMEM;
2300 	goto cleanup;
2301     }
2302     memset(tl_data, 0, sizeof(*tl_data));
2303     tl_data->tl_data_length = 1 + 2 + 2 + 1 + 2 + 4;
2304     tl_data->tl_data_type = 7; /* KDB_TL_USER_INFO */
2305     curr = tl_data->tl_data_contents = malloc(tl_data->tl_data_length);
2306     if (tl_data->tl_data_contents == NULL) {
2307 	retval = ENOMEM;
2308 	goto cleanup;
2309     }
2310 
2311     memset(curr, 1, 1); /* Passing the mask as principal type */
2312     curr += 1;
2313     currlen = 2;
2314     STORE16_INT(curr, currlen);
2315     curr += currlen;
2316     STORE16_INT(curr, princtype);
2317     curr += currlen;
2318 
2319     mask |= KADM5_PRINCIPAL;
2320     mask |= KADM5_ATTRIBUTES ;
2321     mask |= KADM5_MAX_LIFE ;
2322     mask |= KADM5_MAX_RLIFE ;
2323     mask |= KADM5_PRINC_EXPIRE_TIME ;
2324     mask |= KADM5_KEY_DATA;
2325 
2326     entry.tl_data = tl_data;
2327     entry.n_tl_data += 1;
2328     /* Set the creator's name */
2329     {
2330 	krb5_timestamp now;
2331 	if ((retval = krb5_timeofday(context, &now)))
2332 	    goto cleanup;
2333 	if ((retval = krb5_dbe_update_mod_princ_data_new(context, &entry,
2334 			now, &db_create_princ)))
2335 	    goto cleanup;
2336     }
2337     entry.attributes = pblock->flags;
2338     entry.max_life = pblock->max_life;
2339     entry.max_renewable_life = pblock->max_rlife;
2340     entry.expiration = pblock->expiration;
2341     entry.mask = mask;
2342     if ((retval = krb5_copy_principal(context, princ, &entry.princ)))
2343 	goto cleanup;
2344 
2345 
2346     switch (op) {
2347     case TGT_KEY:
2348 	if ((pdata = krb5_princ_component(context, princ, 1)) &&
2349 	    pdata->length == strlen("history") &&
2350 	    !memcmp(pdata->data, "history", strlen("history"))) {
2351 
2352 	    /* Allocate memory for storing the key */
2353 	    if ((entry.key_data = (krb5_key_data *) malloc(
2354 					      sizeof(krb5_key_data))) == NULL) {
2355 		retval = ENOMEM;
2356 		goto cleanup;
2357 	    }
2358 
2359 	    memset(entry.key_data, 0, sizeof(krb5_key_data));
2360 	    entry.n_key_data++;
2361 
2362 	    retval = krb5_c_make_random_key(context, global_params.enctype, &key);
2363 	    if (retval) {
2364 		goto cleanup;
2365 	    }
2366 	    kvno = 1; /* New key is getting set */
2367 	    retval = krb5_dbekd_encrypt_key_data(context,
2368 					&ldap_context->lrparams->mkey,
2369 					&key, NULL, kvno,
2370 					&entry.key_data[entry.n_key_data - 1]);
2371 	    krb5_free_keyblock_contents(context, &key);
2372 	    if (retval) {
2373 		goto cleanup;
2374 	    }
2375 	} else {
2376 	    /*retval = krb5_c_make_random_key(context, 16, &key) ;*/
2377 	    iargs.ctx = context;
2378 	    iargs.rblock = pblock;
2379 	    iargs.dbentp = &entry;
2380 
2381 	    /*
2382 	     * create a set of random keys by iterating through the key/salt
2383 	     * list, ignoring salt types.
2384 	     */
2385 	    if ((retval = krb5_keysalt_iterate(pblock->kslist,
2386 					       pblock->nkslist,
2387 					       1,
2388 					       kdb_ldap_tgt_keysalt_iterate,
2389 					       (krb5_pointer) &iargs)))
2390 		return retval;
2391 	}
2392 	break;
2393 
2394     case MASTER_KEY:
2395 	/* Allocate memory for storing the key */
2396 	if ((entry.key_data = (krb5_key_data *) malloc(
2397 					      sizeof(krb5_key_data))) == NULL) {
2398 	    retval = ENOMEM;
2399 	    goto cleanup;
2400 	}
2401 
2402 	memset(entry.key_data, 0, sizeof(krb5_key_data));
2403 	entry.n_key_data++;
2404 	kvno = 1; /* New key is getting set */
2405 	retval = krb5_dbekd_encrypt_key_data(context, pblock->key,
2406 					 &ldap_context->lrparams->mkey,
2407 					 NULL, kvno,
2408 					 &entry.key_data[entry.n_key_data - 1]);
2409 	if (retval) {
2410 	    goto cleanup;
2411 	}
2412 	break;
2413 
2414     case NULL_KEY:
2415     default:
2416 	break;
2417     } /* end of switch */
2418 
2419     retval = krb5_ldap_put_principal(context, &entry, &nentry, NULL);
2420     if (retval) {
2421 	com_err(NULL, retval, gettext("while adding entries to database"));
2422 	goto cleanup;
2423     }
2424 
2425 cleanup:
2426     krb5_dbe_free_contents(context, &entry);
2427     return retval;
2428 }
2429 
2430 
2431 /*
2432  * This function destroys the realm object and the associated principals
2433  */
2434 void
2435 kdb5_ldap_destroy(argc, argv)
2436     int argc;
2437     char *argv[];
2438 {
2439     extern char *optarg;
2440     extern int optind;
2441     int optchar = 0;
2442     char buf[5] = {0};
2443     krb5_error_code retval = 0;
2444     int force = 0;
2445     int mask = 0;
2446     kdb5_dal_handle *dal_handle = NULL;
2447     krb5_ldap_context *ldap_context = NULL;
2448 #ifdef HAVE_EDIRECTORY
2449     int i = 0, rightsmask = 0;
2450     krb5_ldap_realm_params *rparams = NULL;
2451 #endif
2452     /* Solaris Kerberos: to remove stash file */
2453     char *stash_file = NULL;
2454     struct stat stb;
2455 
2456     optind = 1;
2457     while ((optchar = getopt(argc, argv, "f")) != -1) {
2458 	switch (optchar) {
2459 	case 'f':
2460 	    force++;
2461 	    break;
2462 	case '?':
2463 	default:
2464 	    db_usage(DESTROY_REALM);
2465 	    return;
2466 	    /*NOTREACHED*/
2467 	}
2468     }
2469 
2470     if (!force) {
2471 	printf(gettext("Deleting KDC database of '%s', are you sure?\n"), global_params.realm);
2472 	printf(gettext("(type 'yes' to confirm)? "));
2473 	if (fgets(buf, sizeof(buf), stdin) == NULL) {
2474 	    exit_status++;
2475 	    return;
2476 	}
2477 	if (strcmp(buf, yes)) {
2478 	    exit_status++;
2479 	    return;
2480 	}
2481 	printf(gettext("OK, deleting database of '%s'...\n"), global_params.realm);
2482     }
2483 
2484     dal_handle = (kdb5_dal_handle *)util_context->db_context;
2485     ldap_context = (krb5_ldap_context *) dal_handle->db_context;
2486     if (!(ldap_context)) {
2487 	com_err(argv[0], EINVAL, gettext("while initializing database"));
2488 	exit_status++;
2489 	return;
2490     }
2491 
2492     /* Read the kerberos container from the LDAP Server */
2493     if ((retval = krb5_ldap_read_krbcontainer_params(util_context,
2494 						     &(ldap_context->krbcontainer))) != 0) {
2495 	com_err(argv[0], retval, gettext("while reading kerberos container information"));
2496 	exit_status++;
2497 	return;
2498     }
2499 
2500     /* Read the Realm information from the LDAP Server */
2501     if ((retval = krb5_ldap_read_realm_params(util_context, global_params.realm,
2502 					      &(ldap_context->lrparams), &mask)) != 0) {
2503 	com_err(argv[0], retval, gettext("while reading realm information"));
2504 	exit_status++;
2505 	return;
2506     }
2507 
2508 #ifdef HAVE_EDIRECTORY
2509     if ((mask & LDAP_REALM_KDCSERVERS) || (mask & LDAP_REALM_ADMINSERVERS) ||
2510 	(mask & LDAP_REALM_PASSWDSERVERS)) {
2511 
2512 	printf(gettext("Changing rights for the service object. Please wait ... "));
2513 	fflush(stdout);
2514 
2515 	rparams = ldap_context->lrparams;
2516 	rightsmask = 0;
2517 	rightsmask |= LDAP_REALM_RIGHTS;
2518 	rightsmask |= LDAP_SUBTREE_RIGHTS;
2519 	if ((rparams != NULL) && (rparams->kdcservers != NULL)) {
2520 	    for (i=0; (rparams->kdcservers[i] != NULL); i++) {
2521 		if ((retval = krb5_ldap_delete_service_rights(util_context,
2522 							      LDAP_KDC_SERVICE, rparams->kdcservers[i],
2523 							      rparams->realm_name, rparams->subtree, rightsmask)) != 0) {
2524 		    printf(gettext("failed\n"));
2525 		    com_err(argv[0], retval, gettext("while assigning rights to '%s'"),
2526 			    rparams->realm_name);
2527 		    return;
2528 		}
2529 	    }
2530 	}
2531 	rightsmask = 0;
2532 	rightsmask |= LDAP_REALM_RIGHTS;
2533 	rightsmask |= LDAP_SUBTREE_RIGHTS;
2534 	if ((rparams != NULL) && (rparams->adminservers != NULL)) {
2535 	    for (i=0; (rparams->adminservers[i] != NULL); i++) {
2536 		if ((retval = krb5_ldap_delete_service_rights(util_context,
2537 							      LDAP_ADMIN_SERVICE, rparams->adminservers[i],
2538 							      rparams->realm_name, rparams->subtree, rightsmask)) != 0) {
2539 		    printf(gettext("failed\n"));
2540 		    com_err(argv[0], retval, gettext("while assigning rights to '%s'"),
2541 			    rparams->realm_name);
2542 		    return;
2543 		}
2544 	    }
2545 	}
2546 	rightsmask = 0;
2547 	rightsmask |= LDAP_REALM_RIGHTS;
2548 	rightsmask |= LDAP_SUBTREE_RIGHTS;
2549 	if ((rparams != NULL) && (rparams->passwdservers != NULL)) {
2550 	    for (i=0; (rparams->passwdservers[i] != NULL); i++) {
2551 		if ((retval = krb5_ldap_delete_service_rights(util_context,
2552 							      LDAP_PASSWD_SERVICE, rparams->passwdservers[i],
2553 							      rparams->realm_name, rparams->subtree, rightsmask)) != 0) {
2554 		    printf(gettext("failed\n"));
2555 		    com_err(argv[0], retval, gettext("while assigning rights to '%s'"),
2556 			    rparams->realm_name);
2557 		    return;
2558 		}
2559 	    }
2560 	}
2561 	printf(gettext("done\n"));
2562     }
2563 #endif
2564     /* Delete the realm container and all the associated principals */
2565     retval = krb5_ldap_delete_realm(util_context, global_params.realm);
2566     if (retval) {
2567 	com_err(argv[0], retval, gettext("deleting database of '%s'"), global_params.realm);
2568 	exit_status++;
2569 	return;
2570     }
2571 
2572     /*
2573      * Solaris Kerberos: check for a stash file and delete it if necessary
2574      * This behavior exists in the Solaris version of kdb5_util destroy.
2575      */
2576     if (global_params.stash_file == NULL) {
2577 	char stashbuf[MAXPATHLEN+1];
2578 	int realm_len = strlen(global_params.realm);
2579 
2580 	(void) strlcpy(stashbuf, DEFAULT_KEYFILE_STUB, sizeof (stashbuf));
2581 
2582 	if (realm_len <= (MAXPATHLEN-strlen(stashbuf))) {
2583 	    (void) strncat(stashbuf, global_params.realm,
2584 		(MAXPATHLEN-strlen(stashbuf)));
2585 	} else {
2586 	    com_err(argv[0], EINVAL,
2587 		gettext("can not determine stash file name for '%s'"),
2588 		global_params.realm);
2589 	    exit_status++;
2590 	    return;
2591 	}
2592 	stash_file = stashbuf;
2593     } else {
2594 	stash_file = global_params.stash_file;
2595     }
2596     /* Make sure stash_file is a regular file before unlinking */
2597     if (stat(stash_file, &stb) == 0) {
2598 	if ((stb.st_mode & S_IFMT) == S_IFREG) {
2599 	    (void)unlink(stash_file);
2600 	} else {
2601 	    com_err(argv[0], EINVAL,
2602 		gettext("stash file '%s' not a regular file, can not delete"),
2603 		stash_file);
2604 	    exit_status++;
2605 	    return;
2606 	}
2607     } else if (errno != ENOENT) {
2608 	/*
2609 	 * If the error is something other than the file doesn't exist set an
2610 	 * error.
2611 	 */
2612 	com_err(argv[0], EINVAL,
2613 	    gettext("could not stat stash file '%s', could not delete"),
2614 	    stash_file);
2615 	exit_status++;
2616 	return;
2617     }
2618 
2619     printf(gettext("** Database of '%s' destroyed.\n"), global_params.realm);
2620 
2621     return;
2622 }
2623