/* delete a record */ static int lldb_delete(struct lldb_context *lldb_ac) { struct ldb_context *ldb; struct lldb_private *lldb = lldb_ac->lldb; struct ldb_module *module = lldb_ac->module; struct ldb_request *req = lldb_ac->req; char *dnstr; int ret; ldb = ldb_module_get_ctx(module); ldb_request_set_state(req, LDB_ASYNC_PENDING); dnstr = ldb_dn_alloc_linearized(lldb_ac, req->op.del.dn); ret = ldap_delete_ext(lldb->ldap, dnstr, NULL, NULL, &lldb_ac->msgid); if (ret != LDAP_SUCCESS) { ldb_set_errstring(ldb, ldap_err2string(ret)); } return lldb_ldap_to_ldb(ret); }
/* modify a record */ static int lldb_modify(struct lldb_context *lldb_ac) { struct ldb_context *ldb; struct lldb_private *lldb = lldb_ac->lldb; struct ldb_module *module = lldb_ac->module; struct ldb_request *req = lldb_ac->req; LDAPMod **mods; char *dn; int ret; ldb = ldb_module_get_ctx(module); ldb_request_set_state(req, LDB_ASYNC_PENDING); mods = lldb_msg_to_mods(lldb_ac, req->op.mod.message, 1); if (mods == NULL) { return LDB_ERR_OPERATIONS_ERROR; } dn = ldb_dn_alloc_linearized(lldb_ac, req->op.mod.message->dn); if (dn == NULL) { return LDB_ERR_OPERATIONS_ERROR; } ret = ldap_modify_ext(lldb->ldap, dn, mods, NULL, NULL, &lldb_ac->msgid); if (ret != LDAP_SUCCESS) { ldb_set_errstring(ldb, ldap_err2string(ret)); } return lldb_ldap_to_ldb(ret); }
/* rename a record */ static int lldb_rename(struct lldb_context *lldb_ac) { struct ldb_context *ldb; struct lldb_private *lldb = lldb_ac->lldb; struct ldb_module *module = lldb_ac->module; struct ldb_request *req = lldb_ac->req; const char *rdn_name; const struct ldb_val *rdn_val; char *old_dn; char *newrdn; char *parentdn; int ret; ldb = ldb_module_get_ctx(module); ldb_request_set_state(req, LDB_ASYNC_PENDING); old_dn = ldb_dn_alloc_linearized(lldb_ac, req->op.rename.olddn); if (old_dn == NULL) { return LDB_ERR_OPERATIONS_ERROR; } rdn_name = ldb_dn_get_rdn_name(req->op.rename.newdn); rdn_val = ldb_dn_get_rdn_val(req->op.rename.newdn); if ((rdn_name != NULL) && (rdn_val != NULL)) { newrdn = talloc_asprintf(lldb_ac, "%s=%s", rdn_name, rdn_val->length > 0 ? ldb_dn_escape_value(lldb, *rdn_val) : ""); } else { newrdn = talloc_strdup(lldb_ac, ""); } if (!newrdn) { return LDB_ERR_OPERATIONS_ERROR; } parentdn = ldb_dn_alloc_linearized(lldb_ac, ldb_dn_get_parent(lldb_ac, req->op.rename.newdn)); if (!parentdn) { return LDB_ERR_OPERATIONS_ERROR; } ret = ldap_rename(lldb->ldap, old_dn, newrdn, parentdn, 1, NULL, NULL, &lldb_ac->msgid); if (ret != LDAP_SUCCESS) { ldb_set_errstring(ldb, ldap_err2string(ret)); } return lldb_ldap_to_ldb(ret); }
/* add a record to the database */ static int ltdb_add(struct ltdb_context *ctx) { struct ldb_module *module = ctx->module; struct ldb_request *req = ctx->req; int tret; ldb_request_set_state(req, LDB_ASYNC_PENDING); tret = ltdb_add_internal(module, req->op.add.message); if (tret != LDB_SUCCESS) { return tret; } return LDB_SUCCESS; }
/* rename a record */ static int ltdb_rename(struct ltdb_context *ctx) { struct ldb_module *module = ctx->module; struct ldb_request *req = ctx->req; struct ldb_message *msg; int ret = LDB_SUCCESS; ldb_request_set_state(req, LDB_ASYNC_PENDING); if (ltdb_cache_load(ctx->module) != 0) { return LDB_ERR_OPERATIONS_ERROR; } msg = ldb_msg_new(ctx); if (msg == NULL) { return LDB_ERR_OPERATIONS_ERROR; } /* in case any attribute of the message was indexed, we need to fetch the old record */ ret = ltdb_search_dn1(module, req->op.rename.olddn, msg); if (ret != LDB_SUCCESS) { /* not finding the old record is an error */ return ret; } /* Always delete first then add, to avoid conflicts with * unique indexes. We rely on the transaction to make this * atomic */ ret = ltdb_delete_internal(module, msg->dn); if (ret != LDB_SUCCESS) { return ret; } msg->dn = ldb_dn_copy(msg, req->op.rename.newdn); if (msg->dn == NULL) { return LDB_ERR_OPERATIONS_ERROR; } /* We don't check single value as we can have more than 1 with * deleted attributes. We could go through all elements but that's * maybe not the most efficient way */ ret = ltdb_add_internal(module, msg, false); return ret; }
/* delete a record from the database */ static int ltdb_delete(struct ltdb_context *ctx) { struct ldb_module *module = ctx->module; struct ldb_request *req = ctx->req; int ret = LDB_SUCCESS; ldb_request_set_state(req, LDB_ASYNC_PENDING); if (ltdb_cache_load(module) != 0) { return LDB_ERR_OPERATIONS_ERROR; } ret = ltdb_delete_internal(module, req->op.del.dn); return ret; }
/* rename a record */ static int ltdb_rename(struct ltdb_context *ctx) { struct ldb_module *module = ctx->module; struct ldb_request *req = ctx->req; struct ldb_message *msg; int ret = LDB_SUCCESS; ldb_request_set_state(req, LDB_ASYNC_PENDING); if (ltdb_cache_load(ctx->module) != 0) { return LDB_ERR_OPERATIONS_ERROR; } msg = talloc(ctx, struct ldb_message); if (msg == NULL) { return LDB_ERR_OPERATIONS_ERROR; } /* in case any attribute of the message was indexed, we need to fetch the old record */ ret = ltdb_search_dn1(module, req->op.rename.olddn, msg); if (ret != LDB_SUCCESS) { /* not finding the old record is an error */ return ret; } /* Always delete first then add, to avoid conflicts with * unique indexes. We rely on the transaction to make this * atomic */ ret = ltdb_delete_internal(module, msg->dn); if (ret != LDB_SUCCESS) { return ret; } msg->dn = ldb_dn_copy(msg, req->op.rename.newdn); if (msg->dn == NULL) { return LDB_ERR_OPERATIONS_ERROR; } ret = ltdb_add_internal(module, msg); return ret; }
/* modify a record */ static int ltdb_modify(struct ltdb_context *ctx) { struct ldb_module *module = ctx->module; struct ldb_request *req = ctx->req; int ret = LDB_SUCCESS; ret = ltdb_check_special_dn(module, req->op.mod.message); if (ret != LDB_SUCCESS) { return ret; } ldb_request_set_state(req, LDB_ASYNC_PENDING); if (ltdb_cache_load(module) != 0) { return LDB_ERR_OPERATIONS_ERROR; } ret = ltdb_modify_internal(module, req->op.mod.message, req); return ret; }
/* return sequenceNumber from @BASEINFO */ static int ltdb_sequence_number(struct ltdb_context *ctx, struct ldb_extended **ext) { struct ldb_context *ldb; struct ldb_module *module = ctx->module; struct ldb_request *req = ctx->req; TALLOC_CTX *tmp_ctx = NULL; struct ldb_seqnum_request *seq; struct ldb_seqnum_result *res; struct ldb_message *msg = NULL; struct ldb_dn *dn; const char *date; int ret = LDB_SUCCESS; ldb = ldb_module_get_ctx(module); seq = talloc_get_type(req->op.extended.data, struct ldb_seqnum_request); if (seq == NULL) { return LDB_ERR_OPERATIONS_ERROR; } ldb_request_set_state(req, LDB_ASYNC_PENDING); if (ltdb_lock_read(module) != 0) { return LDB_ERR_OPERATIONS_ERROR; } res = talloc_zero(req, struct ldb_seqnum_result); if (res == NULL) { ret = LDB_ERR_OPERATIONS_ERROR; goto done; } tmp_ctx = talloc_new(req); if (tmp_ctx == NULL) { ret = LDB_ERR_OPERATIONS_ERROR; goto done; } dn = ldb_dn_new(tmp_ctx, ldb, LTDB_BASEINFO); if (dn == NULL) { ret = LDB_ERR_OPERATIONS_ERROR; goto done; } msg = ldb_msg_new(tmp_ctx); if (msg == NULL) { ret = LDB_ERR_OPERATIONS_ERROR; goto done; } ret = ltdb_search_dn1(module, dn, msg); if (ret != LDB_SUCCESS) { goto done; } switch (seq->type) { case LDB_SEQ_HIGHEST_SEQ: res->seq_num = ldb_msg_find_attr_as_uint64(msg, LTDB_SEQUENCE_NUMBER, 0); break; case LDB_SEQ_NEXT: res->seq_num = ldb_msg_find_attr_as_uint64(msg, LTDB_SEQUENCE_NUMBER, 0); res->seq_num++; break; case LDB_SEQ_HIGHEST_TIMESTAMP: date = ldb_msg_find_attr_as_string(msg, LTDB_MOD_TIMESTAMP, NULL); if (date) { res->seq_num = ldb_string_to_time(date); } else { res->seq_num = 0; /* zero is as good as anything when we don't know */ } break; } *ext = talloc_zero(req, struct ldb_extended); if (*ext == NULL) { ret = LDB_ERR_OPERATIONS_ERROR; goto done; } (*ext)->oid = LDB_EXTENDED_SEQUENCE_NUMBER; (*ext)->data = talloc_steal(*ext, res); done: talloc_free(tmp_ctx); ltdb_unlock_read(module); return ret; }
/* rename a record */ static int ltdb_rename(struct ltdb_context *ctx) { struct ldb_module *module = ctx->module; void *data = ldb_module_get_private(module); struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private); struct ldb_request *req = ctx->req; struct ldb_message *msg; int ret = LDB_SUCCESS; TDB_DATA tdb_key, tdb_key_old; ldb_request_set_state(req, LDB_ASYNC_PENDING); if (ltdb_cache_load(ctx->module) != 0) { return LDB_ERR_OPERATIONS_ERROR; } msg = ldb_msg_new(ctx); if (msg == NULL) { return LDB_ERR_OPERATIONS_ERROR; } /* we need to fetch the old record to re-add under the new name */ ret = ltdb_search_dn1(module, req->op.rename.olddn, msg); if (ret != LDB_SUCCESS) { /* not finding the old record is an error */ return ret; } /* We need to, before changing the DB, check if the new DN * exists, so we can return this error to the caller with an * unmodified DB */ tdb_key = ltdb_key(module, req->op.rename.newdn); if (!tdb_key.dptr) { talloc_free(msg); return LDB_ERR_OPERATIONS_ERROR; } tdb_key_old = ltdb_key(module, req->op.rename.olddn); if (!tdb_key_old.dptr) { talloc_free(msg); talloc_free(tdb_key.dptr); return LDB_ERR_OPERATIONS_ERROR; } /* Only declare a conflict if the new DN already exists, and it isn't a case change on the old DN */ if (tdb_key_old.dsize != tdb_key.dsize || memcmp(tdb_key.dptr, tdb_key_old.dptr, tdb_key.dsize) != 0) { if (tdb_exists(ltdb->tdb, tdb_key)) { talloc_free(tdb_key_old.dptr); talloc_free(tdb_key.dptr); ldb_asprintf_errstring(ldb_module_get_ctx(module), "Entry %s already exists", ldb_dn_get_linearized(msg->dn)); /* finding the new record already in the DB is an error */ talloc_free(msg); return LDB_ERR_ENTRY_ALREADY_EXISTS; } } talloc_free(tdb_key_old.dptr); talloc_free(tdb_key.dptr); /* Always delete first then add, to avoid conflicts with * unique indexes. We rely on the transaction to make this * atomic */ ret = ltdb_delete_internal(module, msg->dn); if (ret != LDB_SUCCESS) { talloc_free(msg); return ret; } msg->dn = ldb_dn_copy(msg, req->op.rename.newdn); if (msg->dn == NULL) { talloc_free(msg); return LDB_ERR_OPERATIONS_ERROR; } /* We don't check single value as we can have more than 1 with * deleted attributes. We could go through all elements but that's * maybe not the most efficient way */ ret = ltdb_add_internal(module, msg, false); talloc_free(msg); return ret; }
/* search for matching records */ static int lldb_search(struct lldb_context *lldb_ac) { struct ldb_context *ldb; struct lldb_private *lldb = lldb_ac->lldb; struct ldb_module *module = lldb_ac->module; struct ldb_request *req = lldb_ac->req; struct timeval tv; int ldap_scope; char *search_base; char *expression; int ret; ldb = ldb_module_get_ctx(module); if (!req->callback || !req->context) { ldb_set_errstring(ldb, "Async interface called with NULL callback function or NULL context"); return LDB_ERR_OPERATIONS_ERROR; } if (req->op.search.tree == NULL) { ldb_set_errstring(ldb, "Invalid expression parse tree"); return LDB_ERR_OPERATIONS_ERROR; } if (req->controls != NULL) { ldb_debug(ldb, LDB_DEBUG_WARNING, "Controls are not yet supported by ldb_ldap backend!"); } ldb_request_set_state(req, LDB_ASYNC_PENDING); search_base = ldb_dn_alloc_linearized(lldb_ac, req->op.search.base); if (req->op.search.base == NULL) { search_base = talloc_strdup(lldb_ac, ""); } if (search_base == NULL) { return LDB_ERR_OPERATIONS_ERROR; } expression = ldb_filter_from_tree(lldb_ac, req->op.search.tree); if (expression == NULL) { return LDB_ERR_OPERATIONS_ERROR; } switch (req->op.search.scope) { case LDB_SCOPE_BASE: ldap_scope = LDAP_SCOPE_BASE; break; case LDB_SCOPE_ONELEVEL: ldap_scope = LDAP_SCOPE_ONELEVEL; break; default: ldap_scope = LDAP_SCOPE_SUBTREE; break; } tv.tv_sec = req->timeout; tv.tv_usec = 0; ret = ldap_search_ext(lldb->ldap, search_base, ldap_scope, expression, discard_const_p(char *, req->op.search.attrs), 0, NULL, NULL, &tv, LDAP_NO_LIMIT, &lldb_ac->msgid); if (ret != LDAP_SUCCESS) { ldb_set_errstring(ldb, ldap_err2string(ret)); } return lldb_ldap_to_ldb(ret); }