📄 ldb_tdb.c
字号:
a = ldb_schema_attribute_by_name(ldb, el->name); for (i=0;i<el->num_values;i++) { if (a->syntax->comparison_fn(ldb, ldb, &el->values[i], val) == 0) { if (i<el->num_values-1) { memmove(&el->values[i], &el->values[i+1], sizeof(el->values[i])*(el->num_values-(i+1))); } el->num_values--; if (el->num_values == 0) { return msg_delete_attribute(module, ldb, msg, name); } return 0; } } return -1;}/* modify a record - internal interface yuck - this is O(n^2). Luckily n is usually small so we probably get away with it, but if we ever have really large attribute lists then we'll need to look at this again*/int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *msg){ struct ldb_context *ldb = module->ldb; struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private); TDB_DATA tdb_key, tdb_data; struct ldb_message *msg2; unsigned i, j; int ret, idx; tdb_key = ltdb_key(module, msg->dn); if (!tdb_key.dptr) { return LDB_ERR_OTHER; } tdb_data = tdb_fetch(ltdb->tdb, tdb_key); if (!tdb_data.dptr) { talloc_free(tdb_key.dptr); return ltdb_err_map(tdb_error(ltdb->tdb)); } msg2 = talloc(tdb_key.dptr, struct ldb_message); if (msg2 == NULL) { talloc_free(tdb_key.dptr); return LDB_ERR_OTHER; } ret = ltdb_unpack_data(module, &tdb_data, msg2); if (ret == -1) { ret = LDB_ERR_OTHER; goto failed; } if (!msg2->dn) { msg2->dn = msg->dn; } for (i=0;i<msg->num_elements;i++) { struct ldb_message_element *el = &msg->elements[i]; struct ldb_message_element *el2; struct ldb_val *vals; const char *dn; switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) { case LDB_FLAG_MOD_ADD: /* add this element to the message. fail if it already exists */ idx = find_element(msg2, el->name); if (idx == -1) { if (msg_add_element(ldb, msg2, el) != 0) { ret = LDB_ERR_OTHER; goto failed; } continue; } el2 = &msg2->elements[idx]; /* An attribute with this name already exists, * add all values if they don't already exist * (check both the other elements to be added, * and those already in the db). */ for (j=0;j<el->num_values;j++) { if (ldb_msg_find_val(el2, &el->values[j])) { ldb_asprintf_errstring(module->ldb, "%s: value #%d already exists", el->name, j); ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; goto failed; } if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) { ldb_asprintf_errstring(module->ldb, "%s: value #%d provided more than once", el->name, j); ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; goto failed; } } vals = talloc_realloc(msg2->elements, el2->values, struct ldb_val, el2->num_values + el->num_values); if (vals == NULL) { ret = LDB_ERR_OTHER; goto failed; } for (j=0;j<el->num_values;j++) { vals[el2->num_values + j] = ldb_val_dup(vals, &el->values[j]); } el2->values = vals; el2->num_values += el->num_values; break; case LDB_FLAG_MOD_REPLACE: /* replace all elements of this attribute name with the elements listed. The attribute not existing is not an error */ msg_delete_attribute(module, ldb, msg2, el->name); for (j=0;j<el->num_values;j++) { if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) { ldb_asprintf_errstring(module->ldb, "%s: value #%d provided more than once", el->name, j); ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; goto failed; } } /* add the replacement element, if not empty */ if (el->num_values != 0 && msg_add_element(ldb, msg2, el) != 0) { ret = LDB_ERR_OTHER; goto failed; } break; case LDB_FLAG_MOD_DELETE: dn = ldb_dn_get_linearized(msg->dn); if (dn == NULL) { ret = LDB_ERR_OTHER; goto failed; } /* we could be being asked to delete all values or just some values */ if (msg->elements[i].num_values == 0) { if (msg_delete_attribute(module, ldb, msg2, msg->elements[i].name) != 0) { ldb_asprintf_errstring(module->ldb, "No such attribute: %s for delete on %s", msg->elements[i].name, dn); ret = LDB_ERR_NO_SUCH_ATTRIBUTE; goto failed; } break; } for (j=0;j<msg->elements[i].num_values;j++) { if (msg_delete_element(module, msg2, msg->elements[i].name, &msg->elements[i].values[j]) != 0) { ldb_asprintf_errstring(module->ldb, "No matching attribute value when deleting attribute: %s on %s", msg->elements[i].name, dn); ret = LDB_ERR_NO_SUCH_ATTRIBUTE; goto failed; } ret = ltdb_index_del_value(module, dn, &msg->elements[i], j); if (ret != LDB_SUCCESS) { goto failed; } } break; default: ldb_asprintf_errstring(module->ldb, "Invalid ldb_modify flags on %s: 0x%x", msg->elements[i].name, msg->elements[i].flags & LDB_FLAG_MOD_MASK); ret = LDB_ERR_PROTOCOL_ERROR; goto failed; } } /* we've made all the mods - save the modified record back into the database */ ret = ltdb_store(module, msg2, TDB_MODIFY); if (ret != LDB_SUCCESS) { goto failed; } ret = ltdb_modified(module, msg->dn); if (ret != LDB_SUCCESS) { goto failed; } talloc_free(tdb_key.dptr); free(tdb_data.dptr); return ret;failed: talloc_free(tdb_key.dptr); free(tdb_data.dptr); return ret;}/* modify a record*/static int ltdb_modify(struct ldb_module *module, struct ldb_request *req){ struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private); struct ltdb_context *ltdb_ac; int tret, ret = LDB_SUCCESS; if (check_critical_controls(req->controls)) { return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; } req->handle = NULL; req->handle = init_ltdb_handle(ltdb, module, req); if (req->handle == NULL) { return LDB_ERR_OPERATIONS_ERROR; } ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); tret = ltdb_check_special_dn(module, req->op.mod.message); if (tret != LDB_SUCCESS) { req->handle->status = tret; goto done; } if (ltdb_cache_load(module) != 0) { ret = LDB_ERR_OPERATIONS_ERROR; goto done; } tret = ltdb_modify_internal(module, req->op.mod.message); if (tret != LDB_SUCCESS) { req->handle->status = tret; goto done; } if (ltdb_ac->callback) { ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); }done: req->handle->state = LDB_ASYNC_DONE; return ret;}/* rename a record*/static int ltdb_rename(struct ldb_module *module, struct ldb_request *req){ struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private); struct ltdb_context *ltdb_ac; struct ldb_message *msg; int tret, ret = LDB_SUCCESS; if (check_critical_controls(req->controls)) { return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; } req->handle = NULL; if (ltdb_cache_load(module) != 0) { return LDB_ERR_OPERATIONS_ERROR; } req->handle = init_ltdb_handle(ltdb, module, req); if (req->handle == NULL) { return LDB_ERR_OPERATIONS_ERROR; } ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); msg = talloc(ltdb_ac, struct ldb_message); if (msg == NULL) { ret = LDB_ERR_OPERATIONS_ERROR; goto done; } /* in case any attribute of the message was indexed, we need to fetch the old record */ tret = ltdb_search_dn1(module, req->op.rename.olddn, msg); if (tret != LDB_SUCCESS) { /* not finding the old record is an error */ req->handle->status = tret; goto done; } msg->dn = ldb_dn_copy(msg, req->op.rename.newdn); if (!msg->dn) { ret = LDB_ERR_OPERATIONS_ERROR; goto done; } if (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) == 0) { /* The rename operation is apparently only changing case - the DNs are the same. Delete the old DN before adding the new one to avoid a TDB_ERR_EXISTS error. The only drawback to this is that if the delete succeeds but the add fails, we rely on the transaction to roll this all back. */ ret = ltdb_delete_internal(module, req->op.rename.olddn); if (ret != LDB_SUCCESS) { goto done; } ret = ltdb_add_internal(module, msg); if (ret != LDB_SUCCESS) { goto done; } } else { /* The rename operation is changing DNs. Try to add the new DN first to avoid clobbering another DN not related to this rename operation. */ ret = ltdb_add_internal(module, msg); if (ret != LDB_SUCCESS) { goto done; } tret = ltdb_delete_internal(module, req->op.rename.olddn); if (tret != LDB_SUCCESS) { ltdb_delete_internal(module, req->op.rename.newdn); ret = LDB_ERR_OPERATIONS_ERROR; goto done; } } if (ltdb_ac->callback) { ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); }done: req->handle->state = LDB_ASYNC_DONE; return ret;}static int ltdb_start_trans(struct ldb_module *module){ struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private); if (tdb_transaction_start(ltdb->tdb) != 0) { return ltdb_err_map(tdb_error(ltdb->tdb)); } ltdb->in_transaction++; return LDB_SUCCESS;}static int ltdb_end_trans(struct ldb_module *module){ struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private); ltdb->in_transaction--; if (tdb_transaction_commit(ltdb->tdb) != 0) { return ltdb_err_map(tdb_error(ltdb->tdb)); } return LDB_SUCCESS;}static int ltdb_del_trans(struct ldb_module *module){ struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private); ltdb->in_transaction--; if (tdb_transaction_cancel(ltdb->tdb) != 0) { return ltdb_err_map(tdb_error(ltdb->tdb)); } return LDB_SUCCESS;}static int ltdb_wait(struct ldb_handle *handle, enum ldb_wait_type type){ return handle->status;}static int ltdb_request(struct ldb_module *module, struct ldb_request *req){ /* check for oustanding critical controls and return an error if found */ if (check_critical_controls(req->controls)) { return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; } /* search, add, modify, delete, rename are handled by their own, no other op supported */ return LDB_ERR_OPERATIONS_ERROR;}/* return sequenceNumber from @BASEINFO*/static int ltdb_sequence_number(struct ldb_module *module, struct ldb_request *req){ TALLOC_CTX *tmp_ctx; struct ldb_message *msg = NULL; struct ldb_dn *dn; const char *date; int tret; tmp_ctx = talloc_new(req); if (tmp_ctx == NULL) { talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } dn = ldb_dn_new(tmp_ctx, module->ldb, LTDB_BASEINFO); msg = talloc(tmp_ctx, struct ldb_message); if (msg == NULL) { talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } req->op.seq_num.flags = 0; tret = ltdb_search_dn1(module, dn, msg); if (tret != LDB_SUCCESS) { talloc_free(tmp_ctx); /* zero is as good as anything when we don't know */ req->op.seq_num.seq_num = 0; return LDB_SUCCESS; } switch (req->op.seq_num.type) { case LDB_SEQ_HIGHEST_SEQ: req->op.seq_num.seq_num = ldb_msg_find_attr_as_uint64(msg, LTDB_SEQUENCE_NUMBER, 0); break; case LDB_SEQ_NEXT: req->op.seq_num.seq_num = ldb_msg_find_attr_as_uint64(msg, LTDB_SEQUENCE_NUMBER, 0); req->op.seq_num.seq_num++; break; case LDB_SEQ_HIGHEST_TIMESTAMP: date = ldb_msg_find_attr_as_string(msg, LTDB_MOD_TIMESTAMP, NULL); if (date) { req->op.seq_num.seq_num = ldb_string_to_time(date); } else { req->op.seq_num.seq_num = 0; /* zero is as good as anything when we don't know */ } break; } talloc_free(tmp_ctx); return LDB_SUCCESS;}static const struct ldb_module_ops ltdb_ops = { .name = "tdb", .search = ltdb_search, .add = ltdb_add, .modify = ltdb_modify, .del = ltdb_delete, .rename = ltdb_rename, .request = ltdb_request, .start_transaction = ltdb_start_trans, .end_transaction = ltdb_end_trans, .del_transaction = ltdb_del_trans, .wait = ltdb_wait, .sequence_number = ltdb_sequence_number};/* connect to the database*/static int ltdb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[], struct ldb_module **module){ const char *path; int tdb_flags, open_flags; struct ltdb_private *ltdb; /* parse the url */ if (strchr(url, ':')) { if (strncmp(url, "tdb://", 6) != 0) { ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid tdb URL '%s'", url); return -1; } path = url+6; } else { path = url; } tdb_flags = TDB_DEFAULT | TDB_SEQNUM; /* check for the 'nosync' option */ if (flags & LDB_FLG_NOSYNC) { tdb_flags |= TDB_NOSYNC; } /* and nommap option */ if (flags & LDB_FLG_NOMMAP) { tdb_flags |= TDB_NOMMAP; } if (flags & LDB_FLG_RDONLY) { open_flags = O_RDONLY; } else { open_flags = O_CREAT | O_RDWR; } ltdb = talloc_zero(ldb, struct ltdb_private); if (!ltdb) { ldb_oom(ldb); return -1; } /* note that we use quite a large default hash size */ ltdb->tdb = ltdb_wrap_open(ltdb, path, 10000, tdb_flags, open_flags, ldb->create_perms, ldb); if (!ltdb->tdb) { ldb_debug(ldb, LDB_DEBUG_ERROR, "Unable to open tdb '%s'\n", path); talloc_free(ltdb); return -1; } ltdb->sequence_number = 0; *module = talloc(ldb, struct ldb_module); if (!module) { ldb_oom(ldb); talloc_free(ltdb); return -1; } talloc_set_name_const(*module, "ldb_tdb backend"); (*module)->ldb = ldb; (*module)->prev = (*module)->next = NULL; (*module)->private_data = ltdb; (*module)->ops = <db_ops; if (ltdb_cache_load(*module) != 0) { talloc_free(*module); talloc_free(ltdb); return -1; } return 0;}const struct ldb_backend_ops ldb_tdb_backend_ops = { .name = "tdb", .connect_fn = ltdb_connect};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -