ctdb-scripts: Support storing statd-callout state in cluster filesystem
[samba4-gss.git] / source4 / librpc / rpc / dcerpc_sock.c
blob24eb17ed3b31396423d57b00fda93c962672a074
1 /*
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
26 #include "includes.h"
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);
55 int rc;
56 int sock_fd;
58 /* make it easier to write a function calls */
59 conn = s->conn;
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);
67 return;
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);
74 return;
76 sock_fd = socket_get_fd(s->socket_ctx);
77 if (sock_fd == -1) {
78 TALLOC_FREE(s->socket_ctx);
79 composite_error(c, NT_STATUS_INVALID_HANDLE);
80 return;
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);
103 if (rc < 0) {
104 close(sock_fd);
105 composite_error(c, NT_STATUS_NO_MEMORY);
106 return;
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);
114 return;
117 /* ensure we don't get SIGPIPE */
118 BlockSignals(true, SIGPIPE);
120 composite_done(c);
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;
141 c->private_data = s;
143 s->conn = cn;
144 s->transport = transport;
145 if (localaddr) {
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,
157 &s->socket_ctx, 0);
158 if (!composite_is_ok(c)) return c;
160 conn_req = socket_connect_send(s->socket_ctx, s->localaddr, s->server, 0,
161 c->event_ctx);
162 composite_continue(c, conn_req, continue_socket_connect, c);
163 return c;
166 static NTSTATUS dcerpc_pipe_open_socket_recv(struct composite_context *c,
167 TALLOC_CTX *mem_ctx,
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);
182 talloc_free(c);
183 return status;
186 struct pipe_tcp_state {
187 const char *server;
188 const char *target_hostname;
189 const char **addresses;
190 uint32_t index;
191 uint32_t port;
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;
197 char *local_address;
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);
218 s->index++;
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,
223 NULL,
224 NCACN_IP_TCP);
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
231 on IP transport.
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);
253 s->index++;
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,
258 NULL,
259 NCACN_IP_TCP);
260 composite_continue(c, sock_ip_req, continue_ip_open_socket, c);
262 return;
263 } else {
264 composite_error(c, c->status);
265 return;
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;
274 composite_done(c);
278 Send rpc pipe open request to given host:port using
279 tcp/ip transport
281 struct composite_context* dcerpc_pipe_open_tcp_send(struct dcecli_connection *conn,
282 const char *localaddr,
283 const char *server,
284 const char *target_hostname,
285 uint32_t port,
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;
298 c->private_data = s;
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;
307 s->port = port;
308 s->conn = conn;
309 s->resolve_ctx = resolve_ctx;
310 if (localaddr) {
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);
320 return c;
324 Receive result of pipe open request on tcp/ip
326 NTSTATUS dcerpc_pipe_open_tcp_recv(struct composite_context *c,
327 TALLOC_CTX *mem_ctx,
328 char **localaddr,
329 char **remoteaddr)
331 NTSTATUS status;
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);
346 talloc_free(c);
347 return status;
351 struct pipe_unix_state {
352 const char *path;
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)) {
369 composite_done(c);
370 return;
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,
381 const char *path)
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;
393 c->private_data = s;
395 /* store parameters in state structure */
396 s->path = talloc_strdup(c, path);
397 if (composite_nomem(s->path, c)) return c;
398 s->conn = conn;
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,
406 s->srvaddr, NULL,
407 s->path,
408 NCALRPC);
409 composite_continue(c, sock_unix_req, continue_unix_open_socket, c);
410 return 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);
421 talloc_free(c);
422 return status;
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;
437 composite_done(c);
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)
448 char *canon = NULL;
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;
460 c->private_data = s;
462 /* store parameters in state structure */
463 canon = talloc_strdup(s, identifier);
464 if (composite_nomem(canon, c)) return c;
465 s->conn = conn;
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);
478 return 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);
489 talloc_free(c);
490 return status;
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);