2 Unix SMB/CIFS implementation.
4 [MS-RPCH] - RPC over HTTP client
6 Copyright (C) 2013 Samuel Cabrero <samuelcabrero@kernevil.me>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "lib/events/events.h"
24 #include "lib/util/tevent_ntstatus.h"
25 #include "lib/tls/tls.h"
26 #include "libcli/resolve/resolve.h"
27 #include "libcli/composite/composite.h"
28 #include "auth/credentials/credentials.h"
29 #include "tsocket/tsocket.h"
30 #include "tsocket/tsocket_internal.h"
31 #include "librpc/rpc/dcerpc.h"
32 #include "librpc/rpc/dcerpc_roh.h"
33 #include "librpc/rpc/dcerpc_proto.h"
35 static ssize_t tstream_roh_pending_bytes(struct tstream_context *stream);
36 static struct tevent_req * tstream_roh_readv_send(
38 struct tevent_context *ev,
39 struct tstream_context *stream,
42 static int tstream_roh_readv_recv(struct tevent_req *req, int *perrno);
43 static struct tevent_req * tstream_roh_writev_send(
45 struct tevent_context *ev,
46 struct tstream_context *stream,
47 const struct iovec *vector,
49 static int tstream_roh_writev_recv(struct tevent_req *req, int *perrno);
50 static struct tevent_req * tstream_roh_disconnect_send(
52 struct tevent_context *ev,
53 struct tstream_context *stream);
54 static int tstream_roh_disconnect_recv(struct tevent_req *req, int *perrno);
56 static const struct tstream_context_ops tstream_roh_ops = {
58 .pending_bytes = tstream_roh_pending_bytes,
59 .readv_send = tstream_roh_readv_send,
60 .readv_recv = tstream_roh_readv_recv,
61 .writev_send = tstream_roh_writev_send,
62 .writev_recv = tstream_roh_writev_recv,
63 .disconnect_send = tstream_roh_disconnect_send,
64 .disconnect_recv = tstream_roh_disconnect_recv,
67 struct tstream_roh_context {
68 struct roh_connection *roh_conn;
71 struct roh_open_connection_state {
72 struct tevent_req *req;
73 struct tevent_context *event_ctx;
74 struct cli_credentials *credentials;
75 struct resolve_context *resolve_ctx;
76 const char **rpcproxy_addresses;
77 unsigned int rpcproxy_address_index;
79 struct dcecli_connection *conn;
82 const char *rpc_proxy;
83 unsigned int rpc_proxy_port;
84 const char *rpc_server;
85 unsigned int rpc_server_port;
86 const char *target_hostname;
88 struct roh_connection *roh;
89 struct tstream_tls_params *tls_params;
90 struct loadparm_context *lp_ctx;
94 NTSTATUS dcerpc_pipe_open_roh_recv(struct tevent_req *req,
96 struct tstream_context **stream,
97 struct tevent_queue **queue)
99 struct roh_open_connection_state *state;
100 struct tstream_roh_context *roh_stream_ctx;
103 state = tevent_req_data(req, struct roh_open_connection_state);
104 if (tevent_req_is_nterror(req, &status)) {
105 tevent_req_received(req);
109 *stream = tstream_context_create(mem_ctx, &tstream_roh_ops,
111 struct tstream_roh_context,
114 tevent_req_received(req);
115 return NT_STATUS_NO_MEMORY;
117 ZERO_STRUCTP(roh_stream_ctx);
119 roh_stream_ctx->roh_conn = talloc_move(mem_ctx, &state->roh);
120 *queue = roh_stream_ctx->roh_conn->default_channel_in->send_queue;
122 tevent_req_received(req);
127 static void roh_continue_resolve_name(struct composite_context *ctx);
130 * Send rpc pipe open request to given host:port using http transport
132 struct tevent_req *dcerpc_pipe_open_roh_send(struct dcecli_connection *conn,
133 const char *localaddr,
134 const char *rpc_server,
135 uint32_t rpc_server_port,
136 const char *rpc_proxy,
137 uint32_t rpc_proxy_port,
138 const char *http_proxy,
139 uint32_t http_proxy_port,
142 struct cli_credentials *credentials,
143 struct resolve_context *resolve_ctx,
144 struct loadparm_context *lp_ctx,
148 struct tevent_req *req;
149 struct composite_context *ctx;
150 struct roh_open_connection_state *state;
151 struct nbt_name name;
153 req = tevent_req_create(conn, &state, struct roh_open_connection_state);
158 /* Set state fields */
160 state->event_ctx = conn->event_ctx;
161 state->lp_ctx = lp_ctx,
162 state->credentials = credentials;
164 state->tls = use_tls;
166 /* Initialize connection structure (3.2.1.3) */
167 /* TODO Initialize virtual connection cookie table */
168 state->rpc_server = talloc_strdup(state, rpc_server);
169 state->rpc_server_port = rpc_server_port;
170 state->rpc_proxy = talloc_strdup(state, rpc_proxy);
171 state->rpc_proxy_port = rpc_proxy_port;
172 state->use_ntlm = use_ntlm;
174 state->roh = talloc_zero(state, struct roh_connection);
175 state->roh->protocol_version = ROH_V2;
176 state->roh->connection_state = ROH_STATE_OPEN_START;
177 state->roh->connection_cookie = GUID_random();
178 state->roh->association_group_id_cookie = GUID_random();
180 /* Additional initialization steps (3.2.2.3) */
181 state->roh->proxy_use = use_proxy;
182 state->roh->current_keep_alive_time = 0;
183 state->roh->current_keep_alive_interval = 0;
187 status = tstream_tls_params_client(state->roh, NULL, NULL,
189 if (!NT_STATUS_IS_OK(status)) {
190 DEBUG(0,("%s: Failed tstream_tls_params_client - %s\n",
191 __func__, nt_errstr(status)));
192 tevent_req_nterror(req, status);
193 return tevent_req_post(req, conn->event_ctx);
197 /* Resolve RPC proxy server name */
198 make_nbt_name_server(&name, state->rpc_proxy);
199 ctx = resolve_name_send(resolve_ctx, state, &name, state->event_ctx);
200 if (tevent_req_nomem(ctx, req)) {
201 return tevent_req_post(req, state->event_ctx);
203 ctx->async.fn = roh_continue_resolve_name;
204 ctx->async.private_data = state;
209 static void roh_connect_channel_in_done(struct tevent_req *subreq);
210 static void roh_continue_resolve_name(struct composite_context *ctx)
213 struct roh_open_connection_state *state;
214 struct tevent_req *subreq;
216 state = talloc_get_type_abort(ctx->async.private_data,
217 struct roh_open_connection_state);
218 status = resolve_name_multiple_recv(ctx, state,
219 &state->rpcproxy_addresses);
220 if (tevent_req_nterror(state->req, status)) {
221 DEBUG(2, ("%s: No server found: %s\n", __func__,
226 state->rpcproxy_address_index = 0;
227 if (state->rpcproxy_addresses[state->rpcproxy_address_index] == NULL) {
228 DEBUG(2, ("%s: No server found\n", __func__));
229 tevent_req_nterror(state->req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
234 * TODO Determine proxy use
235 * If state->roh->proxy_use == true, the client has requested to
236 * always use local proxy. Otherwise, run the proxy use discovery
238 state->roh->connection_state = ROH_STATE_OPEN_START;
239 subreq = roh_connect_channel_in_send(state,
241 state->rpcproxy_addresses[state->rpcproxy_address_index],
242 state->rpc_proxy_port,
244 state->roh, state->tls,
246 if (tevent_req_nomem(subreq, state->req)) {
249 tevent_req_set_callback(subreq, roh_connect_channel_in_done, state->req);
252 static void roh_connect_channel_out_done(struct tevent_req *);
253 static void roh_connect_channel_in_done(struct tevent_req *subreq)
256 struct tevent_req *req;
257 struct roh_open_connection_state *state;
259 req = tevent_req_callback_data(subreq, struct tevent_req);
260 state = tevent_req_data(req, struct roh_open_connection_state);
262 status = roh_connect_channel_in_recv(subreq);
264 if (tevent_req_nterror(req, status)) {
268 subreq = roh_connect_channel_out_send(state,
270 state->rpcproxy_addresses[state->rpcproxy_address_index],
271 state->rpc_proxy_port,
276 if (tevent_req_nomem(subreq, req)) {
279 tevent_req_set_callback(subreq, roh_connect_channel_out_done, req);
282 static void roh_send_RPC_DATA_IN_done(struct tevent_req *);
283 static void roh_connect_channel_out_done(struct tevent_req *subreq)
286 struct tevent_req *req;
287 struct roh_open_connection_state *state;
289 req = tevent_req_callback_data(subreq, struct tevent_req);
290 state = tevent_req_data(req, struct roh_open_connection_state);
292 status = roh_connect_channel_out_recv(subreq);
294 if (tevent_req_nterror(req, status)) {
298 subreq = roh_send_RPC_DATA_IN_send(state, state->lp_ctx,
303 state->rpc_server_port,
306 if (tevent_req_nomem(subreq, req)) {
309 tevent_req_set_callback(subreq, roh_send_RPC_DATA_IN_done, req);
312 static void roh_send_RPC_DATA_OUT_done(struct tevent_req *);
313 static void roh_send_RPC_DATA_IN_done(struct tevent_req *subreq)
316 struct tevent_req *req;
317 struct roh_open_connection_state *state;
319 req = tevent_req_callback_data(subreq, struct tevent_req);
320 state = tevent_req_data(req, struct roh_open_connection_state);
322 status = roh_send_RPC_DATA_IN_recv(subreq);
324 if (tevent_req_nterror(req, status)) {
328 subreq = roh_send_RPC_DATA_OUT_send(state,
334 state->rpc_server_port,
337 if (tevent_req_nomem(subreq, req)) {
340 tevent_req_set_callback(subreq, roh_send_RPC_DATA_OUT_done, req);
343 static void roh_send_CONN_A1_done(struct tevent_req *);
344 static void roh_send_RPC_DATA_OUT_done(struct tevent_req *subreq)
347 struct tevent_req *req;
348 struct roh_open_connection_state *state;
350 req = tevent_req_callback_data(subreq, struct tevent_req);
351 state = tevent_req_data(req, struct roh_open_connection_state);
353 status = roh_send_RPC_DATA_OUT_recv(subreq);
355 if (tevent_req_nterror(req, status)) {
359 subreq = roh_send_CONN_A1_send(state, state->event_ctx, state->roh);
360 if (tevent_req_nomem(subreq, req)) {
363 tevent_req_set_callback(subreq, roh_send_CONN_A1_done, req);
366 static void roh_send_CONN_B1_done(struct tevent_req *);
367 static void roh_send_CONN_A1_done(struct tevent_req *subreq)
370 struct tevent_req *req;
371 struct roh_open_connection_state *state;
373 req = tevent_req_callback_data(subreq, struct tevent_req);
374 state = tevent_req_data(req, struct roh_open_connection_state);
376 status = roh_send_CONN_A1_recv(subreq);
378 if (tevent_req_nterror(req, status)) {
382 subreq = roh_send_CONN_B1_send(state, state->event_ctx, state->roh);
383 if (tevent_req_nomem(subreq, req)) {
386 tevent_req_set_callback(subreq, roh_send_CONN_B1_done, req);
389 static void roh_recv_out_channel_response_done(struct tevent_req *);
390 static void roh_send_CONN_B1_done(struct tevent_req *subreq)
393 struct tevent_req *req;
394 struct roh_open_connection_state *state;
396 req = tevent_req_callback_data(subreq, struct tevent_req);
397 state = tevent_req_data(req, struct roh_open_connection_state);
399 status = roh_send_CONN_B1_recv(subreq);
401 if (tevent_req_nterror(req, status)) {
405 state->roh->connection_state = ROH_STATE_OUT_CHANNEL_WAIT;
406 subreq = roh_recv_out_channel_response_send(state, state->event_ctx,
408 if (tevent_req_nomem(subreq, req)) {
411 tevent_req_set_callback(subreq, roh_recv_out_channel_response_done, req);
414 static void roh_recv_CONN_A3_done(struct tevent_req *);
415 static void roh_recv_out_channel_response_done(struct tevent_req *subreq)
419 struct tevent_req *req;
420 struct roh_open_connection_state *state;
422 req = tevent_req_callback_data(subreq, struct tevent_req);
423 state = tevent_req_data(req, struct roh_open_connection_state);
425 status = roh_recv_out_channel_response_recv(subreq, state, &response);
427 if (tevent_req_nterror(req, status)) {
431 state->roh->connection_state = ROH_STATE_WAIT_A3W;
432 subreq = roh_recv_CONN_A3_send(state, state->event_ctx, state->roh);
433 if (tevent_req_nomem(subreq, req)) {
436 tevent_req_set_callback(subreq, roh_recv_CONN_A3_done, req);
439 static void roh_recv_CONN_C2_done(struct tevent_req *);
440 static void roh_recv_CONN_A3_done(struct tevent_req *subreq)
443 struct tevent_req *req;
444 struct roh_open_connection_state *state;
446 req = tevent_req_callback_data(subreq, struct tevent_req);
447 state = tevent_req_data(req, struct roh_open_connection_state);
449 status = roh_recv_CONN_A3_recv(subreq, &state->roh->default_channel_out->connection_timeout);
451 if (tevent_req_nterror(req, status)) {
455 state->roh->connection_state = ROH_STATE_WAIT_C2;
456 subreq = roh_recv_CONN_C2_send(state, state->event_ctx, state->roh);
457 if (tevent_req_nomem(subreq, req)) {
460 tevent_req_set_callback(subreq, roh_recv_CONN_C2_done, req);
463 static void roh_recv_CONN_C2_done(struct tevent_req *subreq)
466 struct tevent_req *req;
467 struct roh_open_connection_state *state;
468 unsigned int version;
470 unsigned int timeout;
472 req = tevent_req_callback_data(subreq, struct tevent_req);
473 state = tevent_req_data(req, struct roh_open_connection_state);
475 status = roh_recv_CONN_C2_recv(subreq, &version, &recv, &timeout);
477 if (tevent_req_nterror(req, status)) {
480 state->roh->connection_state = ROH_STATE_OPENED;
482 tevent_req_done(req);
485 static ssize_t tstream_roh_pending_bytes(struct tstream_context *stream)
487 struct tstream_roh_context *ctx = NULL;
489 ctx = tstream_context_data(stream, struct tstream_roh_context);
490 if (!ctx->roh_conn) {
495 return tstream_pending_bytes(ctx->roh_conn->default_channel_out->streams.active);
498 struct tstream_roh_readv_state {
499 struct roh_connection *roh_conn;
503 static void tstream_roh_readv_handler(struct tevent_req *subreq);
504 static struct tevent_req * tstream_roh_readv_send(TALLOC_CTX *mem_ctx,
505 struct tevent_context *ev,
506 struct tstream_context *stream,
507 struct iovec *vector,
510 struct tstream_roh_context *ctx = NULL;
511 struct tstream_roh_readv_state *state;
512 struct tevent_req *req, *subreq;
514 req = tevent_req_create(mem_ctx, &state, struct tstream_roh_readv_state);
519 ctx = tstream_context_data(stream, struct tstream_roh_context);
520 if (!ctx->roh_conn) {
521 tevent_req_error(req, ENOTCONN);
524 if (!ctx->roh_conn->default_channel_out) {
525 tevent_req_error(req, ENOTCONN);
528 if (!ctx->roh_conn->default_channel_out->streams.active) {
529 tevent_req_error(req, ENOTCONN);
533 state->roh_conn = ctx->roh_conn;
535 subreq = tstream_readv_send(state, ev,
536 ctx->roh_conn->default_channel_out->streams.active,
538 if (tevent_req_nomem(subreq, req)) {
541 tevent_req_set_callback(subreq, tstream_roh_readv_handler, req);
545 tevent_req_post(req, ev);
549 static void tstream_roh_readv_handler(struct tevent_req *subreq)
551 struct tevent_req *req;
552 struct tstream_roh_readv_state *state;
556 req = tevent_req_callback_data(subreq, struct tevent_req);
557 state = tevent_req_data(req, struct tstream_roh_readv_state);
558 ret = tstream_readv_recv(subreq, &sys_errno);
561 tevent_req_error(req, sys_errno);
567 tevent_req_done(req);
570 static int tstream_roh_readv_recv(struct tevent_req *req, int *perrno)
572 struct tstream_roh_readv_state *state;
575 state = tevent_req_data(req, struct tstream_roh_readv_state);
576 ret = tsocket_simple_int_recv(req, perrno);
581 tevent_req_received(req);
585 struct tstream_roh_writev_state {
586 struct roh_connection *roh_conn;
590 static void tstream_roh_writev_handler(struct tevent_req *subreq);
591 static struct tevent_req * tstream_roh_writev_send(TALLOC_CTX *mem_ctx,
592 struct tevent_context *ev,
593 struct tstream_context *stream,
594 const struct iovec *vector,
597 struct tstream_roh_context *ctx = NULL;
598 struct tstream_roh_writev_state *state = NULL;
599 struct tevent_req *req = NULL;
600 struct tevent_req *subreq = NULL;
602 req = tevent_req_create(mem_ctx, &state,
603 struct tstream_roh_writev_state);
608 ctx = tstream_context_data(stream, struct tstream_roh_context);
609 if (!ctx->roh_conn) {
610 tevent_req_error(req, ENOTCONN);
613 if (!ctx->roh_conn->default_channel_in) {
614 tevent_req_error(req, ENOTCONN);
617 if (!ctx->roh_conn->default_channel_in->streams.active) {
618 tevent_req_error(req, ENOTCONN);
622 state->roh_conn = ctx->roh_conn;
624 subreq = tstream_writev_send(state, ev,
625 ctx->roh_conn->default_channel_in->streams.active,
627 if (tevent_req_nomem(subreq, req)) {
630 tevent_req_set_callback(subreq, tstream_roh_writev_handler, req);
634 tevent_req_post(req, ev);
638 static void tstream_roh_writev_handler(struct tevent_req *subreq)
640 struct tevent_req *req;
641 struct tstream_roh_writev_state *state;
645 req = tevent_req_callback_data(subreq, struct tevent_req);
646 state = tevent_req_data(req, struct tstream_roh_writev_state);
647 nwritten = tstream_writev_recv(subreq, &sys_errno);
649 if (nwritten == -1) {
650 tevent_req_error(req, sys_errno);
653 state->nwritten = nwritten;
654 state->roh_conn->default_channel_in->sent_bytes += nwritten;
656 tevent_req_done(req);
659 static int tstream_roh_writev_recv(struct tevent_req *req, int *perrno)
661 struct tstream_roh_writev_state *state;
664 state = tevent_req_data(req, struct tstream_roh_writev_state);
665 ret = tsocket_simple_int_recv(req, perrno);
667 ret = state->nwritten;
673 struct tstream_roh_disconnect_state {
674 struct tstream_context *stream;
675 struct tevent_context *ev;
678 static void tstream_roh_disconnect_channel_in_handler(struct tevent_req *subreq);
679 static struct tevent_req * tstream_roh_disconnect_send(TALLOC_CTX *mem_ctx,
680 struct tevent_context *ev,
681 struct tstream_context *stream)
683 struct tstream_roh_context *ctx = NULL;
684 struct tevent_req *req, *subreq;
685 struct tstream_roh_disconnect_state *state;
687 req = tevent_req_create(mem_ctx, &state, struct tstream_roh_disconnect_state);
692 state->stream = stream;
695 ctx = tstream_context_data(stream, struct tstream_roh_context);
696 if (!ctx->roh_conn) {
697 tevent_req_error(req, ENOTCONN);
700 if (!ctx->roh_conn->default_channel_in) {
701 tevent_req_error(req, ENOTCONN);
704 if (!ctx->roh_conn->default_channel_in->streams.active) {
705 tevent_req_error(req, ENOTCONN);
709 subreq = tstream_disconnect_send(state, ev, ctx->roh_conn->default_channel_in->streams.active);
710 if (tevent_req_nomem(subreq, req)) {
713 tevent_req_set_callback(subreq, tstream_roh_disconnect_channel_in_handler, req);
717 tevent_req_post(req, ev);
721 static void tstream_roh_disconnect_channel_out_handler(struct tevent_req *subreq);
723 static void tstream_roh_disconnect_channel_in_handler(struct tevent_req *subreq)
725 struct tevent_req *req;
726 struct tstream_roh_disconnect_state *state;
727 struct tstream_context *stream;
728 struct tstream_roh_context *roh_stream;
732 req = tevent_req_callback_data(subreq, struct tevent_req);
733 state = tevent_req_data(req, struct tstream_roh_disconnect_state);
734 stream = state->stream;
735 roh_stream = tstream_context_data(stream, struct tstream_roh_context);
737 ret = tstream_disconnect_recv(subreq, &sys_errno);
740 tevent_req_error(req, sys_errno);
743 TALLOC_FREE(roh_stream->roh_conn->default_channel_in);
745 subreq = tstream_disconnect_send(state,
747 roh_stream->roh_conn->default_channel_out->streams.raw);
748 if (tevent_req_nomem(subreq, req)) {
751 tevent_req_set_callback(subreq, tstream_roh_disconnect_channel_out_handler, req);
756 static void tstream_roh_disconnect_channel_out_handler(struct tevent_req *subreq)
758 struct tevent_req *req;
759 struct tstream_roh_disconnect_state *state;
760 struct tstream_context *stream;
761 struct tstream_roh_context *roh_stream;
765 req = tevent_req_callback_data(subreq, struct tevent_req);
766 state = tevent_req_data(req, struct tstream_roh_disconnect_state);
767 stream = state->stream;
768 roh_stream = tstream_context_data(stream, struct tstream_roh_context);
770 ret = tstream_disconnect_recv(subreq, &sys_errno);
773 tevent_req_error(req, sys_errno);
776 TALLOC_FREE(roh_stream->roh_conn->default_channel_out);
778 tevent_req_done(req);
781 static int tstream_roh_disconnect_recv(struct tevent_req *req, int *perrno)
785 ret = tsocket_simple_int_recv(req, perrno);
786 tevent_req_received(req);