/* 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; }
static int ltdb_delete_internal(struct ldb_module *module, struct ldb_dn *dn) { struct ldb_message *msg; int ret; msg = talloc(module, 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, dn, msg); if (ret != LDB_SUCCESS) { /* not finding the old record is an error */ goto done; } ret = ltdb_delete_noindex(module, dn); if (ret != LDB_SUCCESS) { goto done; } /* remove one level attribute */ ret = ltdb_index_one(module, msg, 0); if (ret != LDB_SUCCESS) { goto done; } /* remove any indexed attributes */ ret = ltdb_index_del(module, msg); if (ret != LDB_SUCCESS) { goto done; } ret = ltdb_modified(module, dn); if (ret != LDB_SUCCESS) { goto done; } done: talloc_free(msg); 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; }
/* 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; }
/* return a list of dn's that might match a simple indexed search or */ static int ltdb_index_dn_simple(struct ldb_module *module, const struct ldb_parse_tree *tree, const struct ldb_message *index_list, struct dn_list *list) { struct ldb_context *ldb = module->ldb; struct ldb_dn *dn; int ret; unsigned int i, j; struct ldb_message *msg; list->count = 0; list->dn = NULL; /* if the attribute isn't in the list of indexed attributes then this node needs a full search */ if (ldb_msg_find_idx(index_list, tree->u.equality.attr, NULL, LTDB_IDXATTR) == -1) { return LDB_ERR_OPERATIONS_ERROR; } /* the attribute is indexed. Pull the list of DNs that match the search criterion */ dn = ltdb_index_key(ldb, tree->u.equality.attr, &tree->u.equality.value); if (!dn) return LDB_ERR_OPERATIONS_ERROR; msg = talloc(list, struct ldb_message); if (msg == NULL) { return LDB_ERR_OPERATIONS_ERROR; } ret = ltdb_search_dn1(module, dn, msg); talloc_free(dn); if (ret != LDB_SUCCESS) { return ret; } for (i=0;i<msg->num_elements;i++) { struct ldb_message_element *el; if (strcmp(msg->elements[i].name, LTDB_IDX) != 0) { continue; } el = &msg->elements[i]; list->dn = talloc_array(list, char *, el->num_values); if (!list->dn) { talloc_free(msg); return LDB_ERR_OPERATIONS_ERROR; } for (j=0;j<el->num_values;j++) { list->dn[list->count] = talloc_strdup(list->dn, (char *)el->values[j].data); if (!list->dn[list->count]) { talloc_free(msg); return LDB_ERR_OPERATIONS_ERROR; } list->count++; } } talloc_free(msg); if (list->count > 1) { qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t) list_cmp); } return LDB_SUCCESS; }
/* register any special handlers from @ATTRIBUTES */ static int ltdb_attributes_load(struct ldb_module *module) { struct ldb_context *ldb; void *data = ldb_module_get_private(module); struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private); struct ldb_message *msg = ltdb->cache->attributes; struct ldb_dn *dn; unsigned int i; int r; ldb = ldb_module_get_ctx(module); if (ldb->schema.attribute_handler_override) { /* we skip loading the @ATTRIBUTES record when a module is supplying its own attribute handling */ return 0; } dn = ldb_dn_new(module, ldb, LTDB_ATTRIBUTES); if (dn == NULL) goto failed; r = ltdb_search_dn1(module, dn, msg); talloc_free(dn); if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) { goto failed; } if (r == LDB_ERR_NO_SUCH_OBJECT) { return 0; } /* mapping these flags onto ldap 'syntaxes' isn't strictly correct, but its close enough for now */ for (i=0;i<msg->num_elements;i++) { unsigned flags; const char *syntax; const struct ldb_schema_syntax *s; if (ltdb_attributes_flags(&msg->elements[i], &flags) != 0) { ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid @ATTRIBUTES element for '%s'", msg->elements[i].name); goto failed; } switch (flags & ~LTDB_FLAG_HIDDEN) { case 0: syntax = LDB_SYNTAX_OCTET_STRING; break; case LTDB_FLAG_CASE_INSENSITIVE: syntax = LDB_SYNTAX_DIRECTORY_STRING; break; case LTDB_FLAG_INTEGER: syntax = LDB_SYNTAX_INTEGER; break; default: ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid flag combination 0x%x for '%s' in @ATTRIBUTES", flags, msg->elements[i].name); goto failed; } s = ldb_standard_syntax_by_name(ldb, syntax); if (s == NULL) { ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid attribute syntax '%s' for '%s' in @ATTRIBUTES", syntax, msg->elements[i].name); goto failed; } flags |= LDB_ATTR_FLAG_ALLOCATED; if (ldb_schema_attribute_add_with_syntax(ldb, msg->elements[i].name, flags, s) != 0) { goto failed; } } return 0; failed: return -1; }