*/
#include "includes.h"
+#include "libsmb/namequery.h"
#include "../lib/util/tevent_ntstatus.h"
#include "librpc/gen_ndr/ndr_epmapper_c.h"
#include "../librpc/gen_ndr/ndr_dssetup.h"
#include "auth/gensec/gensec.h"
#include "auth/credentials/credentials.h"
#include "../libcli/smb/smbXcli_base.h"
+#include "../libcli/smb/tstream_smbXcli_np.h"
+#include "librpc/rpc/dcerpc_connection.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_RPC_CLI
state->pkt = talloc(state, struct ncacn_packet);
if (!state->pkt) {
+ /*
+ * TODO: do a real async disconnect ...
+ *
+ * For now do it sync...
+ */
+ TALLOC_FREE(state->cli->transport);
tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
status = dcerpc_pull_ncacn_packet(state->pkt,
&state->incoming_frag,
- state->pkt,
- !state->endianess);
+ state->pkt);
if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * TODO: do a real async disconnect ...
+ *
+ * For now do it sync...
+ */
+ TALLOC_FREE(state->cli->transport);
tevent_req_nterror(req, status);
return;
}
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(ncacn_packet, state->pkt);
+ }
+
status = cli_pipe_validate_current_pdu(state,
state->cli, state->pkt,
&state->incoming_frag,
(unsigned)state->reply_pdu_offset,
nt_errstr(status)));
+ if (state->pkt->ptype != DCERPC_PKT_FAULT && !NT_STATUS_IS_OK(status)) {
+ /*
+ * TODO: do a real async disconnect ...
+ *
+ * For now do it sync...
+ */
+ TALLOC_FREE(state->cli->transport);
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
+ /*
+ * TODO: do a real async disconnect ...
+ *
+ * For now do it sync...
+ */
+ TALLOC_FREE(state->cli->transport);
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ /*
+ * TODO: do a real async disconnect ...
+ *
+ * For now do it sync...
+ */
+ TALLOC_FREE(state->cli->transport);
+ }
if (!NT_STATUS_IS_OK(status)) {
tevent_req_nterror(req, status);
return;
"%s\n",
state->endianess?"little":"big",
state->pkt->drep[0]?"little":"big"));
- tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ /*
+ * TODO: do a real async disconnect ...
+ *
+ * For now do it sync...
+ */
+ TALLOC_FREE(state->cli->transport);
+ tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (state->reply_pdu_offset + rdata.length > MAX_RPC_DATA_SIZE) {
+ /*
+ * TODO: do a real async disconnect ...
+ *
+ * For now do it sync...
+ */
+ TALLOC_FREE(state->cli->transport);
+ tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
return;
}
if (state->reply_pdu.length < state->reply_pdu_offset + rdata.length) {
if (!data_blob_realloc(NULL, &state->reply_pdu,
state->reply_pdu_offset + rdata.length)) {
+ /*
+ * TODO: do a real async disconnect ...
+ *
+ * For now do it sync...
+ */
+ TALLOC_FREE(state->cli->transport);
tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
subreq = get_complete_frag_send(state, state->ev, state->cli,
&state->incoming_frag);
+ if (subreq == NULL) {
+ /*
+ * TODO: do a real async disconnect ...
+ *
+ * For now do it sync...
+ */
+ TALLOC_FREE(state->cli->transport);
+ }
if (tevent_req_nomem(subreq, req)) {
return;
}
return status;
}
- if (cli->auth->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
+ if (cli->auth->auth_level < DCERPC_AUTH_LEVEL_PACKET) {
*client_hdr_signing = false;
return status;
}
auth->auth_type,
auth->auth_level,
0, /* auth_pad_length */
- 1, /* auth_context_id */
+ auth->auth_context_id,
&auth_token,
&auth_info);
if (!NT_STATUS_IS_OK(ret)) {
uint8_t op_num;
uint32_t call_id;
const DATA_BLOB *req_data;
+ const struct GUID *object_uuid;
uint32_t req_data_sent;
DATA_BLOB req_trailer;
uint32_t req_trailer_sent;
struct tevent_context *ev,
struct rpc_pipe_client *cli,
uint8_t op_num,
+ const struct GUID *object_uuid,
const DATA_BLOB *req_data)
{
struct tevent_req *req, *subreq;
state->ev = ev;
state->cli = cli;
state->op_num = op_num;
+ state->object_uuid = object_uuid;
state->req_data = req_data;
state->req_data_sent = 0;
state->call_id = get_rpc_call_id();
return NT_STATUS_OK;
}
- if (a->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
+ if (a->auth_level < DCERPC_AUTH_LEVEL_PACKET) {
return NT_STATUS_OK;
}
u.request.context_id = 0;
u.request.opnum = state->op_num;
+ if (state->object_uuid) {
+ flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
+ u.request.object.object = *state->object_uuid;
+ frag_len += ndr_size_GUID(state->object_uuid, 0);
+ }
+
status = dcerpc_push_ncacn_packet(state,
DCERPC_PKT_REQUEST,
flags,
switch (state->cli->auth->auth_level) {
case DCERPC_AUTH_LEVEL_NONE:
case DCERPC_AUTH_LEVEL_CONNECT:
- case DCERPC_AUTH_LEVEL_PACKET:
break;
+ case DCERPC_AUTH_LEVEL_PACKET:
case DCERPC_AUTH_LEVEL_INTEGRITY:
case DCERPC_AUTH_LEVEL_PRIVACY:
status = dcerpc_add_auth_footer(state->cli->auth, pad_len,
static NTSTATUS create_rpc_bind_auth3(TALLOC_CTX *mem_ctx,
struct rpc_pipe_client *cli,
+ struct pipe_auth_data *auth,
uint32_t rpc_call_id,
- enum dcerpc_AuthType auth_type,
- enum dcerpc_AuthLevel auth_level,
DATA_BLOB *pauth_blob,
DATA_BLOB *rpc_out)
{
u.auth3._pad = 0;
status = dcerpc_push_dcerpc_auth(mem_ctx,
- auth_type,
- auth_level,
+ auth->auth_type,
+ auth->auth_level,
0, /* auth_pad_length */
- 1, /* auth_context_id */
+ auth->auth_context_id,
pauth_blob,
&u.auth3.auth_info);
if (!NT_STATUS_IS_OK(status)) {
********************************************************************/
static NTSTATUS create_rpc_alter_context(TALLOC_CTX *mem_ctx,
- enum dcerpc_AuthType auth_type,
- enum dcerpc_AuthLevel auth_level,
+ struct pipe_auth_data *auth,
uint32_t rpc_call_id,
const struct ndr_syntax_id *abstract,
const struct ndr_syntax_id *transfer,
NTSTATUS status;
status = dcerpc_push_dcerpc_auth(mem_ctx,
- auth_type,
- auth_level,
+ auth->auth_type,
+ auth->auth_level,
0, /* auth_pad_length */
- 1, /* auth_context_id */
+ auth->auth_context_id,
pauth_blob,
&auth_info);
if (!NT_STATUS_IS_OK(status)) {
return;
}
+ if (pkt->ptype == DCERPC_PKT_BIND_ACK) {
+ if (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) {
+ if (pauth->client_hdr_signing) {
+ pauth->hdr_signing = true;
+ }
+ }
+ }
+
state->cli->max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
- state->cli->max_recv_frag = pkt->u.bind_ack.max_recv_frag;
switch(pauth->auth_type) {
tevent_req_nterror(req, status);
return;
}
+
+ if (auth.auth_type != pauth->auth_type) {
+ DEBUG(0, (__location__ " Auth type %u mismatch expected %u.\n",
+ auth.auth_type, pauth->auth_type));
+ tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (auth.auth_level != pauth->auth_level) {
+ DEBUG(0, (__location__ " Auth level %u mismatch expected %u.\n",
+ auth.auth_level, pauth->auth_level));
+ tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (auth.auth_context_id != pauth->auth_context_id) {
+ DEBUG(0, (__location__ " Auth context id %u mismatch expected %u.\n",
+ (unsigned)auth.auth_context_id,
+ (unsigned)pauth->auth_context_id));
+ tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+ return;
+ }
+
break;
}
default:
gensec_security = pauth->auth_ctx;
- if (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) {
- if (pauth->client_hdr_signing) {
- pauth->hdr_signing = true;
- gensec_want_feature(gensec_security,
- GENSEC_FEATURE_SIGN_PKT_HEADER);
- }
- }
status = gensec_update(gensec_security, state,
auth.credentials, &auth_token);
status = rpc_bind_next_send(req, state,
&auth_token);
} else if (NT_STATUS_IS_OK(status)) {
+ if (pauth->hdr_signing) {
+ gensec_want_feature(gensec_security,
+ GENSEC_FEATURE_SIGN_PKT_HEADER);
+ }
+
if (auth_token.length == 0) {
/* Bind complete. */
tevent_req_done(req);
/* Now prepare the alter context pdu. */
data_blob_free(&state->rpc_out);
- status = create_rpc_alter_context(state,
- auth->auth_type,
- auth->auth_level,
+ status = create_rpc_alter_context(state, auth,
state->rpc_call_id,
&state->cli->abstract_syntax,
&state->cli->transfer_syntax,
/* Now prepare the auth3 context pdu. */
data_blob_free(&state->rpc_out);
- status = create_rpc_bind_auth3(state, state->cli,
+ status = create_rpc_bind_auth3(state, state->cli, auth,
state->rpc_call_id,
- auth->auth_type,
- auth->auth_level,
auth_token,
&state->rpc_out);
if (!NT_STATUS_IS_OK(status)) {
{
TALLOC_CTX *frame = talloc_stackframe();
struct tevent_context *ev;
- struct tevent_req *req;
NTSTATUS status = NT_STATUS_OK;
+ struct dcerpc_call *call;
+ struct tevent_req *subreq;
+ struct dcerpc_presentation *pres[1];
ev = samba_tevent_context_init(frame);
if (ev == NULL) {
goto fail;
}
- req = rpc_pipe_bind_send(frame, ev, cli, auth);
- if (req == NULL) {
+ cli->sec = dcerpc_security_allocate(cli, cli->conn,
+ auth->auth_type,
+ auth->auth_level,
+ auth->auth_ctx);
+
+ call = dcerpc_call_allocate(frame, cli->assoc, NULL, NULL);
+
+ pres[0] = cli->pres;
+
+ subreq = dcerpc_do_bind_send(frame, ev, cli->conn, call,
+ cli->sec, ARRAY_SIZE(pres), pres);
+
+ if (subreq == NULL) {
status = NT_STATUS_NO_MEMORY;
goto fail;
}
- if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
goto fail;
}
- status = rpc_pipe_bind_recv(req);
+ status = dcerpc_do_bind_recv(subreq);
fail:
TALLOC_FREE(frame);
return status;
}
struct rpccli_bh_raw_call_state {
+ struct dcerpc_call *call;
DATA_BLOB in_data;
DATA_BLOB out_data;
uint32_t out_flags;
struct rpccli_bh_raw_call_state *state;
bool ok;
struct tevent_req *subreq;
+ bool bigendian = false;
req = tevent_req_create(mem_ctx, &state,
struct rpccli_bh_raw_call_state);
return tevent_req_post(req, ev);
}
- subreq = rpc_api_pipe_req_send(state, ev, hs->rpc_cli,
- opnum, &state->in_data);
+ state->call = dcerpc_call_allocate(state,
+ hs->rpc_cli->assoc,
+ hs->rpc_cli->sec,
+ hs->rpc_cli->pres);
+
+ if (in_flags & LIBNDR_FLAG_BIGENDIAN) {
+ bigendian = true;
+ }
+
+ subreq = dcerpc_do_request_send(state, ev, hs->rpc_cli->conn,
+ state->call, object, opnum,
+ &state->in_data, bigendian);
+// subreq = rpc_api_pipe_req_send(state, ev, hs->rpc_cli,
+// opnum, &state->in_data);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
tevent_req_data(req,
struct rpccli_bh_raw_call_state);
NTSTATUS status;
+ bool bigendian = false;
state->out_flags = 0;
/* TODO: support bigendian responses */
- status = rpc_api_pipe_req_recv(subreq, state, &state->out_data);
+ status = dcerpc_do_request_recv(subreq, state, &state->out_data,
+ &bigendian);
+ //status = rpc_api_pipe_req_recv(subreq, state, &state->out_data);
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
tevent_req_nterror(req, status);
return;
}
+ if (bigendian) {
+ state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
+ }
+
tevent_req_done(req);
}
/*
* TODO: do a real async disconnect ...
*
- * For now the caller needs to free rpc_cli
+ * For now we do it sync...
*/
+ TALLOC_FREE(hs->rpc_cli->transport);
hs->rpc_cli = NULL;
tevent_req_done(req);
result->auth_type = DCERPC_AUTH_TYPE_NONE;
result->auth_level = DCERPC_AUTH_LEVEL_NONE;
+ result->auth_context_id = 0;
status = auth_generic_client_prepare(result,
&auth_generic_ctx);
result->auth_type = auth_type;
result->auth_level = auth_level;
+ result->auth_context_id = 1;
status = auth_generic_client_prepare(result,
&auth_generic_ctx);
result->auth_type = auth_type;
result->auth_level = auth_level;
+ result->auth_context_id = 1;
status = auth_generic_client_prepare(result,
&auth_generic_ctx);
"host", /* target_service */
NAME_NT_AUTHORITY, /* domain */
"SYSTEM",
- "", /* password */
+ NULL, /* password */
CRED_DONT_USE_KERBEROS,
NULL, /* netlogon_creds_CredentialState */
presult);
}
result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
- result->max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
if (ss_addr == NULL) {
if (!resolve_name(host, &addr, NBT_NAME_SERVER, false)) {
result->transport->transport = NCACN_IP_TCP;
+ result->assoc = dcerpc_association_create(result, 0);
+ result->conn = dcerpc_connection_create(result, result->assoc,
+ &result->transport->stream);
+ result->pres = dcerpc_presentation_allocate(result, result->conn, table,
+ &ndr_transfer_syntax_ndr);
+ result->sec = dcerpc_security_allocate(result, result->conn,
+ DCERPC_AUTH_TYPE_NONE,
+ DCERPC_AUTH_LEVEL_NONE,
+ NULL);
+
result->binding_handle = rpccli_bh_create(result, NULL, table);
if (result->binding_handle == NULL) {
TALLOC_FREE(result);
}
result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
- result->max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == -1) {
result->transport->transport = NCALRPC;
+ result->assoc = dcerpc_association_create(result, 0);
+ result->conn = dcerpc_connection_create(result, result->assoc,
+ &result->transport->stream);
+ result->pres = dcerpc_presentation_allocate(result, result->conn, table,
+ &ndr_transfer_syntax_ndr);
+ result->sec = dcerpc_security_allocate(result, result->conn,
+ DCERPC_AUTH_TYPE_NONE,
+ DCERPC_AUTH_LEVEL_NONE,
+ NULL);
+
result->binding_handle = rpccli_bh_create(result, NULL, table);
if (result->binding_handle == NULL) {
TALLOC_FREE(result);
result, "\\\\%s", result->desthost);
result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
- result->max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
TALLOC_FREE(result);
result->transport->transport = NCACN_NP;
+ result->assoc = dcerpc_association_create(result, 0);
+ result->conn = dcerpc_connection_create(result, result->assoc,
+ &result->transport->stream);
+ dcerpc_connection_set_use_trans_fn(result->conn,
+ tstream_smbXcli_np_use_trans);
+ result->pres = dcerpc_presentation_allocate(result, result->conn, table,
+ &ndr_transfer_syntax_ndr);
+ result->sec = dcerpc_security_allocate(result, result->conn,
+ DCERPC_AUTH_TYPE_NONE,
+ DCERPC_AUTH_LEVEL_NONE,
+ NULL);
+
np_ref = talloc(result->transport, struct rpc_pipe_client_np_ref);
if (np_ref == NULL) {
TALLOC_FREE(result);
return status;
}
-NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
- const struct ndr_interface_table *table,
- enum dcerpc_transport_t transport,
- struct cli_credentials *cli_creds,
- struct netlogon_creds_cli_context *netlogon_creds,
- struct rpc_pipe_client **_rpccli)
+NTSTATUS cli_rpc_pipe_open_bind_schannel(
+ struct cli_state *cli,
+ const struct ndr_interface_table *table,
+ enum dcerpc_transport_t transport,
+ struct netlogon_creds_cli_context *netlogon_creds,
+ struct rpc_pipe_client **_rpccli)
{
struct rpc_pipe_client *rpccli;
struct pipe_auth_data *rpcauth;
const char *target_service = table->authservices->names[0];
- struct netlogon_creds_CredentialState *ncreds = NULL;
+ struct cli_credentials *cli_creds;
enum dcerpc_AuthLevel auth_level;
NTSTATUS status;
- int rpc_pipe_bind_dbglvl = 0;
status = cli_rpc_pipe_open(cli, transport, table, &rpccli);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- status = netlogon_creds_cli_lock(netlogon_creds, rpccli, &ncreds);
+ auth_level = netlogon_creds_cli_auth_level(netlogon_creds);
+
+ status = netlogon_creds_bind_cli_credentials(
+ netlogon_creds, rpccli, &cli_creds);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("netlogon_creds_cli_get returned %s\n",
- nt_errstr(status)));
+ DBG_DEBUG("netlogon_creds_bind_cli_credentials failed: %s\n",
+ nt_errstr(status));
TALLOC_FREE(rpccli);
return status;
}
- auth_level = netlogon_creds_cli_auth_level(netlogon_creds);
-
- cli_credentials_set_netlogon_creds(cli_creds, ncreds);
-
status = rpccli_generic_bind_data_from_creds(rpccli,
DCERPC_AUTH_TYPE_SCHANNEL,
auth_level,
}
status = rpc_pipe_bind(rpccli, rpcauth);
- cli_credentials_set_netlogon_creds(cli_creds, NULL);
- if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
- rpc_pipe_bind_dbglvl = 1;
- netlogon_creds_cli_delete(netlogon_creds, &ncreds);
- }
+
+ /* No TALLOC_FREE, gensec takes references */
+ talloc_unlink(rpccli, cli_creds);
+ cli_creds = NULL;
+
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(rpc_pipe_bind_dbglvl,
- ("%s: rpc_pipe_bind failed with error %s\n",
- __func__, nt_errstr(status)));
+ DBG_DEBUG("rpc_pipe_bind failed with error %s\n",
+ nt_errstr(status));
TALLOC_FREE(rpccli);
return status;
}
- TALLOC_FREE(ncreds);
+ *_rpccli = rpccli;
- if (!ndr_syntax_id_equal(&table->syntax_id, &ndr_table_netlogon.syntax_id)) {
- goto done;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
+ const struct ndr_interface_table *table,
+ enum dcerpc_transport_t transport,
+ struct netlogon_creds_cli_context *netlogon_creds,
+ struct rpc_pipe_client **_rpccli)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct rpc_pipe_client *rpccli;
+ struct netlogon_creds_cli_lck *lck;
+ NTSTATUS status;
+
+ status = netlogon_creds_cli_lck(
+ netlogon_creds, NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
+ frame, &lck);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("netlogon_creds_cli_lck returned %s\n",
+ nt_errstr(status));
+ TALLOC_FREE(frame);
+ return status;
}
- status = netlogon_creds_cli_check(netlogon_creds,
- rpccli->binding_handle);
+ status = cli_rpc_pipe_open_bind_schannel(
+ cli, table, transport, netlogon_creds, &rpccli);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
+ netlogon_creds_cli_delete_lck(netlogon_creds);
+ }
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("netlogon_creds_cli_check failed with %s\n",
- nt_errstr(status)));
- TALLOC_FREE(rpccli);
+ DBG_DEBUG("cli_rpc_pipe_open_bind_schannel failed: %s\n",
+ nt_errstr(status));
+ TALLOC_FREE(frame);
return status;
}
+ if (ndr_syntax_id_equal(&table->syntax_id,
+ &ndr_table_netlogon.syntax_id)) {
+ status = netlogon_creds_cli_check(netlogon_creds,
+ rpccli->binding_handle,
+ NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("netlogon_creds_cli_check failed with %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(frame);
+ return status;
+ }
+ }
+
+ DBG_DEBUG("opened pipe %s to machine %s with key %s "
+ "and bound using schannel.\n",
+ table->name, rpccli->desthost,
+ netlogon_creds_cli_debug_string(netlogon_creds, lck));
-done:
- DEBUG(10,("%s: opened pipe %s to machine %s "
- "for domain %s and bound using schannel.\n",
- __func__, table->name,
- rpccli->desthost, cli_credentials_get_domain(cli_creds)));
+ TALLOC_FREE(frame);
*_rpccli = rpccli;
return NT_STATUS_OK;