summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/auth/auth.h8
-rw-r--r--source4/auth/sam.c182
-rw-r--r--source4/auth/session.c147
-rw-r--r--source4/dsdb/samdb/samdb.c11
4 files changed, 264 insertions, 84 deletions
diff --git a/source4/auth/auth.h b/source4/auth/auth.h
index 915d10397b..3984704928 100644
--- a/source4/auth/auth.h
+++ b/source4/auth/auth.h
@@ -244,13 +244,11 @@ NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx,
const char *name_for_logs,
bool allow_domain_trust,
bool password_change);
-struct auth_session_info *system_session(struct loadparm_context *lp_ctx);
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,
+ 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);
+struct auth_session_info *system_session(struct loadparm_context *lp_ctx);
NTSTATUS authsam_make_server_info(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
const char *netbios_name,
const char *domain_name,
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;
diff --git a/source4/auth/session.c b/source4/auth/session.c
index 03d1c91054..7817195727 100644
--- a/source4/auth/session.c
+++ b/source4/auth/session.c
@@ -49,9 +49,71 @@ _PUBLIC_ NTSTATUS auth_generate_session_info(TALLOC_CTX *mem_ctx,
{
struct auth_session_info *session_info;
NTSTATUS nt_status;
+ unsigned int i, num_groupSIDs = 0;
+ const char *account_sid_string;
+ const char *account_sid_dn;
+ DATA_BLOB account_sid_blob;
+ const char *primary_group_string;
+ const char *primary_group_dn;
+ DATA_BLOB primary_group_blob;
- session_info = talloc(mem_ctx, struct auth_session_info);
- NT_STATUS_HAVE_NO_MEMORY(session_info);
+ const char *filter;
+
+ struct dom_sid **groupSIDs = NULL;
+ const struct dom_sid *dom_sid;
+ bool is_enterprise_dc = false;
+
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ if (!auth_context->sam_ctx) {
+ DEBUG(0, ("No SAM available, cannot determine local groups\n"));
+ return NT_STATUS_INVALID_SYSTEM_SERVICE;
+ }
+
+ /* For now, we don't have trusted domains, so we do a very
+ * simple check to see that the user's SID is in *this*
+ * domain, and then trust the user account control. When we
+ * get trusted domains, we should check it's a trusted domain
+ * in this forest. This elaborate check is to try and avoid a
+ * nasty security bug if we forget about this later... */
+
+ if (server_info->acct_flags & ACB_SVRTRUST) {
+ dom_sid = samdb_domain_sid(auth_context->sam_ctx);
+ if (dom_sid) {
+ if (dom_sid_in_domain(dom_sid, server_info->account_sid)) {
+ is_enterprise_dc = true;
+ } else {
+ DEBUG(2, ("DC %s is not in our domain. "
+ "It will not have Enterprise Domain Controllers membership on this server",
+ server_info->account_name));
+ }
+ } else {
+ DEBUG(2, ("Could not obtain local domain SID, "
+ "so can not determine if DC %s is a DC of this domain. "
+ "It will not have Enterprise Domain Controllers membership",
+ server_info->account_name));
+ }
+ }
+
+ groupSIDs = talloc_array(tmp_ctx, struct dom_sid *, server_info->n_domain_groups);
+ NT_STATUS_HAVE_NO_MEMORY_AND_FREE(groupSIDs, tmp_ctx);
+ if (!groupSIDs) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ num_groupSIDs = server_info->n_domain_groups;
+
+ for (i=0; i < server_info->n_domain_groups; i++) {
+ groupSIDs[i] = server_info->domain_groups[i];
+ }
+
+ filter = talloc_asprintf(tmp_ctx, "(&(objectClass=group)(groupType:1.2.840.113556.1.4.803:=%u))",
+ GROUP_TYPE_BUILTIN_LOCAL_GROUP);
+
+ session_info = talloc(tmp_ctx, struct auth_session_info);
+ NT_STATUS_HAVE_NO_MEMORY_AND_FREE(session_info, tmp_ctx);
session_info->server_info = talloc_reference(session_info, server_info);
@@ -59,19 +121,94 @@ _PUBLIC_ NTSTATUS auth_generate_session_info(TALLOC_CTX *mem_ctx,
* key from the auth subsystem */
session_info->session_key = server_info->user_session_key;
+ /* Search for each group in the token */
+
+ /* Expands the account SID - 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
+ * builtin groups
+ *
+ * We already have the primary group in the token, so set
+ * 'only childs' flag to true
+ */
+ account_sid_string = dom_sid_string(tmp_ctx, server_info->account_sid);
+ NT_STATUS_HAVE_NO_MEMORY_AND_FREE(account_sid_string, server_info);
+
+ account_sid_dn = talloc_asprintf(tmp_ctx, "<SID=%s>", account_sid_string);
+ NT_STATUS_HAVE_NO_MEMORY_AND_FREE(account_sid_dn, server_info);
+
+ account_sid_blob = data_blob_string_const(account_sid_dn);
+
+ nt_status = authsam_expand_nested_groups(auth_context->sam_ctx, &account_sid_blob, true, filter,
+ tmp_ctx, &groupSIDs, &num_groupSIDs);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ talloc_free(tmp_ctx);
+ return nt_status;
+ }
+
+ /* 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
+ * builtin groups
+ *
+ * We already have the primary group in the token, so set
+ * 'only childs' flag to true
+ */
+ primary_group_string = dom_sid_string(tmp_ctx, server_info->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);
+
+ nt_status = authsam_expand_nested_groups(auth_context->sam_ctx, &primary_group_blob, true, filter,
+ tmp_ctx, &groupSIDs, &num_groupSIDs);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ talloc_free(tmp_ctx);
+ return nt_status;
+ }
+
+ for (i = 0; i < server_info->n_domain_groups; i++) {
+ const char *group_string;
+ const char *group_dn;
+ DATA_BLOB group_blob;
+ group_string = dom_sid_string(tmp_ctx, server_info->domain_groups[i]);
+ NT_STATUS_HAVE_NO_MEMORY_AND_FREE(group_string, server_info);
+
+ group_dn = talloc_asprintf(tmp_ctx, "<SID=%s>", group_string);
+ NT_STATUS_HAVE_NO_MEMORY_AND_FREE(group_dn, server_info);
+
+ group_blob = data_blob_string_const(group_dn);
+
+ /* This function takes in memberOf values and expands
+ * them, as long as they meet the filter - so only
+ * builtin groups */
+ nt_status = authsam_expand_nested_groups(auth_context->sam_ctx, &group_blob, true, filter,
+ tmp_ctx, &groupSIDs, &num_groupSIDs);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ talloc_free(tmp_ctx);
+ return nt_status;
+ }
+ }
+
nt_status = security_token_create(session_info,
auth_context->event_ctx,
auth_context->lp_ctx,
server_info->account_sid,
server_info->primary_group_sid,
- server_info->n_domain_groups,
- server_info->domain_groups,
+ num_groupSIDs,
+ groupSIDs,
server_info->authenticated,
+ is_enterprise_dc,
&session_info->security_token);
- NT_STATUS_NOT_OK_RETURN(nt_status);
+ NT_STATUS_NOT_OK_RETURN_AND_FREE(nt_status, tmp_ctx);
session_info->credentials = NULL;
+ talloc_steal(mem_ctx, session_info);
*_session_info = session_info;
return NT_STATUS_OK;
}
diff --git a/source4/dsdb/samdb/samdb.c b/source4/dsdb/samdb/samdb.c
index 51e3f73a7e..9e4156407e 100644
--- a/source4/dsdb/samdb/samdb.c
+++ b/source4/dsdb/samdb/samdb.c
@@ -147,6 +147,7 @@ NTSTATUS security_token_create(TALLOC_CTX *mem_ctx,
unsigned int n_groupSIDs,
struct dom_sid **groupSIDs,
bool is_authenticated,
+ bool is_dc,
struct security_token **token)
{
struct security_token *ptoken;
@@ -156,7 +157,7 @@ NTSTATUS security_token_create(TALLOC_CTX *mem_ctx,
ptoken = security_token_initialise(mem_ctx);
NT_STATUS_HAVE_NO_MEMORY(ptoken);
- ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
+ ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 6);
NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
ptoken->user_sid = talloc_reference(ptoken, user_sid);
@@ -178,7 +179,13 @@ NTSTATUS security_token_create(TALLOC_CTX *mem_ctx,
ptoken->num_sids = 4;
if (is_authenticated) {
- ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
+ ptoken->sids[ptoken->num_sids] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
+ NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
+ ptoken->num_sids++;
+ }
+
+ if (is_dc) {
+ ptoken->sids[ptoken->num_sids] = dom_sid_parse_talloc(ptoken->sids, SID_NT_ENTERPRISE_DCS);
NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
ptoken->num_sids++;
}