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/>.
24 #define SOURCE4_LIBRPC_INTERNALS 1
27 #include "system/filesys.h"
28 #include "lib/events/events.h"
29 #include "lib/socket/socket.h"
30 #include "lib/tsocket/tsocket.h"
31 #include "libcli/composite/composite.h"
32 #include "librpc/rpc/dcerpc.h"
33 #include "librpc/rpc/dcerpc_proto.h"
34 #include "libcli/resolve/resolve.h"
35 #include "librpc/rpc/rpc_common.h"
37 struct pipe_open_socket_state
{
38 struct dcecli_connection
*conn
;
39 struct socket_context
*socket_ctx
;
40 struct socket_address
*localaddr
;
41 struct socket_address
*server
;
42 const char *target_hostname
;
43 enum dcerpc_transport_t transport
;
44 struct socket_address
*client
;
48 static void continue_socket_connect(struct composite_context
*ctx
)
50 struct dcecli_connection
*conn
;
51 struct composite_context
*c
= talloc_get_type_abort(
52 ctx
->async
.private_data
, struct composite_context
);
53 struct pipe_open_socket_state
*s
= talloc_get_type_abort(
54 c
->private_data
, struct pipe_open_socket_state
);
58 /* make it easier to write a function calls */
61 c
->status
= socket_connect_recv(ctx
);
62 if (!NT_STATUS_IS_OK(c
->status
)) {
63 DBG_NOTICE("Failed to connect host %s on port %d - %s\n",
64 s
->server
->addr
, s
->server
->port
,
65 nt_errstr(c
->status
));
66 composite_error(c
, c
->status
);
70 s
->client
= socket_get_my_addr(s
->socket_ctx
, s
);
71 if (s
->client
== NULL
) {
72 TALLOC_FREE(s
->socket_ctx
);
73 composite_error(c
, NT_STATUS_NO_MEMORY
);
76 sock_fd
= socket_get_fd(s
->socket_ctx
);
78 TALLOC_FREE(s
->socket_ctx
);
79 composite_error(c
, NT_STATUS_INVALID_HANDLE
);
82 socket_set_flags(s
->socket_ctx
, SOCKET_FLAG_NOCLOSE
);
83 TALLOC_FREE(s
->socket_ctx
);
86 fill in the transport methods
88 conn
->transport
.transport
= s
->transport
;
89 conn
->transport
.private_data
= NULL
;
92 * Windows uses 5840 for ncacn_ip_tcp,
93 * so we also use it (for every transport which uses bsd sockets)
95 conn
->srv_max_xmit_frag
= 5840;
96 conn
->srv_max_recv_frag
= 5840;
98 conn
->transport
.pending_reads
= 0;
99 conn
->server_name
= strupper_talloc(conn
, s
->target_hostname
);
101 rc
= tstream_bsd_existing_socket(conn
, sock_fd
,
102 &conn
->transport
.stream
);
105 composite_error(c
, NT_STATUS_NO_MEMORY
);
109 conn
->transport
.write_queue
=
110 tevent_queue_create(conn
, "dcerpc sock write queue");
111 if (conn
->transport
.write_queue
== NULL
) {
112 TALLOC_FREE(conn
->transport
.stream
);
113 composite_error(c
, NT_STATUS_NO_MEMORY
);
117 /* ensure we don't get SIGPIPE */
118 BlockSignals(true, SIGPIPE
);
124 static struct composite_context
*dcerpc_pipe_open_socket_send(TALLOC_CTX
*mem_ctx
,
125 struct dcecli_connection
*cn
,
126 struct socket_address
*localaddr
,
127 struct socket_address
*server
,
128 const char *target_hostname
,
129 const char *full_path
,
130 enum dcerpc_transport_t transport
)
132 struct composite_context
*c
;
133 struct pipe_open_socket_state
*s
;
134 struct composite_context
*conn_req
;
136 c
= composite_create(mem_ctx
, cn
->event_ctx
);
137 if (c
== NULL
) return NULL
;
139 s
= talloc_zero(c
, struct pipe_open_socket_state
);
140 if (composite_nomem(s
, c
)) return c
;
144 s
->transport
= transport
;
146 s
->localaddr
= socket_address_copy(s
, localaddr
);
147 if (composite_nomem(s
->localaddr
, c
)) return c
;
149 s
->server
= socket_address_copy(s
, server
);
150 if (composite_nomem(s
->server
, c
)) return c
;
151 if (target_hostname
) {
152 s
->target_hostname
= talloc_strdup(s
, target_hostname
);
153 if (composite_nomem(s
->target_hostname
, c
)) return c
;
156 c
->status
= socket_create(s
, server
->family
, SOCKET_TYPE_STREAM
,
158 if (!composite_is_ok(c
)) return c
;
160 conn_req
= socket_connect_send(s
->socket_ctx
, s
->localaddr
, s
->server
, 0,
162 composite_continue(c
, conn_req
, continue_socket_connect
, c
);
166 static NTSTATUS
dcerpc_pipe_open_socket_recv(struct composite_context
*c
,
168 struct socket_address
**localaddr
)
170 NTSTATUS status
= composite_wait(c
);
172 if (NT_STATUS_IS_OK(status
)) {
173 struct pipe_open_socket_state
*s
=
174 talloc_get_type_abort(c
->private_data
,
175 struct pipe_open_socket_state
);
177 if (localaddr
!= NULL
) {
178 *localaddr
= talloc_move(mem_ctx
, &s
->client
);
186 struct pipe_tcp_state
{
188 const char *target_hostname
;
189 const char **addresses
;
192 struct socket_address
*localaddr
;
193 struct socket_address
*srvaddr
;
194 struct resolve_context
*resolve_ctx
;
195 struct dcecli_connection
*conn
;
196 struct nbt_name name
;
198 char *remote_address
;
202 static void continue_ip_open_socket(struct composite_context
*ctx
);
203 static void continue_ip_resolve_name(struct composite_context
*ctx
);
205 static void continue_ip_resolve_name(struct composite_context
*ctx
)
207 struct composite_context
*c
= talloc_get_type_abort(
208 ctx
->async
.private_data
, struct composite_context
);
209 struct pipe_tcp_state
*s
= talloc_get_type_abort(
210 c
->private_data
, struct pipe_tcp_state
);
211 struct composite_context
*sock_ip_req
;
213 c
->status
= resolve_name_multiple_recv(ctx
, s
, &s
->addresses
);
214 if (!composite_is_ok(c
)) return;
216 /* prepare server address using host ip:port and transport name */
217 s
->srvaddr
= socket_address_from_strings(s
->conn
, "ip", s
->addresses
[s
->index
], s
->port
);
219 if (composite_nomem(s
->srvaddr
, c
)) return;
221 sock_ip_req
= dcerpc_pipe_open_socket_send(c
, s
->conn
, s
->localaddr
,
222 s
->srvaddr
, s
->target_hostname
,
225 composite_continue(c
, sock_ip_req
, continue_ip_open_socket
, c
);
230 Stage 2 of dcerpc_pipe_open_tcp_send: receive result of pipe open request
233 static void continue_ip_open_socket(struct composite_context
*ctx
)
235 struct composite_context
*c
= talloc_get_type_abort(
236 ctx
->async
.private_data
, struct composite_context
);
237 struct pipe_tcp_state
*s
= talloc_get_type_abort(
238 c
->private_data
, struct pipe_tcp_state
);
239 struct socket_address
*localaddr
= NULL
;
241 /* receive result socket open request */
242 c
->status
= dcerpc_pipe_open_socket_recv(ctx
, s
, &localaddr
);
243 if (!NT_STATUS_IS_OK(c
->status
)) {
244 /* something went wrong... */
245 DBG_NOTICE("Failed to connect host %s (%s) on port %d - %s.\n",
246 s
->addresses
[s
->index
- 1], s
->target_hostname
,
247 s
->port
, nt_errstr(c
->status
));
248 if (s
->addresses
[s
->index
]) {
249 struct composite_context
*sock_ip_req
;
250 talloc_free(s
->srvaddr
);
251 /* prepare server address using host ip:port and transport name */
252 s
->srvaddr
= socket_address_from_strings(s
->conn
, "ip", s
->addresses
[s
->index
], s
->port
);
254 if (composite_nomem(s
->srvaddr
, c
)) return;
256 sock_ip_req
= dcerpc_pipe_open_socket_send(c
, s
->conn
, s
->localaddr
,
257 s
->srvaddr
, s
->target_hostname
,
260 composite_continue(c
, sock_ip_req
, continue_ip_open_socket
, c
);
264 composite_error(c
, c
->status
);
269 s
->local_address
= talloc_strdup(s
, localaddr
->addr
);
270 if (composite_nomem(s
->local_address
, c
)) return;
271 s
->remote_address
= talloc_strdup(s
, s
->addresses
[s
->index
- 1]);
272 if (composite_nomem(s
->remote_address
, c
)) return;
278 Send rpc pipe open request to given host:port using
281 struct composite_context
* dcerpc_pipe_open_tcp_send(struct dcecli_connection
*conn
,
282 const char *localaddr
,
284 const char *target_hostname
,
286 struct resolve_context
*resolve_ctx
)
288 struct composite_context
*c
;
289 struct pipe_tcp_state
*s
;
290 struct composite_context
*resolve_req
;
292 /* composite context allocation and setup */
293 c
= composite_create(conn
, conn
->event_ctx
);
294 if (c
== NULL
) return NULL
;
296 s
= talloc_zero(c
, struct pipe_tcp_state
);
297 if (composite_nomem(s
, c
)) return c
;
300 /* store input parameters in state structure */
301 s
->server
= talloc_strdup(c
, server
);
302 if (composite_nomem(s
->server
, c
)) return c
;
303 if (target_hostname
) {
304 s
->target_hostname
= talloc_strdup(c
, target_hostname
);
305 if (composite_nomem(s
->target_hostname
, c
)) return c
;
309 s
->resolve_ctx
= resolve_ctx
;
311 s
->localaddr
= socket_address_from_strings(s
, "ip", localaddr
, 0);
312 /* if there is no localaddr, we pass NULL for
313 s->localaddr, which is handled by the socket libraries as
314 meaning no local binding address specified */
317 make_nbt_name_server(&s
->name
, s
->server
);
318 resolve_req
= resolve_name_send(resolve_ctx
, s
, &s
->name
, c
->event_ctx
);
319 composite_continue(c
, resolve_req
, continue_ip_resolve_name
, c
);
324 Receive result of pipe open request on tcp/ip
326 NTSTATUS
dcerpc_pipe_open_tcp_recv(struct composite_context
*c
,
332 status
= composite_wait(c
);
334 if (NT_STATUS_IS_OK(status
)) {
335 struct pipe_tcp_state
*s
= talloc_get_type_abort(
336 c
->private_data
, struct pipe_tcp_state
);
338 if (localaddr
!= NULL
) {
339 *localaddr
= talloc_move(mem_ctx
, &s
->local_address
);
341 if (remoteaddr
!= NULL
) {
342 *remoteaddr
= talloc_move(mem_ctx
, &s
->remote_address
);
351 struct pipe_unix_state
{
353 struct socket_address
*srvaddr
;
354 struct dcecli_connection
*conn
;
359 Stage 2 of dcerpc_pipe_open_unix_stream_send: receive result of pipe open
360 request on unix socket.
362 static void continue_unix_open_socket(struct composite_context
*ctx
)
364 struct composite_context
*c
= talloc_get_type_abort(
365 ctx
->async
.private_data
, struct composite_context
);
367 c
->status
= dcerpc_pipe_open_socket_recv(ctx
, NULL
, NULL
);
368 if (NT_STATUS_IS_OK(c
->status
)) {
373 composite_error(c
, c
->status
);
378 Send pipe open request on unix socket
380 struct composite_context
*dcerpc_pipe_open_unix_stream_send(struct dcecli_connection
*conn
,
383 struct composite_context
*c
;
384 struct composite_context
*sock_unix_req
;
385 struct pipe_unix_state
*s
;
387 /* composite context allocation and setup */
388 c
= composite_create(conn
, conn
->event_ctx
);
389 if (c
== NULL
) return NULL
;
391 s
= talloc_zero(c
, struct pipe_unix_state
);
392 if (composite_nomem(s
, c
)) return c
;
395 /* store parameters in state structure */
396 s
->path
= talloc_strdup(c
, path
);
397 if (composite_nomem(s
->path
, c
)) return c
;
400 /* prepare server address using socket path and transport name */
401 s
->srvaddr
= socket_address_from_strings(conn
, "unix", s
->path
, 0);
402 if (composite_nomem(s
->srvaddr
, c
)) return c
;
404 /* send socket open request */
405 sock_unix_req
= dcerpc_pipe_open_socket_send(c
, s
->conn
, NULL
,
409 composite_continue(c
, sock_unix_req
, continue_unix_open_socket
, c
);
415 Receive result of pipe open request on unix socket
417 NTSTATUS
dcerpc_pipe_open_unix_stream_recv(struct composite_context
*c
)
419 NTSTATUS status
= composite_wait(c
);
427 Stage 2 of dcerpc_pipe_open_pipe_send: receive socket open request
429 static void continue_np_open_socket(struct composite_context
*ctx
)
431 struct composite_context
*c
= talloc_get_type_abort(
432 ctx
->async
.private_data
, struct composite_context
);
434 c
->status
= dcerpc_pipe_open_socket_recv(ctx
, NULL
, NULL
);
435 if (!composite_is_ok(c
)) return;
442 Send pipe open request on ncalrpc
444 struct composite_context
* dcerpc_pipe_open_pipe_send(struct dcecli_connection
*conn
,
445 const char *ncalrpc_dir
,
446 const char *identifier
)
450 struct composite_context
*c
;
451 struct composite_context
*sock_np_req
;
452 struct pipe_unix_state
*s
;
454 /* composite context allocation and setup */
455 c
= composite_create(conn
, conn
->event_ctx
);
456 if (c
== NULL
) return NULL
;
458 s
= talloc_zero(c
, struct pipe_unix_state
);
459 if (composite_nomem(s
, c
)) return c
;
462 /* store parameters in state structure */
463 canon
= talloc_strdup(s
, identifier
);
464 if (composite_nomem(canon
, c
)) return c
;
467 string_replace(canon
, '/', '\\');
468 s
->path
= talloc_asprintf(canon
, "%s/%s", ncalrpc_dir
, canon
);
469 if (composite_nomem(s
->path
, c
)) return c
;
471 /* prepare server address using path and transport name */
472 s
->srvaddr
= socket_address_from_strings(conn
, "unix", s
->path
, 0);
473 if (composite_nomem(s
->srvaddr
, c
)) return c
;
475 /* send socket open request */
476 sock_np_req
= dcerpc_pipe_open_socket_send(c
, s
->conn
, NULL
, s
->srvaddr
, NULL
, s
->path
, NCALRPC
);
477 composite_continue(c
, sock_np_req
, continue_np_open_socket
, c
);
483 Receive result of pipe open request on ncalrpc
485 NTSTATUS
dcerpc_pipe_open_pipe_recv(struct composite_context
*c
)
487 NTSTATUS status
= composite_wait(c
);
495 Open a rpc pipe on a named pipe - sync version
497 NTSTATUS
dcerpc_pipe_open_pipe(struct dcecli_connection
*conn
, const char *ncalrpc_dir
, const char *identifier
)
499 struct composite_context
*c
= dcerpc_pipe_open_pipe_send(conn
, ncalrpc_dir
, identifier
);
500 return dcerpc_pipe_open_pipe_recv(c
);