From 40c5a1d99fba2144fc3b5d4d8ed5959a269600ca Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 24 Oct 2004 14:57:16 +0000 Subject: r3162: Add client-side support for the ncalrpc: and ncacn_unix_stream: transports. ncalrpc uses the new config option "ncalrpc dir" for creating unix sockets. (This used to be commit b15cfbe2512961a199ecb069730d9a19787579f5) --- source4/build/smb_build/makefile.pl | 3 +- source4/dynconfig.c | 2 + source4/include/dynconfig.h | 1 + source4/librpc/config.m4 | 2 +- source4/librpc/idl/atsvc.idl | 3 +- source4/librpc/idl/browser.idl | 3 +- source4/librpc/idl/echo.idl | 2 +- source4/librpc/idl/epmapper.idl | 3 +- source4/librpc/idl/lsa.idl | 2 +- source4/librpc/idl/oxidresolver.idl | 2 +- source4/librpc/idl/samr.idl | 2 +- source4/librpc/idl/svcctl.idl | 1 + source4/librpc/idl/winreg.idl | 2 +- source4/librpc/rpc/dcerpc_sock.c | 536 ++++++++++++++++++++++++++++++++++++ source4/librpc/rpc/dcerpc_tcp.c | 382 ------------------------- source4/librpc/rpc/dcerpc_util.c | 108 ++++++++ source4/param/loadparm.c | 5 + source4/torture/rpc/epmapper.c | 7 +- 18 files changed, 669 insertions(+), 397 deletions(-) create mode 100644 source4/librpc/rpc/dcerpc_sock.c delete mode 100644 source4/librpc/rpc/dcerpc_tcp.c diff --git a/source4/build/smb_build/makefile.pl b/source4/build/smb_build/makefile.pl index 982b542c2e..108e1a45dc 100644 --- a/source4/build/smb_build/makefile.pl +++ b/source4/build/smb_build/makefile.pl @@ -46,6 +46,7 @@ INSTALLPERMS = 0755 LOGFILEBASE = \@logfilebase\@ CONFIGFILE = \$(CONFIGDIR)/smb.conf LMHOSTSFILE = \$(CONFIGDIR)/lmhosts +NCALRPCDIR = \@localstatedir\@/ncalrpc # This is where smbpasswd et al go PRIVATEDIR = \@privatedir\@ @@ -64,7 +65,7 @@ PATH_FLAGS3 = \$(PATH_FLAGS2) -DLMHOSTSFILE=\\\"\$(LMHOSTSFILE)\\\" PATH_FLAGS4 = \$(PATH_FLAGS3) -DLOCKDIR=\\\"\$(LOCKDIR)\\\" -DPIDDIR=\\\"\$(PIDDIR)\\\" PATH_FLAGS5 = \$(PATH_FLAGS4) -DLIBDIR=\\\"\$(LIBDIR)\\\" \\ -DLOGFILEBASE=\\\"\$(LOGFILEBASE)\\\" -DSHLIBEXT=\\\"\@SHLIBEXT\@\\\" -PATH_FLAGS6 = \$(PATH_FLAGS5) -DCONFIGDIR=\\\"\$(CONFIGDIR)\\\" +PATH_FLAGS6 = \$(PATH_FLAGS5) -DCONFIGDIR=\\\"\$(CONFIGDIR)\\\" -DNCALRPCDIR=\\\"\@NCALRPCDIR\@\\\" PATH_FLAGS = \$(PATH_FLAGS6) \$(PASSWD_FLAGS) "; return $output; diff --git a/source4/dynconfig.c b/source4/dynconfig.c index 9fdbee7cde..cbe9ea49ce 100644 --- a/source4/dynconfig.c +++ b/source4/dynconfig.c @@ -48,6 +48,8 @@ pstring dyn_CONFIGFILE = CONFIGFILE; /**< Location of smb.conf file. **/ /** Log file directory. **/ const char *dyn_LOGFILEBASE = LOGFILEBASE; +const char *dyn_NCALRPCDIR = NCALRPCDIR; + /** Statically configured LanMan hosts. **/ pstring dyn_LMHOSTSFILE = LMHOSTSFILE; diff --git a/source4/include/dynconfig.h b/source4/include/dynconfig.h index 845baa320e..48e02c078a 100644 --- a/source4/include/dynconfig.h +++ b/source4/include/dynconfig.h @@ -29,6 +29,7 @@ extern char const *dyn_SBINDIR, *dyn_BINDIR; extern pstring dyn_CONFIGFILE; +extern const char *dyn_NCALRPCDIR; extern const char *dyn_LOGFILEBASE; extern pstring dyn_LMHOSTSFILE; extern pstring dyn_LIBDIR; 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; } diff --git a/source4/param/loadparm.c b/source4/param/loadparm.c index 397d131d75..59e6fa911a 100644 --- a/source4/param/loadparm.c +++ b/source4/param/loadparm.c @@ -93,6 +93,7 @@ typedef struct char **smb_ports; char *dos_charset; char *unix_charset; + char *ncalrpc_dir; char *display_charset; char *szPrintcapname; char *szLockDir; @@ -505,6 +506,7 @@ static struct parm_struct parm_table[] = { {"dos charset", P_STRING, P_GLOBAL, &Globals.dos_charset, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, {"unix charset", P_STRING, P_GLOBAL, &Globals.unix_charset, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, + {"ncalrpc dir", P_STRING, P_GLOBAL, &Globals.ncalrpc_dir, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, {"display charset", P_STRING, P_GLOBAL, &Globals.display_charset, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, {"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT | FLAG_DEVELOPER}, {"path", P_STRING, P_LOCAL, &sDefault.szPath, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT | FLAG_DEVELOPER}, @@ -916,6 +918,8 @@ static void init_globals(void) do_parameter("pid directory", dyn_PIDDIR); do_parameter("lock dir", dyn_LOCKDIR); + do_parameter("ncalrpc dir", dyn_NCALRPCDIR); + do_parameter("socket address", "0.0.0.0"); do_parameter_var("server string", "Samba %s", SAMBA_VERSION_STRING); @@ -1113,6 +1117,7 @@ FN_GLOBAL_STRING(lp_private_dir, &Globals.szPrivateDir) FN_GLOBAL_STRING(lp_serverstring, &Globals.szServerString) FN_GLOBAL_STRING(lp_printcapname, &Globals.szPrintcapname) FN_GLOBAL_STRING(lp_lockdir, &Globals.szLockDir) +FN_GLOBAL_STRING(lp_ncalrpc_dir, &Globals.ncalrpc_dir) FN_GLOBAL_STRING(lp_piddir, &Globals.szPidDir) FN_GLOBAL_LIST(lp_dcerpc_endpoint_servers, &Globals.dcerpc_ep_servers) FN_GLOBAL_LIST(lp_server_services, &Globals.server_services) diff --git a/source4/torture/rpc/epmapper.c b/source4/torture/rpc/epmapper.c index 3fbee64da1..dae5a396f2 100644 --- a/source4/torture/rpc/epmapper.c +++ b/source4/torture/rpc/epmapper.c @@ -141,11 +141,6 @@ static BOOL test_Map(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.out.entry_handle = &handle; r.in.max_towers = 100; - if (twr->tower.num_floors != 5) { - printf(" tower has %d floors - skipping test_Map\n", twr->tower.num_floors); - return True; - } - uuid_str = GUID_string(mem_ctx, &twr->tower.floors[0].lhs.info.uuid.uuid); printf("epm_Map results for '%s':\n", @@ -201,6 +196,8 @@ static BOOL test_Map(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, } } } + + /* FIXME: Extend to do other protocols as well (ncacn_unix_stream, ncalrpc) */ return True; } -- cgit