/* * The object is in the current local domain so it should have * DB_FLAG_INTERNAL_UNIQUE_VALUE set */ static void test_objectSID_in_domain(void **state) { struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx); struct ldb_context *ldb = test_ctx->ldb; struct ldb_message *msg = ldb_msg_new(test_ctx); struct ldb_message_element *el = NULL; struct ldb_request *request = NULL; struct ldb_request *original_request = NULL; int rc; msg->dn = ldb_dn_new(msg, ldb, "dc=test"); add_sid(msg, LOCAL_SID); rc = ldb_build_add_req( &request, test_ctx->ldb, test_ctx, msg, NULL, NULL, ldb_op_default_callback, NULL); assert_int_equal(rc, LDB_SUCCESS); assert_non_null(request); original_request = request; rc = unique_object_sids_add(test_ctx->module, request); assert_int_equal(rc, LDB_SUCCESS); /* * Check that a copy of the request was passed to the next module * and not the original request */ assert_ptr_not_equal(last_request, original_request); /* * Check the flag was set on the request passed to the next * module */ el = ldb_msg_find_element(last_request->op.add.message, "objectSID"); assert_non_null(el); assert_true(el->flags & LDB_FLAG_INTERNAL_FORCE_UNIQUE_INDEX); /* * Check the flag was not set on the original request */ el = ldb_msg_find_element(request->op.add.message, "objectSID"); assert_non_null(el); assert_false(el->flags & LDB_FLAG_INTERNAL_FORCE_UNIQUE_INDEX); }
/* Modify the local record. */ static int map_modify_do_local(struct map_context *ac) { struct ldb_request *local_req; struct ldb_context *ldb; int ret; ldb = ldb_module_get_ctx(ac->module); if (ac->local_dn == NULL) { /* No local record present, add it instead */ /* Add local 'IS_MAPPED' */ /* TODO: use GUIDs here instead */ if (ldb_msg_add_empty(ac->local_msg, IS_MAPPED, LDB_FLAG_MOD_ADD, NULL) != 0) { return LDB_ERR_OPERATIONS_ERROR; } ret = ldb_msg_add_linearized_dn(ac->local_msg, IS_MAPPED, ac->remote_req->op.mod.message->dn); if (ret != 0) { return LDB_ERR_OPERATIONS_ERROR; } /* Prepare the local operation */ ret = ldb_build_add_req(&local_req, ldb, ac, ac->local_msg, ac->req->controls, ac, map_op_local_callback, ac->req); LDB_REQ_SET_LOCATION(local_req); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } } else { /* Prepare the local operation */ ret = ldb_build_mod_req(&local_req, ldb, ac, ac->local_msg, ac->req->controls, ac, map_op_local_callback, ac->req); LDB_REQ_SET_LOCATION(local_req); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } } return ldb_next_request(ac->module, local_req); }
/* Add the local record. */ static int map_add_do_local(struct map_context *ac) { struct ldb_request *local_req; struct ldb_context *ldb; int ret; ldb = ldb_module_get_ctx(ac->module); /* Prepare the local operation */ ret = ldb_build_add_req(&local_req, ldb, ac, ac->local_msg, ac->req->controls, ac, map_op_local_callback, ac->req); LDB_REQ_SET_LOCATION(local_req); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } return ldb_next_request(ac->module, local_req); }
static int sample_add(struct ldb_module *mod, struct ldb_request *req) { struct ldb_context *ldb = ldb_module_get_ctx(mod); struct ldb_control *control = NULL; struct ldb_message *msg = NULL; struct ldb_request *down_req = NULL; int ret; /* check if there's a relax control */ control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID); if (control != NULL) { return LDB_ERR_UNWILLING_TO_PERFORM; } msg = ldb_msg_copy_shallow(req, req->op.add.message); if (msg == NULL) { return LDB_ERR_OPERATIONS_ERROR; } ret = ldb_msg_add_fmt(msg, "touchedBy", "sample"); if (ret != LDB_SUCCESS) { return ret; } ret = ldb_build_add_req(&down_req, ldb, req, msg, req->controls, req, sample_add_callback, req); if (ret != LDB_SUCCESS) { return ret; } talloc_steal(down_req, msg); /* go on with the call chain */ return ldb_next_request(mod, down_req); }
/* * No objectSID on the record so it should pass through the module untouched * */ static void test_no_objectSID(void **state) { struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx); struct ldb_context *ldb = test_ctx->ldb; struct ldb_message *msg = ldb_msg_new(test_ctx); struct ldb_request *request = NULL; struct ldb_request *original_request = NULL; int rc; msg->dn = ldb_dn_new(msg, ldb, "dc=test"); assert_int_equal(LDB_SUCCESS, ldb_msg_add_string(msg, "cn", "test")); rc = ldb_build_add_req( &request, test_ctx->ldb, test_ctx, msg, NULL, NULL, ldb_op_default_callback, NULL); assert_int_equal(rc, LDB_SUCCESS); assert_non_null(request); original_request = request; rc = unique_object_sids_add(test_ctx->module, request); assert_int_equal(rc, LDB_SUCCESS); /* * Check that the original request was passed to the next module * and not a copy */ assert_ptr_equal(last_request, original_request); }
/* add_record: add instancetype attribute */ static int instancetype_add(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb = ldb_module_get_ctx(module); struct ldb_request *down_req; struct ldb_message *msg; struct ldb_message_element *el; uint32_t instanceType; int ret; /* do not manipulate our control entries */ if (ldb_dn_is_special(req->op.add.message->dn)) { return ldb_next_request(module, req); } ldb_debug(ldb, LDB_DEBUG_TRACE, "instancetype_add\n"); el = ldb_msg_find_element(req->op.add.message, "instanceType"); if (el != NULL) { if (el->num_values != 1) { ldb_set_errstring(ldb, "instancetype: the 'instanceType' attribute is single-valued!"); return LDB_ERR_UNWILLING_TO_PERFORM; } instanceType = ldb_msg_find_attr_as_uint(req->op.add.message, "instanceType", 0); if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) { /* * If we have no NC add operation (no TYPE_IS_NC_HEAD) * then "instanceType" can only be "0" or "TYPE_WRITE". */ if ((instanceType != 0) && ((instanceType & INSTANCE_TYPE_WRITE) == 0)) { ldb_set_errstring(ldb, "instancetype: if TYPE_IS_NC_HEAD wasn't set, then only TYPE_WRITE or 0 are allowed!"); return LDB_ERR_UNWILLING_TO_PERFORM; } } else { /* * If we have a NC add operation then we need also the * "TYPE_WRITE" flag in order to succeed, * unless this NC is not instantiated */ if (!(instanceType & INSTANCE_TYPE_UNINSTANT) && !(instanceType & INSTANCE_TYPE_WRITE)) { ldb_set_errstring(ldb, "instancetype: if TYPE_IS_NC_HEAD was set, then also TYPE_WRITE is requested!"); return LDB_ERR_UNWILLING_TO_PERFORM; } } /* we did only tests, so proceed with the original request */ return ldb_next_request(module, req); } /* we have to copy the message as the caller might have it as a const */ msg = ldb_msg_copy_shallow(req, req->op.add.message); if (msg == NULL) { return ldb_oom(ldb); } /* * TODO: calculate correct instance type */ instanceType = INSTANCE_TYPE_WRITE; ret = samdb_msg_add_uint(ldb, msg, msg, "instanceType", instanceType); if (ret != LDB_SUCCESS) { return ret; } ret = ldb_build_add_req(&down_req, ldb, req, msg, req->controls, req, dsdb_next_callback, req); LDB_REQ_SET_LOCATION(down_req); if (ret != LDB_SUCCESS) { return ret; } /* go on with the call chain */ return ldb_next_request(module, down_req); }
WERROR dsdb_origin_objects_commit(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct drsuapi_DsReplicaObjectListItem *first_object, uint32_t *_num, struct drsuapi_DsReplicaObjectIdentifier2 **_ids) { WERROR status; const struct dsdb_schema *schema; const struct drsuapi_DsReplicaObjectListItem *cur; struct ldb_message **objects; struct drsuapi_DsReplicaObjectIdentifier2 *ids; uint32_t i; uint32_t num_objects = 0; const char * const attrs[] = { "objectGUID", "objectSid", NULL }; struct ldb_result *res; int ret; schema = dsdb_get_schema(ldb); if (!schema) { return WERR_DS_SCHEMA_NOT_LOADED; } for (cur = first_object; cur; cur = cur->next_object) { num_objects++; } if (num_objects == 0) { return WERR_OK; } ret = ldb_transaction_start(ldb); if (ret != LDB_SUCCESS) { return WERR_DS_INTERNAL_FAILURE; } objects = talloc_array(mem_ctx, struct ldb_message *, num_objects); if (objects == NULL) { status = WERR_NOMEM; goto cancel; } for (i=0, cur = first_object; cur; cur = cur->next_object, i++) { status = dsdb_convert_object(ldb, schema, cur, objects, &objects[i]); if (!W_ERROR_IS_OK(status)) { goto cancel; } } ids = talloc_array(mem_ctx, struct drsuapi_DsReplicaObjectIdentifier2, num_objects); if (ids == NULL) { status = WERR_NOMEM; goto cancel; } for (i=0; i < num_objects; i++) { struct dom_sid *sid = NULL; struct ldb_request *add_req; DEBUG(6,(__location__ ": adding %s\n", ldb_dn_get_linearized(objects[i]->dn))); ret = ldb_build_add_req(&add_req, ldb, objects, objects[i], NULL, NULL, ldb_op_default_callback, NULL); if (ret != LDB_SUCCESS) { status = WERR_DS_INTERNAL_FAILURE; goto cancel; } ret = ldb_request_add_control(add_req, LDB_CONTROL_RELAX_OID, true, NULL); if (ret != LDB_SUCCESS) { status = WERR_DS_INTERNAL_FAILURE; goto cancel; } ret = ldb_request(ldb, add_req); if (ret == LDB_SUCCESS) { ret = ldb_wait(add_req->handle, LDB_WAIT_ALL); } if (ret != LDB_SUCCESS) { DEBUG(0,(__location__ ": Failed add of %s - %s\n", ldb_dn_get_linearized(objects[i]->dn), ldb_errstring(ldb))); status = WERR_DS_INTERNAL_FAILURE; goto cancel; } talloc_free(add_req); ret = ldb_search(ldb, objects, &res, objects[i]->dn, LDB_SCOPE_BASE, attrs, "(objectClass=*)"); if (ret != LDB_SUCCESS) { status = WERR_DS_INTERNAL_FAILURE; goto cancel; } ids[i].guid = samdb_result_guid(res->msgs[0], "objectGUID"); sid = samdb_result_dom_sid(objects, res->msgs[0], "objectSid"); if (sid) { ids[i].sid = *sid; } else { ZERO_STRUCT(ids[i].sid); } } ret = ldb_transaction_commit(ldb); if (ret != LDB_SUCCESS) { return WERR_DS_INTERNAL_FAILURE; } talloc_free(objects); *_num = num_objects; *_ids = ids; return WERR_OK; cancel: talloc_free(objects); ldb_transaction_cancel(ldb); return status; }
WERROR dsdb_origin_objects_commit(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct drsuapi_DsReplicaObjectListItem *first_object, uint32_t *_num, uint32_t dsdb_repl_flags, struct drsuapi_DsReplicaObjectIdentifier2 **_ids) { WERROR status; const struct dsdb_schema *schema; const struct drsuapi_DsReplicaObjectListItem *cur; struct ldb_message **objects; struct drsuapi_DsReplicaObjectIdentifier2 *ids; uint32_t i; uint32_t num_objects = 0; const char * const attrs[] = { "objectGUID", "objectSid", NULL }; struct ldb_result *res; int ret; for (cur = first_object; cur; cur = cur->next_object) { num_objects++; } if (num_objects == 0) { return WERR_OK; } ret = ldb_transaction_start(ldb); if (ret != LDB_SUCCESS) { return WERR_DS_INTERNAL_FAILURE; } objects = talloc_array(mem_ctx, struct ldb_message *, num_objects); if (objects == NULL) { status = WERR_NOMEM; goto cancel; } schema = dsdb_get_schema(ldb, objects); if (!schema) { return WERR_DS_SCHEMA_NOT_LOADED; } for (i=0, cur = first_object; cur; cur = cur->next_object, i++) { status = dsdb_origin_object_convert(ldb, schema, cur, objects, &objects[i]); if (!W_ERROR_IS_OK(status)) { goto cancel; } } ids = talloc_array(mem_ctx, struct drsuapi_DsReplicaObjectIdentifier2, num_objects); if (ids == NULL) { status = WERR_NOMEM; goto cancel; } if (dsdb_repl_flags & DSDB_REPL_FLAG_ADD_NCNAME) { /* check for possible NC creation */ for (i=0; i < num_objects; i++) { struct ldb_message *msg = objects[i]; struct ldb_message_element *el; struct ldb_dn *nc_dn; if (ldb_msg_check_string_attribute(msg, "objectClass", "crossRef") == 0) { continue; } el = ldb_msg_find_element(msg, "nCName"); if (el == NULL || el->num_values != 1) { continue; } nc_dn = ldb_dn_from_ldb_val(objects, ldb, &el->values[0]); if (!ldb_dn_validate(nc_dn)) { continue; } ret = dsdb_create_partial_replica_NC(ldb, nc_dn); if (ret != LDB_SUCCESS) { status = WERR_DS_INTERNAL_FAILURE; goto cancel; } } } for (i=0; i < num_objects; i++) { struct dom_sid *sid = NULL; struct ldb_request *add_req; DEBUG(6,(__location__ ": adding %s\n", ldb_dn_get_linearized(objects[i]->dn))); ret = ldb_build_add_req(&add_req, ldb, objects, objects[i], NULL, NULL, ldb_op_default_callback, NULL); if (ret != LDB_SUCCESS) { status = WERR_DS_INTERNAL_FAILURE; goto cancel; } ret = ldb_request_add_control(add_req, LDB_CONTROL_RELAX_OID, true, NULL); if (ret != LDB_SUCCESS) { status = WERR_DS_INTERNAL_FAILURE; goto cancel; } ret = ldb_request(ldb, add_req); if (ret == LDB_SUCCESS) { ret = ldb_wait(add_req->handle, LDB_WAIT_ALL); } if (ret != LDB_SUCCESS) { DEBUG(0,(__location__ ": Failed add of %s - %s\n", ldb_dn_get_linearized(objects[i]->dn), ldb_errstring(ldb))); status = WERR_DS_INTERNAL_FAILURE; goto cancel; } talloc_free(add_req); ret = ldb_search(ldb, objects, &res, objects[i]->dn, LDB_SCOPE_BASE, attrs, "(objectClass=*)"); if (ret != LDB_SUCCESS) { status = WERR_DS_INTERNAL_FAILURE; goto cancel; } ids[i].guid = samdb_result_guid(res->msgs[0], "objectGUID"); sid = samdb_result_dom_sid(objects, res->msgs[0], "objectSid"); if (sid) { ids[i].sid = *sid; } else { ZERO_STRUCT(ids[i].sid); } } ret = ldb_transaction_commit(ldb); if (ret != LDB_SUCCESS) { return WERR_DS_INTERNAL_FAILURE; } talloc_free(objects); *_num = num_objects; *_ids = ids; return WERR_OK; cancel: talloc_free(objects); ldb_transaction_cancel(ldb); return status; }
static int rdn_name_add(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb; struct ldb_request *down_req; struct rename_context *ac; struct ldb_message *msg; struct ldb_message_element *attribute; const struct ldb_schema_attribute *a; const char *rdn_name; struct ldb_val rdn_val; int i, ret; ldb = ldb_module_get_ctx(module); /* do not manipulate our control entries */ if (ldb_dn_is_special(req->op.add.message->dn)) { return ldb_next_request(module, req); } ac = talloc_zero(req, struct rename_context); if (ac == NULL) { return LDB_ERR_OPERATIONS_ERROR; } ac->module = module; ac->req = req; msg = ldb_msg_copy_shallow(req, req->op.add.message); if (msg == NULL) { return LDB_ERR_OPERATIONS_ERROR; } rdn_name = ldb_dn_get_rdn_name(msg->dn); if (rdn_name == NULL) { return LDB_ERR_OPERATIONS_ERROR; } rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(msg->dn)); /* Perhaps someone above us tried to set this? */ if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) { attribute->num_values = 0; } if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) { return LDB_ERR_OPERATIONS_ERROR; } attribute = rdn_name_find_attribute(msg, rdn_name); if (!attribute) { if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) { return LDB_ERR_OPERATIONS_ERROR; } } else { a = ldb_schema_attribute_by_name(ldb, rdn_name); for (i = 0; i < attribute->num_values; i++) { ret = a->syntax->comparison_fn(ldb, msg, &rdn_val, &attribute->values[i]); if (ret == 0) { /* overwrite so it matches in case */ attribute->values[i] = rdn_val; break; } } if (i == attribute->num_values) { char *rdn_errstring = talloc_asprintf(ac, "RDN mismatch on %s: %s (%.*s) should match one of:", ldb_dn_get_linearized(msg->dn), rdn_name, (int)rdn_val.length, (const char *)rdn_val.data); for (i = 0; i < attribute->num_values; i++) { rdn_errstring = talloc_asprintf_append( rdn_errstring, " (%.*s)", (int)attribute->values[i].length, (const char *)attribute->values[i].data); } ldb_set_errstring(ldb, rdn_errstring); /* Match AD's error here */ return LDB_ERR_INVALID_DN_SYNTAX; } } ret = ldb_build_add_req(&down_req, ldb, req, msg, req->controls, ac, rdn_name_add_callback, req); if (ret != LDB_SUCCESS) { return ret; } talloc_steal(down_req, msg); /* go on with the call chain */ return ldb_next_request(module, down_req); }
/* Add a record. */ int ldb_map_add(struct ldb_module *module, struct ldb_request *req) { const struct ldb_message *msg = req->op.add.message; struct ldb_context *ldb; struct map_context *ac; struct ldb_message *remote_msg; int ret; ldb = ldb_module_get_ctx(module); /* Do not manipulate our control entries */ if (ldb_dn_is_special(msg->dn)) { return ldb_next_request(module, req); } /* No mapping requested (perhaps no DN mapping specified), skip to next module */ if (!ldb_dn_check_local(module, msg->dn)) { return ldb_next_request(module, req); } /* No mapping needed, fail */ if (!ldb_msg_check_remote(module, msg)) { return LDB_ERR_OPERATIONS_ERROR; } /* Prepare context and handle */ ac = map_init_context(module, req); if (ac == NULL) { return LDB_ERR_OPERATIONS_ERROR; } /* Prepare the local message */ ac->local_msg = ldb_msg_new(ac); if (ac->local_msg == NULL) { map_oom(module); return LDB_ERR_OPERATIONS_ERROR; } ac->local_msg->dn = msg->dn; /* Prepare the remote message */ remote_msg = ldb_msg_new(ac); if (remote_msg == NULL) { map_oom(module); return LDB_ERR_OPERATIONS_ERROR; } remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn); /* Split local from remote message */ ldb_msg_partition(module, req->operation, ac->local_msg, remote_msg, msg); /* Prepare the remote operation */ ret = ldb_build_add_req(&ac->remote_req, ldb, ac, remote_msg, req->controls, ac, map_op_remote_callback, req); LDB_REQ_SET_LOCATION(ac->remote_req); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } if ((ac->local_msg->num_elements == 0) || ( ! map_check_local_db(ac->module))) { /* No local data or db, just run the remote request */ return ldb_next_remote_request(ac->module, ac->remote_req); } /* Store remote DN in 'IS_MAPPED' */ /* TODO: use GUIDs here instead */ ret = ldb_msg_add_linearized_dn(ac->local_msg, IS_MAPPED, remote_msg->dn); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } return map_add_do_local(ac); }