xref: /freebsd/crypto/krb5/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
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 k5_buf_cstring(&buf);
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     size_t                      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     size_t                      i=0, j=0, l=0, ntree=0;
213     int                         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 && !st; ++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 == KRB5_KDB_NOENTRY)
279                             st = 0;
280                     }
281                     krb5_free_principal(context, principal);
282                 }
283                 ldap_value_free(values);
284                 if (st)
285                     goto cleanup;
286             }
287         }
288     }
289 
290     /* Delete all password policies */
291     krb5_ldap_iterate_password_policy (context, "*", delete_password_policy, context);
292 
293     /* Delete all ticket policies */
294     {
295         if ((st = krb5_ldap_list_policy (context, ldap_context->lrparams->realmdn, &policy)) != 0) {
296             k5_prependmsg(context, st, _("Error reading ticket policy"));
297             goto cleanup;
298         }
299 
300         for (i = 0; policy [i] != NULL; i++)
301             krb5_ldap_delete_policy(context, policy[i]);
302     }
303 
304     /* Delete the realm object */
305     if ((st=ldap_delete_ext_s(ld, ldap_context->lrparams->realmdn, NULL, NULL)) != LDAP_SUCCESS) {
306         int ost = st;
307         st = translate_ldap_error (st, OP_DEL);
308         k5_setmsg(context, st, _("Realm Delete FAILED: %s"),
309                   ldap_err2string(ost));
310     }
311 
312 cleanup:
313     if (subtrees) {
314         for (l=0; l < ntree; ++l) {
315             if (subtrees[l])
316                 free (subtrees[l]);
317         }
318         free (subtrees);
319     }
320 
321     if (result_arr != NULL) {
322         for (l = 0; l < ntree; l++)
323             ldap_msgfree(result_arr[l]);
324         free(result_arr);
325     }
326 
327     if (policy != NULL) {
328         for (i = 0; policy[i] != NULL; i++)
329             free (policy[i]);
330         free (policy);
331     }
332 
333     krb5_ldap_free_realm_params(rparam);
334     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
335     return st;
336 }
337 
338 
339 /*
340  * Modify the realm attributes in the Directory.
341  */
342 
343 krb5_error_code
krb5_ldap_modify_realm(krb5_context context,krb5_ldap_realm_params * rparams,int mask)344 krb5_ldap_modify_realm(krb5_context context, krb5_ldap_realm_params *rparams,
345                        int mask)
346 {
347     LDAP                  *ld=NULL;
348     krb5_error_code       st=0;
349     char                  **strval=NULL, *strvalprc[5]={NULL};
350     LDAPMod               **mods = NULL;
351     size_t                k=0;
352     int                   objectmask=0;
353     kdb5_dal_handle       *dal_handle=NULL;
354     krb5_ldap_context     *ldap_context=NULL;
355     krb5_ldap_server_handle *ldap_server_handle=NULL;
356 
357     if (mask == 0)
358         return 0;
359 
360     if (rparams == NULL) {
361         st = EINVAL;
362         return st;
363     }
364 
365     SETUP_CONTEXT ();
366 
367     /* Check validity of arguments */
368     if (ldap_context->container_dn == NULL ||
369         rparams->tl_data == NULL ||
370         rparams->tl_data->tl_data_contents == NULL ||
371         ((mask & LDAP_REALM_SUBTREE) && rparams->subtree == NULL) ||
372         ((mask & LDAP_REALM_CONTREF) && rparams->containerref == NULL) ||
373         0) {
374         st = EINVAL;
375         goto cleanup;
376     }
377 
378     /* get ldap handle */
379     GET_HANDLE ();
380 
381     /* SUBTREE ATTRIBUTE */
382     if (mask & LDAP_REALM_SUBTREE) {
383         if ( rparams->subtree!=NULL)  {
384             /*replace the subtrees with the present if the subtrees are present*/
385             for(k=0;k<rparams->subtreecount && rparams->subtree[k]!=NULL;k++) {
386                 if (strlen(rparams->subtree[k]) != 0) {
387                     st = checkattributevalue(ld, rparams->subtree[k], "Objectclass", subtreeclass,
388                                              &objectmask);
389                     CHECK_CLASS_VALIDITY(st, objectmask, _("subtree value: "));
390                 }
391             }
392             strval = rparams->subtree;
393             if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbsubtrees", LDAP_MOD_REPLACE,
394                                               strval)) != 0) {
395                 goto cleanup;
396             }
397         }
398     }
399 
400     /* CONTAINERREF ATTRIBUTE */
401     if (mask & LDAP_REALM_CONTREF) {
402         if (strlen(rparams->containerref) != 0 ) {
403             st = checkattributevalue(ld, rparams->containerref, "Objectclass", subtreeclass,
404                                      &objectmask);
405             CHECK_CLASS_VALIDITY(st, objectmask,
406                                  _("container reference value: "));
407             strvalprc[0] = rparams->containerref;
408             strvalprc[1] = NULL;
409             if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbPrincContainerRef", LDAP_MOD_REPLACE,
410                                               strvalprc)) != 0)
411                 goto cleanup;
412         }
413     }
414 
415     /* SEARCHSCOPE ATTRIBUTE */
416     if (mask & LDAP_REALM_SEARCHSCOPE) {
417         if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbsearchscope", LDAP_MOD_REPLACE,
418                                           (rparams->search_scope == LDAP_SCOPE_ONELEVEL
419                                            || rparams->search_scope == LDAP_SCOPE_SUBTREE) ?
420                                           rparams->search_scope : LDAP_SCOPE_SUBTREE)) != 0)
421             goto cleanup;
422     }
423 
424     if (mask & LDAP_REALM_MAXRENEWLIFE) {
425 
426         if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxRenewableAge", LDAP_MOD_REPLACE,
427                                           rparams->max_renewable_life)) != 0)
428             goto cleanup;
429     }
430 
431     /* krbMaxTicketLife ATTRIBUTE */
432 
433     if (mask & LDAP_REALM_MAXTICKETLIFE) {
434 
435         if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxTicketLife", LDAP_MOD_REPLACE,
436                                           rparams->max_life)) != 0)
437             goto cleanup;
438     }
439 
440     /* krbTicketFlags ATTRIBUTE */
441 
442     if (mask & LDAP_REALM_KRBTICKETFLAGS) {
443 
444         if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbTicketFlags", LDAP_MOD_REPLACE,
445                                           rparams->tktflags)) != 0)
446             goto cleanup;
447     }
448 
449 
450     /* Realm modify operation */
451     if (mods != NULL) {
452         if ((st=ldap_modify_ext_s(ld, rparams->realmdn, mods, NULL, NULL)) != LDAP_SUCCESS) {
453             st = set_ldap_error (context, st, OP_MOD);
454             goto cleanup;
455         }
456     }
457 
458 cleanup:
459 
460     ldap_mods_free(mods, 1);
461     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
462     return st;
463 }
464 
465 
466 
467 /*
468  * Create the Kerberos container in the Directory if it does not exist
469  */
470 
471 krb5_error_code
krb5_ldap_create_krbcontainer(krb5_context context,const char * dn)472 krb5_ldap_create_krbcontainer(krb5_context context, const char *dn)
473 {
474     LDAP                        *ld=NULL;
475     char                        *strval[2]={NULL}, **rdns=NULL;
476     LDAPMod                     **mods = NULL;
477     krb5_error_code             st=0;
478     kdb5_dal_handle             *dal_handle=NULL;
479     krb5_ldap_context           *ldap_context=NULL;
480     krb5_ldap_server_handle     *ldap_server_handle=NULL;
481 
482     SETUP_CONTEXT ();
483 
484     /* get ldap handle */
485     GET_HANDLE ();
486 
487     if (dn == NULL) {
488         st = EINVAL;
489         k5_setmsg(context, st, _("Kerberos Container information is missing"));
490         goto cleanup;
491     }
492 
493     strval[0] = "krbContainer";
494     strval[1] = NULL;
495     if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
496         goto cleanup;
497 
498     rdns = ldap_explode_dn(dn, 1);
499     if (rdns == NULL) {
500         st = EINVAL;
501         k5_setmsg(context, st, _("Invalid Kerberos container DN"));
502         goto cleanup;
503     }
504 
505     strval[0] = rdns[0];
506     strval[1] = NULL;
507     if ((st=krb5_add_str_mem_ldap_mod(&mods, "cn", LDAP_MOD_ADD, strval)) != 0)
508         goto cleanup;
509 
510     /* create the kerberos container */
511     st = ldap_add_ext_s(ld, dn, mods, NULL, NULL);
512     if (st == LDAP_ALREADY_EXISTS)
513         st = LDAP_SUCCESS;
514     if (st != LDAP_SUCCESS) {
515         int ost = st;
516         st = translate_ldap_error (st, OP_ADD);
517         k5_setmsg(context, st, _("Kerberos Container create FAILED: %s"),
518                   ldap_err2string(ost));
519         goto cleanup;
520     }
521 
522 cleanup:
523 
524     if (rdns)
525         ldap_value_free (rdns);
526 
527     ldap_mods_free(mods, 1);
528     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
529     return(st);
530 }
531 
532 /*
533  * Delete the Kerberos container in the Directory
534  */
535 
536 krb5_error_code
krb5_ldap_delete_krbcontainer(krb5_context context,const char * dn)537 krb5_ldap_delete_krbcontainer(krb5_context context, const char *dn)
538 {
539     LDAP                        *ld=NULL;
540     krb5_error_code             st=0;
541     kdb5_dal_handle             *dal_handle=NULL;
542     krb5_ldap_context           *ldap_context=NULL;
543     krb5_ldap_server_handle     *ldap_server_handle=NULL;
544 
545     SETUP_CONTEXT ();
546 
547     /* get ldap handle */
548     GET_HANDLE ();
549 
550     if (dn == NULL) {
551         st = EINVAL;
552         k5_setmsg(context, st, _("Kerberos Container information is missing"));
553         goto cleanup;
554     }
555 
556     /* delete the kerberos container */
557     if ((st = ldap_delete_ext_s(ld, dn, NULL, NULL)) != LDAP_SUCCESS) {
558         int ost = st;
559         st = translate_ldap_error (st, OP_ADD);
560         k5_setmsg(context, st, _("Kerberos Container delete FAILED: %s"),
561                   ldap_err2string(ost));
562         goto cleanup;
563     }
564 
565 cleanup:
566 
567     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
568     return(st);
569 }
570 
571 
572 /*
573  * Create Realm in eDirectory. This is used by kdb5_util
574  */
575 
576 krb5_error_code
krb5_ldap_create_realm(krb5_context context,krb5_ldap_realm_params * rparams,int mask)577 krb5_ldap_create_realm(krb5_context context, krb5_ldap_realm_params *rparams,
578                        int mask)
579 {
580     LDAP                        *ld=NULL;
581     krb5_error_code             st=0;
582     char                        *dn=NULL;
583     char                        *strval[4]={NULL};
584     char                        *contref[2]={NULL};
585     LDAPMod                     **mods = NULL;
586     size_t                      i=0, subtreecount=0;
587     int                         objectmask=0;
588     kdb5_dal_handle             *dal_handle=NULL;
589     krb5_ldap_context           *ldap_context=NULL;
590     krb5_ldap_server_handle     *ldap_server_handle=NULL;
591     char                        *realm_name;
592 
593     SETUP_CONTEXT ();
594 
595     /* Check input validity ... */
596     if (ldap_context->container_dn == NULL ||
597         rparams == NULL ||
598         rparams->realm_name == NULL ||
599         ((mask & LDAP_REALM_SUBTREE) && rparams->subtree  == NULL) ||
600         ((mask & LDAP_REALM_CONTREF) && rparams->containerref == NULL) ||
601         0) {
602         st = EINVAL;
603         return st;
604     }
605 
606     /* get ldap handle */
607     GET_HANDLE ();
608 
609     realm_name = rparams->realm_name;
610 
611     if (asprintf(&dn, "cn=%s,%s", realm_name, ldap_context->container_dn) < 0)
612         dn = NULL;
613     CHECK_NULL(dn);
614 
615     strval[0] = realm_name;
616     strval[1] = NULL;
617     if ((st=krb5_add_str_mem_ldap_mod(&mods, "cn", LDAP_MOD_ADD, strval)) != 0)
618         goto cleanup;
619 
620     strval[0] = "top";
621     strval[1] = "krbrealmcontainer";
622     strval[2] = "krbticketpolicyaux";
623     strval[3] = NULL;
624 
625     if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
626         goto cleanup;
627 
628     /* SUBTREE ATTRIBUTE */
629     if (mask & LDAP_REALM_SUBTREE) {
630         if ( rparams->subtree!=NULL)  {
631             subtreecount = rparams->subtreecount;
632             for (i=0; rparams->subtree[i]!=NULL && i<subtreecount; i++) {
633                 if (strlen(rparams->subtree[i]) != 0) {
634                     st = checkattributevalue(ld, rparams->subtree[i], "Objectclass", subtreeclass,
635                                              &objectmask);
636                     CHECK_CLASS_VALIDITY(st, objectmask,
637                                          _("realm object value: "));
638                 }
639             }
640             if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbsubtrees", LDAP_MOD_ADD,
641                                               rparams->subtree)) != 0) {
642                 goto cleanup;
643             }
644         }
645     }
646 
647     /* CONTAINER REFERENCE ATTRIBUTE */
648     if (mask & LDAP_REALM_CONTREF) {
649         if (strlen(rparams->containerref) != 0 ) {
650             st = checkattributevalue(ld, rparams->containerref, "Objectclass", subtreeclass,
651                                      &objectmask);
652             CHECK_CLASS_VALIDITY(st, objectmask, "realm object value: ");
653             contref[0] = rparams->containerref;
654             contref[1] = NULL;
655             if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbPrincContainerRef", LDAP_MOD_ADD,
656                                               contref)) != 0)
657                 goto cleanup;
658         }
659     }
660 
661     /* SEARCHSCOPE ATTRIBUTE */
662     if (mask & LDAP_REALM_SEARCHSCOPE) {
663         if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbsearchscope", LDAP_MOD_ADD,
664                                           (rparams->search_scope == LDAP_SCOPE_ONELEVEL
665                                            || rparams->search_scope == LDAP_SCOPE_SUBTREE) ?
666                                           rparams->search_scope : LDAP_SCOPE_SUBTREE)) != 0)
667             goto cleanup;
668     }
669     if (mask & LDAP_REALM_MAXRENEWLIFE) {
670 
671         if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxRenewableAge", LDAP_MOD_ADD,
672                                           rparams->max_renewable_life)) != 0)
673             goto cleanup;
674     }
675 
676     /* krbMaxTicketLife ATTRIBUTE */
677 
678     if (mask & LDAP_REALM_MAXTICKETLIFE) {
679 
680         if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxTicketLife", LDAP_MOD_ADD,
681                                           rparams->max_life)) != 0)
682             goto cleanup;
683     }
684 
685     /* krbTicketFlags ATTRIBUTE */
686 
687     if (mask & LDAP_REALM_KRBTICKETFLAGS) {
688 
689         if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbTicketFlags", LDAP_MOD_ADD,
690                                           rparams->tktflags)) != 0)
691             goto cleanup;
692     }
693 
694 
695     /* realm creation operation */
696     if ((st=ldap_add_ext_s(ld, dn, mods, NULL, NULL)) != LDAP_SUCCESS) {
697         st = set_ldap_error (context, st, OP_ADD);
698         goto cleanup;
699     }
700 
701 cleanup:
702 
703     if (dn)
704         free(dn);
705 
706     ldap_mods_free(mods, 1);
707     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
708     return st;
709 }
710 
711 /*
712  * Read the realm container configuration from eDirectory for the specified realm.
713  */
714 
715 krb5_error_code
krb5_ldap_read_realm_params(krb5_context context,char * lrealm,krb5_ldap_realm_params ** rlparamp,int * mask)716 krb5_ldap_read_realm_params(krb5_context context, char *lrealm,
717                             krb5_ldap_realm_params **rlparamp, int *mask)
718 {
719     char                   **values=NULL;
720     krb5_error_code        st=0, tempst=0;
721     LDAP                   *ld=NULL;
722     LDAPMessage            *result=NULL,*ent=NULL;
723     krb5_ldap_realm_params *rlparams=NULL;
724     kdb5_dal_handle        *dal_handle=NULL;
725     krb5_ldap_context      *ldap_context=NULL;
726     krb5_ldap_server_handle *ldap_server_handle=NULL;
727     size_t x=0;
728 
729     SETUP_CONTEXT ();
730 
731     /* validate the input parameter */
732     if (lrealm == NULL || ldap_context->container_dn == NULL) {
733         st = EINVAL;
734         goto cleanup;
735     }
736 
737     /* get ldap handle */
738     GET_HANDLE ();
739 
740     /* Initialize realm container structure */
741     rlparams =(krb5_ldap_realm_params *) malloc(sizeof(krb5_ldap_realm_params));
742     CHECK_NULL(rlparams);
743     memset(rlparams, 0, sizeof(krb5_ldap_realm_params));
744 
745     /* allocate tl_data structure to store MASK information */
746     rlparams->tl_data = malloc (sizeof(krb5_tl_data));
747     if (rlparams->tl_data == NULL) {
748         st = ENOMEM;
749         goto cleanup;
750     }
751     memset(rlparams->tl_data, 0, sizeof(krb5_tl_data));
752     rlparams->tl_data->tl_data_type = KDB_TL_USER_INFO;
753 
754     /* set the mask parameter to 0 */
755     *mask = 0;
756 
757     /* set default values */
758     rlparams->search_scope = LDAP_SCOPE_SUBTREE;
759 
760     if (asprintf(&rlparams->realmdn, "cn=%s,%s", lrealm,
761                  ldap_context->container_dn) < 0) {
762         rlparams->realmdn = NULL;
763         st = ENOMEM;
764         goto cleanup;
765     }
766 
767     /* populate the realm name in the structure */
768     rlparams->realm_name = strdup(lrealm);
769     CHECK_NULL(rlparams->realm_name);
770 
771     LDAP_SEARCH(rlparams->realmdn, LDAP_SCOPE_BASE, "(objectclass=krbRealmContainer)", realm_attributes);
772 
773     if ((st = ldap_count_entries(ld, result)) <= 0) {
774         /* This could happen when the DN used to bind and read the realm object
775          * does not have sufficient rights to read its attributes
776          */
777         st = KRB5_KDB_ACCESS_ERROR; /* return some other error ? */
778         goto cleanup;
779     }
780 
781     ent = ldap_first_entry (ld, result);
782     if (ent == NULL) {
783         ldap_get_option (ld, LDAP_OPT_ERROR_NUMBER, (void *) &st);
784         goto cleanup;
785     }
786 
787     /* Read the attributes */
788     {
789         if ((values=ldap_get_values(ld, ent, "krbSubTrees")) != NULL) {
790             rlparams->subtreecount = ldap_count_values(values);
791             rlparams->subtree = (char **) malloc(sizeof(char *) * (rlparams->subtreecount + 1));
792             if (rlparams->subtree == NULL) {
793                 st = ENOMEM;
794                 goto cleanup;
795             }
796             for (x=0; x<rlparams->subtreecount; x++) {
797                 rlparams->subtree[x] = strdup(values[x]);
798                 if (rlparams->subtree[x] == NULL) {
799                     st = ENOMEM;
800                     goto cleanup;
801                 }
802             }
803             rlparams->subtree[rlparams->subtreecount] = NULL;
804             *mask |= LDAP_REALM_SUBTREE;
805             ldap_value_free(values);
806         }
807 
808         if((values=ldap_get_values(ld, ent, "krbPrincContainerRef")) != NULL) {
809             rlparams->containerref = strdup(values[0]);
810             if(rlparams->containerref == NULL) {
811                 st = ENOMEM;
812                 goto cleanup;
813             }
814             *mask |= LDAP_REALM_CONTREF;
815             ldap_value_free(values);
816         }
817 
818         if ((values=ldap_get_values(ld, ent, "krbSearchScope")) != NULL) {
819             rlparams->search_scope=atoi(values[0]);
820             /* searchscope can be ONE-LEVEL or SUBTREE, else default to SUBTREE */
821             if (!(rlparams->search_scope==1 || rlparams->search_scope==2))
822                 rlparams->search_scope = LDAP_SCOPE_SUBTREE;
823             *mask |= LDAP_REALM_SEARCHSCOPE;
824             ldap_value_free(values);
825         }
826 
827         if ((values=ldap_get_values(ld, ent, "krbMaxTicketLife")) != NULL) {
828             rlparams->max_life = atoi(values[0]);
829             *mask |= LDAP_REALM_MAXTICKETLIFE;
830             ldap_value_free(values);
831         }
832 
833         if ((values=ldap_get_values(ld, ent, "krbMaxRenewableAge")) != NULL) {
834             rlparams->max_renewable_life = atoi(values[0]);
835             *mask |= LDAP_REALM_MAXRENEWLIFE;
836             ldap_value_free(values);
837         }
838 
839         if ((values=ldap_get_values(ld, ent, "krbTicketFlags")) != NULL) {
840             rlparams->tktflags = atoi(values[0]);
841             *mask |= LDAP_REALM_KRBTICKETFLAGS;
842             ldap_value_free(values);
843         }
844 
845     }
846 
847     rlparams->mask = *mask;
848     *rlparamp = rlparams;
849     st = store_tl_data(rlparams->tl_data, KDB_TL_MASK, mask);
850 
851 cleanup:
852 
853     /* if there is an error, free allocated structures */
854     if (st != 0) {
855         krb5_ldap_free_realm_params(rlparams);
856         *rlparamp=NULL;
857     }
858     ldap_msgfree(result);
859     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
860     return st;
861 }
862 
863 
864 /*
865   Free the krb5_ldap_realm_params.
866 */
867 void
krb5_ldap_free_realm_params(krb5_ldap_realm_params * rparams)868 krb5_ldap_free_realm_params(krb5_ldap_realm_params *rparams)
869 {
870     size_t i=0;
871 
872     if (rparams) {
873         if (rparams->realmdn)
874             free(rparams->realmdn);
875 
876         if (rparams->realm_name)
877             free(rparams->realm_name);
878 
879         if (rparams->subtree) {
880             for (i=0; i<rparams->subtreecount && rparams->subtree[i] ; i++)
881                 free(rparams->subtree[i]);
882             free(rparams->subtree);
883         }
884 
885         if (rparams->containerref)
886             free(rparams->containerref);
887 
888         if (rparams->kdcservers) {
889             for (i=0; rparams->kdcservers[i]; ++i)
890                 free(rparams->kdcservers[i]);
891             free(rparams->kdcservers);
892         }
893 
894         if (rparams->adminservers) {
895             for (i=0; rparams->adminservers[i]; ++i)
896                 free(rparams->adminservers[i]);
897             free(rparams->adminservers);
898         }
899 
900         if (rparams->passwdservers) {
901             for (i=0; rparams->passwdservers[i]; ++i)
902                 free(rparams->passwdservers[i]);
903             free(rparams->passwdservers);
904         }
905 
906         if (rparams->tl_data) {
907             if (rparams->tl_data->tl_data_contents)
908                 free(rparams->tl_data->tl_data_contents);
909             free(rparams->tl_data);
910         }
911 
912         free(rparams);
913     }
914     return;
915 }
916 
917 /*
918  * ******************************************************************************
919  * DAL functions
920  * ******************************************************************************
921  */
922 
923 krb5_error_code
krb5_ldap_delete_realm_1(krb5_context kcontext,char * conf_section,char ** db_args)924 krb5_ldap_delete_realm_1(krb5_context kcontext, char *conf_section,
925                          char **db_args)
926 {
927     krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
928     k5_setmsg(kcontext, status, "LDAP %s", error_message(status));
929     return status;
930 }
931