diff options
Diffstat (limited to 'source4')
| -rw-r--r-- | source4/dsdb/samdb/ldb_modules/linked_attributes.c | 107 | 
1 files changed, 97 insertions, 10 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c index 3ad6f0ca8c..5ebf4efed4 100644 --- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c +++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c @@ -64,8 +64,59 @@ struct la_context {  	struct la_op_store *ops;  	struct ldb_extended *op_response;  	struct ldb_control **op_controls; +	/* +	 * For futur use +	 * will tell which GC to use for resolving links +	 */ +	char *gc_dns_name;  }; + +static int handle_verify_name_control(TALLOC_CTX *ctx, struct ldb_context *ldb, +					struct ldb_control *control, struct la_context *ac) +{ +	/* +	 * If we are a GC let's remove the control, +	 * if there is a specified GC check that is us. +	 */ +	struct ldb_verify_name_control *lvnc = (struct ldb_verify_name_control *)control->data; +	if (samdb_is_gc(ldb)) { +		/* Because we can't easily talloc a struct ldb_dn*/ +		struct ldb_dn **dn = talloc_array(ctx, struct ldb_dn *, 1); +		int ret = samdb_server_reference_dn(ldb, ctx, dn); +		const char *dns; + +		if (ret != LDB_SUCCESS) { +			return ldb_operr(ldb); +		} + +		dns = samdb_dn_to_dnshostname(ldb, ctx, *dn); +		if (!dns) { +			return ldb_operr(ldb); +		} +		if (!lvnc->gc || strcasecmp(dns, lvnc->gc) == 0) { +			if (!ldb_save_controls(control, ctx, NULL)) { +				return ldb_operr(ldb); +			} +		} else { +			control->critical = true; +		} +		talloc_free(dn); +	} else { +		/* For the moment we don't remove the control is this case in order +		 * to fail the request. It's better than having the client thinking +		 * that we honnor its control. +		 * Hopefully only a very small set of usecase should hit this problem. +		 */ +		if (lvnc->gc) { +			ac->gc_dns_name = talloc_strdup(ac, lvnc->gc); +		} +		control->critical = true; +	} + +	return LDB_SUCCESS; +} +  static struct la_context *linked_attributes_init(struct ldb_module *module,  						 struct ldb_request *req)  { @@ -189,6 +240,7 @@ static int linked_attributes_add(struct ldb_module *module, struct ldb_request *  	const char *attr_name;  	struct ldb_control *ctrl;  	unsigned int i, j; +	struct ldb_control *control;  	int ret;  	ldb = ldb_module_get_ctx(module); @@ -198,23 +250,33 @@ static int linked_attributes_add(struct ldb_module *module, struct ldb_request *  		return ldb_next_request(module, req);  	} +	ac = linked_attributes_init(module, req); +	if (!ac) { +		return ldb_operr(ldb); +	} + +	control = ldb_request_get_control(req, LDB_CONTROL_VERIFY_NAME_OID); +	if (control != NULL && control->data != NULL) { +		ret = handle_verify_name_control(req, ldb, control, ac); +		if (ret != LDB_SUCCESS) { +			return ldb_operr(ldb); +		} +	} +  	if (!(ctrl = ldb_request_get_control(req, DSDB_CONTROL_APPLY_LINKS))) {  		/* don't do anything special for linked attributes, repl_meta_data has done it */ +		talloc_free(ac);  		return ldb_next_request(module, req);  	}  	ctrl->critical = false; -	ac = linked_attributes_init(module, req); -	if (!ac) { -		return ldb_operr(ldb); -	} -  	if (!ac->schema) {  		/* without schema, this doesn't make any sense */  		talloc_free(ac);  		return ldb_next_request(module, req);  	} +  	/* 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]; @@ -409,6 +471,7 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques  	/* Determine the effect of the modification */  	/* Apply the modify to the linked entry */ +	struct ldb_control *control;  	struct ldb_context *ldb;  	unsigned int i, j;  	struct la_context *ac; @@ -424,17 +487,26 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques  		return ldb_next_request(module, req);  	} +	ac = linked_attributes_init(module, req); +	if (!ac) { +		return ldb_operr(ldb); +	} + +	control = ldb_request_get_control(req, LDB_CONTROL_VERIFY_NAME_OID); +	if (control != NULL && control->data != NULL) { +		ret = handle_verify_name_control(req, ldb, control, ac); +		if (ret != LDB_SUCCESS) { +			return ldb_operr(ldb); +		} +	} +  	if (!(ctrl = ldb_request_get_control(req, DSDB_CONTROL_APPLY_LINKS))) {  		/* don't do anything special for linked attributes, repl_meta_data has done it */ +		talloc_free(ac);  		return ldb_next_request(module, req);  	}  	ctrl->critical = false; -	ac = linked_attributes_init(module, req); -	if (!ac) { -		return ldb_operr(ldb); -	} -  	if (!ac->schema) {  		/* without schema, this doesn't make any sense */  		return ldb_next_request(module, req); @@ -1089,12 +1161,27 @@ static int linked_attributes_del_transaction(struct ldb_module *module)  	return ldb_next_del_trans(module);  } +static int linked_attributes_ldb_init(struct ldb_module *module) +{ +	int ret; + +	ret = ldb_mod_register_control(module, LDB_CONTROL_VERIFY_NAME_OID); +	if (ret != LDB_SUCCESS) { +		ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR, +			"verify_name: Unable to register control with rootdse!\n"); +		return ldb_operr(ldb_module_get_ctx(module)); +	} + +	return ldb_next_init(module); +} +  static const struct ldb_module_ops ldb_linked_attributes_module_ops = {  	.name		   = "linked_attributes",  	.add               = linked_attributes_add,  	.modify            = linked_attributes_modify,  	.rename            = linked_attributes_rename, +	.init_context      = linked_attributes_ldb_init,  	.start_transaction = linked_attributes_start_transaction,  	.prepare_commit    = linked_attributes_prepare_commit,  	.del_transaction   = linked_attributes_del_transaction,  | 
