2 Unix SMB/CIFS implementation.
4 dcerpc over standard sockets transport
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Jelmer Vernooij 2004
8 Copyright (C) Rafal Szczesniak 2006
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "lib/events/events.h"
27 #include "lib/socket/socket.h"
28 #include "lib/stream/packet.h"
29 #include "libcli/composite/composite.h"
30 #include "librpc/rpc/dcerpc.h"
32 /* transport private information used by general socket pipe transports */
35 struct socket_context
*sock
;
38 struct packet_context
*packet
;
39 uint32_t pending_reads
;
46 static void sock_dead(struct dcerpc_connection
*p
, NTSTATUS status
)
48 struct sock_private
*sock
= p
->transport
.private;
50 if (sock
&& sock
->sock
!= NULL
) {
51 talloc_free(sock
->fde
);
52 talloc_free(sock
->sock
);
56 if (!NT_STATUS_IS_OK(status
)) {
57 p
->transport
.recv_data(p
, NULL
, status
);
63 handle socket recv errors
65 static void sock_error_handler(void *private, NTSTATUS status
)
67 struct dcerpc_connection
*p
= talloc_get_type(private,
68 struct dcerpc_connection
);
73 check if a blob is a complete packet
75 static NTSTATUS
sock_complete_packet(void *private, DATA_BLOB blob
, size_t *size
)
77 if (blob
.length
< DCERPC_FRAG_LEN_OFFSET
+2) {
78 return STATUS_MORE_ENTRIES
;
80 *size
= dcerpc_get_frag_length(&blob
);
81 if (*size
> blob
.length
) {
82 return STATUS_MORE_ENTRIES
;
90 static NTSTATUS
sock_process_recv(void *private, DATA_BLOB blob
)
92 struct dcerpc_connection
*p
= talloc_get_type(private,
93 struct dcerpc_connection
);
94 struct sock_private
*sock
= p
->transport
.private;
95 sock
->pending_reads
--;
96 if (sock
->pending_reads
== 0) {
97 packet_recv_disable(sock
->packet
);
99 p
->transport
.recv_data(p
, &blob
, NT_STATUS_OK
);
104 called when a IO is triggered by the events system
106 static void sock_io_handler(struct event_context
*ev
, struct fd_event
*fde
,
107 uint16_t flags
, void *private)
109 struct dcerpc_connection
*p
= talloc_get_type(private,
110 struct dcerpc_connection
);
111 struct sock_private
*sock
= p
->transport
.private;
113 if (flags
& EVENT_FD_WRITE
) {
114 packet_queue_run(sock
->packet
);
118 if (sock
->sock
== NULL
) {
122 if (flags
& EVENT_FD_READ
) {
123 packet_recv(sock
->packet
);
128 initiate a read request - not needed for dcerpc sockets
130 static NTSTATUS
sock_send_read(struct dcerpc_connection
*p
)
132 struct sock_private
*sock
= p
->transport
.private;
133 sock
->pending_reads
++;
134 if (sock
->pending_reads
== 1) {
135 packet_recv_enable(sock
->packet
);
141 send an initial pdu in a multi-pdu sequence
143 static NTSTATUS
sock_send_request(struct dcerpc_connection
*p
, DATA_BLOB
*data
,
146 struct sock_private
*sock
= p
->transport
.private;
150 if (sock
->sock
== NULL
) {
151 return NT_STATUS_CONNECTION_DISCONNECTED
;
154 blob
= data_blob_talloc(sock
->packet
, data
->data
, data
->length
);
155 if (blob
.data
== NULL
) {
156 return NT_STATUS_NO_MEMORY
;
159 status
= packet_send(sock
->packet
, blob
);
160 if (!NT_STATUS_IS_OK(status
)) {
172 shutdown sock pipe connection
174 static NTSTATUS
sock_shutdown_pipe(struct dcerpc_connection
*p
)
176 struct sock_private
*sock
= p
->transport
.private;
178 if (sock
&& sock
->sock
) {
179 sock_dead(p
, NT_STATUS_OK
);
186 return sock server name
188 static const char *sock_peer_name(struct dcerpc_connection
*p
)
190 struct sock_private
*sock
= talloc_get_type(p
->transport
.private, struct sock_private
);
191 return sock
->server_name
;
195 return remote name we make the actual connection (good for kerberos)
197 static const char *sock_target_hostname(struct dcerpc_connection
*p
)
199 struct sock_private
*sock
= talloc_get_type(p
->transport
.private, struct sock_private
);
200 return sock
->server_name
;
204 struct pipe_open_socket_state
{
205 struct dcerpc_connection
*conn
;
206 struct socket_context
*socket_ctx
;
207 struct sock_private
*sock
;
208 struct socket_address
*server
;
209 const char *target_hostname
;
210 enum dcerpc_transport_t transport
;
214 static void continue_socket_connect(struct composite_context
*ctx
)
216 struct dcerpc_connection
*conn
;
217 struct sock_private
*sock
;
218 struct composite_context
*c
= talloc_get_type(ctx
->async
.private_data
,
219 struct composite_context
);
220 struct pipe_open_socket_state
*s
= talloc_get_type(c
->private_data
,
221 struct pipe_open_socket_state
);
223 /* make it easier to write a function calls */
227 c
->status
= socket_connect_recv(ctx
);
228 if (!NT_STATUS_IS_OK(c
->status
)) {
229 DEBUG(0, ("Failed to connect host %s on port %d - %s\n",
230 s
->server
->addr
, s
->server
->port
,
231 nt_errstr(c
->status
)));
232 composite_error(c
, c
->status
);
237 fill in the transport methods
239 conn
->transport
.transport
= s
->transport
;
240 conn
->transport
.private = NULL
;
242 conn
->transport
.send_request
= sock_send_request
;
243 conn
->transport
.send_read
= sock_send_read
;
244 conn
->transport
.recv_data
= NULL
;
246 conn
->transport
.shutdown_pipe
= sock_shutdown_pipe
;
247 conn
->transport
.peer_name
= sock_peer_name
;
248 conn
->transport
.target_hostname
= sock_target_hostname
;
250 sock
->sock
= s
->socket_ctx
;
251 sock
->pending_reads
= 0;
252 sock
->server_name
= strupper_talloc(sock
, s
->target_hostname
);
254 sock
->fde
= event_add_fd(conn
->event_ctx
, sock
->sock
, socket_get_fd(sock
->sock
),
255 0, sock_io_handler
, conn
);
257 conn
->transport
.private = sock
;
259 sock
->packet
= packet_init(sock
);
260 if (sock
->packet
== NULL
) {
261 composite_error(c
, NT_STATUS_NO_MEMORY
);
266 packet_set_private(sock
->packet
, conn
);
267 packet_set_socket(sock
->packet
, sock
->sock
);
268 packet_set_callback(sock
->packet
, sock_process_recv
);
269 packet_set_full_request(sock
->packet
, sock_complete_packet
);
270 packet_set_error_handler(sock
->packet
, sock_error_handler
);
271 packet_set_event_context(sock
->packet
, conn
->event_ctx
);
272 packet_set_fde(sock
->packet
, sock
->fde
);
273 packet_set_serialise(sock
->packet
);
274 packet_recv_disable(sock
->packet
);
275 packet_set_initial_read(sock
->packet
, 16);
277 /* ensure we don't get SIGPIPE */
278 BlockSignals(True
,SIGPIPE
);
284 struct composite_context
*dcerpc_pipe_open_socket_send(TALLOC_CTX
*mem_ctx
,
285 struct dcerpc_connection
*cn
,
286 struct socket_address
*server
,
287 const char *target_hostname
,
288 enum dcerpc_transport_t transport
)
290 struct composite_context
*c
;
291 struct pipe_open_socket_state
*s
;
292 struct composite_context
*conn_req
;
294 c
= composite_create(mem_ctx
, cn
->event_ctx
);
295 if (c
== NULL
) return NULL
;
297 s
= talloc_zero(c
, struct pipe_open_socket_state
);
298 if (composite_nomem(s
, c
)) return c
;
302 s
->transport
= transport
;
303 s
->server
= talloc_reference(c
, server
);
304 if (composite_nomem(s
->server
, c
)) return c
;
305 s
->target_hostname
= talloc_reference(s
, target_hostname
);
307 s
->sock
= talloc(cn
, struct sock_private
);
308 if (composite_nomem(s
->sock
, c
)) return c
;
310 c
->status
= socket_create(server
->family
, SOCKET_TYPE_STREAM
, &s
->socket_ctx
, 0);
311 if (!composite_is_ok(c
)) return c
;
313 talloc_steal(s
->sock
, s
->socket_ctx
);
315 conn_req
= socket_connect_send(s
->socket_ctx
, NULL
, s
->server
, 0, c
->event_ctx
);
316 composite_continue(c
, conn_req
, continue_socket_connect
, c
);
321 NTSTATUS
dcerpc_pipe_open_socket_recv(struct composite_context
*c
)
323 NTSTATUS status
= composite_wait(c
);
330 open a rpc connection using the generic socket library
332 NTSTATUS
dcerpc_pipe_open_socket(struct dcerpc_connection
*conn
,
333 struct socket_address
*server
,
334 const char *target_hostname
,
335 enum dcerpc_transport_t transport
)
337 struct composite_context
*c
;
339 c
= dcerpc_pipe_open_socket_send(conn
, conn
, server
, target_hostname
, transport
);
340 return dcerpc_pipe_open_socket_recv(c
);
344 struct pipe_tcp_state
{
345 const char *target_hostname
;
348 struct socket_address
*srvaddr
;
349 struct dcerpc_connection
*conn
;
353 void continue_ipv6_open_socket(struct composite_context
*ctx
);
354 void continue_ipv4_open_socket(struct composite_context
*ctx
);
358 Stage 2 of dcerpc_pipe_open_tcp_send: receive result of pipe open request
359 on IPv6 and send the request on IPv4 unless IPv6 transport succeeded.
361 void continue_ipv6_open_socket(struct composite_context
*ctx
)
363 struct composite_context
*c
= talloc_get_type(ctx
->async
.private_data
,
364 struct composite_context
);
365 struct pipe_tcp_state
*s
= talloc_get_type(c
->private_data
,
366 struct pipe_tcp_state
);
367 struct composite_context
*sock_ipv4_req
;
369 /* receive result of socket open request */
370 c
->status
= dcerpc_pipe_open_socket_recv(ctx
);
371 if (NT_STATUS_IS_OK(c
->status
)) {
376 talloc_free(s
->srvaddr
);
378 /* prepare server address using host:ip and transport name */
379 s
->srvaddr
= socket_address_from_strings(s
->conn
, "ipv4", s
->address
, s
->port
);
380 if (composite_nomem(s
->srvaddr
, c
)) return;
382 /* try IPv4 if IPv6 fails */
383 sock_ipv4_req
= dcerpc_pipe_open_socket_send(c
, s
->conn
,
384 s
->srvaddr
, s
->target_hostname
,
386 composite_continue(c
, sock_ipv4_req
, continue_ipv4_open_socket
, c
);
391 Stage 2 of dcerpc_pipe_open_tcp_send: receive result of pipe open request
394 void continue_ipv4_open_socket(struct composite_context
*ctx
)
396 struct composite_context
*c
= talloc_get_type(ctx
->async
.private_data
,
397 struct composite_context
);
398 struct pipe_tcp_state
*s
= talloc_get_type(c
->private_data
,
399 struct pipe_tcp_state
);
401 /* receive result socket open request */
402 c
->status
= dcerpc_pipe_open_socket_recv(ctx
);
403 if (!NT_STATUS_IS_OK(c
->status
)) {
404 /* something went wrong... */
405 DEBUG(0, ("Failed to connect host %s (%s) on port %d - %s.\n",
406 s
->address
, s
->target_hostname
,
407 s
->port
, nt_errstr(c
->status
)));
409 composite_error(c
, c
->status
);
418 Send rpc pipe open request to given host:port using
421 struct composite_context
* dcerpc_pipe_open_tcp_send(struct dcerpc_connection
*conn
,
423 const char *target_hostname
,
426 struct composite_context
*c
;
427 struct composite_context
*sock_ipv6_req
;
428 struct pipe_tcp_state
*s
;
430 /* composite context allocation and setup */
431 c
= composite_create(conn
, conn
->event_ctx
);
432 if (c
== NULL
) return NULL
;
434 s
= talloc_zero(c
, struct pipe_tcp_state
);
435 if (composite_nomem(s
, c
)) return c
;
438 /* store input parameters in state structure */
439 s
->address
= talloc_strdup(c
, address
);
440 s
->target_hostname
= talloc_strdup(c
, target_hostname
);
444 /* prepare server address using host ip:port and transport name */
445 s
->srvaddr
= socket_address_from_strings(s
->conn
, "ipv6", address
, s
->port
);
446 if (composite_nomem(s
->srvaddr
, c
)) return c
;
448 /* try IPv6 first - send socket open request */
449 sock_ipv6_req
= dcerpc_pipe_open_socket_send(c
, s
->conn
,
450 s
->srvaddr
, s
->target_hostname
,
452 composite_continue(c
, sock_ipv6_req
, continue_ipv6_open_socket
, c
);
458 Receive result of pipe open request on tcp/ip
460 NTSTATUS
dcerpc_pipe_open_tcp_recv(struct composite_context
*c
)
463 status
= composite_wait(c
);
471 Open rpc pipe on tcp/ip transport - sync version
473 NTSTATUS
dcerpc_pipe_open_tcp(struct dcerpc_connection
*conn
, const char *server
,
474 const char *target_hostname
,
477 struct composite_context
*c
;
479 c
= dcerpc_pipe_open_tcp_send(conn
, server
, target_hostname
, port
);
480 return dcerpc_pipe_open_tcp_recv(c
);
484 struct pipe_unix_state
{
486 struct socket_address
*srvaddr
;
487 struct dcerpc_connection
*conn
;
492 Stage 2 of dcerpc_pipe_open_unix_stream_send: receive result of pipe open
493 request on unix socket.
495 void continue_unix_open_socket(struct composite_context
*ctx
)
497 struct composite_context
*c
= talloc_get_type(ctx
->async
.private_data
,
498 struct composite_context
);
500 c
->status
= dcerpc_pipe_open_socket_recv(ctx
);
501 if (NT_STATUS_IS_OK(c
->status
)) {
506 composite_error(c
, c
->status
);
511 Send pipe open request on unix socket
513 struct composite_context
*dcerpc_pipe_open_unix_stream_send(struct dcerpc_connection
*conn
,
516 struct composite_context
*c
;
517 struct composite_context
*sock_unix_req
;
518 struct pipe_unix_state
*s
;
520 /* composite context allocation and setup */
521 c
= composite_create(conn
, conn
->event_ctx
);
522 if (c
== NULL
) return NULL
;
524 s
= talloc_zero(c
, struct pipe_unix_state
);
525 if (composite_nomem(s
, c
)) return c
;
528 /* store parameters in state structure */
529 s
->path
= talloc_strdup(c
, path
);
530 if (composite_nomem(s
->path
, c
)) return c
;
533 /* prepare server address using socket path and transport name */
534 s
->srvaddr
= socket_address_from_strings(conn
, "unix", s
->path
, 0);
535 if (composite_nomem(s
->srvaddr
, c
)) return c
;
537 /* send socket open request */
538 sock_unix_req
= dcerpc_pipe_open_socket_send(c
, s
->conn
,
541 composite_continue(c
, sock_unix_req
, continue_unix_open_socket
, c
);
547 Receive result of pipe open request on unix socket
549 NTSTATUS
dcerpc_pipe_open_unix_stream_recv(struct composite_context
*c
)
551 NTSTATUS status
= composite_wait(c
);
559 Open a rpc pipe on a unix socket - sync version
561 NTSTATUS
dcerpc_pipe_open_unix_stream(struct dcerpc_connection
*conn
, const char *path
)
563 struct composite_context
*c
= dcerpc_pipe_open_unix_stream_send(conn
, path
);
564 return dcerpc_pipe_open_unix_stream_recv(c
);
568 struct pipe_np_state
{
570 struct socket_address
*srvaddr
;
571 struct dcerpc_connection
*conn
;
576 Stage 2 of dcerpc_pipe_open_pipe_send: receive socket open request
578 void continue_np_open_socket(struct composite_context
*ctx
)
580 struct composite_context
*c
= talloc_get_type(ctx
->async
.private_data
,
581 struct composite_context
);
583 c
->status
= dcerpc_pipe_open_socket_recv(ctx
);
584 if (!composite_is_ok(c
)) return;
591 Send pipe open request on ncalrpc
593 struct composite_context
* dcerpc_pipe_open_pipe_send(struct dcerpc_connection
*conn
,
594 const char *identifier
)
598 struct composite_context
*c
;
599 struct composite_context
*sock_np_req
;
600 struct pipe_np_state
*s
;
602 /* composite context allocation and setup */
603 c
= composite_create(conn
, conn
->event_ctx
);
604 if (c
== NULL
) return NULL
;
606 s
= talloc_zero(c
, struct pipe_np_state
);
607 if (composite_nomem(s
, c
)) return c
;
610 /* store parameters in state structure */
611 canon
= talloc_strdup(s
, identifier
);
612 if (composite_nomem(canon
, c
)) return c
;
615 string_replace(canon
, '/', '\\');
616 s
->full_path
= talloc_asprintf(canon
, "%s/%s", lp_ncalrpc_dir(), canon
);
617 if (composite_nomem(s
->full_path
, c
)) return c
;
619 /* prepare server address using path and transport name */
620 s
->srvaddr
= socket_address_from_strings(conn
, "unix", s
->full_path
, 0);
621 if (composite_nomem(s
->srvaddr
, c
)) return c
;
623 /* send socket open request */
624 sock_np_req
= dcerpc_pipe_open_socket_send(c
, s
->conn
, s
->srvaddr
, NULL
, NCALRPC
);
625 composite_continue(c
, sock_np_req
, continue_np_open_socket
, c
);
631 Receive result of pipe open request on ncalrpc
633 NTSTATUS
dcerpc_pipe_open_pipe_recv(struct composite_context
*c
)
635 NTSTATUS status
= composite_wait(c
);
643 Open a rpc pipe on a named pipe - sync version
645 NTSTATUS
dcerpc_pipe_open_pipe(struct dcerpc_connection
*conn
, const char *identifier
)
647 struct composite_context
*c
= dcerpc_pipe_open_pipe_send(conn
, identifier
);
648 return dcerpc_pipe_open_pipe_recv(c
);