static int samldb_allocate_next_rid(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, const struct dom_sid *dom_sid, struct dom_sid **new_sid) { struct dom_sid *obj_sid; uint32_t old_rid; int ret; ret = samldb_find_next_rid(module, mem_ctx, dn, &old_rid); if (ret) { return ret; } /* return the new object sid */ obj_sid = dom_sid_add_rid(mem_ctx, dom_sid, old_rid); *new_sid = dom_sid_add_rid(mem_ctx, dom_sid, old_rid + 1); if (!*new_sid) { return LDB_ERR_OPERATIONS_ERROR; } ret = samldb_notice_sid(module, mem_ctx, *new_sid); if (ret != 0) { /* gah, there are conflicting sids. * This is a critical situation it means that someone messed up with * the DB and nextRid is not returning free RIDs, report an error * and refuse to create any user until the problem is fixed */ ldb_asprintf_errstring(module->ldb, "Critical Error: unconsistent DB, unable to retireve an unique RID to generate a new SID: %s", ldb_errstring(module->ldb)); return ret; } return ret; }
static struct dom_sid *get_default_ag(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct security_token *token, struct ldb_context *ldb) { TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); const struct dom_sid *domain_sid = samdb_domain_sid(ldb); struct dom_sid *da_sid = dom_sid_add_rid(tmp_ctx, domain_sid, DOMAIN_RID_ADMINS); struct dom_sid *ea_sid = dom_sid_add_rid(tmp_ctx, domain_sid, DOMAIN_RID_ENTERPRISE_ADMINS); struct dom_sid *sa_sid = dom_sid_add_rid(tmp_ctx, domain_sid, DOMAIN_RID_SCHEMA_ADMINS); struct dom_sid *dag_sid; struct ldb_dn *nc_root; int ret; ret = dsdb_find_nc_root(ldb, tmp_ctx, dn, &nc_root); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return NULL; } if (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0) { if (security_token_has_sid(token, sa_sid)) { dag_sid = dom_sid_dup(mem_ctx, sa_sid); } else if (security_token_has_sid(token, ea_sid)) { dag_sid = dom_sid_dup(mem_ctx, ea_sid); } else if (security_token_has_sid(token, da_sid)) { dag_sid = dom_sid_dup(mem_ctx, da_sid); } else if (security_token_is_system(token)) { dag_sid = dom_sid_dup(mem_ctx, sa_sid); } else { dag_sid = NULL; } } else if (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) { if (security_token_has_sid(token, ea_sid)) { dag_sid = dom_sid_dup(mem_ctx, ea_sid); } else if (security_token_has_sid(token, da_sid)) { dag_sid = dom_sid_dup(mem_ctx, da_sid); } else if (security_token_is_system(token)) { dag_sid = dom_sid_dup(mem_ctx, ea_sid); } else { dag_sid = NULL; } } else if (ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) { if (security_token_has_sid(token, da_sid)) { dag_sid = dom_sid_dup(mem_ctx, da_sid); } else if (security_token_has_sid(token, ea_sid)) { dag_sid = dom_sid_dup(mem_ctx, ea_sid); } else if (security_token_is_system(token)) { dag_sid = dom_sid_dup(mem_ctx, da_sid); } else { dag_sid = NULL; } } else { dag_sid = NULL; } talloc_free(tmp_ctx); return dag_sid; }
static bool test_userinfo_async(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle *domain_handle, struct dom_sid2 *domain_sid, const char* user_name, uint32_t *rid) { const uint16_t level = 10; NTSTATUS status; struct composite_context *c; struct libnet_rpc_userinfo user; struct dom_sid *user_sid; user_sid = dom_sid_add_rid(mem_ctx, domain_sid, *rid); user.in.domain_handle = *domain_handle; user.in.sid = dom_sid_string(mem_ctx, user_sid); user.in.level = level; /* this should be extended */ printf("Testing async libnet_rpc_userinfo (SID argument)\n"); c = libnet_rpc_userinfo_send(p, &user, msg_handler); if (!c) { printf("Failed to call sync libnet_rpc_userinfo_send\n"); return false; } status = libnet_rpc_userinfo_recv(c, mem_ctx, &user); if (!NT_STATUS_IS_OK(status)) { printf("Calling async libnet_rpc_userinfo failed - %s\n", nt_errstr(status)); return false; } ZERO_STRUCT(user); user.in.domain_handle = *domain_handle; user.in.sid = NULL; user.in.username = TEST_USERNAME; user.in.level = level; printf("Testing async libnet_rpc_userinfo (username argument)\n"); c = libnet_rpc_userinfo_send(p, &user, msg_handler); if (!c) { printf("Failed to call sync libnet_rpc_userinfo_send\n"); return false; } status = libnet_rpc_userinfo_recv(c, mem_ctx, &user); if (!NT_STATUS_IS_OK(status)) { printf("Calling async libnet_rpc_userinfo failed - %s\n", nt_errstr(status)); return false; } return true; }
static bool test_userinfo_async(struct torture_context *tctx, struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle *domain_handle, struct dom_sid2 *domain_sid, const char* user_name, uint32_t *rid) { const uint16_t level = 10; NTSTATUS status; struct composite_context *c; struct libnet_rpc_userinfo user; struct dom_sid *user_sid; user_sid = dom_sid_add_rid(mem_ctx, domain_sid, *rid); ZERO_STRUCT(user); user.in.domain_handle = *domain_handle; user.in.sid = dom_sid_string(mem_ctx, user_sid); user.in.level = level; /* this should be extended */ torture_comment(tctx, "Testing async libnet_rpc_userinfo (SID argument)\n"); c = libnet_rpc_userinfo_send(mem_ctx, tctx->ev, p->binding_handle, &user, msg_handler); torture_assert(tctx, c != NULL, "Failed to call async libnet_rpc_userinfo_send"); status = libnet_rpc_userinfo_recv(c, mem_ctx, &user); torture_assert_ntstatus_ok(tctx, status, "Calling async libnet_rpc_userinfo_recv failed"); ZERO_STRUCT(user); user.in.domain_handle = *domain_handle; user.in.sid = NULL; user.in.username = user_name; user.in.level = level; torture_comment(tctx, "Testing async libnet_rpc_userinfo (username argument)\n"); c = libnet_rpc_userinfo_send(mem_ctx, tctx->ev, p->binding_handle, &user, msg_handler); torture_assert(tctx, c != NULL, "Failed to call async libnet_rpc_userinfo_send"); status = libnet_rpc_userinfo_recv(c, mem_ctx, &user); torture_assert_ntstatus_ok(tctx, status, "Calling async libnet_rpc_userinfo_recv failed"); return true; }
static bool test_groupinfo(struct torture_context *tctx, struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle *domain_handle, struct dom_sid2 *domain_sid, const char* group_name, uint32_t *rid) { const uint16_t level = 5; NTSTATUS status; struct libnet_rpc_groupinfo group; struct dom_sid *group_sid; group_sid = dom_sid_add_rid(mem_ctx, domain_sid, *rid); group.in.domain_handle = *domain_handle; group.in.sid = dom_sid_string(mem_ctx, group_sid); group.in.level = level; /* this should be extended */ torture_comment(tctx, "Testing sync libnet_rpc_groupinfo (SID argument)\n"); status = libnet_rpc_groupinfo(p, mem_ctx, &group); if (!NT_STATUS_IS_OK(status)) { torture_comment(tctx, "Failed to call sync libnet_rpc_userinfo - %s\n", nt_errstr(status)); return false; } ZERO_STRUCT(group); group.in.domain_handle = *domain_handle; group.in.sid = NULL; group.in.groupname = TEST_GROUPNAME; group.in.level = level; printf("Testing sync libnet_rpc_groupinfo (groupname argument)\n"); status = libnet_rpc_groupinfo(p, mem_ctx, &group); if (!NT_STATUS_IS_OK(status)) { torture_comment(tctx, "Failed to call sync libnet_rpc_groupinfo - %s\n", nt_errstr(status)); return false; } return true; }
enum security_user_level security_session_user_level(struct auth_session_info *session_info, const struct dom_sid *domain_sid) { if (!session_info) { return SECURITY_ANONYMOUS; } if (security_token_is_system(session_info->security_token)) { return SECURITY_SYSTEM; } if (security_token_is_anonymous(session_info->security_token)) { return SECURITY_ANONYMOUS; } if (security_token_has_builtin_administrators(session_info->security_token)) { return SECURITY_ADMINISTRATOR; } if (domain_sid) { struct dom_sid *rodc_dcs; rodc_dcs = dom_sid_add_rid(session_info, domain_sid, DOMAIN_RID_READONLY_DCS); if (security_token_has_sid(session_info->security_token, rodc_dcs)) { talloc_free(rodc_dcs); return SECURITY_RO_DOMAIN_CONTROLLER; } talloc_free(rodc_dcs); } if (security_token_has_enterprise_dcs(session_info->security_token)) { return SECURITY_DOMAIN_CONTROLLER; } if (security_token_has_nt_authenticated_users(session_info->security_token)) { return SECURITY_USER; } return SECURITY_ANONYMOUS; }
/* decode a SID It can either be a special 2 letter code, or in S-* format */ static struct dom_sid *sddl_decode_sid(TALLOC_CTX *mem_ctx, const char **sddlp, const struct dom_sid *domain_sid) { const char *sddl = (*sddlp); int i; /* see if its in the numeric format */ if (strncmp(sddl, "S-", 2) == 0) { struct dom_sid *sid; char *sid_str; size_t len = strspn(sddl+2, "-0123456789"); sid_str = talloc_strndup(mem_ctx, sddl, len+2); if (!sid_str) { return NULL; } (*sddlp) += len+2; sid = dom_sid_parse_talloc(mem_ctx, sid_str); talloc_free(sid_str); return sid; } /* now check for one of the special codes */ for (i=0;i<ARRAY_SIZE(sid_codes);i++) { if (strncmp(sid_codes[i].code, sddl, 2) == 0) break; } if (i == ARRAY_SIZE(sid_codes)) { DEBUG(1,("Unknown sddl sid code '%2.2s'\n", sddl)); return NULL; } (*sddlp) += 2; if (sid_codes[i].sid == NULL) { return dom_sid_add_rid(mem_ctx, domain_sid, sid_codes[i].rid); } return dom_sid_parse_talloc(mem_ctx, sid_codes[i].sid); }
/* Get the SID from a user */ static const struct dom_sid *get_user_sid(struct torture_context *tctx, struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, const char *user) { struct lsa_ObjectAttribute attr; struct lsa_QosInfo qos; struct lsa_OpenPolicy2 r; struct lsa_Close c; NTSTATUS status; struct policy_handle handle; struct lsa_LookupNames l; struct lsa_TransSidArray sids; struct lsa_RefDomainList *domains = NULL; struct lsa_String lsa_name; uint32_t count = 0; struct dom_sid *result; TALLOC_CTX *tmp_ctx; struct dcerpc_pipe *p2; struct dcerpc_binding_handle *b; const char *domain = cli_credentials_get_domain(cmdline_credentials); torture_assert_ntstatus_ok(tctx, torture_rpc_connection(tctx, &p2, &ndr_table_lsarpc), "could not open lsarpc pipe"); b = p2->binding_handle; if (!(tmp_ctx = talloc_new(mem_ctx))) { return NULL; } qos.len = 0; qos.impersonation_level = 2; qos.context_mode = 1; qos.effective_only = 0; attr.len = 0; attr.root_dir = NULL; attr.object_name = NULL; attr.attributes = 0; attr.sec_desc = NULL; attr.sec_qos = &qos; r.in.system_name = "\\"; r.in.attr = &attr; r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; r.out.handle = &handle; status = dcerpc_lsa_OpenPolicy2_r(b, tmp_ctx, &r); if (!NT_STATUS_IS_OK(status)) { torture_comment(tctx, "OpenPolicy2 failed - %s\n", nt_errstr(status)); talloc_free(tmp_ctx); return NULL; } if (!NT_STATUS_IS_OK(r.out.result)) { torture_comment(tctx, "OpenPolicy2_ failed - %s\n", nt_errstr(r.out.result)); talloc_free(tmp_ctx); return NULL; } sids.count = 0; sids.sids = NULL; lsa_name.string = talloc_asprintf(tmp_ctx, "%s\\%s", domain, user); l.in.handle = &handle; l.in.num_names = 1; l.in.names = &lsa_name; l.in.sids = &sids; l.in.level = 1; l.in.count = &count; l.out.count = &count; l.out.sids = &sids; l.out.domains = &domains; status = dcerpc_lsa_LookupNames_r(b, tmp_ctx, &l); if (!NT_STATUS_IS_OK(status)) { torture_comment(tctx, "LookupNames of %s failed - %s\n", lsa_name.string, nt_errstr(status)); talloc_free(tmp_ctx); return NULL; } if (domains->count == 0) { return NULL; } result = dom_sid_add_rid(mem_ctx, domains->domains[0].sid, l.out.sids->sids[0].rid); c.in.handle = &handle; c.out.handle = &handle; status = dcerpc_lsa_Close_r(b, tmp_ctx, &c); if (!NT_STATUS_IS_OK(status)) { torture_comment(tctx, "dcerpc_lsa_Close failed - %s\n", nt_errstr(status)); talloc_free(tmp_ctx); return NULL; } if (!NT_STATUS_IS_OK(c.out.result)) { torture_comment(tctx, "dcerpc_lsa_Close failed - %s\n", nt_errstr(c.out.result)); talloc_free(tmp_ctx); return NULL; } talloc_free(tmp_ctx); talloc_free(p2); torture_comment(tctx, "Get_user_sid finished\n"); return result; }
struct test_join *torture_create_testuser(struct torture_context *torture, const char *username, const char *domain, uint16_t acct_type, const char **random_password) { NTSTATUS status; struct samr_Connect c; struct samr_CreateUser2 r; struct samr_OpenDomain o; struct samr_LookupDomain l; struct dom_sid2 *sid = NULL; struct samr_GetUserPwInfo pwp; struct samr_PwInfo info; struct samr_SetUserInfo s; union samr_UserInfo u; struct policy_handle handle; struct policy_handle domain_handle; uint32_t access_granted; uint32_t rid; DATA_BLOB session_key; struct lsa_String name; int policy_min_pw_len = 0; struct test_join *join; char *random_pw; const char *dc_binding = torture_setting_string(torture, "dc_binding", NULL); join = talloc(NULL, struct test_join); if (join == NULL) { return NULL; } ZERO_STRUCTP(join); printf("Connecting to SAMR\n"); if (dc_binding) { status = dcerpc_pipe_connect(join, &join->p, dc_binding, &ndr_table_samr, cmdline_credentials, NULL, torture->lp_ctx); } else { status = torture_rpc_connection(torture, &join->p, &ndr_table_samr); } if (!NT_STATUS_IS_OK(status)) { return NULL; } c.in.system_name = NULL; c.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; c.out.connect_handle = &handle; status = dcerpc_samr_Connect(join->p, join, &c); if (!NT_STATUS_IS_OK(status)) { const char *errstr = nt_errstr(status); if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { errstr = dcerpc_errstr(join, join->p->last_fault_code); } printf("samr_Connect failed - %s\n", errstr); return NULL; } printf("Opening domain %s\n", domain); name.string = domain; l.in.connect_handle = &handle; l.in.domain_name = &name; l.out.sid = &sid; status = dcerpc_samr_LookupDomain(join->p, join, &l); if (!NT_STATUS_IS_OK(status)) { printf("LookupDomain failed - %s\n", nt_errstr(status)); goto failed; } talloc_steal(join, *l.out.sid); join->dom_sid = *l.out.sid; join->dom_netbios_name = talloc_strdup(join, domain); if (!join->dom_netbios_name) goto failed; o.in.connect_handle = &handle; o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; o.in.sid = *l.out.sid; o.out.domain_handle = &domain_handle; status = dcerpc_samr_OpenDomain(join->p, join, &o); if (!NT_STATUS_IS_OK(status)) { printf("OpenDomain failed - %s\n", nt_errstr(status)); goto failed; } printf("Creating account %s\n", username); again: name.string = username; r.in.domain_handle = &domain_handle; r.in.account_name = &name; r.in.acct_flags = acct_type; r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; r.out.user_handle = &join->user_handle; r.out.access_granted = &access_granted; r.out.rid = &rid; status = dcerpc_samr_CreateUser2(join->p, join, &r); if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) { status = DeleteUser_byname(join->p, join, &domain_handle, name.string); if (NT_STATUS_IS_OK(status)) { goto again; } } if (!NT_STATUS_IS_OK(status)) { printf("CreateUser2 failed - %s\n", nt_errstr(status)); goto failed; } join->user_sid = dom_sid_add_rid(join, join->dom_sid, rid); pwp.in.user_handle = &join->user_handle; pwp.out.info = &info; status = dcerpc_samr_GetUserPwInfo(join->p, join, &pwp); if (NT_STATUS_IS_OK(status)) { policy_min_pw_len = pwp.out.info->min_password_length; } random_pw = generate_random_str(join, MAX(8, policy_min_pw_len)); printf("Setting account password '%s'\n", random_pw); ZERO_STRUCT(u); s.in.user_handle = &join->user_handle; s.in.info = &u; s.in.level = 24; encode_pw_buffer(u.info24.password.data, random_pw, STR_UNICODE); u.info24.password_expired = 0; status = dcerpc_fetch_session_key(join->p, &session_key); if (!NT_STATUS_IS_OK(status)) { printf("SetUserInfo level %u - no session key - %s\n", s.in.level, nt_errstr(status)); torture_leave_domain(torture, join); goto failed; } arcfour_crypt_blob(u.info24.password.data, 516, &session_key); status = dcerpc_samr_SetUserInfo(join->p, join, &s); if (!NT_STATUS_IS_OK(status)) { printf("SetUserInfo failed - %s\n", nt_errstr(status)); goto failed; } ZERO_STRUCT(u); s.in.user_handle = &join->user_handle; s.in.info = &u; s.in.level = 21; u.info21.acct_flags = acct_type | ACB_PWNOEXP; u.info21.fields_present = SAMR_FIELD_ACCT_FLAGS | SAMR_FIELD_DESCRIPTION | SAMR_FIELD_COMMENT | SAMR_FIELD_FULL_NAME; u.info21.comment.string = talloc_asprintf(join, "Tortured by Samba4: %s", timestring(join, time(NULL))); u.info21.full_name.string = talloc_asprintf(join, "Torture account for Samba4: %s", timestring(join, time(NULL))); u.info21.description.string = talloc_asprintf(join, "Samba4 torture account created by host %s: %s", lp_netbios_name(torture->lp_ctx), timestring(join, time(NULL))); printf("Resetting ACB flags, force pw change time\n"); status = dcerpc_samr_SetUserInfo(join->p, join, &s); if (!NT_STATUS_IS_OK(status)) { printf("SetUserInfo failed - %s\n", nt_errstr(status)); goto failed; } if (random_password) { *random_password = random_pw; } return join; failed: torture_leave_domain(torture, join); return NULL; }
struct test_join *torture_create_testuser_max_pwlen(struct torture_context *torture, const char *username, const char *domain, uint16_t acct_type, const char **random_password, int max_pw_len) { NTSTATUS status; struct samr_Connect c; struct samr_CreateUser2 r; struct samr_OpenDomain o; struct samr_LookupDomain l; struct dom_sid2 *sid = NULL; struct samr_GetUserPwInfo pwp; struct samr_PwInfo info; struct samr_SetUserInfo s; union samr_UserInfo u; struct policy_handle handle; uint32_t access_granted; uint32_t rid; DATA_BLOB session_key; struct lsa_String name; int policy_min_pw_len = 0; struct test_join *join; char *random_pw; const char *dc_binding = torture_setting_string(torture, "dc_binding", NULL); struct dcerpc_binding_handle *b = NULL; join = talloc(NULL, struct test_join); if (join == NULL) { return NULL; } ZERO_STRUCTP(join); printf("Connecting to SAMR\n"); if (dc_binding) { status = dcerpc_pipe_connect(join, &join->p, dc_binding, &ndr_table_samr, cmdline_credentials, NULL, torture->lp_ctx); } else { status = torture_rpc_connection(torture, &join->p, &ndr_table_samr); } if (!NT_STATUS_IS_OK(status)) { return NULL; } b = join->p->binding_handle; c.in.system_name = NULL; c.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; c.out.connect_handle = &handle; status = dcerpc_samr_Connect_r(b, join, &c); if (!NT_STATUS_IS_OK(status)) { const char *errstr = nt_errstr(status); printf("samr_Connect failed - %s\n", errstr); return NULL; } if (!NT_STATUS_IS_OK(c.out.result)) { const char *errstr = nt_errstr(c.out.result); printf("samr_Connect failed - %s\n", errstr); return NULL; } if (domain) { printf("Opening domain %s\n", domain); name.string = domain; l.in.connect_handle = &handle; l.in.domain_name = &name; l.out.sid = &sid; status = dcerpc_samr_LookupDomain_r(b, join, &l); if (!NT_STATUS_IS_OK(status)) { printf("LookupDomain failed - %s\n", nt_errstr(status)); goto failed; } if (!NT_STATUS_IS_OK(l.out.result)) { printf("LookupDomain failed - %s\n", nt_errstr(l.out.result)); goto failed; } } else { struct samr_EnumDomains e; uint32_t resume_handle = 0, num_entries; struct samr_SamArray *sam; int i; e.in.connect_handle = &handle; e.in.buf_size = (uint32_t)-1; e.in.resume_handle = &resume_handle; e.out.sam = &sam; e.out.num_entries = &num_entries; e.out.resume_handle = &resume_handle; status = dcerpc_samr_EnumDomains_r(b, join, &e); if (!NT_STATUS_IS_OK(status)) { printf("EnumDomains failed - %s\n", nt_errstr(status)); goto failed; } if (!NT_STATUS_IS_OK(e.out.result)) { printf("EnumDomains failed - %s\n", nt_errstr(e.out.result)); goto failed; } if ((num_entries != 2) || (sam && sam->count != 2)) { printf("unexpected number of domains\n"); goto failed; } for (i=0; i < 2; i++) { if (!strequal(sam->entries[i].name.string, "builtin")) { domain = sam->entries[i].name.string; break; } } if (domain) { printf("Opening domain %s\n", domain); name.string = domain; l.in.connect_handle = &handle; l.in.domain_name = &name; l.out.sid = &sid; status = dcerpc_samr_LookupDomain_r(b, join, &l); if (!NT_STATUS_IS_OK(status)) { printf("LookupDomain failed - %s\n", nt_errstr(status)); goto failed; } if (!NT_STATUS_IS_OK(l.out.result)) { printf("LookupDomain failed - %s\n", nt_errstr(l.out.result)); goto failed; } } else { printf("cannot proceed without domain name\n"); goto failed; } } talloc_steal(join, *l.out.sid); join->dom_sid = *l.out.sid; join->dom_netbios_name = talloc_strdup(join, domain); if (!join->dom_netbios_name) goto failed; o.in.connect_handle = &handle; o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; o.in.sid = *l.out.sid; o.out.domain_handle = &join->domain_handle; status = dcerpc_samr_OpenDomain_r(b, join, &o); if (!NT_STATUS_IS_OK(status)) { printf("OpenDomain failed - %s\n", nt_errstr(status)); goto failed; } if (!NT_STATUS_IS_OK(o.out.result)) { printf("OpenDomain failed - %s\n", nt_errstr(o.out.result)); goto failed; } printf("Creating account %s\n", username); again: name.string = username; r.in.domain_handle = &join->domain_handle; r.in.account_name = &name; r.in.acct_flags = acct_type; r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; r.out.user_handle = &join->user_handle; r.out.access_granted = &access_granted; r.out.rid = &rid; status = dcerpc_samr_CreateUser2_r(b, join, &r); if (!NT_STATUS_IS_OK(status)) { printf("CreateUser2 failed - %s\n", nt_errstr(status)); goto failed; } if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_USER_EXISTS)) { status = DeleteUser_byname(b, join, &join->domain_handle, name.string); if (NT_STATUS_IS_OK(status)) { goto again; } } if (!NT_STATUS_IS_OK(r.out.result)) { printf("CreateUser2 failed - %s\n", nt_errstr(r.out.result)); goto failed; } join->user_sid = dom_sid_add_rid(join, join->dom_sid, rid); pwp.in.user_handle = &join->user_handle; pwp.out.info = &info; status = dcerpc_samr_GetUserPwInfo_r(b, join, &pwp); if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(pwp.out.result)) { policy_min_pw_len = pwp.out.info->min_password_length; } random_pw = generate_random_password(join, MAX(8, policy_min_pw_len), max_pw_len); printf("Setting account password '%s'\n", random_pw); ZERO_STRUCT(u); s.in.user_handle = &join->user_handle; s.in.info = &u; s.in.level = 24; encode_pw_buffer(u.info24.password.data, random_pw, STR_UNICODE); u.info24.password_expired = 0; status = dcerpc_fetch_session_key(join->p, &session_key); if (!NT_STATUS_IS_OK(status)) { printf("SetUserInfo level %u - no session key - %s\n", s.in.level, nt_errstr(status)); torture_leave_domain(torture, join); goto failed; } arcfour_crypt_blob(u.info24.password.data, 516, &session_key); status = dcerpc_samr_SetUserInfo_r(b, join, &s); if (!NT_STATUS_IS_OK(status)) { printf("SetUserInfo failed - %s\n", nt_errstr(status)); goto failed; } if (!NT_STATUS_IS_OK(s.out.result)) { printf("SetUserInfo failed - %s\n", nt_errstr(s.out.result)); goto failed; } ZERO_STRUCT(u); s.in.user_handle = &join->user_handle; s.in.info = &u; s.in.level = 21; u.info21.acct_flags = acct_type | ACB_PWNOEXP; u.info21.fields_present = SAMR_FIELD_ACCT_FLAGS | SAMR_FIELD_DESCRIPTION | SAMR_FIELD_COMMENT | SAMR_FIELD_FULL_NAME; u.info21.comment.string = talloc_asprintf(join, "Tortured by Samba4: %s", timestring(join, time(NULL))); u.info21.full_name.string = talloc_asprintf(join, "Torture account for Samba4: %s", timestring(join, time(NULL))); u.info21.description.string = talloc_asprintf(join, "Samba4 torture account created by host %s: %s", lpcfg_netbios_name(torture->lp_ctx), timestring(join, time(NULL))); printf("Resetting ACB flags, force pw change time\n"); status = dcerpc_samr_SetUserInfo_r(b, join, &s); if (!NT_STATUS_IS_OK(status)) { printf("SetUserInfo failed - %s\n", nt_errstr(status)); goto failed; } if (!NT_STATUS_IS_OK(s.out.result)) { printf("SetUserInfo failed - %s\n", nt_errstr(s.out.result)); goto failed; } if (random_password) { *random_password = random_pw; } return join; failed: torture_leave_domain(torture, join); return NULL; }
/* 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; }
bool torture_rpc_lsa_lookup(struct torture_context *torture) { NTSTATUS status; struct dcerpc_pipe *p; bool ret = true; struct policy_handle *handle; struct dom_sid *dom_sid = NULL; struct dom_sid *trusted_sid = NULL; struct dom_sid *sids[NUM_SIDS]; struct dcerpc_binding_handle *b; status = torture_rpc_connection(torture, &p, &ndr_table_lsarpc); if (!NT_STATUS_IS_OK(status)) { torture_fail(torture, "unable to connect to table"); } b = p->binding_handle; if (p->binding->transport != NCACN_NP && p->binding->transport != NCALRPC) { torture_comment(torture, "torture_rpc_lsa_lookup is only available " "over NCACN_NP or NCALRPC"); return true; } ret &= open_policy(torture, b, &handle); if (!ret) return false; ret &= get_domainsid(torture, b, handle, &dom_sid); if (!ret) return false; ret &= get_downleveltrust(torture, b, handle, &trusted_sid); if (!ret) return false; torture_comment(torture, "domain sid: %s\n", dom_sid_string(torture, dom_sid)); sids[0] = dom_sid_parse_talloc(torture, "S-1-1-0"); sids[1] = dom_sid_parse_talloc(torture, "S-1-5-4"); sids[2] = dom_sid_parse_talloc(torture, "S-1-5-32"); sids[3] = dom_sid_parse_talloc(torture, "S-1-5-32-545"); sids[4] = dom_sid_dup(torture, dom_sid); sids[5] = dom_sid_add_rid(torture, dom_sid, 512); sids[6] = dom_sid_dup(torture, trusted_sid); sids[7] = dom_sid_add_rid(torture, trusted_sid, 512); ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 0, NT_STATUS_INVALID_PARAMETER, NULL); { enum lsa_SidType types[NUM_SIDS] = { SID_NAME_WKN_GRP, SID_NAME_WKN_GRP, SID_NAME_DOMAIN, SID_NAME_ALIAS, SID_NAME_DOMAIN, SID_NAME_DOM_GRP, SID_NAME_DOMAIN, SID_NAME_DOM_GRP }; ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 1, NT_STATUS_OK, types); } { enum lsa_SidType types[NUM_SIDS] = { SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_DOMAIN, SID_NAME_DOM_GRP, SID_NAME_DOMAIN, SID_NAME_DOM_GRP }; ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 2, STATUS_SOME_UNMAPPED, types); } { enum lsa_SidType types[NUM_SIDS] = { SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_DOMAIN, SID_NAME_DOM_GRP, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN }; ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 3, STATUS_SOME_UNMAPPED, types); } { enum lsa_SidType types[NUM_SIDS] = { SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_DOMAIN, SID_NAME_DOM_GRP, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN }; ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 4, STATUS_SOME_UNMAPPED, types); } ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 5, NT_STATUS_NONE_MAPPED, NULL); { enum lsa_SidType types[NUM_SIDS] = { SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_DOMAIN, SID_NAME_DOM_GRP, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN }; ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 6, STATUS_SOME_UNMAPPED, types); } ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 7, NT_STATUS_INVALID_PARAMETER, NULL); ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 8, NT_STATUS_INVALID_PARAMETER, NULL); ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 9, NT_STATUS_INVALID_PARAMETER, NULL); ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 10, NT_STATUS_INVALID_PARAMETER, NULL); return ret; }
NTSTATUS dsdb_lookup_rids(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct dom_sid *domain_sid, unsigned int num_rids, uint32_t *rids, const char **names, enum lsa_SidType *lsa_attrs) { const char *attrs[] = { "sAMAccountType", "sAMAccountName", NULL }; unsigned int i, num_mapped; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); num_mapped = 0; for (i=0; i<num_rids; i++) { struct ldb_message *msg; struct ldb_dn *dn; uint32_t attr; int rc; lsa_attrs[i] = SID_NAME_UNKNOWN; dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<SID=%s>", dom_sid_string(tmp_ctx, dom_sid_add_rid(tmp_ctx, domain_sid, rids[i]))); if (dn == NULL) { talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rc = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE, attrs, 0, "samAccountName=*"); if (rc == LDB_ERR_NO_SUCH_OBJECT) { continue; } else if (rc != LDB_SUCCESS) { talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } names[i] = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL); if (names[i] == NULL) { DEBUG(10, ("no samAccountName\n")); continue; } talloc_steal(names, names[i]); attr = ldb_msg_find_attr_as_uint(msg, "samAccountType", 0); lsa_attrs[i] = ds_atype_map(attr); if (lsa_attrs[i] == SID_NAME_UNKNOWN) { continue; } num_mapped += 1; } talloc_free(tmp_ctx); if (num_mapped == 0) { return NT_STATUS_NONE_MAPPED; } if (num_mapped < num_rids) { return STATUS_SOME_UNMAPPED; } return NT_STATUS_OK; }
BOOL torture_rpc_lsa_lookup(struct torture_context *torture) { NTSTATUS status; struct dcerpc_pipe *p; TALLOC_CTX *mem_ctx; BOOL ret = True; struct policy_handle *handle; struct dom_sid *dom_sid; struct dom_sid *trusted_sid; struct dom_sid *sids[NUM_SIDS]; mem_ctx = talloc_init("torture_rpc_lsa"); status = torture_rpc_connection(mem_ctx, &p, &dcerpc_table_lsarpc); if (!NT_STATUS_IS_OK(status)) { ret = False; goto done; } ret &= open_policy(mem_ctx, p, &handle); if (!ret) goto done; ret &= get_domainsid(mem_ctx, p, handle, &dom_sid); if (!ret) goto done; ret &= get_downleveltrust(mem_ctx, p, handle, &trusted_sid); if (!ret) goto done; printf("domain sid: %s\n", dom_sid_string(mem_ctx, dom_sid)); sids[0] = dom_sid_parse_talloc(mem_ctx, "S-1-1-0"); sids[1] = dom_sid_parse_talloc(mem_ctx, "S-1-5-4"); sids[2] = dom_sid_parse_talloc(mem_ctx, "S-1-5-32"); sids[3] = dom_sid_parse_talloc(mem_ctx, "S-1-5-32-545"); sids[4] = dom_sid_dup(mem_ctx, dom_sid); sids[5] = dom_sid_add_rid(mem_ctx, dom_sid, 512); sids[6] = dom_sid_dup(mem_ctx, trusted_sid); sids[7] = dom_sid_add_rid(mem_ctx, trusted_sid, 512); ret &= test_lookupsids(mem_ctx, p, handle, sids, NUM_SIDS, 0, NT_STATUS_INVALID_PARAMETER, NULL); { enum lsa_SidType types[NUM_SIDS] = { SID_NAME_WKN_GRP, SID_NAME_WKN_GRP, SID_NAME_DOMAIN, SID_NAME_ALIAS, SID_NAME_DOMAIN, SID_NAME_DOM_GRP, SID_NAME_DOMAIN, SID_NAME_DOM_GRP }; ret &= test_lookupsids(mem_ctx, p, handle, sids, NUM_SIDS, 1, NT_STATUS_OK, types); } { enum lsa_SidType types[NUM_SIDS] = { SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_DOMAIN, SID_NAME_DOM_GRP, SID_NAME_DOMAIN, SID_NAME_DOM_GRP }; ret &= test_lookupsids(mem_ctx, p, handle, sids, NUM_SIDS, 2, STATUS_SOME_UNMAPPED, types); } { enum lsa_SidType types[NUM_SIDS] = { SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_DOMAIN, SID_NAME_DOM_GRP, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN }; ret &= test_lookupsids(mem_ctx, p, handle, sids, NUM_SIDS, 3, STATUS_SOME_UNMAPPED, types); } { enum lsa_SidType types[NUM_SIDS] = { SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_DOMAIN, SID_NAME_DOM_GRP, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN }; ret &= test_lookupsids(mem_ctx, p, handle, sids, NUM_SIDS, 4, STATUS_SOME_UNMAPPED, types); } ret &= test_lookupsids(mem_ctx, p, handle, sids, NUM_SIDS, 5, NT_STATUS_NONE_MAPPED, NULL); { enum lsa_SidType types[NUM_SIDS] = { SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN, SID_NAME_DOMAIN, SID_NAME_DOM_GRP, SID_NAME_UNKNOWN, SID_NAME_UNKNOWN }; ret &= test_lookupsids(mem_ctx, p, handle, sids, NUM_SIDS, 6, STATUS_SOME_UNMAPPED, types); } ret &= test_lookupsids(mem_ctx, p, handle, sids, NUM_SIDS, 7, NT_STATUS_INVALID_PARAMETER, NULL); ret &= test_lookupsids(mem_ctx, p, handle, sids, NUM_SIDS, 8, NT_STATUS_INVALID_PARAMETER, NULL); ret &= test_lookupsids(mem_ctx, p, handle, sids, NUM_SIDS, 9, NT_STATUS_INVALID_PARAMETER, NULL); ret &= test_lookupsids(mem_ctx, p, handle, sids, NUM_SIDS, 10, NT_STATUS_INVALID_PARAMETER, NULL); done: talloc_free(mem_ctx); return ret; }