/* * 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; }
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; }
/* * 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; }
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; }
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; }
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; }
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; }
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 ); }
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; }