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 DBG_NOTICE("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
);
76 TALLOC_FREE(s
->socket_ctx
);
77 composite_error(c
, NT_STATUS_INVALID_HANDLE
);
80 socket_set_flags(s
->socket_ctx
, SOCKET_FLAG_NOCLOSE
);
81 TALLOC_FREE(s
->socket_ctx
);
84 fill in the transport methods
86 conn
->transport
.transport
= s
->transport
;
87 conn
->transport
.private_data
= NULL
;
90 * Windows uses 5840 for ncacn_ip_tcp,
91 * so we also use it (for every transport which uses bsd sockets)
93 conn
->srv_max_xmit_frag
= 5840;
94 conn
->srv_max_recv_frag
= 5840;
96 conn
->transport
.pending_reads
= 0;
97 conn
->server_name
= strupper_talloc(conn
, s
->target_hostname
);
99 rc
= tstream_bsd_existing_socket(conn
, sock_fd
,
100 &conn
->transport
.stream
);
103 composite_error(c
, NT_STATUS_NO_MEMORY
);
107 conn
->transport
.write_queue
=
108 tevent_queue_create(conn
, "dcerpc sock write queue");
109 if (conn
->transport
.write_queue
== NULL
) {
110 TALLOC_FREE(conn
->transport
.stream
);
111 composite_error(c
, NT_STATUS_NO_MEMORY
);
115 /* ensure we don't get SIGPIPE */
116 BlockSignals(true, SIGPIPE
);
122 static struct composite_context
*dcerpc_pipe_open_socket_send(TALLOC_CTX
*mem_ctx
,
123 struct dcecli_connection
*cn
,
124 struct socket_address
*localaddr
,
125 struct socket_address
*server
,
126 const char *target_hostname
,
127 const char *full_path
,
128 enum dcerpc_transport_t transport
)
130 struct composite_context
*c
;
131 struct pipe_open_socket_state
*s
;
132 struct composite_context
*conn_req
;
134 c
= composite_create(mem_ctx
, cn
->event_ctx
);
135 if (c
== NULL
) return NULL
;
137 s
= talloc_zero(c
, struct pipe_open_socket_state
);
138 if (composite_nomem(s
, c
)) return c
;
142 s
->transport
= transport
;
144 s
->localaddr
= socket_address_copy(s
, localaddr
);
145 if (composite_nomem(s
->localaddr
, c
)) return c
;
147 s
->server
= socket_address_copy(s
, server
);
148 if (composite_nomem(s
->server
, c
)) return c
;
149 if (target_hostname
) {
150 s
->target_hostname
= talloc_strdup(s
, target_hostname
);
151 if (composite_nomem(s
->target_hostname
, c
)) return c
;
154 c
->status
= socket_create(s
, server
->family
, SOCKET_TYPE_STREAM
,
156 if (!composite_is_ok(c
)) return c
;
158 conn_req
= socket_connect_send(s
->socket_ctx
, s
->localaddr
, s
->server
, 0,
160 composite_continue(c
, conn_req
, continue_socket_connect
, c
);
164 static NTSTATUS
dcerpc_pipe_open_socket_recv(struct composite_context
*c
,
166 struct socket_address
**localaddr
)
168 NTSTATUS status
= composite_wait(c
);
170 if (NT_STATUS_IS_OK(status
)) {
171 struct pipe_open_socket_state
*s
=
172 talloc_get_type_abort(c
->private_data
,
173 struct pipe_open_socket_state
);
175 if (localaddr
!= NULL
) {
176 *localaddr
= talloc_move(mem_ctx
, &s
->client
);
184 struct pipe_tcp_state
{
186 const char *target_hostname
;
187 const char **addresses
;
190 struct socket_address
*localaddr
;
191 struct socket_address
*srvaddr
;
192 struct resolve_context
*resolve_ctx
;
193 struct dcecli_connection
*conn
;
194 struct nbt_name name
;
196 char *remote_address
;
200 static void continue_ip_open_socket(struct composite_context
*ctx
);
201 static void continue_ip_resolve_name(struct composite_context
*ctx
);
203 static void continue_ip_resolve_name(struct composite_context
*ctx
)
205 struct composite_context
*c
= talloc_get_type_abort(
206 ctx
->async
.private_data
, struct composite_context
);
207 struct pipe_tcp_state
*s
= talloc_get_type_abort(
208 c
->private_data
, struct pipe_tcp_state
);
209 struct composite_context
*sock_ip_req
;
211 c
->status
= resolve_name_multiple_recv(ctx
, s
, &s
->addresses
);
212 if (!composite_is_ok(c
)) return;
214 /* prepare server address using host ip:port and transport name */
215 s
->srvaddr
= socket_address_from_strings(s
->conn
, "ip", s
->addresses
[s
->index
], s
->port
);
217 if (composite_nomem(s
->srvaddr
, c
)) return;
219 sock_ip_req
= dcerpc_pipe_open_socket_send(c
, s
->conn
, s
->localaddr
,
220 s
->srvaddr
, s
->target_hostname
,
223 composite_continue(c
, sock_ip_req
, continue_ip_open_socket
, c
);
228 Stage 2 of dcerpc_pipe_open_tcp_send: receive result of pipe open request
231 static void continue_ip_open_socket(struct composite_context
*ctx
)
233 struct composite_context
*c
= talloc_get_type_abort(
234 ctx
->async
.private_data
, struct composite_context
);
235 struct pipe_tcp_state
*s
= talloc_get_type_abort(
236 c
->private_data
, struct pipe_tcp_state
);
237 struct socket_address
*localaddr
= NULL
;
239 /* receive result socket open request */
240 c
->status
= dcerpc_pipe_open_socket_recv(ctx
, s
, &localaddr
);
241 if (!NT_STATUS_IS_OK(c
->status
)) {
242 /* something went wrong... */
243 DBG_NOTICE("Failed to connect host %s (%s) on port %d - %s.\n",
244 s
->addresses
[s
->index
- 1], s
->target_hostname
,
245 s
->port
, nt_errstr(c
->status
));
246 if (s
->addresses
[s
->index
]) {
247 struct composite_context
*sock_ip_req
;
248 talloc_free(s
->srvaddr
);
249 /* prepare server address using host ip:port and transport name */
250 s
->srvaddr
= socket_address_from_strings(s
->conn
, "ip", s
->addresses
[s
->index
], s
->port
);
252 if (composite_nomem(s
->srvaddr
, c
)) return;
254 sock_ip_req
= dcerpc_pipe_open_socket_send(c
, s
->conn
, s
->localaddr
,
255 s
->srvaddr
, s
->target_hostname
,
258 composite_continue(c
, sock_ip_req
, continue_ip_open_socket
, c
);
262 composite_error(c
, c
->status
);
267 s
->local_address
= talloc_strdup(s
, localaddr
->addr
);
268 if (composite_nomem(s
->local_address
, c
)) return;
269 s
->remote_address
= talloc_strdup(s
, s
->addresses
[s
->index
- 1]);
270 if (composite_nomem(s
->remote_address
, c
)) return;
276 Send rpc pipe open request to given host:port using
279 struct composite_context
* dcerpc_pipe_open_tcp_send(struct dcecli_connection
*conn
,
280 const char *localaddr
,
282 const char *target_hostname
,
284 struct resolve_context
*resolve_ctx
)
286 struct composite_context
*c
;
287 struct pipe_tcp_state
*s
;
288 struct composite_context
*resolve_req
;
290 /* composite context allocation and setup */
291 c
= composite_create(conn
, conn
->event_ctx
);
292 if (c
== NULL
) return NULL
;
294 s
= talloc_zero(c
, struct pipe_tcp_state
);
295 if (composite_nomem(s
, c
)) return c
;
298 /* store input parameters in state structure */
299 s
->server
= talloc_strdup(c
, server
);
300 if (composite_nomem(s
->server
, c
)) return c
;
301 if (target_hostname
) {
302 s
->target_hostname
= talloc_strdup(c
, target_hostname
);
303 if (composite_nomem(s
->target_hostname
, c
)) return c
;
307 s
->resolve_ctx
= resolve_ctx
;
309 s
->localaddr
= socket_address_from_strings(s
, "ip", localaddr
, 0);
310 /* if there is no localaddr, we pass NULL for
311 s->localaddr, which is handled by the socket libraries as
312 meaning no local binding address specified */
315 make_nbt_name_server(&s
->name
, s
->server
);
316 resolve_req
= resolve_name_send(resolve_ctx
, s
, &s
->name
, c
->event_ctx
);
317 composite_continue(c
, resolve_req
, continue_ip_resolve_name
, c
);
322 Receive result of pipe open request on tcp/ip
324 NTSTATUS
dcerpc_pipe_open_tcp_recv(struct composite_context
*c
,
330 status
= composite_wait(c
);
332 if (NT_STATUS_IS_OK(status
)) {
333 struct pipe_tcp_state
*s
= talloc_get_type_abort(
334 c
->private_data
, struct pipe_tcp_state
);
336 if (localaddr
!= NULL
) {
337 *localaddr
= talloc_move(mem_ctx
, &s
->local_address
);
339 if (remoteaddr
!= NULL
) {
340 *remoteaddr
= talloc_move(mem_ctx
, &s
->remote_address
);
349 struct pipe_unix_state
{
351 struct socket_address
*srvaddr
;
352 struct dcecli_connection
*conn
;
357 Stage 2 of dcerpc_pipe_open_unix_stream_send: receive result of pipe open
358 request on unix socket.
360 static void continue_unix_open_socket(struct composite_context
*ctx
)
362 struct composite_context
*c
= talloc_get_type_abort(
363 ctx
->async
.private_data
, struct composite_context
);
365 c
->status
= dcerpc_pipe_open_socket_recv(ctx
, NULL
, NULL
);
366 if (NT_STATUS_IS_OK(c
->status
)) {
371 composite_error(c
, c
->status
);
376 Send pipe open request on unix socket
378 struct composite_context
*dcerpc_pipe_open_unix_stream_send(struct dcecli_connection
*conn
,
381 struct composite_context
*c
;
382 struct composite_context
*sock_unix_req
;
383 struct pipe_unix_state
*s
;
385 /* composite context allocation and setup */
386 c
= composite_create(conn
, conn
->event_ctx
);
387 if (c
== NULL
) return NULL
;
389 s
= talloc_zero(c
, struct pipe_unix_state
);
390 if (composite_nomem(s
, c
)) return c
;
393 /* store parameters in state structure */
394 s
->path
= talloc_strdup(c
, path
);
395 if (composite_nomem(s
->path
, c
)) return c
;
398 /* prepare server address using socket path and transport name */
399 s
->srvaddr
= socket_address_from_strings(conn
, "unix", s
->path
, 0);
400 if (composite_nomem(s
->srvaddr
, c
)) return c
;
402 /* send socket open request */
403 sock_unix_req
= dcerpc_pipe_open_socket_send(c
, s
->conn
, NULL
,
407 composite_continue(c
, sock_unix_req
, continue_unix_open_socket
, c
);
413 Receive result of pipe open request on unix socket
415 NTSTATUS
dcerpc_pipe_open_unix_stream_recv(struct composite_context
*c
)
417 NTSTATUS status
= composite_wait(c
);
425 Stage 2 of dcerpc_pipe_open_pipe_send: receive socket open request
427 static void continue_np_open_socket(struct composite_context
*ctx
)
429 struct composite_context
*c
= talloc_get_type_abort(
430 ctx
->async
.private_data
, struct composite_context
);
432 c
->status
= dcerpc_pipe_open_socket_recv(ctx
, NULL
, NULL
);
433 if (!composite_is_ok(c
)) return;
440 Send pipe open request on ncalrpc
442 struct composite_context
* dcerpc_pipe_open_pipe_send(struct dcecli_connection
*conn
,
443 const char *ncalrpc_dir
,
444 const char *identifier
)
448 struct composite_context
*c
;
449 struct composite_context
*sock_np_req
;
450 struct pipe_unix_state
*s
;
452 /* composite context allocation and setup */
453 c
= composite_create(conn
, conn
->event_ctx
);
454 if (c
== NULL
) return NULL
;
456 s
= talloc_zero(c
, struct pipe_unix_state
);
457 if (composite_nomem(s
, c
)) return c
;
460 /* store parameters in state structure */
461 canon
= talloc_strdup(s
, identifier
);
462 if (composite_nomem(canon
, c
)) return c
;
465 string_replace(canon
, '/', '\\');
466 s
->path
= talloc_asprintf(canon
, "%s/%s", ncalrpc_dir
, canon
);
467 if (composite_nomem(s
->path
, c
)) return c
;
469 /* prepare server address using path and transport name */
470 s
->srvaddr
= socket_address_from_strings(conn
, "unix", s
->path
, 0);
471 if (composite_nomem(s
->srvaddr
, c
)) return c
;
473 /* send socket open request */
474 sock_np_req
= dcerpc_pipe_open_socket_send(c
, s
->conn
, NULL
, s
->srvaddr
, NULL
, s
->path
, NCALRPC
);
475 composite_continue(c
, sock_np_req
, continue_np_open_socket
, c
);
481 Receive result of pipe open request on ncalrpc
483 NTSTATUS
dcerpc_pipe_open_pipe_recv(struct composite_context
*c
)
485 NTSTATUS status
= composite_wait(c
);
493 Open a rpc pipe on a named pipe - sync version
495 NTSTATUS
dcerpc_pipe_open_pipe(struct dcecli_connection
*conn
, const char *ncalrpc_dir
, const char *identifier
)
497 struct composite_context
*c
= dcerpc_pipe_open_pipe_send(conn
, ncalrpc_dir
, identifier
);
498 return dcerpc_pipe_open_pipe_recv(c
);