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

📄 partition.c

📁 samba最新软件
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    Partitions ldb module   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006   Copyright (C) Stefan Metzmacher <metze@samba.org> 2007   * NOTICE: this module is NOT released under the GNU LGPL license as   * other ldb code. This module is release under the GNU GPL v3 or   * later license.   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 partitions module * *  Description: Implement LDAP partitions * *  Author: Andrew Bartlett *  Author: Stefan Metzmacher */#include "includes.h"#include "ldb/include/ldb_includes.h"#include "dsdb/samdb/samdb.h"struct partition_private_data {	struct dsdb_control_current_partition **partitions;	struct ldb_dn **replicate;};struct partition_context {	struct ldb_module *module;	struct ldb_request *orig_req;	struct ldb_request **down_req;	int num_requests;	int finished_requests;};static struct partition_context *partition_init_handle(struct ldb_request *req, struct ldb_module *module){	struct partition_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 partition_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->orig_req = req;	req->handle = h;	return ac;}static struct ldb_module *make_module_for_next_request(TALLOC_CTX *mem_ctx, 						       struct ldb_context *ldb,						       struct ldb_module *module){	struct ldb_module *current;	static const struct ldb_module_ops ops; /* zero */	current = talloc_zero(mem_ctx, struct ldb_module);	if (current == NULL) {		return module;	}		current->ldb = ldb;	current->ops = &ops;	current->prev = NULL;	current->next = module;	return current;}static struct dsdb_control_current_partition *find_partition(struct partition_private_data *data,							     struct ldb_dn *dn){	int i;	/* Look at base DN */	/* Figure out which partition it is under */	/* Skip the lot if 'data' isn't here yet (initialistion) */	for (i=0; data && data->partitions && data->partitions[i]; i++) {		if (ldb_dn_compare_base(data->partitions[i]->dn, dn) == 0) {			return data->partitions[i];		}	}	return NULL;};/** * fire the caller's callback for every entry, but only send 'done' once. */static int partition_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares){	struct partition_context *ac;	ac = talloc_get_type(context, struct partition_context);	if (ares->type == LDB_REPLY_ENTRY) {		return ac->orig_req->callback(ldb, ac->orig_req->context, ares);	} else {		ac->finished_requests++;		if (ac->finished_requests == ac->num_requests) {			return ac->orig_req->callback(ldb, ac->orig_req->context, ares);		} else {			talloc_free(ares);			return LDB_SUCCESS;		}	}}/** * only fire the 'last' callback, and only for START-TLS for now  */static int partition_other_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares){	struct partition_context *ac;	ac = talloc_get_type(context, struct partition_context);	if (!ac->orig_req->callback) {		talloc_free(ares);		return LDB_SUCCESS;	}	if (!ares 	    || (ares->type == LDB_REPLY_EXTENDED 		&& strcmp(ares->response->oid, LDB_EXTENDED_START_TLS_OID))) {		ac->finished_requests++;		if (ac->finished_requests == ac->num_requests) {			return ac->orig_req->callback(ldb, ac->orig_req->context, ares);		}		talloc_free(ares);		return LDB_SUCCESS;	}	ldb_set_errstring(ldb, "partition_other_callback: Unknown reply type, only supports START_TLS");	talloc_free(ares);	return LDB_ERR_OPERATIONS_ERROR;}static int partition_send_request(struct partition_context *ac, 				  struct dsdb_control_current_partition *partition){	int ret;	struct ldb_module *backend;	struct ldb_request *req;	if (partition) {		backend = make_module_for_next_request(ac, ac->module->ldb, partition->module);	} else {		backend = ac->module;	}	ac->down_req = talloc_realloc(ac, ac->down_req, 					struct ldb_request *, ac->num_requests + 1);	if (!ac->down_req) {		ldb_oom(ac->module->ldb);		return LDB_ERR_OPERATIONS_ERROR;	}	req = ac->down_req[ac->num_requests] = talloc(ac, struct ldb_request);	if (req == NULL) {		ldb_oom(ac->module->ldb);		return LDB_ERR_OPERATIONS_ERROR;	}		*req = *ac->orig_req; /* copy the request */	if (req->controls) {		req->controls			= talloc_memdup(req,					ac->orig_req->controls, talloc_get_size(ac->orig_req->controls));		if (req->controls == NULL) {			ldb_oom(ac->module->ldb);			return LDB_ERR_OPERATIONS_ERROR;		}	}	if (req->operation == LDB_SEARCH) {		/* If the search is for 'more' than this partition,		 * then change the basedn, so a remote LDAP server		 * doesn't object */		if (partition) {			if (ldb_dn_compare_base(partition->dn, req->op.search.base) != 0) {				req->op.search.base = partition->dn;			}		} else {			req->op.search.base = NULL;		}		req->callback = partition_search_callback;		req->context = ac;	} else {		req->callback = partition_other_callback;		req->context = ac;	}	if (partition) {		ret = ldb_request_add_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID, false, partition);		if (ret != LDB_SUCCESS) {			return ret;		}	}	/* Spray off search requests the backend */	ret = ldb_next_request(backend, req);	if (ret != LDB_SUCCESS) {		return ret;	}	ac->num_requests++;	return LDB_SUCCESS;}/** * Send a request down to all the partitions */static int partition_send_all(struct ldb_module *module, 			      struct partition_context *ac, 			      struct ldb_request *req) {	int i;	struct partition_private_data *data = talloc_get_type(module->private_data, 							      struct partition_private_data);	int ret = partition_send_request(ac, NULL);	if (ret != LDB_SUCCESS) {		return ret;	}	for (i=0; data && data->partitions && data->partitions[i]; i++) {		ret = partition_send_request(ac, data->partitions[i]);		if (ret != LDB_SUCCESS) {			return ret;		}	}	return LDB_SUCCESS;}/** * Figure out which backend a request needs to be aimed at.  Some * requests must be replicated to all backends */static int partition_replicate(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn) {	unsigned i;	int ret;	struct dsdb_control_current_partition *partition;	struct ldb_module *backend;	struct partition_private_data *data = talloc_get_type(module->private_data, 							      struct partition_private_data);		if (req->operation != LDB_SEARCH) {		/* Is this a special DN, we need to replicate to every backend? */		for (i=0; data->replicate && data->replicate[i]; i++) {			if (ldb_dn_compare(data->replicate[i], 					   dn) == 0) {				struct partition_context *ac;								ac = partition_init_handle(req, module);				if (!ac) {					return LDB_ERR_OPERATIONS_ERROR;				}								return partition_send_all(module, ac, req);			}		}	}	/* Otherwise, we need to find the partition to fire it to */	/* Find partition */	partition = find_partition(data, dn);	if (!partition) {		/*		 * if we haven't found a matching partition		 * pass the request to the main ldb		 *		 * TODO: we should maybe return an error here		 *       if it's not a special dn		 */		return ldb_next_request(module, req);	}	backend = make_module_for_next_request(req, module->ldb, partition->module);	if (!backend) {		return LDB_ERR_OPERATIONS_ERROR;	}	ret = ldb_request_add_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID, false, partition);	if (ret != LDB_SUCCESS) {		return ret;	}	/* issue request */	return ldb_next_request(backend, req);}/* search */static int partition_search(struct ldb_module *module, struct ldb_request *req){	struct ldb_control **saved_controls;		/* Find backend */	struct partition_private_data *data = talloc_get_type(module->private_data, 							      struct partition_private_data);	/* issue request */	/* (later) consider if we should be searching multiple	 * partitions (for 'invisible' partition behaviour */	struct ldb_control *search_control = ldb_request_get_control(req, LDB_CONTROL_SEARCH_OPTIONS_OID);	struct ldb_control *domain_scope_control = ldb_request_get_control(req, LDB_CONTROL_DOMAIN_SCOPE_OID);		struct ldb_search_options_control *search_options = NULL;	if (search_control) {		search_options = talloc_get_type(search_control->data, struct ldb_search_options_control);	}	/* Remove the domain_scope control, so we don't confuse a backend server */	if (domain_scope_control && !save_controls(domain_scope_control, req, &saved_controls)) {		ldb_oom(module->ldb);		return LDB_ERR_OPERATIONS_ERROR;	}	/* TODO:	   Generate referrals (look for a partition under this DN) if we don't have the above control specified	*/		if (search_options && (search_options->search_options & LDB_SEARCH_OPTION_PHANTOM_ROOT)) {		int ret, i;		struct partition_context *ac;		if ((search_options->search_options & ~LDB_SEARCH_OPTION_PHANTOM_ROOT) == 0) {			/* We have processed this flag, so we are done with this control now */			/* Remove search control, so we don't confuse a backend server */			if (search_control && !save_controls(search_control, req, &saved_controls)) {				ldb_oom(module->ldb);				return LDB_ERR_OPERATIONS_ERROR;			}		}		ac = partition_init_handle(req, module);		if (!ac) {			return LDB_ERR_OPERATIONS_ERROR;		}		/* Search from the base DN */		if (!req->op.search.base || ldb_dn_is_null(req->op.search.base)) {			return partition_send_all(module, ac, req);		}		for (i=0; data && data->partitions && data->partitions[i]; i++) {			/* Find all partitions under the search base */			if (ldb_dn_compare_base(req->op.search.base, data->partitions[i]->dn) == 0) {				ret = partition_send_request(ac, data->partitions[i]);				if (ret != LDB_SUCCESS) {					return ret;				}			}		}		/* Perhaps we didn't match any partitions.  Try the main partition, only */		if (ac->num_requests == 0) {			talloc_free(ac);			return ldb_next_request(module, req);		}				return LDB_SUCCESS;	} else {		/* Handle this like all other requests */		if (search_control && (search_options->search_options & ~LDB_SEARCH_OPTION_PHANTOM_ROOT) == 0) {			/* We have processed this flag, so we are done with this control now */			/* Remove search control, so we don't confuse a backend server */			if (search_control && !save_controls(search_control, req, &saved_controls)) {				ldb_oom(module->ldb);				return LDB_ERR_OPERATIONS_ERROR;			}		}		return partition_replicate(module, req, req->op.search.base);	}}/* add */static int partition_add(struct ldb_module *module, struct ldb_request *req){	return partition_replicate(module, req, req->op.add.message->dn);}/* modify */static int partition_modify(struct ldb_module *module, struct ldb_request *req){	return partition_replicate(module, req, req->op.mod.message->dn);}/* delete */static int partition_delete(struct ldb_module *module, struct ldb_request *req){	return partition_replicate(module, req, req->op.del.dn);}/* rename */static int partition_rename(struct ldb_module *module, struct ldb_request *req){	int i, matched = -1;	/* Find backend */	struct dsdb_control_current_partition *backend, *backend2;		struct partition_private_data *data = talloc_get_type(module->private_data, 							      struct partition_private_data);	/* Skip the lot if 'data' isn't here yet (initialistion) */	if (!data) {		return LDB_ERR_OPERATIONS_ERROR;	}	backend = find_partition(data, req->op.rename.olddn);	backend2 = find_partition(data, req->op.rename.newdn);	if ((backend && !backend2) || (!backend && backend2)) {		return LDB_ERR_AFFECTS_MULTIPLE_DSAS;	}	if (backend != backend2) {		ldb_asprintf_errstring(module->ldb, 				       "Cannot rename from %s in %s to %s in %s: %s",				       ldb_dn_get_linearized(req->op.rename.olddn),				       ldb_dn_get_linearized(backend->dn),				       ldb_dn_get_linearized(req->op.rename.newdn),				       ldb_dn_get_linearized(backend2->dn),				       ldb_strerror(LDB_ERR_AFFECTS_MULTIPLE_DSAS));		return LDB_ERR_AFFECTS_MULTIPLE_DSAS;	}	for (i=0; data && data->partitions && data->partitions[i]; i++) {		if (ldb_dn_compare_base(req->op.rename.olddn, data->partitions[i]->dn) == 0) {			matched = i;		}	}	if (matched > 0) {		ldb_asprintf_errstring(module->ldb, 				       "Cannot rename from %s to %s, subtree rename would cross partition %s: %s",				       ldb_dn_get_linearized(req->op.rename.olddn),				       ldb_dn_get_linearized(req->op.rename.newdn),				       ldb_dn_get_linearized(data->partitions[matched]->dn),				       ldb_strerror(LDB_ERR_AFFECTS_MULTIPLE_DSAS));		return LDB_ERR_AFFECTS_MULTIPLE_DSAS;	}	return partition_replicate(module, req, req->op.rename.olddn);}/* start a transaction */static int partition_start_trans(struct ldb_module *module){	int i, ret;	struct partition_private_data *data = talloc_get_type(module->private_data, 							      struct partition_private_data);	/* Look at base DN */	/* Figure out which partition it is under */	/* Skip the lot if 'data' isn't here yet (initialistion) */	ret = ldb_next_start_trans(module);	if (ret != LDB_SUCCESS) {		return ret;	}	for (i=0; data && data->partitions && data->partitions[i]; i++) {		struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);		ret = ldb_next_start_trans(next);		talloc_free(next);		if (ret != LDB_SUCCESS) {			/* Back it out, if it fails on one */			for (i--; i >= 0; i--) {				next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);				ldb_next_del_trans(next);				talloc_free(next);			}			return ret;		}	}	return LDB_SUCCESS;}/* end a transaction */static int partition_end_trans(struct ldb_module *module){	int i, ret, ret2 = LDB_SUCCESS;	struct partition_private_data *data = talloc_get_type(module->private_data, 							      struct partition_private_data);	ret = ldb_next_end_trans(module);	if (ret != LDB_SUCCESS) {		return ret;	}	/* Look at base DN */

⌨️ 快捷键说明

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