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); }
/* 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); }
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); }
/* Rename the local record. */ static int map_rename_do_local(struct map_context *ac) { struct ldb_request *local_req; struct ldb_context *ldb; int ret; ldb = ldb_module_get_ctx(ac->module); /* No local record, continue remotely */ if (ac->local_dn == NULL) { /* Do the remote request. */ return ldb_next_remote_request(ac->module, ac->remote_req); } /* Prepare the local operation */ ret = ldb_build_rename_req(&local_req, ldb, ac, ac->req->op.rename.olddn, ac->req->op.rename.newdn, ac->req->controls, ac, map_rename_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 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 acl_search(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb; struct acl_context *ac; struct ldb_request *down_req; struct acl_private *data; int ret, i; ldb = ldb_module_get_ctx(module); ac = talloc_zero(req, struct acl_context); if (ac == NULL) { ldb_oom(ldb); return LDB_ERR_OPERATIONS_ERROR; } data = talloc_get_type(ldb_module_get_private(module), struct acl_private); ac->module = module; ac->req = req; ac->user_type = what_is_user(module); ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes"); ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective"); ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses"); ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective"); ac->sDRightsEffective = ldb_attr_in_list(req->op.search.attrs, "sDRightsEffective"); /* replace any attributes in the parse tree that are private, so we don't allow a search for 'userPassword=penguin', just as we would not allow that attribute to be returned */ if (ac->user_type != SECURITY_SYSTEM) { /* FIXME: We should copy the tree and keep the original unmodified. */ /* remove password attributes */ if (data && data->password_attrs) { for (i = 0; data->password_attrs[i]; i++) { ldb_parse_tree_attr_replace(req->op.search.tree, data->password_attrs[i], "kludgeACLredactedattribute"); } } } ret = ldb_build_search_req_ex(&down_req, ldb, ac, req->op.search.base, req->op.search.scope, req->op.search.tree, req->op.search.attrs, req->controls, ac, acl_search_callback, req); if (ret != LDB_SUCCESS) { return ret; } /* perform the search */ return ldb_next_request(module, down_req); }
/* TODO: free old DNs and messages? */ int ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request) { const struct ldb_map_context *data = map_get_context(module); struct ldb_context *ldb; struct ldb_message *msg; ldb = ldb_module_get_ctx(module); switch (request->operation) { case LDB_SEARCH: if (request->op.search.base) { request->op.search.base = ldb_dn_rebase_remote(request, data, request->op.search.base); } else { request->op.search.base = data->remote_base_dn; /* TODO: adjust scope? */ } break; case LDB_ADD: msg = ldb_msg_copy_shallow(request, request->op.add.message); if (msg == NULL) { return LDB_ERR_OPERATIONS_ERROR; } msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn); request->op.add.message = msg; break; case LDB_MODIFY: msg = ldb_msg_copy_shallow(request, request->op.mod.message); if (msg == NULL) { return LDB_ERR_OPERATIONS_ERROR; } msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn); request->op.mod.message = msg; break; case LDB_DELETE: request->op.del.dn = ldb_dn_rebase_remote(request, data, request->op.del.dn); break; case LDB_RENAME: request->op.rename.olddn = ldb_dn_rebase_remote(request, data, request->op.rename.olddn); request->op.rename.newdn = ldb_dn_rebase_remote(request, data, request->op.rename.newdn); break; default: ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: " "Invalid remote request!"); return LDB_ERR_OPERATIONS_ERROR; } return ldb_next_request(module, request); }
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); }
static int sample_modify(struct ldb_module *mod, struct ldb_request *req) { struct ldb_control *control; /* 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; } /* not found go on */ return ldb_next_request(mod, 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); }
/* 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. */ int map_add_do_local(struct ldb_handle *handle) { struct map_context *ac; ac = talloc_get_type(handle->private_data, struct map_context); ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req); ac->step = MAP_ADD_LOCAL; handle->state = LDB_ASYNC_INIT; handle->status = LDB_SUCCESS; return ldb_next_request(ac->module, ac->local_req); }
/* 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); }
int sample_add(struct ldb_module *mod, struct ldb_request *req) { struct ldb_control *control; struct ldb_control *controls; ldb_msg_add_fmt(req->op.add.message, "touchedBy", "sample"); /* check if there's a relax control */ control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID); if (control == NULL) { /* not found go on */ return ldb_next_request(mod, req); } else { return LDB_ERR_UNWILLING_TO_PERFORM; } }
/* Update the local 'IS_MAPPED' attribute. */ static int map_rename_do_fixup(struct map_context *ac) { struct ldb_request *local_req; /* Prepare the fixup operation */ /* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */ local_req = map_build_fixup_req(ac, ac->req->op.rename.newdn, ac->remote_req->op.rename.newdn, ac, map_op_local_callback); if (local_req == NULL) { 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); }
/* 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; }
/* search for attrs on one DN, in the modules below */ int dsdb_module_search_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_result **_res, struct ldb_dn *basedn, const char * const *attrs, uint32_t dsdb_flags, struct ldb_request *parent) { int ret; struct ldb_request *req; TALLOC_CTX *tmp_ctx; struct ldb_result *res; tmp_ctx = talloc_new(mem_ctx); res = talloc_zero(tmp_ctx, struct ldb_result); if (!res) { talloc_free(tmp_ctx); return ldb_oom(ldb_module_get_ctx(module)); } ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx, basedn, LDB_SCOPE_BASE, NULL, attrs, NULL, res, ldb_search_default_callback, parent); LDB_REQ_SET_LOCATION(req); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } ret = dsdb_request_add_controls(req, dsdb_flags); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } if (dsdb_flags & DSDB_FLAG_TRUSTED) { ldb_req_mark_trusted(req); } /* Run the new request */ if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) { ret = ldb_next_request(module, req); } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) { ret = ldb_request(ldb_module_get_ctx(module), req); } else { const struct ldb_module_ops *ops = ldb_module_get_ops(module); SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE); ret = ops->search(module, req); } if (ret == LDB_SUCCESS) { ret = ldb_wait(req->handle, LDB_WAIT_ALL); } if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } if (res->count != 1) { /* we may be reading a DB that does not have the 'check base on search' option... */ ret = LDB_ERR_NO_SUCH_OBJECT; ldb_asprintf_errstring(ldb_module_get_ctx(module), "dsdb_module_search_dn: did not find base dn %s (%d results)", ldb_dn_get_linearized(basedn), res->count); } else { *_res = talloc_steal(mem_ctx, res); } talloc_free(tmp_ctx); return ret; }
int dsdb_module_search_tree(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_result **_res, struct ldb_dn *basedn, enum ldb_scope scope, struct ldb_parse_tree *tree, const char * const *attrs, int dsdb_flags, struct ldb_request *parent) { int ret; struct ldb_request *req; TALLOC_CTX *tmp_ctx; struct ldb_result *res; tmp_ctx = talloc_new(mem_ctx); /* cross-partitions searches with a basedn break multi-domain support */ SMB_ASSERT(basedn == NULL || (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) == 0); res = talloc_zero(tmp_ctx, struct ldb_result); if (!res) { talloc_free(tmp_ctx); return ldb_oom(ldb_module_get_ctx(module)); } ret = ldb_build_search_req_ex(&req, ldb_module_get_ctx(module), tmp_ctx, basedn, scope, tree, attrs, NULL, res, ldb_search_default_callback, parent); LDB_REQ_SET_LOCATION(req); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } ret = dsdb_request_add_controls(req, dsdb_flags); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } if (dsdb_flags & DSDB_FLAG_TRUSTED) { ldb_req_mark_trusted(req); } if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) { ret = ldb_next_request(module, req); } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) { ret = ldb_request(ldb_module_get_ctx(module), req); } else { const struct ldb_module_ops *ops = ldb_module_get_ops(module); SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE); ret = ops->search(module, req); } if (ret == LDB_SUCCESS) { ret = ldb_wait(req->handle, LDB_WAIT_ALL); } talloc_free(req); if (ret == LDB_SUCCESS) { *_res = talloc_steal(mem_ctx, res); } talloc_free(tmp_ctx); return ret; }
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); }
int sample_add(struct ldb_module *mod, struct ldb_request *req) { ldb_msg_add_fmt(req->op.add.message, "touchedBy", "sample"); return ldb_next_request(mod, req); }
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; }
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; }
static int rdn_rename_callback(struct ldb_request *req, struct ldb_reply *ares) { struct ldb_context *ldb; struct rename_context *ac; struct ldb_request *mod_req; const char *rdn_name; struct ldb_val rdn_val; struct ldb_message *msg; int ret; ac = talloc_get_type(req->context, struct rename_context); ldb = ldb_module_get_ctx(ac->module); if (!ares) { goto error; } if (ares->error != LDB_SUCCESS) { return ldb_module_done(ac->req, ares->controls, ares->response, ares->error); } /* the only supported reply right now is a LDB_REPLY_DONE */ if (ares->type != LDB_REPLY_DONE) { goto error; } /* save reply for caller */ ac->ares = talloc_steal(ac, ares); msg = ldb_msg_new(ac); if (msg == NULL) { goto error; } msg->dn = ldb_dn_copy(msg, ac->req->op.rename.newdn); if (msg->dn == NULL) { goto error; } rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn); if (rdn_name == NULL) { goto error; } rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(ac->req->op.rename.newdn)); if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) { goto error; } if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) { goto error; } if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) { goto error; } if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) { goto error; } ret = ldb_build_mod_req(&mod_req, ldb, ac, msg, NULL, ac, rdn_modify_callback, req); if (ret != LDB_SUCCESS) { return ldb_module_done(ac->req, NULL, NULL, ret); } talloc_steal(mod_req, msg); /* go on with the call chain */ return ldb_next_request(ac->module, mod_req); error: return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); }
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); }
/* search for attrs on one DN, in the modules below */ int dsdb_module_search_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_result **_res, struct ldb_dn *basedn, const char * const *attrs, uint32_t dsdb_flags) { int ret; struct ldb_request *req; TALLOC_CTX *tmp_ctx; struct ldb_result *res; tmp_ctx = talloc_new(mem_ctx); res = talloc_zero(tmp_ctx, struct ldb_result); if (!res) { return LDB_ERR_OPERATIONS_ERROR; } ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx, basedn, LDB_SCOPE_BASE, NULL, attrs, NULL, res, ldb_search_default_callback, NULL); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } ret = dsdb_request_add_controls(module, req, dsdb_flags); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } ret = ldb_next_request(module, req); if (ret == LDB_SUCCESS) { ret = ldb_wait(req->handle, LDB_WAIT_ALL); } if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } if (res->count != 1) { /* we may be reading a DB that does not have the 'check base on search' option... */ ret = LDB_ERR_NO_SUCH_OBJECT; ldb_asprintf_errstring(ldb_module_get_ctx(module), "dsdb_module_search_dn: did not find base dn %s (%d results)", ldb_dn_get_linearized(basedn), res->count); } else { *_res = talloc_steal(mem_ctx, res); } talloc_free(tmp_ctx); return ret; }