static NTSTATUS get_system_info3(TALLOC_CTX *mem_ctx, struct netr_SamInfo3 *info3) { NTSTATUS status; struct dom_sid *system_sid; /* Set account name */ init_lsa_String(&info3->base.account_name, "SYSTEM"); /* Set domain name */ init_lsa_StringLarge(&info3->base.logon_domain, "NT AUTHORITY"); /* The SID set here will be overwirtten anyway, but try and make it SID_NT_SYSTEM anyway */ /* Domain sid is NT_AUTHORITY */ system_sid = dom_sid_parse_talloc(mem_ctx, SID_NT_SYSTEM); if (system_sid == NULL) { return NT_STATUS_NO_MEMORY; } status = dom_sid_split_rid(mem_ctx, system_sid, &info3->base.domain_sid, &info3->base.rid); TALLOC_FREE(system_sid); if (!NT_STATUS_IS_OK(status)) { return status; } /* Primary gid is the same */ info3->base.primary_gid = info3->base.rid; return NT_STATUS_OK; }
static NTSTATUS auth_convert_user_info_dc_sambaseinfo(TALLOC_CTX *mem_ctx, const struct auth_user_info_dc *user_info_dc, struct netr_SamBaseInfo *sam) { NTSTATUS status; const struct auth_user_info *info; ZERO_STRUCTP(sam); if (user_info_dc->num_sids > PRIMARY_USER_SID_INDEX) { status = dom_sid_split_rid(sam, &user_info_dc->sids[PRIMARY_USER_SID_INDEX], &sam->domain_sid, &sam->rid); if (!NT_STATUS_IS_OK(status)) { return status; } } else { return NT_STATUS_INVALID_PARAMETER; } if (user_info_dc->num_sids > PRIMARY_GROUP_SID_INDEX) { status = dom_sid_split_rid(NULL, &user_info_dc->sids[PRIMARY_GROUP_SID_INDEX], NULL, &sam->primary_gid); if (!NT_STATUS_IS_OK(status)) { return status; } } else { /* if we have to encode something like SYSTEM (with no * second SID in the token) then this is the only * choice */ sam->primary_gid = sam->rid; } info = user_info_dc->info; sam->logon_time = info->last_logon; sam->logoff_time = info->last_logoff; sam->kickoff_time = info->acct_expiry; sam->last_password_change = info->last_password_change; sam->allow_password_change = info->allow_password_change; sam->force_password_change = info->force_password_change; #define _COPY_STRING_TALLOC(src_name, dst_name) do { \ if (info->src_name != NULL) {\ sam->dst_name.string = talloc_strdup(mem_ctx, info->src_name); \ if (sam->dst_name.string == NULL) { \ return NT_STATUS_NO_MEMORY; \ } \ } \ } while(0) _COPY_STRING_TALLOC(account_name, account_name); _COPY_STRING_TALLOC(full_name, full_name); _COPY_STRING_TALLOC(logon_script, logon_script); _COPY_STRING_TALLOC(profile_path, profile_path); _COPY_STRING_TALLOC(home_directory, home_directory); _COPY_STRING_TALLOC(home_drive, home_drive); _COPY_STRING_TALLOC(logon_server, logon_server); _COPY_STRING_TALLOC(domain_name, logon_domain); #undef _COPY_STRING_TALLOC sam->logon_count = info->logon_count; sam->bad_password_count = info->bad_password_count; sam->groups.count = 0; sam->groups.rids = NULL; if (user_info_dc->num_sids > 2) { size_t i; sam->groups.rids = talloc_array(mem_ctx, struct samr_RidWithAttribute, user_info_dc->num_sids); if (sam->groups.rids == NULL) return NT_STATUS_NO_MEMORY; for (i=2; i<user_info_dc->num_sids; i++) { struct dom_sid *group_sid = &user_info_dc->sids[i]; if (!dom_sid_in_domain(sam->domain_sid, group_sid)) { /* We handle this elsewhere */ continue; } sam->groups.rids[sam->groups.count].rid = group_sid->sub_auths[group_sid->num_auths-1]; sam->groups.rids[sam->groups.count].attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; sam->groups.count += 1; } }
/* lookup a SID for 1 name */ static NTSTATUS dcesrv_lsa_lookup_name(struct tevent_context *ev_ctx, struct loadparm_context *lp_ctx, struct lsa_policy_state *state, TALLOC_CTX *mem_ctx, const char *name, const char **authority_name, struct dom_sid **sid, enum lsa_SidType *rtype, uint32_t *rid) { int ret, i; uint32_t atype; struct ldb_message **res; const char * const attrs[] = { "objectSid", "sAMAccountType", NULL}; const char *p; const char *domain; const char *username; struct ldb_dn *domain_dn; struct dom_sid *domain_sid; NTSTATUS status; p = strchr_m(name, '\\'); if (p != NULL) { domain = talloc_strndup(mem_ctx, name, p-name); if (!domain) { return NT_STATUS_NO_MEMORY; } username = p + 1; } else if (strchr_m(name, '@')) { status = crack_name_to_nt4_name(mem_ctx, ev_ctx, lp_ctx, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL, name, &domain, &username); if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("Failed to crack name %s into an NT4 name: %s\n", name, nt_errstr(status))); return status; } } else { domain = NULL; username = name; } if (!domain) { /* Look up table of well known names */ status = lookup_well_known_names(mem_ctx, NULL, username, authority_name, sid, rtype); if (NT_STATUS_IS_OK(status)) { dom_sid_split_rid(NULL, *sid, NULL, rid); return NT_STATUS_OK; } if (username == NULL) { *authority_name = NAME_BUILTIN; *sid = dom_sid_parse_talloc(mem_ctx, SID_BUILTIN); *rtype = SID_NAME_DOMAIN; *rid = 0xFFFFFFFF; return NT_STATUS_OK; } if (strcasecmp_m(username, NAME_NT_AUTHORITY) == 0) { *authority_name = NAME_NT_AUTHORITY; *sid = dom_sid_parse_talloc(mem_ctx, SID_NT_AUTHORITY); *rtype = SID_NAME_DOMAIN; dom_sid_split_rid(NULL, *sid, NULL, rid); return NT_STATUS_OK; } if (strcasecmp_m(username, NAME_BUILTIN) == 0) { *authority_name = NAME_BUILTIN; *sid = dom_sid_parse_talloc(mem_ctx, SID_BUILTIN); *rtype = SID_NAME_DOMAIN; *rid = 0xFFFFFFFF; return NT_STATUS_OK; } if (strcasecmp_m(username, state->domain_dns) == 0) { *authority_name = state->domain_name; *sid = state->domain_sid; *rtype = SID_NAME_DOMAIN; *rid = 0xFFFFFFFF; return NT_STATUS_OK; } if (strcasecmp_m(username, state->domain_name) == 0) { *authority_name = state->domain_name; *sid = state->domain_sid; *rtype = SID_NAME_DOMAIN; *rid = 0xFFFFFFFF; return NT_STATUS_OK; } /* Perhaps this is a well known user? */ name = talloc_asprintf(mem_ctx, "%s\\%s", NAME_NT_AUTHORITY, username); if (!name) { return NT_STATUS_NO_MEMORY; } status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid); if (NT_STATUS_IS_OK(status)) { return status; } /* Perhaps this is a BUILTIN user? */ name = talloc_asprintf(mem_ctx, "%s\\%s", NAME_BUILTIN, username); if (!name) { return NT_STATUS_NO_MEMORY; } status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid); if (NT_STATUS_IS_OK(status)) { return status; } /* OK, I give up - perhaps we need to assume the user is in our domain? */ name = talloc_asprintf(mem_ctx, "%s\\%s", state->domain_name, username); if (!name) { return NT_STATUS_NO_MEMORY; } status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid); if (NT_STATUS_IS_OK(status)) { return status; } return STATUS_SOME_UNMAPPED; } else if (strcasecmp_m(domain, NAME_NT_AUTHORITY) == 0) { if (!*username) { *authority_name = NAME_NT_AUTHORITY; *sid = dom_sid_parse_talloc(mem_ctx, SID_NT_AUTHORITY); *rtype = SID_NAME_DOMAIN; dom_sid_split_rid(NULL, *sid, NULL, rid); return NT_STATUS_OK; } /* Look up table of well known names */ status = lookup_well_known_names(mem_ctx, domain, username, authority_name, sid, rtype); if (NT_STATUS_IS_OK(status)) { dom_sid_split_rid(NULL, *sid, NULL, rid); } return status; } else if (strcasecmp_m(domain, NAME_BUILTIN) == 0) { *authority_name = NAME_BUILTIN; domain_dn = state->builtin_dn; } else if (strcasecmp_m(domain, state->domain_dns) == 0) { *authority_name = state->domain_name; domain_dn = state->domain_dn; } else if (strcasecmp_m(domain, state->domain_name) == 0) { *authority_name = state->domain_name; domain_dn = state->domain_dn; } else { /* Not local, need to ask winbind in future */ return STATUS_SOME_UNMAPPED; } ret = gendb_search_dn(state->sam_ldb, mem_ctx, domain_dn, &res, attrs); if (ret == 1) { domain_sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid"); if (domain_sid == NULL) { return NT_STATUS_INVALID_SID; } } else { return NT_STATUS_INVALID_SID; } if (!*username) { *sid = domain_sid; *rtype = SID_NAME_DOMAIN; *rid = 0xFFFFFFFF; return NT_STATUS_OK; } ret = gendb_search(state->sam_ldb, mem_ctx, domain_dn, &res, attrs, "(&(sAMAccountName=%s)(objectSid=*))", ldb_binary_encode_string(mem_ctx, username)); if (ret == -1) { return NT_STATUS_INVALID_SID; } for (i=0; i < ret; i++) { *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid"); if (*sid == NULL) { return NT_STATUS_INVALID_SID; } /* Check that this is in the domain */ if (!dom_sid_in_domain(domain_sid, *sid)) { continue; } atype = samdb_result_uint(res[i], "sAMAccountType", 0); *rtype = ds_atype_map(atype); if (*rtype == SID_NAME_UNKNOWN) { return STATUS_SOME_UNMAPPED; } dom_sid_split_rid(NULL, *sid, NULL, rid); return NT_STATUS_OK; } /* need to check for an allocated sid */ return NT_STATUS_INVALID_SID; }
_PUBLIC_ NTSTATUS authsam_make_user_info_dc(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx, const char *netbios_name, const char *domain_name, struct ldb_dn *domain_dn, struct ldb_message *msg, DATA_BLOB user_sess_key, DATA_BLOB lm_sess_key, struct auth_user_info_dc **_user_info_dc) { NTSTATUS status; struct auth_user_info_dc *user_info_dc; struct auth_user_info *info; const char *str, *filter; /* SIDs for the account and his primary group */ struct dom_sid *account_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 *sids = NULL; unsigned int num_sids = 0, i; struct dom_sid *domain_sid; TALLOC_CTX *tmp_ctx; struct ldb_message_element *el; user_info_dc = talloc(mem_ctx, struct auth_user_info_dc); NT_STATUS_HAVE_NO_MEMORY(user_info_dc); tmp_ctx = talloc_new(user_info_dc); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(user_info_dc, user_info_dc); sids = talloc_array(user_info_dc, struct dom_sid, 2); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sids, user_info_dc); num_sids = 2; account_sid = samdb_result_dom_sid(user_info_dc, msg, "objectSid"); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(account_sid, user_info_dc); status = dom_sid_split_rid(tmp_ctx, account_sid, &domain_sid, NULL); if (!NT_STATUS_IS_OK(status)) { talloc_free(user_info_dc); return status; } sids[PRIMARY_USER_SID_INDEX] = *account_sid; sids[PRIMARY_GROUP_SID_INDEX] = *domain_sid; sid_append_rid(&sids[PRIMARY_GROUP_SID_INDEX], ldb_msg_find_attr_as_uint(msg, "primaryGroupID", ~0)); /* 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, user_info_dc); primary_group_string = dom_sid_string(tmp_ctx, &sids[PRIMARY_GROUP_SID_INDEX]); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(primary_group_string, user_info_dc); primary_group_dn = talloc_asprintf(tmp_ctx, "<SID=%s>", primary_group_string); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(primary_group_dn, user_info_dc); 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 = dsdb_expand_nested_groups(sam_ctx, &primary_group_blob, true, filter, user_info_dc, &sids, &num_sids); if (!NT_STATUS_IS_OK(status)) { talloc_free(user_info_dc); return status; } /* 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 = dsdb_expand_nested_groups(sam_ctx, &el->values[i], false, filter, user_info_dc, &sids, &num_sids); if (!NT_STATUS_IS_OK(status)) { talloc_free(user_info_dc); return status; } } user_info_dc->sids = sids; user_info_dc->num_sids = num_sids; user_info_dc->info = info = talloc_zero(user_info_dc, struct auth_user_info); NT_STATUS_HAVE_NO_MEMORY(user_info_dc->info); info->account_name = talloc_steal(info, ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL)); info->domain_name = talloc_strdup(info, domain_name); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(info->domain_name, user_info_dc); str = ldb_msg_find_attr_as_string(msg, "displayName", ""); info->full_name = talloc_strdup(info, str); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(info->full_name, user_info_dc); str = ldb_msg_find_attr_as_string(msg, "scriptPath", ""); info->logon_script = talloc_strdup(info, str); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(info->logon_script, user_info_dc); str = ldb_msg_find_attr_as_string(msg, "profilePath", ""); info->profile_path = talloc_strdup(info, str); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(info->profile_path, user_info_dc); str = ldb_msg_find_attr_as_string(msg, "homeDirectory", ""); info->home_directory = talloc_strdup(info, str); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(info->home_directory, user_info_dc); str = ldb_msg_find_attr_as_string(msg, "homeDrive", ""); info->home_drive = talloc_strdup(info, str); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(info->home_drive, user_info_dc); info->logon_server = talloc_strdup(info, netbios_name); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(info->logon_server, user_info_dc); info->last_logon = samdb_result_nttime(msg, "lastLogon", 0); info->last_logoff = samdb_result_last_logoff(msg); info->acct_expiry = samdb_result_account_expires(msg); info->last_password_change = samdb_result_nttime(msg, "pwdLastSet", 0); info->allow_password_change = samdb_result_allow_password_change(sam_ctx, mem_ctx, domain_dn, msg, "pwdLastSet"); info->force_password_change = samdb_result_force_password_change(sam_ctx, mem_ctx, domain_dn, msg); info->logon_count = ldb_msg_find_attr_as_uint(msg, "logonCount", 0); info->bad_password_count = ldb_msg_find_attr_as_uint(msg, "badPwdCount", 0); info->acct_flags = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, domain_dn); user_info_dc->user_session_key = data_blob_talloc(user_info_dc, user_sess_key.data, user_sess_key.length); if (user_sess_key.data) { NT_STATUS_HAVE_NO_MEMORY_AND_FREE(user_info_dc->user_session_key.data, user_info_dc); } user_info_dc->lm_session_key = data_blob_talloc(user_info_dc, lm_sess_key.data, lm_sess_key.length); if (lm_sess_key.data) { NT_STATUS_HAVE_NO_MEMORY_AND_FREE(user_info_dc->lm_session_key.data, user_info_dc); } if (info->acct_flags & ACB_SVRTRUST) { /* the SID_NT_ENTERPRISE_DCS SID gets added into the PAC */ user_info_dc->sids = talloc_realloc(user_info_dc, user_info_dc->sids, struct dom_sid, user_info_dc->num_sids+1); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(user_info_dc->sids, user_info_dc); user_info_dc->sids[user_info_dc->num_sids] = global_sid_Enterprise_DCs; user_info_dc->num_sids++; }
/* construct the token groups for SAM objects from a message */ static int construct_token_groups(struct ldb_module *module, struct ldb_message *msg, enum ldb_scope scope, struct ldb_request *parent) { struct ldb_context *ldb = ldb_module_get_ctx(module);; TALLOC_CTX *tmp_ctx = talloc_new(msg); unsigned int i; int ret; const char *filter; NTSTATUS status; struct dom_sid *primary_group_sid; const char *primary_group_string; const char *primary_group_dn; DATA_BLOB primary_group_blob; struct dom_sid *account_sid; const char *account_sid_string; const char *account_sid_dn; DATA_BLOB account_sid_blob; struct dom_sid *groupSIDs = NULL; unsigned int num_groupSIDs = 0; struct dom_sid *domain_sid; if (scope != LDB_SCOPE_BASE) { ldb_set_errstring(ldb, "Cannot provide tokenGroups attribute, this is not a BASE search"); return LDB_ERR_OPERATIONS_ERROR; } /* If it's not a user, it won't have a primaryGroupID */ if (ldb_msg_find_element(msg, "primaryGroupID") == NULL) { talloc_free(tmp_ctx); return LDB_SUCCESS; } /* Ensure it has an objectSID too */ account_sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid"); if (account_sid == NULL) { talloc_free(tmp_ctx); return LDB_SUCCESS; } status = dom_sid_split_rid(tmp_ctx, account_sid, &domain_sid, NULL); if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { talloc_free(tmp_ctx); return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; } else if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } primary_group_sid = dom_sid_add_rid(tmp_ctx, domain_sid, ldb_msg_find_attr_as_uint(msg, "primaryGroupID", ~0)); if (!primary_group_sid) { talloc_free(tmp_ctx); return ldb_oom(ldb); } /* only return security groups */ filter = talloc_asprintf(tmp_ctx, "(&(objectClass=group)(groupType:1.2.840.113556.1.4.803:=%u))", GROUP_TYPE_SECURITY_ENABLED); if (!filter) { talloc_free(tmp_ctx); return ldb_oom(ldb); } primary_group_string = dom_sid_string(tmp_ctx, primary_group_sid); if (!primary_group_string) { talloc_free(tmp_ctx); return ldb_oom(ldb); } primary_group_dn = talloc_asprintf(tmp_ctx, "<SID=%s>", primary_group_string); if (!primary_group_dn) { talloc_free(tmp_ctx); return ldb_oom(ldb); } primary_group_blob = data_blob_string_const(primary_group_dn); account_sid_string = dom_sid_string(tmp_ctx, account_sid); if (!account_sid_string) { talloc_free(tmp_ctx); return ldb_oom(ldb); } account_sid_dn = talloc_asprintf(tmp_ctx, "<SID=%s>", account_sid_string); if (!account_sid_dn) { talloc_free(tmp_ctx); return ldb_oom(ldb); } account_sid_blob = data_blob_string_const(account_sid_dn); status = dsdb_expand_nested_groups(ldb, &account_sid_blob, true, /* We don't want to add the object's SID itself, it's not returend in this attribute */ filter, tmp_ctx, &groupSIDs, &num_groupSIDs); if (!NT_STATUS_IS_OK(status)) { ldb_asprintf_errstring(ldb, "Failed to construct tokenGroups: expanding groups of SID %s failed: %s", account_sid_string, nt_errstr(status)); talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } /* 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 */ status = dsdb_expand_nested_groups(ldb, &primary_group_blob, false, filter, tmp_ctx, &groupSIDs, &num_groupSIDs); if (!NT_STATUS_IS_OK(status)) { ldb_asprintf_errstring(ldb, "Failed to construct tokenGroups: expanding groups of SID %s failed: %s", account_sid_string, nt_errstr(status)); talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } for (i=0; i < num_groupSIDs; i++) { ret = samdb_msg_add_dom_sid(ldb, msg, msg, "tokenGroups", &groupSIDs[i]); if (ret) { talloc_free(tmp_ctx); return ret; } } return LDB_SUCCESS; }
static NTSTATUS get_info3_from_wbcAuthUserInfo(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *ic, struct wbcAuthUserInfo *info, struct netr_SamInfo3 *info3) { int i, j; struct samr_RidWithAttribute *rids = NULL; info3->base.last_logon = info->logon_time; info3->base.last_logoff = info->logoff_time; info3->base.acct_expiry = info->kickoff_time; info3->base.last_password_change = info->pass_last_set_time; info3->base.allow_password_change = info->pass_can_change_time; info3->base.force_password_change = info->pass_must_change_time; info3->base.account_name.string = talloc_strdup(mem_ctx, info->account_name); info3->base.full_name.string = talloc_strdup(mem_ctx, info->full_name); info3->base.logon_script.string = talloc_strdup(mem_ctx, info->logon_script); info3->base.profile_path.string = talloc_strdup(mem_ctx, info->profile_path); info3->base.home_directory.string = talloc_strdup(mem_ctx, info->home_directory); info3->base.home_drive.string = talloc_strdup(mem_ctx, info->home_drive); info3->base.logon_server.string = talloc_strdup(mem_ctx, info->logon_server); info3->base.domain.string = talloc_strdup(mem_ctx, info->domain_name); info3->base.logon_count = info->logon_count; info3->base.bad_password_count = info->bad_password_count; info3->base.user_flags = info->user_flags; memcpy(info3->base.key.key, info->user_session_key, sizeof(info3->base.key.key)); memcpy(info3->base.LMSessKey.key, info->lm_session_key, sizeof(info3->base.LMSessKey.key)); info3->base.acct_flags = info->acct_flags; memset(info3->base.unknown, 0, sizeof(info3->base.unknown)); if (info->num_sids < 2) { return NT_STATUS_INVALID_PARAMETER; } dom_sid_split_rid(mem_ctx, (struct dom_sid2 *) &info->sids[0].sid, &info3->base.domain_sid, &info3->base.rid); dom_sid_split_rid(mem_ctx, (struct dom_sid2 *) &info->sids[1].sid, NULL, &info3->base.primary_gid); /* We already handled the first two, now take care of the rest */ info3->base.groups.count = info->num_sids - 2; rids = talloc_array(mem_ctx, struct samr_RidWithAttribute, info3->base.groups.count); NT_STATUS_HAVE_NO_MEMORY(rids); for (i = 2, j = 0; i < info->num_sids; ++i, ++j) { rids[j].attributes = info->sids[i].attributes; dom_sid_split_rid(mem_ctx, (struct dom_sid2 *) &info->sids[i].sid, NULL, &rids[j].rid); } info3->base.groups.rids = rids; return NT_STATUS_OK; }