Esempio n. 1
0
/*
  match a simple leaf node
*/
static int ldb_match_equality(struct ldb_context *ldb, 
			      const struct ldb_message *msg,
			      const struct ldb_parse_tree *tree,
			      enum ldb_scope scope,
			      bool *matched)
{
	unsigned int i;
	struct ldb_message_element *el;
	const struct ldb_schema_attribute *a;
	struct ldb_dn *valuedn;
	int ret;

	if (ldb_attr_dn(tree->u.equality.attr) == 0) {
		valuedn = ldb_dn_from_ldb_val(ldb, ldb, &tree->u.equality.value);
		if (valuedn == NULL) {
			return LDB_ERR_INVALID_DN_SYNTAX;
		}

		ret = ldb_dn_compare(msg->dn, valuedn);

		talloc_free(valuedn);

		*matched = (ret == 0);
		return LDB_SUCCESS;
	}

	/* TODO: handle the "*" case derived from an extended search
	   operation without the attibute type defined */
	el = ldb_msg_find_element(msg, tree->u.equality.attr);
	if (el == NULL) {
		*matched = false;
		return LDB_SUCCESS;
	}

	a = ldb_schema_attribute_by_name(ldb, el->name);
	if (a == NULL) {
		return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
	}

	for (i=0;i<el->num_values;i++) {
		if (a->syntax->operator_fn) {
			ret = a->syntax->operator_fn(ldb, LDB_OP_EQUALITY, a,
						     &tree->u.equality.value, &el->values[i], matched);
			if (ret != LDB_SUCCESS) return ret;
			if (*matched) return LDB_SUCCESS;
		} else {
			if (a->syntax->comparison_fn(ldb, ldb, &tree->u.equality.value,
						     &el->values[i]) == 0) {
				*matched = true;
				return LDB_SUCCESS;
			}
		}
	}

	*matched = false;
	return LDB_SUCCESS;
}
Esempio n. 2
0
/*
  delete all elements matching an attribute name/value

  return LDB Error on failure
*/
static int msg_delete_element(struct ldb_module *module,
			      struct ldb_message *msg,
			      const char *name,
			      const struct ldb_val *val)
{
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	unsigned int i;
	int found, ret;
	struct ldb_message_element *el;
	const struct ldb_schema_attribute *a;

	found = find_element(msg, name);
	if (found == -1) {
		return LDB_ERR_NO_SUCH_ATTRIBUTE;
	}

	i = (unsigned int) found;
	el = &(msg->elements[i]);

	a = ldb_schema_attribute_by_name(ldb, el->name);

	for (i=0;i<el->num_values;i++) {
		bool matched;
		if (a->syntax->operator_fn) {
			ret = a->syntax->operator_fn(ldb, LDB_OP_EQUALITY, a,
						     &el->values[i], val, &matched);
			if (ret != LDB_SUCCESS) return ret;
		} else {
			matched = (a->syntax->comparison_fn(ldb, ldb,
							    &el->values[i], val) == 0);
		}
		if (matched) {
			if (el->num_values == 1) {
				return msg_delete_attribute(module, ldb, msg, name);
			}

			ret = ltdb_index_del_value(module, msg->dn, el, i);
			if (ret != LDB_SUCCESS) {
				return ret;
			}

			if (i<el->num_values-1) {
				memmove(&el->values[i], &el->values[i+1],
					sizeof(el->values[i])*
						(el->num_values-(i+1)));
			}
			el->num_values--;

			/* per definition we find in a canonicalised message an
			   attribute value only once. So we are finished here */
			return LDB_SUCCESS;
		}
	}

	/* Not found */
	return LDB_ERR_NO_SUCH_ATTRIBUTE;
}
Esempio n. 3
0
static int ltdb_add_internal(struct ldb_module *module,
			     const struct ldb_message *msg)
{
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	int ret, i;

	ret = ltdb_check_special_dn(module, msg);
	if (ret != LDB_SUCCESS) {
		return ret;
	}

	if (ltdb_cache_load(module) != 0) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	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 (a && a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) {
			if (el->num_values > 1) {
				ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s speicified more than once", 
						       el->name, ldb_dn_get_linearized(msg->dn));
				return LDB_ERR_CONSTRAINT_VIOLATION;
			}
		}
	}

	ret = ltdb_store(module, msg, TDB_INSERT);

	if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
		ldb_asprintf_errstring(ldb,
					"Entry %s already exists",
					ldb_dn_get_linearized(msg->dn));
		return ret;
	}

	if (ret == LDB_SUCCESS) {
		ret = ltdb_index_one(module, msg, 1);
		if (ret != LDB_SUCCESS) {
			return ret;
		}

		ret = ltdb_modified(module, msg->dn);
		if (ret != LDB_SUCCESS) {
			return ret;
		}
	}

	return ret;
}
Esempio n. 4
0
static int ldb_match_comparison(struct ldb_context *ldb, 
				const struct ldb_message *msg,
				const struct ldb_parse_tree *tree,
				enum ldb_scope scope,
				enum ldb_parse_op comp_op, bool *matched)
{
	unsigned int i;
	struct ldb_message_element *el;
	const struct ldb_schema_attribute *a;

	/* FIXME: APPROX comparison not handled yet */
	if (comp_op == LDB_OP_APPROX) {
		return LDB_ERR_INAPPROPRIATE_MATCHING;
	}

	el = ldb_msg_find_element(msg, tree->u.comparison.attr);
	if (el == NULL) {
		*matched = false;
		return LDB_SUCCESS;
	}

	a = ldb_schema_attribute_by_name(ldb, el->name);
	if (!a) {
		return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
	}

	for (i = 0; i < el->num_values; i++) {
		if (a->syntax->operator_fn) {
			int ret;
			ret = a->syntax->operator_fn(ldb, comp_op, a, &el->values[i], &tree->u.comparison.value, matched);
			if (ret != LDB_SUCCESS) return ret;
			if (*matched) return LDB_SUCCESS;
		} else {
			int ret = a->syntax->comparison_fn(ldb, ldb, &el->values[i], &tree->u.comparison.value);

			if (ret == 0) {
				*matched = true;
				return LDB_SUCCESS;
			}
			if (ret > 0 && comp_op == LDB_OP_GREATER) {
				*matched = true;
				return LDB_SUCCESS;
			}
			if (ret < 0 && comp_op == LDB_OP_LESS) {
				*matched = true;
				return LDB_SUCCESS;
			}
		}
	}

	*matched = false;
	return LDB_SUCCESS;
}
Esempio n. 5
0
/*
  delete all elements matching an attribute name/value

  return 0 on success, -1 on failure
*/
static int msg_delete_element(struct ldb_module *module,
			      struct ldb_message *msg,
			      const char *name,
			      const struct ldb_val *val)
{
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	unsigned int i;
	int found, ret;
	struct ldb_message_element *el;
	const struct ldb_schema_attribute *a;

	found = find_element(msg, name);
	if (found == -1) {
		return -1;
	}

	el = &msg->elements[found];

	a = ldb_schema_attribute_by_name(ldb, el->name);

	for (i=0;i<el->num_values;i++) {
		if (a->syntax->comparison_fn(ldb, ldb,
					     &el->values[i], val) == 0) {
			if (el->num_values == 1) {
				return msg_delete_attribute(module, ldb, msg, name);
			}

			ret = ltdb_index_del_value(module, msg->dn, el, i);
			if (ret != LDB_SUCCESS) {
				return -1;
			}

			if (i<el->num_values-1) {
				memmove(&el->values[i], &el->values[i+1],
					sizeof(el->values[i])*
						(el->num_values-(i+1)));
			}
			el->num_values--;

			/* per definition we find in a canonicalised message an
			   attribute value only once. So we are finished here */
			return 0;
		}
	}

	/* Not found */
	return -1;
}
Esempio n. 6
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;

	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;
		}
	}

	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;
}
Esempio n. 7
0
/*
  return the dn key to be used for an index
  caller frees
*/
static struct ldb_dn *ltdb_index_key(struct ldb_context *ldb,
				     const char *attr, const struct ldb_val *value)
{
	struct ldb_dn *ret;
	struct ldb_val v;
	const struct ldb_schema_attribute *a;
	char *attr_folded;
	int r;

	attr_folded = ldb_attr_casefold(ldb, attr);
	if (!attr_folded) {
		return NULL;
	}

	a = ldb_schema_attribute_by_name(ldb, attr);
	r = a->syntax->canonicalise_fn(ldb, ldb, value, &v);
	if (r != LDB_SUCCESS) {
		const char *errstr = ldb_errstring(ldb);
		/* canonicalisation can be refused. For example, 
		   a attribute that takes wildcards will refuse to canonicalise
		   if the value contains a wildcard */
		ldb_asprintf_errstring(ldb, "Failed to create index key for attribute '%s':%s%s%s",
				       attr, ldb_strerror(r), (errstr?":":""), (errstr?errstr:""));
		talloc_free(attr_folded);
		return NULL;
	}
	if (ldb_should_b64_encode(&v)) {
		char *vstr = ldb_base64_encode(ldb, (char *)v.data, v.length);
		if (!vstr) return NULL;
		ret = ldb_dn_new_fmt(ldb, ldb, "%s:%s::%s", LTDB_INDEX, attr_folded, vstr);
		talloc_free(vstr);
	} else {
		ret = ldb_dn_new_fmt(ldb, ldb, "%s:%s:%.*s", LTDB_INDEX, attr_folded, (int)v.length, (char *)v.data);
	}

	if (v.data != value->data) {
		talloc_free(v.data);
	}
	talloc_free(attr_folded);

	return ret;
}
Esempio n. 8
0
/*
  match if node is present
*/
static int ldb_match_present(struct ldb_context *ldb, 
			     const struct ldb_message *msg,
			     const struct ldb_parse_tree *tree,
			     enum ldb_scope scope, bool *matched)
{
	const struct ldb_schema_attribute *a;
	struct ldb_message_element *el;

	if (ldb_attr_dn(tree->u.present.attr) == 0) {
		*matched = true;
		return LDB_SUCCESS;
	}

	el = ldb_msg_find_element(msg, tree->u.present.attr);
	if (el == NULL) {
		*matched = false;
		return LDB_SUCCESS;
	}

	a = ldb_schema_attribute_by_name(ldb, el->name);
	if (!a) {
		return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
	}

	if (a->syntax->operator_fn) {
		unsigned int i;
		for (i = 0; i < el->num_values; i++) {
			int ret = a->syntax->operator_fn(ldb, LDB_OP_PRESENT, a, &el->values[i], NULL, matched);
			if (ret != LDB_SUCCESS) return ret;
			if (*matched) return LDB_SUCCESS;
		}
		*matched = false;
		return LDB_SUCCESS;
	}

	*matched = true;
	return LDB_SUCCESS;
}
Esempio n. 9
0
File: ldb.c Progetto: gojdic/samba
static bool torture_ldb_attrs(struct torture_context *torture)
{
    TALLOC_CTX *mem_ctx = talloc_new(torture);
    struct ldb_context *ldb;
    const struct ldb_schema_attribute *attr;
    struct ldb_val string_sid_blob, binary_sid_blob;
    struct ldb_val string_guid_blob, string_guid_blob2, binary_guid_blob;

    DATA_BLOB sid_blob = strhex_to_data_blob(mem_ctx, hex_sid);
    DATA_BLOB guid_blob = strhex_to_data_blob(mem_ctx, hex_guid);

    torture_assert(torture,
                   ldb = ldb_init(mem_ctx, torture->ev),
                   "Failed to init ldb");

    torture_assert_int_equal(torture,
                             ldb_register_samba_handlers(ldb), 0,
                             "Failed to register Samba handlers");

    ldb_set_utf8_fns(ldb, NULL, wrap_casefold);

    /* Test SID behaviour */
    torture_assert(torture, attr = ldb_schema_attribute_by_name(ldb, "objectSid"),
                   "Failed to get objectSid schema attribute");

    string_sid_blob = data_blob_string_const(sid);

    torture_assert_int_equal(torture,
                             attr->syntax->ldif_read_fn(ldb, mem_ctx,
                                     &string_sid_blob, &binary_sid_blob), 0,
                             "Failed to parse string SID");

    torture_assert_data_blob_equal(torture, binary_sid_blob, sid_blob,
                                   "Read SID into blob form failed");

    torture_assert_int_equal(torture,
                             attr->syntax->ldif_read_fn(ldb, mem_ctx,
                                     &sid_blob, &binary_sid_blob), -1,
                             "Should have failed to parse binary SID");

    torture_assert_int_equal(torture,
                             attr->syntax->ldif_write_fn(ldb, mem_ctx, &binary_sid_blob, &string_sid_blob), 0,
                             "Failed to parse binary SID");

    torture_assert_data_blob_equal(torture,
                                   string_sid_blob, data_blob_string_const(sid),
                                   "Write SID into string form failed");

    torture_assert_int_equal(torture,
                             attr->syntax->comparison_fn(ldb, mem_ctx, &binary_sid_blob, &string_sid_blob), 0,
                             "Failed to compare binary and string SID");

    torture_assert_int_equal(torture,
                             attr->syntax->comparison_fn(ldb, mem_ctx, &string_sid_blob, &binary_sid_blob), 0,
                             "Failed to compare string and binary binary SID");

    torture_assert_int_equal(torture,
                             attr->syntax->comparison_fn(ldb, mem_ctx, &string_sid_blob, &string_sid_blob), 0,
                             "Failed to compare string and string SID");

    torture_assert_int_equal(torture,
                             attr->syntax->comparison_fn(ldb, mem_ctx, &binary_sid_blob, &binary_sid_blob), 0,
                             "Failed to compare binary and binary SID");

    torture_assert(torture, attr->syntax->comparison_fn(ldb, mem_ctx, &guid_blob, &binary_sid_blob) != 0,
                   "Failed to distinguish binary GUID and binary SID");


    /* Test GUID behaviour */
    torture_assert(torture, attr = ldb_schema_attribute_by_name(ldb, "objectGUID"),
                   "Failed to get objectGUID schema attribute");

    string_guid_blob = data_blob_string_const(guid);

    torture_assert_int_equal(torture,
                             attr->syntax->ldif_read_fn(ldb, mem_ctx,
                                     &string_guid_blob, &binary_guid_blob), 0,
                             "Failed to parse string GUID");

    torture_assert_data_blob_equal(torture, binary_guid_blob, guid_blob,
                                   "Read GUID into blob form failed");

    string_guid_blob2 = data_blob_string_const(guid2);

    torture_assert_int_equal(torture,
                             attr->syntax->ldif_read_fn(ldb, mem_ctx,
                                     &string_guid_blob2, &binary_guid_blob), 0,
                             "Failed to parse string GUID");

    torture_assert_data_blob_equal(torture, binary_guid_blob, guid_blob,
                                   "Read GUID into blob form failed");

    torture_assert_int_equal(torture,
                             attr->syntax->ldif_read_fn(ldb, mem_ctx,
                                     &guid_blob, &binary_guid_blob), 0,
                             "Failed to parse binary GUID");

    torture_assert_data_blob_equal(torture, binary_guid_blob, guid_blob,
                                   "Read GUID into blob form failed");

    torture_assert_int_equal(torture,
                             attr->syntax->ldif_write_fn(ldb, mem_ctx, &binary_guid_blob, &string_guid_blob), 0,
                             "Failed to print binary GUID as string");

    torture_assert_data_blob_equal(torture, string_sid_blob, data_blob_string_const(sid),
                                   "Write SID into string form failed");

    torture_assert_int_equal(torture,
                             attr->syntax->comparison_fn(ldb, mem_ctx, &binary_guid_blob, &string_guid_blob), 0,
                             "Failed to compare binary and string GUID");

    torture_assert_int_equal(torture,
                             attr->syntax->comparison_fn(ldb, mem_ctx, &string_guid_blob, &binary_guid_blob), 0,
                             "Failed to compare string and binary binary GUID");

    torture_assert_int_equal(torture,
                             attr->syntax->comparison_fn(ldb, mem_ctx, &string_guid_blob, &string_guid_blob), 0,
                             "Failed to compare string and string GUID");

    torture_assert_int_equal(torture,
                             attr->syntax->comparison_fn(ldb, mem_ctx, &binary_guid_blob, &binary_guid_blob), 0,
                             "Failed to compare binary and binary GUID");



    talloc_free(mem_ctx);
    return true;
}
Esempio n. 10
0
/*
  modify a record - internal interface

  yuck - this is O(n^2). Luckily n is usually small so we probably
  get away with it, but if we ever have really large attribute lists
  then we'll need to look at this again

  'req' is optional, and is used to specify controls if supplied
*/
int ltdb_modify_internal(struct ldb_module *module,
			 const struct ldb_message *msg,
			 struct ldb_request *req)
{
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	void *data = ldb_module_get_private(module);
	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
	TDB_DATA tdb_key, tdb_data;
	struct ldb_val ldb_data;
	struct ldb_message *msg2;
	unsigned int i, j, k;
	int ret = LDB_SUCCESS, idx;
	struct ldb_control *control_permissive = NULL;

	if (req) {
		control_permissive = ldb_request_get_control(req,
					LDB_CONTROL_PERMISSIVE_MODIFY_OID);
	}

	tdb_key = ltdb_key(module, msg->dn);
	if (!tdb_key.dptr) {
		return LDB_ERR_OTHER;
	}

	tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
	if (!tdb_data.dptr) {
		talloc_free(tdb_key.dptr);
		return ltdb_err_map(tdb_error(ltdb->tdb));
	}

	msg2 = ldb_msg_new(tdb_key.dptr);
	if (msg2 == NULL) {
		free(tdb_data.dptr);
		ret = LDB_ERR_OTHER;
		goto done;
	}

	ldb_data.data = tdb_data.dptr;
	ldb_data.length = tdb_data.dsize;

	ret = ldb_unpack_data(ldb_module_get_ctx(module), &ldb_data, msg2);
	free(tdb_data.dptr);
	if (ret == -1) {
		ret = LDB_ERR_OTHER;
		goto done;
	}

	if (!msg2->dn) {
		msg2->dn = msg->dn;
	}

	for (i=0; i<msg->num_elements; i++) {
		struct ldb_message_element *el = &msg->elements[i], *el2;
		struct ldb_val *vals;
		const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, el->name);
		const char *dn;

		switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
		case LDB_FLAG_MOD_ADD:

			if (el->num_values == 0) {
				ldb_asprintf_errstring(ldb,
						       "attribute '%s': attribute on '%s' specified, but with 0 values (illegal)",
						       el->name, ldb_dn_get_linearized(msg2->dn));
				ret = LDB_ERR_CONSTRAINT_VIOLATION;
				goto done;
			}

			/* make a copy of the array so that a permissive
			 * control can remove duplicates without changing the
			 * original values, but do not copy data as we do not
			 * need to keep it around once the operation is
			 * finished */
			if (control_permissive) {
				el = talloc(msg2, struct ldb_message_element);
				if (!el) {
					ret = LDB_ERR_OTHER;
					goto done;
				}
				*el = msg->elements[i];
				el->values = talloc_array(el, struct ldb_val, el->num_values);
				if (el->values == NULL) {
					ret = LDB_ERR_OTHER;
					goto done;
				}
				for (j = 0; j < el->num_values; j++) {
					el->values[j] = msg->elements[i].values[j];
				}
			}

			if (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(msg2->dn));
				ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
				goto done;
			}

			/* Checks if element already exists */
			idx = find_element(msg2, el->name);
			if (idx == -1) {
				if (ltdb_msg_add_element(ldb, msg2, el) != 0) {
					ret = LDB_ERR_OTHER;
					goto done;
				}
				ret = ltdb_index_add_element(module, msg2->dn,
							     el);
				if (ret != LDB_SUCCESS) {
					goto done;
				}
			} else {
				j = (unsigned int) idx;
				el2 = &(msg2->elements[j]);

				/* We cannot add another value on a existing one
				   if the attribute is single-valued */
				if (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(msg2->dn));
					ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
					goto done;
				}

				/* Check that values don't exist yet on multi-
				   valued attributes or aren't provided twice */
				/* TODO: This is O(n^2) - replace with more efficient check */
				for (j = 0; j < el->num_values; j++) {
					if (ldb_msg_find_val(el2, &el->values[j]) != NULL) {
						if (control_permissive) {
							/* remove this one as if it was never added */
							el->num_values--;
							for (k = j; k < el->num_values; k++) {
								el->values[k] = el->values[k + 1];
							}
							j--; /* rewind */

							continue;
						}

						ldb_asprintf_errstring(ldb,
								       "attribute '%s': value #%u on '%s' already exists",
								       el->name, j, ldb_dn_get_linearized(msg2->dn));
						ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
						goto done;
					}
					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(msg2->dn));
						ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
						goto done;
					}
				}

				/* Now combine existing and new values to a new
				   attribute record */
				vals = talloc_realloc(msg2->elements,
						      el2->values, struct ldb_val,
						      el2->num_values + el->num_values);
				if (vals == NULL) {
					ldb_oom(ldb);
					ret = LDB_ERR_OTHER;
					goto done;
				}

				for (j=0; j<el->num_values; j++) {
					vals[el2->num_values + j] =
						ldb_val_dup(vals, &el->values[j]);
				}

				el2->values = vals;
				el2->num_values += el->num_values;

				ret = ltdb_index_add_element(module, msg2->dn, el);
				if (ret != LDB_SUCCESS) {
					goto done;
				}
			}

			break;

		case LDB_FLAG_MOD_REPLACE:

			if (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(msg2->dn));
				ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
				goto done;
			}

			/* 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(msg2->dn));
					ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
					goto done;
				}
			}

			/* Checks if element already exists */
			idx = find_element(msg2, el->name);
			if (idx != -1) {
				j = (unsigned int) idx;
				el2 = &(msg2->elements[j]);

				/* we consider two elements to be
				 * equal only if the order
				 * matches. This allows dbcheck to
				 * fix the ordering on attributes
				 * where order matters, such as
				 * objectClass
				 */
				if (ldb_msg_element_equal_ordered(el, el2)) {
					continue;
				}

				/* Delete the attribute if it exists in the DB */
				if (msg_delete_attribute(module, ldb, msg2,
							 el->name) != 0) {
					ret = LDB_ERR_OTHER;
					goto done;
				}
			}

			/* Recreate it with the new values */
			if (ltdb_msg_add_element(ldb, msg2, el) != 0) {
				ret = LDB_ERR_OTHER;
				goto done;
			}

			ret = ltdb_index_add_element(module, msg2->dn, el);
			if (ret != LDB_SUCCESS) {
				goto done;
			}

			break;

		case LDB_FLAG_MOD_DELETE:
			dn = ldb_dn_get_linearized(msg2->dn);
			if (dn == NULL) {
				ret = LDB_ERR_OTHER;
				goto done;
			}

			if (msg->elements[i].num_values == 0) {
				/* Delete the whole attribute */
				ret = msg_delete_attribute(module, ldb, msg2,
							   msg->elements[i].name);
				if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE &&
				    control_permissive) {
					ret = LDB_SUCCESS;
				} else {
					ldb_asprintf_errstring(ldb,
							       "attribute '%s': no such attribute for delete on '%s'",
							       msg->elements[i].name, dn);
				}
				if (ret != LDB_SUCCESS) {
					goto done;
				}
			} else {
				/* Delete specified values from an attribute */
				for (j=0; j < msg->elements[i].num_values; j++) {
					ret = msg_delete_element(module,
							         msg2,
							         msg->elements[i].name,
							         &msg->elements[i].values[j]);
					if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE &&
					    control_permissive) {
						ret = LDB_SUCCESS;
					} else {
						ldb_asprintf_errstring(ldb,
								       "attribute '%s': no matching attribute value while deleting attribute on '%s'",
								       msg->elements[i].name, dn);
					}
					if (ret != LDB_SUCCESS) {
						goto done;
					}
				}
			}
			break;
		default:
			ldb_asprintf_errstring(ldb,
					       "attribute '%s': invalid modify flags on '%s': 0x%x",
					       msg->elements[i].name, ldb_dn_get_linearized(msg->dn),
					       msg->elements[i].flags & LDB_FLAG_MOD_MASK);
			ret = LDB_ERR_PROTOCOL_ERROR;
			goto done;
		}
	}

	ret = ltdb_store(module, msg2, TDB_MODIFY);
	if (ret != LDB_SUCCESS) {
		goto done;
	}

	ret = ltdb_modified(module, msg2->dn);
	if (ret != LDB_SUCCESS) {
		goto done;
	}

done:
	talloc_free(tdb_key.dptr);
	return ret;
}
Esempio n. 11
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;
}
Esempio n. 12
0
static int ldb_wildcard_compare(struct ldb_context *ldb,
				const struct ldb_parse_tree *tree,
				const struct ldb_val value, bool *matched)
{
	const struct ldb_schema_attribute *a;
	struct ldb_val val;
	struct ldb_val cnk;
	struct ldb_val *chunk;
	char *p, *g;
	uint8_t *save_p = NULL;
	unsigned int c = 0;

	a = ldb_schema_attribute_by_name(ldb, tree->u.substring.attr);
	if (!a) {
		return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
	}

	if (tree->u.substring.chunks == NULL) {
		*matched = false;
		return LDB_SUCCESS;
	}

	if (a->syntax->canonicalise_fn(ldb, ldb, &value, &val) != 0) {
		return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
	}

	save_p = val.data;
	cnk.data = NULL;

	if ( ! tree->u.substring.start_with_wildcard ) {

		chunk = tree->u.substring.chunks[c];
		if (a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto mismatch;

		/* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */
		if (cnk.length > val.length) {
			goto mismatch;
		}
		if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) goto mismatch;
		val.length -= cnk.length;
		val.data += cnk.length;
		c++;
		talloc_free(cnk.data);
		cnk.data = NULL;
	}

	while (tree->u.substring.chunks[c]) {

		chunk = tree->u.substring.chunks[c];
		if(a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto mismatch;

		/* FIXME: case of embedded nulls */
		p = strstr((char *)val.data, (char *)cnk.data);
		if (p == NULL) goto mismatch;
		if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) {
			do { /* greedy */
				g = strstr((char *)p + cnk.length, (char *)cnk.data);
				if (g) p = g;
			} while(g);
		}
		val.length = val.length - (p - (char *)(val.data)) - cnk.length;
		val.data = (uint8_t *)(p + cnk.length);
		c++;
		talloc_free(cnk.data);
		cnk.data = NULL;
	}

	/* last chunk may not have reached end of string */
	if ( (! tree->u.substring.end_with_wildcard) && (*(val.data) != 0) ) goto mismatch;
	talloc_free(save_p);
	*matched = true;
	return LDB_SUCCESS;

mismatch:
	*matched = false;
	talloc_free(save_p);
	talloc_free(cnk.data);
	return LDB_SUCCESS;
}
Esempio n. 13
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);
}
Esempio n. 14
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);
}
Esempio n. 15
0
/*
  modify a record - internal interface

  yuck - this is O(n^2). Luckily n is usually small so we probably
  get away with it, but if we ever have really large attribute lists
  then we'll need to look at this again

  'req' is optional, and is used to specify controls if supplied
*/
int ltdb_modify_internal(struct ldb_module *module,
			 const struct ldb_message *msg,
			 struct ldb_request *req)
{
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	void *data = ldb_module_get_private(module);
	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
	TDB_DATA tdb_key, tdb_data;
	struct ldb_message *msg2;
	unsigned i, j;
	int ret = LDB_SUCCESS, idx;

	tdb_key = ltdb_key(module, msg->dn);
	if (!tdb_key.dptr) {
		return LDB_ERR_OTHER;
	}

	tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
	if (!tdb_data.dptr) {
		talloc_free(tdb_key.dptr);
		return ltdb_err_map(tdb_error(ltdb->tdb));
	}

	msg2 = talloc(tdb_key.dptr, struct ldb_message);
	if (msg2 == NULL) {
		free(tdb_data.dptr);
		ret = LDB_ERR_OTHER;
		goto done;
	}

	ret = ltdb_unpack_data(module, &tdb_data, msg2);
	free(tdb_data.dptr);
	if (ret == -1) {
		ret = LDB_ERR_OTHER;
		goto done;
	}

	if (!msg2->dn) {
		msg2->dn = msg->dn;
	}

	for (i=0; i<msg->num_elements; i++) {
		struct ldb_message_element *el = &msg->elements[i], *el2;
		struct ldb_val *vals;
		const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, el->name);
		const char *dn;

		if (ldb_attr_cmp(el->name, "distinguishedName") == 0) {
			ldb_asprintf_errstring(ldb, "it is not permitted to perform a modify on 'distinguishedName' (use rename instead): %s",
					       ldb_dn_get_linearized(msg2->dn));
			ret = LDB_ERR_CONSTRAINT_VIOLATION;
			goto done;
		}

		switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
		case LDB_FLAG_MOD_ADD:
			if (el->num_values == 0) {
				ldb_asprintf_errstring(ldb, "attribute %s on %s specified, but with 0 values (illigal)",
						       el->name, ldb_dn_get_linearized(msg2->dn));
				ret = LDB_ERR_CONSTRAINT_VIOLATION;
				goto done;
			}

			if (a && a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) {
				if (el->num_values > 1) {
					ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
						               el->name, ldb_dn_get_linearized(msg2->dn));
					ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
					goto done;
				}
			}

			/* Checks if element already exists */
			idx = find_element(msg2, el->name);
			if (idx == -1) {
				if (ltdb_msg_add_element(ldb, msg2, el) != 0) {
					ret = LDB_ERR_OTHER;
					goto done;
				}
				ret = ltdb_index_add_element(module, msg2->dn, el);
				if (ret != LDB_SUCCESS) {
					goto done;
				}
			} else {
				/* We cannot add another value on a existing one
				   if the attribute is single-valued */
				if (a && a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) {
					ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
						               el->name, ldb_dn_get_linearized(msg2->dn));
					ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
					goto done;
				}

				el2 = &(msg2->elements[idx]);

				/* Check that values don't exist yet on multi-
				   valued attributes or aren't provided twice */
				for (j=0; j<el->num_values; j++) {
					if (ldb_msg_find_val(el2, &el->values[j]) != NULL) {
						ldb_asprintf_errstring(ldb, "%s: value #%d already exists", el->name, j);
						ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
						goto done;
					}
					if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) {
						ldb_asprintf_errstring(ldb, "%s: value #%d provided more than once", el->name, j);
						ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
						goto done;
					}
				}

				/* Now combine existing and new values to a new
				   attribute record */
				vals = talloc_realloc(msg2->elements,
						      el2->values, struct ldb_val,
						      el2->num_values + el->num_values);
				if (vals == NULL) {
					ldb_oom(ldb);
					ret = LDB_ERR_OTHER;
					goto done;
				}

				for (j=0; j<el->num_values; j++) {
					vals[el2->num_values + j] =
						ldb_val_dup(vals, &el->values[j]);
				}

				el2->values = vals;
				el2->num_values += el->num_values;

				ret = ltdb_index_add_element(module, msg2->dn, el);
				if (ret != LDB_SUCCESS) {
					goto done;
				}
			}

			break;

		case LDB_FLAG_MOD_REPLACE:
			if (a && a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) {
				/* the RELAX control overrides this
				   check for replace. This is needed as
				   DRS replication can produce multiple
				   values here for a single valued
				   attribute when the values are deleted
				   links
				*/
				if (el->num_values > 1 &&
				    (!req || !ldb_request_get_control(req, LDB_CONTROL_RELAX_OID))) {
					ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
						               el->name, ldb_dn_get_linearized(msg2->dn));
					ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
					goto done;
				}
			}

			/* 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, "%s: value #%d provided more than once", el->name, j);
					ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
					goto done;
				}
			}

			idx = find_element(msg2, el->name);
			if (idx != -1) {
				el2 = &(msg2->elements[idx]);
				if (ldb_msg_element_compare(el, el2) == 0) {
					/* we are replacing with the same values */
					continue;
				}
			
				/* Delete the attribute if it exists in the DB */
				if (msg_delete_attribute(module, ldb, msg2, el->name) != 0) {
					ret = LDB_ERR_OTHER;
					goto done;
				}
			}

			/* Recreate it with the new values */
			if (ltdb_msg_add_element(ldb, msg2, el) != 0) {
				ret = LDB_ERR_OTHER;
				goto done;
			}

			ret = ltdb_index_add_element(module, msg2->dn, el);
			if (ret != LDB_SUCCESS) {
				goto done;
			}

			break;

		case LDB_FLAG_MOD_DELETE:
			dn = ldb_dn_get_linearized(msg2->dn);
			if (dn == NULL) {
				ret = LDB_ERR_OTHER;
				goto done;
			}

			if (msg->elements[i].num_values == 0) {
				/* Delete the whole attribute */
				if (msg_delete_attribute(module, ldb, msg2,
							 msg->elements[i].name) != 0) {
					ldb_asprintf_errstring(ldb, "No such attribute: %s for delete on %s",
							       msg->elements[i].name, dn);
					ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
					goto done;
				}
			} else {
				/* Delete specified values from an attribute */
				for (j=0; j < msg->elements[i].num_values; j++) {
					if (msg_delete_element(module,
							       msg2,
							       msg->elements[i].name,
							       &msg->elements[i].values[j]) != 0) {
						ldb_asprintf_errstring(ldb, "No matching attribute value when deleting attribute: %s on %s",
								       msg->elements[i].name, dn);
						ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
						goto done;
					}
				}
			}
			break;
		default:
			ldb_asprintf_errstring(ldb,
				"Invalid ldb_modify flags on %s: 0x%x",
				msg->elements[i].name,
				msg->elements[i].flags & LDB_FLAG_MOD_MASK);
			ret = LDB_ERR_PROTOCOL_ERROR;
			goto done;
		}
	}

	ret = ltdb_store(module, msg2, TDB_MODIFY);
	if (ret != LDB_SUCCESS) {
		goto done;
	}

	ret = ltdb_modified(module, msg2->dn);
	if (ret != LDB_SUCCESS) {
		goto done;
	}

done:
	talloc_free(tdb_key.dptr);
	return ret;
}