2 Unix SMB/CIFS implementation.
4 [MS-RPCH] - RPC over HTTP client
6 Copyright (C) 2013 Samuel Cabrero <samuelcabrero@kernevil.me>
7 Copyright (C) Julien Kerihuel <j.kerihuel@openchange.org> 2013
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "lib/tsocket/tsocket.h"
27 #include "lib/tls/tls.h"
28 #include "lib/util/tevent_ntstatus.h"
29 #include "lib/util/util_net.h"
30 #include "libcli/resolve/resolve.h"
31 #include "libcli/composite/composite.h"
32 #include "auth/credentials/credentials.h"
33 #include "auth/credentials/credentials_internal.h"
34 #include <gen_ndr/dcerpc.h>
35 #include <gen_ndr/ndr_dcerpc.h>
37 #include "librpc/rpc/dcerpc.h"
38 #include "librpc/rpc/dcerpc_roh.h"
39 #include "librpc/rpc/dcerpc_proto.h"
40 #include "lib/http/http.h"
42 struct roh_connect_channel_state
{
43 struct tevent_context
*ev
;
44 struct tsocket_address
*local_address
;
45 struct tsocket_address
*remote_address
;
46 struct cli_credentials
*credentials
;
47 struct roh_connection
*roh
;
49 struct tstream_tls_params
*tls_params
;
52 static void roh_connect_channel_out_done(struct tevent_req
*subreq
);
53 struct tevent_req
*roh_connect_channel_out_send(TALLOC_CTX
*mem_ctx
,
54 struct tevent_context
*ev
,
55 const char *rpcproxy_ip_address
,
56 unsigned int rpcproxy_port
,
57 struct cli_credentials
*credentials
,
58 struct roh_connection
*roh
,
60 struct tstream_tls_params
*tls_params
)
63 struct tevent_req
*req
;
64 struct tevent_req
*subreq
;
65 struct roh_connect_channel_state
*state
;
68 DEBUG(8, ("%s: Connecting channel out socket, RPC proxy is %s:%d (TLS: %s)\n",
69 __func__
, rpcproxy_ip_address
, rpcproxy_port
,
70 (tls
? "true" : "false")));
72 req
= tevent_req_create(mem_ctx
, &state
, struct roh_connect_channel_state
);
77 if (!is_ipaddress(rpcproxy_ip_address
)) {
78 DEBUG(0, ("%s: Invalid host (%s), needs to be an IP address\n",
79 __func__
, rpcproxy_ip_address
));
80 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
81 return tevent_req_post(req
, ev
);
85 state
->credentials
= credentials
;
88 state
->tls_params
= tls_params
;
89 ret
= tsocket_address_inet_from_strings(state
, "ip", NULL
, 0,
90 &state
->local_address
);
92 DEBUG(0, ("%s: Cannot create local socket address, error: %s (%d)\n",
93 __func__
, strerror(errno
), errno
));
94 status
= map_nt_error_from_unix_common(errno
);
95 tevent_req_nterror(req
, status
);
96 return tevent_req_post(req
, ev
);
99 ret
= tsocket_address_inet_from_strings(state
, "ip",
102 &state
->remote_address
);
104 DEBUG(0, ("%s: Cannot create remote socket address, error: %s (%d)\n",
105 __func__
, strerror(errno
), errno
));
106 status
= map_nt_error_from_unix_common(errno
);
107 tevent_req_nterror(req
, status
);
108 return tevent_req_post(req
, ev
);
111 /* Initialize channel structure */
112 state
->roh
->default_channel_out
= talloc_zero(roh
, struct roh_channel
);
113 if (tevent_req_nomem(state
->roh
->default_channel_out
, req
)) {
114 return tevent_req_post(req
, ev
);
117 state
->roh
->default_channel_out
->send_queue
=
118 tevent_queue_create(state
->roh
->default_channel_out
,
119 "RoH OUT virtual channel send queue");
120 if (tevent_req_nomem(state
->roh
->default_channel_out
->send_queue
, req
)) {
121 return tevent_req_post(req
, ev
);
124 state
->roh
->default_channel_out
->channel_cookie
= GUID_random();
125 subreq
= tstream_inet_tcp_connect_send(state
, ev
, state
->local_address
,
126 state
->remote_address
);
127 if (tevent_req_nomem(subreq
, req
)) {
128 return tevent_req_post(req
, ev
);
130 tevent_req_set_callback(subreq
, roh_connect_channel_out_done
, req
);
135 static void roh_connect_channel_out_tls_done(struct tevent_req
*subreq
);
136 static void roh_connect_channel_out_done(struct tevent_req
*subreq
)
139 struct tevent_req
*req
;
140 struct roh_connect_channel_state
*state
;
144 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
145 state
= tevent_req_data(req
, struct roh_connect_channel_state
);
146 ret
= tstream_inet_tcp_connect_recv(subreq
, &sys_errno
, state
,
147 &state
->roh
->default_channel_out
->streams
.raw
,
149 talloc_steal(state
->roh
->default_channel_out
,
150 state
->roh
->default_channel_out
->streams
.raw
);
151 state
->roh
->default_channel_out
->streams
.active
= state
->roh
->default_channel_out
->streams
.raw
;
154 status
= map_nt_error_from_unix_common(sys_errno
);
155 tevent_req_nterror(req
, status
);
159 DEBUG(8, ("%s: Socket connected\n", __func__
));
161 DEBUG(8, ("%s: Starting TLS handshake\n", __func__
));
162 subreq
= _tstream_tls_connect_send(state
,
164 state
->roh
->default_channel_out
->streams
.raw
,
167 if (tevent_req_nomem(subreq
, req
)) {
170 tevent_req_set_callback(subreq
, roh_connect_channel_out_tls_done
, req
);
174 tevent_req_done(req
);
177 static void roh_connect_channel_out_tls_done(struct tevent_req
*subreq
)
180 struct tevent_req
*req
;
181 struct roh_connect_channel_state
*state
;
185 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
186 state
= tevent_req_data(req
, struct roh_connect_channel_state
);
187 ret
= tstream_tls_connect_recv(subreq
, &sys_errno
, state
,
188 &state
->roh
->default_channel_out
->streams
.tls
);
189 talloc_steal(state
->roh
->default_channel_out
,
190 state
->roh
->default_channel_out
->streams
.tls
);
191 state
->roh
->default_channel_out
->streams
.active
= state
->roh
->default_channel_out
->streams
.tls
;
194 status
= map_nt_error_from_unix_common(sys_errno
);
195 tevent_req_nterror(req
, status
);
198 DEBUG(8, ("%s: TLS handshake completed\n", __func__
));
200 tevent_req_done(req
);
203 NTSTATUS
roh_connect_channel_out_recv(struct tevent_req
*req
)
207 if (tevent_req_is_nterror(req
, &status
)) {
208 tevent_req_received(req
);
212 tevent_req_received(req
);
216 struct roh_request_state
{
217 struct http_request
*request
;
218 struct http_request
*response
;
221 static void roh_send_RPC_DATA_OUT_done(struct tevent_req
*subreq
);
222 struct tevent_req
*roh_send_RPC_DATA_OUT_send(TALLOC_CTX
*mem_ctx
,
223 struct loadparm_context
*lp_ctx
,
224 struct tevent_context
*ev
,
225 struct cli_credentials
*credentials
,
226 struct roh_connection
*roh
,
227 const char *rpc_server
,
228 uint32_t rpc_server_port
,
229 const char *rpc_proxy
,
232 struct tevent_req
*req
;
233 struct tevent_req
*subreq
;
234 struct roh_request_state
*state
;
239 DEBUG(8, ("%s: Sending RPC_OUT_DATA request\n", __func__
));
241 req
= tevent_req_create(mem_ctx
, &state
, struct roh_request_state
);
246 state
->request
= talloc_zero(state
, struct http_request
);
247 if (tevent_req_nomem(state
->request
, req
)) {
248 return tevent_req_post(req
, ev
);
251 /* Build URI, as specified in section 2.2.2 */
252 query
= talloc_asprintf(state
, "%s:%d", rpc_server
, rpc_server_port
);
253 if (tevent_req_nomem(query
, req
)) {
254 return tevent_req_post(req
, ev
);
258 * TODO This path changes to "/rpcwithcert/rpcproxy.dll" when using
261 path
= "/rpc/rpcproxy.dll";
262 uri
= talloc_asprintf(state
, "%s?%s", path
, query
);
263 if (tevent_req_nomem(uri
, req
)) {
264 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
265 return tevent_req_post(req
, ev
);
270 * Create the HTTP channel OUT request as specified in the
273 state
->request
->type
= HTTP_REQ_RPC_OUT_DATA
;
274 state
->request
->uri
= uri
;
275 state
->request
->body
.length
= 0;
276 state
->request
->body
.data
= NULL
;
277 state
->request
->major
= '1';
278 state
->request
->minor
= '0';
280 http_add_header(state
, &state
->request
->headers
,
281 "Accept", "application/rpc");
282 http_add_header(state
, &state
->request
->headers
,
283 "User-Agent", "MSRPC");
284 http_add_header(state
, &state
->request
->headers
,
286 http_add_header(state
, &state
->request
->headers
,
287 "Connection", "keep-alive");
288 http_add_header(state
, &state
->request
->headers
,
289 "Content-Length", "76");
290 http_add_header(state
, &state
->request
->headers
,
291 "Cache-Control", "no-cache");
292 http_add_header(state
, &state
->request
->headers
,
293 "Pragma", "no-cache");
295 subreq
= http_send_auth_request_send(state
,
297 roh
->default_channel_out
->streams
.active
,
298 roh
->default_channel_out
->send_queue
,
303 if (tevent_req_nomem(subreq
, req
)) {
304 return tevent_req_post(req
, ev
);
306 tevent_req_set_callback(subreq
, roh_send_RPC_DATA_OUT_done
, req
);
311 static void roh_send_RPC_DATA_OUT_done(struct tevent_req
*subreq
)
314 struct tevent_req
*req
;
316 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
318 /* Receive the sent bytes to check if request has been properly sent */
319 status
= http_send_auth_request_recv(subreq
);
321 if (tevent_req_nterror(req
, status
)) {
325 DEBUG(8, ("%s: RPC_OUT_DATA sent", __func__
));
327 tevent_req_done(req
);
330 NTSTATUS
roh_send_RPC_DATA_OUT_recv(struct tevent_req
*req
)
334 if (tevent_req_is_nterror(req
, &status
)) {
335 tevent_req_received(req
);
339 tevent_req_received(req
);
343 struct roh_send_pdu_state
{
350 static void roh_send_CONN_A1_done(struct tevent_req
*subreq
);
351 struct tevent_req
*roh_send_CONN_A1_send(TALLOC_CTX
*mem_ctx
,
352 struct tevent_context
*ev
,
353 struct roh_connection
*roh
)
355 struct tevent_req
*req
;
356 struct tevent_req
*subreq
;
357 struct roh_send_pdu_state
*state
;
358 struct dcerpc_rts rts
;
359 struct ncacn_packet pkt
;
360 struct ndr_push
*ndr
;
362 DEBUG(8, ("%s: Sending CONN/A1 request\n", __func__
));
364 req
= tevent_req_create(mem_ctx
, &state
, struct roh_send_pdu_state
);
369 rts
.Flags
= RTS_FLAG_NONE
;
370 rts
.NumberOfCommands
= 4;
371 rts
.Commands
= talloc_array(state
, struct dcerpc_rts_cmd
, 4);
373 /* CONN/A1: Version RTS command */
374 rts
.Commands
[0].CommandType
= 0x00000006;
375 rts
.Commands
[0].Command
.Version
.Version
= 0x00000001;
377 /* CONN/A1: VirtualConnectionCookie RTS command */
378 rts
.Commands
[1].CommandType
= 0x00000003;
379 rts
.Commands
[1].Command
.Cookie
.Cookie
.Cookie
= roh
->connection_cookie
;
381 /* CONN/A1: OutChannelCookie RTS command */
382 rts
.Commands
[2].CommandType
= 0x00000003;
383 rts
.Commands
[2].Command
.Cookie
.Cookie
.Cookie
=
384 roh
->default_channel_out
->channel_cookie
;
386 /* CONN/A1: ReceiveWindowSize */
387 rts
.Commands
[3].CommandType
= 0x00000000;
388 rts
.Commands
[3].Command
.ReceiveWindowSize
.ReceiveWindowSize
= 0x40000;
391 pkt
.rpc_vers_minor
= 0;
392 pkt
.ptype
= DCERPC_PKT_RTS
;
393 pkt
.pfc_flags
= DCERPC_PFC_FLAG_LAST
| DCERPC_PFC_FLAG_FIRST
;
394 pkt
.drep
[0] = DCERPC_DREP_LE
;
398 pkt
.frag_length
= 76;
403 ndr
= ndr_push_init_ctx(state
);
405 ndr_push_ncacn_packet(ndr
, NDR_SCALARS
, &pkt
);
407 state
->buffer
= ndr_push_blob(ndr
);
408 state
->iov
.iov_base
= (char *) state
->buffer
.data
;
409 state
->iov
.iov_len
= state
->buffer
.length
;
411 subreq
= tstream_writev_queue_send(mem_ctx
,
413 roh
->default_channel_out
->streams
.active
,
414 roh
->default_channel_out
->send_queue
,
417 if (tevent_req_nomem(subreq
, req
)) {
418 return tevent_req_post(req
, ev
);
420 tevent_req_set_callback(subreq
, roh_send_CONN_A1_done
, req
);
425 static void roh_send_CONN_A1_done(struct tevent_req
*subreq
)
428 struct tevent_req
*req
;
429 struct roh_send_pdu_state
*state
;
432 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
433 state
= tevent_req_data(req
, struct roh_send_pdu_state
);
435 state
->bytes_written
= tstream_writev_queue_recv(subreq
, &sys_errno
);
436 state
->sys_errno
= sys_errno
;
438 if (state
->bytes_written
<= 0 && sys_errno
!= 0) {
439 status
= map_nt_error_from_unix_common(sys_errno
);
440 tevent_req_nterror(req
, status
);
443 DEBUG(8, ("%s: CONN/A1 sent (%d bytes written)\n",
444 __func__
, state
->bytes_written
));
446 tevent_req_done(req
);
449 NTSTATUS
roh_send_CONN_A1_recv(struct tevent_req
*req
)
453 if (tevent_req_is_nterror(req
, &status
)) {
454 tevent_req_received(req
);
458 tevent_req_received(req
);
462 struct roh_recv_response_state
464 struct http_request
*response
;
467 static void roh_recv_out_channel_response_done(struct tevent_req
*);
468 struct tevent_req
*roh_recv_out_channel_response_send(TALLOC_CTX
*mem_ctx
,
469 struct tevent_context
*ev
,
470 struct roh_connection
*roh
)
472 struct tevent_req
*req
;
473 struct tevent_req
*subreq
;
474 struct roh_recv_response_state
*state
;
476 DEBUG(8, ("%s: Waiting for RPC_OUT_DATA response\n", __func__
));
478 req
= tevent_req_create(mem_ctx
, &state
, struct roh_recv_response_state
);
483 subreq
= http_read_response_send(state
, ev
,
484 roh
->default_channel_out
->streams
.active
,
485 0); /* we'll get the content later */
486 if (tevent_req_nomem(subreq
, req
)) {
487 return tevent_req_post(req
, ev
);
489 tevent_req_set_callback(subreq
, roh_recv_out_channel_response_done
, req
);
494 static void roh_recv_out_channel_response_done(struct tevent_req
*subreq
)
497 struct tevent_req
*req
;
498 struct roh_recv_response_state
*state
;
500 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
501 state
= tevent_req_data(req
, struct roh_recv_response_state
);
502 status
= http_read_response_recv(subreq
, state
, &state
->response
);
504 if (tevent_req_nterror(req
, status
)) {
508 DEBUG(8, ("%s: RCP_OUT_DATA response received\n", __func__
));
510 /* TODO Map response code to nt error */
511 switch (state
->response
->response_code
) {
515 DEBUG(0, ("%s: Server response: Access denied\n", __func__
));
516 tevent_req_nterror(req
, NT_STATUS_ACCESS_DENIED
);
519 /* TODO Decode error info as specified in section 2.1.2.1.3 */
520 DEBUG(0, ("%s: Server response: RPC error\n", __func__
));
521 tevent_req_nterror(req
, NT_STATUS_GENERIC_NOT_MAPPED
);
524 DEBUG(0, ("%s: Server response: Unknown error\n", __func__
));
525 tevent_req_nterror(req
, NT_STATUS_GENERIC_NOT_MAPPED
);
529 tevent_req_done(req
);
532 NTSTATUS
roh_recv_out_channel_response_recv(struct tevent_req
*req
,
538 if (tevent_req_is_nterror(req
, &status
)) {
539 tevent_req_received(req
);
543 tevent_req_received(req
);
547 struct roh_recv_pdu_state
{
548 struct roh_connection
*roh
;
549 uint32_t connection_timeout
;
551 uint32_t recv_window_size
;
554 static void roh_recv_CONN_A3_done(struct tevent_req
*subreq
);
555 struct tevent_req
*roh_recv_CONN_A3_send(TALLOC_CTX
*mem_ctx
,
556 struct tevent_context
*ev
,
557 struct roh_connection
*roh
)
559 struct tevent_req
*req
;
560 struct tevent_req
*subreq
;
561 struct roh_recv_pdu_state
*state
;
563 req
= tevent_req_create(mem_ctx
, &state
, struct roh_recv_pdu_state
);
568 DEBUG(8, ("%s: Waiting for CONN/A3\n", __func__
));
569 subreq
= dcerpc_read_ncacn_packet_send(state
, ev
,
570 roh
->default_channel_out
->streams
.active
);
571 if (tevent_req_nomem(subreq
, req
)) {
572 return tevent_req_post(req
, ev
);
574 tevent_req_set_callback(subreq
, roh_recv_CONN_A3_done
, req
);
579 static void roh_recv_CONN_A3_done(struct tevent_req
*subreq
)
582 struct tevent_req
*req
;
583 struct roh_recv_pdu_state
*state
;
584 struct ncacn_packet
*pkt
;
586 struct dcerpc_rts rts
;
588 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
589 state
= tevent_req_data(req
, struct roh_recv_pdu_state
);
590 status
= dcerpc_read_ncacn_packet_recv(subreq
, state
, &pkt
, &buffer
);
593 if (tevent_req_nterror(req
, status
)) {
594 DEBUG(0, ("%s: Error receiving PDU\n", __func__
));
599 * Check if it is a CONN/A3 (2.2.4.4) packet and get the connection
603 if (rts
.NumberOfCommands
!= 1) {
604 DEBUG(0, ("%s: Invalid number of commands received\n", __func__
));
605 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
609 if (rts
.Commands
[0].CommandType
!= ROH_CMD_TYPE_CONNECTION_TIMEOUT
) {
610 DEBUG(0, ("%s: Invalid command type received\n", __func__
));
611 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
615 /* Extract connection timeout */
616 state
->connection_timeout
= rts
.Commands
[0].Command
.ConnectionTimeout
.ConnectionTimeout
;
618 DEBUG(8, ("%s: CONN/A3 received, connection timeout is %u\n",
619 __func__
, state
->connection_timeout
));
620 tevent_req_done(req
);
623 NTSTATUS
roh_recv_CONN_A3_recv(struct tevent_req
*req
,
624 unsigned int *connection_timeout
)
627 struct roh_recv_pdu_state
*state
;
629 state
= tevent_req_data(req
, struct roh_recv_pdu_state
);
630 if (tevent_req_is_nterror(req
, &status
)) {
631 tevent_req_received(req
);
635 *connection_timeout
= state
->connection_timeout
;
637 tevent_req_received(req
);
641 static void roh_recv_CONN_C2_done(struct tevent_req
*subreq
);
642 struct tevent_req
*roh_recv_CONN_C2_send(TALLOC_CTX
*mem_ctx
,
643 struct tevent_context
*ev
,
644 struct roh_connection
*roh
)
646 struct tevent_req
*req
;
647 struct tevent_req
*subreq
;
648 struct roh_recv_pdu_state
*state
;
650 req
= tevent_req_create(mem_ctx
, &state
, struct roh_recv_pdu_state
);
655 DEBUG(8, ("%s: Waiting for CONN/C2\n", __func__
));
656 subreq
= dcerpc_read_ncacn_packet_send(state
, ev
,
657 roh
->default_channel_out
->streams
.active
);
658 if (tevent_req_nomem(subreq
, req
)) {
659 return tevent_req_post(req
, ev
);
661 tevent_req_set_callback(subreq
, roh_recv_CONN_C2_done
, req
);
666 static void roh_recv_CONN_C2_done(struct tevent_req
*subreq
)
669 struct tevent_req
*req
;
670 struct roh_recv_pdu_state
*state
;
671 struct ncacn_packet
*pkt
;
673 struct dcerpc_rts rts
;
675 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
676 state
= tevent_req_data(req
, struct roh_recv_pdu_state
);
678 status
= dcerpc_read_ncacn_packet_recv(subreq
, state
, &pkt
, &buffer
);
680 if (tevent_req_nterror(req
, status
)) {
681 DEBUG(0, ("%s: Error receiving PDU\n", __func__
));
686 * Check if it is a CONN/C2 packet (2.2.4.9), and get the version, the
687 * receive windows size and the connection timeout for the IN channel
690 if (rts
.NumberOfCommands
!= 3) {
691 DEBUG(0, ("%s: Invalid number of commands received\n",
693 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
696 if (rts
.Commands
[0].CommandType
!= ROH_CMD_TYPE_VERSION
) {
697 DEBUG(0, ("%s: Invalid command type received\n", __func__
));
698 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
701 if (rts
.Commands
[1].CommandType
!= ROH_CMD_TYPE_RECV_WINDOWS_SIZE
) {
702 DEBUG(0, ("%s: Invalid command type received\n", __func__
));
703 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
706 if (rts
.Commands
[2].CommandType
!= ROH_CMD_TYPE_CONNECTION_TIMEOUT
) {
707 DEBUG(0, ("%s: Invalid command type received\n", __func__
));
708 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
713 state
->version
= rts
.Commands
[0].Command
.Version
.Version
;
714 state
->recv_window_size
= rts
.Commands
[1].Command
.ReceiveWindowSize
.ReceiveWindowSize
;
715 state
->connection_timeout
= rts
.Commands
[2].Command
.ConnectionTimeout
.ConnectionTimeout
;
717 DEBUG(8, ("%s: CONN/C2 received, version is %u, receive windows size is %u, connection timeout is %u\n",
718 __func__
, state
->version
, state
->recv_window_size
,
719 state
->connection_timeout
));
720 tevent_req_done(req
);
723 NTSTATUS
roh_recv_CONN_C2_recv(struct tevent_req
*req
,
724 unsigned int *version
,
725 unsigned int *recv_window_size
,
726 unsigned int *connection_timeout
)
729 struct roh_recv_pdu_state
*state
;
731 if (tevent_req_is_nterror(req
, &status
)) {
732 tevent_req_received(req
);
736 state
= tevent_req_data(req
, struct roh_recv_pdu_state
);
737 *version
= state
->version
;
738 *recv_window_size
= state
->recv_window_size
;
739 *connection_timeout
= state
->connection_timeout
;
741 tevent_req_received(req
);