1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-22 22:04:08 +03:00

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 commit is contained in:
Jelmer Vernooij 2004-10-24 14:57:16 +00:00 committed by Gerald (Jerry) Carter
parent a953d4a42c
commit b15cfbe251
18 changed files with 669 additions and 397 deletions

View 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;

View 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;

View 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;

View 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])

View 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 {

View File

@ -1,7 +1,8 @@
[
uuid(6bffd098-a112-3610-9833-012892020162),
version(0.0),
helpstring("Browsing")
helpstring("Browsing"),
endpoint("lcalrpc:")
]
interface browser
{

View 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")
]

View 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

View 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

View 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

View 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
{

View 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
{

View 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

View File

@ -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;
}

View File

@ -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;
}

View 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;
}

View 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)

View 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;
}