summaryrefslogtreecommitdiff
path: root/source4/librpc
diff options
context:
space:
mode:
Diffstat (limited to 'source4/librpc')
-rw-r--r--source4/librpc/config.m42
-rw-r--r--source4/librpc/idl/atsvc.idl3
-rw-r--r--source4/librpc/idl/browser.idl3
-rw-r--r--source4/librpc/idl/echo.idl2
-rw-r--r--source4/librpc/idl/epmapper.idl3
-rw-r--r--source4/librpc/idl/lsa.idl2
-rw-r--r--source4/librpc/idl/oxidresolver.idl2
-rw-r--r--source4/librpc/idl/samr.idl2
-rw-r--r--source4/librpc/idl/svcctl.idl1
-rw-r--r--source4/librpc/idl/winreg.idl2
-rw-r--r--source4/librpc/rpc/dcerpc_sock.c536
-rw-r--r--source4/librpc/rpc/dcerpc_tcp.c382
-rw-r--r--source4/librpc/rpc/dcerpc_util.c108
13 files changed, 657 insertions, 391 deletions
diff --git a/source4/librpc/config.m4 b/source4/librpc/config.m4
index a10b4bc7b7..22abcc6f20 100644
--- a/source4/librpc/config.m4
+++ b/source4/librpc/config.m4
@@ -56,7 +56,7 @@ SMB_SUBSYSTEM(LIBRPC_RAW,[],
librpc/rpc/dcerpc_ntlm.o
librpc/rpc/dcerpc_spnego.o
librpc/rpc/dcerpc_smb.o
- librpc/rpc/dcerpc_tcp.o])
+ librpc/rpc/dcerpc_sock.o])
SMB_SUBSYSTEM(LIBRPC,[],[],[],
[LIBNDR_RAW LIBRPC_RAW])
diff --git a/source4/librpc/idl/atsvc.idl b/source4/librpc/idl/atsvc.idl
index e2e5d3e2c8..e9e56bfb6a 100644
--- a/source4/librpc/idl/atsvc.idl
+++ b/source4/librpc/idl/atsvc.idl
@@ -7,7 +7,8 @@
[ uuid(1ff70682-0a51-30e8-076d-740be8cee98b),
version(1.0),
pointer_default(unique),
- helpstring("Queue/List/Remove jobs for later execution")
+ helpstring("Queue/List/Remove jobs for later execution"),
+ endpoint("ncacn_np:[\\pipe\\atsvc]", "ncalrpc:")
] interface atsvc
{
typedef struct {
diff --git a/source4/librpc/idl/browser.idl b/source4/librpc/idl/browser.idl
index 46011aa6a4..2d4784246d 100644
--- a/source4/librpc/idl/browser.idl
+++ b/source4/librpc/idl/browser.idl
@@ -1,7 +1,8 @@
[
uuid(6bffd098-a112-3610-9833-012892020162),
version(0.0),
- helpstring("Browsing")
+ helpstring("Browsing"),
+ endpoint("lcalrpc:")
]
interface browser
{
diff --git a/source4/librpc/idl/echo.idl b/source4/librpc/idl/echo.idl
index e54b3914f8..cfa6041208 100644
--- a/source4/librpc/idl/echo.idl
+++ b/source4/librpc/idl/echo.idl
@@ -3,7 +3,7 @@
[
uuid(60a15ec5-4de8-11d7-a637-005056a20182),
- endpoint("ncacn_np:[\\pipe\\rpcecho]", "ncacn_ip_tcp:"),
+ endpoint("ncacn_np:[\\pipe\\rpcecho]", "ncacn_ip_tcp:", "ncalrpc:"),
version(1.0),
helpstring("Simple echo pipe")
]
diff --git a/source4/librpc/idl/epmapper.idl b/source4/librpc/idl/epmapper.idl
index e1e980b0fd..e0d79a0fe1 100644
--- a/source4/librpc/idl/epmapper.idl
+++ b/source4/librpc/idl/epmapper.idl
@@ -11,7 +11,8 @@ http://www.opengroup.org/onlinepubs/9629399/chap6.htm#tagcjh_11_02_03_01: bindin
[
uuid(e1af8308-5d1f-11c9-91a4-08002b14a0fa),
version(3.0),
- endpoint("ncacn_np:[\\pipe\\epmapper]", "ncacn_ip_tcp:[135]"),
+ endpoint("ncacn_np:[\\pipe\\epmapper]", "ncacn_ip_tcp:[135]",
+ "ncalrpc:[EPMAPPER]", "ncacn_unix_stream:[/tmp/epmapper]"),
pointer_default(unique)
]
interface epmapper
diff --git a/source4/librpc/idl/lsa.idl b/source4/librpc/idl/lsa.idl
index ca1090545a..a404ebebff 100644
--- a/source4/librpc/idl/lsa.idl
+++ b/source4/librpc/idl/lsa.idl
@@ -6,7 +6,7 @@
[ uuid(12345778-1234-abcd-ef00-0123456789ab),
version(0.0),
- endpoint("ncacn_np:[\\pipe\\lsarpc]","ncacn_np:[\\pipe\\lsass]","ncacn_ip_tcp:"),
+ endpoint("ncacn_np:[\\pipe\\lsarpc]","ncacn_np:[\\pipe\\lsass]", "ncacn_ip_tcp:"),
pointer_default(unique),
helpstring("Local Server Authentication(?)")
] interface lsarpc
diff --git a/source4/librpc/idl/oxidresolver.idl b/source4/librpc/idl/oxidresolver.idl
index 6354e7b380..5627c89f9e 100644
--- a/source4/librpc/idl/oxidresolver.idl
+++ b/source4/librpc/idl/oxidresolver.idl
@@ -15,7 +15,7 @@
[
uuid(99fcfec4-5260-101b-bbcb-00aa0021347a),
helpstring("Object Exporter ID Resolver"),
- endpoint("ncacn_np:[\\pipe\\epmapper]", "ncacn_ip_tcp:[135]"),
+ endpoint("ncacn_np:[\\pipe\\epmapper]", "ncacn_ip_tcp:[135]", "ncalrpc:"),
pointer_default(unique)
]
interface IOXIDResolver
diff --git a/source4/librpc/idl/samr.idl b/source4/librpc/idl/samr.idl
index f40f71df3e..43880831f5 100644
--- a/source4/librpc/idl/samr.idl
+++ b/source4/librpc/idl/samr.idl
@@ -10,7 +10,7 @@
[ uuid(12345778-1234-abcd-ef00-0123456789ac),
version(1.0),
- endpoint("ncacn_np:[\\pipe\\samr]","ncacn_ip_tcp:"),
+ endpoint("ncacn_np:[\\pipe\\samr]","ncacn_ip_tcp:", "ncalrpc:"),
pointer_default(unique)
] interface samr
{
diff --git a/source4/librpc/idl/svcctl.idl b/source4/librpc/idl/svcctl.idl
index 87b47fd6dd..7ea1fee116 100644
--- a/source4/librpc/idl/svcctl.idl
+++ b/source4/librpc/idl/svcctl.idl
@@ -7,6 +7,7 @@
[ uuid(367abb81-9844-35f1-ad32-98f038001003),
version(2.0),
pointer_default(unique),
+ endpoint("ncacn_np:[\\pipe\\svcctl]", "ncalrpc:"),
helpstring("Service Control")
] interface svcctl
{
diff --git a/source4/librpc/idl/winreg.idl b/source4/librpc/idl/winreg.idl
index 1f7123f7f3..c90879f278 100644
--- a/source4/librpc/idl/winreg.idl
+++ b/source4/librpc/idl/winreg.idl
@@ -6,7 +6,7 @@
[ uuid(338cd001-2244-31f1-aaaa-900038001003),
version(1.0),
- endpoint("ncacn_np:[\\pipe\\winreg]","ncacn_ip_tcp:"),
+ endpoint("ncacn_np:[\\pipe\\winreg]","ncacn_ip_tcp:","ncalrpc:"),
pointer_default(unique),
helpstring("Remote Registry Service")
] interface winreg
diff --git a/source4/librpc/rpc/dcerpc_sock.c b/source4/librpc/rpc/dcerpc_sock.c
new file mode 100644
index 0000000000..9ad5c06ad2
--- /dev/null
+++ b/source4/librpc/rpc/dcerpc_sock.c
@@ -0,0 +1,536 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ dcerpc over standard sockets transport
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Jelmer Vernooij 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#define MIN_HDR_SIZE 16
+
+struct sock_blob {
+ struct sock_blob *next, *prev;
+ DATA_BLOB data;
+};
+
+/* transport private information used by general socket pipe transports */
+struct sock_private {
+ struct event_context *event_ctx;
+ struct fd_event *fde;
+ int fd;
+ char *server_name;
+ uint32_t port;
+
+ struct sock_blob *pending_send;
+
+ struct {
+ size_t received;
+ DATA_BLOB data;
+ uint_t pending_count;
+ } recv;
+};
+
+
+/*
+ mark the socket dead
+*/
+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;
+ }
+
+ /* wipe any pending sends */
+ while (sock->pending_send) {
+ struct sock_blob *blob = sock->pending_send;
+ DLIST_REMOVE(sock->pending_send, blob);
+ talloc_free(blob);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ p->transport.recv_data(p, NULL, status);
+ }
+}
+
+/*
+ process send requests
+*/
+static void sock_process_send(struct dcerpc_pipe *p)
+{
+ struct sock_private *sock = p->transport.private;
+
+ 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);
+ }
+ break;
+ }
+ if (ret == 0) {
+ sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
+ break;
+ }
+
+ blob->data.data += ret;
+ blob->data.length -= ret;
+
+ if (blob->data.length != 0) {
+ break;
+ }
+
+ DLIST_REMOVE(sock->pending_send, blob);
+ talloc_free(blob);
+ }
+
+ if (sock->pending_send == NULL) {
+ sock->fde->flags &= ~EVENT_FD_WRITE;
+ }
+}
+
+
+/*
+ process recv requests
+*/
+static void sock_process_recv(struct dcerpc_pipe *p)
+{
+ struct sock_private *sock = p->transport.private;
+ ssize_t ret;
+
+ if (sock->recv.data.data == NULL) {
+ sock->recv.data = data_blob_talloc(sock, NULL, MIN_HDR_SIZE);
+ }
+
+ /* read in the base header to get the fragment length */
+ 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);
+ }
+ return;
+ }
+ if (ret == 0) {
+ sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
+ return;
+ }
+
+ sock->recv.received += ret;
+
+ if (sock->recv.received != MIN_HDR_SIZE) {
+ return;
+ }
+ frag_length = dcerpc_get_frag_length(&sock->recv.data);
+
+ sock->recv.data.data = talloc_realloc(sock, sock->recv.data.data,
+ frag_length);
+ if (sock->recv.data.data == NULL) {
+ sock_dead(p, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ sock->recv.data.length = frag_length;
+ }
+
+ /* 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);
+ }
+ return;
+ }
+ if (ret == 0) {
+ sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
+ return;
+ }
+
+ sock->recv.received += ret;
+
+ if (sock->recv.received != sock->recv.data.length) {
+ return;
+ }
+
+ /* we have a full packet */
+ p->transport.recv_data(p, &sock->recv.data, NT_STATUS_OK);
+ talloc_free(sock->recv.data.data);
+ sock->recv.data = data_blob(NULL, 0);
+ sock->recv.received = 0;
+ sock->recv.pending_count--;
+ if (sock->recv.pending_count == 0) {
+ sock->fde->flags &= ~EVENT_FD_READ;
+ }
+}
+
+/*
+ called when a IO is triggered by the events system
+*/
+static void sock_io_handler(struct event_context *ev, struct fd_event *fde,
+ time_t t, uint16_t flags)
+{
+ struct dcerpc_pipe *p = fde->private;
+ struct sock_private *sock = p->transport.private;
+
+ if (flags & EVENT_FD_WRITE) {
+ sock_process_send(p);
+ }
+
+ if (sock->fd == -1) {
+ return;
+ }
+
+ if (flags & EVENT_FD_READ) {
+ sock_process_recv(p);
+ }
+}
+
+/*
+ initiate a read request
+*/
+static NTSTATUS sock_send_read(struct dcerpc_pipe *p)
+{
+ struct sock_private *sock = p->transport.private;
+
+ sock->recv.pending_count++;
+ if (sock->recv.pending_count == 1) {
+ sock->fde->flags |= EVENT_FD_READ;
+ }
+ return NT_STATUS_OK;
+}
+
+/*
+ send an initial pdu in a multi-pdu sequence
+*/
+static NTSTATUS sock_send_request(struct dcerpc_pipe *p, DATA_BLOB *data, BOOL trigger_read)
+{
+ struct sock_private *sock = p->transport.private;
+ struct sock_blob *blob;
+
+ blob = talloc_p(sock, struct sock_blob);
+ if (blob == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ blob->data = data_blob_talloc(blob, data->data, data->length);
+ if (blob->data.data == NULL) {
+ talloc_free(blob);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DLIST_ADD_END(sock->pending_send, blob, struct sock_blob *);
+
+ sock->fde->flags |= EVENT_FD_WRITE;
+
+ if (trigger_read) {
+ sock_send_read(p);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ return the event context so the caller can process asynchronously
+*/
+static struct event_context *sock_event_context(struct dcerpc_pipe *p)
+{
+ struct sock_private *sock = p->transport.private;
+
+ return sock->event_ctx;
+}
+
+/*
+ shutdown sock pipe connection
+*/
+static NTSTATUS sock_shutdown_pipe(struct dcerpc_pipe *p)
+{
+ sock_dead(p, NT_STATUS_OK);
+
+ return NT_STATUS_OK;
+}
+
+/*
+ return sock server name
+*/
+static const char *sock_peer_name(struct dcerpc_pipe *p)
+{
+ struct sock_private *sock = p->transport.private;
+ return sock->server_name;
+}
+
+/*
+ open a rpc connection to a named pipe
+*/
+NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p,
+ const char *server,
+ uint32_t port,
+ int family)
+{
+ struct sock_private *sock;
+ int fd, gai_err;
+ struct fd_event fde;
+ struct addrinfo hints, *res, *tmpres;
+ char portname[16];
+
+ 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;
+ }
+
+ 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;
+ }
+
+ freeaddrinfo(res);
+
+ if (fd == -1) {
+ return NT_STATUS_PORT_CONNECTION_REFUSED;
+ }
+
+ 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_IP_TCP;
+ (*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), server);
+ 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 NT_STATUS_OK;
+}
+
+/*
+ open a rpc connection to a unix socket
+*/
+NTSTATUS dcerpc_pipe_open_unix_stream(struct dcerpc_pipe **p,
+ const char *path)
+{
+ 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) {
+ 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 NT_STATUS_OK;
+}
+
+/*
+ open a rpc connection to a named pipe
+*/
+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;
+ char *canon, *full_path;
+
+ if (!(*p = dcerpc_pipe_init())) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ canon = talloc_strdup(*p, identifier);
+
+ string_replace(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) {
+ 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);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/librpc/rpc/dcerpc_tcp.c b/source4/librpc/rpc/dcerpc_tcp.c
deleted file mode 100644
index 130f20a861..0000000000
--- a/source4/librpc/rpc/dcerpc_tcp.c
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
-
- dcerpc over TCP transport
-
- Copyright (C) Andrew Tridgell 2003
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "includes.h"
-
-#define MIN_HDR_SIZE 16
-
-struct tcp_blob {
- struct tcp_blob *next, *prev;
- DATA_BLOB data;
-};
-
-/* transport private information used by TCP pipe transport */
-struct tcp_private {
- struct event_context *event_ctx;
- struct fd_event *fde;
- int fd;
- char *server_name;
- uint32_t port;
-
- struct tcp_blob *pending_send;
-
- struct {
- size_t received;
- DATA_BLOB data;
- uint_t pending_count;
- } recv;
-};
-
-
-/*
- mark the socket dead
-*/
-static void tcp_sock_dead(struct dcerpc_pipe *p, NTSTATUS status)
-{
- struct tcp_private *tcp = p->transport.private;
-
- if (tcp && tcp->fd != -1) {
- close(tcp->fd);
- tcp->fd = -1;
- }
-
- /* wipe any pending sends */
- while (tcp->pending_send) {
- struct tcp_blob *blob = tcp->pending_send;
- DLIST_REMOVE(tcp->pending_send, blob);
- talloc_free(blob);
- }
-
- if (!NT_STATUS_IS_OK(status)) {
- p->transport.recv_data(p, NULL, status);
- }
-}
-
-/*
- process send requests
-*/
-static void tcp_process_send(struct dcerpc_pipe *p)
-{
- struct tcp_private *tcp = p->transport.private;
-
- while (tcp->pending_send) {
- struct tcp_blob *blob = tcp->pending_send;
- ssize_t ret = write(tcp->fd, blob->data.data, blob->data.length);
- if (ret == -1) {
- if (errno != EAGAIN && errno != EINTR) {
- tcp_sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
- }
- break;
- }
- if (ret == 0) {
- tcp_sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
- break;
- }
-
- blob->data.data += ret;
- blob->data.length -= ret;
-
- if (blob->data.length != 0) {
- break;
- }
-
- DLIST_REMOVE(tcp->pending_send, blob);
- talloc_free(blob);
- }
-
- if (tcp->pending_send == NULL) {
- tcp->fde->flags &= ~EVENT_FD_WRITE;
- }
-}
-
-
-/*
- process recv requests
-*/
-static void tcp_process_recv(struct dcerpc_pipe *p)
-{
- struct tcp_private *tcp = p->transport.private;
- ssize_t ret;
-
- if (tcp->recv.data.data == NULL) {
- tcp->recv.data = data_blob_talloc(tcp, NULL, MIN_HDR_SIZE);
- }
-
- /* read in the base header to get the fragment length */
- if (tcp->recv.received < MIN_HDR_SIZE) {
- uint32_t frag_length;
-
- ret = read(tcp->fd, tcp->recv.data.data,
- MIN_HDR_SIZE - tcp->recv.received);
- if (ret == -1) {
- if (errno != EAGAIN && errno != EINTR) {
- tcp_sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
- }
- return;
- }
- if (ret == 0) {
- tcp_sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
- return;
- }
-
- tcp->recv.received += ret;
-
- if (tcp->recv.received != MIN_HDR_SIZE) {
- return;
- }
- frag_length = dcerpc_get_frag_length(&tcp->recv.data);
-
- tcp->recv.data.data = talloc_realloc(tcp, tcp->recv.data.data,
- frag_length);
- if (tcp->recv.data.data == NULL) {
- tcp_sock_dead(p, NT_STATUS_NO_MEMORY);
- return;
- }
- tcp->recv.data.length = frag_length;
- }
-
- /* read in the rest of the packet */
- ret = read(tcp->fd, tcp->recv.data.data + tcp->recv.received,
- tcp->recv.data.length - tcp->recv.received);
- if (ret == -1) {
- if (errno != EAGAIN && errno != EINTR) {
- tcp_sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
- }
- return;
- }
- if (ret == 0) {
- tcp_sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
- return;
- }
-
- tcp->recv.received += ret;
-
- if (tcp->recv.received != tcp->recv.data.length) {
- return;
- }
-
- /* we have a full packet */
- p->transport.recv_data(p, &tcp->recv.data, NT_STATUS_OK);
- talloc_free(tcp->recv.data.data);
- tcp->recv.data = data_blob(NULL, 0);
- tcp->recv.received = 0;
- tcp->recv.pending_count--;
- if (tcp->recv.pending_count == 0) {
- tcp->fde->flags &= ~EVENT_FD_READ;
- }
-}
-
-/*
- called when a IO is triggered by the events system
-*/
-static void tcp_io_handler(struct event_context *ev, struct fd_event *fde,
- time_t t, uint16_t flags)
-{
- struct dcerpc_pipe *p = fde->private;
- struct tcp_private *tcp = p->transport.private;
-
- if (flags & EVENT_FD_WRITE) {
- tcp_process_send(p);
- }
-
- if (tcp->fd == -1) {
- return;
- }
-
- if (flags & EVENT_FD_READ) {
- tcp_process_recv(p);
- }
-}
-
-/*
- initiate a read request
-*/
-static NTSTATUS tcp_send_read(struct dcerpc_pipe *p)
-{
- struct tcp_private *tcp = p->transport.private;
-
- tcp->recv.pending_count++;
- if (tcp->recv.pending_count == 1) {
- tcp->fde->flags |= EVENT_FD_READ;
- }
- return NT_STATUS_OK;
-}
-
-/*
- send an initial pdu in a multi-pdu sequence
-*/
-static NTSTATUS tcp_send_request(struct dcerpc_pipe *p, DATA_BLOB *data, BOOL trigger_read)
-{
- struct tcp_private *tcp = p->transport.private;
- struct tcp_blob *blob;
-
- blob = talloc_p(tcp, struct tcp_blob);
- if (blob == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- blob->data = data_blob_talloc(blob, data->data, data->length);
- if (blob->data.data == NULL) {
- talloc_free(blob);
- return NT_STATUS_NO_MEMORY;
- }
-
- DLIST_ADD_END(tcp->pending_send, blob, struct tcp_blob *);
-
- tcp->fde->flags |= EVENT_FD_WRITE;
-
- if (trigger_read) {
- tcp_send_read(p);
- }
-
- return NT_STATUS_OK;
-}
-
-/*
- return the event context so the caller can process asynchronously
-*/
-static struct event_context *tcp_event_context(struct dcerpc_pipe *p)
-{
- struct tcp_private *tcp = p->transport.private;
-
- return tcp->event_ctx;
-}
-
-/*
- shutdown TCP pipe connection
-*/
-static NTSTATUS tcp_shutdown_pipe(struct dcerpc_pipe *p)
-{
- tcp_sock_dead(p, NT_STATUS_OK);
-
- return NT_STATUS_OK;
-}
-
-/*
- return TCP server name
-*/
-static const char *tcp_peer_name(struct dcerpc_pipe *p)
-{
- struct tcp_private *tcp = p->transport.private;
- return tcp->server_name;
-}
-
-/*
- open a rpc connection to a named pipe
-*/
-NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p,
- const char *server,
- uint32_t port,
- int family)
-{
- struct tcp_private *tcp;
- int fd, gai_err;
- struct fd_event fde;
- struct addrinfo hints, *res, *tmpres;
- char portname[16];
-
- 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;
- }
-
- 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;
- }
-
- freeaddrinfo(res);
-
- if (fd == -1) {
- return NT_STATUS_PORT_CONNECTION_REFUSED;
- }
-
- 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_IP_TCP;
- (*p)->transport.private = NULL;
-
- (*p)->transport.send_request = tcp_send_request;
- (*p)->transport.send_read = tcp_send_read;
- (*p)->transport.event_context = tcp_event_context;
- (*p)->transport.recv_data = NULL;
-
- (*p)->transport.shutdown_pipe = tcp_shutdown_pipe;
- (*p)->transport.peer_name = tcp_peer_name;
-
- tcp = talloc((*p), sizeof(*tcp));
- if (!tcp) {
- dcerpc_pipe_close(*p);
- return NT_STATUS_NO_MEMORY;
- }
-
- tcp->fd = fd;
- tcp->server_name = talloc_strdup((*p), server);
- tcp->event_ctx = event_context_init(tcp);
- tcp->pending_send = NULL;
- tcp->recv.received = 0;
- tcp->recv.data = data_blob(NULL, 0);
- tcp->recv.pending_count = 0;
-
- fde.fd = fd;
- fde.flags = 0;
- fde.handler = tcp_io_handler;
- fde.private = *p;
-
- tcp->fde = event_add_fd(tcp->event_ctx, &fde);
-
- (*p)->transport.private = tcp;
-
- /* ensure we don't get SIGPIPE */
- BlockSignals(True,SIGPIPE);
-
- return NT_STATUS_OK;
-}
diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c
index f13d969e89..48ae0eec92 100644
--- a/source4/librpc/rpc/dcerpc_util.c
+++ b/source4/librpc/rpc/dcerpc_util.c
@@ -715,6 +715,7 @@ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx, struct dcerpc_binding *
tower->floors[2 + i].lhs.protocol = protseq[i];
tower->floors[2 + i].lhs.info.lhs_data = data_blob_talloc(mem_ctx, NULL, 0);
ZERO_STRUCT(tower->floors[2 + i].rhs);
+ floor_set_rhs_data(mem_ctx, &tower->floors[2 + i], "");
}
/* The 4th floor contains the endpoint */
@@ -724,6 +725,7 @@ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx, struct dcerpc_binding *
return status;
}
}
+
/* The 5th contains the network address */
if (num_protocols >= 3 && binding->host) {
status = floor_set_rhs_data(mem_ctx, &tower->floors[4], binding->host);
@@ -845,6 +847,106 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **p,
return NT_STATUS_OK;
}
+/* open a rpc connection to a rpc pipe on SMP using the binding
+ structure to determine the endpoint and options */
+static NTSTATUS dcerpc_pipe_connect_ncalrpc(struct dcerpc_pipe **p,
+ struct dcerpc_binding *binding,
+ const char *pipe_uuid,
+ uint32_t pipe_version,
+ const char *domain,
+ const char *username,
+ const char *password)
+{
+ NTSTATUS status;
+
+ /* FIXME: Look up identifier using the epmapper */
+ if (!binding->options || !binding->options[0]) {
+ DEBUG(0, ("Identifier not specified\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = dcerpc_pipe_open_pipe(p, binding->options[0]);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("Failed to open ncalrpc pipe '%s'\n", binding->options[0]));
+ return status;
+ }
+
+ (*p)->flags = binding->flags;
+
+ /* remember the binding string for possible secondary connections */
+ (*p)->binding_string = dcerpc_binding_string((*p), binding);
+
+ if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) {
+ status = dcerpc_bind_auth_schannel(*p, pipe_uuid, pipe_version,
+ domain, username, password);
+ } else if (username && username[0]) {
+ status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version, domain, username, password);
+ } else {
+ status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("Failed to bind to uuid %s - %s\n",
+ pipe_uuid, nt_errstr(status)));
+ dcerpc_pipe_close(*p);
+ *p = NULL;
+ return status;
+ }
+
+ return status;
+}
+
+
+
+/* open a rpc connection to a rpc pipe on SMP using the binding
+ structure to determine the endpoint and options */
+static NTSTATUS dcerpc_pipe_connect_ncacn_unix_stream(struct dcerpc_pipe **p,
+ struct dcerpc_binding *binding,
+ const char *pipe_uuid,
+ uint32_t pipe_version,
+ const char *domain,
+ const char *username,
+ const char *password)
+{
+ NTSTATUS status;
+
+ /* FIXME: Look up path via the epmapper */
+ if (!binding->options || !binding->options[0]) {
+ DEBUG(0, ("Path to unix socket not specified\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = dcerpc_pipe_open_unix_stream(p, binding->options[0]);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("Failed to open unix socket %s\n", binding->options[0]));
+ return status;
+ }
+
+ (*p)->flags = binding->flags;
+
+ /* remember the binding string for possible secondary connections */
+ (*p)->binding_string = dcerpc_binding_string((*p), binding);
+
+ if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) {
+ status = dcerpc_bind_auth_schannel(*p, pipe_uuid, pipe_version,
+ domain, username, password);
+ } else if (username && username[0]) {
+ status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version, domain, username, password);
+ } else {
+ status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("Failed to bind to uuid %s - %s\n",
+ pipe_uuid, nt_errstr(status)));
+ dcerpc_pipe_close(*p);
+ *p = NULL;
+ return status;
+ }
+
+ return status;
+}
/* open a rpc connection to a rpc pipe on SMP using the binding
structure to determine the endpoint and options */
@@ -928,6 +1030,12 @@ NTSTATUS dcerpc_pipe_connect_b(struct dcerpc_pipe **p,
status = dcerpc_pipe_connect_ncacn_ip_tcp(p, binding, pipe_uuid, pipe_version,
domain, username, password);
break;
+ case NCACN_UNIX_STREAM:
+ status = dcerpc_pipe_connect_ncacn_unix_stream(p, binding, pipe_uuid, pipe_version, domain, username, password);
+ break;
+ case NCALRPC:
+ status = dcerpc_pipe_connect_ncalrpc(p, binding, pipe_uuid, pipe_version, domain, username, password);
+ break;
default:
return NT_STATUS_NOT_SUPPORTED;
}