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 3 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, see <http://www.gnu.org/licenses/>.
25 #include "system/filesys.h"
26 #include "lib/events/events.h"
27 #include "lib/socket/socket.h"
28 #include "lib/tsocket/tsocket.h"
29 #include "libcli/composite/composite.h"
30 #include "librpc/rpc/dcerpc.h"
31 #include "librpc/rpc/dcerpc_proto.h"
32 #include "libcli/resolve/resolve.h"
33 #include "librpc/rpc/rpc_common.h"
35 struct pipe_open_socket_state
{
36 struct dcecli_connection
*conn
;
37 struct socket_context
*socket_ctx
;
38 struct socket_address
*localaddr
;
39 struct socket_address
*server
;
40 const char *target_hostname
;
41 enum dcerpc_transport_t transport
;
42 struct socket_address
*client
;
46 static void continue_socket_connect(struct composite_context
*ctx
)
48 struct dcecli_connection
*conn
;
49 struct composite_context
*c
= talloc_get_type_abort(
50 ctx
->async
.private_data
, struct composite_context
);
51 struct pipe_open_socket_state
*s
= talloc_get_type_abort(
52 c
->private_data
, struct pipe_open_socket_state
);
56 /* make it easier to write a function calls */
59 c
->status
= socket_connect_recv(ctx
);
60 if (!NT_STATUS_IS_OK(c
->status
)) {
61 DEBUG(0, ("Failed to connect host %s on port %d - %s\n",
62 s
->server
->addr
, s
->server
->port
,
63 nt_errstr(c
->status
)));
64 composite_error(c
, c
->status
);
68 s
->client
= socket_get_my_addr(s
->socket_ctx
, s
);
69 if (s
->client
== NULL
) {
70 TALLOC_FREE(s
->socket_ctx
);
71 composite_error(c
, NT_STATUS_NO_MEMORY
);
74 sock_fd
= socket_get_fd(s
->socket_ctx
);
75 socket_set_flags(s
->socket_ctx
, SOCKET_FLAG_NOCLOSE
);
76 TALLOC_FREE(s
->socket_ctx
);
79 fill in the transport methods
81 conn
->transport
.transport
= s
->transport
;
82 conn
->transport
.private_data
= NULL
;
85 * Windows uses 5840 for ncacn_ip_tcp,
86 * so we also use it (for every transport which uses bsd sockets)
88 conn
->srv_max_xmit_frag
= 5840;
89 conn
->srv_max_recv_frag
= 5840;
91 conn
->transport
.pending_reads
= 0;
92 conn
->server_name
= strupper_talloc(conn
, s
->target_hostname
);
94 rc
= tstream_bsd_existing_socket(conn
, sock_fd
,
95 &conn
->transport
.stream
);
98 composite_error(c
, NT_STATUS_NO_MEMORY
);
102 conn
->transport
.write_queue
=
103 tevent_queue_create(conn
, "dcerpc sock write queue");
104 if (conn
->transport
.write_queue
== NULL
) {
105 TALLOC_FREE(conn
->transport
.stream
);
106 composite_error(c
, NT_STATUS_NO_MEMORY
);
110 /* ensure we don't get SIGPIPE */
111 BlockSignals(true, SIGPIPE
);
117 static struct composite_context
*dcerpc_pipe_open_socket_send(TALLOC_CTX
*mem_ctx
,
118 struct dcecli_connection
*cn
,
119 struct socket_address
*localaddr
,
120 struct socket_address
*server
,
121 const char *target_hostname
,
122 const char *full_path
,
123 enum dcerpc_transport_t transport
)
125 struct composite_context
*c
;
126 struct pipe_open_socket_state
*s
;
127 struct composite_context
*conn_req
;
129 c
= composite_create(mem_ctx
, cn
->event_ctx
);
130 if (c
== NULL
) return NULL
;
132 s
= talloc_zero(c
, struct pipe_open_socket_state
);
133 if (composite_nomem(s
, c
)) return c
;
137 s
->transport
= transport
;
139 s
->localaddr
= socket_address_copy(s
, localaddr
);
140 if (composite_nomem(s
->localaddr
, c
)) return c
;
142 s
->server
= socket_address_copy(s
, server
);
143 if (composite_nomem(s
->server
, c
)) return c
;
144 if (target_hostname
) {
145 s
->target_hostname
= talloc_strdup(s
, target_hostname
);
146 if (composite_nomem(s
->target_hostname
, c
)) return c
;
149 c
->status
= socket_create(server
->family
, SOCKET_TYPE_STREAM
, &s
->socket_ctx
, 0);
150 if (!composite_is_ok(c
)) return c
;
152 talloc_steal(s
, s
->socket_ctx
);
154 conn_req
= socket_connect_send(s
->socket_ctx
, s
->localaddr
, s
->server
, 0,
156 composite_continue(c
, conn_req
, continue_socket_connect
, c
);
160 static NTSTATUS
dcerpc_pipe_open_socket_recv(struct composite_context
*c
,
162 struct socket_address
**localaddr
)
164 NTSTATUS status
= composite_wait(c
);
166 if (NT_STATUS_IS_OK(status
)) {
167 struct pipe_open_socket_state
*s
=
168 talloc_get_type_abort(c
->private_data
,
169 struct pipe_open_socket_state
);
171 if (localaddr
!= NULL
) {
172 *localaddr
= talloc_move(mem_ctx
, &s
->client
);
180 struct pipe_tcp_state
{
182 const char *target_hostname
;
183 const char **addresses
;
186 struct socket_address
*localaddr
;
187 struct socket_address
*srvaddr
;
188 struct resolve_context
*resolve_ctx
;
189 struct dcecli_connection
*conn
;
191 char *remote_address
;
195 static void continue_ip_open_socket(struct composite_context
*ctx
);
196 static void continue_ip_resolve_name(struct composite_context
*ctx
);
198 static void continue_ip_resolve_name(struct composite_context
*ctx
)
200 struct composite_context
*c
= talloc_get_type_abort(
201 ctx
->async
.private_data
, struct composite_context
);
202 struct pipe_tcp_state
*s
= talloc_get_type_abort(
203 c
->private_data
, struct pipe_tcp_state
);
204 struct composite_context
*sock_ip_req
;
206 c
->status
= resolve_name_multiple_recv(ctx
, s
, &s
->addresses
);
207 if (!composite_is_ok(c
)) return;
209 /* prepare server address using host ip:port and transport name */
210 s
->srvaddr
= socket_address_from_strings(s
->conn
, "ip", s
->addresses
[s
->index
], s
->port
);
212 if (composite_nomem(s
->srvaddr
, c
)) return;
214 sock_ip_req
= dcerpc_pipe_open_socket_send(c
, s
->conn
, s
->localaddr
,
215 s
->srvaddr
, s
->target_hostname
,
218 composite_continue(c
, sock_ip_req
, continue_ip_open_socket
, c
);
223 Stage 2 of dcerpc_pipe_open_tcp_send: receive result of pipe open request
226 static void continue_ip_open_socket(struct composite_context
*ctx
)
228 struct composite_context
*c
= talloc_get_type_abort(
229 ctx
->async
.private_data
, struct composite_context
);
230 struct pipe_tcp_state
*s
= talloc_get_type_abort(
231 c
->private_data
, struct pipe_tcp_state
);
232 struct socket_address
*localaddr
= NULL
;
234 /* receive result socket open request */
235 c
->status
= dcerpc_pipe_open_socket_recv(ctx
, s
, &localaddr
);
236 if (!NT_STATUS_IS_OK(c
->status
)) {
237 /* something went wrong... */
238 DEBUG(0, ("Failed to connect host %s (%s) on port %d - %s.\n",
239 s
->addresses
[s
->index
- 1], s
->target_hostname
,
240 s
->port
, nt_errstr(c
->status
)));
241 if (s
->addresses
[s
->index
]) {
242 struct composite_context
*sock_ip_req
;
243 talloc_free(s
->srvaddr
);
244 /* prepare server address using host ip:port and transport name */
245 s
->srvaddr
= socket_address_from_strings(s
->conn
, "ip", s
->addresses
[s
->index
], s
->port
);
247 if (composite_nomem(s
->srvaddr
, c
)) return;
249 sock_ip_req
= dcerpc_pipe_open_socket_send(c
, s
->conn
, s
->localaddr
,
250 s
->srvaddr
, s
->target_hostname
,
253 composite_continue(c
, sock_ip_req
, continue_ip_open_socket
, c
);
257 composite_error(c
, c
->status
);
262 s
->local_address
= talloc_strdup(s
, localaddr
->addr
);
263 if (composite_nomem(s
->local_address
, c
)) return;
264 s
->remote_address
= talloc_strdup(s
, s
->addresses
[s
->index
- 1]);
265 if (composite_nomem(s
->remote_address
, c
)) return;
271 Send rpc pipe open request to given host:port using
274 struct composite_context
* dcerpc_pipe_open_tcp_send(struct dcecli_connection
*conn
,
275 const char *localaddr
,
277 const char *target_hostname
,
279 struct resolve_context
*resolve_ctx
)
281 struct composite_context
*c
;
282 struct pipe_tcp_state
*s
;
283 struct composite_context
*resolve_req
;
284 struct nbt_name name
;
286 /* composite context allocation and setup */
287 c
= composite_create(conn
, conn
->event_ctx
);
288 if (c
== NULL
) return NULL
;
290 s
= talloc_zero(c
, struct pipe_tcp_state
);
291 if (composite_nomem(s
, c
)) return c
;
294 /* store input parameters in state structure */
295 s
->server
= talloc_strdup(c
, server
);
296 if (composite_nomem(s
->server
, c
)) return c
;
297 if (target_hostname
) {
298 s
->target_hostname
= talloc_strdup(c
, target_hostname
);
299 if (composite_nomem(s
->target_hostname
, c
)) return c
;
303 s
->resolve_ctx
= resolve_ctx
;
305 s
->localaddr
= socket_address_from_strings(s
, "ip", localaddr
, 0);
306 /* if there is no localaddr, we pass NULL for
307 s->localaddr, which is handled by the socket libraries as
308 meaning no local binding address specified */
311 make_nbt_name_server(&name
, server
);
312 resolve_req
= resolve_name_send(resolve_ctx
, s
, &name
, c
->event_ctx
);
313 composite_continue(c
, resolve_req
, continue_ip_resolve_name
, c
);
318 Receive result of pipe open request on tcp/ip
320 NTSTATUS
dcerpc_pipe_open_tcp_recv(struct composite_context
*c
,
326 status
= composite_wait(c
);
328 if (NT_STATUS_IS_OK(status
)) {
329 struct pipe_tcp_state
*s
= talloc_get_type_abort(
330 c
->private_data
, struct pipe_tcp_state
);
332 if (localaddr
!= NULL
) {
333 *localaddr
= talloc_move(mem_ctx
, &s
->local_address
);
335 if (remoteaddr
!= NULL
) {
336 *remoteaddr
= talloc_move(mem_ctx
, &s
->remote_address
);
345 struct pipe_unix_state
{
347 struct socket_address
*srvaddr
;
348 struct dcecli_connection
*conn
;
353 Stage 2 of dcerpc_pipe_open_unix_stream_send: receive result of pipe open
354 request on unix socket.
356 static void continue_unix_open_socket(struct composite_context
*ctx
)
358 struct composite_context
*c
= talloc_get_type_abort(
359 ctx
->async
.private_data
, struct composite_context
);
361 c
->status
= dcerpc_pipe_open_socket_recv(ctx
, NULL
, NULL
);
362 if (NT_STATUS_IS_OK(c
->status
)) {
367 composite_error(c
, c
->status
);
372 Send pipe open request on unix socket
374 struct composite_context
*dcerpc_pipe_open_unix_stream_send(struct dcecli_connection
*conn
,
377 struct composite_context
*c
;
378 struct composite_context
*sock_unix_req
;
379 struct pipe_unix_state
*s
;
381 /* composite context allocation and setup */
382 c
= composite_create(conn
, conn
->event_ctx
);
383 if (c
== NULL
) return NULL
;
385 s
= talloc_zero(c
, struct pipe_unix_state
);
386 if (composite_nomem(s
, c
)) return c
;
389 /* store parameters in state structure */
390 s
->path
= talloc_strdup(c
, path
);
391 if (composite_nomem(s
->path
, c
)) return c
;
394 /* prepare server address using socket path and transport name */
395 s
->srvaddr
= socket_address_from_strings(conn
, "unix", s
->path
, 0);
396 if (composite_nomem(s
->srvaddr
, c
)) return c
;
398 /* send socket open request */
399 sock_unix_req
= dcerpc_pipe_open_socket_send(c
, s
->conn
, NULL
,
403 composite_continue(c
, sock_unix_req
, continue_unix_open_socket
, c
);
409 Receive result of pipe open request on unix socket
411 NTSTATUS
dcerpc_pipe_open_unix_stream_recv(struct composite_context
*c
)
413 NTSTATUS status
= composite_wait(c
);
421 Stage 2 of dcerpc_pipe_open_pipe_send: receive socket open request
423 static void continue_np_open_socket(struct composite_context
*ctx
)
425 struct composite_context
*c
= talloc_get_type_abort(
426 ctx
->async
.private_data
, struct composite_context
);
428 c
->status
= dcerpc_pipe_open_socket_recv(ctx
, NULL
, NULL
);
429 if (!composite_is_ok(c
)) return;
436 Send pipe open request on ncalrpc
438 struct composite_context
* dcerpc_pipe_open_pipe_send(struct dcecli_connection
*conn
,
439 const char *ncalrpc_dir
,
440 const char *identifier
)
444 struct composite_context
*c
;
445 struct composite_context
*sock_np_req
;
446 struct pipe_unix_state
*s
;
448 /* composite context allocation and setup */
449 c
= composite_create(conn
, conn
->event_ctx
);
450 if (c
== NULL
) return NULL
;
452 s
= talloc_zero(c
, struct pipe_unix_state
);
453 if (composite_nomem(s
, c
)) return c
;
456 /* store parameters in state structure */
457 canon
= talloc_strdup(s
, identifier
);
458 if (composite_nomem(canon
, c
)) return c
;
461 string_replace(canon
, '/', '\\');
462 s
->path
= talloc_asprintf(canon
, "%s/%s", ncalrpc_dir
, canon
);
463 if (composite_nomem(s
->path
, c
)) return c
;
465 /* prepare server address using path and transport name */
466 s
->srvaddr
= socket_address_from_strings(conn
, "unix", s
->path
, 0);
467 if (composite_nomem(s
->srvaddr
, c
)) return c
;
469 /* send socket open request */
470 sock_np_req
= dcerpc_pipe_open_socket_send(c
, s
->conn
, NULL
, s
->srvaddr
, NULL
, s
->path
, NCALRPC
);
471 composite_continue(c
, sock_np_req
, continue_np_open_socket
, c
);
477 Receive result of pipe open request on ncalrpc
479 NTSTATUS
dcerpc_pipe_open_pipe_recv(struct composite_context
*c
)
481 NTSTATUS status
= composite_wait(c
);
489 Open a rpc pipe on a named pipe - sync version
491 NTSTATUS
dcerpc_pipe_open_pipe(struct dcecli_connection
*conn
, const char *ncalrpc_dir
, const char *identifier
)
493 struct composite_context
*c
= dcerpc_pipe_open_pipe_send(conn
, ncalrpc_dir
, identifier
);
494 return dcerpc_pipe_open_pipe_recv(c
);