From 9d055846f225bea4953822f40fab1d2f1a2e2d07 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 27 Oct 2004 03:15:42 +0000 Subject: r3278: - rewrote the client side rpc connection code to use lib/socket/ rather than doing everything itself. This greatly simplifies the code, although I really don't like the socket_recv() interface (it always allocates memory for you, which means an extra memcpy in this code) - fixed several bugs in the socket_ipv4.c code, in particular client side code used a non-blocking connect but didn't handle EINPROGRESS, so it had no chance of working. Also fixed the error codes, using map_nt_error_from_unix() - cleaned up and expanded map_nt_error_from_unix() - changed interpret_addr2() to not take a mem_ctx. It makes absolutely no sense to allocate a fixed size 4 byte structure like this. Dozens of places in the code were also using interpret_addr2() incorrectly (precisely because the allocation made no sense) (This used to be commit 7f2c771b0e0e98c5c9e5cf662592d64d34ff1205) --- source4/librpc/rpc/dcerpc_sock.c | 302 ++++++++++----------------------------- source4/librpc/rpc/dcerpc_util.c | 9 +- 2 files changed, 83 insertions(+), 228 deletions(-) (limited to 'source4/librpc') diff --git a/source4/librpc/rpc/dcerpc_sock.c b/source4/librpc/rpc/dcerpc_sock.c index b22ada1d7f..fa2d565084 100644 --- a/source4/librpc/rpc/dcerpc_sock.c +++ b/source4/librpc/rpc/dcerpc_sock.c @@ -34,7 +34,7 @@ struct sock_blob { struct sock_private { struct event_context *event_ctx; struct fd_event *fde; - int fd; + struct socket_context *sock; char *server_name; uint32_t port; @@ -55,9 +55,9 @@ static void sock_dead(struct dcerpc_pipe *p, NTSTATUS status) { struct sock_private *sock = p->transport.private; - if (sock && sock->fd != -1) { - close(sock->fd); - sock->fd = -1; + if (sock && sock->sock != NULL) { + talloc_free(sock->sock); + sock->sock = NULL; } /* wipe any pending sends */ @@ -81,20 +81,19 @@ static void sock_process_send(struct dcerpc_pipe *p) while (sock->pending_send) { struct sock_blob *blob = sock->pending_send; - ssize_t ret = write(sock->fd, blob->data.data, blob->data.length); - if (ret == -1) { - if (errno != EAGAIN && errno != EINTR) { - sock_dead(p, NT_STATUS_NET_WRITE_FAULT); - } + NTSTATUS status; + size_t sent; + status = socket_send(sock->sock, blob, &blob->data, &sent, 0); + if (NT_STATUS_IS_ERR(status)) { + sock_dead(p, NT_STATUS_NET_WRITE_FAULT); break; } - if (ret == 0) { - sock_dead(p, NT_STATUS_NET_WRITE_FAULT); + if (sent == 0) { break; } - blob->data.data += ret; - blob->data.length -= ret; + blob->data.data += sent; + blob->data.length -= sent; if (blob->data.length != 0) { break; @@ -116,7 +115,8 @@ static void sock_process_send(struct dcerpc_pipe *p) static void sock_process_recv(struct dcerpc_pipe *p) { struct sock_private *sock = p->transport.private; - ssize_t ret; + NTSTATUS status; + DATA_BLOB blob; if (sock->recv.data.data == NULL) { sock->recv.data = data_blob_talloc(sock, NULL, MIN_HDR_SIZE); @@ -126,20 +126,19 @@ static void sock_process_recv(struct dcerpc_pipe *p) if (sock->recv.received < MIN_HDR_SIZE) { uint32_t frag_length; - ret = read(sock->fd, sock->recv.data.data, - MIN_HDR_SIZE - sock->recv.received); - if (ret == -1) { - if (errno != EAGAIN && errno != EINTR) { - sock_dead(p, NT_STATUS_NET_WRITE_FAULT); - } + status = socket_recv(sock->sock, sock, &blob, MIN_HDR_SIZE - sock->recv.received, 0); + if (NT_STATUS_IS_ERR(status)) { + sock_dead(p, NT_STATUS_NET_WRITE_FAULT); return; } - if (ret == 0) { - sock_dead(p, NT_STATUS_NET_WRITE_FAULT); + if (blob.length == 0) { return; } - - sock->recv.received += ret; + + memcpy(sock->recv.data.data + sock->recv.received, + blob.data, blob.length); + sock->recv.received += blob.length; + talloc_free(blob.data); if (sock->recv.received != MIN_HDR_SIZE) { return; @@ -156,20 +155,18 @@ static void sock_process_recv(struct dcerpc_pipe *p) } /* read in the rest of the packet */ - ret = read(sock->fd, sock->recv.data.data + sock->recv.received, - sock->recv.data.length - sock->recv.received); - if (ret == -1) { - if (errno != EAGAIN && errno != EINTR) { - sock_dead(p, NT_STATUS_NET_WRITE_FAULT); - } + status = socket_recv(sock->sock, sock, &blob, sock->recv.data.length - sock->recv.received, 0); + if (NT_STATUS_IS_ERR(status)) { + sock_dead(p, NT_STATUS_NET_WRITE_FAULT); return; } - if (ret == 0) { - sock_dead(p, NT_STATUS_NET_WRITE_FAULT); + if (blob.length == 0) { return; } - - sock->recv.received += ret; + memcpy(sock->recv.data.data + sock->recv.received, + blob.data, blob.length); + sock->recv.received += blob.length; + talloc_free(blob.data); if (sock->recv.received != sock->recv.data.length) { return; @@ -199,7 +196,7 @@ static void sock_io_handler(struct event_context *ev, struct fd_event *fde, sock_process_send(p); } - if (sock->fd == -1) { + if (sock->sock == NULL) { return; } @@ -282,67 +279,50 @@ static const char *sock_peer_name(struct dcerpc_pipe *p) } /* - open a rpc connection to a named pipe + open a rpc connection using the generic socket library */ -NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p, - const char *server, - uint32_t port, - int family) +static NTSTATUS dcerpc_pipe_open_socket(struct dcerpc_pipe **p, + const char *server, + uint32_t port, + const char *type, + enum dcerpc_transport_t transport) { struct sock_private *sock; - int fd, gai_err; + struct socket_context *socket_ctx; struct fd_event fde; - struct addrinfo hints, *res, *tmpres; - char portname[16]; + NTSTATUS status; if (port == 0) { port = EPMAPPER_PORT; } - memset(&hints, 0, sizeof(struct addrinfo)); - - hints.ai_family = family; - hints.ai_socktype = SOCK_STREAM; - - snprintf(portname, sizeof(portname)-1, "%d", port); - - gai_err = getaddrinfo(server, portname, &hints, &res); - if (gai_err < 0) - { - DEBUG(0, ("Unable to connect to %s:%d : %s\n", server, port, gai_strerror(gai_err))); - return NT_STATUS_BAD_NETWORK_NAME; + if (!(*p = dcerpc_pipe_init())) { + return NT_STATUS_NO_MEMORY; } - - tmpres = res; - - while (tmpres) { - fd = socket(tmpres->ai_family, tmpres->ai_socktype, tmpres->ai_protocol); - - if(fd >= 0) { - if (connect(fd, tmpres->ai_addr, tmpres->ai_addrlen) == 0) - break; - fd = -1; - } - - tmpres = tmpres->ai_next; + + sock = talloc_p((*p), struct sock_private); + if (!sock) { + talloc_free(*p); + return NT_STATUS_NO_MEMORY; } - freeaddrinfo(res); - - if (fd == -1) { - return NT_STATUS_PORT_CONNECTION_REFUSED; + status = socket_create(type, SOCKET_TYPE_STREAM, &socket_ctx, 0); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(*p); + return status; } + talloc_steal(sock, socket_ctx); - set_socket_options(fd, lp_socket_options()); - - if (!(*p = dcerpc_pipe_init())) { - return NT_STATUS_NO_MEMORY; + status = socket_connect(socket_ctx, NULL, 0, server, port, 0); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(*p); + return status; } - + /* fill in the transport methods */ - (*p)->transport.transport = NCACN_IP_TCP; + (*p)->transport.transport = transport; (*p)->transport.private = NULL; (*p)->transport.send_request = sock_send_request; @@ -353,13 +333,7 @@ NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p, (*p)->transport.shutdown_pipe = sock_shutdown_pipe; (*p)->transport.peer_name = sock_peer_name; - sock = talloc((*p), sizeof(*sock)); - if (!sock) { - dcerpc_pipe_close(*p); - return NT_STATUS_NO_MEMORY; - } - - sock->fd = fd; + sock->sock = socket_ctx; sock->server_name = talloc_strdup((*p), server); sock->event_ctx = event_context_init(sock); sock->pending_send = NULL; @@ -367,7 +341,7 @@ NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p, sock->recv.data = data_blob(NULL, 0); sock->recv.pending_count = 0; - fde.fd = fd; + fde.fd = socket_get_fd(sock->sock); fde.flags = 0; fde.handler = sock_io_handler; fde.private = *p; @@ -379,160 +353,40 @@ NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p, /* ensure we don't get SIGPIPE */ BlockSignals(True,SIGPIPE); - return NT_STATUS_OK; + return NT_STATUS_OK; } /* - open a rpc connection to a unix socket + open a rpc connection using tcp */ -NTSTATUS dcerpc_pipe_open_unix_stream(struct dcerpc_pipe **p, - const char *path) +NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p, const char *server, uint32_t port) { - struct sock_private *sock; - int fd; - struct fd_event fde; - struct sockaddr_un sa; - - fd = socket(PF_UNIX, SOCK_STREAM, 0); - - if (fd < 0) { - return NT_STATUS_NOT_SUPPORTED; - } - - sa.sun_family = AF_UNIX; - strncpy(sa.sun_path, path, sizeof(sa.sun_path)); - - if (connect(fd, &sa, sizeof(sa)) < 0) { - DEBUG(0, ("Unable to connect to unix socket %s: %s\n", path, strerror(errno))); - return NT_STATUS_BAD_NETWORK_NAME; - } - - set_socket_options(fd, lp_socket_options()); - - if (!(*p = dcerpc_pipe_init())) { - return NT_STATUS_NO_MEMORY; - } - - /* - fill in the transport methods - */ - (*p)->transport.transport = NCACN_UNIX_STREAM; - (*p)->transport.private = NULL; - - (*p)->transport.send_request = sock_send_request; - (*p)->transport.send_read = sock_send_read; - (*p)->transport.event_context = sock_event_context; - (*p)->transport.recv_data = NULL; - - (*p)->transport.shutdown_pipe = sock_shutdown_pipe; - (*p)->transport.peer_name = sock_peer_name; - - sock = talloc((*p), sizeof(*sock)); - if (!sock) { - dcerpc_pipe_close(*p); - return NT_STATUS_NO_MEMORY; - } - - sock->fd = fd; - sock->server_name = talloc_strdup((*p), path); - sock->event_ctx = event_context_init(sock); - sock->pending_send = NULL; - sock->recv.received = 0; - sock->recv.data = data_blob(NULL, 0); - sock->recv.pending_count = 0; - - fde.fd = fd; - fde.flags = 0; - fde.handler = sock_io_handler; - fde.private = *p; - - sock->fde = event_add_fd(sock->event_ctx, &fde); - - (*p)->transport.private = sock; - - /* ensure we don't get SIGPIPE */ - BlockSignals(True,SIGPIPE); + return dcerpc_pipe_open_socket(p, server, port, "ip", NCACN_IP_TCP); +} - return NT_STATUS_OK; +/* + open a rpc connection to a unix socket +*/ +NTSTATUS dcerpc_pipe_open_unix_stream(struct dcerpc_pipe **p, const char *path) +{ + return dcerpc_pipe_open_socket(p, path, 0, "unix", NCACN_UNIX_STREAM); } /* open a rpc connection to a named pipe */ -NTSTATUS dcerpc_pipe_open_pipe(struct dcerpc_pipe **p, - const char *identifier) +NTSTATUS dcerpc_pipe_open_pipe(struct dcerpc_pipe **p, const char *identifier) { - struct sock_private *sock; - int fd; - struct fd_event fde; - struct sockaddr_un sa; + NTSTATUS status; char *canon, *full_path; - if (!(*p = dcerpc_pipe_init())) { - return NT_STATUS_NO_MEMORY; - } - - canon = talloc_strdup(*p, identifier); + canon = talloc_strdup(NULL, identifier); string_replace(canon, '/', '\\'); + full_path = talloc_asprintf(canon, "%s/%s", lp_ncalrpc_dir(), canon); - full_path = talloc_asprintf(*p, "%s/%s", lp_ncalrpc_dir(), canon); - - fd = socket(PF_UNIX, SOCK_STREAM, 0); - - if (fd < 0) { - return NT_STATUS_NOT_SUPPORTED; - } - - sa.sun_family = AF_UNIX; - strncpy(sa.sun_path, full_path, sizeof(sa.sun_path)); - - if (connect(fd, &sa, sizeof(sa)) < 0) { - DEBUG(0, ("Unable to connect to unix socket %s (%s): %s\n", full_path, identifier, strerror(errno))); - return NT_STATUS_BAD_NETWORK_NAME; - } - - set_socket_options(fd, lp_socket_options()); - - /* - fill in the transport methods - */ - (*p)->transport.transport = NCALRPC; - (*p)->transport.private = NULL; - - (*p)->transport.send_request = sock_send_request; - (*p)->transport.send_read = sock_send_read; - (*p)->transport.event_context = sock_event_context; - (*p)->transport.recv_data = NULL; - - (*p)->transport.shutdown_pipe = sock_shutdown_pipe; - (*p)->transport.peer_name = sock_peer_name; - - sock = talloc((*p), sizeof(*sock)); - if (!sock) { - dcerpc_pipe_close(*p); - return NT_STATUS_NO_MEMORY; - } - - sock->fd = fd; - sock->server_name = full_path; - sock->event_ctx = event_context_init(sock); - sock->pending_send = NULL; - sock->recv.received = 0; - sock->recv.data = data_blob(NULL, 0); - sock->recv.pending_count = 0; - - fde.fd = fd; - fde.flags = 0; - fde.handler = sock_io_handler; - fde.private = *p; - - sock->fde = event_add_fd(sock->event_ctx, &fde); - - (*p)->transport.private = sock; - - /* ensure we don't get SIGPIPE */ - BlockSignals(True,SIGPIPE); + status = dcerpc_pipe_open_socket(p, full_path, 0, "unix", NCALRPC); + talloc_free(canon); - return NT_STATUS_OK; + return status; } diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c index cbdb0f2069..8fd99eef04 100644 --- a/source4/librpc/rpc/dcerpc_util.c +++ b/source4/librpc/rpc/dcerpc_util.c @@ -865,7 +865,7 @@ static NTSTATUS dcerpc_pipe_connect_ncalrpc(struct dcerpc_pipe **p, status = dcerpc_pipe_open_pipe(p, binding->endpoint); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Failed to open ncalrpc pipe '%s'\n", binding->endpoint)); + DEBUG(0,("Failed to open ncalrpc pipe '%s' - %s\n", binding->endpoint, nt_errstr(status))); talloc_destroy(mem_ctx); return status; } @@ -918,9 +918,10 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_unix_stream(struct dcerpc_pipe **p, status = dcerpc_pipe_open_unix_stream(p, binding->endpoint); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Failed to open unix socket %s\n", binding->endpoint)); + DEBUG(0,("Failed to open unix socket %s - %s\n", + binding->endpoint, nt_errstr(status))); return status; - } + } (*p)->flags = binding->flags; @@ -974,7 +975,7 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp(struct dcerpc_pipe **p, port = atoi(binding->endpoint); - status = dcerpc_pipe_open_tcp(p, binding->host, port, AF_UNSPEC); + status = dcerpc_pipe_open_tcp(p, binding->host, port); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Failed to connect to %s:%d\n", binding->host, port)); return status; -- cgit