Пример #1
0
/*
  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;
}
Пример #2
0
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);
}
Пример #3
0
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);
}
Пример #4
0
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);
}
Пример #5
0
/*
 * @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;
}
Пример #6
0
/* 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);
}
Пример #7
0
/*
  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;
}
Пример #8
0
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;
}
Пример #9
0
/*
  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;
}
Пример #10
0
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);
}
Пример #11
0
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;
}
Пример #12
0
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);
}
Пример #14
0
/*
 * @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;
}
Пример #15
0
/* 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);
}
Пример #16
0
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);
}
Пример #17
0
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;
}
Пример #18
0
/* 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);
}
Пример #19
0
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;
}
Пример #20
0
/* 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);
}
Пример #21
0
/* 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;
}
Пример #22
0
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;
}
Пример #23
0
/*
  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;
}
Пример #24
0
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);
}
Пример #25
0
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);
}
Пример #26
0
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);
}