diff options
-rw-r--r-- | source4/librpc/rpc/dcerpc_sock.c | 179 |
1 files changed, 135 insertions, 44 deletions
diff --git a/source4/librpc/rpc/dcerpc_sock.c b/source4/librpc/rpc/dcerpc_sock.c index 838ddc628b..da48ae0f7d 100644 --- a/source4/librpc/rpc/dcerpc_sock.c +++ b/source4/librpc/rpc/dcerpc_sock.c @@ -27,6 +27,7 @@ #include "librpc/gen_ndr/ndr_epmapper.h" #include "lib/socket/socket.h" #include "lib/stream/packet.h" +#include "libcli/composite/composite.h" /* transport private information used by general socket pipe transports */ struct sock_private { @@ -190,70 +191,73 @@ static const char *sock_peer_name(struct dcerpc_connection *p) return sock->server_name; } -/* - open a rpc connection using the generic socket library -*/ -static NTSTATUS dcerpc_pipe_open_socket(struct dcerpc_connection *c, - const char *server, - uint32_t port, - const char *type, - enum dcerpc_transport_t transport) -{ - struct sock_private *sock; - struct socket_context *socket_ctx; - NTSTATUS status; - sock = talloc(c, struct sock_private); - if (!sock) { - return NT_STATUS_NO_MEMORY; - } +struct pipe_open_socket_state { + struct dcerpc_connection *conn; + struct socket_context *socket_ctx; + struct sock_private *sock; + const char *server; + uint32_t port; + enum dcerpc_transport_t transport; +}; - status = socket_create(type, SOCKET_TYPE_STREAM, &socket_ctx, 0); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(sock); - return status; - } - talloc_steal(sock, socket_ctx); - status = socket_connect_ev(socket_ctx, NULL, 0, server, port, 0, c->event_ctx); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(sock); - return status; +static void continue_socket_connect(struct composite_context *ctx) +{ + struct dcerpc_connection *conn; + struct sock_private *sock; + struct composite_context *c = talloc_get_type(ctx->async.private_data, + struct composite_context); + struct pipe_open_socket_state *s = talloc_get_type(c->private_data, + struct pipe_open_socket_state); + + /* make it easier to write a function calls */ + conn = s->conn; + sock = s->sock; + + c->status = socket_connect_recv(ctx); + if (!NT_STATUS_IS_OK(c->status)) { + DEBUG(0, ("Failed to connect host %s on port %d - %s\n", s->server, s->port, + nt_errstr(c->status))); + composite_error(c, c->status); + return; } /* fill in the transport methods */ - c->transport.transport = transport; - c->transport.private = NULL; + conn->transport.transport = s->transport; + conn->transport.private = NULL; - c->transport.send_request = sock_send_request; - c->transport.send_read = sock_send_read; - c->transport.recv_data = NULL; + conn->transport.send_request = sock_send_request; + conn->transport.send_read = sock_send_read; + conn->transport.recv_data = NULL; - c->transport.shutdown_pipe = sock_shutdown_pipe; - c->transport.peer_name = sock_peer_name; - - sock->sock = socket_ctx; - sock->pending_reads = 0; - sock->server_name = strupper_talloc(sock, server); + conn->transport.shutdown_pipe = sock_shutdown_pipe; + conn->transport.peer_name = sock_peer_name; - sock->fde = event_add_fd(c->event_ctx, sock->sock, socket_get_fd(sock->sock), - 0, sock_io_handler, c); + sock->sock = s->socket_ctx; + sock->pending_reads = 0; + sock->server_name = strupper_talloc(sock, s->server); - c->transport.private = sock; + sock->fde = event_add_fd(conn->event_ctx, sock->sock, socket_get_fd(sock->sock), + 0, sock_io_handler, conn); + + conn->transport.private = sock; sock->packet = packet_init(sock); if (sock->packet == NULL) { + composite_error(c, NT_STATUS_NO_MEMORY); talloc_free(sock); - return NT_STATUS_NO_MEMORY; + return; } - packet_set_private(sock->packet, c); + + packet_set_private(sock->packet, conn); packet_set_socket(sock->packet, sock->sock); packet_set_callback(sock->packet, sock_process_recv); packet_set_full_request(sock->packet, sock_complete_packet); packet_set_error_handler(sock->packet, sock_error_handler); - packet_set_event_context(sock->packet, c->event_ctx); + packet_set_event_context(sock->packet, conn->event_ctx); packet_set_fde(sock->packet, sock->fde); packet_set_serialise(sock->packet); packet_recv_disable(sock->packet); @@ -262,9 +266,96 @@ static NTSTATUS dcerpc_pipe_open_socket(struct dcerpc_connection *c, /* ensure we don't get SIGPIPE */ BlockSignals(True,SIGPIPE); - return NT_STATUS_OK; + composite_done(c); } + +struct composite_context *dcerpc_pipe_open_socket_send(TALLOC_CTX *mem_ctx, + struct dcerpc_connection *cn, + const char *server, + uint32_t port, + const char *type, + enum dcerpc_transport_t transport) +{ + NTSTATUS status; + struct composite_context *c; + struct pipe_open_socket_state *s; + struct composite_context *conn_req; + + c = talloc_zero(mem_ctx, struct composite_context); + if (c == NULL) return NULL; + + s = talloc_zero(c, struct pipe_open_socket_state); + if (s == NULL) { + composite_error(c, NT_STATUS_NO_MEMORY); + goto done; + } + + c->state = COMPOSITE_STATE_IN_PROGRESS; + c->private_data = s; + c->event_ctx = cn->event_ctx; + + s->conn = cn; + s->transport = transport; + s->port = port; + s->server = talloc_strdup(c, server); + if (s->server == NULL) { + composite_error(c, NT_STATUS_NO_MEMORY); + goto done; + } + + s->sock = talloc(cn, struct sock_private); + if (s->sock == NULL) { + composite_error(c, NT_STATUS_NO_MEMORY); + goto done; + } + + status = socket_create(type, SOCKET_TYPE_STREAM, &s->socket_ctx, 0); + if (!NT_STATUS_IS_OK(status)) { + composite_error(c, status); + talloc_free(s->sock); + goto done; + } + talloc_steal(s->sock, s->socket_ctx); + + conn_req = socket_connect_send(s->socket_ctx, NULL, 0, s->server, s->port, 0, c->event_ctx); + if (conn_req == NULL) { + composite_error(c, NT_STATUS_NO_MEMORY); + goto done; + } + + composite_continue(c, conn_req, continue_socket_connect, c); + +done: + return c; +} + + +NTSTATUS dcerpc_pipe_open_socket_recv(struct composite_context *c) +{ + NTSTATUS status = composite_wait(c); + + talloc_free(c); + return status; +} + +/* + open a rpc connection using the generic socket library +*/ +NTSTATUS dcerpc_pipe_open_socket(struct dcerpc_connection *conn, + const char *server, + uint32_t port, + const char *type, + enum dcerpc_transport_t transport) +{ + struct composite_context *c; + + c = dcerpc_pipe_open_socket_send(conn, conn, server, port, + type, transport); + return dcerpc_pipe_open_socket_recv(c); +} + + /* open a rpc connection using tcp */ |