xref: /illumos-gate/usr/src/lib/krb5/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c (revision 54925bf60766fbb4f1f2d7c843721406a7b7a3fb)
1 #pragma ident	"%Z%%M%	%I%	%E% SMI"
2 /*
3  * lib/kdb/kdb_ldap/ldap_realm.c
4  *
5  * Copyright (c) 2004-2005, Novell, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  *   * Redistributions of source code must retain the above copyright notice,
12  *       this list of conditions and the following disclaimer.
13  *   * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in the
15  *       documentation and/or other materials provided with the distribution.
16  *   * The copyright holder's name is not used to endorse or promote products
17  *       derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
34  * Use is subject to license terms.
35  */
36 
37 #include "ldap_main.h"
38 #include "ldap_realm.h"
39 #include "ldap_principal.h"
40 #include "ldap_pwd_policy.h"
41 #include "ldap_err.h"
42 #include <libintl.h>
43 
44 #define END_OF_LIST -1
45 char  *realm_attributes[] = {"krbSearchScope","krbSubTrees", "krbPrincContainerRef",
46 			     "krbMaxTicketLife", "krbMaxRenewableAge",
47 			     "krbTicketFlags", "krbUpEnabled",
48 			     "krbTicketPolicyReference",
49 			     "krbLdapServers",
50 			     "krbKdcServers",  "krbAdmServers",
51 			     "krbPwdServers", NULL};
52 
53 
54 char  *policy_attributes[] = { "krbMaxTicketLife",
55 			       "krbMaxRenewableAge",
56 			       "krbTicketFlags",
57 			       NULL };
58 
59 
60 
61 char  *policyclass[] =     { "krbTicketPolicy", NULL };
62 char  *kdcclass[] =        { "krbKdcService", NULL };
63 char  *adminclass[] =      { "krbAdmService", NULL };
64 char  *pwdclass[] =        { "krbPwdService", NULL };
65 char  *subtreeclass[] =    { "Organization", "OrganizationalUnit", "Domain", "krbContainer",
66                              "krbRealmContainer", "Country", "Locality", NULL };
67 
68 
69 char  *krbContainerRefclass[] = { "krbContainerRefAux", NULL};
70 
71 /*
72  * list realms from eDirectory
73  */
74 
75 /*
76  * Function to remove all special characters from a string (rfc2254).
77  * Use whenever exact matching is to be done ...
78  */
79 char *ldap_filter_correct (char *in)
80 {
81     size_t i, count;
82     char *out, *ptr;
83     size_t len = strlen(in);
84 
85     for (i = 0, count = 0; i < len; i++)
86 	switch (in[i]) {
87 	case '*':
88 	case '(':
89 	case ')':
90 	case '\\':
91 	case '\0':
92 	    count ++;
93 	}
94 
95     out = (char *)malloc((len + (count * 2) + 1) * sizeof (char));
96     assert (out != NULL);
97     memset(out, 0, len + (count * 2) + 1);
98 
99     for (i = 0, ptr = out; i < len; i++)
100 	switch (in[i]) {
101 	case '*':
102 	    ptr[0] = '\\';
103 	    ptr[1] = '2';
104 	    ptr[2] = 'a';
105 	    ptr += 3;
106 	    break;
107 	case '(':
108 	    ptr[0] = '\\';
109 	    ptr[1] = '2';
110 	    ptr[2] = '8';
111 	    ptr += 3;
112 	    break;
113 	case ')':
114 	    ptr[0] = '\\';
115 	    ptr[1] = '2';
116 	    ptr[2] = '9';
117 	    ptr += 3;
118 	    break;
119 	case '\\':
120 	    ptr[0] = '\\';
121 	    ptr[1] = '5';
122 	    ptr[2] = 'c';
123 	    ptr += 3;
124 	    break;
125 	case '\0':
126 	    ptr[0] = '\\';
127 	    ptr[1] = '0';
128 	    ptr[2] = '0';
129 	    ptr += 3;
130 	    break;
131 	default:
132 	    ptr[0] = in[i];
133 	    ptr += 1;
134 	    break;
135 	}
136 
137     /* ptr[count - 1] = '\0'; */
138 
139     return out;
140 }
141 
142 static int principal_in_realm_2(krb5_principal principal, char *realm) {
143     /* Cross realm trust ... */
144     if (principal->length == 2 &&
145 	principal->data[0].length == sizeof ("krbtgt") &&
146 	strncasecmp (principal->data[0].data, "krbtgt", sizeof ("krbtgt")) &&
147 	principal->data[1].length == strlen (realm) &&
148 	strncasecmp (principal->data[1].data, realm, strlen (realm)))
149 	return 0;
150 
151     if (strlen(realm) != principal->realm.length)
152 	return 1;
153 
154     if (strncasecmp(realm, principal->realm.data, principal->realm.length) != 0)
155 	return 1;
156 
157     return 0;
158 }
159 
160 /*
161  * Lists the realms in the Directory.
162  */
163 
164 krb5_error_code
165 krb5_ldap_list_realm(context, realms)
166     krb5_context	        context;
167     char                        ***realms;
168 {
169     char                        **values = NULL;
170     unsigned int                i = 0;
171     int                		count = 0;
172     krb5_error_code             st = 0, tempst = 0;
173     LDAP                        *ld = NULL;
174     LDAPMessage                 *result = NULL, *ent = NULL;
175     kdb5_dal_handle             *dal_handle = NULL;
176     krb5_ldap_context           *ldap_context = NULL;
177     krb5_ldap_server_handle     *ldap_server_handle = NULL;
178 
179     SETUP_CONTEXT ();
180 
181     /* get the kerberos container DN information */
182     if (ldap_context->krbcontainer == NULL) {
183 	if ((st = krb5_ldap_read_krbcontainer_params(context,
184 						     &(ldap_context->krbcontainer))) != 0)
185 	    goto cleanup;
186     }
187 
188     /* get ldap handle */
189     GET_HANDLE ();
190 
191     {
192 	char *cn[] = {"cn", NULL};
193 	LDAP_SEARCH(ldap_context->krbcontainer->DN,
194 		    LDAP_SCOPE_ONELEVEL,
195 		    "(objectclass=krbRealmContainer)",
196 		    cn);
197     }
198 
199     *realms = NULL;
200 
201     count = ldap_count_entries (ld, result);
202     if (count == -1) {
203 	ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &st);
204 	st = set_ldap_error (context, st, OP_SEARCH);
205 	goto cleanup;
206     }
207 
208     *realms = calloc(count+1, sizeof (char *));
209     CHECK_NULL(*realms);
210 
211     for (ent = ldap_first_entry(ld, result), count = 0; ent != NULL;
212 	 ent = ldap_next_entry(ld, ent)) {
213 
214 	if ((values = ldap_get_values (ld, ent, "cn")) != NULL) {
215 
216 	    (*realms)[count] = strdup(values[0]);
217 	    CHECK_NULL((*realms)[count]);
218 	    count += 1;
219 
220 	    ldap_value_free(values);
221 	}
222     } /* for (ent= ... */
223     ldap_msgfree(result);
224 
225 cleanup:
226 
227     /* some error, free up all the memory */
228     if (st != 0) {
229 	if (*realms) {
230 	    for (i=0; (*realms)[i] != NULL; ++i) {
231 		free ((*realms)[i]);
232 	    }
233 	    free (*realms);
234 	    *realms = NULL;
235 	}
236     }
237 
238     /* If there are no elements, still return a NULL terminated array */
239 
240     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
241     return st;
242 }
243 
244 /*
245  * Delete the realm along with the principals belonging to the realm in the Directory.
246  */
247 
248 static void
249 delete_password_policy (krb5_pointer ptr, osa_policy_ent_t pol)
250 {
251     krb5_ldap_delete_password_policy ((krb5_context)ptr, pol->name);
252 }
253 
254 krb5_error_code
255 krb5_ldap_delete_realm (context, lrealm)
256     krb5_context                context;
257     char                        *lrealm;
258 {
259     LDAP                        *ld = NULL;
260     krb5_error_code             st = 0, tempst=0;
261     char                        **values=NULL, **subtrees=NULL, **policy=NULL;
262     LDAPMessage                 **result_arr=NULL, *result = NULL, *ent = NULL;
263     krb5_principal              principal;
264     int                         l=0, i=0, j=0, mask=0;
265     unsigned int		ntree=0;
266     kdb5_dal_handle             *dal_handle = NULL;
267     krb5_ldap_context           *ldap_context = NULL;
268     krb5_ldap_server_handle     *ldap_server_handle = NULL;
269     krb5_ldap_realm_params      *rparam=NULL;
270 
271     SETUP_CONTEXT ();
272 
273     if (lrealm == NULL) {
274 	st = EINVAL;
275 	krb5_set_error_message (context, st, gettext("Realm information not available"));
276 	goto cleanup;
277     }
278 
279     if ((st=krb5_ldap_read_realm_params(context, lrealm, &rparam, &mask)) != 0)
280 	goto cleanup;
281 
282     /* get ldap handle */
283     GET_HANDLE ();
284 
285     /* delete all the principals belonging to the realm in the tree */
286     {
287 	char *attr[] = {"krbprincipalname", NULL}, *realm=NULL, filter[256];
288 	krb5_ldap_context lcontext;
289 
290 	realm = ldap_filter_correct (lrealm);
291 	assert (sizeof (filter) >= sizeof ("(krbprincipalname=)") +
292 		strlen (realm) + 2 /* "*@" */ + 1);
293 
294 	/*LINTED*/
295 	sprintf (filter, "(krbprincipalname=*@%s)", realm);
296 	free (realm);
297 
298 	/* LDAP_SEARCH(NULL, LDAP_SCOPE_SUBTREE, filter, attr); */
299 	memset(&lcontext, 0, sizeof(krb5_ldap_context));
300 	lcontext.lrparams = rparam;
301 	if ((st=krb5_get_subtree_info(&lcontext, &subtrees, &ntree)) != 0)
302 	    goto cleanup;
303 
304         result_arr = (LDAPMessage **)  calloc(ntree+1, sizeof(LDAPMessage *));
305         if (result_arr == NULL) {
306             st = ENOMEM;
307             goto cleanup;
308         }
309 
310 	for (l=0; l < ntree; ++l) {
311 	    LDAP_SEARCH(subtrees[l], rparam->search_scope, filter, attr);
312 	    result_arr[l] = result;
313 	}
314     }
315 
316     /* NOTE: Here all the principals should be cached and the ldap handle should be freed,
317      * as a DAL-LDAP interface is called right down here. Caching might be constrained by
318      * availability of the memory. The caching is not done, however there would be limit
319      * on the minimum number of handles for a server and it is 2. As the DAL-LDAP is not
320      * thread-safe this should suffice.
321      */
322     for (j=0; (result=result_arr[j]) != NULL; ++j) {
323 	for (ent = ldap_first_entry (ld, result); ent != NULL;
324 	     ent = ldap_next_entry (ld, ent)) {
325 	    if ((values = ldap_get_values(ld, ent, "krbPrincipalName")) != NULL) {
326 		for (i = 0; values[i] != NULL; ++i) {
327 		    krb5_parse_name(context, values[i], &principal);
328 		    if (principal_in_realm_2(principal, lrealm) == 0) {
329 			int nent = 0;
330 			if ((st=krb5_ldap_delete_principal(context, principal,
331 							   &nent)) != LDAP_SUCCESS)
332 			    goto cleanup;
333 		    }
334 		    krb5_free_principal(context, principal);
335 		}
336 		ldap_value_free(values);
337 	    }
338 	}
339 	ldap_msgfree(result);
340     }
341 
342     /* Delete all password policies */
343     krb5_ldap_iterate_password_policy (context, "*", delete_password_policy, context);
344 
345     /* Delete all ticket policies */
346     {
347 	if ((st = krb5_ldap_list_policy (context, ldap_context->lrparams->realmdn, &policy)) != 0) {
348 	    prepend_err_str (context, gettext("Error reading ticket policy: "), st, st);
349 	    goto cleanup;
350 	}
351 
352 	for (i = 0; policy [i] != NULL; i++)
353 	    krb5_ldap_delete_policy(context, policy[i]);
354     }
355 
356     /* Delete the realm object */
357     if ((st=ldap_delete_ext_s(ld, ldap_context->lrparams->realmdn, NULL, NULL)) != LDAP_SUCCESS) {
358 	int ost = st;
359 	st = translate_ldap_error (st, OP_DEL);
360 	krb5_set_error_message (context, st, gettext("Realm Delete FAILED: %s"),
361 				ldap_err2string(ost));
362     }
363 
364 cleanup:
365     if (subtrees) {
366 	for (l=0; l < ntree; ++l) {
367 	if (subtrees[l])
368 	    free (subtrees[l]);
369         }
370 	free (subtrees);
371     }
372 
373     if (policy != NULL) {
374 	for (i = 0; policy[i] != NULL; i++)
375 	    free (policy[i]);
376 	free (policy);
377     }
378 
379     krb5_ldap_free_realm_params(rparam);
380     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
381     return st;
382 }
383 
384 
385 /*
386  * Modify the realm attributes in the Directory.
387  */
388 
389 krb5_error_code
390 krb5_ldap_modify_realm(context, rparams, mask)
391     krb5_context             context;
392     krb5_ldap_realm_params   *rparams;
393     int                      mask;
394 {
395     LDAP                  *ld=NULL;
396     krb5_error_code       st=0;
397     char                  **strval=NULL, *strvalprc[5]={NULL};
398 #ifdef HAVE_EDIRECTORY
399     char                  **values=NULL;
400     char                  **oldkdcservers=NULL, **oldadminservers=NULL, **oldpasswdservers=NULL;
401     LDAPMessage           *result=NULL, *ent=NULL;
402     int                   count=0;
403     char errbuf[1024];
404 #endif
405     LDAPMod               **mods = NULL;
406 #ifdef HAVE_EDIRECTORY
407     int                   i=0;
408 #endif
409     /* Solaris kerberos: oldmask isn't used */
410     /* int                   oldmask=0, objectmask=0,k=0; */
411     int                   objectmask=0,k=0;
412     kdb5_dal_handle       *dal_handle=NULL;
413     krb5_ldap_context     *ldap_context=NULL;
414     krb5_ldap_server_handle *ldap_server_handle=NULL;
415 
416     if (mask == 0)
417 	return 0;
418 
419     if (rparams == NULL) {
420 	st = EINVAL;
421 	return st;
422     }
423 
424     SETUP_CONTEXT ();
425 
426     /* Check validity of arguments */
427     if (ldap_context->krbcontainer == NULL ||
428 	rparams->tl_data == NULL ||
429 	rparams->tl_data->tl_data_contents == NULL ||
430 	((mask & LDAP_REALM_SUBTREE) && rparams->subtree == NULL) ||
431 	((mask & LDAP_REALM_CONTREF) && rparams->containerref == NULL) ||
432 #ifdef HAVE_EDIRECTORY
433 	((mask & LDAP_REALM_KDCSERVERS) && rparams->kdcservers == NULL) ||
434 	((mask & LDAP_REALM_ADMINSERVERS) && rparams->adminservers == NULL) ||
435 	((mask & LDAP_REALM_PASSWDSERVERS) && rparams->passwdservers == NULL) ||
436 #endif
437 	0) {
438 	st = EINVAL;
439 	goto cleanup;
440     }
441 
442     /* get ldap handle */
443     GET_HANDLE ();
444     /* Solaris kerberos: oldmask isn't used */
445 #if 0 /************** Begin IFDEF'ed OUT *******************************/
446     /* get the oldmask obtained from the krb5_ldap_read_realm_params */
447     {
448 	void *voidptr=NULL;
449 
450 	if ((st=decode_tl_data(rparams->tl_data, KDB_TL_MASK, &voidptr)) == 0) {
451 	    oldmask = *((int *) voidptr);
452 	    free (voidptr);
453 	} else {
454 	    st = EINVAL;
455 	    krb5_set_error_message (context, st, gettext("'tl_data' not available"));
456 	    goto cleanup;
457 	}
458     }
459 #endif /**************** END IFDEF'ed OUT *******************************/
460 
461 
462     /* SUBTREE ATTRIBUTE */
463     if (mask & LDAP_REALM_SUBTREE) {
464         if ( rparams->subtree!=NULL)  {
465             /*replace the subtrees with the present if the subtrees are present*/
466             for(k=0;k<rparams->subtreecount && rparams->subtree[k]!=NULL;k++) {
467                     if (strlen(rparams->subtree[k]) != 0) {
468                         st = checkattributevalue(ld, rparams->subtree[k], "Objectclass", subtreeclass,
469                                 &objectmask);
470                         CHECK_CLASS_VALIDITY(st, objectmask, "subtree value: ");
471                     }
472             }
473 	    strval = rparams->subtree;
474 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbsubtrees", LDAP_MOD_REPLACE,
475 					    strval)) != 0) {
476 	       goto cleanup;
477 	    }
478         }
479     }
480 
481     /* CONTAINERREF ATTRIBUTE */
482     if (mask & LDAP_REALM_CONTREF) {
483         if (strlen(rparams->containerref) != 0 ) {
484             st = checkattributevalue(ld, rparams->containerref, "Objectclass", subtreeclass,
485                      &objectmask);
486             CHECK_CLASS_VALIDITY(st, objectmask, "container reference value: ");
487             strvalprc[0] = rparams->containerref;
488             strvalprc[1] = NULL;
489             if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbPrincContainerRef", LDAP_MOD_REPLACE,
490                             strvalprc)) != 0)
491                 goto cleanup;
492         }
493     }
494 
495     /* SEARCHSCOPE ATTRIBUTE */
496     if (mask & LDAP_REALM_SEARCHSCOPE) {
497 	if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbsearchscope", LDAP_MOD_REPLACE,
498 					  (rparams->search_scope == LDAP_SCOPE_ONELEVEL
499 					   || rparams->search_scope == LDAP_SCOPE_SUBTREE) ?
500 					  rparams->search_scope : LDAP_SCOPE_SUBTREE)) != 0)
501 	    goto cleanup;
502     }
503 
504     if (mask & LDAP_REALM_MAXRENEWLIFE) {
505 
506 	if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxRenewableAge", LDAP_MOD_REPLACE,
507 					  rparams->max_renewable_life)) != 0)
508 	    goto cleanup;
509     }
510 
511     /* krbMaxTicketLife ATTRIBUTE */
512 
513     if (mask & LDAP_REALM_MAXTICKETLIFE) {
514 
515 	if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxTicketLife", LDAP_MOD_REPLACE,
516 					  rparams->max_life)) != 0)
517 	    goto cleanup;
518     }
519 
520     /* krbTicketFlags ATTRIBUTE */
521 
522     if (mask & LDAP_REALM_KRBTICKETFLAGS) {
523 
524 	if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbTicketFlags", LDAP_MOD_REPLACE,
525 					  rparams->tktflags)) != 0)
526 	    goto cleanup;
527     }
528 
529 
530 #ifdef HAVE_EDIRECTORY
531 
532     /* KDCSERVERS ATTRIBUTE */
533     if (mask & LDAP_REALM_KDCSERVERS) {
534 	/* validate the server list */
535 	for (i=0; rparams->kdcservers[i] != NULL; ++i) {
536 	    st = checkattributevalue(ld, rparams->kdcservers[i], "objectClass", kdcclass,
537 				     &objectmask);
538 	    CHECK_CLASS_VALIDITY(st, objectmask, "kdc service object value: ");
539 	}
540 
541 	if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbkdcservers", LDAP_MOD_REPLACE,
542 					  rparams->kdcservers)) != 0)
543 	    goto cleanup;
544     }
545 
546     /* ADMINSERVERS ATTRIBUTE */
547     if (mask & LDAP_REALM_ADMINSERVERS) {
548 	/* validate the server list */
549 	for (i=0; rparams->adminservers[i] != NULL; ++i) {
550 	    st = checkattributevalue(ld, rparams->adminservers[i], "objectClass", adminclass,
551 				     &objectmask);
552 	    CHECK_CLASS_VALIDITY(st, objectmask, "admin service object value: ");
553 	}
554 
555 	if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbadmservers", LDAP_MOD_REPLACE,
556 					  rparams->adminservers)) != 0)
557 	    goto cleanup;
558     }
559 
560     /* PASSWDSERVERS ATTRIBUTE */
561     if (mask & LDAP_REALM_PASSWDSERVERS) {
562 	/* validate the server list */
563 	for (i=0; rparams->passwdservers[i] != NULL; ++i) {
564 	    st = checkattributevalue(ld, rparams->passwdservers[i], "objectClass", pwdclass,
565 				     &objectmask);
566 	    CHECK_CLASS_VALIDITY(st, objectmask, "password service object value: ");
567 	}
568 
569 	if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdservers", LDAP_MOD_REPLACE,
570 					  rparams->passwdservers)) != 0)
571 	    goto cleanup;
572     }
573 
574     /*
575      * Read the old values of the krbkdcservers, krbadmservers and
576      * krbpwdservers.  This information is later used to decided the
577      * deletions/additions to the list.
578      */
579     if (mask & LDAP_REALM_KDCSERVERS || mask & LDAP_REALM_ADMINSERVERS ||
580 	mask & LDAP_REALM_PASSWDSERVERS) {
581 	char *servers[] = {"krbKdcServers", "krbAdmServers", "krbPwdServers", NULL};
582 
583 	if ((st= ldap_search_ext_s(ld,
584 				   rparams->realmdn,
585 				   LDAP_SCOPE_BASE,
586 				   0,
587 				   servers,
588 				   0,
589 				   NULL,
590 				   NULL,
591 				   NULL,
592 				   0,
593 				   &result)) != LDAP_SUCCESS) {
594 	    st = set_ldap_error (context, st, OP_SEARCH);
595 	    goto cleanup;
596 	}
597 
598 	ent = ldap_first_entry(ld, result);
599 	if (ent) {
600 	    if ((values=ldap_get_values(ld, ent, "krbKdcServers")) != NULL) {
601 		count = ldap_count_values(values);
602 		if ((st=copy_arrays(values, &oldkdcservers, count)) != 0)
603 		    goto cleanup;
604 		ldap_value_free(values);
605 	    }
606 
607 	    if ((values=ldap_get_values(ld, ent, "krbAdmServers")) != NULL) {
608 		count = ldap_count_values(values);
609 		if ((st=copy_arrays(values, &oldadminservers, count)) != 0)
610 		    goto cleanup;
611 		ldap_value_free(values);
612 	    }
613 
614 	    if ((values=ldap_get_values(ld, ent, "krbPwdServers")) != NULL) {
615 		count = ldap_count_values(values);
616 		if ((st=copy_arrays(values, &oldpasswdservers, count)) != 0)
617 		    goto cleanup;
618 		ldap_value_free(values);
619 	    }
620 	}
621 	ldap_msgfree(result);
622     }
623 #endif
624 
625     /* Realm modify opearation */
626     if (mods != NULL) {
627         if ((st=ldap_modify_ext_s(ld, rparams->realmdn, mods, NULL, NULL)) != LDAP_SUCCESS) {
628 	    st = set_ldap_error (context, st, OP_MOD);
629 	    goto cleanup;
630         }
631     }
632 
633 #ifdef HAVE_EDIRECTORY
634     /* krbRealmReferences attribute is updated here, depending on the additions/deletions
635      * to the 4 servers' list.
636      */
637     if (mask & LDAP_REALM_KDCSERVERS) {
638 	char **newkdcservers=NULL;
639 
640 	count = ldap_count_values(rparams->kdcservers);
641 	if ((st=copy_arrays(rparams->kdcservers, &newkdcservers, count)) != 0)
642 	    goto cleanup;
643 
644 	/* find the deletions and additions to the server list */
645 	if (oldkdcservers && newkdcservers)
646 	    disjoint_members(oldkdcservers, newkdcservers);
647 
648 	/* delete the krbRealmReferences attribute from the servers that are dis-associated. */
649 	if (oldkdcservers)
650 	    for (i=0; oldkdcservers[i]; ++i)
651 		if ((st=deleteAttribute(ld, oldkdcservers[i], "krbRealmReferences",
652 					rparams->realmdn)) != 0) {
653 		    snprintf (errbuf, sizeof(errbuf), gettext("Error removing 'krbRealmReferences' from %s: "),
654 			     oldkdcservers[i]);
655 		    prepend_err_str (context, errbuf, st, st);
656 		    goto cleanup;
657 		}
658 
659 	/* add the krbRealmReferences attribute from the servers that are associated. */
660 	if (newkdcservers)
661 	    for (i=0; newkdcservers[i]; ++i)
662 		if ((st=updateAttribute(ld, newkdcservers[i], "krbRealmReferences",
663 					rparams->realmdn)) != 0) {
664 		    snprintf (errbuf, sizeof(errbuf), gettext("Error adding 'krbRealmReferences' to %s: "),
665 			     newkdcservers[i]);
666 		    prepend_err_str (context, errbuf, st, st);
667 		    goto cleanup;
668 		}
669 
670 	if (newkdcservers)
671 	    ldap_value_free(newkdcservers);
672     }
673 
674     if (mask & LDAP_REALM_ADMINSERVERS) {
675 	char **newadminservers=NULL;
676 
677 	count = ldap_count_values(rparams->adminservers);
678 	if ((st=copy_arrays(rparams->adminservers, &newadminservers, count)) != 0)
679 	    goto cleanup;
680 
681 	/* find the deletions and additions to the server list */
682 	if (oldadminservers && newadminservers)
683 	    disjoint_members(oldadminservers, newadminservers);
684 
685 	/* delete the krbRealmReferences attribute from the servers that are dis-associated. */
686 	if (oldadminservers)
687 	    for (i=0; oldadminservers[i]; ++i)
688 		if ((st=deleteAttribute(ld, oldadminservers[i], "krbRealmReferences",
689 					rparams->realmdn)) != 0) {
690 		    snprintf(errbuf, sizeof(errbuf), gettext("Error removing 'krbRealmReferences' from "
691 			    "%s: "), oldadminservers[i]);
692 		    prepend_err_str (context, errbuf, st, st);
693 		    goto cleanup;
694 		}
695 
696 	/* add the krbRealmReferences attribute from the servers that are associated. */
697 	if (newadminservers)
698 	    for (i=0; newadminservers[i]; ++i)
699 		if ((st=updateAttribute(ld, newadminservers[i], "krbRealmReferences",
700 					rparams->realmdn)) != 0) {
701 		    snprintf(errbuf, sizeof(errbuf), gettext("Error adding 'krbRealmReferences' to %s: "),
702 			    newadminservers[i]);
703 		    prepend_err_str (context, errbuf, st, st);
704 		    goto cleanup;
705 		}
706 	if (newadminservers)
707 	    ldap_value_free(newadminservers);
708     }
709 
710     if (mask & LDAP_REALM_PASSWDSERVERS) {
711 	char **newpasswdservers=NULL;
712 
713 	count = ldap_count_values(rparams->passwdservers);
714 	if ((st=copy_arrays(rparams->passwdservers, &newpasswdservers, count)) != 0)
715 	    goto cleanup;
716 
717 	/* find the deletions and additions to the server list */
718 	if (oldpasswdservers && newpasswdservers)
719 	    disjoint_members(oldpasswdservers, newpasswdservers);
720 
721 	/* delete the krbRealmReferences attribute from the servers that are dis-associated. */
722 	if (oldpasswdservers)
723 	    for (i=0; oldpasswdservers[i]; ++i)
724 		if ((st=deleteAttribute(ld, oldpasswdservers[i], "krbRealmReferences",
725 					rparams->realmdn)) != 0) {
726 		    snprintf(errbuf, sizeof(errbuf), gettext("Error removing 'krbRealmReferences' from "
727 			    "%s: "), oldpasswdservers[i]);
728 		    prepend_err_str (context, errbuf, st, st);
729 		    goto cleanup;
730 		}
731 
732 	/* add the krbRealmReferences attribute from the servers that are associated. */
733 	if (newpasswdservers)
734 	    for (i=0; newpasswdservers[i]; ++i)
735 		if ((st=updateAttribute(ld, newpasswdservers[i], "krbRealmReferences",
736 					rparams->realmdn)) != 0) {
737 		    snprintf(errbuf, sizeof(errbuf), gettext("Error adding 'krbRealmReferences' to %s: "),
738 			    newpasswdservers[i]);
739 		    prepend_err_str (context, errbuf, st, st);
740 		    goto cleanup;
741 		}
742 	if (newpasswdservers)
743 	    ldap_value_free(newpasswdservers);
744     }
745 #endif
746 
747 cleanup:
748 
749 #ifdef HAVE_EDIRECTORY
750     if (oldkdcservers) {
751 	for (i=0; oldkdcservers[i]; ++i)
752 	    free(oldkdcservers[i]);
753 	free(oldkdcservers);
754     }
755 
756     if (oldadminservers) {
757 	for (i=0; oldadminservers[i]; ++i)
758 	    free(oldadminservers[i]);
759 	free(oldadminservers);
760     }
761 
762     if (oldpasswdservers) {
763 	for (i=0; oldpasswdservers[i]; ++i)
764 	    free(oldpasswdservers[i]);
765 	free(oldpasswdservers);
766     }
767 #endif
768 
769     ldap_mods_free(mods, 1);
770     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
771     return st;
772 }
773 
774 
775 
776 /*
777  * Create the Kerberos container in the Directory
778  */
779 
780 krb5_error_code
781 krb5_ldap_create_krbcontainer(context, krbcontparams)
782     krb5_context                          context;
783     const krb5_ldap_krbcontainer_params   *krbcontparams;
784 {
785     LDAP                        *ld=NULL;
786     char                        *strval[2]={NULL}, *kerberoscontdn=NULL, **rdns=NULL;
787     int                         pmask=0;
788     LDAPMod                     **mods = NULL;
789     krb5_error_code             st=0;
790     kdb5_dal_handle             *dal_handle=NULL;
791     krb5_ldap_context           *ldap_context=NULL;
792     krb5_ldap_server_handle     *ldap_server_handle=NULL;
793 #ifdef HAVE_EDIRECTORY
794     int                         crmask=0;
795 #endif
796 
797     SETUP_CONTEXT ();
798 
799     /* get ldap handle */
800     GET_HANDLE ();
801 
802     if (krbcontparams != NULL && krbcontparams->DN != NULL) {
803 	kerberoscontdn = krbcontparams->DN;
804     } else {
805 	/* If the user has not given, use the default cn=Kerberos,cn=Security */
806 #ifdef HAVE_EDIRECTORY
807 	kerberoscontdn = KERBEROS_CONTAINER;
808 #else
809 	st = EINVAL;
810 	krb5_set_error_message (context, st, gettext("Kerberos Container information is missing"));
811 	goto cleanup;
812 #endif
813     }
814 
815     strval[0] = "krbContainer";
816     strval[1] = NULL;
817     if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
818 	goto cleanup;
819 
820     rdns = ldap_explode_dn(kerberoscontdn, 1);
821     if (rdns == NULL) {
822 	st = EINVAL;
823 	krb5_set_error_message(context, st, gettext("Invalid Kerberos container DN"));
824 	goto cleanup;
825     }
826 
827     strval[0] = rdns[0];
828     strval[1] = NULL;
829     if ((st=krb5_add_str_mem_ldap_mod(&mods, "cn", LDAP_MOD_ADD, strval)) != 0)
830 	goto cleanup;
831 
832     /* check if the policy reference value exists and is of krbticketpolicyreference object class */
833     if (krbcontparams && krbcontparams->policyreference) {
834 	st = checkattributevalue(ld, krbcontparams->policyreference, "objectclass", policyclass,
835 				 &pmask);
836 	CHECK_CLASS_VALIDITY(st, pmask, "ticket policy object value: ");
837 
838 	strval[0] = krbcontparams->policyreference;
839 	strval[1] = NULL;
840 	if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_ADD,
841 					  strval)) != 0)
842 	    goto cleanup;
843     }
844 
845     /* create the kerberos container */
846     if ((st = ldap_add_ext_s(ld, kerberoscontdn, mods, NULL, NULL)) != LDAP_SUCCESS) {
847 	int ost = st;
848 	st = translate_ldap_error (st, OP_ADD);
849 	krb5_set_error_message (context, st, gettext("Kerberos Container create FAILED: %s"), ldap_err2string(ost));
850 	goto cleanup;
851     }
852 
853 #ifdef HAVE_EDIRECTORY
854 
855     /* free the mods array */
856     ldap_mods_free(mods, 1);
857     mods=NULL;
858 
859     /* check whether the security container is bound to krbcontainerrefaux object class */
860     if ((st=checkattributevalue(ld, SECURITY_CONTAINER, "objectClass",
861 				krbContainerRefclass, &crmask)) != 0) {
862 	prepend_err_str (context, gettext("Security Container read FAILED: "), st, st);
863 	/* delete Kerberos Container, status ignored intentionally */
864 	ldap_delete_ext_s(ld, kerberoscontdn, NULL, NULL);
865 	goto cleanup;
866     }
867 
868     if (crmask == 0) {
869 	/* Security Container is extended with krbcontainerrefaux object class */
870 	strval[0] = "krbContainerRefAux";
871 	if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
872 	    goto cleanup;
873     }
874 
875     strval[0] = kerberoscontdn;
876     strval[1] = NULL;
877     if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbcontainerreference", LDAP_MOD_ADD, strval)) != 0)
878 	goto cleanup;
879 
880     /* update the security container with krbContainerReference attribute */
881     if ((st=ldap_modify_ext_s(ld, SECURITY_CONTAINER, mods, NULL, NULL)) != LDAP_SUCCESS) {
882 	int ost = st;
883 	st = translate_ldap_error (st, OP_MOD);
884 	krb5_set_error_message (context, st, gettext("Security Container update FAILED: %s"), ldap_err2string(ost));
885 	/* delete Kerberos Container, status ignored intentionally */
886 	ldap_delete_ext_s(ld, kerberoscontdn, NULL, NULL);
887 	goto cleanup;
888     }
889 #endif
890 
891 cleanup:
892 
893     if (rdns)
894 	ldap_value_free (rdns);
895 
896     ldap_mods_free(mods, 1);
897     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
898     return(st);
899 }
900 
901 /*
902  * Delete the Kerberos container in the Directory
903  */
904 
905 krb5_error_code
906 krb5_ldap_delete_krbcontainer(krb5_context context,
907     const krb5_ldap_krbcontainer_params *krbcontparams)
908 {
909     LDAP                        *ld=NULL;
910     char                        *kerberoscontdn=NULL;
911     krb5_error_code             st=0;
912     kdb5_dal_handle             *dal_handle=NULL;
913     krb5_ldap_context           *ldap_context=NULL;
914     krb5_ldap_server_handle     *ldap_server_handle=NULL;
915 
916     SETUP_CONTEXT ();
917 
918     /* get ldap handle */
919     GET_HANDLE ();
920 
921     if (krbcontparams != NULL && krbcontparams->DN != NULL) {
922 	kerberoscontdn = krbcontparams->DN;
923     } else {
924 	/* If the user has not given, use the default cn=Kerberos,cn=Security */
925 #ifdef HAVE_EDIRECTORY
926 	kerberoscontdn = KERBEROS_CONTAINER;
927 #else
928 	st = EINVAL;
929 	krb5_set_error_message (context, st, gettext("Kerberos Container information is missing"));
930 	goto cleanup;
931 #endif
932     }
933 
934     /* delete the kerberos container */
935     if ((st = ldap_delete_ext_s(ld, kerberoscontdn, NULL, NULL)) != LDAP_SUCCESS) {
936 	int ost = st;
937 	st = translate_ldap_error (st, OP_ADD);
938 	krb5_set_error_message (context, st, gettext("Kerberos Container delete FAILED: %s"), ldap_err2string(ost));
939 	goto cleanup;
940     }
941 
942 cleanup:
943 
944     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
945     return(st);
946 }
947 
948 
949 /*
950  * Create Realm in eDirectory. This is used by kdb5_util
951  */
952 
953 krb5_error_code
954 krb5_ldap_create_realm(context, rparams, mask)
955     krb5_context                context;
956     krb5_ldap_realm_params      *rparams;
957     int                         mask;
958 {
959     LDAP                        *ld=NULL;
960     krb5_error_code             st=0;
961     char                        *dn=NULL;
962     char                        *strval[4]={NULL};
963     char		        *contref[2]={NULL};
964     LDAPMod                     **mods = NULL;
965     int                         i=0, objectmask=0, subtreecount=0;
966     kdb5_dal_handle             *dal_handle=NULL;
967     krb5_ldap_context           *ldap_context=NULL;
968     krb5_ldap_server_handle     *ldap_server_handle=NULL;
969 #ifdef HAVE_EDIRECTORY
970     char errbuf[1024];
971 #endif
972     char                        *realm_name;
973 
974     SETUP_CONTEXT ();
975 
976     /* Check input validity ... */
977     if (ldap_context->krbcontainer == NULL ||
978 	ldap_context->krbcontainer->DN == NULL ||
979 	rparams == NULL ||
980 	rparams->realm_name == NULL ||
981 	((mask & LDAP_REALM_SUBTREE) && rparams->subtree  == NULL) ||
982 	((mask & LDAP_REALM_CONTREF) && rparams->containerref == NULL) ||
983 	((mask & LDAP_REALM_POLICYREFERENCE) && rparams->policyreference == NULL) ||
984 #ifdef HAVE_EDIRECTORY
985 	((mask & LDAP_REALM_KDCSERVERS) && rparams->kdcservers == NULL) ||
986 	((mask & LDAP_REALM_ADMINSERVERS) && rparams->adminservers == NULL) ||
987 	((mask & LDAP_REALM_PASSWDSERVERS) && rparams->passwdservers == NULL) ||
988 #endif
989 	0) {
990 	st = EINVAL;
991 	return st;
992     }
993 
994     if (ldap_context->krbcontainer == NULL) {
995 	if ((st = krb5_ldap_read_krbcontainer_params(context,
996 						     &(ldap_context->krbcontainer))) != 0)
997 	    goto cleanup;
998     }
999 
1000     /* get ldap handle */
1001     GET_HANDLE ();
1002 
1003     realm_name = rparams->realm_name;
1004 
1005     dn = malloc(strlen("cn=") + strlen(realm_name) + strlen(ldap_context->krbcontainer->DN) + 2);
1006     CHECK_NULL(dn);
1007     /*LINTED*/
1008     sprintf(dn, "cn=%s,%s", realm_name, ldap_context->krbcontainer->DN);
1009 
1010     strval[0] = realm_name;
1011     strval[1] = NULL;
1012     if ((st=krb5_add_str_mem_ldap_mod(&mods, "cn", LDAP_MOD_ADD, strval)) != 0)
1013 	goto cleanup;
1014 
1015     strval[0] = "top";
1016     strval[1] = "krbrealmcontainer";
1017     strval[2] = "krbticketpolicyaux";
1018     strval[3] = NULL;
1019 
1020     if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
1021 	goto cleanup;
1022 
1023     /* SUBTREE ATTRIBUTE */
1024     if (mask & LDAP_REALM_SUBTREE) {
1025         if ( rparams->subtree!=NULL)  {
1026               subtreecount = rparams->subtreecount;
1027 	      for (i=0; rparams->subtree[i]!=NULL && i<subtreecount; i++) {
1028 	          if (strlen(rparams->subtree[i]) != 0) {
1029                       st = checkattributevalue(ld, rparams->subtree[i], "Objectclass", subtreeclass,
1030                              &objectmask);
1031                       CHECK_CLASS_VALIDITY(st, objectmask, "realm object value: ");
1032 		  }
1033 	      }
1034 	      if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbsubtrees", LDAP_MOD_ADD,
1035                               rparams->subtree)) != 0) {
1036 	         goto cleanup;
1037 	      }
1038 	}
1039     }
1040 
1041     /* CONTAINER REFERENCE ATTRIBUTE */
1042     if (mask & LDAP_REALM_CONTREF) {
1043         if (strlen(rparams->containerref) != 0 ) {
1044             st = checkattributevalue(ld, rparams->containerref, "Objectclass", subtreeclass,
1045                              &objectmask);
1046             CHECK_CLASS_VALIDITY(st, objectmask, "realm object value: ");
1047             contref[0] = rparams->containerref;
1048             contref[1] = NULL;
1049             if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbPrincContainerRef", LDAP_MOD_ADD,
1050                                               contref)) != 0)
1051                 goto cleanup;
1052         }
1053     }
1054 
1055     /* SEARCHSCOPE ATTRIBUTE */
1056     if (mask & LDAP_REALM_SEARCHSCOPE) {
1057 	if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbsearchscope", LDAP_MOD_ADD,
1058 					  (rparams->search_scope == LDAP_SCOPE_ONELEVEL
1059 					   || rparams->search_scope == LDAP_SCOPE_SUBTREE) ?
1060 					  rparams->search_scope : LDAP_SCOPE_SUBTREE)) != 0)
1061 	    goto cleanup;
1062     }
1063     if (mask & LDAP_REALM_MAXRENEWLIFE) {
1064 
1065 	if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxRenewableAge", LDAP_MOD_ADD,
1066 					  rparams->max_renewable_life)) != 0)
1067 	    goto cleanup;
1068     }
1069 
1070     /* krbMaxTicketLife ATTRIBUTE */
1071 
1072     if (mask & LDAP_REALM_MAXTICKETLIFE) {
1073 
1074 	if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxTicketLife", LDAP_MOD_ADD,
1075 					  rparams->max_life)) != 0)
1076 	    goto cleanup;
1077     }
1078 
1079     /* krbTicketFlags ATTRIBUTE */
1080 
1081     if (mask & LDAP_REALM_KRBTICKETFLAGS) {
1082 
1083 	if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbTicketFlags", LDAP_MOD_ADD,
1084 					  rparams->tktflags)) != 0)
1085 	    goto cleanup;
1086     }
1087 
1088 
1089 #ifdef HAVE_EDIRECTORY
1090 
1091     /* KDCSERVERS ATTRIBUTE */
1092     if (mask & LDAP_REALM_KDCSERVERS) {
1093 	/* validate the server list */
1094 	for (i=0; rparams->kdcservers[i] != NULL; ++i) {
1095 	    st = checkattributevalue(ld, rparams->kdcservers[i], "objectClass", kdcclass,
1096 				     &objectmask);
1097 	    CHECK_CLASS_VALIDITY(st, objectmask, "kdc service object value: ");
1098 
1099 	}
1100 
1101 	if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbkdcservers", LDAP_MOD_ADD,
1102 					  rparams->kdcservers)) != 0)
1103 	    goto cleanup;
1104     }
1105 
1106     /* ADMINSERVERS ATTRIBUTE */
1107     if (mask & LDAP_REALM_ADMINSERVERS) {
1108 	/* validate the server list */
1109 	for (i=0; rparams->adminservers[i] != NULL; ++i) {
1110 	    st = checkattributevalue(ld, rparams->adminservers[i], "objectClass", adminclass,
1111 				     &objectmask);
1112 	    CHECK_CLASS_VALIDITY(st, objectmask, "admin service object value: ");
1113 
1114 	}
1115 
1116 	if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbadmservers", LDAP_MOD_ADD,
1117 					  rparams->adminservers)) != 0)
1118 	    goto cleanup;
1119     }
1120 
1121     /* PASSWDSERVERS ATTRIBUTE */
1122     if (mask & LDAP_REALM_PASSWDSERVERS) {
1123 	/* validate the server list */
1124 	for (i=0; rparams->passwdservers[i] != NULL; ++i) {
1125 	    st = checkattributevalue(ld, rparams->passwdservers[i], "objectClass", pwdclass,
1126 				     &objectmask);
1127 	    CHECK_CLASS_VALIDITY(st, objectmask, "password service object value: ");
1128 
1129 	}
1130 
1131 	if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdservers", LDAP_MOD_ADD,
1132 					  rparams->passwdservers)) != 0)
1133 	    goto cleanup;
1134     }
1135 #endif
1136 
1137     /* realm creation operation */
1138     if ((st=ldap_add_ext_s(ld, dn, mods, NULL, NULL)) != LDAP_SUCCESS) {
1139 	st = set_ldap_error (context, st, OP_ADD);
1140 	goto cleanup;
1141     }
1142 
1143 #ifdef HAVE_EDIRECTORY
1144     if (mask & LDAP_REALM_KDCSERVERS)
1145 	for (i=0; rparams->kdcservers[i]; ++i)
1146 	    if ((st=updateAttribute(ld, rparams->kdcservers[i], "krbRealmReferences", dn)) != 0) {
1147 		snprintf(errbuf, sizeof(errbuf), gettext("Error adding 'krbRealmReferences' to %s: "),
1148 			rparams->kdcservers[i]);
1149 		prepend_err_str (context, errbuf, st, st);
1150 		/* delete Realm, status ignored intentionally */
1151 		ldap_delete_ext_s(ld, dn, NULL, NULL);
1152 		goto cleanup;
1153 	    }
1154 
1155     if (mask & LDAP_REALM_ADMINSERVERS)
1156 	for (i=0; rparams->adminservers[i]; ++i)
1157 	    if ((st=updateAttribute(ld, rparams->adminservers[i], "krbRealmReferences", dn)) != 0) {
1158 		snprintf(errbuf, sizeof(errbuf), gettext("Error adding 'krbRealmReferences' to %s: "),
1159 			rparams->adminservers[i]);
1160 		prepend_err_str (context, errbuf, st, st);
1161 		/* delete Realm, status ignored intentionally */
1162 		ldap_delete_ext_s(ld, dn, NULL, NULL);
1163 		goto cleanup;
1164 	    }
1165 
1166     if (mask & LDAP_REALM_PASSWDSERVERS)
1167 	for (i=0; rparams->passwdservers[i]; ++i)
1168 	    if ((st=updateAttribute(ld, rparams->passwdservers[i], "krbRealmReferences", dn)) != 0) {
1169 		snprintf(errbuf, sizeof(errbuf), gettext("Error adding 'krbRealmReferences' to %s: "),
1170 			rparams->passwdservers[i]);
1171 		prepend_err_str (context, errbuf, st, st);
1172 		/* delete Realm, status ignored intentionally */
1173 		ldap_delete_ext_s(ld, dn, NULL, NULL);
1174 		goto cleanup;
1175 	    }
1176 #endif
1177 
1178 cleanup:
1179 
1180     if (dn)
1181 	free(dn);
1182 
1183     ldap_mods_free(mods, 1);
1184     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
1185     return st;
1186 }
1187 
1188 /*
1189  * Read the realm container configuration from eDirectory for the specified realm.
1190  */
1191 
1192 krb5_error_code
1193 krb5_ldap_read_realm_params(context, lrealm, rlparamp, mask)
1194     krb5_context	context;
1195     char            *lrealm;
1196     krb5_ldap_realm_params **rlparamp;
1197     int             *mask;
1198 {
1199     char                   **values=NULL, *krbcontDN=NULL /*, *curr=NULL */;
1200 #ifdef HAVE_EDIRECTORY
1201     unsigned int           count=0;
1202 #endif
1203     krb5_error_code        st=0, tempst=0;
1204     LDAP                   *ld=NULL;
1205     LDAPMessage            *result=NULL,*ent=NULL;
1206     krb5_ldap_realm_params *rlparams=NULL;
1207     kdb5_dal_handle        *dal_handle=NULL;
1208     krb5_ldap_context      *ldap_context=NULL;
1209     krb5_ldap_server_handle *ldap_server_handle=NULL;
1210     int x=0;
1211 
1212     SETUP_CONTEXT ();
1213 
1214     /* validate the input parameter */
1215     if (lrealm == NULL ||
1216 	ldap_context->krbcontainer == NULL ||
1217 	ldap_context->krbcontainer->DN == NULL) {
1218 	st = EINVAL;
1219 	goto cleanup;
1220     }
1221 
1222     /* read kerberos container, if not read already */
1223     if (ldap_context->krbcontainer == NULL) {
1224 	if ((st = krb5_ldap_read_krbcontainer_params(context,
1225 						     &(ldap_context->krbcontainer))) != 0)
1226 	    goto cleanup;
1227     }
1228     /* get ldap handle */
1229     GET_HANDLE ();
1230 
1231     /* Initialize realm container structure */
1232     rlparams =(krb5_ldap_realm_params *) malloc(sizeof(krb5_ldap_realm_params));
1233     CHECK_NULL(rlparams);
1234     memset((char *) rlparams, 0, sizeof(krb5_ldap_realm_params));
1235 
1236     /* allocate tl_data structure to store MASK information */
1237     rlparams->tl_data = malloc (sizeof(krb5_tl_data));
1238     if (rlparams->tl_data == NULL) {
1239 	st = ENOMEM;
1240 	goto cleanup;
1241     }
1242     memset((char *) rlparams->tl_data, 0, sizeof(krb5_tl_data));
1243     rlparams->tl_data->tl_data_type = KDB_TL_USER_INFO;
1244 
1245     /* set the mask parameter to 0 */
1246     *mask = 0;
1247 
1248     /* set default values */
1249     rlparams->search_scope = LDAP_SCOPE_SUBTREE;
1250 
1251     krbcontDN = ldap_context->krbcontainer->DN;
1252 
1253     rlparams->realmdn = (char *) malloc(strlen("cn=") + strlen(lrealm) + strlen(krbcontDN) + 2);
1254     if (rlparams->realmdn == NULL) {
1255 	st = ENOMEM;
1256 	goto cleanup;
1257     }
1258     /*LINTED*/
1259     sprintf(rlparams->realmdn, "cn=%s,%s", lrealm, krbcontDN);
1260 
1261     /* populate the realm name in the structure */
1262     rlparams->realm_name = strdup(lrealm);
1263     CHECK_NULL(rlparams->realm_name);
1264 
1265     LDAP_SEARCH(rlparams->realmdn, LDAP_SCOPE_BASE, "(objectclass=krbRealmContainer)", realm_attributes);
1266 
1267     if ((st = ldap_count_entries(ld, result)) <= 0) {
1268         /* This could happen when the DN used to bind and read the realm object
1269          * does not have sufficient rights to read its attributes
1270          */
1271         st = KRB5_KDB_ACCESS_ERROR; /* return some other error ? */
1272         goto cleanup;
1273     }
1274 
1275     ent = ldap_first_entry (ld, result);
1276     if (ent == NULL) {
1277 	ldap_get_option (ld, LDAP_OPT_ERROR_NUMBER, (void *) &st);
1278 #if 0
1279 	st = translate_ldap_error(st, OP_SEARCH);
1280 #endif
1281 	goto cleanup;
1282     }
1283 
1284     /* Read the attributes */
1285     {
1286 	if ((values=ldap_get_values(ld, ent, "krbSubTrees")) != NULL) {
1287             rlparams->subtreecount = ldap_count_values(values);
1288             rlparams->subtree = (char **) malloc(sizeof(char *) * (rlparams->subtreecount + 1));
1289 	    if (rlparams->subtree == NULL) {
1290 		st = ENOMEM;
1291 		goto cleanup;
1292 	    }
1293             for (x=0; x<rlparams->subtreecount; x++) {
1294                 rlparams->subtree[x] = strdup(values[x]);
1295 	        if (rlparams->subtree[x] == NULL) {
1296 		    st = ENOMEM;
1297 		    goto cleanup;
1298 	        }
1299             }
1300             rlparams->subtree[rlparams->subtreecount] = NULL;
1301 	    *mask |= LDAP_REALM_SUBTREE;
1302 	    ldap_value_free(values);
1303 	}
1304 
1305         if((values=ldap_get_values(ld, ent, "krbPrincContainerRef")) != NULL) {
1306             rlparams->containerref = strdup(values[0]);
1307             if(rlparams->containerref == NULL) {
1308                 st = ENOMEM;
1309                 goto cleanup;
1310             }
1311             *mask |= LDAP_REALM_CONTREF;
1312             ldap_value_free(values);
1313         }
1314 
1315 	if ((values=ldap_get_values(ld, ent, "krbSearchScope")) != NULL) {
1316 	    rlparams->search_scope=atoi(values[0]);
1317 	    /* searchscope can be ONE-LEVEL or SUBTREE, else default to SUBTREE */
1318 	    if (!(rlparams->search_scope==1 || rlparams->search_scope==2))
1319 		rlparams->search_scope = LDAP_SCOPE_SUBTREE;
1320 	    *mask |= LDAP_REALM_SEARCHSCOPE;
1321 	    ldap_value_free(values);
1322 	}
1323 
1324 	if ((values=ldap_get_values(ld, ent, "krbMaxTicketLife")) != NULL) {
1325 	    rlparams->max_life = atoi(values[0]);
1326 	    *mask |= LDAP_REALM_MAXTICKETLIFE;
1327 	    ldap_value_free(values);
1328 	}
1329 
1330 	if ((values=ldap_get_values(ld, ent, "krbMaxRenewableAge")) != NULL) {
1331 	    rlparams->max_renewable_life = atoi(values[0]);
1332 	    *mask |= LDAP_REALM_MAXRENEWLIFE;
1333 	    ldap_value_free(values);
1334 	}
1335 
1336 	if ((values=ldap_get_values(ld, ent, "krbTicketFlags")) != NULL) {
1337 	    rlparams->tktflags = atoi(values[0]);
1338 	    *mask |= LDAP_REALM_KRBTICKETFLAGS;
1339 	    ldap_value_free(values);
1340 	}
1341 
1342 #ifdef HAVE_EDIRECTORY
1343 
1344 	if ((values=ldap_get_values(ld, ent, "krbKdcServers")) != NULL) {
1345 	    count = ldap_count_values(values);
1346 	    if ((st=copy_arrays(values, &(rlparams->kdcservers), (int) count)) != 0)
1347 		goto cleanup;
1348 	    *mask |= LDAP_REALM_KDCSERVERS;
1349 	    ldap_value_free(values);
1350 	}
1351 
1352 	if ((values=ldap_get_values(ld, ent, "krbAdmServers")) != NULL) {
1353 	    count = ldap_count_values(values);
1354 	    if ((st=copy_arrays(values, &(rlparams->adminservers), (int) count)) != 0)
1355 		goto cleanup;
1356 	    *mask |= LDAP_REALM_ADMINSERVERS;
1357 	    ldap_value_free(values);
1358 	}
1359 
1360 	if ((values=ldap_get_values(ld, ent, "krbPwdServers")) != NULL) {
1361 	    count = ldap_count_values(values);
1362 	    if ((st=copy_arrays(values, &(rlparams->passwdservers), (int) count)) != 0)
1363 		goto cleanup;
1364 	    *mask |= LDAP_REALM_PASSWDSERVERS;
1365 	    ldap_value_free(values);
1366 	}
1367 #endif
1368     }
1369     ldap_msgfree(result);
1370 
1371     /*
1372      * If all of maxtktlife, maxrenewlife and ticketflags are not directly
1373      * available, use the policy dn from the policy reference attribute, if
1374      * available, to fetch the missing.
1375      */
1376 
1377     if ((!(*mask & LDAP_REALM_MAXTICKETLIFE && *mask & LDAP_REALM_MAXRENEWLIFE &&
1378 	   *mask & LDAP_REALM_KRBTICKETFLAGS)) && rlparams->policyreference) {
1379 
1380 	LDAP_SEARCH_1(rlparams->policyreference, LDAP_SCOPE_BASE, NULL, policy_attributes, IGNORE_STATUS);
1381 	if (st != LDAP_SUCCESS && st != LDAP_NO_SUCH_OBJECT) {
1382 	    int ost = st;
1383 	    st = translate_ldap_error (st, OP_SEARCH);
1384 	    krb5_set_error_message (context, st, gettext("Policy object read failed: %s"), ldap_err2string(ost));
1385 	    goto cleanup;
1386 	}
1387 	ent = ldap_first_entry (ld, result);
1388 	if (ent != NULL) {
1389 	    if ((*mask & LDAP_REALM_MAXTICKETLIFE) == 0) {
1390 		if ((values=ldap_get_values(ld, ent, "krbmaxticketlife")) != NULL) {
1391 		    rlparams->max_life = atoi(values[0]);
1392 		    *mask |= LDAP_REALM_MAXTICKETLIFE;
1393 		    ldap_value_free(values);
1394 		}
1395 	    }
1396 
1397 	    if ((*mask & LDAP_REALM_MAXRENEWLIFE) == 0) {
1398 		if ((values=ldap_get_values(ld, ent, "krbmaxrenewableage")) != NULL) {
1399 		    rlparams->max_renewable_life = atoi(values[0]);
1400 		    *mask |= LDAP_REALM_MAXRENEWLIFE;
1401 		    ldap_value_free(values);
1402 		}
1403 	    }
1404 
1405 	    if ((*mask & LDAP_REALM_KRBTICKETFLAGS) == 0) {
1406 		if ((values=ldap_get_values(ld, ent, "krbticketflags")) != NULL) {
1407 		    rlparams->tktflags = atoi(values[0]);
1408 		    *mask |= LDAP_REALM_KRBTICKETFLAGS;
1409 		    ldap_value_free(values);
1410 		}
1411 	    }
1412 	}
1413 	ldap_msgfree(result);
1414     }
1415 
1416     rlparams->mask = *mask;
1417     *rlparamp = rlparams;
1418     st = store_tl_data(rlparams->tl_data, KDB_TL_MASK, mask);
1419 
1420 cleanup:
1421 
1422     /* if there is an error, free allocated structures */
1423     if (st != 0) {
1424 	krb5_ldap_free_realm_params(rlparams);
1425 	*rlparamp=NULL;
1426     }
1427     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
1428     return st;
1429 }
1430 
1431 
1432 /*
1433   Free the krb5_ldap_realm_params.
1434 */
1435 void
1436 krb5_ldap_free_realm_params(rparams)
1437     krb5_ldap_realm_params *rparams;
1438 {
1439     int i=0;
1440 
1441     if (rparams) {
1442 	if (rparams->realmdn)
1443 	    free(rparams->realmdn);
1444 
1445 	if (rparams->realm_name)
1446 	    krb5_xfree(rparams->realm_name);
1447 
1448 	if (rparams->subtree) {
1449 	    for (i=0; i<rparams->subtreecount && rparams->subtree[i] ; i++)
1450 	        krb5_xfree(rparams->subtree[i]);
1451 	    krb5_xfree(rparams->subtree);
1452         }
1453 
1454 	if (rparams->kdcservers) {
1455 	    for (i=0; rparams->kdcservers[i]; ++i)
1456 		krb5_xfree(rparams->kdcservers[i]);
1457 	    krb5_xfree(rparams->kdcservers);
1458 	}
1459 
1460 	if (rparams->adminservers) {
1461 	    for (i=0; rparams->adminservers[i]; ++i)
1462 		krb5_xfree(rparams->adminservers[i]);
1463 	    krb5_xfree(rparams->adminservers);
1464 	}
1465 
1466 	if (rparams->passwdservers) {
1467 	    for (i=0; rparams->passwdservers[i]; ++i)
1468 		krb5_xfree(rparams->passwdservers[i]);
1469 	    krb5_xfree(rparams->passwdservers);
1470 	}
1471 
1472 	if (rparams->tl_data) {
1473 	    if (rparams->tl_data->tl_data_contents)
1474 		krb5_xfree(rparams->tl_data->tl_data_contents);
1475 	    krb5_xfree(rparams->tl_data);
1476 	}
1477 
1478 	if (rparams->mkey.contents) {
1479 	    memset(rparams->mkey.contents, 0, rparams->mkey.length);
1480 	    krb5_xfree(rparams->mkey.contents);
1481 	}
1482 
1483 	krb5_xfree(rparams);
1484     }
1485     return;
1486 }
1487 
1488 /*
1489  * ******************************************************************************
1490  * DAL functions
1491  * ******************************************************************************
1492  */
1493 
1494 krb5_error_code
1495 krb5_ldap_delete_realm_1(krb5_context kcontext, char *conf_section, char **db_args)
1496 {
1497     krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
1498     krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
1499     return status;
1500 }
1501