diff options
Diffstat (limited to 'source4/libnet/libnet_rpc.c')
-rw-r--r-- | source4/libnet/libnet_rpc.c | 191 |
1 files changed, 189 insertions, 2 deletions
diff --git a/source4/libnet/libnet_rpc.c b/source4/libnet/libnet_rpc.c index 1f98e575d1b..aba393d7fb9 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; +} + |