⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 linked_attributes.c

📁 samba最新软件
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    ldb database library   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007   This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 3 of the License, or   (at your option) any later version.      This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.      You should have received a copy of the GNU General Public License   along with this program.  If not, see <http://www.gnu.org/licenses/>.*//* *  Name: ldb * *  Component: ldb linked_attributes module * *  Description: Module to ensure linked attribute pairs remain in sync * *  Author: Andrew Bartlett */#include "includes.h"#include "ldb/include/ldb.h"#include "ldb/include/ldb_errors.h"#include "ldb/include/ldb_private.h"#include "dsdb/samdb/samdb.h"struct linked_attributes_context {	enum la_step {LA_SEARCH, LA_DO_OPS, LA_DO_ORIG} step;	struct ldb_module *module;	struct ldb_handle *handle;	struct ldb_request *orig_req;	struct ldb_request *search_req;	struct ldb_request **down_req;	struct ldb_request *orig_down_req;	int num_requests;	int finished_requests;	const char **linked_attrs;};struct replace_context {	struct linked_attributes_context *ac;	struct ldb_message_element *el;};static int linked_attributes_rename_del_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares);static struct linked_attributes_context *linked_attributes_init_handle(struct ldb_request *req, 								 struct ldb_module *module){	struct linked_attributes_context *ac;	struct ldb_handle *h;	h = talloc_zero(req, struct ldb_handle);	if (h == NULL) {		ldb_set_errstring(module->ldb, "Out of Memory");		return NULL;	}	h->module = module;	ac = talloc_zero(h, struct linked_attributes_context);	if (ac == NULL) {		ldb_set_errstring(module->ldb, "Out of Memory");		talloc_free(h);		return NULL;	}	h->private_data	= ac;	ac->module = module;	ac->handle = h;	ac->orig_req = req;		ac->orig_down_req = talloc(ac, struct ldb_request);	if (!ac->orig_down_req) {		ldb_oom(ac->module->ldb);		return NULL;	}	*ac->orig_down_req = *req;	req->handle = h;	return ac;}/* Common routine to handle reading the attributes and creating a * series of modify requests */static int setup_modifies(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 			  struct linked_attributes_context *ac,			  const struct ldb_message *msg, 			  struct ldb_dn *olddn, struct ldb_dn *newdn) {	int i, j, ret = LDB_SUCCESS;	const struct dsdb_schema *schema = dsdb_get_schema(ldb);	/* Look up each of the returned attributes */	/* Find their schema */	/* And it is an actual entry: now create a series of modify requests */	for (i=0; i < msg->num_elements; i++) {		int otherid;		const struct dsdb_attribute *target_attr;		const struct ldb_message_element *el = &msg->elements[i];		const struct dsdb_attribute *schema_attr			= dsdb_attribute_by_lDAPDisplayName(schema, el->name);		if (!schema_attr) {			ldb_asprintf_errstring(ldb, 					       "attribute %s is not a valid attribute in schema", el->name);			return LDB_ERR_OBJECT_CLASS_VIOLATION;					}		/* We have a valid attribute, but if it's not linked they maybe we just got an extra return on our search... */		if (schema_attr->linkID == 0) {			continue;		}				/* Depending on which direction this link is in, we need to find it's partner */		if ((schema_attr->linkID & 1) == 1) {			otherid = schema_attr->linkID - 1;		} else {			otherid = schema_attr->linkID + 1;		}				/* Now find the target attribute */		target_attr = dsdb_attribute_by_linkID(schema, otherid);		if (!target_attr) {			ldb_asprintf_errstring(ldb, 					       "attribute %s does not have valid link target", el->name);			return LDB_ERR_OBJECT_CLASS_VIOLATION;					}				/* For each value being moded, we need to setup the modify */		for (j=0; j < el->num_values; j++) {			struct ldb_message_element *ret_el;			struct ldb_request *new_req;			struct ldb_message *new_msg;			/* Create a spot in the list for the requests */			ac->down_req = talloc_realloc(ac, ac->down_req, 						      struct ldb_request *, ac->num_requests + 1);			if (!ac->down_req) {				ldb_oom(ldb);				return LDB_ERR_OPERATIONS_ERROR;			}			/* Create the modify request */			new_msg = ldb_msg_new(ac->down_req);			if (!new_msg) {				ldb_oom(ldb);				return LDB_ERR_OPERATIONS_ERROR;			}			new_msg->dn = ldb_dn_new(new_msg, ldb, (char *)el->values[j].data);			if (!new_msg->dn) {				ldb_asprintf_errstring(ldb, 						       "attribute %s value %s was not a valid DN", msg->elements[i].name,						       el->values[j].data);				return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;			}						if (olddn) {				ret = ldb_msg_add_empty(new_msg, target_attr->lDAPDisplayName, 							LDB_FLAG_MOD_DELETE, &ret_el);				if (ret != LDB_SUCCESS) {					return ret;				}					ret_el->values = talloc_array(new_msg, struct ldb_val, 1);				if (!ret_el->values) {					ldb_oom(ldb);					return LDB_ERR_OPERATIONS_ERROR;				}				ret_el->values[0] = data_blob_string_const(ldb_dn_get_linearized(olddn));				ret_el->num_values = 1;			}						if (newdn) {				ret = ldb_msg_add_empty(new_msg, target_attr->lDAPDisplayName, 							LDB_FLAG_MOD_ADD, &ret_el);				if (ret != LDB_SUCCESS) {					return ret;				}					ret_el->values = talloc_array(new_msg, struct ldb_val, 1);				if (!ret_el->values) {					ldb_oom(ldb);					return LDB_ERR_OPERATIONS_ERROR;				}				ret_el->values[0] = data_blob_string_const(ldb_dn_get_linearized(newdn));				ret_el->num_values = 1;			}			ret = ldb_build_mod_req(&new_req, ldb, ac->down_req,						new_msg,						NULL,						NULL,						NULL);			if (ret != LDB_SUCCESS) {				return ret;			}						talloc_steal(new_req, new_msg);						ldb_set_timeout_from_prev_req(ldb, ac->orig_req, new_req);						ac->down_req[ac->num_requests] = new_req;			ac->num_requests++;						/* Run the new request */			ret = ldb_next_request(ac->module, new_req);			if (ret != LDB_SUCCESS) {				return ret;			}		}	}	return ret;}/* add */static int linked_attributes_add(struct ldb_module *module, struct ldb_request *req){	int i;	struct linked_attributes_context *ac;	const struct dsdb_schema *schema = dsdb_get_schema(module->ldb);	if (!schema) {		/* without schema, this doesn't make any sense */		return ldb_next_request(module, req);	}	if (ldb_dn_is_special(req->op.mod.message->dn)) {		/* do not manipulate our control entries */		return ldb_next_request(module, req);	}	ac = linked_attributes_init_handle(req, module);	if (!ac) {		return LDB_ERR_OPERATIONS_ERROR;	}		ac->step = LA_DO_OPS;		/* Need to ensure we only have forward links being specified */	for (i=0; i < req->op.add.message->num_elements; i++) {		const struct ldb_message_element *el = &req->op.add.message->elements[i];		const struct dsdb_attribute *schema_attr			= dsdb_attribute_by_lDAPDisplayName(schema, el->name);		if (!schema_attr) {			ldb_asprintf_errstring(module->ldb, 					       "attribute %s is not a valid attribute in schema", req->op.add.message->elements[i].name);			return LDB_ERR_OBJECT_CLASS_VIOLATION;					}		/* We have a valid attribute, not find out if it is linked */		if (schema_attr->linkID == 0) {			continue;		}				if ((schema_attr->linkID & 1) == 1) {			/* Odd is for the target.  Illigal to modify */			ldb_asprintf_errstring(module->ldb, 					       "attribute %s must not be modified directly, it is a linked attribute", req->op.add.message->elements[i].name);			return LDB_ERR_UNWILLING_TO_PERFORM;		}				/* Even link IDs are for the originating attribute */	}	/* Now call the common routine to setup the modifies across all the attributes */	return setup_modifies(module->ldb, ac, ac, req->op.add.message, NULL, req->op.add.message->dn);}struct merge {	struct ldb_dn *dn;	bool add;	bool ignore;};static int merge_cmp(struct merge *merge1, struct merge *merge2) {	int ret;	ret = ldb_dn_compare(merge1->dn, merge2->dn);	if (ret == 0) {		if (merge1->add == merge2->add) {			return 0;		}		if (merge1->add == true) {			return 1;		}		return -1;	}	return ret;}static int linked_attributes_mod_replace_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) {	struct replace_context *ac2 = talloc_get_type(context, struct replace_context);	struct linked_attributes_context *ac = ac2->ac;    	/* OK, we have one search result here: */	/* Only entries are interesting, and we only want the olddn */	if (ares->type == LDB_REPLY_ENTRY	    && ldb_dn_compare(ares->message->dn, ac->orig_req->op.mod.message->dn) == 0) {		/* only bother at all if there were some linked attributes found */		struct ldb_message_element *search_el			= ldb_msg_find_element(ares->message,					       ac2->el->name);				/* See if this element already exists */		if (search_el) {			struct merge *merged_list = NULL;			int ret, size = 0, i;			struct ldb_message *msg = ldb_msg_new(ac);			if (!msg) {				ldb_oom(ac->module->ldb);				return LDB_ERR_OPERATIONS_ERROR;			}			/* Add all the existing elements, marking as 'proposed for delete' by setting .add = false */			for (i=0; i < search_el->num_values; i++) {				merged_list = talloc_realloc(ares, merged_list, struct merge, size + 1);				merged_list[size].dn = ldb_dn_new(merged_list, ldb, (char *)search_el->values[i].data);				merged_list[size].add = false;				merged_list[size].ignore = false;				size++;			}			/* Add all the new replacement elements, marking as 'proposed for add' by setting .add = true */			for (i=0; i < ac2->el->num_values; i++) {				merged_list = talloc_realloc(ares, merged_list, struct merge, size + 1);				merged_list[size].dn = ldb_dn_new(merged_list, ldb, (char *)ac2->el->values[i].data);				merged_list[size].add = true;				merged_list[size].ignore = false;				size++;			}			/* Sort the list, so we can pick out an add and delete for the same DN, and eliminate them */			qsort(merged_list, size,			      sizeof(*merged_list),			      (comparison_fn_t)merge_cmp);			/* Now things are sorted, it is trivial to mark pairs of DNs as 'ignore' */			for (i=0; i + 1 < size; i++) {				if (ldb_dn_compare(merged_list[i].dn, 						   merged_list[i+1].dn) == 0 				    /* Fortunetly the sort also sorts 'add == false' first */				    && merged_list[i].add == false				    && merged_list[i+1].add == true) {					/* Mark as ignore, so we include neither in the actual operations */					merged_list[i].ignore = true;					merged_list[i+1].ignore = true;				}			}			/* Arrange to delete anything the search found that we don't re-add */			for (i=0; i < size; i++) {				if (merged_list[i].ignore == false				    && merged_list[i].add == false) {					ldb_msg_add_steal_string(msg, search_el->name, 								 ldb_dn_get_linearized(merged_list[i].dn));				}			}			/* The DN to set on the linked attributes is the original DN of the modify message */			msg->dn = ac->orig_req->op.mod.message->dn;						ret = setup_modifies(ac->module->ldb, ac2, ac, msg, ares->message->dn, NULL);			if (ret != LDB_SUCCESS) {				return ret;			}			/* Now add links for all the actually new elements */			for (i=0; i < size; i++) {				if (merged_list[i].ignore == false && merged_list[i].add == true) {					ldb_msg_add_steal_string(msg, search_el->name, 								 ldb_dn_get_linearized(merged_list[i].dn));				}			}			ret = setup_modifies(ac->module->ldb, ac2, ac, msg, NULL, ares->message->dn);			if (ret != LDB_SUCCESS) {				return ret;			}						talloc_free(merged_list);		} else {			/* Looks like it doesn't exist, process like an 'add' */			struct ldb_message *msg = ldb_msg_new(ac);			if (!msg) {				ldb_oom(ac->module->ldb);				return LDB_ERR_OPERATIONS_ERROR;			}			msg->num_elements = 1;			msg->elements = ac2->el;			msg->dn = ac->orig_req->op.mod.message->dn;			return setup_modifies(ac->module->ldb, ac2, ac, msg, NULL, ac->orig_req->op.mod.message->dn);		}		talloc_free(ares);		return LDB_SUCCESS;	} else if (ares->type == LDB_REPLY_ENTRY) {		/* Guh?  We only asked for this DN */		return LDB_ERR_OPERATIONS_ERROR;	} else {		talloc_free(ares);		return LDB_SUCCESS;	}		}/* modify */static int linked_attributes_modify(struct ldb_module *module, struct ldb_request *req){	/* Look over list of modifications */	/* Find if any are for linked attributes */	/* Determine the effect of the modification */	/* Apply the modify to the linked entry */	int i, j;	struct linked_attributes_context *ac;	const struct dsdb_schema *schema = dsdb_get_schema(module->ldb);	if (!schema) {		/* without schema, this doesn't make any sense */		return ldb_next_request(module, req);	}	if (ldb_dn_is_special(req->op.mod.message->dn)) {		/* do not manipulate our control entries */		return ldb_next_request(module, req);	}	ac = linked_attributes_init_handle(req, module);	if (!ac) {		return LDB_ERR_OPERATIONS_ERROR;	}		/* prepare the first operation */	ac->step = LA_DO_OPS;	for (i=0; i < req->op.mod.message->num_elements; i++) {		int ret;		struct ldb_request *new_req;		const struct dsdb_attribute *target_attr;		const struct ldb_message_element *el = &req->op.mod.message->elements[i];		const struct dsdb_attribute *schema_attr			= dsdb_attribute_by_lDAPDisplayName(schema, el->name);		if (!schema_attr) {			ldb_asprintf_errstring(module->ldb, 					       "attribute %s is not a valid attribute in schema", req->op.mod.message->elements[i].name);			return LDB_ERR_OBJECT_CLASS_VIOLATION;					}		/* We have a valid attribute, not find out if it is linked */		if (schema_attr->linkID == 0) {			continue;		}				if ((schema_attr->linkID & 1) == 1) {			/* Odd is for the target.  Illigal to modify */			ldb_asprintf_errstring(module->ldb, 					       "attribute %s must not be modified directly, it is a linked attribute", req->op.mod.message->elements[i].name);			return LDB_ERR_UNWILLING_TO_PERFORM;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -