*/
#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 "../libcli/auth/schannel.h"
+#include "../libcli/auth/netlogon_creds_cli.h"
#include "auth_generic.h"
#include "librpc/gen_ndr/ndr_dcerpc.h"
#include "librpc/gen_ndr/ndr_netlogon_c.h"
Rpc pipe call id.
********************************************************************/
-static uint32 get_rpc_call_id(void)
+static uint32_t get_rpc_call_id(void)
{
- static uint32 call_id = 0;
+ static uint32_t call_id = 0;
return ++call_id;
}
struct ncacn_packet *pkt,
DATA_BLOB *pdu,
uint8_t expected_pkt_type,
+ uint32_t call_id,
DATA_BLOB *rdata,
DATA_BLOB *reply_pdu)
{
- struct dcerpc_response *r;
- NTSTATUS ret = NT_STATUS_OK;
- size_t pad_len = 0;
+ const struct dcerpc_response *r = NULL;
+ DATA_BLOB tmp_stub = data_blob_null;
+ NTSTATUS ret;
/*
* Point the return values at the real data including the RPC
*/
*rdata = *pdu;
+ if ((pkt->ptype == DCERPC_PKT_BIND_ACK) &&
+ !(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
+ /*
+ * TODO: do we still need this hack which was introduced
+ * in commit a42afcdcc7ab9aa9ed193ae36d3dbb10843447f0.
+ *
+ * I don't even know what AS/U might be...
+ */
+ DEBUG(5, (__location__ ": bug in server (AS/U?), setting "
+ "fragment first/last ON.\n"));
+ pkt->pfc_flags |= DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
+ }
+
/* Ensure we have the correct type. */
switch (pkt->ptype) {
- case DCERPC_PKT_ALTER_RESP:
+ case DCERPC_PKT_BIND_NAK:
+ DEBUG(1, (__location__ ": Bind NACK received from %s!\n",
+ rpccli_pipe_txt(talloc_tos(), cli)));
+
+ ret = dcerpc_verify_ncacn_packet_header(pkt,
+ DCERPC_PKT_BIND_NAK,
+ 0, /* max_auth_info */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST,
+ 0); /* optional flags */
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(1, (__location__ ": Connection to %s got an unexpected "
+ "RPC packet type - %u, expected %u: %s\n",
+ rpccli_pipe_txt(talloc_tos(), cli),
+ pkt->ptype, expected_pkt_type,
+ nt_errstr(ret)));
+ NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ return ret;
+ }
+
+ /* Use this for now... */
+ return NT_STATUS_NETWORK_ACCESS_DENIED;
+
case DCERPC_PKT_BIND_ACK:
+ ret = dcerpc_verify_ncacn_packet_header(pkt,
+ expected_pkt_type,
+ pkt->u.bind_ack.auth_info.length,
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST,
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(1, (__location__ ": Connection to %s got an unexpected "
+ "RPC packet type - %u, expected %u: %s\n",
+ rpccli_pipe_txt(talloc_tos(), cli),
+ pkt->ptype, expected_pkt_type,
+ nt_errstr(ret)));
+ NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ return ret;
+ }
- /* Client code never receives this kind of packets */
break;
+ case DCERPC_PKT_ALTER_RESP:
+ ret = dcerpc_verify_ncacn_packet_header(pkt,
+ expected_pkt_type,
+ pkt->u.alter_resp.auth_info.length,
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST,
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(1, (__location__ ": Connection to %s got an unexpected "
+ "RPC packet type - %u, expected %u: %s\n",
+ rpccli_pipe_txt(talloc_tos(), cli),
+ pkt->ptype, expected_pkt_type,
+ nt_errstr(ret)));
+ NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ return ret;
+ }
+
+ break;
case DCERPC_PKT_RESPONSE:
r = &pkt->u.response;
+ ret = dcerpc_verify_ncacn_packet_header(pkt,
+ expected_pkt_type,
+ r->stub_and_verifier.length,
+ 0, /* required_flags */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(1, (__location__ ": Connection to %s got an unexpected "
+ "RPC packet type - %u, expected %u: %s\n",
+ rpccli_pipe_txt(talloc_tos(), cli),
+ pkt->ptype, expected_pkt_type,
+ nt_errstr(ret)));
+ NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ return ret;
+ }
+
+ tmp_stub.data = r->stub_and_verifier.data;
+ tmp_stub.length = r->stub_and_verifier.length;
+
/* Here's where we deal with incoming sign/seal. */
ret = dcerpc_check_auth(cli->auth, pkt,
- &r->stub_and_verifier,
+ &tmp_stub,
DCERPC_RESPONSE_LENGTH,
- pdu, &pad_len);
+ pdu);
if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(1, (__location__ ": Connection to %s got an unexpected "
+ "RPC packet type - %u, expected %u: %s\n",
+ rpccli_pipe_txt(talloc_tos(), cli),
+ pkt->ptype, expected_pkt_type,
+ nt_errstr(ret)));
+ NDR_PRINT_DEBUG(ncacn_packet, pkt);
return ret;
}
- if (pkt->frag_length < DCERPC_RESPONSE_LENGTH + pad_len) {
- return NT_STATUS_BUFFER_TOO_SMALL;
- }
-
/* Point the return values at the NDR data. */
- rdata->data = r->stub_and_verifier.data;
-
- if (pkt->auth_length) {
- /* We've already done integer wrap tests in
- * dcerpc_check_auth(). */
- rdata->length = r->stub_and_verifier.length
- - pad_len
- - DCERPC_AUTH_TRAILER_LENGTH
- - pkt->auth_length;
- } else {
- rdata->length = r->stub_and_verifier.length;
- }
+ *rdata = tmp_stub;
- DEBUG(10, ("Got pdu len %lu, data_len %lu, ss_len %u\n",
+ DEBUG(10, ("Got pdu len %lu, data_len %lu\n",
(long unsigned int)pdu->length,
- (long unsigned int)rdata->length,
- (unsigned int)pad_len));
+ (long unsigned int)rdata->length));
/*
* If this is the first reply, and the allocation hint is
break;
- case DCERPC_PKT_BIND_NAK:
- DEBUG(1, (__location__ ": Bind NACK received from %s!\n",
- rpccli_pipe_txt(talloc_tos(), cli)));
- /* Use this for now... */
- return NT_STATUS_NETWORK_ACCESS_DENIED;
-
case DCERPC_PKT_FAULT:
+ ret = dcerpc_verify_ncacn_packet_header(pkt,
+ DCERPC_PKT_FAULT,
+ 0, /* max_auth_info */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST,
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(1, (__location__ ": Connection to %s got an unexpected "
+ "RPC packet type - %u, expected %u: %s\n",
+ rpccli_pipe_txt(talloc_tos(), cli),
+ pkt->ptype, expected_pkt_type,
+ nt_errstr(ret)));
+ NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ return ret;
+ }
+
DEBUG(1, (__location__ ": RPC fault code %s received "
"from %s!\n",
dcerpc_errstr(talloc_tos(),
"from %s!\n",
(unsigned int)pkt->ptype,
rpccli_pipe_txt(talloc_tos(), cli)));
- return NT_STATUS_INVALID_INFO_CLASS;
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
}
- if (pkt->ptype != expected_pkt_type) {
+
+ if (pkt->call_id != call_id) {
DEBUG(3, (__location__ ": Connection to %s got an unexpected "
- "RPC packet type - %u, not %u\n",
+ "RPC call_id - %u, not %u\n",
rpccli_pipe_txt(talloc_tos(), cli),
- pkt->ptype, expected_pkt_type));
- return NT_STATUS_INVALID_INFO_CLASS;
- }
-
- /* Do this just before return - we don't want to modify any rpc header
- data before now as we may have needed to do cryptographic actions on
- it before. */
-
- if ((pkt->ptype == DCERPC_PKT_BIND_ACK) &&
- !(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
- DEBUG(5, (__location__ ": bug in server (AS/U?), setting "
- "fragment first/last ON.\n"));
- pkt->pfc_flags |= DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
+ pkt->call_id, call_id));
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
}
return NT_STATUS_OK;
struct tevent_context *ev;
struct rpc_pipe_client *cli;
uint8_t expected_pkt_type;
+ uint32_t call_id;
DATA_BLOB incoming_frag;
struct ncacn_packet *pkt;
struct tevent_context *ev,
struct rpc_pipe_client *cli,
DATA_BLOB *data, /* Outgoing PDU */
- uint8_t expected_pkt_type)
+ uint8_t expected_pkt_type,
+ uint32_t call_id)
{
struct tevent_req *req, *subreq;
struct rpc_api_pipe_state *state;
state->ev = ev;
state->cli = cli;
state->expected_pkt_type = expected_pkt_type;
+ state->call_id = call_id;
state->endianess = DCERPC_DREP_LE;
/*
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 (state->incoming_frag.length != state->pkt->frag_length) {
- DEBUG(5, ("Incorrect pdu length %u, expected %u\n",
- (unsigned int)state->incoming_frag.length,
- (unsigned int)state->pkt->frag_length));
- tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
- 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,
state->expected_pkt_type,
+ state->call_id,
&rdata,
&state->reply_pdu);
(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;
}
static NTSTATUS create_generic_auth_rpc_bind_req(struct rpc_pipe_client *cli,
TALLOC_CTX *mem_ctx,
- DATA_BLOB *auth_token)
+ DATA_BLOB *auth_token,
+ bool *client_hdr_signing)
{
struct gensec_security *gensec_security;
DATA_BLOB null_blob = data_blob_null;
+ NTSTATUS status;
- gensec_security = talloc_get_type_abort(cli->auth->auth_ctx,
- struct gensec_security);
+ gensec_security = cli->auth->auth_ctx;
DEBUG(5, ("create_generic_auth_rpc_bind_req: generate first token\n"));
- return gensec_update(gensec_security, mem_ctx, NULL, null_blob, auth_token);
+ status = gensec_update(gensec_security, mem_ctx, null_blob, auth_token);
+
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED))
+ {
+ return status;
+ }
+
+ if (client_hdr_signing == NULL) {
+ return status;
+ }
+
+ if (cli->auth->auth_level < DCERPC_AUTH_LEVEL_PACKET) {
+ *client_hdr_signing = false;
+ return status;
+ }
+
+ *client_hdr_signing = gensec_have_feature(gensec_security,
+ GENSEC_FEATURE_SIGN_PKT_HEADER);
+
+ return status;
}
/*******************************************************************
static NTSTATUS create_bind_or_alt_ctx_internal(TALLOC_CTX *mem_ctx,
enum dcerpc_pkt_type ptype,
- uint32 rpc_call_id,
+ uint32_t rpc_call_id,
const struct ndr_syntax_id *abstract,
const struct ndr_syntax_id *transfer,
const DATA_BLOB *auth_info,
+ bool client_hdr_signing,
DATA_BLOB *blob)
{
- uint16 auth_len = auth_info->length;
+ uint16_t auth_len = auth_info->length;
NTSTATUS status;
union dcerpc_payload u;
struct dcerpc_ctx_list ctx_list;
+ uint8_t pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
if (auth_len) {
auth_len -= DCERPC_AUTH_TRAILER_LENGTH;
}
+ if (client_hdr_signing) {
+ pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
+ }
+
ctx_list.context_id = 0;
ctx_list.num_transfer_syntaxes = 1;
ctx_list.abstract_syntax = *abstract;
u.bind.auth_info = *auth_info;
status = dcerpc_push_ncacn_packet(mem_ctx,
- ptype,
- DCERPC_PFC_FLAG_FIRST |
- DCERPC_PFC_FLAG_LAST,
+ ptype, pfc_flags,
auth_len,
rpc_call_id,
&u,
static NTSTATUS create_rpc_bind_req(TALLOC_CTX *mem_ctx,
struct rpc_pipe_client *cli,
struct pipe_auth_data *auth,
- uint32 rpc_call_id,
+ uint32_t rpc_call_id,
const struct ndr_syntax_id *abstract,
const struct ndr_syntax_id *transfer,
DATA_BLOB *rpc_out)
{
DATA_BLOB auth_token = data_blob_null;
DATA_BLOB auth_info = data_blob_null;
- NTSTATUS ret = NT_STATUS_OK;
+ NTSTATUS ret;
switch (auth->auth_type) {
- case DCERPC_AUTH_TYPE_SCHANNEL:
- case DCERPC_AUTH_TYPE_NTLMSSP:
- case DCERPC_AUTH_TYPE_KRB5:
- case DCERPC_AUTH_TYPE_SPNEGO:
- ret = create_generic_auth_rpc_bind_req(cli, mem_ctx, &auth_token);
+ case DCERPC_AUTH_TYPE_NONE:
+ break;
+
+ default:
+ ret = create_generic_auth_rpc_bind_req(cli, mem_ctx,
+ &auth_token,
+ &auth->client_hdr_signing);
if (!NT_STATUS_IS_OK(ret) &&
!NT_STATUS_EQUAL(ret, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
return ret;
}
break;
-
- case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
- auth_token = data_blob_talloc(mem_ctx,
- "NCALRPC_AUTH_TOKEN",
- 18);
- break;
-
- case DCERPC_AUTH_TYPE_NONE:
- break;
-
- default:
- /* "Can't" happen. */
- return NT_STATUS_INVALID_INFO_CLASS;
}
if (auth_token.length != 0) {
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)) {
abstract,
transfer,
&auth_info,
+ auth->client_hdr_signing,
rpc_out);
return ret;
}
struct rpc_pipe_client *cli;
uint8_t op_num;
uint32_t call_id;
- DATA_BLOB *req_data;
+ const DATA_BLOB *req_data;
+ const struct GUID *object_uuid;
uint32_t req_data_sent;
+ DATA_BLOB req_trailer;
+ uint32_t req_trailer_sent;
+ bool verify_bitmask1;
+ bool verify_pcontext;
DATA_BLOB rpc_out;
DATA_BLOB reply_pdu;
};
static void rpc_api_pipe_req_write_done(struct tevent_req *subreq);
static void rpc_api_pipe_req_done(struct tevent_req *subreq);
+static NTSTATUS prepare_verification_trailer(struct rpc_api_pipe_req_state *state);
static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state,
bool *is_last_frag);
-struct tevent_req *rpc_api_pipe_req_send(TALLOC_CTX *mem_ctx,
+static struct tevent_req *rpc_api_pipe_req_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct rpc_pipe_client *cli,
uint8_t op_num,
- DATA_BLOB *req_data)
+ const struct GUID *object_uuid,
+ const DATA_BLOB *req_data)
{
struct tevent_req *req, *subreq;
struct rpc_api_pipe_req_state *state;
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();
goto post_status;
}
+ status = prepare_verification_trailer(state);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto post_status;
+ }
+
status = prepare_next_frag(state, &is_last_frag);
if (!NT_STATUS_IS_OK(status)) {
goto post_status;
if (is_last_frag) {
subreq = rpc_api_pipe_send(state, ev, state->cli,
&state->rpc_out,
- DCERPC_PKT_RESPONSE);
+ DCERPC_PKT_RESPONSE,
+ state->call_id);
if (subreq == NULL) {
goto fail;
}
return NULL;
}
+static NTSTATUS prepare_verification_trailer(struct rpc_api_pipe_req_state *state)
+{
+ struct pipe_auth_data *a = state->cli->auth;
+ struct dcerpc_sec_verification_trailer *t;
+ struct dcerpc_sec_vt *c = NULL;
+ struct ndr_push *ndr = NULL;
+ enum ndr_err_code ndr_err;
+ size_t align = 0;
+ size_t pad = 0;
+
+ if (a == NULL) {
+ return NT_STATUS_OK;
+ }
+
+ if (a->auth_level < DCERPC_AUTH_LEVEL_PACKET) {
+ return NT_STATUS_OK;
+ }
+
+ t = talloc_zero(state, struct dcerpc_sec_verification_trailer);
+ if (t == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!a->verified_bitmask1) {
+ t->commands = talloc_realloc(t, t->commands,
+ struct dcerpc_sec_vt,
+ t->count.count + 1);
+ if (t->commands == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ c = &t->commands[t->count.count++];
+ ZERO_STRUCTP(c);
+
+ c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
+ if (a->client_hdr_signing) {
+ c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
+ }
+ state->verify_bitmask1 = true;
+ }
+
+ if (!state->cli->verified_pcontext) {
+ t->commands = talloc_realloc(t, t->commands,
+ struct dcerpc_sec_vt,
+ t->count.count + 1);
+ if (t->commands == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ c = &t->commands[t->count.count++];
+ ZERO_STRUCTP(c);
+
+ c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
+ c->u.pcontext.abstract_syntax = state->cli->abstract_syntax;
+ c->u.pcontext.transfer_syntax = state->cli->transfer_syntax;
+
+ state->verify_pcontext = true;
+ }
+
+ if (!a->hdr_signing) {
+ t->commands = talloc_realloc(t, t->commands,
+ struct dcerpc_sec_vt,
+ t->count.count + 1);
+ if (t->commands == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ c = &t->commands[t->count.count++];
+ ZERO_STRUCTP(c);
+
+ c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
+ c->u.header2.ptype = DCERPC_PKT_REQUEST;
+ c->u.header2.drep[0] = DCERPC_DREP_LE;
+ c->u.header2.drep[1] = 0;
+ c->u.header2.drep[2] = 0;
+ c->u.header2.drep[3] = 0;
+ c->u.header2.call_id = state->call_id;
+ c->u.header2.context_id = 0;
+ c->u.header2.opnum = state->op_num;
+ }
+
+ if (t->count.count == 0) {
+ TALLOC_FREE(t);
+ return NT_STATUS_OK;
+ }
+
+ c = &t->commands[t->count.count - 1];
+ c->command |= DCERPC_SEC_VT_COMMAND_END;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
+ }
+
+ ndr = ndr_push_init_ctx(state);
+ if (ndr == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
+ NDR_SCALARS | NDR_BUFFERS,
+ t);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ state->req_trailer = ndr_push_blob(ndr);
+
+ align = state->req_data->length & 0x3;
+ if (align > 0) {
+ pad = 4 - align;
+ }
+ if (pad > 0) {
+ bool ok;
+ uint8_t *p;
+ const uint8_t zeros[4] = { 0, };
+
+ ok = data_blob_append(ndr, &state->req_trailer, zeros, pad);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* move the padding to the start */
+ p = state->req_trailer.data;
+ memmove(p + pad, p, state->req_trailer.length - pad);
+ memset(p, 0, pad);
+ }
+
+ return NT_STATUS_OK;
+}
+
static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state,
bool *is_last_frag)
{
- size_t data_sent_thistime;
size_t auth_len;
size_t frag_len;
uint8_t flags = 0;
size_t pad_len;
size_t data_left;
+ size_t data_thistime;
+ size_t trailer_left;
+ size_t trailer_thistime = 0;
+ size_t total_left;
+ size_t total_thistime;
NTSTATUS status;
+ bool ok;
union dcerpc_payload u;
data_left = state->req_data->length - state->req_data_sent;
+ trailer_left = state->req_trailer.length - state->req_trailer_sent;
+ total_left = data_left + trailer_left;
+ if ((total_left < data_left) || (total_left < trailer_left)) {
+ /*
+ * overflow
+ */
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
status = dcerpc_guess_sizes(state->cli->auth,
- DCERPC_REQUEST_LENGTH, data_left,
+ DCERPC_REQUEST_LENGTH, total_left,
state->cli->max_xmit_frag,
- CLIENT_NDR_PADDING_SIZE,
- &data_sent_thistime,
+ &total_thistime,
&frag_len, &auth_len, &pad_len);
if (!NT_STATUS_IS_OK(status)) {
return status;
flags = DCERPC_PFC_FLAG_FIRST;
}
- if (data_sent_thistime == data_left) {
+ if (total_thistime == total_left) {
flags |= DCERPC_PFC_FLAG_LAST;
}
+ data_thistime = MIN(total_thistime, data_left);
+ if (data_thistime < total_thistime) {
+ trailer_thistime = total_thistime - data_thistime;
+ }
+
data_blob_free(&state->rpc_out);
ZERO_STRUCT(u.request);
- u.request.alloc_hint = state->req_data->length;
+ u.request.alloc_hint = total_left;
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,
* at this stage */
dcerpc_set_frag_length(&state->rpc_out, frag_len);
- /* Copy in the data. */
- if (!data_blob_append(NULL, &state->rpc_out,
+ if (data_thistime > 0) {
+ /* Copy in the data. */
+ ok = data_blob_append(NULL, &state->rpc_out,
state->req_data->data + state->req_data_sent,
- data_sent_thistime)) {
- return NT_STATUS_NO_MEMORY;
+ data_thistime);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ state->req_data_sent += data_thistime;
+ }
+
+ if (trailer_thistime > 0) {
+ /* Copy in the verification trailer. */
+ ok = data_blob_append(NULL, &state->rpc_out,
+ state->req_trailer.data + state->req_trailer_sent,
+ trailer_thistime);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ state->req_trailer_sent += trailer_thistime;
}
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,
return NT_STATUS_INVALID_PARAMETER;
}
- state->req_data_sent += data_sent_thistime;
*is_last_frag = ((flags & DCERPC_PFC_FLAG_LAST) != 0);
return status;
if (is_last_frag) {
subreq = rpc_api_pipe_send(state, state->ev, state->cli,
&state->rpc_out,
- DCERPC_PKT_RESPONSE);
+ DCERPC_PKT_RESPONSE,
+ state->call_id);
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_nterror(req, status);
return;
}
+
+ if (state->cli->auth == NULL) {
+ tevent_req_done(req);
+ return;
+ }
+
+ if (state->verify_bitmask1) {
+ state->cli->auth->verified_bitmask1 = true;
+ }
+
+ if (state->verify_pcontext) {
+ state->cli->verified_pcontext = true;
+ }
+
tevent_req_done(req);
}
-NTSTATUS rpc_api_pipe_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+static NTSTATUS rpc_api_pipe_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
DATA_BLOB *reply_pdu)
{
struct rpc_api_pipe_req_state *state = tevent_req_data(
if (r->num_results != 0x1 || ctx.result != 0) {
DEBUG(2,("bind_rpc_pipe: bind denied results: %d reason: %x\n",
- r->num_results, ctx.reason));
+ r->num_results, ctx.reason.value));
}
DEBUG(5,("check_bind_response: accepted!\n"));
static NTSTATUS create_rpc_bind_auth3(TALLOC_CTX *mem_ctx,
struct rpc_pipe_client *cli,
- uint32 rpc_call_id,
- enum dcerpc_AuthType auth_type,
- enum dcerpc_AuthLevel auth_level,
+ struct pipe_auth_data *auth,
+ uint32_t rpc_call_id,
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,
- uint32 rpc_call_id,
+ struct pipe_auth_data *auth,
+ uint32_t rpc_call_id,
const struct ndr_syntax_id *abstract,
const struct ndr_syntax_id *transfer,
const DATA_BLOB *pauth_blob, /* spnego auth blob already created. */
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)) {
abstract,
transfer,
&auth_info,
+ false, /* client_hdr_signing */
rpc_out);
data_blob_free(&auth_info);
return status;
}
subreq = rpc_api_pipe_send(state, ev, cli, &state->rpc_out,
- DCERPC_PKT_BIND_ACK);
+ DCERPC_PKT_BIND_ACK, state->rpc_call_id);
if (subreq == NULL) {
goto fail;
}
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) {
case DCERPC_AUTH_TYPE_NONE:
- case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
- case DCERPC_AUTH_TYPE_SCHANNEL:
/* Bind complete. */
tevent_req_done(req);
return;
- case DCERPC_AUTH_TYPE_NTLMSSP:
- case DCERPC_AUTH_TYPE_SPNEGO:
- case DCERPC_AUTH_TYPE_KRB5:
- /* Paranoid lenght checks */
- if (pkt->frag_length < DCERPC_AUTH_TRAILER_LENGTH
- + pkt->auth_length) {
- tevent_req_nterror(req,
- NT_STATUS_INFO_LENGTH_MISMATCH);
+ default:
+ if (pkt->auth_length == 0) {
+ tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
return;
}
+
/* get auth credentials */
- status = dcerpc_pull_dcerpc_auth(talloc_tos(),
- &pkt->u.bind_ack.auth_info,
- &auth, false);
+ status = dcerpc_pull_auth_trailer(pkt, talloc_tos(),
+ &pkt->u.bind_ack.auth_info,
+ &auth, NULL, true);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("Failed to pull dcerpc auth: %s.\n",
nt_errstr(status)));
tevent_req_nterror(req, status);
return;
}
- break;
- default:
- goto err_out;
+ 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;
}
/*
switch(pauth->auth_type) {
case DCERPC_AUTH_TYPE_NONE:
- case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
- case DCERPC_AUTH_TYPE_SCHANNEL:
/* Bind complete. */
tevent_req_done(req);
return;
- case DCERPC_AUTH_TYPE_NTLMSSP:
- case DCERPC_AUTH_TYPE_KRB5:
- case DCERPC_AUTH_TYPE_SPNEGO:
- gensec_security = talloc_get_type_abort(pauth->auth_ctx,
- struct gensec_security);
- status = gensec_update(gensec_security, state, NULL,
+ default:
+ gensec_security = pauth->auth_ctx;
+
+
+ status = gensec_update(gensec_security, state,
auth.credentials, &auth_token);
if (NT_STATUS_EQUAL(status,
NT_STATUS_MORE_PROCESSING_REQUIRED)) {
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);
&auth_token);
}
break;
-
- default:
- goto err_out;
}
if (!NT_STATUS_IS_OK(status)) {
tevent_req_nterror(req, status);
}
return;
-
-err_out:
- DEBUG(0,("cli_finish_bind_auth: unknown auth type %u\n",
- (unsigned int)state->cli->auth->auth_type));
- tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
}
static NTSTATUS rpc_bind_next_send(struct tevent_req *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,
}
subreq = rpc_api_pipe_send(state, state->ev, state->cli,
- &state->rpc_out, DCERPC_PKT_ALTER_RESP);
+ &state->rpc_out, DCERPC_PKT_ALTER_RESP,
+ state->rpc_call_id);
if (subreq == NULL) {
return NT_STATUS_NO_MEMORY;
}
/* 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)) {
}
subreq = rpc_api_pipe_send(state, state->ev, state->cli,
- &state->rpc_out, DCERPC_PKT_AUTH3);
+ &state->rpc_out, DCERPC_PKT_AUTH3,
+ state->rpc_call_id);
if (subreq == NULL) {
return NT_STATUS_NO_MEMORY;
}
goto fail;
}
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
}
subreq = rpc_api_pipe_req_send(state, ev, hs->rpc_cli,
- opnum, &state->in_data);
+ opnum, object, &state->in_data);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
/*
* 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);
return h;
}
-NTSTATUS rpccli_ncalrpc_bind_data(TALLOC_CTX *mem_ctx,
- struct pipe_auth_data **presult)
+NTSTATUS rpccli_anon_bind_data(TALLOC_CTX *mem_ctx,
+ struct pipe_auth_data **presult)
{
struct pipe_auth_data *result;
+ struct auth_generic_state *auth_generic_ctx;
+ NTSTATUS status;
- result = talloc(mem_ctx, struct pipe_auth_data);
+ result = talloc_zero(mem_ctx, struct pipe_auth_data);
if (result == NULL) {
return NT_STATUS_NO_MEMORY;
}
- result->auth_type = DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM;
- result->auth_level = DCERPC_AUTH_LEVEL_CONNECT;
+ result->auth_type = DCERPC_AUTH_TYPE_NONE;
+ result->auth_level = DCERPC_AUTH_LEVEL_NONE;
+ result->auth_context_id = 0;
- result->user_name = talloc_strdup(result, "");
- result->domain = talloc_strdup(result, "");
- if ((result->user_name == NULL) || (result->domain == NULL)) {
- TALLOC_FREE(result);
- return NT_STATUS_NO_MEMORY;
+ status = auth_generic_client_prepare(result,
+ &auth_generic_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to create auth_generic context: %s\n",
+ nt_errstr(status)));
}
- *presult = result;
- return NT_STATUS_OK;
-}
-
-NTSTATUS rpccli_anon_bind_data(TALLOC_CTX *mem_ctx,
- struct pipe_auth_data **presult)
-{
- struct pipe_auth_data *result;
-
- result = talloc(mem_ctx, struct pipe_auth_data);
- if (result == NULL) {
- return NT_STATUS_NO_MEMORY;
+ status = auth_generic_set_username(auth_generic_ctx, "");
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to set username: %s\n",
+ nt_errstr(status)));
}
- result->auth_type = DCERPC_AUTH_TYPE_NONE;
- result->auth_level = DCERPC_AUTH_LEVEL_NONE;
+ status = auth_generic_set_domain(auth_generic_ctx, "");
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to set domain: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
- result->user_name = talloc_strdup(result, "");
- result->domain = talloc_strdup(result, "");
- if ((result->user_name == NULL) || (result->domain == NULL)) {
- TALLOC_FREE(result);
- return NT_STATUS_NO_MEMORY;
+ status = gensec_set_credentials(auth_generic_ctx->gensec_security,
+ auth_generic_ctx->credentials);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to set GENSEC credentials: %s\n",
+ nt_errstr(status)));
+ return status;
}
+ talloc_unlink(auth_generic_ctx, auth_generic_ctx->credentials);
+ auth_generic_ctx->credentials = NULL;
+ result->auth_ctx = talloc_move(result, &auth_generic_ctx->gensec_security);
+ talloc_free(auth_generic_ctx);
*presult = result;
return NT_STATUS_OK;
}
struct pipe_auth_data *result;
NTSTATUS status;
- result = talloc(mem_ctx, struct pipe_auth_data);
+ result = talloc_zero(mem_ctx, struct pipe_auth_data);
if (result == NULL) {
return NT_STATUS_NO_MEMORY;
}
result->auth_type = auth_type;
result->auth_level = auth_level;
-
- result->user_name = talloc_strdup(result, username);
- result->domain = talloc_strdup(result, domain);
- if ((result->user_name == NULL) || (result->domain == NULL)) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
+ result->auth_context_id = 1;
status = auth_generic_client_prepare(result,
&auth_generic_ctx);
return status;
}
+/* This routine steals the creds pointer that is passed in */
+static NTSTATUS rpccli_generic_bind_data_from_creds(TALLOC_CTX *mem_ctx,
+ enum dcerpc_AuthType auth_type,
+ enum dcerpc_AuthLevel auth_level,
+ const char *server,
+ const char *target_service,
+ struct cli_credentials *creds,
+ struct pipe_auth_data **presult)
+{
+ struct auth_generic_state *auth_generic_ctx;
+ struct pipe_auth_data *result;
+ NTSTATUS status;
+
+ result = talloc_zero(mem_ctx, struct pipe_auth_data);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ result->auth_type = auth_type;
+ result->auth_level = auth_level;
+ result->auth_context_id = 1;
+
+ status = auth_generic_client_prepare(result,
+ &auth_generic_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ status = auth_generic_set_creds(auth_generic_ctx, creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ status = gensec_set_target_service(auth_generic_ctx->gensec_security, target_service);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ status = gensec_set_target_hostname(auth_generic_ctx->gensec_security, server);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ status = auth_generic_client_start_by_authtype(auth_generic_ctx, auth_type, auth_level);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ result->auth_ctx = talloc_move(result, &auth_generic_ctx->gensec_security);
+ talloc_free(auth_generic_ctx);
+ *presult = result;
+ return NT_STATUS_OK;
+
+ fail:
+ TALLOC_FREE(result);
+ return status;
+}
+
+NTSTATUS rpccli_ncalrpc_bind_data(TALLOC_CTX *mem_ctx,
+ struct pipe_auth_data **presult)
+{
+ return rpccli_generic_bind_data(mem_ctx,
+ DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM,
+ DCERPC_AUTH_LEVEL_CONNECT,
+ NULL, /* server */
+ "host", /* target_service */
+ NAME_NT_AUTHORITY, /* domain */
+ "SYSTEM",
+ NULL, /* password */
+ CRED_DONT_USE_KERBEROS,
+ NULL, /* netlogon_creds_CredentialState */
+ presult);
+}
+
/**
* Create an rpc pipe client struct, connecting to a tcp port.
*/
result->transfer_syntax = ndr_transfer_syntax_ndr;
result->desthost = talloc_strdup(result, host);
+ if (result->desthost == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
result->srv_name_slash = talloc_asprintf_strupper_m(
result, "\\\\%s", result->desthost);
- if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
+ if (result->srv_name_slash == NULL) {
status = NT_STATUS_NO_MEMORY;
goto fail;
}
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)) {
struct pipe_auth_data *auth = NULL;
struct dcerpc_binding *map_binding = NULL;
struct dcerpc_binding *res_binding = NULL;
+ enum dcerpc_transport_t transport;
+ const char *endpoint = NULL;
struct epm_twr_t *map_tower = NULL;
struct epm_twr_t *res_towers = NULL;
struct policy_handle *entry_handle = NULL;
/* create tower for asking the epmapper */
- map_binding = talloc_zero(tmp_ctx, struct dcerpc_binding);
- if (map_binding == NULL) {
- status = NT_STATUS_NO_MEMORY;
+ status = dcerpc_parse_binding(tmp_ctx, "ncacn_ip_tcp:[135]",
+ &map_binding);
+ if (!NT_STATUS_IS_OK(status)) {
goto done;
}
- map_binding->transport = NCACN_IP_TCP;
- map_binding->object = table->syntax_id;
- map_binding->host = host; /* needed? */
- map_binding->endpoint = "0"; /* correct? needed? */
+ status = dcerpc_binding_set_abstract_syntax(map_binding,
+ &table->syntax_id);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
map_tower = talloc_zero(tmp_ctx, struct epm_twr_t);
if (map_tower == NULL) {
goto done;
}
+ transport = dcerpc_binding_get_transport(res_binding);
+ endpoint = dcerpc_binding_get_string_option(res_binding, "endpoint");
+
/* are further checks here necessary? */
- if (res_binding->transport != NCACN_IP_TCP) {
- status = NT_STATUS_UNSUCCESSFUL;
+ if (transport != NCACN_IP_TCP) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+
+ if (endpoint == NULL) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
goto done;
}
- *pport = (uint16_t)atoi(res_binding->endpoint);
+ *pport = (uint16_t)atoi(endpoint);
done:
TALLOC_FREE(tmp_ctx);
result->transfer_syntax = ndr_transfer_syntax_ndr;
result->desthost = get_myname(result);
+ if (result->desthost == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
result->srv_name_slash = talloc_asprintf_strupper_m(
result, "\\\\%s", result->desthost);
- if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
+ if (result->srv_name_slash == NULL) {
status = NT_STATUS_NO_MEMORY;
goto fail;
}
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->abstract_syntax = table->syntax_id;
result->transfer_syntax = ndr_transfer_syntax_ndr;
- result->desthost = talloc_strdup(result, smbXcli_conn_remote_name(cli->conn));
- result->srv_name_slash = talloc_asprintf_strupper_m(
- result, "\\\\%s", result->desthost);
- result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
- result->max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
+ result->desthost = talloc_strdup(
+ result, smbXcli_conn_remote_name(cli->conn));
+ if (result->desthost == NULL) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
- if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
+ result->srv_name_slash = talloc_asprintf_strupper_m(
+ result, "\\\\%s", result->desthost);
+ if (result->srv_name_slash == NULL) {
TALLOC_FREE(result);
return NT_STATUS_NO_MEMORY;
}
+ result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
+
status = rpc_transport_np_init(result, cli, table,
&result->transport);
if (!NT_STATUS_IS_OK(status)) {
* from the enclosing SMB creds
*/
- TALLOC_FREE(auth->user_name);
- TALLOC_FREE(auth->domain);
-
- auth->user_name = talloc_strdup(auth, cli->user_name);
- auth->domain = talloc_strdup(auth, cli->domain);
-
if (transport == NCACN_NP) {
struct smbXcli_session *session;
}
}
- if ((auth->user_name == NULL) || (auth->domain == NULL)) {
- TALLOC_FREE(result);
- return NT_STATUS_NO_MEMORY;
- }
-
status = rpc_pipe_bind(result, auth);
if (!NT_STATUS_IS_OK(status)) {
int lvl = 0;
/****************************************************************************
Open a named pipe to an SMB server and bind using the mech specified
+
+ This routine references the creds pointer that is passed in
****************************************************************************/
-NTSTATUS cli_rpc_pipe_open_generic_auth(struct cli_state *cli,
- const struct ndr_interface_table *table,
- enum dcerpc_transport_t transport,
- enum dcerpc_AuthType auth_type,
- enum dcerpc_AuthLevel auth_level,
- const char *server,
- const char *domain,
- const char *username,
- const char *password,
- struct rpc_pipe_client **presult)
+NTSTATUS cli_rpc_pipe_open_with_creds(struct cli_state *cli,
+ const struct ndr_interface_table *table,
+ enum dcerpc_transport_t transport,
+ enum dcerpc_AuthType auth_type,
+ enum dcerpc_AuthLevel auth_level,
+ const char *server,
+ struct cli_credentials *creds,
+ struct rpc_pipe_client **presult)
{
struct rpc_pipe_client *result;
struct pipe_auth_data *auth = NULL;
const char *target_service = table->authservices->names[0];
-
NTSTATUS status;
status = cli_rpc_pipe_open(cli, transport, table, &result);
return status;
}
- status = rpccli_generic_bind_data(result,
- auth_type, auth_level,
- server, target_service,
- domain, username, password,
- CRED_AUTO_USE_KERBEROS,
- NULL,
- &auth);
+ status = rpccli_generic_bind_data_from_creds(result,
+ auth_type, auth_level,
+ server, target_service,
+ creds,
+ &auth);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("rpccli_generic_bind_data returned %s\n",
- nt_errstr(status)));
+ DBG_ERR("rpccli_generic_bind_data_from_creds returned %s\n",
+ nt_errstr(status));
goto err;
}
status = rpc_pipe_bind(result, auth);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("cli_rpc_pipe_open_generic_auth: cli_rpc_pipe_bind failed with error %s\n",
- nt_errstr(status) ));
+ DBG_ERR("cli_rpc_pipe_bind failed with error %s\n",
+ nt_errstr(status));
goto err;
}
- DEBUG(10,("cli_rpc_pipe_open_generic_auth: opened pipe %s to "
- "machine %s and bound as user %s\\%s.\n", table->name,
- result->desthost, domain, username));
+ DBG_DEBUG("opened pipe %s to machine %s and bound as user %s.\n",
+ table->name,
+ result->desthost,
+ cli_credentials_get_unparsed_name(creds, talloc_tos()));
*presult = result;
return NT_STATUS_OK;
return status;
}
-/****************************************************************************
- External interface.
- Open a named pipe to an SMB server and bind using schannel (bind type 68)
- using session_key. sign and seal.
-
- The *pdc will be stolen onto this new pipe
- ****************************************************************************/
-
-NTSTATUS cli_rpc_pipe_open_schannel_with_key(struct cli_state *cli,
- const struct ndr_interface_table *table,
- enum dcerpc_transport_t transport,
- enum dcerpc_AuthLevel auth_level,
- const char *domain,
- struct netlogon_creds_CredentialState **pdc,
- 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;
- NTSTATUS status;
- NTSTATUS result;
- struct netlogon_creds_CredentialState save_creds;
- struct netr_Authenticator auth;
- struct netr_Authenticator return_auth;
- union netr_Capabilities capabilities;
const char *target_service = table->authservices->names[0];
+ struct cli_credentials *cli_creds;
+ enum dcerpc_AuthLevel auth_level;
+ NTSTATUS status;
status = cli_rpc_pipe_open(cli, transport, table, &rpccli);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- status = rpccli_generic_bind_data(rpccli,
- DCERPC_AUTH_TYPE_SCHANNEL,
- auth_level,
- NULL,
- target_service,
- domain,
- (*pdc)->computer_name,
- NULL,
- CRED_AUTO_USE_KERBEROS,
- *pdc,
- &rpcauth);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("rpccli_generic_bind_data returned %s\n",
- nt_errstr(status)));
- TALLOC_FREE(rpccli);
- return status;
- }
-
- /*
- * The credentials on a new netlogon pipe are the ones we are passed
- * in - copy them over
- *
- * This may get overwritten... in rpc_pipe_bind()...
- */
- rpccli->dc = netlogon_creds_copy(rpccli, *pdc);
- if (rpccli->dc == NULL) {
- TALLOC_FREE(rpccli);
- return NT_STATUS_NO_MEMORY;
- }
+ auth_level = netlogon_creds_cli_auth_level(netlogon_creds);
- status = rpc_pipe_bind(rpccli, rpcauth);
+ status = netlogon_creds_bind_cli_credentials(
+ netlogon_creds, rpccli, &cli_creds);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("cli_rpc_pipe_open_schannel_with_key: "
- "cli_rpc_pipe_bind failed with error %s\n",
- nt_errstr(status) ));
+ DBG_DEBUG("netlogon_creds_bind_cli_credentials failed: %s\n",
+ nt_errstr(status));
TALLOC_FREE(rpccli);
return status;
}
- if (!ndr_syntax_id_equal(&table->syntax_id, &ndr_table_netlogon.syntax_id)) {
- goto done;
- }
-
- save_creds = *rpccli->dc;
- ZERO_STRUCT(return_auth);
- ZERO_STRUCT(capabilities);
-
- netlogon_creds_client_authenticator(&save_creds, &auth);
-
- status = dcerpc_netr_LogonGetCapabilities(rpccli->binding_handle,
- talloc_tos(),
- rpccli->srv_name_slash,
- save_creds.computer_name,
- &auth, &return_auth,
- 1, &capabilities,
- &result);
- if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
- if (save_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
- DEBUG(5, ("AES was negotiated and the error was %s - "
- "downgrade detected\n",
- nt_errstr(status)));
- TALLOC_FREE(rpccli);
- return NT_STATUS_INVALID_NETWORK_RESPONSE;
- }
-
- /* This is probably an old Samba Version */
- DEBUG(5, ("We are checking against an NT or old Samba - %s\n",
- nt_errstr(status)));
- goto done;
- }
-
+ status = rpccli_generic_bind_data_from_creds(rpccli,
+ DCERPC_AUTH_TYPE_SCHANNEL,
+ auth_level,
+ rpccli->desthost,
+ target_service,
+ cli_creds,
+ &rpcauth);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("dcerpc_netr_LogonGetCapabilities failed with %s\n",
+ DEBUG(0, ("rpccli_generic_bind_data_from_creds returned %s\n",
nt_errstr(status)));
TALLOC_FREE(rpccli);
return status;
}
- if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
- if (save_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
- /* This means AES isn't supported. */
- DEBUG(5, ("AES was negotiated and the result was %s - "
- "downgrade detected\n",
- nt_errstr(result)));
- TALLOC_FREE(rpccli);
- return NT_STATUS_INVALID_NETWORK_RESPONSE;
- }
-
- /* This is probably an old Windows version */
- DEBUG(5, ("We are checking against an win2k3 or Samba - %s\n",
- nt_errstr(result)));
- goto done;
- }
-
- /*
- * We need to check the credential state here, cause win2k3 and earlier
- * returns NT_STATUS_NOT_IMPLEMENTED
- */
- if (!netlogon_creds_client_check(&save_creds, &return_auth.cred)) {
- /*
- * Server replied with bad credential. Fail.
- */
- DEBUG(0,("cli_rpc_pipe_open_schannel_with_key: server %s "
- "replied with bad credential\n",
- rpccli->desthost));
- TALLOC_FREE(rpccli);
- return NT_STATUS_INVALID_NETWORK_RESPONSE;
- }
- *rpccli->dc = save_creds;
-
- if (!NT_STATUS_IS_OK(result)) {
- DEBUG(0, ("dcerpc_netr_LogonGetCapabilities failed with %s\n",
- nt_errstr(result)));
- TALLOC_FREE(rpccli);
- return result;
- }
+ status = rpc_pipe_bind(rpccli, rpcauth);
- if (!(save_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES)) {
- /* This means AES isn't supported. */
- DEBUG(5, ("AES is not negotiated, but netr_LogonGetCapabilities "
- "was OK - downgrade detected\n"));
- TALLOC_FREE(rpccli);
- return NT_STATUS_INVALID_NETWORK_RESPONSE;
- }
+ /* No TALLOC_FREE, gensec takes references */
+ talloc_unlink(rpccli, cli_creds);
+ cli_creds = NULL;
- if (save_creds.negotiate_flags != capabilities.server_capabilities) {
- DEBUG(0, ("The client capabilities don't match the server "
- "capabilities: local[0x%08X] remote[0x%08X]\n",
- save_creds.negotiate_flags,
- capabilities.server_capabilities));
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_DEBUG("rpc_pipe_bind failed with error %s\n",
+ nt_errstr(status));
TALLOC_FREE(rpccli);
- return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ return status;
}
-done:
- DEBUG(10,("cli_rpc_pipe_open_schannel_with_key: opened pipe %s to machine %s "
- "for domain %s and bound using schannel.\n",
- table->name,
- rpccli->desthost, domain));
-
*_rpccli = rpccli;
+
return NT_STATUS_OK;
}
-NTSTATUS cli_rpc_pipe_open_spnego(struct cli_state *cli,
- const struct ndr_interface_table *table,
- enum dcerpc_transport_t transport,
- const char *oid,
- enum dcerpc_AuthLevel auth_level,
- const char *server,
- const char *domain,
- const char *username,
- const char *password,
- struct rpc_pipe_client **presult)
+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)
{
- struct rpc_pipe_client *result;
- struct pipe_auth_data *auth = NULL;
- const char *target_service = table->authservices->names[0];
-
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct rpc_pipe_client *rpccli;
+ struct netlogon_creds_cli_lck *lck;
NTSTATUS status;
- enum credentials_use_kerberos use_kerberos;
-
- if (strcmp(oid, GENSEC_OID_KERBEROS5) == 0) {
- use_kerberos = CRED_MUST_USE_KERBEROS;
- } else if (strcmp(oid, GENSEC_OID_NTLMSSP) == 0) {
- use_kerberos = CRED_DONT_USE_KERBEROS;
- } else {
- return NT_STATUS_INVALID_PARAMETER;
- }
- status = cli_rpc_pipe_open(cli, transport, table, &result);
+ 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 = rpccli_generic_bind_data(result,
- DCERPC_AUTH_TYPE_SPNEGO, auth_level,
- server, target_service,
- domain, username, password,
- use_kerberos, NULL,
- &auth);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("rpccli_generic_bind_data returned %s\n",
- nt_errstr(status)));
- goto err;
+ 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);
}
-
- status = rpc_pipe_bind(result, auth);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("cli_rpc_pipe_open_spnego: cli_rpc_pipe_bind failed with error %s\n",
- nt_errstr(status) ));
- goto err;
+ DBG_DEBUG("cli_rpc_pipe_open_bind_schannel failed: %s\n",
+ nt_errstr(status));
+ TALLOC_FREE(frame);
+ return status;
}
- DEBUG(10,("cli_rpc_pipe_open_spnego: opened pipe %s to "
- "machine %s.\n", table->name,
- result->desthost));
+ 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;
+ }
+ }
- *presult = result;
- return NT_STATUS_OK;
+ 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));
- err:
+ TALLOC_FREE(frame);
- TALLOC_FREE(result);
- return status;
+ *_rpccli = rpccli;
+ return NT_STATUS_OK;
}
NTSTATUS cli_get_session_key(TALLOC_CTX *mem_ctx,
}
switch (cli->auth->auth_type) {
- case DCERPC_AUTH_TYPE_SPNEGO:
- case DCERPC_AUTH_TYPE_NTLMSSP:
- case DCERPC_AUTH_TYPE_KRB5:
- gensec_security = talloc_get_type_abort(a->auth_ctx,
- struct gensec_security);
- status = gensec_session_key(gensec_security, mem_ctx, &sk);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
- make_dup = false;
- break;
- case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
case DCERPC_AUTH_TYPE_NONE:
sk = data_blob_const(a->transport_session_key.data,
a->transport_session_key.length);
make_dup = true;
break;
default:
+ gensec_security = a->auth_ctx;
+ status = gensec_session_key(gensec_security, mem_ctx, &sk);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ make_dup = false;
break;
}