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