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