/* we've made a modification to a dn - possibly reindex and update sequence number */ static int ltdb_modified(struct ldb_module *module, struct ldb_dn *dn) { int ret = LDB_SUCCESS; struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private); /* only allow modifies inside a transaction, otherwise the * ldb is unsafe */ if (ltdb->in_transaction == 0) { ldb_set_errstring(ldb_module_get_ctx(module), "ltdb modify without transaction"); return LDB_ERR_OPERATIONS_ERROR; } if (ldb_dn_is_special(dn) && (ldb_dn_check_special(dn, LTDB_INDEXLIST) || ldb_dn_check_special(dn, LTDB_ATTRIBUTES)) ) { ret = ltdb_reindex(module); } /* If the modify was to a normal record, or any special except @BASEINFO, update the seq number */ if (ret == LDB_SUCCESS && !(ldb_dn_is_special(dn) && ldb_dn_check_special(dn, LTDB_BASEINFO)) ) { ret = ltdb_increase_sequence_number(module); } /* If the modify was to @OPTIONS, reload the cache */ if (ret == LDB_SUCCESS && ldb_dn_is_special(dn) && (ldb_dn_check_special(dn, LTDB_OPTIONS)) ) { ret = ltdb_cache_reload(module); } return ret; }
static int validate_update_modify(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb; struct dsdb_schema *schema; int ret; ldb = ldb_module_get_ctx(module); schema = dsdb_get_schema(ldb); if (!schema) { return ldb_next_request(module, req); } /* do not manipulate our control entries */ if (ldb_dn_is_special(req->op.mod.message->dn)) { return ldb_next_request(module, req); } ret = validate_update_message(ldb, schema, req->op.mod.message); if (ret != LDB_SUCCESS) { return ret; } return ldb_next_request(module, req); }
static int rdn_name_modify(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb; ldb = ldb_module_get_ctx(module); /* do not manipulate our control entries */ if (ldb_dn_is_special(req->op.mod.message->dn)) { return ldb_next_request(module, req); } if (ldb_msg_find_element(req->op.mod.message, "name")) { ldb_asprintf_errstring(ldb, "Modify of 'name' on %s not permitted, must use 'rename' operation instead", ldb_dn_get_linearized(req->op.mod.message->dn)); return LDB_ERR_NOT_ALLOWED_ON_RDN; } if (ldb_msg_find_element(req->op.mod.message, ldb_dn_get_rdn_name(req->op.mod.message->dn))) { ldb_asprintf_errstring(ldb, "Modify of RDN '%s' on %s not permitted, must use 'rename' operation instead", ldb_dn_get_rdn_name(req->op.mod.message->dn), ldb_dn_get_linearized(req->op.mod.message->dn)); return LDB_ERR_NOT_ALLOWED_ON_RDN; } /* All OK, they kept their fingers out of the special attributes */ return ldb_next_request(module, req); }
static int subtree_delete(struct ldb_module *module, struct ldb_request *req) { static const char * const attrs[] = { NULL }; int ret; struct ldb_result *res = NULL; if (ldb_dn_is_special(req->op.del.dn)) { /* do not manipulate our control entries */ return ldb_next_request(module, req); } /* see if we have any children */ ret = dsdb_module_search(module, req, &res, req->op.del.dn, LDB_SCOPE_ONELEVEL, attrs, DSDB_SEARCH_SHOW_DELETED, NULL); if (ret != LDB_SUCCESS) { talloc_free(res); return ret; } if (res->count > 0) { ldb_asprintf_errstring(ldb_module_get_ctx(module), "Cannot delete %s, not a leaf node " "(has %d children)\n", ldb_dn_get_linearized(req->op.del.dn), res->count); talloc_free(res); return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF; } talloc_free(res); return ldb_next_request(module, req); }
/* * @brief Decrypt all the secret attributes on an ldb_message * * Decrypt all the secret attributes on an ldb_message. Any secret attributes * are removed from message and decrypted copies of the attributes added. * In the event of an error the contents of the message will be inconsistent. * * @param ldb ldb context, to allow logging. * @param msg The ldb_message to have it's secret attributes encrypted. * @param data The context data for this module. * * @returns ldb status code * LDB_SUCESS If the value was successfully encrypted * LDB_ERR_OPERATIONS_ERROR If there was an error. */ static int decrypt_secret_attributes(struct ldb_context *ldb, struct ldb_message *msg, struct es_data *data) { int i, ret; if (ldb_dn_is_special(msg->dn)) { return LDB_SUCCESS; } for (i = 0; i < num_secret_attributes; i++) { struct ldb_message_element *el = ldb_msg_find_element(msg, secret_attributes[i]); if (el != NULL) { const int flags = el->flags; struct ldb_message_element* dec = decrypt_element(&ret, msg->elements, ldb, el, data); if (ret != LDB_SUCCESS) { return ret; } ldb_msg_remove_element(msg, el); ret = ldb_msg_add(msg, dec, flags); if (ret != LDB_SUCCESS) { return ret; } } } return LDB_SUCCESS; }
/* Rename a record. */ int ldb_map_rename(struct ldb_module *module, struct ldb_request *req) { struct ldb_request *search_req = NULL; struct ldb_context *ldb; struct map_context *ac; int ret; ldb = ldb_module_get_ctx(module); /* Do not manipulate our control entries */ if (ldb_dn_is_special(req->op.rename.olddn)) { return ldb_next_request(module, req); } /* No mapping requested (perhaps no DN mapping specified). * Skip to next module */ if ((!ldb_dn_check_local(module, req->op.rename.olddn)) && (!ldb_dn_check_local(module, req->op.rename.newdn))) { return ldb_next_request(module, req); } /* Rename into/out of the mapped partition requested, bail out */ if (!ldb_dn_check_local(module, req->op.rename.olddn) || !ldb_dn_check_local(module, req->op.rename.newdn)) { return LDB_ERR_AFFECTS_MULTIPLE_DSAS; } /* Prepare context and handle */ ac = map_init_context(module, req); if (ac == NULL) { return LDB_ERR_OPERATIONS_ERROR; } /* Prepare the remote operation */ ret = ldb_build_rename_req(&ac->remote_req, ldb, ac, ldb_dn_map_local(module, ac, req->op.rename.olddn), ldb_dn_map_local(module, ac, req->op.rename.newdn), req->controls, ac, map_op_remote_callback, req); LDB_REQ_SET_LOCATION(ac->remote_req); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } /* No local db, just run the remote request */ if (!map_check_local_db(ac->module)) { /* Do the remote request. */ return ldb_next_remote_request(ac->module, ac->remote_req); } /* Prepare the search operation */ ret = map_search_self_req(&search_req, ac, req->op.rename.olddn); if (ret != LDB_SUCCESS) { map_oom(module); return LDB_ERR_OPERATIONS_ERROR; } return ldb_next_request(module, search_req); }
/* check special dn's have valid attributes currently only @ATTRIBUTES is checked */ static int ltdb_check_special_dn(struct ldb_module *module, const struct ldb_message *msg) { struct ldb_context *ldb = ldb_module_get_ctx(module); unsigned int i, j; if (! ldb_dn_is_special(msg->dn) || ! ldb_dn_check_special(msg->dn, LTDB_ATTRIBUTES)) { return LDB_SUCCESS; } /* we have @ATTRIBUTES, let's check attributes are fine */ /* should we check that we deny multivalued attributes ? */ for (i = 0; i < msg->num_elements; i++) { if (ldb_attr_cmp(msg->elements[i].name, "distinguishedName") == 0) continue; for (j = 0; j < msg->elements[i].num_values; j++) { if (ltdb_check_at_attributes_values(&msg->elements[i].values[j]) != 0) { ldb_set_errstring(ldb, "Invalid attribute value in an @ATTRIBUTES entry"); return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; } } } return LDB_SUCCESS; }
static bool lldb_dn_is_special(struct ldb_request *req) { struct ldb_dn *dn = NULL; switch (req->operation) { case LDB_ADD: dn = req->op.add.message->dn; break; case LDB_MODIFY: dn = req->op.mod.message->dn; break; case LDB_DELETE: dn = req->op.del.dn; break; case LDB_RENAME: dn = req->op.rename.olddn; break; default: break; } if (dn && ldb_dn_is_special(dn)) { return true; } return false; }
/* we've made a modification to a dn - possibly reindex and update sequence number */ static int ltdb_modified(struct ldb_module *module, struct ldb_dn *dn) { int ret = LDB_SUCCESS; if (ldb_dn_is_special(dn) && (ldb_dn_check_special(dn, LTDB_INDEXLIST) || ldb_dn_check_special(dn, LTDB_ATTRIBUTES)) ) { ret = ltdb_reindex(module); } if (ret == LDB_SUCCESS && !(ldb_dn_is_special(dn) && ldb_dn_check_special(dn, LTDB_BASEINFO)) ) { ret = ltdb_increase_sequence_number(module); } return ret; }
static int acl_add(struct ldb_module *module, struct ldb_request *req) { int ret; struct ldb_dn *parent = ldb_dn_get_parent(req, req->op.add.message->dn); struct ldb_context *ldb; struct ldb_message_element *oc_el; const struct GUID *guid; struct object_tree *root = NULL; struct object_tree *new_node = NULL; if (what_is_user(module) == SECURITY_SYSTEM) { return ldb_next_request(module, req); } if (ldb_dn_is_special(req->op.add.message->dn)) { return ldb_next_request(module, req); } ldb = ldb_module_get_ctx(module); /* Creating an NC. There is probably something we should do here, * but we will establish that later */ if ((ldb_dn_compare(req->op.add.message->dn, (ldb_get_schema_basedn(ldb))) == 0) || (ldb_dn_compare(req->op.add.message->dn, (ldb_get_config_basedn(ldb))) == 0) || (ldb_dn_compare(req->op.add.message->dn, (ldb_get_root_basedn(ldb))) == 0)) { return ldb_next_request(module, req); } oc_el = ldb_msg_find_element(req->op.add.message, "objectClass"); if (!oc_el || oc_el->num_values == 0) { DEBUG(10,("acl:operation error %s\n", ldb_dn_get_linearized(req->op.add.message->dn))); return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); } guid = class_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb), (char *)oc_el->values[oc_el->num_values-1].data); if (!insert_in_object_tree(req, guid, SEC_ADS_CREATE_CHILD, &root, &new_node)) { return LDB_ERR_OPERATIONS_ERROR; } ret = check_access_on_dn(module, req, parent, SEC_ADS_CREATE_CHILD, root); if (ret != LDB_SUCCESS) { return ret; } return ldb_next_request(module, req); }
static int wins_ldb_verify(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb = ldb_module_get_ctx(module); struct winsdb_handle *h = talloc_get_type(ldb_get_opaque(ldb, "winsdb_handle"), struct winsdb_handle); const struct ldb_message *msg; switch (req->operation) { case LDB_ADD: msg = req->op.add.message; break; case LDB_MODIFY: msg = req->op.mod.message; break; default: return ldb_next_request(module, req); } /* do not manipulate our control entries */ if (ldb_dn_is_special(msg->dn)) { return ldb_next_request(module, req); } if (!h) { ldb_debug_set(ldb, LDB_DEBUG_FATAL, "%s", "WINS_LDB: INTERNAL ERROR: no winsdb_handle present!"); return LDB_ERR_OTHER; } switch (h->caller) { case WINSDB_HANDLE_CALLER_NBTD: case WINSDB_HANDLE_CALLER_WREPL: /* we trust our nbt and wrepl code ... */ return ldb_next_request(module, req); case WINSDB_HANDLE_CALLER_ADMIN: ldb_debug(ldb, LDB_DEBUG_WARNING, "%s\n", "WINS_LDB: TODO verify add/modify for WINSDB_HANDLE_CALLER_ADMIN"); return ldb_next_request(module, req); } return LDB_ERR_OTHER; }
static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb; struct rename_context *ac; struct ldb_request *down_req; int ret; ldb = ldb_module_get_ctx(module); /* do not manipulate our control entries */ if (ldb_dn_is_special(req->op.rename.newdn)) { 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; ret = ldb_build_rename_req(&down_req, ldb, ac, req->op.rename.olddn, req->op.rename.newdn, req->controls, ac, rdn_rename_callback, req); if (ret != LDB_SUCCESS) { return ret; } /* rename first, modify "name" if rename is ok */ return ldb_next_request(module, down_req); }
/* deny instancetype modification */ static int instancetype_mod(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb = ldb_module_get_ctx(module); struct ldb_message_element *el; /* do not manipulate our control entries */ if (ldb_dn_is_special(req->op.mod.message->dn)) { return ldb_next_request(module, req); } ldb_debug(ldb, LDB_DEBUG_TRACE, "instancetype_mod\n"); el = ldb_msg_find_element(req->op.mod.message, "instanceType"); if (el != NULL) { /* Except to allow dbcheck to fix things, this must never be modified */ if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) { ldb_set_errstring(ldb, "instancetype: the 'instanceType' attribute can never be changed!"); return LDB_ERR_CONSTRAINT_VIOLATION; } } return ldb_next_request(module, req); }
/* * @brief Encrypt all the secret attributes on an ldb_message * * Encrypt all the secret attributes on an ldb_message. Any secret * attributes are removed from message and encrypted copies of the * attributes added. In the event of an error the contents of the * message will be inconsistent. * * @param err Pointer to an error code, set to: * LDB_SUCESS If the value was successfully encrypted * LDB_ERR_OPERATIONS_ERROR If there was an error. * @param ldb ldb context, to allow logging. * @param msg The ldb_message to have it's secret attributes encrypted. * * @param data The context data for this module. */ static const struct ldb_message *encrypt_secret_attributes( int *err, TALLOC_CTX *ctx, struct ldb_context *ldb, const struct ldb_message *msg, const struct es_data *data) { struct ldb_message *encrypted_msg = NULL; int i; if (ldb_dn_is_special(msg->dn)) { return NULL; } for (i = 0; i < msg->num_elements; i++) { const struct ldb_message_element *el = &msg->elements[i]; if (should_encrypt(el)) { struct ldb_message_element* enc = NULL; if (encrypted_msg == NULL) { encrypted_msg = ldb_msg_copy_shallow(ctx, msg); encrypted_msg->dn = msg->dn; } enc = encrypt_element(err, msg->elements, ldb, el, data); if (*err != LDB_SUCCESS) { return NULL; } encrypted_msg->elements[i] = *enc; } } return encrypted_msg; }
/* similar to the modify for the time being. * We need to concider the special delete tree case, though - TODO */ static int acl_delete(struct ldb_module *module, struct ldb_request *req) { int ret; struct ldb_dn *parent = ldb_dn_get_parent(req, req->op.del.dn); struct ldb_context *ldb; DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn))); if (what_is_user(module) == SECURITY_SYSTEM) { return ldb_next_request(module, req); } if (ldb_dn_is_special(req->op.del.dn)) { return ldb_next_request(module, req); } ldb = ldb_module_get_ctx(module); /* first check if we have delete object right */ ret = check_access_on_dn(module, req, req->op.del.dn, SEC_STD_DELETE, NULL); if (ret == LDB_SUCCESS) { return ldb_next_request(module, req); } /* Nope, we don't have delete object. Lets check if we have delete child on the parent */ /* No parent, so check fails */ if ((ldb_dn_compare(req->op.del.dn, (ldb_get_schema_basedn(ldb))) == 0) || (ldb_dn_compare(req->op.del.dn, (ldb_get_config_basedn(ldb))) == 0) || (ldb_dn_compare(req->op.del.dn, (ldb_get_root_basedn(ldb))) == 0)) { DEBUG(10,("acl:deleting an NC\n")); return ldb_module_done(req, NULL, NULL, LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS); } ret = check_access_on_dn(module, req, parent, SEC_ADS_DELETE_CHILD, NULL); if (ret != LDB_SUCCESS) { return ret; } return ldb_next_request(module, req); }
static int acl_rename(struct ldb_module *module, struct ldb_request *req) { int ret; struct ldb_dn *oldparent = ldb_dn_get_parent(req, req->op.rename.olddn); struct ldb_dn *newparent = ldb_dn_get_parent(req, req->op.rename.newdn); struct ldb_context *ldb; struct security_descriptor *sd = NULL; struct dom_sid *sid = NULL; struct ldb_result *acl_res; const struct GUID *guid; struct object_tree *root = NULL; struct object_tree *new_node = NULL; TALLOC_CTX *tmp_ctx = talloc_new(req); NTSTATUS status; uint32_t access_granted; static const char *acl_attrs[] = { "nTSecurityDescriptor", "objectClass", "objectSid", NULL }; DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn))); if (what_is_user(module) == SECURITY_SYSTEM) { return ldb_next_request(module, req); } if (ldb_dn_is_special(req->op.rename.olddn)) { return ldb_next_request(module, req); } ldb = ldb_module_get_ctx(module); /* TODO search to include deleted objects */ ret = ldb_search(ldb, req, &acl_res, req->op.rename.olddn, LDB_SCOPE_BASE, acl_attrs, NULL); /* we sould be able to find the parent */ if (ret != LDB_SUCCESS) { DEBUG(10,("acl: failed to find object %s\n", ldb_dn_get_linearized(req->op.rename.olddn))); return ret; } guid = get_oc_guid_from_message(module,acl_res->msgs[0]); if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP, &root, &new_node)) { return LDB_ERR_OPERATIONS_ERROR; }; guid = attribute_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb), "name"); if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP, &new_node, &new_node)) { return LDB_ERR_OPERATIONS_ERROR; }; ret = get_sd_from_ldb_message(req, acl_res->msgs[0], &sd); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } /* Theoretically we pass the check if the object has no sd */ if (!sd) { return LDB_SUCCESS; } ret = get_dom_sid_from_ldb_message(req, acl_res->msgs[0], &sid); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } status = sec_access_check_ds(sd, acl_user_token(module), SEC_ADS_WRITE_PROP, &access_granted, root, sid); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Object %s nas no wp on name\n", ldb_dn_get_linearized(req->op.rename.olddn))); acl_debug(sd, acl_user_token(module), req->op.rename.olddn, true, 10); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } if (ldb_dn_compare(oldparent, newparent) == 0) { /* regular rename, not move, nothing more to do */ return ldb_next_request(module, req); } /* What exactly to do in this case? It would fail anyway.. */ if ((ldb_dn_compare(req->op.rename.newdn, (ldb_get_schema_basedn(ldb))) == 0) || (ldb_dn_compare(req->op.rename.newdn, (ldb_get_config_basedn(ldb))) == 0) || (ldb_dn_compare(req->op.rename.newdn, (ldb_get_root_basedn(ldb))) == 0)) { DEBUG(10,("acl:moving as an NC\n")); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } /* new parent should have create child */ talloc_free(tmp_ctx); tmp_ctx = talloc_new(req); root = NULL; new_node = NULL; guid = get_oc_guid_from_message(module,acl_res->msgs[0]); if (!guid) { DEBUG(10,("acl:renamed object has no object class\n")); return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); } if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_CREATE_CHILD, &root, &new_node)) { return LDB_ERR_OPERATIONS_ERROR; } ret = check_access_on_dn(module, req, newparent, SEC_ADS_CREATE_CHILD, root); if (ret != LDB_SUCCESS) { DEBUG(10,("acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn))); return ret; } /* do we have delete object on the object? */ status = sec_access_check_ds(sd, acl_user_token(module), SEC_STD_DELETE, &access_granted, NULL, sid); if (NT_STATUS_IS_OK(status)) { return ldb_next_request(module, req); } /* what about delete child on the current parent */ ret = check_access_on_dn(module, req, oldparent, SEC_ADS_DELETE_CHILD, NULL); if (ret != LDB_SUCCESS) { DEBUG(10,("acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn))); return ldb_module_done(req, NULL, NULL, ret); } return ldb_next_request(module, req); }
static int acl_modify(struct ldb_module *module, struct ldb_request *req) { int ret; struct ldb_context *ldb = ldb_module_get_ctx(module); const struct dsdb_schema *schema = dsdb_get_schema(ldb); int i; bool modify_sd = false; const struct GUID *guid; uint32_t access_granted; struct object_tree *root = NULL; struct object_tree *new_node = NULL; NTSTATUS status; struct ldb_result *acl_res; struct security_descriptor *sd; struct dom_sid *sid = NULL; TALLOC_CTX *tmp_ctx = talloc_new(req); static const char *acl_attrs[] = { "nTSecurityDescriptor", "objectClass", "objectSid", NULL }; /* Don't print this debug statement if elements[0].name is going to be NULL */ if(req->op.mod.message->num_elements > 0) { DEBUG(10, ("ldb:acl_modify: %s\n", req->op.mod.message->elements[0].name)); } if (what_is_user(module) == SECURITY_SYSTEM) { return ldb_next_request(module, req); } if (ldb_dn_is_special(req->op.mod.message->dn)) { return ldb_next_request(module, req); } ret = ldb_search(ldb, req, &acl_res, req->op.mod.message->dn, LDB_SCOPE_BASE, acl_attrs, NULL); if (ret != LDB_SUCCESS) { return ret; } ret = get_sd_from_ldb_message(req, acl_res->msgs[0], &sd); if (ret != LDB_SUCCESS) { DEBUG(10, ("acl_modify: cannot get descriptor\n")); return ret; } /* Theoretically we pass the check if the object has no sd */ if (!sd) { return LDB_SUCCESS; } guid = get_oc_guid_from_message(module,acl_res->msgs[0]); if (!guid) { DEBUG(10, ("acl_modify: cannot get guid\n")); goto fail; } ret = get_dom_sid_from_ldb_message(req, acl_res->msgs[0], &sid); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP, &root, &new_node)) { DEBUG(10, ("acl_modify: cannot add to object tree\n")); goto fail; } for (i=0; i < req->op.mod.message->num_elements; i++){ const struct dsdb_attribute *attr; /* clearTextPassword is not in schema */ if (strcmp("clearTextPassword", req->op.mod.message->elements[i].name) == 0) { attr = dsdb_attribute_by_lDAPDisplayName(schema, "unicodePwd"); } else { attr = dsdb_attribute_by_lDAPDisplayName(schema, req->op.mod.message->elements[i].name); } if (strcmp("nTSecurityDescriptor", req->op.mod.message->elements[i].name) == 0) { modify_sd = true; } else { if (!attr) { DEBUG(10, ("acl_modify: cannot find attribute %s\n", req->op.mod.message->elements[i].name)); goto fail; } if (!insert_in_object_tree(tmp_ctx, &attr->attributeSecurityGUID, SEC_ADS_WRITE_PROP, &new_node, &new_node)) { DEBUG(10, ("acl_modify: cannot add to object tree securityGUID\n")); goto fail; } if (!insert_in_object_tree(tmp_ctx, &attr->schemaIDGUID, SEC_ADS_WRITE_PROP, &new_node, &new_node)) { DEBUG(10, ("acl_modify: cannot add to object tree attributeGUID\n")); goto fail; } } } if (root->num_of_children > 0) { status = sec_access_check_ds(sd, acl_user_token(module), SEC_ADS_WRITE_PROP, &access_granted, root, sid); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Object %s nas no write property access\n", ldb_dn_get_linearized(req->op.mod.message->dn))); acl_debug(sd, acl_user_token(module), req->op.mod.message->dn, true, 10); talloc_free(tmp_ctx); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } } if (modify_sd) { status = sec_access_check_ds(sd, acl_user_token(module), SEC_STD_WRITE_DAC, &access_granted, NULL, sid); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Object %s nas no write dacl access\n", ldb_dn_get_linearized(req->op.mod.message->dn))); acl_debug(sd, acl_user_token(module), req->op.mod.message->dn, true, 10); talloc_free(tmp_ctx); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } } talloc_free(tmp_ctx); return ldb_next_request(module, req); fail: talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; }
/* 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); }
static int ltdb_add_internal(struct ldb_module *module, const struct ldb_message *msg, bool check_single_value) { struct ldb_context *ldb = ldb_module_get_ctx(module); int ret = LDB_SUCCESS; unsigned int i, j; for (i=0;i<msg->num_elements;i++) { struct ldb_message_element *el = &msg->elements[i]; const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, el->name); if (el->num_values == 0) { ldb_asprintf_errstring(ldb, "attribute '%s' on '%s' specified, but with 0 values (illegal)", el->name, ldb_dn_get_linearized(msg->dn)); return LDB_ERR_CONSTRAINT_VIOLATION; } if (check_single_value && el->num_values > 1 && ldb_tdb_single_valued(a, el)) { ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once", el->name, ldb_dn_get_linearized(msg->dn)); return LDB_ERR_CONSTRAINT_VIOLATION; } /* Do not check "@ATTRIBUTES" for duplicated values */ if (ldb_dn_is_special(msg->dn) && ldb_dn_check_special(msg->dn, LTDB_ATTRIBUTES)) { continue; } /* TODO: This is O(n^2) - replace with more efficient check */ for (j=0; j<el->num_values; j++) { if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) { ldb_asprintf_errstring(ldb, "attribute '%s': value #%u on '%s' provided more than once", el->name, j, ldb_dn_get_linearized(msg->dn)); return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; } } } ret = ltdb_store(module, msg, TDB_INSERT); if (ret != LDB_SUCCESS) { if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) { ldb_asprintf_errstring(ldb, "Entry %s already exists", ldb_dn_get_linearized(msg->dn)); } return ret; } ret = ltdb_index_add_new(module, msg); if (ret != LDB_SUCCESS) { return ret; } ret = ltdb_modified(module, msg->dn); return ret; }
/* Modify a record. */ int ldb_map_modify(struct ldb_module *module, struct ldb_request *req) { const struct ldb_message *msg = req->op.mod.message; struct ldb_request *search_req = NULL; struct ldb_message *remote_msg; struct ldb_context *ldb; struct map_context *ac; 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, skip to next module */ /* TODO: What if the remote part exists, the local doesn't, * and this request wants to modify local data and thus * add the local record? */ 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->remote_req); 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_mod_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); } /* prepare the search operation */ ret = map_search_self_req(&search_req, ac, msg->dn); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } return ldb_next_request(module, search_req); }
/* Add a record. */ int map_add(struct ldb_module *module, struct ldb_request *req) { const struct ldb_message *msg = req->op.add.message; struct ldb_handle *h; struct map_context *ac; struct ldb_message *local, *remote; const char *dn; /* 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 */ h = map_init_handle(req, module); if (h == NULL) { return LDB_ERR_OPERATIONS_ERROR; } ac = talloc_get_type(h->private_data, struct map_context); /* Prepare the local operation */ ac->local_req = talloc(ac, struct ldb_request); if (ac->local_req == NULL) { goto oom; } *(ac->local_req) = *req; /* copy the request */ ac->local_req->context = NULL; ac->local_req->callback = NULL; /* Prepare the remote operation */ ac->remote_req = talloc(ac, struct ldb_request); if (ac->remote_req == NULL) { goto oom; } *(ac->remote_req) = *req; /* copy the request */ ac->remote_req->context = NULL; ac->remote_req->callback = NULL; /* Prepare the local message */ local = ldb_msg_new(ac->local_req); if (local == NULL) { goto oom; } local->dn = msg->dn; /* Prepare the remote message */ remote = ldb_msg_new(ac->remote_req); if (remote == NULL) { goto oom; } remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn); /* Split local from remote message */ ldb_msg_partition(module, local, remote, msg); ac->local_req->op.add.message = local; ac->remote_req->op.add.message = remote; if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) { /* No local data or db, just run the remote request */ talloc_free(ac->local_req); req->handle = h; /* return our own handle to deal with this call */ return map_add_do_remote(h); } /* Store remote DN in 'IS_MAPPED' */ /* TODO: use GUIDs here instead */ dn = ldb_dn_linearize(local, remote->dn); if (ldb_msg_add_string(local, IS_MAPPED, dn) != 0) { goto failed; } req->handle = h; /* return our own handle to deal with this call */ return map_add_do_local(h); oom: map_oom(module); failed: talloc_free(h); return LDB_ERR_OPERATIONS_ERROR; }
static int samldb_add(struct ldb_module *module, struct ldb_request *req) { const struct ldb_message *msg = req->op.add.message; struct ldb_message *msg2 = NULL; struct ldb_request *down_req; int ret; ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_add_record\n"); if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */ return ldb_next_request(module, req); } /* is user or computer? */ if ((samdb_find_attribute(module->ldb, msg, "objectclass", "user") != NULL) || (samdb_find_attribute(module->ldb, msg, "objectclass", "computer") != NULL)) { /* add all relevant missing objects */ ret = samldb_fill_user_or_computer_object(module, msg, &msg2); if (ret) { return ret; } } /* is group? add all relevant missing objects */ if ( ! msg2 ) { if (samdb_find_attribute(module->ldb, msg, "objectclass", "group") != NULL) { ret = samldb_fill_group_object(module, msg, &msg2); if (ret) { return ret; } } } /* perhaps a foreignSecurityPrincipal? */ if ( ! msg2 ) { if (samdb_find_attribute(module->ldb, msg, "objectclass", "foreignSecurityPrincipal") != NULL) { ret = samldb_fill_foreignSecurityPrincipal_object(module, msg, &msg2); if (ret) { return ret; } } } if (msg2 == NULL) { return ldb_next_request(module, req); } down_req = talloc(req, struct ldb_request); if (down_req == NULL) { return LDB_ERR_OPERATIONS_ERROR; } *down_req = *req; down_req->op.add.message = talloc_steal(down_req, msg2); ldb_set_timeout_from_prev_req(module->ldb, req, down_req); /* go on with the call chain */ ret = ldb_next_request(module, down_req); /* do not free down_req as the call results may be linked to it, * it will be freed when the upper level request get freed */ if (ret == LDB_SUCCESS) { req->handle = down_req->handle; } return ret; }
/* return 0 if the given parse tree matches the given message. Assumes the message is in sorted order return 1 if it matches, and 0 if it doesn't match this is a recursive function, and does short-circuit evaluation */ static int ldb_match_message(struct ldb_context *ldb, const struct ldb_message *msg, const struct ldb_parse_tree *tree, enum ldb_scope scope, bool *matched) { unsigned int i; int ret; *matched = false; if (scope != LDB_SCOPE_BASE && ldb_dn_is_special(msg->dn)) { /* don't match special records except on base searches */ return LDB_SUCCESS; } switch (tree->operation) { case LDB_OP_AND: for (i=0;i<tree->u.list.num_elements;i++) { ret = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope, matched); if (ret != LDB_SUCCESS) return ret; if (!*matched) return LDB_SUCCESS; } *matched = true; return LDB_SUCCESS; case LDB_OP_OR: for (i=0;i<tree->u.list.num_elements;i++) { ret = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope, matched); if (ret != LDB_SUCCESS) return ret; if (*matched) return LDB_SUCCESS; } *matched = false; return LDB_SUCCESS; case LDB_OP_NOT: ret = ldb_match_message(ldb, msg, tree->u.isnot.child, scope, matched); if (ret != LDB_SUCCESS) return ret; *matched = ! *matched; return LDB_SUCCESS; case LDB_OP_EQUALITY: return ldb_match_equality(ldb, msg, tree, scope, matched); case LDB_OP_SUBSTRING: return ldb_match_substring(ldb, msg, tree, scope, matched); case LDB_OP_GREATER: return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_GREATER, matched); case LDB_OP_LESS: return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_LESS, matched); case LDB_OP_PRESENT: return ldb_match_present(ldb, msg, tree, scope, matched); case LDB_OP_APPROX: return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_APPROX, matched); case LDB_OP_EXTENDED: return ldb_match_extended(ldb, msg, tree, scope, matched); } return LDB_ERR_INAPPROPRIATE_MATCHING; }
static int subtree_delete(struct ldb_module *module, struct ldb_request *req) { static const char * const attrs[] = { NULL }; struct ldb_result *res = NULL; uint32_t flags; unsigned int i; int ret; if (ldb_dn_is_special(req->op.del.dn)) { /* do not manipulate our control entries */ return ldb_next_request(module, req); } /* see if we have any children */ ret = dsdb_module_search(module, req, &res, req->op.del.dn, LDB_SCOPE_ONELEVEL, attrs, DSDB_FLAG_NEXT_MODULE, req, "(objectClass=*)"); if (ret != LDB_SUCCESS) { talloc_free(res); return ret; } if (res->count == 0) { talloc_free(res); return ldb_next_request(module, req); } if (ldb_request_get_control(req, LDB_CONTROL_TREE_DELETE_OID) == NULL) { /* Do not add any DN outputs to this error string! * Some MMC consoles (eg release 2000) have a strange * bug and prevent subtree deletes afterwards. */ ldb_asprintf_errstring(ldb_module_get_ctx(module), "subtree_delete: Unable to " "delete a non-leaf node " "(it has %u children)!", res->count); talloc_free(res); return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF; } /* * First we sort the results from the leaf to the root */ LDB_TYPESAFE_QSORT(res->msgs, res->count, NULL, subtree_delete_sort); /* * we need to start from the top since other LDB modules could * enforce constraints (eg "objectclass" and "samldb" do so). * * We pass DSDB_FLAG_AS_SYSTEM as the acl module above us * has already checked for SEC_ADS_DELETE_TREE. */ flags = DSDB_FLAG_TOP_MODULE | DSDB_FLAG_AS_SYSTEM | DSDB_FLAG_TRUSTED | DSDB_TREE_DELETE; if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) { flags |= DSDB_MODIFY_RELAX; } for (i = 0; i < res->count; i++) { ret = dsdb_module_del(module, res->msgs[i]->dn, flags, req); if (ret != LDB_SUCCESS) { return ret; } } talloc_free(res); return ldb_next_request(module, req); }
static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA _dbuf, void *state) { int ret, i, j; struct ldb_dn *dn = state; struct ldb_message *msg = talloc_zero(NULL, struct ldb_message); struct ldb_val dbuf = { .data = _dbuf.dptr, .length = _dbuf.dsize, }; struct ldb_ldif ldif = { .msg = msg, .changetype = LDB_CHANGETYPE_NONE }; if (!msg) { return -1; } ret = ldb_unpack_data(ldb, &dbuf, msg); if (ret != 0) { fprintf(stderr, "Failed to parse record %*.*s as an LDB record\n", (int)key.dsize, (int)key.dsize, (char *)key.dptr); TALLOC_FREE(msg); return 0; } if (dn && ldb_dn_compare(msg->dn, dn) != 0) { TALLOC_FREE(msg); return 0; } if (!show_index && ldb_dn_is_special(msg->dn)) { const char *dn_lin = ldb_dn_get_linearized(msg->dn); if ((strcmp(dn_lin, "@BASEINFO") == 0) || (strncmp(dn_lin, "@INDEX:", strlen("@INDEX:")) == 0)) { /* the user has asked not to show index records. Also exclude BASEINFO as it contains meta-data which will be re-created if this database is restored */ TALLOC_FREE(msg); return 0; } } if (!validate_contents || ldb_dn_is_special(msg->dn)) { ldb_ldif_write_file(ldb, stdout, &ldif); TALLOC_FREE(msg); return 0; } for (i=0;i<msg->num_elements;i++) { const struct ldb_schema_attribute *a; a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name); for (j=0;j<msg->elements[i].num_values;j++) { struct ldb_val v; ret = a->syntax->ldif_write_fn(ldb, msg, &msg->elements[i].values[j], &v); if (ret != 0) { v = msg->elements[i].values[j]; if (ldb_should_b64_encode(ldb, &v)) { v.data = (uint8_t *)ldb_base64_encode(ldb, (char *)v.data, v.length); v.length = strlen((char *)v.data); } fprintf(stderr, "On %s element %s value %d (%*.*s) failed to convert to LDIF correctly, skipping possibly corrupt record\n", ldb_dn_get_linearized(msg->dn), msg->elements[i].name, j, (int)v.length, (int)v.length, v.data); TALLOC_FREE(msg); return 0; } } } ldb_ldif_write_file(ldb, stdout, &ldif); TALLOC_FREE(msg); return 0; } static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3,4); static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) { va_list ap; const char *name = tdb_name(tdb); const char *prefix = ""; if (!name) name = "unnamed"; switch (level) { case TDB_DEBUG_ERROR: prefix = "ERROR: "; break; case TDB_DEBUG_WARNING: prefix = "WARNING: "; break; case TDB_DEBUG_TRACE: return; default: case TDB_DEBUG_FATAL: prefix = "FATAL: "; break; } va_start(ap, fmt); fprintf(stderr, "tdb(%s): %s", name, prefix); vfprintf(stderr, fmt, ap); va_end(ap); }
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_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); }