static DATA_BLOB *get_new_descriptor(struct ldb_module *module,
				     struct ldb_dn *dn,
				     TALLOC_CTX *mem_ctx,
				     const struct dsdb_class *objectclass,
				     const struct ldb_val *parent,
				     const struct ldb_val *object,
				     const struct ldb_val *old_sd,
				     uint32_t sd_flags)
{
	struct security_descriptor *user_descriptor = NULL, *parent_descriptor = NULL;
	struct security_descriptor *old_descriptor = NULL;
	struct security_descriptor *new_sd, *final_sd;
	DATA_BLOB *linear_sd;
	enum ndr_err_code ndr_err;
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	struct auth_session_info *session_info
		= ldb_get_opaque(ldb, DSDB_SESSION_INFO);
	const struct dom_sid *domain_sid = samdb_domain_sid(ldb);
	struct dom_sid *default_owner;
	struct dom_sid *default_group;
	struct security_descriptor *default_descriptor = NULL;
	struct GUID *object_list = NULL;

	if (objectclass != NULL) {
		default_descriptor = get_sd_unpacked(module, mem_ctx, objectclass);
		object_list = talloc_zero_array(mem_ctx, struct GUID, 2);
		if (object_list == NULL) {
			return NULL;
		}
		object_list[0] = objectclass->schemaIDGUID;
	}

	if (object) {
		user_descriptor = talloc(mem_ctx, struct security_descriptor);
		if (!user_descriptor) {
			return NULL;
		}
		ndr_err = ndr_pull_struct_blob(object, user_descriptor, 
					       user_descriptor,
					       (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);

		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
			talloc_free(user_descriptor);
			return NULL;
		}
	} else {
		user_descriptor = default_descriptor;
	}

	if (old_sd) {
		old_descriptor = talloc(mem_ctx, struct security_descriptor);
		if (!old_descriptor) {
			return NULL;
		}
		ndr_err = ndr_pull_struct_blob(old_sd, old_descriptor, 
					       old_descriptor,
					       (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);

		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
			talloc_free(old_descriptor);
			return NULL;
		}
	}

	if (parent) {
		parent_descriptor = talloc(mem_ctx, struct security_descriptor);
		if (!parent_descriptor) {
			return NULL;
		}
		ndr_err = ndr_pull_struct_blob(parent, parent_descriptor, 
					       parent_descriptor,
					       (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);

		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
			talloc_free(parent_descriptor);
			return NULL;
		}
	}

	if (user_descriptor && default_descriptor &&
	    (user_descriptor->dacl == NULL))
	{
		user_descriptor->dacl = default_descriptor->dacl;
		user_descriptor->type |= default_descriptor->type & (
			SEC_DESC_DACL_PRESENT |
			SEC_DESC_DACL_DEFAULTED|SEC_DESC_DACL_AUTO_INHERIT_REQ |
			SEC_DESC_DACL_AUTO_INHERITED|SEC_DESC_DACL_PROTECTED |
			SEC_DESC_DACL_TRUSTED);
	}

	if (user_descriptor && default_descriptor &&
	    (user_descriptor->sacl == NULL))
	{
		user_descriptor->sacl = default_descriptor->sacl;
		user_descriptor->type |= default_descriptor->type & (
			SEC_DESC_SACL_PRESENT |
			SEC_DESC_SACL_DEFAULTED|SEC_DESC_SACL_AUTO_INHERIT_REQ |
			SEC_DESC_SACL_AUTO_INHERITED|SEC_DESC_SACL_PROTECTED |
			SEC_DESC_SERVER_SECURITY);
	}


	if (!(sd_flags & SECINFO_OWNER) && user_descriptor) {
		user_descriptor->owner_sid = NULL;

		/*
		 * We need the correct owner sid
		 * when calculating the DACL or SACL
		 */
		if (old_descriptor) {
			user_descriptor->owner_sid = old_descriptor->owner_sid;
		}
	}
	if (!(sd_flags & SECINFO_GROUP) && user_descriptor) {
		user_descriptor->group_sid = NULL;

		/*
		 * We need the correct group sid
		 * when calculating the DACL or SACL
		 */
		if (old_descriptor) {
			user_descriptor->group_sid = old_descriptor->group_sid;
		}
	}
	if (!(sd_flags & SECINFO_DACL) && user_descriptor) {
		user_descriptor->dacl = NULL;

		/*
		 * We add SEC_DESC_DACL_PROTECTED so that
		 * create_security_descriptor() skips
		 * the unused inheritance calculation
		 */
		user_descriptor->type |= SEC_DESC_DACL_PROTECTED;
	}
	if (!(sd_flags & SECINFO_SACL) && user_descriptor) {
		user_descriptor->sacl = NULL;

		/*
		 * We add SEC_DESC_SACL_PROTECTED so that
		 * create_security_descriptor() skips
		 * the unused inheritance calculation
		 */
		user_descriptor->type |= SEC_DESC_SACL_PROTECTED;
	}

	default_owner = get_default_ag(mem_ctx, dn,
				       session_info->security_token, ldb);
	default_group = get_default_group(mem_ctx, ldb, default_owner);
	new_sd = create_security_descriptor(mem_ctx,
					    parent_descriptor,
					    user_descriptor,
					    true,
					    object_list,
					    SEC_DACL_AUTO_INHERIT |
					    SEC_SACL_AUTO_INHERIT,
					    session_info->security_token,
					    default_owner, default_group,
					    map_generic_rights_ds);
	if (!new_sd) {
		return NULL;
	}
	final_sd = descr_handle_sd_flags(mem_ctx, new_sd, old_descriptor, sd_flags);

	if (!final_sd) {
		return NULL;
	}

	if (final_sd->dacl) {
		final_sd->dacl->revision = SECURITY_ACL_REVISION_ADS;
	}
	if (final_sd->sacl) {
		final_sd->sacl->revision = SECURITY_ACL_REVISION_ADS;
	}

	{
		TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
		DBG_DEBUG("Object %s created with descriptor %s\n\n",
			  ldb_dn_get_linearized(dn),
			  sddl_encode(tmp_ctx, final_sd, domain_sid));
		TALLOC_FREE(tmp_ctx);
	}

	linear_sd = talloc(mem_ctx, DATA_BLOB);
	if (!linear_sd) {
		return NULL;
	}

	ndr_err = ndr_push_struct_blob(linear_sd, mem_ctx,
				       final_sd,
				       (ndr_push_flags_fn_t)ndr_push_security_descriptor);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		return NULL;
	}

	return linear_sd;
}