📄 samsync.c
字号:
/* Unix SMB/CIFS implementation. test suite for netlogon rpc operations Copyright (C) Andrew Tridgell 2003 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004 Copyright (C) Tim Potter 2003 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.*/#include "includes.h"#include "torture/torture.h"#include "auth/auth.h"#include "lib/util/dlinklist.h"#include "lib/crypto/crypto.h"#include "system/time.h"#include "torture/rpc/rpc.h"#include "auth/gensec/schannel_proto.h"#include "auth/gensec/gensec.h"#include "libcli/auth/libcli_auth.h"#include "libcli/security/security.h"#include "librpc/gen_ndr/ndr_netlogon.h"#include "librpc/gen_ndr/ndr_netlogon_c.h"#include "librpc/gen_ndr/ndr_lsa_c.h"#include "librpc/gen_ndr/ndr_samr_c.h"#include "librpc/gen_ndr/ndr_security.h"#include "param/param.h"#define TEST_MACHINE_NAME "samsynctest"#define TEST_WKSTA_MACHINE_NAME "samsynctest2"#define TEST_USER_NAME "samsynctestuser"/* try a netlogon SamLogon*/static NTSTATUS test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct creds_CredentialState *creds, const char *domain, const char *account_name, const char *workstation, struct samr_Password *lm_hash, struct samr_Password *nt_hash, struct netr_SamInfo3 **info3){ NTSTATUS status; struct netr_LogonSamLogon r; struct netr_Authenticator auth, auth2; struct netr_NetworkInfo ninfo; ninfo.identity_info.domain_name.string = domain; ninfo.identity_info.parameter_control = 0; ninfo.identity_info.logon_id_low = 0; ninfo.identity_info.logon_id_high = 0; ninfo.identity_info.account_name.string = account_name; ninfo.identity_info.workstation.string = workstation; generate_random_buffer(ninfo.challenge, sizeof(ninfo.challenge)); if (nt_hash) { ninfo.nt.length = 24; ninfo.nt.data = talloc_array(mem_ctx, uint8_t, 24); SMBOWFencrypt(nt_hash->hash, ninfo.challenge, ninfo.nt.data); } else { ninfo.nt.length = 0; ninfo.nt.data = NULL; } if (lm_hash) { ninfo.lm.length = 24; ninfo.lm.data = talloc_array(mem_ctx, uint8_t, 24); SMBOWFencrypt(lm_hash->hash, ninfo.challenge, ninfo.lm.data); } else { ninfo.lm.length = 0; ninfo.lm.data = NULL; } r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p)); r.in.computer_name = workstation; r.in.credential = &auth; r.in.return_authenticator = &auth2; r.in.logon_level = 2; r.in.logon.network = &ninfo; ZERO_STRUCT(auth2); creds_client_authenticator(creds, &auth); r.in.validation_level = 3; status = dcerpc_netr_LogonSamLogon(p, mem_ctx, &r); if (!creds_client_check(creds, &r.out.return_authenticator->cred)) { printf("Credential chaining failed\n"); } if (info3) { *info3 = r.out.validation.sam3; } return status;}struct samsync_state {/* we remember the sequence numbers so we can easily do a DatabaseDelta */ uint64_t seq_num[3]; const char *domain_name[2]; struct samsync_secret *secrets; struct samsync_trusted_domain *trusted_domains; struct creds_CredentialState *creds; struct creds_CredentialState *creds_netlogon_wksta; struct policy_handle *connect_handle; struct policy_handle *domain_handle[2]; struct dom_sid *sid[2]; struct dcerpc_pipe *p; struct dcerpc_pipe *p_netlogon_wksta; struct dcerpc_pipe *p_samr; struct dcerpc_pipe *p_lsa; struct policy_handle *lsa_handle;};struct samsync_secret { struct samsync_secret *prev, *next; DATA_BLOB secret; const char *name; NTTIME mtime;};struct samsync_trusted_domain { struct samsync_trusted_domain *prev, *next; struct dom_sid *sid; const char *name;};static struct policy_handle *samsync_open_domain(TALLOC_CTX *mem_ctx, struct samsync_state *samsync_state, const char *domain, struct dom_sid **sid){ struct lsa_String name; struct samr_OpenDomain o; struct samr_LookupDomain l; struct policy_handle *domain_handle = talloc(mem_ctx, struct policy_handle); NTSTATUS nt_status; name.string = domain; l.in.connect_handle = samsync_state->connect_handle; l.in.domain_name = &name; nt_status = dcerpc_samr_LookupDomain(samsync_state->p_samr, mem_ctx, &l); if (!NT_STATUS_IS_OK(nt_status)) { printf("LookupDomain failed - %s\n", nt_errstr(nt_status)); return NULL; } o.in.connect_handle = samsync_state->connect_handle; o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; o.in.sid = l.out.sid; o.out.domain_handle = domain_handle; if (sid) { *sid = l.out.sid; } nt_status = dcerpc_samr_OpenDomain(samsync_state->p_samr, mem_ctx, &o); if (!NT_STATUS_IS_OK(nt_status)) { printf("OpenDomain failed - %s\n", nt_errstr(nt_status)); return NULL; } return domain_handle;}static struct sec_desc_buf *samsync_query_samr_sec_desc(TALLOC_CTX *mem_ctx, struct samsync_state *samsync_state, struct policy_handle *handle) { struct samr_QuerySecurity r; NTSTATUS status; r.in.handle = handle; r.in.sec_info = 0x7; status = dcerpc_samr_QuerySecurity(samsync_state->p_samr, mem_ctx, &r); if (!NT_STATUS_IS_OK(status)) { printf("SAMR QuerySecurity failed - %s\n", nt_errstr(status)); return NULL; } return r.out.sdbuf;}static struct sec_desc_buf *samsync_query_lsa_sec_desc(TALLOC_CTX *mem_ctx, struct samsync_state *samsync_state, struct policy_handle *handle) { struct lsa_QuerySecurity r; NTSTATUS status; r.in.handle = handle; r.in.sec_info = 0x7; status = dcerpc_lsa_QuerySecurity(samsync_state->p_lsa, mem_ctx, &r); if (!NT_STATUS_IS_OK(status)) { printf("LSA QuerySecurity failed - %s\n", nt_errstr(status)); return NULL; } return r.out.sdbuf;}#define TEST_UINT64_EQUAL(i1, i2) do {\ if (i1 != i2) {\ printf("%s: uint64 mismatch: " #i1 ": 0x%016llx (%lld) != " #i2 ": 0x%016llx (%lld)\n", \ __location__, \ (long long)i1, (long long)i1, \ (long long)i2, (long long)i2);\ ret = false;\ } \} while (0)#define TEST_INT_EQUAL(i1, i2) do {\ if (i1 != i2) {\ printf("%s: integer mismatch: " #i1 ": 0x%08x (%d) != " #i2 ": 0x%08x (%d)\n", \ __location__, i1, i1, i2, i2); \ ret = false;\ } \} while (0)#define TEST_TIME_EQUAL(t1, t2) do {\ if (t1 != t2) {\ printf("%s: NTTIME mismatch: " #t1 ":%s != " #t2 ": %s\n", \ __location__, nt_time_string(mem_ctx, t1), nt_time_string(mem_ctx, t2));\ ret = false;\ } \} while (0)#define TEST_STRING_EQUAL(s1, s2) do {\ if (!((!s1.string || s1.string[0]=='\0') && (!s2.string || s2.string[0]=='\0')) \ && strcmp_safe(s1.string, s2.string) != 0) {\ printf("%s: string mismatch: " #s1 ":%s != " #s2 ": %s\n", \ __location__, s1.string, s2.string);\ ret = false;\ } \} while (0)#define TEST_SID_EQUAL(s1, s2) do {\ if (!dom_sid_equal(s1, s2)) {\ printf("%s: dom_sid mismatch: " #s1 ":%s != " #s2 ": %s\n", \ __location__, dom_sid_string(mem_ctx, s1), dom_sid_string(mem_ctx, s2));\ ret = false;\ } \} while (0)/* The ~SEC_DESC_SACL_PRESENT is because we don't, as administrator, * get back the SACL part of the SD when we ask over SAMR */#define TEST_SEC_DESC_EQUAL(sd1, pipe, handle) do {\ struct sec_desc_buf *sdbuf = samsync_query_ ##pipe## _sec_desc(mem_ctx, samsync_state, \ handle); \ if (!sdbuf || !sdbuf->sd) { \ printf("Could not obtain security descriptor to match " #sd1 "\n");\ ret = false; \ } else {\ if (!security_descriptor_mask_equal(sd1.sd, sdbuf->sd, \ ~SEC_DESC_SACL_PRESENT)) {\ printf("Security Descriptor Mismatch for %s:\n", #sd1);\ ndr_print_debug((ndr_print_fn_t)ndr_print_security_descriptor, "SamSync", sd1.sd);\ ndr_print_debug((ndr_print_fn_t)ndr_print_security_descriptor, "SamR", sdbuf->sd);\ ret = false;\ }\ }\} while (0)static bool samsync_handle_domain(TALLOC_CTX *mem_ctx, struct samsync_state *samsync_state, int database_id, struct netr_DELTA_ENUM *delta) { struct netr_DELTA_DOMAIN *domain = delta->delta_union.domain; struct dom_sid *dom_sid; struct samr_QueryDomainInfo q[14]; /* q[0] will be unused simple for clarity */ uint16_t levels[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13}; NTSTATUS nt_status; int i; bool ret = true; samsync_state->seq_num[database_id] = domain->sequence_num; switch (database_id) { case SAM_DATABASE_DOMAIN: break; case SAM_DATABASE_BUILTIN: if (strcasecmp_m("BUILTIN", domain->domain_name.string) != 0) { printf("BUILTIN domain has different name: %s\n", domain->domain_name.string); } break; case SAM_DATABASE_PRIVS: printf("DOMAIN entry on privs DB!\n"); return false; break; } if (!samsync_state->domain_name[database_id]) { samsync_state->domain_name[database_id] = talloc_reference(samsync_state, domain->domain_name.string); } else { if (strcasecmp_m(samsync_state->domain_name[database_id], domain->domain_name.string) != 0) { printf("Domain has name varies!: %s != %s\n", samsync_state->domain_name[database_id], domain->domain_name.string); return false; } } if (!samsync_state->domain_handle[database_id]) { samsync_state->domain_handle[database_id] = talloc_reference(samsync_state, samsync_open_domain(mem_ctx, samsync_state, samsync_state->domain_name[database_id], &dom_sid)); } if (samsync_state->domain_handle[database_id]) { samsync_state->sid[database_id] = talloc_reference(samsync_state, dom_sid); } printf("\tsequence_nums[%d/%s]=%llu\n", database_id, domain->domain_name.string, (long long)samsync_state->seq_num[database_id]); for (i=0;i<ARRAY_SIZE(levels);i++) { q[levels[i]].in.domain_handle = samsync_state->domain_handle[database_id]; q[levels[i]].in.level = levels[i]; nt_status = dcerpc_samr_QueryDomainInfo(samsync_state->p_samr, mem_ctx, &q[levels[i]]); if (!NT_STATUS_IS_OK(nt_status)) { printf("QueryDomainInfo level %u failed - %s\n", q[levels[i]].in.level, nt_errstr(nt_status)); return false; } } TEST_STRING_EQUAL(q[5].out.info->info5.domain_name, domain->domain_name); TEST_STRING_EQUAL(q[2].out.info->info2.comment, domain->comment); TEST_STRING_EQUAL(q[4].out.info->info4.comment, domain->comment); TEST_TIME_EQUAL(q[2].out.info->info2.force_logoff_time, domain->force_logoff_time); TEST_TIME_EQUAL(q[3].out.info->info3.force_logoff_time, domain->force_logoff_time); TEST_TIME_EQUAL(q[1].out.info->info1.min_password_length, domain->min_password_length); TEST_TIME_EQUAL(q[1].out.info->info1.password_history_length, domain->password_history_length); TEST_TIME_EQUAL(q[1].out.info->info1.max_password_age, domain->max_password_age); TEST_TIME_EQUAL(q[1].out.info->info1.min_password_age, domain->min_password_age); TEST_UINT64_EQUAL(q[8].out.info->info8.sequence_num, domain->sequence_num); TEST_TIME_EQUAL(q[8].out.info->info8.domain_create_time, domain->domain_create_time); TEST_TIME_EQUAL(q[13].out.info->info13.domain_create_time, domain->domain_create_time); TEST_SEC_DESC_EQUAL(domain->sdbuf, samr, samsync_state->domain_handle[database_id]); return ret;}static bool samsync_handle_policy(TALLOC_CTX *mem_ctx, struct samsync_state *samsync_state, int database_id, struct netr_DELTA_ENUM *delta) { struct netr_DELTA_POLICY *policy = delta->delta_union.policy; samsync_state->seq_num[database_id] = policy->sequence_num; if (!samsync_state->domain_name[SAM_DATABASE_DOMAIN]) { samsync_state->domain_name[SAM_DATABASE_DOMAIN] = talloc_reference(samsync_state, policy->primary_domain_name.string); } else { if (strcasecmp_m(samsync_state->domain_name[SAM_DATABASE_DOMAIN], policy->primary_domain_name.string) != 0) { printf("PRIMARY domain has name varies between DOMAIN and POLICY!: %s != %s\n", samsync_state->domain_name[SAM_DATABASE_DOMAIN], policy->primary_domain_name.string); return false; } } if (!dom_sid_equal(samsync_state->sid[SAM_DATABASE_DOMAIN], policy->sid)) { printf("Domain SID from POLICY (%s) does not match domain sid from SAMR (%s)\n", dom_sid_string(mem_ctx, policy->sid), dom_sid_string(mem_ctx, samsync_state->sid[SAM_DATABASE_DOMAIN])); return false; } printf("\tsequence_nums[%d/PRIVS]=%llu\n", database_id, (long long)samsync_state->seq_num[database_id]); return true;}static bool samsync_handle_user(struct torture_context *tctx, TALLOC_CTX *mem_ctx, struct samsync_state *samsync_state, int database_id, struct netr_DELTA_ENUM *delta) { uint32_t rid = delta->delta_id_union.rid; struct netr_DELTA_USER *user = delta->delta_union.user; struct netr_SamInfo3 *info3; struct samr_Password lm_hash; struct samr_Password nt_hash; struct samr_Password *lm_hash_p = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -