{
return p->conn ? p->conn->server_name : NULL;
}
-
-
-/*
- get the dcerpc auth_level for a open connection
-*/
-uint32_t dcerpc_auth_level(struct dcecli_connection *c)
-{
- uint8_t auth_level;
-
- if (c->flags & DCERPC_SEAL) {
- auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
- } else if (c->flags & DCERPC_SIGN) {
- auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
- } else if (c->flags & DCERPC_PACKET) {
- auth_level = DCERPC_AUTH_LEVEL_PACKET;
- } else if (c->flags & DCERPC_CONNECT) {
- auth_level = DCERPC_AUTH_LEVEL_CONNECT;
- } else {
- auth_level = DCERPC_AUTH_LEVEL_NONE;
- }
- return auth_level;
-}
-
-struct dcerpc_alter_context_state {
- struct tevent_context *ev;
- struct dcerpc_pipe *p;
-};
-
-static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
-static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
- DATA_BLOB *raw_packet,
- struct ncacn_packet *pkt);
-
-struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct dcerpc_pipe *p,
- const struct ndr_syntax_id *syntax,
- const struct ndr_syntax_id *transfer_syntax)
-{
- struct tevent_req *req;
- struct dcerpc_alter_context_state *state;
- struct ncacn_packet pkt;
- DATA_BLOB blob;
- NTSTATUS status;
- struct rpc_request *subreq;
- uint32_t flags;
-
- req = tevent_req_create(mem_ctx, &state,
- struct dcerpc_alter_context_state);
- if (req == NULL) {
- return NULL;
- }
-
- state->ev = ev;
- state->p = p;
-
- p->syntax = *syntax;
- p->transfer_syntax = *transfer_syntax;
-
- flags = dcerpc_binding_get_flags(p->binding);
-
- init_ncacn_hdr(p->conn, &pkt);
-
- pkt.ptype = DCERPC_PKT_ALTER;
- pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
- pkt.call_id = p->conn->call_id;
- pkt.auth_length = 0;
-
- if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
- pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
- }
-
- pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
- pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
- pkt.u.alter.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
- pkt.u.alter.num_contexts = 1;
- pkt.u.alter.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
- pkt.u.alter.num_contexts);
- if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
- return tevent_req_post(req, ev);
- }
- pkt.u.alter.ctx_list[0].context_id = p->context_id;
- pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
- pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
- pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
- pkt.u.alter.auth_info = data_blob(NULL, 0);
-
- /* construct the NDR form of the packet */
- status = ncacn_push_auth(&blob, state, &pkt,
- p->conn->security_state.tmp_auth_info.out);
- if (tevent_req_nterror(req, status)) {
- return tevent_req_post(req, ev);
- }
-
- /*
- * we allocate a dcerpc_request so we can be in the same
- * request queue as normal requests
- */
- subreq = talloc_zero(state, struct rpc_request);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
-
- subreq->state = RPC_REQUEST_PENDING;
- subreq->call_id = pkt.call_id;
- subreq->async.private_data = req;
- subreq->async.callback = dcerpc_alter_context_fail_handler;
- subreq->p = p;
- subreq->recv_handler = dcerpc_alter_context_recv_handler;
- DLIST_ADD_END(p->conn->pending, subreq);
- talloc_set_destructor(subreq, dcerpc_req_dequeue);
-
- status = dcerpc_send_request(p->conn, &blob, true);
- if (tevent_req_nterror(req, status)) {
- return tevent_req_post(req, ev);
- }
-
- tevent_add_timer(ev, subreq,
- timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
- dcerpc_timeout_handler, subreq);
-
- return req;
-}
-
-static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
-{
- struct tevent_req *req =
- talloc_get_type_abort(subreq->async.private_data,
- struct tevent_req);
- struct dcerpc_alter_context_state *state =
- tevent_req_data(req,
- struct dcerpc_alter_context_state);
- NTSTATUS status = subreq->status;
-
- TALLOC_FREE(subreq);
-
- /*
- * We trigger the callback in the next event run
- * because the code in this file might trigger
- * multiple request callbacks from within a single
- * while loop.
- *
- * In order to avoid segfaults from within
- * dcerpc_connection_dead() we call
- * tevent_req_defer_callback().
- */
- tevent_req_defer_callback(req, state->ev);
-
- tevent_req_nterror(req, status);
-}
-
-static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
- DATA_BLOB *raw_packet,
- struct ncacn_packet *pkt)
-{
- struct tevent_req *req =
- talloc_get_type_abort(subreq->async.private_data,
- struct tevent_req);
- struct dcerpc_alter_context_state *state =
- tevent_req_data(req,
- struct dcerpc_alter_context_state);
- struct dcecli_connection *conn = state->p->conn;
- struct dcecli_security *sec = &conn->security_state;
- NTSTATUS status;
-
- /*
- * Note that pkt is allocated under raw_packet->data,
- * while raw_packet->data is a child of subreq.
- */
- talloc_steal(state, raw_packet->data);
- TALLOC_FREE(subreq);
-
- /*
- * We trigger the callback in the next event run
- * because the code in this file might trigger
- * multiple request callbacks from within a single
- * while loop.
- *
- * In order to avoid segfaults from within
- * dcerpc_connection_dead() we call
- * tevent_req_defer_callback().
- */
- tevent_req_defer_callback(req, state->ev);
-
- if (pkt->ptype == DCERPC_PKT_FAULT) {
- DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
- dcerpc_errstr(state, pkt->u.fault.status)));
- if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
- state->p->last_fault_code = pkt->u.fault.status;
- tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
- } else if (pkt->u.fault.status == DCERPC_FAULT_SEC_PKG_ERROR) {
- state->p->last_fault_code = pkt->u.fault.status;
- tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
- } else {
- state->p->last_fault_code = pkt->u.fault.status;
- status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
- tevent_req_nterror(req, status);
- }
- return;
- }
-
- status = dcerpc_verify_ncacn_packet_header(pkt,
- DCERPC_PKT_ALTER_RESP,
- 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(status)) {
- state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
- tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
- return;
- }
-
- if (pkt->u.alter_resp.num_results != 1) {
- state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
- tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
- return;
- }
-
- if (pkt->u.alter_resp.ctx_list[0].result != 0) {
- status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
- DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
- pkt->u.alter_resp.ctx_list[0].reason.value,
- nt_errstr(status)));
- tevent_req_nterror(req, status);
- return;
- }
-
- /* the alter_resp might contain a reply set of credentials */
- if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
- status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
- &pkt->u.alter_resp.auth_info,
- sec->tmp_auth_info.in,
- NULL, true);
- if (tevent_req_nterror(req, status)) {
- return;
- }
- }
-
- tevent_req_done(req);
-}
-
-NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
-{
- return tevent_req_simple_recv_ntstatus(req);
-}
-
-/*
- send a dcerpc alter_context request
-*/
-_PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
- TALLOC_CTX *mem_ctx,
- const struct ndr_syntax_id *syntax,
- const struct ndr_syntax_id *transfer_syntax)
-{
- struct tevent_req *subreq;
- struct tevent_context *ev = p->conn->event_ctx;
- bool ok;
-
- /* TODO: create a new event context here */
-
- subreq = dcerpc_alter_context_send(mem_ctx, ev,
- p, syntax, transfer_syntax);
- if (subreq == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- ok = tevent_req_poll(subreq, ev);
- if (!ok) {
- NTSTATUS status;
- status = map_nt_error_from_unix_common(errno);
- return status;
- }
-
- return dcerpc_alter_context_recv(subreq);
-}
-
-static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
-{
- if (c->transport.stream == NULL) {
- return;
- }
-
- tevent_queue_stop(c->transport.write_queue);
- TALLOC_FREE(c->transport.read_subreq);
- TALLOC_FREE(c->transport.stream);
-
- if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
- status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
- }
-
- if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
- status = NT_STATUS_END_OF_FILE;
- }
-
- dcerpc_recv_data(c, NULL, status);
-}
-
-
-/*
- shutdown SMB pipe connection
-*/
-struct dcerpc_shutdown_pipe_state {
- struct dcecli_connection *c;
- NTSTATUS status;
-};
-
-static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
-
-static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
-{
- struct dcerpc_shutdown_pipe_state *state;
- struct tevent_req *subreq;
-
- if (c->transport.stream == NULL) {
- return NT_STATUS_OK;
- }
-
- state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
- if (state == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- state->c = c;
- state->status = status;
-
- subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
- if (subreq == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
-
- return status;
-}
-
-static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
-{
- struct dcerpc_shutdown_pipe_state *state =
- tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
- struct dcecli_connection *c = state->c;
- NTSTATUS status = state->status;
- int error;
-
- /*
- * here we ignore the return values...
- */
- tstream_disconnect_recv(subreq, &error);
- TALLOC_FREE(subreq);
-
- TALLOC_FREE(state);
-
- dcerpc_transport_dead(c, status);
-}
-
-
-
-struct dcerpc_send_read_state {
- struct dcecli_connection *p;
-};
-
-static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
-{
- struct dcecli_connection *p = state->p;
-
- p->transport.read_subreq = NULL;
-
- return 0;
-}
-
-static void dcerpc_send_read_done(struct tevent_req *subreq);
-
-static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
-{
- struct dcerpc_send_read_state *state;
-
- if (p->transport.read_subreq != NULL) {
- p->transport.pending_reads++;
- return NT_STATUS_OK;
- }
-
- state = talloc_zero(p, struct dcerpc_send_read_state);
- if (state == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- state->p = p;
-
- talloc_set_destructor(state, dcerpc_send_read_state_destructor);
-
- p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
- p->event_ctx,
- p->transport.stream);
- if (p->transport.read_subreq == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
-
- return NT_STATUS_OK;
-}
-
-static void dcerpc_send_read_done(struct tevent_req *subreq)
-{
- struct dcerpc_send_read_state *state =
- tevent_req_callback_data(subreq,
- struct dcerpc_send_read_state);
- struct dcecli_connection *p = state->p;
- NTSTATUS status;
- struct ncacn_packet *pkt;
- DATA_BLOB blob;
-
- status = dcerpc_read_ncacn_packet_recv(subreq, state,
- &pkt, &blob);
- TALLOC_FREE(subreq);
- if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(state);
- dcerpc_transport_dead(p, status);
- return;
- }
-NDR_PRINT_DEBUG(ncacn_packet, pkt);
- /*
- * here we steal into thet connection context,
- * but p->transport.recv_data() will steal or free it again
- */
- talloc_steal(p, blob.data);
- TALLOC_FREE(state);
-
- if (p->transport.pending_reads > 0) {
- p->transport.pending_reads--;
-
- status = dcerpc_send_read(p);
- if (!NT_STATUS_IS_OK(status)) {
- dcerpc_transport_dead(p, status);
- return;
- }
- }
-
- dcerpc_recv_data(p, &blob, NT_STATUS_OK);
-}
-
-struct dcerpc_send_request_state {
- struct dcecli_connection *p;
- DATA_BLOB blob;
- struct iovec iov;
-};
-
-static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
-{
- struct dcecli_connection *p = state->p;
-
- p->transport.read_subreq = NULL;
-
- return 0;
-}
-
-static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
-static void dcerpc_send_request_done(struct tevent_req *subreq);
-
-static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
- bool trigger_read)
-{
- struct dcerpc_send_request_state *state;
- struct tevent_req *subreq;
- bool use_trans = trigger_read;
-
- if (p->transport.stream == NULL) {
- return NT_STATUS_CONNECTION_DISCONNECTED;
- }
-
- state = talloc_zero(p, struct dcerpc_send_request_state);
- if (state == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- state->p = p;
-
- state->blob = data_blob_talloc(state, data->data, data->length);
- if (state->blob.data == NULL) {
- TALLOC_FREE(state);
- return NT_STATUS_NO_MEMORY;
- }
- state->iov.iov_base = (void *)state->blob.data;
- state->iov.iov_len = state->blob.length;
-
- if (p->transport.read_subreq != NULL) {
- use_trans = false;
- }
-
- if (!tstream_is_smbXcli_np(p->transport.stream)) {
- use_trans = false;
- }
-
- if (use_trans) {
- /*
- * we need to block reads until our write is
- * the next in the write queue.
- */
- p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
- p->transport.write_queue);
- if (p->transport.read_subreq == NULL) {
- TALLOC_FREE(state);
- return NT_STATUS_NO_MEMORY;
- }
- tevent_req_set_callback(p->transport.read_subreq,
- dcerpc_send_request_wait_done,
- state);
-
- talloc_set_destructor(state, dcerpc_send_request_state_destructor);
-
- trigger_read = false;
- }
-
- subreq = tstream_writev_queue_send(state, p->event_ctx,
- p->transport.stream,
- p->transport.write_queue,
- &state->iov, 1);
- if (subreq == NULL) {
- TALLOC_FREE(state);
- return NT_STATUS_NO_MEMORY;
- }
- tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
-
- if (trigger_read) {
- dcerpc_send_read(p);
- }
-
- return NT_STATUS_OK;
-}
-
-static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
-{
- struct dcerpc_send_request_state *state =
- tevent_req_callback_data(subreq,
- struct dcerpc_send_request_state);
- struct dcecli_connection *p = state->p;
- NTSTATUS status;
- bool ok;
-
- p->transport.read_subreq = NULL;
- talloc_set_destructor(state, NULL);
-
- ok = tevent_queue_wait_recv(subreq);
- if (!ok) {
- TALLOC_FREE(state);
- dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
- return;
- }
-
- if (tevent_queue_length(p->transport.write_queue) <= 2) {
- status = tstream_smbXcli_np_use_trans(p->transport.stream);
- if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(state);
- dcerpc_transport_dead(p, status);
- return;
- }
- }
-
- /* we free subreq after tstream_cli_np_use_trans */
- TALLOC_FREE(subreq);
-
- dcerpc_send_read(p);
-}
-
-static void dcerpc_send_request_done(struct tevent_req *subreq)
-{
- struct dcerpc_send_request_state *state =
- tevent_req_callback_data(subreq,
- struct dcerpc_send_request_state);
- int ret;
- int error;
-
- ret = tstream_writev_queue_recv(subreq, &error);
- TALLOC_FREE(subreq);
- if (ret == -1) {
- struct dcecli_connection *p = state->p;
- NTSTATUS status = map_nt_error_from_unix_common(error);
-
- TALLOC_FREE(state);
- dcerpc_transport_dead(p, status);
- return;
- }
-
- TALLOC_FREE(state);
-}