summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2006-01-13 12:52:56 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:51:00 -0500
commitb15582ed816f3d477f978976f43b82cfa90bf6dc (patch)
tree01a6d0f6eaa039fe1262945c7dc2320f942e379a /source4
parent867ae22a9bf4cfe829e405fcbbb9de994505fc30 (diff)
downloadsamba-b15582ed816f3d477f978976f43b82cfa90bf6dc.tar.gz
samba-b15582ed816f3d477f978976f43b82cfa90bf6dc.tar.bz2
samba-b15582ed816f3d477f978976f43b82cfa90bf6dc.zip
r12903: Factor out a new routine libnet_RpcConnectDCInfo, to both connect to
the remote sever, and to query it for domain information. Provide and use this information in the SamSync/Vampire callbacks, to allow a parallel connection to LDAP, if we are talking to AD. This allows us to get at some important attributes not exposed in the old protocol. With this, we are able to do a all-GUI vampire of a AD domain from SWAT, including getting all the SIDs, servicePrincipalNames and the like correct. Andrew Bartlett (This used to be commit 918358cee0b4a1b2c9bc9e68d9d53428a634281e)
Diffstat (limited to 'source4')
-rw-r--r--source4/libnet/libnet_join.c250
-rw-r--r--source4/libnet/libnet_join.h1
-rw-r--r--source4/libnet/libnet_rpc.c191
-rw-r--r--source4/libnet/libnet_rpc.h19
-rw-r--r--source4/libnet/libnet_samdump.c9
-rw-r--r--source4/libnet/libnet_samdump_keytab.c5
-rw-r--r--source4/libnet/libnet_samsync_ldb.c164
-rw-r--r--source4/libnet/libnet_vampire.c43
-rw-r--r--source4/libnet/libnet_vampire.h9
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);