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