1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* plugins/kdb/ldap/libkdb_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 2006 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 
42 #define END_OF_LIST -1
43 char  *realm_attributes[] = {"krbSearchScope","krbSubTrees", "krbPrincContainerRef",
44                              "krbMaxTicketLife", "krbMaxRenewableAge",
45                              "krbTicketFlags", "krbUpEnabled",
46                              "krbLdapServers",
47                              "krbKdcServers",  "krbAdmServers",
48                              "krbPwdServers", NULL};
49 
50 
51 char  *policy_attributes[] = { "krbMaxTicketLife",
52                                "krbMaxRenewableAge",
53                                "krbTicketFlags",
54                                NULL };
55 
56 
57 
58 char  *policyclass[] =     { "krbTicketPolicy", NULL };
59 char  *kdcclass[] =        { "krbKdcService", NULL };
60 char  *adminclass[] =      { "krbAdmService", NULL };
61 char  *pwdclass[] =        { "krbPwdService", NULL };
62 char  *subtreeclass[] =    { "Organization", "OrganizationalUnit", "Domain", "krbContainer",
63                              "krbRealmContainer", "Country", "Locality", NULL };
64 
65 
66 char  *krbContainerRefclass[] = { "krbContainerRefAux", NULL};
67 
68 /*
69  * list realms from eDirectory
70  */
71 
72 /* Return a copy of in, quoting all characters which are special in an LDAP
73  * filter (RFC 4515) or DN string (RFC 4514).  Return NULL on failure. */
74 char *
ldap_filter_correct(char * in)75 ldap_filter_correct (char *in)
76 {
77     size_t count;
78     const char special[] = "*()\\ #\"+,;<>";
79     struct k5buf buf;
80 
81     k5_buf_init_dynamic(&buf);
82     while (TRUE) {
83         count = strcspn(in, special);
84         k5_buf_add_len(&buf, in, count);
85         in += count;
86         if (*in == '\0')
87             break;
88         k5_buf_add_fmt(&buf, "\\%2x", (unsigned char)*in++);
89     }
90     return buf.data;
91 }
92 
93 static int
principal_in_realm_2(krb5_principal principal,char * realm)94 principal_in_realm_2(krb5_principal principal, char *realm) {
95     /* Cross realm trust ... */
96     if (principal->length == 2 &&
97         principal->data[0].length == sizeof ("krbtgt") &&
98         strncasecmp (principal->data[0].data, "krbtgt", sizeof ("krbtgt")) &&
99         principal->data[1].length == strlen (realm) &&
100         strncasecmp (principal->data[1].data, realm, strlen (realm)))
101         return 0;
102 
103     if (strlen(realm) != principal->realm.length)
104         return 1;
105 
106     if (strncasecmp(realm, principal->realm.data, principal->realm.length) != 0)
107         return 1;
108 
109     return 0;
110 }
111 
112 /*
113  * Lists the realms in the Directory.
114  */
115 
116 krb5_error_code
krb5_ldap_list_realm(krb5_context context,char *** realms)117 krb5_ldap_list_realm(krb5_context context, char ***realms)
118 {
119     char                        **values = NULL;
120     unsigned int                i = 0;
121     int                         count = 0;
122     krb5_error_code             st = 0, tempst = 0;
123     LDAP                        *ld = NULL;
124     LDAPMessage                 *result = NULL, *ent = NULL;
125     kdb5_dal_handle             *dal_handle = NULL;
126     krb5_ldap_context           *ldap_context = NULL;
127     krb5_ldap_server_handle     *ldap_server_handle = NULL;
128 
129     SETUP_CONTEXT ();
130 
131     /* get the kerberos container DN information */
132     if (ldap_context->container_dn == NULL) {
133         if ((st = krb5_ldap_read_krbcontainer_dn(context,
134                                                  &(ldap_context->container_dn))) != 0)
135             goto cleanup;
136     }
137 
138     /* get ldap handle */
139     GET_HANDLE ();
140 
141     {
142         char *cn[] = {"cn", NULL};
143         LDAP_SEARCH(ldap_context->container_dn,
144                     LDAP_SCOPE_ONELEVEL,
145                     "(objectclass=krbRealmContainer)",
146                     cn);
147     }
148 
149     *realms = NULL;
150 
151     count = ldap_count_entries (ld, result);
152     if (count == -1) {
153         ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &st);
154         st = set_ldap_error (context, st, OP_SEARCH);
155         goto cleanup;
156     }
157 
158     *realms = calloc((unsigned int) count+1, sizeof (char *));
159     CHECK_NULL(*realms);
160 
161     for (ent = ldap_first_entry(ld, result), count = 0; ent != NULL;
162          ent = ldap_next_entry(ld, ent)) {
163 
164         if ((values = ldap_get_values (ld, ent, "cn")) != NULL) {
165 
166             (*realms)[count] = strdup(values[0]);
167             CHECK_NULL((*realms)[count]);
168             count += 1;
169 
170             ldap_value_free(values);
171         }
172     } /* for (ent= ... */
173 
174 cleanup:
175 
176     /* some error, free up all the memory */
177     if (st != 0) {
178         if (*realms) {
179             for (i=0; (*realms)[i] != NULL; ++i) {
180                 free ((*realms)[i]);
181             }
182             free (*realms);
183             *realms = NULL;
184         }
185     }
186 
187     /* If there are no elements, still return a NULL terminated array */
188 
189     ldap_msgfree(result);
190     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
191     return st;
192 }
193 
194 /*
195  * Delete the realm along with the principals belonging to the realm in the Directory.
196  */
197 
198 static void
delete_password_policy(krb5_pointer ptr,osa_policy_ent_t pol)199 delete_password_policy (krb5_pointer ptr, osa_policy_ent_t pol)
200 {
201     krb5_ldap_delete_password_policy ((krb5_context)ptr, pol->name);
202 }
203 
204 krb5_error_code
krb5_ldap_delete_realm(krb5_context context,char * lrealm)205 krb5_ldap_delete_realm (krb5_context context, char *lrealm)
206 {
207     LDAP                        *ld = NULL;
208     krb5_error_code             st = 0, tempst=0;
209     char                        **values=NULL, **subtrees=NULL, **policy=NULL;
210     LDAPMessage                 **result_arr=NULL, *result = NULL, *ent = NULL;
211     krb5_principal              principal;
212     unsigned int                l=0, ntree=0;
213     int                         i=0, j=0, mask=0;
214     kdb5_dal_handle             *dal_handle = NULL;
215     krb5_ldap_context           *ldap_context = NULL;
216     krb5_ldap_server_handle     *ldap_server_handle = NULL;
217     krb5_ldap_realm_params      *rparam=NULL;
218 
219     SETUP_CONTEXT ();
220 
221     if (lrealm == NULL) {
222         st = EINVAL;
223         k5_setmsg(context, st, _("Realm information not available"));
224         goto cleanup;
225     }
226 
227     if ((st=krb5_ldap_read_realm_params(context, lrealm, &rparam, &mask)) != 0)
228         goto cleanup;
229 
230     /* get ldap handle */
231     GET_HANDLE ();
232 
233     /* delete all the principals belonging to the realm in the tree */
234     {
235         char *attr[] = {"krbprincipalname", NULL}, *realm=NULL, filter[256];
236         krb5_ldap_context lcontext;
237 
238         realm = ldap_filter_correct (lrealm);
239         assert (sizeof (filter) >= sizeof ("(krbprincipalname=)") +
240                 strlen (realm) + 2 /* "*@" */ + 1);
241 
242         snprintf (filter, sizeof(filter), "(krbprincipalname=*@%s)", realm);
243         free (realm);
244 
245         /* LDAP_SEARCH(NULL, LDAP_SCOPE_SUBTREE, filter, attr); */
246         memset(&lcontext, 0, sizeof(krb5_ldap_context));
247         lcontext.lrparams = rparam;
248         if ((st=krb5_get_subtree_info(&lcontext, &subtrees, &ntree)) != 0)
249             goto cleanup;
250 
251         result_arr = (LDAPMessage **)  calloc((unsigned int)ntree+1,
252                                               sizeof(LDAPMessage *));
253         if (result_arr == NULL) {
254             st = ENOMEM;
255             goto cleanup;
256         }
257 
258         for (l=0; l < ntree; ++l) {
259             LDAP_SEARCH(subtrees[l], rparam->search_scope, filter, attr);
260             result_arr[l] = result;
261         }
262     }
263 
264     /* NOTE: Here all the principals should be cached and the ldap handle should be freed,
265      * as a DAL-LDAP interface is called right down here. Caching might be constrained by
266      * availability of the memory. The caching is not done, however there would be limit
267      * on the minimum number of handles for a server and it is 2. As the DAL-LDAP is not
268      * thread-safe this should suffice.
269      */
270     for (j=0; (result=result_arr[j]) != NULL; ++j) {
271         for (ent = ldap_first_entry (ld, result); ent != NULL;
272              ent = ldap_next_entry (ld, ent)) {
273             if ((values = ldap_get_values(ld, ent, "krbPrincipalName")) != NULL) {
274                 for (i = 0; values[i] != NULL; ++i) {
275                     krb5_parse_name(context, values[i], &principal);
276                     if (principal_in_realm_2(principal, lrealm) == 0) {
277                         st=krb5_ldap_delete_principal(context, principal);
278                         if (st && st != KRB5_KDB_NOENTRY)
279                             goto cleanup;
280                     }
281                     krb5_free_principal(context, principal);
282                 }
283                 ldap_value_free(values);
284             }
285         }
286     }
287 
288     /* Delete all password policies */
289     krb5_ldap_iterate_password_policy (context, "*", delete_password_policy, context);
290 
291     /* Delete all ticket policies */
292     {
293         if ((st = krb5_ldap_list_policy (context, ldap_context->lrparams->realmdn, &policy)) != 0) {
294             k5_prependmsg(context, st, _("Error reading ticket policy"));
295             goto cleanup;
296         }
297 
298         for (i = 0; policy [i] != NULL; i++)
299             krb5_ldap_delete_policy(context, policy[i]);
300     }
301 
302     /* Delete the realm object */
303     if ((st=ldap_delete_ext_s(ld, ldap_context->lrparams->realmdn, NULL, NULL)) != LDAP_SUCCESS) {
304         int ost = st;
305         st = translate_ldap_error (st, OP_DEL);
306         k5_setmsg(context, st, _("Realm Delete FAILED: %s"),
307                   ldap_err2string(ost));
308     }
309 
310 cleanup:
311     if (subtrees) {
312         for (l=0; l < ntree; ++l) {
313             if (subtrees[l])
314                 free (subtrees[l]);
315         }
316         free (subtrees);
317     }
318 
319     if (result_arr != NULL) {
320         for (l = 0; l < ntree; l++)
321             ldap_msgfree(result_arr[l]);
322         free(result_arr);
323     }
324 
325     if (policy != NULL) {
326         for (i = 0; policy[i] != NULL; i++)
327             free (policy[i]);
328         free (policy);
329     }
330 
331     krb5_ldap_free_realm_params(rparam);
332     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
333     return st;
334 }
335 
336 
337 /*
338  * Modify the realm attributes in the Directory.
339  */
340 
341 krb5_error_code
krb5_ldap_modify_realm(krb5_context context,krb5_ldap_realm_params * rparams,int mask)342 krb5_ldap_modify_realm(krb5_context context, krb5_ldap_realm_params *rparams,
343                        int mask)
344 {
345     LDAP                  *ld=NULL;
346     krb5_error_code       st=0;
347     char                  **strval=NULL, *strvalprc[5]={NULL};
348     LDAPMod               **mods = NULL;
349     int                   objectmask=0,k=0;
350     kdb5_dal_handle       *dal_handle=NULL;
351     krb5_ldap_context     *ldap_context=NULL;
352     krb5_ldap_server_handle *ldap_server_handle=NULL;
353 
354     if (mask == 0)
355         return 0;
356 
357     if (rparams == NULL) {
358         st = EINVAL;
359         return st;
360     }
361 
362     SETUP_CONTEXT ();
363 
364     /* Check validity of arguments */
365     if (ldap_context->container_dn == NULL ||
366         rparams->tl_data == NULL ||
367         rparams->tl_data->tl_data_contents == NULL ||
368         ((mask & LDAP_REALM_SUBTREE) && rparams->subtree == NULL) ||
369         ((mask & LDAP_REALM_CONTREF) && rparams->containerref == NULL) ||
370         0) {
371         st = EINVAL;
372         goto cleanup;
373     }
374 
375     /* get ldap handle */
376     GET_HANDLE ();
377 
378     /* SUBTREE ATTRIBUTE */
379     if (mask & LDAP_REALM_SUBTREE) {
380         if ( rparams->subtree!=NULL)  {
381             /*replace the subtrees with the present if the subtrees are present*/
382             for(k=0;k<rparams->subtreecount && rparams->subtree[k]!=NULL;k++) {
383                 if (strlen(rparams->subtree[k]) != 0) {
384                     st = checkattributevalue(ld, rparams->subtree[k], "Objectclass", subtreeclass,
385                                              &objectmask);
386                     CHECK_CLASS_VALIDITY(st, objectmask, _("subtree value: "));
387                 }
388             }
389             strval = rparams->subtree;
390             if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbsubtrees", LDAP_MOD_REPLACE,
391                                               strval)) != 0) {
392                 goto cleanup;
393             }
394         }
395     }
396 
397     /* CONTAINERREF ATTRIBUTE */
398     if (mask & LDAP_REALM_CONTREF) {
399         if (strlen(rparams->containerref) != 0 ) {
400             st = checkattributevalue(ld, rparams->containerref, "Objectclass", subtreeclass,
401                                      &objectmask);
402             CHECK_CLASS_VALIDITY(st, objectmask,
403                                  _("container reference value: "));
404             strvalprc[0] = rparams->containerref;
405             strvalprc[1] = NULL;
406             if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbPrincContainerRef", LDAP_MOD_REPLACE,
407                                               strvalprc)) != 0)
408                 goto cleanup;
409         }
410     }
411 
412     /* SEARCHSCOPE ATTRIBUTE */
413     if (mask & LDAP_REALM_SEARCHSCOPE) {
414         if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbsearchscope", LDAP_MOD_REPLACE,
415                                           (rparams->search_scope == LDAP_SCOPE_ONELEVEL
416                                            || rparams->search_scope == LDAP_SCOPE_SUBTREE) ?
417                                           rparams->search_scope : LDAP_SCOPE_SUBTREE)) != 0)
418             goto cleanup;
419     }
420 
421     if (mask & LDAP_REALM_MAXRENEWLIFE) {
422 
423         if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxRenewableAge", LDAP_MOD_REPLACE,
424                                           rparams->max_renewable_life)) != 0)
425             goto cleanup;
426     }
427 
428     /* krbMaxTicketLife ATTRIBUTE */
429 
430     if (mask & LDAP_REALM_MAXTICKETLIFE) {
431 
432         if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxTicketLife", LDAP_MOD_REPLACE,
433                                           rparams->max_life)) != 0)
434             goto cleanup;
435     }
436 
437     /* krbTicketFlags ATTRIBUTE */
438 
439     if (mask & LDAP_REALM_KRBTICKETFLAGS) {
440 
441         if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbTicketFlags", LDAP_MOD_REPLACE,
442                                           rparams->tktflags)) != 0)
443             goto cleanup;
444     }
445 
446 
447     /* Realm modify opearation */
448     if (mods != NULL) {
449         if ((st=ldap_modify_ext_s(ld, rparams->realmdn, mods, NULL, NULL)) != LDAP_SUCCESS) {
450             st = set_ldap_error (context, st, OP_MOD);
451             goto cleanup;
452         }
453     }
454 
455 cleanup:
456 
457     ldap_mods_free(mods, 1);
458     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
459     return st;
460 }
461 
462 
463 
464 /*
465  * Create the Kerberos container in the Directory if it does not exist
466  */
467 
468 krb5_error_code
krb5_ldap_create_krbcontainer(krb5_context context,const char * dn)469 krb5_ldap_create_krbcontainer(krb5_context context, const char *dn)
470 {
471     LDAP                        *ld=NULL;
472     char                        *strval[2]={NULL}, **rdns=NULL;
473     LDAPMod                     **mods = NULL;
474     krb5_error_code             st=0;
475     kdb5_dal_handle             *dal_handle=NULL;
476     krb5_ldap_context           *ldap_context=NULL;
477     krb5_ldap_server_handle     *ldap_server_handle=NULL;
478 
479     SETUP_CONTEXT ();
480 
481     /* get ldap handle */
482     GET_HANDLE ();
483 
484     if (dn == NULL) {
485         st = EINVAL;
486         k5_setmsg(context, st, _("Kerberos Container information is missing"));
487         goto cleanup;
488     }
489 
490     strval[0] = "krbContainer";
491     strval[1] = NULL;
492     if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
493         goto cleanup;
494 
495     rdns = ldap_explode_dn(dn, 1);
496     if (rdns == NULL) {
497         st = EINVAL;
498         k5_setmsg(context, st, _("Invalid Kerberos container DN"));
499         goto cleanup;
500     }
501 
502     strval[0] = rdns[0];
503     strval[1] = NULL;
504     if ((st=krb5_add_str_mem_ldap_mod(&mods, "cn", LDAP_MOD_ADD, strval)) != 0)
505         goto cleanup;
506 
507     /* create the kerberos container */
508     st = ldap_add_ext_s(ld, dn, mods, NULL, NULL);
509     if (st == LDAP_ALREADY_EXISTS)
510         st = LDAP_SUCCESS;
511     if (st != LDAP_SUCCESS) {
512         int ost = st;
513         st = translate_ldap_error (st, OP_ADD);
514         k5_setmsg(context, st, _("Kerberos Container create FAILED: %s"),
515                   ldap_err2string(ost));
516         goto cleanup;
517     }
518 
519 cleanup:
520 
521     if (rdns)
522         ldap_value_free (rdns);
523 
524     ldap_mods_free(mods, 1);
525     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
526     return(st);
527 }
528 
529 /*
530  * Delete the Kerberos container in the Directory
531  */
532 
533 krb5_error_code
krb5_ldap_delete_krbcontainer(krb5_context context,const char * dn)534 krb5_ldap_delete_krbcontainer(krb5_context context, const char *dn)
535 {
536     LDAP                        *ld=NULL;
537     krb5_error_code             st=0;
538     kdb5_dal_handle             *dal_handle=NULL;
539     krb5_ldap_context           *ldap_context=NULL;
540     krb5_ldap_server_handle     *ldap_server_handle=NULL;
541 
542     SETUP_CONTEXT ();
543 
544     /* get ldap handle */
545     GET_HANDLE ();
546 
547     if (dn == NULL) {
548         st = EINVAL;
549         k5_setmsg(context, st, _("Kerberos Container information is missing"));
550         goto cleanup;
551     }
552 
553     /* delete the kerberos container */
554     if ((st = ldap_delete_ext_s(ld, dn, NULL, NULL)) != LDAP_SUCCESS) {
555         int ost = st;
556         st = translate_ldap_error (st, OP_ADD);
557         k5_setmsg(context, st, _("Kerberos Container delete FAILED: %s"),
558                   ldap_err2string(ost));
559         goto cleanup;
560     }
561 
562 cleanup:
563 
564     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
565     return(st);
566 }
567 
568 
569 /*
570  * Create Realm in eDirectory. This is used by kdb5_util
571  */
572 
573 krb5_error_code
krb5_ldap_create_realm(krb5_context context,krb5_ldap_realm_params * rparams,int mask)574 krb5_ldap_create_realm(krb5_context context, krb5_ldap_realm_params *rparams,
575                        int mask)
576 {
577     LDAP                        *ld=NULL;
578     krb5_error_code             st=0;
579     char                        *dn=NULL;
580     char                        *strval[4]={NULL};
581     char                        *contref[2]={NULL};
582     LDAPMod                     **mods = NULL;
583     int                         i=0, objectmask=0, subtreecount=0;
584     kdb5_dal_handle             *dal_handle=NULL;
585     krb5_ldap_context           *ldap_context=NULL;
586     krb5_ldap_server_handle     *ldap_server_handle=NULL;
587     char                        *realm_name;
588 
589     SETUP_CONTEXT ();
590 
591     /* Check input validity ... */
592     if (ldap_context->container_dn == NULL ||
593         rparams == NULL ||
594         rparams->realm_name == NULL ||
595         ((mask & LDAP_REALM_SUBTREE) && rparams->subtree  == NULL) ||
596         ((mask & LDAP_REALM_CONTREF) && rparams->containerref == NULL) ||
597         0) {
598         st = EINVAL;
599         return st;
600     }
601 
602     /* get ldap handle */
603     GET_HANDLE ();
604 
605     realm_name = rparams->realm_name;
606 
607     if (asprintf(&dn, "cn=%s,%s", realm_name, ldap_context->container_dn) < 0)
608         dn = NULL;
609     CHECK_NULL(dn);
610 
611     strval[0] = realm_name;
612     strval[1] = NULL;
613     if ((st=krb5_add_str_mem_ldap_mod(&mods, "cn", LDAP_MOD_ADD, strval)) != 0)
614         goto cleanup;
615 
616     strval[0] = "top";
617     strval[1] = "krbrealmcontainer";
618     strval[2] = "krbticketpolicyaux";
619     strval[3] = NULL;
620 
621     if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
622         goto cleanup;
623 
624     /* SUBTREE ATTRIBUTE */
625     if (mask & LDAP_REALM_SUBTREE) {
626         if ( rparams->subtree!=NULL)  {
627             subtreecount = rparams->subtreecount;
628             for (i=0; rparams->subtree[i]!=NULL && i<subtreecount; i++) {
629                 if (strlen(rparams->subtree[i]) != 0) {
630                     st = checkattributevalue(ld, rparams->subtree[i], "Objectclass", subtreeclass,
631                                              &objectmask);
632                     CHECK_CLASS_VALIDITY(st, objectmask,
633                                          _("realm object value: "));
634                 }
635             }
636             if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbsubtrees", LDAP_MOD_ADD,
637                                               rparams->subtree)) != 0) {
638                 goto cleanup;
639             }
640         }
641     }
642 
643     /* CONTAINER REFERENCE ATTRIBUTE */
644     if (mask & LDAP_REALM_CONTREF) {
645         if (strlen(rparams->containerref) != 0 ) {
646             st = checkattributevalue(ld, rparams->containerref, "Objectclass", subtreeclass,
647                                      &objectmask);
648             CHECK_CLASS_VALIDITY(st, objectmask, "realm object value: ");
649             contref[0] = rparams->containerref;
650             contref[1] = NULL;
651             if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbPrincContainerRef", LDAP_MOD_ADD,
652                                               contref)) != 0)
653                 goto cleanup;
654         }
655     }
656 
657     /* SEARCHSCOPE ATTRIBUTE */
658     if (mask & LDAP_REALM_SEARCHSCOPE) {
659         if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbsearchscope", LDAP_MOD_ADD,
660                                           (rparams->search_scope == LDAP_SCOPE_ONELEVEL
661                                            || rparams->search_scope == LDAP_SCOPE_SUBTREE) ?
662                                           rparams->search_scope : LDAP_SCOPE_SUBTREE)) != 0)
663             goto cleanup;
664     }
665     if (mask & LDAP_REALM_MAXRENEWLIFE) {
666 
667         if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxRenewableAge", LDAP_MOD_ADD,
668                                           rparams->max_renewable_life)) != 0)
669             goto cleanup;
670     }
671 
672     /* krbMaxTicketLife ATTRIBUTE */
673 
674     if (mask & LDAP_REALM_MAXTICKETLIFE) {
675 
676         if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxTicketLife", LDAP_MOD_ADD,
677                                           rparams->max_life)) != 0)
678             goto cleanup;
679     }
680 
681     /* krbTicketFlags ATTRIBUTE */
682 
683     if (mask & LDAP_REALM_KRBTICKETFLAGS) {
684 
685         if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbTicketFlags", LDAP_MOD_ADD,
686                                           rparams->tktflags)) != 0)
687             goto cleanup;
688     }
689 
690 
691     /* realm creation operation */
692     if ((st=ldap_add_ext_s(ld, dn, mods, NULL, NULL)) != LDAP_SUCCESS) {
693         st = set_ldap_error (context, st, OP_ADD);
694         goto cleanup;
695     }
696 
697 cleanup:
698 
699     if (dn)
700         free(dn);
701 
702     ldap_mods_free(mods, 1);
703     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
704     return st;
705 }
706 
707 /*
708  * Read the realm container configuration from eDirectory for the specified realm.
709  */
710 
711 krb5_error_code
krb5_ldap_read_realm_params(krb5_context context,char * lrealm,krb5_ldap_realm_params ** rlparamp,int * mask)712 krb5_ldap_read_realm_params(krb5_context context, char *lrealm,
713                             krb5_ldap_realm_params **rlparamp, int *mask)
714 {
715     char                   **values=NULL;
716     krb5_error_code        st=0, tempst=0;
717     LDAP                   *ld=NULL;
718     LDAPMessage            *result=NULL,*ent=NULL;
719     krb5_ldap_realm_params *rlparams=NULL;
720     kdb5_dal_handle        *dal_handle=NULL;
721     krb5_ldap_context      *ldap_context=NULL;
722     krb5_ldap_server_handle *ldap_server_handle=NULL;
723     int x=0;
724 
725     SETUP_CONTEXT ();
726 
727     /* validate the input parameter */
728     if (lrealm == NULL || ldap_context->container_dn == NULL) {
729         st = EINVAL;
730         goto cleanup;
731     }
732 
733     /* get ldap handle */
734     GET_HANDLE ();
735 
736     /* Initialize realm container structure */
737     rlparams =(krb5_ldap_realm_params *) malloc(sizeof(krb5_ldap_realm_params));
738     CHECK_NULL(rlparams);
739     memset(rlparams, 0, sizeof(krb5_ldap_realm_params));
740 
741     /* allocate tl_data structure to store MASK information */
742     rlparams->tl_data = malloc (sizeof(krb5_tl_data));
743     if (rlparams->tl_data == NULL) {
744         st = ENOMEM;
745         goto cleanup;
746     }
747     memset(rlparams->tl_data, 0, sizeof(krb5_tl_data));
748     rlparams->tl_data->tl_data_type = KDB_TL_USER_INFO;
749 
750     /* set the mask parameter to 0 */
751     *mask = 0;
752 
753     /* set default values */
754     rlparams->search_scope = LDAP_SCOPE_SUBTREE;
755 
756     if (asprintf(&rlparams->realmdn, "cn=%s,%s", lrealm,
757                  ldap_context->container_dn) < 0) {
758         rlparams->realmdn = NULL;
759         st = ENOMEM;
760         goto cleanup;
761     }
762 
763     /* populate the realm name in the structure */
764     rlparams->realm_name = strdup(lrealm);
765     CHECK_NULL(rlparams->realm_name);
766 
767     LDAP_SEARCH(rlparams->realmdn, LDAP_SCOPE_BASE, "(objectclass=krbRealmContainer)", realm_attributes);
768 
769     if ((st = ldap_count_entries(ld, result)) <= 0) {
770         /* This could happen when the DN used to bind and read the realm object
771          * does not have sufficient rights to read its attributes
772          */
773         st = KRB5_KDB_ACCESS_ERROR; /* return some other error ? */
774         goto cleanup;
775     }
776 
777     ent = ldap_first_entry (ld, result);
778     if (ent == NULL) {
779         ldap_get_option (ld, LDAP_OPT_ERROR_NUMBER, (void *) &st);
780         goto cleanup;
781     }
782 
783     /* Read the attributes */
784     {
785         if ((values=ldap_get_values(ld, ent, "krbSubTrees")) != NULL) {
786             rlparams->subtreecount = ldap_count_values(values);
787             rlparams->subtree = (char **) malloc(sizeof(char *) * (rlparams->subtreecount + 1));
788             if (rlparams->subtree == NULL) {
789                 st = ENOMEM;
790                 goto cleanup;
791             }
792             for (x=0; x<rlparams->subtreecount; x++) {
793                 rlparams->subtree[x] = strdup(values[x]);
794                 if (rlparams->subtree[x] == NULL) {
795                     st = ENOMEM;
796                     goto cleanup;
797                 }
798             }
799             rlparams->subtree[rlparams->subtreecount] = NULL;
800             *mask |= LDAP_REALM_SUBTREE;
801             ldap_value_free(values);
802         }
803 
804         if((values=ldap_get_values(ld, ent, "krbPrincContainerRef")) != NULL) {
805             rlparams->containerref = strdup(values[0]);
806             if(rlparams->containerref == NULL) {
807                 st = ENOMEM;
808                 goto cleanup;
809             }
810             *mask |= LDAP_REALM_CONTREF;
811             ldap_value_free(values);
812         }
813 
814         if ((values=ldap_get_values(ld, ent, "krbSearchScope")) != NULL) {
815             rlparams->search_scope=atoi(values[0]);
816             /* searchscope can be ONE-LEVEL or SUBTREE, else default to SUBTREE */
817             if (!(rlparams->search_scope==1 || rlparams->search_scope==2))
818                 rlparams->search_scope = LDAP_SCOPE_SUBTREE;
819             *mask |= LDAP_REALM_SEARCHSCOPE;
820             ldap_value_free(values);
821         }
822 
823         if ((values=ldap_get_values(ld, ent, "krbMaxTicketLife")) != NULL) {
824             rlparams->max_life = atoi(values[0]);
825             *mask |= LDAP_REALM_MAXTICKETLIFE;
826             ldap_value_free(values);
827         }
828 
829         if ((values=ldap_get_values(ld, ent, "krbMaxRenewableAge")) != NULL) {
830             rlparams->max_renewable_life = atoi(values[0]);
831             *mask |= LDAP_REALM_MAXRENEWLIFE;
832             ldap_value_free(values);
833         }
834 
835         if ((values=ldap_get_values(ld, ent, "krbTicketFlags")) != NULL) {
836             rlparams->tktflags = atoi(values[0]);
837             *mask |= LDAP_REALM_KRBTICKETFLAGS;
838             ldap_value_free(values);
839         }
840 
841     }
842 
843     rlparams->mask = *mask;
844     *rlparamp = rlparams;
845     st = store_tl_data(rlparams->tl_data, KDB_TL_MASK, mask);
846 
847 cleanup:
848 
849     /* if there is an error, free allocated structures */
850     if (st != 0) {
851         krb5_ldap_free_realm_params(rlparams);
852         *rlparamp=NULL;
853     }
854     ldap_msgfree(result);
855     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
856     return st;
857 }
858 
859 
860 /*
861   Free the krb5_ldap_realm_params.
862 */
863 void
krb5_ldap_free_realm_params(krb5_ldap_realm_params * rparams)864 krb5_ldap_free_realm_params(krb5_ldap_realm_params *rparams)
865 {
866     int i=0;
867 
868     if (rparams) {
869         if (rparams->realmdn)
870             free(rparams->realmdn);
871 
872         if (rparams->realm_name)
873             free(rparams->realm_name);
874 
875         if (rparams->subtree) {
876             for (i=0; i<rparams->subtreecount && rparams->subtree[i] ; i++)
877                 free(rparams->subtree[i]);
878             free(rparams->subtree);
879         }
880 
881         if (rparams->containerref)
882             free(rparams->containerref);
883 
884         if (rparams->kdcservers) {
885             for (i=0; rparams->kdcservers[i]; ++i)
886                 free(rparams->kdcservers[i]);
887             free(rparams->kdcservers);
888         }
889 
890         if (rparams->adminservers) {
891             for (i=0; rparams->adminservers[i]; ++i)
892                 free(rparams->adminservers[i]);
893             free(rparams->adminservers);
894         }
895 
896         if (rparams->passwdservers) {
897             for (i=0; rparams->passwdservers[i]; ++i)
898                 free(rparams->passwdservers[i]);
899             free(rparams->passwdservers);
900         }
901 
902         if (rparams->tl_data) {
903             if (rparams->tl_data->tl_data_contents)
904                 free(rparams->tl_data->tl_data_contents);
905             free(rparams->tl_data);
906         }
907 
908         free(rparams);
909     }
910     return;
911 }
912 
913 /*
914  * ******************************************************************************
915  * DAL functions
916  * ******************************************************************************
917  */
918 
919 krb5_error_code
krb5_ldap_delete_realm_1(krb5_context kcontext,char * conf_section,char ** db_args)920 krb5_ldap_delete_realm_1(krb5_context kcontext, char *conf_section,
921                          char **db_args)
922 {
923     krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
924     k5_setmsg(kcontext, status, "LDAP %s", error_message(status));
925     return status;
926 }
927