summaryrefslogtreecommitdiff
path: root/source4/auth/sam.c
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2010-04-13 22:11:26 +1000
committerAndrew Bartlett <abartlet@samba.org>2010-05-20 17:39:09 +1000
commit5f9024c8a4350792e67e1d8dbe8e45ff5732bd66 (patch)
tree37bd039a17555bfa92231cfe63a352743df9a2d5 /source4/auth/sam.c
parent564b4c7443b256e002b7ac173d4c5e8870980de3 (diff)
downloadsamba-5f9024c8a4350792e67e1d8dbe8e45ff5732bd66.tar.gz
samba-5f9024c8a4350792e67e1d8dbe8e45ff5732bd66.tar.bz2
samba-5f9024c8a4350792e67e1d8dbe8e45ff5732bd66.zip
s4:auth Move BUILTIN group addition into session.c
The group list in the PAC does not include 'enterprise DCs' and BUILTIN groups, so we should generate it on each server, not in the list we pass around in the PAC or SamLogon reply. Andrew Bartlett
Diffstat (limited to 'source4/auth/sam.c')
-rw-r--r--source4/auth/sam.c182
1 files changed, 110 insertions, 72 deletions
diff --git a/source4/auth/sam.c b/source4/auth/sam.c
index 201185cf4d..244ebc732e 100644
--- a/source4/auth/sam.c
+++ b/source4/auth/sam.c
@@ -294,72 +294,94 @@ static bool sids_contains_sid(const struct dom_sid **sids,
* "false".
* The "only_childs" flag is particularly useful if you have a user SID and
* want to include all his groups (referenced with "memberOf") without his SID
- * itself.
+ * itself, or considering if that SID matches the filter
*
* At the beginning "res_sids" should reference to a NULL pointer.
*/
-_PUBLIC_ NTSTATUS authsam_expand_nested_groups(struct ldb_context *sam_ctx,
- const struct dom_sid *sid, const bool only_childs,
- TALLOC_CTX *res_sids_ctx, struct dom_sid ***res_sids,
- unsigned int *num_res_sids)
+NTSTATUS authsam_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 *tmp_dn;
- struct dom_sid *tmp_sid;
+ struct ldb_dn *dn;
+ struct dom_sid *sid;
TALLOC_CTX *tmp_ctx;
- struct ldb_message **res;
+ struct ldb_result *res;
NTSTATUS status;
+ const struct ldb_val *v;
+ const struct ldb_message_element *el;
+ enum ndr_err_code ndr_err;
if (*res_sids == NULL) {
*num_res_sids = 0;
}
- if (sid == NULL) {
- return NT_STATUS_OK;
+ tmp_ctx = talloc_new(res_sids_ctx);
+
+ sid = talloc(tmp_ctx, struct dom_sid);
+ NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sid, tmp_ctx);
+
+ dn = ldb_dn_from_ldb_val(tmp_ctx, sam_ctx, dn_val);
+ if (dn == NULL) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
+ v = ldb_dn_get_extended_component(dn, "SID");
+ ndr_err = ndr_pull_struct_blob(v, sid, NULL, sid,
+ (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ /* This is an O(n^2) linear search */
already_there = sids_contains_sid((const struct dom_sid**) *res_sids,
- *num_res_sids, sid);
+ *num_res_sids, sid);
if (already_there) {
return NT_STATUS_OK;
}
- if (!only_childs) {
- tmp_sid = dom_sid_dup(res_sids_ctx, sid);
- NT_STATUS_HAVE_NO_MEMORY(tmp_sid);
- *res_sids = talloc_realloc(res_sids_ctx, *res_sids,
- struct dom_sid *, *num_res_sids + 1);
- NT_STATUS_HAVE_NO_MEMORY(*res_sids);
- (*res_sids)[*num_res_sids] = tmp_sid;
- ++(*num_res_sids);
+ if (only_childs) {
+ ret = dsdb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_SHOW_EXTENDED_DN, NULL);
+ } else {
+ ret = dsdb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_SHOW_EXTENDED_DN, "%s", filter);
}
- tmp_ctx = talloc_new(res_sids_ctx);
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+ }
- ret = gendb_search(sam_ctx, tmp_ctx, NULL, &res, attrs,
- "objectSid=%s", ldap_encode_ndr_dom_sid(tmp_ctx, sid));
- if (ret != 1) {
+ if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
- if (res[0]->num_elements == 0) {
- talloc_free(res);
+ /* 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;
}
- for (i = 0; i < res[0]->elements[0].num_values; i++) {
- tmp_dn = ldb_dn_from_ldb_val(tmp_ctx, sam_ctx,
- &res[0]->elements[0].values[i]);
- tmp_sid = samdb_search_dom_sid(sam_ctx, tmp_ctx, tmp_dn,
- "objectSid", NULL);
+ /* 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(*res_sids);
+ (*res_sids)[*num_res_sids] = talloc_steal(*res_sids, sid);
+ ++(*num_res_sids);
+ }
- status = authsam_expand_nested_groups(sam_ctx, tmp_sid,
- false, res_sids_ctx, res_sids, num_res_sids);
+ el = ldb_msg_find_element(res->msgs[0], "memberOf");
+
+ for (i = 0; el && i < el->num_values; i++) {
+ status = authsam_expand_nested_groups(sam_ctx, &el->values[i],
+ false, filter, res_sids_ctx, res_sids, num_res_sids);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(res);
talloc_free(tmp_ctx);
@@ -385,72 +407,87 @@ _PUBLIC_ NTSTATUS authsam_make_server_info(TALLOC_CTX *mem_ctx,
{
NTSTATUS status;
struct auth_serversupplied_info *server_info;
- const char *str;
- struct dom_sid *tmp_sid;
+ const char *str, *filter;
/* SIDs for the account and his primary group */
struct dom_sid *account_sid;
struct dom_sid *primary_group_sid;
+ const char *primary_group_string;
+ const char *primary_group_dn;
+ DATA_BLOB primary_group_blob;
/* SID structures for the expanded group memberships */
- struct dom_sid **groupSIDs = NULL, **groupSIDs_2 = NULL;
- unsigned int num_groupSIDs = 0, num_groupSIDs_2 = 0, i;
- uint32_t userAccountControl;
+ struct dom_sid **groupSIDs = NULL;
+ unsigned int num_groupSIDs = 0, i;
+ struct dom_sid *domain_sid;
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_message_element *el;
server_info = talloc(mem_ctx, struct auth_serversupplied_info);
NT_STATUS_HAVE_NO_MEMORY(server_info);
+ tmp_ctx = talloc_new(server_info);
+ NT_STATUS_HAVE_NO_MEMORY_AND_FREE(server_info, server_info);
+
account_sid = samdb_result_dom_sid(server_info, msg, "objectSid");
NT_STATUS_HAVE_NO_MEMORY_AND_FREE(account_sid, server_info);
- primary_group_sid = dom_sid_add_rid(server_info,
- samdb_domain_sid(sam_ctx),
- samdb_result_uint(msg, "primaryGroupID", ~0));
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(primary_group_sid, server_info);
-
- /* Expands the primary group */
- status = authsam_expand_nested_groups(sam_ctx, primary_group_sid, false,
- server_info, &groupSIDs, &num_groupSIDs);
+ status = dom_sid_split_rid(tmp_ctx, account_sid, &domain_sid, NULL);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(server_info);
return status;
}
- /* Expands the additional groups */
- status = authsam_expand_nested_groups(sam_ctx, account_sid, true,
- server_info, &groupSIDs_2, &num_groupSIDs_2);
+ primary_group_sid = dom_sid_add_rid(server_info,
+ domain_sid,
+ samdb_result_uint(msg, "primaryGroupID", ~0));
+ NT_STATUS_HAVE_NO_MEMORY_AND_FREE(primary_group_sid, server_info);
+
+ /* Filter out builtin groups from this token. We will search
+ * for builtin groups later, and not include them in the PAC
+ * on SamLogon validation info */
+ filter = talloc_asprintf(tmp_ctx, "(&(objectClass=group)(!(groupType:1.2.840.113556.1.4.803:=%u))(groupType:1.2.840.113556.1.4.803:=%u))", GROUP_TYPE_BUILTIN_LOCAL_GROUP, GROUP_TYPE_SECURITY_ENABLED);
+ NT_STATUS_HAVE_NO_MEMORY_AND_FREE(filter, server_info);
+
+ primary_group_string = dom_sid_string(tmp_ctx, primary_group_sid);
+ NT_STATUS_HAVE_NO_MEMORY_AND_FREE(primary_group_string, server_info);
+
+ primary_group_dn = talloc_asprintf(tmp_ctx, "<SID=%s>", primary_group_string);
+ NT_STATUS_HAVE_NO_MEMORY_AND_FREE(primary_group_dn, server_info);
+
+ primary_group_blob = data_blob_string_const(primary_group_dn);
+
+ /* Expands the primary group - this function takes in
+ * memberOf-like values, so we fake one up with the
+ * <SID=S-...> format of DN and then let it expand
+ * them, as long as they meet the filter - so only
+ * domain groups, not builtin groups
+ *
+ * The primary group is still treated specially, so we set the
+ * 'only childs' flag to true
+ */
+ status = authsam_expand_nested_groups(sam_ctx, &primary_group_blob, true, filter,
+ server_info, &groupSIDs, &num_groupSIDs);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(server_info);
return status;
}
- /* Merge the two expanded structures (groupSIDs, groupSIDs_2) */
- for (i = 0; i < num_groupSIDs_2; i++)
- if (!sids_contains_sid((const struct dom_sid **) groupSIDs,
- num_groupSIDs, groupSIDs_2[i])) {
- tmp_sid = dom_sid_dup(server_info, groupSIDs_2[i]);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(tmp_sid, server_info);
- groupSIDs = talloc_realloc(server_info, groupSIDs,
- struct dom_sid *, num_groupSIDs + 1);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(groupSIDs,
- server_info);
- groupSIDs[num_groupSIDs] = tmp_sid;
- ++num_groupSIDs;
+ /* Expands the additional groups */
+ el = ldb_msg_find_element(msg, "memberOf");
+ for (i = 0; el && i < el->num_values; i++) {
+ /* This function takes in memberOf values and expands
+ * them, as long as they meet the filter - so only
+ * domain groups, not builtin groups */
+ status = authsam_expand_nested_groups(sam_ctx, &el->values[i], false, filter,
+ server_info, &groupSIDs, &num_groupSIDs);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(server_info);
+ return status;
}
- talloc_free(groupSIDs_2);
+ }
server_info->account_sid = account_sid;
server_info->primary_group_sid = primary_group_sid;
- /* DCs also get SID_NT_ENTERPRISE_DCS */
- userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
- if (userAccountControl & UF_SERVER_TRUST_ACCOUNT) {
- groupSIDs = talloc_realloc(server_info, groupSIDs, struct dom_sid *,
- num_groupSIDs+1);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(groupSIDs, server_info);
- groupSIDs[num_groupSIDs] = dom_sid_parse_talloc(groupSIDs, SID_NT_ENTERPRISE_DCS);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(groupSIDs[num_groupSIDs], server_info);
- num_groupSIDs++;
- }
-
server_info->domain_groups = groupSIDs;
server_info->n_domain_groups = num_groupSIDs;
@@ -523,6 +560,7 @@ _PUBLIC_ NTSTATUS authsam_make_server_info(TALLOC_CTX *mem_ctx,
server_info->authenticated = true;
+ talloc_free(tmp_ctx);
*_server_info = server_info;
return NT_STATUS_OK;