diff options
Diffstat (limited to 'source4/libnet')
-rw-r--r-- | source4/libnet/libnet_join.c | 250 | ||||
-rw-r--r-- | source4/libnet/libnet_join.h | 1 | ||||
-rw-r--r-- | source4/libnet/libnet_rpc.c | 191 | ||||
-rw-r--r-- | source4/libnet/libnet_rpc.h | 19 | ||||
-rw-r--r-- | source4/libnet/libnet_samdump.c | 9 | ||||
-rw-r--r-- | source4/libnet/libnet_samdump_keytab.c | 5 | ||||
-rw-r--r-- | source4/libnet/libnet_samsync_ldb.c | 164 | ||||
-rw-r--r-- | source4/libnet/libnet_vampire.c | 43 | ||||
-rw-r--r-- | source4/libnet/libnet_vampire.h | 9 |
9 files changed, 440 insertions, 251 deletions
diff --git a/source4/libnet/libnet_join.c b/source4/libnet/libnet_join.c index c961ff0cfe..0147679bcd 100644 --- a/source4/libnet/libnet_join.c +++ b/source4/libnet/libnet_join.c @@ -544,21 +544,23 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J /* * do a domain join using DCERPC/SAMR calls - * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) - * is it correct to contact the the pdc of the domain of the user who's password should be set? - * 2. do a samr_Connect to get a policy handle - * 3. do a samr_LookupDomain to get the domain sid - * 4. do a samr_OpenDomain to get a domain handle - * 5. do a samr_CreateAccount to try and get a new account + * - connect to the LSA pipe, to try and find out information about the domain + * - create a secondary connection to SAMR pipe + * - do a samr_Connect to get a policy handle + * - do a samr_LookupDomain to get the domain sid + * - do a samr_OpenDomain to get a domain handle + * - do a samr_CreateAccount to try and get a new account * * If that fails, do: - * 5.1. do a samr_LookupNames to get the users rid - * 5.2. do a samr_OpenUser to get a user handle + * - do a samr_LookupNames to get the users rid + * - do a samr_OpenUser to get a user handle + * - potentially delete and recreate the user + * - assert the account is of the right type with samrQueryUserInfo * - * 6. call libnet_SetPassword_samr_handle to set the password + * - call libnet_SetPassword_samr_handle to set the password * - * 7. do a samrSetUserInfo to set the account flags - * 8. do some ADS specific things when we join as Domain Controller, + * - do a samrSetUserInfo to set the account flags + * - do some ADS specific things when we join as Domain Controller, * look at libnet_joinADSDomain() for the details */ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_JoinDomain *r) @@ -566,17 +568,10 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru TALLOC_CTX *tmp_ctx; NTSTATUS status, cu_status; - struct libnet_RpcConnect *c; - struct lsa_ObjectAttribute attr; - struct lsa_QosInfo qos; - struct lsa_OpenPolicy2 lsa_open_policy; - struct policy_handle lsa_p_handle; - struct lsa_QueryInfoPolicy2 lsa_query_info2; - struct lsa_QueryInfoPolicy lsa_query_info; - - struct dcerpc_binding *samr_binding; + + struct libnet_RpcConnectDCInfo *connect_with_info; struct dcerpc_pipe *samr_pipe; - struct dcerpc_pipe *lsa_pipe; + struct samr_Connect sc; struct policy_handle p_handle; struct samr_OpenDomain od; @@ -596,9 +591,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru uint32_t rid, access_granted; int policy_min_pw_len = 0; - struct dom_sid *domain_sid = NULL; struct dom_sid *account_sid = NULL; - const char *domain_name = NULL; const char *password_str = NULL; const char *realm = NULL; /* Also flag for remote being AD */ @@ -619,162 +612,47 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru return NT_STATUS_NO_MEMORY; } - samr_pipe = talloc(tmp_ctx, struct dcerpc_pipe); - if (!samr_pipe) { - r->out.error_string = NULL; - talloc_free(tmp_ctx); - return NT_STATUS_NO_MEMORY; - } - - c = talloc(tmp_ctx, struct libnet_RpcConnect); - if (!c) { + connect_with_info = talloc(tmp_ctx, struct libnet_RpcConnectDCInfo); + if (!connect_with_info) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } - + /* prepare connect to the LSA pipe of PDC */ if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) { - c->level = LIBNET_RPC_CONNECT_PDC; - c->in.name = r->in.domain_name; + connect_with_info->level = LIBNET_RPC_CONNECT_PDC; + connect_with_info->in.name = r->in.domain_name; } else { - c->level = LIBNET_RPC_CONNECT_BINDING; - c->in.binding = r->in.binding; + connect_with_info->level = LIBNET_RPC_CONNECT_BINDING; + connect_with_info->in.binding = r->in.binding; } - c->in.dcerpc_iface = &dcerpc_table_lsarpc; - - /* connect to the LSA pipe of the PDC */ - status = libnet_RpcConnect(ctx, c, c); + connect_with_info->in.dcerpc_iface = &dcerpc_table_samr; + /* + establish a SAMR connection, on the same CIFS transport + */ + + status = libnet_RpcConnectDCInfo(ctx, connect_with_info); if (!NT_STATUS_IS_OK(status)) { - if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) { + if (r->in.binding) { r->out.error_string = talloc_asprintf(mem_ctx, - "Connection to LSA pipe of PDC of domain '%s' failed: %s", - r->in.domain_name, nt_errstr(status)); + "Connection to SAMR pipe of DC %s failed: %s", + r->in.binding, connect_with_info->out.error_string); } else { r->out.error_string = talloc_asprintf(mem_ctx, - "Connection to LSA pipe with binding '%s' failed: %s", - r->in.binding, nt_errstr(status)); - } - talloc_free(tmp_ctx); - return status; - } - lsa_pipe = c->out.dcerpc_pipe; - - /* Get an LSA policy handle */ - - ZERO_STRUCT(lsa_p_handle); - 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; - - lsa_open_policy.in.attr = &attr; - - lsa_open_policy.in.system_name = talloc_asprintf(tmp_ctx, "\\"); - if (!lsa_open_policy.in.system_name) { - r->out.error_string = NULL; - talloc_free(tmp_ctx); - return NT_STATUS_NO_MEMORY; - } - - lsa_open_policy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - lsa_open_policy.out.handle = &lsa_p_handle; - - status = dcerpc_lsa_OpenPolicy2(lsa_pipe, tmp_ctx, &lsa_open_policy); - - /* This now fails on ncacn_ip_tcp against Win2k3 SP1 */ - if (NT_STATUS_IS_OK(status)) { - /* Look to see if this is ADS (a fault indicates NT4 or Samba 3.0) */ - - lsa_query_info2.in.handle = &lsa_p_handle; - lsa_query_info2.in.level = LSA_POLICY_INFO_DNS; - - status = dcerpc_lsa_QueryInfoPolicy2(lsa_pipe, tmp_ctx, - &lsa_query_info2); - - if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { - if (!NT_STATUS_IS_OK(status)) { - r->out.error_string = talloc_asprintf(mem_ctx, - "lsa_QueryInfoPolicy2 failed: %s", - nt_errstr(status)); - talloc_free(tmp_ctx); - return status; - } - realm = lsa_query_info2.out.info->dns.dns_domain.string; - } - - /* Grab the domain SID (regardless of the result of the previous call */ - - lsa_query_info.in.handle = &lsa_p_handle; - lsa_query_info.in.level = LSA_POLICY_INFO_DOMAIN; - - status = dcerpc_lsa_QueryInfoPolicy(lsa_pipe, tmp_ctx, - &lsa_query_info); - - if (!NT_STATUS_IS_OK(status)) { - r->out.error_string = talloc_asprintf(mem_ctx, - "lsa_QueryInfoPolicy2 failed: %s", - nt_errstr(status)); - talloc_free(tmp_ctx); - return status; - } - - domain_sid = lsa_query_info.out.info->domain.sid; - domain_name = lsa_query_info.out.info->domain.name.string; - } else { - /* Cause the code further down to try this with just SAMR */ - domain_sid = NULL; - if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) { - domain_name = talloc_strdup(tmp_ctx, r->in.domain_name); - } else { - /* Bugger, we just lost our way to automaticly find the domain name */ - domain_name = talloc_strdup(tmp_ctx, lp_workgroup()); + "Connection to SAMR pipe of PDC for %s failed: %s", + r->in.domain_name, connect_with_info->out.error_string); } - } - - /* - establish a SAMR connection, on the same CIFS transport - */ - - /* Find the original binding string */ - samr_binding = talloc(tmp_ctx, struct dcerpc_binding); - if (!samr_binding) { - return NT_STATUS_NO_MEMORY; - } - *samr_binding = *lsa_pipe->binding; - - /* Make binding string for samr, not the other pipe */ - status = dcerpc_epm_map_binding(tmp_ctx, samr_binding, - &dcerpc_table_samr, - lsa_pipe->conn->event_ctx); - if (!NT_STATUS_IS_OK(status)) { - r->out.error_string = talloc_asprintf(mem_ctx, - "Failed to map DCERPC/TCP NCACN_NP pipe for '%s' - %s", - DCERPC_NETLOGON_UUID, - nt_errstr(status)); talloc_free(tmp_ctx); return status; } - /* Setup a SAMR connection */ - status = dcerpc_secondary_connection(lsa_pipe, &samr_pipe, samr_binding); - if (!NT_STATUS_IS_OK(status)) { - r->out.error_string = talloc_asprintf(mem_ctx, - "SAMR secondary connection failed: %s", - nt_errstr(status)); - talloc_free(tmp_ctx); - return status; - } + samr_pipe = connect_with_info->out.dcerpc_pipe, - status = dcerpc_pipe_auth(samr_pipe, samr_binding, &dcerpc_table_samr, ctx->cred); + status = dcerpc_pipe_auth(samr_pipe, + connect_with_info->out.dcerpc_pipe->binding, + &dcerpc_table_samr, ctx->cred); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "SAMR bind failed: %s", @@ -799,11 +677,21 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru return status; } + /* If this is a connection on ncacn_ip_tcp to Win2k3 SP1, we don't get back this useful info */ + if (!connect_with_info->out.domain_name) { + if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) { + connect_with_info->out.domain_name = talloc_strdup(tmp_ctx, r->in.domain_name); + } else { + /* Bugger, we just lost our way to automaticly find the domain name */ + connect_with_info->out.domain_name = talloc_strdup(tmp_ctx, lp_workgroup()); + } + } + /* Perhaps we didn't get a SID above, because we are against ncacn_ip_tcp */ - if (!domain_sid) { + if (!connect_with_info->out.domain_sid) { struct lsa_String name; struct samr_LookupDomain l; - name.string = domain_name; + name.string = connect_with_info->out.domain_name; l.in.connect_handle = &p_handle; l.in.domain_name = &name; @@ -815,23 +703,23 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru talloc_free(tmp_ctx); return status; } - domain_sid = l.out.sid; + connect_with_info->out.domain_sid = l.out.sid; } /* prepare samr_OpenDomain */ ZERO_STRUCT(d_handle); od.in.connect_handle = &p_handle; od.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - od.in.sid = domain_sid; + od.in.sid = connect_with_info->out.domain_sid; od.out.domain_handle = &d_handle; /* do a samr_OpenDomain to get a domain handle */ status = dcerpc_samr_OpenDomain(samr_pipe, tmp_ctx, &od); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, - "samr_OpenDomain for [%s] failed: %s", - r->in.domain_name, - nt_errstr(status)); + "samr_OpenDomain for [%s] failed: %s", + dom_sid_string(tmp_ctx, connect_with_info->out.domain_sid), + nt_errstr(status)); talloc_free(tmp_ctx); return status; } @@ -1010,7 +898,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru "The machine account (%s) already exists in the domain %s, " "but is a %s. You asked to join as a %s. Please delete " "the account and try again.\n", - r->in.account_name, domain_name, old_account_type, new_account_type); + r->in.account_name, connect_with_info->out.domain_name, old_account_type, new_account_type); talloc_free(tmp_ctx); return NT_STATUS_USER_EXISTS; } @@ -1065,7 +953,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru } } - account_sid = dom_sid_add_rid(mem_ctx, domain_sid, rid); + account_sid = dom_sid_add_rid(mem_ctx, connect_with_info->out.domain_sid, rid); if (!account_sid) { r->out.error_string = NULL; talloc_free(tmp_ctx); @@ -1074,24 +962,22 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru /* Finish out by pushing various bits of status data out for the caller to use */ r->out.join_password = password_str; - talloc_steal(mem_ctx, password_str); + talloc_steal(mem_ctx, r->out.join_password); - r->out.domain_sid = domain_sid; - talloc_steal(mem_ctx, domain_sid); + r->out.domain_sid = connect_with_info->out.domain_sid; + talloc_steal(mem_ctx, r->out.domain_sid); r->out.account_sid = account_sid; - talloc_steal(mem_ctx, account_sid); - - r->out.domain_name = domain_name; - talloc_steal(mem_ctx, domain_name); - r->out.realm = realm; - talloc_steal(mem_ctx, realm); - r->out.lsa_pipe = lsa_pipe; - talloc_steal(mem_ctx, lsa_pipe); + talloc_steal(mem_ctx, r->out.account_sid); + + r->out.domain_name = connect_with_info->out.domain_name; + talloc_steal(mem_ctx, r->out.domain_name); + r->out.realm = connect_with_info->out.realm; + talloc_steal(mem_ctx, r->out.realm); r->out.samr_pipe = samr_pipe; talloc_steal(mem_ctx, samr_pipe); - r->out.samr_binding = samr_binding; - talloc_steal(mem_ctx, samr_binding); + r->out.samr_binding = samr_pipe->binding; + talloc_steal(mem_ctx, r->out.samr_binding); r->out.user_handle = u_handle; talloc_steal(mem_ctx, u_handle); r->out.error_string = r2.samr_handle.out.error_string; diff --git a/source4/libnet/libnet_join.h b/source4/libnet/libnet_join.h index 04f23c1d99..35460b7a0a 100644 --- a/source4/libnet/libnet_join.h +++ b/source4/libnet/libnet_join.h @@ -53,7 +53,6 @@ struct libnet_JoinDomain { const char *account_dn_str; const char *server_dn_str; uint32_t kvno; /* msDS-KeyVersionNumber */ - struct dcerpc_pipe *lsa_pipe; struct dcerpc_pipe *samr_pipe; struct dcerpc_binding *samr_binding; struct policy_handle *user_handle; diff --git a/source4/libnet/libnet_rpc.c b/source4/libnet/libnet_rpc.c index 1f98e575d1..aba393d7fb 100644 --- a/source4/libnet/libnet_rpc.c +++ b/source4/libnet/libnet_rpc.c @@ -78,7 +78,7 @@ static NTSTATUS libnet_RpcConnectSrv(struct libnet_context *ctx, TALLOC_CTX *mem * @return nt status of the call **/ -static NTSTATUS libnet_RpcConnectPdc(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r) +static NTSTATUS libnet_RpcConnectDC(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r) { NTSTATUS status; struct libnet_RpcConnect r2; @@ -153,8 +153,195 @@ NTSTATUS libnet_RpcConnect(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru case LIBNET_RPC_CONNECT_PDC: case LIBNET_RPC_CONNECT_DC: - return libnet_RpcConnectPdc(ctx, mem_ctx, r); + return libnet_RpcConnectDC(ctx, mem_ctx, r); } return NT_STATUS_INVALID_LEVEL; } + +/** + * Connects to rpc pipe on remote server or pdc, and returns info on the domain name, domain sid and realm + * + * @param ctx initialised libnet context + * @param r data structure containing necessary parameters and return values. Must be a talloc context + * @return nt status of the call + **/ + +NTSTATUS libnet_RpcConnectDCInfo(struct libnet_context *ctx, + struct libnet_RpcConnectDCInfo *r) +{ + TALLOC_CTX *tmp_ctx; + NTSTATUS status; + + struct libnet_RpcConnect *c; + struct lsa_ObjectAttribute attr; + struct lsa_QosInfo qos; + struct lsa_OpenPolicy2 lsa_open_policy; + struct policy_handle lsa_p_handle; + struct lsa_QueryInfoPolicy2 lsa_query_info2; + struct lsa_QueryInfoPolicy lsa_query_info; + + struct dcerpc_pipe *lsa_pipe; + + struct dcerpc_binding *final_binding; + struct dcerpc_pipe *final_pipe; + + tmp_ctx = talloc_new(r); + if (!tmp_ctx) { + r->out.error_string = NULL; + return NT_STATUS_NO_MEMORY; + } + + c = talloc(tmp_ctx, struct libnet_RpcConnect); + if (!c) { + r->out.error_string = NULL; + talloc_free(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + c->level = r->level; + + if (r->level != LIBNET_RPC_CONNECT_BINDING) { + c->in.name = r->in.name; + } else { + c->in.binding = r->in.binding; + } + + c->in.dcerpc_iface = &dcerpc_table_lsarpc; + + /* connect to the LSA pipe of the PDC */ + + status = libnet_RpcConnect(ctx, c, c); + if (!NT_STATUS_IS_OK(status)) { + if (r->level != LIBNET_RPC_CONNECT_BINDING) { + r->out.error_string = talloc_asprintf(r, + "Connection to LSA pipe of DC failed: %s", + c->out.error_string); + } else { + r->out.error_string = talloc_asprintf(r, + "Connection to LSA pipe with binding '%s' failed: %s", + r->in.binding, c->out.error_string); + } + talloc_free(tmp_ctx); + return status; + } + lsa_pipe = c->out.dcerpc_pipe; + + /* Get an LSA policy handle */ + + ZERO_STRUCT(lsa_p_handle); + 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; + + lsa_open_policy.in.attr = &attr; + + lsa_open_policy.in.system_name = talloc_asprintf(tmp_ctx, "\\"); + if (!lsa_open_policy.in.system_name) { + r->out.error_string = NULL; + talloc_free(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + + lsa_open_policy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + lsa_open_policy.out.handle = &lsa_p_handle; + + status = dcerpc_lsa_OpenPolicy2(lsa_pipe, tmp_ctx, &lsa_open_policy); + + /* This now fails on ncacn_ip_tcp against Win2k3 SP1 */ + if (NT_STATUS_IS_OK(status)) { + /* Look to see if this is ADS (a fault indicates NT4 or Samba 3.0) */ + + lsa_query_info2.in.handle = &lsa_p_handle; + lsa_query_info2.in.level = LSA_POLICY_INFO_DNS; + + status = dcerpc_lsa_QueryInfoPolicy2(lsa_pipe, tmp_ctx, + &lsa_query_info2); + + if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { + if (!NT_STATUS_IS_OK(status)) { + r->out.error_string = talloc_asprintf(r, + "lsa_QueryInfoPolicy2 failed: %s", + nt_errstr(status)); + talloc_free(tmp_ctx); + return status; + } + r->out.realm = lsa_query_info2.out.info->dns.dns_domain.string; + } else { + r->out.realm = NULL; + } + + /* Grab the domain SID (regardless of the result of the previous call */ + + lsa_query_info.in.handle = &lsa_p_handle; + lsa_query_info.in.level = LSA_POLICY_INFO_DOMAIN; + + status = dcerpc_lsa_QueryInfoPolicy(lsa_pipe, tmp_ctx, + &lsa_query_info); + + if (!NT_STATUS_IS_OK(status)) { + r->out.error_string = talloc_asprintf(r, + "lsa_QueryInfoPolicy2 failed: %s", + nt_errstr(status)); + talloc_free(tmp_ctx); + return status; + } + + r->out.domain_sid = lsa_query_info.out.info->domain.sid; + r->out.domain_name = lsa_query_info.out.info->domain.name.string; + } else { + /* Cause the code further down to try this with just SAMR */ + r->out.domain_sid = NULL; + r->out.domain_name = NULL; + r->out.realm = NULL; + } + + /* Find the original binding string */ + final_binding = talloc(tmp_ctx, struct dcerpc_binding); + if (!final_binding) { + return NT_STATUS_NO_MEMORY; + } + *final_binding = *lsa_pipe->binding; + /* Ensure we keep hold of the member elements */ + talloc_reference(final_binding, lsa_pipe->binding); + + /* Make binding string for samr, not the other pipe */ + status = dcerpc_epm_map_binding(tmp_ctx, final_binding, + r->in.dcerpc_iface, + lsa_pipe->conn->event_ctx); + if (!NT_STATUS_IS_OK(status)) { + r->out.error_string = talloc_asprintf(r, + "Failed to map pipe with endpoint mapper - %s", + nt_errstr(status)); + talloc_free(tmp_ctx); + return status; + } + + /* Now that we have the info setup a final connection to the pipe they wanted */ + status = dcerpc_secondary_connection(lsa_pipe, &final_pipe, final_binding); + if (!NT_STATUS_IS_OK(status)) { + r->out.error_string = talloc_asprintf(r, + "secondary connection failed: %s", + nt_errstr(status)); + talloc_free(tmp_ctx); + return status; + } + r->out.dcerpc_pipe = final_pipe; + + talloc_steal(r, r->out.realm); + talloc_steal(r, r->out.domain_sid); + talloc_steal(r, r->out.domain_name); + talloc_steal(r, r->out.dcerpc_pipe); + + /* This should close the LSA pipe, which we don't need now we have the info */ + talloc_free(tmp_ctx); + return NT_STATUS_OK; +} + diff --git a/source4/libnet/libnet_rpc.h b/source4/libnet/libnet_rpc.h index 5505e69a09..ce88462485 100644 --- a/source4/libnet/libnet_rpc.h +++ b/source4/libnet/libnet_rpc.h @@ -45,3 +45,22 @@ struct libnet_RpcConnect { const char *error_string; } out; }; + +struct libnet_RpcConnectDCInfo { + enum libnet_RpcConnect_level level; + + struct { + const char *name; + const char *binding; + const struct dcerpc_interface_table *dcerpc_iface; + } in; + struct { + struct dcerpc_pipe *dcerpc_pipe; + struct dom_sid *domain_sid; + const char *domain_name; + + /* This parameter only present if the remote server is known to be AD */ + const char *realm; + const char *error_string; + } out; +}; diff --git a/source4/libnet/libnet_samdump.c b/source4/libnet/libnet_samdump.c index e094293916..8936d6829a 100644 --- a/source4/libnet/libnet_samdump.c +++ b/source4/libnet/libnet_samdump.c @@ -46,7 +46,6 @@ struct samdump_state { }; static NTSTATUS vampire_samdump_handle_user(TALLOC_CTX *mem_ctx, - struct creds_CredentialState *creds, struct netr_DELTA_ENUM *delta) { uint32_t rid = delta->delta_id_union.rid; @@ -72,7 +71,6 @@ static NTSTATUS vampire_samdump_handle_user(TALLOC_CTX *mem_ctx, static NTSTATUS vampire_samdump_handle_secret(TALLOC_CTX *mem_ctx, struct samdump_state *samdump_state, - struct creds_CredentialState *creds, struct netr_DELTA_ENUM *delta) { struct netr_DELTA_SECRET *secret = delta->delta_union.secret; @@ -90,7 +88,6 @@ static NTSTATUS vampire_samdump_handle_secret(TALLOC_CTX *mem_ctx, static NTSTATUS vampire_samdump_handle_trusted_domain(TALLOC_CTX *mem_ctx, struct samdump_state *samdump_state, - struct creds_CredentialState *creds, struct netr_DELTA_ENUM *delta) { struct netr_DELTA_TRUSTED_DOMAIN *trusted_domain = delta->delta_union.trusted_domain; @@ -108,7 +105,6 @@ static NTSTATUS vampire_samdump_handle_trusted_domain(TALLOC_CTX *mem_ctx, static NTSTATUS libnet_samdump_fn(TALLOC_CTX *mem_ctx, void *private, - struct creds_CredentialState *creds, enum netr_SamDatabaseID database, struct netr_DELTA_ENUM *delta, char **error_string) @@ -123,7 +119,6 @@ static NTSTATUS libnet_samdump_fn(TALLOC_CTX *mem_ctx, /* not interested in builtin users */ if (database == SAM_DATABASE_DOMAIN) { nt_status = vampire_samdump_handle_user(mem_ctx, - creds, delta); break; } @@ -132,7 +127,6 @@ static NTSTATUS libnet_samdump_fn(TALLOC_CTX *mem_ctx, { nt_status = vampire_samdump_handle_secret(mem_ctx, samdump_state, - creds, delta); break; } @@ -140,7 +134,6 @@ static NTSTATUS libnet_samdump_fn(TALLOC_CTX *mem_ctx, { nt_status = vampire_samdump_handle_trusted_domain(mem_ctx, samdump_state, - creds, delta); break; } @@ -169,11 +162,13 @@ NTSTATUS libnet_SamDump(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct r2.out.error_string = NULL; r2.in.binding_string = r->in.binding_string; + r2.in.init_fn = NULL; r2.in.delta_fn = libnet_samdump_fn; r2.in.fn_ctx = samdump_state; r2.in.machine_account = r->in.machine_account; nt_status = libnet_SamSync_netlogon(ctx, samdump_state, &r2); r->out.error_string = r2.out.error_string; + talloc_steal(mem_ctx, r->out.error_string); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(samdump_state); diff --git a/source4/libnet/libnet_samdump_keytab.c b/source4/libnet/libnet_samdump_keytab.c index f16e0ae383..de575ec668 100644 --- a/source4/libnet/libnet_samdump_keytab.c +++ b/source4/libnet/libnet_samdump_keytab.c @@ -27,7 +27,6 @@ static NTSTATUS samdump_keytab_handle_user(TALLOC_CTX *mem_ctx, const char *keytab_name, - struct creds_CredentialState *creds, struct netr_DELTA_ENUM *delta) { struct netr_DELTA_USER *user = delta->delta_union.user; @@ -66,7 +65,6 @@ static NTSTATUS samdump_keytab_handle_user(TALLOC_CTX *mem_ctx, static NTSTATUS libnet_samdump_keytab_fn(TALLOC_CTX *mem_ctx, void *private, - struct creds_CredentialState *creds, enum netr_SamDatabaseID database, struct netr_DELTA_ENUM *delta, char **error_string) @@ -82,7 +80,6 @@ static NTSTATUS libnet_samdump_keytab_fn(TALLOC_CTX *mem_ctx, if (database == SAM_DATABASE_DOMAIN) { nt_status = samdump_keytab_handle_user(mem_ctx, keytab_name, - creds, delta); break; } @@ -101,11 +98,13 @@ NTSTATUS libnet_SamDump_keytab(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, r2.out.error_string = NULL; r2.in.binding_string = r->in.binding_string; + r2.in.init_fn = NULL; r2.in.delta_fn = libnet_samdump_keytab_fn; r2.in.fn_ctx = discard_const(r->in.keytab_name); r2.in.machine_account = r->in.machine_account; nt_status = libnet_SamSync_netlogon(ctx, mem_ctx, &r2); r->out.error_string = r2.out.error_string; + talloc_steal(mem_ctx, r->out.error_string); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; diff --git a/source4/libnet/libnet_samsync_ldb.c b/source4/libnet/libnet_samsync_ldb.c index 5587f208ef..da4e777a15 100644 --- a/source4/libnet/libnet_samsync_ldb.c +++ b/source4/libnet/libnet_samsync_ldb.c @@ -43,8 +43,13 @@ struct samsync_ldb_trusted_domain { }; struct samsync_ldb_state { + /* Values from the LSA lookup */ + const char *domain_name; + const struct dom_sid *domain_sid; + const char *realm; + struct dom_sid *dom_sid[3]; - struct ldb_context *sam_ldb; + struct ldb_context *sam_ldb, *remote_ldb; struct ldb_dn *base_dn[3]; struct samsync_ldb_secret *secrets; struct samsync_ldb_trusted_domain *trusted_domains; @@ -106,7 +111,6 @@ static NTSTATUS samsync_ldb_add_foreignSecurityPrincipal(TALLOC_CTX *mem_ctx, static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx, struct samsync_ldb_state *state, - struct creds_CredentialState *creds, enum netr_SamDatabaseID database, struct netr_DELTA_ENUM *delta, char **error_string) @@ -137,9 +141,13 @@ static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx, state->base_dn[database] = samdb_result_dn(state, msgs_domain[0], "nCName", NULL); - state->dom_sid[database] = samdb_search_dom_sid(state->sam_ldb, state, - state->base_dn[database], - "objectSid", NULL); + if (state->domain_sid) { + state->dom_sid[database] = dom_sid_dup(state, state->domain_sid); + } else { + state->dom_sid[database] = samdb_search_dom_sid(state->sam_ldb, state, + state->base_dn[database], + "objectSid", NULL); + } } else if (database == SAM_DATABASE_BUILTIN) { /* work out the builtin_dn - useful for so many calls its worth fetching here */ @@ -187,6 +195,10 @@ static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx, samdb_msg_add_uint64(state->sam_ldb, mem_ctx, msg, "creationTime", domain->domain_create_time); + /* Update the domain sid with the incoming domain */ + samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, + msg, "objectSid", state->dom_sid[database]); + /* TODO: Account lockout, password properties */ ret = samdb_replace(state->sam_ldb, mem_ctx, msg); @@ -199,7 +211,6 @@ static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx, static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx, struct samsync_ldb_state *state, - struct creds_CredentialState *creds, enum netr_SamDatabaseID database, struct netr_DELTA_ENUM *delta, char **error_string) @@ -209,13 +220,22 @@ static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx, const char *container, *obj_class; char *cn_name; int cn_name_len; - + const struct dom_sid *user_sid; struct ldb_message *msg; struct ldb_message **msgs; - int ret; + struct ldb_message **remote_msgs; + int ret, i; uint32_t acb; BOOL add = False; const char *attrs[] = { NULL }; + /* we may change this to a global search, then fill in only the things not in ldap later */ + const char *remote_attrs[] = { "userPrincipalName", "servicePrincipalName", + "msDS-KeyVersionNumber", NULL}; + + user_sid = dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid); + if (!user_sid) { + return NT_STATUS_NO_MEMORY; + } msg = ldb_msg_new(mem_ctx); if (msg == NULL) { @@ -225,29 +245,49 @@ static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx, /* search for the user, by rid */ ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs, "(&(objectClass=user)(objectSid=%s))", - ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); + ldap_encode_ndr_dom_sid(mem_ctx, user_sid)); if (ret == -1) { - *error_string = talloc_asprintf(mem_ctx, "gendb_search for user %s failed: %s", - dom_sid_string(mem_ctx, - dom_sid_add_rid(mem_ctx, - state->dom_sid[database], - rid)), + *error_string = talloc_asprintf(mem_ctx, "LDB for user %s failed: %s", + dom_sid_string(mem_ctx, user_sid), ldb_errstring(state->sam_ldb)); return NT_STATUS_INTERNAL_DB_CORRUPTION; } else if (ret == 0) { add = True; } else if (ret > 1) { - *error_string = talloc_asprintf(mem_ctx, "More than one user with SID: %s", - dom_sid_string(mem_ctx, - dom_sid_add_rid(mem_ctx, - state->dom_sid[database], - rid))); + *error_string = talloc_asprintf(mem_ctx, "More than one user with SID: %s in local LDB", + dom_sid_string(mem_ctx, user_sid)); return NT_STATUS_INTERNAL_DB_CORRUPTION; } else { - msg->dn = talloc_steal(msg, msgs[0]->dn); + msg->dn = msgs[0]->dn; + talloc_steal(msg, msgs[0]->dn); } + /* and do the same on the remote database */ + ret = gendb_search(state->remote_ldb, mem_ctx, state->base_dn[database], + &remote_msgs, remote_attrs, "(&(objectClass=user)(objectSid=%s))", + ldap_encode_ndr_dom_sid(mem_ctx, user_sid)); + + if (ret == -1) { + *error_string = talloc_asprintf(mem_ctx, "remote LDAP for user %s failed: %s", + dom_sid_string(mem_ctx, user_sid), + ldb_errstring(state->remote_ldb)); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } else if (ret == 0) { + *error_string = talloc_asprintf(mem_ctx, "User exists in samsync but not in remote LDAP domain! (base: %s, SID: %s)", + ldb_dn_linearize(mem_ctx, state->base_dn[database]), + dom_sid_string(mem_ctx, user_sid)); + return NT_STATUS_NO_SUCH_USER; + } else if (ret > 1) { + *error_string = talloc_asprintf(mem_ctx, "More than one user in remote LDAP domain with SID: %s", + dom_sid_string(mem_ctx, user_sid)); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + + /* Try to put things in the same location as the remote server */ + } else if (add) { + msg->dn = remote_msgs[0]->dn; + talloc_steal(msg, remote_msgs[0]->dn); + } cn_name = talloc_strdup(mem_ctx, user->account_name.string); NT_STATUS_HAVE_NO_MEMORY(cn_name); @@ -324,6 +364,16 @@ static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx, #undef ADD_OR_DEL + for (i=0; remote_attrs[i]; i++) { + struct ldb_message_element *el = ldb_msg_find_element(remote_msgs[0], remote_attrs[i]); + if (!el) { + samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, + remote_attrs[i]); + } else { + ldb_msg_add(msg, el, LDB_FLAG_MOD_REPLACE); + } + } + acb = user->acct_flags; if (acb & (ACB_WSTRUST)) { cn_name[cn_name_len - 1] = '\0'; @@ -352,10 +402,17 @@ static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx, ret = samdb_add(state->sam_ldb, mem_ctx, msg); if (ret != 0) { - *error_string = talloc_asprintf(mem_ctx, "Failed to create user record %s: %s", - ldb_dn_linearize(mem_ctx, msg->dn), - ldb_errstring(state->sam_ldb)); - return NT_STATUS_INTERNAL_DB_CORRUPTION; + struct ldb_dn *first_try_dn = msg->dn; + /* Try again with the default DN */ + msg->dn = talloc_steal(msg, msgs[0]->dn); + ret = samdb_add(state->sam_ldb, mem_ctx, msg); + if (ret != 0) { + *error_string = talloc_asprintf(mem_ctx, "Failed to create user record. Tried both %s and %s: %s", + ldb_dn_linearize(mem_ctx, first_try_dn), + ldb_dn_linearize(mem_ctx, msg->dn), + ldb_errstring(state->sam_ldb)); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } } } else { ret = samdb_replace(state->sam_ldb, mem_ctx, msg); @@ -372,7 +429,6 @@ static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx, static NTSTATUS samsync_ldb_delete_user(TALLOC_CTX *mem_ctx, struct samsync_ldb_state *state, - struct creds_CredentialState *creds, enum netr_SamDatabaseID database, struct netr_DELTA_ENUM *delta, char **error_string) @@ -414,7 +470,6 @@ static NTSTATUS samsync_ldb_delete_user(TALLOC_CTX *mem_ctx, static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx, struct samsync_ldb_state *state, - struct creds_CredentialState *creds, enum netr_SamDatabaseID database, struct netr_DELTA_ENUM *delta, char **error_string) @@ -513,7 +568,6 @@ static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx, static NTSTATUS samsync_ldb_delete_group(TALLOC_CTX *mem_ctx, struct samsync_ldb_state *state, - struct creds_CredentialState *creds, enum netr_SamDatabaseID database, struct netr_DELTA_ENUM *delta, char **error_string) @@ -555,7 +609,6 @@ static NTSTATUS samsync_ldb_delete_group(TALLOC_CTX *mem_ctx, static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx, struct samsync_ldb_state *state, - struct creds_CredentialState *creds, enum netr_SamDatabaseID database, struct netr_DELTA_ENUM *delta, char **error_string) @@ -629,7 +682,6 @@ static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx, static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx, struct samsync_ldb_state *state, - struct creds_CredentialState *creds, enum netr_SamDatabaseID database, struct netr_DELTA_ENUM *delta, char **error_string) @@ -730,7 +782,6 @@ static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx, static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx, struct samsync_ldb_state *state, - struct creds_CredentialState *creds, enum netr_SamDatabaseID database, struct netr_DELTA_ENUM *delta, char **error_string) @@ -767,7 +818,6 @@ static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx, static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx, struct samsync_ldb_state *state, - struct creds_CredentialState *creds, enum netr_SamDatabaseID database, struct netr_DELTA_ENUM *delta, char **error_string) @@ -850,7 +900,6 @@ static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx, static NTSTATUS samsync_ldb_handle_account(TALLOC_CTX *mem_ctx, struct samsync_ldb_state *state, - struct creds_CredentialState *creds, enum netr_SamDatabaseID database, struct netr_DELTA_ENUM *delta, char **error_string) @@ -914,7 +963,6 @@ static NTSTATUS samsync_ldb_handle_account(TALLOC_CTX *mem_ctx, static NTSTATUS samsync_ldb_delete_account(TALLOC_CTX *mem_ctx, struct samsync_ldb_state *state, - struct creds_CredentialState *creds, enum netr_SamDatabaseID database, struct netr_DELTA_ENUM *delta, char **error_string) @@ -964,13 +1012,12 @@ static NTSTATUS samsync_ldb_delete_account(TALLOC_CTX *mem_ctx, static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx, void *private, - struct creds_CredentialState *creds, enum netr_SamDatabaseID database, struct netr_DELTA_ENUM *delta, char **error_string) { NTSTATUS nt_status = NT_STATUS_OK; - struct samsync_ldb_state *state = private; + struct samsync_ldb_state *state = talloc_get_type(private, struct samsync_ldb_state); *error_string = NULL; switch (delta->delta_type) { @@ -978,7 +1025,6 @@ static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx, { nt_status = samsync_ldb_handle_domain(mem_ctx, state, - creds, database, delta, error_string); @@ -988,7 +1034,6 @@ static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx, { nt_status = samsync_ldb_handle_user(mem_ctx, state, - creds, database, delta, error_string); @@ -998,7 +1043,6 @@ static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx, { nt_status = samsync_ldb_delete_user(mem_ctx, state, - creds, database, delta, error_string); @@ -1008,7 +1052,6 @@ static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx, { nt_status = samsync_ldb_handle_group(mem_ctx, state, - creds, database, delta, error_string); @@ -1018,7 +1061,6 @@ static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx, { nt_status = samsync_ldb_delete_group(mem_ctx, state, - creds, database, delta, error_string); @@ -1028,7 +1070,6 @@ static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx, { nt_status = samsync_ldb_handle_group_member(mem_ctx, state, - creds, database, delta, error_string); @@ -1038,7 +1079,6 @@ static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx, { nt_status = samsync_ldb_handle_alias(mem_ctx, state, - creds, database, delta, error_string); @@ -1048,7 +1088,6 @@ static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx, { nt_status = samsync_ldb_delete_alias(mem_ctx, state, - creds, database, delta, error_string); @@ -1058,7 +1097,6 @@ static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx, { nt_status = samsync_ldb_handle_alias_member(mem_ctx, state, - creds, database, delta, error_string); @@ -1068,7 +1106,6 @@ static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx, { nt_status = samsync_ldb_handle_account(mem_ctx, state, - creds, database, delta, error_string); @@ -1078,7 +1115,6 @@ static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx, { nt_status = samsync_ldb_delete_account(mem_ctx, state, - creds, database, delta, error_string); @@ -1094,6 +1130,40 @@ static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx, return nt_status; } +static NTSTATUS libnet_samsync_ldb_init(TALLOC_CTX *mem_ctx, + void *private, + struct libnet_context *machine_net_ctx, + struct dcerpc_pipe *p, + const char *domain_name, + const struct dom_sid *domain_sid, + const char *realm, + char **error_string) +{ + struct samsync_ldb_state *state = talloc_get_type(private, struct samsync_ldb_state); + const char *server = dcerpc_server_name(p); + char *ldap_url; + + state->domain_name = domain_name; + state->domain_sid = domain_sid; + state->realm = realm; + + if (realm) { + if (!server || !*server) { + /* huh? how do we not have a server name? */ + *error_string = talloc_strdup(mem_ctx, "No DCE/RPC server name available. How did we connect?"); + return NT_STATUS_INVALID_PARAMETER; + } + ldap_url = talloc_asprintf(state, "ldap://%s", dcerpc_server_name(p)); + + state->remote_ldb = ldb_wrap_connect(mem_ctx, ldap_url, + NULL, machine_net_ctx->cred, + 0, NULL); + /* TODO: Make inquires to see if this is AD, then decide that + * the ldap connection is critical */ + } + return NT_STATUS_OK; +} + NTSTATUS libnet_samsync_ldb(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r) { NTSTATUS nt_status; @@ -1111,11 +1181,13 @@ NTSTATUS libnet_samsync_ldb(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, str r2.out.error_string = NULL; r2.in.binding_string = r->in.binding_string; + r2.in.init_fn = libnet_samsync_ldb_init; r2.in.delta_fn = libnet_samsync_ldb_fn; r2.in.fn_ctx = state; r2.in.machine_account = NULL; /* TODO: Create a machine account, fill this in, and the delete it */ nt_status = libnet_SamSync_netlogon(ctx, state, &r2); r->out.error_string = r2.out.error_string; + talloc_steal(mem_ctx, r->out.error_string); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(state); diff --git a/source4/libnet/libnet_vampire.c b/source4/libnet/libnet_vampire.c index da8c3b49d1..b9fb37fea6 100644 --- a/source4/libnet/libnet_vampire.c +++ b/source4/libnet/libnet_vampire.c @@ -152,7 +152,7 @@ NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx struct cli_credentials *machine_account; struct dcerpc_pipe *p; struct libnet_context *machine_net_ctx; - struct libnet_RpcConnect *c; + struct libnet_RpcConnectDCInfo *c; const enum netr_SamDatabaseID database_ids[] = {SAM_DATABASE_DOMAIN, SAM_DATABASE_BUILTIN, SAM_DATABASE_PRIVS}; int i; @@ -187,7 +187,7 @@ NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } - c = talloc(samsync_ctx, struct libnet_RpcConnect); + c = talloc(samsync_ctx, struct libnet_RpcConnectDCInfo); if (!c) { r->out.error_string = NULL; talloc_free(samsync_ctx); @@ -217,7 +217,7 @@ NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx machine_net_ctx->cred = machine_account; /* connect to the NETLOGON pipe of the PDC */ - nt_status = libnet_RpcConnect(machine_net_ctx, c, c); + nt_status = libnet_RpcConnectDCInfo(machine_net_ctx, c); if (!NT_STATUS_IS_OK(nt_status)) { if (r->in.binding_string) { r->out.error_string = talloc_asprintf(mem_ctx, @@ -258,6 +258,26 @@ NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx return nt_status; } + /* initialise the callback layer. It may wish to contact the + * server with ldap, now we know the name */ + + if (r->in.init_fn) { + char *error_string; + nt_status = r->in.init_fn(samsync_ctx, + r->in.fn_ctx, + machine_net_ctx, + p, + c->out.domain_name, + c->out.domain_sid, + c->out.realm, + &error_string); + if (!NT_STATUS_IS_OK(nt_status)) { + r->out.error_string = talloc_steal(mem_ctx, error_string); + talloc_free(samsync_ctx); + return nt_status; + } + } + /* get NETLOGON credentails */ nt_status = dcerpc_schannel_creds(p->conn->security_state.generic_state, samsync_ctx, &creds); @@ -285,13 +305,13 @@ NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx dbsync_nt_status = dcerpc_netr_DatabaseSync(p, loop_ctx, &dbsync); if (!NT_STATUS_IS_OK(dbsync_nt_status) && !NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES)) { - r->out.error_string = talloc_asprintf(samsync_ctx, "DatabaseSync failed - %s", nt_errstr(nt_status)); + r->out.error_string = talloc_asprintf(mem_ctx, "DatabaseSync failed - %s", nt_errstr(nt_status)); talloc_free(samsync_ctx); return nt_status; } if (!creds_client_check(creds, &dbsync.out.return_authenticator.cred)) { - r->out.error_string = talloc_strdup(samsync_ctx, "Credential chaining failed"); + r->out.error_string = talloc_strdup(mem_ctx, "Credential chaining on incoming DatabaseSync failed"); talloc_free(samsync_ctx); return NT_STATUS_ACCESS_DENIED; } @@ -310,7 +330,7 @@ NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx &dbsync.out.delta_enum_array->delta_enum[d], &error_string); if (!NT_STATUS_IS_OK(nt_status)) { - r->out.error_string = talloc_steal(samsync_ctx, error_string); + r->out.error_string = talloc_steal(mem_ctx, error_string); talloc_free(samsync_ctx); return nt_status; } @@ -320,12 +340,11 @@ NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx * write to an ldb */ nt_status = r->in.delta_fn(delta_ctx, r->in.fn_ctx, - creds, dbsync.in.database_id, &dbsync.out.delta_enum_array->delta_enum[d], &error_string); if (!NT_STATUS_IS_OK(nt_status)) { - r->out.error_string = talloc_steal(samsync_ctx, error_string); + r->out.error_string = talloc_steal(mem_ctx, error_string); talloc_free(samsync_ctx); return nt_status; } @@ -333,7 +352,13 @@ NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx } talloc_free(loop_ctx); } while (NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES)); - nt_status = dbsync_nt_status; + + if (!NT_STATUS_IS_OK(dbsync_nt_status)) { + r->out.error_string = talloc_asprintf(mem_ctx, "libnet_SamSync_netlogon failed: unexpected inconsistancy. Should not get error %s here", nt_errstr(nt_status)); + talloc_free(samsync_ctx); + return dbsync_nt_status; + } + nt_status = NT_STATUS_OK; } talloc_free(samsync_ctx); return nt_status; diff --git a/source4/libnet/libnet_vampire.h b/source4/libnet/libnet_vampire.h index 4bbdf2733a..03a085aa87 100644 --- a/source4/libnet/libnet_vampire.h +++ b/source4/libnet/libnet_vampire.h @@ -24,9 +24,16 @@ struct libnet_SamSync { struct { const char *binding_string; + NTSTATUS (*init_fn)(TALLOC_CTX *mem_ctx, + void *private, + struct libnet_context *machine_net_ctx, + struct dcerpc_pipe *p, + const char *domain_name, + const struct dom_sid *domain_sid, + const char *realm, + char **error_string); NTSTATUS (*delta_fn)(TALLOC_CTX *mem_ctx, void *private, - struct creds_CredentialState *creds, enum netr_SamDatabaseID database, struct netr_DELTA_ENUM *delta, char **error_string); |