r3162: Add client-side support for the ncalrpc: and ncacn_unix_stream: transports.
authorJelmer Vernooij <jelmer@samba.org>
Sun, 24 Oct 2004 14:57:16 +0000 (14:57 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:02:27 +0000 (13:02 -0500)
ncalrpc uses the new config option "ncalrpc dir" for creating unix sockets.
(This used to be commit b15cfbe2512961a199ecb069730d9a19787579f5)

18 files changed:
source4/build/smb_build/makefile.pl
source4/dynconfig.c
source4/include/dynconfig.h
source4/librpc/config.m4
source4/librpc/idl/atsvc.idl
source4/librpc/idl/browser.idl
source4/librpc/idl/echo.idl
source4/librpc/idl/epmapper.idl
source4/librpc/idl/lsa.idl
source4/librpc/idl/oxidresolver.idl
source4/librpc/idl/samr.idl
source4/librpc/idl/svcctl.idl
source4/librpc/idl/winreg.idl
source4/librpc/rpc/dcerpc_sock.c [new file with mode: 0644]
source4/librpc/rpc/dcerpc_tcp.c [deleted file]
source4/librpc/rpc/dcerpc_util.c
source4/param/loadparm.c
source4/torture/rpc/epmapper.c

index 982b542c2ed5b4d988cd67d949afab4423729b98..108e1a45dc4c6c20913d2a4cfd3c2ff63f796519 100644 (file)
@@ -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;
index 9fdbee7cdebcec031414c039c8c5e40da83e2be1..cbe9ea49cea5ec00dae0018cfba42a51dc7b9fa5 100644 (file)
@@ -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;
 
index 845baa320e162e3eb0598d989479cf42855eb43c..48e02c078a3eca17f0f429bcad801639c07cb362 100644 (file)
@@ -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;
index a10b4bc7b7eb47bf40a1534d2b568e2a5b841e68..22abcc6f2052af9c620b83199b7a8f709df97a5f 100644 (file)
@@ -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])
index e2e5d3e2c8cce86bd5b417e8411e44e814bdf472..e9e56bfb6abacf8526134ed26bc604aa84c39f2a 100644 (file)
@@ -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 {
index 46011aa6a4cd7dbf1fe01ab149f42850cff7d408..2d4784246daf5ce52ec43f2a22096d1294b1f6cd 100644 (file)
@@ -1,7 +1,8 @@
 [ 
   uuid(6bffd098-a112-3610-9833-012892020162),
   version(0.0), 
-  helpstring("Browsing")
+  helpstring("Browsing"),
+  endpoint("lcalrpc:")
 ] 
 interface browser
 {
index e54b3914f87176c6b8126364e0255bfeca7af940..cfa60412085eff9c70f1c6cc9929a9076a5725ad 100644 (file)
@@ -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")
 ]
index e1e980b0fd8f12a65323b43460b3e0a995c6e486..e0d79a0fe17b74557d3fe30777d262d93a32ba86 100644 (file)
@@ -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
index ca1090545aa7c8e0acb273ca7186eccea40c5fe7..a404ebebff6a282455883d7be2699d990752e6ee 100644 (file)
@@ -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
index 6354e7b38008fe6605effbd7a1ebe3a3053918aa..5627c89f9e0b3dbbccc027f9bbea219d4630d94a 100644 (file)
@@ -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
index f40f71df3ee0716d815baec8739f8f5dd311b23c..43880831f5f1fa73aab5c26c8a424d430b33fe97 100644 (file)
@@ -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
 {
index 87b47fd6dd7f5c1ac91c569a60cc66a371c31cc7..7ea1fee116a3e40e8dcc3e0b453ff4b2284e3979 100644 (file)
@@ -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
 {
index 1f7123f7f379f8c132efe57b39e7b5aff98b3159..c90879f2788cbe33729d9821d29cb5b33a6f2f18 100644 (file)
@@ -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 (file)
index 0000000..9ad5c06
--- /dev/null
@@ -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 (file)
index 130f20a..0000000
+++ /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;
-}
index f13d969e89bf38fe4733e067dfdca64f91f859bc..48ae0eec92ed32401b5a32a9df49c089fba72810 100644 (file)
@@ -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;
        }
index 397d131d7506485605ff018709cb612da7a3278d..59e6fa911a55da7e1c874fef9f445a36521f5309 100644 (file)
@@ -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)
index 3fbee64da1e5b82c360661043ccd2d591a83f58a..dae5a396f260cb73f038bcf5199900369e4f71da 100644 (file)
@@ -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;
 }