Exemple #1
0
/*
  return an array of SIDs from a ldb_message given an attribute name
  assumes the SIDs are in extended DN format
 */
WERROR samdb_result_sid_array_dn(struct ldb_context *sam_ctx,
				 struct ldb_message *msg,
				 TALLOC_CTX *mem_ctx,
				 const char *attr,
				 const struct dom_sid ***sids)
{
	struct ldb_message_element *el;
	unsigned int i;

	el = ldb_msg_find_element(msg, attr);
	if (!el) {
		*sids = NULL;
		return WERR_OK;
	}

	(*sids) = talloc_array(mem_ctx, const struct dom_sid *, el->num_values + 1);
	W_ERROR_HAVE_NO_MEMORY(*sids);

	for (i=0; i<el->num_values; i++) {
		struct ldb_dn *dn = ldb_dn_from_ldb_val(mem_ctx, sam_ctx, &el->values[i]);
		NTSTATUS status;
		struct dom_sid *sid;

		sid = talloc(*sids, struct dom_sid);
		W_ERROR_HAVE_NO_MEMORY(sid);
		status = dsdb_get_extended_dn_sid(dn, sid, "SID");
		if (!NT_STATUS_IS_OK(status)) {
			return WERR_INTERNAL_DB_CORRUPTION;
		}
		(*sids)[i] = sid;
	}
	(*sids)[i] = NULL;

	return WERR_OK;
}
Exemple #2
0
/*
 * This function generates the transitive closure of a given SAM object "dn_val"
 * (it basically expands nested memberships).
 * If the object isn't located in the "res_sids" structure yet and the
 * "only_childs" flag is false, we add it to "res_sids".
 * Then we've always to consider the "memberOf" attributes. We invoke the
 * function recursively on each of it with the "only_childs" flag set to
 * "false".
 * The "only_childs" flag is particularly useful if you have a user object and
 * want to include all it's groups (referenced with "memberOf") but not itself
 * or considering if that object matches the filter.
 *
 * At the beginning "res_sids" should reference to a NULL pointer.
 */
NTSTATUS dsdb_expand_nested_groups(struct ldb_context *sam_ctx,
				   struct ldb_val *dn_val, const bool only_childs, const char *filter,
				   TALLOC_CTX *res_sids_ctx, struct dom_sid **res_sids,
				   unsigned int *num_res_sids)
{
	const char * const attrs[] = { "memberOf", NULL };
	unsigned int i;
	int ret;
	bool already_there;
	struct ldb_dn *dn;
	struct dom_sid sid;
	TALLOC_CTX *tmp_ctx;
	struct ldb_result *res;
	NTSTATUS status;
	const struct ldb_message_element *el;

	if (*res_sids == NULL) {
		*num_res_sids = 0;
	}

	if (!sam_ctx) {
		DEBUG(0, ("No SAM available, cannot determine local groups\n"));
		return NT_STATUS_INVALID_SYSTEM_SERVICE;
	}

	tmp_ctx = talloc_new(res_sids_ctx);

	dn = ldb_dn_from_ldb_val(tmp_ctx, sam_ctx, dn_val);
	if (dn == NULL) {
		talloc_free(tmp_ctx);
		DEBUG(0, (__location__ ": we failed parsing DN %.*s, so we cannot calculate the group token\n",
			  (int)dn_val->length, dn_val->data));
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	status = dsdb_get_extended_dn_sid(dn, &sid, "SID");
	if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
		/* If we fail finding a SID then this is no error since it could
		 * be a non SAM object - e.g. a group with object class
		 * "groupOfNames" */
		talloc_free(tmp_ctx);
		return NT_STATUS_OK;
	} else if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, (__location__ ": when parsing DN '%s' we failed to parse it's SID component, so we cannot calculate the group token: %s\n",
			  ldb_dn_get_extended_linearized(tmp_ctx, dn, 1),
			  nt_errstr(status)));
		talloc_free(tmp_ctx);
		return status;
	}

	if (!ldb_dn_minimise(dn)) {
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	if (only_childs) {
		ret = dsdb_search_dn(sam_ctx, tmp_ctx, &res, dn, attrs,
				     DSDB_SEARCH_SHOW_EXTENDED_DN);
	} else {
		/* This is an O(n^2) linear search */
		already_there = sids_contains_sid(*res_sids,
						  *num_res_sids, &sid);
		if (already_there) {
			talloc_free(tmp_ctx);
			return NT_STATUS_OK;
		}

		ret = dsdb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
				  attrs, DSDB_SEARCH_SHOW_EXTENDED_DN, "%s",
				  filter);
	}

	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		talloc_free(tmp_ctx);
		return NT_STATUS_OK;
	}

	if (ret != LDB_SUCCESS) {
		DEBUG(1, (__location__ ": dsdb_search for %s failed: %s\n",
			  ldb_dn_get_extended_linearized(tmp_ctx, dn, 1),
			  ldb_errstring(sam_ctx)));
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	/* We may get back 0 results, if the SID didn't match the filter - such as it wasn't a domain group, for example */
	if (res->count != 1) {
		talloc_free(tmp_ctx);
		return NT_STATUS_OK;
	}

	/* We only apply this test once we know the SID matches the filter */
	if (!only_childs) {
		*res_sids = talloc_realloc(res_sids_ctx, *res_sids,
			struct dom_sid, *num_res_sids + 1);
		NT_STATUS_HAVE_NO_MEMORY_AND_FREE(*res_sids, tmp_ctx);
		(*res_sids)[*num_res_sids] = sid;
		++(*num_res_sids);
	}
Exemple #3
0
/* Return the members of this group (which may be a domain group or an alias) */
NTSTATUS dsdb_enum_group_mem(struct ldb_context *ldb,
			     TALLOC_CTX *mem_ctx,
			     struct ldb_dn *dn,
			     struct dom_sid **members_out,
			     unsigned int *pnum_members)
{
	struct ldb_message *msg;
	unsigned int i, j;
	int ret;
	struct dom_sid *members;
	struct ldb_message_element *member_el;
	const char *attrs[] = { "member", NULL };
	NTSTATUS status;
	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
	NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);

	ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE, attrs,
			      DSDB_SEARCH_SHOW_EXTENDED_DN, NULL);
	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		talloc_free(tmp_ctx);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}
	if (ret != LDB_SUCCESS) {
		DEBUG(1, ("dsdb_enum_group_mem: dsdb_search for %s failed: %s\n",
			  ldb_dn_get_linearized(dn), ldb_errstring(ldb)));
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	member_el = ldb_msg_find_element(msg, "member");
	if (!member_el) {
		*members_out = NULL;
		*pnum_members = 0;
		talloc_free(tmp_ctx);
		return NT_STATUS_OK;
	}

	members = talloc_array(mem_ctx, struct dom_sid, member_el->num_values);
	if (members == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	j = 0;
	for (i=0; i <member_el->num_values; i++) {
		struct ldb_dn *member_dn = ldb_dn_from_ldb_val(tmp_ctx, ldb,
							       &member_el->values[i]);
		if (!member_dn || !ldb_dn_validate(member_dn)) {
			DEBUG(1, ("Could not parse %*.*s as a DN\n",
				  (int)member_el->values[i].length,
				  (int)member_el->values[i].length,
				  (const char *)member_el->values[i].data));
			talloc_free(tmp_ctx);
			return NT_STATUS_INTERNAL_DB_CORRUPTION;
		}

		status = dsdb_get_extended_dn_sid(member_dn, &members[j],
						  "SID");
		if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
			/* If we fail finding a SID then this is no error since
			 * it could be a non SAM object - e.g. a contact */
			continue;
		} else if (!NT_STATUS_IS_OK(status)) {
			DEBUG(1, ("When parsing DN '%s' we failed to parse it's SID component, so we cannot fetch the membership: %s\n",
				  ldb_dn_get_extended_linearized(tmp_ctx, member_dn, 1),
				  nt_errstr(status)));
			talloc_free(tmp_ctx);
			return status;
		}

		++j;
	}

	*members_out = talloc_steal(mem_ctx, members);
	*pnum_members = j;
	talloc_free(tmp_ctx);
	return NT_STATUS_OK;
}