Example #1
0
/*
 * If attribute or attrvalues is NULL, just check for the existence of dn.
 * Otherwise, read values for attribute from dn; then set the bit 1<<n in mask
 * for each attrvalues[n] which is present in the values read.
 */
krb5_error_code
checkattributevalue(LDAP *ld, char *dn, char *attribute, char **attrvalues,
                    int *mask)
{
    krb5_error_code ret;
    int one = 1, i, j;
    char **values = NULL, *attributes[2] = { NULL };
    LDAPMessage *result = NULL, *entry;

    if (strlen(dn) == 0)
        return set_ldap_error(0, LDAP_NO_SUCH_OBJECT, OP_SEARCH);

    attributes[0] = attribute;

    /* Read values for attribute from the dn, or check for its existence. */
    ret = ldap_search_ext_s(ld, dn, LDAP_SCOPE_BASE, 0, attributes, 0, NULL,
                            NULL, &timelimit, LDAP_NO_LIMIT, &result);
    if (ret != LDAP_SUCCESS) {
        ldap_msgfree(result);
        return set_ldap_error(0, ret, OP_SEARCH);
    }

    /* Don't touch *mask if we are only checking for existence. */
    if (attribute == NULL || attrvalues == NULL)
        goto done;

    *mask = 0;

    entry = ldap_first_entry(ld, result);
    if (entry == NULL)
        goto done;
    values = ldap_get_values(ld, entry, attribute);
    if (values == NULL)
        goto done;

    /* Set bits in mask for each matching value we read. */
    for (i = 0; attrvalues[i]; i++) {
        for (j = 0; values[j]; j++) {
            if (strcasecmp(attrvalues[i], values[j]) == 0) {
                *mask |= (one << i);
                break;
            }
        }
    }

done:
    ldap_msgfree(result);
    ldap_value_free(values);
    return 0;
}
Example #2
0
krb5_error_code
krb5_ldap_read_krbcontainer_params(krb5_context context,
                                   krb5_ldap_krbcontainer_params **cparamp)

{
    krb5_error_code                 st=0, tempst=0;
    LDAP                            *ld=NULL;
    LDAPMessage                     *result=NULL, *ent=NULL;
    krb5_ldap_krbcontainer_params   *cparams=NULL;
    kdb5_dal_handle                 *dal_handle=NULL;
    krb5_ldap_context               *ldap_context=NULL;
    krb5_ldap_server_handle         *ldap_server_handle=NULL;

    SETUP_CONTEXT();
    GET_HANDLE();

    cparams =(krb5_ldap_krbcontainer_params *) malloc(sizeof(krb5_ldap_krbcontainer_params));
    CHECK_NULL(cparams);
    memset(cparams, 0, sizeof(krb5_ldap_krbcontainer_params));

    /* read kerberos containter location from [dbmodules] section of krb5.conf file */
    if (ldap_context->conf_section) {
        if ((st=profile_get_string(context->profile, KDB_MODULE_SECTION, ldap_context->conf_section,
                                   KRB5_CONF_LDAP_KERBEROS_CONTAINER_DN, NULL,
                                   &cparams->DN)) != 0) {
            krb5_set_error_message(context, st,
                                   _("Error reading kerberos container "
                                     "location from krb5.conf"));
            goto cleanup;
        }
    }

    /* read kerberos containter location from [dbdefaults] section of krb5.conf file */
    if (cparams->DN == NULL) {
        if ((st=profile_get_string(context->profile, KDB_MODULE_DEF_SECTION,
                                   KRB5_CONF_LDAP_KERBEROS_CONTAINER_DN, NULL,
                                   NULL, &cparams->DN)) != 0) {
            krb5_set_error_message(context, st,
                                   _("Error reading kerberos container "
                                     "location from krb5.conf"));
            goto cleanup;
        }
    }

    if (cparams->DN == NULL) {
        st = KRB5_KDB_SERVER_INTERNAL_ERR;
        krb5_set_error_message(context, st,
                               _("Kerberos container location not specified"));
        goto cleanup;
    }

    /* NOTE: krbmaxtktlife, krbmaxrenewableage ... present on Kerberos Container is
     * not read
     */
    LDAP_SEARCH_1(cparams->DN, LDAP_SCOPE_BASE, "(objectclass=krbContainer)", policyrefattribute, IGNORE_STATUS);
    if (st != LDAP_SUCCESS && st != LDAP_NO_SUCH_OBJECT) {
        st = set_ldap_error(context, st, OP_SEARCH);
        goto cleanup;
    }

    if (st == LDAP_NO_SUCH_OBJECT) {
        st = KRB5_KDB_NOENTRY;
        goto cleanup;
    }

    if ((ent = ldap_first_entry(ld, result))) {
        if ((st=krb5_ldap_get_string(ld, ent, "krbticketpolicyreference",
                                     &(cparams->policyreference), NULL)) != 0)
            goto cleanup;
    }
    ldap_msgfree(result);

    if (cparams->policyreference != NULL) {
        LDAP_SEARCH_1(cparams->policyreference, LDAP_SCOPE_BASE, NULL, policy_attributes, IGNORE_STATUS);
        if (st != LDAP_SUCCESS && st!= LDAP_NO_SUCH_OBJECT) {
            st = set_ldap_error(context, st, OP_SEARCH);
            goto cleanup;
        }
        st = LDAP_SUCCESS; /* reset the return status in case it is LDAP_NO_SUCH_OBJECT */

        ent=ldap_first_entry(ld, result);
        if (ent != NULL) {
            krb5_ldap_get_value(ld, ent, "krbmaxtktlife", &(cparams->max_life));
            krb5_ldap_get_value(ld, ent, "krbmaxrenewableage", &(cparams->max_renewable_life));
            krb5_ldap_get_value(ld, ent, "krbticketflags", &(cparams->tktflags));
        }
        ldap_msgfree(result);
    }
    *cparamp=cparams;

cleanup:
    if (st != 0) {
        krb5_ldap_free_krbcontainer_params(cparams);
        *cparamp=NULL;
    }
    krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
    return st;
}
Example #3
0
/*
 * Fill out a krb5_db_entry princ entry struct given a LDAP message containing
 * the results of a principal search of the directory.
 */
krb5_error_code
populate_krb5_db_entry(krb5_context context, krb5_ldap_context *ldap_context,
                       LDAP *ld, LDAPMessage *ent, krb5_const_principal princ,
                       krb5_db_entry *entry)
{
    krb5_error_code ret;
    unsigned int mask = 0;
    int val, i, pcount, objtype;
    krb5_boolean attr_present;
    krb5_kvno mkvno = 0;
    krb5_timestamp lastpwdchange, unlock_time;
    char *policydn = NULL, *pwdpolicydn = NULL, *polname = NULL, *user = NULL;
    char *tktpolname = NULL, *dn = NULL, **link_references = NULL;
    char **pnvalues = NULL, **ocvalues = NULL, **a2d2 = NULL;
    struct berval **ber_key_data = NULL, **ber_tl_data = NULL;
    krb5_tl_data userinfo_tl_data = { NULL }, **endp, *tl;
    osa_princ_ent_rec princ_ent;

    memset(&princ_ent, 0, sizeof(princ_ent));

    ret = krb5_copy_principal(context, princ, &entry->princ);
    if (ret)
        goto cleanup;

    /* get the associated directory user information */
    pnvalues = ldap_get_values(ld, ent, "krbprincipalname");
    if (pnvalues != NULL) {
        ret = krb5_unparse_name(context, princ, &user);
        if (ret)
            goto cleanup;

        pcount = 0;
        for (i = 0; pnvalues[i] != NULL; i++) {
            if (strcasecmp(pnvalues[i], user) == 0) {
                pcount = ldap_count_values(pnvalues);
                break;
            }
        }

        dn = ldap_get_dn(ld, ent);
        if (dn == NULL) {
            ldap_get_option(ld, LDAP_OPT_RESULT_CODE, &ret);
            ret = set_ldap_error(context, ret, 0);
            goto cleanup;
        }

        ocvalues = ldap_get_values(ld, ent, "objectclass");
        if (ocvalues != NULL) {
            for (i = 0; ocvalues[i] != NULL; i++) {
                if (strcasecmp(ocvalues[i], "krbprincipal") == 0) {
                    objtype = KDB_STANDALONE_PRINCIPAL_OBJECT;
                    ret = store_tl_data(&userinfo_tl_data, KDB_TL_PRINCTYPE,
                                        &objtype);
                    if (ret)
                        goto cleanup;
                    break;
                }
            }
        }

        /* Add principalcount, DN and principaltype user information to
         * tl_data */
        ret = store_tl_data(&userinfo_tl_data, KDB_TL_PRINCCOUNT, &pcount);
        if (ret)
            goto cleanup;
        ret = store_tl_data(&userinfo_tl_data, KDB_TL_USERDN, dn);
        if (ret)
            goto cleanup;
    }

    ret = get_time(ld, ent, "krbLastSuccessfulAuth", &entry->last_success,
                   &attr_present);
    if (ret)
        goto cleanup;
    if (attr_present)
        mask |= KDB_LAST_SUCCESS_ATTR;

    ret = get_time(ld, ent, "krbLastFailedAuth", &entry->last_failed,
                   &attr_present);
    if (ret)
        goto cleanup;
    if (attr_present)
        mask |= KDB_LAST_FAILED_ATTR;

    if (krb5_ldap_get_value(ld, ent, "krbLoginFailedCount", &val) == 0) {
        entry->fail_auth_count = val;
        mask |= KDB_FAIL_AUTH_COUNT_ATTR;
    }
    if (krb5_ldap_get_value(ld, ent, "krbmaxticketlife", &val) == 0) {
        entry->max_life = val;
        mask |= KDB_MAX_LIFE_ATTR;
    }
    if (krb5_ldap_get_value(ld, ent, "krbmaxrenewableage", &val) == 0) {
        entry->max_renewable_life = val;
        mask |= KDB_MAX_RLIFE_ATTR;
    }
    if (krb5_ldap_get_value(ld, ent, "krbticketflags", &val) == 0) {
        entry->attributes = val;
        mask |= KDB_TKT_FLAGS_ATTR;
    }
    ret = get_time(ld, ent, "krbprincipalexpiration", &entry->expiration,
                   &attr_present);
    if (ret)
        goto cleanup;
    if (attr_present)
        mask |= KDB_PRINC_EXPIRE_TIME_ATTR;

    ret = get_time(ld, ent, "krbpasswordexpiration", &entry->pw_expiration,
                   &attr_present);
    if (ret)
        goto cleanup;
    if (attr_present)
        mask |= KDB_PWD_EXPIRE_TIME_ATTR;

    ret = krb5_ldap_get_string(ld, ent, "krbticketpolicyreference", &policydn,
                               &attr_present);
    if (ret)
        goto cleanup;
    if (attr_present) {
        mask |= KDB_POL_REF_ATTR;
        /* Ensure that the policy is inside the realm container. */
        ret = krb5_ldap_policydn_to_name(context, policydn, &tktpolname);
        if (ret)
            goto cleanup;
    }

    ret = krb5_ldap_get_string(ld, ent, "krbpwdpolicyreference", &pwdpolicydn,
                               &attr_present);
    if (ret)
        goto cleanup;
    if (attr_present) {
        mask |= KDB_PWD_POL_REF_ATTR;

        /* Ensure that the policy is inside the realm container. */
        ret = krb5_ldap_policydn_to_name(context, pwdpolicydn, &polname);
        if (ret)
            goto cleanup;
        princ_ent.policy = polname;
        princ_ent.aux_attributes |= KADM5_POLICY;
    }

    ber_key_data = ldap_get_values_len(ld, ent, "krbpwdhistory");
    if (ber_key_data != NULL) {
        mask |= KDB_PWD_HISTORY_ATTR;
        ret = krb5_decode_histkey(context, ber_key_data, &princ_ent);
        if (ret)
            goto cleanup;
        ldap_value_free_len(ber_key_data);
    }

    if (princ_ent.aux_attributes) {
        ret = krb5_update_tl_kadm_data(context, entry, &princ_ent);
        if (ret)
            goto cleanup;
    }

    ber_key_data = ldap_get_values_len(ld, ent, "krbprincipalkey");
    if (ber_key_data != NULL) {
        mask |= KDB_SECRET_KEY_ATTR;
        ret = krb5_decode_krbsecretkey(context, entry, ber_key_data, &mkvno);
        if (ret)
            goto cleanup;
        if (mkvno != 0) {
            ret = krb5_dbe_update_mkvno(context, entry, mkvno);
            if (ret)
                goto cleanup;
        }
    }

    ret = get_time(ld, ent, "krbLastPwdChange", &lastpwdchange, &attr_present);
    if (ret)
        goto cleanup;
    if (attr_present) {
        ret = krb5_dbe_update_last_pwd_change(context, entry, lastpwdchange);
        if (ret)
            goto cleanup;
        mask |= KDB_LAST_PWD_CHANGE_ATTR;
    }

    ret = get_time(ld, ent, "krbLastAdminUnlock", &unlock_time, &attr_present);
    if (ret)
        goto cleanup;
    if (attr_present) {
        ret = krb5_dbe_update_last_admin_unlock(context, entry, unlock_time);
        if (ret)
            goto cleanup;
        mask |= KDB_LAST_ADMIN_UNLOCK_ATTR;
    }

    a2d2 = ldap_get_values(ld, ent, "krbAllowedToDelegateTo");
    if (a2d2 != NULL) {
        for (endp = &entry->tl_data; *endp; endp = &(*endp)->tl_data_next);
        for (i = 0; a2d2[i] != NULL; i++) {
            tl = k5alloc(sizeof(*tl), &ret);
            if (tl == NULL)
                goto cleanup;
            tl->tl_data_type = KRB5_TL_CONSTRAINED_DELEGATION_ACL;
            tl->tl_data_length = strlen(a2d2[i]);
            tl->tl_data_contents = (unsigned char *)strdup(a2d2[i]);
            if (tl->tl_data_contents == NULL) {
                ret = ENOMEM;
                free(tl);
                goto cleanup;
            }
            tl->tl_data_next = NULL;
            *endp = tl;
            endp = &tl->tl_data_next;
        }
    }

    link_references = ldap_get_values(ld, ent, "krbobjectreferences");
    if (link_references != NULL) {
        for (i = 0; link_references[i] != NULL; i++) {
            ret = store_tl_data(&userinfo_tl_data, KDB_TL_LINKDN,
                                link_references[i]);
            if (ret)
                goto cleanup;
        }
    }

    ber_tl_data = ldap_get_values_len(ld, ent, "krbExtraData");
    if (ber_tl_data != NULL) {
        for (i = 0; ber_tl_data[i] != NULL; i++) {
            ret = berval2tl_data(ber_tl_data[i], &tl);
            if (ret)
                goto cleanup;
            ret = krb5_dbe_update_tl_data(context, entry, tl);
            free(tl->tl_data_contents);
            free(tl);
            if (ret)
                goto cleanup;
        }
        mask |= KDB_EXTRA_DATA_ATTR;
    }

    /* Auth indicators from krbPrincipalAuthInd will replace those from
     * krbExtraData. */
    ret = get_ldap_auth_ind(context, ld, ent, entry, &mask);
    if (ret)
        goto cleanup;

    /* Update the mask of attributes present on the directory object to the
     * tl_data. */
    ret = store_tl_data(&userinfo_tl_data, KDB_TL_MASK, &mask);
    if (ret)
        goto cleanup;
    ret = krb5_dbe_update_tl_data(context, entry, &userinfo_tl_data);
    if (ret)
        goto cleanup;

    ret = krb5_read_tkt_policy(context, ldap_context, entry, tktpolname);
    if (ret)
        goto cleanup;

    /* For compatibility with DB2 principals. */
    entry->len = KRB5_KDB_V1_BASE_LENGTH;

cleanup:
    ldap_memfree(dn);
    ldap_value_free_len(ber_key_data);
    ldap_value_free_len(ber_tl_data);
    ldap_value_free(pnvalues);
    ldap_value_free(ocvalues);
    ldap_value_free(link_references);
    ldap_value_free(a2d2);
    free(userinfo_tl_data.tl_data_contents);
    free(pwdpolicydn);
    free(polname);
    free(tktpolname);
    free(policydn);
    krb5_free_unparsed_name(context, user);
    free_princ_ent_contents(&princ_ent);
    return ret;
}
Example #4
0
krb5_error_code
krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
                        char **db_args)
{
    int                         l=0, kerberos_principal_object_type=0;
    krb5_error_code             st=0, tempst=0;
    LDAP                        *ld=NULL;
    LDAPMessage                 *result=NULL, *ent=NULL;
    char                        *user=NULL, *subtree=NULL, *principal_dn=NULL;
    char                        **values=NULL, *strval[10]= {NULL}, errbuf[1024];
    struct berval               **bersecretkey=NULL;
    LDAPMod                     **mods=NULL;
    krb5_boolean                create_standalone_prinicipal=FALSE;
    krb5_boolean                krb_identity_exists=FALSE, establish_links=FALSE;
    char                        *standalone_principal_dn=NULL;
    krb5_tl_data                *tl_data=NULL;
    krb5_key_data               **keys=NULL;
    kdb5_dal_handle             *dal_handle=NULL;
    krb5_ldap_context           *ldap_context=NULL;
    krb5_ldap_server_handle     *ldap_server_handle=NULL;
    osa_princ_ent_rec           princ_ent;
    xargs_t                     xargs = {0};
    char                        *polname = NULL;
    OPERATION optype;
    krb5_boolean                found_entry = FALSE;

    /* Clear the global error string */
    krb5_clear_error_message(context);

    SETUP_CONTEXT();
    if (ldap_context->lrparams == NULL || ldap_context->krbcontainer == NULL)
        return EINVAL;

    /* get ldap handle */
    GET_HANDLE();

    if (is_principal_in_realm(ldap_context, entry->princ) != 0) {
        st = EINVAL;
        krb5_set_error_message(context, st, _("Principal does not belong to "
                                              "the default realm"));
        goto cleanup;
    }

    /* get the principal information to act on */
    if (entry->princ) {
        if (((st=krb5_unparse_name(context, entry->princ, &user)) != 0) ||
                ((st=krb5_ldap_unparse_principal_name(user)) != 0))
            goto cleanup;
    }

    /* Identity the type of operation, it can be
     * add principal or modify principal.
     * hack if the entry->mask has KRB_PRINCIPAL flag set
     * then it is a add operation
     */
    if (entry->mask & KADM5_PRINCIPAL)
        optype = ADD_PRINCIPAL;
    else
        optype = MODIFY_PRINCIPAL;

    if (((st=krb5_get_princ_type(context, entry, &kerberos_principal_object_type)) != 0) ||
            ((st=krb5_get_userdn(context, entry, &principal_dn)) != 0))
        goto cleanup;

    if ((st=process_db_args(context, db_args, &xargs, optype)) != 0)
        goto cleanup;

    if (entry->mask & KADM5_LOAD) {
        int              tree = 0, ntrees = 0, princlen = 0, numlentries = 0;
        char             **subtreelist = NULL, *filter = NULL;

        /*  A load operation is special, will do a mix-in (add krbprinc
         *  attrs to a non-krb object entry) if an object exists with a
         *  matching krbprincipalname attribute so try to find existing
         *  object and set principal_dn.  This assumes that the
         *  krbprincipalname attribute is unique (only one object entry has
         *  a particular krbprincipalname attribute).
         */
        if (user == NULL) {
            /* must have principal name for search */
            st = EINVAL;
            krb5_set_error_message(context, st,
                                   _("operation can not continue, principal "
                                     "name not found"));
            goto cleanup;
        }
        princlen = strlen(FILTER) + strlen(user) + 2 + 1;      /* 2 for closing brackets */
        if ((filter = malloc(princlen)) == NULL) {
            st = ENOMEM;
            goto cleanup;
        }
        snprintf(filter, princlen, FILTER"%s))", user);

        /* get the current subtree list */
        if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
            goto cleanup;

        found_entry = FALSE;
        /* search for entry with matching krbprincipalname attribute */
        for (tree = 0; found_entry == FALSE && tree < ntrees; ++tree) {
            result = NULL;
            if (principal_dn == NULL) {
                LDAP_SEARCH_1(subtreelist[tree], ldap_context->lrparams->search_scope, filter, principal_attributes, IGNORE_STATUS);
            } else {
                /* just look for entry with principal_dn */
                LDAP_SEARCH_1(principal_dn, LDAP_SCOPE_BASE, filter, principal_attributes, IGNORE_STATUS);
            }
            if (st == LDAP_SUCCESS) {
                numlentries = ldap_count_entries(ld, result);
                if (numlentries > 1) {
                    ldap_msgfree(result);
                    free(filter);
                    st = EINVAL;
                    krb5_set_error_message(context, st,
                                           _("operation can not continue, "
                                             "more than one entry with "
                                             "principal name \"%s\" found"),
                                           user);
                    goto cleanup;
                } else if (numlentries == 1) {
                    found_entry = TRUE;
                    if (principal_dn == NULL) {
                        ent = ldap_first_entry(ld, result);
                        if (ent != NULL) {
                            /* setting principal_dn will cause that entry to be modified further down */
                            if ((principal_dn = ldap_get_dn(ld, ent)) == NULL) {
                                ldap_get_option (ld, LDAP_OPT_RESULT_CODE, &st);
                                st = set_ldap_error (context, st, 0);
                                ldap_msgfree(result);
                                free(filter);
                                goto cleanup;
                            }
                        }
                    }
                }
                if (result)
                    ldap_msgfree(result);
            } else if (st != LDAP_NO_SUCH_OBJECT) {
                /* could not perform search, return with failure */
                st = set_ldap_error (context, st, 0);
                free(filter);
                goto cleanup;
            }
            /*
             * If it isn't found then assume a standalone princ entry is to
             * be created.
             */
        } /* end for (tree = 0; principal_dn == ... */

        free(filter);

        if (found_entry == FALSE && principal_dn != NULL) {
            /*
             * if principal_dn is null then there is code further down to
             * deal with setting standalone_principal_dn.  Also note that
             * this will set create_standalone_prinicipal true for
             * non-mix-in entries which is okay if loading from a dump.
             */
            create_standalone_prinicipal = TRUE;
            standalone_principal_dn = strdup(principal_dn);
            CHECK_NULL(standalone_principal_dn);
        }
    } /* end if (entry->mask & KADM5_LOAD */

    /* time to generate the DN information with the help of
     * containerdn, principalcontainerreference or
     * realmcontainerdn information
     */
    if (principal_dn == NULL && xargs.dn == NULL) { /* creation of standalone principal */
        /* get the subtree information */
        if (entry->princ->length == 2 && entry->princ->data[0].length == strlen("krbtgt") &&
                strncmp(entry->princ->data[0].data, "krbtgt", entry->princ->data[0].length) == 0) {
            /* if the principal is a inter-realm principal, always created in the realm container */
            subtree = strdup(ldap_context->lrparams->realmdn);
        } else if (xargs.containerdn) {
            if ((st=checkattributevalue(ld, xargs.containerdn, NULL, NULL, NULL)) != 0) {
                if (st == KRB5_KDB_NOENTRY || st == KRB5_KDB_CONSTRAINT_VIOLATION) {
                    int ost = st;
                    st = EINVAL;
                    snprintf(errbuf, sizeof(errbuf), _("'%s' not found: "),
                             xargs.containerdn);
                    prepend_err_str(context, errbuf, st, ost);
                }
                goto cleanup;
            }
            subtree = strdup(xargs.containerdn);
        } else if (ldap_context->lrparams->containerref && strlen(ldap_context->lrparams->containerref) != 0) {
            /*
             * Here the subtree should be changed with
             * principalcontainerreference attribute value
             */
            subtree = strdup(ldap_context->lrparams->containerref);
        } else {
            subtree = strdup(ldap_context->lrparams->realmdn);
        }
        CHECK_NULL(subtree);

        if (asprintf(&standalone_principal_dn, "krbprincipalname=%s,%s",
                     user, subtree) < 0)
            standalone_principal_dn = NULL;
        CHECK_NULL(standalone_principal_dn);
        /*
         * free subtree when you are done using the subtree
         * set the boolean create_standalone_prinicipal to TRUE
         */
        create_standalone_prinicipal = TRUE;
        free(subtree);
        subtree = NULL;
    }

    /*
     * If the DN information is presented by the user, time to
     * validate the input to ensure that the DN falls under
     * any of the subtrees
     */
    if (xargs.dn_from_kbd == TRUE) {
        /* make sure the DN falls in the subtree */
        int              tre=0, dnlen=0, subtreelen=0, ntrees=0;
        char             **subtreelist=NULL;
        char             *dn=NULL;
        krb5_boolean     outofsubtree=TRUE;

        if (xargs.dn != NULL) {
            dn = xargs.dn;
        } else if (xargs.linkdn != NULL) {
            dn = xargs.linkdn;
        } else if (standalone_principal_dn != NULL) {
            /*
             * Even though the standalone_principal_dn is constructed
             * within this function, there is the containerdn input
             * from the user that can become part of the it.
             */
            dn = standalone_principal_dn;
        }

        /* get the current subtree list */
        if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
            goto cleanup;

        for (tre=0; tre<ntrees; ++tre) {
            if (subtreelist[tre] == NULL || strlen(subtreelist[tre]) == 0) {
                outofsubtree = FALSE;
                break;
            } else {
                dnlen = strlen (dn);
                subtreelen = strlen(subtreelist[tre]);
                if ((dnlen >= subtreelen) && (strcasecmp((dn + dnlen - subtreelen), subtreelist[tre]) == 0)) {
                    outofsubtree = FALSE;
                    break;
                }
            }
        }

        for (tre=0; tre < ntrees; ++tre) {
            free(subtreelist[tre]);
        }

        if (outofsubtree == TRUE) {
            st = EINVAL;
            krb5_set_error_message(context, st,
                                   _("DN is out of the realm subtree"));
            goto cleanup;
        }

        /*
         * dn value will be set either by dn, linkdn or the standalone_principal_dn
         * In the first 2 cases, the dn should be existing and in the last case we
         * are supposed to create the ldap object. so the below should not be
         * executed for the last case.
         */

        if (standalone_principal_dn == NULL) {
            /*
             * If the ldap object is missing, this results in an error.
             */

            /*
             * Search for krbprincipalname attribute here.
             * This is to find if a kerberos identity is already present
             * on the ldap object, in which case adding a kerberos identity
             * on the ldap object should result in an error.
             */
            char  *attributes[]= {"krbticketpolicyreference", "krbprincipalname", NULL};

            LDAP_SEARCH_1(dn, LDAP_SCOPE_BASE, 0, attributes, IGNORE_STATUS);
            if (st == LDAP_SUCCESS) {
                ent = ldap_first_entry(ld, result);
                if (ent != NULL) {
                    if ((values=ldap_get_values(ld, ent, "krbticketpolicyreference")) != NULL) {
                        ldap_value_free(values);
                    }

                    if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
                        krb_identity_exists = TRUE;
                        ldap_value_free(values);
                    }
                }
                ldap_msgfree(result);
            } else {
                st = set_ldap_error(context, st, OP_SEARCH);
                goto cleanup;
            }
        }
    }

    /*
     * If xargs.dn is set then the request is to add a
     * kerberos principal on a ldap object, but if
     * there is one already on the ldap object this
     * should result in an error.
     */

    if (xargs.dn != NULL && krb_identity_exists == TRUE) {
        st = EINVAL;
        snprintf(errbuf, sizeof(errbuf),
                 _("ldap object is already kerberized"));
        krb5_set_error_message(context, st, "%s", errbuf);
        goto cleanup;
    }

    if (xargs.linkdn != NULL) {
        /*
         * link information can be changed using modprinc.
         * However, link information can be changed only on the
         * standalone kerberos principal objects. A standalone
         * kerberos principal object is of type krbprincipal
         * structural objectclass.
         *
         * NOTE: kerberos principals on an ldap object can't be
         * linked to other ldap objects.
         */
        if (optype == MODIFY_PRINCIPAL &&
                kerberos_principal_object_type != KDB_STANDALONE_PRINCIPAL_OBJECT) {
            st = EINVAL;
            snprintf(errbuf, sizeof(errbuf),
                     _("link information can not be set/updated as the "
                       "kerberos principal belongs to an ldap object"));
            krb5_set_error_message(context, st, "%s", errbuf);
            goto cleanup;
        }
        /*
         * Check the link information. If there is already a link
         * existing then this operation is not allowed.
         */
        {
            char **linkdns=NULL;
            int  j=0;

            if ((st=krb5_get_linkdn(context, entry, &linkdns)) != 0) {
                snprintf(errbuf, sizeof(errbuf),
                         _("Failed getting object references"));
                krb5_set_error_message(context, st, "%s", errbuf);
                goto cleanup;
            }
            if (linkdns != NULL) {
                st = EINVAL;
                snprintf(errbuf, sizeof(errbuf),
                         _("kerberos principal is already linked to a ldap "
                           "object"));
                krb5_set_error_message(context, st, "%s", errbuf);
                for (j=0; linkdns[j] != NULL; ++j)
                    free (linkdns[j]);
                free (linkdns);
                goto cleanup;
            }
        }

        establish_links = TRUE;
    }

    if (entry->mask & KADM5_LAST_SUCCESS) {
        memset(strval, 0, sizeof(strval));
        if ((strval[0]=getstringtime(entry->last_success)) == NULL)
            goto cleanup;
        if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastSuccessfulAuth", LDAP_MOD_REPLACE, strval)) != 0) {
            free (strval[0]);
            goto cleanup;
        }
        free (strval[0]);
    }

    if (entry->mask & KADM5_LAST_FAILED) {
        memset(strval, 0, sizeof(strval));
        if ((strval[0]=getstringtime(entry->last_failed)) == NULL)
            goto cleanup;
        if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastFailedAuth", LDAP_MOD_REPLACE, strval)) != 0) {
            free (strval[0]);
            goto cleanup;
        }
        free(strval[0]);
    }

    if (entry->mask & KADM5_FAIL_AUTH_COUNT) {
        krb5_kvno fail_auth_count;

        fail_auth_count = entry->fail_auth_count;
        if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT)
            fail_auth_count++;

        st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
                                       LDAP_MOD_REPLACE,
                                       fail_auth_count);
        if (st != 0)
            goto cleanup;
    } else if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT) {
        int attr_mask = 0;
        krb5_boolean has_fail_count;

        /* Check if the krbLoginFailedCount attribute exists.  (Through
         * krb5 1.8.1, it wasn't set in new entries.) */
        st = krb5_get_attributes_mask(context, entry, &attr_mask);
        if (st != 0)
            goto cleanup;
        has_fail_count = ((attr_mask & KDB_FAIL_AUTH_COUNT_ATTR) != 0);

        /*
         * If the client library and server supports RFC 4525,
         * then use it to increment by one the value of the
         * krbLoginFailedCount attribute. Otherwise, assert the
         * (provided) old value by deleting it before adding.
         */
#ifdef LDAP_MOD_INCREMENT
        if (ldap_server_handle->server_info->modify_increment &&
                has_fail_count) {
            st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
                                           LDAP_MOD_INCREMENT, 1);
            if (st != 0)
                goto cleanup;
        } else {
#endif /* LDAP_MOD_INCREMENT */
            if (has_fail_count) {
                st = krb5_add_int_mem_ldap_mod(&mods,
                                               "krbLoginFailedCount",
                                               LDAP_MOD_DELETE,
                                               entry->fail_auth_count);
                if (st != 0)
                    goto cleanup;
            }
            st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
                                           LDAP_MOD_ADD,
                                           entry->fail_auth_count + 1);
            if (st != 0)
                goto cleanup;
#ifdef LDAP_MOD_INCREMENT
        }
#endif
    } else if (optype == ADD_PRINCIPAL) {
        /* Initialize krbLoginFailedCount in new entries to help avoid a
         * race during the first failed login. */
        st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
                                       LDAP_MOD_ADD, 0);
    }

    if (entry->mask & KADM5_MAX_LIFE) {
        if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_REPLACE, entry->max_life)) != 0)
            goto cleanup;
    }

    if (entry->mask & KADM5_MAX_RLIFE) {
        if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_REPLACE,
                                          entry->max_renewable_life)) != 0)
            goto cleanup;
    }

    if (entry->mask & KADM5_ATTRIBUTES) {
        if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_REPLACE,
                                          entry->attributes)) != 0)
            goto cleanup;
    }

    if (entry->mask & KADM5_PRINCIPAL) {
        memset(strval, 0, sizeof(strval));
        strval[0] = user;
        if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalname", LDAP_MOD_REPLACE, strval)) != 0)
            goto cleanup;
    }

    if (entry->mask & KADM5_PRINC_EXPIRE_TIME) {
        memset(strval, 0, sizeof(strval));
        if ((strval[0]=getstringtime(entry->expiration)) == NULL)
            goto cleanup;
        if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalexpiration", LDAP_MOD_REPLACE, strval)) != 0) {
            free (strval[0]);
            goto cleanup;
        }
        free (strval[0]);
    }

    if (entry->mask & KADM5_PW_EXPIRATION) {
        memset(strval, 0, sizeof(strval));
        if ((strval[0]=getstringtime(entry->pw_expiration)) == NULL)
            goto cleanup;
        if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpasswordexpiration",
                                          LDAP_MOD_REPLACE,
                                          strval)) != 0) {
            free (strval[0]);
            goto cleanup;
        }
        free (strval[0]);
    }

    if (entry->mask & KADM5_POLICY) {
        memset(&princ_ent, 0, sizeof(princ_ent));
        for (tl_data=entry->tl_data; tl_data; tl_data=tl_data->tl_data_next) {
            if (tl_data->tl_data_type == KRB5_TL_KADM_DATA) {
                /* FIX ME: I guess the princ_ent should be freed after this call */
                if ((st = krb5_lookup_tl_kadm_data(tl_data, &princ_ent)) != 0) {
                    goto cleanup;
                }
            }
        }

        if (princ_ent.aux_attributes & KADM5_POLICY) {
            memset(strval, 0, sizeof(strval));
            if ((st = krb5_ldap_name_to_policydn (context, princ_ent.policy, &polname)) != 0)
                goto cleanup;
            strval[0] = polname;
            if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
                goto cleanup;
        } else {
            st = EINVAL;
            krb5_set_error_message(context, st, "Password policy value null");
            goto cleanup;
        }
    } else if (entry->mask & KADM5_LOAD && found_entry == TRUE) {
        /*
         * a load is special in that existing entries must have attrs that
         * removed.
         */

        if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, NULL)) != 0)
            goto cleanup;
    }

    if (entry->mask & KADM5_POLICY_CLR) {
        if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_DELETE, NULL)) != 0)
            goto cleanup;
    }

    if (entry->mask & KADM5_KEY_DATA || entry->mask & KADM5_KVNO) {
        krb5_kvno mkvno;

        if ((st=krb5_dbe_lookup_mkvno(context, entry, &mkvno)) != 0)
            goto cleanup;
        bersecretkey = krb5_encode_krbsecretkey (entry->key_data,
                       entry->n_key_data, mkvno);

        if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbprincipalkey",
                                          LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, bersecretkey)) != 0)
            goto cleanup;

        if (!(entry->mask & KADM5_PRINCIPAL)) {
            memset(strval, 0, sizeof(strval));
            if ((strval[0]=getstringtime(entry->pw_expiration)) == NULL)
                goto cleanup;
            if ((st=krb5_add_str_mem_ldap_mod(&mods,
                                              "krbpasswordexpiration",
                                              LDAP_MOD_REPLACE, strval)) != 0) {
                free (strval[0]);
                goto cleanup;
            }
            free (strval[0]);
        }

        /* Update last password change whenever a new key is set */
        {
            krb5_timestamp last_pw_changed;
            if ((st=krb5_dbe_lookup_last_pwd_change(context, entry,
                                                    &last_pw_changed)) != 0)
                goto cleanup;

            memset(strval, 0, sizeof(strval));
            if ((strval[0] = getstringtime(last_pw_changed)) == NULL)
                goto cleanup;

            if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastPwdChange",
                                              LDAP_MOD_REPLACE, strval)) != 0) {
                free (strval[0]);
                goto cleanup;
            }
            free (strval[0]);
        }

    } /* Modify Key data ends here */

    /* Set tl_data */
    if (entry->tl_data != NULL) {
        int count = 0;
        struct berval **ber_tl_data = NULL;
        krb5_tl_data *ptr;
        krb5_timestamp unlock_time;
        for (ptr = entry->tl_data; ptr != NULL; ptr = ptr->tl_data_next) {
            if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
#ifdef SECURID
                    || ptr->tl_data_type == KRB5_TL_DB_ARGS
#endif
                    || ptr->tl_data_type == KRB5_TL_KADM_DATA
                    || ptr->tl_data_type == KDB_TL_USER_INFO
                    || ptr->tl_data_type == KRB5_TL_CONSTRAINED_DELEGATION_ACL
                    || ptr->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK)
                continue;
            count++;
        }
        if (count != 0) {
            int j;
            ber_tl_data = (struct berval **) calloc (count + 1,
                          sizeof (struct berval*));
            if (ber_tl_data == NULL) {
                st = ENOMEM;
                goto cleanup;
            }
            for (j = 0, ptr = entry->tl_data; ptr != NULL; ptr = ptr->tl_data_next) {
                /* Ignore tl_data that are stored in separate directory
                 * attributes */
                if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
#ifdef SECURID
                        || ptr->tl_data_type == KRB5_TL_DB_ARGS
#endif
                        || ptr->tl_data_type == KRB5_TL_KADM_DATA
                        || ptr->tl_data_type == KDB_TL_USER_INFO
                        || ptr->tl_data_type == KRB5_TL_CONSTRAINED_DELEGATION_ACL
                        || ptr->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK)
                    continue;
                if ((st = tl_data2berval (ptr, &ber_tl_data[j])) != 0)
                    break;
                j++;
            }
            if (st == 0) {
                ber_tl_data[count] = NULL;
                st=krb5_add_ber_mem_ldap_mod(&mods, "krbExtraData",
                                             LDAP_MOD_REPLACE |
                                             LDAP_MOD_BVALUES, ber_tl_data);
            }
            for (j = 0; ber_tl_data[j] != NULL; j++) {
                free(ber_tl_data[j]->bv_val);
                free(ber_tl_data[j]);
            }
            free(ber_tl_data);
            if (st != 0)
                goto cleanup;
        }
        if ((st=krb5_dbe_lookup_last_admin_unlock(context, entry,
                &unlock_time)) != 0)
            goto cleanup;
        if (unlock_time != 0) {
            /* Update last admin unlock */
            memset(strval, 0, sizeof(strval));
            if ((strval[0] = getstringtime(unlock_time)) == NULL)
                goto cleanup;

            if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastAdminUnlock",
                                              LDAP_MOD_REPLACE, strval)) != 0) {
                free (strval[0]);
                goto cleanup;
            }
            free (strval[0]);
        }
    }

    /* Directory specific attribute */
    if (xargs.tktpolicydn != NULL) {
        int tmask=0;

        if (strlen(xargs.tktpolicydn) != 0) {
            st = checkattributevalue(ld, xargs.tktpolicydn, "objectclass", policyclass, &tmask);
            CHECK_CLASS_VALIDITY(st, tmask, _("ticket policy object value: "));

            strval[0] = xargs.tktpolicydn;
            strval[1] = NULL;
            if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
                goto cleanup;

        } else {
            /* if xargs.tktpolicydn is a empty string, then delete
             * already existing krbticketpolicyreference attr */
            if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_DELETE, NULL)) != 0)
                goto cleanup;
        }

    }

    if (establish_links == TRUE) {
        memset(strval, 0, sizeof(strval));
        strval[0] = xargs.linkdn;
        if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbObjectReferences", LDAP_MOD_REPLACE, strval)) != 0)
            goto cleanup;
    }

    /*
     * in case mods is NULL then return
     * not sure but can happen in a modprinc
     * so no need to return an error
     * addprinc will at least have the principal name
     * and the keys passed in
     */
    if (mods == NULL)
        goto cleanup;

    if (create_standalone_prinicipal == TRUE) {
        memset(strval, 0, sizeof(strval));
        strval[0] = "krbprincipal";
        strval[1] = "krbprincipalaux";
        strval[2] = "krbTicketPolicyAux";

        if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
            goto cleanup;

        st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL);
        if (st == LDAP_ALREADY_EXISTS && entry->mask & KADM5_LOAD) {
            /* a load operation must replace an existing entry */
            st = ldap_delete_ext_s(ld, standalone_principal_dn, NULL, NULL);
            if (st != LDAP_SUCCESS) {
                snprintf(errbuf, sizeof(errbuf),
                         _("Principal delete failed (trying to replace "
                           "entry): %s"), ldap_err2string(st));
                st = translate_ldap_error (st, OP_ADD);
                krb5_set_error_message(context, st, "%s", errbuf);
                goto cleanup;
            } else {
                st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL);
            }
        }
        if (st != LDAP_SUCCESS) {
            snprintf(errbuf, sizeof(errbuf), _("Principal add failed: %s"),
                     ldap_err2string(st));
            st = translate_ldap_error (st, OP_ADD);
            krb5_set_error_message(context, st, "%s", errbuf);
            goto cleanup;
        }
    } else {
        /*
         * Here existing ldap object is modified and can be related
         * to any attribute, so always ensure that the ldap
         * object is extended with all the kerberos related
         * objectclasses so that there are no constraint
         * violations.
         */
        {
            char *attrvalues[] = {"krbprincipalaux", "krbTicketPolicyAux", NULL};
            int p, q, r=0, amask=0;

            if ((st=checkattributevalue(ld, (xargs.dn) ? xargs.dn : principal_dn,
                                        "objectclass", attrvalues, &amask)) != 0)
                goto cleanup;

            memset(strval, 0, sizeof(strval));
            for (p=1, q=0; p<=2; p<<=1, ++q) {
                if ((p & amask) == 0)
                    strval[r++] = attrvalues[q];
            }
            if (r != 0) {
                if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
                    goto cleanup;
            }
        }
        if (xargs.dn != NULL)
            st=ldap_modify_ext_s(ld, xargs.dn, mods, NULL, NULL);
        else
            st = ldap_modify_ext_s(ld, principal_dn, mods, NULL, NULL);

        if (st != LDAP_SUCCESS) {
            snprintf(errbuf, sizeof(errbuf), _("User modification failed: %s"),
                     ldap_err2string(st));
            st = translate_ldap_error (st, OP_MOD);
            krb5_set_error_message(context, st, "%s", errbuf);
            goto cleanup;
        }

        if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT)
            entry->fail_auth_count++;
    }

cleanup:
    if (user)
        free(user);

    free_xargs(xargs);

    if (standalone_principal_dn)
        free(standalone_principal_dn);

    if (principal_dn)
        free (principal_dn);

    if (polname != NULL)
        free(polname);

    if (subtree)
        free (subtree);

    if (bersecretkey) {
        for (l=0; bersecretkey[l]; ++l) {
            if (bersecretkey[l]->bv_val)
                free (bersecretkey[l]->bv_val);
            free (bersecretkey[l]);
        }
        free (bersecretkey);
    }

    if (keys)
        free (keys);

    ldap_mods_free(mods, 1);
    krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
    return(st);
}
/*
 * delete a principal from the directory.
 */
krb5_error_code
krb5_ldap_delete_principal(krb5_context context,
                           krb5_const_principal searchfor)
{
    char                      *user=NULL, *DN=NULL, *strval[10] = {NULL};
    LDAPMod                   **mods=NULL;
    LDAP                      *ld=NULL;
    int                       j=0, ptype=0, pcount=0, attrsetmask=0;
    krb5_error_code           st=0;
    krb5_boolean              singleentry=FALSE;
    KEY                       *secretkey=NULL;
    kdb5_dal_handle           *dal_handle=NULL;
    krb5_ldap_context         *ldap_context=NULL;
    krb5_ldap_server_handle   *ldap_server_handle=NULL;
    krb5_db_entry             *entry = NULL;

    /* Clear the global error string */
    krb5_clear_error_message(context);

    SETUP_CONTEXT();
    /* get the principal info */
    if ((st=krb5_ldap_get_principal(context, searchfor, 0, &entry)))
        goto cleanup;

    if (((st=krb5_get_princ_type(context, entry, &(ptype))) != 0) ||
        ((st=krb5_get_attributes_mask(context, entry, &(attrsetmask))) != 0) ||
        ((st=krb5_get_princ_count(context, entry, &(pcount))) != 0) ||
        ((st=krb5_get_userdn(context, entry, &(DN))) != 0))
        goto cleanup;

    if (DN == NULL) {
        st = EINVAL;
        krb5_set_error_message(context, st, "DN information missing");
        goto cleanup;
    }

    GET_HANDLE();

    if (ptype == KDB_STANDALONE_PRINCIPAL_OBJECT) {
        st = ldap_delete_ext_s(ld, DN, NULL, NULL);
        if (st != LDAP_SUCCESS) {
            st = set_ldap_error (context, st, OP_DEL);
            goto cleanup;
        }
    } else {
        if (((st=krb5_unparse_name(context, searchfor, &user)) != 0)
            || ((st=krb5_ldap_unparse_principal_name(user)) != 0))
            goto cleanup;

        memset(strval, 0, sizeof(strval));
        strval[0] = user;
        if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalname", LDAP_MOD_DELETE,
                                          strval)) != 0)
            goto cleanup;

        singleentry = (pcount == 1) ? TRUE: FALSE;
        if (singleentry == FALSE) {
            if (secretkey != NULL) {
                if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbprincipalkey", LDAP_MOD_DELETE | LDAP_MOD_BVALUES,
                                                  secretkey->keys)) != 0)
                    goto cleanup;
            }
        } else {
            /*
             * If the Kerberos user principal to be deleted happens to be the last one associated
             * with the directory user object, then it is time to delete the other kerberos
             * specific attributes like krbmaxticketlife, i.e, unkerberize the directory user.
             * From the attrsetmask value, identify the attributes set on the directory user
             * object and delete them.
             * NOTE: krbsecretkey attribute has per principal entries. There can be chances that the
             * other principals' keys are exisiting/left-over. So delete all the values.
             */
            while (attrsetmask) {
                if (attrsetmask & 1) {
                    if ((st=krb5_add_str_mem_ldap_mod(&mods, attributes_set[j], LDAP_MOD_DELETE,
                                                      NULL)) != 0)
                        goto cleanup;
                }
                attrsetmask >>= 1;
                ++j;
            }

            /* the same should be done with the objectclass attributes */
            {
                char *attrvalues[] = {"krbticketpolicyaux", "krbprincipalaux", NULL};
/*              char *attrvalues[] = {"krbpwdpolicyrefaux", "krbticketpolicyaux", "krbprincipalaux", NULL};  */
                int p, q, r=0, amask=0;

                if ((st=checkattributevalue(ld, DN, "objectclass", attrvalues, &amask)) != 0)
                    goto cleanup;
                memset(strval, 0, sizeof(strval));
                for (p=1, q=0; p<=4; p<<=1, ++q)
                    if (p & amask)
                        strval[r++] = attrvalues[q];
                strval[r] = NULL;
                if (r > 0) {
                    if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_DELETE,
                                                      strval)) != 0)
                        goto cleanup;
                }
            }
        }
        st=ldap_modify_ext_s(ld, DN, mods, NULL, NULL);
        if (st != LDAP_SUCCESS) {
            st = set_ldap_error(context, st, OP_MOD);
            goto cleanup;
        }
    }

cleanup:
    if (user)
        free (user);

    if (DN)
        free (DN);

    if (secretkey != NULL) {
        int i=0;
        while (i < secretkey->nkey) {
            free (secretkey->keys[i]->bv_val);
            free (secretkey->keys[i]);
            ++i;
        }
        free (secretkey->keys);
        free (secretkey);
    }

    krb5_ldap_free_principal(context, entry);

    ldap_mods_free(mods, 1);
    krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
    return st;
}
Example #6
0
krb5_error_code
krb5_ldap_create_realm(krb5_context context, krb5_ldap_realm_params *rparams,
                       int mask)
{
    LDAP                        *ld=NULL;
    krb5_error_code             st=0;
    char                        *dn=NULL;
    char                        *strval[4]={NULL};
    char                        *contref[2]={NULL};
    LDAPMod                     **mods = NULL;
    int                         i=0, objectmask=0, subtreecount=0;
    kdb5_dal_handle             *dal_handle=NULL;
    krb5_ldap_context           *ldap_context=NULL;
    krb5_ldap_server_handle     *ldap_server_handle=NULL;
    char                        *realm_name;

    SETUP_CONTEXT ();

    /* Check input validity ... */
    if (ldap_context->container_dn == NULL ||
        rparams == NULL ||
        rparams->realm_name == NULL ||
        ((mask & LDAP_REALM_SUBTREE) && rparams->subtree  == NULL) ||
        ((mask & LDAP_REALM_CONTREF) && rparams->containerref == NULL) ||
        0) {
        st = EINVAL;
        return st;
    }

    /* get ldap handle */
    GET_HANDLE ();

    realm_name = rparams->realm_name;

    if (asprintf(&dn, "cn=%s,%s", realm_name, ldap_context->container_dn) < 0)
        dn = NULL;
    CHECK_NULL(dn);

    strval[0] = realm_name;
    strval[1] = NULL;
    if ((st=krb5_add_str_mem_ldap_mod(&mods, "cn", LDAP_MOD_ADD, strval)) != 0)
        goto cleanup;

    strval[0] = "top";
    strval[1] = "krbrealmcontainer";
    strval[2] = "krbticketpolicyaux";
    strval[3] = NULL;

    if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
        goto cleanup;

    /* SUBTREE ATTRIBUTE */
    if (mask & LDAP_REALM_SUBTREE) {
        if ( rparams->subtree!=NULL)  {
            subtreecount = rparams->subtreecount;
            for (i=0; rparams->subtree[i]!=NULL && i<subtreecount; i++) {
                if (strlen(rparams->subtree[i]) != 0) {
                    st = checkattributevalue(ld, rparams->subtree[i], "Objectclass", subtreeclass,
                                             &objectmask);
                    CHECK_CLASS_VALIDITY(st, objectmask,
                                         _("realm object value: "));
                }
            }
            if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbsubtrees", LDAP_MOD_ADD,
                                              rparams->subtree)) != 0) {
                goto cleanup;
            }
        }
    }

    /* CONTAINER REFERENCE ATTRIBUTE */
    if (mask & LDAP_REALM_CONTREF) {
        if (strlen(rparams->containerref) != 0 ) {
            st = checkattributevalue(ld, rparams->containerref, "Objectclass", subtreeclass,
                                     &objectmask);
            CHECK_CLASS_VALIDITY(st, objectmask, "realm object value: ");
            contref[0] = rparams->containerref;
            contref[1] = NULL;
            if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbPrincContainerRef", LDAP_MOD_ADD,
                                              contref)) != 0)
                goto cleanup;
        }
    }

    /* SEARCHSCOPE ATTRIBUTE */
    if (mask & LDAP_REALM_SEARCHSCOPE) {
        if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbsearchscope", LDAP_MOD_ADD,
                                          (rparams->search_scope == LDAP_SCOPE_ONELEVEL
                                           || rparams->search_scope == LDAP_SCOPE_SUBTREE) ?
                                          rparams->search_scope : LDAP_SCOPE_SUBTREE)) != 0)
            goto cleanup;
    }
    if (mask & LDAP_REALM_MAXRENEWLIFE) {

        if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxRenewableAge", LDAP_MOD_ADD,
                                          rparams->max_renewable_life)) != 0)
            goto cleanup;
    }

    /* krbMaxTicketLife ATTRIBUTE */

    if (mask & LDAP_REALM_MAXTICKETLIFE) {

        if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxTicketLife", LDAP_MOD_ADD,
                                          rparams->max_life)) != 0)
            goto cleanup;
    }

    /* krbTicketFlags ATTRIBUTE */

    if (mask & LDAP_REALM_KRBTICKETFLAGS) {

        if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbTicketFlags", LDAP_MOD_ADD,
                                          rparams->tktflags)) != 0)
            goto cleanup;
    }


    /* realm creation operation */
    if ((st=ldap_add_ext_s(ld, dn, mods, NULL, NULL)) != LDAP_SUCCESS) {
        st = set_ldap_error (context, st, OP_ADD);
        goto cleanup;
    }

cleanup:

    if (dn)
        free(dn);

    ldap_mods_free(mods, 1);
    krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
    return st;
}
Example #7
0
krb5_error_code
krb5_ldap_modify_realm(krb5_context context, krb5_ldap_realm_params *rparams,
                       int mask)
{
    LDAP                  *ld=NULL;
    krb5_error_code       st=0;
    char                  **strval=NULL, *strvalprc[5]={NULL};
    LDAPMod               **mods = NULL;
    int                   objectmask=0,k=0;
    kdb5_dal_handle       *dal_handle=NULL;
    krb5_ldap_context     *ldap_context=NULL;
    krb5_ldap_server_handle *ldap_server_handle=NULL;

    if (mask == 0)
        return 0;

    if (rparams == NULL) {
        st = EINVAL;
        return st;
    }

    SETUP_CONTEXT ();

    /* Check validity of arguments */
    if (ldap_context->container_dn == NULL ||
        rparams->tl_data == NULL ||
        rparams->tl_data->tl_data_contents == NULL ||
        ((mask & LDAP_REALM_SUBTREE) && rparams->subtree == NULL) ||
        ((mask & LDAP_REALM_CONTREF) && rparams->containerref == NULL) ||
        0) {
        st = EINVAL;
        goto cleanup;
    }

    /* get ldap handle */
    GET_HANDLE ();

    /* SUBTREE ATTRIBUTE */
    if (mask & LDAP_REALM_SUBTREE) {
        if ( rparams->subtree!=NULL)  {
            /*replace the subtrees with the present if the subtrees are present*/
            for(k=0;k<rparams->subtreecount && rparams->subtree[k]!=NULL;k++) {
                if (strlen(rparams->subtree[k]) != 0) {
                    st = checkattributevalue(ld, rparams->subtree[k], "Objectclass", subtreeclass,
                                             &objectmask);
                    CHECK_CLASS_VALIDITY(st, objectmask, _("subtree value: "));
                }
            }
            strval = rparams->subtree;
            if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbsubtrees", LDAP_MOD_REPLACE,
                                              strval)) != 0) {
                goto cleanup;
            }
        }
    }

    /* CONTAINERREF ATTRIBUTE */
    if (mask & LDAP_REALM_CONTREF) {
        if (strlen(rparams->containerref) != 0 ) {
            st = checkattributevalue(ld, rparams->containerref, "Objectclass", subtreeclass,
                                     &objectmask);
            CHECK_CLASS_VALIDITY(st, objectmask,
                                 _("container reference value: "));
            strvalprc[0] = rparams->containerref;
            strvalprc[1] = NULL;
            if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbPrincContainerRef", LDAP_MOD_REPLACE,
                                              strvalprc)) != 0)
                goto cleanup;
        }
    }

    /* SEARCHSCOPE ATTRIBUTE */
    if (mask & LDAP_REALM_SEARCHSCOPE) {
        if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbsearchscope", LDAP_MOD_REPLACE,
                                          (rparams->search_scope == LDAP_SCOPE_ONELEVEL
                                           || rparams->search_scope == LDAP_SCOPE_SUBTREE) ?
                                          rparams->search_scope : LDAP_SCOPE_SUBTREE)) != 0)
            goto cleanup;
    }

    if (mask & LDAP_REALM_MAXRENEWLIFE) {

        if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxRenewableAge", LDAP_MOD_REPLACE,
                                          rparams->max_renewable_life)) != 0)
            goto cleanup;
    }

    /* krbMaxTicketLife ATTRIBUTE */

    if (mask & LDAP_REALM_MAXTICKETLIFE) {

        if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxTicketLife", LDAP_MOD_REPLACE,
                                          rparams->max_life)) != 0)
            goto cleanup;
    }

    /* krbTicketFlags ATTRIBUTE */

    if (mask & LDAP_REALM_KRBTICKETFLAGS) {

        if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbTicketFlags", LDAP_MOD_REPLACE,
                                          rparams->tktflags)) != 0)
            goto cleanup;
    }


    /* Realm modify opearation */
    if (mods != NULL) {
        if ((st=ldap_modify_ext_s(ld, rparams->realmdn, mods, NULL, NULL)) != LDAP_SUCCESS) {
            st = set_ldap_error (context, st, OP_MOD);
            goto cleanup;
        }
    }

cleanup:

    ldap_mods_free(mods, 1);
    krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
    return st;
}
Example #8
0
krb5_error_code
krb5_ldap_list_realm(krb5_context context, char ***realms)
{
    char                        **values = NULL;
    unsigned int                i = 0;
    int                         count = 0;
    krb5_error_code             st = 0, tempst = 0;
    LDAP                        *ld = NULL;
    LDAPMessage                 *result = NULL, *ent = NULL;
    kdb5_dal_handle             *dal_handle = NULL;
    krb5_ldap_context           *ldap_context = NULL;
    krb5_ldap_server_handle     *ldap_server_handle = NULL;

    SETUP_CONTEXT ();

    /* get the kerberos container DN information */
    if (ldap_context->container_dn == NULL) {
        if ((st = krb5_ldap_read_krbcontainer_dn(context,
                                                 &(ldap_context->container_dn))) != 0)
            goto cleanup;
    }

    /* get ldap handle */
    GET_HANDLE ();

    {
        char *cn[] = {"cn", NULL};
        LDAP_SEARCH(ldap_context->container_dn,
                    LDAP_SCOPE_ONELEVEL,
                    "(objectclass=krbRealmContainer)",
                    cn);
    }

    *realms = NULL;

    count = ldap_count_entries (ld, result);
    if (count == -1) {
        ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &st);
        st = set_ldap_error (context, st, OP_SEARCH);
        goto cleanup;
    }

    *realms = calloc((unsigned int) count+1, sizeof (char *));
    CHECK_NULL(*realms);

    for (ent = ldap_first_entry(ld, result), count = 0; ent != NULL;
         ent = ldap_next_entry(ld, ent)) {

        if ((values = ldap_get_values (ld, ent, "cn")) != NULL) {

            (*realms)[count] = strdup(values[0]);
            CHECK_NULL((*realms)[count]);
            count += 1;

            ldap_value_free(values);
        }
    } /* for (ent= ... */

cleanup:

    /* some error, free up all the memory */
    if (st != 0) {
        if (*realms) {
            for (i=0; (*realms)[i] != NULL; ++i) {
                free ((*realms)[i]);
            }
            free (*realms);
            *realms = NULL;
        }
    }

    /* If there are no elements, still return a NULL terminated array */

    ldap_msgfree(result);
    krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
    return st;
}
Example #9
0
int
slap_send_search_entry( Operation *op, SlapReply *rs )
{
	BerElementBuffer berbuf;
	BerElement	*ber = (BerElement *) &berbuf;
	Attribute	*a;
	int		i, j, rc = LDAP_UNAVAILABLE, bytes;
	int		userattrs;
	AccessControlState acl_state = ACL_STATE_INIT;
	int			 attrsonly;
	AttributeDescription *ad_entry = slap_schema.si_ad_entry;

	/* a_flags: array of flags telling if the i-th element will be
	 *          returned or filtered out
	 * e_flags: array of a_flags
	 */
	char **e_flags = NULL;

	rs->sr_type = REP_SEARCH;

	if ( op->ors_slimit >= 0 && rs->sr_nentries >= op->ors_slimit ) {
		rc = LDAP_SIZELIMIT_EXCEEDED;
		goto error_return;
	}

	/* Every 64 entries, check for thread pool pause */
	if ( ( ( rs->sr_nentries & 0x3f ) == 0x3f ) &&
		ldap_pvt_thread_pool_pausing( &connection_pool ) > 0 )
	{
		rc = LDAP_BUSY;
		goto error_return;
	}

	/* eventually will loop through generated operational attribute types
	 * currently implemented types include:
	 *	entryDN, subschemaSubentry, and hasSubordinates */
	/* NOTE: moved before overlays callback circling because
	 * they may modify entry and other stuff in rs */
	/* check for special all operational attributes ("+") type */
	/* FIXME: maybe we could set this flag at the operation level;
	 * however, in principle the caller of send_search_entry() may
	 * change the attribute list at each call */
	rs->sr_attr_flags = slap_attr_flags( rs->sr_attrs );

	rc = backend_operational( op, rs );
	if ( rc ) {
		goto error_return;
	}

	if ( op->o_callback ) {
		rc = slap_response_play( op, rs );
		if ( rc != SLAP_CB_CONTINUE ) {
			goto error_return;
		}
	}

	Debug( LDAP_DEBUG_TRACE, "=> send_search_entry: conn %lu dn=\"%s\"%s\n",
		op->o_connid, rs->sr_entry->e_name.bv_val,
		op->ors_attrsonly ? " (attrsOnly)" : "" );

	attrsonly = op->ors_attrsonly;

	if ( !access_allowed( op, rs->sr_entry, ad_entry, NULL, ACL_READ, NULL )) {
		Debug( LDAP_DEBUG_ACL,
			"send_search_entry: conn %lu access to entry (%s) not allowed\n",
			op->o_connid, rs->sr_entry->e_name.bv_val );

		rc = LDAP_INSUFFICIENT_ACCESS;
		goto error_return;
	}

	if ( op->o_res_ber ) {
		/* read back control or LDAP_CONNECTIONLESS */
	    ber = op->o_res_ber;
	} else {
		struct berval	bv;

		bv.bv_len = entry_flatsize( rs->sr_entry, 0 );
		bv.bv_val = op->o_tmpalloc( bv.bv_len, op->o_tmpmemctx );

		ber_init2( ber, &bv, LBER_USE_DER );
		ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
	}

#ifdef LDAP_CONNECTIONLESS
	if ( op->o_conn && op->o_conn->c_is_udp ) {
		/* CONNECTIONLESS */
		if ( op->o_protocol == LDAP_VERSION2 ) {
	    	rc = ber_printf(ber, "t{O{" /*}}*/,
				LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
		} else {
	    	rc = ber_printf( ber, "{it{O{" /*}}}*/, op->o_msgid,
				LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
		}
	} else
#endif
	if ( op->o_res_ber ) {
		/* read back control */
	    rc = ber_printf( ber, "t{O{" /*}}*/,
			LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
	} else {
	    rc = ber_printf( ber, "{it{O{" /*}}}*/, op->o_msgid,
			LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
	}

	if ( rc == -1 ) {
		Debug( LDAP_DEBUG_ANY,
			"send_search_entry: conn %lu  ber_printf failed\n",
			op->o_connid );

		if ( op->o_res_ber == NULL ) ber_free_buf( ber );
		set_ldap_error( rs, LDAP_OTHER, "encoding DN error" );
		rc = rs->sr_err;
		goto error_return;
	}

	/* check for special all user attributes ("*") type */
	userattrs = SLAP_USERATTRS( rs->sr_attr_flags );

	/* create an array of arrays of flags. Each flag corresponds
	 * to particular value of attribute and equals 1 if value matches
	 * to ValuesReturnFilter or 0 if not
	 */
	if ( op->o_vrFilter != NULL ) {
		int	k = 0;
		size_t	size;

		for ( a = rs->sr_entry->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
			for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) k++;
		}

		size = i * sizeof(char *) + k;
		if ( size > 0 ) {
			char	*a_flags;
			e_flags = slap_sl_calloc ( 1, i * sizeof(char *) + k, op->o_tmpmemctx );
			if( e_flags == NULL ) {
		    	Debug( LDAP_DEBUG_ANY,
					"send_search_entry: conn %lu slap_sl_calloc failed\n",
					op->o_connid );
				ber_free( ber, 1 );

				set_ldap_error( rs, LDAP_OTHER, "out of memory" );
				goto error_return;
			}
			a_flags = (char *)(e_flags + i);
			memset( a_flags, 0, k );
			for ( a=rs->sr_entry->e_attrs, i=0; a != NULL; a=a->a_next, i++ ) {
				for ( j = 0; a->a_vals[j].bv_val != NULL; j++ );
				e_flags[i] = a_flags;
				a_flags += j;
			}

			rc = filter_matched_values(op, rs->sr_entry->e_attrs, &e_flags) ;
			if ( rc == -1 ) {
			    	Debug( LDAP_DEBUG_ANY, "send_search_entry: "
					"conn %lu matched values filtering failed\n",
					op->o_connid );
				if ( op->o_res_ber == NULL ) ber_free_buf( ber );
				set_ldap_error( rs, LDAP_OTHER,
					"matched values filtering error" );
				rc = rs->sr_err;
				goto error_return;
			}
		}
	}

	for ( a = rs->sr_entry->e_attrs, j = 0; a != NULL; a = a->a_next, j++ ) {
		AttributeDescription *desc = a->a_desc;
		int finish = 0;

		if ( rs->sr_attrs == NULL ) {
			/* all user attrs request, skip operational attributes */
			if( is_at_operational( desc->ad_type ) ) {
				continue;
			}

		} else {
			/* specific attrs requested */
			if ( is_at_operational( desc->ad_type ) ) {
				/* if not explicitly requested */
				if ( !ad_inlist( desc, rs->sr_attrs )) {
					/* if not all op attrs requested, skip */
					if ( !SLAP_OPATTRS( rs->sr_attr_flags ))
						continue;
					/* if DSA-specific and replicating, skip */
					if ( op->o_sync != SLAP_CONTROL_NONE &&
						desc->ad_type->sat_usage == LDAP_SCHEMA_DSA_OPERATION )
						continue;
				}
			} else {
				if ( !userattrs && !ad_inlist( desc, rs->sr_attrs ) ) {
					continue;
				}
			}
		}

		if ( attrsonly ) {
			if ( ! access_allowed( op, rs->sr_entry, desc, NULL,
				ACL_READ, &acl_state ) )
			{
				Debug( LDAP_DEBUG_ACL, "send_search_entry: "
					"conn %lu access to attribute %s not allowed\n",
				        op->o_connid, desc->ad_cname.bv_val );
				continue;
			}

			if (( rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname )) == -1 ) {
				Debug( LDAP_DEBUG_ANY,
					"send_search_entry: conn %lu  ber_printf failed\n",
					op->o_connid );

				if ( op->o_res_ber == NULL ) ber_free_buf( ber );
				set_ldap_error( rs, LDAP_OTHER,
					"encoding description error");
				rc = rs->sr_err;
				goto error_return;
			}
			finish = 1;

		} else {
			int first = 1;
			for ( i = 0; a->a_nvals[i].bv_val != NULL; i++ ) {
				if ( ! access_allowed( op, rs->sr_entry,
					desc, &a->a_nvals[i], ACL_READ, &acl_state ) )
				{
					Debug( LDAP_DEBUG_ACL,
						"send_search_entry: conn %lu "
						"access to attribute %s, value #%d not allowed\n",
						op->o_connid, desc->ad_cname.bv_val, i );

					continue;
				}

				if ( op->o_vrFilter && e_flags[j][i] == 0 ){
					continue;
				}

				if ( first ) {
					first = 0;
					finish = 1;
					if (( rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname )) == -1 ) {
						Debug( LDAP_DEBUG_ANY,
							"send_search_entry: conn %lu  ber_printf failed\n",
							op->o_connid );

						if ( op->o_res_ber == NULL ) ber_free_buf( ber );
						set_ldap_error( rs, LDAP_OTHER,
							"encoding description error");
						rc = rs->sr_err;
						goto error_return;
					}
				}
				if (( rc = ber_printf( ber, "O", &a->a_vals[i] )) == -1 ) {
					Debug( LDAP_DEBUG_ANY,
						"send_search_entry: conn %lu  "
						"ber_printf failed.\n", op->o_connid );

					if ( op->o_res_ber == NULL ) ber_free_buf( ber );
					set_ldap_error( rs, LDAP_OTHER,
						"encoding values error" );
					rc = rs->sr_err;
					goto error_return;
				}
			}
		}

		if ( finish && ( rc = ber_printf( ber, /*{[*/ "]N}" )) == -1 ) {
			Debug( LDAP_DEBUG_ANY,
				"send_search_entry: conn %lu ber_printf failed\n",
				op->o_connid );

			if ( op->o_res_ber == NULL ) ber_free_buf( ber );
			set_ldap_error( rs, LDAP_OTHER, "encode end error" );
			rc = rs->sr_err;
			goto error_return;
		}
	}

	/* NOTE: moved before overlays callback circling because
	 * they may modify entry and other stuff in rs */
	if ( rs->sr_operational_attrs != NULL && op->o_vrFilter != NULL ) {
		int	k = 0;
		size_t	size;

		for ( a = rs->sr_operational_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
			for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) k++;
		}

		size = i * sizeof(char *) + k;
		if ( size > 0 ) {
			char	*a_flags, **tmp;

			/*
			 * Reuse previous memory - we likely need less space
			 * for operational attributes
			 */
			tmp = slap_sl_realloc( e_flags, i * sizeof(char *) + k,
				op->o_tmpmemctx );
			if ( tmp == NULL ) {
			    	Debug( LDAP_DEBUG_ANY,
					"send_search_entry: conn %lu "
					"not enough memory "
					"for matched values filtering\n",
					op->o_connid );
				if ( op->o_res_ber == NULL ) ber_free_buf( ber );
				set_ldap_error( rs, LDAP_OTHER,
					"not enough memory for matched values filtering" );
				goto error_return;
			}
			e_flags = tmp;
			a_flags = (char *)(e_flags + i);
			memset( a_flags, 0, k );
			for ( a = rs->sr_operational_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
				for ( j = 0; a->a_vals[j].bv_val != NULL; j++ );
				e_flags[i] = a_flags;
				a_flags += j;
			}
			rc = filter_matched_values(op, rs->sr_operational_attrs, &e_flags) ;

			if ( rc == -1 ) {
			    	Debug( LDAP_DEBUG_ANY,
					"send_search_entry: conn %lu "
					"matched values filtering failed\n",
					op->o_connid);
				if ( op->o_res_ber == NULL ) ber_free_buf( ber );
				set_ldap_error( rs, LDAP_OTHER,
					"matched values filtering error" );
				rc = rs->sr_err;
				goto error_return;
			}
		}
	}

	for (a = rs->sr_operational_attrs, j=0; a != NULL; a = a->a_next, j++ ) {
		AttributeDescription *desc = a->a_desc;

		if ( rs->sr_attrs == NULL ) {
			/* all user attrs request, skip operational attributes */
			if( is_at_operational( desc->ad_type ) ) {
				continue;
			}

		} else {
			/* specific attrs requested */
			if( is_at_operational( desc->ad_type ) ) {
				if ( !SLAP_OPATTRS( rs->sr_attr_flags ) &&
					!ad_inlist( desc, rs->sr_attrs ) )
				{
					continue;
				}
				/* if DSA-specific and replicating, skip */
				if ( op->o_sync != SLAP_CONTROL_NONE &&
					desc->ad_type->sat_usage == LDAP_SCHEMA_DSA_OPERATION )
					continue;
			} else {
				if ( !userattrs && !ad_inlist( desc, rs->sr_attrs ) ) {
					continue;
				}
			}
		}

		if ( ! access_allowed( op, rs->sr_entry, desc, NULL,
			ACL_READ, &acl_state ) )
		{
			Debug( LDAP_DEBUG_ACL,
				"send_search_entry: conn %lu "
				"access to attribute %s not allowed\n",
				op->o_connid, desc->ad_cname.bv_val );

			continue;
		}

		rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname );
		if ( rc == -1 ) {
			Debug( LDAP_DEBUG_ANY,
				"send_search_entry: conn %lu  "
				"ber_printf failed\n", op->o_connid );

			if ( op->o_res_ber == NULL ) ber_free_buf( ber );
			set_ldap_error( rs, LDAP_OTHER,
				"encoding description error" );
			rc = rs->sr_err;
			goto error_return;
		}

		if ( ! attrsonly ) {
			for ( i = 0; a->a_vals[i].bv_val != NULL; i++ ) {
				if ( ! access_allowed( op, rs->sr_entry,
					desc, &a->a_vals[i], ACL_READ, &acl_state ) )
				{
					Debug( LDAP_DEBUG_ACL,
						"send_search_entry: conn %lu "
						"access to %s, value %d not allowed\n",
						op->o_connid, desc->ad_cname.bv_val, i );

					continue;
				}

				if ( op->o_vrFilter && e_flags[j][i] == 0 ){
					continue;
				}

				if (( rc = ber_printf( ber, "O", &a->a_vals[i] )) == -1 ) {
					Debug( LDAP_DEBUG_ANY,
						"send_search_entry: conn %lu  ber_printf failed\n",
						op->o_connid );

					if ( op->o_res_ber == NULL ) ber_free_buf( ber );
					set_ldap_error( rs, LDAP_OTHER,
						"encoding values error" );
					rc = rs->sr_err;
					goto error_return;
				}
			}
		}

		if (( rc = ber_printf( ber, /*{[*/ "]N}" )) == -1 ) {
			Debug( LDAP_DEBUG_ANY,
				"send_search_entry: conn %lu  ber_printf failed\n",
				op->o_connid );

			if ( op->o_res_ber == NULL ) ber_free_buf( ber );
			set_ldap_error( rs, LDAP_OTHER, "encode end error" );
			rc = rs->sr_err;
			goto error_return;
		}
	}

	/* free e_flags */
	if ( e_flags ) {
		slap_sl_free( e_flags, op->o_tmpmemctx );
		e_flags = NULL;
	}

	rc = ber_printf( ber, /*{{*/ "}N}" );

	if( rc != -1 ) {
		rc = send_ldap_controls( op, ber, rs->sr_ctrls );
	}

	if( rc != -1 ) {
#ifdef LDAP_CONNECTIONLESS
		if( op->o_conn && op->o_conn->c_is_udp ) {
			if ( op->o_protocol != LDAP_VERSION2 ) {
				rc = ber_printf( ber, /*{*/ "N}" );
			}
		} else
#endif
		if ( op->o_res_ber == NULL ) {
			rc = ber_printf( ber, /*{*/ "N}" );
		}
	}

	if ( rc == -1 ) {
		Debug( LDAP_DEBUG_ANY, "ber_printf failed\n" );

		if ( op->o_res_ber == NULL ) ber_free_buf( ber );
		set_ldap_error( rs, LDAP_OTHER, "encode entry end error" );
		rc = rs->sr_err;
		goto error_return;
	}

	Statslog( LDAP_DEBUG_STATS2, "%s ENTRY dn=\"%s\"\n",
	    op->o_log_prefix, rs->sr_entry->e_nname.bv_val );

	rs_flush_entry( op, rs, NULL );

	if ( op->o_res_ber == NULL ) {
		bytes = send_ldap_ber( op, ber );
		ber_free_buf( ber );

		if ( bytes < 0 ) {
			Debug( LDAP_DEBUG_ANY,
				"send_search_entry: conn %lu  ber write failed.\n",
				op->o_connid );

			rc = LDAP_UNAVAILABLE;
			goto error_return;
		}
		rs->sr_nentries++;

		ldap_pvt_thread_mutex_lock( &op->o_counters->sc_mutex );
		ldap_pvt_mp_add_ulong( op->o_counters->sc_bytes, (unsigned long)bytes );
		ldap_pvt_mp_add_ulong( op->o_counters->sc_entries, 1 );
		ldap_pvt_mp_add_ulong( op->o_counters->sc_pdu, 1 );
		ldap_pvt_thread_mutex_unlock( &op->o_counters->sc_mutex );
	}

	Debug( LDAP_DEBUG_TRACE,
		"<= send_search_entry: conn %lu exit.\n", op->o_connid );

	rc = LDAP_SUCCESS;

error_return:;
	if ( op->o_callback ) {
		(void)slap_cleanup_play( op, rs );
	}

	if ( e_flags ) {
		slap_sl_free( e_flags, op->o_tmpmemctx );
	}

	/* FIXME: Can break if rs now contains an extended response */
	if ( rs->sr_operational_attrs ) {
		attrs_free( rs->sr_operational_attrs );
		rs->sr_operational_attrs = NULL;
	}
	rs->sr_attr_flags = SLAP_ATTRS_UNDEFINED;

	if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
		rs_flush_entry( op, rs, NULL );
	} else {
		RS_ASSERT( (rs->sr_flags & REP_ENTRY_MASK) == 0 );
	}

	if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) {
		rs->sr_flags ^= REP_CTRLS_MUSTBEFREED; /* paranoia */
		if ( rs->sr_ctrls ) {
			slap_free_ctrls( op, rs->sr_ctrls );
			rs->sr_ctrls = NULL;
		}
	}

	return( rc );
}
Example #10
0
int
slap_send_search_reference( Operation *op, SlapReply *rs )
{
	BerElementBuffer berbuf;
	BerElement	*ber = (BerElement *) &berbuf;
	int rc = 0;
	int bytes;
	char *edn = rs->sr_entry ? rs->sr_entry->e_name.bv_val : "(null)";

	AttributeDescription *ad_ref = slap_schema.si_ad_ref;
	AttributeDescription *ad_entry = slap_schema.si_ad_entry;

	rs->sr_type = REP_SEARCHREF;
	if ( op->o_callback ) {
		rc = slap_response_play( op, rs );
		if ( rc != SLAP_CB_CONTINUE ) {
			goto rel;
		}
	}

	Debug( LDAP_DEBUG_TRACE,
		"=> send_search_reference: dn=\"%s\"\n",
		edn );

	if (  rs->sr_entry && ! access_allowed( op, rs->sr_entry,
		ad_entry, NULL, ACL_READ, NULL ) )
	{
		Debug( LDAP_DEBUG_ACL,
			"send_search_reference: access to entry not allowed\n" );
		rc = 1;
		goto rel;
	}

	if ( rs->sr_entry && ! access_allowed( op, rs->sr_entry,
		ad_ref, NULL, ACL_READ, NULL ) )
	{
		Debug( LDAP_DEBUG_ACL,
			"send_search_reference: access "
			"to reference not allowed\n" );
		rc = 1;
		goto rel;
	}

	if( op->o_domain_scope ) {
		Debug( LDAP_DEBUG_ANY,
			"send_search_reference: domainScope control in (%s)\n",
			edn );
		rc = 0;
		goto rel;
	}

	if( rs->sr_ref == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			"send_search_reference: null ref in (%s)\n",
			edn );
		rc = 1;
		goto rel;
	}

	if( op->o_protocol < LDAP_VERSION3 ) {
		rc = 0;
		/* save the references for the result */
		if( rs->sr_ref[0].bv_val != NULL ) {
			if( value_add( &rs->sr_v2ref, rs->sr_ref ) )
				rc = LDAP_OTHER;
		}
		goto rel;
	}

#ifdef LDAP_CONNECTIONLESS
	if( op->o_conn && op->o_conn->c_is_udp ) {
		ber = op->o_res_ber;
	} else
#endif
	{
		ber_init_w_nullc( ber, LBER_USE_DER );
		ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
	}

	rc = ber_printf( ber, "{it{W}" /*"}"*/ , op->o_msgid,
		LDAP_RES_SEARCH_REFERENCE, rs->sr_ref );

	if( rc != -1 ) {
		rc = send_ldap_controls( op, ber, rs->sr_ctrls );
	}

	if( rc != -1 ) {
		rc = ber_printf( ber, /*"{"*/ "N}" );
	}

	if ( rc == -1 ) {
		Debug( LDAP_DEBUG_ANY,
			"send_search_reference: ber_printf failed\n" );

#ifdef LDAP_CONNECTIONLESS
		if (!op->o_conn || op->o_conn->c_is_udp == 0)
#endif
		ber_free_buf( ber );
		set_ldap_error( rs, LDAP_OTHER, "encode DN error" );
		goto rel;
	}

	rc = 0;
	rs_flush_entry( op, rs, NULL );

#ifdef LDAP_CONNECTIONLESS
	if (!op->o_conn || op->o_conn->c_is_udp == 0) {
#endif
	bytes = send_ldap_ber( op, ber );
	ber_free_buf( ber );

	if ( bytes < 0 ) {
		rc = LDAP_UNAVAILABLE;
	} else {
		ldap_pvt_thread_mutex_lock( &op->o_counters->sc_mutex );
		ldap_pvt_mp_add_ulong( op->o_counters->sc_bytes, (unsigned long)bytes );
		ldap_pvt_mp_add_ulong( op->o_counters->sc_refs, 1 );
		ldap_pvt_mp_add_ulong( op->o_counters->sc_pdu, 1 );
		ldap_pvt_thread_mutex_unlock( &op->o_counters->sc_mutex );
	}
#ifdef LDAP_CONNECTIONLESS
	}
#endif
	if ( rs->sr_ref != NULL ) {
		int	r;

		for ( r = 0; !BER_BVISNULL( &rs->sr_ref[ r ] ); r++ ) {
			Statslog( LDAP_DEBUG_STATS2, "%s REF #%d \"%s\"\n",
				op->o_log_prefix, r, rs->sr_ref[0].bv_val );
		}

	} else {
		Statslog( LDAP_DEBUG_STATS2, "%s REF \"(null)\"\n",
			op->o_log_prefix );
	}

	Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n" );

	if ( 0 ) {
rel:
	    rs_flush_entry( op, rs, NULL );
	}

	if ( op->o_callback ) {
		(void)slap_cleanup_play( op, rs );
	}

	if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) {
		rs->sr_flags ^= REP_CTRLS_MUSTBEFREED; /* paranoia */
		if ( rs->sr_ctrls ) {
			slap_free_ctrls( op, rs->sr_ctrls );
			rs->sr_ctrls = NULL;
		}
	}

	return rc;
}